@voidhash/mimic-effect 1.0.0-beta.1 → 1.0.0-beta.3

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 (111) hide show
  1. package/.turbo/turbo-build.log +102 -60
  2. package/dist/DocumentManager.cjs +109 -39
  3. package/dist/DocumentManager.d.cts +12 -4
  4. package/dist/DocumentManager.d.cts.map +1 -1
  5. package/dist/DocumentManager.d.mts +12 -4
  6. package/dist/DocumentManager.d.mts.map +1 -1
  7. package/dist/DocumentManager.mjs +110 -40
  8. package/dist/DocumentManager.mjs.map +1 -1
  9. package/dist/Errors.cjs +10 -1
  10. package/dist/Errors.d.cts +18 -3
  11. package/dist/Errors.d.cts.map +1 -1
  12. package/dist/Errors.d.mts +18 -3
  13. package/dist/Errors.d.mts.map +1 -1
  14. package/dist/Errors.mjs +9 -1
  15. package/dist/Errors.mjs.map +1 -1
  16. package/dist/HotStorage.cjs +23 -0
  17. package/dist/HotStorage.d.cts +17 -1
  18. package/dist/HotStorage.d.cts.map +1 -1
  19. package/dist/HotStorage.d.mts +17 -1
  20. package/dist/HotStorage.d.mts.map +1 -1
  21. package/dist/HotStorage.mjs +23 -0
  22. package/dist/HotStorage.mjs.map +1 -1
  23. package/dist/Metrics.cjs +23 -1
  24. package/dist/Metrics.d.cts +4 -0
  25. package/dist/Metrics.d.cts.map +1 -1
  26. package/dist/Metrics.d.mts +4 -0
  27. package/dist/Metrics.d.mts.map +1 -1
  28. package/dist/Metrics.mjs +21 -1
  29. package/dist/Metrics.mjs.map +1 -1
  30. package/dist/MimicClusterServerEngine.cjs +114 -36
  31. package/dist/MimicClusterServerEngine.d.cts.map +1 -1
  32. package/dist/MimicClusterServerEngine.d.mts +1 -1
  33. package/dist/MimicClusterServerEngine.d.mts.map +1 -1
  34. package/dist/MimicClusterServerEngine.mjs +119 -41
  35. package/dist/MimicClusterServerEngine.mjs.map +1 -1
  36. package/dist/MimicServer.cjs +1 -1
  37. package/dist/MimicServer.d.cts +1 -1
  38. package/dist/MimicServer.d.cts.map +1 -1
  39. package/dist/MimicServer.d.mts +1 -1
  40. package/dist/MimicServer.d.mts.map +1 -1
  41. package/dist/MimicServer.mjs +1 -1
  42. package/dist/MimicServerEngine.d.cts +7 -4
  43. package/dist/MimicServerEngine.d.cts.map +1 -1
  44. package/dist/MimicServerEngine.d.mts +7 -4
  45. package/dist/MimicServerEngine.d.mts.map +1 -1
  46. package/dist/MimicServerEngine.mjs.map +1 -1
  47. package/dist/index.cjs +3 -2
  48. package/dist/index.d.cts +2 -2
  49. package/dist/index.d.mts +2 -2
  50. package/dist/index.mjs +2 -2
  51. package/dist/testing/ColdStorageTestSuite.cjs +508 -0
  52. package/dist/testing/ColdStorageTestSuite.d.cts +36 -0
  53. package/dist/testing/ColdStorageTestSuite.d.cts.map +1 -0
  54. package/dist/testing/ColdStorageTestSuite.d.mts +36 -0
  55. package/dist/testing/ColdStorageTestSuite.d.mts.map +1 -0
  56. package/dist/testing/ColdStorageTestSuite.mjs +508 -0
  57. package/dist/testing/ColdStorageTestSuite.mjs.map +1 -0
  58. package/dist/testing/FailingStorage.cjs +135 -0
  59. package/dist/testing/FailingStorage.d.cts +43 -0
  60. package/dist/testing/FailingStorage.d.cts.map +1 -0
  61. package/dist/testing/FailingStorage.d.mts +43 -0
  62. package/dist/testing/FailingStorage.d.mts.map +1 -0
  63. package/dist/testing/FailingStorage.mjs +136 -0
  64. package/dist/testing/FailingStorage.mjs.map +1 -0
  65. package/dist/testing/HotStorageTestSuite.cjs +585 -0
  66. package/dist/testing/HotStorageTestSuite.d.cts +40 -0
  67. package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
  68. package/dist/testing/HotStorageTestSuite.d.mts +40 -0
  69. package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
  70. package/dist/testing/HotStorageTestSuite.mjs +585 -0
  71. package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
  72. package/dist/testing/StorageIntegrationTestSuite.cjs +349 -0
  73. package/dist/testing/StorageIntegrationTestSuite.d.cts +35 -0
  74. package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
  75. package/dist/testing/StorageIntegrationTestSuite.d.mts +35 -0
  76. package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
  77. package/dist/testing/StorageIntegrationTestSuite.mjs +349 -0
  78. package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
  79. package/dist/testing/assertions.cjs +114 -0
  80. package/dist/testing/assertions.mjs +109 -0
  81. package/dist/testing/assertions.mjs.map +1 -0
  82. package/dist/testing/index.cjs +14 -0
  83. package/dist/testing/index.d.cts +6 -0
  84. package/dist/testing/index.d.mts +6 -0
  85. package/dist/testing/index.mjs +7 -0
  86. package/dist/testing/types.cjs +15 -0
  87. package/dist/testing/types.d.cts +90 -0
  88. package/dist/testing/types.d.cts.map +1 -0
  89. package/dist/testing/types.d.mts +90 -0
  90. package/dist/testing/types.d.mts.map +1 -0
  91. package/dist/testing/types.mjs +16 -0
  92. package/dist/testing/types.mjs.map +1 -0
  93. package/package.json +8 -3
  94. package/src/DocumentManager.ts +195 -87
  95. package/src/Errors.ts +15 -1
  96. package/src/HotStorage.ts +75 -1
  97. package/src/Metrics.ts +24 -0
  98. package/src/MimicClusterServerEngine.ts +178 -56
  99. package/src/MimicServerEngine.ts +7 -3
  100. package/src/index.ts +2 -31
  101. package/src/testing/ColdStorageTestSuite.ts +589 -0
  102. package/src/testing/FailingStorage.ts +286 -0
  103. package/src/testing/HotStorageTestSuite.ts +762 -0
  104. package/src/testing/StorageIntegrationTestSuite.ts +504 -0
  105. package/src/testing/assertions.ts +181 -0
  106. package/src/testing/index.ts +83 -0
  107. package/src/testing/types.ts +100 -0
  108. package/tests/ColdStorage.test.ts +8 -120
  109. package/tests/HotStorage.test.ts +7 -126
  110. package/tests/StorageIntegration.test.ts +259 -0
  111. package/tsdown.config.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MimicServerEngine.mjs","names":["documentManagerLayer","presenceManagerLayer"],"sources":["../src/MimicServerEngine.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - MimicServerEngine\n *\n * Core document management service for Mimic real-time collaboration.\n * Handles document lifecycle, storage, presence, and transaction processing.\n *\n * This is the engine layer - for WebSocket routes, use MimicServer.layerHttpLayerRouter().\n */\nimport {\n Context,\n Duration,\n Effect,\n Layer,\n Scope,\n Stream,\n} from \"effect\";\nimport type { Presence, Primitive, Transaction } from \"@voidhash/mimic\";\nimport type {\n MimicServerEngineConfig,\n PresenceEntry,\n PresenceEvent,\n PresenceSnapshot,\n ResolvedConfig,\n} from \"./Types\";\nimport type * as Protocol from \"./Protocol\";\nimport { ColdStorageTag } from \"./ColdStorage\";\nimport { HotStorageTag } from \"./HotStorage\";\nimport { MimicAuthServiceTag } from \"./MimicAuthService\";\nimport {\n DocumentManagerTag,\n DocumentManagerConfigTag,\n layer as documentManagerLayer,\n type SubmitResult,\n} from \"./DocumentManager\";\nimport {\n PresenceManagerTag,\n layer as presenceManagerLayer,\n} from \"./PresenceManager\";\n\n// =============================================================================\n// MimicServerEngine Interface\n// =============================================================================\n\n/**\n * MimicServerEngine service interface.\n *\n * Provides document management operations for Mimic collaboration.\n * Use MimicServer.layerHttpLayerRouter() to create WebSocket routes.\n */\nexport interface MimicServerEngine {\n /**\n * Submit a transaction to a document.\n * Authorization is checked against the auth service.\n */\n readonly submit: (\n documentId: string,\n transaction: Transaction.Transaction\n ) => Effect.Effect<SubmitResult, never>;\n\n /**\n * Get document snapshot (current state and version).\n */\n readonly getSnapshot: (\n documentId: string\n ) => Effect.Effect<{ state: unknown; version: number }, never>;\n\n /**\n * Subscribe to document broadcasts (transactions).\n * Returns a stream of server messages.\n * Requires a Scope for cleanup when the subscription ends.\n */\n readonly subscribe: (\n documentId: string\n ) => Effect.Effect<Stream.Stream<Protocol.ServerMessage, never, never>, never, Scope.Scope>;\n\n /**\n * Touch document to prevent idle garbage collection.\n */\n readonly touch: (documentId: string) => Effect.Effect<void, never>;\n\n /**\n * Get presence snapshot for a document.\n */\n readonly getPresenceSnapshot: (\n documentId: string\n ) => Effect.Effect<PresenceSnapshot, never>;\n\n /**\n * Set presence for a connection.\n */\n readonly setPresence: (\n documentId: string,\n connectionId: string,\n entry: PresenceEntry\n ) => Effect.Effect<void, never>;\n\n /**\n * Remove presence for a connection.\n */\n readonly removePresence: (\n documentId: string,\n connectionId: string\n ) => Effect.Effect<void, never>;\n\n /**\n * Subscribe to presence events for a document.\n * Requires a Scope for cleanup when the subscription ends.\n */\n readonly subscribePresence: (\n documentId: string\n ) => Effect.Effect<Stream.Stream<PresenceEvent, never, never>, never, Scope.Scope>;\n\n /**\n * Resolved engine configuration.\n * Used by route layer to access schema, presence config, etc.\n */\n readonly config: ResolvedConfig<Primitive.AnyPrimitive>;\n}\n\n// =============================================================================\n// Context Tag\n// =============================================================================\n\n/**\n * Context tag for MimicServerEngine\n */\nexport class MimicServerEngineTag extends Context.Tag(\n \"@voidhash/mimic-effect/MimicServerEngine\"\n)<MimicServerEngineTag, MimicServerEngine>() {}\n\n// =============================================================================\n// Default Configuration\n// =============================================================================\n\nconst DEFAULT_MAX_IDLE_TIME = Duration.minutes(5);\nconst DEFAULT_MAX_TRANSACTION_HISTORY = 1000;\nconst DEFAULT_SNAPSHOT_INTERVAL = Duration.minutes(5);\nconst DEFAULT_SNAPSHOT_THRESHOLD = 100;\n\n/**\n * Resolve configuration with defaults\n */\nconst resolveConfig = <TSchema extends Primitive.AnyPrimitive>(\n config: MimicServerEngineConfig<TSchema>\n): ResolvedConfig<TSchema> => ({\n schema: config.schema,\n initial: config.initial,\n presence: config.presence,\n maxIdleTime: config.maxIdleTime\n ? Duration.decode(config.maxIdleTime)\n : DEFAULT_MAX_IDLE_TIME,\n maxTransactionHistory:\n config.maxTransactionHistory ?? DEFAULT_MAX_TRANSACTION_HISTORY,\n snapshot: {\n interval: config.snapshot?.interval\n ? Duration.decode(config.snapshot.interval)\n : DEFAULT_SNAPSHOT_INTERVAL,\n transactionThreshold:\n config.snapshot?.transactionThreshold ?? DEFAULT_SNAPSHOT_THRESHOLD,\n },\n});\n\n// =============================================================================\n// Factory\n// =============================================================================\n\n/**\n * Create a MimicServerEngine layer.\n *\n * This creates the core document management service. To expose it via WebSocket,\n * use MimicServer.layerHttpLayerRouter().\n *\n * @example\n * ```typescript\n * // 1. Create the engine\n * const Engine = MimicServerEngine.make({\n * schema: DocSchema,\n * initial: { title: \"Untitled\" },\n * presence: CursorPresence,\n * maxIdleTime: \"5 minutes\",\n * snapshot: { interval: \"5 minutes\", transactionThreshold: 100 },\n * })\n *\n * // 2. Create the WebSocket route\n * const MimicRoute = MimicServer.layerHttpLayerRouter({\n * path: \"/mimic\",\n * })\n *\n * // 3. Wire together\n * const MimicLive = MimicRoute.pipe(\n * Layer.provide(Engine),\n * Layer.provide(ColdStorage.InMemory.make()),\n * Layer.provide(HotStorage.InMemory.make()),\n * Layer.provide(MimicAuthService.NoAuth.make()),\n * )\n * ```\n */\nexport const make = <TSchema extends Primitive.AnyPrimitive>(\n config: MimicServerEngineConfig<TSchema>\n): Layer.Layer<\n MimicServerEngineTag,\n never,\n ColdStorageTag | HotStorageTag | MimicAuthServiceTag\n> => {\n const resolvedConfig = resolveConfig(config);\n\n // Create config layer for DocumentManager\n const configLayer = Layer.succeed(\n DocumentManagerConfigTag,\n resolvedConfig as ResolvedConfig<Primitive.AnyPrimitive>\n );\n\n // Create internal layers\n const internalLayers = Layer.mergeAll(\n documentManagerLayer.pipe(Layer.provide(configLayer)),\n presenceManagerLayer\n );\n\n return Layer.scoped(\n MimicServerEngineTag,\n Effect.gen(function* () {\n const documentManager = yield* DocumentManagerTag;\n const presenceManager = yield* PresenceManagerTag;\n\n const engine: MimicServerEngine = {\n submit: (documentId, transaction) =>\n documentManager.submit(documentId, transaction),\n\n getSnapshot: (documentId) => documentManager.getSnapshot(documentId),\n\n subscribe: (documentId) =>\n documentManager.subscribe(documentId) as Effect.Effect<\n Stream.Stream<Protocol.ServerMessage, never, never>,\n never\n >,\n\n touch: (documentId) => documentManager.touch(documentId),\n\n getPresenceSnapshot: (documentId) =>\n presenceManager.getSnapshot(documentId),\n\n setPresence: (documentId, connectionId, entry) =>\n presenceManager.set(documentId, connectionId, entry),\n\n removePresence: (documentId, connectionId) =>\n presenceManager.remove(documentId, connectionId),\n\n subscribePresence: (documentId) =>\n presenceManager.subscribe(documentId),\n\n config: resolvedConfig as ResolvedConfig<Primitive.AnyPrimitive>,\n };\n\n return engine;\n })\n ).pipe(Layer.provide(internalLayers));\n};\n\n// =============================================================================\n// Re-export namespace\n// =============================================================================\n\nexport const MimicServerEngine = {\n Tag: MimicServerEngineTag,\n make,\n};\n\n// =============================================================================\n// Re-export SubmitResult type\n// =============================================================================\n\nexport type { SubmitResult };\n"],"mappings":";;;;;;;;;;;;;;;;AA8HA,IAAa,uBAAb,cAA0C,QAAQ,IAChD,2CACD,EAA2C,CAAC;AAM7C,MAAM,wBAAwB,SAAS,QAAQ,EAAE;AACjD,MAAM,kCAAkC;AACxC,MAAM,4BAA4B,SAAS,QAAQ,EAAE;AACrD,MAAM,6BAA6B;;;;AAKnC,MAAM,iBACJ,WAC4B;;QAAC;EAC7B,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,UAAU,OAAO;EACjB,aAAa,OAAO,cAChB,SAAS,OAAO,OAAO,YAAY,GACnC;EACJ,gDACE,OAAO,8FAAyB;EAClC,UAAU;GACR,+BAAU,OAAO,8EAAU,YACvB,SAAS,OAAO,OAAO,SAAS,SAAS,GACzC;GACJ,oEACE,OAAO,gFAAU,6FAAwB;GAC5C;EACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCD,MAAa,QACX,WAKG;CACH,MAAM,iBAAiB,cAAc,OAAO;CAG5C,MAAM,cAAc,MAAM,QACxB,0BACA,eACD;CAGD,MAAM,iBAAiB,MAAM,SAC3BA,MAAqB,KAAK,MAAM,QAAQ,YAAY,CAAC,EACrDC,QACD;AAED,QAAO,MAAM,OACX,sBACA,OAAO,IAAI,aAAa;EACtB,MAAM,kBAAkB,OAAO;EAC/B,MAAM,kBAAkB,OAAO;AA+B/B,SA7BkC;GAChC,SAAS,YAAY,gBACnB,gBAAgB,OAAO,YAAY,YAAY;GAEjD,cAAc,eAAe,gBAAgB,YAAY,WAAW;GAEpE,YAAY,eACV,gBAAgB,UAAU,WAAW;GAKvC,QAAQ,eAAe,gBAAgB,MAAM,WAAW;GAExD,sBAAsB,eACpB,gBAAgB,YAAY,WAAW;GAEzC,cAAc,YAAY,cAAc,UACtC,gBAAgB,IAAI,YAAY,cAAc,MAAM;GAEtD,iBAAiB,YAAY,iBAC3B,gBAAgB,OAAO,YAAY,aAAa;GAElD,oBAAoB,eAClB,gBAAgB,UAAU,WAAW;GAEvC,QAAQ;GACT;GAGD,CACH,CAAC,KAAK,MAAM,QAAQ,eAAe,CAAC;;AAOvC,MAAa,oBAAoB;CAC/B,KAAK;CACL;CACD"}
1
+ {"version":3,"file":"MimicServerEngine.mjs","names":["documentManagerLayer","presenceManagerLayer"],"sources":["../src/MimicServerEngine.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - MimicServerEngine\n *\n * Core document management service for Mimic real-time collaboration.\n * Handles document lifecycle, storage, presence, and transaction processing.\n *\n * This is the engine layer - for WebSocket routes, use MimicServer.layerHttpLayerRouter().\n */\nimport {\n Context,\n Duration,\n Effect,\n Layer,\n Scope,\n Stream,\n} from \"effect\";\nimport type { Presence, Primitive, Transaction } from \"@voidhash/mimic\";\nimport type {\n MimicServerEngineConfig,\n PresenceEntry,\n PresenceEvent,\n PresenceSnapshot,\n ResolvedConfig,\n} from \"./Types\";\nimport type * as Protocol from \"./Protocol\";\nimport { ColdStorageTag } from \"./ColdStorage\";\nimport { HotStorageTag } from \"./HotStorage\";\nimport { MimicAuthServiceTag } from \"./MimicAuthService\";\nimport {\n DocumentManagerTag,\n DocumentManagerConfigTag,\n layer as documentManagerLayer,\n type SubmitResult,\n type DocumentManagerError,\n} from \"./DocumentManager\";\nimport {\n PresenceManagerTag,\n layer as presenceManagerLayer,\n} from \"./PresenceManager\";\n\n// =============================================================================\n// MimicServerEngine Interface\n// =============================================================================\n\n/**\n * MimicServerEngine service interface.\n *\n * Provides document management operations for Mimic collaboration.\n * Use MimicServer.layerHttpLayerRouter() to create WebSocket routes.\n */\nexport interface MimicServerEngine {\n /**\n * Submit a transaction to a document.\n * Authorization is checked against the auth service.\n * May fail with DocumentManagerError if storage is unavailable.\n */\n readonly submit: (\n documentId: string,\n transaction: Transaction.Transaction\n ) => Effect.Effect<SubmitResult, DocumentManagerError>;\n\n /**\n * Get document snapshot (current state and version).\n * May fail with DocumentManagerError if storage is unavailable.\n */\n readonly getSnapshot: (\n documentId: string\n ) => Effect.Effect<{ state: unknown; version: number }, DocumentManagerError>;\n\n /**\n * Subscribe to document broadcasts (transactions).\n * Returns a stream of server messages.\n * Requires a Scope for cleanup when the subscription ends.\n * May fail with DocumentManagerError if storage is unavailable.\n */\n readonly subscribe: (\n documentId: string\n ) => Effect.Effect<Stream.Stream<Protocol.ServerMessage, never, never>, DocumentManagerError, Scope.Scope>;\n\n /**\n * Touch document to prevent idle garbage collection.\n */\n readonly touch: (documentId: string) => Effect.Effect<void, never>;\n\n /**\n * Get presence snapshot for a document.\n */\n readonly getPresenceSnapshot: (\n documentId: string\n ) => Effect.Effect<PresenceSnapshot, never>;\n\n /**\n * Set presence for a connection.\n */\n readonly setPresence: (\n documentId: string,\n connectionId: string,\n entry: PresenceEntry\n ) => Effect.Effect<void, never>;\n\n /**\n * Remove presence for a connection.\n */\n readonly removePresence: (\n documentId: string,\n connectionId: string\n ) => Effect.Effect<void, never>;\n\n /**\n * Subscribe to presence events for a document.\n * Requires a Scope for cleanup when the subscription ends.\n */\n readonly subscribePresence: (\n documentId: string\n ) => Effect.Effect<Stream.Stream<PresenceEvent, never, never>, never, Scope.Scope>;\n\n /**\n * Resolved engine configuration.\n * Used by route layer to access schema, presence config, etc.\n */\n readonly config: ResolvedConfig<Primitive.AnyPrimitive>;\n}\n\n// =============================================================================\n// Context Tag\n// =============================================================================\n\n/**\n * Context tag for MimicServerEngine\n */\nexport class MimicServerEngineTag extends Context.Tag(\n \"@voidhash/mimic-effect/MimicServerEngine\"\n)<MimicServerEngineTag, MimicServerEngine>() {}\n\n// =============================================================================\n// Default Configuration\n// =============================================================================\n\nconst DEFAULT_MAX_IDLE_TIME = Duration.minutes(5);\nconst DEFAULT_MAX_TRANSACTION_HISTORY = 1000;\nconst DEFAULT_SNAPSHOT_INTERVAL = Duration.minutes(5);\nconst DEFAULT_SNAPSHOT_THRESHOLD = 100;\n\n/**\n * Resolve configuration with defaults\n */\nconst resolveConfig = <TSchema extends Primitive.AnyPrimitive>(\n config: MimicServerEngineConfig<TSchema>\n): ResolvedConfig<TSchema> => ({\n schema: config.schema,\n initial: config.initial,\n presence: config.presence,\n maxIdleTime: config.maxIdleTime\n ? Duration.decode(config.maxIdleTime)\n : DEFAULT_MAX_IDLE_TIME,\n maxTransactionHistory:\n config.maxTransactionHistory ?? DEFAULT_MAX_TRANSACTION_HISTORY,\n snapshot: {\n interval: config.snapshot?.interval\n ? Duration.decode(config.snapshot.interval)\n : DEFAULT_SNAPSHOT_INTERVAL,\n transactionThreshold:\n config.snapshot?.transactionThreshold ?? DEFAULT_SNAPSHOT_THRESHOLD,\n },\n});\n\n// =============================================================================\n// Factory\n// =============================================================================\n\n/**\n * Create a MimicServerEngine layer.\n *\n * This creates the core document management service. To expose it via WebSocket,\n * use MimicServer.layerHttpLayerRouter().\n *\n * @example\n * ```typescript\n * // 1. Create the engine\n * const Engine = MimicServerEngine.make({\n * schema: DocSchema,\n * initial: { title: \"Untitled\" },\n * presence: CursorPresence,\n * maxIdleTime: \"5 minutes\",\n * snapshot: { interval: \"5 minutes\", transactionThreshold: 100 },\n * })\n *\n * // 2. Create the WebSocket route\n * const MimicRoute = MimicServer.layerHttpLayerRouter({\n * path: \"/mimic\",\n * })\n *\n * // 3. Wire together\n * const MimicLive = MimicRoute.pipe(\n * Layer.provide(Engine),\n * Layer.provide(ColdStorage.InMemory.make()),\n * Layer.provide(HotStorage.InMemory.make()),\n * Layer.provide(MimicAuthService.NoAuth.make()),\n * )\n * ```\n */\nexport const make = <TSchema extends Primitive.AnyPrimitive>(\n config: MimicServerEngineConfig<TSchema>\n): Layer.Layer<\n MimicServerEngineTag,\n never,\n ColdStorageTag | HotStorageTag | MimicAuthServiceTag\n> => {\n const resolvedConfig = resolveConfig(config);\n\n // Create config layer for DocumentManager\n const configLayer = Layer.succeed(\n DocumentManagerConfigTag,\n resolvedConfig as ResolvedConfig<Primitive.AnyPrimitive>\n );\n\n // Create internal layers\n const internalLayers = Layer.mergeAll(\n documentManagerLayer.pipe(Layer.provide(configLayer)),\n presenceManagerLayer\n );\n\n return Layer.scoped(\n MimicServerEngineTag,\n Effect.gen(function* () {\n const documentManager = yield* DocumentManagerTag;\n const presenceManager = yield* PresenceManagerTag;\n\n const engine: MimicServerEngine = {\n submit: (documentId, transaction) =>\n documentManager.submit(documentId, transaction),\n\n getSnapshot: (documentId) => documentManager.getSnapshot(documentId),\n\n subscribe: (documentId) =>\n documentManager.subscribe(documentId) as Effect.Effect<\n Stream.Stream<Protocol.ServerMessage, never, never>,\n never\n >,\n\n touch: (documentId) => documentManager.touch(documentId),\n\n getPresenceSnapshot: (documentId) =>\n presenceManager.getSnapshot(documentId),\n\n setPresence: (documentId, connectionId, entry) =>\n presenceManager.set(documentId, connectionId, entry),\n\n removePresence: (documentId, connectionId) =>\n presenceManager.remove(documentId, connectionId),\n\n subscribePresence: (documentId) =>\n presenceManager.subscribe(documentId),\n\n config: resolvedConfig as ResolvedConfig<Primitive.AnyPrimitive>,\n };\n\n return engine;\n })\n ).pipe(Layer.provide(internalLayers));\n};\n\n// =============================================================================\n// Re-export namespace\n// =============================================================================\n\nexport const MimicServerEngine = {\n Tag: MimicServerEngineTag,\n make,\n};\n\n// =============================================================================\n// Re-export SubmitResult type\n// =============================================================================\n\nexport type { SubmitResult };\n"],"mappings":";;;;;;;;;;;;;;;;AAkIA,IAAa,uBAAb,cAA0C,QAAQ,IAChD,2CACD,EAA2C,CAAC;AAM7C,MAAM,wBAAwB,SAAS,QAAQ,EAAE;AACjD,MAAM,kCAAkC;AACxC,MAAM,4BAA4B,SAAS,QAAQ,EAAE;AACrD,MAAM,6BAA6B;;;;AAKnC,MAAM,iBACJ,WAC4B;;QAAC;EAC7B,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,UAAU,OAAO;EACjB,aAAa,OAAO,cAChB,SAAS,OAAO,OAAO,YAAY,GACnC;EACJ,gDACE,OAAO,8FAAyB;EAClC,UAAU;GACR,+BAAU,OAAO,8EAAU,YACvB,SAAS,OAAO,OAAO,SAAS,SAAS,GACzC;GACJ,oEACE,OAAO,gFAAU,6FAAwB;GAC5C;EACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCD,MAAa,QACX,WAKG;CACH,MAAM,iBAAiB,cAAc,OAAO;CAG5C,MAAM,cAAc,MAAM,QACxB,0BACA,eACD;CAGD,MAAM,iBAAiB,MAAM,SAC3BA,MAAqB,KAAK,MAAM,QAAQ,YAAY,CAAC,EACrDC,QACD;AAED,QAAO,MAAM,OACX,sBACA,OAAO,IAAI,aAAa;EACtB,MAAM,kBAAkB,OAAO;EAC/B,MAAM,kBAAkB,OAAO;AA+B/B,SA7BkC;GAChC,SAAS,YAAY,gBACnB,gBAAgB,OAAO,YAAY,YAAY;GAEjD,cAAc,eAAe,gBAAgB,YAAY,WAAW;GAEpE,YAAY,eACV,gBAAgB,UAAU,WAAW;GAKvC,QAAQ,eAAe,gBAAgB,MAAM,WAAW;GAExD,sBAAsB,eACpB,gBAAgB,YAAY,WAAW;GAEzC,cAAc,YAAY,cAAc,UACtC,gBAAgB,IAAI,YAAY,cAAc,MAAM;GAEtD,iBAAiB,YAAY,iBAC3B,gBAAgB,OAAO,YAAY,aAAa;GAElD,oBAAoB,eAClB,gBAAgB,UAAU,WAAW;GAEvC,QAAQ;GACT;GAGD,CACH,CAAC,KAAK,MAAM,QAAQ,eAAe,CAAC;;AAOvC,MAAa,oBAAoB;CAC/B,KAAK;CACL;CACD"}
package/dist/index.cjs CHANGED
@@ -1,11 +1,11 @@
1
1
  const require_ColdStorage = require('./ColdStorage.cjs');
2
+ const require_Errors = require('./Errors.cjs');
2
3
  const require_HotStorage = require('./HotStorage.cjs');
3
4
  const require_Metrics = require('./Metrics.cjs');
4
5
  const require_DocumentManager = require('./DocumentManager.cjs');
5
6
  const require_PresenceManager = require('./PresenceManager.cjs');
6
7
  const require_MimicServerEngine = require('./MimicServerEngine.cjs');
7
8
  const require_MimicClusterServerEngine = require('./MimicClusterServerEngine.cjs');
8
- const require_Errors = require('./Errors.cjs');
9
9
  const require_Protocol = require('./Protocol.cjs');
10
10
  const require_MimicAuthService = require('./MimicAuthService.cjs');
11
11
  const require_MimicServer = require('./MimicServer.cjs');
@@ -38,4 +38,5 @@ Object.defineProperty(exports, 'Protocol', {
38
38
  return require_Protocol.Protocol_exports;
39
39
  }
40
40
  });
41
- exports.TransactionRejectedError = require_Errors.TransactionRejectedError;
41
+ exports.TransactionRejectedError = require_Errors.TransactionRejectedError;
42
+ exports.WalVersionGapError = require_Errors.WalVersionGapError;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AuthContext, DurationInput, Initial, InitialContext, InitialFn, MimicClusterServerEngineConfig, MimicServerEngineConfig, MimicServerRouteConfig, Permission, PresenceEntry, PresenceEvent, PresenceRemoveEvent, PresenceSnapshot, PresenceUpdateEvent, ResolvedClusterConfig, ResolvedConfig, ResolvedRouteConfig, SnapshotConfig, StoredDocument, WalEntry } from "./Types.cjs";
2
- import { AuthenticationError, AuthorizationError, ColdStorageError, HotStorageError, MessageParseError, MimicError, MissingDocumentIdError, TransactionRejectedError } from "./Errors.cjs";
2
+ import { AuthenticationError, AuthorizationError, ColdStorageError, HotStorageError, MessageParseError, MimicError, MissingDocumentIdError, TransactionRejectedError, WalVersionGapError } from "./Errors.cjs";
3
3
  import { Protocol_d_exports } from "./Protocol.cjs";
4
4
  import { ColdStorage, ColdStorageTag } from "./ColdStorage.cjs";
5
5
  import { HotStorage, HotStorageTag } from "./HotStorage.cjs";
@@ -10,4 +10,4 @@ import { MimicClusterServerEngine } from "./MimicClusterServerEngine.cjs";
10
10
  import { MimicServer } from "./MimicServer.cjs";
11
11
  import { MimicMetrics } from "./Metrics.cjs";
12
12
  import { PresenceManager, PresenceManagerTag } from "./PresenceManager.cjs";
13
- export { type AuthContext, AuthenticationError, AuthorizationError, ColdStorage, ColdStorageError, ColdStorageTag, DocumentManager, DocumentManagerConfigTag, DocumentManagerTag, type DurationInput, HotStorage, HotStorageError, HotStorageTag, type Initial, type InitialContext, type InitialFn, MessageParseError, MimicAuthService, MimicAuthServiceTag, MimicClusterServerEngine, type MimicClusterServerEngineConfig, type MimicError, MimicMetrics, MimicServer, MimicServerEngine, type MimicServerEngineConfig, MimicServerEngineTag, type MimicServerRouteConfig, MissingDocumentIdError, type Permission, type PresenceEntry, type PresenceEvent, PresenceManager, PresenceManagerTag, type PresenceRemoveEvent, type PresenceSnapshot, type PresenceUpdateEvent, Protocol_d_exports as Protocol, type ResolvedClusterConfig, type ResolvedConfig, type ResolvedRouteConfig, type SnapshotConfig, type StoredDocument, type SubmitResult, TransactionRejectedError, type WalEntry };
13
+ export { AuthContext, AuthenticationError, AuthorizationError, ColdStorage, ColdStorageError, ColdStorageTag, DocumentManager, DocumentManagerConfigTag, DocumentManagerTag, DurationInput, HotStorage, HotStorageError, HotStorageTag, Initial, InitialContext, InitialFn, MessageParseError, MimicAuthService, MimicAuthServiceTag, MimicClusterServerEngine, MimicClusterServerEngineConfig, MimicError, MimicMetrics, MimicServer, MimicServerEngine, MimicServerEngineConfig, MimicServerEngineTag, type MimicServerRouteConfig, MissingDocumentIdError, Permission, PresenceEntry, PresenceEvent, PresenceManager, PresenceManagerTag, PresenceRemoveEvent, PresenceSnapshot, PresenceUpdateEvent, Protocol_d_exports as Protocol, ResolvedClusterConfig, ResolvedConfig, ResolvedRouteConfig, SnapshotConfig, StoredDocument, type SubmitResult, TransactionRejectedError, WalEntry, WalVersionGapError };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AuthContext, DurationInput, Initial, InitialContext, InitialFn, MimicClusterServerEngineConfig, MimicServerEngineConfig, MimicServerRouteConfig, Permission, PresenceEntry, PresenceEvent, PresenceRemoveEvent, PresenceSnapshot, PresenceUpdateEvent, ResolvedClusterConfig, ResolvedConfig, ResolvedRouteConfig, SnapshotConfig, StoredDocument, WalEntry } from "./Types.mjs";
2
- import { AuthenticationError, AuthorizationError, ColdStorageError, HotStorageError, MessageParseError, MimicError, MissingDocumentIdError, TransactionRejectedError } from "./Errors.mjs";
2
+ import { AuthenticationError, AuthorizationError, ColdStorageError, HotStorageError, MessageParseError, MimicError, MissingDocumentIdError, TransactionRejectedError, WalVersionGapError } from "./Errors.mjs";
3
3
  import { Protocol_d_exports } from "./Protocol.mjs";
4
4
  import { ColdStorage, ColdStorageTag } from "./ColdStorage.mjs";
5
5
  import { HotStorage, HotStorageTag } from "./HotStorage.mjs";
@@ -10,4 +10,4 @@ import { MimicClusterServerEngine } from "./MimicClusterServerEngine.mjs";
10
10
  import { MimicServer } from "./MimicServer.mjs";
11
11
  import { MimicMetrics } from "./Metrics.mjs";
12
12
  import { PresenceManager, PresenceManagerTag } from "./PresenceManager.mjs";
13
- export { type AuthContext, AuthenticationError, AuthorizationError, ColdStorage, ColdStorageError, ColdStorageTag, DocumentManager, DocumentManagerConfigTag, DocumentManagerTag, type DurationInput, HotStorage, HotStorageError, HotStorageTag, type Initial, type InitialContext, type InitialFn, MessageParseError, MimicAuthService, MimicAuthServiceTag, MimicClusterServerEngine, type MimicClusterServerEngineConfig, type MimicError, MimicMetrics, MimicServer, MimicServerEngine, type MimicServerEngineConfig, MimicServerEngineTag, type MimicServerRouteConfig, MissingDocumentIdError, type Permission, type PresenceEntry, type PresenceEvent, PresenceManager, PresenceManagerTag, type PresenceRemoveEvent, type PresenceSnapshot, type PresenceUpdateEvent, Protocol_d_exports as Protocol, type ResolvedClusterConfig, type ResolvedConfig, type ResolvedRouteConfig, type SnapshotConfig, type StoredDocument, type SubmitResult, TransactionRejectedError, type WalEntry };
13
+ export { AuthContext, AuthenticationError, AuthorizationError, ColdStorage, ColdStorageError, ColdStorageTag, DocumentManager, DocumentManagerConfigTag, DocumentManagerTag, DurationInput, HotStorage, HotStorageError, HotStorageTag, Initial, InitialContext, InitialFn, MessageParseError, MimicAuthService, MimicAuthServiceTag, MimicClusterServerEngine, MimicClusterServerEngineConfig, MimicError, MimicMetrics, MimicServer, MimicServerEngine, MimicServerEngineConfig, MimicServerEngineTag, type MimicServerRouteConfig, MissingDocumentIdError, Permission, PresenceEntry, PresenceEvent, PresenceManager, PresenceManagerTag, PresenceRemoveEvent, PresenceSnapshot, PresenceUpdateEvent, Protocol_d_exports as Protocol, ResolvedClusterConfig, ResolvedConfig, ResolvedRouteConfig, SnapshotConfig, StoredDocument, type SubmitResult, TransactionRejectedError, WalEntry, WalVersionGapError };
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
1
  import { ColdStorage, ColdStorageTag } from "./ColdStorage.mjs";
2
+ import { AuthenticationError, AuthorizationError, ColdStorageError, HotStorageError, MessageParseError, MissingDocumentIdError, TransactionRejectedError, WalVersionGapError } from "./Errors.mjs";
2
3
  import { HotStorage, HotStorageTag } from "./HotStorage.mjs";
3
4
  import { MimicMetrics } from "./Metrics.mjs";
4
5
  import { DocumentManager, DocumentManagerConfigTag, DocumentManagerTag } from "./DocumentManager.mjs";
5
6
  import { PresenceManager, PresenceManagerTag } from "./PresenceManager.mjs";
6
7
  import { MimicServerEngine, MimicServerEngineTag } from "./MimicServerEngine.mjs";
7
8
  import { MimicClusterServerEngine } from "./MimicClusterServerEngine.mjs";
8
- import { AuthenticationError, AuthorizationError, ColdStorageError, HotStorageError, MessageParseError, MissingDocumentIdError, TransactionRejectedError } from "./Errors.mjs";
9
9
  import { Protocol_exports } from "./Protocol.mjs";
10
10
  import { MimicAuthService, MimicAuthServiceTag } from "./MimicAuthService.mjs";
11
11
  import { MimicServer } from "./MimicServer.mjs";
12
12
 
13
- export { AuthenticationError, AuthorizationError, ColdStorage, ColdStorageError, ColdStorageTag, DocumentManager, DocumentManagerConfigTag, DocumentManagerTag, HotStorage, HotStorageError, HotStorageTag, MessageParseError, MimicAuthService, MimicAuthServiceTag, MimicClusterServerEngine, MimicMetrics, MimicServer, MimicServerEngine, MimicServerEngineTag, MissingDocumentIdError, PresenceManager, PresenceManagerTag, Protocol_exports as Protocol, TransactionRejectedError };
13
+ export { AuthenticationError, AuthorizationError, ColdStorage, ColdStorageError, ColdStorageTag, DocumentManager, DocumentManagerConfigTag, DocumentManagerTag, HotStorage, HotStorageError, HotStorageTag, MessageParseError, MimicAuthService, MimicAuthServiceTag, MimicClusterServerEngine, MimicMetrics, MimicServer, MimicServerEngine, MimicServerEngineTag, MissingDocumentIdError, PresenceManager, PresenceManagerTag, Protocol_exports as Protocol, TransactionRejectedError, WalVersionGapError };
@@ -0,0 +1,508 @@
1
+ const require_ColdStorage = require('../ColdStorage.cjs');
2
+ const require_objectSpread2 = require('../_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.cjs');
3
+ const require_assertions = require('./assertions.cjs');
4
+ let effect = require("effect");
5
+
6
+ //#region src/testing/ColdStorageTestSuite.ts
7
+ /**
8
+ * @voidhash/mimic-effect/testing - ColdStorage Test Suite
9
+ *
10
+ * Comprehensive test suite for ColdStorage adapter implementations.
11
+ * These tests verify that an adapter correctly implements the ColdStorage interface
12
+ * and can reliably store/retrieve document snapshots without data loss.
13
+ */
14
+ const Categories = {
15
+ BasicOperations: "Basic Operations",
16
+ DataIntegrity: "Data Integrity",
17
+ VersionHandling: "Version Handling",
18
+ TimestampHandling: "Timestamp Handling",
19
+ DocumentIdEdgeCases: "Document ID Edge Cases",
20
+ DocumentIsolation: "Document Isolation",
21
+ ConsistencyGuarantees: "Consistency Guarantees"
22
+ };
23
+ const makeDoc = (overrides = {}) => require_objectSpread2._objectSpread2({
24
+ state: { title: "Test Document" },
25
+ version: 1,
26
+ schemaVersion: 1,
27
+ savedAt: Date.now()
28
+ }, overrides);
29
+ const generateLargeState = (sizeKB) => {
30
+ const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
31
+ const targetBytes = sizeKB * 1024;
32
+ let content = "";
33
+ while (content.length < targetBytes) content += chars[Math.floor(Math.random() * 62)];
34
+ return {
35
+ content,
36
+ padding: Array(100).fill("x")
37
+ };
38
+ };
39
+ const tests = [
40
+ {
41
+ name: "load returns undefined for non-existent document",
42
+ category: Categories.BasicOperations,
43
+ run: effect.Effect.gen(function* () {
44
+ yield* require_assertions.assertUndefined(yield* (yield* require_ColdStorage.ColdStorageTag).load("non-existent-doc-id-12345"), "Expected undefined for non-existent document");
45
+ })
46
+ },
47
+ {
48
+ name: "save then load returns exact same document",
49
+ category: Categories.BasicOperations,
50
+ run: effect.Effect.gen(function* () {
51
+ const storage = yield* require_ColdStorage.ColdStorageTag;
52
+ const doc = makeDoc();
53
+ yield* storage.save("test-doc-1", doc);
54
+ yield* require_assertions.assertEqual(yield* storage.load("test-doc-1"), doc, "Loaded document should match saved document");
55
+ })
56
+ },
57
+ {
58
+ name: "save overwrites existing document",
59
+ category: Categories.BasicOperations,
60
+ run: effect.Effect.gen(function* () {
61
+ const storage = yield* require_ColdStorage.ColdStorageTag;
62
+ const doc1 = makeDoc({
63
+ state: { title: "First" },
64
+ version: 1
65
+ });
66
+ const doc2 = makeDoc({
67
+ state: { title: "Second" },
68
+ version: 2
69
+ });
70
+ yield* storage.save("test-doc-2", doc1);
71
+ yield* storage.save("test-doc-2", doc2);
72
+ yield* require_assertions.assertEqual(yield* storage.load("test-doc-2"), doc2, "Should return the second (overwritten) document");
73
+ })
74
+ },
75
+ {
76
+ name: "delete removes document",
77
+ category: Categories.BasicOperations,
78
+ run: effect.Effect.gen(function* () {
79
+ const storage = yield* require_ColdStorage.ColdStorageTag;
80
+ const doc = makeDoc();
81
+ yield* storage.save("test-doc-3", doc);
82
+ yield* storage.delete("test-doc-3");
83
+ yield* require_assertions.assertUndefined(yield* storage.load("test-doc-3"), "Document should be undefined after deletion");
84
+ })
85
+ },
86
+ {
87
+ name: "delete on non-existent document does not error",
88
+ category: Categories.BasicOperations,
89
+ run: effect.Effect.gen(function* () {
90
+ yield* (yield* require_ColdStorage.ColdStorageTag).delete("definitely-non-existent-doc-xyz");
91
+ })
92
+ },
93
+ {
94
+ name: "all StoredDocument fields are preserved",
95
+ category: Categories.DataIntegrity,
96
+ run: effect.Effect.gen(function* () {
97
+ const storage = yield* require_ColdStorage.ColdStorageTag;
98
+ const doc = {
99
+ state: { nested: { value: 42 } },
100
+ version: 123,
101
+ schemaVersion: 2,
102
+ savedAt: 17040672e5
103
+ };
104
+ yield* storage.save("fields-test", doc);
105
+ const definedLoaded = yield* require_assertions.assertDefined(yield* storage.load("fields-test"), "Document should exist");
106
+ yield* require_assertions.assertEqual(definedLoaded.state, doc.state, "state should be preserved");
107
+ yield* require_assertions.assertEqual(definedLoaded.version, doc.version, "version should be preserved");
108
+ yield* require_assertions.assertEqual(definedLoaded.schemaVersion, doc.schemaVersion, "schemaVersion should be preserved");
109
+ yield* require_assertions.assertEqual(definedLoaded.savedAt, doc.savedAt, "savedAt should be preserved");
110
+ })
111
+ },
112
+ {
113
+ name: "complex nested state objects survive roundtrip",
114
+ category: Categories.DataIntegrity,
115
+ run: effect.Effect.gen(function* () {
116
+ const storage = yield* require_ColdStorage.ColdStorageTag;
117
+ const doc = makeDoc({ state: {
118
+ level1: {
119
+ level2: { level3: {
120
+ value: "deep",
121
+ array: [
122
+ 1,
123
+ 2,
124
+ { nested: true }
125
+ ]
126
+ } },
127
+ sibling: "value"
128
+ },
129
+ topLevel: 42
130
+ } });
131
+ yield* storage.save("complex-state", doc);
132
+ yield* require_assertions.assertEqual(yield* storage.load("complex-state"), doc, "Complex nested state should survive roundtrip");
133
+ })
134
+ },
135
+ {
136
+ name: "arrays in state survive roundtrip",
137
+ category: Categories.DataIntegrity,
138
+ run: effect.Effect.gen(function* () {
139
+ const storage = yield* require_ColdStorage.ColdStorageTag;
140
+ const doc = makeDoc({ state: {
141
+ numbers: [
142
+ 1,
143
+ 2,
144
+ 3,
145
+ 4,
146
+ 5
147
+ ],
148
+ strings: [
149
+ "a",
150
+ "b",
151
+ "c"
152
+ ],
153
+ mixed: [
154
+ 1,
155
+ "two",
156
+ { three: 3 },
157
+ [4]
158
+ ],
159
+ empty: []
160
+ } });
161
+ yield* storage.save("arrays-test", doc);
162
+ yield* require_assertions.assertEqual(yield* storage.load("arrays-test"), doc, "Arrays should survive roundtrip");
163
+ })
164
+ },
165
+ {
166
+ name: "null values in state survive roundtrip",
167
+ category: Categories.DataIntegrity,
168
+ run: effect.Effect.gen(function* () {
169
+ const storage = yield* require_ColdStorage.ColdStorageTag;
170
+ const doc = makeDoc({ state: {
171
+ nullValue: null,
172
+ nested: { alsoNull: null },
173
+ array: [
174
+ null,
175
+ 1,
176
+ null
177
+ ]
178
+ } });
179
+ yield* storage.save("null-test", doc);
180
+ yield* require_assertions.assertEqual(yield* storage.load("null-test"), doc, "null values should survive roundtrip");
181
+ })
182
+ },
183
+ {
184
+ name: "empty object survives roundtrip",
185
+ category: Categories.DataIntegrity,
186
+ run: effect.Effect.gen(function* () {
187
+ const storage = yield* require_ColdStorage.ColdStorageTag;
188
+ const doc = makeDoc({ state: {} });
189
+ yield* storage.save("empty-obj", doc);
190
+ yield* require_assertions.assertEqual(yield* storage.load("empty-obj"), doc, "Empty object should survive roundtrip");
191
+ })
192
+ },
193
+ {
194
+ name: "empty array survives roundtrip",
195
+ category: Categories.DataIntegrity,
196
+ run: effect.Effect.gen(function* () {
197
+ const storage = yield* require_ColdStorage.ColdStorageTag;
198
+ const doc = makeDoc({ state: [] });
199
+ yield* storage.save("empty-arr", doc);
200
+ yield* require_assertions.assertEqual(yield* storage.load("empty-arr"), doc, "Empty array should survive roundtrip");
201
+ })
202
+ },
203
+ {
204
+ name: "unicode strings in state survive roundtrip",
205
+ category: Categories.DataIntegrity,
206
+ run: effect.Effect.gen(function* () {
207
+ const storage = yield* require_ColdStorage.ColdStorageTag;
208
+ const doc = makeDoc({ state: {
209
+ emoji: "Hello! How are you?",
210
+ chinese: "Chinese Characters",
211
+ arabic: "Arabic Letters",
212
+ special: "Combined: Cafe"
213
+ } });
214
+ yield* storage.save("unicode-test", doc);
215
+ yield* require_assertions.assertEqual(yield* storage.load("unicode-test"), doc, "Unicode strings should survive roundtrip");
216
+ })
217
+ },
218
+ {
219
+ name: "large state objects (100KB+) survive roundtrip",
220
+ category: Categories.DataIntegrity,
221
+ run: effect.Effect.gen(function* () {
222
+ const storage = yield* require_ColdStorage.ColdStorageTag;
223
+ const doc = makeDoc({ state: generateLargeState(100) });
224
+ yield* storage.save("large-doc", doc);
225
+ yield* require_assertions.assertEqual(yield* storage.load("large-doc"), doc, "Large documents should survive roundtrip");
226
+ })
227
+ },
228
+ {
229
+ name: "special JSON characters survive roundtrip",
230
+ category: Categories.DataIntegrity,
231
+ run: effect.Effect.gen(function* () {
232
+ const storage = yield* require_ColdStorage.ColdStorageTag;
233
+ const doc = makeDoc({ state: {
234
+ quotes: "He said \"hello\"",
235
+ backslash: "path\\to\\file",
236
+ newline: "line1\nline2",
237
+ tab: "col1 col2",
238
+ mixed: "All: \"\\\n "
239
+ } });
240
+ yield* storage.save("special-chars", doc);
241
+ yield* require_assertions.assertEqual(yield* storage.load("special-chars"), doc, "Special JSON characters should survive roundtrip");
242
+ })
243
+ },
244
+ {
245
+ name: "version 0 is preserved correctly",
246
+ category: Categories.VersionHandling,
247
+ run: effect.Effect.gen(function* () {
248
+ const storage = yield* require_ColdStorage.ColdStorageTag;
249
+ const doc = makeDoc({ version: 0 });
250
+ yield* storage.save("version-0", doc);
251
+ yield* require_assertions.assertEqual((yield* require_assertions.assertDefined(yield* storage.load("version-0"), "Document should exist")).version, 0, "Version 0 should be preserved");
252
+ })
253
+ },
254
+ {
255
+ name: "version 1 is preserved correctly",
256
+ category: Categories.VersionHandling,
257
+ run: effect.Effect.gen(function* () {
258
+ const storage = yield* require_ColdStorage.ColdStorageTag;
259
+ const doc = makeDoc({ version: 1 });
260
+ yield* storage.save("version-1", doc);
261
+ yield* require_assertions.assertEqual((yield* require_assertions.assertDefined(yield* storage.load("version-1"), "Document should exist")).version, 1, "Version 1 should be preserved");
262
+ })
263
+ },
264
+ {
265
+ name: "large version numbers are preserved",
266
+ category: Categories.VersionHandling,
267
+ run: effect.Effect.gen(function* () {
268
+ const storage = yield* require_ColdStorage.ColdStorageTag;
269
+ const largeVersion = Number.MAX_SAFE_INTEGER;
270
+ const doc = makeDoc({ version: largeVersion });
271
+ yield* storage.save("large-version", doc);
272
+ yield* require_assertions.assertEqual((yield* require_assertions.assertDefined(yield* storage.load("large-version"), "Document should exist")).version, largeVersion, "Large version number should be preserved exactly");
273
+ })
274
+ },
275
+ {
276
+ name: "schema version is preserved correctly",
277
+ category: Categories.VersionHandling,
278
+ run: effect.Effect.gen(function* () {
279
+ const storage = yield* require_ColdStorage.ColdStorageTag;
280
+ const doc = makeDoc({ schemaVersion: 42 });
281
+ yield* storage.save("schema-version", doc);
282
+ yield* require_assertions.assertEqual((yield* require_assertions.assertDefined(yield* storage.load("schema-version"), "Document should exist")).schemaVersion, 42, "Schema version should be preserved");
283
+ })
284
+ },
285
+ {
286
+ name: "savedAt timestamp is preserved exactly",
287
+ category: Categories.TimestampHandling,
288
+ run: effect.Effect.gen(function* () {
289
+ const storage = yield* require_ColdStorage.ColdStorageTag;
290
+ const timestamp = 17040672e5;
291
+ const doc = makeDoc({ savedAt: timestamp });
292
+ yield* storage.save("timestamp-exact", doc);
293
+ yield* require_assertions.assertEqual((yield* require_assertions.assertDefined(yield* storage.load("timestamp-exact"), "Document should exist")).savedAt, timestamp, "savedAt should be preserved exactly");
294
+ })
295
+ },
296
+ {
297
+ name: "timestamp 0 is preserved correctly",
298
+ category: Categories.TimestampHandling,
299
+ run: effect.Effect.gen(function* () {
300
+ const storage = yield* require_ColdStorage.ColdStorageTag;
301
+ const doc = makeDoc({ savedAt: 0 });
302
+ yield* storage.save("timestamp-0", doc);
303
+ yield* require_assertions.assertEqual((yield* require_assertions.assertDefined(yield* storage.load("timestamp-0"), "Document should exist")).savedAt, 0, "Timestamp 0 should be preserved");
304
+ })
305
+ },
306
+ {
307
+ name: "recent timestamps are preserved correctly",
308
+ category: Categories.TimestampHandling,
309
+ run: effect.Effect.gen(function* () {
310
+ const storage = yield* require_ColdStorage.ColdStorageTag;
311
+ const now = Date.now();
312
+ const doc = makeDoc({ savedAt: now });
313
+ yield* storage.save("timestamp-recent", doc);
314
+ yield* require_assertions.assertEqual((yield* require_assertions.assertDefined(yield* storage.load("timestamp-recent"), "Document should exist")).savedAt, now, "Recent timestamp should be preserved");
315
+ })
316
+ },
317
+ {
318
+ name: "long documentId (1000+ chars) works",
319
+ category: Categories.DocumentIdEdgeCases,
320
+ run: effect.Effect.gen(function* () {
321
+ const storage = yield* require_ColdStorage.ColdStorageTag;
322
+ const longId = "x".repeat(1e3);
323
+ const doc = makeDoc();
324
+ yield* storage.save(longId, doc);
325
+ yield* require_assertions.assertEqual(yield* storage.load(longId), doc, "Long documentId should work correctly");
326
+ })
327
+ },
328
+ {
329
+ name: "unicode documentId works",
330
+ category: Categories.DocumentIdEdgeCases,
331
+ run: effect.Effect.gen(function* () {
332
+ const storage = yield* require_ColdStorage.ColdStorageTag;
333
+ const unicodeId = "doc-test-id";
334
+ const doc = makeDoc();
335
+ yield* storage.save(unicodeId, doc);
336
+ yield* require_assertions.assertEqual(yield* storage.load(unicodeId), doc, "Unicode documentId should work correctly");
337
+ })
338
+ },
339
+ {
340
+ name: "documentId with special chars works",
341
+ category: Categories.DocumentIdEdgeCases,
342
+ run: effect.Effect.gen(function* () {
343
+ const storage = yield* require_ColdStorage.ColdStorageTag;
344
+ const specialId = "doc/path:to.file";
345
+ const doc = makeDoc();
346
+ yield* storage.save(specialId, doc);
347
+ yield* require_assertions.assertEqual(yield* storage.load(specialId), doc, "DocumentId with special chars should work");
348
+ })
349
+ },
350
+ {
351
+ name: "documentId with spaces works",
352
+ category: Categories.DocumentIdEdgeCases,
353
+ run: effect.Effect.gen(function* () {
354
+ const storage = yield* require_ColdStorage.ColdStorageTag;
355
+ const spacedId = "doc with spaces";
356
+ const doc = makeDoc();
357
+ yield* storage.save(spacedId, doc);
358
+ yield* require_assertions.assertEqual(yield* storage.load(spacedId), doc, "DocumentId with spaces should work");
359
+ })
360
+ },
361
+ {
362
+ name: "different documents are stored independently",
363
+ category: Categories.DocumentIsolation,
364
+ run: effect.Effect.gen(function* () {
365
+ const storage = yield* require_ColdStorage.ColdStorageTag;
366
+ const doc1 = makeDoc({
367
+ state: { id: 1 },
368
+ version: 1
369
+ });
370
+ const doc2 = makeDoc({
371
+ state: { id: 2 },
372
+ version: 2
373
+ });
374
+ yield* storage.save("iso-doc-1", doc1);
375
+ yield* storage.save("iso-doc-2", doc2);
376
+ const loaded1 = yield* storage.load("iso-doc-1");
377
+ const loaded2 = yield* storage.load("iso-doc-2");
378
+ yield* require_assertions.assertEqual(loaded1, doc1, "First document should be unchanged");
379
+ yield* require_assertions.assertEqual(loaded2, doc2, "Second document should be unchanged");
380
+ })
381
+ },
382
+ {
383
+ name: "deleting one document does not affect others",
384
+ category: Categories.DocumentIsolation,
385
+ run: effect.Effect.gen(function* () {
386
+ const storage = yield* require_ColdStorage.ColdStorageTag;
387
+ const doc1 = makeDoc({ state: { id: 1 } });
388
+ const doc2 = makeDoc({ state: { id: 2 } });
389
+ yield* storage.save("del-iso-1", doc1);
390
+ yield* storage.save("del-iso-2", doc2);
391
+ yield* storage.delete("del-iso-1");
392
+ const loaded1 = yield* storage.load("del-iso-1");
393
+ const loaded2 = yield* storage.load("del-iso-2");
394
+ yield* require_assertions.assertUndefined(loaded1, "Deleted document should be undefined");
395
+ yield* require_assertions.assertEqual(loaded2, doc2, "Other document should be unchanged");
396
+ })
397
+ },
398
+ {
399
+ name: "updating one document does not affect others",
400
+ category: Categories.DocumentIsolation,
401
+ run: effect.Effect.gen(function* () {
402
+ const storage = yield* require_ColdStorage.ColdStorageTag;
403
+ const doc1v1 = makeDoc({
404
+ state: {
405
+ id: 1,
406
+ v: 1
407
+ },
408
+ version: 1
409
+ });
410
+ const doc1v2 = makeDoc({
411
+ state: {
412
+ id: 1,
413
+ v: 2
414
+ },
415
+ version: 2
416
+ });
417
+ const doc2 = makeDoc({ state: { id: 2 } });
418
+ yield* storage.save("upd-iso-1", doc1v1);
419
+ yield* storage.save("upd-iso-2", doc2);
420
+ yield* storage.save("upd-iso-1", doc1v2);
421
+ const loaded1 = yield* storage.load("upd-iso-1");
422
+ const loaded2 = yield* storage.load("upd-iso-2");
423
+ yield* require_assertions.assertEqual(loaded1, doc1v2, "Updated document should have new value");
424
+ yield* require_assertions.assertEqual(loaded2, doc2, "Other document should be unchanged");
425
+ })
426
+ },
427
+ {
428
+ name: "multiple saves to same doc, load returns latest",
429
+ category: Categories.ConsistencyGuarantees,
430
+ run: effect.Effect.gen(function* () {
431
+ const storage = yield* require_ColdStorage.ColdStorageTag;
432
+ const doc1 = makeDoc({
433
+ state: { v: 1 },
434
+ version: 1
435
+ });
436
+ const doc2 = makeDoc({
437
+ state: { v: 2 },
438
+ version: 2
439
+ });
440
+ const doc3 = makeDoc({
441
+ state: { v: 3 },
442
+ version: 3
443
+ });
444
+ yield* storage.save("multi-save", doc1);
445
+ yield* storage.save("multi-save", doc2);
446
+ yield* storage.save("multi-save", doc3);
447
+ yield* require_assertions.assertEqual(yield* storage.load("multi-save"), doc3, "Should return the latest saved document");
448
+ })
449
+ },
450
+ {
451
+ name: "save-delete-save sequence works correctly",
452
+ category: Categories.ConsistencyGuarantees,
453
+ run: effect.Effect.gen(function* () {
454
+ const storage = yield* require_ColdStorage.ColdStorageTag;
455
+ const doc1 = makeDoc({
456
+ state: { phase: "first" },
457
+ version: 1
458
+ });
459
+ const doc2 = makeDoc({
460
+ state: { phase: "second" },
461
+ version: 2
462
+ });
463
+ yield* storage.save("sds-test", doc1);
464
+ yield* storage.delete("sds-test");
465
+ yield* storage.save("sds-test", doc2);
466
+ yield* require_assertions.assertEqual(yield* storage.load("sds-test"), doc2, "Should return document saved after delete");
467
+ })
468
+ }
469
+ ];
470
+ /**
471
+ * Get all ColdStorage test cases.
472
+ *
473
+ * @returns Array of test cases that require ColdStorageTag
474
+ */
475
+ const makeTests = () => tests;
476
+ /**
477
+ * Run all tests and collect results.
478
+ *
479
+ * @returns Effect that produces TestResults
480
+ */
481
+ const runAll = () => effect.Effect.gen(function* () {
482
+ const passed = [];
483
+ const failed = [];
484
+ for (const test of tests) {
485
+ const result = yield* effect.Effect.either(test.run);
486
+ if (result._tag === "Right") passed.push(test);
487
+ else failed.push({
488
+ test,
489
+ error: result.left
490
+ });
491
+ }
492
+ return {
493
+ passed,
494
+ failed,
495
+ total: tests.length,
496
+ passCount: passed.length,
497
+ failCount: failed.length
498
+ };
499
+ });
500
+ const ColdStorageTestSuite = {
501
+ Categories,
502
+ makeTests,
503
+ runAll
504
+ };
505
+
506
+ //#endregion
507
+ exports.Categories = Categories;
508
+ exports.ColdStorageTestSuite = ColdStorageTestSuite;
@@ -0,0 +1,36 @@
1
+ import { ColdStorageError } from "../Errors.cjs";
2
+ import { ColdStorageTag } from "../ColdStorage.cjs";
3
+ import { StorageTestCase, TestError, TestResults } from "./types.cjs";
4
+ import { Effect } from "effect";
5
+
6
+ //#region src/testing/ColdStorageTestSuite.d.ts
7
+
8
+ /**
9
+ * Error type for ColdStorage tests - can be either a TestError or a ColdStorageError
10
+ */
11
+ type ColdStorageTestError = TestError | ColdStorageError;
12
+ declare const Categories: {
13
+ readonly BasicOperations: "Basic Operations";
14
+ readonly DataIntegrity: "Data Integrity";
15
+ readonly VersionHandling: "Version Handling";
16
+ readonly TimestampHandling: "Timestamp Handling";
17
+ readonly DocumentIdEdgeCases: "Document ID Edge Cases";
18
+ readonly DocumentIsolation: "Document Isolation";
19
+ readonly ConsistencyGuarantees: "Consistency Guarantees";
20
+ };
21
+ declare const ColdStorageTestSuite: {
22
+ Categories: {
23
+ readonly BasicOperations: "Basic Operations";
24
+ readonly DataIntegrity: "Data Integrity";
25
+ readonly VersionHandling: "Version Handling";
26
+ readonly TimestampHandling: "Timestamp Handling";
27
+ readonly DocumentIdEdgeCases: "Document ID Edge Cases";
28
+ readonly DocumentIsolation: "Document Isolation";
29
+ readonly ConsistencyGuarantees: "Consistency Guarantees";
30
+ };
31
+ makeTests: () => StorageTestCase<ColdStorageTestError, ColdStorageTag>[];
32
+ runAll: () => Effect.Effect<TestResults<ColdStorageTestError, ColdStorageTag>, never, ColdStorageTag>;
33
+ };
34
+ //#endregion
35
+ export { Categories, ColdStorageTestError, ColdStorageTestSuite };
36
+ //# sourceMappingURL=ColdStorageTestSuite.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ColdStorageTestSuite.d.cts","names":[],"sources":["../../src/testing/ColdStorageTestSuite.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;AA6iBE,KAvhBU,oBAAA,GAAuB,SAuhBjC,GAvhB6C,gBAuhB7C;AAHwB,cA9gBb,UA8gBoB,EAAA;EAAM,SAAA,eAAA,EAAA,kBAAA;;;;;;;;cA8B1B;;;;;;;;;;mBAxCgB,gBAC3B,sBACA;gBAQwB,MAAA,CAAO,OAC/B,YAAY,sBAAsB,wBAElC"}