@voidhash/mimic-effect 0.0.8 → 1.0.0-beta.1
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 +93 -89
- 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 +193 -82
- package/dist/DocumentManager.d.cts +33 -19
- package/dist/DocumentManager.d.cts.map +1 -1
- package/dist/DocumentManager.d.mts +33 -19
- package/dist/DocumentManager.d.mts.map +1 -1
- package/dist/DocumentManager.mjs +189 -67
- package/dist/DocumentManager.mjs.map +1 -1
- package/dist/Errors.cjs +45 -0
- package/dist/Errors.d.cts +81 -0
- package/dist/Errors.d.cts.map +1 -0
- package/dist/Errors.d.mts +81 -0
- package/dist/Errors.d.mts.map +1 -0
- package/dist/Errors.mjs +40 -0
- package/dist/Errors.mjs.map +1 -0
- package/dist/HotStorage.cjs +77 -0
- package/dist/HotStorage.d.cts +54 -0
- package/dist/HotStorage.d.cts.map +1 -0
- package/dist/HotStorage.d.mts +54 -0
- package/dist/HotStorage.d.mts.map +1 -0
- package/dist/HotStorage.mjs +77 -0
- package/dist/HotStorage.mjs.map +1 -0
- package/dist/Metrics.cjs +121 -0
- package/dist/Metrics.d.cts +27 -0
- package/dist/Metrics.d.cts.map +1 -0
- package/dist/Metrics.d.mts +27 -0
- package/dist/Metrics.d.mts.map +1 -0
- package/dist/Metrics.mjs +106 -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 +443 -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 +445 -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 +75 -0
- package/dist/MimicServerEngine.d.cts.map +1 -0
- package/dist/MimicServerEngine.d.mts +75 -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/package.json +14 -6
- package/src/ColdStorage.ts +136 -0
- package/src/DocumentManager.ts +445 -193
- package/src/Errors.ts +100 -0
- package/src/HotStorage.ts +165 -0
- package/src/Metrics.ts +163 -0
- package/src/MimicAuthService.ts +126 -64
- package/src/MimicClusterServerEngine.ts +824 -0
- package/src/MimicServer.ts +448 -195
- package/src/MimicServerEngine.ts +272 -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/tests/ColdStorage.test.ts +136 -0
- package/tests/DocumentManager.test.ts +158 -287
- package/tests/HotStorage.test.ts +143 -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/tsconfig.json +1 -1
- package/dist/DocumentProtocol.cjs +0 -94
- package/dist/DocumentProtocol.d.cts +0 -113
- package/dist/DocumentProtocol.d.cts.map +0 -1
- package/dist/DocumentProtocol.d.mts +0 -113
- package/dist/DocumentProtocol.d.mts.map +0 -1
- package/dist/DocumentProtocol.mjs +0 -89
- package/dist/DocumentProtocol.mjs.map +0 -1
- package/dist/MimicConfig.cjs +0 -60
- package/dist/MimicConfig.d.cts +0 -141
- package/dist/MimicConfig.d.cts.map +0 -1
- package/dist/MimicConfig.d.mts +0 -141
- package/dist/MimicConfig.d.mts.map +0 -1
- package/dist/MimicConfig.mjs +0 -50
- package/dist/MimicConfig.mjs.map +0 -1
- package/dist/MimicDataStorage.cjs +0 -83
- package/dist/MimicDataStorage.d.cts +0 -113
- package/dist/MimicDataStorage.d.cts.map +0 -1
- package/dist/MimicDataStorage.d.mts +0 -113
- package/dist/MimicDataStorage.d.mts.map +0 -1
- package/dist/MimicDataStorage.mjs +0 -74
- package/dist/MimicDataStorage.mjs.map +0 -1
- package/dist/WebSocketHandler.cjs +0 -365
- package/dist/WebSocketHandler.d.cts +0 -34
- package/dist/WebSocketHandler.d.cts.map +0 -1
- package/dist/WebSocketHandler.d.mts +0 -34
- package/dist/WebSocketHandler.d.mts.map +0 -1
- package/dist/WebSocketHandler.mjs +0 -355
- package/dist/WebSocketHandler.mjs.map +0 -1
- package/dist/auth/NoAuth.cjs +0 -43
- package/dist/auth/NoAuth.d.cts +0 -22
- package/dist/auth/NoAuth.d.cts.map +0 -1
- package/dist/auth/NoAuth.d.mts +0 -22
- package/dist/auth/NoAuth.d.mts.map +0 -1
- package/dist/auth/NoAuth.mjs +0 -36
- package/dist/auth/NoAuth.mjs.map +0 -1
- package/dist/errors.cjs +0 -74
- package/dist/errors.d.cts +0 -89
- package/dist/errors.d.cts.map +0 -1
- package/dist/errors.d.mts +0 -89
- package/dist/errors.d.mts.map +0 -1
- package/dist/errors.mjs +0 -67
- package/dist/errors.mjs.map +0 -1
- package/dist/storage/InMemoryDataStorage.cjs +0 -57
- package/dist/storage/InMemoryDataStorage.d.cts +0 -19
- package/dist/storage/InMemoryDataStorage.d.cts.map +0 -1
- package/dist/storage/InMemoryDataStorage.d.mts +0 -19
- package/dist/storage/InMemoryDataStorage.d.mts.map +0 -1
- package/dist/storage/InMemoryDataStorage.mjs +0 -48
- package/dist/storage/InMemoryDataStorage.mjs.map +0 -1
- package/src/DocumentProtocol.ts +0 -112
- package/src/MimicConfig.ts +0 -211
- package/src/MimicDataStorage.ts +0 -157
- package/src/WebSocketHandler.ts +0 -735
- package/src/auth/NoAuth.ts +0 -46
- package/src/errors.ts +0 -113
- package/src/storage/InMemoryDataStorage.ts +0 -66
- package/tests/DocumentProtocol.test.ts +0 -113
- package/tests/InMemoryDataStorage.test.ts +0 -190
- package/tests/MimicConfig.test.ts +0 -290
- package/tests/MimicDataStorage.test.ts +0 -190
- package/tests/NoAuth.test.ts +0 -94
- package/tests/WebSocketHandler.test.ts +0 -321
- package/tests/errors.test.ts +0 -77
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { HotStorage, HotStorageTag } from "../src/HotStorage";
|
|
4
|
+
import type { WalEntry } from "../src/Types";
|
|
5
|
+
import { Transaction } from "@voidhash/mimic";
|
|
6
|
+
|
|
7
|
+
describe("HotStorage", () => {
|
|
8
|
+
describe("InMemory", () => {
|
|
9
|
+
const layer = HotStorage.InMemory.make();
|
|
10
|
+
|
|
11
|
+
const makeEntry = (version: number): WalEntry => ({
|
|
12
|
+
transaction: Transaction.make([]),
|
|
13
|
+
version,
|
|
14
|
+
timestamp: Date.now(),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it("should return empty array for missing document", async () => {
|
|
18
|
+
const result = await Effect.runPromise(
|
|
19
|
+
Effect.gen(function* () {
|
|
20
|
+
const storage = yield* HotStorageTag;
|
|
21
|
+
return yield* storage.getEntries("non-existent", 0);
|
|
22
|
+
}).pipe(Effect.provide(layer))
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
expect(result).toEqual([]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should append and retrieve entries", async () => {
|
|
29
|
+
const entry1 = makeEntry(1);
|
|
30
|
+
const entry2 = makeEntry(2);
|
|
31
|
+
|
|
32
|
+
const result = await Effect.runPromise(
|
|
33
|
+
Effect.gen(function* () {
|
|
34
|
+
const storage = yield* HotStorageTag;
|
|
35
|
+
yield* storage.append("doc-1", entry1);
|
|
36
|
+
yield* storage.append("doc-1", entry2);
|
|
37
|
+
return yield* storage.getEntries("doc-1", 0);
|
|
38
|
+
}).pipe(Effect.provide(layer))
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
expect(result.length).toBe(2);
|
|
42
|
+
expect(result[0]!.version).toBe(1);
|
|
43
|
+
expect(result[1]!.version).toBe(2);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should filter entries by sinceVersion", async () => {
|
|
47
|
+
const entries = [makeEntry(1), makeEntry(2), makeEntry(3), makeEntry(4)];
|
|
48
|
+
|
|
49
|
+
const result = await Effect.runPromise(
|
|
50
|
+
Effect.gen(function* () {
|
|
51
|
+
const storage = yield* HotStorageTag;
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
yield* storage.append("doc-1", entry);
|
|
54
|
+
}
|
|
55
|
+
return yield* storage.getEntries("doc-1", 2);
|
|
56
|
+
}).pipe(Effect.provide(layer))
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(result.length).toBe(2);
|
|
60
|
+
expect(result[0]!.version).toBe(3);
|
|
61
|
+
expect(result[1]!.version).toBe(4);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("should truncate entries up to version", async () => {
|
|
65
|
+
const entries = [makeEntry(1), makeEntry(2), makeEntry(3), makeEntry(4)];
|
|
66
|
+
|
|
67
|
+
const result = await Effect.runPromise(
|
|
68
|
+
Effect.gen(function* () {
|
|
69
|
+
const storage = yield* HotStorageTag;
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
yield* storage.append("doc-1", entry);
|
|
72
|
+
}
|
|
73
|
+
yield* storage.truncate("doc-1", 2);
|
|
74
|
+
return yield* storage.getEntries("doc-1", 0);
|
|
75
|
+
}).pipe(Effect.provide(layer))
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(result.length).toBe(2);
|
|
79
|
+
expect(result[0]!.version).toBe(3);
|
|
80
|
+
expect(result[1]!.version).toBe(4);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should maintain order after append", async () => {
|
|
84
|
+
const entries = [makeEntry(3), makeEntry(1), makeEntry(2)];
|
|
85
|
+
|
|
86
|
+
const result = await Effect.runPromise(
|
|
87
|
+
Effect.gen(function* () {
|
|
88
|
+
const storage = yield* HotStorageTag;
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
yield* storage.append("doc-1", entry);
|
|
91
|
+
}
|
|
92
|
+
return yield* storage.getEntries("doc-1", 0);
|
|
93
|
+
}).pipe(Effect.provide(layer))
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Should be sorted by version
|
|
97
|
+
expect(result.length).toBe(3);
|
|
98
|
+
expect(result[0]!.version).toBe(1);
|
|
99
|
+
expect(result[1]!.version).toBe(2);
|
|
100
|
+
expect(result[2]!.version).toBe(3);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("should isolate documents", async () => {
|
|
104
|
+
const entry1 = makeEntry(1);
|
|
105
|
+
const entry2 = makeEntry(2);
|
|
106
|
+
|
|
107
|
+
const result = await Effect.runPromise(
|
|
108
|
+
Effect.gen(function* () {
|
|
109
|
+
const storage = yield* HotStorageTag;
|
|
110
|
+
yield* storage.append("doc-1", entry1);
|
|
111
|
+
yield* storage.append("doc-2", entry2);
|
|
112
|
+
|
|
113
|
+
const entries1 = yield* storage.getEntries("doc-1", 0);
|
|
114
|
+
const entries2 = yield* storage.getEntries("doc-2", 0);
|
|
115
|
+
|
|
116
|
+
return { entries1, entries2 };
|
|
117
|
+
}).pipe(Effect.provide(layer))
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
expect(result.entries1.length).toBe(1);
|
|
121
|
+
expect(result.entries1[0]!.version).toBe(1);
|
|
122
|
+
expect(result.entries2.length).toBe(1);
|
|
123
|
+
expect(result.entries2[0]!.version).toBe(2);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("should not error when truncating non-existent document", async () => {
|
|
127
|
+
await expect(
|
|
128
|
+
Effect.runPromise(
|
|
129
|
+
Effect.gen(function* () {
|
|
130
|
+
const storage = yield* HotStorageTag;
|
|
131
|
+
yield* storage.truncate("non-existent", 5);
|
|
132
|
+
}).pipe(Effect.provide(layer))
|
|
133
|
+
)
|
|
134
|
+
).resolves.toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("Tag", () => {
|
|
139
|
+
it("should have correct identifier", () => {
|
|
140
|
+
expect(HotStorageTag.key).toBe("@voidhash/mimic-effect/HotStorage");
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -1,184 +1,152 @@
|
|
|
1
1
|
import { describe, it, expect } from "vitest";
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import { Effect, Layer, Context } from "effect";
|
|
3
|
+
import {
|
|
4
|
+
MimicAuthService,
|
|
5
|
+
MimicAuthServiceTag,
|
|
6
|
+
} from "../src/MimicAuthService";
|
|
7
|
+
import { AuthenticationError } from "../src/Errors";
|
|
8
8
|
|
|
9
9
|
describe("MimicAuthService", () => {
|
|
10
|
-
describe("
|
|
11
|
-
|
|
12
|
-
const authService = MimicAuthService.make((token) => ({
|
|
13
|
-
success: true,
|
|
14
|
-
userId: `user-${token}`,
|
|
15
|
-
}));
|
|
16
|
-
|
|
17
|
-
const result = await Effect.runPromise(
|
|
18
|
-
authService.authenticate("test-token")
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
expect(result.success).toBe(true);
|
|
22
|
-
if (result.success) {
|
|
23
|
-
expect(result.userId).toBe("user-test-token");
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it("should create auth service with async handler", async () => {
|
|
28
|
-
const authService = MimicAuthService.make(async (token) => {
|
|
29
|
-
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
30
|
-
return { success: true, userId: `async-${token}` };
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const result = await Effect.runPromise(
|
|
34
|
-
authService.authenticate("async-token")
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
expect(result.success).toBe(true);
|
|
38
|
-
if (result.success) {
|
|
39
|
-
expect(result.userId).toBe("async-async-token");
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it("should handle auth failure", async () => {
|
|
44
|
-
const authService = MimicAuthService.make((_token) => ({
|
|
45
|
-
success: false,
|
|
46
|
-
error: "Invalid token",
|
|
47
|
-
}));
|
|
10
|
+
describe("NoAuth", () => {
|
|
11
|
+
const layer = MimicAuthService.NoAuth.make();
|
|
48
12
|
|
|
13
|
+
it("should authenticate any token with write permission", async () => {
|
|
49
14
|
const result = await Effect.runPromise(
|
|
50
|
-
|
|
15
|
+
Effect.gen(function* () {
|
|
16
|
+
const auth = yield* MimicAuthServiceTag;
|
|
17
|
+
return yield* auth.authenticate("any-token", "any-doc");
|
|
18
|
+
}).pipe(Effect.provide(layer))
|
|
51
19
|
);
|
|
52
20
|
|
|
53
|
-
expect(result.
|
|
54
|
-
|
|
55
|
-
expect(result.error).toBe("Invalid token");
|
|
56
|
-
}
|
|
21
|
+
expect(result.userId).toBe("anonymous");
|
|
22
|
+
expect(result.permission).toBe("write");
|
|
57
23
|
});
|
|
58
24
|
|
|
59
|
-
it("should
|
|
60
|
-
const authService = MimicAuthService.make((_token) => ({
|
|
61
|
-
success: true,
|
|
62
|
-
}));
|
|
63
|
-
|
|
25
|
+
it("should work with empty token", async () => {
|
|
64
26
|
const result = await Effect.runPromise(
|
|
65
|
-
|
|
27
|
+
Effect.gen(function* () {
|
|
28
|
+
const auth = yield* MimicAuthServiceTag;
|
|
29
|
+
return yield* auth.authenticate("", "doc-1");
|
|
30
|
+
}).pipe(Effect.provide(layer))
|
|
66
31
|
);
|
|
67
32
|
|
|
68
|
-
expect(result.
|
|
69
|
-
|
|
70
|
-
expect(result.userId).toBeUndefined();
|
|
71
|
-
}
|
|
33
|
+
expect(result.userId).toBe("anonymous");
|
|
34
|
+
expect(result.permission).toBe("write");
|
|
72
35
|
});
|
|
73
36
|
});
|
|
74
37
|
|
|
75
|
-
describe("
|
|
76
|
-
it("should
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
38
|
+
describe("Static", () => {
|
|
39
|
+
it("should return configured permissions", async () => {
|
|
40
|
+
const layer = MimicAuthService.Static.make({
|
|
41
|
+
permissions: {
|
|
42
|
+
"user-1": "write",
|
|
43
|
+
"user-2": "read",
|
|
44
|
+
},
|
|
45
|
+
});
|
|
80
46
|
|
|
81
47
|
const result = await Effect.runPromise(
|
|
82
|
-
authService.authenticate("effect-token")
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
expect(result.success).toBe(true);
|
|
86
|
-
if (result.success) {
|
|
87
|
-
expect(result.userId).toBe("effect-effect-token");
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("should support Effect operations in authenticate", async () => {
|
|
92
|
-
const authService = MimicAuthService.makeEffect((token) =>
|
|
93
48
|
Effect.gen(function* () {
|
|
94
|
-
yield*
|
|
95
|
-
|
|
96
|
-
|
|
49
|
+
const auth = yield* MimicAuthServiceTag;
|
|
50
|
+
const result1 = yield* auth.authenticate("user-1", "doc-1");
|
|
51
|
+
const result2 = yield* auth.authenticate("user-2", "doc-1");
|
|
52
|
+
return { result1, result2 };
|
|
53
|
+
}).pipe(Effect.provide(layer))
|
|
97
54
|
);
|
|
98
55
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
expect(result.success).toBe(true);
|
|
104
|
-
if (result.success) {
|
|
105
|
-
expect(result.userId).toBe("delayed-delay-token");
|
|
106
|
-
}
|
|
56
|
+
expect(result.result1.userId).toBe("user-1");
|
|
57
|
+
expect(result.result1.permission).toBe("write");
|
|
58
|
+
expect(result.result2.userId).toBe("user-2");
|
|
59
|
+
expect(result.result2.permission).toBe("read");
|
|
107
60
|
});
|
|
108
|
-
});
|
|
109
61
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
62
|
+
it("should use default permission for unknown users", async () => {
|
|
63
|
+
const layer = MimicAuthService.Static.make({
|
|
64
|
+
permissions: {
|
|
65
|
+
"user-1": "write",
|
|
66
|
+
},
|
|
67
|
+
defaultPermission: "read",
|
|
114
68
|
});
|
|
115
69
|
|
|
116
70
|
const result = await Effect.runPromise(
|
|
117
71
|
Effect.gen(function* () {
|
|
118
|
-
const
|
|
119
|
-
return yield*
|
|
120
|
-
}).pipe(Effect.provide(
|
|
72
|
+
const auth = yield* MimicAuthServiceTag;
|
|
73
|
+
return yield* auth.authenticate("unknown-user", "doc-1");
|
|
74
|
+
}).pipe(Effect.provide(layer))
|
|
121
75
|
);
|
|
122
76
|
|
|
123
|
-
expect(result.
|
|
124
|
-
|
|
125
|
-
expect(result.userId).toBe("layer-layer-token");
|
|
126
|
-
}
|
|
77
|
+
expect(result.userId).toBe("unknown-user");
|
|
78
|
+
expect(result.permission).toBe("read");
|
|
127
79
|
});
|
|
128
|
-
});
|
|
129
80
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
const testLayer = MimicAuthService.layerService(service);
|
|
81
|
+
it("should fail for unknown users without default permission", async () => {
|
|
82
|
+
const layer = MimicAuthService.Static.make({
|
|
83
|
+
permissions: {
|
|
84
|
+
"user-1": "write",
|
|
85
|
+
},
|
|
86
|
+
});
|
|
138
87
|
|
|
139
88
|
const result = await Effect.runPromise(
|
|
140
89
|
Effect.gen(function* () {
|
|
141
|
-
const
|
|
142
|
-
return yield*
|
|
143
|
-
|
|
90
|
+
const auth = yield* MimicAuthServiceTag;
|
|
91
|
+
return yield* Effect.either(
|
|
92
|
+
auth.authenticate("unknown-user", "doc-1")
|
|
93
|
+
);
|
|
94
|
+
}).pipe(Effect.provide(layer))
|
|
144
95
|
);
|
|
145
96
|
|
|
146
|
-
expect(result.
|
|
147
|
-
if (result.
|
|
148
|
-
expect(result.
|
|
97
|
+
expect(result._tag).toBe("Left");
|
|
98
|
+
if (result._tag === "Left") {
|
|
99
|
+
expect(result.left).toBeInstanceOf(AuthenticationError);
|
|
100
|
+
expect(result.left.reason).toBe("Unknown user");
|
|
149
101
|
}
|
|
150
102
|
});
|
|
151
103
|
});
|
|
152
104
|
|
|
153
|
-
describe("
|
|
154
|
-
it("should
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
105
|
+
describe("make (custom)", () => {
|
|
106
|
+
it("should allow custom implementation with service access", async () => {
|
|
107
|
+
// Create a mock service
|
|
108
|
+
class MockDatabaseTag extends Context.Tag("MockDatabase")<
|
|
109
|
+
MockDatabaseTag,
|
|
110
|
+
{ getPermission: (userId: string) => Effect.Effect<"read" | "write"> }
|
|
111
|
+
>() {}
|
|
112
|
+
|
|
113
|
+
const mockDbLayer = Layer.succeed(MockDatabaseTag, {
|
|
114
|
+
getPermission: (userId: string) =>
|
|
115
|
+
Effect.succeed(userId === "admin" ? "write" : "read"),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
const authLayer = MimicAuthService.make(
|
|
119
|
+
Effect.gen(function* () {
|
|
120
|
+
const db = yield* MockDatabaseTag;
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
authenticate: (token: string, _documentId: string) =>
|
|
124
|
+
Effect.gen(function* () {
|
|
125
|
+
const permission = yield* db.getPermission(token);
|
|
126
|
+
return { userId: token, permission };
|
|
127
|
+
}),
|
|
128
|
+
};
|
|
129
|
+
})
|
|
130
|
+
).pipe(Layer.provide(mockDbLayer));
|
|
163
131
|
|
|
164
132
|
const result = await Effect.runPromise(
|
|
165
133
|
Effect.gen(function* () {
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
134
|
+
const auth = yield* MimicAuthServiceTag;
|
|
135
|
+
const admin = yield* auth.authenticate("admin", "doc-1");
|
|
136
|
+
const user = yield* auth.authenticate("user", "doc-1");
|
|
137
|
+
return { admin, user };
|
|
138
|
+
}).pipe(Effect.provide(authLayer))
|
|
169
139
|
);
|
|
170
140
|
|
|
171
|
-
expect(result.
|
|
172
|
-
|
|
173
|
-
expect(result.userId).toBe("effect-layer-effect-layer-token");
|
|
174
|
-
}
|
|
141
|
+
expect(result.admin.permission).toBe("write");
|
|
142
|
+
expect(result.user.permission).toBe("read");
|
|
175
143
|
});
|
|
176
144
|
});
|
|
177
145
|
|
|
178
|
-
describe("
|
|
179
|
-
it("should have
|
|
180
|
-
expect(
|
|
181
|
-
"@voidhash/mimic-
|
|
146
|
+
describe("Tag", () => {
|
|
147
|
+
it("should have correct identifier", () => {
|
|
148
|
+
expect(MimicAuthServiceTag.key).toBe(
|
|
149
|
+
"@voidhash/mimic-effect/MimicAuthService"
|
|
182
150
|
);
|
|
183
151
|
});
|
|
184
152
|
});
|