@capybara-hq/kernel 0.1.0-rc.24 → 0.1.0-rc.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/admin.module.js +2 -0
- package/dist/admin/health.service.d.ts +2 -2
- package/dist/admin/health.service.js +6 -2
- package/dist/admin/outbox-dead.service.d.ts +7 -3
- package/dist/admin/outbox-dead.service.js +17 -6
- package/dist/admin/overview.service.d.ts +6 -6
- package/dist/admin/overview.service.js +7 -7
- package/dist/agents/agents.module.js +3 -0
- package/dist/agents/agents.service.d.ts +6 -1
- package/dist/agents/agents.service.js +11 -2
- package/dist/background/wake-rules.d.ts +5 -0
- package/dist/background/wake-rules.js +16 -5
- package/dist/catalog/catalog-import.module.js +0 -4
- package/dist/catalog/catalog-scope.service.d.ts +63 -26
- package/dist/catalog/catalog-scope.service.js +146 -71
- package/dist/catalog/catalog.module.js +4 -3
- package/dist/catalog/catalog.service.d.ts +11 -4
- package/dist/catalog/catalog.service.js +21 -5
- package/dist/catalog/cli.d.ts +4 -3
- package/dist/catalog/cli.js +8 -13
- package/dist/catalog/job-ids.d.ts +8 -20
- package/dist/catalog/job-ids.js +11 -16
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/org-plugin-uploads.d.ts +11 -4
- package/dist/catalog/org-plugin-uploads.js +21 -6
- package/dist/catalog/owned-items.d.ts +6 -13
- package/dist/catalog/owned-items.js +11 -29
- package/dist/catalog/owned-plugin-cleanup.d.ts +8 -17
- package/dist/catalog/owned-plugin-cleanup.js +12 -66
- package/dist/catalog/platform-components.d.ts +56 -34
- package/dist/catalog/platform-components.js +68 -78
- package/dist/catalog/plugin-import.d.ts +28 -25
- package/dist/catalog/plugin-import.js +90 -76
- package/dist/catalog/plugin-upgrade.d.ts +4 -4
- package/dist/catalog/plugin-upgrade.js +7 -19
- package/dist/catalog/scope-jobs.d.ts +59 -0
- package/dist/catalog/scope-jobs.js +65 -0
- package/dist/catalog/scope-sync-workers.d.ts +22 -0
- package/dist/catalog/scope-sync-workers.js +58 -2
- package/dist/catalog/scope-sync.d.ts +40 -65
- package/dist/catalog/scope-sync.js +114 -122
- package/dist/channels/channels.module.d.ts +9 -8
- package/dist/channels/channels.module.js +11 -10
- package/dist/channels/connections.service.d.ts +3 -3
- package/dist/channels/connections.service.js +6 -6
- package/dist/channels/deliver-job.d.ts +10 -3
- package/dist/channels/deliver-job.js +7 -3
- package/dist/channels/inbound.js +2 -2
- package/dist/channels/jobs.d.ts +11 -4
- package/dist/channels/jobs.js +18 -3
- package/dist/channels/outbound.d.ts +5 -2
- package/dist/channels/outbound.js +9 -2
- package/dist/channels/threads.d.ts +4 -3
- package/dist/channels/threads.js +4 -3
- package/dist/conversations/conversations.controller.d.ts +4 -2
- package/dist/conversations/conversations.controller.js +8 -4
- package/dist/conversations/conversations.service.d.ts +54 -9
- package/dist/conversations/conversations.service.js +94 -25
- package/dist/conversations/events.d.ts +27 -0
- package/dist/conversations/events.js +30 -1
- package/dist/conversations/source.d.ts +10 -0
- package/dist/conversations/source.js +17 -0
- package/dist/conversations/tree.d.ts +10 -0
- package/dist/conversations/tree.js +35 -0
- package/dist/db/kernel-schema.d.ts +19 -15
- package/dist/devices/devices.service.d.ts +25 -14
- package/dist/devices/devices.service.js +36 -30
- package/dist/evals/evals.module.js +5 -1
- package/dist/evals/jobs.d.ts +14 -6
- package/dist/evals/jobs.js +21 -19
- package/dist/evals/run-replay.d.ts +13 -2
- package/dist/evals/run-replay.js +28 -1
- package/dist/evals/runs.service.d.ts +5 -6
- package/dist/evals/runs.service.js +11 -33
- package/dist/evals/snapshot.d.ts +7 -1
- package/dist/evals/snapshot.js +2 -1
- package/dist/extensions/hooks.d.ts +22 -3
- package/dist/extensions/hooks.js +15 -1
- package/dist/extensions/lifecycle-hooks.d.ts +99 -0
- package/dist/extensions/lifecycle-hooks.js +273 -0
- package/dist/extensions/org-config.d.ts +13 -1
- package/dist/extensions/org-config.js +19 -2
- package/dist/extensions/permission-view.d.ts +9 -5
- package/dist/extensions/permission-view.js +9 -4
- package/dist/extensions/point-defaults.d.ts +28 -1
- package/dist/extensions/point-defaults.js +44 -13
- package/dist/inbox/inbox.service.d.ts +6 -20
- package/dist/inbox/inbox.service.js +0 -3
- package/dist/inbox/org-notices.d.ts +1 -1
- package/dist/inbox/platform-inbox.service.d.ts +3 -32
- package/dist/inbox/platform-inbox.service.js +5 -54
- package/dist/infra/outbox/outbox.service.d.ts +6 -0
- package/dist/infra/outbox/outbox.service.js +51 -17
- package/dist/infra/outbox/registry.d.ts +176 -0
- package/dist/infra/outbox/registry.js +183 -0
- package/dist/infra/queue/queue-names.d.ts +1 -1
- package/dist/infra/queue/queue-names.js +1 -0
- package/dist/local-devices/device-policy.service.d.ts +131 -26
- package/dist/local-devices/device-policy.service.js +341 -145
- package/dist/local-devices/machines.d.ts +17 -2
- package/dist/local-devices/machines.js +66 -5
- package/dist/local-devices/policy-op-jobs.d.ts +15 -0
- package/dist/local-devices/policy-op-jobs.js +12 -0
- package/dist/local-devices/policy-summary.d.ts +36 -3
- package/dist/local-devices/policy-summary.js +47 -1
- package/dist/orgs/directory-sync.js +1 -1
- package/dist/orgs/members.service.js +1 -1
- package/dist/orgs/offboarding.d.ts +50 -57
- package/dist/orgs/offboarding.js +117 -162
- package/dist/orgs/orgs.module.js +3 -0
- package/dist/orgs/orgs.service.d.ts +11 -5
- package/dist/orgs/orgs.service.js +19 -7
- package/dist/overrides.d.ts +7 -0
- package/dist/overrides.js +4 -0
- package/dist/platform/ops/conversations.ops.js +1 -1
- package/dist/platform/ops/inbox.ops.js +4 -20
- package/dist/platform/ops/platform.ops.d.ts +1 -0
- package/dist/platform/ops/platform.ops.js +6 -3
- package/dist/roles/worker-role.d.ts +10 -5
- package/dist/roles/worker-role.js +19 -9
- package/dist/roles/worker.module.js +2 -4
- package/dist/runtime/context/build.d.ts +3 -0
- package/dist/runtime/context/build.js +15 -0
- package/dist/runtime/context/plugin-context.d.ts +20 -0
- package/dist/runtime/context/plugin-context.js +30 -0
- package/dist/runtime/langgraph-loop.js +4 -0
- package/dist/runtime/loop.d.ts +8 -0
- package/dist/runtime/maintenance.d.ts +9 -4
- package/dist/runtime/maintenance.js +52 -13
- package/dist/runtime/model-call.d.ts +6 -1
- package/dist/runtime/model-call.js +1 -0
- package/dist/runtime/plugin-context.service.d.ts +75 -0
- package/dist/runtime/plugin-context.service.js +220 -0
- package/dist/runtime/run-context.service.d.ts +7 -3
- package/dist/runtime/run-context.service.js +12 -2
- package/dist/runtime/run-control.d.ts +6 -1
- package/dist/runtime/run-control.js +13 -0
- package/dist/runtime/run-finish.d.ts +2 -2
- package/dist/runtime/run-finish.js +11 -6
- package/dist/runtime/run-jobs.d.ts +21 -4
- package/dist/runtime/run-jobs.js +29 -6
- package/dist/runtime/run-orphan-check.job.d.ts +14 -11
- package/dist/runtime/run-orphan-check.job.js +16 -11
- package/dist/runtime/run-queue.d.ts +29 -24
- package/dist/runtime/run-queue.js +118 -57
- package/dist/runtime/run-status.d.ts +12 -0
- package/dist/runtime/run-status.js +21 -0
- package/dist/runtime/run-worker.d.ts +32 -3
- package/dist/runtime/run-worker.js +143 -21
- package/dist/runtime/runtime.module.js +2 -0
- package/dist/runtime/step-log.d.ts +6 -5
- package/dist/runtime/step-log.js +6 -5
- package/dist/runtime/subagents/dispatch.js +1 -0
- package/dist/runtime/subagents/skill-fork.js +3 -0
- package/dist/runtime/usage-report.d.ts +3 -1
- package/dist/runtime/usage-report.js +4 -2
- package/dist/runtime/waits.d.ts +16 -6
- package/dist/runtime/waits.js +37 -15
- package/dist/sandbox/jobs.d.ts +20 -10
- package/dist/sandbox/jobs.js +23 -17
- package/dist/schedules/fire.d.ts +25 -4
- package/dist/schedules/fire.js +87 -13
- package/dist/schedules/job-ids.d.ts +66 -17
- package/dist/schedules/job-ids.js +81 -13
- package/dist/schedules/run-tracker.js +2 -1
- package/dist/schedules/scan.job.d.ts +16 -35
- package/dist/schedules/scan.job.js +38 -147
- package/dist/schedules/scheduled-tasks.service.d.ts +6 -6
- package/dist/schedules/scheduled-tasks.service.js +17 -14
- package/dist/schedules/schedules.module.js +0 -4
- package/dist/skills/catalog.d.ts +7 -3
- package/dist/skills/catalog.js +12 -2
- package/dist/skills/changes.controller.d.ts +1 -1
- package/dist/skills/changes.controller.js +1 -1
- package/dist/tools/approvals.service.d.ts +111 -23
- package/dist/tools/approvals.service.js +326 -77
- package/dist/tools/builtins/sandbox/task-output.js +21 -6
- package/dist/tools/device-op-resolver.d.ts +40 -0
- package/dist/tools/device-op-resolver.js +121 -0
- package/dist/tools/network-asks.d.ts +1 -1
- package/dist/tools/network-asks.js +4 -3
- package/dist/tools/pipeline.d.ts +11 -2
- package/dist/tools/pipeline.js +5 -0
- package/dist/tools/questions.service.d.ts +15 -4
- package/dist/tools/questions.service.js +21 -19
- package/dist/tools/registry.d.ts +8 -1
- package/dist/tools/registry.js +9 -0
- package/dist/tools/tools.module.js +4 -0
- package/package.json +3 -3
- package/src/migrations/0121_drop_platform_migration_runs.sql +12 -0
- package/src/migrations/0122_drop_scheduled_task_runs_rechecked_at.sql +5 -0
- package/src/migrations/0123_pgvector.sql +27 -0
- package/src/migrations/0124_conversation_source.sql +36 -0
- package/src/migrations/0125_conversation_tree_stopped_at.sql +5 -0
- package/dist/catalog/platform-migration.d.ts +0 -115
- package/dist/catalog/platform-migration.js +0 -583
- package/dist/infra/queue/add-job-once.d.ts +0 -14
- package/dist/infra/queue/add-job-once.js +0 -16
|
@@ -9,8 +9,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
9
9
|
};
|
|
10
10
|
import { createHash, randomUUID } from "node:crypto";
|
|
11
11
|
import { appearanceIssues, PLUGIN_MANIFEST_FILE, parseSkillMd, pluginDescription, SDK_VERSION, SKILL_ENTRY_FILE, } from "@capybara-hq/plugin-sdk";
|
|
12
|
-
import {
|
|
13
|
-
import { Inject, Injectable } from "@nestjs/common";
|
|
12
|
+
import { Inject, Injectable, Optional } from "@nestjs/common";
|
|
14
13
|
import { sql } from "kysely";
|
|
15
14
|
import semver from "semver";
|
|
16
15
|
import { ClientBuilds } from "../client/client-builds.service.js";
|
|
@@ -35,10 +34,10 @@ import { afterCommit } from "../infra/database/after-commit.js";
|
|
|
35
34
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
36
35
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
37
36
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
37
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
38
38
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
39
39
|
import { OrgLock } from "../orgs/org-lock.js";
|
|
40
40
|
import { packPackageTgz } from "../packages/tgz.js";
|
|
41
|
-
import { MAINTENANCE_QUEUE_NAME } from "../runtime/maintenance-queue.js";
|
|
42
41
|
import { checkSkillFiles, SkillArchiveError } from "../skills/package.js";
|
|
43
42
|
import { StorageService } from "../storage/storage.service.js";
|
|
44
43
|
import { canonicalJson } from "../tools/canonical-json.js";
|
|
@@ -52,15 +51,13 @@ import { item as reportItem, sortItems, } from "./claude/report.js";
|
|
|
52
51
|
import { isClaudePluginTree, translateClaudePlugin } from "./claude/translate.js";
|
|
53
52
|
import { CatalogItemLock } from "./locks.js";
|
|
54
53
|
import { assertNameFree, assertPackageFree, assertShareable, packageOwner, releaseExtensionClaim, shareGate, usableBy, } from "./ownership.js";
|
|
55
|
-
import { PlatformComponents } from "./platform-components.js";
|
|
56
|
-
import { PLATFORM_MIGRATION_JOB } from "./platform-migration.js";
|
|
54
|
+
import { PlanStale, PlatformComponents } from "./platform-components.js";
|
|
57
55
|
import { PluginPackageError, readPluginFiles, readPluginPackage, themeApiError, } from "./plugin-package.js";
|
|
58
56
|
import { hasImportRequests, importRequestOf, resolveImportRequests } from "./request-rules.js";
|
|
59
57
|
import { assertNameNotReserved } from "./reserved-names.js";
|
|
58
|
+
import { oweScopeItem, SCOPE_BACKSTOP_DELAY, SCOPE_BACKSTOP_DELAY_MS } from "./scope-jobs.js";
|
|
60
59
|
import { addScopeOrg } from "./scope-orgs.js";
|
|
61
60
|
import { maxSatisfying, satisfiesRange } from "./versions.js";
|
|
62
|
-
/** How long after a failed post-import platform sync the migration job runs for the item. */
|
|
63
|
-
export const PLATFORM_SYNC_RETRY_MS = 60_000;
|
|
64
61
|
/**
|
|
65
62
|
* Platform import of a plugin (package ecosystem spec §4.3): one review for every plugin, whatever
|
|
66
63
|
* it contains (an extension, skills, connector templates, dependencies), confirmed once.
|
|
@@ -86,8 +83,10 @@ export const PLATFORM_SYNC_RETRY_MS = 60_000;
|
|
|
86
83
|
* snapshot when it is installed or upgraded by this import (source web, audit
|
|
87
84
|
* `extension.permissions_approved` carrying the plugin), and creates the item (with the scope the
|
|
88
85
|
* admin chose, default `optional`) or adds the version (`manifest` = the normalized plugin.json,
|
|
89
|
-
* `extension_sha256`, the files under the staging prefix)
|
|
90
|
-
*
|
|
86
|
+
* `extension_sha256`, the files under the staging prefix); an item's first usable version also
|
|
87
|
+
* gets its platform component rows there (their files copied before, keyed by content: a failure
|
|
88
|
+
* leaves nothing a retry copies again; no job heals an item later). After the commit the plugin's
|
|
89
|
+
* own extension is installed on the deployment and enabled (`ExtensionAdminOps.install` + `enable`;
|
|
91
90
|
* each replica reconciles, no restart); a failure is returned, not thrown, and an upgrade that was
|
|
92
91
|
* not installed gets its old snapshot back.
|
|
93
92
|
*
|
|
@@ -164,8 +163,9 @@ let PluginImport = class PluginImport {
|
|
|
164
163
|
log;
|
|
165
164
|
txHost;
|
|
166
165
|
platform;
|
|
167
|
-
maintenance;
|
|
168
166
|
clientBuilds;
|
|
167
|
+
outbox;
|
|
168
|
+
backstopDelayMs;
|
|
169
169
|
/** Where plugin files go (the kernel's object storage; the CLI's own, see {@link useCliStorage}). */
|
|
170
170
|
files;
|
|
171
171
|
/**
|
|
@@ -183,12 +183,14 @@ let PluginImport = class PluginImport {
|
|
|
183
183
|
blobs,
|
|
184
184
|
/** Config-declared names, loaded connectors and extension versions (the extension registry). */
|
|
185
185
|
registry, log, txHost,
|
|
186
|
-
/** The platform rows of a new item's components, written
|
|
186
|
+
/** The platform rows of a new item's components, written in the confirm's transaction. */
|
|
187
187
|
platform,
|
|
188
|
-
/** A failed platform sync enqueues a run of the migration job here (it heals the item). */
|
|
189
|
-
maintenance,
|
|
190
188
|
/** The client build of a dropped org upload's package is deleted with it. */
|
|
191
|
-
clientBuilds
|
|
189
|
+
clientBuilds,
|
|
190
|
+
/** The scope sync's backstop, owed by the confirm's commit (ruling R24). */
|
|
191
|
+
outbox,
|
|
192
|
+
/** The backstop's delay (a test seam; default `SCOPE_BACKSTOP_DELAY_MS`). */
|
|
193
|
+
backstopDelayMs = SCOPE_BACKSTOP_DELAY_MS) {
|
|
192
194
|
this.kdb = kdb;
|
|
193
195
|
this.adminLock = adminLock;
|
|
194
196
|
this.orgLock = orgLock;
|
|
@@ -204,8 +206,9 @@ let PluginImport = class PluginImport {
|
|
|
204
206
|
this.log = log;
|
|
205
207
|
this.txHost = txHost;
|
|
206
208
|
this.platform = platform;
|
|
207
|
-
this.maintenance = maintenance;
|
|
208
209
|
this.clientBuilds = clientBuilds;
|
|
210
|
+
this.outbox = outbox;
|
|
211
|
+
this.backstopDelayMs = backstopDelayMs;
|
|
209
212
|
this.files = storage;
|
|
210
213
|
}
|
|
211
214
|
/** The kernel-schema handle of the current context (the transaction, else the pool). */
|
|
@@ -734,11 +737,16 @@ let PluginImport = class PluginImport {
|
|
|
734
737
|
const stored = reviewed && reviewed.action !== "keep" && owner === undefined
|
|
735
738
|
? await this.readStored(reviewed.sha256)
|
|
736
739
|
: undefined;
|
|
740
|
+
// The platform components of the item's first usable version: planned and their files copied
|
|
741
|
+
// (keyed by content) before the transaction, their rows written in it
|
|
742
|
+
const prepared = staged.retry === true || (owner !== undefined && reviewed !== undefined)
|
|
743
|
+
? undefined
|
|
744
|
+
: await this.prepareFirstVersion(staged, row.object_prefix, owner);
|
|
737
745
|
const committed = await this.commit(actor, { stagingId, review, staged, src, manifest, objectPrefix: row.object_prefix }, {
|
|
738
746
|
scope,
|
|
739
747
|
orgs: [...new Set(orgs ?? [])].sort(),
|
|
740
748
|
...(owner !== undefined && { owner, shareable: input.shareable ?? false }),
|
|
741
|
-
}, stored, opts);
|
|
749
|
+
}, stored, opts, prepared);
|
|
742
750
|
const { now } = committed;
|
|
743
751
|
if (committed.pending) {
|
|
744
752
|
// Waits for the super admin (P3-10): no platform components, nothing deployed
|
|
@@ -750,11 +758,6 @@ let PluginImport = class PluginImport {
|
|
|
750
758
|
firstVersion: false,
|
|
751
759
|
};
|
|
752
760
|
}
|
|
753
|
-
// A new item's skills, agent templates and connector templates become platform components
|
|
754
|
-
// (plugin scope phase 2); a new version of an existing item leaves them to the platform
|
|
755
|
-
// update. After the commit: it copies files in object storage
|
|
756
|
-
if (committed.firstVersion)
|
|
757
|
-
await this.syncPlatform(committed.itemId, staged.version);
|
|
758
761
|
if (input.deploy === false) {
|
|
759
762
|
return {
|
|
760
763
|
item: await this.itemView(committed.itemId),
|
|
@@ -780,12 +783,31 @@ let PluginImport = class PluginImport {
|
|
|
780
783
|
};
|
|
781
784
|
}
|
|
782
785
|
/**
|
|
783
|
-
*
|
|
784
|
-
*
|
|
785
|
-
*
|
|
786
|
+
* The platform components of the staged version when its confirm will most likely make it the
|
|
787
|
+
* item's first usable version ({@link commit} decides under its locks): no live item of the name
|
|
788
|
+
* yet, or an org upload replacing its own first upload still awaiting confirmation. Planned from
|
|
789
|
+
* the staged content and their files copied, outside any transaction; otherwise undefined.
|
|
786
790
|
*/
|
|
787
|
-
async
|
|
788
|
-
await this.
|
|
791
|
+
async prepareFirstVersion(staged, objectPrefix, owner) {
|
|
792
|
+
const live = await this.db
|
|
793
|
+
.selectFrom("catalog_items")
|
|
794
|
+
.select(["id", "awaiting_confirmation", "owner_org_id"])
|
|
795
|
+
.where("name", "=", staged.manifest.name)
|
|
796
|
+
.where("deleted_at", "is", null)
|
|
797
|
+
.executeTakeFirst();
|
|
798
|
+
const first = live === undefined ||
|
|
799
|
+
(owner !== undefined && live.awaiting_confirmation && live.owner_org_id === owner.orgId);
|
|
800
|
+
if (!first)
|
|
801
|
+
return undefined;
|
|
802
|
+
return this.platform.prepareImport({
|
|
803
|
+
itemId: live?.id ?? staged.itemId,
|
|
804
|
+
plugin: staged.manifest.name,
|
|
805
|
+
version: staged.version,
|
|
806
|
+
manifest: staged.manifest,
|
|
807
|
+
objectPrefix,
|
|
808
|
+
files: staged.files,
|
|
809
|
+
sourceFormat: staged.sourceFormat ?? "capybara",
|
|
810
|
+
});
|
|
789
811
|
}
|
|
790
812
|
/**
|
|
791
813
|
* The confirm's transaction: the staging row consumed, the extension's action recomputed under
|
|
@@ -800,8 +822,15 @@ let PluginImport = class PluginImport {
|
|
|
800
822
|
* upload without an extension for an item whose first version still waits (plan Task 6) replaces
|
|
801
823
|
* that upload and applies at once: the item stops waiting and the claim is released (nothing
|
|
802
824
|
* was installed under it).
|
|
825
|
+
*
|
|
826
|
+
* The item's first usable version (a new item not waiting, or an awaiting first upload replaced)
|
|
827
|
+
* writes the platform rows of its skills, agent templates, connector templates and themes
|
|
828
|
+
* (plugin scope phase 2) from `prepared` (their files copied before the transaction, keyed by
|
|
829
|
+
* content): a failure rolls the whole confirm back, and a retry copies nothing again. A plan made
|
|
830
|
+
* for another item or version, or a component changed since it -> `plugin.review_stale`. A new
|
|
831
|
+
* version of an existing item leaves them to the platform update.
|
|
803
832
|
*/
|
|
804
|
-
async commit(actor, c, scope, stored, opts) {
|
|
833
|
+
async commit(actor, c, scope, stored, opts, prepared) {
|
|
805
834
|
const { stagingId, review, staged, src, manifest } = c;
|
|
806
835
|
const reviewed = review.extension;
|
|
807
836
|
const stale = () => reviewStale(review);
|
|
@@ -1034,61 +1063,44 @@ let PluginImport = class PluginImport {
|
|
|
1034
1063
|
await markVersionApplied(t, itemId, staged.version);
|
|
1035
1064
|
await releaseExtensionClaim(t, m.name, existing.package_name);
|
|
1036
1065
|
}
|
|
1066
|
+
const firstVersion = (created && !pending) || replacedAwaiting;
|
|
1067
|
+
if (firstVersion) {
|
|
1068
|
+
if (prepared?.plan.itemId !== itemId || prepared.plan.version !== staged.version) {
|
|
1069
|
+
throw stale();
|
|
1070
|
+
}
|
|
1071
|
+
try {
|
|
1072
|
+
await this.platform.applySyncIn(prepared);
|
|
1073
|
+
}
|
|
1074
|
+
catch (e) {
|
|
1075
|
+
if (e instanceof PlanStale)
|
|
1076
|
+
throw stale();
|
|
1077
|
+
throw e;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
// The commit owes the scope sync's backstop (ruling R24) when the item's scope turns it on by
|
|
1081
|
+
// itself: the caller owes the immediate sync after the deploy, which a crash may lose
|
|
1082
|
+
if (!pending) {
|
|
1083
|
+
const item = await t
|
|
1084
|
+
.selectFrom("catalog_items")
|
|
1085
|
+
.select("scope")
|
|
1086
|
+
.where("id", "=", itemId)
|
|
1087
|
+
.executeTakeFirstOrThrow();
|
|
1088
|
+
if (item.scope !== "optional") {
|
|
1089
|
+
await oweScopeItem(this.outbox, t, itemId, {
|
|
1090
|
+
backstop: true,
|
|
1091
|
+
backstopDelayMs: this.backstopDelayMs,
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1037
1095
|
return {
|
|
1038
1096
|
itemId,
|
|
1039
1097
|
created,
|
|
1040
|
-
firstVersion
|
|
1098
|
+
firstVersion,
|
|
1041
1099
|
pending,
|
|
1042
1100
|
now,
|
|
1043
1101
|
previous,
|
|
1044
1102
|
};
|
|
1045
1103
|
}
|
|
1046
|
-
/**
|
|
1047
|
-
* The platform components of a new item. The item is committed already, so a failure is logged
|
|
1048
|
-
* and not thrown (like a failed deploy, the import itself succeeded); a run of the platform
|
|
1049
|
-
* components migration job (which writes what is missing) is enqueued on `cap-kernel-maintenance`
|
|
1050
|
-
* after {@link PLATFORM_SYNC_RETRY_MS}, one per item (deterministic job id). If that run fails
|
|
1051
|
-
* too, its `itemsFailed` shows in the super admin's inbox; the daily run and every worker start
|
|
1052
|
-
* try again.
|
|
1053
|
-
*/
|
|
1054
|
-
async syncPlatform(itemId, version) {
|
|
1055
|
-
try {
|
|
1056
|
-
await this.platform.syncFromVersion(itemId, version, { initial: true });
|
|
1057
|
-
}
|
|
1058
|
-
catch (err) {
|
|
1059
|
-
// Removed meanwhile (an org deletion racing a confirmation, P3-20): nothing to write
|
|
1060
|
-
const live = await this.db
|
|
1061
|
-
.selectFrom("catalog_items")
|
|
1062
|
-
.select("id")
|
|
1063
|
-
.where("id", "=", itemId)
|
|
1064
|
-
.where("deleted_at", "is", null)
|
|
1065
|
-
.executeTakeFirst();
|
|
1066
|
-
if (live === undefined) {
|
|
1067
|
-
this.log.info("catalog item removed before its platform components were written", {
|
|
1068
|
-
itemId,
|
|
1069
|
-
version,
|
|
1070
|
-
});
|
|
1071
|
-
return;
|
|
1072
|
-
}
|
|
1073
|
-
this.log.error("writing the platform components of a new catalog item failed", {
|
|
1074
|
-
itemId,
|
|
1075
|
-
version,
|
|
1076
|
-
err,
|
|
1077
|
-
});
|
|
1078
|
-
try {
|
|
1079
|
-
await this.maintenance.add(PLATFORM_MIGRATION_JOB, {}, {
|
|
1080
|
-
jobId: `${PLATFORM_MIGRATION_JOB}-retry-${itemId}`,
|
|
1081
|
-
delay: PLATFORM_SYNC_RETRY_MS,
|
|
1082
|
-
attempts: 1,
|
|
1083
|
-
removeOnComplete: true,
|
|
1084
|
-
removeOnFail: { age: 86_400 },
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
1087
|
-
catch (e) {
|
|
1088
|
-
this.log.warn("cannot enqueue the platform components migration", { itemId, err: e });
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
1104
|
/**
|
|
1093
1105
|
* Writes the extension's permission snapshot for the version being imported (source web; cli
|
|
1094
1106
|
* without an actor; bootstrap for the bootstrap step), after
|
|
@@ -1727,8 +1739,10 @@ PluginImport = __decorate([
|
|
|
1727
1739
|
__param(13, Inject(KERNEL_LOGGER)),
|
|
1728
1740
|
__param(14, Inject(TransactionHost)),
|
|
1729
1741
|
__param(15, Inject(PlatformComponents)),
|
|
1730
|
-
__param(16, Inject(
|
|
1731
|
-
__param(17, Inject(
|
|
1742
|
+
__param(16, Inject(ClientBuilds)),
|
|
1743
|
+
__param(17, Inject(OutboxService)),
|
|
1744
|
+
__param(18, Optional()),
|
|
1745
|
+
__param(18, Inject(SCOPE_BACKSTOP_DELAY))
|
|
1732
1746
|
], PluginImport);
|
|
1733
1747
|
export { PluginImport };
|
|
1734
1748
|
/**
|
|
@@ -178,14 +178,14 @@ export type UpdateTarget = VersionRow;
|
|
|
178
178
|
* the extension first (`ExtensionAdminOps.install`, enabled when the update installs it; added
|
|
179
179
|
* permissions wait for the admin's approval as for any extension upgrade), then one transaction
|
|
180
180
|
* under the item name's lock that recomputes the diff (`plugin.upgrade_stale` on a difference)
|
|
181
|
-
* and writes the platform versions (`PlatformComponents.
|
|
181
|
+
* and writes the platform versions (`PlatformComponents.applySyncIn`, which records
|
|
182
182
|
* `platform_synced_version`), the removals (a component no agent uses is soft-deleted, so
|
|
183
183
|
* unpinned linked copies go with it; pinned copies keep their own version; a removed connector
|
|
184
184
|
* template leaves its connectors as the orgs' own), clears the pins of linked copies, fans
|
|
185
185
|
* changed templates out to every connector made from them (`applyTemplateIn`, under each org's
|
|
186
186
|
* row lock, credentials cleared only for a changed credential shape), moves every org install to the version and audits
|
|
187
|
-
* `plugin.platform_updated`; the scope sync of the item and its dependencies is
|
|
188
|
-
*
|
|
187
|
+
* `plugin.platform_updated`; the scope sync of the item and its dependencies is owed in that
|
|
188
|
+
* transaction (orgs get new dependencies by rule 9). A failure rolls the transaction back and
|
|
189
189
|
* puts the extension back where it was (audit `plugin.platform_update_failed`, 502
|
|
190
190
|
* `plugin.upgrade_failed`); files copied to `deployment/platform/` stay unreferenced.
|
|
191
191
|
* Storage is never read or written inside the transaction: the target's contents (and the
|
|
@@ -363,7 +363,7 @@ export declare class PlatformPluginUpdater {
|
|
|
363
363
|
/**
|
|
364
364
|
* Other platform plugins depending on this one must accept the target (their platform version's
|
|
365
365
|
* dependency range); returns the catalog items of the target's own dependencies (their scope
|
|
366
|
-
* sync is
|
|
366
|
+
* sync is owed with the update: rule 9).
|
|
367
367
|
*/
|
|
368
368
|
private checkDependents;
|
|
369
369
|
/** The plugin's live platform components with their current versions. */
|
|
@@ -26,7 +26,6 @@ import { audit } from "../identity/audit.js";
|
|
|
26
26
|
import { SuperAdminLock } from "../identity/super-admin.js";
|
|
27
27
|
import { addOrgNotice, itemDisplayName, notifySharedUpdate } from "../inbox/org-notices.js";
|
|
28
28
|
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
29
|
-
import { afterCommit } from "../infra/database/after-commit.js";
|
|
30
29
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
31
30
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
32
31
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
@@ -105,14 +104,14 @@ const filesDigest = (row) => skillFilesDigest(row.files.map((f) => ({ path: f.pa
|
|
|
105
104
|
* the extension first (`ExtensionAdminOps.install`, enabled when the update installs it; added
|
|
106
105
|
* permissions wait for the admin's approval as for any extension upgrade), then one transaction
|
|
107
106
|
* under the item name's lock that recomputes the diff (`plugin.upgrade_stale` on a difference)
|
|
108
|
-
* and writes the platform versions (`PlatformComponents.
|
|
107
|
+
* and writes the platform versions (`PlatformComponents.applySyncIn`, which records
|
|
109
108
|
* `platform_synced_version`), the removals (a component no agent uses is soft-deleted, so
|
|
110
109
|
* unpinned linked copies go with it; pinned copies keep their own version; a removed connector
|
|
111
110
|
* template leaves its connectors as the orgs' own), clears the pins of linked copies, fans
|
|
112
111
|
* changed templates out to every connector made from them (`applyTemplateIn`, under each org's
|
|
113
112
|
* row lock, credentials cleared only for a changed credential shape), moves every org install to the version and audits
|
|
114
|
-
* `plugin.platform_updated`; the scope sync of the item and its dependencies is
|
|
115
|
-
*
|
|
113
|
+
* `plugin.platform_updated`; the scope sync of the item and its dependencies is owed in that
|
|
114
|
+
* transaction (orgs get new dependencies by rule 9). A failure rolls the transaction back and
|
|
116
115
|
* puts the extension back where it was (audit `plugin.platform_update_failed`, 502
|
|
117
116
|
* `plugin.upgrade_failed`); files copied to `deployment/platform/` stay unreferenced.
|
|
118
117
|
* Storage is never read or written inside the transaction: the target's contents (and the
|
|
@@ -669,20 +668,9 @@ let PlatformPluginUpdater = class PlatformPluginUpdater {
|
|
|
669
668
|
...opts.auditDetail,
|
|
670
669
|
},
|
|
671
670
|
});
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
try {
|
|
676
|
-
await this.sync.enqueueItem(id);
|
|
677
|
-
}
|
|
678
|
-
catch (err) {
|
|
679
|
-
this.log.warn("enqueueing the scope sync after a platform update failed", {
|
|
680
|
-
itemId: id,
|
|
681
|
-
err,
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
});
|
|
671
|
+
// The scope sync of the item and its dependencies is owed with the update (outbox spec §8.1)
|
|
672
|
+
for (const id of [itemId, ...diff.dependencies])
|
|
673
|
+
await this.sync.enqueueItem(id);
|
|
686
674
|
return diff;
|
|
687
675
|
}
|
|
688
676
|
/**
|
|
@@ -1340,7 +1328,7 @@ let PlatformPluginUpdater = class PlatformPluginUpdater {
|
|
|
1340
1328
|
/**
|
|
1341
1329
|
* Other platform plugins depending on this one must accept the target (their platform version's
|
|
1342
1330
|
* dependency range); returns the catalog items of the target's own dependencies (their scope
|
|
1343
|
-
* sync is
|
|
1331
|
+
* sync is owed with the update: rule 9).
|
|
1344
1332
|
*/
|
|
1345
1333
|
async checkDependents(name, to) {
|
|
1346
1334
|
const rows = await this.db
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { KernelSchemaDb } from "../db/kernel-schema.js";
|
|
2
|
+
import type { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
3
|
+
/**
|
|
4
|
+
* The plugin scope sync's jobs as the outbox owes them (transactional outbox spec §8.1): a leaf
|
|
5
|
+
* module (type imports only), so the import confirm (`PluginImport`, below the scope service) and
|
|
6
|
+
* the CLI owe them without the sync. `scope-sync.ts` (the consumer side) re-exports these names.
|
|
7
|
+
*/
|
|
8
|
+
/** The scope sync queue (no `:` in the name). */
|
|
9
|
+
export declare const PLUGIN_SCOPE_QUEUE = "cap-kernel-plugin-scope";
|
|
10
|
+
/** The job converging one item in every org. */
|
|
11
|
+
export declare const SCOPE_ITEM_JOB = "scope-item";
|
|
12
|
+
/** The job converging every item in one org. */
|
|
13
|
+
export declare const SCOPE_ORG_JOB = "scope-org";
|
|
14
|
+
/**
|
|
15
|
+
* The delayed backstop of an item job owed by a confirmation's commit (ruling R24): it converges
|
|
16
|
+
* the item as {@link SCOPE_ITEM_JOB} does once the extension is deployed, and fails (BullMQ
|
|
17
|
+
* retries it with its backoff) while the extension is not enabled on the deployment yet.
|
|
18
|
+
*/
|
|
19
|
+
export declare const SCOPE_BACKSTOP_JOB = "scope-item-backstop";
|
|
20
|
+
/** How long after the confirmation's commit the backstop runs (the deploy has finished by then). */
|
|
21
|
+
export declare const SCOPE_BACKSTOP_DELAY_MS: number;
|
|
22
|
+
/**
|
|
23
|
+
* Optional provider (a test seam): the backstop's delay (ms) instead of
|
|
24
|
+
* {@link SCOPE_BACKSTOP_DELAY_MS}, so a long test file never has a backstop fire in a later test.
|
|
25
|
+
*/
|
|
26
|
+
export declare const SCOPE_BACKSTOP_DELAY: unique symbol;
|
|
27
|
+
/** One item job per scope version (no `:`: item ids are UUIDs). */
|
|
28
|
+
export declare const scopeItemJobId: (itemId: string, version: number) => string;
|
|
29
|
+
/** The backstop of the item job of a scope version (distinct from the immediate one). */
|
|
30
|
+
export declare const scopeBackstopJobId: (itemId: string, version: number) => string;
|
|
31
|
+
/** One org job at a time per org. */
|
|
32
|
+
export declare const scopeOrgJobId: (orgId: string) => string;
|
|
33
|
+
/**
|
|
34
|
+
* The delayed retry `n` of an item job whose extension this replica had not loaded yet (ruling
|
|
35
|
+
* P3-38); deterministic, so replicas deferring the same item add it once.
|
|
36
|
+
*/
|
|
37
|
+
export declare const scopeRetryJobId: (itemId: string, version: number, n: number) => string;
|
|
38
|
+
/**
|
|
39
|
+
* The job's data. `retry`: the item job's delayed retry number (P3-38). `backstop`: a
|
|
40
|
+
* {@link SCOPE_BACKSTOP_JOB}.
|
|
41
|
+
*/
|
|
42
|
+
export type ScopeJob = {
|
|
43
|
+
kind: "item";
|
|
44
|
+
itemId: string;
|
|
45
|
+
retry?: number;
|
|
46
|
+
backstop?: true;
|
|
47
|
+
} | {
|
|
48
|
+
kind: "org";
|
|
49
|
+
orgId: string;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Owes the item's scope sync in the transaction in context, once per scope version (read in that
|
|
53
|
+
* transaction, so after its own bump); `backstop` owes the delayed backstop instead, due
|
|
54
|
+
* `backstopDelayMs` later (default {@link SCOPE_BACKSTOP_DELAY_MS}). A missing item owes nothing.
|
|
55
|
+
*/
|
|
56
|
+
export declare function oweScopeItem(outbox: Pick<OutboxService, "add">, db: KernelSchemaDb, itemId: string, opts?: {
|
|
57
|
+
backstop?: boolean;
|
|
58
|
+
backstopDelayMs?: number;
|
|
59
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugin scope sync's jobs as the outbox owes them (transactional outbox spec §8.1): a leaf
|
|
3
|
+
* module (type imports only), so the import confirm (`PluginImport`, below the scope service) and
|
|
4
|
+
* the CLI owe them without the sync. `scope-sync.ts` (the consumer side) re-exports these names.
|
|
5
|
+
*/
|
|
6
|
+
/** The scope sync queue (no `:` in the name). */
|
|
7
|
+
export const PLUGIN_SCOPE_QUEUE = "cap-kernel-plugin-scope";
|
|
8
|
+
/** The job converging one item in every org. */
|
|
9
|
+
export const SCOPE_ITEM_JOB = "scope-item";
|
|
10
|
+
/** The job converging every item in one org. */
|
|
11
|
+
export const SCOPE_ORG_JOB = "scope-org";
|
|
12
|
+
/**
|
|
13
|
+
* The delayed backstop of an item job owed by a confirmation's commit (ruling R24): it converges
|
|
14
|
+
* the item as {@link SCOPE_ITEM_JOB} does once the extension is deployed, and fails (BullMQ
|
|
15
|
+
* retries it with its backoff) while the extension is not enabled on the deployment yet.
|
|
16
|
+
*/
|
|
17
|
+
export const SCOPE_BACKSTOP_JOB = "scope-item-backstop";
|
|
18
|
+
/** How long after the confirmation's commit the backstop runs (the deploy has finished by then). */
|
|
19
|
+
export const SCOPE_BACKSTOP_DELAY_MS = 5 * 60_000;
|
|
20
|
+
/**
|
|
21
|
+
* Optional provider (a test seam): the backstop's delay (ms) instead of
|
|
22
|
+
* {@link SCOPE_BACKSTOP_DELAY_MS}, so a long test file never has a backstop fire in a later test.
|
|
23
|
+
*/
|
|
24
|
+
export const SCOPE_BACKSTOP_DELAY = Symbol("SCOPE_BACKSTOP_DELAY");
|
|
25
|
+
/** One item job per scope version (no `:`: item ids are UUIDs). */
|
|
26
|
+
export const scopeItemJobId = (itemId, version) => `scope-item-${itemId}-${version}`;
|
|
27
|
+
/** The backstop of the item job of a scope version (distinct from the immediate one). */
|
|
28
|
+
export const scopeBackstopJobId = (itemId, version) => `${scopeItemJobId(itemId, version)}-backstop`;
|
|
29
|
+
/** One org job at a time per org. */
|
|
30
|
+
export const scopeOrgJobId = (orgId) => `scope-org-${orgId}`;
|
|
31
|
+
/**
|
|
32
|
+
* The delayed retry `n` of an item job whose extension this replica had not loaded yet (ruling
|
|
33
|
+
* P3-38); deterministic, so replicas deferring the same item add it once.
|
|
34
|
+
*/
|
|
35
|
+
export const scopeRetryJobId = (itemId, version, n) => `scope-item-${itemId}-${version}-r${n}`;
|
|
36
|
+
/**
|
|
37
|
+
* Owes the item's scope sync in the transaction in context, once per scope version (read in that
|
|
38
|
+
* transaction, so after its own bump); `backstop` owes the delayed backstop instead, due
|
|
39
|
+
* `backstopDelayMs` later (default {@link SCOPE_BACKSTOP_DELAY_MS}). A missing item owes nothing.
|
|
40
|
+
*/
|
|
41
|
+
export async function oweScopeItem(outbox, db, itemId, opts = {}) {
|
|
42
|
+
const row = await db
|
|
43
|
+
.selectFrom("catalog_items")
|
|
44
|
+
.select("scope_version")
|
|
45
|
+
.where("id", "=", itemId)
|
|
46
|
+
.executeTakeFirst();
|
|
47
|
+
if (!row)
|
|
48
|
+
return;
|
|
49
|
+
if (opts.backstop === true) {
|
|
50
|
+
await outbox.add({
|
|
51
|
+
queue: PLUGIN_SCOPE_QUEUE,
|
|
52
|
+
name: SCOPE_BACKSTOP_JOB,
|
|
53
|
+
jobId: scopeBackstopJobId(itemId, row.scope_version),
|
|
54
|
+
data: { kind: "item", itemId, backstop: true },
|
|
55
|
+
runAt: new Date(Date.now() + (opts.backstopDelayMs ?? SCOPE_BACKSTOP_DELAY_MS)),
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
await outbox.add({
|
|
60
|
+
queue: PLUGIN_SCOPE_QUEUE,
|
|
61
|
+
name: SCOPE_ITEM_JOB,
|
|
62
|
+
jobId: scopeItemJobId(itemId, row.scope_version),
|
|
63
|
+
data: { kind: "item", itemId },
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
import { WorkerHost } from "@nestjs/bullmq";
|
|
2
|
+
import type { Job, Worker } from "bullmq";
|
|
3
|
+
import type { KernelLogger } from "../log.js";
|
|
4
|
+
import { PluginScopeSync, type ScopeJob } from "./scope-sync.js";
|
|
5
|
+
/**
|
|
6
|
+
* The consumer of {@link PLUGIN_SCOPE_QUEUE}: {@link PluginScopeSync} runs the `scope-item`,
|
|
7
|
+
* `scope-item-backstop` and `scope-org` jobs the outbox delivers (any other name fails the job; a
|
|
8
|
+
* backstop whose extension is not deployed yet throws, so BullMQ retries it).
|
|
9
|
+
*/
|
|
10
|
+
export declare class PluginScopeSyncProcessor extends WorkerHost<Worker<ScopeJob>> {
|
|
11
|
+
private readonly sync;
|
|
12
|
+
private readonly log;
|
|
13
|
+
private readonly stopping;
|
|
14
|
+
constructor(sync: PluginScopeSync, log: Pick<KernelLogger, "error">);
|
|
15
|
+
process(job: Job<ScopeJob>): Promise<void>;
|
|
16
|
+
/** Starts consuming (worker role, after the extensions loaded; built with `autorun: false`). */
|
|
17
|
+
start(): void;
|
|
18
|
+
/** Stops between pairs and closes the worker. */
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
failed(job: Job<ScopeJob> | undefined, err: Error): void;
|
|
21
|
+
error(err: Error): void;
|
|
22
|
+
}
|
|
1
23
|
/**
|
|
2
24
|
* The plugin scope queue's consumer: {@link PluginScopeSyncProcessor}. Imported only by the worker
|
|
3
25
|
* role (`WorkerModule`), so other roles get no processor and no BullMQ worker. It never starts by
|
|
@@ -4,10 +4,66 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
4
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { OnWorkerEvent, WorkerHost } from "@nestjs/bullmq";
|
|
11
|
+
import { Inject, Injectable, Module } from "@nestjs/common";
|
|
8
12
|
import { configuredProcessor } from "../infra/queue/configured-processor.js";
|
|
13
|
+
import { runJob } from "../infra/queue/run-job.js";
|
|
14
|
+
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
9
15
|
import { CatalogModule } from "./catalog.module.js";
|
|
10
|
-
import { PLUGIN_SCOPE_CONCURRENCY, PLUGIN_SCOPE_QUEUE,
|
|
16
|
+
import { PLUGIN_SCOPE_CONCURRENCY, PLUGIN_SCOPE_QUEUE, PluginScopeSync, SCOPE_BACKSTOP_JOB, SCOPE_ITEM_JOB, SCOPE_ORG_JOB, } from "./scope-sync.js";
|
|
17
|
+
/**
|
|
18
|
+
* The consumer of {@link PLUGIN_SCOPE_QUEUE}: {@link PluginScopeSync} runs the `scope-item`,
|
|
19
|
+
* `scope-item-backstop` and `scope-org` jobs the outbox delivers (any other name fails the job; a
|
|
20
|
+
* backstop whose extension is not deployed yet throws, so BullMQ retries it).
|
|
21
|
+
*/
|
|
22
|
+
let PluginScopeSyncProcessor = class PluginScopeSyncProcessor extends WorkerHost {
|
|
23
|
+
sync;
|
|
24
|
+
log;
|
|
25
|
+
stopping = new AbortController();
|
|
26
|
+
constructor(sync, log) {
|
|
27
|
+
super();
|
|
28
|
+
this.sync = sync;
|
|
29
|
+
this.log = log;
|
|
30
|
+
}
|
|
31
|
+
process(job) {
|
|
32
|
+
return runJob(PLUGIN_SCOPE_QUEUE, job, () => {
|
|
33
|
+
if (![SCOPE_ITEM_JOB, SCOPE_BACKSTOP_JOB, SCOPE_ORG_JOB].includes(job.name)) {
|
|
34
|
+
throw new Error(`unknown plugin scope job ${job.name}`);
|
|
35
|
+
}
|
|
36
|
+
return this.sync.process(job.data, this.stopping.signal);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
/** Starts consuming (worker role, after the extensions loaded; built with `autorun: false`). */
|
|
40
|
+
start() {
|
|
41
|
+
void this.worker.run().catch((err) => this.error(err));
|
|
42
|
+
}
|
|
43
|
+
/** Stops between pairs and closes the worker. */
|
|
44
|
+
async close() {
|
|
45
|
+
this.stopping.abort();
|
|
46
|
+
await this.worker.close();
|
|
47
|
+
}
|
|
48
|
+
failed(job, err) {
|
|
49
|
+
this.log.error("plugin scope job failed", { name: job?.name, jobId: job?.id, err });
|
|
50
|
+
}
|
|
51
|
+
error(err) {
|
|
52
|
+
this.log.error("plugin scope worker error", { err });
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
__decorate([
|
|
56
|
+
OnWorkerEvent("failed")
|
|
57
|
+
], PluginScopeSyncProcessor.prototype, "failed", null);
|
|
58
|
+
__decorate([
|
|
59
|
+
OnWorkerEvent("error")
|
|
60
|
+
], PluginScopeSyncProcessor.prototype, "error", null);
|
|
61
|
+
PluginScopeSyncProcessor = __decorate([
|
|
62
|
+
Injectable(),
|
|
63
|
+
__param(0, Inject(PluginScopeSync)),
|
|
64
|
+
__param(1, Inject(KERNEL_LOGGER))
|
|
65
|
+
], PluginScopeSyncProcessor);
|
|
66
|
+
export { PluginScopeSyncProcessor };
|
|
11
67
|
/**
|
|
12
68
|
* The plugin scope queue's consumer: {@link PluginScopeSyncProcessor}. Imported only by the worker
|
|
13
69
|
* role (`WorkerModule`), so other roles get no processor and no BullMQ worker. It never starts by
|