@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,268 @@
1
+ /**
2
+ * Procedure Storage Factory
3
+ *
4
+ * Factory functions for creating storage-backed procedure registries.
5
+ */
6
+
7
+ import type { Client } from "@procedures/client";
8
+ import type { CollectionStorage } from "@procedures/collections";
9
+ import { InMemoryStorage } from "@procedures/collections";
10
+ import { ApiStorage } from "./api.js";
11
+ import { HybridStorage } from "./hybrid.js";
12
+ import type { HybridStorageOptions } from "./hybrid.js";
13
+ import { ProcedureRegistry, PROCEDURE_REGISTRY } from "@procedures/client";
14
+ import type { SerializedProcedure, SyncedRegistryOptions, HandlerLoader } from "./types.js";
15
+ import { SyncedProcedureRegistry } from "./synced-registry.js";
16
+ import { getSerializedKey } from "./serialization.js";
17
+
18
+ // =============================================================================
19
+ // Factory Configuration
20
+ // =============================================================================
21
+
22
+ /**
23
+ * Configuration for creating a synced procedure registry.
24
+ */
25
+ export interface CreateSyncedRegistryConfig {
26
+ /**
27
+ * Storage type to use.
28
+ * - "memory": In-memory only (fast, volatile)
29
+ * - "api": Remote storage via client procedures
30
+ * - "hybrid": Local cache + remote sync
31
+ */
32
+ type: "memory" | "api" | "hybrid";
33
+
34
+ /**
35
+ * Universal client instance (required for "api" and "hybrid" types).
36
+ */
37
+ client?: Client | undefined;
38
+
39
+ /**
40
+ * The collection of the core collection procedures on the server: the calls go to
41
+ * `collections.<collection>.<operation>`.
42
+ * @default "procedures"
43
+ */
44
+ collection?: string | undefined;
45
+
46
+ /**
47
+ * The service of the calls, for a server with other paths. The default is
48
+ * `collections.<collection>`.
49
+ */
50
+ service?: string | undefined;
51
+
52
+ /**
53
+ * Additional options for hybrid storage.
54
+ */
55
+ hybridOptions?: Partial<HybridStorageOptions> | undefined;
56
+
57
+ /**
58
+ * Options for the synced registry.
59
+ */
60
+ registryOptions?: Partial<SyncedRegistryOptions> | undefined;
61
+
62
+ /**
63
+ * Base registry to wrap.
64
+ * @default PROCEDURE_REGISTRY (global singleton)
65
+ */
66
+ baseRegistry?: ProcedureRegistry | undefined;
67
+
68
+ /**
69
+ * Custom handler loader.
70
+ * @default Dynamic import loader
71
+ */
72
+ handlerLoader?: HandlerLoader | undefined;
73
+ }
74
+
75
+ // =============================================================================
76
+ // Factory Function
77
+ // =============================================================================
78
+
79
+ /**
80
+ * Create a synced procedure registry with the specified storage backend.
81
+ *
82
+ * @param config - Configuration for the registry
83
+ * @returns SyncedProcedureRegistry instance
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * // In-memory only (for testing)
88
+ * const registry = createSyncedRegistry({ type: 'memory' });
89
+ *
90
+ * // API storage (remote persistence)
91
+ * const registry = createSyncedRegistry({
92
+ * type: 'api',
93
+ * client: myClient,
94
+ * service: 'procedures',
95
+ * });
96
+ *
97
+ * // Hybrid storage (offline-first)
98
+ * const registry = createSyncedRegistry({
99
+ * type: 'hybrid',
100
+ * client: myClient,
101
+ * service: 'procedures',
102
+ * hybridOptions: {
103
+ * writeStrategy: 'write-through',
104
+ * conflictResolution: 'remote',
105
+ * },
106
+ * });
107
+ * ```
108
+ */
109
+ export function createSyncedRegistry(config: CreateSyncedRegistryConfig): SyncedProcedureRegistry {
110
+ const {
111
+ type,
112
+ client,
113
+ collection = "procedures",
114
+ service,
115
+ hybridOptions,
116
+ registryOptions = {},
117
+ baseRegistry = PROCEDURE_REGISTRY,
118
+ // No loader unless the caller gives one: stored records load as stubs. (Before, the default
119
+ // imported any module a stored record named: BUGS-2026-07 M11, deep dive CORE-7.)
120
+ handlerLoader,
121
+ } = config;
122
+
123
+ // Validate client is provided for api/hybrid
124
+ if ((type === "api" || type === "hybrid") && !client) {
125
+ throw new Error(`Client is required for storage type: ${type}`);
126
+ }
127
+
128
+ // Create the appropriate storage backend
129
+ let storage: CollectionStorage<SerializedProcedure>;
130
+
131
+ switch (type) {
132
+ case "memory":
133
+ storage = new InMemoryStorage<SerializedProcedure>();
134
+ break;
135
+
136
+ case "api":
137
+ storage = new ApiStorage<SerializedProcedure>(client!, {
138
+ collection,
139
+ ...(service !== undefined && { service }),
140
+ });
141
+ break;
142
+
143
+ case "hybrid": {
144
+ const remoteStorage = new ApiStorage<SerializedProcedure>(client!, {
145
+ collection,
146
+ ...(service !== undefined && { service }),
147
+ });
148
+ storage = new HybridStorage<SerializedProcedure>(
149
+ remoteStorage,
150
+ {
151
+ writeStrategy: hybridOptions?.writeStrategy ?? "write-through",
152
+ conflictResolution: hybridOptions?.conflictResolution ?? "local",
153
+ // A procedure record has no id: its key is its path (deep dive DATA-9)
154
+ keyOf: getSerializedKey,
155
+ ...hybridOptions,
156
+ }
157
+ );
158
+ break;
159
+ }
160
+
161
+ default:
162
+ throw new Error(`Unknown storage type: ${type}`);
163
+ }
164
+
165
+ // Create and return the synced registry
166
+ return new SyncedProcedureRegistry(baseRegistry, storage, {
167
+ ...registryOptions,
168
+ handlerLoader,
169
+ });
170
+ }
171
+
172
+ // =============================================================================
173
+ // Convenience Functions
174
+ // =============================================================================
175
+
176
+ /**
177
+ * Create an in-memory synced registry.
178
+ * Useful for testing or when persistence isn't needed.
179
+ *
180
+ * @param baseRegistry - Base registry to wrap
181
+ * @returns SyncedProcedureRegistry with in-memory storage
182
+ */
183
+ export function createMemorySyncedRegistry(
184
+ baseRegistry: ProcedureRegistry = PROCEDURE_REGISTRY
185
+ ): SyncedProcedureRegistry {
186
+ return createSyncedRegistry({
187
+ type: "memory",
188
+ baseRegistry,
189
+ });
190
+ }
191
+
192
+ /**
193
+ * Create an API-backed synced registry.
194
+ *
195
+ * @param client - Universal client instance
196
+ * @param collection - The collection of the core collection procedures on the server
197
+ * @param baseRegistry - Base registry to wrap
198
+ * @returns SyncedProcedureRegistry with API storage
199
+ */
200
+ export function createApiSyncedRegistry(
201
+ client: Client,
202
+ collection = "procedures",
203
+ baseRegistry: ProcedureRegistry = PROCEDURE_REGISTRY
204
+ ): SyncedProcedureRegistry {
205
+ return createSyncedRegistry({
206
+ type: "api",
207
+ client,
208
+ collection,
209
+ baseRegistry,
210
+ });
211
+ }
212
+
213
+ /**
214
+ * Create a hybrid synced registry (offline-first).
215
+ *
216
+ * @param client - Universal client instance
217
+ * @param collection - The collection of the core collection procedures on the server
218
+ * @param options - Hybrid storage options
219
+ * @param baseRegistry - Base registry to wrap
220
+ * @returns SyncedProcedureRegistry with hybrid storage
221
+ */
222
+ export function createHybridSyncedRegistry(
223
+ client: Client,
224
+ collection = "procedures",
225
+ options?: Partial<HybridStorageOptions>,
226
+ baseRegistry: ProcedureRegistry = PROCEDURE_REGISTRY
227
+ ): SyncedProcedureRegistry {
228
+ return createSyncedRegistry({
229
+ type: "hybrid",
230
+ client,
231
+ collection,
232
+ hybridOptions: options,
233
+ baseRegistry,
234
+ });
235
+ }
236
+
237
+ // =============================================================================
238
+ // Custom Storage Factory
239
+ // =============================================================================
240
+
241
+ /**
242
+ * Create a synced registry with a custom storage backend.
243
+ *
244
+ * @param storage - Custom CollectionStorage implementation
245
+ * @param options - Registry options
246
+ * @param baseRegistry - Base registry to wrap
247
+ * @returns SyncedProcedureRegistry with custom storage
248
+ *
249
+ * @example
250
+ * ```typescript
251
+ * // Use MongoDB storage
252
+ * const mongoStorage = new MongoCollectionStorage<SerializedProcedure>(
253
+ * mongoClient,
254
+ * 'procedures'
255
+ * );
256
+ * const registry = createCustomSyncedRegistry(mongoStorage);
257
+ * ```
258
+ */
259
+ export function createCustomSyncedRegistry(
260
+ storage: CollectionStorage<SerializedProcedure>,
261
+ options?: Partial<SyncedRegistryOptions>,
262
+ baseRegistry: ProcedureRegistry = PROCEDURE_REGISTRY
263
+ ): SyncedProcedureRegistry {
264
+ // No default loader: see createSyncedRegistry
265
+ return new SyncedProcedureRegistry(baseRegistry, storage, {
266
+ ...options,
267
+ });
268
+ }