diff --git a/Gemfile b/Gemfile index 838308992..db9594753 100644 --- a/Gemfile +++ b/Gemfile @@ -19,6 +19,7 @@ gem 'json_schemer' gem 'js-routes' gem 'kramdown' gem 'kramdown-parser-gfm' +gem 'loofah' gem 'nested_form_fields' gem 'net-http' gem 'net-imap', require: false @@ -30,6 +31,7 @@ gem 'proformaxml', '~> 1.4.0' gem 'puma' gem 'rails', '~> 7.1.3' gem 'rails_admin' +gem 'rails-html-sanitizer' gem 'rails-i18n' gem 'ransack' gem 'rqrcode' @@ -39,6 +41,7 @@ gem 'sassc-rails' gem 'shakapacker', '8.0.1' gem 'simple_form' gem 'slim-rails' +gem 'solid_queue' gem 'sprockets-rails' gem 'terser' gem 'turbolinks' diff --git a/Gemfile.lock b/Gemfile.lock index bd40a83d6..6d1fe1753 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -154,6 +154,8 @@ GEM docile (1.4.0) drb (2.2.1) erubi (1.13.0) + et-orbi (1.2.11) + tzinfo event_stream_parser (1.0.0) execjs (2.9.1) factory_bot (6.4.6) @@ -169,6 +171,9 @@ GEM faraday-net_http (3.1.0) net-http ffi (1.17.0) + fugit (1.11.0) + et-orbi (~> 1, >= 1.2.11) + raabro (~> 1.4) glob (0.4.1) globalid (1.2.1) activesupport (>= 6.1) @@ -280,7 +285,7 @@ GEM net-smtp (0.5.0) net-protocol nio4r (2.7.3) - nokogiri (1.16.6) + nokogiri (1.16.7) mini_portile2 (~> 2.8.2) racc (~> 1.4) omniauth (2.1.2) @@ -299,7 +304,7 @@ GEM parser (3.3.4.0) ast (~> 2.4.1) racc - pg (1.5.6) + pg (1.5.7) proformaxml (1.4.0) activemodel (>= 5.2.3, < 8.0.0) activesupport (>= 5.2.3, < 8.0.0) @@ -326,6 +331,7 @@ GEM rspec-expectations (~> 3.12) rspec-mocks (~> 3.12) rspec-support (~> 3.12) + raabro (1.4.0) racc (1.8.0) rack (3.1.7) rack-mini-profiler (3.3.1) @@ -522,6 +528,12 @@ GEM slim_lint (0.27.0) rubocop (>= 1.0, < 2.0) slim (>= 3.0, < 6.0) + solid_queue (0.3.3) + activejob (>= 7.1) + activerecord (>= 7.1) + concurrent-ruby (>= 1.3.1) + fugit (~> 1.11.0) + railties (>= 7.1) sorted_set (1.0.3) rbtree set (~> 1.0) @@ -608,6 +620,7 @@ DEPENDENCIES kramdown-parser-gfm letter_opener listen + loofah mnemosyne-ruby nested_form_fields net-http @@ -628,6 +641,7 @@ DEPENDENCIES rack-mini-profiler rails (~> 7.1.3) rails-controller-testing + rails-html-sanitizer rails-i18n rails_admin ransack @@ -654,6 +668,7 @@ DEPENDENCIES simplecov slim-rails slim_lint + solid_queue sprockets-rails stackprof terser diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 000000000..f378bca4a --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class ApplicationJob < ActiveJob::Base + include ActiveRecordLogging + + # Automatically retry jobs that encountered a deadlock + retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + discard_on ActiveJob::DeserializationError +end diff --git a/app/jobs/concerns/active_record_logging.rb b/app/jobs/concerns/active_record_logging.rb new file mode 100644 index 000000000..5a2c38c4a --- /dev/null +++ b/app/jobs/concerns/active_record_logging.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +# This module is used to log ActiveRecord queries performed in jobs. +module ActiveRecordLogging + extend ActiveSupport::Concern + + included do + around_perform do |_job, block| + # With our current Solid Queue setup, there is a difference between both logger: + # - *ActiveRecord::Base.logger*: This logger is used for SQL queries and, normally, writes to the log file only. + # - *Rails.logger*: The regular logger, which writes to the log file and the console. + # For the duration of the job, we want to write the SQL queries to the Rails logger, so they show up in the console. + # See config/solid_queue_logging.rb for more information. + previous_logger = ActiveRecord::Base.logger + ActiveRecord::Base.logger = Rails.logger + block.call + ActiveRecord::Base.logger = previous_logger + end + end +end diff --git a/app/jobs/nbp_sync_all_job.rb b/app/jobs/nbp_sync_all_job.rb new file mode 100644 index 000000000..c560e4b45 --- /dev/null +++ b/app/jobs/nbp_sync_all_job.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +class NbpSyncAllJob < ApplicationJob + def perform + uuids = Set[] + + # First, add all uploaded UUIDs. + # This allows us to delete the ones that are still present remote but no longer in the local database. + Nbp::PushConnector.instance.process_uploaded_task_uuids do |uuid| + uuids.add(uuid) + end + + # Then, add all local UUIDs. + # This allows us to upload tasks missing remote (and remove private tasks not yet removed). + Task.select(:id, :uuid).find_each {|task| uuids.add(task.uuid) } + + # Finally, schedule a full sync for each UUID identified. + uuids.each do |uuid| + NbpSyncJob.perform_later uuid + end + end +end diff --git a/app/jobs/nbp_sync_job.rb b/app/jobs/nbp_sync_job.rb new file mode 100644 index 000000000..b52952002 --- /dev/null +++ b/app/jobs/nbp_sync_job.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class NbpSyncJob < ApplicationJob + retry_on Faraday::Error, Nbp::PushConnector::ServerError, wait: :polynomially_longer, attempts: 5 + + def perform(uuid) + task = Task.find_by(uuid:) + + if task.present? && task.access_level_public? + builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') {|xml| LomService::ExportLom.call(task:, xml:) } + Nbp::PushConnector.instance.push_lom!(builder.to_xml) + Rails.logger.debug { "Task ##{task.id} \"#{task}\" pushed to NBP" } + else + Nbp::PushConnector.instance.delete_task!(uuid) + Rails.logger.debug { "Task with UUID #{uuid} deleted from NBP" } + end + end +end diff --git a/app/models/task.rb b/app/models/task.rb index 0872dfc74..28fe2d2df 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -5,11 +5,13 @@ class Task < ApplicationRecord acts_as_taggable_on :state + before_validation :lowercase_language + after_commit :sync_metadata_with_nbp, if: -> { Nbp::PushConnector.enabled? } + validates :title, presence: true validates :uuid, uniqueness: true - before_validation :lowercase_language validates :language, format: {with: /\A[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*\z/, message: :not_de_or_us} validate :primary_language_tag_in_iso639? @@ -102,6 +104,13 @@ def self.ransackable_associations(_auth_object = nil) %w[labels] end + def sync_metadata_with_nbp + if access_level_public? || saved_change_to_access_level? + NbpSyncJob.perform_later uuid + NbpSyncJob.perform_later uuid_previously_was if saved_change_to_uuid? && access_level_previously_was == 'public' + end + end + # This method creates a duplicate while leaving permissions and ownership unchanged def duplicate dup.tap do |task| diff --git a/app/services/lom_service/export_lom.rb b/app/services/lom_service/export_lom.rb index 723bc27e6..6c037c013 100644 --- a/app/services/lom_service/export_lom.rb +++ b/app/services/lom_service/export_lom.rb @@ -38,7 +38,9 @@ def oml_general(xml) end xml.language @task.iso639_lang xml.description do - xml.string ApplicationController.helpers.render_markdown(@task.description), language: @task.iso639_lang + html_fragment = Loofah.fragment(ApplicationController.helpers.render_markdown(@task.description)) + html_fragment.scrub!(NbpScrubber.new) + xml.string html_fragment.to_s, language: @task.iso639_lang end if @task.programming_language&.language.present? xml.keyword do diff --git a/app/services/lom_service/nbp_scrubber.rb b/app/services/lom_service/nbp_scrubber.rb new file mode 100644 index 000000000..f2c4b2125 --- /dev/null +++ b/app/services/lom_service/nbp_scrubber.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module LomService + class NbpScrubber < Rails::HTML::PermitScrubber + ALLOW_LIST = YAML.safe_load_file(Rails.root.join('app/services/lom_service/nbp_scrubber_allow_list.yml')) + + def initialize + super + self.tags = ALLOW_LIST['tags'] + self.attributes = ALLOW_LIST['attributes'] + end + end +end diff --git a/app/services/lom_service/nbp_scrubber_allow_list.yml b/app/services/lom_service/nbp_scrubber_allow_list.yml new file mode 100644 index 000000000..5707e1779 --- /dev/null +++ b/app/services/lom_service/nbp_scrubber_allow_list.yml @@ -0,0 +1,197 @@ +--- +tags: + - a + - abbr + - acronym + - address + - area + - article + - aside + - b + - bdi + - big + - blockquote + - body + - br + - button + - caption + - center + - cite + - code + - col + - colgroup + - data + - datalist + - dd + - del + - details + - dfn + - dir + - div + - dl + - dt + - em + - fieldset + - figcaption + - figure + - font + - footer + - form + - h1 + - h2 + - h3 + - h4 + - h5 + - h6 + - head + - header + - hr + - html + - i + - img + - input + - ins + - kbd + - keygen + - label + - legend + - li + - main + - map + - mark + - menu + - menuitem + - meter + - nav + - ol + - optgroup + - option + - output + - p + - pre + - progress + - q + - rp + - rt + - ruby + - s + - samp + - section + - select + - small + - span + - strike + - strong + - sub + - summary + - sup + - table + - tbody + - td + - textarea + - tfoot + - th + - thead + - time + - tr + - tt + - u + - ul + - var + - wbr +attributes: + - abbr + - accept-charset + - accept + - accesskey + - action + - align + - alt + - autocomplete + - autosave + - axis + - bgcolor + - border + - cellpadding + - cellspacing + - challenge + - char + - charoff + - charset + - checked + - cite + - clear + - color + - cols + - colspan + - compact + - contenteditable + - coords + - datetime + - dir + - disabled + - draggable + - dropzone + - enctype + - for + - frame + - headers + - height + - high + - href + - hreflang + - hspace + - ismap + - keytype + - label + - lang + - list + - longdesc + - low + - max + - maxlength + - media + - method + - min + - multiple + - name + - nohref + - noshade + - novalidate + - nowrap + - open + - optimum + - pattern + - placeholder + - prompt + - pubdate + - radiogroup + - readonly + - rel + - required + - rev + - reversed + - rows + - rowspan + - rules + - scope + - selected + - shape + - size + - span + - spellcheck + - src + - start + - step + - style + - summary + - tabindex + - target + - title + - type + - usemap + - valign + - value + - vspace + - width + - wrap diff --git a/config/application.rb b/config/application.rb index 4a01363fb..bcbeffd74 100644 --- a/config/application.rb +++ b/config/application.rb @@ -50,5 +50,8 @@ class Application < Rails::Application # Fix invalid Content-Type header for incoming requests made by edu-sharing. config.middleware.insert_before 0, Middleware::EduSharingContentType + + # Configure some defaults for the Solid Queue Supervisor + require_relative 'solid_queue_defaults' end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 80d25f19b..cda0c98b1 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -44,6 +44,10 @@ # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false + # Use a real queuing backend for Active Job (and separate queues per environment). + config.active_job.queue_adapter = :solid_queue + config.active_job.queue_name_prefix = 'codeharbor_development' + config.action_mailer.perform_caching = false # Print deprecation notices to the Rails logger. diff --git a/config/environments/production.rb b/config/environments/production.rb index c167344d6..a5249631a 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -77,8 +77,8 @@ # config.cache_store = :mem_cache_store # Use a real queuing backend for Active Job (and separate queues per environment). - # config.active_job.queue_adapter = :resque - # config.active_job.queue_name_prefix = "codeharbor_production" + config.active_job.queue_adapter = :solid_queue + config.active_job.queue_name_prefix = 'codeharbor_production' config.action_mailer.perform_caching = false diff --git a/config/environments/test.rb b/config/environments/test.rb index 70f731662..79c2510d0 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -39,6 +39,10 @@ # Store uploaded files on the local file system in a temporary directory. config.active_storage.service = :test + # Use a real queuing backend for Active Job (and separate queues per environment). + config.active_job.queue_adapter = :solid_queue + config.active_job.queue_name_prefix = 'codeharbor_test' + config.action_mailer.perform_caching = false # Tell Action Mailer not to deliver emails to the real world. diff --git a/config/schedule.rb b/config/schedule.rb index 072c66669..9c8afb02d 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -28,4 +28,5 @@ every 1.day, at: '3:00 am' do rake 'import_cache_files:cleanup' + runner 'SolidQueue::Job.clear_finished_in_batches' end diff --git a/config/settings/test.yml b/config/settings/test.yml index 69bd94c33..dfb4a50be 100644 --- a/config/settings/test.yml +++ b/config/settings/test.yml @@ -20,5 +20,16 @@ omniauth: private_key: ~ oai_pmh: admin_mail: admin@example.org +nbp: + push_connector: + enable: true + client_id: testing_client_id + client_secret: testing_client_secret + token_path: 'https://test.provider/token' + api_host: 'https://test.api.host' + source: + organization: test_organization + name: CodeHarbor + slug: CoHaP2 open_ai: model: gpt-4o-mini diff --git a/config/solid_queue.yml b/config/solid_queue.yml new file mode 100644 index 000000000..73dd19e0c --- /dev/null +++ b/config/solid_queue.yml @@ -0,0 +1,25 @@ + default: &default + dispatchers: + - polling_interval: 1 + batch_size: 500 + workers: + - queues: "*" + threads: 3 + processes: 1 + polling_interval: 0.1 + + development: + <<: *default + + test: + <<: *default + + production: + <<: *default + dispatchers: + - polling_interval: 1 + batch_size: 500 + recurring_tasks: + nbp_sync_all_job: + class: NbpSyncAllJob + schedule: "0 3 * * *" diff --git a/config/solid_queue_defaults.rb b/config/solid_queue_defaults.rb new file mode 100644 index 000000000..d30aadd5f --- /dev/null +++ b/config/solid_queue_defaults.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# This file must be loaded before other initializers due to the logging configuration. +Rails.application.configure do + # On shutdown, jobs Solid Queue will wait the specified timeout before forcefully shutting down. + # Any job not finished by then will be picked up again after a restart. + config.solid_queue.shutdown_timeout = 10.seconds + # Remove *successful* jobs from the database after 30 days + config.solid_queue.clear_finished_jobs_after = 30.days + config.solid_queue.supervisor_pidfile = Rails.root.join('tmp/pids/solid_queue_supervisor.pid') + + # For Solid Queue, we want to hide regular SQL queries from the console, but still log them to a separate file. + # For the normal webserver, this dedicated setup is neither needed nor desired. + next unless Rake.application.top_level_tasks.to_s.include?('solid_queue:') + + # Specify that all logs should be written to the specified log file + file_name = "#{Rails.env}.solid_queue.log" + config.paths.add 'log', with: "log/#{file_name}" + + # Send all logs regarding SQL queries to the log file. + # This will include all queries performed by Solid Queue including periodic job checks. + log_file = ActiveSupport::Logger.new(Rails.root.join('log', file_name)) + config.active_record.logger = ActiveSupport::BroadcastLogger.new(log_file) + + config.after_initialize do + # Create a new logger that will write to the console + console = ActiveSupport::Logger.new($stdout) + console.level = Rails.logger.level + # Enable this line to have the same log format as Rails.logger + # It will include the job name, the job ID for each line + # console.formatter = Rails.logger.formatter + + ActiveSupport.on_load :solid_queue_record do + # Once SolidQueue is loaded, we can broadcast its logs to the console, too. + # Due to the initialization order, this will effectively start logging once SolidQueue is about to start. + Rails.logger.broadcast_to console + end + end +end diff --git a/db/migrate/20240609104039_create_solid_queue_tables.solid_queue.rb b/db/migrate/20240609104039_create_solid_queue_tables.solid_queue.rb new file mode 100644 index 000000000..874f68ba0 --- /dev/null +++ b/db/migrate/20240609104039_create_solid_queue_tables.solid_queue.rb @@ -0,0 +1,103 @@ +# frozen_string_literal: true + +# This migration comes from solid_queue (originally 20231211200639) +class CreateSolidQueueTables < ActiveRecord::Migration[7.0] + def change + create_table :solid_queue_jobs do |t| + t.string :queue_name, null: false + t.string :class_name, null: false, index: true + t.text :arguments + t.integer :priority, default: 0, null: false + t.string :active_job_id, index: true + t.datetime :scheduled_at + t.datetime :finished_at, index: true + t.string :concurrency_key + + t.timestamps + + t.index %i[queue_name finished_at], name: 'index_solid_queue_jobs_for_filtering' + t.index %i[scheduled_at finished_at], name: 'index_solid_queue_jobs_for_alerting' + end + + create_table :solid_queue_scheduled_executions do |t| + t.references :job, index: {unique: true}, null: false + t.string :queue_name, null: false + t.integer :priority, default: 0, null: false + t.datetime :scheduled_at, null: false + + t.datetime :created_at, null: false + + t.index %i[scheduled_at priority job_id], name: 'index_solid_queue_dispatch_all' + end + + create_table :solid_queue_ready_executions do |t| + t.references :job, index: {unique: true}, null: false + t.string :queue_name, null: false + t.integer :priority, default: 0, null: false + + t.datetime :created_at, null: false + + t.index %i[priority job_id], name: 'index_solid_queue_poll_all' + t.index %i[queue_name priority job_id], name: 'index_solid_queue_poll_by_queue' + end + + create_table :solid_queue_claimed_executions do |t| + t.references :job, index: {unique: true}, null: false + t.bigint :process_id + t.datetime :created_at, null: false + + t.index %i[process_id job_id] + end + + create_table :solid_queue_blocked_executions do |t| + t.references :job, index: {unique: true}, null: false + t.string :queue_name, null: false + t.integer :priority, default: 0, null: false + t.string :concurrency_key, null: false + t.datetime :expires_at, null: false + + t.datetime :created_at, null: false + + t.index %i[expires_at concurrency_key], name: 'index_solid_queue_blocked_executions_for_maintenance' + end + + create_table :solid_queue_failed_executions do |t| + t.references :job, index: {unique: true}, null: false + t.text :error + t.datetime :created_at, null: false + end + + create_table :solid_queue_pauses do |t| + t.string :queue_name, null: false, index: {unique: true} + t.datetime :created_at, null: false + end + + create_table :solid_queue_processes do |t| + t.string :kind, null: false + t.datetime :last_heartbeat_at, null: false, index: true + t.bigint :supervisor_id, index: true + + t.integer :pid, null: false + t.string :hostname + t.text :metadata + + t.datetime :created_at, null: false + end + + create_table :solid_queue_semaphores do |t| + t.string :key, null: false, index: {unique: true} + t.integer :value, default: 1, null: false + t.datetime :expires_at, null: false, index: true + + t.timestamps + + t.index %i[key value], name: 'index_solid_queue_semaphores_on_key_and_value' + end + + add_foreign_key :solid_queue_blocked_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade + add_foreign_key :solid_queue_claimed_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade + add_foreign_key :solid_queue_failed_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade + add_foreign_key :solid_queue_ready_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade + add_foreign_key :solid_queue_scheduled_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade + end +end diff --git a/db/migrate/20240609104040_add_missing_index_to_blocked_executions.solid_queue.rb b/db/migrate/20240609104040_add_missing_index_to_blocked_executions.solid_queue.rb new file mode 100644 index 000000000..491e2181d --- /dev/null +++ b/db/migrate/20240609104040_add_missing_index_to_blocked_executions.solid_queue.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# This migration comes from solid_queue (originally 20240110143450) +class AddMissingIndexToBlockedExecutions < ActiveRecord::Migration[7.1] + def change + add_index :solid_queue_blocked_executions, %i[concurrency_key priority job_id], name: 'index_solid_queue_blocked_executions_for_release' + end +end diff --git a/db/migrate/20240609104041_create_recurring_executions.solid_queue.rb b/db/migrate/20240609104041_create_recurring_executions.solid_queue.rb new file mode 100644 index 000000000..69847c125 --- /dev/null +++ b/db/migrate/20240609104041_create_recurring_executions.solid_queue.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +# This migration comes from solid_queue (originally 20240218110712) +class CreateRecurringExecutions < ActiveRecord::Migration[7.1] + def change + create_table :solid_queue_recurring_executions do |t| + t.references :job, index: {unique: true}, null: false + t.string :task_key, null: false + t.datetime :run_at, null: false + t.datetime :created_at, null: false + + t.index %i[task_key run_at], unique: true + end + + add_foreign_key :solid_queue_recurring_executions, :solid_queue_jobs, column: :job_id, on_delete: :cascade + end +end diff --git a/db/schema.rb b/db/schema.rb index 8b9a81aa7..d658d30d6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_07_03_221801) do +ActiveRecord::Schema[7.1].define(version: 2024_06_09_104041) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" enable_extension "plpgsql" @@ -200,6 +200,109 @@ t.index ["user_id"], name: "index_reports_on_user_id" end + create_table "solid_queue_blocked_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.string "concurrency_key", null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.index ["concurrency_key", "priority", "job_id"], name: "index_solid_queue_blocked_executions_for_release" + t.index ["expires_at", "concurrency_key"], name: "index_solid_queue_blocked_executions_for_maintenance" + t.index ["job_id"], name: "index_solid_queue_blocked_executions_on_job_id", unique: true + end + + create_table "solid_queue_claimed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.bigint "process_id" + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_claimed_executions_on_job_id", unique: true + t.index ["process_id", "job_id"], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id" + end + + create_table "solid_queue_failed_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.text "error" + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_failed_executions_on_job_id", unique: true + end + + create_table "solid_queue_jobs", force: :cascade do |t| + t.string "queue_name", null: false + t.string "class_name", null: false + t.text "arguments" + t.integer "priority", default: 0, null: false + t.string "active_job_id" + t.datetime "scheduled_at" + t.datetime "finished_at" + t.string "concurrency_key" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["active_job_id"], name: "index_solid_queue_jobs_on_active_job_id" + t.index ["class_name"], name: "index_solid_queue_jobs_on_class_name" + t.index ["finished_at"], name: "index_solid_queue_jobs_on_finished_at" + t.index ["queue_name", "finished_at"], name: "index_solid_queue_jobs_for_filtering" + t.index ["scheduled_at", "finished_at"], name: "index_solid_queue_jobs_for_alerting" + end + + create_table "solid_queue_pauses", force: :cascade do |t| + t.string "queue_name", null: false + t.datetime "created_at", null: false + t.index ["queue_name"], name: "index_solid_queue_pauses_on_queue_name", unique: true + end + + create_table "solid_queue_processes", force: :cascade do |t| + t.string "kind", null: false + t.datetime "last_heartbeat_at", null: false + t.bigint "supervisor_id" + t.integer "pid", null: false + t.string "hostname" + t.text "metadata" + t.datetime "created_at", null: false + t.index ["last_heartbeat_at"], name: "index_solid_queue_processes_on_last_heartbeat_at" + t.index ["supervisor_id"], name: "index_solid_queue_processes_on_supervisor_id" + end + + create_table "solid_queue_ready_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_ready_executions_on_job_id", unique: true + t.index ["priority", "job_id"], name: "index_solid_queue_poll_all" + t.index ["queue_name", "priority", "job_id"], name: "index_solid_queue_poll_by_queue" + end + + create_table "solid_queue_recurring_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "task_key", null: false + t.datetime "run_at", null: false + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_recurring_executions_on_job_id", unique: true + t.index ["task_key", "run_at"], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true + end + + create_table "solid_queue_scheduled_executions", force: :cascade do |t| + t.bigint "job_id", null: false + t.string "queue_name", null: false + t.integer "priority", default: 0, null: false + t.datetime "scheduled_at", null: false + t.datetime "created_at", null: false + t.index ["job_id"], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true + t.index ["scheduled_at", "priority", "job_id"], name: "index_solid_queue_dispatch_all" + end + + create_table "solid_queue_semaphores", force: :cascade do |t| + t.string "key", null: false + t.integer "value", default: 1, null: false + t.datetime "expires_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["expires_at"], name: "index_solid_queue_semaphores_on_expires_at" + t.index ["key", "value"], name: "index_solid_queue_semaphores_on_key_and_value" + t.index ["key"], name: "index_solid_queue_semaphores_on_key", unique: true + end + create_table "taggings", id: :serial, force: :cascade do |t| t.integer "tag_id" t.string "taggable_type" @@ -352,6 +455,12 @@ add_foreign_key "ratings", "users" add_foreign_key "reports", "tasks" add_foreign_key "reports", "users" + add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "task_labels", "tasks" add_foreign_key "tasks", "licenses" add_foreign_key "tests", "tasks" diff --git a/docs/LOCAL_SETUP.md b/docs/LOCAL_SETUP.md index 14d419740..5ac404d7d 100644 --- a/docs/LOCAL_SETUP.md +++ b/docs/LOCAL_SETUP.md @@ -181,7 +181,9 @@ rake db:setup ### Start CodeHarbor -For the development environment, two server processes are required: the Rails server for the main application and a Webpack server providing JavaScript and CSS assets. +For the development environment, three server processes are required: +the Rails server for the main application, a Webpack server providing JavaScript and CSS assets +and the Solid Queue supervisor to process background jobs. 1. Webpack dev server: @@ -201,6 +203,12 @@ This will launch a dedicated server on port 3045 (default setting) and allow inc This will launch the CodeHarbor web application server on port 7500 (default setting) and allow incoming connections from your browser. +3. Solid Queue supervisor: + + ```shell + bundle exec rake solid_queue:start + ``` + **Check with:** Open your web browser at diff --git a/lib/nbp/push_connector.rb b/lib/nbp/push_connector.rb new file mode 100644 index 000000000..bfa2c089d --- /dev/null +++ b/lib/nbp/push_connector.rb @@ -0,0 +1,154 @@ +# frozen_string_literal: true + +require 'singleton' +require 'concurrent' + +module Nbp + class PushConnector + include Singleton + + class Error < StandardError; end + class SettingsError < Error; end + class ServerError < Error; end + + def initialize + super + @token = Concurrent::ThreadLocalVar.new + @token_expiration = Concurrent::ThreadLocalVar.new + + create_source! unless source_exists? + end + + def self.enabled? + @enabled = Settings.nbp&.push_connector&.enable || false if @enabled.nil? + @enabled + end + + def push_lom!(xml) + response = api_conn.put("/push-connector/api/lom-v2/#{source_slug}") do |req| + req.body = {metadata: xml}.to_json + end + raise ServerError if response.status == 500 + + raise_connector_error('Could not push task LOM', response) unless response.success? + end + + def delete_task!(task_uuid) + response = api_conn.delete("/push-connector/api/course/#{source_slug}/#{task_uuid}") + raise ServerError if response.status == 500 + + raise_connector_error('Could not delete task', response) unless response.success? || response.status == 404 + end + + def process_uploaded_task_uuids(&) + offset = 0 + until (uuids = get_uploaded_task_uuids(offset)).empty? + offset += uuids.length + uuids.map(&) + end + end + + def source_exists? + response = api_conn.get("/datenraum/api/core/sources/slug/#{source_slug}") + if response.status == 200 + true + elsif response.status == 404 + false + else + raise_connector_error('Could not determine if source exists', response) + end + end + + private + + def get_uploaded_task_uuids(offset, limit = 100) # rubocop:disable Metrics/AbcSize + raise Error('The NBP API does not accept limits over 100') if limit > 100 + + response = api_conn.get('/datenraum/api/core/nodes') do |req| + req.params[:sourceSlug] = source_slug + req.params[:offset] = offset + req.params[:limit] = limit + end + raise ServerError if response.status == 500 + + raise_connector_error('Could query existing tasks', response) unless response.success? + + nodes = JSON.parse(response.body).deep_symbolize_keys.dig(:_embedded, :nodes) + raise_connector_error('Nodes response did not contain nodes list', response) if nodes.nil? + + nodes.pluck(:externalId).compact + end + + def create_source! + response = api_conn.post('/datenraum/api/core/sources') do |req| + req.body = settings.source.to_json + end + raise_connector_error('Failed to create source', response) unless response.success? + end + + def token + if @token.value.present? && @token_expiration.value > 10.seconds.from_now + @token.value + else + update_token + end + end + + def update_token + response = Faraday.post(settings.token_path, auth) + result = JSON.parse(response.body) + + if response.success? + @token_expiration.value = Time.zone.now + result['expires_in'] + @token.value = result['access_token'] + else + raise_connector_error('Failed to get fresh access token', response) + end + end + + def auth + { + grant_type: 'client_credentials', + client_id: settings.client_id, + client_secret: settings.client_secret, + } + end + + def api_conn + Faraday.new(url: settings.api_host, headers:) + end + + def source_slug + settings.source.slug + end + + def settings + return @connector_settings if @connector_settings + + check_settings! + @connector_settings = Settings.nbp&.push_connector + end + + def check_settings! # rubocop:disable Metrics/AbcSize + settings_hash = Settings.nbp&.push_connector.to_h + + if PushConnector.enabled? + missing_keys = %i[client_id client_secret token_path api_host source] - settings_hash.keys + raise SettingsError.new("Nbp::PushConnector is missing some settings: #{missing_keys}") if missing_keys.any? + + missing_source_keys = %i[organization name slug] - settings_hash[:source].keys + raise SettingsError.new("Nbp::PushConnector source is missing some settings: #{missing_source_keys}") if missing_source_keys.any? + else + raise SettingsError.new('Nbp::PushConnector is disabled but got accessed') + end + end + + def raise_connector_error(message, faraday_response) + raise Error.new("#{message} (code #{faraday_response.status}). Response was: '#{faraday_response.body}'") + end + + def headers + {authorization: "Bearer #{token}", 'content-type': 'application/json', accept: 'application/json'} + end + end +end diff --git a/lib/tasks/nbp_push_all_tasks.rake b/lib/tasks/nbp_push_all_tasks.rake new file mode 100644 index 000000000..fc5752f5d --- /dev/null +++ b/lib/tasks/nbp_push_all_tasks.rake @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +namespace :nbp do + desc 'Pushes all tasks to the NBP for an initial sync' + task push_all: :environment do + NbpSyncAllJob.perform_later + end +end diff --git a/package.json b/package.json index ffa8b2681..d5b995dc7 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,10 @@ "name": "codeharbor", "private": true, "dependencies": { - "@babel/core": "7.24.9", + "@babel/core": "7.25.2", "@babel/plugin-transform-runtime": "7.24.7", - "@babel/preset-env": "7.24.8", - "@babel/runtime": "7.24.8", + "@babel/preset-env": "7.25.2", + "@babel/runtime": "7.25.0", "@fortawesome/fontawesome-free": "^6.6.0", "@popperjs/core": "^2.11.8", "@sentry/browser": "^8.20.0", diff --git a/spec/fixtures/files/nbp/empty_nodes.json b/spec/fixtures/files/nbp/empty_nodes.json new file mode 100644 index 000000000..36f2fb2cc --- /dev/null +++ b/spec/fixtures/files/nbp/empty_nodes.json @@ -0,0 +1,12 @@ +{ + "total":0, + "offset":3, + "limit":100, + "_embedded":{ + "nodes":[] + }, + "_links":{ + "self":null, + "next":null + } +} diff --git a/spec/fixtures/files/nbp/nodes.json b/spec/fixtures/files/nbp/nodes.json new file mode 100644 index 000000000..5f130d748 --- /dev/null +++ b/spec/fixtures/files/nbp/nodes.json @@ -0,0 +1,151 @@ +{ + "total":3, + "offset":0, + "limit":100, + "_embedded":{ + "nodes":[ + { + "id":"d381bbac-4686-4d6c-8679-5637b5efd104", + "title":"Minimal Hello World", + "description":"Write a simple program that prints \"Hello World\".", + "externalId":"external-id-1", + "sourceId":"a3634a05-ab0a-4550-8961-65796b05ca47", + "metadata":{ + "Amb":{ + "id":"http://localhost:7500/tasks/2", + "name":"Minimal Hello World", + "type":[ + "LearningResource", + "Course" + ], + "creator":[ + { + "name":"some first name jackson351467", + "type":"Organization" + } + ], + "@context":[ + "https://w3id.org/kim/amb/context.jsonld", + "https://schema.org", + { + "@language":"en" + } + ], + "inLanguage":[ + "en" + ], + "dateCreated":"2024-05-24T00:00:00", + "description":"Write a simple program that prints \"Hello World\".", + "isAccessibleForFree":true + } + }, + "class":"LearningOpportunity", + "_embedded":null, + "_links":{ + "self":{ + "href":"https://dam.demo.meinbildungsraum.de/datenraum/api/core/nodes/d381bbac-4686-4d6c-8679-5637b5efd104" + }, + "headNodes":null, + "tailNodes":null, + "childNodes":null + } + }, + { + "id":"500ad140-6a62-43f4-b78e-3554697b27e6", + "title":"nbp test task", + "description":"", + "externalId":"external-id-2", + "sourceId":"a3634a05-ab0a-4550-8961-65796b05ca47", + "metadata":{ + "Amb":{ + "id":"http://localhost:7500/tasks/8", + "name":"nbp test task", + "type":[ + "LearningResource", + "Course" + ], + "creator":[ + { + "name":"john oliver", + "type":"Organization" + } + ], + "@context":[ + "https://w3id.org/kim/amb/context.jsonld", + "https://schema.org", + { + "@language":"en" + } + ], + "inLanguage":[ + "en" + ], + "dateCreated":"2024-06-17T00:00:00", + "description":"", + "isAccessibleForFree":true + } + }, + "class":"LearningOpportunity", + "_embedded":null, + "_links":{ + "self":{ + "href":"https://dam.demo.meinbildungsraum.de/datenraum/api/core/nodes/500ad140-6a62-43f4-b78e-3554697b27e6" + }, + "headNodes":null, + "tailNodes":null, + "childNodes":null + } + }, + { + "id":"50c9dc43-5ede-4748-a1f4-3b045e506d30", + "title":"nbp test task", + "description":"", + "externalId":"external-id-3", + "sourceId":"a3634a05-ab0a-4550-8961-65796b05ca47", + "metadata":{ + "Amb":{ + "id":"http://localhost:7500/tasks/6", + "name":"nbp test task", + "type":[ + "LearningResource", + "Course" + ], + "creator":[ + { + "name":"john oliver", + "type":"Organization" + } + ], + "@context":[ + "https://w3id.org/kim/amb/context.jsonld", + "https://schema.org", + { + "@language":"en" + } + ], + "inLanguage":[ + "en" + ], + "dateCreated":"2024-06-10T00:00:00", + "description":"", + "isAccessibleForFree":true + } + }, + "class":"LearningOpportunity", + "_embedded":null, + "_links":{ + "self":{ + "href":"https://dam.demo.meinbildungsraum.de/datenraum/api/core/nodes/50c9dc43-5ede-4748-a1f4-3b045e506d30" + }, + "headNodes":null, + "tailNodes":null, + "childNodes":null + } + } + ] + }, + "_links":{ + "self":null, + "next":null + } +} diff --git a/spec/jobs/nbp_sync_all_job_spec.rb b/spec/jobs/nbp_sync_all_job_spec.rb new file mode 100644 index 000000000..76957fcd7 --- /dev/null +++ b/spec/jobs/nbp_sync_all_job_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe NbpSyncAllJob do + include ActiveJob::TestHelper + + let(:api_host) { Settings.nbp.push_connector.api_host } + let(:source_slug) { Settings.nbp.push_connector.source.slug } + + let!(:local_uuids) { create_list(:task, 3, access_level: :public).pluck(:uuid) } + let!(:uploaded_uuids) { [Random.uuid, local_uuids.first, local_uuids.second] } + let!(:all_uuids) { local_uuids | uploaded_uuids } + + before do + stub_request(:post, Settings.nbp.push_connector.token_path).to_return_json(body: {token: 'sometoken', expires_in: 600}) + stub_request(:get, "#{api_host}/datenraum/api/core/sources/slug/#{source_slug}").to_return(status: 200) + + allow(Nbp::PushConnector.instance).to receive(:get_uploaded_task_uuids).with(0).and_return(uploaded_uuids) + allow(Nbp::PushConnector.instance).to receive(:get_uploaded_task_uuids).with(3).and_return([]) + end + + describe 'perform' do + subject(:perform_job) { described_class.perform_now } + + it 'schedules the correct sync jobs' do + expect { perform_job }.to have_enqueued_job(NbpSyncJob).with(all_uuids.first) + .and have_enqueued_job(NbpSyncJob).with(all_uuids.second) + .and have_enqueued_job(NbpSyncJob).with(all_uuids.third) + .and have_enqueued_job(NbpSyncJob).with(all_uuids.fourth) + end + end + + describe 'rake' do + subject(:push_all) { Rake::Task['nbp:push_all'].invoke } + + before { Rails.application.load_tasks if Rake::Task.tasks.empty? } + + it 'schedules the desired job' do + expect { push_all }.to have_enqueued_job(described_class) + end + end +end diff --git a/spec/jobs/nbp_sync_job_spec.rb b/spec/jobs/nbp_sync_job_spec.rb new file mode 100644 index 000000000..4b89f7129 --- /dev/null +++ b/spec/jobs/nbp_sync_job_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe NbpSyncJob do + let(:task) { create(:task, access_level:) } + let(:uuid) { task.uuid } + + before do + allow(Nbp::PushConnector).to receive(:instance) + allow(Nbp::PushConnector.instance).to receive(:push_lom!) + allow(Nbp::PushConnector.instance).to receive(:delete_task!) + end + + describe 'perform' do + subject(:perform_job) { described_class.perform_now(uuid) } + + context 'when the task is public' do + let(:access_level) { :public } + + it 'pushes the task' do + perform_job + expect(Nbp::PushConnector.instance).to have_received(:push_lom!) + end + end + + context 'when the task does not exist' do + let(:uuid) { :not_existing_uuid } + + it 'deletes the task' do + perform_job + expect(Nbp::PushConnector.instance).to have_received(:delete_task!) + end + end + + context 'when the task is private' do + let(:access_level) { :private } + + it 'deletes the task' do + perform_job + expect(Nbp::PushConnector.instance).to have_received(:delete_task!) + end + end + end +end diff --git a/spec/lib/nbp/push_connector_spec.rb b/spec/lib/nbp/push_connector_spec.rb new file mode 100644 index 000000000..a764e5857 --- /dev/null +++ b/spec/lib/nbp/push_connector_spec.rb @@ -0,0 +1,163 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Nbp::PushConnector do + let(:api_host) { Settings.nbp.push_connector.api_host } + let(:source_slug) { Settings.nbp.push_connector.source.slug } + let(:token_expiration) { 600 } + + let(:task) { create(:task) } + let(:task_xml) { (Nokogiri::XML::Builder.new(encoding: 'UTF-8') {|xml| LomService::ExportLom.call(task:, xml:) }).to_xml } + + let(:connector) { Class.new(described_class).instance } # https://stackoverflow.com/a/23901644 + + before do + stub_request(:post, Settings.nbp.push_connector.token_path).to_return_json(body: {access_token: 'sometoken', expires_in: token_expiration}) + stub_request(:post, "#{api_host}/datenraum/api/core/sources") + stub_request(:put, "#{api_host}/push-connector/api/lom-v2/#{source_slug}") + stub_request(:delete, %r{#{api_host}/push-connector/api/course/#{source_slug}/}) + stub_request(:get, "#{api_host}/datenraum/api/core/sources/slug/#{source_slug}").to_return(status: 404) + + stub_request(:get, %r{#{api_host}/datenraum/api/core/nodes}) + .to_return(body: file_fixture('nbp/empty_nodes.json')) + + stub_request(:get, %r{#{api_host}/datenraum/api/core/nodes}) + .with(query: hash_including('offset' => '0')) + .to_return(body: file_fixture('nbp/nodes.json')) + end + + describe 'initialize' do + context 'when no source exists' do + it 'creates a source' do + connector + expect(WebMock).to have_requested(:post, "#{api_host}/datenraum/api/core/sources") + end + + context 'when the push connector is disabled' do + before do + # Disable push connector temporarily + Settings.nbp.push_connector.enable = false + described_class.instance_variable_set :@enabled, nil + end + + after do + # Allow push connector to be re-enabled + Settings.nbp.push_connector.enable = true + described_class.instance_variable_set :@enabled, nil + end + + it 'raises an error' do + expect { connector }.to raise_error(Nbp::PushConnector::SettingsError) + end + end + end + + context 'when a source exists' do + before { stub_request(:get, "#{api_host}/datenraum/api/core/sources/slug/#{source_slug}").to_return(status: 200) } + + it 'does not create a source' do + connector + expect(WebMock).not_to have_requested(:post, "#{api_host}/datenraum/api/core/sources") + end + end + + context 'when the source could not be determined' do + before { stub_request(:get, "#{api_host}/datenraum/api/core/sources/slug/#{source_slug}").to_return(status: 500) } + + it 'does not create a source' do + begin + connector + rescue Nbp::PushConnector::Error + # no op for the spec + end + + expect(WebMock).not_to have_requested(:post, "#{api_host}/datenraum/api/core/sources") + end + + it 'raises an error' do + expect { connector }.to raise_error(Nbp::PushConnector::Error) + end + end + end + + describe 'push_lom!' do + subject(:push_lom!) { connector.push_lom!(task_xml) } + + context 'without any errors' do + it 'pushes the metadata' do + push_lom! + expect(WebMock).to have_requested(:put, "#{api_host}/push-connector/api/lom-v2/#{source_slug}") + end + end + + context 'when the token is still valid' do + before do + connector + WebMock.reset_executed_requests! + end + + it 'does not renew the token' do + push_lom! + expect(WebMock).not_to have_requested(:post, Settings.nbp.push_connector.token_path) + end + end + + context 'when the token expired' do + let(:token_expiration) { 0 } + + before do + connector + WebMock.reset_executed_requests! + end + + it 'renews the token' do + push_lom! + expect(WebMock).to have_requested(:post, Settings.nbp.push_connector.token_path) + end + end + + context 'when the token cannot be renewed' do + let(:token_expiration) { 0 } + + before do + connector + stub_request(:post, Settings.nbp.push_connector.token_path).to_return_json(body: {}, status: 500) + WebMock.reset_executed_requests! + end + + it 'raises an error' do + expect { push_lom! }.to raise_error(Nbp::PushConnector::Error) + end + + it 'does not push the metadata' do + begin + push_lom! + rescue Nbp::PushConnector::Error + # no op for the spec + end + + expect(WebMock).not_to have_requested(:put, "#{api_host}/push-connector/api/lom-v2/#{source_slug}") + end + end + end + + describe 'delete_task!' do + subject(:delete_task!) { connector.delete_task!(task.uuid) } + + context 'without any errors' do + it 'pushes the metadata' do + delete_task! + expect(WebMock).to have_requested(:delete, "#{api_host}/push-connector/api/course/#{source_slug}/#{task.uuid}") + end + end + end + + describe 'process_uploaded_task_uuids' do + it 'iterates the correct UUIDs' do + uuids = [] + connector.process_uploaded_task_uuids {|uuid| uuids << uuid } + expect(uuids).to eq(%w[external-id-1 external-id-2 external-id-3]) + end + end +end diff --git a/spec/models/task_spec.rb b/spec/models/task_spec.rb index 923bb2815..ea8f22102 100644 --- a/spec/models/task_spec.rb +++ b/spec/models/task_spec.rb @@ -3,6 +3,8 @@ require 'rails_helper' RSpec.describe Task do + include ActiveJob::TestHelper + describe '#valid?' do it { is_expected.to validate_presence_of(:title) } it { is_expected.to validate_uniqueness_of(:uuid).case_insensitive } @@ -107,7 +109,7 @@ end it 'has the correct parent_uuid' do - expect(duplicate.parent_uuid).to be task.uuid + expect(duplicate.parent_uuid).to eq task.uuid end it 'has the same attributes' do @@ -186,5 +188,86 @@ destroy expect(collection.reload.tasks).to be_empty end + + it 'enqueues an NbpSyncJob' do + expect { destroy }.to have_enqueued_job(NbpSyncJob).with(task.uuid) + end + end + + describe '#update' do + subject(:update) { task.update(new_attributes) } + + let!(:task) { create(:task, access_level:) } + + context 'when updating a public task' do + let(:access_level) { :public } + let(:new_attributes) { {title: 'some new title'} } + + it 'enqueues an NbpSyncJob' do + expect { update }.to have_enqueued_job(NbpSyncJob).with(task.uuid) + end + + context 'when updating the uuid' do + let(:new_attributes) { {uuid: Random.uuid} } + let!(:old_uuid) { task.uuid } + + it 'enqueues an NbpSyncJob for the old uuid' do + expect { update }.to have_enqueued_job(NbpSyncJob).with(old_uuid) + end + end + end + + context 'when updating a private task' do + let(:access_level) { :private } + let(:new_attributes) { {title: 'some new title'} } + + it 'does not enqueue an NbpSyncJob' do + expect { update }.not_to have_enqueued_job(NbpSyncJob) + end + + context 'when updating the uuid' do + let(:new_attributes) { {uuid: Random.uuid} } + + it 'does not enqueue an NbpSyncJob' do + expect { update }.not_to have_enqueued_job(NbpSyncJob) + end + end + end + + context 'when changing the access level from private to public' do + let(:access_level) { :private } + let(:new_attributes) { {access_level: :public} } + + it 'enqueues an NbpSyncJob' do + expect { update }.to have_enqueued_job(NbpSyncJob).with(task.uuid) + end + + context 'when also updating the uuid' do + let(:new_attributes) { {access_level: :public, uuid: Random.uuid} } + let!(:old_uuid) { task.uuid } + + it 'does not enqueue an NbpSyncJob for the old uuid' do + expect { update }.not_to have_enqueued_job(NbpSyncJob).with(old_uuid) + end + end + end + + context 'when changing the access level from public to private' do + let(:access_level) { :public } + let(:new_attributes) { {access_level: :private} } + + it 'enqueues an NbpSyncJob' do + expect { update }.to have_enqueued_job(NbpSyncJob).with(task.uuid) + end + + context 'when also updating the uuid' do + let(:new_attributes) { {access_level: :private, uuid: Random.uuid} } + let!(:old_uuid) { task.uuid } + + it 'enqueues an NbpSyncJob for the old uuid' do + expect { update }.to have_enqueued_job(NbpSyncJob).with(old_uuid) + end + end + end end end diff --git a/yarn.lock b/yarn.lock index 3f8c7e846..7d4ebdbe3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,76 +25,45 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/compat-data@npm:7.24.7" - checksum: 10c0/dcd93a5632b04536498fbe2be5af1057f635fd7f7090483d8e797878559037e5130b26862ceb359acbae93ed27e076d395ddb4663db6b28a665756ffd02d324f - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/compat-data@npm:7.24.8" - checksum: 10c0/7f465e9d8e44c5b516eeb3001362a3cd9a6df51dd90d3ac9868e1e7fa631ac57fc781cec6700110d4f555ba37fe59c4a71927b445106fe0062e79e79ffe11091 +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/compat-data@npm:7.25.2" + checksum: 10c0/5bf1f14d6e5f0d37c19543e99209ff4a94bb97915e1ce01e5334a144aa08cd56b6e62ece8135dac77e126723d63d4d4b96fc603a12c43b88c28f4b5e070270c5 languageName: node linkType: hard -"@babel/core@npm:7.24.9": - version: 7.24.9 - resolution: "@babel/core@npm:7.24.9" +"@babel/core@npm:7.25.2": + version: 7.25.2 + resolution: "@babel/core@npm:7.25.2" dependencies: "@ampproject/remapping": "npm:^2.2.0" "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.24.9" - "@babel/helper-compilation-targets": "npm:^7.24.8" - "@babel/helper-module-transforms": "npm:^7.24.9" - "@babel/helpers": "npm:^7.24.8" - "@babel/parser": "npm:^7.24.8" - "@babel/template": "npm:^7.24.7" - "@babel/traverse": "npm:^7.24.8" - "@babel/types": "npm:^7.24.9" + "@babel/generator": "npm:^7.25.0" + "@babel/helper-compilation-targets": "npm:^7.25.2" + "@babel/helper-module-transforms": "npm:^7.25.2" + "@babel/helpers": "npm:^7.25.0" + "@babel/parser": "npm:^7.25.0" + "@babel/template": "npm:^7.25.0" + "@babel/traverse": "npm:^7.25.2" + "@babel/types": "npm:^7.25.2" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10c0/e104ec6efbf099f55184933e9ab078eb5821c792ddfef3e9c6561986ec4ff103f5c11e3d7d6e5e8929e50e2c58db1cc80e5b6f14b530335b6622095ec4b4124c + checksum: 10c0/a425fa40e73cb72b6464063a57c478bc2de9dbcc19c280f1b55a3d88b35d572e87e8594e7d7b4880331addb6faef641bbeb701b91b41b8806cd4deae5d74f401 languageName: node linkType: hard -"@babel/generator@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/generator@npm:7.24.7" +"@babel/generator@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/generator@npm:7.25.0" dependencies: - "@babel/types": "npm:^7.24.7" + "@babel/types": "npm:^7.25.0" "@jridgewell/gen-mapping": "npm:^0.3.5" "@jridgewell/trace-mapping": "npm:^0.3.25" jsesc: "npm:^2.5.1" - checksum: 10c0/06b1f3350baf527a3309e50ffd7065f7aee04dd06e1e7db794ddfde7fe9d81f28df64edd587173f8f9295496a7ddb74b9a185d4bf4de7bb619e6d4ec45c8fd35 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/generator@npm:7.24.8" - dependencies: - "@babel/types": "npm:^7.24.8" - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.25" - jsesc: "npm:^2.5.1" - checksum: 10c0/e8a278e75a895f13a7b17dd79abe1e894fe82a5ed3abb127c33c14c66773d69993762521c094c6c364723f8f7375683b0d4a96097781175a29407baedf67b769 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.24.9": - version: 7.24.9 - resolution: "@babel/generator@npm:7.24.9" - dependencies: - "@babel/types": "npm:^7.24.9" - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.25" - jsesc: "npm:^2.5.1" - checksum: 10c0/cd1f7edce7717462546c349e15289d1267a3ed627c6f6583fbf51e78eacacc6500ec2f0024f08f1cc7138989e575635b931acf4549f9e728017a22176a9ea6b6 + checksum: 10c0/d0e2dfcdc8bdbb5dded34b705ceebf2e0bc1b06795a1530e64fb6a3ccf313c189db7f60c1616effae48114e1a25adc75855bc4496f3779a396b3377bae718ce7 languageName: node linkType: hard @@ -117,61 +86,46 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-compilation-targets@npm:7.24.7" - dependencies: - "@babel/compat-data": "npm:^7.24.7" - "@babel/helper-validator-option": "npm:^7.24.7" - browserslist: "npm:^4.22.2" - lru-cache: "npm:^5.1.1" - semver: "npm:^6.3.1" - checksum: 10c0/1d580a9bcacefe65e6bf02ba1dafd7ab278269fef45b5e281d8354d95c53031e019890464e7f9351898c01502dd2e633184eb0bcda49ed2ecd538675ce310f51 - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-compilation-targets@npm:7.24.8" +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.24.7, @babel/helper-compilation-targets@npm:^7.24.8, @babel/helper-compilation-targets@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/helper-compilation-targets@npm:7.25.2" dependencies: - "@babel/compat-data": "npm:^7.24.8" + "@babel/compat-data": "npm:^7.25.2" "@babel/helper-validator-option": "npm:^7.24.8" browserslist: "npm:^4.23.1" lru-cache: "npm:^5.1.1" semver: "npm:^6.3.1" - checksum: 10c0/2885c44ef6aaf82b7e4352b30089bb09fbe08ed5ec24eb452c2bdc3c021e2a65ab412f74b3d67ec1398da0356c730b33a2ceca1d67d34c85080d31ca6efa9aec + checksum: 10c0/de10e986b5322c9f807350467dc845ec59df9e596a5926a3b5edbb4710d8e3b8009d4396690e70b88c3844fe8ec4042d61436dd4b92d1f5f75655cf43ab07e99 languageName: node linkType: hard "@babel/helper-create-class-features-plugin@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-create-class-features-plugin@npm:7.24.7" + version: 7.25.0 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.0" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-function-name": "npm:^7.24.7" - "@babel/helper-member-expression-to-functions": "npm:^7.24.7" + "@babel/helper-member-expression-to-functions": "npm:^7.24.8" "@babel/helper-optimise-call-expression": "npm:^7.24.7" - "@babel/helper-replace-supers": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.25.0" "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" - "@babel/helper-split-export-declaration": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.0" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/6b7b47d70b41c00f39f86790cff67acf2bce0289d52a7c182b28e797f4e0e6d69027e3d06eccf1d54dddc2e5dde1df663bb1932437e5f447aeb8635d8d64a6ab + checksum: 10c0/2f8ac36cfeb45d462432acea64c78312cc9180dda7aa9337b77017961e373c323065362d2452f3d6f8bffeb254ff3f7346ac1b25c8ad7b81db813a95924f4053 languageName: node linkType: hard -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.24.7" +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.7, @babel/helper-create-regexp-features-plugin@npm:^7.25.0": + version: 7.25.2 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.2" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.24.7" regexpu-core: "npm:^5.3.1" semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/ed611a7eb0c71843f9cdc471eeb38767972229f9225f7aaa90d124d7ee0062cf6908fd53ee9c34f731394c429594f06049a7738a71d342e0191d4047b2fc0ac2 + checksum: 10c0/85a7e3639c118856fb1113f54fb7e3bf7698171ddfd0cd6fccccd5426b3727bc1434fe7f69090441dcde327feef9de917e00d35e47ab820047057518dd675317 languageName: node linkType: hard @@ -190,41 +144,13 @@ __metadata: languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-environment-visitor@npm:7.24.7" - dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10c0/36ece78882b5960e2d26abf13cf15ff5689bf7c325b10a2895a74a499e712de0d305f8d78bb382dd3c05cfba7e47ec98fe28aab5674243e0625cd38438dd0b2d - languageName: node - linkType: hard - -"@babel/helper-function-name@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-function-name@npm:7.24.7" - dependencies: - "@babel/template": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/e5e41e6cf86bd0f8bf272cbb6e7c5ee0f3e9660414174435a46653efba4f2479ce03ce04abff2aa2ef9359cf057c79c06cb7b134a565ad9c0e8a50dcdc3b43c4 - languageName: node - linkType: hard - -"@babel/helper-hoist-variables@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-hoist-variables@npm:7.24.7" - dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10c0/19ee37563bbd1219f9d98991ad0e9abef77803ee5945fd85aa7aa62a67c69efca9a801696a1b58dda27f211e878b3327789e6fd2a6f6c725ccefe36774b5ce95 - languageName: node - linkType: hard - -"@babel/helper-member-expression-to-functions@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-member-expression-to-functions@npm:7.24.7" +"@babel/helper-member-expression-to-functions@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.8" dependencies: - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/9638c1d33cf6aba028461ccd3db6061c76ff863ca0d5013dd9a088bf841f2f77c46956493f9da18355c16759449d23b74cc1de4da357ade5c5c34c858f840f0a + "@babel/traverse": "npm:^7.24.8" + "@babel/types": "npm:^7.24.8" + checksum: 10c0/7e14a5acc91f6cd26305a4441b82eb6f616bd70b096a4d2099a968f16b26d50207eec0b9ebfc466fefd62bd91587ac3be878117cdfec819b7151911183cb0e5a languageName: node linkType: hard @@ -238,48 +164,17 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-module-transforms@npm:7.24.7" - dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-module-imports": "npm:^7.24.7" - "@babel/helper-simple-access": "npm:^7.24.7" - "@babel/helper-split-export-declaration": "npm:^7.24.7" - "@babel/helper-validator-identifier": "npm:^7.24.7" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/4f311755fcc3b4cbdb689386309cdb349cf0575a938f0b9ab5d678e1a81bbb265aa34ad93174838245f2ac7ff6d5ddbd0104638a75e4e961958ed514355687b6 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helper-module-transforms@npm:7.24.8" +"@babel/helper-module-transforms@npm:^7.24.7, @babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.25.0, @babel/helper-module-transforms@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/helper-module-transforms@npm:7.25.2" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.7" "@babel/helper-module-imports": "npm:^7.24.7" "@babel/helper-simple-access": "npm:^7.24.7" - "@babel/helper-split-export-declaration": "npm:^7.24.7" "@babel/helper-validator-identifier": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.2" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/b76496d5045af55be9de60e59e65e56a43033f01ccc746b26b7af911c358668c206b688ce70a23ab31ec04f9728f3a38e8d01073c85244115ab62f271a7fa3d1 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.24.9": - version: 7.24.9 - resolution: "@babel/helper-module-transforms@npm:7.24.9" - dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-module-imports": "npm:^7.24.7" - "@babel/helper-simple-access": "npm:^7.24.7" - "@babel/helper-split-export-declaration": "npm:^7.24.7" - "@babel/helper-validator-identifier": "npm:^7.24.7" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/e27bca43bc113731ee4f2b33a4c5bf9c7eebf4d64487b814c305cbd5feb272c29fcd3d79634ba03131ade171e5972bc7ede8dbc83ba0deb02f1e62d318c87770 + checksum: 10c0/adaa15970ace0aee5934b5a633789b5795b6229c6a9cf3e09a7e80aa33e478675eee807006a862aa9aa517935d81f88a6db8a9f5936e3a2a40ec75f8062bc329 languageName: node linkType: hard @@ -292,43 +187,36 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": - version: 7.24.7 - resolution: "@babel/helper-plugin-utils@npm:7.24.7" - checksum: 10c0/c3d38cd9b3520757bb4a279255cc3f956fc0ac1c193964bd0816ebd5c86e30710be8e35252227e0c9d9e0f4f56d9b5f916537f2bc588084b0988b4787a967d31 - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.24.8": +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.24.8 resolution: "@babel/helper-plugin-utils@npm:7.24.8" checksum: 10c0/0376037f94a3bfe6b820a39f81220ac04f243eaee7193774b983e956c1750883ff236b30785795abbcda43fac3ece74750566830c2daa4d6e3870bb0dff34c2d languageName: node linkType: hard -"@babel/helper-remap-async-to-generator@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-remap-async-to-generator@npm:7.24.7" +"@babel/helper-remap-async-to-generator@npm:^7.24.7, @babel/helper-remap-async-to-generator@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-remap-async-to-generator@npm:7.25.0" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.24.7" - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-wrap-function": "npm:^7.24.7" + "@babel/helper-wrap-function": "npm:^7.25.0" + "@babel/traverse": "npm:^7.25.0" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/4e7fa2cdcbc488e41c27066c16e562857ef3c5c2bfe70d2f1e32e9ee7546b17c3fc1c20d05bf2a7f1c291bd9e7a0a219f6a9fa387209013294be79a26fcfe64d + checksum: 10c0/0d17b5f7bb6a607edc9cc62fff8056dd9f341bf2f919884f97b99170d143022a5e7ae57922c4891e4fc360ad291e708d2f8cd8989f1d3cd7a17600159984f5a6 languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-replace-supers@npm:7.24.7" +"@babel/helper-replace-supers@npm:^7.24.7, @babel/helper-replace-supers@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-replace-supers@npm:7.25.0" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-member-expression-to-functions": "npm:^7.24.7" + "@babel/helper-member-expression-to-functions": "npm:^7.24.8" "@babel/helper-optimise-call-expression": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.0" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/0e133bb03371dee78e519c334a09c08e1493103a239d9628db0132dfaac3fc16380479ca3c590d278a9b71b624030a338c18ebbfe6d430ebb2e4653775c4b3e3 + checksum: 10c0/b4b6650ab3d56c39a259367cd97f8df2f21c9cebb3716fea7bca40a150f8847bfb82f481e98927c7c6579b48a977b5a8f77318a1c6aeb497f41ecd6dbc3fdfef languageName: node linkType: hard @@ -352,22 +240,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-split-export-declaration@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-split-export-declaration@npm:7.24.7" - dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10c0/0254577d7086bf09b01bbde98f731d4fcf4b7c3fa9634fdb87929801307c1f6202a1352e3faa5492450fa8da4420542d44de604daf540704ff349594a78184f6 - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-string-parser@npm:7.24.7" - checksum: 10c0/47840c7004e735f3dc93939c77b099bb41a64bf3dda0cae62f60e6f74a5ff80b63e9b7cf77b5ec25a324516381fc994e1f62f922533236a8e3a6af57decb5e1e - languageName: node - linkType: hard - "@babel/helper-string-parser@npm:^7.24.8": version: 7.24.8 resolution: "@babel/helper-string-parser@npm:7.24.8" @@ -382,13 +254,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-validator-option@npm:7.24.7" - checksum: 10c0/21aea2b7bc5cc8ddfb828741d5c8116a84cbc35b4a3184ec53124f08e09746f1f67a6f9217850188995ca86059a7942e36d8965a6730784901def777b7e8a436 - languageName: node - linkType: hard - "@babel/helper-validator-option@npm:^7.24.8": version: 7.24.8 resolution: "@babel/helper-validator-option@npm:7.24.8" @@ -396,25 +261,24 @@ __metadata: languageName: node linkType: hard -"@babel/helper-wrap-function@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/helper-wrap-function@npm:7.24.7" +"@babel/helper-wrap-function@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-wrap-function@npm:7.25.0" dependencies: - "@babel/helper-function-name": "npm:^7.24.7" - "@babel/template": "npm:^7.24.7" - "@babel/traverse": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/d5689f031bf0eb38c0d7fad6b7e320ddef4bfbdf08d12d7d76ef41b7ca365a32721e74cb5ed5a9a9ec634bc20f9b7a27314fa6fb08f1576b8f6d8330fcea6f47 + "@babel/template": "npm:^7.25.0" + "@babel/traverse": "npm:^7.25.0" + "@babel/types": "npm:^7.25.0" + checksum: 10c0/d54601a98384c191cbc1ff07b03a19e288ef8d5c6bfafe270b2a303d96e7304eb296002921ed464cc1b105a547d1db146eb86b0be617924dee1ba1b379cdc216 languageName: node linkType: hard -"@babel/helpers@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/helpers@npm:7.24.8" +"@babel/helpers@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helpers@npm:7.25.0" dependencies: - "@babel/template": "npm:^7.24.7" - "@babel/types": "npm:^7.24.8" - checksum: 10c0/42b8939b0a0bf72d6df9721973eb0fd7cd48f42641c5c9c740916397faa586255c06d36c6e6a7e091860723096281c620f6ffaee0011a3bb254a6f5475d89a12 + "@babel/template": "npm:^7.25.0" + "@babel/types": "npm:^7.25.0" + checksum: 10c0/b7fe007fc4194268abf70aa3810365085e290e6528dcb9fbbf7a765d43c74b6369ce0f99c5ccd2d44c413853099daa449c9a0123f0b212ac8d18643f2e8174b8 languageName: node linkType: hard @@ -430,44 +294,46 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/parser@npm:7.24.7" +"@babel/parser@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/parser@npm:7.25.0" bin: parser: ./bin/babel-parser.js - checksum: 10c0/8b244756872185a1c6f14b979b3535e682ff08cb5a2a5fd97cc36c017c7ef431ba76439e95e419d43000c5b07720495b00cf29a7f0d9a483643d08802b58819b + checksum: 10c0/4aecf13829fa6f4a66835429bd235458544d9cd14374b17c19bc7726f472727ca33f500e51e1298ddc72db93bdd77fcaa9ddc095200b0b792173069e6cf9742e languageName: node linkType: hard -"@babel/parser@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/parser@npm:7.24.8" - bin: - parser: ./bin/babel-parser.js - checksum: 10c0/ce69671de8fa6f649abf849be262707ac700b573b8b1ce1893c66cc6cd76aeb1294a19e8c290b0eadeb2f47d3f413a2e57a281804ffbe76bfb9fa50194cf3c52 +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.25.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/traverse": "npm:^7.25.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/08aecaa7c83fa78a44ea758863083261093374f38f783d3971d2c08de640d701bb464c9c7eaee7a84ce6551b573d703b1b07e59786752cc1f679827ae53d1e4a languageName: node linkType: hard -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.7" +"@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-safari-class-field-initializer-scope@npm:7.25.0" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/394c30e2b708ad385fa1219528e039066a1f1cb40f47986f283878848fd354c745e6397f588b4e5a046ee8d64bfdf4c208e4c3dfbdcfb2fd34315ec67c64e7af + checksum: 10c0/9645a1f47b3750acadb1353c02e71cc712d072aafe5ce115ed3a886bc14c5d9200cfb0b5b5e60e813baa549b800cf798f8714019fd246c699053cf68c428e426 languageName: node linkType: hard -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.24.7" +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.0" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/a36307428ecc1a01b00cf90812335eed1575d13f211ab24fe4d0c55c28a2fcbd4135f142efabc3b277b2a8e09ee05df594a1272353f061b63829495b5dcfdb96 + checksum: 10c0/ed1ce1c90cac46c01825339fd0f2a96fa071b016fb819d8dfaf8e96300eae30e74870cb47e4dc80d4ce2fb287869f102878b4f3b35bc927fec8b1d0d76bcf612 languageName: node linkType: hard @@ -484,15 +350,15 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.24.7" +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.0" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/traverse": "npm:^7.25.0" peerDependencies: "@babel/core": ^7.0.0 - checksum: 10c0/2b52a73e444f6adc73f927b623e53a4cf64397170dd1071268536df1b3db1e02131418c8dc91351af48837a6298212118f4a72d5407f8005cf9a732370a315b0 + checksum: 10c0/45988025537a9d4a27b610fd696a18fd9ba9336621a69b4fb40560eeb10c79657f85c92a37f30c7c8fb29c22970eea0b373315795a891f1a05549a6cfe5a6bfe languageName: node linkType: hard @@ -715,17 +581,17 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-async-generator-functions@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-async-generator-functions@npm:7.24.7" +"@babel/plugin-transform-async-generator-functions@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.0" dependencies: - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" - "@babel/helper-remap-async-to-generator": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-remap-async-to-generator": "npm:^7.25.0" "@babel/plugin-syntax-async-generators": "npm:^7.8.4" + "@babel/traverse": "npm:^7.25.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6b5e33ae66dce0afce9b06d8dace6fa052528e60f7622aa6cfd3e71bd372ca5079d426e78336ca564bc0d5f37acbcda1b21f4fe656fcb642f1a93a697ab39742 + checksum: 10c0/5348c3a33d16e0d62f13482c6fa432185ba096d58880b08d42450f7db662d6b03e6149d495c8620897dcd3da35061068cbd6c09da7d0ec95743e55a788809e4e languageName: node linkType: hard @@ -753,14 +619,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-block-scoping@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-block-scoping@npm:7.24.7" +"@babel/plugin-transform-block-scoping@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-transform-block-scoping@npm:7.25.0" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/dcbc5e385c0ca5fb5736b1c720c90755cffe9f91d8c854f82e61e59217dd3f6c91b3633eeee4b55a89d3f59e5275d0f5b0b1b1363d4fa70c49c468b55aa87700 + checksum: 10c0/382931c75a5d0ea560387e76cb57b03461300527e4784efcb2fb62f36c1eb0ab331327b6034def256baa0cad9050925a61f9c0d56261b6afd6a29c3065fb0bd4 languageName: node linkType: hard @@ -789,21 +655,19 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-classes@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/plugin-transform-classes@npm:7.24.8" +"@babel/plugin-transform-classes@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-transform-classes@npm:7.25.0" dependencies: "@babel/helper-annotate-as-pure": "npm:^7.24.7" "@babel/helper-compilation-targets": "npm:^7.24.8" - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-function-name": "npm:^7.24.7" "@babel/helper-plugin-utils": "npm:^7.24.8" - "@babel/helper-replace-supers": "npm:^7.24.7" - "@babel/helper-split-export-declaration": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.25.0" + "@babel/traverse": "npm:^7.25.0" globals: "npm:^11.1.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/4423da0f747bdb6aab1995d98a74533fa679f637ec20706810dd57fb4ba2b1885ec8cae6a0b2c3f69f27165de6ff6aa2da9c4061c893848736a8267d0c653079 + checksum: 10c0/4451dccf8a7979427ae042afe381233f30764a8072faf0de1337a4fc297c6d7cb40df9e28931ac096e5b56392d0cd97d3ce10aee68288150a8701624d362a791 languageName: node linkType: hard @@ -853,6 +717,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-transform-duplicate-named-capturing-groups-regex@npm:7.25.0" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.25.0" + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/1c9b57ddd9b33696e88911d0e7975e1573ebc46219c4b30eb1dc746cbb71aedfac6f6dab7fdfdec54dd58f31468bf6ab56b157661ea4ffe58f906d71f89544c8 + languageName: node + linkType: hard + "@babel/plugin-transform-dynamic-import@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.7" @@ -901,16 +777,16 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-function-name@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-function-name@npm:7.24.7" +"@babel/plugin-transform-function-name@npm:^7.25.1": + version: 7.25.1 + resolution: "@babel/plugin-transform-function-name@npm:7.25.1" dependencies: - "@babel/helper-compilation-targets": "npm:^7.24.7" - "@babel/helper-function-name": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-compilation-targets": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/traverse": "npm:^7.25.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/3e9642428d6952851850d89ea9307d55946528d18973784d0e2f04a651b23bd9924dd8a2641c824b483bd4ab1223bab1d2f6a1106a939998f7ced512cb60ac5b + checksum: 10c0/e74912174d5e33d1418b840443c2e226a7b76cc017c1ed20ee30a566e4f1794d4a123be03180da046241576e8b692731807ba1f52608922acf1cb2cb6957593f languageName: node linkType: hard @@ -926,14 +802,14 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-literals@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-literals@npm:7.24.7" +"@babel/plugin-transform-literals@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/plugin-transform-literals@npm:7.25.2" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/9f3f6f3831929cd2a977748c07addf9944d5cccb50bd3a24a58beb54f91f00d6cacd3d7831d13ffe1ad6f8aba0aefd7bca5aec65d63b77f39c62ad1f2d484a3e + checksum: 10c0/0796883217b0885d37e7f6d350773be349e469a812b6bf11ccf862a6edf65103d3e7c849529d65381b441685c12e756751d8c2489a0fd3f8139bb5ef93185f58 languageName: node linkType: hard @@ -985,17 +861,17 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-modules-systemjs@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.24.7" +"@babel/plugin-transform-modules-systemjs@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.0" dependencies: - "@babel/helper-hoist-variables": "npm:^7.24.7" - "@babel/helper-module-transforms": "npm:^7.24.7" - "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.25.0" + "@babel/helper-plugin-utils": "npm:^7.24.8" "@babel/helper-validator-identifier": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/e2a795e0a6baafe26f4a74010622212ddd873170742d673f450e0097f8d984f6e6a95eb8ce41b05071ee9790c4be088b33801aaab3f78ee202c567634e52a331 + checksum: 10c0/fca6198da71237e4bb1274b3b67a0c81d56013c9535361242b6bfa87d70a9597854aadb45d4d8203369be4a655e158be2a5d20af0040b1f8d1bfc47db3ad7b68 languageName: node linkType: hard @@ -1096,20 +972,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-optional-chaining@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.7" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.7" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" - "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/b9e3649b299e103b0d1767bbdba56574d065ff776e5350403b7bfd4e3982743c0cdb373d33bdbf94fa3c322d155e45d0aad946acf0aa741b870aed22dfec8b8e - languageName: node - linkType: hard - -"@babel/plugin-transform-optional-chaining@npm:^7.24.8": +"@babel/plugin-transform-optional-chaining@npm:^7.24.7, @babel/plugin-transform-optional-chaining@npm:^7.24.8": version: 7.24.8 resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.8" dependencies: @@ -1312,18 +1175,19 @@ __metadata: languageName: node linkType: hard -"@babel/preset-env@npm:7.24.8": - version: 7.24.8 - resolution: "@babel/preset-env@npm:7.24.8" +"@babel/preset-env@npm:7.25.2": + version: 7.25.2 + resolution: "@babel/preset-env@npm:7.25.2" dependencies: - "@babel/compat-data": "npm:^7.24.8" - "@babel/helper-compilation-targets": "npm:^7.24.8" + "@babel/compat-data": "npm:^7.25.2" + "@babel/helper-compilation-targets": "npm:^7.25.2" "@babel/helper-plugin-utils": "npm:^7.24.8" "@babel/helper-validator-option": "npm:^7.24.8" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.24.7" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.7" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "npm:^7.25.0" + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "npm:^7.25.0" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.25.0" "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.7" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.7" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.25.0" "@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators": "npm:^7.8.4" "@babel/plugin-syntax-class-properties": "npm:^7.12.13" @@ -1344,29 +1208,30 @@ __metadata: "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" "@babel/plugin-transform-arrow-functions": "npm:^7.24.7" - "@babel/plugin-transform-async-generator-functions": "npm:^7.24.7" + "@babel/plugin-transform-async-generator-functions": "npm:^7.25.0" "@babel/plugin-transform-async-to-generator": "npm:^7.24.7" "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.7" - "@babel/plugin-transform-block-scoping": "npm:^7.24.7" + "@babel/plugin-transform-block-scoping": "npm:^7.25.0" "@babel/plugin-transform-class-properties": "npm:^7.24.7" "@babel/plugin-transform-class-static-block": "npm:^7.24.7" - "@babel/plugin-transform-classes": "npm:^7.24.8" + "@babel/plugin-transform-classes": "npm:^7.25.0" "@babel/plugin-transform-computed-properties": "npm:^7.24.7" "@babel/plugin-transform-destructuring": "npm:^7.24.8" "@babel/plugin-transform-dotall-regex": "npm:^7.24.7" "@babel/plugin-transform-duplicate-keys": "npm:^7.24.7" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "npm:^7.25.0" "@babel/plugin-transform-dynamic-import": "npm:^7.24.7" "@babel/plugin-transform-exponentiation-operator": "npm:^7.24.7" "@babel/plugin-transform-export-namespace-from": "npm:^7.24.7" "@babel/plugin-transform-for-of": "npm:^7.24.7" - "@babel/plugin-transform-function-name": "npm:^7.24.7" + "@babel/plugin-transform-function-name": "npm:^7.25.1" "@babel/plugin-transform-json-strings": "npm:^7.24.7" - "@babel/plugin-transform-literals": "npm:^7.24.7" + "@babel/plugin-transform-literals": "npm:^7.25.2" "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.7" "@babel/plugin-transform-member-expression-literals": "npm:^7.24.7" "@babel/plugin-transform-modules-amd": "npm:^7.24.7" "@babel/plugin-transform-modules-commonjs": "npm:^7.24.8" - "@babel/plugin-transform-modules-systemjs": "npm:^7.24.7" + "@babel/plugin-transform-modules-systemjs": "npm:^7.25.0" "@babel/plugin-transform-modules-umd": "npm:^7.24.7" "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.24.7" "@babel/plugin-transform-new-target": "npm:^7.24.7" @@ -1399,7 +1264,7 @@ __metadata: semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/a6f29498ec58989845a61f9c10b1b4e80586f1810a33db461d597cdb0ad2cd847381a993038b09f727512a08b2c1a33a330a5d4e6d65463ee98a1b4302d52ec6 + checksum: 10c0/0b613b31cc78695391501dceded4127240ff4795b19b206560f9adb5cf87bc04eafea3a5727d314ac05b410d35e1973075636ae2ab9e56d798ea586c9fb22a96 languageName: node linkType: hard @@ -1423,101 +1288,49 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:7.24.8": - version: 7.24.8 - resolution: "@babel/runtime@npm:7.24.8" - dependencies: - regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/f24b30af6b3ecae19165b3b032f9bc37b2d1769677bd63b69a6f81061967cfc847aa822518402ea6616b1d301d7eb46986b99c9f69cdb5880834fca2e6b34881 - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.8.4": - version: 7.24.7 - resolution: "@babel/runtime@npm:7.24.7" +"@babel/runtime@npm:7.25.0, @babel/runtime@npm:^7.16.7, @babel/runtime@npm:^7.8.4": + version: 7.25.0 + resolution: "@babel/runtime@npm:7.25.0" dependencies: regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/b6fa3ec61a53402f3c1d75f4d808f48b35e0dfae0ec8e2bb5c6fc79fb95935da75766e0ca534d0f1c84871f6ae0d2ebdd950727cfadb745a2cdbef13faef5513 + checksum: 10c0/bd3faf246170826cef2071a94d7b47b49d532351360ecd17722d03f6713fd93a3eb3dbd9518faa778d5e8ccad7392a7a604e56bd37aaad3f3aa68d619ccd983d languageName: node linkType: hard -"@babel/template@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/template@npm:7.24.7" +"@babel/template@npm:^7.24.7, @babel/template@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/template@npm:7.25.0" dependencies: "@babel/code-frame": "npm:^7.24.7" - "@babel/parser": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10c0/95b0b3ee80fcef685b7f4426f5713a855ea2cd5ac4da829b213f8fb5afe48a2a14683c2ea04d446dbc7f711c33c5cd4a965ef34dcbe5bc387c9e966b67877ae3 + "@babel/parser": "npm:^7.25.0" + "@babel/types": "npm:^7.25.0" + checksum: 10c0/4e31afd873215744c016e02b04f43b9fa23205d6d0766fb2e93eb4091c60c1b88897936adb895fb04e3c23de98dfdcbe31bc98daaa1a4e0133f78bb948e1209b languageName: node linkType: hard -"@babel/traverse@npm:^7.24.7": - version: 7.24.7 - resolution: "@babel/traverse@npm:7.24.7" +"@babel/traverse@npm:^7.24.7, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.1, @babel/traverse@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/traverse@npm:7.25.2" dependencies: "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.24.7" - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-function-name": "npm:^7.24.7" - "@babel/helper-hoist-variables": "npm:^7.24.7" - "@babel/helper-split-export-declaration": "npm:^7.24.7" - "@babel/parser": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" + "@babel/generator": "npm:^7.25.0" + "@babel/parser": "npm:^7.25.0" + "@babel/template": "npm:^7.25.0" + "@babel/types": "npm:^7.25.2" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10c0/a5135e589c3f1972b8877805f50a084a04865ccb1d68e5e1f3b94a8841b3485da4142e33413d8fd76bc0e6444531d3adf1f59f359c11ffac452b743d835068ab - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/traverse@npm:7.24.8" - dependencies: - "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.24.8" - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-function-name": "npm:^7.24.7" - "@babel/helper-hoist-variables": "npm:^7.24.7" - "@babel/helper-split-export-declaration": "npm:^7.24.7" - "@babel/parser": "npm:^7.24.8" - "@babel/types": "npm:^7.24.8" - debug: "npm:^4.3.1" - globals: "npm:^11.1.0" - checksum: 10c0/67a5cc35824455cdb54fb9e196a44b3186283e29018a9c2331f51763921e18e891b3c60c283615a27540ec8eb4c8b89f41c237b91f732a7aa518b2eb7a0d434d - languageName: node - linkType: hard - -"@babel/types@npm:^7.24.7, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.24.7 - resolution: "@babel/types@npm:7.24.7" - dependencies: - "@babel/helper-string-parser": "npm:^7.24.7" - "@babel/helper-validator-identifier": "npm:^7.24.7" - to-fast-properties: "npm:^2.0.0" - checksum: 10c0/d9ecbfc3eb2b05fb1e6eeea546836ac30d990f395ef3fe3f75ced777a222c3cfc4489492f72e0ce3d9a5a28860a1ce5f81e66b88cf5088909068b3ff4fab72c1 - languageName: node - linkType: hard - -"@babel/types@npm:^7.24.8": - version: 7.24.8 - resolution: "@babel/types@npm:7.24.8" - dependencies: - "@babel/helper-string-parser": "npm:^7.24.8" - "@babel/helper-validator-identifier": "npm:^7.24.7" - to-fast-properties: "npm:^2.0.0" - checksum: 10c0/2d7bf561ae993e794cb052c5a81d3a6d1877da13e1e2eb2a59ae75a8fb1c965b618fb3e4abd42548f5f9a4587d3a149185a32d6c4c4ea82195da7dd86f2da0f1 + checksum: 10c0/1edcb602801d6ea577584e957a3f6ad48753c4ccb9373fce4c92ebfdee04833f5bd5f1b74758ab7d61fe66d6d83ffdd7c8d482f46199767feeaed6af7df2191e languageName: node linkType: hard -"@babel/types@npm:^7.24.9": - version: 7.24.9 - resolution: "@babel/types@npm:7.24.9" +"@babel/types@npm:^7.24.7, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.25.2 + resolution: "@babel/types@npm:7.25.2" dependencies: "@babel/helper-string-parser": "npm:^7.24.8" "@babel/helper-validator-identifier": "npm:^7.24.7" to-fast-properties: "npm:^2.0.0" - checksum: 10c0/4970b3481cab39c5c3fdb7c28c834df5c7049f3c7f43baeafe121bb05270ebf0da7c65b097abf314877f213baa591109c82204f30d66cdd46c22ece4a2f32415 + checksum: 10c0/e489435856be239f8cc1120c90a197e4c2865385121908e5edb7223cfdff3768cba18f489adfe0c26955d9e7bbb1fb10625bc2517505908ceb0af848989bd864 languageName: node linkType: hard @@ -1528,14 +1341,7 @@ __metadata: languageName: node linkType: hard -"@fortawesome/fontawesome-free@npm:>=5.15.0 <7.0.0": - version: 6.5.2 - resolution: "@fortawesome/fontawesome-free@npm:6.5.2" - checksum: 10c0/932a8119376eab45da6c0702e955dcea55b916bbd7e118a365a8b3356a6322e725536f28f78e039bd47f4e1650b69bf9a85c2e40d0fdd69f9f0c138a5ef07e67 - languageName: node - linkType: hard - -"@fortawesome/fontawesome-free@npm:^6.6.0": +"@fortawesome/fontawesome-free@npm:>=5.15.0 <7.0.0, @fortawesome/fontawesome-free@npm:^6.6.0": version: 6.6.0 resolution: "@fortawesome/fontawesome-free@npm:6.6.0" checksum: 10c0/35c55bfecac9eb4943cf94f4380093dbe286fa29ce593488252644322b83e28eecbac757cef3eabdff7b3df67fc531c4f6dce6a3b00236f5de0174e186a9b5bb @@ -1671,12 +1477,12 @@ __metadata: languageName: node linkType: hard -"@jsonjoy.com/util@npm:^1.1.2": - version: 1.2.0 - resolution: "@jsonjoy.com/util@npm:1.2.0" +"@jsonjoy.com/util@npm:^1.1.2, @jsonjoy.com/util@npm:^1.3.0": + version: 1.3.0 + resolution: "@jsonjoy.com/util@npm:1.3.0" peerDependencies: tslib: 2 - checksum: 10c0/979b85076871ed1ce6961dfe7be725c8c413f50d09755e6e88184ba9b3682b59da20672b979eae74d3701fcfb094d5bba781dc7f53ffd45747f65026e699685e + checksum: 10c0/892bbe2073bb20bf392dd4dfed77881c6f7ae6a0cc5802e537fe3cbeeadde7738de5369f2d4529156efc5e98d9d43b15c85906ddb79140e322f1b26eaaf854df languageName: node linkType: hard @@ -1903,12 +1709,12 @@ __metadata: linkType: hard "@types/eslint@npm:*": - version: 8.56.10 - resolution: "@types/eslint@npm:8.56.10" + version: 9.6.0 + resolution: "@types/eslint@npm:9.6.0" dependencies: "@types/estree": "npm:*" "@types/json-schema": "npm:*" - checksum: 10c0/674349d6c342c3864d70f4d5a9965f96fb253801532752c8c500ad6a1c2e8b219e01ccff5dc8791dcb58b5483012c495708bb9f3ff929f5c9322b3da126c15d3 + checksum: 10c0/69301356bc73b85e381ae00931291de2e96d1cc49a112c592c74ee32b2f85412203dea6a333b4315fd9839bb14f364f265cbfe7743fc5a78492ee0326dd6a2c1 languageName: node linkType: hard @@ -2008,11 +1814,11 @@ __metadata: linkType: hard "@types/node@npm:*": - version: 20.14.10 - resolution: "@types/node@npm:20.14.10" + version: 22.0.0 + resolution: "@types/node@npm:22.0.0" dependencies: - undici-types: "npm:~5.26.4" - checksum: 10c0/0b06cff14365c2d0085dc16cc8cbea5c40ec09cfc1fea966be9eeecf35562760bfde8f88e86de6edfaf394501236e229d9c1084fad04fb4dec472ae245d8ae69 + undici-types: "npm:~6.11.1" + checksum: 10c0/af26a8ec7266c857b0ced75dc3a93c6b65280d1fa40d1b4488c814d30831c5c752489c99ecb5698daec1376145b1a9ddd08350882dc2e07769917a5f22a460bc languageName: node linkType: hard @@ -2077,11 +1883,11 @@ __metadata: linkType: hard "@types/ws@npm:^8.5.10": - version: 8.5.10 - resolution: "@types/ws@npm:8.5.10" + version: 8.5.12 + resolution: "@types/ws@npm:8.5.12" dependencies: "@types/node": "npm:*" - checksum: 10c0/e9af279b984c4a04ab53295a40aa95c3e9685f04888df5c6920860d1dd073fcc57c7bd33578a04b285b2c655a0b52258d34bee0a20569dca8defb8393e1e5d29 + checksum: 10c0/3fd77c9e4e05c24ce42bfc7647f7506b08c40a40fe2aea236ef6d4e96fc7cb4006a81ed1b28ec9c457e177a74a72924f4768b7b4652680b42dfd52bc380e15f9 languageName: node linkType: hard @@ -2407,14 +2213,14 @@ __metadata: linkType: hard "ajv@npm:^8.0.0, ajv@npm:^8.9.0": - version: 8.16.0 - resolution: "ajv@npm:8.16.0" + version: 8.17.1 + resolution: "ajv@npm:8.17.1" dependencies: fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" json-schema-traverse: "npm:^1.0.0" require-from-string: "npm:^2.0.2" - uri-js: "npm:^4.4.1" - checksum: 10c0/6fc38aa8fd4fbfaa7096ac049e48c0cb440db36b76fef2d7d5b7d92b102735670d055d412d19176c08c9d48eaa9d06661b67e59f04943dc71ab1551e0484f88c + checksum: 10c0/ec3ba10a573c6b60f94639ffc53526275917a2df6810e4ab5a6b959d87459f9ef3f00d5e7865b82677cb7d21590355b34da14d1d0b9c32d75f95a187e76fff35 languageName: node linkType: hard @@ -2638,17 +2444,17 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.22.2, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1": - version: 4.23.1 - resolution: "browserslist@npm:4.23.1" +"browserslist@npm:^4.0.0, browserslist@npm:^4.21.10, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1": + version: 4.23.2 + resolution: "browserslist@npm:4.23.2" dependencies: - caniuse-lite: "npm:^1.0.30001629" - electron-to-chromium: "npm:^1.4.796" + caniuse-lite: "npm:^1.0.30001640" + electron-to-chromium: "npm:^1.4.820" node-releases: "npm:^2.0.14" - update-browserslist-db: "npm:^1.0.16" + update-browserslist-db: "npm:^1.1.0" bin: browserslist: cli.js - checksum: 10c0/eb47c7ab9d60db25ce2faca70efeb278faa7282a2f62b7f2fa2f92e5f5251cf65144244566c86559419ff4f6d78f59ea50e39911321ad91f3b27788901f1f5e9 + checksum: 10c0/0217d23c69ed61cdd2530c7019bf7c822cd74c51f8baab18dd62457fed3129f52499f8d3a6f809ae1fb7bb3050aa70caa9a529cc36c7478427966dbf429723a5 languageName: node linkType: hard @@ -2683,8 +2489,8 @@ __metadata: linkType: hard "cacache@npm:^18.0.0": - version: 18.0.3 - resolution: "cacache@npm:18.0.3" + version: 18.0.4 + resolution: "cacache@npm:18.0.4" dependencies: "@npmcli/fs": "npm:^3.1.0" fs-minipass: "npm:^3.0.0" @@ -2698,7 +2504,7 @@ __metadata: ssri: "npm:^10.0.0" tar: "npm:^6.1.11" unique-filename: "npm:^3.0.0" - checksum: 10c0/dfda92840bb371fb66b88c087c61a74544363b37a265023223a99965b16a16bbb87661fe4948718d79df6e0cc04e85e62784fbcf1832b2a5e54ff4c46fbb45b7 + checksum: 10c0/6c055bafed9de4f3dcc64ac3dc7dd24e863210902b7c470eb9ce55a806309b3efff78033e3d8b4f7dcc5d467f2db43c6a2857aaaf26f0094b8a351d44c42179f languageName: node linkType: hard @@ -2727,10 +2533,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001629": - version: 1.0.30001640 - resolution: "caniuse-lite@npm:1.0.30001640" - checksum: 10c0/d87fce999e52c354029893a23887d2e48ac297e3af55bd14161fcafdd711f97bdb2649c79d2d3049e628603cb59bc4257ca2961644b0b8d206e7b7dd126d37ea +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001640": + version: 1.0.30001643 + resolution: "caniuse-lite@npm:1.0.30001643" + checksum: 10c0/7fcd0fd180bbe6764311ad57b0d39c23afdcc3bb1d8f804e7a76752c62a85b1bb7cf74b672d9da2f0afe7ad75336ff811a6fe279eb2a54bc04c272b6b62e57f1 languageName: node linkType: hard @@ -2817,10 +2623,10 @@ __metadata: version: 0.0.0-use.local resolution: "codeharbor@workspace:." dependencies: - "@babel/core": "npm:7.24.9" + "@babel/core": "npm:7.25.2" "@babel/plugin-transform-runtime": "npm:7.24.7" - "@babel/preset-env": "npm:7.24.8" - "@babel/runtime": "npm:7.24.8" + "@babel/preset-env": "npm:7.25.2" + "@babel/runtime": "npm:7.25.0" "@fortawesome/fontawesome-free": "npm:^6.6.0" "@popperjs/core": "npm:^2.11.8" "@sentry/browser": "npm:^8.20.0" @@ -3227,14 +3033,14 @@ __metadata: linkType: hard "debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.4": - version: 4.3.5 - resolution: "debug@npm:4.3.5" + version: 4.3.6 + resolution: "debug@npm:4.3.6" dependencies: ms: "npm:2.1.2" peerDependenciesMeta: supports-color: optional: true - checksum: 10c0/082c375a2bdc4f4469c99f325ff458adad62a3fc2c482d59923c260cb08152f34e2659f72b3767db8bb2f21ca81a60a42d1019605a412132d7b9f59363a005cc + checksum: 10c0/3293416bff072389c101697d4611c402a6bacd1900ac20c0492f61a9cdd6b3b29750fc7f5e299f8058469ef60ff8fb79b86395a30374fbd2490113c1c7112285 languageName: node linkType: hard @@ -3385,10 +3191,10 @@ __metadata: languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.796": - version: 1.4.820 - resolution: "electron-to-chromium@npm:1.4.820" - checksum: 10c0/7fc22fdfd53a80f811cf8ab1c392006a8b7915f1c127998c19dc377f9cc2c1b62a11df38ce973b6e0be6db4fb2c3bbaf6626e24dfbe7c58fa60849508d7069b4 +"electron-to-chromium@npm:^1.4.820": + version: 1.5.3 + resolution: "electron-to-chromium@npm:1.5.3" + checksum: 10c0/acd4dad650dafa16c4bd19868fe79c58ae3208f666d868ef8d4c81012707b2855b1816241d1c243b50c75a6933817a9e33401a5a17bc4222c52a5ee8abf457e8 languageName: node linkType: hard @@ -3430,12 +3236,12 @@ __metadata: linkType: hard "enhanced-resolve@npm:^5.17.0": - version: 5.17.0 - resolution: "enhanced-resolve@npm:5.17.0" + version: 5.17.1 + resolution: "enhanced-resolve@npm:5.17.1" dependencies: graceful-fs: "npm:^4.2.4" tapable: "npm:^2.2.0" - checksum: 10c0/90065e58e4fd08e77ba47f827eaa17d60c335e01e4859f6e644bb3b8d0e32b203d33894aee92adfa5121fa262f912b48bdf0d0475e98b4a0a1132eea1169ad37 + checksum: 10c0/81a0515675eca17efdba2cf5bad87abc91a528fc1191aad50e275e74f045b41506167d420099022da7181c8d787170ea41e4a11a0b10b7a16f6237daecb15370 languageName: node linkType: hard @@ -3651,6 +3457,13 @@ __metadata: languageName: node linkType: hard +"fast-uri@npm:^3.0.1": + version: 3.0.1 + resolution: "fast-uri@npm:3.0.1" + checksum: 10c0/3cd46d6006083b14ca61ffe9a05b8eef75ef87e9574b6f68f2e17ecf4daa7aaadeff44e3f0f7a0ef4e0f7e7c20fc07beec49ff14dc72d0b500f00386592f2d10 + languageName: node + linkType: hard + "fastest-levenshtein@npm:^1.0.12": version: 1.0.16 resolution: "fastest-levenshtein@npm:1.0.16" @@ -4129,21 +3942,21 @@ __metadata: linkType: hard "immutable@npm:^4.0.0": - version: 4.3.6 - resolution: "immutable@npm:4.3.6" - checksum: 10c0/7d0952a768b4fadcee47230ed86dc9505a4517095eceaf5a47e65288571c42400c6e4a2ae21eca4eda957cb7bc50720213135b62cf6a181639111f8acae128c3 + version: 4.3.7 + resolution: "immutable@npm:4.3.7" + checksum: 10c0/9b099197081b22f6433003e34929da8ecddbbdc1474cdc8aa3b7669dee4adda349c06143de22def36016d1b6de5322b043eccd7a11db1dad2ca85dad4fff5435 languageName: node linkType: hard "import-local@npm:^3.0.2": - version: 3.1.0 - resolution: "import-local@npm:3.1.0" + version: 3.2.0 + resolution: "import-local@npm:3.2.0" dependencies: pkg-dir: "npm:^4.2.0" resolve-cwd: "npm:^3.0.0" bin: import-local-fixture: fixtures/cli.js - checksum: 10c0/c67ecea72f775fe8684ca3d057e54bdb2ae28c14bf261d2607c269c18ea0da7b730924c06262eca9aed4b8ab31e31d65bc60b50e7296c85908a56e2f7d41ecd2 + checksum: 10c0/94cd6367a672b7e0cb026970c85b76902d2710a64896fa6de93bd5c571dd03b228c5759308959de205083e3b1c61e799f019c9e36ee8e9c523b993e1057f0433 languageName: node linkType: hard @@ -4216,11 +4029,11 @@ __metadata: linkType: hard "is-core-module@npm:^2.13.0": - version: 2.14.0 - resolution: "is-core-module@npm:2.14.0" + version: 2.15.0 + resolution: "is-core-module@npm:2.15.0" dependencies: hasown: "npm:^2.0.2" - checksum: 10c0/ae8dbc82bd20426558bc8d20ce290ce301c1cfd6ae4446266d10cacff4c63c67ab16440ade1d72ced9ec41c569fbacbcee01e293782ce568527c4cdf35936e4c + checksum: 10c0/da161f3d9906f459486da65609b2f1a2dfdc60887c689c234d04e88a062cb7920fa5be5fb7ab08dc43b732929653c4135ef05bf77888ae2a9040ce76815eb7b1 languageName: node linkType: hard @@ -4349,15 +4162,15 @@ __metadata: linkType: hard "jackspeak@npm:^3.1.2": - version: 3.4.2 - resolution: "jackspeak@npm:3.4.2" + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" dependencies: "@isaacs/cliui": "npm:^8.0.2" "@pkgjs/parseargs": "npm:^0.11.0" dependenciesMeta: "@pkgjs/parseargs": optional: true - checksum: 10c0/31952961f4d0d51831b8973db5c800233dc0f2181c3ca74af96f02cdc5c3f2b3df147a9ce2b56a643bd459036d782fb8c59f8992658d2bb4564753c42bb80c6c + checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 languageName: node linkType: hard @@ -4679,14 +4492,14 @@ __metadata: linkType: hard "memfs@npm:^4.6.0": - version: 4.9.3 - resolution: "memfs@npm:4.9.3" + version: 4.11.0 + resolution: "memfs@npm:4.11.0" dependencies: "@jsonjoy.com/json-pack": "npm:^1.0.3" - "@jsonjoy.com/util": "npm:^1.1.2" + "@jsonjoy.com/util": "npm:^1.3.0" tree-dump: "npm:^1.0.1" tslib: "npm:^2.0.0" - checksum: 10c0/a59537537716653b6cf5287c5a23b3bbb6466aa2e596aa4710279564521d1b23f2fde403e20a91003dac89cb804d17fabee005bd95dab10943d9e4f62f47db09 + checksum: 10c0/2424dfe2bcd40e6935b46a22e90256a0ca3c5c64546aa4e9fdac318be87010625a512d24ee32a4f910c3f0a077d1637d2dcf25e1670c4e49474160c5f988a1e9 languageName: node linkType: hard @@ -4721,13 +4534,20 @@ __metadata: languageName: node linkType: hard -"mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": +"mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa languageName: node linkType: hard +"mime-db@npm:>= 1.43.0 < 2": + version: 1.53.0 + resolution: "mime-db@npm:1.53.0" + checksum: 10c0/1dcc37ba8ed5d1c179f5c6f0837e8db19371d5f2ea3690c3c2f3fa8c3858f976851d3460b172b4dee78ebd606762cbb407aa398545fbacd539e519f858cd7bf4 + languageName: node + linkType: hard + "mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": version: 2.1.35 resolution: "mime-types@npm:2.1.35" @@ -4938,8 +4758,8 @@ __metadata: linkType: hard "node-gyp@npm:latest": - version: 10.1.0 - resolution: "node-gyp@npm:10.1.0" + version: 10.2.0 + resolution: "node-gyp@npm:10.2.0" dependencies: env-paths: "npm:^2.2.0" exponential-backoff: "npm:^3.1.1" @@ -4947,20 +4767,20 @@ __metadata: graceful-fs: "npm:^4.2.6" make-fetch-happen: "npm:^13.0.0" nopt: "npm:^7.0.0" - proc-log: "npm:^3.0.0" + proc-log: "npm:^4.1.0" semver: "npm:^7.3.5" - tar: "npm:^6.1.2" + tar: "npm:^6.2.1" which: "npm:^4.0.0" bin: node-gyp: bin/node-gyp.js - checksum: 10c0/9cc821111ca244a01fb7f054db7523ab0a0cd837f665267eb962eb87695d71fb1e681f9e21464cc2fd7c05530dc4c81b810bca1a88f7d7186909b74477491a3c + checksum: 10c0/00630d67dbd09a45aee0a5d55c05e3916ca9e6d427ee4f7bc392d2d3dc5fad7449b21fc098dd38260a53d9dcc9c879b36704a1994235d4707e7271af7e9a835b languageName: node linkType: hard "node-releases@npm:^2.0.14": - version: 2.0.14 - resolution: "node-releases@npm:2.0.14" - checksum: 10c0/199fc93773ae70ec9969bc6d5ac5b2bbd6eb986ed1907d751f411fef3ede0e4bfdb45ceb43711f8078bea237b6036db8b1bf208f6ff2b70c7d615afd157f3ab9 + version: 2.0.18 + resolution: "node-releases@npm:2.0.18" + checksum: 10c0/786ac9db9d7226339e1dc84bbb42007cb054a346bd9257e6aa154d294f01bc6a6cddb1348fa099f079be6580acbb470e3c048effd5f719325abd0179e566fd27 languageName: node linkType: hard @@ -5548,12 +5368,12 @@ __metadata: linkType: hard "postcss-selector-parser@npm:^6.0.16, postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.1.0": - version: 6.1.0 - resolution: "postcss-selector-parser@npm:6.1.0" + version: 6.1.1 + resolution: "postcss-selector-parser@npm:6.1.1" dependencies: cssesc: "npm:^3.0.0" util-deprecate: "npm:^1.0.2" - checksum: 10c0/91e9c6434772506bc7f318699dd9d19d32178b52dfa05bed24cb0babbdab54f8fb765d9920f01ac548be0a642aab56bce493811406ceb00ae182bbb53754c473 + checksum: 10c0/5608765e033fee35d448e1f607ffbaa750eb86901824a8bc4a911ea8bc137cb82f29239330787427c5d3695afd90d8721e190f211dbbf733e25033d8b3100763 languageName: node linkType: hard @@ -5588,24 +5408,17 @@ __metadata: linkType: hard "postcss@npm:^8.4.33, postcss@npm:^8.4.38": - version: 8.4.39 - resolution: "postcss@npm:8.4.39" + version: 8.4.40 + resolution: "postcss@npm:8.4.40" dependencies: nanoid: "npm:^3.3.7" picocolors: "npm:^1.0.1" source-map-js: "npm:^1.2.0" - checksum: 10c0/16f5ac3c4e32ee76d1582b3c0dcf1a1fdb91334a45ad755eeb881ccc50318fb8d64047de4f1601ac96e30061df203f0f2e2edbdc0bfc49b9c57bc9fb9bedaea3 - languageName: node - linkType: hard - -"proc-log@npm:^3.0.0": - version: 3.0.0 - resolution: "proc-log@npm:3.0.0" - checksum: 10c0/f66430e4ff947dbb996058f6fd22de2c66612ae1a89b097744e17fb18a4e8e7a86db99eda52ccf15e53f00b63f4ec0b0911581ff2aac0355b625c8eac509b0dc + checksum: 10c0/65ed67573e5443beaeb582282ff27a6be7c7fe3b4d9fa15761157616f2b97510cb1c335023c26220b005909f007337026d6e3ff092f25010b484ad484e80ea7f languageName: node linkType: hard -"proc-log@npm:^4.2.0": +"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": version: 4.2.0 resolution: "proc-log@npm:4.2.0" checksum: 10c0/17db4757c2a5c44c1e545170e6c70a26f7de58feb985091fb1763f5081cab3d01b181fb2dd240c9f4a4255a1d9227d163d5771b7e69c9e49a561692db865efb9 @@ -5630,25 +5443,25 @@ __metadata: linkType: hard "prosemirror-commands@npm:^1.1.9": - version: 1.5.2 - resolution: "prosemirror-commands@npm:1.5.2" + version: 1.6.0 + resolution: "prosemirror-commands@npm:1.6.0" dependencies: prosemirror-model: "npm:^1.0.0" prosemirror-state: "npm:^1.0.0" prosemirror-transform: "npm:^1.0.0" - checksum: 10c0/9ff0b525d4bc654ecd41a27f11d8aff52f719ea9a7da2587d9632cfc00bcac46ecc3be628623d1a768e3aa7c7ed2fe291326bb7d63b0a5c0814e53b0a6af5b35 + checksum: 10c0/ba7317917159645980b7cafb04d24c4b3c6cc877b30929c776f51242289930333dc2351f5b55d9a81153331cdfa5c6fe13742b7925d7ec290addadab5ff4affc languageName: node linkType: hard "prosemirror-history@npm:^1.1.3": - version: 1.4.0 - resolution: "prosemirror-history@npm:1.4.0" + version: 1.4.1 + resolution: "prosemirror-history@npm:1.4.1" dependencies: prosemirror-state: "npm:^1.2.2" prosemirror-transform: "npm:^1.0.0" prosemirror-view: "npm:^1.31.0" rope-sequence: "npm:^1.3.0" - checksum: 10c0/46299435ac963d5626e6faaca292369b1ae1d8746a5039b63df3aeed767c58d797e7bcfda3b4429b828798f6818e36476cc669f37cb2a40689cb8bf2635984ce + checksum: 10c0/fd2dfae5fb956a8710bb1a4131e9b6d8b92e846bf88fa643bc59ba595c8a835f6695574d5e33bcea9a6e7fbf2eafc7c1b1003abf11326e8571e196cd0f16dcd8 languageName: node linkType: hard @@ -5673,11 +5486,11 @@ __metadata: linkType: hard "prosemirror-model@npm:^1.0.0, prosemirror-model@npm:^1.14.1, prosemirror-model@npm:^1.20.0, prosemirror-model@npm:^1.21.0": - version: 1.21.3 - resolution: "prosemirror-model@npm:1.21.3" + version: 1.22.2 + resolution: "prosemirror-model@npm:1.22.2" dependencies: orderedmap: "npm:^2.0.0" - checksum: 10c0/237b27317f6e9150a491d90290d303c57377e4c2dbdbbece0cce74f9a5b7b8b2bd2b81746fc6c38f6c0ecc35289fb19cf687ecdaea89c42bf3d4a210a3bae20a + checksum: 10c0/60935c18b779d93c64bd6e4a74f257efab3d539500c635cebdcec27005091ec9d297b87d7668645098db7a269f0e50184abae07ebfabf7bc73e747342c488380 languageName: node linkType: hard @@ -5702,13 +5515,13 @@ __metadata: linkType: hard "prosemirror-view@npm:^1.18.7, prosemirror-view@npm:^1.27.0, prosemirror-view@npm:^1.31.0": - version: 1.33.8 - resolution: "prosemirror-view@npm:1.33.8" + version: 1.33.9 + resolution: "prosemirror-view@npm:1.33.9" dependencies: prosemirror-model: "npm:^1.20.0" prosemirror-state: "npm:^1.0.0" prosemirror-transform: "npm:^1.1.0" - checksum: 10c0/aed7098d4251341bfcf2be2e07c6a227b71582a4e5b216e8c86b2b2add42ebda6df68dcd0f1839f86f65d79fd5d078783e940ae1d08534e35a8b299d1d2fe97a + checksum: 10c0/69e17ee613fe9d69fcb2201664f9878aefda80aa662ead9184fa30b3e14691e7a14952d325decc2d3877417f13fe8dbfa1291d486b34701407962b061100a195 languageName: node linkType: hard @@ -6108,11 +5921,11 @@ __metadata: linkType: hard "semver@npm:^7.3.5, semver@npm:^7.5.4": - version: 7.6.2 - resolution: "semver@npm:7.6.2" + version: 7.6.3 + resolution: "semver@npm:7.6.3" bin: semver: bin/semver.js - checksum: 10c0/97d3441e97ace8be4b1976433d1c32658f6afaff09f143e52c593bae7eef33de19e3e369c88bd985ce1042c6f441c80c6803078d1de2a9988080b66684cbb30c + checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf languageName: node linkType: hard @@ -6553,7 +6366,7 @@ __metadata: languageName: node linkType: hard -"tar@npm:^6.1.11, tar@npm:^6.1.2": +"tar@npm:^6.1.11, tar@npm:^6.2.1": version: 6.2.1 resolution: "tar@npm:6.2.1" dependencies: @@ -6590,8 +6403,8 @@ __metadata: linkType: hard "terser@npm:^5.26.0": - version: 5.31.1 - resolution: "terser@npm:5.31.1" + version: 5.31.3 + resolution: "terser@npm:5.31.3" dependencies: "@jridgewell/source-map": "npm:^0.3.3" acorn: "npm:^8.8.2" @@ -6599,7 +6412,7 @@ __metadata: source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: 10c0/4d49a58f64c11f3742e779a0a03aff69972ca5739decb361d909d22c8f3f7d8e2ec982a928d987d56737ad50229e8ab3f62d8ba993e4b5f360a53ed487d3c06c + checksum: 10c0/eb2b525dada9febd3db74e94bd295f9cd7abd809e4f9c6bbc795a3048ad50fd327c15eab99db383fa820239680eef6d2dbd7dc05361769c204ddee5cf684d41e languageName: node linkType: hard @@ -6668,10 +6481,10 @@ __metadata: languageName: node linkType: hard -"undici-types@npm:~5.26.4": - version: 5.26.5 - resolution: "undici-types@npm:5.26.5" - checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501 +"undici-types@npm:~6.11.1": + version: 6.11.1 + resolution: "undici-types@npm:6.11.1" + checksum: 10c0/d8f5739a8e6c779d72336c82deb49c56d5ac9f9f6e0eb2e8dd4d3f6929ae9db7cde370d2e46516fe6cad04ea53e790c5e16c4c75eed7cd0f9bd31b0763bb2fa3 languageName: node linkType: hard @@ -6731,7 +6544,7 @@ __metadata: languageName: node linkType: hard -"update-browserslist-db@npm:^1.0.16": +"update-browserslist-db@npm:^1.1.0": version: 1.1.0 resolution: "update-browserslist-db@npm:1.1.0" dependencies: @@ -6745,7 +6558,7 @@ __metadata: languageName: node linkType: hard -"uri-js@npm:^4.2.2, uri-js@npm:^4.4.1": +"uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" dependencies: @@ -6860,8 +6673,8 @@ __metadata: linkType: hard "webpack-dev-middleware@npm:^7.1.0": - version: 7.2.1 - resolution: "webpack-dev-middleware@npm:7.2.1" + version: 7.3.0 + resolution: "webpack-dev-middleware@npm:7.3.0" dependencies: colorette: "npm:^2.0.10" memfs: "npm:^4.6.0" @@ -6874,7 +6687,7 @@ __metadata: peerDependenciesMeta: webpack: optional: true - checksum: 10c0/e3a61098d5fe3325f698f8f97395f8625b96717e690170f3e4704c939dc96cbb57a871730d3ba4d19f06975b558d4f283bdcc801d823463a12da0dbc3844b531 + checksum: 10c0/03d34e1c7af3af8c98efe754ce6cfb9fe84a1f02d312bc37a77f55b8ae9525bc3ac913fc92c0143ab93a3a6377781661f07336031fcd5e6bbddccc11df9345db languageName: node linkType: hard