@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.
Files changed (115) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +65 -2
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/errors.d.ts +16 -0
  6. package/dist/errors.d.ts.map +1 -0
  7. package/dist/errors.js +18 -0
  8. package/dist/errors.js.map +1 -0
  9. package/dist/index.d.ts +19 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +19 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/module.d.ts +23 -0
  14. package/dist/module.d.ts.map +1 -0
  15. package/dist/module.js +26 -0
  16. package/dist/module.js.map +1 -0
  17. package/dist/procedures.d.ts +13 -0
  18. package/dist/procedures.d.ts.map +1 -0
  19. package/dist/procedures.js +14 -0
  20. package/dist/procedures.js.map +1 -0
  21. package/dist/program-store/attach.d.ts +20 -0
  22. package/dist/program-store/attach.d.ts.map +1 -0
  23. package/dist/program-store/attach.js +36 -0
  24. package/dist/program-store/attach.js.map +1 -0
  25. package/dist/program-store/collection.d.ts +19 -0
  26. package/dist/program-store/collection.d.ts.map +1 -0
  27. package/dist/program-store/collection.js +34 -0
  28. package/dist/program-store/collection.js.map +1 -0
  29. package/dist/program-store/file.d.ts +29 -0
  30. package/dist/program-store/file.d.ts.map +1 -0
  31. package/dist/program-store/file.js +156 -0
  32. package/dist/program-store/file.js.map +1 -0
  33. package/dist/program-store/index.d.ts +11 -0
  34. package/dist/program-store/index.d.ts.map +1 -0
  35. package/dist/program-store/index.js +10 -0
  36. package/dist/program-store/index.js.map +1 -0
  37. package/dist/program-store/memory.d.ts +15 -0
  38. package/dist/program-store/memory.d.ts.map +1 -0
  39. package/dist/program-store/memory.js +25 -0
  40. package/dist/program-store/memory.js.map +1 -0
  41. package/dist/program-store/procedures.d.ts +23 -0
  42. package/dist/program-store/procedures.d.ts.map +1 -0
  43. package/dist/program-store/procedures.js +228 -0
  44. package/dist/program-store/procedures.js.map +1 -0
  45. package/dist/program-store/types.d.ts +50 -0
  46. package/dist/program-store/types.d.ts.map +1 -0
  47. package/dist/program-store/types.js +41 -0
  48. package/dist/program-store/types.js.map +1 -0
  49. package/dist/register.d.ts +7 -0
  50. package/dist/register.d.ts.map +1 -0
  51. package/dist/register.js +9 -0
  52. package/dist/register.js.map +1 -0
  53. package/dist/storage/adapter.d.ts +148 -0
  54. package/dist/storage/adapter.d.ts.map +1 -0
  55. package/dist/storage/adapter.js +214 -0
  56. package/dist/storage/adapter.js.map +1 -0
  57. package/dist/storage/api.d.ts +125 -0
  58. package/dist/storage/api.d.ts.map +1 -0
  59. package/dist/storage/api.js +220 -0
  60. package/dist/storage/api.js.map +1 -0
  61. package/dist/storage/factory.d.ts +134 -0
  62. package/dist/storage/factory.d.ts.map +1 -0
  63. package/dist/storage/factory.js +166 -0
  64. package/dist/storage/factory.js.map +1 -0
  65. package/dist/storage/hybrid.d.ts +193 -0
  66. package/dist/storage/hybrid.d.ts.map +1 -0
  67. package/dist/storage/hybrid.js +519 -0
  68. package/dist/storage/hybrid.js.map +1 -0
  69. package/dist/storage/index.d.ts +21 -0
  70. package/dist/storage/index.d.ts.map +1 -0
  71. package/dist/storage/index.js +20 -0
  72. package/dist/storage/index.js.map +1 -0
  73. package/dist/storage/procedures.d.ts +14 -0
  74. package/dist/storage/procedures.d.ts.map +1 -0
  75. package/dist/storage/procedures.js +101 -0
  76. package/dist/storage/procedures.js.map +1 -0
  77. package/dist/storage/serialization.d.ts +123 -0
  78. package/dist/storage/serialization.d.ts.map +1 -0
  79. package/dist/storage/serialization.js +216 -0
  80. package/dist/storage/serialization.js.map +1 -0
  81. package/dist/storage/synced-registry.d.ts +246 -0
  82. package/dist/storage/synced-registry.d.ts.map +1 -0
  83. package/dist/storage/synced-registry.js +575 -0
  84. package/dist/storage/synced-registry.js.map +1 -0
  85. package/dist/storage/types.d.ts +130 -0
  86. package/dist/storage/types.d.ts.map +1 -0
  87. package/dist/storage/types.js +8 -0
  88. package/dist/storage/types.js.map +1 -0
  89. package/dist/types.d.ts +7 -0
  90. package/dist/types.d.ts.map +1 -0
  91. package/dist/types.js +7 -0
  92. package/dist/types.js.map +1 -0
  93. package/package.json +78 -3
  94. package/src/errors.ts +20 -0
  95. package/src/index.ts +19 -0
  96. package/src/module.ts +30 -0
  97. package/src/procedures.ts +17 -0
  98. package/src/program-store/attach.ts +46 -0
  99. package/src/program-store/collection.ts +39 -0
  100. package/src/program-store/file.ts +157 -0
  101. package/src/program-store/index.ts +17 -0
  102. package/src/program-store/memory.ts +30 -0
  103. package/src/program-store/procedures.ts +351 -0
  104. package/src/program-store/types.ts +78 -0
  105. package/src/register.ts +11 -0
  106. package/src/storage/adapter.ts +273 -0
  107. package/src/storage/api.ts +335 -0
  108. package/src/storage/factory.ts +268 -0
  109. package/src/storage/hybrid.ts +676 -0
  110. package/src/storage/index.ts +61 -0
  111. package/src/storage/procedures.ts +149 -0
  112. package/src/storage/serialization.ts +283 -0
  113. package/src/storage/synced-registry.ts +698 -0
  114. package/src/storage/types.ts +180 -0
  115. 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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"}