@voidhash/mimic-effect 0.0.9 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +136 -90
- package/README.md +385 -0
- package/dist/ColdStorage.cjs +60 -0
- package/dist/ColdStorage.d.cts +53 -0
- package/dist/ColdStorage.d.cts.map +1 -0
- package/dist/ColdStorage.d.mts +53 -0
- package/dist/ColdStorage.d.mts.map +1 -0
- package/dist/ColdStorage.mjs +60 -0
- package/dist/ColdStorage.mjs.map +1 -0
- package/dist/DocumentManager.cjs +263 -82
- package/dist/DocumentManager.d.cts +44 -22
- package/dist/DocumentManager.d.cts.map +1 -1
- package/dist/DocumentManager.d.mts +44 -22
- package/dist/DocumentManager.d.mts.map +1 -1
- package/dist/DocumentManager.mjs +259 -67
- package/dist/DocumentManager.mjs.map +1 -1
- package/dist/Errors.cjs +54 -0
- package/dist/Errors.d.cts +96 -0
- package/dist/Errors.d.cts.map +1 -0
- package/dist/Errors.d.mts +96 -0
- package/dist/Errors.d.mts.map +1 -0
- package/dist/Errors.mjs +48 -0
- package/dist/Errors.mjs.map +1 -0
- package/dist/HotStorage.cjs +100 -0
- package/dist/HotStorage.d.cts +70 -0
- package/dist/HotStorage.d.cts.map +1 -0
- package/dist/HotStorage.d.mts +70 -0
- package/dist/HotStorage.d.mts.map +1 -0
- package/dist/HotStorage.mjs +100 -0
- package/dist/HotStorage.mjs.map +1 -0
- package/dist/Metrics.cjs +143 -0
- package/dist/Metrics.d.cts +31 -0
- package/dist/Metrics.d.cts.map +1 -0
- package/dist/Metrics.d.mts +31 -0
- package/dist/Metrics.d.mts.map +1 -0
- package/dist/Metrics.mjs +126 -0
- package/dist/Metrics.mjs.map +1 -0
- package/dist/MimicAuthService.cjs +61 -45
- package/dist/MimicAuthService.d.cts +61 -48
- package/dist/MimicAuthService.d.cts.map +1 -1
- package/dist/MimicAuthService.d.mts +61 -48
- package/dist/MimicAuthService.d.mts.map +1 -1
- package/dist/MimicAuthService.mjs +60 -36
- package/dist/MimicAuthService.mjs.map +1 -1
- package/dist/MimicClusterServerEngine.cjs +521 -0
- package/dist/MimicClusterServerEngine.d.cts +17 -0
- package/dist/MimicClusterServerEngine.d.cts.map +1 -0
- package/dist/MimicClusterServerEngine.d.mts +17 -0
- package/dist/MimicClusterServerEngine.d.mts.map +1 -0
- package/dist/MimicClusterServerEngine.mjs +523 -0
- package/dist/MimicClusterServerEngine.mjs.map +1 -0
- package/dist/MimicServer.cjs +205 -96
- package/dist/MimicServer.d.cts +9 -110
- package/dist/MimicServer.d.cts.map +1 -1
- package/dist/MimicServer.d.mts +9 -110
- package/dist/MimicServer.d.mts.map +1 -1
- package/dist/MimicServer.mjs +206 -90
- package/dist/MimicServer.mjs.map +1 -1
- package/dist/MimicServerEngine.cjs +97 -0
- package/dist/MimicServerEngine.d.cts +78 -0
- package/dist/MimicServerEngine.d.cts.map +1 -0
- package/dist/MimicServerEngine.d.mts +78 -0
- package/dist/MimicServerEngine.d.mts.map +1 -0
- package/dist/MimicServerEngine.mjs +97 -0
- package/dist/MimicServerEngine.mjs.map +1 -0
- package/dist/PresenceManager.cjs +75 -91
- package/dist/PresenceManager.d.cts +17 -66
- package/dist/PresenceManager.d.cts.map +1 -1
- package/dist/PresenceManager.d.mts +17 -66
- package/dist/PresenceManager.d.mts.map +1 -1
- package/dist/PresenceManager.mjs +74 -78
- package/dist/PresenceManager.mjs.map +1 -1
- package/dist/Protocol.cjs +146 -0
- package/dist/Protocol.d.cts +203 -0
- package/dist/Protocol.d.cts.map +1 -0
- package/dist/Protocol.d.mts +203 -0
- package/dist/Protocol.d.mts.map +1 -0
- package/dist/Protocol.mjs +132 -0
- package/dist/Protocol.mjs.map +1 -0
- package/dist/Types.d.cts +172 -0
- package/dist/Types.d.cts.map +1 -0
- package/dist/Types.d.mts +172 -0
- package/dist/Types.d.mts.map +1 -0
- package/dist/_virtual/rolldown_runtime.cjs +1 -25
- package/dist/_virtual/rolldown_runtime.mjs +4 -1
- package/dist/index.cjs +37 -75
- package/dist/index.d.cts +13 -12
- package/dist/index.d.mts +13 -12
- package/dist/index.mjs +12 -12
- package/dist/testing/ColdStorageTestSuite.cjs +508 -0
- package/dist/testing/ColdStorageTestSuite.d.cts +36 -0
- package/dist/testing/ColdStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/ColdStorageTestSuite.d.mts +36 -0
- package/dist/testing/ColdStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/ColdStorageTestSuite.mjs +508 -0
- package/dist/testing/ColdStorageTestSuite.mjs.map +1 -0
- package/dist/testing/FailingStorage.cjs +135 -0
- package/dist/testing/FailingStorage.d.cts +43 -0
- package/dist/testing/FailingStorage.d.cts.map +1 -0
- package/dist/testing/FailingStorage.d.mts +43 -0
- package/dist/testing/FailingStorage.d.mts.map +1 -0
- package/dist/testing/FailingStorage.mjs +136 -0
- package/dist/testing/FailingStorage.mjs.map +1 -0
- package/dist/testing/HotStorageTestSuite.cjs +585 -0
- package/dist/testing/HotStorageTestSuite.d.cts +40 -0
- package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/HotStorageTestSuite.d.mts +40 -0
- package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/HotStorageTestSuite.mjs +585 -0
- package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.cjs +349 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts +35 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts +35 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs +349 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
- package/dist/testing/assertions.cjs +114 -0
- package/dist/testing/assertions.mjs +109 -0
- package/dist/testing/assertions.mjs.map +1 -0
- package/dist/testing/index.cjs +14 -0
- package/dist/testing/index.d.cts +6 -0
- package/dist/testing/index.d.mts +6 -0
- package/dist/testing/index.mjs +7 -0
- package/dist/testing/types.cjs +15 -0
- package/dist/testing/types.d.cts +90 -0
- package/dist/testing/types.d.cts.map +1 -0
- package/dist/testing/types.d.mts +90 -0
- package/dist/testing/types.d.mts.map +1 -0
- package/dist/testing/types.mjs +16 -0
- package/dist/testing/types.mjs.map +1 -0
- package/package.json +18 -3
- package/src/ColdStorage.ts +136 -0
- package/src/DocumentManager.ts +550 -190
- package/src/Errors.ts +114 -0
- package/src/HotStorage.ts +239 -0
- package/src/Metrics.ts +187 -0
- package/src/MimicAuthService.ts +126 -64
- package/src/MimicClusterServerEngine.ts +946 -0
- package/src/MimicServer.ts +448 -195
- package/src/MimicServerEngine.ts +276 -0
- package/src/PresenceManager.ts +169 -240
- package/src/Protocol.ts +350 -0
- package/src/Types.ts +231 -0
- package/src/index.ts +57 -23
- package/src/testing/ColdStorageTestSuite.ts +589 -0
- package/src/testing/FailingStorage.ts +286 -0
- package/src/testing/HotStorageTestSuite.ts +762 -0
- package/src/testing/StorageIntegrationTestSuite.ts +504 -0
- package/src/testing/assertions.ts +181 -0
- package/src/testing/index.ts +83 -0
- package/src/testing/types.ts +100 -0
- package/tests/ColdStorage.test.ts +24 -0
- package/tests/DocumentManager.test.ts +158 -287
- package/tests/HotStorage.test.ts +24 -0
- package/tests/MimicAuthService.test.ts +102 -134
- package/tests/MimicClusterServerEngine.test.ts +587 -0
- package/tests/MimicServer.test.ts +90 -226
- package/tests/MimicServerEngine.test.ts +521 -0
- package/tests/PresenceManager.test.ts +22 -63
- package/tests/Protocol.test.ts +190 -0
- package/tests/StorageIntegration.test.ts +259 -0
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +1 -1
- package/dist/DocumentProtocol.cjs +0 -94
- package/dist/DocumentProtocol.d.cts +0 -113
- package/dist/DocumentProtocol.d.cts.map +0 -1
- package/dist/DocumentProtocol.d.mts +0 -113
- package/dist/DocumentProtocol.d.mts.map +0 -1
- package/dist/DocumentProtocol.mjs +0 -89
- package/dist/DocumentProtocol.mjs.map +0 -1
- package/dist/MimicConfig.cjs +0 -60
- package/dist/MimicConfig.d.cts +0 -141
- package/dist/MimicConfig.d.cts.map +0 -1
- package/dist/MimicConfig.d.mts +0 -141
- package/dist/MimicConfig.d.mts.map +0 -1
- package/dist/MimicConfig.mjs +0 -50
- package/dist/MimicConfig.mjs.map +0 -1
- package/dist/MimicDataStorage.cjs +0 -83
- package/dist/MimicDataStorage.d.cts +0 -113
- package/dist/MimicDataStorage.d.cts.map +0 -1
- package/dist/MimicDataStorage.d.mts +0 -113
- package/dist/MimicDataStorage.d.mts.map +0 -1
- package/dist/MimicDataStorage.mjs +0 -74
- package/dist/MimicDataStorage.mjs.map +0 -1
- package/dist/WebSocketHandler.cjs +0 -365
- package/dist/WebSocketHandler.d.cts +0 -34
- package/dist/WebSocketHandler.d.cts.map +0 -1
- package/dist/WebSocketHandler.d.mts +0 -34
- package/dist/WebSocketHandler.d.mts.map +0 -1
- package/dist/WebSocketHandler.mjs +0 -355
- package/dist/WebSocketHandler.mjs.map +0 -1
- package/dist/auth/NoAuth.cjs +0 -43
- package/dist/auth/NoAuth.d.cts +0 -22
- package/dist/auth/NoAuth.d.cts.map +0 -1
- package/dist/auth/NoAuth.d.mts +0 -22
- package/dist/auth/NoAuth.d.mts.map +0 -1
- package/dist/auth/NoAuth.mjs +0 -36
- package/dist/auth/NoAuth.mjs.map +0 -1
- package/dist/errors.cjs +0 -74
- package/dist/errors.d.cts +0 -89
- package/dist/errors.d.cts.map +0 -1
- package/dist/errors.d.mts +0 -89
- package/dist/errors.d.mts.map +0 -1
- package/dist/errors.mjs +0 -67
- package/dist/errors.mjs.map +0 -1
- package/dist/storage/InMemoryDataStorage.cjs +0 -57
- package/dist/storage/InMemoryDataStorage.d.cts +0 -19
- package/dist/storage/InMemoryDataStorage.d.cts.map +0 -1
- package/dist/storage/InMemoryDataStorage.d.mts +0 -19
- package/dist/storage/InMemoryDataStorage.d.mts.map +0 -1
- package/dist/storage/InMemoryDataStorage.mjs +0 -48
- package/dist/storage/InMemoryDataStorage.mjs.map +0 -1
- package/src/DocumentProtocol.ts +0 -112
- package/src/MimicConfig.ts +0 -211
- package/src/MimicDataStorage.ts +0 -157
- package/src/WebSocketHandler.ts +0 -735
- package/src/auth/NoAuth.ts +0 -46
- package/src/errors.ts +0 -113
- package/src/storage/InMemoryDataStorage.ts +0 -66
- package/tests/DocumentProtocol.test.ts +0 -113
- package/tests/InMemoryDataStorage.test.ts +0 -190
- package/tests/MimicConfig.test.ts +0 -290
- package/tests/MimicDataStorage.test.ts +0 -190
- package/tests/NoAuth.test.ts +0 -94
- package/tests/WebSocketHandler.test.ts +0 -321
- package/tests/errors.test.ts +0 -77
package/src/MimicConfig.ts
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @since 0.0.1
|
|
3
|
-
* Configuration types for the Mimic server.
|
|
4
|
-
*/
|
|
5
|
-
import * as Context from "effect/Context";
|
|
6
|
-
import * as Duration from "effect/Duration";
|
|
7
|
-
import type { DurationInput } from "effect/Duration";
|
|
8
|
-
import * as Effect from "effect/Effect";
|
|
9
|
-
import * as Layer from "effect/Layer";
|
|
10
|
-
import { Primitive, Presence } from "@voidhash/mimic";
|
|
11
|
-
|
|
12
|
-
// =============================================================================
|
|
13
|
-
// Initial State Types
|
|
14
|
-
// =============================================================================
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Context available when computing initial state for a document.
|
|
18
|
-
*/
|
|
19
|
-
export interface InitialContext {
|
|
20
|
-
/**
|
|
21
|
-
* The document ID being initialized.
|
|
22
|
-
*/
|
|
23
|
-
readonly documentId: string;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Function that computes initial state for a document.
|
|
28
|
-
* Receives context with the document ID and returns an Effect that produces the initial state.
|
|
29
|
-
*/
|
|
30
|
-
export type InitialFn<TSchema extends Primitive.AnyPrimitive> = (
|
|
31
|
-
context: InitialContext
|
|
32
|
-
) => Effect.Effect<Primitive.InferSetInput<TSchema>>;
|
|
33
|
-
|
|
34
|
-
// =============================================================================
|
|
35
|
-
// Mimic Server Configuration
|
|
36
|
-
// =============================================================================
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Configuration for the Mimic server.
|
|
40
|
-
*
|
|
41
|
-
* Note: Authentication and persistence are now handled by injectable services
|
|
42
|
-
* (MimicAuthService and MimicDataStorage) rather than config options.
|
|
43
|
-
*/
|
|
44
|
-
export interface MimicServerConfig<
|
|
45
|
-
TSchema extends Primitive.AnyPrimitive = Primitive.AnyPrimitive,
|
|
46
|
-
> {
|
|
47
|
-
/**
|
|
48
|
-
* The schema defining the document structure.
|
|
49
|
-
*/
|
|
50
|
-
readonly schema: TSchema;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Maximum idle time for a document before it is cleaned up.
|
|
54
|
-
* @default "5 minutes"
|
|
55
|
-
*/
|
|
56
|
-
readonly maxIdleTime: Duration.Duration;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Maximum number of processed transaction IDs to track for deduplication.
|
|
60
|
-
* @default 1000
|
|
61
|
-
*/
|
|
62
|
-
readonly maxTransactionHistory: number;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Heartbeat interval for WebSocket connections.
|
|
66
|
-
* @default "30 seconds"
|
|
67
|
-
*/
|
|
68
|
-
readonly heartbeatInterval: Duration.Duration;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Timeout for heartbeat responses before considering connection dead.
|
|
72
|
-
* @default "10 seconds"
|
|
73
|
-
*/
|
|
74
|
-
readonly heartbeatTimeout: Duration.Duration;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Optional presence schema for ephemeral per-user data.
|
|
78
|
-
* When provided, enables presence features on WebSocket connections.
|
|
79
|
-
* @default undefined (presence disabled)
|
|
80
|
-
*/
|
|
81
|
-
readonly presence: Presence.AnyPresence | undefined;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Initial state function for new documents.
|
|
85
|
-
* Called when a document is created and no existing state is found in storage.
|
|
86
|
-
* Receives the document ID and returns an Effect that produces the initial state.
|
|
87
|
-
* @default undefined (documents start empty or use schema defaults)
|
|
88
|
-
*/
|
|
89
|
-
readonly initial: InitialFn<TSchema> | undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Options for creating a MimicServerConfig.
|
|
94
|
-
*/
|
|
95
|
-
export interface MimicServerConfigOptions<
|
|
96
|
-
TSchema extends Primitive.AnyPrimitive = Primitive.AnyPrimitive,
|
|
97
|
-
> {
|
|
98
|
-
/**
|
|
99
|
-
* The schema defining the document structure.
|
|
100
|
-
*/
|
|
101
|
-
readonly schema: TSchema;
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Maximum idle time for a document before it is cleaned up.
|
|
105
|
-
* @default "5 minutes"
|
|
106
|
-
*/
|
|
107
|
-
readonly maxIdleTime?: DurationInput;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Maximum number of processed transaction IDs to track for deduplication.
|
|
111
|
-
* @default 1000
|
|
112
|
-
*/
|
|
113
|
-
readonly maxTransactionHistory?: number;
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Heartbeat interval for WebSocket connections.
|
|
117
|
-
* @default "30 seconds"
|
|
118
|
-
*/
|
|
119
|
-
readonly heartbeatInterval?: DurationInput;
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Timeout for heartbeat responses.
|
|
123
|
-
* @default "10 seconds"
|
|
124
|
-
*/
|
|
125
|
-
readonly heartbeatTimeout?: DurationInput;
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Optional presence schema for ephemeral per-user data.
|
|
129
|
-
* When provided, enables presence features on WebSocket connections.
|
|
130
|
-
* @default undefined (presence disabled)
|
|
131
|
-
*/
|
|
132
|
-
readonly presence?: Presence.AnyPresence;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Initial state for new documents.
|
|
136
|
-
* Can be either:
|
|
137
|
-
* - A plain object with the initial state values
|
|
138
|
-
* - A function that receives context (with documentId) and returns an Effect producing the initial state
|
|
139
|
-
*
|
|
140
|
-
* Type-safe: required fields (without defaults) must be provided,
|
|
141
|
-
* while optional fields and fields with defaults can be omitted.
|
|
142
|
-
*
|
|
143
|
-
* @example
|
|
144
|
-
* // Plain object
|
|
145
|
-
* initial: { title: "New Document", count: 0 }
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* // Function returning Effect
|
|
149
|
-
* initial: ({ documentId }) => Effect.succeed({ title: `Doc ${documentId}`, count: 0 })
|
|
150
|
-
*
|
|
151
|
-
* @default undefined (documents start empty or use schema defaults)
|
|
152
|
-
*/
|
|
153
|
-
readonly initial?: Primitive.InferSetInput<TSchema> | InitialFn<TSchema>;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Check if a value is an InitialFn (function) rather than a plain object.
|
|
158
|
-
*/
|
|
159
|
-
const isInitialFn = <TSchema extends Primitive.AnyPrimitive>(
|
|
160
|
-
value: Primitive.InferSetInput<TSchema> | InitialFn<TSchema> | undefined
|
|
161
|
-
): value is InitialFn<TSchema> => typeof value === "function";
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Create a MimicServerConfig from options.
|
|
165
|
-
*/
|
|
166
|
-
export const make = <TSchema extends Primitive.AnyPrimitive>(
|
|
167
|
-
options: MimicServerConfigOptions<TSchema>
|
|
168
|
-
): MimicServerConfig<TSchema> => {
|
|
169
|
-
const { initial, schema } = options;
|
|
170
|
-
|
|
171
|
-
// Convert initial to a function that applies defaults
|
|
172
|
-
const initialFn: InitialFn<TSchema> | undefined = initial === undefined
|
|
173
|
-
? undefined
|
|
174
|
-
: isInitialFn<TSchema>(initial)
|
|
175
|
-
? (context) => Effect.map(
|
|
176
|
-
initial(context),
|
|
177
|
-
(state) => Primitive.applyDefaults(schema, state as Partial<Primitive.InferState<TSchema>>)
|
|
178
|
-
) as Effect.Effect<Primitive.InferSetInput<TSchema>>
|
|
179
|
-
: () => Effect.succeed(
|
|
180
|
-
Primitive.applyDefaults(schema, initial as Partial<Primitive.InferState<TSchema>>)
|
|
181
|
-
) as Effect.Effect<Primitive.InferSetInput<TSchema>>;
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
schema,
|
|
185
|
-
maxIdleTime: Duration.decode(options.maxIdleTime ?? "5 minutes"),
|
|
186
|
-
maxTransactionHistory: options.maxTransactionHistory ?? 1000,
|
|
187
|
-
heartbeatInterval: Duration.decode(options.heartbeatInterval ?? "30 seconds"),
|
|
188
|
-
heartbeatTimeout: Duration.decode(options.heartbeatTimeout ?? "10 seconds"),
|
|
189
|
-
presence: options.presence,
|
|
190
|
-
initial: initialFn,
|
|
191
|
-
};
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
// =============================================================================
|
|
195
|
-
// Context Tag
|
|
196
|
-
// =============================================================================
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Context tag for MimicServerConfig.
|
|
200
|
-
*/
|
|
201
|
-
export class MimicServerConfigTag extends Context.Tag(
|
|
202
|
-
"@voidhash/mimic-server-effect/MimicServerConfig"
|
|
203
|
-
)<MimicServerConfigTag, MimicServerConfig>() {}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Create a Layer that provides MimicServerConfig.
|
|
207
|
-
*/
|
|
208
|
-
export const layer = <TSchema extends Primitive.AnyPrimitive>(
|
|
209
|
-
options: MimicServerConfigOptions<TSchema>
|
|
210
|
-
): Layer.Layer<MimicServerConfigTag> =>
|
|
211
|
-
Layer.succeed(MimicServerConfigTag, make(options) as unknown as MimicServerConfig);
|
package/src/MimicDataStorage.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @since 0.0.1
|
|
3
|
-
* Data storage service interface for Mimic documents.
|
|
4
|
-
* Provides pluggable storage adapters with load/save hooks for data transformation.
|
|
5
|
-
*/
|
|
6
|
-
import * as Effect from "effect/Effect";
|
|
7
|
-
import * as Context from "effect/Context";
|
|
8
|
-
import * as Layer from "effect/Layer";
|
|
9
|
-
import * as Data from "effect/Data";
|
|
10
|
-
|
|
11
|
-
// =============================================================================
|
|
12
|
-
// Error Types
|
|
13
|
-
// =============================================================================
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Error when loading a document from storage fails.
|
|
17
|
-
*/
|
|
18
|
-
export class StorageLoadError extends Data.TaggedError("StorageLoadError")<{
|
|
19
|
-
readonly documentId: string;
|
|
20
|
-
readonly cause: unknown;
|
|
21
|
-
}> {
|
|
22
|
-
override get message(): string {
|
|
23
|
-
return `Failed to load document ${this.documentId}: ${String(this.cause)}`;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Error when saving a document to storage fails.
|
|
29
|
-
*/
|
|
30
|
-
export class StorageSaveError extends Data.TaggedError("StorageSaveError")<{
|
|
31
|
-
readonly documentId: string;
|
|
32
|
-
readonly cause: unknown;
|
|
33
|
-
}> {
|
|
34
|
-
override get message(): string {
|
|
35
|
-
return `Failed to save document ${this.documentId}: ${String(this.cause)}`;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Error when deleting a document from storage fails.
|
|
41
|
-
*/
|
|
42
|
-
export class StorageDeleteError extends Data.TaggedError("StorageDeleteError")<{
|
|
43
|
-
readonly documentId: string;
|
|
44
|
-
readonly cause: unknown;
|
|
45
|
-
}> {
|
|
46
|
-
override get message(): string {
|
|
47
|
-
return `Failed to delete document ${this.documentId}: ${String(this.cause)}`;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Union of all storage errors.
|
|
53
|
-
*/
|
|
54
|
-
export type StorageError = StorageLoadError | StorageSaveError | StorageDeleteError;
|
|
55
|
-
|
|
56
|
-
// =============================================================================
|
|
57
|
-
// Storage Service Interface
|
|
58
|
-
// =============================================================================
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Data storage service interface.
|
|
62
|
-
* Implementations can persist documents to various backends (memory, S3, database, etc.)
|
|
63
|
-
*/
|
|
64
|
-
export interface MimicDataStorage {
|
|
65
|
-
/**
|
|
66
|
-
* Load a document's state from storage.
|
|
67
|
-
* @param documentId - The unique identifier for the document
|
|
68
|
-
* @returns The document state, or undefined if not found
|
|
69
|
-
*/
|
|
70
|
-
readonly load: (
|
|
71
|
-
documentId: string
|
|
72
|
-
) => Effect.Effect<unknown | undefined, StorageLoadError>;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Save a document's state to storage.
|
|
76
|
-
* @param documentId - The unique identifier for the document
|
|
77
|
-
* @param state - The document state to persist
|
|
78
|
-
*/
|
|
79
|
-
readonly save: (
|
|
80
|
-
documentId: string,
|
|
81
|
-
state: unknown
|
|
82
|
-
) => Effect.Effect<void, StorageSaveError>;
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Delete a document from storage.
|
|
86
|
-
* @param documentId - The unique identifier for the document
|
|
87
|
-
*/
|
|
88
|
-
readonly delete: (
|
|
89
|
-
documentId: string
|
|
90
|
-
) => Effect.Effect<void, StorageDeleteError>;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Transform data after loading from storage.
|
|
94
|
-
* Useful for migrations, decryption, decompression, etc.
|
|
95
|
-
* @param state - The raw state loaded from storage
|
|
96
|
-
* @returns The transformed state
|
|
97
|
-
*/
|
|
98
|
-
readonly onLoad: (state: unknown) => Effect.Effect<unknown>;
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Transform/validate data before saving to storage.
|
|
102
|
-
* Useful for encryption, compression, validation, etc.
|
|
103
|
-
* @param state - The state to be saved
|
|
104
|
-
* @returns The transformed state
|
|
105
|
-
*/
|
|
106
|
-
readonly onSave: (state: unknown) => Effect.Effect<unknown>;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// =============================================================================
|
|
110
|
-
// Context Tag
|
|
111
|
-
// =============================================================================
|
|
112
|
-
|
|
113
|
-
/**
|
|
114
|
-
* Context tag for MimicDataStorage service.
|
|
115
|
-
*/
|
|
116
|
-
export class MimicDataStorageTag extends Context.Tag(
|
|
117
|
-
"@voidhash/mimic-server-effect/MimicDataStorage"
|
|
118
|
-
)<MimicDataStorageTag, MimicDataStorage>() {}
|
|
119
|
-
|
|
120
|
-
// =============================================================================
|
|
121
|
-
// Layer Constructors
|
|
122
|
-
// =============================================================================
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Create a MimicDataStorage layer from a storage implementation.
|
|
126
|
-
*/
|
|
127
|
-
export const layer = (storage: MimicDataStorage): Layer.Layer<MimicDataStorageTag> =>
|
|
128
|
-
Layer.succeed(MimicDataStorageTag, storage);
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Create a MimicDataStorage layer from an Effect that produces a storage implementation.
|
|
132
|
-
*/
|
|
133
|
-
export const layerEffect = <E, R>(
|
|
134
|
-
effect: Effect.Effect<MimicDataStorage, E, R>
|
|
135
|
-
): Layer.Layer<MimicDataStorageTag, E, R> =>
|
|
136
|
-
Layer.effect(MimicDataStorageTag, effect);
|
|
137
|
-
|
|
138
|
-
// =============================================================================
|
|
139
|
-
// Helper Functions
|
|
140
|
-
// =============================================================================
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Create a simple storage implementation with minimal configuration.
|
|
144
|
-
*/
|
|
145
|
-
export const make = (options: {
|
|
146
|
-
readonly load: (documentId: string) => Effect.Effect<unknown | undefined, StorageLoadError>;
|
|
147
|
-
readonly save: (documentId: string, state: unknown) => Effect.Effect<void, StorageSaveError>;
|
|
148
|
-
readonly delete?: (documentId: string) => Effect.Effect<void, StorageDeleteError>;
|
|
149
|
-
readonly onLoad?: (state: unknown) => Effect.Effect<unknown>;
|
|
150
|
-
readonly onSave?: (state: unknown) => Effect.Effect<unknown>;
|
|
151
|
-
}): MimicDataStorage => ({
|
|
152
|
-
load: options.load,
|
|
153
|
-
save: options.save,
|
|
154
|
-
delete: options.delete ?? (() => Effect.void),
|
|
155
|
-
onLoad: options.onLoad ?? ((state) => Effect.succeed(state)),
|
|
156
|
-
onSave: options.onSave ?? ((state) => Effect.succeed(state)),
|
|
157
|
-
});
|