@tomflow/proflow-platform-cli 0.1.15 → 0.1.17
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/DOCS.md +27 -0
- package/SETUP.md +7 -0
- package/dist/deployment/adapter.d.ts +58 -34
- package/dist/deployment/adapter.js +28 -12
- package/dist/deployment/descriptor.d.ts +5 -16
- package/dist/deployment/descriptor.js +10 -21
- package/dist/src/cli.js +131 -137
- package/dist/src/contracts.d.ts +0 -2
- package/dist/src/discovery/discover.d.ts +1 -3
- package/dist/src/discovery/discover.js +1 -10
- package/dist/src/errors.d.ts +1 -1
- package/dist/src/errors.js +0 -2
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.js +0 -1
- package/dist/src/lifecycle/dispatch.d.ts +4 -11
- package/dist/src/lifecycle/dispatch.js +28 -56
- package/dist/src/lifecycle/index.d.ts +4 -4
- package/dist/src/lifecycle/index.js +2 -2
- package/dist/src/lifecycle/thin.d.ts +19 -7
- package/dist/src/lifecycle/thin.js +80 -55
- package/dist/src/persistence/index.d.ts +0 -2
- package/dist/src/persistence/index.js +0 -1
- package/package.json +7 -5
- package/proflow.module.json +5 -20
- package/dist/src/binding/production-bindings.d.ts +0 -37
- package/dist/src/binding/production-bindings.js +0 -75
- package/dist/src/docs/aggregate.d.ts +0 -18
- package/dist/src/docs/aggregate.js +0 -44
- package/dist/src/docs/docs.d.ts +0 -16
- package/dist/src/docs/docs.js +0 -68
- package/dist/src/docs/index.d.ts +0 -2
- package/dist/src/docs/index.js +0 -1
- package/dist/src/persistence/config.d.ts +0 -6
- package/dist/src/persistence/config.js +0 -54
- package/dist/src/persistence/guards.d.ts +0 -1
- package/dist/src/persistence/guards.js +0 -7
|
@@ -1,72 +1,44 @@
|
|
|
1
1
|
import { moduleOperationResultSchema, } from "@tomflow/proflow-module-contract";
|
|
2
2
|
import { PlatformError } from "../errors.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
6
|
-
function isPrimitiveFn(value) {
|
|
7
|
-
return typeof value === "function";
|
|
8
|
-
}
|
|
9
|
-
function isWrappedResult(value) {
|
|
10
|
-
return isRecord(value) && "result" in value;
|
|
11
|
-
}
|
|
3
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
+
const isCommandFn = (value) => typeof value === "function";
|
|
12
5
|
function moduleSource(module) {
|
|
13
|
-
|
|
14
|
-
type: module.source.type,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
6
|
+
return module.source.path === undefined
|
|
7
|
+
? { type: module.source.type, packageName: module.packageName }
|
|
8
|
+
: {
|
|
9
|
+
type: module.source.type,
|
|
10
|
+
packageName: module.packageName,
|
|
11
|
+
path: module.source.path,
|
|
12
|
+
};
|
|
20
13
|
}
|
|
21
14
|
function resolveBehaviorAdapter(namespace) {
|
|
22
|
-
if (!isRecord(namespace))
|
|
23
|
-
throw new PlatformError("COMMAND_FAILED", "
|
|
24
|
-
|
|
25
|
-
const behaviorAdapter = namespace.behaviorAdapter;
|
|
26
|
-
if (!isRecord(behaviorAdapter)) {
|
|
27
|
-
throw new PlatformError("COMMAND_FAILED", "lifecycle adapter exposes no behaviorAdapter object");
|
|
28
|
-
}
|
|
29
|
-
return behaviorAdapter;
|
|
30
|
-
}
|
|
31
|
-
function observedEffectsOf(value) {
|
|
32
|
-
if (!Array.isArray(value))
|
|
33
|
-
return [];
|
|
34
|
-
return value.filter((item) => typeof item === "string");
|
|
15
|
+
if (!isRecord(namespace) || !isRecord(namespace.behaviorAdapter))
|
|
16
|
+
throw new PlatformError("COMMAND_FAILED", "module adapter exposes no behaviorAdapter object");
|
|
17
|
+
return namespace.behaviorAdapter;
|
|
35
18
|
}
|
|
36
19
|
function normalizeInvocation(raw) {
|
|
37
|
-
if (
|
|
38
|
-
return {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
20
|
+
if (!isRecord(raw) || !("result" in raw))
|
|
21
|
+
return { result: raw, observedEffects: [] };
|
|
22
|
+
return {
|
|
23
|
+
result: raw.result,
|
|
24
|
+
observedEffects: Array.isArray(raw.observedEffects)
|
|
25
|
+
? raw.observedEffects.filter((item) => typeof item === "string")
|
|
26
|
+
: [],
|
|
27
|
+
};
|
|
44
28
|
}
|
|
45
|
-
|
|
46
|
-
* Dispatches a single lifecycle primitive against one module through its
|
|
47
|
-
* public deployment adapter. The descriptor is the source of truth for what is
|
|
48
|
-
* supported: a primitive not declared in `lifecycle` is rejected with
|
|
49
|
-
* `LIFECYCLE_UNSUPPORTED` rather than faked. The adapter result is always
|
|
50
|
-
* runtime-validated against the Module Operation Result schema.
|
|
51
|
-
*/
|
|
52
|
-
export async function dispatchLifecycle(catalog, module, primitive) {
|
|
53
|
-
if (!module.lifecycle.includes(primitive)) {
|
|
54
|
-
throw new PlatformError("LIFECYCLE_UNSUPPORTED", `module ${module.moduleRef} does not declare lifecycle primitive "${primitive}"`);
|
|
55
|
-
}
|
|
29
|
+
export async function dispatchModuleCommand(catalog, module, command, context) {
|
|
56
30
|
const namespace = await catalog.loadAdapter(moduleSource(module));
|
|
57
31
|
const adapter = resolveBehaviorAdapter(namespace);
|
|
58
|
-
const invoke = adapter[
|
|
59
|
-
if (!
|
|
60
|
-
throw new PlatformError("COMMAND_FAILED", `module ${module.moduleRef}
|
|
61
|
-
}
|
|
62
|
-
const { result, observedEffects } = normalizeInvocation(await invoke());
|
|
32
|
+
const invoke = adapter[command];
|
|
33
|
+
if (!isCommandFn(invoke))
|
|
34
|
+
throw new PlatformError("COMMAND_FAILED", `module ${module.moduleRef} does not implement standard command "${command}"`);
|
|
35
|
+
const { result, observedEffects } = normalizeInvocation(await invoke(context));
|
|
63
36
|
const parsed = moduleOperationResultSchema.safeParse(result);
|
|
64
|
-
if (!parsed.success)
|
|
65
|
-
throw new PlatformError("COMMAND_FAILED", `module ${module.moduleRef} "${
|
|
66
|
-
}
|
|
37
|
+
if (!parsed.success)
|
|
38
|
+
throw new PlatformError("COMMAND_FAILED", `module ${module.moduleRef} "${command}" returned an invalid result: ${parsed.error.message}`);
|
|
67
39
|
return {
|
|
68
40
|
moduleRef: module.moduleRef,
|
|
69
|
-
|
|
41
|
+
command,
|
|
70
42
|
result: parsed.data,
|
|
71
43
|
observedEffects,
|
|
72
44
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type {
|
|
2
|
-
export {
|
|
3
|
-
export type {
|
|
4
|
-
export { observeStatuses,
|
|
1
|
+
export type { ModuleDispatchResult } from "./dispatch.ts";
|
|
2
|
+
export { dispatchModuleCommand } from "./dispatch.ts";
|
|
3
|
+
export type { ModuleBatchResult } from "./thin.ts";
|
|
4
|
+
export { installModulesThin, observeDocs, observeStatuses, setupModulesThin, startModulesThin, stopModulesThin, uninstallModulesThin, } from "./thin.ts";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { observeStatuses,
|
|
1
|
+
export { dispatchModuleCommand } from "./dispatch.js";
|
|
2
|
+
export { installModulesThin, observeDocs, observeStatuses, setupModulesThin, startModulesThin, stopModulesThin, uninstallModulesThin, } from "./thin.js";
|
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
import { type ModuleSetupStatus } from "@tomflow/proflow-module-contract";
|
|
1
2
|
import type { ResolvedModule } from "../contracts.ts";
|
|
2
3
|
import type { ModuleCatalog } from "../modules.ts";
|
|
3
|
-
import { type
|
|
4
|
-
export interface
|
|
5
|
-
phase: "
|
|
6
|
-
results:
|
|
4
|
+
import { type ModuleDispatchResult } from "./dispatch.ts";
|
|
5
|
+
export interface ModuleBatchResult {
|
|
6
|
+
phase: "install" | "uninstall" | "setup" | "start" | "stop";
|
|
7
|
+
results: ModuleDispatchResult[];
|
|
7
8
|
completed: boolean;
|
|
9
|
+
blockedBy?: {
|
|
10
|
+
moduleRef: string;
|
|
11
|
+
setupStatus: ModuleSetupStatus;
|
|
12
|
+
};
|
|
8
13
|
}
|
|
9
|
-
export declare function observeStatuses(catalog: ModuleCatalog, modules: readonly ResolvedModule[]): Promise<
|
|
10
|
-
export declare function
|
|
11
|
-
export declare
|
|
14
|
+
export declare function observeStatuses(catalog: ModuleCatalog, modules: readonly ResolvedModule[], workspaceRoot: string): Promise<ModuleDispatchResult[]>;
|
|
15
|
+
export declare function observeDocs(catalog: ModuleCatalog, modules: readonly ResolvedModule[], workspaceRoot: string): Promise<ModuleDispatchResult[]>;
|
|
16
|
+
export declare const installModulesThin: (catalog: ModuleCatalog, modules: readonly ResolvedModule[], workspaceRoot: string) => Promise<ModuleBatchResult>;
|
|
17
|
+
export declare const uninstallModulesThin: (catalog: ModuleCatalog, modules: readonly ResolvedModule[], workspaceRoot: string) => Promise<ModuleBatchResult>;
|
|
18
|
+
export declare const stopModulesThin: (catalog: ModuleCatalog, modules: readonly ResolvedModule[], workspaceRoot: string) => Promise<ModuleBatchResult>;
|
|
19
|
+
export declare function setupModulesThin(catalog: ModuleCatalog, modules: readonly ResolvedModule[], workspaceRoot: string, target?: {
|
|
20
|
+
moduleRef: string;
|
|
21
|
+
input?: unknown;
|
|
22
|
+
}): Promise<ModuleBatchResult>;
|
|
23
|
+
export declare function startModulesThin(catalog: ModuleCatalog, modules: readonly ResolvedModule[], workspaceRoot: string): Promise<ModuleBatchResult>;
|
|
@@ -1,68 +1,93 @@
|
|
|
1
|
+
import { moduleStatusObservationSchema, } from "@tomflow/proflow-module-contract";
|
|
2
|
+
import { PlatformError } from "../errors.js";
|
|
1
3
|
import { buildDependencyGraph } from "../graph/graph.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
import { dispatchModuleCommand, } from "./dispatch.js";
|
|
5
|
+
const succeeded = (result) => result.status === "SUCCEEDED";
|
|
6
|
+
const context = (workspaceRoot, input) => input === undefined ? { workspaceRoot } : { workspaceRoot, input };
|
|
7
|
+
function ordered(modules, reverse = false) {
|
|
8
|
+
const graph = buildDependencyGraph(modules);
|
|
9
|
+
const refs = reverse ? [...graph.order].reverse() : [...graph.order];
|
|
10
|
+
const byRef = new Map(modules.map((module) => [module.moduleRef, module]));
|
|
11
|
+
return refs
|
|
12
|
+
.map((ref) => byRef.get(ref))
|
|
13
|
+
.filter((item) => item !== undefined);
|
|
5
14
|
}
|
|
6
|
-
async function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
15
|
+
export async function observeStatuses(catalog, modules, workspaceRoot) {
|
|
16
|
+
const results = [];
|
|
17
|
+
for (const module of [...modules].sort((a, b) => a.moduleRef.localeCompare(b.moduleRef)))
|
|
18
|
+
results.push(await dispatchModuleCommand(catalog, module, "status", context(workspaceRoot)));
|
|
19
|
+
return results;
|
|
10
20
|
}
|
|
11
|
-
export async function
|
|
21
|
+
export async function observeDocs(catalog, modules, workspaceRoot) {
|
|
12
22
|
const results = [];
|
|
13
|
-
for (const module of [...modules].sort((a, b) => a.moduleRef.localeCompare(b.moduleRef)))
|
|
14
|
-
|
|
15
|
-
continue;
|
|
16
|
-
results.push(await dispatchLifecycle(catalog, module, "status"));
|
|
17
|
-
}
|
|
23
|
+
for (const module of [...modules].sort((a, b) => a.moduleRef.localeCompare(b.moduleRef)))
|
|
24
|
+
results.push(await dispatchModuleCommand(catalog, module, "docs", context(workspaceRoot)));
|
|
18
25
|
return results;
|
|
19
26
|
}
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
continue;
|
|
28
|
-
const result = await dispatchIfSupported(catalog, module, "preflight");
|
|
29
|
-
if (result === undefined)
|
|
30
|
-
continue;
|
|
31
|
-
preflight.push(result);
|
|
32
|
-
if (!succeeded(result.result)) {
|
|
33
|
-
return { phase: "preflight", results: preflight, completed: false };
|
|
34
|
-
}
|
|
27
|
+
async function runOrdered(catalog, modules, workspaceRoot, command, reverse) {
|
|
28
|
+
const results = [];
|
|
29
|
+
for (const module of ordered(modules, reverse)) {
|
|
30
|
+
const result = await dispatchModuleCommand(catalog, module, command, context(workspaceRoot));
|
|
31
|
+
results.push(result);
|
|
32
|
+
if (!succeeded(result.result))
|
|
33
|
+
return { phase: command, results, completed: false };
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
return { phase: command, results, completed: true };
|
|
36
|
+
}
|
|
37
|
+
export const installModulesThin = (catalog, modules, workspaceRoot) => runOrdered(catalog, modules, workspaceRoot, "install", false);
|
|
38
|
+
export const uninstallModulesThin = (catalog, modules, workspaceRoot) => runOrdered(catalog, modules, workspaceRoot, "uninstall", true);
|
|
39
|
+
export const stopModulesThin = (catalog, modules, workspaceRoot) => runOrdered(catalog, modules, workspaceRoot, "stop", true);
|
|
40
|
+
export async function setupModulesThin(catalog, modules, workspaceRoot, target) {
|
|
41
|
+
const results = [];
|
|
42
|
+
let matched = target === undefined;
|
|
43
|
+
for (const module of ordered(modules)) {
|
|
44
|
+
if (target !== undefined && module.moduleRef !== target.moduleRef)
|
|
40
45
|
continue;
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
matched = true;
|
|
47
|
+
const status = await dispatchModuleCommand(catalog, module, "status", context(workspaceRoot));
|
|
48
|
+
if (!succeeded(status.result))
|
|
49
|
+
return {
|
|
50
|
+
phase: "setup",
|
|
51
|
+
results: [...results, status],
|
|
52
|
+
completed: false,
|
|
53
|
+
};
|
|
54
|
+
const observed = moduleStatusObservationSchema.parse(status.result.data);
|
|
55
|
+
if (observed.setupStatus === "READY" && target?.input === undefined)
|
|
43
56
|
continue;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
const setup = await dispatchModuleCommand(catalog, module, "setup", context(workspaceRoot, target?.input));
|
|
58
|
+
results.push(setup);
|
|
59
|
+
if (!succeeded(setup.result))
|
|
60
|
+
return { phase: "setup", results, completed: false };
|
|
48
61
|
}
|
|
49
|
-
|
|
62
|
+
if (!matched)
|
|
63
|
+
throw new PlatformError("INVALID_REQUEST", `setup target module ${target?.moduleRef ?? ""} was not discovered`);
|
|
64
|
+
return { phase: "setup", results, completed: true };
|
|
50
65
|
}
|
|
51
|
-
export async function
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
export async function startModulesThin(catalog, modules, workspaceRoot) {
|
|
67
|
+
const results = [];
|
|
68
|
+
for (const module of ordered(modules)) {
|
|
69
|
+
const status = await dispatchModuleCommand(catalog, module, "status", context(workspaceRoot));
|
|
70
|
+
if (!succeeded(status.result))
|
|
71
|
+
return {
|
|
72
|
+
phase: "start",
|
|
73
|
+
results: [...results, status],
|
|
74
|
+
completed: false,
|
|
75
|
+
};
|
|
76
|
+
const observed = moduleStatusObservationSchema.parse(status.result.data);
|
|
77
|
+
if (observed.setupStatus !== "READY")
|
|
78
|
+
return {
|
|
79
|
+
phase: "start",
|
|
80
|
+
results: [...results, status],
|
|
81
|
+
completed: false,
|
|
82
|
+
blockedBy: {
|
|
83
|
+
moduleRef: module.moduleRef,
|
|
84
|
+
setupStatus: observed.setupStatus,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
const started = await dispatchModuleCommand(catalog, module, "start", context(workspaceRoot));
|
|
88
|
+
results.push(started);
|
|
89
|
+
if (!succeeded(started.result))
|
|
90
|
+
return { phase: "start", results, completed: false };
|
|
66
91
|
}
|
|
67
|
-
return { phase: "
|
|
92
|
+
return { phase: "start", results, completed: true };
|
|
68
93
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomflow/proflow-platform-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.17",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -18,14 +18,16 @@
|
|
|
18
18
|
"dist",
|
|
19
19
|
"proflow.module.json",
|
|
20
20
|
"conformance.json",
|
|
21
|
-
"README.md"
|
|
21
|
+
"README.md",
|
|
22
|
+
"DOCS.md",
|
|
23
|
+
"SETUP.md"
|
|
22
24
|
],
|
|
23
25
|
"dependencies": {
|
|
24
|
-
"@tomflow/proflow-module-contract": "^0.1.
|
|
26
|
+
"@tomflow/proflow-module-contract": "^0.1.4"
|
|
25
27
|
},
|
|
26
28
|
"devDependencies": {
|
|
27
|
-
"@tomflow/proflow-deployment-conformance": "^0.1.
|
|
28
|
-
"@tomflow/proflow-module-template": "^0.1.
|
|
29
|
+
"@tomflow/proflow-deployment-conformance": "^0.1.4",
|
|
30
|
+
"@tomflow/proflow-module-template": "^0.1.4"
|
|
29
31
|
},
|
|
30
32
|
"description": "Thin Platform CLI for Module discovery, documentation, package synchronization and lifecycle orchestration.",
|
|
31
33
|
"keywords": [
|
package/proflow.module.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"contractVersion": "1.0.0",
|
|
4
4
|
"moduleRef": "platform-cli",
|
|
5
5
|
"packageName": "@tomflow/proflow-platform-cli",
|
|
6
|
-
"moduleVersion": "0.1.
|
|
6
|
+
"moduleVersion": "0.1.17",
|
|
7
7
|
"kind": "cli",
|
|
8
8
|
"templateVersion": "1.0.0",
|
|
9
9
|
"platformCompatibility": ">=1.0.0 <2.0.0",
|
|
@@ -21,24 +21,9 @@
|
|
|
21
21
|
}
|
|
22
22
|
],
|
|
23
23
|
"configSlots": [],
|
|
24
|
-
"lifecycle": {
|
|
25
|
-
"supported": ["describe", "preflight", "status", "verify", "doctor"]
|
|
26
|
-
},
|
|
27
|
-
"verification": {
|
|
28
|
-
"checks": [
|
|
29
|
-
{
|
|
30
|
-
"id": "cli-surface",
|
|
31
|
-
"description": "Deterministic command surface parses and dispatches",
|
|
32
|
-
"lifecycle": "verify"
|
|
33
|
-
}
|
|
34
|
-
]
|
|
35
|
-
},
|
|
36
24
|
"effects": [],
|
|
37
|
-
"documentation":
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"description": "Platform CLI package overview and command surface"
|
|
42
|
-
}
|
|
43
|
-
]
|
|
25
|
+
"documentation": {
|
|
26
|
+
"docs": "DOCS.md",
|
|
27
|
+
"setup": "SETUP.md"
|
|
28
|
+
}
|
|
44
29
|
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { ResolvedModule } from "../contracts.ts";
|
|
2
|
-
type ResolvedSource = ResolvedModule["source"];
|
|
3
|
-
export interface DeploymentAdapterBinding {
|
|
4
|
-
behaviorAdapter: Record<string, unknown>;
|
|
5
|
-
}
|
|
6
|
-
export type ProductionBindingFactory = (input: {
|
|
7
|
-
moduleRef: string;
|
|
8
|
-
config: Record<string, string>;
|
|
9
|
-
workspaceRoot: string;
|
|
10
|
-
modules: readonly ResolvedModule[];
|
|
11
|
-
configByModuleRef: ReadonlyMap<string, Record<string, string>>;
|
|
12
|
-
}) => Promise<DeploymentAdapterBinding | undefined> | DeploymentAdapterBinding | undefined;
|
|
13
|
-
export interface ProductionBindingOptions {
|
|
14
|
-
workspaceRoot: string;
|
|
15
|
-
modules: readonly ResolvedModule[];
|
|
16
|
-
configByModuleRef: ReadonlyMap<string, {
|
|
17
|
-
publicValues: Record<string, string>;
|
|
18
|
-
secretValues: Record<string, string>;
|
|
19
|
-
}>;
|
|
20
|
-
importAdapter: (packageName: string, source: ResolvedSource) => Promise<Record<string, unknown>>;
|
|
21
|
-
}
|
|
22
|
-
export declare function importRawAdapter(packageName: string, source: ResolvedSource, workspaceRoot: string): Promise<Record<string, unknown>>;
|
|
23
|
-
/**
|
|
24
|
-
* The shipped Platform CLI production binding factory. For every discovered
|
|
25
|
-
* module it imports the module's own `deployment/adapter.ts` and, when that
|
|
26
|
-
* adapter exposes a `createProductionBinding` factory, invokes it with the
|
|
27
|
-
* module's materialized config to obtain a real bound adapter. A module without
|
|
28
|
-
* a production factory, or whose materialized config the adapter does not accept,
|
|
29
|
-
* is left out of the map. Import/factory exceptions are surfaced with module
|
|
30
|
-
* identity instead of being mistaken for ordinary unconfigured state. The
|
|
31
|
-
* catalog falls back to the module's unbound default only for explicit undefined
|
|
32
|
-
* bindings, which must fail-closed
|
|
33
|
-
* (ACTION_REQUIRED / NOT_READY). Platform CLI never invents a service or
|
|
34
|
-
* resource reality: it only relays the adapter's own current reality.
|
|
35
|
-
*/
|
|
36
|
-
export declare function buildProductionBindings(options: ProductionBindingOptions): Promise<ReadonlyMap<string, DeploymentAdapterBinding>>;
|
|
37
|
-
export {};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
-
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
-
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
-
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
return path;
|
|
8
|
-
};
|
|
9
|
-
import { createRequire } from "node:module";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
import { pathToFileURL } from "node:url";
|
|
12
|
-
import { PlatformError } from "../errors.js";
|
|
13
|
-
export async function importRawAdapter(packageName, source, workspaceRoot) {
|
|
14
|
-
if (source.type === "workspace") {
|
|
15
|
-
if (source.path === undefined)
|
|
16
|
-
return {};
|
|
17
|
-
const url = pathToFileURL(join(source.path, "deployment", "adapter.ts"));
|
|
18
|
-
return (await /* architecture-allow-local-file-url-import */ import(__rewriteRelativeImportExtension(url.href)));
|
|
19
|
-
}
|
|
20
|
-
const workspaceRequire = createRequire(pathToFileURL(join(workspaceRoot, "package.json")));
|
|
21
|
-
const resolved = workspaceRequire.resolve(`${packageName}/deployment/adapter`);
|
|
22
|
-
const url = pathToFileURL(resolved);
|
|
23
|
-
return (await /* architecture-allow-local-file-url-import */ import(__rewriteRelativeImportExtension(url.href)));
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* The shipped Platform CLI production binding factory. For every discovered
|
|
27
|
-
* module it imports the module's own `deployment/adapter.ts` and, when that
|
|
28
|
-
* adapter exposes a `createProductionBinding` factory, invokes it with the
|
|
29
|
-
* module's materialized config to obtain a real bound adapter. A module without
|
|
30
|
-
* a production factory, or whose materialized config the adapter does not accept,
|
|
31
|
-
* is left out of the map. Import/factory exceptions are surfaced with module
|
|
32
|
-
* identity instead of being mistaken for ordinary unconfigured state. The
|
|
33
|
-
* catalog falls back to the module's unbound default only for explicit undefined
|
|
34
|
-
* bindings, which must fail-closed
|
|
35
|
-
* (ACTION_REQUIRED / NOT_READY). Platform CLI never invents a service or
|
|
36
|
-
* resource reality: it only relays the adapter's own current reality.
|
|
37
|
-
*/
|
|
38
|
-
export async function buildProductionBindings(options) {
|
|
39
|
-
const bindings = new Map();
|
|
40
|
-
const publicConfigByModuleRef = new Map([...options.configByModuleRef].map(([moduleRef, config]) => [
|
|
41
|
-
moduleRef,
|
|
42
|
-
{ ...config.publicValues },
|
|
43
|
-
]));
|
|
44
|
-
for (const module of options.modules) {
|
|
45
|
-
try {
|
|
46
|
-
const namespace = await options.importAdapter(module.packageName, module.source);
|
|
47
|
-
const materialized = options.configByModuleRef.get(module.moduleRef);
|
|
48
|
-
const config = materialized === undefined
|
|
49
|
-
? {}
|
|
50
|
-
: { ...materialized.publicValues, ...materialized.secretValues };
|
|
51
|
-
const factory = namespace
|
|
52
|
-
.createProductionBinding;
|
|
53
|
-
if (typeof factory !== "function")
|
|
54
|
-
continue;
|
|
55
|
-
const binding = await factory({
|
|
56
|
-
moduleRef: module.moduleRef,
|
|
57
|
-
config,
|
|
58
|
-
workspaceRoot: options.workspaceRoot,
|
|
59
|
-
modules: options.modules,
|
|
60
|
-
configByModuleRef: publicConfigByModuleRef,
|
|
61
|
-
});
|
|
62
|
-
if (binding !== undefined &&
|
|
63
|
-
typeof binding === "object" &&
|
|
64
|
-
binding !== null &&
|
|
65
|
-
typeof binding.behaviorAdapter === "object" &&
|
|
66
|
-
binding.behaviorAdapter !== null) {
|
|
67
|
-
bindings.set(module.packageName, binding);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
catch (error) {
|
|
71
|
-
throw new PlatformError("COMMAND_FAILED", `production binding failed for ${module.moduleRef}: ${error instanceof Error ? error.message : String(error)}`);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
return bindings;
|
|
75
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { type ConfigSlot, type ModuleProvide, type ModuleRequire } from "@tomflow/proflow-module-contract";
|
|
2
|
-
import type { ResolvedModule } from "../contracts.ts";
|
|
3
|
-
import type { ModuleCatalog } from "../modules.ts";
|
|
4
|
-
export interface AggregatedDocument {
|
|
5
|
-
id: string;
|
|
6
|
-
path: string;
|
|
7
|
-
description?: string;
|
|
8
|
-
content: string;
|
|
9
|
-
}
|
|
10
|
-
export interface AggregatedModuleDocs {
|
|
11
|
-
moduleRef: string;
|
|
12
|
-
version: string;
|
|
13
|
-
provides: ModuleProvide[];
|
|
14
|
-
requires: ModuleRequire[];
|
|
15
|
-
configSlots: ConfigSlot[];
|
|
16
|
-
documents: AggregatedDocument[];
|
|
17
|
-
}
|
|
18
|
-
export declare function aggregateModuleDocs(workspaceRoot: string, catalog: ModuleCatalog, modules: readonly ResolvedModule[]): Promise<AggregatedModuleDocs[]>;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { parseModuleDescriptor, } from "@tomflow/proflow-module-contract";
|
|
2
|
-
import { readModuleDocument } from "./docs.js";
|
|
3
|
-
function sourceOf(module) {
|
|
4
|
-
return module.source.path === undefined
|
|
5
|
-
? { type: module.source.type, packageName: module.packageName }
|
|
6
|
-
: {
|
|
7
|
-
type: module.source.type,
|
|
8
|
-
packageName: module.packageName,
|
|
9
|
-
path: module.source.path,
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
export async function aggregateModuleDocs(workspaceRoot, catalog, modules) {
|
|
13
|
-
const output = [];
|
|
14
|
-
for (const module of [...modules].sort((a, b) => a.moduleRef.localeCompare(b.moduleRef))) {
|
|
15
|
-
const source = sourceOf(module);
|
|
16
|
-
const descriptor = parseModuleDescriptor(await catalog.loadDescriptor(source));
|
|
17
|
-
const documents = [];
|
|
18
|
-
for (const entry of descriptor.documentation) {
|
|
19
|
-
const document = await readModuleDocument({
|
|
20
|
-
workspaceRoot,
|
|
21
|
-
source,
|
|
22
|
-
descriptor,
|
|
23
|
-
documentId: entry.id,
|
|
24
|
-
});
|
|
25
|
-
documents.push({
|
|
26
|
-
id: document.documentId,
|
|
27
|
-
path: document.path,
|
|
28
|
-
...(document.description === undefined
|
|
29
|
-
? {}
|
|
30
|
-
: { description: document.description }),
|
|
31
|
-
content: document.content,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
output.push({
|
|
35
|
-
moduleRef: module.moduleRef,
|
|
36
|
-
version: module.moduleVersion,
|
|
37
|
-
provides: [...descriptor.provides],
|
|
38
|
-
requires: [...descriptor.requires],
|
|
39
|
-
configSlots: [...descriptor.configSlots],
|
|
40
|
-
documents,
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
return output;
|
|
44
|
-
}
|
package/dist/src/docs/docs.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { ModuleDescriptor } from "@tomflow/proflow-module-contract";
|
|
2
|
-
import type { ModuleSource } from "../modules.ts";
|
|
3
|
-
export interface ModuleDocumentContent {
|
|
4
|
-
moduleRef: string;
|
|
5
|
-
packageName: string;
|
|
6
|
-
documentId: string;
|
|
7
|
-
path: string;
|
|
8
|
-
description?: string;
|
|
9
|
-
content: string;
|
|
10
|
-
}
|
|
11
|
-
export declare function readModuleDocument(input: {
|
|
12
|
-
workspaceRoot: string;
|
|
13
|
-
source: ModuleSource;
|
|
14
|
-
descriptor: ModuleDescriptor;
|
|
15
|
-
documentId: string;
|
|
16
|
-
}): Promise<ModuleDocumentContent>;
|
package/dist/src/docs/docs.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { readFile, realpath, stat } from "node:fs/promises";
|
|
2
|
-
import { createRequire } from "node:module";
|
|
3
|
-
import { dirname, join, resolve, sep } from "node:path";
|
|
4
|
-
import { pathToFileURL } from "node:url";
|
|
5
|
-
import { PlatformError } from "../errors.js";
|
|
6
|
-
async function packageRootFor(workspaceRoot, source) {
|
|
7
|
-
if (source.type === "workspace") {
|
|
8
|
-
if (source.path === undefined) {
|
|
9
|
-
throw new PlatformError("DESCRIPTOR_INVALID", `workspace source missing path for ${source.packageName}`);
|
|
10
|
-
}
|
|
11
|
-
return await realpath(source.path);
|
|
12
|
-
}
|
|
13
|
-
const require = createRequire(pathToFileURL(join(workspaceRoot, "package.json")));
|
|
14
|
-
let current;
|
|
15
|
-
try {
|
|
16
|
-
current = dirname(require.resolve(`${source.packageName}/deployment/descriptor`));
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
throw new PlatformError("DESCRIPTOR_INVALID", `cannot resolve installed package ${source.packageName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
20
|
-
}
|
|
21
|
-
for (;;) {
|
|
22
|
-
try {
|
|
23
|
-
const manifest = JSON.parse(await readFile(join(current, "package.json"), "utf8"));
|
|
24
|
-
if (manifest.name === source.packageName)
|
|
25
|
-
return await realpath(current);
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
// Export maps commonly hide package.json; keep walking from a resolved
|
|
29
|
-
// package-owned descriptor until the package root is found.
|
|
30
|
-
}
|
|
31
|
-
const parent = dirname(current);
|
|
32
|
-
if (parent === current)
|
|
33
|
-
break;
|
|
34
|
-
current = parent;
|
|
35
|
-
}
|
|
36
|
-
throw new PlatformError("DESCRIPTOR_INVALID", `package root not found for ${source.packageName}`);
|
|
37
|
-
}
|
|
38
|
-
export async function readModuleDocument(input) {
|
|
39
|
-
const entry = input.descriptor.documentation.find((candidate) => candidate.id === input.documentId);
|
|
40
|
-
if (entry === undefined) {
|
|
41
|
-
throw new PlatformError("INVALID_REQUEST", `document "${input.documentId}" is not declared by ${input.descriptor.moduleRef}`);
|
|
42
|
-
}
|
|
43
|
-
const packageRoot = await packageRootFor(input.workspaceRoot, input.source);
|
|
44
|
-
const root = resolve(packageRoot);
|
|
45
|
-
const target = resolve(root, entry.path);
|
|
46
|
-
if (target === root || !target.startsWith(`${root}${sep}`)) {
|
|
47
|
-
throw new PlatformError("DESCRIPTOR_INVALID", `documentation path escapes package root for ${input.descriptor.moduleRef}`);
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
const info = await stat(target);
|
|
51
|
-
if (!info.isFile())
|
|
52
|
-
throw new Error("not a file");
|
|
53
|
-
const content = await readFile(target, "utf8");
|
|
54
|
-
return {
|
|
55
|
-
moduleRef: input.descriptor.moduleRef,
|
|
56
|
-
packageName: input.descriptor.packageName,
|
|
57
|
-
documentId: entry.id,
|
|
58
|
-
path: entry.path,
|
|
59
|
-
...(entry.description === undefined
|
|
60
|
-
? {}
|
|
61
|
-
: { description: entry.description }),
|
|
62
|
-
content,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
throw new PlatformError("DESCRIPTOR_INVALID", `cannot read document ${entry.id} for ${input.descriptor.moduleRef}: ${error instanceof Error ? error.message : String(error)}`);
|
|
67
|
-
}
|
|
68
|
-
}
|
package/dist/src/docs/index.d.ts
DELETED