@voidhash/mimic-effect 1.0.0-beta.1 → 1.0.0-beta.11
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 +116 -74
- package/dist/ColdStorage.cjs +9 -5
- package/dist/ColdStorage.d.cts.map +1 -1
- package/dist/ColdStorage.d.mts.map +1 -1
- package/dist/ColdStorage.mjs +9 -5
- package/dist/ColdStorage.mjs.map +1 -1
- package/dist/DocumentInstance.cjs +264 -0
- package/dist/DocumentInstance.d.cts +78 -0
- package/dist/DocumentInstance.d.cts.map +1 -0
- package/dist/DocumentInstance.d.mts +78 -0
- package/dist/DocumentInstance.d.mts.map +1 -0
- package/dist/DocumentInstance.mjs +265 -0
- package/dist/DocumentInstance.mjs.map +1 -0
- package/dist/Errors.cjs +10 -1
- package/dist/Errors.d.cts +18 -3
- package/dist/Errors.d.cts.map +1 -1
- package/dist/Errors.d.mts +18 -3
- package/dist/Errors.d.mts.map +1 -1
- package/dist/Errors.mjs +9 -1
- package/dist/Errors.mjs.map +1 -1
- package/dist/HotStorage.cjs +40 -12
- package/dist/HotStorage.d.cts +21 -1
- package/dist/HotStorage.d.cts.map +1 -1
- package/dist/HotStorage.d.mts +21 -1
- package/dist/HotStorage.d.mts.map +1 -1
- package/dist/HotStorage.mjs +40 -12
- package/dist/HotStorage.mjs.map +1 -1
- package/dist/Metrics.cjs +29 -1
- package/dist/Metrics.d.cts +5 -0
- package/dist/Metrics.d.cts.map +1 -1
- package/dist/Metrics.d.mts +5 -0
- package/dist/Metrics.d.mts.map +1 -1
- package/dist/Metrics.mjs +26 -1
- package/dist/Metrics.mjs.map +1 -1
- package/dist/MimicClusterServerEngine.cjs +44 -139
- package/dist/MimicClusterServerEngine.d.cts.map +1 -1
- package/dist/MimicClusterServerEngine.d.mts +1 -1
- package/dist/MimicClusterServerEngine.d.mts.map +1 -1
- package/dist/MimicClusterServerEngine.mjs +46 -141
- package/dist/MimicClusterServerEngine.mjs.map +1 -1
- package/dist/MimicServer.cjs +20 -20
- package/dist/MimicServer.d.cts.map +1 -1
- package/dist/MimicServer.d.mts.map +1 -1
- package/dist/MimicServer.mjs +20 -20
- package/dist/MimicServer.mjs.map +1 -1
- package/dist/MimicServerEngine.cjs +92 -11
- package/dist/MimicServerEngine.d.cts +12 -4
- package/dist/MimicServerEngine.d.cts.map +1 -1
- package/dist/MimicServerEngine.d.mts +12 -4
- package/dist/MimicServerEngine.d.mts.map +1 -1
- package/dist/MimicServerEngine.mjs +94 -13
- package/dist/MimicServerEngine.mjs.map +1 -1
- package/dist/PresenceManager.cjs +5 -5
- package/dist/PresenceManager.d.cts.map +1 -1
- package/dist/PresenceManager.d.mts.map +1 -1
- package/dist/PresenceManager.mjs +5 -5
- package/dist/PresenceManager.mjs.map +1 -1
- package/dist/Protocol.d.cts +1 -1
- package/dist/Protocol.d.mts +1 -1
- package/dist/Types.d.cts +9 -2
- package/dist/Types.d.cts.map +1 -1
- package/dist/Types.d.mts +9 -2
- package/dist/Types.d.mts.map +1 -1
- package/dist/index.cjs +5 -6
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -3
- 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 +162 -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 +163 -0
- package/dist/testing/FailingStorage.mjs.map +1 -0
- package/dist/testing/HotStorageTestSuite.cjs +858 -0
- package/dist/testing/HotStorageTestSuite.d.cts +42 -0
- package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/HotStorageTestSuite.d.mts +42 -0
- package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/HotStorageTestSuite.mjs +858 -0
- package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.cjs +487 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts +37 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts +37 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs +487 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
- package/dist/testing/assertions.cjs +117 -0
- package/dist/testing/assertions.mjs +112 -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 +8 -3
- package/src/ColdStorage.ts +21 -12
- package/src/DocumentInstance.ts +531 -0
- package/src/Errors.ts +15 -1
- package/src/HotStorage.ts +130 -24
- package/src/Metrics.ts +30 -0
- package/src/MimicClusterServerEngine.ts +120 -275
- package/src/MimicServer.ts +83 -75
- package/src/MimicServerEngine.ts +230 -30
- package/src/PresenceManager.ts +44 -34
- package/src/Types.ts +9 -2
- package/src/index.ts +5 -35
- package/src/testing/ColdStorageTestSuite.ts +589 -0
- package/src/testing/FailingStorage.ts +338 -0
- package/src/testing/HotStorageTestSuite.ts +1161 -0
- package/src/testing/StorageIntegrationTestSuite.ts +736 -0
- package/src/testing/assertions.ts +188 -0
- package/src/testing/index.ts +83 -0
- package/src/testing/types.ts +100 -0
- package/tests/ColdStorage.test.ts +8 -120
- package/tests/DocumentInstance.test.ts +669 -0
- package/tests/HotStorage.test.ts +7 -126
- package/tests/StorageIntegration.test.ts +259 -0
- package/tsdown.config.ts +1 -1
- package/dist/DocumentManager.cjs +0 -229
- package/dist/DocumentManager.d.cts +0 -59
- package/dist/DocumentManager.d.cts.map +0 -1
- package/dist/DocumentManager.d.mts +0 -59
- package/dist/DocumentManager.d.mts.map +0 -1
- package/dist/DocumentManager.mjs +0 -227
- package/dist/DocumentManager.mjs.map +0 -1
- package/src/DocumentManager.ts +0 -506
- package/tests/DocumentManager.test.ts +0 -335
package/dist/HotStorage.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WalVersionGapError } from "./Errors.mjs";
|
|
1
2
|
import { Context, Effect, HashMap, Layer, Ref } from "effect";
|
|
2
3
|
|
|
3
4
|
//#region src/HotStorage.ts
|
|
@@ -44,27 +45,54 @@ var HotStorageTag = class extends Context.Tag("@voidhash/mimic-effect/HotStorage
|
|
|
44
45
|
const make = (effect) => Layer.effect(HotStorageTag, effect);
|
|
45
46
|
let InMemory;
|
|
46
47
|
(function(_InMemory) {
|
|
47
|
-
_InMemory.make = () => Layer.effect(HotStorageTag, Effect.
|
|
48
|
+
_InMemory.make = () => Layer.effect(HotStorageTag, Effect.fn("hot-storage.in-memory.create")(function* () {
|
|
48
49
|
const store = yield* Ref.make(HashMap.empty());
|
|
49
50
|
return {
|
|
50
|
-
append: (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
append: Effect.fn("hot-storage.append")(function* (documentId, entry) {
|
|
52
|
+
yield* Ref.update(store, (map) => {
|
|
53
|
+
const existing = HashMap.get(map, documentId);
|
|
54
|
+
const entries = existing._tag === "Some" ? existing.value : [];
|
|
55
|
+
return HashMap.set(map, documentId, [...entries, entry]);
|
|
56
|
+
});
|
|
54
57
|
}),
|
|
55
|
-
|
|
58
|
+
appendWithCheck: Effect.fn("hot-storage.append-with-check")(function* (documentId, entry, expectedVersion, baseVersion) {
|
|
59
|
+
const result = yield* Ref.modify(store, (map) => {
|
|
60
|
+
const existing = HashMap.get(map, documentId);
|
|
61
|
+
const entries = existing._tag === "Some" ? existing.value : [];
|
|
62
|
+
const lastEntryVersion = entries.length > 0 ? Math.max(...entries.map((e) => e.version)) : 0;
|
|
63
|
+
const effectiveLastVersion = baseVersion !== void 0 ? Math.max(lastEntryVersion, baseVersion) : lastEntryVersion;
|
|
64
|
+
if (expectedVersion === 1) {
|
|
65
|
+
if (effectiveLastVersion >= 1) return [{
|
|
66
|
+
type: "gap",
|
|
67
|
+
lastVersion: effectiveLastVersion
|
|
68
|
+
}, map];
|
|
69
|
+
} else if (effectiveLastVersion !== expectedVersion - 1) return [{
|
|
70
|
+
type: "gap",
|
|
71
|
+
lastVersion: effectiveLastVersion > 0 ? effectiveLastVersion : void 0
|
|
72
|
+
}, map];
|
|
73
|
+
return [{ type: "ok" }, HashMap.set(map, documentId, [...entries, entry])];
|
|
74
|
+
});
|
|
75
|
+
if (result.type === "gap") return yield* Effect.fail(new WalVersionGapError({
|
|
76
|
+
documentId,
|
|
77
|
+
expectedVersion,
|
|
78
|
+
actualPreviousVersion: result.lastVersion
|
|
79
|
+
}));
|
|
80
|
+
}),
|
|
81
|
+
getEntries: Effect.fn("hot-storage.get-entries")(function* (documentId, sinceVersion) {
|
|
56
82
|
const current = yield* Ref.get(store);
|
|
57
83
|
const existing = HashMap.get(current, documentId);
|
|
58
84
|
return (existing._tag === "Some" ? existing.value : []).filter((e) => e.version > sinceVersion).sort((a, b) => a.version - b.version);
|
|
59
85
|
}),
|
|
60
|
-
truncate: (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
86
|
+
truncate: Effect.fn("hot-storage.truncate")(function* (documentId, upToVersion) {
|
|
87
|
+
yield* Ref.update(store, (map) => {
|
|
88
|
+
const existing = HashMap.get(map, documentId);
|
|
89
|
+
if (existing._tag === "None") return map;
|
|
90
|
+
const filtered = existing.value.filter((e) => e.version > upToVersion);
|
|
91
|
+
return HashMap.set(map, documentId, filtered);
|
|
92
|
+
});
|
|
65
93
|
})
|
|
66
94
|
};
|
|
67
|
-
}));
|
|
95
|
+
})());
|
|
68
96
|
})(InMemory || (InMemory = {}));
|
|
69
97
|
const HotStorage = {
|
|
70
98
|
Tag: HotStorageTag,
|
package/dist/HotStorage.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HotStorage.mjs","names":[],"sources":["../src/HotStorage.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - HotStorage\n *\n * Interface and implementations for Write-Ahead Log (WAL) storage.\n */\nimport { Context, Effect, HashMap, Layer, Ref } from \"effect\";\nimport type { WalEntry } from \"./Types\";\nimport { HotStorageError } from \"./Errors\";\n\n// =============================================================================\n// HotStorage Interface\n// =============================================================================\n\n/**\n * HotStorage interface for storing Write-Ahead Log entries.\n *\n * This is the \"hot\" tier of the two-tier storage system.\n * It stores every transaction as a WAL entry for durability between snapshots.\n * WAL entries are small (just the transaction) and writes are append-only.\n */\nexport interface HotStorage {\n /**\n * Append a WAL entry for a document.\n */\n readonly append: (\n documentId: string,\n entry: WalEntry\n ) => Effect.Effect<void, HotStorageError>;\n\n /**\n * Get all WAL entries for a document since a given version.\n * Returns entries with version > sinceVersion, ordered by version.\n */\n readonly getEntries: (\n documentId: string,\n sinceVersion: number\n ) => Effect.Effect<WalEntry[], HotStorageError>;\n\n /**\n * Truncate WAL entries up to (and including) a given version.\n * Called after a snapshot is saved to remove entries that are now in the snapshot.\n */\n readonly truncate: (\n documentId: string,\n upToVersion: number\n ) => Effect.Effect<void, HotStorageError>;\n}\n\n// =============================================================================\n// Context Tag\n// =============================================================================\n\n/**\n * Context tag for HotStorage service\n */\nexport class HotStorageTag extends Context.Tag(\"@voidhash/mimic-effect/HotStorage\")<\n HotStorageTag,\n HotStorage\n>() {}\n\n// =============================================================================\n// Factory\n// =============================================================================\n\n/**\n * Create a HotStorage layer from an Effect that produces a HotStorage service.\n *\n * This allows you to access other Effect services when implementing custom storage.\n *\n * @example\n * ```typescript\n * const Hot = HotStorage.make(\n * Effect.gen(function*() {\n * const redis = yield* RedisService\n *\n * return {\n * append: (documentId, entry) =>\n * redis.rpush(`wal:${documentId}`, JSON.stringify(entry)),\n * getEntries: (documentId, sinceVersion) =>\n * redis.lrange(`wal:${documentId}`, 0, -1).pipe(\n * Effect.map(entries =>\n * entries\n * .map(e => JSON.parse(e))\n * .filter(e => e.version > sinceVersion)\n * .sort((a, b) => a.version - b.version)\n * )\n * ),\n * truncate: (documentId, upToVersion) =>\n * // Implementation depends on Redis data structure\n * Effect.void,\n * }\n * })\n * )\n * ```\n */\nexport const make = <E, R>(\n effect: Effect.Effect<HotStorage, E, R>\n): Layer.Layer<HotStorageTag, E, R> =>\n Layer.effect(HotStorageTag, effect);\n\n// =============================================================================\n// InMemory Implementation\n// =============================================================================\n\n/**\n * In-memory HotStorage implementation.\n *\n * Useful for testing and development. Not suitable for production\n * as data is lost when the process restarts.\n */\nexport namespace InMemory {\n /**\n * Create an in-memory HotStorage layer.\n */\n export const make = (): Layer.Layer<HotStorageTag> =>\n Layer.effect(\n HotStorageTag,\n Effect.gen(function* () {\n const store = yield* Ref.make(HashMap.empty<string, WalEntry[]>());\n\n return {\n append: (documentId, entry) =>\n Ref.update(store, (map) => {\n const existing = HashMap.get(map, documentId);\n const entries =\n existing._tag === \"Some\" ? existing.value : [];\n return HashMap.set(map, documentId, [...entries, entry]);\n }),\n\n getEntries: (documentId, sinceVersion) =>\n Effect.gen(function* () {\n const current = yield* Ref.get(store);\n const existing = HashMap.get(current, documentId);\n const entries =\n existing._tag === \"Some\" ? existing.value : [];\n return entries\n .filter((e) => e.version > sinceVersion)\n .sort((a, b) => a.version - b.version);\n }),\n\n truncate: (documentId, upToVersion) =>\n Ref.update(store, (map) => {\n const existing = HashMap.get(map, documentId);\n if (existing._tag === \"None\") {\n return map;\n }\n const filtered = existing.value.filter(\n (e) => e.version > upToVersion\n );\n return HashMap.set(map, documentId, filtered);\n }),\n };\n })\n );\n}\n\n// =============================================================================\n// Re-export namespace\n// =============================================================================\n\nexport const HotStorage = {\n Tag: HotStorageTag,\n make,\n InMemory,\n};\n"],"mappings":";;;;;;;;;;;AAuDA,IAAa,gBAAb,cAAmC,QAAQ,IAAI,oCAAoC,EAGhF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCJ,MAAa,QACX,WAEA,MAAM,OAAO,eAAe,OAAO;;;wBAiBjC,MAAM,OACJ,eACA,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO,IAAI,KAAK,QAAQ,OAA2B,CAAC;AAElE,SAAO;GACL,SAAS,YAAY,UACnB,IAAI,OAAO,QAAQ,QAAQ;IACzB,MAAM,WAAW,QAAQ,IAAI,KAAK,WAAW;IAC7C,MAAM,UACJ,SAAS,SAAS,SAAS,SAAS,QAAQ,EAAE;AAChD,WAAO,QAAQ,IAAI,KAAK,YAAY,CAAC,GAAG,SAAS,MAAM,CAAC;KACxD;GAEJ,aAAa,YAAY,iBACvB,OAAO,IAAI,aAAa;IACtB,MAAM,UAAU,OAAO,IAAI,IAAI,MAAM;IACrC,MAAM,WAAW,QAAQ,IAAI,SAAS,WAAW;AAGjD,YADE,SAAS,SAAS,SAAS,SAAS,QAAQ,EAAE,EAE7C,QAAQ,MAAM,EAAE,UAAU,aAAa,CACvC,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,QAAQ;KACxC;GAEJ,WAAW,YAAY,gBACrB,IAAI,OAAO,QAAQ,QAAQ;IACzB,MAAM,WAAW,QAAQ,IAAI,KAAK,WAAW;AAC7C,QAAI,SAAS,SAAS,OACpB,QAAO;IAET,MAAM,WAAW,SAAS,MAAM,QAC7B,MAAM,EAAE,UAAU,YACpB;AACD,WAAO,QAAQ,IAAI,KAAK,YAAY,SAAS;KAC7C;GACL;GACD,CACH;;AAOL,MAAa,aAAa;CACxB,KAAK;CACL;CACA;CACD"}
|
|
1
|
+
{"version":3,"file":"HotStorage.mjs","names":["result: CheckResult"],"sources":["../src/HotStorage.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - HotStorage\n *\n * Interface and implementations for Write-Ahead Log (WAL) storage.\n */\nimport { Context, Effect, HashMap, Layer, Ref } from \"effect\";\nimport type { WalEntry } from \"./Types\";\nimport { HotStorageError, WalVersionGapError } from \"./Errors\";\n\n// =============================================================================\n// HotStorage Interface\n// =============================================================================\n\n/**\n * HotStorage interface for storing Write-Ahead Log entries.\n *\n * This is the \"hot\" tier of the two-tier storage system.\n * It stores every transaction as a WAL entry for durability between snapshots.\n * WAL entries are small (just the transaction) and writes are append-only.\n */\nexport interface HotStorage {\n /**\n * Append a WAL entry for a document.\n */\n readonly append: (\n documentId: string,\n entry: WalEntry\n ) => Effect.Effect<void, HotStorageError>;\n\n /**\n * Append a WAL entry with version gap checking.\n *\n * This is an atomic operation that:\n * 1. Verifies the previous entry has version = expectedVersion - 1\n * (or this is the first entry if expectedVersion === 1, accounting for baseVersion)\n * 2. Appends the entry if check passes\n *\n * Use this for two-phase commit to guarantee WAL ordering at write time.\n *\n * @param documentId - Document ID\n * @param entry - WAL entry to append\n * @param expectedVersion - The version this entry should have (entry.version)\n * @param baseVersion - Optional known snapshot version. When provided, an empty WAL\n * is treated as \"at this version\" rather than \"new document at version 0\".\n * This is necessary after truncation or restart to correctly validate\n * that the next entry is baseVersion + 1.\n * @returns Effect that fails with WalVersionGapError if gap detected\n */\n readonly appendWithCheck: (\n documentId: string,\n entry: WalEntry,\n expectedVersion: number,\n baseVersion?: number\n ) => Effect.Effect<void, HotStorageError | WalVersionGapError>;\n\n /**\n * Get all WAL entries for a document since a given version.\n * Returns entries with version > sinceVersion, ordered by version.\n */\n readonly getEntries: (\n documentId: string,\n sinceVersion: number\n ) => Effect.Effect<WalEntry[], HotStorageError>;\n\n /**\n * Truncate WAL entries up to (and including) a given version.\n * Called after a snapshot is saved to remove entries that are now in the snapshot.\n */\n readonly truncate: (\n documentId: string,\n upToVersion: number\n ) => Effect.Effect<void, HotStorageError>;\n}\n\n// =============================================================================\n// Context Tag\n// =============================================================================\n\n/**\n * Context tag for HotStorage service\n */\nexport class HotStorageTag extends Context.Tag(\"@voidhash/mimic-effect/HotStorage\")<\n HotStorageTag,\n HotStorage\n>() {}\n\n// =============================================================================\n// Factory\n// =============================================================================\n\n/**\n * Create a HotStorage layer from an Effect that produces a HotStorage service.\n *\n * This allows you to access other Effect services when implementing custom storage.\n *\n * @example\n * ```typescript\n * const Hot = HotStorage.make(\n * Effect.gen(function*() {\n * const redis = yield* RedisService\n *\n * return {\n * append: (documentId, entry) =>\n * redis.rpush(`wal:${documentId}`, JSON.stringify(entry)),\n * getEntries: (documentId, sinceVersion) =>\n * redis.lrange(`wal:${documentId}`, 0, -1).pipe(\n * Effect.map(entries =>\n * entries\n * .map(e => JSON.parse(e))\n * .filter(e => e.version > sinceVersion)\n * .sort((a, b) => a.version - b.version)\n * )\n * ),\n * truncate: (documentId, upToVersion) =>\n * // Implementation depends on Redis data structure\n * Effect.void,\n * }\n * })\n * )\n * ```\n */\nexport const make = <E, R>(\n effect: Effect.Effect<HotStorage, E, R>\n): Layer.Layer<HotStorageTag, E, R> =>\n Layer.effect(HotStorageTag, effect);\n\n// =============================================================================\n// InMemory Implementation\n// =============================================================================\n\n/**\n * In-memory HotStorage implementation.\n *\n * Useful for testing and development. Not suitable for production\n * as data is lost when the process restarts.\n */\nexport namespace InMemory {\n /**\n * Create an in-memory HotStorage layer.\n */\n export const make = (): Layer.Layer<HotStorageTag> =>\n Layer.effect(\n HotStorageTag,\n Effect.fn(\"hot-storage.in-memory.create\")(function* () {\n const store = yield* Ref.make(HashMap.empty<string, WalEntry[]>());\n\n return {\n append: Effect.fn(\"hot-storage.append\")(\n function* (documentId: string, entry: WalEntry) {\n yield* Ref.update(store, (map) => {\n const existing = HashMap.get(map, documentId);\n const entries =\n existing._tag === \"Some\" ? existing.value : [];\n return HashMap.set(map, documentId, [...entries, entry]);\n });\n }\n ),\n\n appendWithCheck: Effect.fn(\"hot-storage.append-with-check\")(\n function* (\n documentId: string,\n entry: WalEntry,\n expectedVersion: number,\n baseVersion?: number\n ) {\n type CheckResult =\n | { type: \"ok\" }\n | { type: \"gap\"; lastVersion: number | undefined };\n\n // Use Ref.modify for atomic check + update\n const result: CheckResult = yield* Ref.modify(\n store,\n (map): [CheckResult, HashMap.HashMap<string, WalEntry[]>] => {\n const existing = HashMap.get(map, documentId);\n const entries =\n existing._tag === \"Some\" ? existing.value : [];\n\n // Find the highest version in existing entries\n const lastEntryVersion =\n entries.length > 0\n ? Math.max(...entries.map((e) => e.version))\n : 0;\n\n // Effective \"last version\" is max of entries and baseVersion\n // This handles the case after truncation or restart where\n // WAL is empty but we know the snapshot version\n const effectiveLastVersion =\n baseVersion !== undefined\n ? Math.max(lastEntryVersion, baseVersion)\n : lastEntryVersion;\n\n // Gap check\n if (expectedVersion === 1) {\n // First entry: should have no entries with version >= 1\n // and baseVersion should be 0 or undefined\n if (effectiveLastVersion >= 1) {\n return [{ type: \"gap\", lastVersion: effectiveLastVersion }, map];\n }\n } else {\n // Not first: effective last version should be expectedVersion - 1\n if (effectiveLastVersion !== expectedVersion - 1) {\n return [\n {\n type: \"gap\",\n lastVersion: effectiveLastVersion > 0 ? effectiveLastVersion : undefined,\n },\n map,\n ];\n }\n }\n\n // No gap: append and return success\n return [\n { type: \"ok\" },\n HashMap.set(map, documentId, [...entries, entry]),\n ];\n }\n );\n\n if (result.type === \"gap\") {\n return yield* Effect.fail(\n new WalVersionGapError({\n documentId,\n expectedVersion,\n actualPreviousVersion: result.lastVersion,\n })\n );\n }\n }\n ),\n\n getEntries: Effect.fn(\"hot-storage.get-entries\")(\n function* (documentId: string, sinceVersion: number) {\n const current = yield* Ref.get(store);\n const existing = HashMap.get(current, documentId);\n const entries =\n existing._tag === \"Some\" ? existing.value : [];\n return entries\n .filter((e) => e.version > sinceVersion)\n .sort((a, b) => a.version - b.version);\n }\n ),\n\n truncate: Effect.fn(\"hot-storage.truncate\")(\n function* (documentId: string, upToVersion: number) {\n yield* Ref.update(store, (map) => {\n const existing = HashMap.get(map, documentId);\n if (existing._tag === \"None\") {\n return map;\n }\n const filtered = existing.value.filter(\n (e) => e.version > upToVersion\n );\n return HashMap.set(map, documentId, filtered);\n });\n }\n ),\n };\n })()\n );\n}\n\n// =============================================================================\n// Re-export namespace\n// =============================================================================\n\nexport const HotStorage = {\n Tag: HotStorageTag,\n make,\n InMemory,\n};\n"],"mappings":";;;;;;;;;;;;AAiFA,IAAa,gBAAb,cAAmC,QAAQ,IAAI,oCAAoC,EAGhF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCJ,MAAa,QACX,WAEA,MAAM,OAAO,eAAe,OAAO;;;wBAiBjC,MAAM,OACJ,eACA,OAAO,GAAG,+BAA+B,CAAC,aAAa;EACrD,MAAM,QAAQ,OAAO,IAAI,KAAK,QAAQ,OAA2B,CAAC;AAElE,SAAO;GACL,QAAQ,OAAO,GAAG,qBAAqB,CACrC,WAAW,YAAoB,OAAiB;AAC9C,WAAO,IAAI,OAAO,QAAQ,QAAQ;KAChC,MAAM,WAAW,QAAQ,IAAI,KAAK,WAAW;KAC7C,MAAM,UACJ,SAAS,SAAS,SAAS,SAAS,QAAQ,EAAE;AAChD,YAAO,QAAQ,IAAI,KAAK,YAAY,CAAC,GAAG,SAAS,MAAM,CAAC;MACxD;KAEL;GAED,iBAAiB,OAAO,GAAG,gCAAgC,CACzD,WACE,YACA,OACA,iBACA,aACA;IAMA,MAAMA,SAAsB,OAAO,IAAI,OACrC,QACC,QAA4D;KAC3D,MAAM,WAAW,QAAQ,IAAI,KAAK,WAAW;KAC7C,MAAM,UACJ,SAAS,SAAS,SAAS,SAAS,QAAQ,EAAE;KAGhD,MAAM,mBACJ,QAAQ,SAAS,IACb,KAAK,IAAI,GAAG,QAAQ,KAAK,MAAM,EAAE,QAAQ,CAAC,GAC1C;KAKN,MAAM,uBACJ,gBAAgB,SACZ,KAAK,IAAI,kBAAkB,YAAY,GACvC;AAGN,SAAI,oBAAoB,GAGtB;UAAI,wBAAwB,EAC1B,QAAO,CAAC;OAAE,MAAM;OAAO,aAAa;OAAsB,EAAE,IAAI;gBAI9D,yBAAyB,kBAAkB,EAC7C,QAAO,CACL;MACE,MAAM;MACN,aAAa,uBAAuB,IAAI,uBAAuB;MAChE,EACD,IACD;AAKL,YAAO,CACL,EAAE,MAAM,MAAM,EACd,QAAQ,IAAI,KAAK,YAAY,CAAC,GAAG,SAAS,MAAM,CAAC,CAClD;MAEJ;AAED,QAAI,OAAO,SAAS,MAClB,QAAO,OAAO,OAAO,KACnB,IAAI,mBAAmB;KACrB;KACA;KACA,uBAAuB,OAAO;KAC/B,CAAC,CACH;KAGN;GAED,YAAY,OAAO,GAAG,0BAA0B,CAC9C,WAAW,YAAoB,cAAsB;IACnD,MAAM,UAAU,OAAO,IAAI,IAAI,MAAM;IACrC,MAAM,WAAW,QAAQ,IAAI,SAAS,WAAW;AAGjD,YADE,SAAS,SAAS,SAAS,SAAS,QAAQ,EAAE,EAE7C,QAAQ,MAAM,EAAE,UAAU,aAAa,CACvC,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,QAAQ;KAE3C;GAED,UAAU,OAAO,GAAG,uBAAuB,CACzC,WAAW,YAAoB,aAAqB;AAClD,WAAO,IAAI,OAAO,QAAQ,QAAQ;KAChC,MAAM,WAAW,QAAQ,IAAI,KAAK,WAAW;AAC7C,SAAI,SAAS,SAAS,OACpB,QAAO;KAET,MAAM,WAAW,SAAS,MAAM,QAC7B,MAAM,EAAE,UAAU,YACpB;AACD,YAAO,QAAQ,IAAI,KAAK,YAAY,SAAS;MAC7C;KAEL;GACF;GACD,EAAE,CACL;;AAOL,MAAa,aAAa;CACxB,KAAK;CACL;CACA;CACD"}
|
package/dist/Metrics.cjs
CHANGED
|
@@ -63,6 +63,10 @@ const transactionsLatency = effect.Metric.histogram("mimic.transactions.latency_
|
|
|
63
63
|
*/
|
|
64
64
|
const storageSnapshots = effect.Metric.counter("mimic.storage.snapshots");
|
|
65
65
|
/**
|
|
66
|
+
* Snapshots triggered by idle document detection
|
|
67
|
+
*/
|
|
68
|
+
const storageIdleSnapshots = effect.Metric.counter("mimic.storage.idle_snapshots");
|
|
69
|
+
/**
|
|
66
70
|
* Snapshot save duration histogram (milliseconds)
|
|
67
71
|
*/
|
|
68
72
|
const storageSnapshotLatency = effect.Metric.histogram("mimic.storage.snapshot_latency_ms", effect.MetricBoundaries.exponential({
|
|
@@ -75,6 +79,22 @@ const storageSnapshotLatency = effect.Metric.histogram("mimic.storage.snapshot_l
|
|
|
75
79
|
*/
|
|
76
80
|
const storageWalAppends = effect.Metric.counter("mimic.storage.wal_appends");
|
|
77
81
|
/**
|
|
82
|
+
* Version gaps detected during WAL replay
|
|
83
|
+
*/
|
|
84
|
+
const storageVersionGaps = effect.Metric.counter("mimic.storage.version_gaps");
|
|
85
|
+
/**
|
|
86
|
+
* Failed WAL appends causing transaction rollback
|
|
87
|
+
*/
|
|
88
|
+
const walAppendFailures = effect.Metric.counter("mimic.storage.wal_append_failures");
|
|
89
|
+
/**
|
|
90
|
+
* ColdStorage load failures during document restore
|
|
91
|
+
*/
|
|
92
|
+
const coldStorageLoadFailures = effect.Metric.counter("mimic.storage.cold_load_failures");
|
|
93
|
+
/**
|
|
94
|
+
* HotStorage getEntries failures during document restore
|
|
95
|
+
*/
|
|
96
|
+
const hotStorageLoadFailures = effect.Metric.counter("mimic.storage.hot_load_failures");
|
|
97
|
+
/**
|
|
78
98
|
* Presence set operations
|
|
79
99
|
*/
|
|
80
100
|
const presenceUpdates = effect.Metric.counter("mimic.presence.updates");
|
|
@@ -95,8 +115,13 @@ const MimicMetrics = {
|
|
|
95
115
|
transactionsRejected,
|
|
96
116
|
transactionsLatency,
|
|
97
117
|
storageSnapshots,
|
|
118
|
+
storageIdleSnapshots,
|
|
98
119
|
storageSnapshotLatency,
|
|
99
120
|
storageWalAppends,
|
|
121
|
+
storageVersionGaps,
|
|
122
|
+
walAppendFailures,
|
|
123
|
+
coldStorageLoadFailures,
|
|
124
|
+
hotStorageLoadFailures,
|
|
100
125
|
presenceUpdates,
|
|
101
126
|
presenceActive
|
|
102
127
|
};
|
|
@@ -113,9 +138,12 @@ exports.documentsEvicted = documentsEvicted;
|
|
|
113
138
|
exports.documentsRestored = documentsRestored;
|
|
114
139
|
exports.presenceActive = presenceActive;
|
|
115
140
|
exports.presenceUpdates = presenceUpdates;
|
|
141
|
+
exports.storageIdleSnapshots = storageIdleSnapshots;
|
|
116
142
|
exports.storageSnapshotLatency = storageSnapshotLatency;
|
|
117
143
|
exports.storageSnapshots = storageSnapshots;
|
|
144
|
+
exports.storageVersionGaps = storageVersionGaps;
|
|
118
145
|
exports.storageWalAppends = storageWalAppends;
|
|
119
146
|
exports.transactionsLatency = transactionsLatency;
|
|
120
147
|
exports.transactionsProcessed = transactionsProcessed;
|
|
121
|
-
exports.transactionsRejected = transactionsRejected;
|
|
148
|
+
exports.transactionsRejected = transactionsRejected;
|
|
149
|
+
exports.walAppendFailures = walAppendFailures;
|
package/dist/Metrics.d.cts
CHANGED
|
@@ -17,8 +17,13 @@ declare const MimicMetrics: {
|
|
|
17
17
|
transactionsRejected: Metric.Metric.Counter<number>;
|
|
18
18
|
transactionsLatency: Metric.Metric<effect_MetricKeyType0.MetricKeyType.Histogram, number, effect_MetricState0.MetricState.Histogram>;
|
|
19
19
|
storageSnapshots: Metric.Metric.Counter<number>;
|
|
20
|
+
storageIdleSnapshots: Metric.Metric.Counter<number>;
|
|
20
21
|
storageSnapshotLatency: Metric.Metric<effect_MetricKeyType0.MetricKeyType.Histogram, number, effect_MetricState0.MetricState.Histogram>;
|
|
21
22
|
storageWalAppends: Metric.Metric.Counter<number>;
|
|
23
|
+
storageVersionGaps: Metric.Metric.Counter<number>;
|
|
24
|
+
walAppendFailures: Metric.Metric.Counter<number>;
|
|
25
|
+
coldStorageLoadFailures: Metric.Metric.Counter<number>;
|
|
26
|
+
hotStorageLoadFailures: Metric.Metric.Counter<number>;
|
|
22
27
|
presenceUpdates: Metric.Metric.Counter<number>;
|
|
23
28
|
presenceActive: Metric.Metric.Gauge<number>;
|
|
24
29
|
};
|
package/dist/Metrics.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Metrics.d.cts","names":[],"sources":["../src/Metrics.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"Metrics.d.cts","names":[],"sources":["../src/Metrics.ts"],"sourcesContent":[],"mappings":";;;;;;cAiKa"}
|
package/dist/Metrics.d.mts
CHANGED
|
@@ -17,8 +17,13 @@ declare const MimicMetrics: {
|
|
|
17
17
|
transactionsRejected: Metric.Metric.Counter<number>;
|
|
18
18
|
transactionsLatency: Metric.Metric<effect_MetricKeyType0.MetricKeyType.Histogram, number, effect_MetricState0.MetricState.Histogram>;
|
|
19
19
|
storageSnapshots: Metric.Metric.Counter<number>;
|
|
20
|
+
storageIdleSnapshots: Metric.Metric.Counter<number>;
|
|
20
21
|
storageSnapshotLatency: Metric.Metric<effect_MetricKeyType0.MetricKeyType.Histogram, number, effect_MetricState0.MetricState.Histogram>;
|
|
21
22
|
storageWalAppends: Metric.Metric.Counter<number>;
|
|
23
|
+
storageVersionGaps: Metric.Metric.Counter<number>;
|
|
24
|
+
walAppendFailures: Metric.Metric.Counter<number>;
|
|
25
|
+
coldStorageLoadFailures: Metric.Metric.Counter<number>;
|
|
26
|
+
hotStorageLoadFailures: Metric.Metric.Counter<number>;
|
|
22
27
|
presenceUpdates: Metric.Metric.Counter<number>;
|
|
23
28
|
presenceActive: Metric.Metric.Gauge<number>;
|
|
24
29
|
};
|
package/dist/Metrics.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Metrics.d.mts","names":[],"sources":["../src/Metrics.ts"],"sourcesContent":[],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"Metrics.d.mts","names":[],"sources":["../src/Metrics.ts"],"sourcesContent":[],"mappings":";;;;;;cAiKa"}
|
package/dist/Metrics.mjs
CHANGED
|
@@ -63,6 +63,10 @@ const transactionsLatency = Metric.histogram("mimic.transactions.latency_ms", Me
|
|
|
63
63
|
*/
|
|
64
64
|
const storageSnapshots = Metric.counter("mimic.storage.snapshots");
|
|
65
65
|
/**
|
|
66
|
+
* Snapshots triggered by idle document detection
|
|
67
|
+
*/
|
|
68
|
+
const storageIdleSnapshots = Metric.counter("mimic.storage.idle_snapshots");
|
|
69
|
+
/**
|
|
66
70
|
* Snapshot save duration histogram (milliseconds)
|
|
67
71
|
*/
|
|
68
72
|
const storageSnapshotLatency = Metric.histogram("mimic.storage.snapshot_latency_ms", MetricBoundaries.exponential({
|
|
@@ -75,6 +79,22 @@ const storageSnapshotLatency = Metric.histogram("mimic.storage.snapshot_latency_
|
|
|
75
79
|
*/
|
|
76
80
|
const storageWalAppends = Metric.counter("mimic.storage.wal_appends");
|
|
77
81
|
/**
|
|
82
|
+
* Version gaps detected during WAL replay
|
|
83
|
+
*/
|
|
84
|
+
const storageVersionGaps = Metric.counter("mimic.storage.version_gaps");
|
|
85
|
+
/**
|
|
86
|
+
* Failed WAL appends causing transaction rollback
|
|
87
|
+
*/
|
|
88
|
+
const walAppendFailures = Metric.counter("mimic.storage.wal_append_failures");
|
|
89
|
+
/**
|
|
90
|
+
* ColdStorage load failures during document restore
|
|
91
|
+
*/
|
|
92
|
+
const coldStorageLoadFailures = Metric.counter("mimic.storage.cold_load_failures");
|
|
93
|
+
/**
|
|
94
|
+
* HotStorage getEntries failures during document restore
|
|
95
|
+
*/
|
|
96
|
+
const hotStorageLoadFailures = Metric.counter("mimic.storage.hot_load_failures");
|
|
97
|
+
/**
|
|
78
98
|
* Presence set operations
|
|
79
99
|
*/
|
|
80
100
|
const presenceUpdates = Metric.counter("mimic.presence.updates");
|
|
@@ -95,12 +115,17 @@ const MimicMetrics = {
|
|
|
95
115
|
transactionsRejected,
|
|
96
116
|
transactionsLatency,
|
|
97
117
|
storageSnapshots,
|
|
118
|
+
storageIdleSnapshots,
|
|
98
119
|
storageSnapshotLatency,
|
|
99
120
|
storageWalAppends,
|
|
121
|
+
storageVersionGaps,
|
|
122
|
+
walAppendFailures,
|
|
123
|
+
coldStorageLoadFailures,
|
|
124
|
+
hotStorageLoadFailures,
|
|
100
125
|
presenceUpdates,
|
|
101
126
|
presenceActive
|
|
102
127
|
};
|
|
103
128
|
|
|
104
129
|
//#endregion
|
|
105
|
-
export { MimicMetrics, connectionsActive, connectionsDuration, connectionsErrors, connectionsTotal, documentsActive, documentsCreated, documentsEvicted, documentsRestored, presenceActive, presenceUpdates, storageSnapshotLatency, storageSnapshots, storageWalAppends, transactionsLatency, transactionsProcessed, transactionsRejected };
|
|
130
|
+
export { MimicMetrics, connectionsActive, connectionsDuration, connectionsErrors, connectionsTotal, documentsActive, documentsCreated, documentsEvicted, documentsRestored, presenceActive, presenceUpdates, storageIdleSnapshots, storageSnapshotLatency, storageSnapshots, storageVersionGaps, storageWalAppends, transactionsLatency, transactionsProcessed, transactionsRejected, walAppendFailures };
|
|
106
131
|
//# sourceMappingURL=Metrics.mjs.map
|
package/dist/Metrics.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Metrics.mjs","names":[],"sources":["../src/Metrics.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - Metrics\n *\n * Observability metrics using Effect's Metric API.\n */\nimport { Metric, MetricBoundaries } from \"effect\";\n\n// =============================================================================\n// Connection Metrics\n// =============================================================================\n\n/**\n * Current active WebSocket connections\n */\nexport const connectionsActive = Metric.gauge(\"mimic.connections.active\");\n\n/**\n * Total connections over lifetime\n */\nexport const connectionsTotal = Metric.counter(\"mimic.connections.total\");\n\n/**\n * Connection duration histogram (milliseconds)\n */\nexport const connectionsDuration = Metric.histogram(\n \"mimic.connections.duration_ms\",\n MetricBoundaries.exponential({\n start: 100,\n factor: 2,\n count: 15, // Up to ~3.2 million ms (~53 minutes)\n })\n);\n\n/**\n * Connection errors (auth failures, etc.)\n */\nexport const connectionsErrors = Metric.counter(\"mimic.connections.errors\");\n\n// =============================================================================\n// Document Metrics\n// =============================================================================\n\n/**\n * Documents currently in memory\n */\nexport const documentsActive = Metric.gauge(\"mimic.documents.active\");\n\n/**\n * New documents created\n */\nexport const documentsCreated = Metric.counter(\"mimic.documents.created\");\n\n/**\n * Documents restored from storage\n */\nexport const documentsRestored = Metric.counter(\"mimic.documents.restored\");\n\n/**\n * Documents garbage collected (evicted)\n */\nexport const documentsEvicted = Metric.counter(\"mimic.documents.evicted\");\n\n// =============================================================================\n// Transaction Metrics\n// =============================================================================\n\n/**\n * Successfully processed transactions\n */\nexport const transactionsProcessed = Metric.counter(\n \"mimic.transactions.processed\"\n);\n\n/**\n * Rejected transactions\n */\nexport const transactionsRejected = Metric.counter(\n \"mimic.transactions.rejected\"\n);\n\n/**\n * Transaction processing latency histogram (milliseconds)\n */\nexport const transactionsLatency = Metric.histogram(\n \"mimic.transactions.latency_ms\",\n MetricBoundaries.exponential({\n start: 0.1,\n factor: 2,\n count: 15, // Up to ~1638 ms\n })\n);\n\n// =============================================================================\n// Storage Metrics\n// =============================================================================\n\n/**\n * Snapshots saved to ColdStorage\n */\nexport const storageSnapshots = Metric.counter(\"mimic.storage.snapshots\");\n\n/**\n * Snapshot save duration histogram (milliseconds)\n */\nexport const storageSnapshotLatency = Metric.histogram(\n \"mimic.storage.snapshot_latency_ms\",\n MetricBoundaries.exponential({\n start: 1,\n factor: 2,\n count: 12, // Up to ~4 seconds\n })\n);\n\n/**\n * WAL entries written to HotStorage\n */\nexport const storageWalAppends = Metric.counter(\"mimic.storage.wal_appends\");\n\n// =============================================================================\n// Presence Metrics\n// =============================================================================\n\n/**\n * Presence set operations\n */\nexport const presenceUpdates = Metric.counter(\"mimic.presence.updates\");\n\n/**\n * Active presence entries\n */\nexport const presenceActive = Metric.gauge(\"mimic.presence.active\");\n\n// =============================================================================\n// Export namespace\n// =============================================================================\n\nexport const MimicMetrics = {\n // Connection\n connectionsActive,\n connectionsTotal,\n connectionsDuration,\n connectionsErrors,\n\n // Document\n documentsActive,\n documentsCreated,\n documentsRestored,\n documentsEvicted,\n\n // Transaction\n transactionsProcessed,\n transactionsRejected,\n transactionsLatency,\n\n // Storage\n storageSnapshots,\n storageSnapshotLatency,\n storageWalAppends,\n\n // Presence\n presenceUpdates,\n presenceActive,\n};\n"],"mappings":";;;;;;;;;;;AAcA,MAAa,oBAAoB,OAAO,MAAM,2BAA2B;;;;AAKzE,MAAa,mBAAmB,OAAO,QAAQ,0BAA0B;;;;AAKzE,MAAa,sBAAsB,OAAO,UACxC,iCACA,iBAAiB,YAAY;CAC3B,OAAO;CACP,QAAQ;CACR,OAAO;CACR,CAAC,CACH;;;;AAKD,MAAa,oBAAoB,OAAO,QAAQ,2BAA2B;;;;AAS3E,MAAa,kBAAkB,OAAO,MAAM,yBAAyB;;;;AAKrE,MAAa,mBAAmB,OAAO,QAAQ,0BAA0B;;;;AAKzE,MAAa,oBAAoB,OAAO,QAAQ,2BAA2B;;;;AAK3E,MAAa,mBAAmB,OAAO,QAAQ,0BAA0B;;;;AASzE,MAAa,wBAAwB,OAAO,QAC1C,+BACD;;;;AAKD,MAAa,uBAAuB,OAAO,QACzC,8BACD;;;;AAKD,MAAa,sBAAsB,OAAO,UACxC,iCACA,iBAAiB,YAAY;CAC3B,OAAO;CACP,QAAQ;CACR,OAAO;CACR,CAAC,CACH;;;;AASD,MAAa,mBAAmB,OAAO,QAAQ,0BAA0B;;;;AAKzE,MAAa,yBAAyB,OAAO,UAC3C,qCACA,iBAAiB,YAAY;CAC3B,OAAO;CACP,QAAQ;CACR,OAAO;CACR,CAAC,CACH;;;;AAKD,MAAa,oBAAoB,OAAO,QAAQ,4BAA4B;;;;
|
|
1
|
+
{"version":3,"file":"Metrics.mjs","names":[],"sources":["../src/Metrics.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - Metrics\n *\n * Observability metrics using Effect's Metric API.\n */\nimport { Metric, MetricBoundaries } from \"effect\";\n\n// =============================================================================\n// Connection Metrics\n// =============================================================================\n\n/**\n * Current active WebSocket connections\n */\nexport const connectionsActive = Metric.gauge(\"mimic.connections.active\");\n\n/**\n * Total connections over lifetime\n */\nexport const connectionsTotal = Metric.counter(\"mimic.connections.total\");\n\n/**\n * Connection duration histogram (milliseconds)\n */\nexport const connectionsDuration = Metric.histogram(\n \"mimic.connections.duration_ms\",\n MetricBoundaries.exponential({\n start: 100,\n factor: 2,\n count: 15, // Up to ~3.2 million ms (~53 minutes)\n })\n);\n\n/**\n * Connection errors (auth failures, etc.)\n */\nexport const connectionsErrors = Metric.counter(\"mimic.connections.errors\");\n\n// =============================================================================\n// Document Metrics\n// =============================================================================\n\n/**\n * Documents currently in memory\n */\nexport const documentsActive = Metric.gauge(\"mimic.documents.active\");\n\n/**\n * New documents created\n */\nexport const documentsCreated = Metric.counter(\"mimic.documents.created\");\n\n/**\n * Documents restored from storage\n */\nexport const documentsRestored = Metric.counter(\"mimic.documents.restored\");\n\n/**\n * Documents garbage collected (evicted)\n */\nexport const documentsEvicted = Metric.counter(\"mimic.documents.evicted\");\n\n// =============================================================================\n// Transaction Metrics\n// =============================================================================\n\n/**\n * Successfully processed transactions\n */\nexport const transactionsProcessed = Metric.counter(\n \"mimic.transactions.processed\"\n);\n\n/**\n * Rejected transactions\n */\nexport const transactionsRejected = Metric.counter(\n \"mimic.transactions.rejected\"\n);\n\n/**\n * Transaction processing latency histogram (milliseconds)\n */\nexport const transactionsLatency = Metric.histogram(\n \"mimic.transactions.latency_ms\",\n MetricBoundaries.exponential({\n start: 0.1,\n factor: 2,\n count: 15, // Up to ~1638 ms\n })\n);\n\n// =============================================================================\n// Storage Metrics\n// =============================================================================\n\n/**\n * Snapshots saved to ColdStorage\n */\nexport const storageSnapshots = Metric.counter(\"mimic.storage.snapshots\");\n\n/**\n * Snapshots triggered by idle document detection\n */\nexport const storageIdleSnapshots = Metric.counter(\"mimic.storage.idle_snapshots\");\n\n/**\n * Snapshot save duration histogram (milliseconds)\n */\nexport const storageSnapshotLatency = Metric.histogram(\n \"mimic.storage.snapshot_latency_ms\",\n MetricBoundaries.exponential({\n start: 1,\n factor: 2,\n count: 12, // Up to ~4 seconds\n })\n);\n\n/**\n * WAL entries written to HotStorage\n */\nexport const storageWalAppends = Metric.counter(\"mimic.storage.wal_appends\");\n\n/**\n * Version gaps detected during WAL replay\n */\nexport const storageVersionGaps = Metric.counter(\"mimic.storage.version_gaps\");\n\n/**\n * Failed WAL appends causing transaction rollback\n */\nexport const walAppendFailures = Metric.counter(\"mimic.storage.wal_append_failures\");\n\n/**\n * ColdStorage load failures during document restore\n */\nexport const coldStorageLoadFailures = Metric.counter(\"mimic.storage.cold_load_failures\");\n\n/**\n * HotStorage getEntries failures during document restore\n */\nexport const hotStorageLoadFailures = Metric.counter(\"mimic.storage.hot_load_failures\");\n\n// =============================================================================\n// Presence Metrics\n// =============================================================================\n\n/**\n * Presence set operations\n */\nexport const presenceUpdates = Metric.counter(\"mimic.presence.updates\");\n\n/**\n * Active presence entries\n */\nexport const presenceActive = Metric.gauge(\"mimic.presence.active\");\n\n// =============================================================================\n// Export namespace\n// =============================================================================\n\nexport const MimicMetrics = {\n // Connection\n connectionsActive,\n connectionsTotal,\n connectionsDuration,\n connectionsErrors,\n\n // Document\n documentsActive,\n documentsCreated,\n documentsRestored,\n documentsEvicted,\n\n // Transaction\n transactionsProcessed,\n transactionsRejected,\n transactionsLatency,\n\n // Storage\n storageSnapshots,\n storageIdleSnapshots,\n storageSnapshotLatency,\n storageWalAppends,\n storageVersionGaps,\n walAppendFailures,\n coldStorageLoadFailures,\n hotStorageLoadFailures,\n\n // Presence\n presenceUpdates,\n presenceActive,\n};\n"],"mappings":";;;;;;;;;;;AAcA,MAAa,oBAAoB,OAAO,MAAM,2BAA2B;;;;AAKzE,MAAa,mBAAmB,OAAO,QAAQ,0BAA0B;;;;AAKzE,MAAa,sBAAsB,OAAO,UACxC,iCACA,iBAAiB,YAAY;CAC3B,OAAO;CACP,QAAQ;CACR,OAAO;CACR,CAAC,CACH;;;;AAKD,MAAa,oBAAoB,OAAO,QAAQ,2BAA2B;;;;AAS3E,MAAa,kBAAkB,OAAO,MAAM,yBAAyB;;;;AAKrE,MAAa,mBAAmB,OAAO,QAAQ,0BAA0B;;;;AAKzE,MAAa,oBAAoB,OAAO,QAAQ,2BAA2B;;;;AAK3E,MAAa,mBAAmB,OAAO,QAAQ,0BAA0B;;;;AASzE,MAAa,wBAAwB,OAAO,QAC1C,+BACD;;;;AAKD,MAAa,uBAAuB,OAAO,QACzC,8BACD;;;;AAKD,MAAa,sBAAsB,OAAO,UACxC,iCACA,iBAAiB,YAAY;CAC3B,OAAO;CACP,QAAQ;CACR,OAAO;CACR,CAAC,CACH;;;;AASD,MAAa,mBAAmB,OAAO,QAAQ,0BAA0B;;;;AAKzE,MAAa,uBAAuB,OAAO,QAAQ,+BAA+B;;;;AAKlF,MAAa,yBAAyB,OAAO,UAC3C,qCACA,iBAAiB,YAAY;CAC3B,OAAO;CACP,QAAQ;CACR,OAAO;CACR,CAAC,CACH;;;;AAKD,MAAa,oBAAoB,OAAO,QAAQ,4BAA4B;;;;AAK5E,MAAa,qBAAqB,OAAO,QAAQ,6BAA6B;;;;AAK9E,MAAa,oBAAoB,OAAO,QAAQ,oCAAoC;;;;AAKpF,MAAa,0BAA0B,OAAO,QAAQ,mCAAmC;;;;AAKzF,MAAa,yBAAyB,OAAO,QAAQ,kCAAkC;;;;AASvF,MAAa,kBAAkB,OAAO,QAAQ,yBAAyB;;;;AAKvE,MAAa,iBAAiB,OAAO,MAAM,wBAAwB;AAMnE,MAAa,eAAe;CAE1B;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CAGA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACD"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
const require_ColdStorage = require('./ColdStorage.cjs');
|
|
2
2
|
const require_HotStorage = require('./HotStorage.cjs');
|
|
3
3
|
const require_Metrics = require('./Metrics.cjs');
|
|
4
|
+
const require_DocumentInstance = require('./DocumentInstance.cjs');
|
|
4
5
|
const require_objectSpread2 = require('./_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.cjs');
|
|
5
6
|
const require_MimicServerEngine = require('./MimicServerEngine.cjs');
|
|
6
7
|
let effect = require("effect");
|
|
7
|
-
let _voidhash_mimic_server = require("@voidhash/mimic/server");
|
|
8
8
|
let _effect_cluster = require("@effect/cluster");
|
|
9
9
|
let _effect_rpc = require("@effect/rpc");
|
|
10
10
|
|
|
@@ -21,6 +21,7 @@ const DEFAULT_MAX_IDLE_TIME = effect.Duration.minutes(5);
|
|
|
21
21
|
const DEFAULT_MAX_TRANSACTION_HISTORY = 1e3;
|
|
22
22
|
const DEFAULT_SNAPSHOT_INTERVAL = effect.Duration.minutes(5);
|
|
23
23
|
const DEFAULT_SNAPSHOT_THRESHOLD = 100;
|
|
24
|
+
const DEFAULT_SNAPSHOT_IDLE_TIMEOUT = effect.Duration.seconds(30);
|
|
24
25
|
const DEFAULT_SHARD_GROUP = "mimic-documents";
|
|
25
26
|
/**
|
|
26
27
|
* Schema for encoded transaction (wire format)
|
|
@@ -99,7 +100,7 @@ const MimicDocumentEntity = _effect_cluster.Entity.make("MimicDocument", [
|
|
|
99
100
|
*/
|
|
100
101
|
var MimicClusterConfigTag = class extends effect.Context.Tag("@voidhash/mimic-effect/MimicClusterConfig")() {};
|
|
101
102
|
const resolveClusterConfig = (config) => {
|
|
102
|
-
var _config$maxTransactio, _config$snapshot, _config$snapshot$tran, _config$snapshot2, _config$shardGroup;
|
|
103
|
+
var _config$maxTransactio, _config$snapshot, _config$snapshot$tran, _config$snapshot2, _config$snapshot3, _config$shardGroup;
|
|
103
104
|
return {
|
|
104
105
|
schema: config.schema,
|
|
105
106
|
initial: config.initial,
|
|
@@ -108,7 +109,8 @@ const resolveClusterConfig = (config) => {
|
|
|
108
109
|
maxTransactionHistory: (_config$maxTransactio = config.maxTransactionHistory) !== null && _config$maxTransactio !== void 0 ? _config$maxTransactio : DEFAULT_MAX_TRANSACTION_HISTORY,
|
|
109
110
|
snapshot: {
|
|
110
111
|
interval: ((_config$snapshot = config.snapshot) === null || _config$snapshot === void 0 ? void 0 : _config$snapshot.interval) ? effect.Duration.decode(config.snapshot.interval) : DEFAULT_SNAPSHOT_INTERVAL,
|
|
111
|
-
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
|
|
112
|
+
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,
|
|
113
|
+
idleTimeout: ((_config$snapshot3 = config.snapshot) === null || _config$snapshot3 === void 0 ? void 0 : _config$snapshot3.idleTimeout) ? effect.Duration.decode(config.snapshot.idleTimeout) : DEFAULT_SNAPSHOT_IDLE_TIMEOUT
|
|
112
114
|
},
|
|
113
115
|
shardGroup: (_config$shardGroup = config.shardGroup) !== null && _config$shardGroup !== void 0 ? _config$shardGroup : DEFAULT_SHARD_GROUP
|
|
114
116
|
};
|
|
@@ -130,150 +132,53 @@ const encodeTransaction = (tx) => {
|
|
|
130
132
|
/**
|
|
131
133
|
* Create the entity handler for MimicDocument
|
|
132
134
|
*/
|
|
133
|
-
const createEntityHandler = (config, coldStorage, hotStorage) => effect.Effect.
|
|
135
|
+
const createEntityHandler = (config, coldStorage, hotStorage) => effect.Effect.fn("cluster.entity.handler.create")(function* () {
|
|
134
136
|
const documentId = (yield* _effect_cluster.Entity.CurrentAddress).entityId;
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
};
|
|
141
|
-
const storedDoc = yield* effect.Effect.catchAll(coldStorage.load(documentId), () => effect.Effect.succeed(void 0));
|
|
142
|
-
let initialState;
|
|
143
|
-
let initialVersion = 0;
|
|
144
|
-
if (storedDoc) {
|
|
145
|
-
initialState = storedDoc.state;
|
|
146
|
-
initialVersion = storedDoc.version;
|
|
147
|
-
} else initialState = yield* computeInitialState();
|
|
148
|
-
const broadcastPubSub = yield* effect.PubSub.unbounded();
|
|
137
|
+
const instance = yield* require_DocumentInstance.DocumentInstance.make(documentId, {
|
|
138
|
+
schema: config.schema,
|
|
139
|
+
initial: config.initial,
|
|
140
|
+
maxTransactionHistory: config.maxTransactionHistory,
|
|
141
|
+
snapshot: config.snapshot
|
|
142
|
+
}, coldStorage, hotStorage).pipe(effect.Effect.orDie);
|
|
149
143
|
const presencePubSub = yield* effect.PubSub.unbounded();
|
|
150
144
|
const stateRef = yield* effect.Ref.make({
|
|
151
|
-
|
|
152
|
-
broadcastPubSub,
|
|
145
|
+
instance,
|
|
153
146
|
presences: effect.HashMap.empty(),
|
|
154
|
-
presencePubSub
|
|
155
|
-
lastSnapshotVersion: initialVersion,
|
|
156
|
-
lastSnapshotTime: Date.now(),
|
|
157
|
-
transactionsSinceSnapshot: 0
|
|
158
|
-
});
|
|
159
|
-
const document = _voidhash_mimic_server.ServerDocument.make({
|
|
160
|
-
schema: config.schema,
|
|
161
|
-
initialState,
|
|
162
|
-
initialVersion,
|
|
163
|
-
maxTransactionHistory: config.maxTransactionHistory,
|
|
164
|
-
onBroadcast: (message) => {
|
|
165
|
-
effect.Effect.runSync(effect.PubSub.publish(broadcastPubSub, {
|
|
166
|
-
type: "transaction",
|
|
167
|
-
transaction: message.transaction,
|
|
168
|
-
version: message.version
|
|
169
|
-
}));
|
|
170
|
-
},
|
|
171
|
-
onRejection: (transactionId, reason) => {
|
|
172
|
-
effect.Effect.runSync(effect.PubSub.publish(broadcastPubSub, {
|
|
173
|
-
type: "error",
|
|
174
|
-
transactionId,
|
|
175
|
-
reason
|
|
176
|
-
}));
|
|
177
|
-
}
|
|
147
|
+
presencePubSub
|
|
178
148
|
});
|
|
179
|
-
yield* effect.
|
|
180
|
-
|
|
181
|
-
for (const entry of walEntries) {
|
|
182
|
-
const result = document.submit(entry.transaction);
|
|
183
|
-
if (!result.success) yield* effect.Effect.logWarning("Skipping corrupted WAL entry", {
|
|
184
|
-
documentId,
|
|
185
|
-
version: entry.version,
|
|
186
|
-
reason: result.reason
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
if (storedDoc) yield* effect.Metric.increment(require_Metrics.documentsRestored);
|
|
190
|
-
else yield* effect.Metric.increment(require_Metrics.documentsCreated);
|
|
191
|
-
yield* effect.Metric.incrementBy(require_Metrics.documentsActive, 1);
|
|
192
|
-
/**
|
|
193
|
-
* Save snapshot to ColdStorage
|
|
194
|
-
*/
|
|
195
|
-
const saveSnapshot = effect.Effect.gen(function* () {
|
|
196
|
-
const state = yield* effect.Ref.get(stateRef);
|
|
197
|
-
const docState = state.document.get();
|
|
198
|
-
const version = state.document.getVersion();
|
|
199
|
-
if (docState === void 0) return;
|
|
200
|
-
const storedDocument = {
|
|
201
|
-
state: docState,
|
|
202
|
-
version,
|
|
203
|
-
schemaVersion: SCHEMA_VERSION,
|
|
204
|
-
savedAt: Date.now()
|
|
205
|
-
};
|
|
206
|
-
const snapshotStartTime = Date.now();
|
|
207
|
-
yield* effect.Effect.catchAll(coldStorage.save(documentId, storedDocument), (e) => effect.Effect.logError("Failed to save snapshot", {
|
|
208
|
-
documentId,
|
|
209
|
-
error: e
|
|
210
|
-
}));
|
|
211
|
-
const snapshotDuration = Date.now() - snapshotStartTime;
|
|
212
|
-
yield* effect.Metric.increment(require_Metrics.storageSnapshots);
|
|
213
|
-
yield* effect.Metric.update(require_Metrics.storageSnapshotLatency, snapshotDuration);
|
|
214
|
-
yield* effect.Effect.catchAll(hotStorage.truncate(documentId, version), (e) => effect.Effect.logError("Failed to truncate WAL", {
|
|
149
|
+
yield* effect.Effect.addFinalizer(() => effect.Effect.fn("cluster.entity.finalize")(function* () {
|
|
150
|
+
yield* effect.Effect.catchAll(instance.saveSnapshot(), (e) => effect.Effect.logError("Failed to save snapshot during entity finalization", {
|
|
215
151
|
documentId,
|
|
216
152
|
error: e
|
|
217
153
|
}));
|
|
218
|
-
yield* effect.Ref.update(stateRef, (s) => require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, s), {}, {
|
|
219
|
-
lastSnapshotVersion: version,
|
|
220
|
-
lastSnapshotTime: Date.now(),
|
|
221
|
-
transactionsSinceSnapshot: 0
|
|
222
|
-
}));
|
|
223
|
-
});
|
|
224
|
-
/**
|
|
225
|
-
* Check if snapshot should be triggered
|
|
226
|
-
*/
|
|
227
|
-
const checkSnapshotTriggers = effect.Effect.gen(function* () {
|
|
228
|
-
const state = yield* effect.Ref.get(stateRef);
|
|
229
|
-
const now = Date.now();
|
|
230
|
-
const intervalMs = effect.Duration.toMillis(config.snapshot.interval);
|
|
231
|
-
const threshold = config.snapshot.transactionThreshold;
|
|
232
|
-
if (state.transactionsSinceSnapshot >= threshold) {
|
|
233
|
-
yield* saveSnapshot;
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
if (now - state.lastSnapshotTime >= intervalMs) {
|
|
237
|
-
yield* saveSnapshot;
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
yield* effect.Effect.addFinalizer(() => effect.Effect.gen(function* () {
|
|
242
|
-
yield* saveSnapshot;
|
|
243
154
|
yield* effect.Metric.incrementBy(require_Metrics.documentsActive, -1);
|
|
244
155
|
yield* effect.Metric.increment(require_Metrics.documentsEvicted);
|
|
245
156
|
yield* effect.Effect.logDebug("Entity finalized", { documentId });
|
|
246
|
-
}));
|
|
157
|
+
})());
|
|
158
|
+
if (effect.Duration.toMillis(config.snapshot.idleTimeout) > 0) yield* effect.Effect.fn("cluster.entity.snapshot.loop")(function* () {
|
|
159
|
+
if (yield* instance.needsSnapshot()) {
|
|
160
|
+
yield* effect.Effect.catchAll(instance.saveSnapshot(), (e) => effect.Effect.logWarning("Periodic snapshot failed in cluster entity", {
|
|
161
|
+
documentId,
|
|
162
|
+
error: e
|
|
163
|
+
}));
|
|
164
|
+
yield* effect.Metric.increment(require_Metrics.storageIdleSnapshots);
|
|
165
|
+
}
|
|
166
|
+
})().pipe(effect.Effect.repeat(effect.Schedule.spaced(config.snapshot.idleTimeout)), effect.Effect.fork);
|
|
247
167
|
return {
|
|
248
|
-
Submit: effect.Effect.
|
|
249
|
-
const submitStartTime = Date.now();
|
|
250
|
-
const state = yield* effect.Ref.get(stateRef);
|
|
168
|
+
Submit: effect.Effect.fn("cluster.document.transaction.submit")(function* ({ payload }) {
|
|
251
169
|
const transaction = decodeTransaction(payload.transaction);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
yield* effect.Metric.increment(require_Metrics.transactionsProcessed);
|
|
257
|
-
const walEntry = {
|
|
258
|
-
transaction,
|
|
259
|
-
version: result.version,
|
|
260
|
-
timestamp: Date.now()
|
|
261
|
-
};
|
|
262
|
-
yield* effect.Effect.catchAll(hotStorage.append(documentId, walEntry), (e) => effect.Effect.logError("Failed to append to WAL", {
|
|
263
|
-
documentId,
|
|
264
|
-
error: e
|
|
265
|
-
}));
|
|
266
|
-
yield* effect.Metric.increment(require_Metrics.storageWalAppends);
|
|
267
|
-
yield* effect.Ref.update(stateRef, (s) => require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, s), {}, { transactionsSinceSnapshot: s.transactionsSinceSnapshot + 1 }));
|
|
268
|
-
yield* checkSnapshotTriggers;
|
|
269
|
-
} else yield* effect.Metric.increment(require_Metrics.transactionsRejected);
|
|
270
|
-
return result;
|
|
170
|
+
return yield* instance.submit(transaction).pipe(effect.Effect.catchAll((error) => effect.Effect.succeed({
|
|
171
|
+
success: false,
|
|
172
|
+
reason: `Storage error: ${String(error)}`
|
|
173
|
+
})));
|
|
271
174
|
}),
|
|
272
|
-
GetSnapshot: effect.Effect.
|
|
273
|
-
return
|
|
175
|
+
GetSnapshot: effect.Effect.fn("cluster.document.snapshot.get")(function* () {
|
|
176
|
+
return instance.getSnapshot();
|
|
274
177
|
}),
|
|
275
|
-
Touch: effect.Effect.
|
|
276
|
-
|
|
178
|
+
Touch: effect.Effect.fn("cluster.document.touch")(function* () {
|
|
179
|
+
yield* instance.touch();
|
|
180
|
+
}),
|
|
181
|
+
SetPresence: effect.Effect.fn("cluster.presence.set")(function* ({ payload }) {
|
|
277
182
|
const { connectionId, entry } = payload;
|
|
278
183
|
yield* effect.Ref.update(stateRef, (s) => require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, s), {}, { presences: effect.HashMap.set(s.presences, connectionId, entry) }));
|
|
279
184
|
yield* effect.Metric.increment(require_Metrics.presenceUpdates);
|
|
@@ -287,7 +192,7 @@ const createEntityHandler = (config, coldStorage, hotStorage) => effect.Effect.g
|
|
|
287
192
|
};
|
|
288
193
|
yield* effect.PubSub.publish(state.presencePubSub, event);
|
|
289
194
|
}),
|
|
290
|
-
RemovePresence: effect.Effect.
|
|
195
|
+
RemovePresence: effect.Effect.fn("cluster.presence.remove")(function* ({ payload }) {
|
|
291
196
|
const { connectionId } = payload;
|
|
292
197
|
const state = yield* effect.Ref.get(stateRef);
|
|
293
198
|
if (!effect.HashMap.has(state.presences, connectionId)) return;
|
|
@@ -299,20 +204,20 @@ const createEntityHandler = (config, coldStorage, hotStorage) => effect.Effect.g
|
|
|
299
204
|
};
|
|
300
205
|
yield* effect.PubSub.publish(state.presencePubSub, event);
|
|
301
206
|
}),
|
|
302
|
-
GetPresenceSnapshot: effect.Effect.
|
|
207
|
+
GetPresenceSnapshot: effect.Effect.fn("cluster.presence.snapshot.get")(function* () {
|
|
303
208
|
const state = yield* effect.Ref.get(stateRef);
|
|
304
209
|
const presences = {};
|
|
305
210
|
for (const [id, entry] of state.presences) presences[id] = entry;
|
|
306
211
|
return { presences };
|
|
307
212
|
})
|
|
308
213
|
};
|
|
309
|
-
});
|
|
214
|
+
})();
|
|
310
215
|
var SubscriptionStoreTag = class extends effect.Context.Tag("@voidhash/mimic-effect/SubscriptionStore")() {};
|
|
311
|
-
const subscriptionStoreLayer = effect.Layer.effect(SubscriptionStoreTag, effect.Effect.
|
|
216
|
+
const subscriptionStoreLayer = effect.Layer.effect(SubscriptionStoreTag, effect.Effect.fn("cluster.subscriptions.layer.create")(function* () {
|
|
312
217
|
const documentPubSubs = yield* effect.Ref.make(effect.HashMap.empty());
|
|
313
218
|
const presencePubSubs = yield* effect.Ref.make(effect.HashMap.empty());
|
|
314
219
|
return {
|
|
315
|
-
getOrCreatePubSub:
|
|
220
|
+
getOrCreatePubSub: effect.Effect.fn("cluster.subscriptions.pubsub.get-or-create")(function* (documentId) {
|
|
316
221
|
const current = yield* effect.Ref.get(documentPubSubs);
|
|
317
222
|
const existing = effect.HashMap.get(current, documentId);
|
|
318
223
|
if (existing._tag === "Some") return existing.value;
|
|
@@ -320,7 +225,7 @@ const subscriptionStoreLayer = effect.Layer.effect(SubscriptionStoreTag, effect.
|
|
|
320
225
|
yield* effect.Ref.update(documentPubSubs, (map) => effect.HashMap.set(map, documentId, pubsub));
|
|
321
226
|
return pubsub;
|
|
322
227
|
}),
|
|
323
|
-
getOrCreatePresencePubSub:
|
|
228
|
+
getOrCreatePresencePubSub: effect.Effect.fn("cluster.subscriptions.presence-pubsub.get-or-create")(function* (documentId) {
|
|
324
229
|
const current = yield* effect.Ref.get(presencePubSubs);
|
|
325
230
|
const existing = effect.HashMap.get(current, documentId);
|
|
326
231
|
if (existing._tag === "Some") return existing.value;
|
|
@@ -329,7 +234,7 @@ const subscriptionStoreLayer = effect.Layer.effect(SubscriptionStoreTag, effect.
|
|
|
329
234
|
return pubsub;
|
|
330
235
|
})
|
|
331
236
|
};
|
|
332
|
-
}));
|
|
237
|
+
})());
|
|
333
238
|
/**
|
|
334
239
|
* Create a MimicClusterServerEngine layer.
|
|
335
240
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MimicClusterServerEngine.d.cts","names":[],"sources":["../src/MimicClusterServerEngine.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"MimicClusterServerEngine.d.cts","names":[],"sources":["../src/MimicClusterServerEngine.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;cA0pBa;yBA3JwB,SAAA,CAAU,sBACrC,+BAA+B,aACtC,KAAA,CAAM,MACP,6BAEA,iBAAiB,gBAAgB,sBAAsB,QAAA,CAAS"}
|
|
@@ -4,8 +4,8 @@ import { HotStorageTag } from "./HotStorage.mjs";
|
|
|
4
4
|
import { MimicAuthServiceTag } from "./MimicAuthService.mjs";
|
|
5
5
|
import { MimicServerEngineTag } from "./MimicServerEngine.mjs";
|
|
6
6
|
import { Layer } from "effect";
|
|
7
|
-
import { Sharding } from "@effect/cluster";
|
|
8
7
|
import { Primitive } from "@voidhash/mimic";
|
|
8
|
+
import { Sharding } from "@effect/cluster";
|
|
9
9
|
|
|
10
10
|
//#region src/MimicClusterServerEngine.d.ts
|
|
11
11
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MimicClusterServerEngine.d.mts","names":[],"sources":["../src/MimicClusterServerEngine.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"MimicClusterServerEngine.d.mts","names":[],"sources":["../src/MimicClusterServerEngine.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;cA0pBa;yBA3JwB,SAAA,CAAU,sBACrC,+BAA+B,aACtC,KAAA,CAAM,MACP,6BAEA,iBAAiB,gBAAgB,sBAAsB,QAAA,CAAS"}
|