@zhin.js/gateway 0.0.1-bootstrap.0 → 1.1.2
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/LICENSE +21 -0
- package/README.md +61 -0
- package/lib/config/ai-config-loader.d.ts +22 -0
- package/lib/config/ai-config-loader.js +96 -0
- package/lib/config/configuration-chat-policy.d.ts +57 -0
- package/lib/config/configuration-chat-policy.js +423 -0
- package/lib/config/configuration-patch.d.ts +16 -0
- package/lib/config/configuration-patch.js +105 -0
- package/lib/config/configuration-path.d.ts +6 -0
- package/lib/config/configuration-path.js +40 -0
- package/lib/config/configuration-projection.d.ts +6 -0
- package/lib/config/configuration-projection.js +28 -0
- package/lib/config/configuration-redaction.d.ts +18 -0
- package/lib/config/configuration-redaction.js +75 -0
- package/lib/config/configuration.d.ts +81 -0
- package/lib/config/configuration.js +686 -0
- package/lib/config/console-schema.d.ts +11 -0
- package/lib/config/console-schema.js +223 -0
- package/lib/config/environment-files.d.ts +3 -0
- package/lib/config/environment-files.js +14 -0
- package/lib/config/literal-secrets.d.ts +34 -0
- package/lib/config/literal-secrets.js +136 -0
- package/lib/config/plugin-package-map.d.ts +2 -0
- package/lib/config/plugin-package-map.js +14 -0
- package/lib/config/plugin-schema-catalog.d.ts +22 -0
- package/lib/config/plugin-schema-catalog.js +262 -0
- package/lib/config.d.ts +13 -0
- package/lib/config.js +13 -0
- package/lib/database/config.d.ts +22 -0
- package/lib/database/config.js +159 -0
- package/lib/database/index.d.ts +2 -0
- package/lib/database/index.js +2 -0
- package/lib/database/project-database.d.ts +31 -0
- package/lib/database/project-database.js +130 -0
- package/lib/database.d.ts +2 -0
- package/lib/database.js +2 -0
- package/lib/http/console-rpc.d.ts +27 -0
- package/lib/http/console-rpc.js +51 -0
- package/lib/http/gateway-console.d.ts +63 -0
- package/lib/http/gateway-console.js +309 -0
- package/lib/http/gateway-events.d.ts +40 -0
- package/lib/http/gateway-events.js +185 -0
- package/lib/http/gateway-http-server.d.ts +95 -0
- package/lib/http/gateway-http-server.js +522 -0
- package/lib/http/local-principal.d.ts +2 -0
- package/lib/http/local-principal.js +16 -0
- package/lib/http/plugin-switch-rpc.d.ts +19 -0
- package/lib/http/plugin-switch-rpc.js +214 -0
- package/lib/http/run-gateway.d.ts +43 -0
- package/lib/http/run-gateway.js +268 -0
- package/lib/http/start-gateway.d.ts +114 -0
- package/lib/http/start-gateway.js +226 -0
- package/lib/http-response.d.ts +6 -0
- package/lib/http-response.js +25 -0
- package/lib/http.d.ts +6 -0
- package/lib/http.js +6 -0
- package/lib/iam/crypto.d.ts +12 -0
- package/lib/iam/crypto.js +58 -0
- package/lib/iam/index.d.ts +8 -0
- package/lib/iam/index.js +8 -0
- package/lib/iam/install.d.ts +36 -0
- package/lib/iam/install.js +74 -0
- package/lib/iam/local-admin.d.ts +27 -0
- package/lib/iam/local-admin.js +102 -0
- package/lib/iam/rate-limit.d.ts +15 -0
- package/lib/iam/rate-limit.js +52 -0
- package/lib/iam/routes.d.ts +23 -0
- package/lib/iam/routes.js +157 -0
- package/lib/iam/rpc.d.ts +14 -0
- package/lib/iam/rpc.js +100 -0
- package/lib/iam/service.d.ts +203 -0
- package/lib/iam/service.js +784 -0
- package/lib/iam/setup-service.d.ts +83 -0
- package/lib/iam/setup-service.js +206 -0
- package/lib/iam/tables.d.ts +20 -0
- package/lib/iam/tables.js +82 -0
- package/lib/iam.d.ts +2 -0
- package/lib/iam.js +2 -0
- package/lib/index.d.ts +22 -0
- package/lib/index.js +22 -0
- package/lib/local/client.d.ts +71 -0
- package/lib/local/client.js +296 -0
- package/lib/local/handler.d.ts +30 -0
- package/lib/local/handler.js +86 -0
- package/lib/local/local-socket.d.ts +55 -0
- package/lib/local/local-socket.js +232 -0
- package/lib/local/paths.d.ts +34 -0
- package/lib/local/paths.js +58 -0
- package/lib/local/protocol.d.ts +140 -0
- package/lib/local/protocol.js +90 -0
- package/lib/local/state-file.d.ts +8 -0
- package/lib/local/state-file.js +45 -0
- package/lib/local.d.ts +10 -0
- package/lib/local.js +10 -0
- package/lib/onboarding/allowlist.d.ts +54 -0
- package/lib/onboarding/allowlist.js +106 -0
- package/lib/onboarding/errors.d.ts +7 -0
- package/lib/onboarding/errors.js +17 -0
- package/lib/onboarding/index.d.ts +6 -0
- package/lib/onboarding/index.js +6 -0
- package/lib/onboarding/install.d.ts +99 -0
- package/lib/onboarding/install.js +132 -0
- package/lib/onboarding/package-manager.d.ts +47 -0
- package/lib/onboarding/package-manager.js +179 -0
- package/lib/onboarding/service.d.ts +53 -0
- package/lib/onboarding/service.js +144 -0
- package/lib/onboarding/state-store.d.ts +26 -0
- package/lib/onboarding/state-store.js +97 -0
- package/lib/onboarding.d.ts +2 -0
- package/lib/onboarding.js +2 -0
- package/lib/packages/authorization.d.ts +24 -0
- package/lib/packages/authorization.js +128 -0
- package/lib/packages/errors.d.ts +11 -0
- package/lib/packages/errors.js +26 -0
- package/lib/packages/index.d.ts +5 -0
- package/lib/packages/index.js +5 -0
- package/lib/packages/rpc.d.ts +30 -0
- package/lib/packages/rpc.js +160 -0
- package/lib/packages/service.d.ts +139 -0
- package/lib/packages/service.js +504 -0
- package/lib/packages/snapshot.d.ts +14 -0
- package/lib/packages/snapshot.js +73 -0
- package/lib/packages.d.ts +2 -0
- package/lib/packages.js +2 -0
- package/lib/plugin-management/activity.d.ts +6 -0
- package/lib/plugin-management/activity.js +14 -0
- package/lib/plugin-management/config-explanation.d.ts +6 -0
- package/lib/plugin-management/config-explanation.js +113 -0
- package/lib/plugin-management/use-cases.d.ts +15 -0
- package/lib/plugin-management/use-cases.js +120 -0
- package/lib/plugin-management/workflow.d.ts +136 -0
- package/lib/plugin-management/workflow.js +878 -0
- package/lib/plugin-management.d.ts +5 -0
- package/lib/plugin-management.js +5 -0
- package/lib/project/config-file.d.ts +6 -0
- package/lib/project/config-file.js +58 -0
- package/lib/project/environment.d.ts +13 -0
- package/lib/project/environment.js +52 -0
- package/lib/project/instance-declarations.d.ts +55 -0
- package/lib/project/instance-declarations.js +542 -0
- package/lib/project/legacy-config.d.ts +25 -0
- package/lib/project/legacy-config.js +70 -0
- package/lib/project/node-requirements.d.ts +7 -0
- package/lib/project/node-requirements.js +20 -0
- package/lib/project/tsx-module-loader.d.ts +7 -0
- package/lib/project/tsx-module-loader.js +29 -0
- package/lib/project.d.ts +7 -0
- package/lib/project.js +7 -0
- package/lib/server.d.ts +11 -0
- package/lib/server.js +11 -0
- package/lib/supervisor/instance-logs.d.ts +39 -0
- package/lib/supervisor/instance-logs.js +152 -0
- package/lib/supervisor/instance-supervisor.d.ts +140 -0
- package/lib/supervisor/instance-supervisor.js +408 -0
- package/lib/supervisor/run-instance.d.ts +35 -0
- package/lib/supervisor/run-instance.js +161 -0
- package/lib/supervisor/terminal-state.d.ts +30 -0
- package/lib/supervisor/terminal-state.js +57 -0
- package/lib/supervisor.d.ts +4 -0
- package/lib/supervisor.js +4 -0
- package/lib/terminal/backends.d.ts +38 -0
- package/lib/terminal/backends.js +193 -0
- package/lib/terminal/config.d.ts +63 -0
- package/lib/terminal/config.js +237 -0
- package/lib/terminal/host.d.ts +26 -0
- package/lib/terminal/host.js +76 -0
- package/lib/terminal/index.d.ts +60 -0
- package/lib/terminal/index.js +135 -0
- package/lib/terminal/modules.d.ts +87 -0
- package/lib/terminal/modules.js +44 -0
- package/lib/terminal/service.d.ts +101 -0
- package/lib/terminal/service.js +455 -0
- package/lib/terminal/tickets.d.ts +46 -0
- package/lib/terminal/tickets.js +76 -0
- package/lib/terminal.d.ts +3 -0
- package/lib/terminal.js +3 -0
- package/lib/usage/aggregate.d.ts +87 -0
- package/lib/usage/aggregate.js +212 -0
- package/lib/usage.d.ts +2 -0
- package/lib/usage.js +2 -0
- package/package.json +117 -4
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport-independent dispatcher for the gateway's own RPC (`gateway.packages.*`,
|
|
3
|
+
* `gateway.instance.*`, ADR 0054 §4 / §5). The HTTP server maps envelopes onto it; the permission
|
|
4
|
+
* map in `@zhin.js/console-protocol` is checked here, then each service applies its own rules.
|
|
5
|
+
*/
|
|
6
|
+
import { GATEWAY_RPC, GATEWAY_RPC_PERMISSIONS, } from '@zhin.js/console-protocol';
|
|
7
|
+
import { OnboardingError } from '../onboarding/errors.js';
|
|
8
|
+
import { gatewayPrincipalAllows } from './authorization.js';
|
|
9
|
+
import { GatewayError } from './errors.js';
|
|
10
|
+
const GATEWAY_TYPES = new Set(Object.values(GATEWAY_RPC));
|
|
11
|
+
const DEFAULT_LOG_LINES = 200;
|
|
12
|
+
const MAX_LOG_LINES = 1_000;
|
|
13
|
+
export function isGatewayRpcType(type) {
|
|
14
|
+
return typeof type === 'string' && GATEWAY_TYPES.has(type);
|
|
15
|
+
}
|
|
16
|
+
export function createGatewayRpcDispatcher(dependencies) {
|
|
17
|
+
return (request, principal) => dispatchGatewayRpc(request, principal, dependencies);
|
|
18
|
+
}
|
|
19
|
+
/** Dispatches one gateway RPC; never throws (errors become `{ ok: false }`). */
|
|
20
|
+
export async function dispatchGatewayRpc(request, principal, dependencies) {
|
|
21
|
+
try {
|
|
22
|
+
const type = request?.type;
|
|
23
|
+
if (!isGatewayRpcType(type))
|
|
24
|
+
throw new GatewayError('unmapped', `RPC "${String(type ?? '').slice(0, 64)}" 未登记权限`);
|
|
25
|
+
if (!principal)
|
|
26
|
+
throw new GatewayError('forbidden', '未登录');
|
|
27
|
+
const packageMutation = type === GATEWAY_RPC.PLAN || type === GATEWAY_RPC.INSTALL;
|
|
28
|
+
// The bootstrap token reaches plan / install only, where the service limits it to database drivers.
|
|
29
|
+
const bootstrapDelegated = principal !== 'local' && principal.kind === 'bootstrap' && packageMutation;
|
|
30
|
+
if (!bootstrapDelegated && !gatewayPrincipalAllows(principal, GATEWAY_RPC_PERMISSIONS[type])) {
|
|
31
|
+
throw new GatewayError('forbidden', `缺少权限 ${GATEWAY_RPC_PERMISSIONS[type]}`);
|
|
32
|
+
}
|
|
33
|
+
const data = record(request.data);
|
|
34
|
+
return Object.freeze({ ok: true, data: await handle(type, data, principal, dependencies) });
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
return failure(error);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function handle(type, data, principal, deps) {
|
|
41
|
+
switch (type) {
|
|
42
|
+
case 'gateway.packages.list': return packagesOf(deps).list(principal);
|
|
43
|
+
case 'gateway.packages.plan': {
|
|
44
|
+
const operation = data.operation;
|
|
45
|
+
if (operation !== 'install' && operation !== 'uninstall' && operation !== 'update')
|
|
46
|
+
throw new GatewayError('invalid_input', 'operation 只能是 install / uninstall / update');
|
|
47
|
+
return packagesOf(deps).plan(operation, packageList(data, operation === 'update'), principal);
|
|
48
|
+
}
|
|
49
|
+
case 'gateway.packages.install':
|
|
50
|
+
return packagesOf(deps).install(packageList(data, false), {
|
|
51
|
+
principal, ...optionalBoolean(data, 'enable'), ...optionalBoolean(data, 'startInstance'),
|
|
52
|
+
});
|
|
53
|
+
case 'gateway.packages.uninstall':
|
|
54
|
+
return packagesOf(deps).uninstall(packageList(data, false), {
|
|
55
|
+
principal, ...optionalBoolean(data, 'startInstance'), ...optionalBoolean(data, 'removeDependency'),
|
|
56
|
+
});
|
|
57
|
+
case 'gateway.packages.update':
|
|
58
|
+
return packagesOf(deps).update(packageList(data, true), { principal, ...optionalBoolean(data, 'startInstance') });
|
|
59
|
+
case 'gateway.plugins.declare': {
|
|
60
|
+
if (data.config !== undefined && (!data.config || typeof data.config !== 'object' || Array.isArray(data.config))) {
|
|
61
|
+
throw new GatewayError('invalid_input', 'config 必须是对象');
|
|
62
|
+
}
|
|
63
|
+
return packagesOf(deps).declare({ package: data.package, instanceKey: data.instanceKey, config: data.config }, {
|
|
64
|
+
principal, ...optionalBoolean(data, 'startInstance'),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
case 'gateway.plugins.enable':
|
|
68
|
+
case 'gateway.plugins.disable':
|
|
69
|
+
return packagesOf(deps).setEnabled({ plugin: data.plugin }, type === 'gateway.plugins.enable', {
|
|
70
|
+
principal, ...optionalBoolean(data, 'startInstance'),
|
|
71
|
+
});
|
|
72
|
+
case 'gateway.instance.status': return instanceStatus(instanceOf(deps).status());
|
|
73
|
+
case 'gateway.instance.logs': {
|
|
74
|
+
const lines = data.lines === undefined ? DEFAULT_LOG_LINES : data.lines;
|
|
75
|
+
if (typeof lines !== 'number' || !Number.isInteger(lines) || lines < 1 || lines > MAX_LOG_LINES) {
|
|
76
|
+
throw new GatewayError('invalid_input', `lines 必须是 1–${MAX_LOG_LINES} 的整数`);
|
|
77
|
+
}
|
|
78
|
+
const result = Object.freeze({
|
|
79
|
+
lines: Object.freeze(instanceOf(deps).logs.tail(lines).map(line => Object.freeze({ seq: line.seq, time: line.time, stream: line.stream, line: line.line }))),
|
|
80
|
+
});
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
case 'gateway.instance.start':
|
|
84
|
+
case 'gateway.instance.stop':
|
|
85
|
+
case 'gateway.instance.restart': {
|
|
86
|
+
const instance = instanceOf(deps);
|
|
87
|
+
// A dependency transaction owns the instance until it ends.
|
|
88
|
+
if (deps.packages?.activeTransaction)
|
|
89
|
+
throw new GatewayError('conflict', '依赖事务进行中,实例由事务停启');
|
|
90
|
+
try {
|
|
91
|
+
if (type === 'gateway.instance.start')
|
|
92
|
+
await instance.start();
|
|
93
|
+
else if (type === 'gateway.instance.stop')
|
|
94
|
+
await instance.stop({ reason: 'console' });
|
|
95
|
+
else
|
|
96
|
+
await instance.restart({ reason: 'console' });
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw new GatewayError('unavailable', error instanceof Error ? error.message : String(error), { cause: error });
|
|
100
|
+
}
|
|
101
|
+
return instanceStatus(instance.status());
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function packagesOf(deps) {
|
|
106
|
+
if (!deps.packages)
|
|
107
|
+
throw new GatewayError('unavailable', '依赖管理不可用');
|
|
108
|
+
return deps.packages;
|
|
109
|
+
}
|
|
110
|
+
function instanceOf(deps) {
|
|
111
|
+
if (!deps.instance)
|
|
112
|
+
throw new GatewayError('unavailable', '网关未管理实例');
|
|
113
|
+
return deps.instance;
|
|
114
|
+
}
|
|
115
|
+
export function instanceStatus(status) {
|
|
116
|
+
return Object.freeze({
|
|
117
|
+
instanceId: 'default',
|
|
118
|
+
state: status.state,
|
|
119
|
+
...(status.pid === undefined ? {} : { pid: status.pid }),
|
|
120
|
+
...(status.startedAt === undefined ? {} : { startedAt: status.startedAt }),
|
|
121
|
+
...(status.generation === undefined ? {} : { generation: status.generation }),
|
|
122
|
+
...(status.protocolVersion === undefined ? {} : { protocolVersion: status.protocolVersion }),
|
|
123
|
+
lastExitCode: status.lastExitCode,
|
|
124
|
+
lastExitSignal: status.lastExitSignal,
|
|
125
|
+
...(status.lastFailure ? { lastFailure: Object.freeze({ ...status.lastFailure }) } : {}),
|
|
126
|
+
recentRestarts: status.recentRestarts,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function record(value) {
|
|
130
|
+
if (value === undefined || value === null)
|
|
131
|
+
return {};
|
|
132
|
+
if (typeof value !== 'object' || Array.isArray(value))
|
|
133
|
+
throw new GatewayError('invalid_input', 'data 必须是对象');
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
function packageList(data, allowAll) {
|
|
137
|
+
const value = data.packages;
|
|
138
|
+
if (allowAll && value === 'all')
|
|
139
|
+
return 'all';
|
|
140
|
+
if (!Array.isArray(value))
|
|
141
|
+
throw new GatewayError('invalid_input', allowAll ? 'packages 必须是数组或 "all"' : 'packages 必须是数组');
|
|
142
|
+
return value;
|
|
143
|
+
}
|
|
144
|
+
function optionalBoolean(data, key) {
|
|
145
|
+
const value = data[key];
|
|
146
|
+
if (value === undefined)
|
|
147
|
+
return {};
|
|
148
|
+
if (typeof value !== 'boolean')
|
|
149
|
+
throw new GatewayError('invalid_input', `${key} 必须是布尔值`);
|
|
150
|
+
return { [key]: value };
|
|
151
|
+
}
|
|
152
|
+
function failure(error) {
|
|
153
|
+
const known = error instanceof GatewayError ? error
|
|
154
|
+
: error instanceof OnboardingError ? new GatewayError(error.code, error.message)
|
|
155
|
+
: undefined;
|
|
156
|
+
const code = known?.code ?? 'internal';
|
|
157
|
+
// Unexpected errors are not echoed: they may carry paths or package-manager output.
|
|
158
|
+
const message = known?.message ?? '网关内部错误';
|
|
159
|
+
return Object.freeze({ ok: false, error: Object.freeze({ code, message, status: known?.status ?? 500, ...known?.details }) });
|
|
160
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { GatewayAuthorizedPackage, GatewayPackageEvent, GatewayPackageList, GatewayPackageOperation, GatewayPackagePlan, GatewayPackageTransactionResult } from '@zhin.js/console-protocol';
|
|
2
|
+
import { type InstallAllowlist, type MarketCatalogEntry } from '../onboarding/allowlist.js';
|
|
3
|
+
import { type PackageManagerOutput } from '../onboarding/package-manager.js';
|
|
4
|
+
import { type PluginManagementOptions } from '../plugin-management/workflow.js';
|
|
5
|
+
import { type InstanceFailure, type InstanceState, type InstanceStatus, type InstanceStopOptions } from '../supervisor/instance-supervisor.js';
|
|
6
|
+
import type { InstanceLogLine } from '../supervisor/instance-logs.js';
|
|
7
|
+
import { type GatewayPackageAction, type GatewayPrincipal } from './authorization.js';
|
|
8
|
+
/** The part of `InstanceSupervisor` a transaction drives. */
|
|
9
|
+
export interface PackageTransactionInstance {
|
|
10
|
+
readonly state: InstanceState;
|
|
11
|
+
start(): Promise<void>;
|
|
12
|
+
stop(options?: InstanceStopOptions): Promise<void>;
|
|
13
|
+
status(): InstanceStatus;
|
|
14
|
+
on(event: 'failure', listener: (failure: InstanceFailure) => void): unknown;
|
|
15
|
+
off(event: 'failure', listener: (failure: InstanceFailure) => void): unknown;
|
|
16
|
+
readonly logs?: {
|
|
17
|
+
tail(limit?: number): readonly InstanceLogLine[];
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** The part of `PluginManagementWorkflow` (`PluginManagementPort`) a transaction uses. */
|
|
21
|
+
export interface PackageWorkflowPort {
|
|
22
|
+
inspect(request: string): Promise<{
|
|
23
|
+
readonly declared: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
install(spec: string, expectedRevision?: string, expectedProjectRevision?: string, options?: {
|
|
26
|
+
readonly enable?: boolean;
|
|
27
|
+
}): Promise<unknown>;
|
|
28
|
+
uninstall(request: string, expectedRevision?: string, expectedProjectRevision?: string, options?: {
|
|
29
|
+
readonly removeDependency?: boolean;
|
|
30
|
+
}): Promise<unknown>;
|
|
31
|
+
update(request: string, targetVersion: string): Promise<unknown>;
|
|
32
|
+
/** Validates a declaration without writing (throws `PluginDeclarationError`). */
|
|
33
|
+
planDeclaration?(request: string, config?: unknown, options?: {
|
|
34
|
+
readonly instanceKey?: string;
|
|
35
|
+
}): Promise<unknown>;
|
|
36
|
+
declare?(request: string, config?: unknown, options?: {
|
|
37
|
+
readonly instanceKey?: string;
|
|
38
|
+
}): Promise<unknown>;
|
|
39
|
+
/** Validates an enable / disable without writing (throws `PluginEnablementError`). */
|
|
40
|
+
planSetEnabled?(request: string, enabled: boolean): Promise<{
|
|
41
|
+
readonly packageName: string;
|
|
42
|
+
readonly instanceKey: string;
|
|
43
|
+
readonly changed: boolean;
|
|
44
|
+
}>;
|
|
45
|
+
setEnabled?(request: string, enabled: boolean): Promise<unknown>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Runs the package manager with pnpm-style args (`add|remove|update|install …`), streaming output.
|
|
49
|
+
* The default spawns the project's detected manager without a shell.
|
|
50
|
+
*/
|
|
51
|
+
export type GatewayPackageManager = (args: readonly string[], projectRoot: string, output: PackageManagerOutput) => Promise<void>;
|
|
52
|
+
export type GatewayPackageListener = (event: GatewayPackageEvent) => void;
|
|
53
|
+
export interface GatewayPackageServiceOptions {
|
|
54
|
+
readonly projectRoot: string;
|
|
55
|
+
/** The supervised instance; omitted when no instance is managed (CLI without a running gateway). */
|
|
56
|
+
readonly instance?: PackageTransactionInstance;
|
|
57
|
+
readonly packageManager?: GatewayPackageManager;
|
|
58
|
+
/** Defaults to a `PluginManagementWorkflow` on the project root using {@link packageManager}. */
|
|
59
|
+
readonly workflow?: PackageWorkflowPort;
|
|
60
|
+
/** Options for the default workflow. */
|
|
61
|
+
readonly workflowOptions?: Omit<PluginManagementOptions, 'installDependencies'>;
|
|
62
|
+
/** True once an owner exists (bootstrap token refused afterwards). Default: true (deny bootstrap). */
|
|
63
|
+
readonly hasOwner?: () => boolean | Promise<boolean>;
|
|
64
|
+
/** Plugin-market entries joining the non-owner allowlist. */
|
|
65
|
+
readonly marketCatalog?: () => readonly MarketCatalogEntry[] | Promise<readonly MarketCatalogEntry[]>;
|
|
66
|
+
/** Extra policy after the built-in rules; throw to deny. */
|
|
67
|
+
readonly authorize?: (principal: GatewayPrincipal, action: GatewayPackageAction, packages: readonly GatewayAuthorizedPackage[]) => void | Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Time the instance gets to report `ready` after a transaction. Default 60 s
|
|
70
|
+
* (`gateway.readyTimeout`). A function is read at each start, after {@link beforeTransaction}.
|
|
71
|
+
*/
|
|
72
|
+
readonly readyTimeoutMs?: number | (() => number | undefined);
|
|
73
|
+
/** Runs at the start of every transaction (the gateway re-reads `gateway.readyTimeout`). */
|
|
74
|
+
readonly beforeTransaction?: () => Promise<void>;
|
|
75
|
+
/** After `ready`, a failure within this window (crash, crash storm) fails the transaction. Default 5 s. */
|
|
76
|
+
readonly stableMs?: number;
|
|
77
|
+
readonly now?: () => number;
|
|
78
|
+
}
|
|
79
|
+
export interface GatewayTransactionOptions {
|
|
80
|
+
readonly principal: GatewayPrincipal | undefined;
|
|
81
|
+
/** Start the instance afterwards even when it was not running before. */
|
|
82
|
+
readonly startInstance?: boolean;
|
|
83
|
+
readonly onEvent?: GatewayPackageListener;
|
|
84
|
+
}
|
|
85
|
+
export interface GatewayUninstallOptions extends GatewayTransactionOptions {
|
|
86
|
+
/** Also remove the npm dependency when nothing else references it (default true). */
|
|
87
|
+
readonly removeDependency?: boolean;
|
|
88
|
+
}
|
|
89
|
+
export interface GatewayInstallOptions extends GatewayTransactionOptions {
|
|
90
|
+
/** Declare installed plugins in the root config (default true). */
|
|
91
|
+
readonly enable?: boolean;
|
|
92
|
+
}
|
|
93
|
+
export interface GatewayDeclareRequest {
|
|
94
|
+
readonly package: unknown;
|
|
95
|
+
readonly instanceKey?: unknown;
|
|
96
|
+
readonly config?: unknown;
|
|
97
|
+
}
|
|
98
|
+
export interface GatewaySetEnabledRequest {
|
|
99
|
+
/** A declared instance key, or the package name of a package declared exactly once. */
|
|
100
|
+
readonly plugin: unknown;
|
|
101
|
+
}
|
|
102
|
+
export declare const DEFAULT_PACKAGE_READY_TIMEOUT_MS = 60000;
|
|
103
|
+
export declare const DEFAULT_PACKAGE_STABLE_MS = 5000;
|
|
104
|
+
export declare class GatewayPackageService {
|
|
105
|
+
#private;
|
|
106
|
+
constructor(options: GatewayPackageServiceOptions);
|
|
107
|
+
/** Id of the running transaction, if any. */
|
|
108
|
+
get activeTransaction(): string | undefined;
|
|
109
|
+
/** Progress of every transaction (for `gateway.packages.progress`); returns an unsubscribe function. */
|
|
110
|
+
subscribe(listener: GatewayPackageListener): () => void;
|
|
111
|
+
allowlist(): Promise<InstallAllowlist>;
|
|
112
|
+
/** Authorizes one action; throws {@link GatewayError} (deny by default). */
|
|
113
|
+
authorize(principal: GatewayPrincipal | undefined, action: GatewayPackageAction, packages?: readonly unknown[] | 'all'): Promise<readonly GatewayAuthorizedPackage[]>;
|
|
114
|
+
/** Declared dependencies with their installed versions. */
|
|
115
|
+
list(principal: GatewayPrincipal | undefined): Promise<GatewayPackageList>;
|
|
116
|
+
/** What a transaction would do, after authorization; changes nothing. */
|
|
117
|
+
plan(operation: GatewayPackageOperation, packages: readonly unknown[] | 'all', principal: GatewayPrincipal | undefined): Promise<GatewayPackagePlan>;
|
|
118
|
+
install(packages: readonly unknown[], options: GatewayInstallOptions): Promise<GatewayPackageTransactionResult>;
|
|
119
|
+
/**
|
|
120
|
+
* `gateway.plugins.declare`: declares an installed plugin with its first configuration (schema
|
|
121
|
+
* validated before the instance is touched), then restarts the instance; a failed start rolls
|
|
122
|
+
* the configuration file back and starts the previous instance again.
|
|
123
|
+
*/
|
|
124
|
+
declare(request: GatewayDeclareRequest, options: GatewayTransactionOptions): Promise<GatewayPackageTransactionResult>;
|
|
125
|
+
/**
|
|
126
|
+
* `gateway.plugins.enable` / `gateway.plugins.disable`: rewrites `disable_plugins` for one
|
|
127
|
+
* declared instance, then restarts the instance (a failed start restores the configuration file
|
|
128
|
+
* and starts the previous instance again). Validation runs before the instance is touched; an
|
|
129
|
+
* instance already in the requested state succeeds without stopping anything or writing.
|
|
130
|
+
*/
|
|
131
|
+
setEnabled(request: GatewaySetEnabledRequest, enabled: boolean, options: GatewayTransactionOptions): Promise<GatewayPackageTransactionResult>;
|
|
132
|
+
uninstall(packages: readonly unknown[], options: GatewayUninstallOptions): Promise<GatewayPackageTransactionResult>;
|
|
133
|
+
/** Exact versions go through the workflow (verified); bare names / `'all'` run the manager's update. */
|
|
134
|
+
update(packages: readonly unknown[] | 'all', options: GatewayTransactionOptions): Promise<GatewayPackageTransactionResult>;
|
|
135
|
+
/** {@link install} / {@link uninstall} / {@link update} as an async iterator of its events. */
|
|
136
|
+
stream(operation: GatewayPackageOperation, packages: readonly unknown[] | 'all', options: GatewayInstallOptions): AsyncIterableIterator<GatewayPackageEvent> & {
|
|
137
|
+
readonly result: Promise<GatewayPackageTransactionResult>;
|
|
138
|
+
};
|
|
139
|
+
}
|