@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
package/dist/catalog/cli.js
CHANGED
|
@@ -10,14 +10,14 @@ import { assertSecretsReachable } from "../extensions/host.js";
|
|
|
10
10
|
import { importExtensionModule, matchesSection } from "../extensions/instance.js";
|
|
11
11
|
import { packageRootOf, syncPackage } from "../extensions/sync.js";
|
|
12
12
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
14
|
+
import { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
15
15
|
import { packagePath } from "../packages/tgz.js";
|
|
16
16
|
import { PrefixedStorage } from "../storage/storage.service.js";
|
|
17
17
|
import { CatalogImportModule } from "./catalog.module.js";
|
|
18
18
|
import { CatalogService } from "./catalog.service.js";
|
|
19
19
|
import { PluginImport } from "./plugin-import.js";
|
|
20
|
-
import {
|
|
20
|
+
import { oweScopeItem } from "./scope-jobs.js";
|
|
21
21
|
/**
|
|
22
22
|
* Sets up the deployment's object-store extension inside the CLI process. The CLI hosts no
|
|
23
23
|
* extensions, so this runs only the provider's `setup` with a context that offers `config` and
|
|
@@ -183,7 +183,8 @@ export async function openCatalogCli(config, log, opts = {}) {
|
|
|
183
183
|
cli.app.get(ClientBuilds).useCliStorage(storage);
|
|
184
184
|
const catalog = cli.app.get(CatalogService);
|
|
185
185
|
const db = cli.app.get(KernelDb);
|
|
186
|
-
const
|
|
186
|
+
const txHost = cli.app.get(TransactionHost);
|
|
187
|
+
const outbox = cli.app.get(OutboxService);
|
|
187
188
|
return {
|
|
188
189
|
...cli,
|
|
189
190
|
catalog,
|
|
@@ -192,18 +193,12 @@ export async function openCatalogCli(config, log, opts = {}) {
|
|
|
192
193
|
if (item.scope === "optional")
|
|
193
194
|
return false;
|
|
194
195
|
try {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
.select("scope_version")
|
|
198
|
-
.where("id", "=", item.id)
|
|
199
|
-
.executeTakeFirst();
|
|
200
|
-
if (!row)
|
|
201
|
-
return false;
|
|
202
|
-
await addJobOnce(redis, PLUGIN_SCOPE_QUEUE, scopeItemJob(item.id, row.scope_version));
|
|
196
|
+
// owed in a transaction of its own after the deploy; a worker's relay delivers it
|
|
197
|
+
await txHost.run(() => oweScopeItem(outbox, db.db, item.id));
|
|
203
198
|
return true;
|
|
204
199
|
}
|
|
205
200
|
catch (err) {
|
|
206
|
-
log.warn("cannot
|
|
201
|
+
log.warn("cannot owe the plugin scope sync; the import's backstop converges the orgs in a few minutes", { itemId: item.id, err });
|
|
207
202
|
return false;
|
|
208
203
|
}
|
|
209
204
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import type { OutboxService } from "../infra/outbox/outbox.service.js";
|
|
2
|
+
/** The catalog's job names and ids (a leaf module: type imports only). */
|
|
2
3
|
/**
|
|
3
4
|
* Periodic marketplace refresh (C26), every `marketplaces.refreshIntervalMinutes` (a
|
|
4
5
|
* `@LockedInterval`, once per tick across replicas): refreshes each enabled marketplace in turn.
|
|
@@ -18,28 +19,15 @@ export declare const PLUGIN_STAGING_CLEANUP_SCHEDULER_ID = "app-staging-cleanup-
|
|
|
18
19
|
* P3-21; `OwnedPluginCleanup.run`), on `cap-kernel-maintenance`.
|
|
19
20
|
*/
|
|
20
21
|
export declare const OWNED_PLUGIN_CLEANUP_JOB = "owned-plugin-cleanup";
|
|
21
|
-
/** The daily `@LockedCron` repairing lost {@link OWNED_PLUGIN_CLEANUP_JOB} enqueues. */
|
|
22
|
-
export declare const OWNED_PLUGIN_CLEANUP_SWEEP_JOB = "owned-plugin-cleanup-sweep";
|
|
23
22
|
/** The data of an {@link OWNED_PLUGIN_CLEANUP_JOB}. */
|
|
24
23
|
export interface OwnedPluginCleanupData {
|
|
25
24
|
itemId: string;
|
|
26
25
|
}
|
|
26
|
+
/** The cleanup job id of one removed item (no `:`: item ids are UUIDs). */
|
|
27
|
+
export declare const ownedPluginCleanupJobId: (itemId: string) => string;
|
|
27
28
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
29
|
+
* Owes the cleanup of removed item `itemId` in the transaction in context (transactional outbox
|
|
30
|
+
* spec §8.1): the removal and its cleanup commit together. Platform work (no org: the owner org
|
|
31
|
+
* may be the one being deleted). The job's options are its outbox registry entry's.
|
|
31
32
|
*/
|
|
32
|
-
export declare function
|
|
33
|
-
name: string;
|
|
34
|
-
data: OwnedPluginCleanupData;
|
|
35
|
-
opts: {
|
|
36
|
-
jobId: string;
|
|
37
|
-
attempts: number;
|
|
38
|
-
backoff: {
|
|
39
|
-
type: "exponential";
|
|
40
|
-
delay: number;
|
|
41
|
-
};
|
|
42
|
-
removeOnComplete: true;
|
|
43
|
-
removeOnFail: true;
|
|
44
|
-
};
|
|
45
|
-
};
|
|
33
|
+
export declare function oweOwnedPluginCleanup(outbox: Pick<OutboxService, "add">, itemId: string): Promise<boolean>;
|
package/dist/catalog/job-ids.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** The catalog's
|
|
1
|
+
/** The catalog's job names and ids (a leaf module: type imports only). */
|
|
2
2
|
/**
|
|
3
3
|
* Periodic marketplace refresh (C26), every `marketplaces.refreshIntervalMinutes` (a
|
|
4
4
|
* `@LockedInterval`, once per tick across replicas): refreshes each enabled marketplace in turn.
|
|
@@ -18,23 +18,18 @@ export const PLUGIN_STAGING_CLEANUP_SCHEDULER_ID = "app-staging-cleanup-hourly";
|
|
|
18
18
|
* P3-21; `OwnedPluginCleanup.run`), on `cap-kernel-maintenance`.
|
|
19
19
|
*/
|
|
20
20
|
export const OWNED_PLUGIN_CLEANUP_JOB = "owned-plugin-cleanup";
|
|
21
|
-
/** The
|
|
22
|
-
export const
|
|
21
|
+
/** The cleanup job id of one removed item (no `:`: item ids are UUIDs). */
|
|
22
|
+
export const ownedPluginCleanupJobId = (itemId) => `${OWNED_PLUGIN_CLEANUP_JOB}-${itemId}`;
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* Owes the cleanup of removed item `itemId` in the transaction in context (transactional outbox
|
|
25
|
+
* spec §8.1): the removal and its cleanup commit together. Platform work (no org: the owner org
|
|
26
|
+
* may be the one being deleted). The job's options are its outbox registry entry's.
|
|
27
27
|
*/
|
|
28
|
-
export function
|
|
29
|
-
return {
|
|
28
|
+
export function oweOwnedPluginCleanup(outbox, itemId) {
|
|
29
|
+
return outbox.add({
|
|
30
|
+
queue: "cap-kernel-maintenance",
|
|
30
31
|
name: OWNED_PLUGIN_CLEANUP_JOB,
|
|
32
|
+
jobId: ownedPluginCleanupJobId(itemId),
|
|
31
33
|
data: { itemId },
|
|
32
|
-
|
|
33
|
-
jobId: `${OWNED_PLUGIN_CLEANUP_JOB}-${itemId}`,
|
|
34
|
-
attempts: 3,
|
|
35
|
-
backoff: { type: "exponential", delay: 5_000 },
|
|
36
|
-
removeOnComplete: true,
|
|
37
|
-
removeOnFail: true,
|
|
38
|
-
},
|
|
39
|
-
};
|
|
34
|
+
});
|
|
40
35
|
}
|
|
@@ -188,7 +188,7 @@ export declare function headsToResolve(entries: readonly MarketplaceEntry[], imp
|
|
|
188
188
|
/** The host versions (an entry's `minKernel` is judged against them). */
|
|
189
189
|
export declare const HOST_VERSIONS: {
|
|
190
190
|
readonly kernel: string;
|
|
191
|
-
readonly sdk: "0.1.0-rc.
|
|
191
|
+
readonly sdk: "0.1.0-rc.20";
|
|
192
192
|
};
|
|
193
193
|
/** Whether this deployment satisfies the entry's `minKernel`. */
|
|
194
194
|
export declare const entryCompatible: (e: Pick<MarketplaceEntry, "minKernel">) => boolean;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SingleProviderNote } from "../extensions/single-provider.js";
|
|
2
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
2
3
|
import type { ActorOpts, CatalogItemView } from "./catalog.service.js";
|
|
3
4
|
import { CatalogScopeService } from "./catalog-scope.service.js";
|
|
4
5
|
import { PluginImport, type PluginReview } from "./plugin-import.js";
|
|
@@ -40,8 +41,8 @@ export declare function ownerUpdateHash(reviewHash: string, diffHash: string): s
|
|
|
40
41
|
* An org admin's plugin upload (spec §14.1 item 1, rulings P3-7, P3-8, P3-12, P3-13 to P3-15'): a
|
|
41
42
|
* `.tgz` prepared and confirmed through {@link PluginImport} in owner mode (the org's own staging,
|
|
42
43
|
* its admin re-checked under the org row lock), owned by the org with scope `named: [owner]`. After
|
|
43
|
-
* the confirm
|
|
44
|
-
*
|
|
44
|
+
* the confirm the item's scope sync is owed here (as `CatalogScopeService.confirmImport` does;
|
|
45
|
+
* `PluginImport` cannot reach the scope service, which depends on it), and installs it in the
|
|
45
46
|
* owner org.
|
|
46
47
|
*
|
|
47
48
|
* A new version of the org's own plugin without an extension (P3-12, P3-12') is reviewed with the
|
|
@@ -55,16 +56,22 @@ export declare class OrgPluginUploads {
|
|
|
55
56
|
private readonly pluginImport;
|
|
56
57
|
private readonly scope;
|
|
57
58
|
private readonly updater;
|
|
58
|
-
|
|
59
|
+
readonly txHost: TransactionHost;
|
|
60
|
+
constructor(pluginImport: PluginImport, scope: CatalogScopeService, updater: PlatformPluginUpdater, txHost: TransactionHost);
|
|
59
61
|
/** Reads, checks and stages the uploaded tgz for the org (see `PluginImport.prepare`). */
|
|
60
62
|
prepare(actor: string, orgId: string, bytes: Uint8Array, opts?: ActorOpts): Promise<OrgUploadReview>;
|
|
61
63
|
/** The org's own staged upload; another org's or the platform's -> 404 `plugin.staging_not_found`. */
|
|
62
64
|
staged(orgId: string, stagingId: string): Promise<OrgUploadReview>;
|
|
63
|
-
/** Confirms the org's staged upload (applying a new version), then
|
|
65
|
+
/** Confirms the org's staged upload (applying a new version), then owes the scope sync. */
|
|
64
66
|
confirm(actor: string, orgId: string, stagingId: string, input: {
|
|
65
67
|
reviewHash: string;
|
|
66
68
|
shareable?: boolean;
|
|
67
69
|
}, opts?: ActorOpts): Promise<OrgUploadResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Owes the confirmed item's scope sync in a transaction of its own: the confirm's writes span
|
|
72
|
+
* more than one transaction (`PluginImport.confirm`), and the sync follows the last of them.
|
|
73
|
+
*/
|
|
74
|
+
private oweSync;
|
|
68
75
|
/** The review with the update preview of a new version and the combined hash (P3-12). */
|
|
69
76
|
private withUpdate;
|
|
70
77
|
}
|
|
@@ -10,6 +10,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
10
10
|
import { createHash } from "node:crypto";
|
|
11
11
|
import { Inject, Injectable } from "@nestjs/common";
|
|
12
12
|
import { ApiError } from "../errors.js";
|
|
13
|
+
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
14
|
+
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
13
15
|
import { canonicalJson } from "../tools/canonical-json.js";
|
|
14
16
|
import { CatalogScopeService } from "./catalog-scope.service.js";
|
|
15
17
|
import { PluginImport } from "./plugin-import.js";
|
|
@@ -26,8 +28,8 @@ const reviewStale = (name, version) => new ApiError("plugin.review_stale", `The
|
|
|
26
28
|
* An org admin's plugin upload (spec §14.1 item 1, rulings P3-7, P3-8, P3-12, P3-13 to P3-15'): a
|
|
27
29
|
* `.tgz` prepared and confirmed through {@link PluginImport} in owner mode (the org's own staging,
|
|
28
30
|
* its admin re-checked under the org row lock), owned by the org with scope `named: [owner]`. After
|
|
29
|
-
* the confirm
|
|
30
|
-
*
|
|
31
|
+
* the confirm the item's scope sync is owed here (as `CatalogScopeService.confirmImport` does;
|
|
32
|
+
* `PluginImport` cannot reach the scope service, which depends on it), and installs it in the
|
|
31
33
|
* owner org.
|
|
32
34
|
*
|
|
33
35
|
* A new version of the org's own plugin without an extension (P3-12, P3-12') is reviewed with the
|
|
@@ -41,10 +43,12 @@ let OrgPluginUploads = class OrgPluginUploads {
|
|
|
41
43
|
pluginImport;
|
|
42
44
|
scope;
|
|
43
45
|
updater;
|
|
44
|
-
|
|
46
|
+
txHost;
|
|
47
|
+
constructor(pluginImport, scope, updater, txHost) {
|
|
45
48
|
this.pluginImport = pluginImport;
|
|
46
49
|
this.scope = scope;
|
|
47
50
|
this.updater = updater;
|
|
51
|
+
this.txHost = txHost;
|
|
48
52
|
}
|
|
49
53
|
/** Reads, checks and stages the uploaded tgz for the org (see `PluginImport.prepare`). */
|
|
50
54
|
async prepare(actor, orgId, bytes, opts = {}) {
|
|
@@ -56,7 +60,7 @@ let OrgPluginUploads = class OrgPluginUploads {
|
|
|
56
60
|
const r = await this.pluginImport.staged(stagingId, { orgId });
|
|
57
61
|
return this.withUpdate(orgId, r.stagingId, r.review);
|
|
58
62
|
}
|
|
59
|
-
/** Confirms the org's staged upload (applying a new version), then
|
|
63
|
+
/** Confirms the org's staged upload (applying a new version), then owes the scope sync. */
|
|
60
64
|
async confirm(actor, orgId, stagingId, input, opts = {}) {
|
|
61
65
|
const st = await this.pluginImport.stagedTarget(stagingId, { orgId });
|
|
62
66
|
if (!appliesAtOnce(st)) {
|
|
@@ -67,7 +71,7 @@ let OrgPluginUploads = class OrgPluginUploads {
|
|
|
67
71
|
// A version waiting for the super admin is synced by their confirmation (P3-10)
|
|
68
72
|
if (r.pending)
|
|
69
73
|
return { item: r.item, outcome: "pending" };
|
|
70
|
-
await this.
|
|
74
|
+
await this.oweSync(r.item.id);
|
|
71
75
|
return { item: r.item, outcome: r.firstVersion ? "installed" : "updated" };
|
|
72
76
|
}
|
|
73
77
|
// The one hash covers the review and the update (P3-12): both recomputed now
|
|
@@ -89,6 +93,13 @@ let OrgPluginUploads = class OrgPluginUploads {
|
|
|
89
93
|
}),
|
|
90
94
|
};
|
|
91
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Owes the confirmed item's scope sync in a transaction of its own: the confirm's writes span
|
|
98
|
+
* more than one transaction (`PluginImport.confirm`), and the sync follows the last of them.
|
|
99
|
+
*/
|
|
100
|
+
async oweSync(itemId) {
|
|
101
|
+
await this.scope.enqueueSync(itemId);
|
|
102
|
+
}
|
|
92
103
|
/** The review with the update preview of a new version and the combined hash (P3-12). */
|
|
93
104
|
async withUpdate(orgId, stagingId, review) {
|
|
94
105
|
const st = await this.pluginImport.stagedTarget(stagingId, { orgId });
|
|
@@ -102,11 +113,15 @@ let OrgPluginUploads = class OrgPluginUploads {
|
|
|
102
113
|
};
|
|
103
114
|
}
|
|
104
115
|
};
|
|
116
|
+
__decorate([
|
|
117
|
+
Transactional()
|
|
118
|
+
], OrgPluginUploads.prototype, "oweSync", null);
|
|
105
119
|
OrgPluginUploads = __decorate([
|
|
106
120
|
Injectable(),
|
|
107
121
|
__param(0, Inject(PluginImport)),
|
|
108
122
|
__param(1, Inject(CatalogScopeService)),
|
|
109
|
-
__param(2, Inject(PlatformPluginUpdater))
|
|
123
|
+
__param(2, Inject(PlatformPluginUpdater)),
|
|
124
|
+
__param(3, Inject(TransactionHost))
|
|
110
125
|
], OrgPluginUploads);
|
|
111
126
|
export { OrgPluginUploads };
|
|
112
127
|
/**
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Queue } from "bullmq";
|
|
2
1
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
3
2
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
4
3
|
import type { KernelLogger } from "../log.js";
|
|
@@ -45,17 +44,13 @@ export declare class OwnedItems {
|
|
|
45
44
|
private readonly installer;
|
|
46
45
|
/** The owner's org skill row, soft-deleted after its promoted platform row leaves it. */
|
|
47
46
|
private readonly skills;
|
|
48
|
-
/** The removed plugin's cleanup job (`owned-plugin-cleanup-<itemId>`, P3-20). */
|
|
49
|
-
private readonly queue;
|
|
50
47
|
private readonly log;
|
|
51
48
|
readonly txHost: TransactionHost;
|
|
52
49
|
constructor(kdb: KernelDb, orgLock: OrgLock, catalog: CatalogService, scope: CatalogScopeService,
|
|
53
50
|
/** The owner org's own uninstall of a removed plugin (ruling P3-41). */
|
|
54
51
|
installer: PluginInstaller,
|
|
55
52
|
/** The owner's org skill row, soft-deleted after its promoted platform row leaves it. */
|
|
56
|
-
skills: SkillsService,
|
|
57
|
-
/** The removed plugin's cleanup job (`owned-plugin-cleanup-<itemId>`, P3-20). */
|
|
58
|
-
queue: Pick<Queue, "add">, log: KernelLogger, txHost: TransactionHost);
|
|
53
|
+
skills: SkillsService, log: KernelLogger, txHost: TransactionHost);
|
|
59
54
|
private get db();
|
|
60
55
|
/**
|
|
61
56
|
* The owner org's 可共享 flag of its item, written on the item and (a plugin) every component
|
|
@@ -137,10 +132,10 @@ export declare class OwnedItems {
|
|
|
137
132
|
* it passed the share gate already, so every org could see it, and the former owner is then an
|
|
138
133
|
* ordinary org that may switch it on again), written
|
|
139
134
|
* directly rather than through the guarded scope writer (ruling P3-27); platform notice
|
|
140
|
-
* `ownership_transferred`, audit `catalog.ownership_transferred`, the scope sync
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* `owned-plugin-cleanup-<itemId>` that takes its extension out; an owner delete
|
|
135
|
+
* `ownership_transferred`, audit `catalog.ownership_transferred`, the scope sync owed with it
|
|
136
|
+
* (it uninstalls the former owner's install). Otherwise -> `removed`: the soft delete of
|
|
137
|
+
* `catalog.remove` ({@link CatalogService.removeIn}, which owes the cleanup job
|
|
138
|
+
* `owned-plugin-cleanup-<itemId>` that takes its extension out); an owner delete
|
|
144
139
|
* (`owner_deleted`) also uninstalls it in the owner org through the normal uninstall, keeping the
|
|
145
140
|
* connectors it created as the org's own (ruling P3-41). A first upload still waiting is never
|
|
146
141
|
* transferred. A gone or platform item -> 404.
|
|
@@ -153,7 +148,7 @@ export declare class OwnedItems {
|
|
|
153
148
|
* each goes through {@link transferOrRemove} with reason `org_deleted`. A first upload still
|
|
154
149
|
* waiting is removed and its extension name released here (nothing is installed under it,
|
|
155
150
|
* pre-flight F10); a pending new version of a transferred plugin is cleared; a removed plugin's
|
|
156
|
-
* extension is taken out by the cleanup job
|
|
151
|
+
* extension is taken out by the cleanup job the deletion owes. The org's unpromoted rows (its own
|
|
157
152
|
* skills, copies, installs) are left: they go with the org as before. Must not inject
|
|
158
153
|
* `OrgsService` (it calls this).
|
|
159
154
|
*/
|
|
@@ -180,8 +175,6 @@ export declare class OwnedItems {
|
|
|
180
175
|
* still depends on, or one still installing, stays (logged).
|
|
181
176
|
*/
|
|
182
177
|
private uninstallInOwner;
|
|
183
|
-
/** Enqueues the removed plugin's cleanup; a failure only warns (the daily sweep repairs it). */
|
|
184
|
-
enqueueCleanup(itemId: string): Promise<void>;
|
|
185
178
|
private computeDelete;
|
|
186
179
|
/** The org's own live plugin (`forUpdate`: row locked); another org's or a platform one -> 404. */
|
|
187
180
|
private ownedRow;
|
|
@@ -14,27 +14,23 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
14
14
|
// since Task 8, the org's own skills and agent templates (promoted ones through their platform
|
|
15
15
|
// rows, ruling P3-3).
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
|
-
import { getQueueToken } from "@nestjs/bullmq";
|
|
18
17
|
import { Inject, Injectable } from "@nestjs/common";
|
|
19
18
|
import { sql } from "kysely";
|
|
20
19
|
import { loadTemplates, readOwnTemplate, softDeleteTemplateIn } from "../agents/templates.js";
|
|
21
20
|
import { ApiError } from "../errors.js";
|
|
22
21
|
import { audit } from "../identity/audit.js";
|
|
23
22
|
import { addPlatformNotice } from "../inbox/platform-notices.js";
|
|
24
|
-
import { afterCommit } from "../infra/database/after-commit.js";
|
|
25
23
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
26
24
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
27
25
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
28
26
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
29
27
|
import { OrgLock } from "../orgs/org-lock.js";
|
|
30
|
-
import { MAINTENANCE_QUEUE_NAME } from "../runtime/maintenance-queue.js";
|
|
31
28
|
import { SkillsService } from "../skills/skills.service.js";
|
|
32
29
|
import { assertNotPlatformDefault } from "../themes/theme-usage.js";
|
|
33
30
|
import { CatalogService } from "./catalog.service.js";
|
|
34
31
|
import { CatalogScopeService } from "./catalog-scope.service.js";
|
|
35
32
|
import { notOwnedError } from "./component-promotion.js";
|
|
36
33
|
import { agentsUsing, COMPONENT_KINDS, componentOn, listedIn, loadComponents, loadScopeState, pluginFactsOf, switchOf, } from "./component-state.js";
|
|
37
|
-
import { ownedPluginCleanupJob } from "./job-ids.js";
|
|
38
34
|
import { orgsUsing } from "./ownership.js";
|
|
39
35
|
import { PluginInstaller } from "./plugin-install.js";
|
|
40
36
|
import { ScopeStillWanted } from "./scope-state.js";
|
|
@@ -79,23 +75,19 @@ let OwnedItems = class OwnedItems {
|
|
|
79
75
|
scope;
|
|
80
76
|
installer;
|
|
81
77
|
skills;
|
|
82
|
-
queue;
|
|
83
78
|
log;
|
|
84
79
|
txHost;
|
|
85
80
|
constructor(kdb, orgLock, catalog, scope,
|
|
86
81
|
/** The owner org's own uninstall of a removed plugin (ruling P3-41). */
|
|
87
82
|
installer,
|
|
88
83
|
/** The owner's org skill row, soft-deleted after its promoted platform row leaves it. */
|
|
89
|
-
skills,
|
|
90
|
-
/** The removed plugin's cleanup job (`owned-plugin-cleanup-<itemId>`, P3-20). */
|
|
91
|
-
queue, log, txHost) {
|
|
84
|
+
skills, log, txHost) {
|
|
92
85
|
this.kdb = kdb;
|
|
93
86
|
this.orgLock = orgLock;
|
|
94
87
|
this.catalog = catalog;
|
|
95
88
|
this.scope = scope;
|
|
96
89
|
this.installer = installer;
|
|
97
90
|
this.skills = skills;
|
|
98
|
-
this.queue = queue;
|
|
99
91
|
this.log = log;
|
|
100
92
|
this.txHost = txHost;
|
|
101
93
|
}
|
|
@@ -377,10 +369,10 @@ let OwnedItems = class OwnedItems {
|
|
|
377
369
|
* it passed the share gate already, so every org could see it, and the former owner is then an
|
|
378
370
|
* ordinary org that may switch it on again), written
|
|
379
371
|
* directly rather than through the guarded scope writer (ruling P3-27); platform notice
|
|
380
|
-
* `ownership_transferred`, audit `catalog.ownership_transferred`, the scope sync
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
* `owned-plugin-cleanup-<itemId>` that takes its extension out; an owner delete
|
|
372
|
+
* `ownership_transferred`, audit `catalog.ownership_transferred`, the scope sync owed with it
|
|
373
|
+
* (it uninstalls the former owner's install). Otherwise -> `removed`: the soft delete of
|
|
374
|
+
* `catalog.remove` ({@link CatalogService.removeIn}, which owes the cleanup job
|
|
375
|
+
* `owned-plugin-cleanup-<itemId>` that takes its extension out); an owner delete
|
|
384
376
|
* (`owner_deleted`) also uninstalls it in the owner org through the normal uninstall, keeping the
|
|
385
377
|
* connectors it created as the org's own (ruling P3-41). A first upload still waiting is never
|
|
386
378
|
* transferred. A gone or platform item -> 404.
|
|
@@ -402,9 +394,10 @@ let OwnedItems = class OwnedItems {
|
|
|
402
394
|
const others = item.awaiting_confirmation ? [] : await orgsUsing(t, ref, { except: owner });
|
|
403
395
|
if (others.length === 0) {
|
|
404
396
|
await this.catalog.removeIn(actor, item.id, { ...opts, reason });
|
|
397
|
+
// removeIn owes the cleanup job of a confirmed plugin (a first upload still waiting has
|
|
398
|
+
// nothing installed: its name claim is released there)
|
|
405
399
|
if (reason === "owner_deleted")
|
|
406
400
|
await this.uninstallInOwner(owner, actor, item.id, opts);
|
|
407
|
-
afterCommit(() => this.enqueueCleanup(item.id));
|
|
408
401
|
return "removed";
|
|
409
402
|
}
|
|
410
403
|
// A transfer leaves none of its themes `all` (an `all` scope is narrowed, P3-39): refused
|
|
@@ -531,7 +524,7 @@ let OwnedItems = class OwnedItems {
|
|
|
531
524
|
...opts.auditDetail,
|
|
532
525
|
},
|
|
533
526
|
});
|
|
534
|
-
|
|
527
|
+
await this.scope.enqueueSync(item.id);
|
|
535
528
|
return "transferred";
|
|
536
529
|
}
|
|
537
530
|
/**
|
|
@@ -541,7 +534,7 @@ let OwnedItems = class OwnedItems {
|
|
|
541
534
|
* each goes through {@link transferOrRemove} with reason `org_deleted`. A first upload still
|
|
542
535
|
* waiting is removed and its extension name released here (nothing is installed under it,
|
|
543
536
|
* pre-flight F10); a pending new version of a transferred plugin is cleared; a removed plugin's
|
|
544
|
-
* extension is taken out by the cleanup job
|
|
537
|
+
* extension is taken out by the cleanup job the deletion owes. The org's unpromoted rows (its own
|
|
545
538
|
* skills, copies, installs) are left: they go with the org as before. Must not inject
|
|
546
539
|
* `OrgsService` (it calls this).
|
|
547
540
|
*/
|
|
@@ -730,16 +723,6 @@ let OwnedItems = class OwnedItems {
|
|
|
730
723
|
});
|
|
731
724
|
}
|
|
732
725
|
}
|
|
733
|
-
/** Enqueues the removed plugin's cleanup; a failure only warns (the daily sweep repairs it). */
|
|
734
|
-
async enqueueCleanup(itemId) {
|
|
735
|
-
const job = ownedPluginCleanupJob(itemId);
|
|
736
|
-
try {
|
|
737
|
-
await this.queue.add(job.name, job.data, job.opts);
|
|
738
|
-
}
|
|
739
|
-
catch (err) {
|
|
740
|
-
this.log.warn("enqueueing the owned plugin cleanup failed", { itemId, err });
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
726
|
async computeDelete(orgId, item) {
|
|
744
727
|
const ref = { kind: "plugin", id: item.id };
|
|
745
728
|
const orgs = item.awaiting_confirmation ? [] : await orgsUsing(this.db, ref, { except: orgId });
|
|
@@ -801,8 +784,7 @@ OwnedItems = __decorate([
|
|
|
801
784
|
__param(3, Inject(CatalogScopeService)),
|
|
802
785
|
__param(4, Inject(PluginInstaller)),
|
|
803
786
|
__param(5, Inject(SkillsService)),
|
|
804
|
-
__param(6, Inject(
|
|
805
|
-
__param(7, Inject(
|
|
806
|
-
__param(8, Inject(TransactionHost))
|
|
787
|
+
__param(6, Inject(KERNEL_LOGGER)),
|
|
788
|
+
__param(7, Inject(TransactionHost))
|
|
807
789
|
], OwnedItems);
|
|
808
790
|
export { OwnedItems };
|
|
@@ -1,30 +1,27 @@
|
|
|
1
1
|
import { ExtensionAdminOps } from "../extensions/admin-ops.js";
|
|
2
2
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
3
3
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
4
|
-
import { LockService } from "../infra/lock/lock.service.js";
|
|
5
4
|
import type { KernelLogger } from "../log.js";
|
|
6
5
|
import { CatalogItemLock } from "./locks.js";
|
|
7
6
|
/**
|
|
8
7
|
* The cleanup of a removed org-owned plugin: {@link run} disables and uninstalls its extension (an
|
|
9
8
|
* install of the item's name from the item's package) when no live catalog item uses it any more
|
|
10
|
-
* ({@link OwnedPluginCleanup.referenced}), then releases the extension name claim, in one
|
|
11
|
-
* (pre-flight F10: the claim of an
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* for every removed org-owned item whose extension is still installed (a lost enqueue).
|
|
9
|
+
* ({@link OwnedPluginCleanup.referenced}), then releases the extension name claim, in one
|
|
10
|
+
* transaction under the import's item name lock (pre-flight F10: the claim of an installed
|
|
11
|
+
* extension is released here, never at the removal). Idempotent: a live item (a transferred one),
|
|
12
|
+
* a platform item or nothing installed changes nothing but the claim. The extension's data,
|
|
13
|
+
* secrets and configs stay, as with every uninstall.
|
|
16
14
|
*/
|
|
17
15
|
export declare class OwnedPluginCleanup {
|
|
18
16
|
private readonly kdb;
|
|
19
17
|
private readonly ops;
|
|
20
18
|
/** The import's item name lock (M5: no uninstall racing a re-import of the package). */
|
|
21
19
|
private readonly itemLock;
|
|
22
|
-
readonly
|
|
23
|
-
readonly log: KernelLogger;
|
|
20
|
+
private readonly log;
|
|
24
21
|
readonly txHost: TransactionHost;
|
|
25
22
|
constructor(kdb: KernelDb, ops: ExtensionAdminOps,
|
|
26
23
|
/** The import's item name lock (M5: no uninstall racing a re-import of the package). */
|
|
27
|
-
itemLock: CatalogItemLock,
|
|
24
|
+
itemLock: CatalogItemLock, log: KernelLogger, txHost: TransactionHost);
|
|
28
25
|
private get db();
|
|
29
26
|
/** Takes out the extension of removed item `itemId` (see the class). */
|
|
30
27
|
run(itemId: string): Promise<void>;
|
|
@@ -34,12 +31,6 @@ export declare class OwnedPluginCleanup {
|
|
|
34
31
|
* is taken out) or waits until this commits, so a newly imported extension is never uninstalled.
|
|
35
32
|
*/
|
|
36
33
|
private takeOut;
|
|
37
|
-
/**
|
|
38
|
-
* Daily: {@link run} for every removed org-owned item no live item {@link referenced} names
|
|
39
|
-
* whose extension is still installed, or whose name claim is still held (a lost enqueue, or a
|
|
40
|
-
* run that uninstalled and failed before releasing the claim).
|
|
41
|
-
*/
|
|
42
|
-
sweep(): Promise<void>;
|
|
43
34
|
/**
|
|
44
35
|
* A live catalog item still uses the extension: one named like it (a plugin and its extension
|
|
45
36
|
* share one name) from the same package whose owner is the removed item's owner (a re-upload)
|
|
@@ -50,7 +41,7 @@ export declare class OwnedPluginCleanup {
|
|
|
50
41
|
}
|
|
51
42
|
/**
|
|
52
43
|
* {@link OwnedPluginCleanup}: imported only by `MaintenanceModule` (the job's dispatcher), which
|
|
53
|
-
* only the worker role imports
|
|
44
|
+
* only the worker role imports.
|
|
54
45
|
*/
|
|
55
46
|
export declare class OwnedPluginCleanupModule {
|
|
56
47
|
}
|
|
@@ -9,9 +9,9 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
9
9
|
};
|
|
10
10
|
// Taking out the extension of a removed org-owned plugin (plugin scope phase 3, spec §14, P3-20,
|
|
11
11
|
// P3-21; pre-flight F9, F10): the one-off job `owned-plugin-cleanup-<itemId>` on
|
|
12
|
-
// `cap-kernel-maintenance` (dispatched by `MaintenanceProcessor`)
|
|
13
|
-
//
|
|
14
|
-
// imports.
|
|
12
|
+
// `cap-kernel-maintenance` (dispatched by `MaintenanceProcessor`), owed in the outbox by the
|
|
13
|
+
// removal's transaction (transactional outbox spec §8.1). Worker-only: `OwnedPluginCleanupModule`
|
|
14
|
+
// is imported only by `MaintenanceModule`, which only `WorkerModule` imports.
|
|
15
15
|
import { Inject, Injectable, Module } from "@nestjs/common";
|
|
16
16
|
import { ApiError } from "../errors.js";
|
|
17
17
|
import { ExtensionAdminOps } from "../extensions/admin-ops.js";
|
|
@@ -19,11 +19,8 @@ import { ExtensionsModule } from "../extensions/extensions.module.js";
|
|
|
19
19
|
import { KernelDb } from "../infra/database/kernel-db.js";
|
|
20
20
|
import { TransactionHost } from "../infra/database/transaction-host.js";
|
|
21
21
|
import { Transactional } from "../infra/database/transactional.decorator.js";
|
|
22
|
-
import { LockService } from "../infra/lock/lock.service.js";
|
|
23
|
-
import { LockedCron } from "../infra/schedule/locked-cron.decorator.js";
|
|
24
22
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
25
23
|
import { CatalogImportModule } from "./catalog.module.js";
|
|
26
|
-
import { OWNED_PLUGIN_CLEANUP_SWEEP_JOB } from "./job-ids.js";
|
|
27
24
|
import { CatalogItemLock } from "./locks.js";
|
|
28
25
|
import { releaseExtensionClaim } from "./ownership.js";
|
|
29
26
|
/** Codes that mean another run (or the confirmation's own take-out) got there first. */
|
|
@@ -31,27 +28,24 @@ const GONE = new Set(["extension.not_found", "extension.not_disabled"]);
|
|
|
31
28
|
/**
|
|
32
29
|
* The cleanup of a removed org-owned plugin: {@link run} disables and uninstalls its extension (an
|
|
33
30
|
* install of the item's name from the item's package) when no live catalog item uses it any more
|
|
34
|
-
* ({@link OwnedPluginCleanup.referenced}), then releases the extension name claim, in one
|
|
35
|
-
* (pre-flight F10: the claim of an
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* for every removed org-owned item whose extension is still installed (a lost enqueue).
|
|
31
|
+
* ({@link OwnedPluginCleanup.referenced}), then releases the extension name claim, in one
|
|
32
|
+
* transaction under the import's item name lock (pre-flight F10: the claim of an installed
|
|
33
|
+
* extension is released here, never at the removal). Idempotent: a live item (a transferred one),
|
|
34
|
+
* a platform item or nothing installed changes nothing but the claim. The extension's data,
|
|
35
|
+
* secrets and configs stay, as with every uninstall.
|
|
40
36
|
*/
|
|
41
37
|
let OwnedPluginCleanup = class OwnedPluginCleanup {
|
|
42
38
|
kdb;
|
|
43
39
|
ops;
|
|
44
40
|
itemLock;
|
|
45
|
-
lockService;
|
|
46
41
|
log;
|
|
47
42
|
txHost;
|
|
48
43
|
constructor(kdb, ops,
|
|
49
44
|
/** The import's item name lock (M5: no uninstall racing a re-import of the package). */
|
|
50
|
-
itemLock,
|
|
45
|
+
itemLock, log, txHost) {
|
|
51
46
|
this.kdb = kdb;
|
|
52
47
|
this.ops = ops;
|
|
53
48
|
this.itemLock = itemLock;
|
|
54
|
-
this.lockService = lockService;
|
|
55
49
|
this.log = log;
|
|
56
50
|
this.txHost = txHost;
|
|
57
51
|
}
|
|
@@ -100,50 +94,6 @@ let OwnedPluginCleanup = class OwnedPluginCleanup {
|
|
|
100
94
|
}
|
|
101
95
|
await releaseExtensionClaim(this.db, name, pkg);
|
|
102
96
|
}
|
|
103
|
-
/**
|
|
104
|
-
* Daily: {@link run} for every removed org-owned item no live item {@link referenced} names
|
|
105
|
-
* whose extension is still installed, or whose name claim is still held (a lost enqueue, or a
|
|
106
|
-
* run that uninstalled and failed before releasing the claim).
|
|
107
|
-
*/
|
|
108
|
-
async sweep() {
|
|
109
|
-
const rows = await this.db
|
|
110
|
-
.selectFrom("catalog_items as ci")
|
|
111
|
-
.select("ci.id")
|
|
112
|
-
.where("ci.deleted_at", "is not", null)
|
|
113
|
-
.where("ci.owner_org_id", "is not", null)
|
|
114
|
-
.where("ci.package_name", "is not", null)
|
|
115
|
-
.where(({ and, or, not, exists, selectFrom }) => and([
|
|
116
|
-
not(exists(selectFrom("catalog_items as live")
|
|
117
|
-
.select("live.id")
|
|
118
|
-
.whereRef("live.name", "=", "ci.name")
|
|
119
|
-
.whereRef("live.package_name", "=", "ci.package_name")
|
|
120
|
-
.where("live.deleted_at", "is", null)
|
|
121
|
-
.where((eb) => eb.or([
|
|
122
|
-
eb("live.owner_org_id", "is", null),
|
|
123
|
-
eb("live.owner_org_id", "=", eb.ref("ci.owner_org_id")),
|
|
124
|
-
])))),
|
|
125
|
-
or([
|
|
126
|
-
exists(selectFrom("extension_installs as x")
|
|
127
|
-
.innerJoin("extension_packages as p", "p.sha256", "x.sha256")
|
|
128
|
-
.select("x.name")
|
|
129
|
-
.whereRef("x.name", "=", "ci.name")
|
|
130
|
-
.whereRef("p.package_name", "=", "ci.package_name")),
|
|
131
|
-
exists(selectFrom("extension_name_owners as o")
|
|
132
|
-
.select("o.name")
|
|
133
|
-
.whereRef("o.name", "=", "ci.name")
|
|
134
|
-
.whereRef("o.package_name", "=", "ci.package_name")),
|
|
135
|
-
]),
|
|
136
|
-
]))
|
|
137
|
-
.execute();
|
|
138
|
-
for (const r of rows) {
|
|
139
|
-
try {
|
|
140
|
-
await this.run(r.id);
|
|
141
|
-
}
|
|
142
|
-
catch (err) {
|
|
143
|
-
this.log.error("owned plugin cleanup failed", { itemId: r.id, err });
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
97
|
/**
|
|
148
98
|
* A live catalog item still uses the extension: one named like it (a plugin and its extension
|
|
149
99
|
* share one name) from the same package whose owner is the removed item's owner (a re-upload)
|
|
@@ -165,22 +115,18 @@ let OwnedPluginCleanup = class OwnedPluginCleanup {
|
|
|
165
115
|
__decorate([
|
|
166
116
|
Transactional()
|
|
167
117
|
], OwnedPluginCleanup.prototype, "takeOut", null);
|
|
168
|
-
__decorate([
|
|
169
|
-
LockedCron("40 3 * * *", { name: OWNED_PLUGIN_CLEANUP_SWEEP_JOB })
|
|
170
|
-
], OwnedPluginCleanup.prototype, "sweep", null);
|
|
171
118
|
OwnedPluginCleanup = __decorate([
|
|
172
119
|
Injectable(),
|
|
173
120
|
__param(0, Inject(KernelDb)),
|
|
174
121
|
__param(1, Inject(ExtensionAdminOps)),
|
|
175
122
|
__param(2, Inject(CatalogItemLock)),
|
|
176
|
-
__param(3, Inject(
|
|
177
|
-
__param(4, Inject(
|
|
178
|
-
__param(5, Inject(TransactionHost))
|
|
123
|
+
__param(3, Inject(KERNEL_LOGGER)),
|
|
124
|
+
__param(4, Inject(TransactionHost))
|
|
179
125
|
], OwnedPluginCleanup);
|
|
180
126
|
export { OwnedPluginCleanup };
|
|
181
127
|
/**
|
|
182
128
|
* {@link OwnedPluginCleanup}: imported only by `MaintenanceModule` (the job's dispatcher), which
|
|
183
|
-
* only the worker role imports
|
|
129
|
+
* only the worker role imports.
|
|
184
130
|
*/
|
|
185
131
|
let OwnedPluginCleanupModule = class OwnedPluginCleanupModule {
|
|
186
132
|
};
|