@voidhash/mimic-effect 0.0.2 → 0.0.4
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 +99 -14
- package/dist/DocumentManager.cjs +118 -0
- package/dist/DocumentManager.d.cts +45 -0
- package/dist/DocumentManager.d.cts.map +1 -0
- package/dist/DocumentManager.d.mts +45 -0
- package/dist/DocumentManager.d.mts.map +1 -0
- package/dist/DocumentManager.mjs +105 -0
- package/dist/DocumentManager.mjs.map +1 -0
- package/dist/DocumentProtocol.cjs +94 -0
- package/dist/DocumentProtocol.d.cts +113 -0
- package/dist/DocumentProtocol.d.cts.map +1 -0
- package/dist/DocumentProtocol.d.mts +113 -0
- package/dist/DocumentProtocol.d.mts.map +1 -0
- package/dist/DocumentProtocol.mjs +89 -0
- package/dist/DocumentProtocol.mjs.map +1 -0
- package/dist/MimicAuthService.cjs +55 -0
- package/dist/MimicAuthService.d.cts +65 -0
- package/dist/MimicAuthService.d.cts.map +1 -0
- package/dist/MimicAuthService.d.mts +65 -0
- package/dist/MimicAuthService.d.mts.map +1 -0
- package/dist/MimicAuthService.mjs +47 -0
- package/dist/MimicAuthService.mjs.map +1 -0
- package/dist/MimicConfig.cjs +52 -0
- package/dist/MimicConfig.d.cts +115 -0
- package/dist/MimicConfig.d.cts.map +1 -0
- package/dist/MimicConfig.d.mts +115 -0
- package/dist/MimicConfig.d.mts.map +1 -0
- package/dist/MimicConfig.mjs +43 -0
- package/dist/MimicConfig.mjs.map +1 -0
- package/dist/MimicDataStorage.cjs +83 -0
- package/dist/MimicDataStorage.d.cts +113 -0
- package/dist/MimicDataStorage.d.cts.map +1 -0
- package/dist/MimicDataStorage.d.mts +113 -0
- package/dist/MimicDataStorage.d.mts.map +1 -0
- package/dist/MimicDataStorage.mjs +74 -0
- package/dist/MimicDataStorage.mjs.map +1 -0
- package/dist/MimicServer.cjs +122 -0
- package/dist/MimicServer.d.cts +106 -0
- package/dist/MimicServer.d.cts.map +1 -0
- package/dist/MimicServer.d.mts +106 -0
- package/dist/MimicServer.d.mts.map +1 -0
- package/dist/MimicServer.mjs +116 -0
- package/dist/MimicServer.mjs.map +1 -0
- package/dist/PresenceManager.cjs +108 -0
- package/dist/PresenceManager.d.cts +91 -0
- package/dist/PresenceManager.d.cts.map +1 -0
- package/dist/PresenceManager.d.mts +91 -0
- package/dist/PresenceManager.d.mts.map +1 -0
- package/dist/PresenceManager.mjs +95 -0
- package/dist/PresenceManager.mjs.map +1 -0
- package/dist/WebSocketHandler.cjs +365 -0
- package/dist/WebSocketHandler.d.cts +34 -0
- package/dist/WebSocketHandler.d.cts.map +1 -0
- package/dist/WebSocketHandler.d.mts +34 -0
- package/dist/WebSocketHandler.d.mts.map +1 -0
- package/dist/WebSocketHandler.mjs +355 -0
- package/dist/WebSocketHandler.mjs.map +1 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.cjs +14 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.mjs +14 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.cjs +27 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.mjs +27 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.cjs +16 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.mjs +16 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.mjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.cjs +18 -0
- package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.mjs +12 -0
- package/dist/_virtual/rolldown_runtime.cjs +43 -0
- package/dist/{chunk-C6wwvPpM.mjs → _virtual/rolldown_runtime.mjs} +1 -1
- package/dist/auth/NoAuth.cjs +43 -0
- package/dist/auth/NoAuth.d.cts +22 -0
- package/dist/auth/NoAuth.d.cts.map +1 -0
- package/dist/auth/NoAuth.d.mts +22 -0
- package/dist/auth/NoAuth.d.mts.map +1 -0
- package/dist/auth/NoAuth.mjs +36 -0
- package/dist/auth/NoAuth.mjs.map +1 -0
- package/dist/errors.cjs +74 -0
- package/dist/errors.d.cts +89 -0
- package/dist/errors.d.cts.map +1 -0
- package/dist/errors.d.mts +89 -0
- package/dist/errors.d.mts.map +1 -0
- package/dist/errors.mjs +67 -0
- package/dist/errors.mjs.map +1 -0
- package/dist/index.cjs +29 -1227
- package/dist/index.d.cts +12 -795
- package/dist/index.d.mts +12 -795
- package/dist/index.mjs +13 -1162
- package/dist/storage/InMemoryDataStorage.cjs +57 -0
- package/dist/storage/InMemoryDataStorage.d.cts +19 -0
- package/dist/storage/InMemoryDataStorage.d.cts.map +1 -0
- package/dist/storage/InMemoryDataStorage.d.mts +19 -0
- package/dist/storage/InMemoryDataStorage.d.mts.map +1 -0
- package/dist/storage/InMemoryDataStorage.mjs +48 -0
- package/dist/storage/InMemoryDataStorage.mjs.map +1 -0
- package/package.json +3 -3
- package/src/DocumentManager.ts +2 -2
- package/src/MimicConfig.ts +22 -1
- package/src/MimicServer.ts +11 -161
- package/tests/DocumentManager.test.ts +61 -0
- package/tests/MimicConfig.test.ts +72 -0
- package/tests/MimicServer.test.ts +55 -162
- package/tsdown.config.ts +1 -1
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,1277 +1,79 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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;
|
|
1
|
+
const require_MimicConfig = require('./MimicConfig.cjs');
|
|
2
|
+
const require_MimicDataStorage = require('./MimicDataStorage.cjs');
|
|
3
|
+
const require_DocumentManager = require('./DocumentManager.cjs');
|
|
4
|
+
const require_MimicAuthService = require('./MimicAuthService.cjs');
|
|
5
|
+
const require_PresenceManager = require('./PresenceManager.cjs');
|
|
6
|
+
const require_errors = require('./errors.cjs');
|
|
7
|
+
const require_WebSocketHandler = require('./WebSocketHandler.cjs');
|
|
8
|
+
const require_InMemoryDataStorage = require('./storage/InMemoryDataStorage.cjs');
|
|
9
|
+
const require_NoAuth = require('./auth/NoAuth.cjs');
|
|
10
|
+
const require_MimicServer = require('./MimicServer.cjs');
|
|
11
|
+
const require_DocumentProtocol = require('./DocumentProtocol.cjs');
|
|
12
|
+
|
|
13
|
+
exports.AuthenticationError = require_errors.AuthenticationError;
|
|
1212
14
|
Object.defineProperty(exports, 'DocumentManager', {
|
|
1213
15
|
enumerable: true,
|
|
1214
16
|
get: function () {
|
|
1215
|
-
return DocumentManager_exports;
|
|
17
|
+
return require_DocumentManager.DocumentManager_exports;
|
|
1216
18
|
}
|
|
1217
19
|
});
|
|
1218
|
-
exports.DocumentNotFoundError = DocumentNotFoundError;
|
|
20
|
+
exports.DocumentNotFoundError = require_errors.DocumentNotFoundError;
|
|
1219
21
|
Object.defineProperty(exports, 'DocumentProtocol', {
|
|
1220
22
|
enumerable: true,
|
|
1221
23
|
get: function () {
|
|
1222
|
-
return DocumentProtocol_exports;
|
|
24
|
+
return require_DocumentProtocol.DocumentProtocol_exports;
|
|
1223
25
|
}
|
|
1224
26
|
});
|
|
1225
|
-
exports.DocumentTypeNotFoundError = DocumentTypeNotFoundError;
|
|
1226
|
-
exports.InvalidConnectionError = InvalidConnectionError;
|
|
1227
|
-
exports.MessageParseError = MessageParseError;
|
|
27
|
+
exports.DocumentTypeNotFoundError = require_errors.DocumentTypeNotFoundError;
|
|
28
|
+
exports.InvalidConnectionError = require_errors.InvalidConnectionError;
|
|
29
|
+
exports.MessageParseError = require_errors.MessageParseError;
|
|
1228
30
|
Object.defineProperty(exports, 'MimicAuthService', {
|
|
1229
31
|
enumerable: true,
|
|
1230
32
|
get: function () {
|
|
1231
|
-
return MimicAuthService_exports;
|
|
33
|
+
return require_MimicAuthService.MimicAuthService_exports;
|
|
1232
34
|
}
|
|
1233
35
|
});
|
|
1234
36
|
Object.defineProperty(exports, 'MimicConfig', {
|
|
1235
37
|
enumerable: true,
|
|
1236
38
|
get: function () {
|
|
1237
|
-
return MimicConfig_exports;
|
|
39
|
+
return require_MimicConfig.MimicConfig_exports;
|
|
1238
40
|
}
|
|
1239
41
|
});
|
|
1240
42
|
Object.defineProperty(exports, 'MimicDataStorage', {
|
|
1241
43
|
enumerable: true,
|
|
1242
44
|
get: function () {
|
|
1243
|
-
return MimicDataStorage_exports;
|
|
45
|
+
return require_MimicDataStorage.MimicDataStorage_exports;
|
|
1244
46
|
}
|
|
1245
47
|
});
|
|
1246
48
|
Object.defineProperty(exports, 'MimicInMemoryDataStorage', {
|
|
1247
49
|
enumerable: true,
|
|
1248
50
|
get: function () {
|
|
1249
|
-
return InMemoryDataStorage_exports;
|
|
51
|
+
return require_InMemoryDataStorage.InMemoryDataStorage_exports;
|
|
1250
52
|
}
|
|
1251
53
|
});
|
|
1252
54
|
Object.defineProperty(exports, 'MimicNoAuth', {
|
|
1253
55
|
enumerable: true,
|
|
1254
56
|
get: function () {
|
|
1255
|
-
return NoAuth_exports;
|
|
57
|
+
return require_NoAuth.NoAuth_exports;
|
|
1256
58
|
}
|
|
1257
59
|
});
|
|
1258
60
|
Object.defineProperty(exports, 'MimicServer', {
|
|
1259
61
|
enumerable: true,
|
|
1260
62
|
get: function () {
|
|
1261
|
-
return MimicServer_exports;
|
|
63
|
+
return require_MimicServer.MimicServer_exports;
|
|
1262
64
|
}
|
|
1263
65
|
});
|
|
1264
|
-
exports.MissingDocumentIdError = MissingDocumentIdError;
|
|
66
|
+
exports.MissingDocumentIdError = require_errors.MissingDocumentIdError;
|
|
1265
67
|
Object.defineProperty(exports, 'PresenceManager', {
|
|
1266
68
|
enumerable: true,
|
|
1267
69
|
get: function () {
|
|
1268
|
-
return PresenceManager_exports;
|
|
70
|
+
return require_PresenceManager.PresenceManager_exports;
|
|
1269
71
|
}
|
|
1270
72
|
});
|
|
1271
|
-
exports.TransactionRejectedError = TransactionRejectedError;
|
|
73
|
+
exports.TransactionRejectedError = require_errors.TransactionRejectedError;
|
|
1272
74
|
Object.defineProperty(exports, 'WebSocketHandler', {
|
|
1273
75
|
enumerable: true,
|
|
1274
76
|
get: function () {
|
|
1275
|
-
return WebSocketHandler_exports;
|
|
77
|
+
return require_WebSocketHandler.WebSocketHandler_exports;
|
|
1276
78
|
}
|
|
1277
79
|
});
|