@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/Protocol.ts
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @voidhash/mimic-effect - WebSocket Protocol
|
|
3
|
+
*
|
|
4
|
+
* Message types and encoding/decoding for WebSocket communication.
|
|
5
|
+
*/
|
|
6
|
+
import { Effect } from "effect";
|
|
7
|
+
import { Transaction } from "@voidhash/mimic";
|
|
8
|
+
import type { Permission, PresenceEntry } from "./Types";
|
|
9
|
+
import { MessageParseError } from "./Errors";
|
|
10
|
+
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Client -> Server Messages
|
|
13
|
+
// =============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Authentication request
|
|
17
|
+
*/
|
|
18
|
+
export interface AuthMessage {
|
|
19
|
+
readonly type: "auth";
|
|
20
|
+
readonly token: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Heartbeat ping
|
|
25
|
+
*/
|
|
26
|
+
export interface PingMessage {
|
|
27
|
+
readonly type: "ping";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Submit a transaction
|
|
32
|
+
*/
|
|
33
|
+
export interface SubmitMessage {
|
|
34
|
+
readonly type: "submit";
|
|
35
|
+
readonly transaction: Transaction.Transaction;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Request current document snapshot
|
|
40
|
+
*/
|
|
41
|
+
export interface RequestSnapshotMessage {
|
|
42
|
+
readonly type: "request_snapshot";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Set presence data
|
|
47
|
+
*/
|
|
48
|
+
export interface PresenceSetMessage {
|
|
49
|
+
readonly type: "presence_set";
|
|
50
|
+
readonly data: unknown;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Clear presence data
|
|
55
|
+
*/
|
|
56
|
+
export interface PresenceClearMessage {
|
|
57
|
+
readonly type: "presence_clear";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Union of all client messages
|
|
62
|
+
*/
|
|
63
|
+
export type ClientMessage =
|
|
64
|
+
| AuthMessage
|
|
65
|
+
| PingMessage
|
|
66
|
+
| SubmitMessage
|
|
67
|
+
| RequestSnapshotMessage
|
|
68
|
+
| PresenceSetMessage
|
|
69
|
+
| PresenceClearMessage;
|
|
70
|
+
|
|
71
|
+
// =============================================================================
|
|
72
|
+
// Server -> Client Messages
|
|
73
|
+
// =============================================================================
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Authentication result
|
|
77
|
+
*/
|
|
78
|
+
export interface AuthResultMessage {
|
|
79
|
+
readonly type: "auth_result";
|
|
80
|
+
readonly success: boolean;
|
|
81
|
+
readonly error?: string;
|
|
82
|
+
readonly userId?: string;
|
|
83
|
+
readonly permission?: Permission;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Heartbeat pong
|
|
88
|
+
*/
|
|
89
|
+
export interface PongMessage {
|
|
90
|
+
readonly type: "pong";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Transaction broadcast
|
|
95
|
+
*/
|
|
96
|
+
export interface TransactionMessage {
|
|
97
|
+
readonly type: "transaction";
|
|
98
|
+
readonly transaction: Transaction.Transaction;
|
|
99
|
+
readonly version: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Document snapshot
|
|
104
|
+
*/
|
|
105
|
+
export interface SnapshotMessage {
|
|
106
|
+
readonly type: "snapshot";
|
|
107
|
+
readonly state: unknown;
|
|
108
|
+
readonly version: number;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Transaction error
|
|
113
|
+
*/
|
|
114
|
+
export interface ErrorMessage {
|
|
115
|
+
readonly type: "error";
|
|
116
|
+
readonly transactionId: string;
|
|
117
|
+
readonly reason: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Presence update broadcast
|
|
122
|
+
*/
|
|
123
|
+
export interface PresenceUpdateMessage {
|
|
124
|
+
readonly type: "presence_update";
|
|
125
|
+
readonly id: string;
|
|
126
|
+
readonly data: unknown;
|
|
127
|
+
readonly userId?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Presence removal broadcast
|
|
132
|
+
*/
|
|
133
|
+
export interface PresenceRemoveMessage {
|
|
134
|
+
readonly type: "presence_remove";
|
|
135
|
+
readonly id: string;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Presence snapshot (sent after auth)
|
|
140
|
+
*/
|
|
141
|
+
export interface PresenceSnapshotMessage {
|
|
142
|
+
readonly type: "presence_snapshot";
|
|
143
|
+
readonly selfId: string;
|
|
144
|
+
readonly presences: Record<string, PresenceEntry>;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Union of all server messages
|
|
149
|
+
*/
|
|
150
|
+
export type ServerMessage =
|
|
151
|
+
| AuthResultMessage
|
|
152
|
+
| PongMessage
|
|
153
|
+
| TransactionMessage
|
|
154
|
+
| SnapshotMessage
|
|
155
|
+
| ErrorMessage
|
|
156
|
+
| PresenceUpdateMessage
|
|
157
|
+
| PresenceRemoveMessage
|
|
158
|
+
| PresenceSnapshotMessage;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Server broadcast messages (transaction or error)
|
|
162
|
+
*/
|
|
163
|
+
export type ServerBroadcast = TransactionMessage | ErrorMessage;
|
|
164
|
+
|
|
165
|
+
// =============================================================================
|
|
166
|
+
// Encoded Types (for wire format)
|
|
167
|
+
// =============================================================================
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Encoded client message (with encoded transaction)
|
|
171
|
+
*/
|
|
172
|
+
export interface EncodedClientMessage {
|
|
173
|
+
readonly type: string;
|
|
174
|
+
readonly token?: string;
|
|
175
|
+
readonly transaction?: Transaction.EncodedTransaction;
|
|
176
|
+
readonly data?: unknown;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Encoded server message (with encoded transaction)
|
|
181
|
+
*/
|
|
182
|
+
export interface EncodedServerMessage {
|
|
183
|
+
readonly type: string;
|
|
184
|
+
readonly success?: boolean;
|
|
185
|
+
readonly error?: string;
|
|
186
|
+
readonly userId?: string;
|
|
187
|
+
readonly permission?: Permission;
|
|
188
|
+
readonly transaction?: Transaction.EncodedTransaction;
|
|
189
|
+
readonly version?: number;
|
|
190
|
+
readonly state?: unknown;
|
|
191
|
+
readonly transactionId?: string;
|
|
192
|
+
readonly reason?: string;
|
|
193
|
+
readonly id?: string;
|
|
194
|
+
readonly data?: unknown;
|
|
195
|
+
readonly selfId?: string;
|
|
196
|
+
readonly presences?: Record<string, PresenceEntry>;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// =============================================================================
|
|
200
|
+
// Encoding/Decoding Functions
|
|
201
|
+
// =============================================================================
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Decode an encoded client message to a ClientMessage
|
|
205
|
+
*/
|
|
206
|
+
export const decodeClientMessage = (
|
|
207
|
+
encoded: EncodedClientMessage
|
|
208
|
+
): ClientMessage => {
|
|
209
|
+
if (encoded.type === "submit" && encoded.transaction) {
|
|
210
|
+
return {
|
|
211
|
+
type: "submit",
|
|
212
|
+
transaction: Transaction.decode(encoded.transaction),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return encoded as ClientMessage;
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Encode a server message for wire format
|
|
220
|
+
*/
|
|
221
|
+
export const encodeServerMessage = (message: ServerMessage): string => {
|
|
222
|
+
if (message.type === "transaction") {
|
|
223
|
+
const encoded: EncodedServerMessage = {
|
|
224
|
+
type: "transaction",
|
|
225
|
+
transaction: Transaction.encode(message.transaction),
|
|
226
|
+
version: message.version,
|
|
227
|
+
};
|
|
228
|
+
return JSON.stringify(encoded);
|
|
229
|
+
}
|
|
230
|
+
return JSON.stringify(message);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Parse a raw WebSocket message to a ClientMessage
|
|
235
|
+
*/
|
|
236
|
+
export const parseClientMessage = (
|
|
237
|
+
data: string | ArrayBuffer | Uint8Array
|
|
238
|
+
): Effect.Effect<ClientMessage, MessageParseError> =>
|
|
239
|
+
Effect.try({
|
|
240
|
+
try: () => {
|
|
241
|
+
const text =
|
|
242
|
+
typeof data === "string"
|
|
243
|
+
? data
|
|
244
|
+
: new TextDecoder().decode(
|
|
245
|
+
data instanceof ArrayBuffer ? new Uint8Array(data) : data
|
|
246
|
+
);
|
|
247
|
+
const encoded = JSON.parse(text) as EncodedClientMessage;
|
|
248
|
+
return decodeClientMessage(encoded);
|
|
249
|
+
},
|
|
250
|
+
catch: (cause) => new MessageParseError({ cause }),
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Create an auth result success message
|
|
255
|
+
*/
|
|
256
|
+
export const authResultSuccess = (
|
|
257
|
+
userId: string,
|
|
258
|
+
permission: Permission
|
|
259
|
+
): AuthResultMessage => ({
|
|
260
|
+
type: "auth_result",
|
|
261
|
+
success: true,
|
|
262
|
+
userId,
|
|
263
|
+
permission,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Create an auth result failure message
|
|
268
|
+
*/
|
|
269
|
+
export const authResultFailure = (error: string): AuthResultMessage => ({
|
|
270
|
+
type: "auth_result",
|
|
271
|
+
success: false,
|
|
272
|
+
error,
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Create a pong message
|
|
277
|
+
*/
|
|
278
|
+
export const pong = (): PongMessage => ({ type: "pong" });
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Create a transaction message
|
|
282
|
+
*/
|
|
283
|
+
export const transactionMessage = (
|
|
284
|
+
transaction: Transaction.Transaction,
|
|
285
|
+
version: number
|
|
286
|
+
): TransactionMessage => ({
|
|
287
|
+
type: "transaction",
|
|
288
|
+
transaction,
|
|
289
|
+
version,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Create a snapshot message
|
|
294
|
+
*/
|
|
295
|
+
export const snapshotMessage = (
|
|
296
|
+
state: unknown,
|
|
297
|
+
version: number
|
|
298
|
+
): SnapshotMessage => ({
|
|
299
|
+
type: "snapshot",
|
|
300
|
+
state,
|
|
301
|
+
version,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Create an error message
|
|
306
|
+
*/
|
|
307
|
+
export const errorMessage = (
|
|
308
|
+
transactionId: string,
|
|
309
|
+
reason: string
|
|
310
|
+
): ErrorMessage => ({
|
|
311
|
+
type: "error",
|
|
312
|
+
transactionId,
|
|
313
|
+
reason,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Create a presence update message
|
|
318
|
+
*/
|
|
319
|
+
export const presenceUpdateMessage = (
|
|
320
|
+
id: string,
|
|
321
|
+
data: unknown,
|
|
322
|
+
userId?: string
|
|
323
|
+
): PresenceUpdateMessage => ({
|
|
324
|
+
type: "presence_update",
|
|
325
|
+
id,
|
|
326
|
+
data,
|
|
327
|
+
userId,
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Create a presence remove message
|
|
332
|
+
*/
|
|
333
|
+
export const presenceRemoveMessage = (
|
|
334
|
+
id: string
|
|
335
|
+
): PresenceRemoveMessage => ({
|
|
336
|
+
type: "presence_remove",
|
|
337
|
+
id,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Create a presence snapshot message
|
|
342
|
+
*/
|
|
343
|
+
export const presenceSnapshotMessage = (
|
|
344
|
+
selfId: string,
|
|
345
|
+
presences: Record<string, PresenceEntry>
|
|
346
|
+
): PresenceSnapshotMessage => ({
|
|
347
|
+
type: "presence_snapshot",
|
|
348
|
+
selfId,
|
|
349
|
+
presences,
|
|
350
|
+
});
|
package/src/Types.ts
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @voidhash/mimic-effect - Common Types
|
|
3
|
+
*
|
|
4
|
+
* Shared types used throughout the mimic-effect package.
|
|
5
|
+
*/
|
|
6
|
+
import type { Duration, Effect } from "effect";
|
|
7
|
+
import type { Presence, Primitive, Transaction } from "@voidhash/mimic";
|
|
8
|
+
|
|
9
|
+
// =============================================================================
|
|
10
|
+
// Permission Types
|
|
11
|
+
// =============================================================================
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Permission level for document access
|
|
15
|
+
* - "read": Can subscribe, receive transactions, get snapshots
|
|
16
|
+
* - "write": All of the above, plus can submit transactions and set presence
|
|
17
|
+
*/
|
|
18
|
+
export type Permission = "read" | "write";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Authentication context returned after successful authentication
|
|
22
|
+
*/
|
|
23
|
+
export interface AuthContext {
|
|
24
|
+
readonly userId: string;
|
|
25
|
+
readonly permission: Permission;
|
|
26
|
+
readonly metadata?: Record<string, unknown>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// Storage Types
|
|
31
|
+
// =============================================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Document state stored in ColdStorage (snapshots)
|
|
35
|
+
*/
|
|
36
|
+
export interface StoredDocument {
|
|
37
|
+
/** Document state */
|
|
38
|
+
readonly state: unknown;
|
|
39
|
+
/** Current version number */
|
|
40
|
+
readonly version: number;
|
|
41
|
+
/** Schema version for future migration support */
|
|
42
|
+
readonly schemaVersion: number;
|
|
43
|
+
/** Unix timestamp (ms) when saved */
|
|
44
|
+
readonly savedAt: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* WAL entry stored in HotStorage
|
|
49
|
+
*/
|
|
50
|
+
export interface WalEntry {
|
|
51
|
+
/** The transaction data */
|
|
52
|
+
readonly transaction: Transaction.Transaction;
|
|
53
|
+
/** Version after this transaction */
|
|
54
|
+
readonly version: number;
|
|
55
|
+
/** Unix timestamp (ms) */
|
|
56
|
+
readonly timestamp: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// =============================================================================
|
|
60
|
+
// Presence Types
|
|
61
|
+
// =============================================================================
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Presence entry for a connection
|
|
65
|
+
*/
|
|
66
|
+
export interface PresenceEntry {
|
|
67
|
+
/** Presence data (schema-validated) */
|
|
68
|
+
readonly data: unknown;
|
|
69
|
+
/** User ID from authentication (optional) */
|
|
70
|
+
readonly userId?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Snapshot of all presences for a document
|
|
75
|
+
*/
|
|
76
|
+
export interface PresenceSnapshot {
|
|
77
|
+
readonly presences: Record<string, PresenceEntry>;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Presence update event
|
|
82
|
+
*/
|
|
83
|
+
export interface PresenceUpdateEvent {
|
|
84
|
+
readonly type: "presence_update";
|
|
85
|
+
readonly id: string;
|
|
86
|
+
readonly data: unknown;
|
|
87
|
+
readonly userId?: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Presence remove event
|
|
92
|
+
*/
|
|
93
|
+
export interface PresenceRemoveEvent {
|
|
94
|
+
readonly type: "presence_remove";
|
|
95
|
+
readonly id: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Union of presence events
|
|
100
|
+
*/
|
|
101
|
+
export type PresenceEvent = PresenceUpdateEvent | PresenceRemoveEvent;
|
|
102
|
+
|
|
103
|
+
// =============================================================================
|
|
104
|
+
// Config Types
|
|
105
|
+
// =============================================================================
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Duration input type - matches Effect's DurationInput
|
|
109
|
+
*/
|
|
110
|
+
export type DurationInput = Duration.DurationInput;
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Snapshot configuration
|
|
114
|
+
*/
|
|
115
|
+
export interface SnapshotConfig {
|
|
116
|
+
/** Time-based snapshot interval */
|
|
117
|
+
readonly interval: DurationInput;
|
|
118
|
+
/** Transaction count threshold for snapshots */
|
|
119
|
+
readonly transactionThreshold: number;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Context passed to initial state function
|
|
124
|
+
*/
|
|
125
|
+
export interface InitialContext {
|
|
126
|
+
readonly documentId: string;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Initial state function type
|
|
131
|
+
*/
|
|
132
|
+
export type InitialFn<TSchema extends Primitive.AnyPrimitive> = (
|
|
133
|
+
context: InitialContext
|
|
134
|
+
) => Effect.Effect<Primitive.InferSetInput<TSchema>>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Initial state - either a static value or a function
|
|
138
|
+
*/
|
|
139
|
+
export type Initial<TSchema extends Primitive.AnyPrimitive> =
|
|
140
|
+
| Primitive.InferSetInput<TSchema>
|
|
141
|
+
| InitialFn<TSchema>;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* MimicServerEngine configuration
|
|
145
|
+
*/
|
|
146
|
+
export interface MimicServerEngineConfig<
|
|
147
|
+
TSchema extends Primitive.AnyPrimitive,
|
|
148
|
+
> {
|
|
149
|
+
/** Document schema (required) */
|
|
150
|
+
readonly schema: TSchema;
|
|
151
|
+
|
|
152
|
+
/** Initial state for new documents (optional) */
|
|
153
|
+
readonly initial?: Initial<TSchema>;
|
|
154
|
+
|
|
155
|
+
/** Presence schema (optional) */
|
|
156
|
+
readonly presence?: Presence.AnyPresence;
|
|
157
|
+
|
|
158
|
+
/** Document idle timeout before GC (default: 5 minutes) */
|
|
159
|
+
readonly maxIdleTime?: DurationInput;
|
|
160
|
+
|
|
161
|
+
/** Maximum transaction history for deduplication (default: 1000) */
|
|
162
|
+
readonly maxTransactionHistory?: number;
|
|
163
|
+
|
|
164
|
+
/** Snapshot configuration */
|
|
165
|
+
readonly snapshot?: SnapshotConfig;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* MimicClusterServerEngine configuration (extends MimicServerEngineConfig)
|
|
170
|
+
*/
|
|
171
|
+
export interface MimicClusterServerEngineConfig<
|
|
172
|
+
TSchema extends Primitive.AnyPrimitive,
|
|
173
|
+
> extends MimicServerEngineConfig<TSchema> {
|
|
174
|
+
/** Shard group name for cluster distribution (default: "mimic-documents") */
|
|
175
|
+
readonly shardGroup?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// =============================================================================
|
|
179
|
+
// Route Config Types
|
|
180
|
+
// =============================================================================
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* MimicServer route configuration
|
|
184
|
+
*/
|
|
185
|
+
export interface MimicServerRouteConfig {
|
|
186
|
+
/** WebSocket route path prefix (default: "/mimic") */
|
|
187
|
+
readonly path?: `/${string}`;
|
|
188
|
+
|
|
189
|
+
/** Heartbeat ping interval (default: 30 seconds) */
|
|
190
|
+
readonly heartbeatInterval?: DurationInput;
|
|
191
|
+
|
|
192
|
+
/** Heartbeat timeout - disconnect if no activity (default: 10 seconds) */
|
|
193
|
+
readonly heartbeatTimeout?: DurationInput;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// =============================================================================
|
|
197
|
+
// Internal Config with Defaults Applied
|
|
198
|
+
// =============================================================================
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Resolved engine configuration with all defaults applied
|
|
202
|
+
*/
|
|
203
|
+
export interface ResolvedConfig<TSchema extends Primitive.AnyPrimitive> {
|
|
204
|
+
readonly schema: TSchema;
|
|
205
|
+
readonly initial: Initial<TSchema> | undefined;
|
|
206
|
+
readonly presence: Presence.AnyPresence | undefined;
|
|
207
|
+
readonly maxIdleTime: Duration.Duration;
|
|
208
|
+
readonly maxTransactionHistory: number;
|
|
209
|
+
readonly snapshot: {
|
|
210
|
+
readonly interval: Duration.Duration;
|
|
211
|
+
readonly transactionThreshold: number;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Resolved route configuration with all defaults applied
|
|
217
|
+
*/
|
|
218
|
+
export interface ResolvedRouteConfig {
|
|
219
|
+
readonly path: string;
|
|
220
|
+
readonly heartbeatInterval: Duration.Duration;
|
|
221
|
+
readonly heartbeatTimeout: Duration.Duration;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Resolved cluster engine configuration with all defaults applied
|
|
226
|
+
*/
|
|
227
|
+
export interface ResolvedClusterConfig<TSchema extends Primitive.AnyPrimitive>
|
|
228
|
+
extends ResolvedConfig<TSchema> {
|
|
229
|
+
/** Shard group name for cluster distribution */
|
|
230
|
+
readonly shardGroup: string;
|
|
231
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,48 +1,82 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @voidhash/mimic-
|
|
2
|
+
* @voidhash/mimic-effect
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Server-side Effect integration for Mimic real-time collaboration.
|
|
5
5
|
*
|
|
6
|
-
* @since 0.0.
|
|
6
|
+
* @since 0.0.9
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
// =============================================================================
|
|
10
|
-
// Main
|
|
10
|
+
// Main Exports
|
|
11
11
|
// =============================================================================
|
|
12
12
|
|
|
13
|
-
export
|
|
13
|
+
export { MimicServerEngine, MimicServerEngineTag } from "./MimicServerEngine";
|
|
14
|
+
export { MimicClusterServerEngine } from "./MimicClusterServerEngine";
|
|
15
|
+
export { MimicServer, type MimicServerRouteConfig } from "./MimicServer";
|
|
16
|
+
export { ColdStorage, ColdStorageTag } from "./ColdStorage";
|
|
17
|
+
export { HotStorage, HotStorageTag } from "./HotStorage";
|
|
18
|
+
export { MimicAuthService, MimicAuthServiceTag } from "./MimicAuthService";
|
|
19
|
+
export { MimicMetrics } from "./Metrics";
|
|
14
20
|
|
|
15
21
|
// =============================================================================
|
|
16
|
-
//
|
|
22
|
+
// Types
|
|
17
23
|
// =============================================================================
|
|
18
24
|
|
|
19
|
-
export
|
|
20
|
-
|
|
25
|
+
export type {
|
|
26
|
+
Permission,
|
|
27
|
+
AuthContext,
|
|
28
|
+
StoredDocument,
|
|
29
|
+
WalEntry,
|
|
30
|
+
PresenceEntry,
|
|
31
|
+
PresenceSnapshot,
|
|
32
|
+
PresenceEvent,
|
|
33
|
+
PresenceUpdateEvent,
|
|
34
|
+
PresenceRemoveEvent,
|
|
35
|
+
DurationInput,
|
|
36
|
+
SnapshotConfig,
|
|
37
|
+
InitialContext,
|
|
38
|
+
InitialFn,
|
|
39
|
+
Initial,
|
|
40
|
+
MimicServerEngineConfig,
|
|
41
|
+
MimicClusterServerEngineConfig,
|
|
42
|
+
ResolvedConfig,
|
|
43
|
+
ResolvedClusterConfig,
|
|
44
|
+
ResolvedRouteConfig,
|
|
45
|
+
} from "./Types";
|
|
21
46
|
|
|
22
47
|
// =============================================================================
|
|
23
|
-
//
|
|
48
|
+
// Errors
|
|
24
49
|
// =============================================================================
|
|
25
50
|
|
|
26
|
-
export
|
|
27
|
-
|
|
51
|
+
export {
|
|
52
|
+
ColdStorageError,
|
|
53
|
+
HotStorageError,
|
|
54
|
+
AuthenticationError,
|
|
55
|
+
AuthorizationError,
|
|
56
|
+
MissingDocumentIdError,
|
|
57
|
+
MessageParseError,
|
|
58
|
+
TransactionRejectedError,
|
|
59
|
+
type MimicError,
|
|
60
|
+
} from "./Errors";
|
|
28
61
|
|
|
29
62
|
// =============================================================================
|
|
30
|
-
//
|
|
63
|
+
// Protocol (for custom implementations)
|
|
31
64
|
// =============================================================================
|
|
32
65
|
|
|
33
|
-
export * as
|
|
66
|
+
export * as Protocol from "./Protocol";
|
|
34
67
|
|
|
35
68
|
// =============================================================================
|
|
36
|
-
// Internal
|
|
69
|
+
// Internal Exports (for advanced use cases)
|
|
37
70
|
// =============================================================================
|
|
38
71
|
|
|
39
|
-
export
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Errors
|
|
46
|
-
// =============================================================================
|
|
72
|
+
export {
|
|
73
|
+
DocumentManager,
|
|
74
|
+
DocumentManagerTag,
|
|
75
|
+
DocumentManagerConfigTag,
|
|
76
|
+
type SubmitResult,
|
|
77
|
+
} from "./DocumentManager";
|
|
47
78
|
|
|
48
|
-
export
|
|
79
|
+
export {
|
|
80
|
+
PresenceManager,
|
|
81
|
+
PresenceManagerTag,
|
|
82
|
+
} from "./PresenceManager";
|