feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,982 @@
// Plugin Package owns its authenticated lifecycle command surface.
import { randomUUID } from 'node:crypto';
import path from 'node:path';
import {
PrivateLocalCommandFileError,
readPrivateLocalCommandFile,
} from '@qinglong/local-command-file';
import {
establishAuthenticatedLocalCommand,
type AuthenticatedLocalCommand,
} from '@qinglong/local-owner-console/authenticated-command';
import {
openLocalSqlitePluginPackageManagementDatabase,
type LocalSqlitePluginPackageManagementDatabase,
type LocalSqliteProfile,
} from '@qinglong/local-sqlite/package-management';
import type {
ApprovalRequestRecord,
ApprovedActionDispatchRecord,
} from '@qinglong/runtime-core/approved-action';
import type { ApprovedActionDispatchBatchSummary } from '@qinglong/runtime-core/approved-action-dispatcher';
import {
normalizePluginPackageLifecycleImpact,
type PluginPackageLifecycleAction,
type PluginPackageLifecycleImpact,
type PluginPackageLifecycleReceipt,
} from '@qinglong/runtime-core/plugin-package-lifecycle';
import {
pluginPackageInstallRecoveryAction,
type PluginPackageInstallActionInput,
type PluginPackageInstallInventoryItem,
} from '@qinglong/runtime-core/plugin-package-install';
import type { PluginPackageInstallProposal } from '@qinglong/runtime-core/plugin-package-proposal';
import { createLocalPluginPackageManagementService } from '@qinglong/local-admin/package-management';
import { createLocalPluginPackageLifecycleService } from '@qinglong/local-admin/package-lifecycle';
const MAX_PATH_BYTES = 4096;
const MAX_DISPATCH_LIMIT = 64;
const LOCAL_INSTALLATION_INVENTORY_LIMITS = Object.freeze({
edge: 16,
standalone: 64,
});
const LOCAL_INSTALLATION_INVENTORY_DEFAULTS = Object.freeze({
edge: 8,
standalone: 32,
});
const PROJECT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
const PACKAGE_NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
const COMMAND_IDENTIFIER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
const REASON_CODE_PATTERN = /^[a-z][a-z0-9_]{0,63}$/;
const LOCAL_PACKAGE_CONSUMER = Object.freeze({
subject: Object.freeze({
type: 'system' as const,
id: 'local_plugin_package_consumer',
}),
authenticationId: 'local_plugin_package_consumer_v1',
});
export interface LocalPluginPackageCommandOptions {
readonly deploymentRoot: string;
readonly databasePath: string;
readonly profile: LocalSqliteProfile;
readonly ownerPepperKeyringDirectory: string;
readonly credentialFilePath: string;
readonly busyTimeoutMs?: number;
}
export interface ProposeLocalPluginPackageCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.propose';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly actionRef: string;
readonly approvalRequestId: string;
readonly proposalAuditEventId: string;
readonly approvalAuditEventId: string;
readonly actionInput: PluginPackageInstallActionInput;
};
}
export interface DecideLocalPluginPackageCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.decide';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly actionRef: string;
readonly approvalRequestId: string;
readonly expectedVersion: number;
readonly decisionId: string;
readonly auditEventId: string;
readonly decision: 'approved' | 'rejected';
readonly reasonCode: string;
};
}
export interface ConsumeLocalPluginPackageCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.consume';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly actionRef: string;
readonly approvalRequestId: string;
readonly expectedVersion: number;
readonly consumptionId: string;
readonly dispatchId: string;
readonly auditEventId: string;
};
}
export interface InspectLocalPluginPackageCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.inspect';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly actionRef: string;
readonly approvalRequestId: string;
};
}
export interface InspectLocalPluginPackageInstallationCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.installation.inspect';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly projectId: string;
readonly packageName: string;
};
}
export interface ListLocalPluginPackageInstallationsCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.installation.list';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly projectId: string;
readonly limit?: number;
readonly after?: Readonly<{ packageName: string }>;
};
}
export interface DispatchLocalPluginPackageCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.dispatch';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly limit?: number;
};
}
export interface PlanLocalPluginPackageLifecycleCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.lifecycle.plan';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly action: PluginPackageLifecycleAction;
readonly projectId: string;
readonly packageName: string;
};
}
export interface ExecuteLocalPluginPackageLifecycleCommand {
readonly schemaVersion: 1;
readonly operation: 'plugin-package.lifecycle.execute';
readonly options: LocalPluginPackageCommandOptions;
readonly request: {
readonly impact: PluginPackageLifecycleImpact;
readonly approvalRequestId: string;
readonly decisionId: string;
readonly consumptionId: string;
readonly dispatchId: string;
readonly approvalAuditEventId: string;
readonly decisionAuditEventId: string;
readonly consumptionAuditEventId: string;
readonly reasonCode: string;
};
}
export type LocalPluginPackageCommand =
| ProposeLocalPluginPackageCommand
| DecideLocalPluginPackageCommand
| ConsumeLocalPluginPackageCommand
| InspectLocalPluginPackageCommand
| InspectLocalPluginPackageInstallationCommand
| ListLocalPluginPackageInstallationsCommand
| DispatchLocalPluginPackageCommand
| PlanLocalPluginPackageLifecycleCommand
| ExecuteLocalPluginPackageLifecycleCommand;
export interface LocalPluginPackageCommandRunner {
run(
commandFilePath: string,
): Promise<Readonly<LocalPluginPackageCommandResult>>;
}
export type LocalPluginPackageCommandResult =
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.propose';
proposalStatus: 'created' | 'existing';
approvalStatus: 'created' | 'existing';
proposal: ReturnType<typeof proposalSummary>;
approval: ReturnType<typeof approvalSummary>;
}>
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.decide';
status: 'decided' | 'existing';
approval: ReturnType<typeof approvalSummary>;
}>
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.consume';
status: 'consumed' | 'existing';
approval: ReturnType<typeof approvalSummary>;
dispatch: ReturnType<typeof dispatchSummary>;
}>
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.inspect';
proposal: ReturnType<typeof proposalSummary> | null;
approval: ReturnType<typeof approvalSummary> | null;
}>
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.installation.inspect';
installation: ReturnType<typeof installationSummary> | null;
}>
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.installation.list';
installations: readonly ReturnType<typeof installationSummary>[];
truncated: boolean;
next: Readonly<{ packageName: string }> | null;
}>
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.dispatch';
summary: Readonly<ApprovedActionDispatchBatchSummary>;
}>
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.lifecycle.plan';
impact: Readonly<PluginPackageLifecycleImpact>;
summary: ReturnType<typeof lifecycleImpactSummary>;
}>
| Readonly<{
schemaVersion: 1;
operation: 'plugin-package.lifecycle.execute';
status: 'created' | 'existing';
approval: ReturnType<typeof approvalSummary>;
receipt: ReturnType<typeof lifecycleReceiptSummary>;
}>;
export class LocalPluginPackageCommandConfigurationError extends TypeError {
readonly code = 'LOCAL_PLUGIN_PACKAGE_COMMAND_CONFIGURATION_INVALID';
constructor(message: string, readonly cause?: unknown) {
super(`Local Plugin Package command configuration is invalid: ${message}`);
this.name = 'LocalPluginPackageCommandConfigurationError';
}
}
interface LocalPluginPackageCommandRunnerDependencies {
readonly openDatabase: typeof openLocalSqlitePluginPackageManagementDatabase;
readonly authenticate: typeof establishAuthenticatedLocalCommand;
}
function exactObject(
value: unknown,
expectedKeys: readonly string[],
label: string,
): asserts value is Record<string, unknown> {
if (!value || typeof value !== 'object' || Array.isArray(value)) {
throw new LocalPluginPackageCommandConfigurationError(
`${label} must be an object`,
);
}
const actual = Object.keys(value).sort();
const expected = [...expectedKeys].sort();
if (
actual.length !== expected.length ||
actual.some((key, index) => key !== expected[index])
) {
throw new LocalPluginPackageCommandConfigurationError(
`${label} shape is invalid`,
);
}
}
function boundedPath(value: unknown, label: string): string {
if (
typeof value !== 'string' ||
!path.isAbsolute(value) ||
path.parse(value).root === value ||
path.normalize(value) !== value ||
value.includes('\0') ||
Buffer.byteLength(value, 'utf8') > MAX_PATH_BYTES
) {
throw new LocalPluginPackageCommandConfigurationError(
`${label} must be a normalized bounded absolute non-root path`,
);
}
return value;
}
function options(value: unknown): LocalPluginPackageCommandOptions {
const hasBusyTimeout =
!!value &&
typeof value === 'object' &&
!Array.isArray(value) &&
Object.hasOwn(value, 'busyTimeoutMs');
exactObject(
value,
[
'deploymentRoot',
'databasePath',
'profile',
'ownerPepperKeyringDirectory',
'credentialFilePath',
...(hasBusyTimeout ? ['busyTimeoutMs'] : []),
],
'options',
);
for (const key of [
'deploymentRoot',
'databasePath',
'ownerPepperKeyringDirectory',
'credentialFilePath',
] as const) {
boundedPath(value[key], key);
}
if (value.profile !== 'edge' && value.profile !== 'standalone') {
throw new LocalPluginPackageCommandConfigurationError(
'profile must be edge or standalone',
);
}
if (
value.busyTimeoutMs !== undefined &&
(!Number.isSafeInteger(value.busyTimeoutMs) ||
(value.busyTimeoutMs as number) < 100 ||
(value.busyTimeoutMs as number) > 30_000)
) {
throw new LocalPluginPackageCommandConfigurationError(
'busyTimeoutMs is invalid',
);
}
return Object.freeze(value as unknown as LocalPluginPackageCommandOptions);
}
function normalizeCommand(value: unknown): Readonly<LocalPluginPackageCommand> {
exactObject(
value,
['schemaVersion', 'operation', 'options', 'request'],
'command',
);
if (value.schemaVersion !== 1) {
throw new LocalPluginPackageCommandConfigurationError(
'schemaVersion is invalid',
);
}
const commandOptions = options(value.options);
switch (value.operation) {
case 'plugin-package.propose':
exactObject(
value.request,
[
'actionRef',
'approvalRequestId',
'proposalAuditEventId',
'approvalAuditEventId',
'actionInput',
],
'proposal request',
);
break;
case 'plugin-package.decide':
exactObject(
value.request,
[
'actionRef',
'approvalRequestId',
'expectedVersion',
'decisionId',
'auditEventId',
'decision',
'reasonCode',
],
'decision request',
);
break;
case 'plugin-package.consume':
exactObject(
value.request,
[
'actionRef',
'approvalRequestId',
'expectedVersion',
'consumptionId',
'dispatchId',
'auditEventId',
],
'consumption request',
);
break;
case 'plugin-package.inspect':
exactObject(
value.request,
['actionRef', 'approvalRequestId'],
'inspection request',
);
break;
case 'plugin-package.installation.inspect':
exactObject(
value.request,
['packageName', 'projectId'],
'installation inspection request',
);
if (
typeof value.request.projectId !== 'string' ||
!PROJECT_ID_PATTERN.test(value.request.projectId) ||
typeof value.request.packageName !== 'string' ||
!PACKAGE_NAME_PATTERN.test(value.request.packageName)
) {
throw new LocalPluginPackageCommandConfigurationError(
'installation inspection identity is invalid',
);
}
break;
case 'plugin-package.installation.list': {
const request =
value.request && typeof value.request === 'object'
? (value.request as Record<string, unknown>)
: {};
const hasLimit = Object.hasOwn(request, 'limit');
const hasAfter = Object.hasOwn(request, 'after');
exactObject(
value.request,
[
'projectId',
...(hasLimit ? ['limit'] : []),
...(hasAfter ? ['after'] : []),
],
'installation list request',
);
if (
typeof request.projectId !== 'string' ||
!PROJECT_ID_PATTERN.test(request.projectId) ||
(request.limit !== undefined &&
(!Number.isSafeInteger(request.limit) ||
(request.limit as number) < 1 ||
(request.limit as number) >
LOCAL_INSTALLATION_INVENTORY_LIMITS[commandOptions.profile]))
) {
throw new LocalPluginPackageCommandConfigurationError(
'installation list request is invalid',
);
}
if (request.after !== undefined) {
exactObject(request.after, ['packageName'], 'installation list cursor');
if (
typeof request.after.packageName !== 'string' ||
!PACKAGE_NAME_PATTERN.test(request.after.packageName)
) {
throw new LocalPluginPackageCommandConfigurationError(
'installation list cursor is invalid',
);
}
}
break;
}
case 'plugin-package.dispatch': {
const hasLimit =
!!value.request &&
typeof value.request === 'object' &&
!Array.isArray(value.request) &&
Object.hasOwn(value.request, 'limit');
exactObject(value.request, hasLimit ? ['limit'] : [], 'dispatch request');
if (
(value.request as { limit?: unknown }).limit !== undefined &&
(!Number.isSafeInteger((value.request as { limit?: unknown }).limit) ||
((value.request as { limit?: number }).limit as number) < 1 ||
((value.request as { limit?: number }).limit as number) >
MAX_DISPATCH_LIMIT)
) {
throw new LocalPluginPackageCommandConfigurationError(
'dispatch limit is invalid',
);
}
break;
}
case 'plugin-package.lifecycle.plan':
exactObject(
value.request,
['action', 'packageName', 'projectId'],
'lifecycle plan request',
);
if (
(value.request.action !== 'disable' &&
value.request.action !== 'enable' &&
value.request.action !== 'uninstall') ||
typeof value.request.projectId !== 'string' ||
!PROJECT_ID_PATTERN.test(value.request.projectId) ||
typeof value.request.packageName !== 'string' ||
!PACKAGE_NAME_PATTERN.test(value.request.packageName)
) {
throw new LocalPluginPackageCommandConfigurationError(
'lifecycle plan request is invalid',
);
}
break;
case 'plugin-package.lifecycle.execute':
exactObject(
value.request,
[
'approvalAuditEventId',
'approvalRequestId',
'consumptionAuditEventId',
'consumptionId',
'decisionAuditEventId',
'decisionId',
'dispatchId',
'impact',
'reasonCode',
],
'lifecycle execution request',
);
try {
normalizePluginPackageLifecycleImpact(
value.request.impact as PluginPackageLifecycleImpact,
);
} catch (error) {
throw new LocalPluginPackageCommandConfigurationError(
'lifecycle impact is invalid',
error,
);
}
if (
[
value.request.approvalRequestId,
value.request.decisionId,
value.request.consumptionId,
value.request.dispatchId,
value.request.approvalAuditEventId,
value.request.decisionAuditEventId,
value.request.consumptionAuditEventId,
].some(
(candidate) =>
typeof candidate !== 'string' ||
!COMMAND_IDENTIFIER_PATTERN.test(candidate),
) ||
typeof value.request.reasonCode !== 'string' ||
!REASON_CODE_PATTERN.test(value.request.reasonCode)
) {
throw new LocalPluginPackageCommandConfigurationError(
'lifecycle execution identity is invalid',
);
}
break;
default:
throw new LocalPluginPackageCommandConfigurationError(
'operation is invalid',
);
}
return Object.freeze({
...value,
options: commandOptions,
} as unknown as LocalPluginPackageCommand);
}
function readCommandFile(
commandFilePath: string,
): Readonly<LocalPluginPackageCommand> {
try {
return normalizeCommand(readPrivateLocalCommandFile(commandFilePath));
} catch (error) {
if (error instanceof LocalPluginPackageCommandConfigurationError) {
throw error;
}
if (error instanceof PrivateLocalCommandFileError) {
throw new LocalPluginPackageCommandConfigurationError(
'command file cannot be read',
error,
);
}
throw error;
}
}
function proposalSummary(proposal: Readonly<PluginPackageInstallProposal>) {
return Object.freeze({
actionRef: proposal.actionRef,
projectId: proposal.projectId,
packageName: proposal.actionInput.manifest.metadata.name,
packageVersion: proposal.actionInput.manifest.metadata.version,
operation: proposal.actionInput.plan.operation,
sourceKind: proposal.actionInput.source.kind,
architecture: proposal.actionInput.architecture,
deploymentProfile: proposal.actionInput.deploymentProfile,
targetGeneration: proposal.actionInput.targetGeneration,
actionDigest: proposal.actionDigest,
previewDigest: proposal.previewDigest,
proposalDigest: proposal.proposalDigest,
createdAtMs: proposal.createdAtMs,
});
}
function approvalSummary(approval: Readonly<ApprovalRequestRecord>) {
return Object.freeze({
id: approval.id,
projectId: approval.projectId,
version: approval.version,
state: approval.state,
risk: approval.risk,
decisionMode: approval.decisionMode,
requestedAtMs: approval.requestedAtMs,
expiresAtMs: approval.expiresAtMs,
decision: approval.decision,
decisionReasonCode: approval.decisionReasonCode,
decidedAtMs: approval.decidedAtMs,
dispatchId: approval.dispatchId,
consumedAtMs: approval.consumedAtMs,
actionDigest: approval.action.actionDigest,
previewDigest: approval.action.previewDigest,
});
}
function dispatchSummary(dispatch: Readonly<ApprovedActionDispatchRecord>) {
return Object.freeze({
id: dispatch.id,
approvalRequestId: dispatch.approvalRequestId,
projectId: dispatch.projectId,
actionRef: dispatch.action.actionRef,
actionDigest: dispatch.action.actionDigest,
createdAtMs: dispatch.createdAtMs,
expiresAtMs: dispatch.expiresAtMs,
});
}
function installationSummary(
item: Readonly<PluginPackageInstallInventoryItem>,
) {
const { record, quarantine } = item;
return Object.freeze({
installationId: record.installationId,
projectId: record.projectId,
packageName: record.packageName,
packageVersion: record.packageVersion,
operation: record.operation,
state: record.state,
targetGeneration: record.targetGeneration,
activeLockDigest: record.activeLockDigest,
previousActiveLockDigest: record.previousActiveLockDigest,
recoveryAction: pluginPackageInstallRecoveryAction(record),
availability: quarantine
? ('quarantined' as const)
: record.state === 'active'
? ('active' as const)
: ('not_active' as const),
quarantineReason: quarantine?.reasonCode ?? null,
quarantineAuthorizationMode: quarantine?.authorizationMode ?? null,
quarantineEventDigest: quarantine?.eventDigest ?? null,
quarantinedAtMs: quarantine?.occurredAtMs ?? null,
withdrawalStatus: quarantine?.capabilityStatus ?? null,
withdrawalReceiptDigest: quarantine?.receiptDigest ?? null,
withdrawalCommittedAtMs: quarantine?.committedAtMs ?? null,
failureReason: record.failure?.reason ?? null,
failedFrom: record.failure?.failedFrom ?? null,
failedAtMs: record.failure?.failedAtMs ?? null,
version: record.version,
createdAtMs: record.createdAtMs,
updatedAtMs: record.updatedAtMs,
recordDigest: record.recordDigest,
});
}
function lifecycleImpactSummary(
impact: Readonly<PluginPackageLifecycleImpact>,
) {
return Object.freeze({
action: impact.action,
projectId: impact.target.projectId,
packageName: impact.target.packageName,
installationId: impact.target.installationId,
lockDigest: impact.target.lockDigest,
installVersion: impact.target.installVersion,
installRecordDigest: impact.target.installRecordDigest,
expectedVersion: impact.expected.version,
expectedDisposition: impact.expected.disposition,
expectedEventDigest: impact.expected.eventDigest,
generationDigest: impact.generationDigest,
materializedRevisionDigest: impact.materializedRevisionDigest,
currentToolSnapshotDigest: impact.currentToolSnapshotDigest,
taskIds: impact.taskIds,
resourceCounts: impact.resourceCounts,
referenceGraphDigest: impact.referenceGraphDigest,
blockingReferences: impact.blockingReferences,
impactDigest: impact.impactDigest,
});
}
function lifecycleReceiptSummary(
receipt: Readonly<PluginPackageLifecycleReceipt>,
) {
return Object.freeze({
eventDigest: receipt.eventDigest,
action: receipt.action,
projectId: receipt.target.projectId,
packageName: receipt.target.packageName,
installationId: receipt.target.installationId,
lockDigest: receipt.target.lockDigest,
lifecycleVersion: receipt.lifecycle.version,
disposition: receipt.lifecycle.disposition,
capabilityStatus: receipt.capability.status,
taskTransitions: receipt.capability.taskTransitions.length,
previousActiveVectorDigest:
receipt.capability.previousActiveVectorDigest,
currentActiveVectorDigest: receipt.capability.currentActiveVectorDigest,
currentToolSnapshotDigest: receipt.capability.currentToolSnapshotDigest,
retainedSourceCount: receipt.capability.retainedSourceCount,
committedAtMs: receipt.committedAtMs,
receiptDigest: receipt.receiptDigest,
});
}
async function execute(
command: Readonly<LocalPluginPackageCommand>,
database: LocalSqlitePluginPackageManagementDatabase,
authenticated: Readonly<AuthenticatedLocalCommand>,
): Promise<Readonly<LocalPluginPackageCommandResult>> {
await authenticated.confirm();
if (command.operation === 'plugin-package.lifecycle.plan') {
const service = createLocalPluginPackageLifecycleService({
authority: database.authority,
});
const impact = await service.plan(
command.request.action,
command.request.projectId,
command.request.packageName,
authenticated.principal,
);
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
impact,
summary: lifecycleImpactSummary(impact),
});
}
if (command.operation === 'plugin-package.lifecycle.execute') {
const service = createLocalPluginPackageLifecycleService({
authority: database.authority,
});
const result = await service.execute({
...command.request,
principal: authenticated.principal,
confirmAuthorization: authenticated.confirm,
});
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
status: result.status,
approval: approvalSummary(result.approval),
receipt: lifecycleReceiptSummary(result.receipt),
});
}
if (command.operation === 'plugin-package.installation.inspect') {
const { LocalSqlitePluginPackageInstallRepository } = await import(
'@qinglong/local-sqlite/plugin-package-install'
);
const repository = new LocalSqlitePluginPackageInstallRepository(
database.authority,
);
const item = await repository.findCurrent(
command.request.projectId,
command.request.packageName,
);
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
installation: item ? installationSummary(item) : null,
});
}
if (command.operation === 'plugin-package.installation.list') {
const { LocalSqlitePluginPackageInstallRepository } = await import(
'@qinglong/local-sqlite/plugin-package-install'
);
const repository = new LocalSqlitePluginPackageInstallRepository(
database.authority,
);
const page = await repository.listCurrentPage({
projectId: command.request.projectId,
limit:
command.request.limit ??
LOCAL_INSTALLATION_INVENTORY_DEFAULTS[command.options.profile],
...(command.request.after === undefined
? {}
: { after: command.request.after }),
});
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
installations: Object.freeze(page.items.map(installationSummary)),
truncated: page.truncated,
next: page.next ?? null,
});
}
const service = createLocalPluginPackageManagementService({
authority: database.authority,
profile: command.options.profile,
consumer: LOCAL_PACKAGE_CONSUMER,
dispatcher: {
owner: 'local_plugin_package_dispatcher',
defaultBatchSize: 4,
createId: randomUUID,
},
});
switch (command.operation) {
case 'plugin-package.propose': {
const current = await service.inspect(
command.request.actionRef,
command.request.approvalRequestId,
);
const result = await service.propose({
...command.request,
requestedAtMs:
current.approvalRequest?.requestedAtMs ??
current.proposal?.createdAtMs ??
Date.now(),
principal: authenticated.principal,
});
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
proposalStatus: result.proposalStatus,
approvalStatus: result.approvalStatus,
proposal: proposalSummary(result.proposal),
approval: approvalSummary(result.approvalRequest),
});
}
case 'plugin-package.decide': {
const { actionRef, ...decisionRequest } = command.request;
const current = await service.inspect(
actionRef,
command.request.approvalRequestId,
);
if (
current.approvalRequest?.action.actionRef === actionRef &&
current.approvalRequest.decisionId === command.request.decisionId &&
current.approvalRequest.decision === command.request.decision &&
current.approvalRequest.decisionReasonCode ===
command.request.reasonCode &&
current.approvalRequest.decidedBy?.type ===
authenticated.principal.subject.type &&
current.approvalRequest.decidedBy.id ===
authenticated.principal.subject.id
) {
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
status: 'existing',
approval: approvalSummary(current.approvalRequest),
});
}
const result = await service.decide({
...decisionRequest,
decidedAtMs: Date.now(),
principal: authenticated.principal,
});
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
status: result.status,
approval: approvalSummary(result.request),
});
}
case 'plugin-package.consume': {
const { actionRef, ...consumptionRequest } = command.request;
const current = await service.inspect(
actionRef,
command.request.approvalRequestId,
);
const result = await service.consume({
...consumptionRequest,
consumedAtMs:
current.approvalRequest?.consumptionId ===
command.request.consumptionId &&
current.approvalRequest.dispatchId === command.request.dispatchId &&
current.approvalRequest.consumedAtMs !== null
? current.approvalRequest.consumedAtMs
: Date.now(),
});
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
status: result.status,
approval: approvalSummary(result.request),
dispatch: dispatchSummary(result.dispatch),
});
}
case 'plugin-package.inspect': {
const result = await service.inspect(
command.request.actionRef,
command.request.approvalRequestId,
);
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
proposal: result.proposal ? proposalSummary(result.proposal) : null,
approval: result.approvalRequest
? approvalSummary(result.approvalRequest)
: null,
});
}
case 'plugin-package.dispatch': {
const result = await service.dispatch(command.request.limit);
return Object.freeze({
schemaVersion: 1,
operation: command.operation,
summary: result,
});
}
}
}
function dependencies(
value: LocalPluginPackageCommandRunnerDependencies,
): Readonly<LocalPluginPackageCommandRunnerDependencies> {
if (
!value ||
typeof value !== 'object' ||
Array.isArray(value) ||
Object.keys(value).length !== 2 ||
typeof value.openDatabase !== 'function' ||
typeof value.authenticate !== 'function'
) {
throw new LocalPluginPackageCommandConfigurationError(
'runner dependencies are invalid',
);
}
return Object.freeze({ ...value });
}
export function createLocalPluginPackageCommandRunner(
candidateDependencies: LocalPluginPackageCommandRunnerDependencies = {
openDatabase: openLocalSqlitePluginPackageManagementDatabase,
authenticate: establishAuthenticatedLocalCommand,
},
): LocalPluginPackageCommandRunner {
const adapters = dependencies(candidateDependencies);
return Object.freeze({
async run(commandFilePath: string) {
const command = readCommandFile(commandFilePath);
const database = await adapters.openDatabase({
databasePath: command.options.databasePath,
profile: command.options.profile,
...(command.options.busyTimeoutMs === undefined
? {}
: { busyTimeoutMs: command.options.busyTimeoutMs }),
});
try {
const authenticated = await adapters.authenticate(database, {
deploymentRoot: command.options.deploymentRoot,
databasePath: command.options.databasePath,
ownerPepperKeyringDirectory:
command.options.ownerPepperKeyringDirectory,
credentialFilePath: command.options.credentialFilePath,
authenticationNamespace: 'local_package',
});
return await execute(command, database, authenticated);
} finally {
await database.close();
}
},
});
}
export function runLocalPluginPackageCommandFile(
commandFilePath: string,
): Promise<Readonly<LocalPluginPackageCommandResult>> {
return createLocalPluginPackageCommandRunner().run(commandFilePath);
}