@procedures/store 0.0.0-stage → 0.2.0
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/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +65 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/errors.d.ts +16 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/module.d.ts +23 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +26 -0
- package/dist/module.js.map +1 -0
- package/dist/procedures.d.ts +13 -0
- package/dist/procedures.d.ts.map +1 -0
- package/dist/procedures.js +14 -0
- package/dist/procedures.js.map +1 -0
- package/dist/program-store/attach.d.ts +20 -0
- package/dist/program-store/attach.d.ts.map +1 -0
- package/dist/program-store/attach.js +36 -0
- package/dist/program-store/attach.js.map +1 -0
- package/dist/program-store/collection.d.ts +19 -0
- package/dist/program-store/collection.d.ts.map +1 -0
- package/dist/program-store/collection.js +34 -0
- package/dist/program-store/collection.js.map +1 -0
- package/dist/program-store/file.d.ts +29 -0
- package/dist/program-store/file.d.ts.map +1 -0
- package/dist/program-store/file.js +156 -0
- package/dist/program-store/file.js.map +1 -0
- package/dist/program-store/index.d.ts +11 -0
- package/dist/program-store/index.d.ts.map +1 -0
- package/dist/program-store/index.js +10 -0
- package/dist/program-store/index.js.map +1 -0
- package/dist/program-store/memory.d.ts +15 -0
- package/dist/program-store/memory.d.ts.map +1 -0
- package/dist/program-store/memory.js +25 -0
- package/dist/program-store/memory.js.map +1 -0
- package/dist/program-store/procedures.d.ts +23 -0
- package/dist/program-store/procedures.d.ts.map +1 -0
- package/dist/program-store/procedures.js +228 -0
- package/dist/program-store/procedures.js.map +1 -0
- package/dist/program-store/types.d.ts +50 -0
- package/dist/program-store/types.d.ts.map +1 -0
- package/dist/program-store/types.js +41 -0
- package/dist/program-store/types.js.map +1 -0
- package/dist/register.d.ts +7 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +9 -0
- package/dist/register.js.map +1 -0
- package/dist/storage/adapter.d.ts +148 -0
- package/dist/storage/adapter.d.ts.map +1 -0
- package/dist/storage/adapter.js +214 -0
- package/dist/storage/adapter.js.map +1 -0
- package/dist/storage/api.d.ts +125 -0
- package/dist/storage/api.d.ts.map +1 -0
- package/dist/storage/api.js +220 -0
- package/dist/storage/api.js.map +1 -0
- package/dist/storage/factory.d.ts +134 -0
- package/dist/storage/factory.d.ts.map +1 -0
- package/dist/storage/factory.js +166 -0
- package/dist/storage/factory.js.map +1 -0
- package/dist/storage/hybrid.d.ts +193 -0
- package/dist/storage/hybrid.d.ts.map +1 -0
- package/dist/storage/hybrid.js +519 -0
- package/dist/storage/hybrid.js.map +1 -0
- package/dist/storage/index.d.ts +21 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +20 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/procedures.d.ts +14 -0
- package/dist/storage/procedures.d.ts.map +1 -0
- package/dist/storage/procedures.js +101 -0
- package/dist/storage/procedures.js.map +1 -0
- package/dist/storage/serialization.d.ts +123 -0
- package/dist/storage/serialization.d.ts.map +1 -0
- package/dist/storage/serialization.js +216 -0
- package/dist/storage/serialization.js.map +1 -0
- package/dist/storage/synced-registry.d.ts +246 -0
- package/dist/storage/synced-registry.d.ts.map +1 -0
- package/dist/storage/synced-registry.js +575 -0
- package/dist/storage/synced-registry.js.map +1 -0
- package/dist/storage/types.d.ts +130 -0
- package/dist/storage/types.d.ts.map +1 -0
- package/dist/storage/types.js +8 -0
- package/dist/storage/types.js.map +1 -0
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/package.json +78 -3
- package/src/errors.ts +20 -0
- package/src/index.ts +19 -0
- package/src/module.ts +30 -0
- package/src/procedures.ts +17 -0
- package/src/program-store/attach.ts +46 -0
- package/src/program-store/collection.ts +39 -0
- package/src/program-store/file.ts +157 -0
- package/src/program-store/index.ts +17 -0
- package/src/program-store/memory.ts +30 -0
- package/src/program-store/procedures.ts +351 -0
- package/src/program-store/types.ts +78 -0
- package/src/register.ts +11 -0
- package/src/storage/adapter.ts +273 -0
- package/src/storage/api.ts +335 -0
- package/src/storage/factory.ts +268 -0
- package/src/storage/hybrid.ts +676 -0
- package/src/storage/index.ts +61 -0
- package/src/storage/procedures.ts +149 -0
- package/src/storage/serialization.ts +283 -0
- package/src/storage/synced-registry.ts +698 -0
- package/src/storage/types.ts +180 -0
- package/src/types.ts +7 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* procedure.register: register a procedure at run time, from a handler reference.
|
|
3
|
+
*
|
|
4
|
+
* With `persist`, the procedure goes into the store of a synced registry (`createSyncedRegistry()`),
|
|
5
|
+
* and only with a handler that the store's loader allows: never a stub (deep dive CORE-16). Without
|
|
6
|
+
* a store, `persist` fails with the code NOT_CONFIGURED.
|
|
7
|
+
*
|
|
8
|
+
* The programs of `procedure.define` have their own store: `procedure.store`, `load` and `sync`
|
|
9
|
+
* (../program-store/procedures.ts, roadmap 3.2).
|
|
10
|
+
*/
|
|
11
|
+
import { defineProcedure } from "@procedures/client";
|
|
12
|
+
import { PROCEDURE_REGISTRY } from "@procedures/client";
|
|
13
|
+
import { pathToKey } from "@procedures/client";
|
|
14
|
+
import { deserializeProcedure, deserializeProcedureSync } from "./serialization.js";
|
|
15
|
+
import { getProcedureStore } from "./synced-registry.js";
|
|
16
|
+
import { ProcedureStoreError } from "../errors.js";
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Any Schema Helper
|
|
19
|
+
// =============================================================================
|
|
20
|
+
const anySchema = {
|
|
21
|
+
parse: (data) => data,
|
|
22
|
+
safeParse: (data) => ({ success: true, data }),
|
|
23
|
+
_output: undefined,
|
|
24
|
+
};
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// The store of the caller
|
|
27
|
+
// =============================================================================
|
|
28
|
+
export { ProcedureStoreError } from "../errors.js";
|
|
29
|
+
/** The registry of the caller: the context's registry when it has one, else the global one. */
|
|
30
|
+
function callerRegistry(ctx) {
|
|
31
|
+
return ctx?.registry ?? PROCEDURE_REGISTRY;
|
|
32
|
+
}
|
|
33
|
+
/** The store of the caller's registry, or a NOT_CONFIGURED error. */
|
|
34
|
+
function requireStore(ctx, what) {
|
|
35
|
+
const store = getProcedureStore(callerRegistry(ctx));
|
|
36
|
+
if (!store) {
|
|
37
|
+
throw new ProcedureStoreError("NOT_CONFIGURED", `${what} needs a procedure store, and this registry has none. ` +
|
|
38
|
+
"Wrap the registry with createSyncedRegistry() or new SyncedProcedureRegistry().");
|
|
39
|
+
}
|
|
40
|
+
return store;
|
|
41
|
+
}
|
|
42
|
+
export const procedureRegisterProcedure = defineProcedure({
|
|
43
|
+
path: ["procedure", "register"],
|
|
44
|
+
input: anySchema,
|
|
45
|
+
output: anySchema,
|
|
46
|
+
metadata: {
|
|
47
|
+
description: "Register a procedure at runtime",
|
|
48
|
+
tags: ["procedure", "registry", "storage"],
|
|
49
|
+
// It never replaces a registered procedure. With `persist`, it writes the record to the
|
|
50
|
+
// store of the synced registry, over a stored record of the same key.
|
|
51
|
+
effects: { reads: ["registry"], writes: ["registry"] },
|
|
52
|
+
},
|
|
53
|
+
handler: async (input, ctx) => {
|
|
54
|
+
const { path, metadata = {}, streaming, handlerRef, persist = false } = input;
|
|
55
|
+
const key = pathToKey(path);
|
|
56
|
+
const serialized = {
|
|
57
|
+
path,
|
|
58
|
+
metadata,
|
|
59
|
+
streaming,
|
|
60
|
+
handlerRef,
|
|
61
|
+
storedAt: Date.now(),
|
|
62
|
+
};
|
|
63
|
+
if (persist) {
|
|
64
|
+
// A stored procedure needs a handler: never store a stub (deep dive CORE-16)
|
|
65
|
+
const store = requireStore(ctx, "procedure.register with persist");
|
|
66
|
+
const loader = store.getHandlerLoader();
|
|
67
|
+
const procedure = handlerRef && loader ? await deserializeProcedure(serialized, { handlerLoader: loader }) : undefined;
|
|
68
|
+
if (!procedure?.handler) {
|
|
69
|
+
throw new ProcedureStoreError("NO_HANDLER", `procedure.register with persist needs a handler for ${key}: give a handlerRef ` +
|
|
70
|
+
"that the handler loader of the store allows.");
|
|
71
|
+
}
|
|
72
|
+
store.register(procedure, { override: false, handlerRef });
|
|
73
|
+
await store.flushWrites();
|
|
74
|
+
return { success: true, message: `Registered and stored ${key}`, path, hasHandler: true };
|
|
75
|
+
}
|
|
76
|
+
// No persist: load the handler when the store's loader allows it, else declare a stub
|
|
77
|
+
const loader = getProcedureStore(callerRegistry(ctx))?.getHandlerLoader();
|
|
78
|
+
const procedure = handlerRef && loader ? await deserializeProcedure(serialized, { handlerLoader: loader }) : deserializeProcedureSync(serialized);
|
|
79
|
+
try {
|
|
80
|
+
callerRegistry(ctx).register(procedure, { override: false });
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
message: error instanceof Error ? error.message : "Registration failed",
|
|
86
|
+
path,
|
|
87
|
+
hasHandler: false,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const hasHandler = typeof procedure.handler === "function";
|
|
91
|
+
return {
|
|
92
|
+
success: true,
|
|
93
|
+
message: hasHandler
|
|
94
|
+
? `Registered ${key}`
|
|
95
|
+
: `Registered ${key} with no handler: a Client sends the calls of this path to its transport`,
|
|
96
|
+
path,
|
|
97
|
+
hasHandler,
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=procedures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"procedures.js","sourceRoot":"","sources":["../../src/storage/procedures.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedure Serialization
|
|
3
|
+
*
|
|
4
|
+
* Utilities for converting procedures to/from serialized format.
|
|
5
|
+
* Enables storage and transmission of procedure definitions.
|
|
6
|
+
*/
|
|
7
|
+
import type { AnyProcedure, ProcedurePath } from "@procedures/client";
|
|
8
|
+
import type { SerializedProcedure, HandlerReference, HandlerLoader } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Options for serializing a procedure.
|
|
11
|
+
*/
|
|
12
|
+
export interface SerializeOptions {
|
|
13
|
+
/** Handler reference to store (optional, handlers can't be serialized directly) */
|
|
14
|
+
handlerRef?: HandlerReference | undefined;
|
|
15
|
+
/** Whether to include version info */
|
|
16
|
+
includeVersion?: boolean | undefined;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Serialize a procedure to storable format.
|
|
20
|
+
*
|
|
21
|
+
* Note: Handler functions cannot be serialized. If the procedure has a handler,
|
|
22
|
+
* you should provide a `handlerRef` that can be used to load it later.
|
|
23
|
+
*
|
|
24
|
+
* @param procedure - Procedure to serialize
|
|
25
|
+
* @param options - Serialization options
|
|
26
|
+
* @returns Serialized procedure definition
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const serialized = serializeProcedure(myProcedure, {
|
|
31
|
+
* handlerRef: {
|
|
32
|
+
* module: "@procedures/cli-run",
|
|
33
|
+
* export: "libScanHandler",
|
|
34
|
+
* },
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function serializeProcedure(procedure: AnyProcedure, options?: SerializeOptions): SerializedProcedure;
|
|
39
|
+
/**
|
|
40
|
+
* Options for deserializing a procedure.
|
|
41
|
+
*/
|
|
42
|
+
export interface DeserializeOptions {
|
|
43
|
+
/** Handler loader to restore handlers from references */
|
|
44
|
+
handlerLoader?: HandlerLoader | undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Deserialize a procedure from stored format.
|
|
48
|
+
*
|
|
49
|
+
* Returns a stub procedure without a handler unless a handlerLoader is provided
|
|
50
|
+
* and the serialized procedure has a handlerRef.
|
|
51
|
+
*
|
|
52
|
+
* @param data - Serialized procedure data
|
|
53
|
+
* @param options - Deserialization options
|
|
54
|
+
* @returns Procedure (stub if no handler can be loaded)
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* // Deserialize as stub (no handler)
|
|
59
|
+
* const stub = await deserializeProcedure(data);
|
|
60
|
+
*
|
|
61
|
+
* // Deserialize with handler loading
|
|
62
|
+
* const proc = await deserializeProcedure(data, {
|
|
63
|
+
* handlerLoader: myLoader,
|
|
64
|
+
* });
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function deserializeProcedure(data: SerializedProcedure, options?: DeserializeOptions): Promise<AnyProcedure>;
|
|
68
|
+
/**
|
|
69
|
+
* Synchronous version that always returns a stub.
|
|
70
|
+
* Use when you don't need to load handlers.
|
|
71
|
+
*/
|
|
72
|
+
export declare function deserializeProcedureSync(data: SerializedProcedure): AnyProcedure;
|
|
73
|
+
/**
|
|
74
|
+
* Get the storage key (ID) for a procedure.
|
|
75
|
+
* Uses the dot-separated path as the key.
|
|
76
|
+
*
|
|
77
|
+
* @param pathOrProcedure - Procedure path or procedure object
|
|
78
|
+
* @returns Storage key string
|
|
79
|
+
*/
|
|
80
|
+
export declare function getProcedureKey(pathOrProcedure: ProcedurePath | AnyProcedure): string;
|
|
81
|
+
/**
|
|
82
|
+
* Get the storage key from a serialized procedure.
|
|
83
|
+
*/
|
|
84
|
+
export declare function getSerializedKey(data: SerializedProcedure): string;
|
|
85
|
+
/**
|
|
86
|
+
* Serialize multiple procedures.
|
|
87
|
+
*
|
|
88
|
+
* @param procedures - Procedures to serialize
|
|
89
|
+
* @param options - Serialization options
|
|
90
|
+
* @returns Array of [key, serialized] tuples for batch storage
|
|
91
|
+
*/
|
|
92
|
+
export declare function serializeProcedures(procedures: AnyProcedure[], options?: SerializeOptions): Array<[string, SerializedProcedure]>;
|
|
93
|
+
/**
|
|
94
|
+
* Deserialize multiple procedures.
|
|
95
|
+
*
|
|
96
|
+
* @param items - Array of serialized procedures
|
|
97
|
+
* @param options - Deserialization options
|
|
98
|
+
* @returns Array of procedures
|
|
99
|
+
*/
|
|
100
|
+
export declare function deserializeProcedures(items: SerializedProcedure[], options?: DeserializeOptions): Promise<AnyProcedure[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Create a handler loader using dynamic imports of the allowed modules only.
|
|
103
|
+
*
|
|
104
|
+
* A stored procedure record names the module of its handler, and the storage can be remote
|
|
105
|
+
* (`api`, `hybrid`). So the loader imports only the modules in `allowedModules` (exact package
|
|
106
|
+
* names, or a prefix that ends with "*"), and never a URL or a path (`data:`, `file:`, `node:`,
|
|
107
|
+
* `./x`, `/x`, a drive letter). Before, it imported any module that a record named: a record
|
|
108
|
+
* with `node:child_process` ran a shell command (BUGS-2026-07 M11, deep dive CORE-7, DATA-11).
|
|
109
|
+
*
|
|
110
|
+
* @param allowedModules - Module names the loader may import, such as "@procedures/git"
|
|
111
|
+
* @returns Handler loader that uses import() to load allowed modules
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* const loader = createDynamicHandlerLoader(["@procedures/*"]);
|
|
116
|
+
* const handler = await loader.load({
|
|
117
|
+
* module: "@procedures/cli-run",
|
|
118
|
+
* export: "libScanHandler",
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export declare function createDynamicHandlerLoader(allowedModules: readonly string[]): HandlerLoader;
|
|
123
|
+
//# sourceMappingURL=serialization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/storage/serialization.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwBvF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,UAAU,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAE1C,sCAAsC;IACtC,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,YAAY,EACvB,OAAO,GAAE,gBAAqB,GAC7B,mBAAmB,CAuBrB;AAMD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,yDAAyD;IACzD,aAAa,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC3C;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,mBAAmB,EACzB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,YAAY,CAAC,CA0BvB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,mBAAmB,GAAG,YAAY,CAahF;AAMD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,eAAe,EAAE,aAAa,GAAG,YAAY,GAAG,MAAM,CAGrF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAElE;AAMD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,YAAY,EAAE,EAC1B,OAAO,GAAE,gBAAqB,GAC7B,KAAK,CAAC,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAKtC;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,mBAAmB,EAAE,EAC5B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,YAAY,EAAE,CAAC,CAEzB;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,0BAA0B,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CAwB3F"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedure Serialization
|
|
3
|
+
*
|
|
4
|
+
* Utilities for converting procedures to/from serialized format.
|
|
5
|
+
* Enables storage and transmission of procedure definitions.
|
|
6
|
+
*/
|
|
7
|
+
import { pathToKey } from "@procedures/client";
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// Any Schema (for deserialized procedures without schemas)
|
|
10
|
+
// =============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Passthrough schema that accepts any value.
|
|
13
|
+
* Used for deserialized procedures where original schemas aren't available.
|
|
14
|
+
*/
|
|
15
|
+
const anySchema = {
|
|
16
|
+
parse: (data) => data,
|
|
17
|
+
safeParse: (data) => ({ success: true, data }),
|
|
18
|
+
_output: undefined,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Serialize a procedure to storable format.
|
|
22
|
+
*
|
|
23
|
+
* Note: Handler functions cannot be serialized. If the procedure has a handler,
|
|
24
|
+
* you should provide a `handlerRef` that can be used to load it later.
|
|
25
|
+
*
|
|
26
|
+
* @param procedure - Procedure to serialize
|
|
27
|
+
* @param options - Serialization options
|
|
28
|
+
* @returns Serialized procedure definition
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const serialized = serializeProcedure(myProcedure, {
|
|
33
|
+
* handlerRef: {
|
|
34
|
+
* module: "@procedures/cli-run",
|
|
35
|
+
* export: "libScanHandler",
|
|
36
|
+
* },
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function serializeProcedure(procedure, options = {}) {
|
|
41
|
+
const serialized = {
|
|
42
|
+
path: procedure.path,
|
|
43
|
+
metadata: { ...procedure.metadata },
|
|
44
|
+
storedAt: Date.now(),
|
|
45
|
+
};
|
|
46
|
+
// Only include streaming if explicitly set
|
|
47
|
+
if (procedure.streaming !== undefined) {
|
|
48
|
+
serialized.streaming = procedure.streaming;
|
|
49
|
+
}
|
|
50
|
+
// Include handler reference if provided
|
|
51
|
+
if (options.handlerRef) {
|
|
52
|
+
serialized.handlerRef = options.handlerRef;
|
|
53
|
+
}
|
|
54
|
+
// Include version if requested
|
|
55
|
+
if (options.includeVersion) {
|
|
56
|
+
serialized.version = 1;
|
|
57
|
+
}
|
|
58
|
+
return serialized;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Deserialize a procedure from stored format.
|
|
62
|
+
*
|
|
63
|
+
* Returns a stub procedure without a handler unless a handlerLoader is provided
|
|
64
|
+
* and the serialized procedure has a handlerRef.
|
|
65
|
+
*
|
|
66
|
+
* @param data - Serialized procedure data
|
|
67
|
+
* @param options - Deserialization options
|
|
68
|
+
* @returns Procedure (stub if no handler can be loaded)
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```typescript
|
|
72
|
+
* // Deserialize as stub (no handler)
|
|
73
|
+
* const stub = await deserializeProcedure(data);
|
|
74
|
+
*
|
|
75
|
+
* // Deserialize with handler loading
|
|
76
|
+
* const proc = await deserializeProcedure(data, {
|
|
77
|
+
* handlerLoader: myLoader,
|
|
78
|
+
* });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export async function deserializeProcedure(data, options = {}) {
|
|
82
|
+
const procedure = {
|
|
83
|
+
path: data.path,
|
|
84
|
+
input: anySchema,
|
|
85
|
+
output: anySchema,
|
|
86
|
+
metadata: { ...data.metadata },
|
|
87
|
+
};
|
|
88
|
+
// Set streaming if present
|
|
89
|
+
if (data.streaming !== undefined) {
|
|
90
|
+
procedure.streaming = data.streaming;
|
|
91
|
+
}
|
|
92
|
+
// Try to load handler if reference exists and loader is provided
|
|
93
|
+
if (data.handlerRef && options.handlerLoader) {
|
|
94
|
+
try {
|
|
95
|
+
const handler = await options.handlerLoader.load(data.handlerRef);
|
|
96
|
+
if (handler && typeof handler === "function") {
|
|
97
|
+
procedure.handler = handler;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Handler loading failed, procedure remains a stub
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return procedure;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Synchronous version that always returns a stub.
|
|
108
|
+
* Use when you don't need to load handlers.
|
|
109
|
+
*/
|
|
110
|
+
export function deserializeProcedureSync(data) {
|
|
111
|
+
const procedure = {
|
|
112
|
+
path: data.path,
|
|
113
|
+
input: anySchema,
|
|
114
|
+
output: anySchema,
|
|
115
|
+
metadata: { ...data.metadata },
|
|
116
|
+
};
|
|
117
|
+
if (data.streaming !== undefined) {
|
|
118
|
+
procedure.streaming = data.streaming;
|
|
119
|
+
}
|
|
120
|
+
return procedure;
|
|
121
|
+
}
|
|
122
|
+
// =============================================================================
|
|
123
|
+
// Storage Key Utilities
|
|
124
|
+
// =============================================================================
|
|
125
|
+
/**
|
|
126
|
+
* Get the storage key (ID) for a procedure.
|
|
127
|
+
* Uses the dot-separated path as the key.
|
|
128
|
+
*
|
|
129
|
+
* @param pathOrProcedure - Procedure path or procedure object
|
|
130
|
+
* @returns Storage key string
|
|
131
|
+
*/
|
|
132
|
+
export function getProcedureKey(pathOrProcedure) {
|
|
133
|
+
const path = Array.isArray(pathOrProcedure) ? pathOrProcedure : pathOrProcedure.path;
|
|
134
|
+
return pathToKey(path);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get the storage key from a serialized procedure.
|
|
138
|
+
*/
|
|
139
|
+
export function getSerializedKey(data) {
|
|
140
|
+
return pathToKey(data.path);
|
|
141
|
+
}
|
|
142
|
+
// =============================================================================
|
|
143
|
+
// Batch Operations
|
|
144
|
+
// =============================================================================
|
|
145
|
+
/**
|
|
146
|
+
* Serialize multiple procedures.
|
|
147
|
+
*
|
|
148
|
+
* @param procedures - Procedures to serialize
|
|
149
|
+
* @param options - Serialization options
|
|
150
|
+
* @returns Array of [key, serialized] tuples for batch storage
|
|
151
|
+
*/
|
|
152
|
+
export function serializeProcedures(procedures, options = {}) {
|
|
153
|
+
return procedures.map((proc) => [
|
|
154
|
+
getProcedureKey(proc),
|
|
155
|
+
serializeProcedure(proc, options),
|
|
156
|
+
]);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Deserialize multiple procedures.
|
|
160
|
+
*
|
|
161
|
+
* @param items - Array of serialized procedures
|
|
162
|
+
* @param options - Deserialization options
|
|
163
|
+
* @returns Array of procedures
|
|
164
|
+
*/
|
|
165
|
+
export async function deserializeProcedures(items, options = {}) {
|
|
166
|
+
return Promise.all(items.map((item) => deserializeProcedure(item, options)));
|
|
167
|
+
}
|
|
168
|
+
// =============================================================================
|
|
169
|
+
// Default Handler Loader
|
|
170
|
+
// =============================================================================
|
|
171
|
+
/**
|
|
172
|
+
* Create a handler loader using dynamic imports of the allowed modules only.
|
|
173
|
+
*
|
|
174
|
+
* A stored procedure record names the module of its handler, and the storage can be remote
|
|
175
|
+
* (`api`, `hybrid`). So the loader imports only the modules in `allowedModules` (exact package
|
|
176
|
+
* names, or a prefix that ends with "*"), and never a URL or a path (`data:`, `file:`, `node:`,
|
|
177
|
+
* `./x`, `/x`, a drive letter). Before, it imported any module that a record named: a record
|
|
178
|
+
* with `node:child_process` ran a shell command (BUGS-2026-07 M11, deep dive CORE-7, DATA-11).
|
|
179
|
+
*
|
|
180
|
+
* @param allowedModules - Module names the loader may import, such as "@procedures/git"
|
|
181
|
+
* @returns Handler loader that uses import() to load allowed modules
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const loader = createDynamicHandlerLoader(["@procedures/*"]);
|
|
186
|
+
* const handler = await loader.load({
|
|
187
|
+
* module: "@procedures/cli-run",
|
|
188
|
+
* export: "libScanHandler",
|
|
189
|
+
* });
|
|
190
|
+
* ```
|
|
191
|
+
*/
|
|
192
|
+
export function createDynamicHandlerLoader(allowedModules) {
|
|
193
|
+
const allowed = (specifier) => {
|
|
194
|
+
// A URL scheme (data:, file:, node:, C:) or a relative or absolute path is never allowed
|
|
195
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(specifier) || /^[./\\]/.test(specifier)) {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
return allowedModules.some((entry) => entry.endsWith("*") ? specifier.startsWith(entry.slice(0, -1)) : specifier === entry);
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
async load(ref) {
|
|
202
|
+
if (!allowed(ref.module)) {
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
// The specifier is checked against the allowlist above. A bundler cannot follow it.
|
|
207
|
+
const module = await import(/* @vite-ignore */ ref.module);
|
|
208
|
+
return module[ref.export];
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=serialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../src/storage/serialization.ts"],"names":[],"mappings":"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"}
|