@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
|
@@ -8,7 +8,6 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
8
8
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
9
|
};
|
|
10
10
|
import { createHash } from "node:crypto";
|
|
11
|
-
import { getQueueToken } from "@nestjs/bullmq";
|
|
12
11
|
import { Inject, Injectable } from "@nestjs/common";
|
|
13
12
|
import { sql } from "kysely";
|
|
14
13
|
import { ApiError } from "../errors.js";
|
|
@@ -19,20 +18,21 @@ import { PluginInstallLock } from "../extensions/locks.js";
|
|
|
19
18
|
import { audit } from "../identity/audit.js";
|
|
20
19
|
import { SuperAdminLock } from "../identity/super-admin.js";
|
|
21
20
|
import { addOrgNotice, itemDisplayName, notifyItemShared } from "../inbox/org-notices.js";
|
|
22
|
-
import { afterCommit } from "../infra/database/after-commit.js";
|
|
23
21
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
24
22
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
25
23
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
24
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
26
25
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
27
26
|
import { OrgLock } from "../orgs/org-lock.js";
|
|
28
|
-
import { MAINTENANCE_QUEUE_NAME } from "../runtime/maintenance-queue.js";
|
|
29
27
|
import { assertNotPlatformDefault, themesPreview, } from "../themes/theme-usage.js";
|
|
30
28
|
import { CatalogService } from "./catalog.service.js";
|
|
31
29
|
import { assertOrgsExist, markVersionApplied } from "./catalog-items.js";
|
|
32
30
|
import { nameConflictError } from "./component-scope.service.js";
|
|
33
31
|
import { agentsUsing, COMPONENT_KINDS, componentOffered, componentOn, listedIn, loadComponents, loadScopeState, pluginFactsOf, skillNameClashes, switchOf, themeIdClashes, } from "./component-state.js";
|
|
34
|
-
import {
|
|
32
|
+
import { oweOwnedPluginCleanup } from "./job-ids.js";
|
|
33
|
+
import { CatalogItemLock } from "./locks.js";
|
|
35
34
|
import { assertNotAwaiting, assertOwnerListed, assertShareable, assertShareableTarget, itemRemovedError, newlySharedWith, ownerOf, ownersOf, PLATFORM_OWNER, packageOwner, pendingDigest, releaseExtensionClaim, } from "./ownership.js";
|
|
35
|
+
import { PlanStale, PlatformComponents } from "./platform-components.js";
|
|
36
36
|
import { PluginImport } from "./plugin-import.js";
|
|
37
37
|
import { PluginInstaller } from "./plugin-install.js";
|
|
38
38
|
import { PlatformPluginUpdater } from "./plugin-upgrade.js";
|
|
@@ -90,10 +90,10 @@ export function conflictsError(conflicts) {
|
|
|
90
90
|
}
|
|
91
91
|
/**
|
|
92
92
|
* The super admin's plugin scope and deployment-level disable (plugin and component management
|
|
93
|
-
* spec §4.1, §5 rules 2-4 and 8), and the import confirm that
|
|
93
|
+
* spec §4.1, §5 rules 2-4 and 8), and the import confirm that owes the scope sync of the item it
|
|
94
94
|
* wrote. A change is previewed, then confirmed with the preview's `scopeHash`, recomputed under the
|
|
95
95
|
* item row lock (a difference -> 409 `plugin.scope_stale`); it bumps `scope_version`, audits
|
|
96
|
-
* `catalog.scope_changed` and
|
|
96
|
+
* `catalog.scope_changed` and owes the item's scope sync in the same transaction, which installs or
|
|
97
97
|
* uninstalls in every org. Disabling keeps the scope, its org list and the org switches, so
|
|
98
98
|
* re-enabling (no hash needed) reinstalls where it was on. Builtin items -> 409 `plugin.builtin`.
|
|
99
99
|
* Stateless, shared by every replica.
|
|
@@ -103,6 +103,8 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
103
103
|
adminLock;
|
|
104
104
|
catalog;
|
|
105
105
|
pluginImport;
|
|
106
|
+
platform;
|
|
107
|
+
itemLock;
|
|
106
108
|
installer;
|
|
107
109
|
extensions;
|
|
108
110
|
ops;
|
|
@@ -111,22 +113,28 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
111
113
|
orgLock;
|
|
112
114
|
installLock;
|
|
113
115
|
lifecycle;
|
|
114
|
-
|
|
116
|
+
outbox;
|
|
115
117
|
log;
|
|
116
118
|
txHost;
|
|
117
|
-
constructor(kdb, adminLock, catalog, pluginImport,
|
|
119
|
+
constructor(kdb, adminLock, catalog, pluginImport,
|
|
120
|
+
/** A confirmed first version's platform components (written in the confirming commit). */
|
|
121
|
+
platform,
|
|
122
|
+
/** The import's item name lock, taken by the confirming commit before the item row. */
|
|
123
|
+
itemLock, installer, extensions, ops, sync, updater,
|
|
118
124
|
/** The owner org's lock: an org admin withdrawing its pending upload (ruling P3-10). */
|
|
119
125
|
orgLock,
|
|
120
126
|
/** The per-name install lock a reject / withdraw releases the name claim under (M1). */
|
|
121
127
|
installLock,
|
|
122
128
|
/** This replica's reconcile once a confirmed extension is enabled (before the scope sync). */
|
|
123
129
|
lifecycle,
|
|
124
|
-
/**
|
|
125
|
-
|
|
130
|
+
/** Owes the scope syncs and the removed org plugin's cleanup (P3-21, pre-flight F9). */
|
|
131
|
+
outbox, log, txHost) {
|
|
126
132
|
this.kdb = kdb;
|
|
127
133
|
this.adminLock = adminLock;
|
|
128
134
|
this.catalog = catalog;
|
|
129
135
|
this.pluginImport = pluginImport;
|
|
136
|
+
this.platform = platform;
|
|
137
|
+
this.itemLock = itemLock;
|
|
130
138
|
this.installer = installer;
|
|
131
139
|
this.extensions = extensions;
|
|
132
140
|
this.ops = ops;
|
|
@@ -135,7 +143,7 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
135
143
|
this.orgLock = orgLock;
|
|
136
144
|
this.installLock = installLock;
|
|
137
145
|
this.lifecycle = lifecycle;
|
|
138
|
-
this.
|
|
146
|
+
this.outbox = outbox;
|
|
139
147
|
this.log = log;
|
|
140
148
|
this.txHost = txHost;
|
|
141
149
|
}
|
|
@@ -144,13 +152,13 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
144
152
|
}
|
|
145
153
|
/**
|
|
146
154
|
* Confirms a staged import ({@link PluginImport.confirm}: installs and enables the extension,
|
|
147
|
-
* writes the new item's scope), then
|
|
155
|
+
* writes the new item's scope), then owes the item's scope sync when its scope turns it on
|
|
148
156
|
* by itself (`all` or `named`; an `optional` item is on only where an org admin switches it on).
|
|
149
157
|
*/
|
|
150
158
|
async confirmImport(actor, stagingId, input, opts = {}) {
|
|
151
159
|
const r = await this.pluginImport.confirm(actor, stagingId, input, opts);
|
|
152
160
|
if (r.item.scope !== "optional")
|
|
153
|
-
await this.
|
|
161
|
+
await this.oweSync(r.item.id);
|
|
154
162
|
return r;
|
|
155
163
|
}
|
|
156
164
|
/**
|
|
@@ -177,6 +185,7 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
177
185
|
"owner_org_id",
|
|
178
186
|
"awaiting_confirmation",
|
|
179
187
|
"pending_version",
|
|
188
|
+
"scope",
|
|
180
189
|
])
|
|
181
190
|
.where("id", "=", itemId)
|
|
182
191
|
.where("deleted_at", "is", null)
|
|
@@ -223,10 +232,15 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
223
232
|
if (!disabled || !(e instanceof ApiError && e.code === "extension.not_pending"))
|
|
224
233
|
throw e;
|
|
225
234
|
}
|
|
235
|
+
// The permissions are confirmed (a stale hash refused above): the backstop before the enable
|
|
236
|
+
// (ruling R24), so a crash before the post-deploy add below still converges the orgs; only
|
|
237
|
+
// when the item's scope turns it on by itself, as the import's commit
|
|
238
|
+
if (item.scope !== "optional")
|
|
239
|
+
await this.oweBackstop(itemId);
|
|
226
240
|
// An occupied single-provider point leaves it installed disabled (the admin view says why)
|
|
227
241
|
if (disabled)
|
|
228
242
|
await this.ops.enableUnlessOccupied(item.name, actor, opts.actorTokenId);
|
|
229
|
-
await this.
|
|
243
|
+
await this.oweSync(itemId);
|
|
230
244
|
return (await this.catalog.get(itemId)).item;
|
|
231
245
|
}
|
|
232
246
|
/**
|
|
@@ -236,9 +250,10 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
236
250
|
* pending version (withdrawn, rejected, replaced by one without an extension) -> 409
|
|
237
251
|
* `extension.not_pending`.
|
|
238
252
|
*
|
|
239
|
-
* A first version: its
|
|
240
|
-
*
|
|
241
|
-
*
|
|
253
|
+
* A first version: its platform components planned and their files copied (keyed by content),
|
|
254
|
+
* its extension installed, its permissions approved, enabled, then (one transaction) the item
|
|
255
|
+
* stops waiting, its platform component rows are written and the owner is told
|
|
256
|
+
* (`upload_confirmed`); after the commit the scope sync is owed. Each step re-reads
|
|
242
257
|
* the item under its row lock: removed meanwhile -> 409 `catalog.item_removed`, the pending
|
|
243
258
|
* version replaced -> `extension.approval_stale`; the extension this confirmation installed is
|
|
244
259
|
* then taken out again. A new version: the platform update to it
|
|
@@ -255,14 +270,13 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
255
270
|
// (the enable does not wait for the reconcile); a sync on a replica that has not loaded it
|
|
256
271
|
// yet defers and retries (ruling P3-38)
|
|
257
272
|
await reconcileWithin(this.lifecycle, `confirmed:${item.name}`, CONFIRM_RECONCILE_WAIT_MS, this.log);
|
|
258
|
-
await this.
|
|
259
|
-
await this.enqueue(item.id);
|
|
273
|
+
await this.oweSync(item.id);
|
|
260
274
|
}
|
|
261
275
|
return (await this.catalog.get(item.id)).item;
|
|
262
276
|
}
|
|
263
277
|
/**
|
|
264
|
-
* {@link confirmOrgUpload} under the item lock; returns the confirmed first version (its
|
|
265
|
-
*
|
|
278
|
+
* {@link confirmOrgUpload} under the item lock; returns the confirmed first version (its scope
|
|
279
|
+
* sync follows after), null for a new version.
|
|
266
280
|
*/
|
|
267
281
|
async confirmLocked(actor, itemId, name, permissionsHash, opts) {
|
|
268
282
|
// Read again under the lock (the caller's read was outside it)
|
|
@@ -358,6 +372,8 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
358
372
|
await this.stillPending(itemId, name, version);
|
|
359
373
|
let installedHere = false;
|
|
360
374
|
try {
|
|
375
|
+
// Planned and copied before any transaction; the rows are written by the confirming commit
|
|
376
|
+
const components = await this.platform.prepareSync(itemId, version, { confirming: true });
|
|
361
377
|
if (install?.sha256 !== sha) {
|
|
362
378
|
await this.ops.install(name, sha, actor, opts.actorTokenId, {
|
|
363
379
|
catalogItemId: itemId,
|
|
@@ -370,7 +386,7 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
370
386
|
await this.stillPending(itemId, name, version);
|
|
371
387
|
// An occupied single-provider point leaves it installed disabled (the admin view says why)
|
|
372
388
|
await this.ops.enableUnlessOccupied(name, actor, opts.actorTokenId);
|
|
373
|
-
await this.finishFirstVersion(actor, itemId, version, opts);
|
|
389
|
+
await this.finishFirstVersion(actor, itemId, version, components, opts);
|
|
374
390
|
}
|
|
375
391
|
catch (e) {
|
|
376
392
|
// Taken out only when this confirmation did not win: the item gone or still waiting
|
|
@@ -466,47 +482,62 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
466
482
|
/**
|
|
467
483
|
* An extension a confirmation installed whose item was removed or replaced meanwhile is taken
|
|
468
484
|
* out again (disabled, uninstalled; P3-21), and the name claim released when the item is gone
|
|
469
|
-
* (ruling P3-37)
|
|
470
|
-
* (`owned-plugin-cleanup-<itemId>`, idempotent) is
|
|
471
|
-
*
|
|
485
|
+
* (ruling P3-37), in one transaction ({@link takeOutIn}). Inline (a failure is logged): when the
|
|
486
|
+
* take-out fails, a removed item's cleanup job (`owned-plugin-cleanup-<itemId>`, idempotent) is
|
|
487
|
+
* owed instead, so the job retries it (pre-flight F9). That owe is the last resort: when it
|
|
488
|
+
* fails too (PG unavailable) nothing retries the take-out, and it is logged as an error.
|
|
472
489
|
*/
|
|
473
490
|
async takeOut(itemId, name, actor, opts) {
|
|
474
491
|
try {
|
|
475
|
-
await this.
|
|
476
|
-
|
|
477
|
-
await this.releaseIfGone(itemId, name);
|
|
492
|
+
await this.takeOutIn(itemId, name, actor, opts);
|
|
493
|
+
return;
|
|
478
494
|
}
|
|
479
495
|
catch (err) {
|
|
480
496
|
this.log.error("taking out the extension of a removed org upload failed", { name, err });
|
|
481
497
|
}
|
|
482
|
-
const gone = await this.db
|
|
483
|
-
.selectFrom("catalog_items")
|
|
484
|
-
.select("id")
|
|
485
|
-
.where("id", "=", itemId)
|
|
486
|
-
.where("deleted_at", "is not", null)
|
|
487
|
-
.executeTakeFirst();
|
|
488
|
-
if (gone === undefined)
|
|
489
|
-
return;
|
|
490
|
-
const job = ownedPluginCleanupJob(itemId);
|
|
491
498
|
try {
|
|
492
|
-
await this.
|
|
499
|
+
await this.oweCleanupIfGone(itemId);
|
|
493
500
|
}
|
|
494
501
|
catch (err) {
|
|
495
|
-
this.log.
|
|
502
|
+
this.log.error("owing the owned plugin cleanup failed; the take-out is not retried", {
|
|
503
|
+
itemId,
|
|
504
|
+
err,
|
|
505
|
+
});
|
|
496
506
|
}
|
|
497
507
|
}
|
|
498
|
-
/**
|
|
499
|
-
|
|
508
|
+
/**
|
|
509
|
+
* {@link takeOut}'s transaction, in the global lock order (ruling P3-50): the super admin lock,
|
|
510
|
+
* the item row, then the extension's install lock (taken by the disable): disabled,
|
|
511
|
+
* uninstalled, and the name claim released when the item is gone.
|
|
512
|
+
*/
|
|
513
|
+
async takeOutIn(itemId, name, actor, opts) {
|
|
514
|
+
await this.adminLock.lockAndAuthorize(actor);
|
|
500
515
|
const row = await this.db
|
|
501
516
|
.selectFrom("catalog_items")
|
|
502
517
|
.select(["deleted_at", "package_name"])
|
|
503
518
|
.where("id", "=", itemId)
|
|
504
519
|
.forUpdate()
|
|
505
520
|
.executeTakeFirst();
|
|
521
|
+
await this.ops.disable(name, actor, opts.actorTokenId);
|
|
522
|
+
await this.ops.uninstall(name, actor, opts.actorTokenId);
|
|
506
523
|
if (row === undefined || row.deleted_at !== null) {
|
|
507
524
|
await releaseExtensionClaim(this.db, name, row?.package_name ?? null);
|
|
508
525
|
}
|
|
509
526
|
}
|
|
527
|
+
/**
|
|
528
|
+
* Owes the cleanup of a removed item; a live item owes nothing (a removal committing later owes
|
|
529
|
+
* its own).
|
|
530
|
+
*/
|
|
531
|
+
async oweCleanupIfGone(itemId) {
|
|
532
|
+
const gone = await this.db
|
|
533
|
+
.selectFrom("catalog_items")
|
|
534
|
+
.select("id")
|
|
535
|
+
.where("id", "=", itemId)
|
|
536
|
+
.where("deleted_at", "is not", null)
|
|
537
|
+
.executeTakeFirst();
|
|
538
|
+
if (gone !== undefined)
|
|
539
|
+
await oweOwnedPluginCleanup(this.outbox, itemId);
|
|
540
|
+
}
|
|
510
541
|
/** The item is still live and pending with `version` (row lock), else 409 (P3-21). */
|
|
511
542
|
async stillPending(itemId, name, version) {
|
|
512
543
|
await this.pendingRow(itemId, name, version);
|
|
@@ -526,14 +557,20 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
526
557
|
throw pendingStale(name);
|
|
527
558
|
return row.owner_org_id;
|
|
528
559
|
}
|
|
529
|
-
/**
|
|
530
|
-
|
|
560
|
+
/**
|
|
561
|
+
* A confirmed first version: the item stops waiting, its platform component rows are written
|
|
562
|
+
* from `components` (a component changed since they were planned -> 409
|
|
563
|
+
* `extension.approval_stale`: confirm again), the owner is told (`upload_confirmed`). The
|
|
564
|
+
* import's item name lock before the item row, as an import's commit takes them (ruling P3-50).
|
|
565
|
+
*/
|
|
566
|
+
async finishFirstVersion(actor, itemId, version, components, opts) {
|
|
531
567
|
await this.adminLock.lockAndAuthorize(actor);
|
|
532
568
|
const named = await this.db
|
|
533
569
|
.selectFrom("catalog_items")
|
|
534
570
|
.select("name")
|
|
535
571
|
.where("id", "=", itemId)
|
|
536
572
|
.executeTakeFirstOrThrow();
|
|
573
|
+
await this.itemLock.lock(named.name);
|
|
537
574
|
const owner = await this.pendingRow(itemId, named.name, version);
|
|
538
575
|
await this.db
|
|
539
576
|
.updateTable("catalog_items")
|
|
@@ -549,6 +586,14 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
549
586
|
.where("id", "=", itemId)
|
|
550
587
|
.execute();
|
|
551
588
|
await markVersionApplied(this.db, itemId, version);
|
|
589
|
+
try {
|
|
590
|
+
await this.platform.applySyncIn(components);
|
|
591
|
+
}
|
|
592
|
+
catch (e) {
|
|
593
|
+
if (e instanceof PlanStale)
|
|
594
|
+
throw pendingStale(named.name);
|
|
595
|
+
throw e;
|
|
596
|
+
}
|
|
552
597
|
await addOrgNotice(this.db, owner, "upload_confirmed", {
|
|
553
598
|
itemId,
|
|
554
599
|
name: named.name,
|
|
@@ -562,6 +607,9 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
562
607
|
target: itemId,
|
|
563
608
|
detail: { name: named.name, version, ownerOrgId: owner },
|
|
564
609
|
});
|
|
610
|
+
// The confirmation's commit owes the sync's backstop (ruling R24); the immediate sync follows
|
|
611
|
+
// the commit
|
|
612
|
+
await this.sync.enqueueBackstop(itemId);
|
|
565
613
|
}
|
|
566
614
|
/**
|
|
567
615
|
* The super admin rejects an org upload's pending version (ruling P3-10, `reason` shown to the
|
|
@@ -781,7 +829,7 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
781
829
|
...opts.auditDetail,
|
|
782
830
|
},
|
|
783
831
|
});
|
|
784
|
-
|
|
832
|
+
await this.enqueue(itemId);
|
|
785
833
|
}
|
|
786
834
|
async writeDisabled(actor, itemId, disabled, hash, opts) {
|
|
787
835
|
await this.adminLock.lockAndAuthorize(actor);
|
|
@@ -817,13 +865,13 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
817
865
|
...opts.auditDetail,
|
|
818
866
|
},
|
|
819
867
|
});
|
|
820
|
-
|
|
868
|
+
await this.enqueue(itemId);
|
|
821
869
|
}
|
|
822
870
|
/**
|
|
823
871
|
* Writes an org-owned plugin's 可共享 flag and copies it to its component rows (ruling P3-2).
|
|
824
872
|
* Turning it off narrows an `optional` / `all` plugin, and each component with its own such
|
|
825
|
-
* scope, to the owner plus the orgs where it is on now (ruling P3-25), and
|
|
826
|
-
* scope sync
|
|
873
|
+
* scope, to the owner plus the orgs where it is on now (ruling P3-25), and owes the item's
|
|
874
|
+
* scope sync with it. The caller authorizes (the owner org's admin, Task 7). A platform
|
|
827
875
|
* item (no owner) or a missing one -> 404.
|
|
828
876
|
*/
|
|
829
877
|
async setShareable(itemId, shareable, actor = null) {
|
|
@@ -865,13 +913,13 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
865
913
|
}
|
|
866
914
|
}
|
|
867
915
|
if (narrowed)
|
|
868
|
-
|
|
916
|
+
await this.enqueue(itemId);
|
|
869
917
|
}
|
|
870
918
|
/**
|
|
871
919
|
* Adds one org to a `named` item's list in the caller's transaction (an approved `access`
|
|
872
920
|
* request, spec §5.1 rule 2): nobody loses access, so no preview. The item row is locked; it
|
|
873
921
|
* must be live and not builtin (404 / `plugin.builtin`). Bumps `scope_version`, audits
|
|
874
|
-
* `catalog.scope_changed` and
|
|
922
|
+
* `catalog.scope_changed` and owes the item's scope sync in that transaction. Returns whether
|
|
875
923
|
* the list changed (false: not `named`, or listed already).
|
|
876
924
|
*/
|
|
877
925
|
async addOrg(actor, itemId, orgId, opts = {}) {
|
|
@@ -879,24 +927,34 @@ let CatalogScopeService = class CatalogScopeService {
|
|
|
879
927
|
assertNotAwaiting(item);
|
|
880
928
|
const changed = await addScopeOrg(this.db, actor, item, orgId, opts);
|
|
881
929
|
if (changed)
|
|
882
|
-
|
|
930
|
+
await this.enqueue(itemId);
|
|
883
931
|
return changed;
|
|
884
932
|
}
|
|
885
933
|
/**
|
|
886
|
-
*
|
|
887
|
-
* `OrgPluginUploads`)
|
|
934
|
+
* Owes the item's scope sync in the caller's transaction (an ownership transfer, an org upload's
|
|
935
|
+
* confirm in `OrgPluginUploads`).
|
|
888
936
|
*/
|
|
889
937
|
async enqueueSync(itemId) {
|
|
890
938
|
await this.enqueue(itemId);
|
|
891
939
|
}
|
|
892
|
-
/**
|
|
940
|
+
/** Owes the item's scope sync in the transaction that changes its scope (outbox spec §8.1). */
|
|
893
941
|
async enqueue(itemId) {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
942
|
+
await this.sync.enqueueItem(itemId);
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Owes the item's scope sync in a transaction of its own, after a confirmation whose last write
|
|
946
|
+
* (the extension's deploy, or the platform components) committed outside the scope service: the
|
|
947
|
+
* sync must not run before the extension it installs is enabled.
|
|
948
|
+
*/
|
|
949
|
+
async oweSync(itemId) {
|
|
950
|
+
await this.enqueue(itemId);
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Owes the delayed backstop of the item's sync in a transaction of its own (ruling R24): a
|
|
954
|
+
* permissions confirm writes nothing of the scope service's before its enable.
|
|
955
|
+
*/
|
|
956
|
+
async oweBackstop(itemId) {
|
|
957
|
+
await this.sync.enqueueBackstop(itemId);
|
|
900
958
|
}
|
|
901
959
|
/**
|
|
902
960
|
* 409 `theme.platform_default` when a live theme of the item is the platform default and `after`
|
|
@@ -1190,7 +1248,10 @@ __decorate([
|
|
|
1190
1248
|
], CatalogScopeService.prototype, "restorePending", null);
|
|
1191
1249
|
__decorate([
|
|
1192
1250
|
Transactional()
|
|
1193
|
-
], CatalogScopeService.prototype, "
|
|
1251
|
+
], CatalogScopeService.prototype, "takeOutIn", null);
|
|
1252
|
+
__decorate([
|
|
1253
|
+
Transactional()
|
|
1254
|
+
], CatalogScopeService.prototype, "oweCleanupIfGone", null);
|
|
1194
1255
|
__decorate([
|
|
1195
1256
|
Transactional()
|
|
1196
1257
|
], CatalogScopeService.prototype, "stillPending", null);
|
|
@@ -1215,22 +1276,36 @@ __decorate([
|
|
|
1215
1276
|
__decorate([
|
|
1216
1277
|
Transactional({ propagation: "mandatory" })
|
|
1217
1278
|
], CatalogScopeService.prototype, "addOrg", null);
|
|
1279
|
+
__decorate([
|
|
1280
|
+
Transactional({ propagation: "mandatory" })
|
|
1281
|
+
], CatalogScopeService.prototype, "enqueueSync", null);
|
|
1282
|
+
__decorate([
|
|
1283
|
+
Transactional({ propagation: "mandatory" })
|
|
1284
|
+
], CatalogScopeService.prototype, "enqueue", null);
|
|
1285
|
+
__decorate([
|
|
1286
|
+
Transactional()
|
|
1287
|
+
], CatalogScopeService.prototype, "oweSync", null);
|
|
1288
|
+
__decorate([
|
|
1289
|
+
Transactional()
|
|
1290
|
+
], CatalogScopeService.prototype, "oweBackstop", null);
|
|
1218
1291
|
CatalogScopeService = __decorate([
|
|
1219
1292
|
Injectable(),
|
|
1220
1293
|
__param(0, Inject(KernelDb)),
|
|
1221
1294
|
__param(1, Inject(SuperAdminLock)),
|
|
1222
1295
|
__param(2, Inject(CatalogService)),
|
|
1223
1296
|
__param(3, Inject(PluginImport)),
|
|
1224
|
-
__param(4, Inject(
|
|
1225
|
-
__param(5, Inject(
|
|
1226
|
-
__param(6, Inject(
|
|
1227
|
-
__param(7, Inject(
|
|
1228
|
-
__param(8, Inject(
|
|
1229
|
-
__param(9, Inject(
|
|
1230
|
-
__param(10, Inject(
|
|
1231
|
-
__param(11, Inject(
|
|
1232
|
-
__param(12, Inject(
|
|
1233
|
-
__param(13, Inject(
|
|
1234
|
-
__param(14, Inject(
|
|
1297
|
+
__param(4, Inject(PlatformComponents)),
|
|
1298
|
+
__param(5, Inject(CatalogItemLock)),
|
|
1299
|
+
__param(6, Inject(PluginInstaller)),
|
|
1300
|
+
__param(7, Inject(ExtensionAdmin)),
|
|
1301
|
+
__param(8, Inject(ExtensionAdminOps)),
|
|
1302
|
+
__param(9, Inject(PluginScopeSync)),
|
|
1303
|
+
__param(10, Inject(PlatformPluginUpdater)),
|
|
1304
|
+
__param(11, Inject(OrgLock)),
|
|
1305
|
+
__param(12, Inject(PluginInstallLock)),
|
|
1306
|
+
__param(13, Inject(ExtensionLifecycle)),
|
|
1307
|
+
__param(14, Inject(OutboxService)),
|
|
1308
|
+
__param(15, Inject(KERNEL_LOGGER)),
|
|
1309
|
+
__param(16, Inject(TransactionHost))
|
|
1235
1310
|
], CatalogScopeService);
|
|
1236
1311
|
export { CatalogScopeService };
|
|
@@ -54,10 +54,11 @@ CatalogModule = __decorate([
|
|
|
54
54
|
StorageModule,
|
|
55
55
|
SkillsModule,
|
|
56
56
|
ToolsModule,
|
|
57
|
-
// the
|
|
57
|
+
// the plugin scope sync's queue: the outbox dispatcher adds the owed jobs through it
|
|
58
|
+
// (`PluginScopeWorkersModule` consumes it)
|
|
58
59
|
PLUGIN_SCOPE_QUEUE_MODULE,
|
|
59
|
-
// a removed org plugin's cleanup job (`OwnedItems`, `CatalogScopeService`;
|
|
60
|
-
// worker role's `MaintenanceProcessor`)
|
|
60
|
+
// the queue of a removed org plugin's owed cleanup job (`OwnedItems`, `CatalogScopeService`;
|
|
61
|
+
// consumed by the worker role's `MaintenanceProcessor`)
|
|
61
62
|
MAINTENANCE_QUEUE_MODULE,
|
|
62
63
|
],
|
|
63
64
|
providers: [
|
|
@@ -7,6 +7,7 @@ import { SuperAdminLock } from "../identity/super-admin.js";
|
|
|
7
7
|
import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
8
8
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
9
9
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
10
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
10
11
|
import type { TranslationReport } from "./claude/report.js";
|
|
11
12
|
import { MarketplacesService } from "./marketplaces.service.js";
|
|
12
13
|
import { type Owner } from "./ownership.js";
|
|
@@ -242,6 +243,8 @@ export declare class CatalogService {
|
|
|
242
243
|
private readonly marketplaces;
|
|
243
244
|
/** Serializes a claim release with an install of that name still committing (F10). */
|
|
244
245
|
private readonly installLock;
|
|
246
|
+
/** A removed org-owned plugin's cleanup job, owed by the removal (transactional outbox §8.1). */
|
|
247
|
+
private readonly outbox;
|
|
245
248
|
readonly txHost: TransactionHost;
|
|
246
249
|
constructor(kdb: KernelDb,
|
|
247
250
|
/** The super admin lock (identity/super-admin.ts): joins the caller's transaction. */
|
|
@@ -253,7 +256,9 @@ export declare class CatalogService {
|
|
|
253
256
|
/** The token of a custom marketplace (sent only to its URL's origin). */
|
|
254
257
|
marketplaces: MarketplacesService,
|
|
255
258
|
/** Serializes a claim release with an install of that name still committing (F10). */
|
|
256
|
-
installLock: PluginInstallLock,
|
|
259
|
+
installLock: PluginInstallLock,
|
|
260
|
+
/** A removed org-owned plugin's cleanup job, owed by the removal (transactional outbox §8.1). */
|
|
261
|
+
outbox: Pick<OutboxService, "add">, txHost: TransactionHost);
|
|
257
262
|
/** The kernel-schema handle of the current context (the transaction, else the pool). */
|
|
258
263
|
private get db();
|
|
259
264
|
/** Downloads a marketplace archive source, verified against its integrity. */
|
|
@@ -335,7 +340,8 @@ export declare class CatalogService {
|
|
|
335
340
|
* still enabled on the deployment -> 409 `catalog.extension_enabled` (details
|
|
336
341
|
* `[{ extension, displayName }]`): disable it on the Extensions page first, as an uninstall
|
|
337
342
|
* requires. A disabled extension keeps its install record (the super admin uninstalls it on the
|
|
338
|
-
* Extensions page); an org-owned item's extension is taken out by `OwnedPluginCleanup
|
|
343
|
+
* Extensions page); an org-owned item's extension is taken out by `OwnedPluginCleanup`, the job
|
|
344
|
+
* the removal owes ({@link removeIn}).
|
|
339
345
|
*/
|
|
340
346
|
remove(actor: string, itemId: string, opts?: ActorOpts): Promise<void>;
|
|
341
347
|
/**
|
|
@@ -356,8 +362,9 @@ export declare class CatalogService {
|
|
|
356
362
|
* `OwnedItems.transferOrRemove`, share it): `deleted_at` set, a pending version cleared, the
|
|
357
363
|
* extension name claim of a first upload still waiting released (ruling P3-37, F10), its themes
|
|
358
364
|
* soft-deleted (refused with 409 `theme.platform_default` while one is the platform default),
|
|
359
|
-
* pending requests cancelled,
|
|
360
|
-
*
|
|
365
|
+
* pending requests cancelled, an org-owned item's cleanup job owed
|
|
366
|
+
* (`owned-plugin-cleanup-<itemId>`), audit `catalog.removed` (`actor` null: the kernel). Returns
|
|
367
|
+
* the removed item's name, or null when it is gone already.
|
|
361
368
|
*/
|
|
362
369
|
removeIn(actor: string | null, itemId: string, opts?: ActorOpts & {
|
|
363
370
|
reason?: string;
|
|
@@ -20,10 +20,12 @@ import { KernelConfigService } from "../infra/config/kernel-config.service.js";
|
|
|
20
20
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
21
21
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
22
22
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
23
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
23
24
|
import { sameRepository } from "../packages/provenance.js";
|
|
24
25
|
import { assertNotPlatformDefault } from "../themes/theme-usage.js";
|
|
25
26
|
import { countInstalls, inAuthorOrder, itemConfirmations, itemScopeFacts, itemView, marketplaceLatest, versionUsable, } from "./catalog-items.js";
|
|
26
27
|
import { expandGitUrl, GitSourceError, gitErrorDetails, normalGitPath, readGitTreeAndOids, resolveGitCommit, } from "./git-source.js";
|
|
28
|
+
import { oweOwnedPluginCleanup } from "./job-ids.js";
|
|
27
29
|
import { fetchMarketplaceArchive, marketplaceNetPolicy, marketplaceUrlProblem, } from "./marketplace-fetch.js";
|
|
28
30
|
import { assertEntryNotDeprecated, entryCompatible, entrySourceHost, HOST_VERSIONS, hostAllowed, loadMarketplaceEntry, MarketplacesService, pluginNameFrom, } from "./marketplaces.service.js";
|
|
29
31
|
import { releaseExtensionClaim } from "./ownership.js";
|
|
@@ -95,6 +97,7 @@ let CatalogService = class CatalogService {
|
|
|
95
97
|
pluginImport;
|
|
96
98
|
marketplaces;
|
|
97
99
|
installLock;
|
|
100
|
+
outbox;
|
|
98
101
|
txHost;
|
|
99
102
|
constructor(kdb,
|
|
100
103
|
/** The super admin lock (identity/super-admin.ts): joins the caller's transaction. */
|
|
@@ -106,7 +109,9 @@ let CatalogService = class CatalogService {
|
|
|
106
109
|
/** The token of a custom marketplace (sent only to its URL's origin). */
|
|
107
110
|
marketplaces,
|
|
108
111
|
/** Serializes a claim release with an install of that name still committing (F10). */
|
|
109
|
-
installLock,
|
|
112
|
+
installLock,
|
|
113
|
+
/** A removed org-owned plugin's cleanup job, owed by the removal (transactional outbox §8.1). */
|
|
114
|
+
outbox, txHost) {
|
|
110
115
|
this.kdb = kdb;
|
|
111
116
|
this.adminLock = adminLock;
|
|
112
117
|
this.config = config;
|
|
@@ -115,6 +120,7 @@ let CatalogService = class CatalogService {
|
|
|
115
120
|
this.pluginImport = pluginImport;
|
|
116
121
|
this.marketplaces = marketplaces;
|
|
117
122
|
this.installLock = installLock;
|
|
123
|
+
this.outbox = outbox;
|
|
118
124
|
this.txHost = txHost;
|
|
119
125
|
}
|
|
120
126
|
/** The kernel-schema handle of the current context (the transaction, else the pool). */
|
|
@@ -469,7 +475,8 @@ let CatalogService = class CatalogService {
|
|
|
469
475
|
* still enabled on the deployment -> 409 `catalog.extension_enabled` (details
|
|
470
476
|
* `[{ extension, displayName }]`): disable it on the Extensions page first, as an uninstall
|
|
471
477
|
* requires. A disabled extension keeps its install record (the super admin uninstalls it on the
|
|
472
|
-
* Extensions page); an org-owned item's extension is taken out by `OwnedPluginCleanup
|
|
478
|
+
* Extensions page); an org-owned item's extension is taken out by `OwnedPluginCleanup`, the job
|
|
479
|
+
* the removal owes ({@link removeIn}).
|
|
473
480
|
*/
|
|
474
481
|
async remove(actor, itemId, opts = {}) {
|
|
475
482
|
if (!UUID_RE.test(itemId))
|
|
@@ -533,8 +540,9 @@ let CatalogService = class CatalogService {
|
|
|
533
540
|
* `OwnedItems.transferOrRemove`, share it): `deleted_at` set, a pending version cleared, the
|
|
534
541
|
* extension name claim of a first upload still waiting released (ruling P3-37, F10), its themes
|
|
535
542
|
* soft-deleted (refused with 409 `theme.platform_default` while one is the platform default),
|
|
536
|
-
* pending requests cancelled,
|
|
537
|
-
*
|
|
543
|
+
* pending requests cancelled, an org-owned item's cleanup job owed
|
|
544
|
+
* (`owned-plugin-cleanup-<itemId>`), audit `catalog.removed` (`actor` null: the kernel). Returns
|
|
545
|
+
* the removed item's name, or null when it is gone already.
|
|
538
546
|
*/
|
|
539
547
|
async removeIn(actor, itemId, opts = {}) {
|
|
540
548
|
const t = this.db;
|
|
@@ -572,6 +580,13 @@ let CatalogService = class CatalogService {
|
|
|
572
580
|
await this.installLock.lock(row.name);
|
|
573
581
|
await releaseExtensionClaim(t, row.name, row.package_name);
|
|
574
582
|
}
|
|
583
|
+
// An org-owned plugin: its extension is taken out (and its name claim released) by the cleanup
|
|
584
|
+
// job the removal owes, whoever removes it (the super admin, its owner, an org deletion). Also
|
|
585
|
+
// while its first upload still waits: a confirmation may have committed its install and not
|
|
586
|
+
// reached its take-out yet (the job is idempotent; nothing installed changes nothing)
|
|
587
|
+
if (row.owner_org_id !== null) {
|
|
588
|
+
await oweOwnedPluginCleanup(this.outbox, itemId);
|
|
589
|
+
}
|
|
575
590
|
// Its themes go with it (themes spec §6): nothing refers to a theme row (a theme picked by an
|
|
576
591
|
// org or a person is an id that falls back once no live theme has it)
|
|
577
592
|
await t
|
|
@@ -615,6 +630,7 @@ CatalogService = __decorate([
|
|
|
615
630
|
__param(5, Inject(PluginImport)),
|
|
616
631
|
__param(6, Inject(MarketplacesService)),
|
|
617
632
|
__param(7, Inject(PluginInstallLock)),
|
|
618
|
-
__param(8, Inject(
|
|
633
|
+
__param(8, Inject(OutboxService)),
|
|
634
|
+
__param(9, Inject(TransactionHost))
|
|
619
635
|
], CatalogService);
|
|
620
636
|
export { CatalogService };
|
package/dist/catalog/cli.d.ts
CHANGED
|
@@ -11,9 +11,10 @@ export interface CatalogCli extends ExtensionCli {
|
|
|
11
11
|
/** Plugin import (prepare / confirm). The CLI acts without an account (actor `null`). */
|
|
12
12
|
imports: PluginImport;
|
|
13
13
|
/**
|
|
14
|
-
* After an import's confirm:
|
|
15
|
-
* confirm does, when its scope turns it on by itself (`all` or `named`)
|
|
16
|
-
*
|
|
14
|
+
* After an import's confirm (and its deploy): owes the item's plugin scope sync in the outbox, as
|
|
15
|
+
* the admin console's confirm does, when its scope turns it on by itself (`all` or `named`); a
|
|
16
|
+
* worker's relay delivers it. A failure only warns (the confirm's commit owed a backstop that
|
|
17
|
+
* converges the orgs a few minutes later); returns whether it was owed.
|
|
17
18
|
*/
|
|
18
19
|
enqueueScopeSync(item: {
|
|
19
20
|
id: string;
|