@voidhash/mimic-effect 0.0.9 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +136 -90
- package/README.md +385 -0
- package/dist/ColdStorage.cjs +60 -0
- package/dist/ColdStorage.d.cts +53 -0
- package/dist/ColdStorage.d.cts.map +1 -0
- package/dist/ColdStorage.d.mts +53 -0
- package/dist/ColdStorage.d.mts.map +1 -0
- package/dist/ColdStorage.mjs +60 -0
- package/dist/ColdStorage.mjs.map +1 -0
- package/dist/DocumentManager.cjs +263 -82
- package/dist/DocumentManager.d.cts +44 -22
- package/dist/DocumentManager.d.cts.map +1 -1
- package/dist/DocumentManager.d.mts +44 -22
- package/dist/DocumentManager.d.mts.map +1 -1
- package/dist/DocumentManager.mjs +259 -67
- package/dist/DocumentManager.mjs.map +1 -1
- package/dist/Errors.cjs +54 -0
- package/dist/Errors.d.cts +96 -0
- package/dist/Errors.d.cts.map +1 -0
- package/dist/Errors.d.mts +96 -0
- package/dist/Errors.d.mts.map +1 -0
- package/dist/Errors.mjs +48 -0
- package/dist/Errors.mjs.map +1 -0
- package/dist/HotStorage.cjs +100 -0
- package/dist/HotStorage.d.cts +70 -0
- package/dist/HotStorage.d.cts.map +1 -0
- package/dist/HotStorage.d.mts +70 -0
- package/dist/HotStorage.d.mts.map +1 -0
- package/dist/HotStorage.mjs +100 -0
- package/dist/HotStorage.mjs.map +1 -0
- package/dist/Metrics.cjs +143 -0
- package/dist/Metrics.d.cts +31 -0
- package/dist/Metrics.d.cts.map +1 -0
- package/dist/Metrics.d.mts +31 -0
- package/dist/Metrics.d.mts.map +1 -0
- package/dist/Metrics.mjs +126 -0
- package/dist/Metrics.mjs.map +1 -0
- package/dist/MimicAuthService.cjs +61 -45
- package/dist/MimicAuthService.d.cts +61 -48
- package/dist/MimicAuthService.d.cts.map +1 -1
- package/dist/MimicAuthService.d.mts +61 -48
- package/dist/MimicAuthService.d.mts.map +1 -1
- package/dist/MimicAuthService.mjs +60 -36
- package/dist/MimicAuthService.mjs.map +1 -1
- package/dist/MimicClusterServerEngine.cjs +521 -0
- package/dist/MimicClusterServerEngine.d.cts +17 -0
- package/dist/MimicClusterServerEngine.d.cts.map +1 -0
- package/dist/MimicClusterServerEngine.d.mts +17 -0
- package/dist/MimicClusterServerEngine.d.mts.map +1 -0
- package/dist/MimicClusterServerEngine.mjs +523 -0
- package/dist/MimicClusterServerEngine.mjs.map +1 -0
- package/dist/MimicServer.cjs +205 -96
- package/dist/MimicServer.d.cts +9 -110
- package/dist/MimicServer.d.cts.map +1 -1
- package/dist/MimicServer.d.mts +9 -110
- package/dist/MimicServer.d.mts.map +1 -1
- package/dist/MimicServer.mjs +206 -90
- package/dist/MimicServer.mjs.map +1 -1
- package/dist/MimicServerEngine.cjs +97 -0
- package/dist/MimicServerEngine.d.cts +78 -0
- package/dist/MimicServerEngine.d.cts.map +1 -0
- package/dist/MimicServerEngine.d.mts +78 -0
- package/dist/MimicServerEngine.d.mts.map +1 -0
- package/dist/MimicServerEngine.mjs +97 -0
- package/dist/MimicServerEngine.mjs.map +1 -0
- package/dist/PresenceManager.cjs +75 -91
- package/dist/PresenceManager.d.cts +17 -66
- package/dist/PresenceManager.d.cts.map +1 -1
- package/dist/PresenceManager.d.mts +17 -66
- package/dist/PresenceManager.d.mts.map +1 -1
- package/dist/PresenceManager.mjs +74 -78
- package/dist/PresenceManager.mjs.map +1 -1
- package/dist/Protocol.cjs +146 -0
- package/dist/Protocol.d.cts +203 -0
- package/dist/Protocol.d.cts.map +1 -0
- package/dist/Protocol.d.mts +203 -0
- package/dist/Protocol.d.mts.map +1 -0
- package/dist/Protocol.mjs +132 -0
- package/dist/Protocol.mjs.map +1 -0
- package/dist/Types.d.cts +172 -0
- package/dist/Types.d.cts.map +1 -0
- package/dist/Types.d.mts +172 -0
- package/dist/Types.d.mts.map +1 -0
- package/dist/_virtual/rolldown_runtime.cjs +1 -25
- package/dist/_virtual/rolldown_runtime.mjs +4 -1
- package/dist/index.cjs +37 -75
- package/dist/index.d.cts +13 -12
- package/dist/index.d.mts +13 -12
- package/dist/index.mjs +12 -12
- package/dist/testing/ColdStorageTestSuite.cjs +508 -0
- package/dist/testing/ColdStorageTestSuite.d.cts +36 -0
- package/dist/testing/ColdStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/ColdStorageTestSuite.d.mts +36 -0
- package/dist/testing/ColdStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/ColdStorageTestSuite.mjs +508 -0
- package/dist/testing/ColdStorageTestSuite.mjs.map +1 -0
- package/dist/testing/FailingStorage.cjs +135 -0
- package/dist/testing/FailingStorage.d.cts +43 -0
- package/dist/testing/FailingStorage.d.cts.map +1 -0
- package/dist/testing/FailingStorage.d.mts +43 -0
- package/dist/testing/FailingStorage.d.mts.map +1 -0
- package/dist/testing/FailingStorage.mjs +136 -0
- package/dist/testing/FailingStorage.mjs.map +1 -0
- package/dist/testing/HotStorageTestSuite.cjs +585 -0
- package/dist/testing/HotStorageTestSuite.d.cts +40 -0
- package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/HotStorageTestSuite.d.mts +40 -0
- package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/HotStorageTestSuite.mjs +585 -0
- package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.cjs +349 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts +35 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts +35 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs +349 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
- package/dist/testing/assertions.cjs +114 -0
- package/dist/testing/assertions.mjs +109 -0
- package/dist/testing/assertions.mjs.map +1 -0
- package/dist/testing/index.cjs +14 -0
- package/dist/testing/index.d.cts +6 -0
- package/dist/testing/index.d.mts +6 -0
- package/dist/testing/index.mjs +7 -0
- package/dist/testing/types.cjs +15 -0
- package/dist/testing/types.d.cts +90 -0
- package/dist/testing/types.d.cts.map +1 -0
- package/dist/testing/types.d.mts +90 -0
- package/dist/testing/types.d.mts.map +1 -0
- package/dist/testing/types.mjs +16 -0
- package/dist/testing/types.mjs.map +1 -0
- package/package.json +18 -3
- package/src/ColdStorage.ts +136 -0
- package/src/DocumentManager.ts +550 -190
- package/src/Errors.ts +114 -0
- package/src/HotStorage.ts +239 -0
- package/src/Metrics.ts +187 -0
- package/src/MimicAuthService.ts +126 -64
- package/src/MimicClusterServerEngine.ts +946 -0
- package/src/MimicServer.ts +448 -195
- package/src/MimicServerEngine.ts +276 -0
- package/src/PresenceManager.ts +169 -240
- package/src/Protocol.ts +350 -0
- package/src/Types.ts +231 -0
- package/src/index.ts +57 -23
- package/src/testing/ColdStorageTestSuite.ts +589 -0
- package/src/testing/FailingStorage.ts +286 -0
- package/src/testing/HotStorageTestSuite.ts +762 -0
- package/src/testing/StorageIntegrationTestSuite.ts +504 -0
- package/src/testing/assertions.ts +181 -0
- package/src/testing/index.ts +83 -0
- package/src/testing/types.ts +100 -0
- package/tests/ColdStorage.test.ts +24 -0
- package/tests/DocumentManager.test.ts +158 -287
- package/tests/HotStorage.test.ts +24 -0
- package/tests/MimicAuthService.test.ts +102 -134
- package/tests/MimicClusterServerEngine.test.ts +587 -0
- package/tests/MimicServer.test.ts +90 -226
- package/tests/MimicServerEngine.test.ts +521 -0
- package/tests/PresenceManager.test.ts +22 -63
- package/tests/Protocol.test.ts +190 -0
- package/tests/StorageIntegration.test.ts +259 -0
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +1 -1
- package/dist/DocumentProtocol.cjs +0 -94
- package/dist/DocumentProtocol.d.cts +0 -113
- package/dist/DocumentProtocol.d.cts.map +0 -1
- package/dist/DocumentProtocol.d.mts +0 -113
- package/dist/DocumentProtocol.d.mts.map +0 -1
- package/dist/DocumentProtocol.mjs +0 -89
- package/dist/DocumentProtocol.mjs.map +0 -1
- package/dist/MimicConfig.cjs +0 -60
- package/dist/MimicConfig.d.cts +0 -141
- package/dist/MimicConfig.d.cts.map +0 -1
- package/dist/MimicConfig.d.mts +0 -141
- package/dist/MimicConfig.d.mts.map +0 -1
- package/dist/MimicConfig.mjs +0 -50
- package/dist/MimicConfig.mjs.map +0 -1
- package/dist/MimicDataStorage.cjs +0 -83
- package/dist/MimicDataStorage.d.cts +0 -113
- package/dist/MimicDataStorage.d.cts.map +0 -1
- package/dist/MimicDataStorage.d.mts +0 -113
- package/dist/MimicDataStorage.d.mts.map +0 -1
- package/dist/MimicDataStorage.mjs +0 -74
- package/dist/MimicDataStorage.mjs.map +0 -1
- package/dist/WebSocketHandler.cjs +0 -365
- package/dist/WebSocketHandler.d.cts +0 -34
- package/dist/WebSocketHandler.d.cts.map +0 -1
- package/dist/WebSocketHandler.d.mts +0 -34
- package/dist/WebSocketHandler.d.mts.map +0 -1
- package/dist/WebSocketHandler.mjs +0 -355
- package/dist/WebSocketHandler.mjs.map +0 -1
- package/dist/auth/NoAuth.cjs +0 -43
- package/dist/auth/NoAuth.d.cts +0 -22
- package/dist/auth/NoAuth.d.cts.map +0 -1
- package/dist/auth/NoAuth.d.mts +0 -22
- package/dist/auth/NoAuth.d.mts.map +0 -1
- package/dist/auth/NoAuth.mjs +0 -36
- package/dist/auth/NoAuth.mjs.map +0 -1
- package/dist/errors.cjs +0 -74
- package/dist/errors.d.cts +0 -89
- package/dist/errors.d.cts.map +0 -1
- package/dist/errors.d.mts +0 -89
- package/dist/errors.d.mts.map +0 -1
- package/dist/errors.mjs +0 -67
- package/dist/errors.mjs.map +0 -1
- package/dist/storage/InMemoryDataStorage.cjs +0 -57
- package/dist/storage/InMemoryDataStorage.d.cts +0 -19
- package/dist/storage/InMemoryDataStorage.d.cts.map +0 -1
- package/dist/storage/InMemoryDataStorage.d.mts +0 -19
- package/dist/storage/InMemoryDataStorage.d.mts.map +0 -1
- package/dist/storage/InMemoryDataStorage.mjs +0 -48
- package/dist/storage/InMemoryDataStorage.mjs.map +0 -1
- package/src/DocumentProtocol.ts +0 -112
- package/src/MimicConfig.ts +0 -211
- package/src/MimicDataStorage.ts +0 -157
- package/src/WebSocketHandler.ts +0 -735
- package/src/auth/NoAuth.ts +0 -46
- package/src/errors.ts +0 -113
- package/src/storage/InMemoryDataStorage.ts +0 -66
- package/tests/DocumentProtocol.test.ts +0 -113
- package/tests/InMemoryDataStorage.test.ts +0 -190
- package/tests/MimicConfig.test.ts +0 -290
- package/tests/MimicDataStorage.test.ts +0 -190
- package/tests/NoAuth.test.ts +0 -94
- package/tests/WebSocketHandler.test.ts +0 -321
- package/tests/errors.test.ts +0 -77
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { MimicServerEngineConfig, PresenceEntry, PresenceEvent, PresenceSnapshot, ResolvedConfig } from "./Types.mjs";
|
|
2
|
+
import { ServerMessage } from "./Protocol.mjs";
|
|
3
|
+
import { ColdStorageTag } from "./ColdStorage.mjs";
|
|
4
|
+
import { HotStorageTag } from "./HotStorage.mjs";
|
|
5
|
+
import { MimicAuthServiceTag } from "./MimicAuthService.mjs";
|
|
6
|
+
import { DocumentManagerError, SubmitResult } from "./DocumentManager.mjs";
|
|
7
|
+
import { Context, Effect, Layer, Scope, Stream } from "effect";
|
|
8
|
+
import { Primitive, Transaction } from "@voidhash/mimic";
|
|
9
|
+
|
|
10
|
+
//#region src/MimicServerEngine.d.ts
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* MimicServerEngine service interface.
|
|
14
|
+
*
|
|
15
|
+
* Provides document management operations for Mimic collaboration.
|
|
16
|
+
* Use MimicServer.layerHttpLayerRouter() to create WebSocket routes.
|
|
17
|
+
*/
|
|
18
|
+
interface MimicServerEngine {
|
|
19
|
+
/**
|
|
20
|
+
* Submit a transaction to a document.
|
|
21
|
+
* Authorization is checked against the auth service.
|
|
22
|
+
* May fail with DocumentManagerError if storage is unavailable.
|
|
23
|
+
*/
|
|
24
|
+
readonly submit: (documentId: string, transaction: Transaction.Transaction) => Effect.Effect<SubmitResult, DocumentManagerError>;
|
|
25
|
+
/**
|
|
26
|
+
* Get document snapshot (current state and version).
|
|
27
|
+
* May fail with DocumentManagerError if storage is unavailable.
|
|
28
|
+
*/
|
|
29
|
+
readonly getSnapshot: (documentId: string) => Effect.Effect<{
|
|
30
|
+
state: unknown;
|
|
31
|
+
version: number;
|
|
32
|
+
}, DocumentManagerError>;
|
|
33
|
+
/**
|
|
34
|
+
* Subscribe to document broadcasts (transactions).
|
|
35
|
+
* Returns a stream of server messages.
|
|
36
|
+
* Requires a Scope for cleanup when the subscription ends.
|
|
37
|
+
* May fail with DocumentManagerError if storage is unavailable.
|
|
38
|
+
*/
|
|
39
|
+
readonly subscribe: (documentId: string) => Effect.Effect<Stream.Stream<ServerMessage, never, never>, DocumentManagerError, Scope.Scope>;
|
|
40
|
+
/**
|
|
41
|
+
* Touch document to prevent idle garbage collection.
|
|
42
|
+
*/
|
|
43
|
+
readonly touch: (documentId: string) => Effect.Effect<void, never>;
|
|
44
|
+
/**
|
|
45
|
+
* Get presence snapshot for a document.
|
|
46
|
+
*/
|
|
47
|
+
readonly getPresenceSnapshot: (documentId: string) => Effect.Effect<PresenceSnapshot, never>;
|
|
48
|
+
/**
|
|
49
|
+
* Set presence for a connection.
|
|
50
|
+
*/
|
|
51
|
+
readonly setPresence: (documentId: string, connectionId: string, entry: PresenceEntry) => Effect.Effect<void, never>;
|
|
52
|
+
/**
|
|
53
|
+
* Remove presence for a connection.
|
|
54
|
+
*/
|
|
55
|
+
readonly removePresence: (documentId: string, connectionId: string) => Effect.Effect<void, never>;
|
|
56
|
+
/**
|
|
57
|
+
* Subscribe to presence events for a document.
|
|
58
|
+
* Requires a Scope for cleanup when the subscription ends.
|
|
59
|
+
*/
|
|
60
|
+
readonly subscribePresence: (documentId: string) => Effect.Effect<Stream.Stream<PresenceEvent, never, never>, never, Scope.Scope>;
|
|
61
|
+
/**
|
|
62
|
+
* Resolved engine configuration.
|
|
63
|
+
* Used by route layer to access schema, presence config, etc.
|
|
64
|
+
*/
|
|
65
|
+
readonly config: ResolvedConfig<Primitive.AnyPrimitive>;
|
|
66
|
+
}
|
|
67
|
+
declare const MimicServerEngineTag_base: Context.TagClass<MimicServerEngineTag, "@voidhash/mimic-effect/MimicServerEngine", MimicServerEngine>;
|
|
68
|
+
/**
|
|
69
|
+
* Context tag for MimicServerEngine
|
|
70
|
+
*/
|
|
71
|
+
declare class MimicServerEngineTag extends MimicServerEngineTag_base {}
|
|
72
|
+
declare const MimicServerEngine: {
|
|
73
|
+
Tag: typeof MimicServerEngineTag;
|
|
74
|
+
make: <TSchema extends Primitive.AnyPrimitive>(config: MimicServerEngineConfig<TSchema>) => Layer.Layer<MimicServerEngineTag, never, ColdStorageTag | HotStorageTag | MimicAuthServiceTag>;
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
export { MimicServerEngine, MimicServerEngineTag };
|
|
78
|
+
//# sourceMappingURL=MimicServerEngine.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MimicServerEngine.d.mts","names":[],"sources":["../src/MimicServerEngine.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;AAkF0C,UAhCzB,iBAAA,CAgCgC;EAO5B;;;;;EAyBc,SAAA,MAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,WAAA,EAxDlB,WAAA,CAAY,WAwDM,EAAA,GAvD5B,MAAA,CAAO,MAuDqB,CAvDd,YAuDc,EAvDA,oBAuDA,CAAA;EAAd;;;;EAMF,SAAA,WAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,GArDZ,MAAA,CAAO,MAqDK,CAAA;IAAc,KAAA,EAAA,OAAA;IAChC,OAAA,EAAA,MAAA;KAtDyD;;;;AA+D1D;AAwIA;;EAjEqC,SAAU,SAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,GA5HxC,MAAA,CAAO,MA4HiC,CA5H1B,MAAA,CAAO,MA4HmB,CA5HZ,aA4HY,EAAA,KAAA,EAAA,KAAA,CAAA,EA5H2B,oBA4H3B,EA5HiD,KAAA,CAAM,KA4HvD,CAAA;EACb;;;EAIhC,SAAA,KAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,GA5HwC,MAAA,CAAO,MA4H/C,CAAA,IAAA,EAAA,KAAA,CAAA;EAAiB;;;EAHL,SAAA,mBAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,GAlHP,MAAA,CAAO,MAkHA,CAlHO,gBAkHP,EAAA,KAAA,CAAA;;;;0EA1GH,kBACJ,MAAA,CAAO;;;;yEAQP,MAAA,CAAO;;;;;sDAQP,MAAA,CAAO,OAAO,MAAA,CAAO,OAAO,qCAAqC,KAAA,CAAM;;;;;mBAM3D,eAAe,SAAA,CAAU;;cAC3C;;;;cASY,oBAAA,SAA6B,yBAAA;cAwI7B;;yBAjEwB,SAAA,CAAU,sBACrC,wBAAwB,aAC/B,KAAA,CAAM,MACP,6BAEA,iBAAiB,gBAAgB"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { DocumentManagerConfigTag, DocumentManagerTag, layer } from "./DocumentManager.mjs";
|
|
2
|
+
import { PresenceManagerTag, layer as layer$1 } from "./PresenceManager.mjs";
|
|
3
|
+
import { Context, Duration, Effect, Layer } from "effect";
|
|
4
|
+
|
|
5
|
+
//#region src/MimicServerEngine.ts
|
|
6
|
+
/**
|
|
7
|
+
* @voidhash/mimic-effect - MimicServerEngine
|
|
8
|
+
*
|
|
9
|
+
* Core document management service for Mimic real-time collaboration.
|
|
10
|
+
* Handles document lifecycle, storage, presence, and transaction processing.
|
|
11
|
+
*
|
|
12
|
+
* This is the engine layer - for WebSocket routes, use MimicServer.layerHttpLayerRouter().
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Context tag for MimicServerEngine
|
|
16
|
+
*/
|
|
17
|
+
var MimicServerEngineTag = class extends Context.Tag("@voidhash/mimic-effect/MimicServerEngine")() {};
|
|
18
|
+
const DEFAULT_MAX_IDLE_TIME = Duration.minutes(5);
|
|
19
|
+
const DEFAULT_MAX_TRANSACTION_HISTORY = 1e3;
|
|
20
|
+
const DEFAULT_SNAPSHOT_INTERVAL = Duration.minutes(5);
|
|
21
|
+
const DEFAULT_SNAPSHOT_THRESHOLD = 100;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve configuration with defaults
|
|
24
|
+
*/
|
|
25
|
+
const resolveConfig = (config) => {
|
|
26
|
+
var _config$maxTransactio, _config$snapshot, _config$snapshot$tran, _config$snapshot2;
|
|
27
|
+
return {
|
|
28
|
+
schema: config.schema,
|
|
29
|
+
initial: config.initial,
|
|
30
|
+
presence: config.presence,
|
|
31
|
+
maxIdleTime: config.maxIdleTime ? Duration.decode(config.maxIdleTime) : DEFAULT_MAX_IDLE_TIME,
|
|
32
|
+
maxTransactionHistory: (_config$maxTransactio = config.maxTransactionHistory) !== null && _config$maxTransactio !== void 0 ? _config$maxTransactio : DEFAULT_MAX_TRANSACTION_HISTORY,
|
|
33
|
+
snapshot: {
|
|
34
|
+
interval: ((_config$snapshot = config.snapshot) === null || _config$snapshot === void 0 ? void 0 : _config$snapshot.interval) ? Duration.decode(config.snapshot.interval) : DEFAULT_SNAPSHOT_INTERVAL,
|
|
35
|
+
transactionThreshold: (_config$snapshot$tran = (_config$snapshot2 = config.snapshot) === null || _config$snapshot2 === void 0 ? void 0 : _config$snapshot2.transactionThreshold) !== null && _config$snapshot$tran !== void 0 ? _config$snapshot$tran : DEFAULT_SNAPSHOT_THRESHOLD
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Create a MimicServerEngine layer.
|
|
41
|
+
*
|
|
42
|
+
* This creates the core document management service. To expose it via WebSocket,
|
|
43
|
+
* use MimicServer.layerHttpLayerRouter().
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // 1. Create the engine
|
|
48
|
+
* const Engine = MimicServerEngine.make({
|
|
49
|
+
* schema: DocSchema,
|
|
50
|
+
* initial: { title: "Untitled" },
|
|
51
|
+
* presence: CursorPresence,
|
|
52
|
+
* maxIdleTime: "5 minutes",
|
|
53
|
+
* snapshot: { interval: "5 minutes", transactionThreshold: 100 },
|
|
54
|
+
* })
|
|
55
|
+
*
|
|
56
|
+
* // 2. Create the WebSocket route
|
|
57
|
+
* const MimicRoute = MimicServer.layerHttpLayerRouter({
|
|
58
|
+
* path: "/mimic",
|
|
59
|
+
* })
|
|
60
|
+
*
|
|
61
|
+
* // 3. Wire together
|
|
62
|
+
* const MimicLive = MimicRoute.pipe(
|
|
63
|
+
* Layer.provide(Engine),
|
|
64
|
+
* Layer.provide(ColdStorage.InMemory.make()),
|
|
65
|
+
* Layer.provide(HotStorage.InMemory.make()),
|
|
66
|
+
* Layer.provide(MimicAuthService.NoAuth.make()),
|
|
67
|
+
* )
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
const make = (config) => {
|
|
71
|
+
const resolvedConfig = resolveConfig(config);
|
|
72
|
+
const configLayer = Layer.succeed(DocumentManagerConfigTag, resolvedConfig);
|
|
73
|
+
const internalLayers = Layer.mergeAll(layer.pipe(Layer.provide(configLayer)), layer$1);
|
|
74
|
+
return Layer.scoped(MimicServerEngineTag, Effect.gen(function* () {
|
|
75
|
+
const documentManager = yield* DocumentManagerTag;
|
|
76
|
+
const presenceManager = yield* PresenceManagerTag;
|
|
77
|
+
return {
|
|
78
|
+
submit: (documentId, transaction) => documentManager.submit(documentId, transaction),
|
|
79
|
+
getSnapshot: (documentId) => documentManager.getSnapshot(documentId),
|
|
80
|
+
subscribe: (documentId) => documentManager.subscribe(documentId),
|
|
81
|
+
touch: (documentId) => documentManager.touch(documentId),
|
|
82
|
+
getPresenceSnapshot: (documentId) => presenceManager.getSnapshot(documentId),
|
|
83
|
+
setPresence: (documentId, connectionId, entry) => presenceManager.set(documentId, connectionId, entry),
|
|
84
|
+
removePresence: (documentId, connectionId) => presenceManager.remove(documentId, connectionId),
|
|
85
|
+
subscribePresence: (documentId) => presenceManager.subscribe(documentId),
|
|
86
|
+
config: resolvedConfig
|
|
87
|
+
};
|
|
88
|
+
})).pipe(Layer.provide(internalLayers));
|
|
89
|
+
};
|
|
90
|
+
const MimicServerEngine = {
|
|
91
|
+
Tag: MimicServerEngineTag,
|
|
92
|
+
make
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
//#endregion
|
|
96
|
+
export { MimicServerEngine, MimicServerEngineTag };
|
|
97
|
+
//# sourceMappingURL=MimicServerEngine.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MimicServerEngine.mjs","names":["documentManagerLayer","presenceManagerLayer"],"sources":["../src/MimicServerEngine.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - MimicServerEngine\n *\n * Core document management service for Mimic real-time collaboration.\n * Handles document lifecycle, storage, presence, and transaction processing.\n *\n * This is the engine layer - for WebSocket routes, use MimicServer.layerHttpLayerRouter().\n */\nimport {\n Context,\n Duration,\n Effect,\n Layer,\n Scope,\n Stream,\n} from \"effect\";\nimport type { Presence, Primitive, Transaction } from \"@voidhash/mimic\";\nimport type {\n MimicServerEngineConfig,\n PresenceEntry,\n PresenceEvent,\n PresenceSnapshot,\n ResolvedConfig,\n} from \"./Types\";\nimport type * as Protocol from \"./Protocol\";\nimport { ColdStorageTag } from \"./ColdStorage\";\nimport { HotStorageTag } from \"./HotStorage\";\nimport { MimicAuthServiceTag } from \"./MimicAuthService\";\nimport {\n DocumentManagerTag,\n DocumentManagerConfigTag,\n layer as documentManagerLayer,\n type SubmitResult,\n type DocumentManagerError,\n} from \"./DocumentManager\";\nimport {\n PresenceManagerTag,\n layer as presenceManagerLayer,\n} from \"./PresenceManager\";\n\n// =============================================================================\n// MimicServerEngine Interface\n// =============================================================================\n\n/**\n * MimicServerEngine service interface.\n *\n * Provides document management operations for Mimic collaboration.\n * Use MimicServer.layerHttpLayerRouter() to create WebSocket routes.\n */\nexport interface MimicServerEngine {\n /**\n * Submit a transaction to a document.\n * Authorization is checked against the auth service.\n * May fail with DocumentManagerError if storage is unavailable.\n */\n readonly submit: (\n documentId: string,\n transaction: Transaction.Transaction\n ) => Effect.Effect<SubmitResult, DocumentManagerError>;\n\n /**\n * Get document snapshot (current state and version).\n * May fail with DocumentManagerError if storage is unavailable.\n */\n readonly getSnapshot: (\n documentId: string\n ) => Effect.Effect<{ state: unknown; version: number }, DocumentManagerError>;\n\n /**\n * Subscribe to document broadcasts (transactions).\n * Returns a stream of server messages.\n * Requires a Scope for cleanup when the subscription ends.\n * May fail with DocumentManagerError if storage is unavailable.\n */\n readonly subscribe: (\n documentId: string\n ) => Effect.Effect<Stream.Stream<Protocol.ServerMessage, never, never>, DocumentManagerError, Scope.Scope>;\n\n /**\n * Touch document to prevent idle garbage collection.\n */\n readonly touch: (documentId: string) => Effect.Effect<void, never>;\n\n /**\n * Get presence snapshot for a document.\n */\n readonly getPresenceSnapshot: (\n documentId: string\n ) => Effect.Effect<PresenceSnapshot, never>;\n\n /**\n * Set presence for a connection.\n */\n readonly setPresence: (\n documentId: string,\n connectionId: string,\n entry: PresenceEntry\n ) => Effect.Effect<void, never>;\n\n /**\n * Remove presence for a connection.\n */\n readonly removePresence: (\n documentId: string,\n connectionId: string\n ) => Effect.Effect<void, never>;\n\n /**\n * Subscribe to presence events for a document.\n * Requires a Scope for cleanup when the subscription ends.\n */\n readonly subscribePresence: (\n documentId: string\n ) => Effect.Effect<Stream.Stream<PresenceEvent, never, never>, never, Scope.Scope>;\n\n /**\n * Resolved engine configuration.\n * Used by route layer to access schema, presence config, etc.\n */\n readonly config: ResolvedConfig<Primitive.AnyPrimitive>;\n}\n\n// =============================================================================\n// Context Tag\n// =============================================================================\n\n/**\n * Context tag for MimicServerEngine\n */\nexport class MimicServerEngineTag extends Context.Tag(\n \"@voidhash/mimic-effect/MimicServerEngine\"\n)<MimicServerEngineTag, MimicServerEngine>() {}\n\n// =============================================================================\n// Default Configuration\n// =============================================================================\n\nconst DEFAULT_MAX_IDLE_TIME = Duration.minutes(5);\nconst DEFAULT_MAX_TRANSACTION_HISTORY = 1000;\nconst DEFAULT_SNAPSHOT_INTERVAL = Duration.minutes(5);\nconst DEFAULT_SNAPSHOT_THRESHOLD = 100;\n\n/**\n * Resolve configuration with defaults\n */\nconst resolveConfig = <TSchema extends Primitive.AnyPrimitive>(\n config: MimicServerEngineConfig<TSchema>\n): ResolvedConfig<TSchema> => ({\n schema: config.schema,\n initial: config.initial,\n presence: config.presence,\n maxIdleTime: config.maxIdleTime\n ? Duration.decode(config.maxIdleTime)\n : DEFAULT_MAX_IDLE_TIME,\n maxTransactionHistory:\n config.maxTransactionHistory ?? DEFAULT_MAX_TRANSACTION_HISTORY,\n snapshot: {\n interval: config.snapshot?.interval\n ? Duration.decode(config.snapshot.interval)\n : DEFAULT_SNAPSHOT_INTERVAL,\n transactionThreshold:\n config.snapshot?.transactionThreshold ?? DEFAULT_SNAPSHOT_THRESHOLD,\n },\n});\n\n// =============================================================================\n// Factory\n// =============================================================================\n\n/**\n * Create a MimicServerEngine layer.\n *\n * This creates the core document management service. To expose it via WebSocket,\n * use MimicServer.layerHttpLayerRouter().\n *\n * @example\n * ```typescript\n * // 1. Create the engine\n * const Engine = MimicServerEngine.make({\n * schema: DocSchema,\n * initial: { title: \"Untitled\" },\n * presence: CursorPresence,\n * maxIdleTime: \"5 minutes\",\n * snapshot: { interval: \"5 minutes\", transactionThreshold: 100 },\n * })\n *\n * // 2. Create the WebSocket route\n * const MimicRoute = MimicServer.layerHttpLayerRouter({\n * path: \"/mimic\",\n * })\n *\n * // 3. Wire together\n * const MimicLive = MimicRoute.pipe(\n * Layer.provide(Engine),\n * Layer.provide(ColdStorage.InMemory.make()),\n * Layer.provide(HotStorage.InMemory.make()),\n * Layer.provide(MimicAuthService.NoAuth.make()),\n * )\n * ```\n */\nexport const make = <TSchema extends Primitive.AnyPrimitive>(\n config: MimicServerEngineConfig<TSchema>\n): Layer.Layer<\n MimicServerEngineTag,\n never,\n ColdStorageTag | HotStorageTag | MimicAuthServiceTag\n> => {\n const resolvedConfig = resolveConfig(config);\n\n // Create config layer for DocumentManager\n const configLayer = Layer.succeed(\n DocumentManagerConfigTag,\n resolvedConfig as ResolvedConfig<Primitive.AnyPrimitive>\n );\n\n // Create internal layers\n const internalLayers = Layer.mergeAll(\n documentManagerLayer.pipe(Layer.provide(configLayer)),\n presenceManagerLayer\n );\n\n return Layer.scoped(\n MimicServerEngineTag,\n Effect.gen(function* () {\n const documentManager = yield* DocumentManagerTag;\n const presenceManager = yield* PresenceManagerTag;\n\n const engine: MimicServerEngine = {\n submit: (documentId, transaction) =>\n documentManager.submit(documentId, transaction),\n\n getSnapshot: (documentId) => documentManager.getSnapshot(documentId),\n\n subscribe: (documentId) =>\n documentManager.subscribe(documentId) as Effect.Effect<\n Stream.Stream<Protocol.ServerMessage, never, never>,\n never\n >,\n\n touch: (documentId) => documentManager.touch(documentId),\n\n getPresenceSnapshot: (documentId) =>\n presenceManager.getSnapshot(documentId),\n\n setPresence: (documentId, connectionId, entry) =>\n presenceManager.set(documentId, connectionId, entry),\n\n removePresence: (documentId, connectionId) =>\n presenceManager.remove(documentId, connectionId),\n\n subscribePresence: (documentId) =>\n presenceManager.subscribe(documentId),\n\n config: resolvedConfig as ResolvedConfig<Primitive.AnyPrimitive>,\n };\n\n return engine;\n })\n ).pipe(Layer.provide(internalLayers));\n};\n\n// =============================================================================\n// Re-export namespace\n// =============================================================================\n\nexport const MimicServerEngine = {\n Tag: MimicServerEngineTag,\n make,\n};\n\n// =============================================================================\n// Re-export SubmitResult type\n// =============================================================================\n\nexport type { SubmitResult };\n"],"mappings":";;;;;;;;;;;;;;;;AAkIA,IAAa,uBAAb,cAA0C,QAAQ,IAChD,2CACD,EAA2C,CAAC;AAM7C,MAAM,wBAAwB,SAAS,QAAQ,EAAE;AACjD,MAAM,kCAAkC;AACxC,MAAM,4BAA4B,SAAS,QAAQ,EAAE;AACrD,MAAM,6BAA6B;;;;AAKnC,MAAM,iBACJ,WAC4B;;QAAC;EAC7B,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB,UAAU,OAAO;EACjB,aAAa,OAAO,cAChB,SAAS,OAAO,OAAO,YAAY,GACnC;EACJ,gDACE,OAAO,8FAAyB;EAClC,UAAU;GACR,+BAAU,OAAO,8EAAU,YACvB,SAAS,OAAO,OAAO,SAAS,SAAS,GACzC;GACJ,oEACE,OAAO,gFAAU,6FAAwB;GAC5C;EACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCD,MAAa,QACX,WAKG;CACH,MAAM,iBAAiB,cAAc,OAAO;CAG5C,MAAM,cAAc,MAAM,QACxB,0BACA,eACD;CAGD,MAAM,iBAAiB,MAAM,SAC3BA,MAAqB,KAAK,MAAM,QAAQ,YAAY,CAAC,EACrDC,QACD;AAED,QAAO,MAAM,OACX,sBACA,OAAO,IAAI,aAAa;EACtB,MAAM,kBAAkB,OAAO;EAC/B,MAAM,kBAAkB,OAAO;AA+B/B,SA7BkC;GAChC,SAAS,YAAY,gBACnB,gBAAgB,OAAO,YAAY,YAAY;GAEjD,cAAc,eAAe,gBAAgB,YAAY,WAAW;GAEpE,YAAY,eACV,gBAAgB,UAAU,WAAW;GAKvC,QAAQ,eAAe,gBAAgB,MAAM,WAAW;GAExD,sBAAsB,eACpB,gBAAgB,YAAY,WAAW;GAEzC,cAAc,YAAY,cAAc,UACtC,gBAAgB,IAAI,YAAY,cAAc,MAAM;GAEtD,iBAAiB,YAAY,iBAC3B,gBAAgB,OAAO,YAAY,aAAa;GAElD,oBAAoB,eAClB,gBAAgB,UAAU,WAAW;GAEvC,QAAQ;GACT;GAGD,CACH,CAAC,KAAK,MAAM,QAAQ,eAAe,CAAC;;AAOvC,MAAa,oBAAoB;CAC/B,KAAK;CACL;CACD"}
|
package/dist/PresenceManager.cjs
CHANGED
|
@@ -1,108 +1,92 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
let effect_Layer = require("effect/Layer");
|
|
5
|
-
effect_Layer = require_rolldown_runtime.__toESM(effect_Layer);
|
|
6
|
-
let effect_PubSub = require("effect/PubSub");
|
|
7
|
-
effect_PubSub = require_rolldown_runtime.__toESM(effect_PubSub);
|
|
8
|
-
let effect_Ref = require("effect/Ref");
|
|
9
|
-
effect_Ref = require_rolldown_runtime.__toESM(effect_Ref);
|
|
10
|
-
let effect_HashMap = require("effect/HashMap");
|
|
11
|
-
effect_HashMap = require_rolldown_runtime.__toESM(effect_HashMap);
|
|
12
|
-
let effect_Context = require("effect/Context");
|
|
13
|
-
effect_Context = require_rolldown_runtime.__toESM(effect_Context);
|
|
14
|
-
let effect_Stream = require("effect/Stream");
|
|
15
|
-
effect_Stream = require_rolldown_runtime.__toESM(effect_Stream);
|
|
1
|
+
const require_Metrics = require('./Metrics.cjs');
|
|
2
|
+
const require_objectSpread2 = require('./_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.cjs');
|
|
3
|
+
let effect = require("effect");
|
|
16
4
|
|
|
17
5
|
//#region src/PresenceManager.ts
|
|
18
6
|
/**
|
|
19
|
-
* @
|
|
20
|
-
*
|
|
21
|
-
*
|
|
7
|
+
* @voidhash/mimic-effect - PresenceManager
|
|
8
|
+
*
|
|
9
|
+
* Internal service for managing presence state per document.
|
|
22
10
|
*/
|
|
23
|
-
var PresenceManager_exports = /* @__PURE__ */ require_rolldown_runtime.__export({
|
|
24
|
-
PresenceManagerTag: () => PresenceManagerTag,
|
|
25
|
-
layer: () => layer,
|
|
26
|
-
layerDefault: () => layerDefault
|
|
27
|
-
});
|
|
28
11
|
/**
|
|
29
|
-
* Context tag for PresenceManager
|
|
12
|
+
* Context tag for PresenceManager service
|
|
30
13
|
*/
|
|
31
|
-
var PresenceManagerTag = class extends
|
|
14
|
+
var PresenceManagerTag = class extends effect.Context.Tag("@voidhash/mimic-effect/PresenceManager")() {};
|
|
32
15
|
/**
|
|
33
|
-
* Create the PresenceManager
|
|
16
|
+
* Create the PresenceManager layer.
|
|
34
17
|
*/
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
18
|
+
const layer = effect.Layer.effect(PresenceManagerTag, effect.Effect.gen(function* () {
|
|
19
|
+
const store = yield* effect.Ref.make(effect.HashMap.empty());
|
|
20
|
+
/**
|
|
21
|
+
* Get or create presence state for a document
|
|
22
|
+
*/
|
|
23
|
+
const getOrCreateDocumentState = (documentId) => effect.Effect.gen(function* () {
|
|
24
|
+
const current = yield* effect.Ref.get(store);
|
|
25
|
+
const existing = effect.HashMap.get(current, documentId);
|
|
40
26
|
if (existing._tag === "Some") return existing.value;
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
27
|
+
const pubsub = yield* effect.PubSub.unbounded();
|
|
28
|
+
const state = {
|
|
29
|
+
presences: effect.HashMap.empty(),
|
|
30
|
+
pubsub
|
|
44
31
|
};
|
|
45
|
-
yield*
|
|
46
|
-
return
|
|
47
|
-
});
|
|
48
|
-
const getSnapshot = (documentId) => effect_Effect.gen(function* () {
|
|
49
|
-
const docPresence = yield* getOrCreateDocument(documentId);
|
|
50
|
-
const entriesMap = yield* effect_Ref.get(docPresence.entries);
|
|
51
|
-
const presences = {};
|
|
52
|
-
for (const [id, entry] of entriesMap) presences[id] = entry;
|
|
53
|
-
return { presences };
|
|
54
|
-
});
|
|
55
|
-
const set = (documentId, connectionId, entry) => effect_Effect.gen(function* () {
|
|
56
|
-
const docPresence = yield* getOrCreateDocument(documentId);
|
|
57
|
-
yield* effect_Ref.update(docPresence.entries, (map) => effect_HashMap.set(map, connectionId, entry));
|
|
58
|
-
yield* effect_PubSub.publish(docPresence.pubsub, {
|
|
59
|
-
type: "presence_update",
|
|
60
|
-
id: connectionId,
|
|
61
|
-
data: entry.data,
|
|
62
|
-
userId: entry.userId
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
const remove = (documentId, connectionId) => effect_Effect.gen(function* () {
|
|
66
|
-
const current = yield* effect_Ref.get(documents);
|
|
67
|
-
const existing = effect_HashMap.get(current, documentId);
|
|
68
|
-
if (existing._tag === "None") return;
|
|
69
|
-
const docPresence = existing.value;
|
|
70
|
-
const entries = yield* effect_Ref.get(docPresence.entries);
|
|
71
|
-
if (!effect_HashMap.has(entries, connectionId)) return;
|
|
72
|
-
yield* effect_Ref.update(docPresence.entries, (map) => effect_HashMap.remove(map, connectionId));
|
|
73
|
-
yield* effect_PubSub.publish(docPresence.pubsub, {
|
|
74
|
-
type: "presence_remove",
|
|
75
|
-
id: connectionId
|
|
76
|
-
});
|
|
77
|
-
});
|
|
78
|
-
const subscribe = (documentId) => effect_Effect.gen(function* () {
|
|
79
|
-
const docPresence = yield* getOrCreateDocument(documentId);
|
|
80
|
-
const queue = yield* effect_PubSub.subscribe(docPresence.pubsub);
|
|
81
|
-
return effect_Stream.fromQueue(queue);
|
|
32
|
+
yield* effect.Ref.update(store, (map) => effect.HashMap.set(map, documentId, state));
|
|
33
|
+
return state;
|
|
82
34
|
});
|
|
83
35
|
return {
|
|
84
|
-
getSnapshot
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
36
|
+
getSnapshot: (documentId) => effect.Effect.gen(function* () {
|
|
37
|
+
const current = yield* effect.Ref.get(store);
|
|
38
|
+
const existing = effect.HashMap.get(current, documentId);
|
|
39
|
+
if (existing._tag === "None") return { presences: {} };
|
|
40
|
+
const presences = {};
|
|
41
|
+
for (const [id, entry] of existing.value.presences) presences[id] = entry;
|
|
42
|
+
return { presences };
|
|
43
|
+
}),
|
|
44
|
+
set: (documentId, connectionId, entry) => effect.Effect.gen(function* () {
|
|
45
|
+
const state = yield* getOrCreateDocumentState(documentId);
|
|
46
|
+
yield* effect.Ref.update(store, (map) => {
|
|
47
|
+
const existing = effect.HashMap.get(map, documentId);
|
|
48
|
+
if (existing._tag === "None") return map;
|
|
49
|
+
return effect.HashMap.set(map, documentId, require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, existing.value), {}, { presences: effect.HashMap.set(existing.value.presences, connectionId, entry) }));
|
|
50
|
+
});
|
|
51
|
+
yield* effect.Metric.increment(require_Metrics.presenceUpdates);
|
|
52
|
+
yield* effect.Metric.incrementBy(require_Metrics.presenceActive, 1);
|
|
53
|
+
const event = {
|
|
54
|
+
type: "presence_update",
|
|
55
|
+
id: connectionId,
|
|
56
|
+
data: entry.data,
|
|
57
|
+
userId: entry.userId
|
|
58
|
+
};
|
|
59
|
+
yield* effect.PubSub.publish(state.pubsub, event);
|
|
60
|
+
}),
|
|
61
|
+
remove: (documentId, connectionId) => effect.Effect.gen(function* () {
|
|
62
|
+
const current = yield* effect.Ref.get(store);
|
|
63
|
+
const existing = effect.HashMap.get(current, documentId);
|
|
64
|
+
if (existing._tag === "None") return;
|
|
65
|
+
if (!effect.HashMap.has(existing.value.presences, connectionId)) return;
|
|
66
|
+
yield* effect.Ref.update(store, (map) => {
|
|
67
|
+
const docState = effect.HashMap.get(map, documentId);
|
|
68
|
+
if (docState._tag === "None") return map;
|
|
69
|
+
return effect.HashMap.set(map, documentId, require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, docState.value), {}, { presences: effect.HashMap.remove(docState.value.presences, connectionId) }));
|
|
70
|
+
});
|
|
71
|
+
yield* effect.Metric.incrementBy(require_Metrics.presenceActive, -1);
|
|
72
|
+
const event = {
|
|
73
|
+
type: "presence_remove",
|
|
74
|
+
id: connectionId
|
|
75
|
+
};
|
|
76
|
+
yield* effect.PubSub.publish(existing.value.pubsub, event);
|
|
77
|
+
}),
|
|
78
|
+
subscribe: (documentId) => effect.Effect.gen(function* () {
|
|
79
|
+
const state = yield* getOrCreateDocumentState(documentId);
|
|
80
|
+
return effect.Stream.fromPubSub(state.pubsub);
|
|
81
|
+
})
|
|
88
82
|
};
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Default layer that provides PresenceManager.
|
|
96
|
-
* Uses the default priority for layer composition.
|
|
97
|
-
*/
|
|
98
|
-
const layerDefault = effect_Layer.effectDiscard(effect_Effect.succeed(void 0)).pipe(effect_Layer.provideMerge(layer));
|
|
83
|
+
}));
|
|
84
|
+
const PresenceManager = {
|
|
85
|
+
Tag: PresenceManagerTag,
|
|
86
|
+
layer
|
|
87
|
+
};
|
|
99
88
|
|
|
100
89
|
//#endregion
|
|
90
|
+
exports.PresenceManager = PresenceManager;
|
|
101
91
|
exports.PresenceManagerTag = PresenceManagerTag;
|
|
102
|
-
Object.defineProperty(exports, 'PresenceManager_exports', {
|
|
103
|
-
enumerable: true,
|
|
104
|
-
get: function () {
|
|
105
|
-
return PresenceManager_exports;
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
92
|
exports.layer = layer;
|
|
@@ -1,91 +1,42 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import * as Context from "effect/Context";
|
|
4
|
-
import * as Scope from "effect/Scope";
|
|
5
|
-
import * as Stream from "effect/Stream";
|
|
1
|
+
import { PresenceEntry, PresenceEvent, PresenceSnapshot } from "./Types.cjs";
|
|
2
|
+
import { Context, Effect, Layer, Scope, Stream } from "effect";
|
|
6
3
|
|
|
7
4
|
//#region src/PresenceManager.d.ts
|
|
8
|
-
|
|
9
|
-
export { PresenceEntry, PresenceEvent, PresenceManager, PresenceManagerTag, PresenceRemoveEvent, PresenceSnapshot, PresenceUpdateEvent, layer, layerDefault };
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* A presence entry stored in the manager.
|
|
13
|
-
*/
|
|
14
|
-
interface PresenceEntry {
|
|
15
|
-
/** The presence data */
|
|
16
|
-
readonly data: unknown;
|
|
17
|
-
/** Optional user ID from authentication */
|
|
18
|
-
readonly userId?: string;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Event emitted when a presence is updated.
|
|
22
|
-
*/
|
|
23
|
-
interface PresenceUpdateEvent {
|
|
24
|
-
readonly type: "presence_update";
|
|
25
|
-
/** The connection ID of the user who updated */
|
|
26
|
-
readonly id: string;
|
|
27
|
-
/** The presence data */
|
|
28
|
-
readonly data: unknown;
|
|
29
|
-
/** Optional user ID from authentication */
|
|
30
|
-
readonly userId?: string;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Event emitted when a presence is removed (user disconnected).
|
|
34
|
-
*/
|
|
35
|
-
interface PresenceRemoveEvent {
|
|
36
|
-
readonly type: "presence_remove";
|
|
37
|
-
/** The connection ID of the user who disconnected */
|
|
38
|
-
readonly id: string;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Union of all presence events.
|
|
42
|
-
*/
|
|
43
|
-
type PresenceEvent = PresenceUpdateEvent | PresenceRemoveEvent;
|
|
44
|
-
/**
|
|
45
|
-
* A snapshot of all presence entries for a document.
|
|
46
|
-
*/
|
|
47
|
-
interface PresenceSnapshot {
|
|
48
|
-
/** Map of connectionId to presence entry */
|
|
49
|
-
readonly presences: Record<string, PresenceEntry>;
|
|
50
|
-
}
|
|
5
|
+
|
|
51
6
|
/**
|
|
52
|
-
*
|
|
7
|
+
* Internal service for managing presence state per document.
|
|
8
|
+
*
|
|
9
|
+
* Presence is ephemeral state associated with connections, not persisted.
|
|
10
|
+
* Each document has its own set of presences, keyed by connectionId.
|
|
53
11
|
*/
|
|
54
12
|
interface PresenceManager {
|
|
55
13
|
/**
|
|
56
|
-
* Get
|
|
14
|
+
* Get snapshot of all presences for a document.
|
|
57
15
|
*/
|
|
58
16
|
readonly getSnapshot: (documentId: string) => Effect.Effect<PresenceSnapshot>;
|
|
59
17
|
/**
|
|
60
18
|
* Set/update presence for a connection.
|
|
61
|
-
* Broadcasts the update to all subscribers.
|
|
62
19
|
*/
|
|
63
20
|
readonly set: (documentId: string, connectionId: string, entry: PresenceEntry) => Effect.Effect<void>;
|
|
64
21
|
/**
|
|
65
|
-
* Remove presence for a connection (
|
|
66
|
-
* Broadcasts the removal to all subscribers.
|
|
22
|
+
* Remove presence for a connection (on disconnect).
|
|
67
23
|
*/
|
|
68
24
|
readonly remove: (documentId: string, connectionId: string) => Effect.Effect<void>;
|
|
69
25
|
/**
|
|
70
26
|
* Subscribe to presence events for a document.
|
|
71
|
-
* Returns a
|
|
27
|
+
* Returns a stream of presence update/remove events.
|
|
72
28
|
*/
|
|
73
29
|
readonly subscribe: (documentId: string) => Effect.Effect<Stream.Stream<PresenceEvent>, never, Scope.Scope>;
|
|
74
30
|
}
|
|
75
|
-
declare const PresenceManagerTag_base: Context.TagClass<PresenceManagerTag, "@voidhash/mimic-
|
|
31
|
+
declare const PresenceManagerTag_base: Context.TagClass<PresenceManagerTag, "@voidhash/mimic-effect/PresenceManager", PresenceManager>;
|
|
76
32
|
/**
|
|
77
|
-
* Context tag for PresenceManager
|
|
33
|
+
* Context tag for PresenceManager service
|
|
78
34
|
*/
|
|
79
35
|
declare class PresenceManagerTag extends PresenceManagerTag_base {}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Default layer that provides PresenceManager.
|
|
86
|
-
* Uses the default priority for layer composition.
|
|
87
|
-
*/
|
|
88
|
-
declare const layerDefault: Layer.Layer<PresenceManagerTag>;
|
|
36
|
+
declare const PresenceManager: {
|
|
37
|
+
Tag: typeof PresenceManagerTag;
|
|
38
|
+
layer: Layer.Layer<PresenceManagerTag, never, never>;
|
|
39
|
+
};
|
|
89
40
|
//#endregion
|
|
90
|
-
export {
|
|
41
|
+
export { PresenceManager, PresenceManagerTag };
|
|
91
42
|
//# sourceMappingURL=PresenceManager.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PresenceManager.d.cts","names":[],"sources":["../src/PresenceManager.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PresenceManager.d.cts","names":[],"sources":["../src/PresenceManager.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAgEO,UA/BU,eAAA,CA+BH;EAAM;AACnB;;gDA1BM,MAAA,CAAO,OAAO;;;AAmCrB;EAoJa,SAAA,GAAA,EAAA,CAAA,UAGZ,EAAA,MAAA,EAAA,YAAA,EAAA,MAAA,EAAA,KAAA,EAlLU,aAkLV,EAAA,GAjLM,MAAA,CAAO,MAiLb,CAAA,IAAA,CAAA;;;;iEAzKM,MAAA,CAAO;;;;;8CAQP,MAAA,CAAO,OAAO,MAAA,CAAO,OAAO,uBAAuB,KAAA,CAAM;;cAC/D;;;;cASY,kBAAA,SAA2B,uBAAA;cAoJ3B"}
|
|
@@ -1,91 +1,42 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import * as Context from "effect/Context";
|
|
4
|
-
import * as Stream from "effect/Stream";
|
|
5
|
-
import * as Scope from "effect/Scope";
|
|
1
|
+
import { PresenceEntry, PresenceEvent, PresenceSnapshot } from "./Types.mjs";
|
|
2
|
+
import { Context, Effect, Layer, Scope, Stream } from "effect";
|
|
6
3
|
|
|
7
4
|
//#region src/PresenceManager.d.ts
|
|
8
|
-
|
|
9
|
-
export { PresenceEntry, PresenceEvent, PresenceManager, PresenceManagerTag, PresenceRemoveEvent, PresenceSnapshot, PresenceUpdateEvent, layer, layerDefault };
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* A presence entry stored in the manager.
|
|
13
|
-
*/
|
|
14
|
-
interface PresenceEntry {
|
|
15
|
-
/** The presence data */
|
|
16
|
-
readonly data: unknown;
|
|
17
|
-
/** Optional user ID from authentication */
|
|
18
|
-
readonly userId?: string;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Event emitted when a presence is updated.
|
|
22
|
-
*/
|
|
23
|
-
interface PresenceUpdateEvent {
|
|
24
|
-
readonly type: "presence_update";
|
|
25
|
-
/** The connection ID of the user who updated */
|
|
26
|
-
readonly id: string;
|
|
27
|
-
/** The presence data */
|
|
28
|
-
readonly data: unknown;
|
|
29
|
-
/** Optional user ID from authentication */
|
|
30
|
-
readonly userId?: string;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Event emitted when a presence is removed (user disconnected).
|
|
34
|
-
*/
|
|
35
|
-
interface PresenceRemoveEvent {
|
|
36
|
-
readonly type: "presence_remove";
|
|
37
|
-
/** The connection ID of the user who disconnected */
|
|
38
|
-
readonly id: string;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Union of all presence events.
|
|
42
|
-
*/
|
|
43
|
-
type PresenceEvent = PresenceUpdateEvent | PresenceRemoveEvent;
|
|
44
|
-
/**
|
|
45
|
-
* A snapshot of all presence entries for a document.
|
|
46
|
-
*/
|
|
47
|
-
interface PresenceSnapshot {
|
|
48
|
-
/** Map of connectionId to presence entry */
|
|
49
|
-
readonly presences: Record<string, PresenceEntry>;
|
|
50
|
-
}
|
|
5
|
+
|
|
51
6
|
/**
|
|
52
|
-
*
|
|
7
|
+
* Internal service for managing presence state per document.
|
|
8
|
+
*
|
|
9
|
+
* Presence is ephemeral state associated with connections, not persisted.
|
|
10
|
+
* Each document has its own set of presences, keyed by connectionId.
|
|
53
11
|
*/
|
|
54
12
|
interface PresenceManager {
|
|
55
13
|
/**
|
|
56
|
-
* Get
|
|
14
|
+
* Get snapshot of all presences for a document.
|
|
57
15
|
*/
|
|
58
16
|
readonly getSnapshot: (documentId: string) => Effect.Effect<PresenceSnapshot>;
|
|
59
17
|
/**
|
|
60
18
|
* Set/update presence for a connection.
|
|
61
|
-
* Broadcasts the update to all subscribers.
|
|
62
19
|
*/
|
|
63
20
|
readonly set: (documentId: string, connectionId: string, entry: PresenceEntry) => Effect.Effect<void>;
|
|
64
21
|
/**
|
|
65
|
-
* Remove presence for a connection (
|
|
66
|
-
* Broadcasts the removal to all subscribers.
|
|
22
|
+
* Remove presence for a connection (on disconnect).
|
|
67
23
|
*/
|
|
68
24
|
readonly remove: (documentId: string, connectionId: string) => Effect.Effect<void>;
|
|
69
25
|
/**
|
|
70
26
|
* Subscribe to presence events for a document.
|
|
71
|
-
* Returns a
|
|
27
|
+
* Returns a stream of presence update/remove events.
|
|
72
28
|
*/
|
|
73
29
|
readonly subscribe: (documentId: string) => Effect.Effect<Stream.Stream<PresenceEvent>, never, Scope.Scope>;
|
|
74
30
|
}
|
|
75
|
-
declare const PresenceManagerTag_base: Context.TagClass<PresenceManagerTag, "@voidhash/mimic-
|
|
31
|
+
declare const PresenceManagerTag_base: Context.TagClass<PresenceManagerTag, "@voidhash/mimic-effect/PresenceManager", PresenceManager>;
|
|
76
32
|
/**
|
|
77
|
-
* Context tag for PresenceManager
|
|
33
|
+
* Context tag for PresenceManager service
|
|
78
34
|
*/
|
|
79
35
|
declare class PresenceManagerTag extends PresenceManagerTag_base {}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Default layer that provides PresenceManager.
|
|
86
|
-
* Uses the default priority for layer composition.
|
|
87
|
-
*/
|
|
88
|
-
declare const layerDefault: Layer.Layer<PresenceManagerTag>;
|
|
36
|
+
declare const PresenceManager: {
|
|
37
|
+
Tag: typeof PresenceManagerTag;
|
|
38
|
+
layer: Layer.Layer<PresenceManagerTag, never, never>;
|
|
39
|
+
};
|
|
89
40
|
//#endregion
|
|
90
|
-
export {
|
|
41
|
+
export { PresenceManager, PresenceManagerTag };
|
|
91
42
|
//# sourceMappingURL=PresenceManager.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PresenceManager.d.mts","names":[],"sources":["../src/PresenceManager.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PresenceManager.d.mts","names":[],"sources":["../src/PresenceManager.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAgEO,UA/BU,eAAA,CA+BH;EAAM;AACnB;;gDA1BM,MAAA,CAAO,OAAO;;;AAmCrB;EAoJa,SAAA,GAAA,EAAA,CAAA,UAGZ,EAAA,MAAA,EAAA,YAAA,EAAA,MAAA,EAAA,KAAA,EAlLU,aAkLV,EAAA,GAjLM,MAAA,CAAO,MAiLb,CAAA,IAAA,CAAA;;;;iEAzKM,MAAA,CAAO;;;;;8CAQP,MAAA,CAAO,OAAO,MAAA,CAAO,OAAO,uBAAuB,KAAA,CAAM;;cAC/D;;;;cASY,kBAAA,SAA2B,uBAAA;cAoJ3B"}
|