@capybara-hq/kernel 0.1.0-rc.22 → 0.1.0-rc.24
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/bootstrap.json +25 -25
- package/dist/admin/admin.controller.d.ts +3 -3
- package/dist/admin/admin.controller.js +6 -2
- package/dist/admin/admin.module.d.ts +2 -1
- package/dist/admin/admin.module.js +7 -3
- package/dist/admin/admin.schemas.d.ts +13 -0
- package/dist/admin/outbox-dead.controller.d.ts +23 -0
- package/dist/admin/outbox-dead.controller.js +62 -0
- package/dist/admin/outbox-dead.schemas.d.ts +8 -0
- package/dist/admin/outbox-dead.schemas.js +18 -0
- package/dist/admin/outbox-dead.service.d.ts +66 -0
- package/dist/admin/outbox-dead.service.js +179 -0
- package/dist/admin/overview.service.d.ts +40 -5
- package/dist/admin/overview.service.js +41 -7
- package/dist/agents/from-template.js +1 -1
- package/dist/background/finish.d.ts +5 -2
- package/dist/background/finish.js +14 -3
- package/dist/background/launch.d.ts +44 -5
- package/dist/background/launch.js +92 -9
- package/dist/background/session.d.ts +14 -2
- package/dist/background/session.js +26 -4
- package/dist/background/status.d.ts +1 -1
- package/dist/background/status.js +3 -3
- package/dist/background/stop.d.ts +0 -2
- package/dist/background/stop.js +1 -21
- package/dist/background/store.d.ts +8 -0
- package/dist/background/store.js +24 -0
- package/dist/catalog/admin-catalog.controller.d.ts +21 -2
- package/dist/catalog/admin-catalog.controller.js +45 -6
- package/dist/catalog/admin-catalog.schemas.d.ts +5 -0
- package/dist/catalog/admin-catalog.schemas.js +8 -0
- package/dist/catalog/catalog-content.d.ts +5 -0
- package/dist/catalog/catalog-content.js +1 -0
- package/dist/catalog/catalog.module.d.ts +2 -1
- package/dist/catalog/catalog.module.js +5 -1
- package/dist/catalog/marketplaces.service.d.ts +1 -1
- package/dist/catalog/platform-import-update.d.ts +50 -0
- package/dist/catalog/platform-import-update.js +116 -0
- package/dist/catalog/plugin-import.d.ts +36 -1
- package/dist/catalog/plugin-import.js +23 -1
- package/dist/catalog/plugin-upgrade.d.ts +18 -0
- package/dist/catalog/plugin-upgrade.js +19 -0
- package/dist/catalog/requests.service.js +2 -2
- package/dist/channels/channels.module.d.ts +5 -2
- package/dist/channels/channels.module.js +9 -2
- package/dist/channels/deliver-job.d.ts +25 -0
- package/dist/channels/deliver-job.js +25 -0
- package/dist/channels/inbound.d.ts +1 -1
- package/dist/channels/inbound.js +2 -15
- package/dist/channels/jobs.d.ts +28 -18
- package/dist/channels/jobs.js +63 -26
- package/dist/config/schema.d.ts +3 -6
- package/dist/config/schema.js +20 -27
- package/dist/conversations/agent-tree.d.ts +16 -0
- package/dist/conversations/agent-tree.js +36 -0
- package/dist/conversations/conversations.service.d.ts +44 -14
- package/dist/conversations/conversations.service.js +52 -38
- package/dist/conversations/event-log.d.ts +7 -10
- package/dist/conversations/event-log.js +24 -15
- package/dist/conversations/events.js +2 -1
- package/dist/conversations/queue.service.d.ts +8 -3
- package/dist/conversations/queue.service.js +37 -13
- package/dist/conversations/titles.d.ts +21 -8
- package/dist/conversations/titles.js +42 -15
- package/dist/db/kernel-schema.d.ts +26 -8
- package/dist/devices/devices.service.d.ts +12 -3
- package/dist/devices/devices.service.js +30 -9
- package/dist/errors.d.ts +15 -0
- package/dist/errors.js +15 -0
- package/dist/evals/run-replay.js +14 -8
- package/dist/extensions/extensions.module.js +3 -0
- package/dist/extensions/lifecycle.d.ts +6 -1
- package/dist/extensions/lifecycle.js +9 -2
- package/dist/extensions/usage-subscribers.d.ts +43 -0
- package/dist/extensions/usage-subscribers.js +108 -0
- package/dist/http/api.module.js +2 -0
- package/dist/identity/settings.d.ts +53 -3
- package/dist/identity/settings.js +92 -9
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/infra/cli/kernel-cli.module.js +5 -0
- package/dist/infra/config/kernel-config.service.d.ts +7 -0
- package/dist/infra/config/kernel-config.service.js +20 -0
- package/dist/infra/events/kernel-events.d.ts +9 -35
- package/dist/infra/outbox/outbox-relay.module.d.ts +6 -0
- package/dist/infra/outbox/outbox-relay.module.js +18 -0
- package/dist/infra/outbox/outbox.dispatcher.d.ts +103 -0
- package/dist/infra/outbox/outbox.dispatcher.js +310 -0
- package/dist/infra/outbox/outbox.module.d.ts +24 -0
- package/dist/infra/outbox/outbox.module.js +50 -0
- package/dist/infra/outbox/outbox.relay.d.ts +31 -0
- package/dist/infra/outbox/outbox.relay.js +76 -0
- package/dist/infra/outbox/outbox.service.d.ts +51 -0
- package/dist/infra/outbox/outbox.service.js +131 -0
- package/dist/infra/outbox/registry.d.ts +120 -0
- package/dist/infra/outbox/registry.js +108 -0
- package/dist/infra/queue/queue-names.d.ts +8 -0
- package/dist/infra/queue/queue-names.js +16 -0
- package/dist/kernel.module.js +3 -0
- package/dist/local-devices/device-policy.service.d.ts +4 -0
- package/dist/local-devices/device-policy.service.js +61 -3
- package/dist/local-devices/local-device-gateway.d.ts +4 -2
- package/dist/local-devices/local-device-gateway.js +39 -14
- package/dist/local-devices/machines.d.ts +25 -1
- package/dist/local-devices/machines.js +91 -15
- package/dist/local-devices/policy-summary.d.ts +44 -1
- package/dist/local-devices/policy-summary.js +69 -0
- package/dist/models/embeddings.d.ts +9 -9
- package/dist/models/embeddings.js +11 -18
- package/dist/models/models.module.js +3 -0
- package/dist/orgs/orgs.service.js +7 -0
- package/dist/orgs/settings.controller.js +2 -2
- package/dist/orgs/settings.service.d.ts +11 -5
- package/dist/orgs/settings.service.js +28 -14
- package/dist/overrides.d.ts +20 -3
- package/dist/overrides.js +10 -2
- package/dist/platform/exclusions.js +5 -0
- package/dist/platform/ops/admin.ops.js +50 -9
- package/dist/platform/ops/catalog-admin.ops.d.ts +3 -1
- package/dist/platform/ops/catalog-admin.ops.js +32 -4
- package/dist/platform/ops/org-settings.ops.js +3 -3
- package/dist/platform/ops/orgs.ops.js +1 -0
- package/dist/platform/ops/outbox.ops.d.ts +21 -0
- package/dist/platform/ops/outbox.ops.js +125 -0
- package/dist/platform/ops/platform.ops.js +1 -1
- package/dist/platform/ops/schedules.ops.js +40 -1
- package/dist/platform/platform-ops.module.d.ts +2 -1
- package/dist/platform/platform-ops.module.js +3 -0
- package/dist/platform/route-schemas.js +3 -0
- package/dist/roles/worker.module.js +9 -4
- package/dist/runtime/langgraph-loop.js +13 -5
- package/dist/runtime/limits.d.ts +15 -0
- package/dist/runtime/limits.js +25 -0
- package/dist/runtime/loop.d.ts +8 -3
- package/dist/runtime/loop.js +2 -1
- package/dist/runtime/maintenance.d.ts +4 -2
- package/dist/runtime/maintenance.js +17 -2
- package/dist/runtime/model-call.d.ts +14 -16
- package/dist/runtime/model-call.js +14 -24
- package/dist/runtime/queue-lost-jobs.d.ts +24 -0
- package/dist/runtime/queue-lost-jobs.js +51 -0
- package/dist/runtime/run-control.d.ts +42 -5
- package/dist/runtime/run-control.js +66 -12
- package/dist/runtime/run-finish.d.ts +39 -12
- package/dist/runtime/run-finish.js +97 -14
- package/dist/runtime/run-jobs.d.ts +95 -13
- package/dist/runtime/run-jobs.js +199 -28
- package/dist/runtime/run-orphan-check.job.d.ts +142 -0
- package/dist/runtime/run-orphan-check.job.js +339 -0
- package/dist/runtime/run-processors.d.ts +16 -9
- package/dist/runtime/run-processors.js +1 -1
- package/dist/runtime/run-queue.d.ts +64 -55
- package/dist/runtime/run-queue.js +147 -284
- package/dist/runtime/run-steps.d.ts +1 -2
- package/dist/runtime/run-steps.js +8 -11
- package/dist/runtime/run-worker.d.ts +6 -17
- package/dist/runtime/run-worker.js +32 -34
- package/dist/runtime/runtime.module.d.ts +2 -3
- package/dist/runtime/runtime.module.js +5 -6
- package/dist/runtime/step-log.d.ts +16 -4
- package/dist/runtime/step-log.js +26 -6
- package/dist/runtime/stream.controller.d.ts +2 -4
- package/dist/runtime/stream.controller.js +5 -11
- package/dist/runtime/subagents/child.js +1 -1
- package/dist/runtime/subagents/definition.d.ts +2 -1
- package/dist/runtime/subagents/definition.js +4 -2
- package/dist/runtime/subagents/deliveries.d.ts +6 -3
- package/dist/runtime/subagents/deliveries.js +16 -7
- package/dist/runtime/subagents/dispatch.d.ts +12 -12
- package/dist/runtime/subagents/dispatch.js +13 -38
- package/dist/runtime/subagents/messages.d.ts +5 -1
- package/dist/runtime/subagents/messages.js +11 -3
- package/dist/runtime/subagents/skill-fork.d.ts +3 -3
- package/dist/runtime/subagents/skill-fork.js +5 -5
- package/dist/runtime/subagents/subagents.service.js +1 -1
- package/dist/runtime/subagents/tree-jobs.d.ts +61 -0
- package/dist/runtime/subagents/tree-jobs.js +86 -0
- package/dist/runtime/usage-report-jobs.d.ts +23 -48
- package/dist/runtime/usage-report-jobs.js +67 -119
- package/dist/runtime/usage-report.d.ts +28 -77
- package/dist/runtime/usage-report.js +35 -213
- package/dist/runtime/waits.d.ts +48 -198
- package/dist/runtime/waits.js +103 -805
- package/dist/sandbox/platform-tiers.d.ts +86 -0
- package/dist/sandbox/platform-tiers.js +97 -0
- package/dist/sandbox/sandbox.service.d.ts +18 -5
- package/dist/sandbox/sandbox.service.js +75 -20
- package/dist/sandbox/tiers.d.ts +14 -2
- package/dist/sandbox/tiers.js +8 -0
- package/dist/schedules/calendar.d.ts +134 -0
- package/dist/schedules/calendar.js +410 -0
- package/dist/schedules/fire.d.ts +1 -3
- package/dist/schedules/fire.js +5 -10
- package/dist/schedules/run-tracker.d.ts +0 -5
- package/dist/schedules/run-tracker.js +0 -13
- package/dist/schedules/scan.job.js +15 -20
- package/dist/schedules/schedule-math.d.ts +42 -0
- package/dist/schedules/schedule-math.js +52 -0
- package/dist/schedules/scheduled-tasks.service.d.ts +16 -0
- package/dist/schedules/scheduled-tasks.service.js +53 -0
- package/dist/schedules/schedules.controller.d.ts +5 -1
- package/dist/schedules/schedules.controller.js +15 -1
- package/dist/schedules/schedules.schemas.d.ts +35 -0
- package/dist/schedules/schedules.schemas.js +27 -0
- package/dist/schedules/store.d.ts +5 -0
- package/dist/schedules/store.js +20 -0
- package/dist/tools/approvals.service.d.ts +26 -7
- package/dist/tools/approvals.service.js +88 -10
- package/dist/tools/builtin-names.d.ts +5 -3
- package/dist/tools/builtin-names.js +12 -4
- package/dist/tools/builtins/builtin-tools.d.ts +1 -2
- package/dist/tools/builtins/builtin-tools.js +21 -17
- package/dist/tools/builtins/sandbox/bash.js +9 -3
- package/dist/tools/builtins/sandbox/common.d.ts +18 -1
- package/dist/tools/builtins/sandbox/common.js +14 -1
- package/dist/tools/builtins/sandbox/index.d.ts +2 -1
- package/dist/tools/builtins/sandbox/index.js +4 -1
- package/dist/tools/builtins/sandbox/task-list.d.ts +12 -0
- package/dist/tools/builtins/sandbox/task-list.js +130 -0
- package/dist/tools/builtins/sandbox/task-output.d.ts +8 -1
- package/dist/tools/builtins/sandbox/task-output.js +21 -3
- package/dist/tools/builtins/web/extract.d.ts +2 -4
- package/dist/tools/builtins/web/extract.js +2 -5
- package/dist/tools/pipeline.d.ts +1 -1
- package/dist/tools/pipeline.js +1 -1
- package/dist/tools/questions.service.d.ts +15 -6
- package/dist/tools/questions.service.js +20 -8
- package/dist/tools/registry.d.ts +4 -2
- package/dist/tools/registry.js +4 -3
- package/dist/tools/tools.module.js +4 -3
- package/package.json +3 -3
- package/src/migrations/0118_device_policy_ops.sql +6 -0
- package/src/migrations/0119_outbox.sql +22 -0
- package/src/migrations/0120_drop_usage_report_sweep.sql +7 -0
package/dist/background/stop.js
CHANGED
|
@@ -13,30 +13,10 @@ import { KernelDb } from "../infra/database/kernel-db.js";
|
|
|
13
13
|
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
14
14
|
import { SandboxService } from "../sandbox/sandbox.service.js";
|
|
15
15
|
import { BackgroundTaskFinisher, } from "./finish.js";
|
|
16
|
-
import {
|
|
17
|
-
import { actingAs, assertTaskRef, decodeTail, killSession, tailCommand, taskActor, } from "./session.js";
|
|
16
|
+
import { actingAs, assertTaskRef, decodeTail, killSession, TERM_EXEC_TIMEOUT_MS, tailCommand, taskActor, termScript, } from "./session.js";
|
|
18
17
|
import { BackgroundTaskStore } from "./store.js";
|
|
19
|
-
/** How long a stop waits after SIGTERM before SIGKILL (spec §2.3). */
|
|
20
|
-
export const STOP_GRACE_MS = 5000;
|
|
21
|
-
/** The time limit of the SIGTERM exec: the grace period plus some room. */
|
|
22
|
-
const TERM_EXEC_TIMEOUT_MS = STOP_GRACE_MS + 5000;
|
|
23
18
|
/** The time limit of reading the last lines after a stop. */
|
|
24
19
|
const TAIL_EXEC_TIMEOUT_MS = 10_000;
|
|
25
|
-
/**
|
|
26
|
-
* Exit code 0 with `exited <code>` when the task had already finished (its exit file exists),
|
|
27
|
-
* else sends SIGTERM to the session and waits up to {@link STOP_GRACE_MS} for it to empty, then
|
|
28
|
-
* prints `term`. Relative to the workspace root.
|
|
29
|
-
*/
|
|
30
|
-
function termScript(id, sid) {
|
|
31
|
-
const f = `${TASKS_DIR}/${id}`;
|
|
32
|
-
const tries = Math.ceil(STOP_GRACE_MS / 200);
|
|
33
|
-
return [
|
|
34
|
-
`if [ -s ${f}.exit ]; then echo "exited $(cat ${f}.exit)"; exit 0; fi`,
|
|
35
|
-
`pkill -TERM -s ${sid} >/dev/null 2>&1`,
|
|
36
|
-
`i=0; while [ "$i" -lt ${tries} ] && pgrep -s ${sid} >/dev/null 2>&1; do sleep 0.2; i=$((i+1)); done`,
|
|
37
|
-
"echo term",
|
|
38
|
-
].join("\n");
|
|
39
|
-
}
|
|
40
20
|
/** How a task that exited by itself ends (spec §4.3): exit 137 past its deadline timed out. */
|
|
41
21
|
export function exitedAs(task, code, now) {
|
|
42
22
|
if (code === 0)
|
|
@@ -137,6 +137,14 @@ export declare class BackgroundTaskStore {
|
|
|
137
137
|
runningStarted(): Promise<BackgroundTaskRow[]>;
|
|
138
138
|
/** The running tasks one conversation owns (not those of its sub-agents), oldest first. */
|
|
139
139
|
runningOwnedBy(conversationId: string): Promise<BackgroundTaskRow[]>;
|
|
140
|
+
/**
|
|
141
|
+
* The finished tasks one conversation owns (not those of its sub-agents), the most recently
|
|
142
|
+
* finished first, at most `limit` of them, with how many it owns in all (`TaskList`).
|
|
143
|
+
*/
|
|
144
|
+
finishedOwnedBy(conversationId: string, limit: number): Promise<{
|
|
145
|
+
rows: BackgroundTaskRow[];
|
|
146
|
+
total: number;
|
|
147
|
+
}>;
|
|
140
148
|
/** The running tasks of one root conversation's tree (what `maxTasks` limits). */
|
|
141
149
|
countRunning(sandboxConversationId: string): Promise<number>;
|
|
142
150
|
/** The tasks owned by any of the conversations, newest first. */
|
package/dist/background/store.js
CHANGED
|
@@ -258,6 +258,30 @@ let BackgroundTaskStore = class BackgroundTaskStore {
|
|
|
258
258
|
.execute();
|
|
259
259
|
return rows.map(toRow);
|
|
260
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* The finished tasks one conversation owns (not those of its sub-agents), the most recently
|
|
263
|
+
* finished first, at most `limit` of them, with how many it owns in all (`TaskList`).
|
|
264
|
+
*/
|
|
265
|
+
async finishedOwnedBy(conversationId, limit) {
|
|
266
|
+
const [rows, count] = await Promise.all([
|
|
267
|
+
this.db
|
|
268
|
+
.selectFrom("background_tasks")
|
|
269
|
+
.selectAll()
|
|
270
|
+
.where("conversation_id", "=", conversationId)
|
|
271
|
+
.where("status", "<>", "running")
|
|
272
|
+
.orderBy("finished_at", "desc")
|
|
273
|
+
.orderBy("id", "desc")
|
|
274
|
+
.limit(limit)
|
|
275
|
+
.execute(),
|
|
276
|
+
this.db
|
|
277
|
+
.selectFrom("background_tasks")
|
|
278
|
+
.select((eb) => eb.fn.countAll().as("n"))
|
|
279
|
+
.where("conversation_id", "=", conversationId)
|
|
280
|
+
.where("status", "<>", "running")
|
|
281
|
+
.executeTakeFirstOrThrow(),
|
|
282
|
+
]);
|
|
283
|
+
return { rows: rows.map(toRow), total: Number(count.n) };
|
|
284
|
+
}
|
|
261
285
|
/** The running tasks of one root conversation's tree (what `maxTasks` limits). */
|
|
262
286
|
async countRunning(sandboxConversationId) {
|
|
263
287
|
const r = await this.db
|
|
@@ -5,12 +5,13 @@ import { type ClientBuildSummary, ClientBuilds } from "../client/client-builds.s
|
|
|
5
5
|
import { PluginGuides, type RenderedSetupGuide } from "../extensions/plugin-guides.js";
|
|
6
6
|
import { PluginIcons } from "../extensions/plugin-icons.js";
|
|
7
7
|
import { type Principal } from "../identity/principal.js";
|
|
8
|
-
import { AdminCatalogGuideQuery, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogNpmImportBody as NpmBody, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody } from "./admin-catalog.schemas.js";
|
|
8
|
+
import { AdminCatalogGuideQuery, CatalogImportUpdateBody, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogNpmImportBody as NpmBody, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody } from "./admin-catalog.schemas.js";
|
|
9
9
|
import { AppearanceApplyBody } from "./appearance.schemas.js";
|
|
10
10
|
import { type AppearanceResult, AppearanceService } from "./appearance.service.js";
|
|
11
11
|
import { type CatalogItemDetail, type CatalogItemView, CatalogService, type PermissionsMismatch } from "./catalog.service.js";
|
|
12
12
|
import { CatalogScopeService, type ScopePreview } from "./catalog-scope.service.js";
|
|
13
13
|
import { OrgCatalogService } from "./org-catalog.service.js";
|
|
14
|
+
import { PlatformImportUpdate, type PlatformImportUpdateResult } from "./platform-import-update.js";
|
|
14
15
|
import { type PluginConfirmResult, PluginImport, type PluginReview } from "./plugin-import.js";
|
|
15
16
|
import { PlatformPluginUpdater, type PlatformUpdatePreview, type PlatformUpdateResult } from "./plugin-upgrade.js";
|
|
16
17
|
declare const ConfirmBody: z.ZodObject<{
|
|
@@ -41,11 +42,12 @@ export declare class AdminCatalogController {
|
|
|
41
42
|
private readonly orgCatalog;
|
|
42
43
|
private readonly scope;
|
|
43
44
|
private readonly updater;
|
|
45
|
+
private readonly importUpdate;
|
|
44
46
|
private readonly icons;
|
|
45
47
|
private readonly appearance;
|
|
46
48
|
private readonly clientBuilds;
|
|
47
49
|
private readonly guides;
|
|
48
|
-
constructor(catalog: CatalogService, pluginImport: PluginImport, orgCatalog: OrgCatalogService, scope: CatalogScopeService, updater: PlatformPluginUpdater, icons: PluginIcons, appearance: AppearanceService, clientBuilds: ClientBuilds, guides: PluginGuides);
|
|
50
|
+
constructor(catalog: CatalogService, pluginImport: PluginImport, orgCatalog: OrgCatalogService, scope: CatalogScopeService, updater: PlatformPluginUpdater, importUpdate: PlatformImportUpdate, icons: PluginIcons, appearance: AppearanceService, clientBuilds: ClientBuilds, guides: PluginGuides);
|
|
49
51
|
/**
|
|
50
52
|
* Prepares the import of an uploaded plugin (an npm-pack tgz as the raw body,
|
|
51
53
|
* `application/octet-stream`, at most `packages.maxBytes`): reads and checks the whole plugin
|
|
@@ -108,6 +110,23 @@ export declare class AdminCatalogController {
|
|
|
108
110
|
* is an unknown field (400 `validation_failed`).
|
|
109
111
|
*/
|
|
110
112
|
confirm(principal: Principal, stagingId: string, body: z.infer<typeof ConfirmBody>): Promise<PluginConfirmResult>;
|
|
113
|
+
/**
|
|
114
|
+
* What confirming a staged new version of an installed platform plugin would do as the platform
|
|
115
|
+
* update (`PlatformImportUpdate`, the one 更新到 wizard): the update preview of the staged
|
|
116
|
+
* version, nothing written (cancelling the wizard leaves only the staging row). Not a platform
|
|
117
|
+
* plugin yet -> 409 `plugin.upgrade_target_invalid` (reason `not_installed`); staging missing ->
|
|
118
|
+
* 404 `plugin.staging_not_found`; otherwise as `items/:id/update/preview`.
|
|
119
|
+
*/
|
|
120
|
+
importUpdatePreview(stagingId: string): Promise<PlatformUpdatePreview>;
|
|
121
|
+
/**
|
|
122
|
+
* Imports the staged version and updates the platform plugin to it, confirmed with the import
|
|
123
|
+
* review's `reviewHash` and the update preview's `diffHash` (201 `{ item, update }`). Stale review
|
|
124
|
+
* -> 409 `plugin.review_stale`, stale preview -> 409 `plugin.upgrade_stale`, another update
|
|
125
|
+
* running -> 409 `plugin.install_in_progress`: nothing written. The update failing after the
|
|
126
|
+
* import -> 409 `plugin.imported_not_updated` (the version stays in the catalog, the platform on
|
|
127
|
+
* its version, the extension's approval put back; details name the cause).
|
|
128
|
+
*/
|
|
129
|
+
importAndUpdate(principal: Principal, stagingId: string, body: z.infer<typeof CatalogImportUpdateBody>): Promise<PlatformImportUpdateResult>;
|
|
111
130
|
/**
|
|
112
131
|
* The item list (`includeDeleted=true` includes deleted items). Paging: `limit` (default 200, at
|
|
113
132
|
* most 1000) and `offset`; `nextOffset` is the next page's offset, null when there is none.
|
|
@@ -16,13 +16,14 @@ import { PluginIcons } from "../extensions/plugin-icons.js";
|
|
|
16
16
|
import { CurrentPrincipal, patTokenId, requireUser, SuperAdmin, } from "../identity/principal.js";
|
|
17
17
|
import { createZodDto } from "../infra/validation/create-zod-dto.js";
|
|
18
18
|
import { ZBody, ZQuery } from "../infra/validation/zod-params.js";
|
|
19
|
-
import { AdminCatalogGuideQuery, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogHash as Hash, CatalogNpmImportBody as NpmBody, CatalogScopeOrgs as Orgs, CatalogScope as Scope, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody, } from "./admin-catalog.schemas.js";
|
|
19
|
+
import { AdminCatalogGuideQuery, CatalogImportUpdateBody, CatalogItemsQuery, CatalogUpdateBody, CatalogUpdatePreviewBody, CatalogDisabledBody as DisabledBody, CatalogGitImportBody as GitBody, CatalogHash as Hash, CatalogNpmImportBody as NpmBody, CatalogScopeOrgs as Orgs, CatalogScope as Scope, CatalogScopeBody as ScopeBody, CatalogScopePreviewBody as ScopePreviewBody, CatalogShownBody as ShownBody, } from "./admin-catalog.schemas.js";
|
|
20
20
|
import { AppearanceApplyBody } from "./appearance.schemas.js";
|
|
21
21
|
import { AppearanceService, suggestedAppearanceOf, } from "./appearance.service.js";
|
|
22
22
|
import { CatalogService, } from "./catalog.service.js";
|
|
23
23
|
import { CatalogScopeService } from "./catalog-scope.service.js";
|
|
24
24
|
import { sendCatalogIcon } from "./org-catalog.controller.js";
|
|
25
25
|
import { OrgCatalogService } from "./org-catalog.service.js";
|
|
26
|
+
import { PlatformImportUpdate } from "./platform-import-update.js";
|
|
26
27
|
import { PluginImport } from "./plugin-import.js";
|
|
27
28
|
import { PlatformPluginUpdater, } from "./plugin-upgrade.js";
|
|
28
29
|
const ConfirmBody = z
|
|
@@ -66,6 +67,8 @@ class CatalogUpdatePreviewBodyDto extends createZodDto(CatalogUpdatePreviewBody,
|
|
|
66
67
|
}
|
|
67
68
|
class CatalogUpdateBodyDto extends createZodDto(CatalogUpdateBody, "CatalogUpdateBody") {
|
|
68
69
|
}
|
|
70
|
+
class CatalogImportUpdateBodyDto extends createZodDto(CatalogImportUpdateBody, "CatalogImportUpdateBody") {
|
|
71
|
+
}
|
|
69
72
|
class AppearanceApplyBodyDto extends createZodDto(AppearanceApplyBody, "AppearanceApplyBody") {
|
|
70
73
|
}
|
|
71
74
|
/**
|
|
@@ -80,16 +83,18 @@ let AdminCatalogController = class AdminCatalogController {
|
|
|
80
83
|
orgCatalog;
|
|
81
84
|
scope;
|
|
82
85
|
updater;
|
|
86
|
+
importUpdate;
|
|
83
87
|
icons;
|
|
84
88
|
appearance;
|
|
85
89
|
clientBuilds;
|
|
86
90
|
guides;
|
|
87
|
-
constructor(catalog, pluginImport, orgCatalog, scope, updater, icons, appearance, clientBuilds, guides) {
|
|
91
|
+
constructor(catalog, pluginImport, orgCatalog, scope, updater, importUpdate, icons, appearance, clientBuilds, guides) {
|
|
88
92
|
this.catalog = catalog;
|
|
89
93
|
this.pluginImport = pluginImport;
|
|
90
94
|
this.orgCatalog = orgCatalog;
|
|
91
95
|
this.scope = scope;
|
|
92
96
|
this.updater = updater;
|
|
97
|
+
this.importUpdate = importUpdate;
|
|
93
98
|
this.icons = icons;
|
|
94
99
|
this.appearance = appearance;
|
|
95
100
|
this.clientBuilds = clientBuilds;
|
|
@@ -169,6 +174,28 @@ let AdminCatalogController = class AdminCatalogController {
|
|
|
169
174
|
...(body.orgs !== undefined && { orgs: body.orgs }),
|
|
170
175
|
}, actorOpts(actor));
|
|
171
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* What confirming a staged new version of an installed platform plugin would do as the platform
|
|
179
|
+
* update (`PlatformImportUpdate`, the one 更新到 wizard): the update preview of the staged
|
|
180
|
+
* version, nothing written (cancelling the wizard leaves only the staging row). Not a platform
|
|
181
|
+
* plugin yet -> 409 `plugin.upgrade_target_invalid` (reason `not_installed`); staging missing ->
|
|
182
|
+
* 404 `plugin.staging_not_found`; otherwise as `items/:id/update/preview`.
|
|
183
|
+
*/
|
|
184
|
+
importUpdatePreview(stagingId) {
|
|
185
|
+
return this.importUpdate.preview(stagingId);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Imports the staged version and updates the platform plugin to it, confirmed with the import
|
|
189
|
+
* review's `reviewHash` and the update preview's `diffHash` (201 `{ item, update }`). Stale review
|
|
190
|
+
* -> 409 `plugin.review_stale`, stale preview -> 409 `plugin.upgrade_stale`, another update
|
|
191
|
+
* running -> 409 `plugin.install_in_progress`: nothing written. The update failing after the
|
|
192
|
+
* import -> 409 `plugin.imported_not_updated` (the version stays in the catalog, the platform on
|
|
193
|
+
* its version, the extension's approval put back; details name the cause).
|
|
194
|
+
*/
|
|
195
|
+
importAndUpdate(principal, stagingId, body) {
|
|
196
|
+
const actor = requireUser(principal);
|
|
197
|
+
return this.importUpdate.confirm(actor.account.id, stagingId, body, actorOpts(actor));
|
|
198
|
+
}
|
|
172
199
|
/**
|
|
173
200
|
* The item list (`includeDeleted=true` includes deleted items). Paging: `limit` (default 200, at
|
|
174
201
|
* most 1000) and `offset`; `nextOffset` is the next page's offset, null when there is none.
|
|
@@ -367,6 +394,17 @@ __decorate([
|
|
|
367
394
|
__param(1, Param("stagingId")),
|
|
368
395
|
__param(2, ZBody(CatalogImportConfirmBody))
|
|
369
396
|
], AdminCatalogController.prototype, "confirm", null);
|
|
397
|
+
__decorate([
|
|
398
|
+
Get("imports/:stagingId/update-preview"),
|
|
399
|
+
__param(0, Param("stagingId"))
|
|
400
|
+
], AdminCatalogController.prototype, "importUpdatePreview", null);
|
|
401
|
+
__decorate([
|
|
402
|
+
Post("imports/:stagingId/update"),
|
|
403
|
+
HttpCode(201),
|
|
404
|
+
__param(0, CurrentPrincipal()),
|
|
405
|
+
__param(1, Param("stagingId")),
|
|
406
|
+
__param(2, ZBody(CatalogImportUpdateBodyDto))
|
|
407
|
+
], AdminCatalogController.prototype, "importAndUpdate", null);
|
|
370
408
|
__decorate([
|
|
371
409
|
Get("items"),
|
|
372
410
|
__param(0, ZQuery(CatalogItemsQueryDto))
|
|
@@ -457,9 +495,10 @@ AdminCatalogController = __decorate([
|
|
|
457
495
|
__param(2, Inject(OrgCatalogService)),
|
|
458
496
|
__param(3, Inject(CatalogScopeService)),
|
|
459
497
|
__param(4, Inject(PlatformPluginUpdater)),
|
|
460
|
-
__param(5, Inject(
|
|
461
|
-
__param(6, Inject(
|
|
462
|
-
__param(7, Inject(
|
|
463
|
-
__param(8, Inject(
|
|
498
|
+
__param(5, Inject(PlatformImportUpdate)),
|
|
499
|
+
__param(6, Inject(PluginIcons)),
|
|
500
|
+
__param(7, Inject(AppearanceService)),
|
|
501
|
+
__param(8, Inject(ClientBuilds)),
|
|
502
|
+
__param(9, Inject(PluginGuides))
|
|
464
503
|
], AdminCatalogController);
|
|
465
504
|
export { AdminCatalogController };
|
|
@@ -20,6 +20,11 @@ export declare const CatalogUpdateBody: z.ZodObject<{
|
|
|
20
20
|
version: z.ZodString;
|
|
21
21
|
diffHash: z.ZodString;
|
|
22
22
|
}, z.core.$strict>;
|
|
23
|
+
/** `POST imports/:stagingId/update`: the import review's hash and the update preview's. */
|
|
24
|
+
export declare const CatalogImportUpdateBody: z.ZodObject<{
|
|
25
|
+
reviewHash: z.ZodString;
|
|
26
|
+
diffHash: z.ZodString;
|
|
27
|
+
}, z.core.$strict>;
|
|
23
28
|
/** `:id` as the routes take it (`@Param`). */
|
|
24
29
|
export declare const CatalogIdPathParams: z.ZodObject<{
|
|
25
30
|
id: z.ZodString;
|
|
@@ -13,6 +13,10 @@ export const CatalogUpdatePreviewBody = z.object({ version: CatalogVersion }).st
|
|
|
13
13
|
export const CatalogUpdateBody = z
|
|
14
14
|
.object({ version: CatalogVersion, diffHash: CatalogHash })
|
|
15
15
|
.strict();
|
|
16
|
+
/** `POST imports/:stagingId/update`: the import review's hash and the update preview's. */
|
|
17
|
+
export const CatalogImportUpdateBody = z
|
|
18
|
+
.object({ reviewHash: CatalogHash, diffHash: CatalogHash })
|
|
19
|
+
.strict();
|
|
16
20
|
/** `:id` as the routes take it (`@Param`). */
|
|
17
21
|
export const CatalogIdPathParams = z.object({ id: z.string().min(1) });
|
|
18
22
|
/** `:stagingId` of a staged import as the route takes it (`@Param`). */
|
|
@@ -75,6 +79,10 @@ export const ADMIN_CATALOG_ROUTES = [
|
|
|
75
79
|
{ route: "POST /api/v1/admin/catalog/import/npm", body: CatalogNpmImportBody },
|
|
76
80
|
{ route: "POST /api/v1/admin/catalog/import/git", body: CatalogGitImportBody },
|
|
77
81
|
{ route: "GET /api/v1/admin/catalog/imports/:stagingId", params: CatalogStagingPathParams },
|
|
82
|
+
{
|
|
83
|
+
route: "GET /api/v1/admin/catalog/imports/:stagingId/update-preview",
|
|
84
|
+
params: CatalogStagingPathParams,
|
|
85
|
+
},
|
|
78
86
|
{
|
|
79
87
|
route: "POST /api/v1/admin/catalog/items/:id/scope/preview",
|
|
80
88
|
params: CatalogIdPathParams,
|
|
@@ -72,6 +72,11 @@ export interface OrgCatalogTemplate {
|
|
|
72
72
|
editableEndpoint: string[];
|
|
73
73
|
auth: Record<string, unknown>;
|
|
74
74
|
ownership: "org" | "personal" | null;
|
|
75
|
+
/**
|
|
76
|
+
* The template file says `defaultEnabled: false`: it starts switched off in every org, so the
|
|
77
|
+
* install wizard does not ask for it (an org admin sets it up when switching it on).
|
|
78
|
+
*/
|
|
79
|
+
defaultOff: boolean;
|
|
75
80
|
/**
|
|
76
81
|
* The template's setup guide in the item's latest version (`GET …/catalog/:itemId/guides/
|
|
77
82
|
* :guideId`), null without one (spec 2026-11-09-setup-guides-v2-design.md §9.3).
|
|
@@ -2,7 +2,8 @@ import { CatalogImportModule } from "./catalog-import.module.js";
|
|
|
2
2
|
export { CatalogImportModule };
|
|
3
3
|
/**
|
|
4
4
|
* The plugin catalog (spec §4, §10): {@link CatalogImportModule}, catalog requests, org installs
|
|
5
|
-
* with their dependencies, the platform plugin update (`PlatformPluginUpdater`)
|
|
5
|
+
* with their dependencies, the platform plugin update (`PlatformPluginUpdater`) and the update to a
|
|
6
|
+
* staged version (`PlatformImportUpdate`), the admin's scope
|
|
6
7
|
* and disable
|
|
7
8
|
* (`CatalogScopeService`), org admins' plugin uploads (`OrgPluginUploads`) and their own plugins (`OwnedItems`), and the producer of the plugin scope sync
|
|
8
9
|
* (`PluginScopeSync`; its consumer is the worker role's `PluginScopeWorkersModule`). The catalog's periodic jobs (`CatalogJobs`) are
|
|
@@ -21,6 +21,7 @@ import { OrgCatalogService } from "./org-catalog.service.js";
|
|
|
21
21
|
import { OrgExtensionSwitch } from "./org-extension-switch.js";
|
|
22
22
|
import { OrgPluginUploads } from "./org-plugin-uploads.js";
|
|
23
23
|
import { OwnedItems } from "./owned-items.js";
|
|
24
|
+
import { PlatformImportUpdate } from "./platform-import-update.js";
|
|
24
25
|
import { PluginInstaller } from "./plugin-install.js";
|
|
25
26
|
import { PlatformPluginUpdater } from "./plugin-upgrade.js";
|
|
26
27
|
import { CatalogRequestsService } from "./requests.service.js";
|
|
@@ -32,7 +33,8 @@ const PLUGIN_SCOPE_QUEUE_MODULE = QueueModule.registerQueue(PLUGIN_SCOPE_QUEUE);
|
|
|
32
33
|
const MAINTENANCE_QUEUE_MODULE = QueueModule.registerQueue(MAINTENANCE_QUEUE_NAME);
|
|
33
34
|
/**
|
|
34
35
|
* The plugin catalog (spec §4, §10): {@link CatalogImportModule}, catalog requests, org installs
|
|
35
|
-
* with their dependencies, the platform plugin update (`PlatformPluginUpdater`)
|
|
36
|
+
* with their dependencies, the platform plugin update (`PlatformPluginUpdater`) and the update to a
|
|
37
|
+
* staged version (`PlatformImportUpdate`), the admin's scope
|
|
36
38
|
* and disable
|
|
37
39
|
* (`CatalogScopeService`), org admins' plugin uploads (`OrgPluginUploads`) and their own plugins (`OwnedItems`), and the producer of the plugin scope sync
|
|
38
40
|
* (`PluginScopeSync`; its consumer is the worker role's `PluginScopeWorkersModule`). The catalog's periodic jobs (`CatalogJobs`) are
|
|
@@ -69,6 +71,7 @@ CatalogModule = __decorate([
|
|
|
69
71
|
ComponentScopeService,
|
|
70
72
|
OrgPluginUploads,
|
|
71
73
|
OwnedItems,
|
|
74
|
+
PlatformImportUpdate,
|
|
72
75
|
],
|
|
73
76
|
exports: [
|
|
74
77
|
PLUGIN_SCOPE_QUEUE_MODULE,
|
|
@@ -84,6 +87,7 @@ CatalogModule = __decorate([
|
|
|
84
87
|
ComponentScopeService,
|
|
85
88
|
OrgPluginUploads,
|
|
86
89
|
OwnedItems,
|
|
90
|
+
PlatformImportUpdate,
|
|
87
91
|
],
|
|
88
92
|
})
|
|
89
93
|
], CatalogModule);
|
|
@@ -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.18";
|
|
192
192
|
};
|
|
193
193
|
/** Whether this deployment satisfies the entry's `minKernel`. */
|
|
194
194
|
export declare const entryCompatible: (e: Pick<MarketplaceEntry, "minKernel">) => boolean;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { KernelLogger } from "../log.js";
|
|
2
|
+
import type { ActorOpts, CatalogItemView } from "./catalog.service.js";
|
|
3
|
+
import { PluginImport } from "./plugin-import.js";
|
|
4
|
+
import { PlatformPluginUpdater, type PlatformUpdatePreview, type PlatformUpdateResult } from "./plugin-upgrade.js";
|
|
5
|
+
/** `POST /api/v1/admin/catalog/imports/:stagingId/update`: the import and the update it applied. */
|
|
6
|
+
export interface PlatformImportUpdateResult {
|
|
7
|
+
item: CatalogItemView;
|
|
8
|
+
update: PlatformUpdateResult;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The platform's update of an installed plugin to a version staged for import (the one wizard of
|
|
12
|
+
* the admin plugin pages, maintainer decision 2026-11-13): the import review (prepared as any
|
|
13
|
+
* import, `PluginImport.prepare`) and the platform update preview of the staged version
|
|
14
|
+
* ({@link preview}: `PlatformPluginUpdater.previewStaged`, the target read from the staging) are
|
|
15
|
+
* confirmed together ({@link confirm} with the review's `reviewHash` and the preview's `diffHash`).
|
|
16
|
+
* Nothing is written before that confirm: cancelling the wizard leaves only the staging row, which
|
|
17
|
+
* expires like any staged import.
|
|
18
|
+
*
|
|
19
|
+
* The confirm holds the item's update lock (`PlatformPluginUpdater.withItemLock`, one per item
|
|
20
|
+
* across replicas: another update -> 409 `plugin.install_in_progress`), recomputes the preview
|
|
21
|
+
* (another `diffHash` -> 409 `plugin.upgrade_stale`, nothing written), commits the import without
|
|
22
|
+
* deploying its extension (the permission snapshot is written as the review approved it), then
|
|
23
|
+
* runs the platform update, which moves the extension with its own rollback and writes the
|
|
24
|
+
* components in one transaction. When that update fails, the platform stays on its version, the
|
|
25
|
+
* extension where it was and its previous approval is put back; the imported version stays in the
|
|
26
|
+
* catalog (its 版本 tab, and 更新到 retries the update with the plain update preview): 409
|
|
27
|
+
* `plugin.imported_not_updated` says so, with the cause in the details. No in-process state.
|
|
28
|
+
*/
|
|
29
|
+
export declare class PlatformImportUpdate {
|
|
30
|
+
private readonly pluginImport;
|
|
31
|
+
private readonly updater;
|
|
32
|
+
private readonly log;
|
|
33
|
+
constructor(pluginImport: PluginImport, updater: PlatformPluginUpdater, log: KernelLogger);
|
|
34
|
+
/**
|
|
35
|
+
* The platform update the staged version would apply (writes nothing). The staging must be a
|
|
36
|
+
* platform staging (else 404 `plugin.staging_not_found`) of a new version of a live
|
|
37
|
+
* platform-owned plugin (else 409 `plugin.upgrade_target_invalid`, reason `not_installed`); the
|
|
38
|
+
* updater's refusals apply as for any update preview. `needsApproval` is false: the confirm
|
|
39
|
+
* approves the permissions the review shows.
|
|
40
|
+
*/
|
|
41
|
+
preview(stagingId: string): Promise<PlatformUpdatePreview>;
|
|
42
|
+
/** Confirms the import and the update together (see the class comment). */
|
|
43
|
+
confirm(actor: string, stagingId: string, input: {
|
|
44
|
+
reviewHash: string;
|
|
45
|
+
diffHash: string;
|
|
46
|
+
}, opts?: ActorOpts): Promise<PlatformImportUpdateResult>;
|
|
47
|
+
/** The staged target, which must be a new version of a live platform-owned plugin. */
|
|
48
|
+
private target;
|
|
49
|
+
private previewOf;
|
|
50
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
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
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
8
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
9
|
+
};
|
|
10
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
11
|
+
import { ApiError } from "../errors.js";
|
|
12
|
+
import { KERNEL_LOGGER } from "../infra/tokens.js";
|
|
13
|
+
import { PluginImport } from "./plugin-import.js";
|
|
14
|
+
import { PlatformPluginUpdater, } from "./plugin-upgrade.js";
|
|
15
|
+
const notInstalled = (name) => new ApiError("plugin.upgrade_target_invalid", `Plugin ${name} is not a platform plugin of this deployment yet; install it with the import review instead`, [{ reason: "not_installed" }]);
|
|
16
|
+
/**
|
|
17
|
+
* The platform's update of an installed plugin to a version staged for import (the one wizard of
|
|
18
|
+
* the admin plugin pages, maintainer decision 2026-11-13): the import review (prepared as any
|
|
19
|
+
* import, `PluginImport.prepare`) and the platform update preview of the staged version
|
|
20
|
+
* ({@link preview}: `PlatformPluginUpdater.previewStaged`, the target read from the staging) are
|
|
21
|
+
* confirmed together ({@link confirm} with the review's `reviewHash` and the preview's `diffHash`).
|
|
22
|
+
* Nothing is written before that confirm: cancelling the wizard leaves only the staging row, which
|
|
23
|
+
* expires like any staged import.
|
|
24
|
+
*
|
|
25
|
+
* The confirm holds the item's update lock (`PlatformPluginUpdater.withItemLock`, one per item
|
|
26
|
+
* across replicas: another update -> 409 `plugin.install_in_progress`), recomputes the preview
|
|
27
|
+
* (another `diffHash` -> 409 `plugin.upgrade_stale`, nothing written), commits the import without
|
|
28
|
+
* deploying its extension (the permission snapshot is written as the review approved it), then
|
|
29
|
+
* runs the platform update, which moves the extension with its own rollback and writes the
|
|
30
|
+
* components in one transaction. When that update fails, the platform stays on its version, the
|
|
31
|
+
* extension where it was and its previous approval is put back; the imported version stays in the
|
|
32
|
+
* catalog (its 版本 tab, and 更新到 retries the update with the plain update preview): 409
|
|
33
|
+
* `plugin.imported_not_updated` says so, with the cause in the details. No in-process state.
|
|
34
|
+
*/
|
|
35
|
+
let PlatformImportUpdate = class PlatformImportUpdate {
|
|
36
|
+
pluginImport;
|
|
37
|
+
updater;
|
|
38
|
+
log;
|
|
39
|
+
constructor(pluginImport, updater, log) {
|
|
40
|
+
this.pluginImport = pluginImport;
|
|
41
|
+
this.updater = updater;
|
|
42
|
+
this.log = log;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The platform update the staged version would apply (writes nothing). The staging must be a
|
|
46
|
+
* platform staging (else 404 `plugin.staging_not_found`) of a new version of a live
|
|
47
|
+
* platform-owned plugin (else 409 `plugin.upgrade_target_invalid`, reason `not_installed`); the
|
|
48
|
+
* updater's refusals apply as for any update preview. `needsApproval` is false: the confirm
|
|
49
|
+
* approves the permissions the review shows.
|
|
50
|
+
*/
|
|
51
|
+
async preview(stagingId) {
|
|
52
|
+
const st = await this.target(stagingId);
|
|
53
|
+
return this.previewOf(st);
|
|
54
|
+
}
|
|
55
|
+
/** Confirms the import and the update together (see the class comment). */
|
|
56
|
+
async confirm(actor, stagingId, input, opts = {}) {
|
|
57
|
+
const st = await this.target(stagingId);
|
|
58
|
+
return this.updater.withItemLock(st.itemId, async () => {
|
|
59
|
+
const preview = await this.previewOf(st);
|
|
60
|
+
if (preview.diffHash !== input.diffHash) {
|
|
61
|
+
throw new ApiError("plugin.upgrade_stale", `What updating plugin ${preview.name} to ${st.version} does changed since the preview; preview it again`);
|
|
62
|
+
}
|
|
63
|
+
// The review hash is checked by the import's confirm (409 plugin.review_stale, nothing
|
|
64
|
+
// written)
|
|
65
|
+
const imported = await this.pluginImport.confirm(actor, stagingId, { reviewHash: input.reviewHash, deploy: false }, opts);
|
|
66
|
+
try {
|
|
67
|
+
const update = await this.updater.updateHeld(actor, st.itemId, { version: st.version, diffHash: input.diffHash }, opts);
|
|
68
|
+
return { item: await this.pluginImport.view(st.itemId), update };
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
let restored = imported.approval === undefined;
|
|
72
|
+
if (imported.approval !== undefined) {
|
|
73
|
+
try {
|
|
74
|
+
restored = await this.pluginImport.restoreApproval(actor, imported.approval, opts);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
this.log.error("cannot restore an extension's approval after a failed update", {
|
|
78
|
+
itemId: st.itemId,
|
|
79
|
+
err,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const cause = e instanceof ApiError ? e : undefined;
|
|
84
|
+
throw new ApiError("plugin.imported_not_updated", `Version ${st.version} of plugin ${preview.name} was imported, but updating the platform to it failed (${cause?.code ?? "internal"}); the platform stays on ${preview.from ?? "(none)"}. Update to ${st.version} from the plugin's page to retry`, [
|
|
85
|
+
{
|
|
86
|
+
version: st.version,
|
|
87
|
+
from: preview.from,
|
|
88
|
+
code: cause?.code ?? "internal",
|
|
89
|
+
...(cause !== undefined && { message: cause.message }),
|
|
90
|
+
...(cause?.details !== undefined && { causeDetails: cause.details }),
|
|
91
|
+
approvalRestored: restored,
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/** The staged target, which must be a new version of a live platform-owned plugin. */
|
|
98
|
+
async target(stagingId) {
|
|
99
|
+
const st = await this.pluginImport.stagedTarget(stagingId);
|
|
100
|
+
if (!st.existing) {
|
|
101
|
+
throw notInstalled((await this.pluginImport.staged(stagingId)).review.name);
|
|
102
|
+
}
|
|
103
|
+
return st;
|
|
104
|
+
}
|
|
105
|
+
async previewOf(st) {
|
|
106
|
+
const p = await this.updater.previewStaged(st.itemId, st.version, st.target);
|
|
107
|
+
return p.extension === null ? p : { ...p, extension: { ...p.extension, needsApproval: false } };
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
PlatformImportUpdate = __decorate([
|
|
111
|
+
Injectable(),
|
|
112
|
+
__param(0, Inject(PluginImport)),
|
|
113
|
+
__param(1, Inject(PlatformPluginUpdater)),
|
|
114
|
+
__param(2, Inject(KERNEL_LOGGER))
|
|
115
|
+
], PlatformImportUpdate);
|
|
116
|
+
export { PlatformImportUpdate };
|
|
@@ -8,6 +8,7 @@ import { ExtensionBlobs } from "../extensions/blobs.js";
|
|
|
8
8
|
import { ExtensionInstalls } from "../extensions/installs.js";
|
|
9
9
|
import { PluginApproveLock, PluginInstallLock } from "../extensions/locks.js";
|
|
10
10
|
import { ExtensionPackageError } from "../extensions/package.js";
|
|
11
|
+
import { type PermissionSet } from "../extensions/permission-set.js";
|
|
11
12
|
import { type PackageWarning, type PermissionGroup, type PermissionItem } from "../extensions/permission-view.js";
|
|
12
13
|
import { ExtensionRegistry } from "../extensions/registry.js";
|
|
13
14
|
import type { SingleProviderBlock } from "../extensions/single-provider.js";
|
|
@@ -317,6 +318,18 @@ export interface PluginConfirmResult {
|
|
|
317
318
|
* extension (applied at once, plan Task 6).
|
|
318
319
|
*/
|
|
319
320
|
firstVersion: boolean;
|
|
321
|
+
/**
|
|
322
|
+
* A confirm with `deploy: false` that approved the extension's permissions (its snapshot
|
|
323
|
+
* written): what {@link PluginImport.restoreApproval} needs to put the previous approval back
|
|
324
|
+
* when the step that was to deploy it fails. Never sent over HTTP (the route always deploys).
|
|
325
|
+
*/
|
|
326
|
+
approval?: HeldApproval;
|
|
327
|
+
}
|
|
328
|
+
/** The approval a confirm without its deploy wrote (see {@link PluginConfirmResult.approval}). */
|
|
329
|
+
export interface HeldApproval {
|
|
330
|
+
review: PluginReview;
|
|
331
|
+
extension: PluginReviewExtension;
|
|
332
|
+
previous: PreviousSnapshot | null;
|
|
320
333
|
}
|
|
321
334
|
/** What prepare checks besides the package itself (npm and marketplace imports). */
|
|
322
335
|
export interface PluginPrepareExpect {
|
|
@@ -338,6 +351,14 @@ export interface ReviewProvenance {
|
|
|
338
351
|
provenance: ProvenanceResult;
|
|
339
352
|
warning?: "repository_mismatch";
|
|
340
353
|
}
|
|
354
|
+
/** The snapshot overwritten at confirm (restored when deploying an upgrade fails). */
|
|
355
|
+
export interface PreviousSnapshot {
|
|
356
|
+
version: string;
|
|
357
|
+
permissions: PermissionSet;
|
|
358
|
+
approvedBy: string | null;
|
|
359
|
+
approvedAt: Date;
|
|
360
|
+
source: "auto" | "web" | "cli" | "bootstrap";
|
|
361
|
+
}
|
|
341
362
|
/** What an org's staged upload targets (see {@link PluginImport.stagedTarget}). */
|
|
342
363
|
export interface StagedTarget {
|
|
343
364
|
itemId: string;
|
|
@@ -521,8 +542,10 @@ export declare class PluginImport {
|
|
|
521
542
|
* whether the item exists (a new version of the org's own plugin) or the version is imported
|
|
522
543
|
* already (F4), and the target as the platform updater reads it: the staged manifest and files,
|
|
523
544
|
* or the imported version's for a retry. Another org's staging -> 404 `plugin.staging_not_found`.
|
|
545
|
+
* Without `owner`: a platform staging, and `existing` means a live platform-owned item (the
|
|
546
|
+
* platform's import and update, `PlatformImportUpdate`).
|
|
524
547
|
*/
|
|
525
|
-
stagedTarget(stagingId: string, owner
|
|
548
|
+
stagedTarget(stagingId: string, owner?: ImportOwner): Promise<StagedTarget>;
|
|
526
549
|
/** The catalog item's view (as a confirm returns it). */
|
|
527
550
|
view(itemId: string): Promise<CatalogItemView>;
|
|
528
551
|
/**
|
|
@@ -553,6 +576,13 @@ export declare class PluginImport {
|
|
|
553
576
|
orgs?: string[];
|
|
554
577
|
/** An org upload's new item: shared with other orgs by its owner (default false, P3-16). */
|
|
555
578
|
shareable?: boolean;
|
|
579
|
+
/**
|
|
580
|
+
* Deploy the extension after the commit (default true). false (the platform's import and
|
|
581
|
+
* update, `PlatformImportUpdate`) leaves the deployment to the platform update that follows,
|
|
582
|
+
* which moves the extension with its own rollback; the approval written is returned in
|
|
583
|
+
* `approval`.
|
|
584
|
+
*/
|
|
585
|
+
deploy?: boolean;
|
|
556
586
|
}, opts?: ActorOpts & {
|
|
557
587
|
owner?: ImportOwner;
|
|
558
588
|
}): Promise<PluginConfirmResult>;
|
|
@@ -603,6 +633,11 @@ export declare class PluginImport {
|
|
|
603
633
|
* admin (the package is already in the package store) with the sha256 from the result.
|
|
604
634
|
*/
|
|
605
635
|
private deploy;
|
|
636
|
+
/**
|
|
637
|
+
* Puts back the approval a confirm with `deploy: false` wrote, after the step that was to deploy
|
|
638
|
+
* the extension failed (see {@link restoreSnapshot}; false when someone changed it meanwhile).
|
|
639
|
+
*/
|
|
640
|
+
restoreApproval(actor: string | null, held: HeldApproval, opts?: ActorOpts): Promise<boolean>;
|
|
606
641
|
/**
|
|
607
642
|
* Restores the snapshot overwritten at confirm (deletes it when there was none before), audits
|
|
608
643
|
* `extension.permissions_restored`. Compare-and-write (row locked): restores only while the
|