@voidhash/mimic-effect 0.0.9 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +136 -90
- package/README.md +385 -0
- package/dist/ColdStorage.cjs +60 -0
- package/dist/ColdStorage.d.cts +53 -0
- package/dist/ColdStorage.d.cts.map +1 -0
- package/dist/ColdStorage.d.mts +53 -0
- package/dist/ColdStorage.d.mts.map +1 -0
- package/dist/ColdStorage.mjs +60 -0
- package/dist/ColdStorage.mjs.map +1 -0
- package/dist/DocumentManager.cjs +263 -82
- package/dist/DocumentManager.d.cts +44 -22
- package/dist/DocumentManager.d.cts.map +1 -1
- package/dist/DocumentManager.d.mts +44 -22
- package/dist/DocumentManager.d.mts.map +1 -1
- package/dist/DocumentManager.mjs +259 -67
- package/dist/DocumentManager.mjs.map +1 -1
- package/dist/Errors.cjs +54 -0
- package/dist/Errors.d.cts +96 -0
- package/dist/Errors.d.cts.map +1 -0
- package/dist/Errors.d.mts +96 -0
- package/dist/Errors.d.mts.map +1 -0
- package/dist/Errors.mjs +48 -0
- package/dist/Errors.mjs.map +1 -0
- package/dist/HotStorage.cjs +100 -0
- package/dist/HotStorage.d.cts +70 -0
- package/dist/HotStorage.d.cts.map +1 -0
- package/dist/HotStorage.d.mts +70 -0
- package/dist/HotStorage.d.mts.map +1 -0
- package/dist/HotStorage.mjs +100 -0
- package/dist/HotStorage.mjs.map +1 -0
- package/dist/Metrics.cjs +143 -0
- package/dist/Metrics.d.cts +31 -0
- package/dist/Metrics.d.cts.map +1 -0
- package/dist/Metrics.d.mts +31 -0
- package/dist/Metrics.d.mts.map +1 -0
- package/dist/Metrics.mjs +126 -0
- package/dist/Metrics.mjs.map +1 -0
- package/dist/MimicAuthService.cjs +61 -45
- package/dist/MimicAuthService.d.cts +61 -48
- package/dist/MimicAuthService.d.cts.map +1 -1
- package/dist/MimicAuthService.d.mts +61 -48
- package/dist/MimicAuthService.d.mts.map +1 -1
- package/dist/MimicAuthService.mjs +60 -36
- package/dist/MimicAuthService.mjs.map +1 -1
- package/dist/MimicClusterServerEngine.cjs +521 -0
- package/dist/MimicClusterServerEngine.d.cts +17 -0
- package/dist/MimicClusterServerEngine.d.cts.map +1 -0
- package/dist/MimicClusterServerEngine.d.mts +17 -0
- package/dist/MimicClusterServerEngine.d.mts.map +1 -0
- package/dist/MimicClusterServerEngine.mjs +523 -0
- package/dist/MimicClusterServerEngine.mjs.map +1 -0
- package/dist/MimicServer.cjs +205 -96
- package/dist/MimicServer.d.cts +9 -110
- package/dist/MimicServer.d.cts.map +1 -1
- package/dist/MimicServer.d.mts +9 -110
- package/dist/MimicServer.d.mts.map +1 -1
- package/dist/MimicServer.mjs +206 -90
- package/dist/MimicServer.mjs.map +1 -1
- package/dist/MimicServerEngine.cjs +97 -0
- package/dist/MimicServerEngine.d.cts +78 -0
- package/dist/MimicServerEngine.d.cts.map +1 -0
- package/dist/MimicServerEngine.d.mts +78 -0
- package/dist/MimicServerEngine.d.mts.map +1 -0
- package/dist/MimicServerEngine.mjs +97 -0
- package/dist/MimicServerEngine.mjs.map +1 -0
- package/dist/PresenceManager.cjs +75 -91
- package/dist/PresenceManager.d.cts +17 -66
- package/dist/PresenceManager.d.cts.map +1 -1
- package/dist/PresenceManager.d.mts +17 -66
- package/dist/PresenceManager.d.mts.map +1 -1
- package/dist/PresenceManager.mjs +74 -78
- package/dist/PresenceManager.mjs.map +1 -1
- package/dist/Protocol.cjs +146 -0
- package/dist/Protocol.d.cts +203 -0
- package/dist/Protocol.d.cts.map +1 -0
- package/dist/Protocol.d.mts +203 -0
- package/dist/Protocol.d.mts.map +1 -0
- package/dist/Protocol.mjs +132 -0
- package/dist/Protocol.mjs.map +1 -0
- package/dist/Types.d.cts +172 -0
- package/dist/Types.d.cts.map +1 -0
- package/dist/Types.d.mts +172 -0
- package/dist/Types.d.mts.map +1 -0
- package/dist/_virtual/rolldown_runtime.cjs +1 -25
- package/dist/_virtual/rolldown_runtime.mjs +4 -1
- package/dist/index.cjs +37 -75
- package/dist/index.d.cts +13 -12
- package/dist/index.d.mts +13 -12
- package/dist/index.mjs +12 -12
- package/dist/testing/ColdStorageTestSuite.cjs +508 -0
- package/dist/testing/ColdStorageTestSuite.d.cts +36 -0
- package/dist/testing/ColdStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/ColdStorageTestSuite.d.mts +36 -0
- package/dist/testing/ColdStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/ColdStorageTestSuite.mjs +508 -0
- package/dist/testing/ColdStorageTestSuite.mjs.map +1 -0
- package/dist/testing/FailingStorage.cjs +135 -0
- package/dist/testing/FailingStorage.d.cts +43 -0
- package/dist/testing/FailingStorage.d.cts.map +1 -0
- package/dist/testing/FailingStorage.d.mts +43 -0
- package/dist/testing/FailingStorage.d.mts.map +1 -0
- package/dist/testing/FailingStorage.mjs +136 -0
- package/dist/testing/FailingStorage.mjs.map +1 -0
- package/dist/testing/HotStorageTestSuite.cjs +585 -0
- package/dist/testing/HotStorageTestSuite.d.cts +40 -0
- package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
- package/dist/testing/HotStorageTestSuite.d.mts +40 -0
- package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
- package/dist/testing/HotStorageTestSuite.mjs +585 -0
- package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.cjs +349 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts +35 -0
- package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts +35 -0
- package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs +349 -0
- package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
- package/dist/testing/assertions.cjs +114 -0
- package/dist/testing/assertions.mjs +109 -0
- package/dist/testing/assertions.mjs.map +1 -0
- package/dist/testing/index.cjs +14 -0
- package/dist/testing/index.d.cts +6 -0
- package/dist/testing/index.d.mts +6 -0
- package/dist/testing/index.mjs +7 -0
- package/dist/testing/types.cjs +15 -0
- package/dist/testing/types.d.cts +90 -0
- package/dist/testing/types.d.cts.map +1 -0
- package/dist/testing/types.d.mts +90 -0
- package/dist/testing/types.d.mts.map +1 -0
- package/dist/testing/types.mjs +16 -0
- package/dist/testing/types.mjs.map +1 -0
- package/package.json +18 -3
- package/src/ColdStorage.ts +136 -0
- package/src/DocumentManager.ts +550 -190
- package/src/Errors.ts +114 -0
- package/src/HotStorage.ts +239 -0
- package/src/Metrics.ts +187 -0
- package/src/MimicAuthService.ts +126 -64
- package/src/MimicClusterServerEngine.ts +946 -0
- package/src/MimicServer.ts +448 -195
- package/src/MimicServerEngine.ts +276 -0
- package/src/PresenceManager.ts +169 -240
- package/src/Protocol.ts +350 -0
- package/src/Types.ts +231 -0
- package/src/index.ts +57 -23
- package/src/testing/ColdStorageTestSuite.ts +589 -0
- package/src/testing/FailingStorage.ts +286 -0
- package/src/testing/HotStorageTestSuite.ts +762 -0
- package/src/testing/StorageIntegrationTestSuite.ts +504 -0
- package/src/testing/assertions.ts +181 -0
- package/src/testing/index.ts +83 -0
- package/src/testing/types.ts +100 -0
- package/tests/ColdStorage.test.ts +24 -0
- package/tests/DocumentManager.test.ts +158 -287
- package/tests/HotStorage.test.ts +24 -0
- package/tests/MimicAuthService.test.ts +102 -134
- package/tests/MimicClusterServerEngine.test.ts +587 -0
- package/tests/MimicServer.test.ts +90 -226
- package/tests/MimicServerEngine.test.ts +521 -0
- package/tests/PresenceManager.test.ts +22 -63
- package/tests/Protocol.test.ts +190 -0
- package/tests/StorageIntegration.test.ts +259 -0
- package/tsconfig.json +1 -1
- package/tsdown.config.ts +1 -1
- package/dist/DocumentProtocol.cjs +0 -94
- package/dist/DocumentProtocol.d.cts +0 -113
- package/dist/DocumentProtocol.d.cts.map +0 -1
- package/dist/DocumentProtocol.d.mts +0 -113
- package/dist/DocumentProtocol.d.mts.map +0 -1
- package/dist/DocumentProtocol.mjs +0 -89
- package/dist/DocumentProtocol.mjs.map +0 -1
- package/dist/MimicConfig.cjs +0 -60
- package/dist/MimicConfig.d.cts +0 -141
- package/dist/MimicConfig.d.cts.map +0 -1
- package/dist/MimicConfig.d.mts +0 -141
- package/dist/MimicConfig.d.mts.map +0 -1
- package/dist/MimicConfig.mjs +0 -50
- package/dist/MimicConfig.mjs.map +0 -1
- package/dist/MimicDataStorage.cjs +0 -83
- package/dist/MimicDataStorage.d.cts +0 -113
- package/dist/MimicDataStorage.d.cts.map +0 -1
- package/dist/MimicDataStorage.d.mts +0 -113
- package/dist/MimicDataStorage.d.mts.map +0 -1
- package/dist/MimicDataStorage.mjs +0 -74
- package/dist/MimicDataStorage.mjs.map +0 -1
- package/dist/WebSocketHandler.cjs +0 -365
- package/dist/WebSocketHandler.d.cts +0 -34
- package/dist/WebSocketHandler.d.cts.map +0 -1
- package/dist/WebSocketHandler.d.mts +0 -34
- package/dist/WebSocketHandler.d.mts.map +0 -1
- package/dist/WebSocketHandler.mjs +0 -355
- package/dist/WebSocketHandler.mjs.map +0 -1
- package/dist/auth/NoAuth.cjs +0 -43
- package/dist/auth/NoAuth.d.cts +0 -22
- package/dist/auth/NoAuth.d.cts.map +0 -1
- package/dist/auth/NoAuth.d.mts +0 -22
- package/dist/auth/NoAuth.d.mts.map +0 -1
- package/dist/auth/NoAuth.mjs +0 -36
- package/dist/auth/NoAuth.mjs.map +0 -1
- package/dist/errors.cjs +0 -74
- package/dist/errors.d.cts +0 -89
- package/dist/errors.d.cts.map +0 -1
- package/dist/errors.d.mts +0 -89
- package/dist/errors.d.mts.map +0 -1
- package/dist/errors.mjs +0 -67
- package/dist/errors.mjs.map +0 -1
- package/dist/storage/InMemoryDataStorage.cjs +0 -57
- package/dist/storage/InMemoryDataStorage.d.cts +0 -19
- package/dist/storage/InMemoryDataStorage.d.cts.map +0 -1
- package/dist/storage/InMemoryDataStorage.d.mts +0 -19
- package/dist/storage/InMemoryDataStorage.d.mts.map +0 -1
- package/dist/storage/InMemoryDataStorage.mjs +0 -48
- package/dist/storage/InMemoryDataStorage.mjs.map +0 -1
- package/src/DocumentProtocol.ts +0 -112
- package/src/MimicConfig.ts +0 -211
- package/src/MimicDataStorage.ts +0 -157
- package/src/WebSocketHandler.ts +0 -735
- package/src/auth/NoAuth.ts +0 -46
- package/src/errors.ts +0 -113
- package/src/storage/InMemoryDataStorage.ts +0 -66
- package/tests/DocumentProtocol.test.ts +0 -113
- package/tests/InMemoryDataStorage.test.ts +0 -190
- package/tests/MimicConfig.test.ts +0 -290
- package/tests/MimicDataStorage.test.ts +0 -190
- package/tests/NoAuth.test.ts +0 -94
- package/tests/WebSocketHandler.test.ts +0 -321
- package/tests/errors.test.ts +0 -77
package/src/auth/NoAuth.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @since 0.0.1
|
|
3
|
-
* No authentication implementation for Mimic connections.
|
|
4
|
-
* All connections are automatically authenticated (open access).
|
|
5
|
-
*/
|
|
6
|
-
import * as Effect from "effect/Effect";
|
|
7
|
-
import * as Layer from "effect/Layer";
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
MimicAuthServiceTag,
|
|
11
|
-
type MimicAuthService,
|
|
12
|
-
} from "../MimicAuthService.js";
|
|
13
|
-
|
|
14
|
-
// =============================================================================
|
|
15
|
-
// No-Auth Implementation
|
|
16
|
-
// =============================================================================
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Authentication service that auto-succeeds all authentication requests.
|
|
20
|
-
* Use this for development or when authentication is handled externally.
|
|
21
|
-
*/
|
|
22
|
-
const noAuthService: MimicAuthService = {
|
|
23
|
-
authenticate: (_token: string) =>
|
|
24
|
-
Effect.succeed({ success: true as const }),
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// =============================================================================
|
|
28
|
-
// Layer
|
|
29
|
-
// =============================================================================
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Layer that provides no authentication (open access).
|
|
33
|
-
* All connections are automatically authenticated.
|
|
34
|
-
*
|
|
35
|
-
* WARNING: Only use this for development or when authentication
|
|
36
|
-
* is handled at a different layer (e.g., API gateway, reverse proxy).
|
|
37
|
-
*/
|
|
38
|
-
export const layer: Layer.Layer<MimicAuthServiceTag> = Layer.succeed(
|
|
39
|
-
MimicAuthServiceTag,
|
|
40
|
-
noAuthService
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Default layer alias for convenience.
|
|
45
|
-
*/
|
|
46
|
-
export const layerDefault = layer;
|
package/src/errors.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @since 0.0.1
|
|
3
|
-
* Error types for the Mimic server.
|
|
4
|
-
*/
|
|
5
|
-
import * as Data from "effect/Data";
|
|
6
|
-
|
|
7
|
-
// =============================================================================
|
|
8
|
-
// Error Types
|
|
9
|
-
// =============================================================================
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Error when a document type is not found in the schema registry.
|
|
13
|
-
*/
|
|
14
|
-
export class DocumentTypeNotFoundError extends Data.TaggedError(
|
|
15
|
-
"DocumentTypeNotFoundError"
|
|
16
|
-
)<{
|
|
17
|
-
readonly documentType: string;
|
|
18
|
-
}> {
|
|
19
|
-
override get message(): string {
|
|
20
|
-
return `Document type not found: ${this.documentType}`;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Error when a document is not found.
|
|
26
|
-
*/
|
|
27
|
-
export class DocumentNotFoundError extends Data.TaggedError(
|
|
28
|
-
"DocumentNotFoundError"
|
|
29
|
-
)<{
|
|
30
|
-
readonly documentId: string;
|
|
31
|
-
}> {
|
|
32
|
-
override get message(): string {
|
|
33
|
-
return `Document not found: ${this.documentId}`;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Error when authentication fails.
|
|
39
|
-
*/
|
|
40
|
-
export class AuthenticationError extends Data.TaggedError(
|
|
41
|
-
"AuthenticationError"
|
|
42
|
-
)<{
|
|
43
|
-
readonly reason: string;
|
|
44
|
-
}> {
|
|
45
|
-
override get message(): string {
|
|
46
|
-
return `Authentication failed: ${this.reason}`;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Error when a transaction is rejected.
|
|
52
|
-
*/
|
|
53
|
-
export class TransactionRejectedError extends Data.TaggedError(
|
|
54
|
-
"TransactionRejectedError"
|
|
55
|
-
)<{
|
|
56
|
-
readonly transactionId: string;
|
|
57
|
-
readonly reason: string;
|
|
58
|
-
}> {
|
|
59
|
-
override get message(): string {
|
|
60
|
-
return `Transaction ${this.transactionId} rejected: ${this.reason}`;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Error when parsing a client message fails.
|
|
66
|
-
*/
|
|
67
|
-
export class MessageParseError extends Data.TaggedError("MessageParseError")<{
|
|
68
|
-
readonly cause: unknown;
|
|
69
|
-
}> {
|
|
70
|
-
override get message(): string {
|
|
71
|
-
return `Failed to parse message: ${String(this.cause)}`;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Error when the WebSocket connection is invalid.
|
|
77
|
-
*/
|
|
78
|
-
export class InvalidConnectionError extends Data.TaggedError(
|
|
79
|
-
"InvalidConnectionError"
|
|
80
|
-
)<{
|
|
81
|
-
readonly reason: string;
|
|
82
|
-
}> {
|
|
83
|
-
override get message(): string {
|
|
84
|
-
return `Invalid connection: ${this.reason}`;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Error when the document ID is missing from the URL path.
|
|
90
|
-
*/
|
|
91
|
-
export class MissingDocumentIdError extends Data.TaggedError(
|
|
92
|
-
"MissingDocumentIdError"
|
|
93
|
-
)<{
|
|
94
|
-
readonly path?: string;
|
|
95
|
-
}> {
|
|
96
|
-
override get message(): string {
|
|
97
|
-
return this.path
|
|
98
|
-
? `Document ID is required in the URL path: ${this.path}`
|
|
99
|
-
: "Document ID is required in the URL path";
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Union of all Mimic server errors.
|
|
105
|
-
*/
|
|
106
|
-
export type MimicServerError =
|
|
107
|
-
| DocumentTypeNotFoundError
|
|
108
|
-
| DocumentNotFoundError
|
|
109
|
-
| AuthenticationError
|
|
110
|
-
| TransactionRejectedError
|
|
111
|
-
| MessageParseError
|
|
112
|
-
| InvalidConnectionError
|
|
113
|
-
| MissingDocumentIdError;
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @since 0.0.1
|
|
3
|
-
* In-memory data storage implementation for Mimic documents.
|
|
4
|
-
* Provides ephemeral storage - data is lost when the server restarts.
|
|
5
|
-
*/
|
|
6
|
-
import * as Effect from "effect/Effect";
|
|
7
|
-
import * as Layer from "effect/Layer";
|
|
8
|
-
import * as Ref from "effect/Ref";
|
|
9
|
-
import * as HashMap from "effect/HashMap";
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
MimicDataStorageTag,
|
|
13
|
-
type MimicDataStorage,
|
|
14
|
-
} from "../MimicDataStorage.js";
|
|
15
|
-
|
|
16
|
-
// =============================================================================
|
|
17
|
-
// In-Memory Storage Implementation
|
|
18
|
-
// =============================================================================
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Create an in-memory storage service.
|
|
22
|
-
* Uses a HashMap to store documents in memory.
|
|
23
|
-
*/
|
|
24
|
-
const makeInMemoryStorage = Effect.gen(function* () {
|
|
25
|
-
// Create a mutable reference to a HashMap for storing documents
|
|
26
|
-
const store = yield* Ref.make(HashMap.empty<string, unknown>());
|
|
27
|
-
|
|
28
|
-
const storage: MimicDataStorage = {
|
|
29
|
-
load: (documentId: string) =>
|
|
30
|
-
Effect.gen(function* () {
|
|
31
|
-
const current = yield* Ref.get(store);
|
|
32
|
-
const result = HashMap.get(current, documentId);
|
|
33
|
-
return result._tag === "Some" ? result.value : undefined;
|
|
34
|
-
}),
|
|
35
|
-
|
|
36
|
-
save: (documentId: string, state: unknown) =>
|
|
37
|
-
Ref.update(store, (map) => HashMap.set(map, documentId, state)),
|
|
38
|
-
|
|
39
|
-
delete: (documentId: string) =>
|
|
40
|
-
Ref.update(store, (map) => HashMap.remove(map, documentId)),
|
|
41
|
-
|
|
42
|
-
onLoad: (state: unknown) => Effect.succeed(state),
|
|
43
|
-
|
|
44
|
-
onSave: (state: unknown) => Effect.succeed(state),
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
return storage;
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// =============================================================================
|
|
51
|
-
// Layer
|
|
52
|
-
// =============================================================================
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Layer that provides in-memory data storage.
|
|
56
|
-
* This is the default storage implementation - ephemeral and non-persistent.
|
|
57
|
-
*/
|
|
58
|
-
export const layer: Layer.Layer<MimicDataStorageTag> = Layer.effect(
|
|
59
|
-
MimicDataStorageTag,
|
|
60
|
-
makeInMemoryStorage
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Default layer alias for convenience.
|
|
65
|
-
*/
|
|
66
|
-
export const layerDefault = layer;
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import * as Schema from "effect/Schema";
|
|
3
|
-
import * as Protocol from "../src/DocumentProtocol";
|
|
4
|
-
|
|
5
|
-
// =============================================================================
|
|
6
|
-
// Schema Tests
|
|
7
|
-
// =============================================================================
|
|
8
|
-
|
|
9
|
-
describe("DocumentProtocol", () => {
|
|
10
|
-
describe("TransactionSchema", () => {
|
|
11
|
-
it("should validate a valid transaction", () => {
|
|
12
|
-
const transaction = {
|
|
13
|
-
id: "tx-123",
|
|
14
|
-
ops: [
|
|
15
|
-
{ kind: "string.set", path: { segments: ["title"] }, payload: "Hello" },
|
|
16
|
-
],
|
|
17
|
-
timestamp: Date.now(),
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const result = Schema.decodeUnknownSync(Protocol.TransactionSchema)(transaction);
|
|
21
|
-
expect(result.id).toBe("tx-123");
|
|
22
|
-
expect(result.ops).toHaveLength(1);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it("should reject invalid transaction", () => {
|
|
26
|
-
const invalid = {
|
|
27
|
-
id: 123, // should be string
|
|
28
|
-
ops: [],
|
|
29
|
-
timestamp: Date.now(),
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
expect(() =>
|
|
33
|
-
Schema.decodeUnknownSync(Protocol.TransactionSchema)(invalid)
|
|
34
|
-
).toThrow();
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
describe("TransactionMessageSchema", () => {
|
|
39
|
-
it("should validate a transaction message", () => {
|
|
40
|
-
const message = {
|
|
41
|
-
type: "transaction",
|
|
42
|
-
transaction: {
|
|
43
|
-
id: "tx-456",
|
|
44
|
-
ops: [],
|
|
45
|
-
timestamp: Date.now(),
|
|
46
|
-
},
|
|
47
|
-
version: 1,
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const result = Schema.decodeUnknownSync(Protocol.TransactionMessageSchema)(message);
|
|
51
|
-
expect(result.type).toBe("transaction");
|
|
52
|
-
expect(result.version).toBe(1);
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
describe("SnapshotMessageSchema", () => {
|
|
57
|
-
it("should validate a snapshot message", () => {
|
|
58
|
-
const message = {
|
|
59
|
-
type: "snapshot",
|
|
60
|
-
state: { title: "Test", count: 42 },
|
|
61
|
-
version: 5,
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const result = Schema.decodeUnknownSync(Protocol.SnapshotMessageSchema)(message);
|
|
65
|
-
expect(result.type).toBe("snapshot");
|
|
66
|
-
expect(result.state).toEqual({ title: "Test", count: 42 });
|
|
67
|
-
expect(result.version).toBe(5);
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe("ErrorMessageSchema", () => {
|
|
72
|
-
it("should validate an error message", () => {
|
|
73
|
-
const message = {
|
|
74
|
-
type: "error",
|
|
75
|
-
transactionId: "tx-789",
|
|
76
|
-
reason: "Transaction is empty",
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const result = Schema.decodeUnknownSync(Protocol.ErrorMessageSchema)(message);
|
|
80
|
-
expect(result.type).toBe("error");
|
|
81
|
-
expect(result.transactionId).toBe("tx-789");
|
|
82
|
-
expect(result.reason).toBe("Transaction is empty");
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe("SubmitResultSchema", () => {
|
|
87
|
-
it("should validate a success result", () => {
|
|
88
|
-
const result = {
|
|
89
|
-
success: true,
|
|
90
|
-
version: 10,
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
const decoded = Schema.decodeUnknownSync(Protocol.SubmitResultSchema)(result);
|
|
94
|
-
expect(decoded.success).toBe(true);
|
|
95
|
-
if (decoded.success) {
|
|
96
|
-
expect(decoded.version).toBe(10);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it("should validate a failure result", () => {
|
|
101
|
-
const result = {
|
|
102
|
-
success: false,
|
|
103
|
-
reason: "Invalid operation",
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const decoded = Schema.decodeUnknownSync(Protocol.SubmitResultSchema)(result);
|
|
107
|
-
expect(decoded.success).toBe(false);
|
|
108
|
-
if (!decoded.success) {
|
|
109
|
-
expect(decoded.reason).toBe("Invalid operation");
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
});
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as InMemoryDataStorage from "../src/storage/InMemoryDataStorage";
|
|
4
|
-
import { MimicDataStorageTag } from "../src/MimicDataStorage";
|
|
5
|
-
|
|
6
|
-
// =============================================================================
|
|
7
|
-
// InMemoryDataStorage Tests
|
|
8
|
-
// =============================================================================
|
|
9
|
-
|
|
10
|
-
describe("InMemoryDataStorage", () => {
|
|
11
|
-
describe("load", () => {
|
|
12
|
-
it("should return undefined for non-existent documents", async () => {
|
|
13
|
-
const result = await Effect.runPromise(
|
|
14
|
-
Effect.gen(function* () {
|
|
15
|
-
const storage = yield* MimicDataStorageTag;
|
|
16
|
-
return yield* storage.load("non-existent-doc");
|
|
17
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
expect(result).toBeUndefined();
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe("save and load", () => {
|
|
25
|
-
it("should save and load document state", async () => {
|
|
26
|
-
const testState = { title: "Test Document", count: 42 };
|
|
27
|
-
|
|
28
|
-
const result = await Effect.runPromise(
|
|
29
|
-
Effect.gen(function* () {
|
|
30
|
-
const storage = yield* MimicDataStorageTag;
|
|
31
|
-
yield* storage.save("doc-1", testState);
|
|
32
|
-
return yield* storage.load("doc-1");
|
|
33
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
expect(result).toEqual(testState);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("should update existing document", async () => {
|
|
40
|
-
const initialState = { title: "Initial", count: 0 };
|
|
41
|
-
const updatedState = { title: "Updated", count: 100 };
|
|
42
|
-
|
|
43
|
-
const result = await Effect.runPromise(
|
|
44
|
-
Effect.gen(function* () {
|
|
45
|
-
const storage = yield* MimicDataStorageTag;
|
|
46
|
-
yield* storage.save("doc-1", initialState);
|
|
47
|
-
yield* storage.save("doc-1", updatedState);
|
|
48
|
-
return yield* storage.load("doc-1");
|
|
49
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
expect(result).toEqual(updatedState);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it("should store multiple documents independently", async () => {
|
|
56
|
-
const state1 = { title: "Doc 1" };
|
|
57
|
-
const state2 = { title: "Doc 2" };
|
|
58
|
-
const state3 = { title: "Doc 3" };
|
|
59
|
-
|
|
60
|
-
const result = await Effect.runPromise(
|
|
61
|
-
Effect.gen(function* () {
|
|
62
|
-
const storage = yield* MimicDataStorageTag;
|
|
63
|
-
yield* storage.save("doc-1", state1);
|
|
64
|
-
yield* storage.save("doc-2", state2);
|
|
65
|
-
yield* storage.save("doc-3", state3);
|
|
66
|
-
return {
|
|
67
|
-
doc1: yield* storage.load("doc-1"),
|
|
68
|
-
doc2: yield* storage.load("doc-2"),
|
|
69
|
-
doc3: yield* storage.load("doc-3"),
|
|
70
|
-
};
|
|
71
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
expect(result.doc1).toEqual(state1);
|
|
75
|
-
expect(result.doc2).toEqual(state2);
|
|
76
|
-
expect(result.doc3).toEqual(state3);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
describe("delete", () => {
|
|
81
|
-
it("should delete existing document", async () => {
|
|
82
|
-
const testState = { title: "To be deleted" };
|
|
83
|
-
|
|
84
|
-
const result = await Effect.runPromise(
|
|
85
|
-
Effect.gen(function* () {
|
|
86
|
-
const storage = yield* MimicDataStorageTag;
|
|
87
|
-
yield* storage.save("doc-1", testState);
|
|
88
|
-
const beforeDelete = yield* storage.load("doc-1");
|
|
89
|
-
yield* storage.delete("doc-1");
|
|
90
|
-
const afterDelete = yield* storage.load("doc-1");
|
|
91
|
-
return { beforeDelete, afterDelete };
|
|
92
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
expect(result.beforeDelete).toEqual(testState);
|
|
96
|
-
expect(result.afterDelete).toBeUndefined();
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it("should handle deleting non-existent document gracefully", async () => {
|
|
100
|
-
await Effect.runPromise(
|
|
101
|
-
Effect.gen(function* () {
|
|
102
|
-
const storage = yield* MimicDataStorageTag;
|
|
103
|
-
yield* storage.delete("non-existent-doc");
|
|
104
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
105
|
-
);
|
|
106
|
-
// Should not throw
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it("should not affect other documents when deleting", async () => {
|
|
110
|
-
const state1 = { title: "Doc 1" };
|
|
111
|
-
const state2 = { title: "Doc 2" };
|
|
112
|
-
|
|
113
|
-
const result = await Effect.runPromise(
|
|
114
|
-
Effect.gen(function* () {
|
|
115
|
-
const storage = yield* MimicDataStorageTag;
|
|
116
|
-
yield* storage.save("doc-1", state1);
|
|
117
|
-
yield* storage.save("doc-2", state2);
|
|
118
|
-
yield* storage.delete("doc-1");
|
|
119
|
-
return {
|
|
120
|
-
doc1: yield* storage.load("doc-1"),
|
|
121
|
-
doc2: yield* storage.load("doc-2"),
|
|
122
|
-
};
|
|
123
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
expect(result.doc1).toBeUndefined();
|
|
127
|
-
expect(result.doc2).toEqual(state2);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe("onLoad", () => {
|
|
132
|
-
it("should pass through state unchanged", async () => {
|
|
133
|
-
const testState = { title: "Test", nested: { value: 123 } };
|
|
134
|
-
|
|
135
|
-
const result = await Effect.runPromise(
|
|
136
|
-
Effect.gen(function* () {
|
|
137
|
-
const storage = yield* MimicDataStorageTag;
|
|
138
|
-
return yield* storage.onLoad(testState);
|
|
139
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
expect(result).toBe(testState);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
describe("onSave", () => {
|
|
147
|
-
it("should pass through state unchanged", async () => {
|
|
148
|
-
const testState = { title: "Test", nested: { value: 456 } };
|
|
149
|
-
|
|
150
|
-
const result = await Effect.runPromise(
|
|
151
|
-
Effect.gen(function* () {
|
|
152
|
-
const storage = yield* MimicDataStorageTag;
|
|
153
|
-
return yield* storage.onSave(testState);
|
|
154
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
expect(result).toBe(testState);
|
|
158
|
-
});
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
describe("layer aliases", () => {
|
|
162
|
-
it("should have layerDefault as an alias for layer", () => {
|
|
163
|
-
expect(InMemoryDataStorage.layerDefault).toBe(InMemoryDataStorage.layer);
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
describe("isolation", () => {
|
|
168
|
-
it("should have independent storage per layer instance", async () => {
|
|
169
|
-
const testState = { title: "Isolated" };
|
|
170
|
-
|
|
171
|
-
// Save in one layer
|
|
172
|
-
await Effect.runPromise(
|
|
173
|
-
Effect.gen(function* () {
|
|
174
|
-
const storage = yield* MimicDataStorageTag;
|
|
175
|
-
yield* storage.save("doc-1", testState);
|
|
176
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
177
|
-
);
|
|
178
|
-
|
|
179
|
-
// Load in a new layer instance - should not find the document
|
|
180
|
-
const result = await Effect.runPromise(
|
|
181
|
-
Effect.gen(function* () {
|
|
182
|
-
const storage = yield* MimicDataStorageTag;
|
|
183
|
-
return yield* storage.load("doc-1");
|
|
184
|
-
}).pipe(Effect.provide(InMemoryDataStorage.layer))
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
expect(result).toBeUndefined();
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
});
|