@voidhash/mimic-effect 0.0.1-alpha.1 → 0.0.1-alpha.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.
- package/.turbo/turbo-build.log +23 -0
- package/LICENSE.md +663 -0
- package/dist/chunk-C6wwvPpM.mjs +18 -0
- package/dist/index.cjs +1277 -0
- package/dist/index.d.cts +795 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +795 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1162 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +11 -11
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1277 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (all, symbols) => {
|
|
9
|
+
let target = {};
|
|
10
|
+
for (var name in all) {
|
|
11
|
+
__defProp(target, name, {
|
|
12
|
+
get: all[name],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
if (symbols) {
|
|
17
|
+
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
18
|
+
}
|
|
19
|
+
return target;
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
23
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
24
|
+
key = keys[i];
|
|
25
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
26
|
+
__defProp(to, key, {
|
|
27
|
+
get: ((k) => from[k]).bind(null, key),
|
|
28
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return to;
|
|
34
|
+
};
|
|
35
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
36
|
+
value: mod,
|
|
37
|
+
enumerable: true
|
|
38
|
+
}) : target, mod));
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
let effect_Effect = require("effect/Effect");
|
|
42
|
+
effect_Effect = __toESM(effect_Effect);
|
|
43
|
+
let effect_Layer = require("effect/Layer");
|
|
44
|
+
effect_Layer = __toESM(effect_Layer);
|
|
45
|
+
let effect_Context = require("effect/Context");
|
|
46
|
+
effect_Context = __toESM(effect_Context);
|
|
47
|
+
let _effect_platform_SocketServer = require("@effect/platform/SocketServer");
|
|
48
|
+
let effect_PubSub = require("effect/PubSub");
|
|
49
|
+
effect_PubSub = __toESM(effect_PubSub);
|
|
50
|
+
let effect_Ref = require("effect/Ref");
|
|
51
|
+
effect_Ref = __toESM(effect_Ref);
|
|
52
|
+
let effect_HashMap = require("effect/HashMap");
|
|
53
|
+
effect_HashMap = __toESM(effect_HashMap);
|
|
54
|
+
let effect_Stream = require("effect/Stream");
|
|
55
|
+
effect_Stream = __toESM(effect_Stream);
|
|
56
|
+
let _voidhash_mimic_server = require("@voidhash/mimic/server");
|
|
57
|
+
let effect_Duration = require("effect/Duration");
|
|
58
|
+
effect_Duration = __toESM(effect_Duration);
|
|
59
|
+
let effect_Data = require("effect/Data");
|
|
60
|
+
effect_Data = __toESM(effect_Data);
|
|
61
|
+
let effect_Fiber = require("effect/Fiber");
|
|
62
|
+
effect_Fiber = __toESM(effect_Fiber);
|
|
63
|
+
let _voidhash_mimic = require("@voidhash/mimic");
|
|
64
|
+
let _effect_platform = require("@effect/platform");
|
|
65
|
+
let effect_Schema = require("effect/Schema");
|
|
66
|
+
effect_Schema = __toESM(effect_Schema);
|
|
67
|
+
|
|
68
|
+
//#region src/MimicConfig.ts
|
|
69
|
+
/**
|
|
70
|
+
* @since 0.0.1
|
|
71
|
+
* Configuration types for the Mimic server.
|
|
72
|
+
*/
|
|
73
|
+
var MimicConfig_exports = /* @__PURE__ */ __export({
|
|
74
|
+
MimicServerConfigTag: () => MimicServerConfigTag,
|
|
75
|
+
layer: () => layer$7,
|
|
76
|
+
make: () => make$2
|
|
77
|
+
});
|
|
78
|
+
/**
|
|
79
|
+
* Create a MimicServerConfig from options.
|
|
80
|
+
*/
|
|
81
|
+
const make$2 = (options) => {
|
|
82
|
+
var _options$maxIdleTime, _options$maxTransacti, _options$heartbeatInt, _options$heartbeatTim;
|
|
83
|
+
return {
|
|
84
|
+
schema: options.schema,
|
|
85
|
+
maxIdleTime: effect_Duration.decode((_options$maxIdleTime = options.maxIdleTime) !== null && _options$maxIdleTime !== void 0 ? _options$maxIdleTime : "5 minutes"),
|
|
86
|
+
maxTransactionHistory: (_options$maxTransacti = options.maxTransactionHistory) !== null && _options$maxTransacti !== void 0 ? _options$maxTransacti : 1e3,
|
|
87
|
+
heartbeatInterval: effect_Duration.decode((_options$heartbeatInt = options.heartbeatInterval) !== null && _options$heartbeatInt !== void 0 ? _options$heartbeatInt : "30 seconds"),
|
|
88
|
+
heartbeatTimeout: effect_Duration.decode((_options$heartbeatTim = options.heartbeatTimeout) !== null && _options$heartbeatTim !== void 0 ? _options$heartbeatTim : "10 seconds"),
|
|
89
|
+
presence: options.presence
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Context tag for MimicServerConfig.
|
|
94
|
+
*/
|
|
95
|
+
var MimicServerConfigTag = class extends effect_Context.Tag("@voidhash/mimic-server-effect/MimicServerConfig")() {};
|
|
96
|
+
/**
|
|
97
|
+
* Create a Layer that provides MimicServerConfig.
|
|
98
|
+
*/
|
|
99
|
+
const layer$7 = (options) => effect_Layer.succeed(MimicServerConfigTag, make$2(options));
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/MimicDataStorage.ts
|
|
103
|
+
/**
|
|
104
|
+
* @since 0.0.1
|
|
105
|
+
* Data storage service interface for Mimic documents.
|
|
106
|
+
* Provides pluggable storage adapters with load/save hooks for data transformation.
|
|
107
|
+
*/
|
|
108
|
+
var MimicDataStorage_exports = /* @__PURE__ */ __export({
|
|
109
|
+
MimicDataStorageTag: () => MimicDataStorageTag,
|
|
110
|
+
StorageDeleteError: () => StorageDeleteError,
|
|
111
|
+
StorageLoadError: () => StorageLoadError,
|
|
112
|
+
StorageSaveError: () => StorageSaveError,
|
|
113
|
+
layer: () => layer$6,
|
|
114
|
+
layerEffect: () => layerEffect$1,
|
|
115
|
+
make: () => make$1
|
|
116
|
+
});
|
|
117
|
+
/**
|
|
118
|
+
* Error when loading a document from storage fails.
|
|
119
|
+
*/
|
|
120
|
+
var StorageLoadError = class extends effect_Data.TaggedError("StorageLoadError") {
|
|
121
|
+
get message() {
|
|
122
|
+
return `Failed to load document ${this.documentId}: ${String(this.cause)}`;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Error when saving a document to storage fails.
|
|
127
|
+
*/
|
|
128
|
+
var StorageSaveError = class extends effect_Data.TaggedError("StorageSaveError") {
|
|
129
|
+
get message() {
|
|
130
|
+
return `Failed to save document ${this.documentId}: ${String(this.cause)}`;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* Error when deleting a document from storage fails.
|
|
135
|
+
*/
|
|
136
|
+
var StorageDeleteError = class extends effect_Data.TaggedError("StorageDeleteError") {
|
|
137
|
+
get message() {
|
|
138
|
+
return `Failed to delete document ${this.documentId}: ${String(this.cause)}`;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* Context tag for MimicDataStorage service.
|
|
143
|
+
*/
|
|
144
|
+
var MimicDataStorageTag = class extends effect_Context.Tag("@voidhash/mimic-server-effect/MimicDataStorage")() {};
|
|
145
|
+
/**
|
|
146
|
+
* Create a MimicDataStorage layer from a storage implementation.
|
|
147
|
+
*/
|
|
148
|
+
const layer$6 = (storage) => effect_Layer.succeed(MimicDataStorageTag, storage);
|
|
149
|
+
/**
|
|
150
|
+
* Create a MimicDataStorage layer from an Effect that produces a storage implementation.
|
|
151
|
+
*/
|
|
152
|
+
const layerEffect$1 = (effect) => effect_Layer.effect(MimicDataStorageTag, effect);
|
|
153
|
+
/**
|
|
154
|
+
* Create a simple storage implementation with minimal configuration.
|
|
155
|
+
*/
|
|
156
|
+
const make$1 = (options) => {
|
|
157
|
+
var _options$delete, _options$onLoad, _options$onSave;
|
|
158
|
+
return {
|
|
159
|
+
load: options.load,
|
|
160
|
+
save: options.save,
|
|
161
|
+
delete: (_options$delete = options.delete) !== null && _options$delete !== void 0 ? _options$delete : (() => effect_Effect.void),
|
|
162
|
+
onLoad: (_options$onLoad = options.onLoad) !== null && _options$onLoad !== void 0 ? _options$onLoad : ((state) => effect_Effect.succeed(state)),
|
|
163
|
+
onSave: (_options$onSave = options.onSave) !== null && _options$onSave !== void 0 ? _options$onSave : ((state) => effect_Effect.succeed(state))
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/DocumentManager.ts
|
|
169
|
+
/**
|
|
170
|
+
* @since 0.0.1
|
|
171
|
+
* Document manager that handles multiple document instances.
|
|
172
|
+
*/
|
|
173
|
+
var DocumentManager_exports = /* @__PURE__ */ __export({
|
|
174
|
+
DocumentManagerTag: () => DocumentManagerTag,
|
|
175
|
+
layer: () => layer$5
|
|
176
|
+
});
|
|
177
|
+
/**
|
|
178
|
+
* Context tag for DocumentManager.
|
|
179
|
+
*/
|
|
180
|
+
var DocumentManagerTag = class extends effect_Context.Tag("@voidhash/mimic-server-effect/DocumentManager")() {};
|
|
181
|
+
/**
|
|
182
|
+
* Create the DocumentManager service.
|
|
183
|
+
*/
|
|
184
|
+
const makeDocumentManager = effect_Effect.gen(function* () {
|
|
185
|
+
const config = yield* MimicServerConfigTag;
|
|
186
|
+
const storage = yield* MimicDataStorageTag;
|
|
187
|
+
const documents = yield* effect_Ref.make(effect_HashMap.empty());
|
|
188
|
+
const getOrCreateDocument = (documentId) => effect_Effect.gen(function* () {
|
|
189
|
+
const current = yield* effect_Ref.get(documents);
|
|
190
|
+
const existing = effect_HashMap.get(current, documentId);
|
|
191
|
+
if (existing._tag === "Some") {
|
|
192
|
+
yield* effect_Ref.update(existing.value.refCount, (n) => n + 1);
|
|
193
|
+
return existing.value;
|
|
194
|
+
}
|
|
195
|
+
const rawState = yield* effect_Effect.catchAll(storage.load(documentId), () => effect_Effect.succeed(void 0));
|
|
196
|
+
const initialState = rawState !== void 0 ? yield* storage.onLoad(rawState) : void 0;
|
|
197
|
+
const pubsub = yield* effect_PubSub.unbounded();
|
|
198
|
+
const serverDocument = _voidhash_mimic_server.ServerDocument.make({
|
|
199
|
+
schema: config.schema,
|
|
200
|
+
initialState,
|
|
201
|
+
maxTransactionHistory: config.maxTransactionHistory,
|
|
202
|
+
onBroadcast: (transactionMessage) => {
|
|
203
|
+
const currentState = serverDocument.get();
|
|
204
|
+
effect_Effect.runFork(effect_Effect.gen(function* () {
|
|
205
|
+
if (currentState !== void 0) {
|
|
206
|
+
const transformedState = yield* storage.onSave(currentState);
|
|
207
|
+
yield* effect_Effect.catchAll(storage.save(documentId, transformedState), (error) => effect_Effect.logError("Failed to save document", error));
|
|
208
|
+
}
|
|
209
|
+
}));
|
|
210
|
+
effect_Effect.runSync(effect_PubSub.publish(pubsub, {
|
|
211
|
+
type: "transaction",
|
|
212
|
+
transaction: transactionMessage.transaction,
|
|
213
|
+
version: transactionMessage.version
|
|
214
|
+
}));
|
|
215
|
+
},
|
|
216
|
+
onRejection: (transactionId, reason) => {
|
|
217
|
+
effect_Effect.runSync(effect_PubSub.publish(pubsub, {
|
|
218
|
+
type: "error",
|
|
219
|
+
transactionId,
|
|
220
|
+
reason
|
|
221
|
+
}));
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
const instance = {
|
|
225
|
+
document: serverDocument,
|
|
226
|
+
pubsub,
|
|
227
|
+
refCount: yield* effect_Ref.make(1)
|
|
228
|
+
};
|
|
229
|
+
yield* effect_Ref.update(documents, (map) => effect_HashMap.set(map, documentId, instance));
|
|
230
|
+
return instance;
|
|
231
|
+
});
|
|
232
|
+
const submit = (documentId, transaction) => effect_Effect.gen(function* () {
|
|
233
|
+
return (yield* getOrCreateDocument(documentId)).document.submit(transaction);
|
|
234
|
+
});
|
|
235
|
+
const getSnapshot = (documentId) => effect_Effect.gen(function* () {
|
|
236
|
+
return (yield* getOrCreateDocument(documentId)).document.getSnapshot();
|
|
237
|
+
});
|
|
238
|
+
const subscribe = (documentId) => effect_Effect.gen(function* () {
|
|
239
|
+
const instance = yield* getOrCreateDocument(documentId);
|
|
240
|
+
const queue = yield* effect_PubSub.subscribe(instance.pubsub);
|
|
241
|
+
yield* effect_Effect.addFinalizer(() => effect_Effect.gen(function* () {
|
|
242
|
+
yield* effect_Ref.updateAndGet(instance.refCount, (n) => n - 1);
|
|
243
|
+
}));
|
|
244
|
+
return effect_Stream.fromQueue(queue);
|
|
245
|
+
});
|
|
246
|
+
return {
|
|
247
|
+
submit,
|
|
248
|
+
getSnapshot,
|
|
249
|
+
subscribe
|
|
250
|
+
};
|
|
251
|
+
});
|
|
252
|
+
/**
|
|
253
|
+
* Layer that provides DocumentManager.
|
|
254
|
+
* Requires MimicServerConfigTag and MimicDataStorageTag.
|
|
255
|
+
*/
|
|
256
|
+
const layer$5 = effect_Layer.effect(DocumentManagerTag, makeDocumentManager);
|
|
257
|
+
|
|
258
|
+
//#endregion
|
|
259
|
+
//#region src/MimicAuthService.ts
|
|
260
|
+
/**
|
|
261
|
+
* @since 0.0.1
|
|
262
|
+
* Authentication service interface for Mimic connections.
|
|
263
|
+
* Provides pluggable authentication adapters.
|
|
264
|
+
*/
|
|
265
|
+
var MimicAuthService_exports = /* @__PURE__ */ __export({
|
|
266
|
+
MimicAuthServiceTag: () => MimicAuthServiceTag,
|
|
267
|
+
layer: () => layer$4,
|
|
268
|
+
layerEffect: () => layerEffect,
|
|
269
|
+
layerService: () => layerService,
|
|
270
|
+
make: () => make,
|
|
271
|
+
makeEffect: () => makeEffect
|
|
272
|
+
});
|
|
273
|
+
/**
|
|
274
|
+
* Context tag for MimicAuthService service.
|
|
275
|
+
*/
|
|
276
|
+
var MimicAuthServiceTag = class extends effect_Context.Tag("@voidhash/mimic-server-effect/MimicAuthService")() {};
|
|
277
|
+
/**
|
|
278
|
+
* Create a MimicAuthService layer from an auth handler function.
|
|
279
|
+
*/
|
|
280
|
+
const layer$4 = (options) => effect_Layer.succeed(MimicAuthServiceTag, { authenticate: (token) => effect_Effect.promise(() => Promise.resolve(options.authHandler(token))) });
|
|
281
|
+
/**
|
|
282
|
+
* Create a MimicAuthService layer from an auth service implementation.
|
|
283
|
+
*/
|
|
284
|
+
const layerService = (service) => effect_Layer.succeed(MimicAuthServiceTag, service);
|
|
285
|
+
/**
|
|
286
|
+
* Create a MimicAuthService layer from an Effect that produces an auth service.
|
|
287
|
+
*/
|
|
288
|
+
const layerEffect = (effect) => effect_Layer.effect(MimicAuthServiceTag, effect);
|
|
289
|
+
/**
|
|
290
|
+
* Create an auth service from an auth handler function.
|
|
291
|
+
*/
|
|
292
|
+
const make = (authHandler) => ({ authenticate: (token) => effect_Effect.promise(() => Promise.resolve(authHandler(token))) });
|
|
293
|
+
/**
|
|
294
|
+
* Create an auth service from an Effect-based authenticate function.
|
|
295
|
+
*/
|
|
296
|
+
const makeEffect = (authenticate) => ({ authenticate });
|
|
297
|
+
|
|
298
|
+
//#endregion
|
|
299
|
+
//#region src/PresenceManager.ts
|
|
300
|
+
/**
|
|
301
|
+
* @since 0.0.1
|
|
302
|
+
* Presence manager for ephemeral per-connection state.
|
|
303
|
+
* Handles in-memory storage and broadcasting of presence updates.
|
|
304
|
+
*/
|
|
305
|
+
var PresenceManager_exports = /* @__PURE__ */ __export({
|
|
306
|
+
PresenceManagerTag: () => PresenceManagerTag,
|
|
307
|
+
layer: () => layer$3,
|
|
308
|
+
layerDefault: () => layerDefault$2
|
|
309
|
+
});
|
|
310
|
+
/**
|
|
311
|
+
* Context tag for PresenceManager.
|
|
312
|
+
*/
|
|
313
|
+
var PresenceManagerTag = class extends effect_Context.Tag("@voidhash/mimic-server-effect/PresenceManager")() {};
|
|
314
|
+
/**
|
|
315
|
+
* Create the PresenceManager service.
|
|
316
|
+
*/
|
|
317
|
+
const makePresenceManager = effect_Effect.gen(function* () {
|
|
318
|
+
const documents = yield* effect_Ref.make(effect_HashMap.empty());
|
|
319
|
+
const getOrCreateDocument = (documentId) => effect_Effect.gen(function* () {
|
|
320
|
+
const current = yield* effect_Ref.get(documents);
|
|
321
|
+
const existing = effect_HashMap.get(current, documentId);
|
|
322
|
+
if (existing._tag === "Some") return existing.value;
|
|
323
|
+
const docPresence = {
|
|
324
|
+
entries: yield* effect_Ref.make(effect_HashMap.empty()),
|
|
325
|
+
pubsub: yield* effect_PubSub.unbounded()
|
|
326
|
+
};
|
|
327
|
+
yield* effect_Ref.update(documents, (map) => effect_HashMap.set(map, documentId, docPresence));
|
|
328
|
+
return docPresence;
|
|
329
|
+
});
|
|
330
|
+
const getSnapshot = (documentId) => effect_Effect.gen(function* () {
|
|
331
|
+
const docPresence = yield* getOrCreateDocument(documentId);
|
|
332
|
+
const entriesMap = yield* effect_Ref.get(docPresence.entries);
|
|
333
|
+
const presences = {};
|
|
334
|
+
for (const [id, entry] of entriesMap) presences[id] = entry;
|
|
335
|
+
return { presences };
|
|
336
|
+
});
|
|
337
|
+
const set = (documentId, connectionId, entry) => effect_Effect.gen(function* () {
|
|
338
|
+
const docPresence = yield* getOrCreateDocument(documentId);
|
|
339
|
+
yield* effect_Ref.update(docPresence.entries, (map) => effect_HashMap.set(map, connectionId, entry));
|
|
340
|
+
yield* effect_PubSub.publish(docPresence.pubsub, {
|
|
341
|
+
type: "presence_update",
|
|
342
|
+
id: connectionId,
|
|
343
|
+
data: entry.data,
|
|
344
|
+
userId: entry.userId
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
const remove = (documentId, connectionId) => effect_Effect.gen(function* () {
|
|
348
|
+
const current = yield* effect_Ref.get(documents);
|
|
349
|
+
const existing = effect_HashMap.get(current, documentId);
|
|
350
|
+
if (existing._tag === "None") return;
|
|
351
|
+
const docPresence = existing.value;
|
|
352
|
+
const entries = yield* effect_Ref.get(docPresence.entries);
|
|
353
|
+
if (!effect_HashMap.has(entries, connectionId)) return;
|
|
354
|
+
yield* effect_Ref.update(docPresence.entries, (map) => effect_HashMap.remove(map, connectionId));
|
|
355
|
+
yield* effect_PubSub.publish(docPresence.pubsub, {
|
|
356
|
+
type: "presence_remove",
|
|
357
|
+
id: connectionId
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
const subscribe = (documentId) => effect_Effect.gen(function* () {
|
|
361
|
+
const docPresence = yield* getOrCreateDocument(documentId);
|
|
362
|
+
const queue = yield* effect_PubSub.subscribe(docPresence.pubsub);
|
|
363
|
+
return effect_Stream.fromQueue(queue);
|
|
364
|
+
});
|
|
365
|
+
return {
|
|
366
|
+
getSnapshot,
|
|
367
|
+
set,
|
|
368
|
+
remove,
|
|
369
|
+
subscribe
|
|
370
|
+
};
|
|
371
|
+
});
|
|
372
|
+
/**
|
|
373
|
+
* Layer that provides PresenceManager.
|
|
374
|
+
*/
|
|
375
|
+
const layer$3 = effect_Layer.effect(PresenceManagerTag, makePresenceManager);
|
|
376
|
+
/**
|
|
377
|
+
* Default layer that provides PresenceManager.
|
|
378
|
+
* Uses the default priority for layer composition.
|
|
379
|
+
*/
|
|
380
|
+
const layerDefault$2 = effect_Layer.effectDiscard(effect_Effect.succeed(void 0)).pipe(effect_Layer.provideMerge(layer$3));
|
|
381
|
+
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/errors.ts
|
|
384
|
+
/**
|
|
385
|
+
* @since 0.0.1
|
|
386
|
+
* Error types for the Mimic server.
|
|
387
|
+
*/
|
|
388
|
+
/**
|
|
389
|
+
* Error when a document type is not found in the schema registry.
|
|
390
|
+
*/
|
|
391
|
+
var DocumentTypeNotFoundError = class extends effect_Data.TaggedError("DocumentTypeNotFoundError") {
|
|
392
|
+
get message() {
|
|
393
|
+
return `Document type not found: ${this.documentType}`;
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
/**
|
|
397
|
+
* Error when a document is not found.
|
|
398
|
+
*/
|
|
399
|
+
var DocumentNotFoundError = class extends effect_Data.TaggedError("DocumentNotFoundError") {
|
|
400
|
+
get message() {
|
|
401
|
+
return `Document not found: ${this.documentId}`;
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
/**
|
|
405
|
+
* Error when authentication fails.
|
|
406
|
+
*/
|
|
407
|
+
var AuthenticationError = class extends effect_Data.TaggedError("AuthenticationError") {
|
|
408
|
+
get message() {
|
|
409
|
+
return `Authentication failed: ${this.reason}`;
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
/**
|
|
413
|
+
* Error when a transaction is rejected.
|
|
414
|
+
*/
|
|
415
|
+
var TransactionRejectedError = class extends effect_Data.TaggedError("TransactionRejectedError") {
|
|
416
|
+
get message() {
|
|
417
|
+
return `Transaction ${this.transactionId} rejected: ${this.reason}`;
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
/**
|
|
421
|
+
* Error when parsing a client message fails.
|
|
422
|
+
*/
|
|
423
|
+
var MessageParseError = class extends effect_Data.TaggedError("MessageParseError") {
|
|
424
|
+
get message() {
|
|
425
|
+
return `Failed to parse message: ${String(this.cause)}`;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
/**
|
|
429
|
+
* Error when the WebSocket connection is invalid.
|
|
430
|
+
*/
|
|
431
|
+
var InvalidConnectionError = class extends effect_Data.TaggedError("InvalidConnectionError") {
|
|
432
|
+
get message() {
|
|
433
|
+
return `Invalid connection: ${this.reason}`;
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
/**
|
|
437
|
+
* Error when the document ID is missing from the URL path.
|
|
438
|
+
*/
|
|
439
|
+
var MissingDocumentIdError = class extends effect_Data.TaggedError("MissingDocumentIdError") {
|
|
440
|
+
get message() {
|
|
441
|
+
return this.path ? `Document ID is required in the URL path: ${this.path}` : "Document ID is required in the URL path";
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
//#endregion
|
|
446
|
+
//#region \0@oxc-project+runtime@0.103.0/helpers/typeof.js
|
|
447
|
+
function _typeof(o) {
|
|
448
|
+
"@babel/helpers - typeof";
|
|
449
|
+
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o$1) {
|
|
450
|
+
return typeof o$1;
|
|
451
|
+
} : function(o$1) {
|
|
452
|
+
return o$1 && "function" == typeof Symbol && o$1.constructor === Symbol && o$1 !== Symbol.prototype ? "symbol" : typeof o$1;
|
|
453
|
+
}, _typeof(o);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
//#endregion
|
|
457
|
+
//#region \0@oxc-project+runtime@0.103.0/helpers/toPrimitive.js
|
|
458
|
+
function toPrimitive(t, r) {
|
|
459
|
+
if ("object" != _typeof(t) || !t) return t;
|
|
460
|
+
var e = t[Symbol.toPrimitive];
|
|
461
|
+
if (void 0 !== e) {
|
|
462
|
+
var i = e.call(t, r || "default");
|
|
463
|
+
if ("object" != _typeof(i)) return i;
|
|
464
|
+
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
465
|
+
}
|
|
466
|
+
return ("string" === r ? String : Number)(t);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
//#endregion
|
|
470
|
+
//#region \0@oxc-project+runtime@0.103.0/helpers/toPropertyKey.js
|
|
471
|
+
function toPropertyKey(t) {
|
|
472
|
+
var i = toPrimitive(t, "string");
|
|
473
|
+
return "symbol" == _typeof(i) ? i : i + "";
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
//#endregion
|
|
477
|
+
//#region \0@oxc-project+runtime@0.103.0/helpers/defineProperty.js
|
|
478
|
+
function _defineProperty(e, r, t) {
|
|
479
|
+
return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
|
|
480
|
+
value: t,
|
|
481
|
+
enumerable: !0,
|
|
482
|
+
configurable: !0,
|
|
483
|
+
writable: !0
|
|
484
|
+
}) : e[r] = t, e;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
//#endregion
|
|
488
|
+
//#region \0@oxc-project+runtime@0.103.0/helpers/objectSpread2.js
|
|
489
|
+
function ownKeys(e, r) {
|
|
490
|
+
var t = Object.keys(e);
|
|
491
|
+
if (Object.getOwnPropertySymbols) {
|
|
492
|
+
var o = Object.getOwnPropertySymbols(e);
|
|
493
|
+
r && (o = o.filter(function(r$1) {
|
|
494
|
+
return Object.getOwnPropertyDescriptor(e, r$1).enumerable;
|
|
495
|
+
})), t.push.apply(t, o);
|
|
496
|
+
}
|
|
497
|
+
return t;
|
|
498
|
+
}
|
|
499
|
+
function _objectSpread2(e) {
|
|
500
|
+
for (var r = 1; r < arguments.length; r++) {
|
|
501
|
+
var t = null != arguments[r] ? arguments[r] : {};
|
|
502
|
+
r % 2 ? ownKeys(Object(t), !0).forEach(function(r$1) {
|
|
503
|
+
_defineProperty(e, r$1, t[r$1]);
|
|
504
|
+
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r$1) {
|
|
505
|
+
Object.defineProperty(e, r$1, Object.getOwnPropertyDescriptor(t, r$1));
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
return e;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
//#endregion
|
|
512
|
+
//#region src/WebSocketHandler.ts
|
|
513
|
+
/**
|
|
514
|
+
* @since 0.0.1
|
|
515
|
+
* WebSocket connection handler using Effect Platform Socket API.
|
|
516
|
+
*/
|
|
517
|
+
var WebSocketHandler_exports = /* @__PURE__ */ __export({
|
|
518
|
+
extractDocumentId: () => extractDocumentId,
|
|
519
|
+
handleConnection: () => handleConnection,
|
|
520
|
+
makeHandler: () => makeHandler
|
|
521
|
+
});
|
|
522
|
+
/**
|
|
523
|
+
* Extract document ID from URL path.
|
|
524
|
+
* Expected format: /doc/{documentId}
|
|
525
|
+
*/
|
|
526
|
+
const extractDocumentId = (path) => {
|
|
527
|
+
const parts = path.replace(/^\/+/, "").split("/");
|
|
528
|
+
const docIndex = parts.lastIndexOf("doc");
|
|
529
|
+
const part = parts[docIndex + 1];
|
|
530
|
+
if (docIndex !== -1 && part) return effect_Effect.succeed(decodeURIComponent(part));
|
|
531
|
+
return effect_Effect.fail(new MissingDocumentIdError({}));
|
|
532
|
+
};
|
|
533
|
+
/**
|
|
534
|
+
* Decodes an encoded client message from the wire format.
|
|
535
|
+
*/
|
|
536
|
+
const decodeClientMessage = (encoded) => {
|
|
537
|
+
if (encoded.type === "submit") return {
|
|
538
|
+
type: "submit",
|
|
539
|
+
transaction: _voidhash_mimic.Transaction.decode(encoded.transaction)
|
|
540
|
+
};
|
|
541
|
+
return encoded;
|
|
542
|
+
};
|
|
543
|
+
/**
|
|
544
|
+
* Encodes a server message for the wire format.
|
|
545
|
+
*/
|
|
546
|
+
const encodeServerMessageForWire = (message) => {
|
|
547
|
+
if (message.type === "transaction") return {
|
|
548
|
+
type: "transaction",
|
|
549
|
+
transaction: _voidhash_mimic.Transaction.encode(message.transaction),
|
|
550
|
+
version: message.version
|
|
551
|
+
};
|
|
552
|
+
return message;
|
|
553
|
+
};
|
|
554
|
+
const parseClientMessage = (data) => effect_Effect.try({
|
|
555
|
+
try: () => {
|
|
556
|
+
const text = typeof data === "string" ? data : new TextDecoder().decode(data);
|
|
557
|
+
return decodeClientMessage(JSON.parse(text));
|
|
558
|
+
},
|
|
559
|
+
catch: (cause) => new MessageParseError({ cause })
|
|
560
|
+
});
|
|
561
|
+
const encodeServerMessage = (message) => JSON.stringify(encodeServerMessageForWire(message));
|
|
562
|
+
/**
|
|
563
|
+
* Handle a WebSocket connection for a document.
|
|
564
|
+
*
|
|
565
|
+
* @param socket - The Effect Platform Socket
|
|
566
|
+
* @param path - The URL path (e.g., "/doc/my-document-id")
|
|
567
|
+
* @returns An Effect that handles the connection lifecycle
|
|
568
|
+
*/
|
|
569
|
+
const handleConnection = (socket, path) => effect_Effect.gen(function* () {
|
|
570
|
+
const config = yield* MimicServerConfigTag;
|
|
571
|
+
const authService = yield* MimicAuthServiceTag;
|
|
572
|
+
const documentManager = yield* DocumentManagerTag;
|
|
573
|
+
const presenceManager = yield* PresenceManagerTag;
|
|
574
|
+
const documentId = yield* extractDocumentId(path);
|
|
575
|
+
const connectionId = crypto.randomUUID();
|
|
576
|
+
let state = {
|
|
577
|
+
documentId,
|
|
578
|
+
connectionId,
|
|
579
|
+
authenticated: false
|
|
580
|
+
};
|
|
581
|
+
let hasPresence = false;
|
|
582
|
+
const write = yield* socket.writer;
|
|
583
|
+
const sendMessage = (message) => write(encodeServerMessage(message));
|
|
584
|
+
const sendPresenceSnapshot = effect_Effect.gen(function* () {
|
|
585
|
+
if (!config.presence) return;
|
|
586
|
+
yield* sendMessage({
|
|
587
|
+
type: "presence_snapshot",
|
|
588
|
+
selfId: connectionId,
|
|
589
|
+
presences: (yield* presenceManager.getSnapshot(documentId)).presences
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
const handleAuth = (token) => effect_Effect.gen(function* () {
|
|
593
|
+
const result = yield* authService.authenticate(token);
|
|
594
|
+
if (result.success) {
|
|
595
|
+
state = _objectSpread2(_objectSpread2({}, state), {}, {
|
|
596
|
+
authenticated: true,
|
|
597
|
+
userId: result.userId
|
|
598
|
+
});
|
|
599
|
+
yield* sendMessage({
|
|
600
|
+
type: "auth_result",
|
|
601
|
+
success: true
|
|
602
|
+
});
|
|
603
|
+
yield* sendPresenceSnapshot;
|
|
604
|
+
} else yield* sendMessage({
|
|
605
|
+
type: "auth_result",
|
|
606
|
+
success: false,
|
|
607
|
+
error: result.error
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
const handlePresenceSet = (data) => effect_Effect.gen(function* () {
|
|
611
|
+
if (!state.authenticated) return;
|
|
612
|
+
if (!config.presence) return;
|
|
613
|
+
const validated = _voidhash_mimic.Presence.validateSafe(config.presence, data);
|
|
614
|
+
if (validated === void 0) {
|
|
615
|
+
yield* effect_Effect.logWarning("Invalid presence data received", {
|
|
616
|
+
connectionId,
|
|
617
|
+
data
|
|
618
|
+
});
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
yield* presenceManager.set(documentId, connectionId, {
|
|
622
|
+
data: validated,
|
|
623
|
+
userId: state.userId
|
|
624
|
+
});
|
|
625
|
+
hasPresence = true;
|
|
626
|
+
});
|
|
627
|
+
const handlePresenceClear = effect_Effect.gen(function* () {
|
|
628
|
+
if (!state.authenticated) return;
|
|
629
|
+
if (!config.presence) return;
|
|
630
|
+
yield* presenceManager.remove(documentId, connectionId);
|
|
631
|
+
hasPresence = false;
|
|
632
|
+
});
|
|
633
|
+
const handleMessage = (message) => effect_Effect.gen(function* () {
|
|
634
|
+
switch (message.type) {
|
|
635
|
+
case "auth":
|
|
636
|
+
yield* handleAuth(message.token);
|
|
637
|
+
break;
|
|
638
|
+
case "ping":
|
|
639
|
+
yield* sendMessage({ type: "pong" });
|
|
640
|
+
break;
|
|
641
|
+
case "submit":
|
|
642
|
+
if (!state.authenticated) {
|
|
643
|
+
yield* sendMessage({
|
|
644
|
+
type: "error",
|
|
645
|
+
transactionId: message.transaction.id,
|
|
646
|
+
reason: "Not authenticated"
|
|
647
|
+
});
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
const submitResult = yield* documentManager.submit(documentId, message.transaction);
|
|
651
|
+
if (!submitResult.success) yield* sendMessage({
|
|
652
|
+
type: "error",
|
|
653
|
+
transactionId: message.transaction.id,
|
|
654
|
+
reason: submitResult.reason
|
|
655
|
+
});
|
|
656
|
+
break;
|
|
657
|
+
case "request_snapshot":
|
|
658
|
+
if (!state.authenticated) return;
|
|
659
|
+
yield* sendMessage(yield* effect_Effect.catchAll(documentManager.getSnapshot(documentId), () => effect_Effect.succeed({
|
|
660
|
+
type: "snapshot",
|
|
661
|
+
state: null,
|
|
662
|
+
version: 0
|
|
663
|
+
})));
|
|
664
|
+
break;
|
|
665
|
+
case "presence_set":
|
|
666
|
+
yield* handlePresenceSet(message.data);
|
|
667
|
+
break;
|
|
668
|
+
case "presence_clear":
|
|
669
|
+
yield* handlePresenceClear;
|
|
670
|
+
break;
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
const subscribeFiber = yield* effect_Effect.fork(effect_Effect.gen(function* () {
|
|
674
|
+
while (!state.authenticated) yield* effect_Effect.sleep(effect_Duration.millis(100));
|
|
675
|
+
const broadcastStream = yield* effect_Effect.catchAll(documentManager.subscribe(documentId), () => effect_Effect.succeed(effect_Stream.empty));
|
|
676
|
+
yield* effect_Stream.runForEach(broadcastStream, (broadcast) => sendMessage(broadcast));
|
|
677
|
+
}).pipe(effect_Effect.scoped));
|
|
678
|
+
const presenceFiber = yield* effect_Effect.fork(effect_Effect.gen(function* () {
|
|
679
|
+
if (!config.presence) return;
|
|
680
|
+
while (!state.authenticated) yield* effect_Effect.sleep(effect_Duration.millis(100));
|
|
681
|
+
const presenceStream = yield* presenceManager.subscribe(documentId);
|
|
682
|
+
yield* effect_Stream.runForEach(presenceStream, (event) => effect_Effect.gen(function* () {
|
|
683
|
+
if (event.id === connectionId) return;
|
|
684
|
+
if (event.type === "presence_update") yield* sendMessage({
|
|
685
|
+
type: "presence_update",
|
|
686
|
+
id: event.id,
|
|
687
|
+
data: event.data,
|
|
688
|
+
userId: event.userId
|
|
689
|
+
});
|
|
690
|
+
else if (event.type === "presence_remove") yield* sendMessage({
|
|
691
|
+
type: "presence_remove",
|
|
692
|
+
id: event.id
|
|
693
|
+
});
|
|
694
|
+
}));
|
|
695
|
+
}).pipe(effect_Effect.scoped));
|
|
696
|
+
yield* effect_Effect.addFinalizer(() => effect_Effect.gen(function* () {
|
|
697
|
+
yield* effect_Fiber.interrupt(subscribeFiber);
|
|
698
|
+
yield* effect_Fiber.interrupt(presenceFiber);
|
|
699
|
+
if (hasPresence && config.presence) yield* presenceManager.remove(documentId, connectionId);
|
|
700
|
+
}));
|
|
701
|
+
yield* socket.runRaw((data) => effect_Effect.gen(function* () {
|
|
702
|
+
yield* handleMessage(yield* parseClientMessage(data));
|
|
703
|
+
}).pipe(effect_Effect.catchAll((error) => effect_Effect.logError("Message handling error", error))));
|
|
704
|
+
});
|
|
705
|
+
/**
|
|
706
|
+
* Create a handler function for the WebSocket server.
|
|
707
|
+
* Returns a function that takes a socket and document ID.
|
|
708
|
+
*/
|
|
709
|
+
const makeHandler = effect_Effect.gen(function* () {
|
|
710
|
+
const config = yield* MimicServerConfigTag;
|
|
711
|
+
const authService = yield* MimicAuthServiceTag;
|
|
712
|
+
const documentManager = yield* DocumentManagerTag;
|
|
713
|
+
const presenceManager = yield* PresenceManagerTag;
|
|
714
|
+
return (socket, documentId) => handleConnectionWithDocumentId(socket, documentId).pipe(effect_Effect.provideService(MimicServerConfigTag, config), effect_Effect.provideService(MimicAuthServiceTag, authService), effect_Effect.provideService(DocumentManagerTag, documentManager), effect_Effect.provideService(PresenceManagerTag, presenceManager), effect_Effect.scoped);
|
|
715
|
+
});
|
|
716
|
+
/**
|
|
717
|
+
* Handle a WebSocket connection for a document (using document ID directly).
|
|
718
|
+
*/
|
|
719
|
+
const handleConnectionWithDocumentId = (socket, documentId) => effect_Effect.gen(function* () {
|
|
720
|
+
const config = yield* MimicServerConfigTag;
|
|
721
|
+
const authService = yield* MimicAuthServiceTag;
|
|
722
|
+
const documentManager = yield* DocumentManagerTag;
|
|
723
|
+
const presenceManager = yield* PresenceManagerTag;
|
|
724
|
+
const connectionId = crypto.randomUUID();
|
|
725
|
+
let state = {
|
|
726
|
+
documentId,
|
|
727
|
+
connectionId,
|
|
728
|
+
authenticated: false
|
|
729
|
+
};
|
|
730
|
+
let hasPresence = false;
|
|
731
|
+
const write = yield* socket.writer;
|
|
732
|
+
const sendMessage = (message) => write(encodeServerMessage(message));
|
|
733
|
+
const sendPresenceSnapshot = effect_Effect.gen(function* () {
|
|
734
|
+
if (!config.presence) return;
|
|
735
|
+
yield* sendMessage({
|
|
736
|
+
type: "presence_snapshot",
|
|
737
|
+
selfId: connectionId,
|
|
738
|
+
presences: (yield* presenceManager.getSnapshot(documentId)).presences
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
const handleAuth = (token) => effect_Effect.gen(function* () {
|
|
742
|
+
const result = yield* authService.authenticate(token);
|
|
743
|
+
if (result.success) {
|
|
744
|
+
state = _objectSpread2(_objectSpread2({}, state), {}, {
|
|
745
|
+
authenticated: true,
|
|
746
|
+
userId: result.userId
|
|
747
|
+
});
|
|
748
|
+
yield* sendMessage({
|
|
749
|
+
type: "auth_result",
|
|
750
|
+
success: true
|
|
751
|
+
});
|
|
752
|
+
yield* sendPresenceSnapshot;
|
|
753
|
+
} else yield* sendMessage({
|
|
754
|
+
type: "auth_result",
|
|
755
|
+
success: false,
|
|
756
|
+
error: result.error
|
|
757
|
+
});
|
|
758
|
+
});
|
|
759
|
+
const handlePresenceSet = (data) => effect_Effect.gen(function* () {
|
|
760
|
+
if (!state.authenticated) return;
|
|
761
|
+
if (!config.presence) return;
|
|
762
|
+
const validated = _voidhash_mimic.Presence.validateSafe(config.presence, data);
|
|
763
|
+
if (validated === void 0) {
|
|
764
|
+
yield* effect_Effect.logWarning("Invalid presence data received", {
|
|
765
|
+
connectionId,
|
|
766
|
+
data
|
|
767
|
+
});
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
yield* presenceManager.set(documentId, connectionId, {
|
|
771
|
+
data: validated,
|
|
772
|
+
userId: state.userId
|
|
773
|
+
});
|
|
774
|
+
hasPresence = true;
|
|
775
|
+
});
|
|
776
|
+
const handlePresenceClear = effect_Effect.gen(function* () {
|
|
777
|
+
if (!state.authenticated) return;
|
|
778
|
+
if (!config.presence) return;
|
|
779
|
+
yield* presenceManager.remove(documentId, connectionId);
|
|
780
|
+
hasPresence = false;
|
|
781
|
+
});
|
|
782
|
+
const handleMessage = (message) => effect_Effect.gen(function* () {
|
|
783
|
+
switch (message.type) {
|
|
784
|
+
case "auth":
|
|
785
|
+
yield* handleAuth(message.token);
|
|
786
|
+
break;
|
|
787
|
+
case "ping":
|
|
788
|
+
yield* sendMessage({ type: "pong" });
|
|
789
|
+
break;
|
|
790
|
+
case "submit":
|
|
791
|
+
if (!state.authenticated) {
|
|
792
|
+
yield* sendMessage({
|
|
793
|
+
type: "error",
|
|
794
|
+
transactionId: message.transaction.id,
|
|
795
|
+
reason: "Not authenticated"
|
|
796
|
+
});
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
const submitResult = yield* documentManager.submit(documentId, message.transaction);
|
|
800
|
+
if (!submitResult.success) yield* sendMessage({
|
|
801
|
+
type: "error",
|
|
802
|
+
transactionId: message.transaction.id,
|
|
803
|
+
reason: submitResult.reason
|
|
804
|
+
});
|
|
805
|
+
break;
|
|
806
|
+
case "request_snapshot":
|
|
807
|
+
if (!state.authenticated) return;
|
|
808
|
+
yield* sendMessage(yield* documentManager.getSnapshot(documentId));
|
|
809
|
+
break;
|
|
810
|
+
case "presence_set":
|
|
811
|
+
yield* handlePresenceSet(message.data);
|
|
812
|
+
break;
|
|
813
|
+
case "presence_clear":
|
|
814
|
+
yield* handlePresenceClear;
|
|
815
|
+
break;
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
const subscribeFiber = yield* effect_Effect.fork(effect_Effect.gen(function* () {
|
|
819
|
+
while (!state.authenticated) yield* effect_Effect.sleep(effect_Duration.millis(100));
|
|
820
|
+
const broadcastStream = yield* documentManager.subscribe(documentId);
|
|
821
|
+
yield* effect_Stream.runForEach(broadcastStream, (broadcast) => sendMessage(broadcast));
|
|
822
|
+
}).pipe(effect_Effect.scoped));
|
|
823
|
+
const presenceFiber = yield* effect_Effect.fork(effect_Effect.gen(function* () {
|
|
824
|
+
if (!config.presence) return;
|
|
825
|
+
while (!state.authenticated) yield* effect_Effect.sleep(effect_Duration.millis(100));
|
|
826
|
+
const presenceStream = yield* presenceManager.subscribe(documentId);
|
|
827
|
+
yield* effect_Stream.runForEach(presenceStream, (event) => effect_Effect.gen(function* () {
|
|
828
|
+
if (event.id === connectionId) return;
|
|
829
|
+
if (event.type === "presence_update") yield* sendMessage({
|
|
830
|
+
type: "presence_update",
|
|
831
|
+
id: event.id,
|
|
832
|
+
data: event.data,
|
|
833
|
+
userId: event.userId
|
|
834
|
+
});
|
|
835
|
+
else if (event.type === "presence_remove") yield* sendMessage({
|
|
836
|
+
type: "presence_remove",
|
|
837
|
+
id: event.id
|
|
838
|
+
});
|
|
839
|
+
}));
|
|
840
|
+
}).pipe(effect_Effect.scoped));
|
|
841
|
+
yield* effect_Effect.addFinalizer(() => effect_Effect.gen(function* () {
|
|
842
|
+
yield* effect_Fiber.interrupt(subscribeFiber);
|
|
843
|
+
yield* effect_Fiber.interrupt(presenceFiber);
|
|
844
|
+
if (hasPresence && config.presence) yield* presenceManager.remove(documentId, connectionId);
|
|
845
|
+
}));
|
|
846
|
+
yield* socket.runRaw((data) => effect_Effect.gen(function* () {
|
|
847
|
+
yield* handleMessage(yield* parseClientMessage(data));
|
|
848
|
+
}).pipe(effect_Effect.catchAll((error) => effect_Effect.logError("Message handling error", error))));
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
//#endregion
|
|
852
|
+
//#region src/storage/InMemoryDataStorage.ts
|
|
853
|
+
/**
|
|
854
|
+
* @since 0.0.1
|
|
855
|
+
* In-memory data storage implementation for Mimic documents.
|
|
856
|
+
* Provides ephemeral storage - data is lost when the server restarts.
|
|
857
|
+
*/
|
|
858
|
+
var InMemoryDataStorage_exports = /* @__PURE__ */ __export({
|
|
859
|
+
layer: () => layer$2,
|
|
860
|
+
layerDefault: () => layerDefault$1
|
|
861
|
+
});
|
|
862
|
+
/**
|
|
863
|
+
* Create an in-memory storage service.
|
|
864
|
+
* Uses a HashMap to store documents in memory.
|
|
865
|
+
*/
|
|
866
|
+
const makeInMemoryStorage = effect_Effect.gen(function* () {
|
|
867
|
+
const store = yield* effect_Ref.make(effect_HashMap.empty());
|
|
868
|
+
return {
|
|
869
|
+
load: (documentId) => effect_Effect.gen(function* () {
|
|
870
|
+
const current = yield* effect_Ref.get(store);
|
|
871
|
+
const result = effect_HashMap.get(current, documentId);
|
|
872
|
+
return result._tag === "Some" ? result.value : void 0;
|
|
873
|
+
}),
|
|
874
|
+
save: (documentId, state) => effect_Ref.update(store, (map) => effect_HashMap.set(map, documentId, state)),
|
|
875
|
+
delete: (documentId) => effect_Ref.update(store, (map) => effect_HashMap.remove(map, documentId)),
|
|
876
|
+
onLoad: (state) => effect_Effect.succeed(state),
|
|
877
|
+
onSave: (state) => effect_Effect.succeed(state)
|
|
878
|
+
};
|
|
879
|
+
});
|
|
880
|
+
/**
|
|
881
|
+
* Layer that provides in-memory data storage.
|
|
882
|
+
* This is the default storage implementation - ephemeral and non-persistent.
|
|
883
|
+
*/
|
|
884
|
+
const layer$2 = effect_Layer.effect(MimicDataStorageTag, makeInMemoryStorage);
|
|
885
|
+
/**
|
|
886
|
+
* Default layer alias for convenience.
|
|
887
|
+
*/
|
|
888
|
+
const layerDefault$1 = layer$2;
|
|
889
|
+
|
|
890
|
+
//#endregion
|
|
891
|
+
//#region src/auth/NoAuth.ts
|
|
892
|
+
/**
|
|
893
|
+
* @since 0.0.1
|
|
894
|
+
* No authentication implementation for Mimic connections.
|
|
895
|
+
* All connections are automatically authenticated (open access).
|
|
896
|
+
*/
|
|
897
|
+
var NoAuth_exports = /* @__PURE__ */ __export({
|
|
898
|
+
layer: () => layer$1,
|
|
899
|
+
layerDefault: () => layerDefault
|
|
900
|
+
});
|
|
901
|
+
/**
|
|
902
|
+
* Authentication service that auto-succeeds all authentication requests.
|
|
903
|
+
* Use this for development or when authentication is handled externally.
|
|
904
|
+
*/
|
|
905
|
+
const noAuthService = { authenticate: (_token) => effect_Effect.succeed({ success: true }) };
|
|
906
|
+
/**
|
|
907
|
+
* Layer that provides no authentication (open access).
|
|
908
|
+
* All connections are automatically authenticated.
|
|
909
|
+
*
|
|
910
|
+
* WARNING: Only use this for development or when authentication
|
|
911
|
+
* is handled at a different layer (e.g., API gateway, reverse proxy).
|
|
912
|
+
*/
|
|
913
|
+
const layer$1 = effect_Layer.succeed(MimicAuthServiceTag, noAuthService);
|
|
914
|
+
/**
|
|
915
|
+
* Default layer alias for convenience.
|
|
916
|
+
*/
|
|
917
|
+
const layerDefault = layer$1;
|
|
918
|
+
|
|
919
|
+
//#endregion
|
|
920
|
+
//#region src/MimicServer.ts
|
|
921
|
+
/**
|
|
922
|
+
* @since 0.0.1
|
|
923
|
+
* Mimic server layer composition.
|
|
924
|
+
*/
|
|
925
|
+
var MimicServer_exports = /* @__PURE__ */ __export({
|
|
926
|
+
MimicWebSocketHandler: () => MimicWebSocketHandler,
|
|
927
|
+
documentManagerLayer: () => documentManagerLayer,
|
|
928
|
+
handlerLayer: () => handlerLayer,
|
|
929
|
+
layer: () => layer,
|
|
930
|
+
layerHttpLayerRouter: () => layerHttpLayerRouter,
|
|
931
|
+
run: () => run
|
|
932
|
+
});
|
|
933
|
+
/**
|
|
934
|
+
* Tag for the WebSocket handler function.
|
|
935
|
+
*/
|
|
936
|
+
var MimicWebSocketHandler = class extends effect_Context.Tag("@voidhash/mimic-server-effect/MimicWebSocketHandler")() {};
|
|
937
|
+
/**
|
|
938
|
+
* Create a Mimic WebSocket handler layer.
|
|
939
|
+
*
|
|
940
|
+
* This layer provides a handler function that can be used with any WebSocket server
|
|
941
|
+
* implementation. The handler takes a socket and document ID and manages the
|
|
942
|
+
* document synchronization.
|
|
943
|
+
*
|
|
944
|
+
* By default, uses in-memory storage and no authentication.
|
|
945
|
+
* Override these by providing MimicDataStorage and MimicAuthService layers.
|
|
946
|
+
*
|
|
947
|
+
* @example
|
|
948
|
+
* ```typescript
|
|
949
|
+
* import { MimicServer, MimicAuthService } from "@voidhash/mimic-effect";
|
|
950
|
+
* import { Primitive } from "@voidhash/mimic";
|
|
951
|
+
*
|
|
952
|
+
* const TodoSchema = Primitive.Struct({
|
|
953
|
+
* title: Primitive.String(),
|
|
954
|
+
* completed: Primitive.Boolean(),
|
|
955
|
+
* });
|
|
956
|
+
*
|
|
957
|
+
* // Create the handler layer with defaults
|
|
958
|
+
* const HandlerLayer = MimicServer.layer({
|
|
959
|
+
* basePath: "/mimic/todo",
|
|
960
|
+
* schema: TodoSchema
|
|
961
|
+
* });
|
|
962
|
+
*
|
|
963
|
+
* // Or with custom auth
|
|
964
|
+
* const HandlerLayerWithAuth = MimicServer.layer({
|
|
965
|
+
* basePath: "/mimic/todo",
|
|
966
|
+
* schema: TodoSchema
|
|
967
|
+
* }).pipe(
|
|
968
|
+
* Layer.provideMerge(MimicAuthService.layer({
|
|
969
|
+
* authHandler: (token) => ({ success: true, userId: "user-123" })
|
|
970
|
+
* }))
|
|
971
|
+
* );
|
|
972
|
+
* ```
|
|
973
|
+
*/
|
|
974
|
+
const layer = (options) => {
|
|
975
|
+
const configLayer = layer$7({
|
|
976
|
+
schema: options.schema,
|
|
977
|
+
maxTransactionHistory: options.maxTransactionHistory,
|
|
978
|
+
presence: options.presence
|
|
979
|
+
});
|
|
980
|
+
return effect_Layer.merge(effect_Layer.effect(MimicWebSocketHandler, makeHandler).pipe(effect_Layer.provide(layer$5), effect_Layer.provide(layer$3), effect_Layer.provide(configLayer)), layer$5.pipe(effect_Layer.provide(configLayer))).pipe(effect_Layer.provide(layerDefault$1), effect_Layer.provide(layerDefault));
|
|
981
|
+
};
|
|
982
|
+
/**
|
|
983
|
+
* Create the Mimic server handler layer.
|
|
984
|
+
* This layer provides the WebSocket handler that can be used with any WebSocket server.
|
|
985
|
+
*
|
|
986
|
+
* @example
|
|
987
|
+
* ```typescript
|
|
988
|
+
* import { MimicServer } from "@voidhash/mimic-server-effect";
|
|
989
|
+
* import { SocketServer } from "@effect/platform/SocketServer";
|
|
990
|
+
* import { Primitive } from "@voidhash/mimic";
|
|
991
|
+
*
|
|
992
|
+
* // Define your document schema
|
|
993
|
+
* const TodoSchema = Primitive.Struct({
|
|
994
|
+
* title: Primitive.String(),
|
|
995
|
+
* completed: Primitive.Boolean(),
|
|
996
|
+
* });
|
|
997
|
+
*
|
|
998
|
+
* // Create the server layer
|
|
999
|
+
* const serverLayer = MimicServer.handlerLayer({
|
|
1000
|
+
* schema: TodoSchema,
|
|
1001
|
+
* });
|
|
1002
|
+
*
|
|
1003
|
+
* // Run with your socket server
|
|
1004
|
+
* Effect.gen(function* () {
|
|
1005
|
+
* const handler = yield* MimicServer.MimicWebSocketHandler;
|
|
1006
|
+
* const server = yield* SocketServer;
|
|
1007
|
+
*
|
|
1008
|
+
* yield* server.run((socket) =>
|
|
1009
|
+
* // Extract document ID from request and call handler
|
|
1010
|
+
* handler(socket, "my-document-id")
|
|
1011
|
+
* );
|
|
1012
|
+
* }).pipe(
|
|
1013
|
+
* Effect.provide(serverLayer),
|
|
1014
|
+
* Effect.provide(YourSocketServerLayer),
|
|
1015
|
+
* );
|
|
1016
|
+
* ```
|
|
1017
|
+
*/
|
|
1018
|
+
const handlerLayer = (options) => effect_Layer.effect(MimicWebSocketHandler, makeHandler).pipe(effect_Layer.provide(layer$5), effect_Layer.provide(layer$3), effect_Layer.provide(layer$7(options)), effect_Layer.provide(layerDefault$1), effect_Layer.provide(layerDefault));
|
|
1019
|
+
/**
|
|
1020
|
+
* Create the document manager layer.
|
|
1021
|
+
*/
|
|
1022
|
+
const documentManagerLayer = (options) => layer$5.pipe(effect_Layer.provide(layer$7(options)), effect_Layer.provide(layerDefault$1), effect_Layer.provide(layerDefault));
|
|
1023
|
+
/**
|
|
1024
|
+
* Run a Mimic WebSocket server with the provided handler.
|
|
1025
|
+
*
|
|
1026
|
+
* This is a helper that:
|
|
1027
|
+
* 1. Gets the WebSocket handler from context
|
|
1028
|
+
* 2. Runs the socket server with the handler
|
|
1029
|
+
*
|
|
1030
|
+
* Note: The document ID extraction from socket is implementation-specific.
|
|
1031
|
+
* You may need to customize this based on your socket server.
|
|
1032
|
+
*/
|
|
1033
|
+
const run = (extractDocumentId$1) => effect_Effect.gen(function* () {
|
|
1034
|
+
const handler = yield* MimicWebSocketHandler;
|
|
1035
|
+
yield* (yield* _effect_platform_SocketServer.SocketServer).run((socket) => effect_Effect.gen(function* () {
|
|
1036
|
+
yield* handler(socket, yield* extractDocumentId$1(socket));
|
|
1037
|
+
}).pipe(effect_Effect.catchAll((error) => effect_Effect.logError("Connection error", error))));
|
|
1038
|
+
});
|
|
1039
|
+
/**
|
|
1040
|
+
* Create the HTTP handler effect for WebSocket upgrade.
|
|
1041
|
+
* This handler:
|
|
1042
|
+
* 1. Extracts the document ID from the URL path
|
|
1043
|
+
* 2. Upgrades the HTTP connection to WebSocket
|
|
1044
|
+
* 3. Delegates to the WebSocketHandler for document sync
|
|
1045
|
+
*/
|
|
1046
|
+
const makeMimicHandler = effect_Effect.gen(function* () {
|
|
1047
|
+
const config = yield* MimicServerConfigTag;
|
|
1048
|
+
const authService = yield* MimicAuthServiceTag;
|
|
1049
|
+
const documentManager = yield* DocumentManagerTag;
|
|
1050
|
+
const presenceManager = yield* PresenceManagerTag;
|
|
1051
|
+
return effect_Effect.gen(function* () {
|
|
1052
|
+
const request = yield* _effect_platform.HttpServerRequest.HttpServerRequest;
|
|
1053
|
+
yield* extractDocumentId(request.url);
|
|
1054
|
+
const socket = yield* request.upgrade;
|
|
1055
|
+
yield* handleConnection(socket, request.url).pipe(effect_Effect.provideService(MimicServerConfigTag, config), effect_Effect.provideService(MimicAuthServiceTag, authService), effect_Effect.provideService(DocumentManagerTag, documentManager), effect_Effect.provideService(PresenceManagerTag, presenceManager), effect_Effect.scoped, effect_Effect.catchAll((error) => effect_Effect.logError("WebSocket connection error", error)));
|
|
1056
|
+
return _effect_platform.HttpServerResponse.empty();
|
|
1057
|
+
}).pipe(effect_Effect.catchAll((error) => effect_Effect.gen(function* () {
|
|
1058
|
+
yield* effect_Effect.logWarning("WebSocket upgrade failed", error);
|
|
1059
|
+
return _effect_platform.HttpServerResponse.text("WebSocket upgrade failed", { status: 400 });
|
|
1060
|
+
})));
|
|
1061
|
+
});
|
|
1062
|
+
/**
|
|
1063
|
+
* Create a Mimic server layer that integrates with HttpLayerRouter.
|
|
1064
|
+
*
|
|
1065
|
+
* This function creates a layer that:
|
|
1066
|
+
* 1. Registers a WebSocket route at the specified base path
|
|
1067
|
+
* 2. Handles WebSocket upgrades for document sync
|
|
1068
|
+
* 3. Provides all required dependencies (config, auth, storage, document manager)
|
|
1069
|
+
*
|
|
1070
|
+
* By default, uses in-memory storage and no authentication.
|
|
1071
|
+
* To override these defaults, provide custom layers before the defaults:
|
|
1072
|
+
*
|
|
1073
|
+
* @example
|
|
1074
|
+
* ```typescript
|
|
1075
|
+
* import { MimicServer, MimicAuthService } from "@voidhash/mimic-effect";
|
|
1076
|
+
* import { HttpLayerRouter } from "@effect/platform";
|
|
1077
|
+
* import { Primitive } from "@voidhash/mimic";
|
|
1078
|
+
*
|
|
1079
|
+
* const TodoSchema = Primitive.Struct({
|
|
1080
|
+
* title: Primitive.String(),
|
|
1081
|
+
* completed: Primitive.Boolean(),
|
|
1082
|
+
* });
|
|
1083
|
+
*
|
|
1084
|
+
* // Create the Mimic route layer with defaults
|
|
1085
|
+
* const MimicRoute = MimicServer.layerHttpLayerRouter({
|
|
1086
|
+
* basePath: "/mimic/todo",
|
|
1087
|
+
* schema: TodoSchema
|
|
1088
|
+
* });
|
|
1089
|
+
*
|
|
1090
|
+
* // Or with custom auth - use Layer.provide to inject before defaults
|
|
1091
|
+
* const MimicRouteWithAuth = MimicServer.layerHttpLayerRouter({
|
|
1092
|
+
* basePath: "/mimic/todo",
|
|
1093
|
+
* schema: TodoSchema,
|
|
1094
|
+
* authLayer: MimicAuthService.layer({
|
|
1095
|
+
* authHandler: (token) => ({ success: true, userId: token })
|
|
1096
|
+
* })
|
|
1097
|
+
* });
|
|
1098
|
+
*
|
|
1099
|
+
* // Merge with other routes and serve
|
|
1100
|
+
* const AllRoutes = Layer.mergeAll(MimicRoute, OtherRoutes);
|
|
1101
|
+
* HttpLayerRouter.serve(AllRoutes).pipe(
|
|
1102
|
+
* Layer.provide(BunHttpServer.layer({ port: 3000 })),
|
|
1103
|
+
* Layer.launch,
|
|
1104
|
+
* BunRuntime.runMain
|
|
1105
|
+
* );
|
|
1106
|
+
* ```
|
|
1107
|
+
*/
|
|
1108
|
+
const layerHttpLayerRouter = (options) => {
|
|
1109
|
+
var _options$basePath, _options$authLayer, _options$storageLayer;
|
|
1110
|
+
const wsPath = `${(_options$basePath = options.basePath) !== null && _options$basePath !== void 0 ? _options$basePath : "/mimic"}/doc/*`;
|
|
1111
|
+
const configLayer = layer$7({
|
|
1112
|
+
schema: options.schema,
|
|
1113
|
+
maxTransactionHistory: options.maxTransactionHistory,
|
|
1114
|
+
presence: options.presence
|
|
1115
|
+
});
|
|
1116
|
+
const authLayer = (_options$authLayer = options.authLayer) !== null && _options$authLayer !== void 0 ? _options$authLayer : layerDefault;
|
|
1117
|
+
const storageLayer = (_options$storageLayer = options.storageLayer) !== null && _options$storageLayer !== void 0 ? _options$storageLayer : layerDefault$1;
|
|
1118
|
+
const registerRoute = effect_Effect.gen(function* () {
|
|
1119
|
+
const router = yield* _effect_platform.HttpLayerRouter.HttpRouter;
|
|
1120
|
+
const handler = yield* makeMimicHandler;
|
|
1121
|
+
yield* router.add("GET", wsPath, handler);
|
|
1122
|
+
});
|
|
1123
|
+
return effect_Layer.scopedDiscard(registerRoute).pipe(effect_Layer.provide(layer$5), effect_Layer.provide(layer$3), effect_Layer.provide(configLayer), effect_Layer.provide(storageLayer), effect_Layer.provide(authLayer));
|
|
1124
|
+
};
|
|
1125
|
+
|
|
1126
|
+
//#endregion
|
|
1127
|
+
//#region src/DocumentProtocol.ts
|
|
1128
|
+
/**
|
|
1129
|
+
* @since 0.0.1
|
|
1130
|
+
* Protocol and schema definitions for document communication.
|
|
1131
|
+
*/
|
|
1132
|
+
var DocumentProtocol_exports = /* @__PURE__ */ __export({
|
|
1133
|
+
AuthResultMessageSchema: () => AuthResultMessageSchema,
|
|
1134
|
+
ErrorMessageSchema: () => ErrorMessageSchema,
|
|
1135
|
+
OperationSchema: () => OperationSchema,
|
|
1136
|
+
PongMessageSchema: () => PongMessageSchema,
|
|
1137
|
+
ServerBroadcastSchema: () => ServerBroadcastSchema,
|
|
1138
|
+
SnapshotMessageSchema: () => SnapshotMessageSchema,
|
|
1139
|
+
SubmitResultSchema: () => SubmitResultSchema,
|
|
1140
|
+
TransactionMessageSchema: () => TransactionMessageSchema,
|
|
1141
|
+
TransactionSchema: () => TransactionSchema
|
|
1142
|
+
});
|
|
1143
|
+
/**
|
|
1144
|
+
* Schema for a transaction operation.
|
|
1145
|
+
*/
|
|
1146
|
+
const OperationSchema = effect_Schema.Struct({
|
|
1147
|
+
kind: effect_Schema.String,
|
|
1148
|
+
path: effect_Schema.Unknown,
|
|
1149
|
+
payload: effect_Schema.Unknown
|
|
1150
|
+
});
|
|
1151
|
+
/**
|
|
1152
|
+
* Schema for a transaction.
|
|
1153
|
+
*/
|
|
1154
|
+
const TransactionSchema = effect_Schema.Struct({
|
|
1155
|
+
id: effect_Schema.String,
|
|
1156
|
+
ops: effect_Schema.Array(OperationSchema),
|
|
1157
|
+
timestamp: effect_Schema.Number
|
|
1158
|
+
});
|
|
1159
|
+
/**
|
|
1160
|
+
* Schema for a server message that broadcasts a committed transaction.
|
|
1161
|
+
*/
|
|
1162
|
+
const TransactionMessageSchema = effect_Schema.Struct({
|
|
1163
|
+
type: effect_Schema.Literal("transaction"),
|
|
1164
|
+
transaction: TransactionSchema,
|
|
1165
|
+
version: effect_Schema.Number
|
|
1166
|
+
});
|
|
1167
|
+
/**
|
|
1168
|
+
* Schema for a server message containing a snapshot.
|
|
1169
|
+
*/
|
|
1170
|
+
const SnapshotMessageSchema = effect_Schema.Struct({
|
|
1171
|
+
type: effect_Schema.Literal("snapshot"),
|
|
1172
|
+
state: effect_Schema.Unknown,
|
|
1173
|
+
version: effect_Schema.Number
|
|
1174
|
+
});
|
|
1175
|
+
/**
|
|
1176
|
+
* Schema for a server error message.
|
|
1177
|
+
*/
|
|
1178
|
+
const ErrorMessageSchema = effect_Schema.Struct({
|
|
1179
|
+
type: effect_Schema.Literal("error"),
|
|
1180
|
+
transactionId: effect_Schema.String,
|
|
1181
|
+
reason: effect_Schema.String
|
|
1182
|
+
});
|
|
1183
|
+
/**
|
|
1184
|
+
* Schema for a pong message.
|
|
1185
|
+
*/
|
|
1186
|
+
const PongMessageSchema = effect_Schema.Struct({ type: effect_Schema.Literal("pong") });
|
|
1187
|
+
/**
|
|
1188
|
+
* Schema for authentication result message.
|
|
1189
|
+
*/
|
|
1190
|
+
const AuthResultMessageSchema = effect_Schema.Struct({
|
|
1191
|
+
type: effect_Schema.Literal("auth_result"),
|
|
1192
|
+
success: effect_Schema.Boolean,
|
|
1193
|
+
error: effect_Schema.optional(effect_Schema.String)
|
|
1194
|
+
});
|
|
1195
|
+
/**
|
|
1196
|
+
* Union of all server broadcast messages.
|
|
1197
|
+
*/
|
|
1198
|
+
const ServerBroadcastSchema = effect_Schema.Union(TransactionMessageSchema, ErrorMessageSchema);
|
|
1199
|
+
/**
|
|
1200
|
+
* Result of submitting a transaction.
|
|
1201
|
+
*/
|
|
1202
|
+
const SubmitResultSchema = effect_Schema.Union(effect_Schema.Struct({
|
|
1203
|
+
success: effect_Schema.Literal(true),
|
|
1204
|
+
version: effect_Schema.Number
|
|
1205
|
+
}), effect_Schema.Struct({
|
|
1206
|
+
success: effect_Schema.Literal(false),
|
|
1207
|
+
reason: effect_Schema.String
|
|
1208
|
+
}));
|
|
1209
|
+
|
|
1210
|
+
//#endregion
|
|
1211
|
+
exports.AuthenticationError = AuthenticationError;
|
|
1212
|
+
Object.defineProperty(exports, 'DocumentManager', {
|
|
1213
|
+
enumerable: true,
|
|
1214
|
+
get: function () {
|
|
1215
|
+
return DocumentManager_exports;
|
|
1216
|
+
}
|
|
1217
|
+
});
|
|
1218
|
+
exports.DocumentNotFoundError = DocumentNotFoundError;
|
|
1219
|
+
Object.defineProperty(exports, 'DocumentProtocol', {
|
|
1220
|
+
enumerable: true,
|
|
1221
|
+
get: function () {
|
|
1222
|
+
return DocumentProtocol_exports;
|
|
1223
|
+
}
|
|
1224
|
+
});
|
|
1225
|
+
exports.DocumentTypeNotFoundError = DocumentTypeNotFoundError;
|
|
1226
|
+
exports.InvalidConnectionError = InvalidConnectionError;
|
|
1227
|
+
exports.MessageParseError = MessageParseError;
|
|
1228
|
+
Object.defineProperty(exports, 'MimicAuthService', {
|
|
1229
|
+
enumerable: true,
|
|
1230
|
+
get: function () {
|
|
1231
|
+
return MimicAuthService_exports;
|
|
1232
|
+
}
|
|
1233
|
+
});
|
|
1234
|
+
Object.defineProperty(exports, 'MimicConfig', {
|
|
1235
|
+
enumerable: true,
|
|
1236
|
+
get: function () {
|
|
1237
|
+
return MimicConfig_exports;
|
|
1238
|
+
}
|
|
1239
|
+
});
|
|
1240
|
+
Object.defineProperty(exports, 'MimicDataStorage', {
|
|
1241
|
+
enumerable: true,
|
|
1242
|
+
get: function () {
|
|
1243
|
+
return MimicDataStorage_exports;
|
|
1244
|
+
}
|
|
1245
|
+
});
|
|
1246
|
+
Object.defineProperty(exports, 'MimicInMemoryDataStorage', {
|
|
1247
|
+
enumerable: true,
|
|
1248
|
+
get: function () {
|
|
1249
|
+
return InMemoryDataStorage_exports;
|
|
1250
|
+
}
|
|
1251
|
+
});
|
|
1252
|
+
Object.defineProperty(exports, 'MimicNoAuth', {
|
|
1253
|
+
enumerable: true,
|
|
1254
|
+
get: function () {
|
|
1255
|
+
return NoAuth_exports;
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
Object.defineProperty(exports, 'MimicServer', {
|
|
1259
|
+
enumerable: true,
|
|
1260
|
+
get: function () {
|
|
1261
|
+
return MimicServer_exports;
|
|
1262
|
+
}
|
|
1263
|
+
});
|
|
1264
|
+
exports.MissingDocumentIdError = MissingDocumentIdError;
|
|
1265
|
+
Object.defineProperty(exports, 'PresenceManager', {
|
|
1266
|
+
enumerable: true,
|
|
1267
|
+
get: function () {
|
|
1268
|
+
return PresenceManager_exports;
|
|
1269
|
+
}
|
|
1270
|
+
});
|
|
1271
|
+
exports.TransactionRejectedError = TransactionRejectedError;
|
|
1272
|
+
Object.defineProperty(exports, 'WebSocketHandler', {
|
|
1273
|
+
enumerable: true,
|
|
1274
|
+
get: function () {
|
|
1275
|
+
return WebSocketHandler_exports;
|
|
1276
|
+
}
|
|
1277
|
+
});
|