@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.
Files changed (176) hide show
  1. package/.turbo/turbo-build.log +93 -89
  2. package/README.md +385 -0
  3. package/dist/ColdStorage.cjs +60 -0
  4. package/dist/ColdStorage.d.cts +53 -0
  5. package/dist/ColdStorage.d.cts.map +1 -0
  6. package/dist/ColdStorage.d.mts +53 -0
  7. package/dist/ColdStorage.d.mts.map +1 -0
  8. package/dist/ColdStorage.mjs +60 -0
  9. package/dist/ColdStorage.mjs.map +1 -0
  10. package/dist/DocumentManager.cjs +193 -82
  11. package/dist/DocumentManager.d.cts +33 -19
  12. package/dist/DocumentManager.d.cts.map +1 -1
  13. package/dist/DocumentManager.d.mts +33 -19
  14. package/dist/DocumentManager.d.mts.map +1 -1
  15. package/dist/DocumentManager.mjs +189 -67
  16. package/dist/DocumentManager.mjs.map +1 -1
  17. package/dist/Errors.cjs +45 -0
  18. package/dist/Errors.d.cts +81 -0
  19. package/dist/Errors.d.cts.map +1 -0
  20. package/dist/Errors.d.mts +81 -0
  21. package/dist/Errors.d.mts.map +1 -0
  22. package/dist/Errors.mjs +40 -0
  23. package/dist/Errors.mjs.map +1 -0
  24. package/dist/HotStorage.cjs +77 -0
  25. package/dist/HotStorage.d.cts +54 -0
  26. package/dist/HotStorage.d.cts.map +1 -0
  27. package/dist/HotStorage.d.mts +54 -0
  28. package/dist/HotStorage.d.mts.map +1 -0
  29. package/dist/HotStorage.mjs +77 -0
  30. package/dist/HotStorage.mjs.map +1 -0
  31. package/dist/Metrics.cjs +121 -0
  32. package/dist/Metrics.d.cts +27 -0
  33. package/dist/Metrics.d.cts.map +1 -0
  34. package/dist/Metrics.d.mts +27 -0
  35. package/dist/Metrics.d.mts.map +1 -0
  36. package/dist/Metrics.mjs +106 -0
  37. package/dist/Metrics.mjs.map +1 -0
  38. package/dist/MimicAuthService.cjs +61 -45
  39. package/dist/MimicAuthService.d.cts +61 -48
  40. package/dist/MimicAuthService.d.cts.map +1 -1
  41. package/dist/MimicAuthService.d.mts +61 -48
  42. package/dist/MimicAuthService.d.mts.map +1 -1
  43. package/dist/MimicAuthService.mjs +60 -36
  44. package/dist/MimicAuthService.mjs.map +1 -1
  45. package/dist/MimicClusterServerEngine.cjs +443 -0
  46. package/dist/MimicClusterServerEngine.d.cts +17 -0
  47. package/dist/MimicClusterServerEngine.d.cts.map +1 -0
  48. package/dist/MimicClusterServerEngine.d.mts +17 -0
  49. package/dist/MimicClusterServerEngine.d.mts.map +1 -0
  50. package/dist/MimicClusterServerEngine.mjs +445 -0
  51. package/dist/MimicClusterServerEngine.mjs.map +1 -0
  52. package/dist/MimicServer.cjs +205 -96
  53. package/dist/MimicServer.d.cts +9 -110
  54. package/dist/MimicServer.d.cts.map +1 -1
  55. package/dist/MimicServer.d.mts +9 -110
  56. package/dist/MimicServer.d.mts.map +1 -1
  57. package/dist/MimicServer.mjs +206 -90
  58. package/dist/MimicServer.mjs.map +1 -1
  59. package/dist/MimicServerEngine.cjs +97 -0
  60. package/dist/MimicServerEngine.d.cts +75 -0
  61. package/dist/MimicServerEngine.d.cts.map +1 -0
  62. package/dist/MimicServerEngine.d.mts +75 -0
  63. package/dist/MimicServerEngine.d.mts.map +1 -0
  64. package/dist/MimicServerEngine.mjs +97 -0
  65. package/dist/MimicServerEngine.mjs.map +1 -0
  66. package/dist/PresenceManager.cjs +75 -91
  67. package/dist/PresenceManager.d.cts +17 -66
  68. package/dist/PresenceManager.d.cts.map +1 -1
  69. package/dist/PresenceManager.d.mts +17 -66
  70. package/dist/PresenceManager.d.mts.map +1 -1
  71. package/dist/PresenceManager.mjs +74 -78
  72. package/dist/PresenceManager.mjs.map +1 -1
  73. package/dist/Protocol.cjs +146 -0
  74. package/dist/Protocol.d.cts +203 -0
  75. package/dist/Protocol.d.cts.map +1 -0
  76. package/dist/Protocol.d.mts +203 -0
  77. package/dist/Protocol.d.mts.map +1 -0
  78. package/dist/Protocol.mjs +132 -0
  79. package/dist/Protocol.mjs.map +1 -0
  80. package/dist/Types.d.cts +172 -0
  81. package/dist/Types.d.cts.map +1 -0
  82. package/dist/Types.d.mts +172 -0
  83. package/dist/Types.d.mts.map +1 -0
  84. package/dist/_virtual/rolldown_runtime.cjs +1 -25
  85. package/dist/_virtual/rolldown_runtime.mjs +4 -1
  86. package/dist/index.cjs +37 -75
  87. package/dist/index.d.cts +13 -12
  88. package/dist/index.d.mts +13 -12
  89. package/dist/index.mjs +12 -12
  90. package/package.json +14 -6
  91. package/src/ColdStorage.ts +136 -0
  92. package/src/DocumentManager.ts +445 -193
  93. package/src/Errors.ts +100 -0
  94. package/src/HotStorage.ts +165 -0
  95. package/src/Metrics.ts +163 -0
  96. package/src/MimicAuthService.ts +126 -64
  97. package/src/MimicClusterServerEngine.ts +824 -0
  98. package/src/MimicServer.ts +448 -195
  99. package/src/MimicServerEngine.ts +272 -0
  100. package/src/PresenceManager.ts +169 -240
  101. package/src/Protocol.ts +350 -0
  102. package/src/Types.ts +231 -0
  103. package/src/index.ts +57 -23
  104. package/tests/ColdStorage.test.ts +136 -0
  105. package/tests/DocumentManager.test.ts +158 -287
  106. package/tests/HotStorage.test.ts +143 -0
  107. package/tests/MimicAuthService.test.ts +102 -134
  108. package/tests/MimicClusterServerEngine.test.ts +587 -0
  109. package/tests/MimicServer.test.ts +90 -226
  110. package/tests/MimicServerEngine.test.ts +521 -0
  111. package/tests/PresenceManager.test.ts +22 -63
  112. package/tests/Protocol.test.ts +190 -0
  113. package/tsconfig.json +1 -1
  114. package/dist/DocumentProtocol.cjs +0 -94
  115. package/dist/DocumentProtocol.d.cts +0 -113
  116. package/dist/DocumentProtocol.d.cts.map +0 -1
  117. package/dist/DocumentProtocol.d.mts +0 -113
  118. package/dist/DocumentProtocol.d.mts.map +0 -1
  119. package/dist/DocumentProtocol.mjs +0 -89
  120. package/dist/DocumentProtocol.mjs.map +0 -1
  121. package/dist/MimicConfig.cjs +0 -60
  122. package/dist/MimicConfig.d.cts +0 -141
  123. package/dist/MimicConfig.d.cts.map +0 -1
  124. package/dist/MimicConfig.d.mts +0 -141
  125. package/dist/MimicConfig.d.mts.map +0 -1
  126. package/dist/MimicConfig.mjs +0 -50
  127. package/dist/MimicConfig.mjs.map +0 -1
  128. package/dist/MimicDataStorage.cjs +0 -83
  129. package/dist/MimicDataStorage.d.cts +0 -113
  130. package/dist/MimicDataStorage.d.cts.map +0 -1
  131. package/dist/MimicDataStorage.d.mts +0 -113
  132. package/dist/MimicDataStorage.d.mts.map +0 -1
  133. package/dist/MimicDataStorage.mjs +0 -74
  134. package/dist/MimicDataStorage.mjs.map +0 -1
  135. package/dist/WebSocketHandler.cjs +0 -365
  136. package/dist/WebSocketHandler.d.cts +0 -34
  137. package/dist/WebSocketHandler.d.cts.map +0 -1
  138. package/dist/WebSocketHandler.d.mts +0 -34
  139. package/dist/WebSocketHandler.d.mts.map +0 -1
  140. package/dist/WebSocketHandler.mjs +0 -355
  141. package/dist/WebSocketHandler.mjs.map +0 -1
  142. package/dist/auth/NoAuth.cjs +0 -43
  143. package/dist/auth/NoAuth.d.cts +0 -22
  144. package/dist/auth/NoAuth.d.cts.map +0 -1
  145. package/dist/auth/NoAuth.d.mts +0 -22
  146. package/dist/auth/NoAuth.d.mts.map +0 -1
  147. package/dist/auth/NoAuth.mjs +0 -36
  148. package/dist/auth/NoAuth.mjs.map +0 -1
  149. package/dist/errors.cjs +0 -74
  150. package/dist/errors.d.cts +0 -89
  151. package/dist/errors.d.cts.map +0 -1
  152. package/dist/errors.d.mts +0 -89
  153. package/dist/errors.d.mts.map +0 -1
  154. package/dist/errors.mjs +0 -67
  155. package/dist/errors.mjs.map +0 -1
  156. package/dist/storage/InMemoryDataStorage.cjs +0 -57
  157. package/dist/storage/InMemoryDataStorage.d.cts +0 -19
  158. package/dist/storage/InMemoryDataStorage.d.cts.map +0 -1
  159. package/dist/storage/InMemoryDataStorage.d.mts +0 -19
  160. package/dist/storage/InMemoryDataStorage.d.mts.map +0 -1
  161. package/dist/storage/InMemoryDataStorage.mjs +0 -48
  162. package/dist/storage/InMemoryDataStorage.mjs.map +0 -1
  163. package/src/DocumentProtocol.ts +0 -112
  164. package/src/MimicConfig.ts +0 -211
  165. package/src/MimicDataStorage.ts +0 -157
  166. package/src/WebSocketHandler.ts +0 -735
  167. package/src/auth/NoAuth.ts +0 -46
  168. package/src/errors.ts +0 -113
  169. package/src/storage/InMemoryDataStorage.ts +0 -66
  170. package/tests/DocumentProtocol.test.ts +0 -113
  171. package/tests/InMemoryDataStorage.test.ts +0 -190
  172. package/tests/MimicConfig.test.ts +0 -290
  173. package/tests/MimicDataStorage.test.ts +0 -190
  174. package/tests/NoAuth.test.ts +0 -94
  175. package/tests/WebSocketHandler.test.ts +0 -321
  176. 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 * as Effect from "effect/Effect";
3
- import * as MimicAuthService from "../src/MimicAuthService";
4
-
5
- // =============================================================================
6
- // MimicAuthService Tests
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("make", () => {
11
- it("should create auth service with sync handler", async () => {
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
- authService.authenticate("bad-token")
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.success).toBe(false);
54
- if (!result.success) {
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 handle success without userId", async () => {
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
- authService.authenticate("token")
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.success).toBe(true);
69
- if (result.success) {
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("makeEffect", () => {
76
- it("should create auth service from Effect-based authenticate function", async () => {
77
- const authService = MimicAuthService.makeEffect((token) =>
78
- Effect.succeed({ success: true as const, userId: `effect-${token}` })
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* Effect.sleep(10);
95
- return { success: true as const, userId: `delayed-${token}` };
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
- const result = await Effect.runPromise(
100
- authService.authenticate("delay-token")
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
- describe("layer", () => {
111
- it("should create a layer from auth handler", async () => {
112
- const testLayer = MimicAuthService.layer({
113
- authHandler: (token) => ({ success: true, userId: `layer-${token}` }),
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 authService = yield* MimicAuthService.MimicAuthServiceTag;
119
- return yield* authService.authenticate("layer-token");
120
- }).pipe(Effect.provide(testLayer))
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.success).toBe(true);
124
- if (result.success) {
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
- describe("layerService", () => {
131
- it("should create a layer from service implementation", async () => {
132
- const service = MimicAuthService.make((token) => ({
133
- success: true,
134
- userId: `service-${token}`,
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 authService = yield* MimicAuthService.MimicAuthServiceTag;
142
- return yield* authService.authenticate("service-token");
143
- }).pipe(Effect.provide(testLayer))
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.success).toBe(true);
147
- if (result.success) {
148
- expect(result.userId).toBe("service-service-token");
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("layerEffect", () => {
154
- it("should create a layer from an Effect", async () => {
155
- const testLayer = MimicAuthService.layerEffect(
156
- Effect.succeed(
157
- MimicAuthService.make((token) => ({
158
- success: true,
159
- userId: `effect-layer-${token}`,
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 authService = yield* MimicAuthService.MimicAuthServiceTag;
167
- return yield* authService.authenticate("effect-layer-token");
168
- }).pipe(Effect.provide(testLayer))
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.success).toBe(true);
172
- if (result.success) {
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("MimicAuthServiceTag", () => {
179
- it("should have the correct tag identifier", () => {
180
- expect(MimicAuthService.MimicAuthServiceTag.key).toBe(
181
- "@voidhash/mimic-server-effect/MimicAuthService"
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
  });