@voidhash/mimic-effect 0.0.3 → 0.0.4

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.
@@ -2,25 +2,15 @@ import { MimicServerConfigOptions } from "./MimicConfig.cjs";
2
2
  import { MimicDataStorageTag } from "./MimicDataStorage.cjs";
3
3
  import { DocumentManagerTag } from "./DocumentManager.cjs";
4
4
  import { MimicAuthServiceTag } from "./MimicAuthService.cjs";
5
- import * as _effect_platform_SocketServer0 from "@effect/platform/SocketServer";
6
- import { SocketServer } from "@effect/platform/SocketServer";
7
- import * as Effect from "effect/Effect";
8
5
  import * as Layer from "effect/Layer";
9
- import * as Context from "effect/Context";
10
- import * as Socket from "@effect/platform/Socket";
11
6
  import { Presence, Primitive } from "@voidhash/mimic";
12
7
  import { HttpLayerRouter } from "@effect/platform";
13
8
  import { PathInput } from "@effect/platform/HttpRouter";
14
9
 
15
10
  //#region src/MimicServer.d.ts
16
11
  declare namespace MimicServer_d_exports {
17
- export { MimicLayerOptions, MimicWebSocketHandler, documentManagerLayer, handlerLayer, layer, layerHttpLayerRouter, run };
12
+ export { MimicLayerOptions, documentManagerLayer, layerHttpLayerRouter };
18
13
  }
19
- declare const MimicWebSocketHandler_base: Context.TagClass<MimicWebSocketHandler, "@voidhash/mimic-server-effect/MimicWebSocketHandler", (socket: Socket.Socket, documentId: string) => Effect.Effect<void, unknown>>;
20
- /**
21
- * Tag for the WebSocket handler function.
22
- */
23
- declare class MimicWebSocketHandler extends MimicWebSocketHandler_base {}
24
14
  /**
25
15
  * Options for creating a Mimic server layer.
26
16
  */
@@ -44,97 +34,21 @@ interface MimicLayerOptions<TSchema extends Primitive.AnyPrimitive> {
44
34
  * When provided, enables presence features on WebSocket connections.
45
35
  */
46
36
  readonly presence?: Presence.AnyPresence;
37
+ /**
38
+ * Initial state for new documents.
39
+ * Used when a document is created and no existing state is found in storage.
40
+ *
41
+ * Type-safe: required fields (without defaults) must be provided,
42
+ * while optional fields and fields with defaults can be omitted.
43
+ *
44
+ * @default undefined (documents start empty or use schema defaults)
45
+ */
46
+ readonly initial?: Primitive.InferSetInput<TSchema>;
47
47
  }
48
- /**
49
- * Create a Mimic WebSocket handler layer.
50
- *
51
- * This layer provides a handler function that can be used with any WebSocket server
52
- * implementation. The handler takes a socket and document ID and manages the
53
- * document synchronization.
54
- *
55
- * By default, uses in-memory storage and no authentication.
56
- * Override these by providing MimicDataStorage and MimicAuthService layers.
57
- *
58
- * @example
59
- * ```typescript
60
- * import { MimicServer, MimicAuthService } from "@voidhash/mimic-effect";
61
- * import { Primitive } from "@voidhash/mimic";
62
- *
63
- * const TodoSchema = Primitive.Struct({
64
- * title: Primitive.String(),
65
- * completed: Primitive.Boolean(),
66
- * });
67
- *
68
- * // Create the handler layer with defaults
69
- * const HandlerLayer = MimicServer.layer({
70
- * basePath: "/mimic/todo",
71
- * schema: TodoSchema
72
- * });
73
- *
74
- * // Or with custom auth
75
- * const HandlerLayerWithAuth = MimicServer.layer({
76
- * basePath: "/mimic/todo",
77
- * schema: TodoSchema
78
- * }).pipe(
79
- * Layer.provideMerge(MimicAuthService.layer({
80
- * authHandler: (token) => ({ success: true, userId: "user-123" })
81
- * }))
82
- * );
83
- * ```
84
- */
85
- declare const layer: <TSchema extends Primitive.AnyPrimitive>(options: MimicLayerOptions<TSchema>) => Layer.Layer<MimicWebSocketHandler | DocumentManagerTag>;
86
- /**
87
- * Create the Mimic server handler layer.
88
- * This layer provides the WebSocket handler that can be used with any WebSocket server.
89
- *
90
- * @example
91
- * ```typescript
92
- * import { MimicServer } from "@voidhash/mimic-server-effect";
93
- * import { SocketServer } from "@effect/platform/SocketServer";
94
- * import { Primitive } from "@voidhash/mimic";
95
- *
96
- * // Define your document schema
97
- * const TodoSchema = Primitive.Struct({
98
- * title: Primitive.String(),
99
- * completed: Primitive.Boolean(),
100
- * });
101
- *
102
- * // Create the server layer
103
- * const serverLayer = MimicServer.handlerLayer({
104
- * schema: TodoSchema,
105
- * });
106
- *
107
- * // Run with your socket server
108
- * Effect.gen(function* () {
109
- * const handler = yield* MimicServer.MimicWebSocketHandler;
110
- * const server = yield* SocketServer;
111
- *
112
- * yield* server.run((socket) =>
113
- * // Extract document ID from request and call handler
114
- * handler(socket, "my-document-id")
115
- * );
116
- * }).pipe(
117
- * Effect.provide(serverLayer),
118
- * Effect.provide(YourSocketServerLayer),
119
- * );
120
- * ```
121
- */
122
- declare const handlerLayer: <TSchema extends Primitive.AnyPrimitive>(options: MimicServerConfigOptions<TSchema>) => Layer.Layer<MimicWebSocketHandler>;
123
48
  /**
124
49
  * Create the document manager layer.
125
50
  */
126
51
  declare const documentManagerLayer: <TSchema extends Primitive.AnyPrimitive>(options: MimicServerConfigOptions<TSchema>) => Layer.Layer<DocumentManagerTag>;
127
- /**
128
- * Run a Mimic WebSocket server with the provided handler.
129
- *
130
- * This is a helper that:
131
- * 1. Gets the WebSocket handler from context
132
- * 2. Runs the socket server with the handler
133
- *
134
- * Note: The document ID extraction from socket is implementation-specific.
135
- * You may need to customize this based on your socket server.
136
- */
137
- declare const run: (extractDocumentId: (socket: Socket.Socket) => Effect.Effect<string>) => Effect.Effect<void, _effect_platform_SocketServer0.SocketServerError, MimicWebSocketHandler | SocketServer>;
138
52
  /**
139
53
  * Create a Mimic server layer that integrates with HttpLayerRouter.
140
54
  *
@@ -1 +1 @@
1
- {"version":3,"file":"MimicServer.d.cts","names":[],"sources":["../src/MimicServer.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;cAoBwD,oIAa7C,MAAA,CAAO,+BAA+B,MAAA,CAAO;;;;cAJ3C,qBAAA,SAA8B,0BAAA;;;;AATa,UAuBvC,iBAV4D,CAAA,gBAU1B,SAAA,CAAU,YAVgB,CAAA,CAAA;;;;;sBAevD;EAnBT;AAcb;;EAKsB,SAAA,MAAA,EAIH,OAJG;EAIH;;;AAsDnB;EAAsC,SAAU,qBAAA,CAAA,EAAA,MAAA;EACnB;;;;EAC1B,SAAM,QAAA,CAAA,EA9Ca,QAAA,CAAS,WA8CtB;;AA2DT;;;;;;;AAeA;;;;;;;AAwBA;;;;;;;;AAqHA;;;;;;;;;;;;;;;cAzNa,wBAAyB,SAAA,CAAU,uBACrC,kBAAkB,aAC1B,KAAA,CAAM,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA2D1B,+BAAgC,SAAA,CAAU,uBAC5C,yBAAqC,aAC7C,KAAA,CAAM,MAAM;;;;cAaF,uCAAwC,SAAA,CAAU,uBACpD,yBAAqC,aAC7C,KAAA,CAAM,MAAM;;;;;;;;;;;cAsBF,kCACiB,MAAA,CAAO,WAAW,MAAA,CAAO,mBAAc,MAAA,CAAA,aAAR,8BAAA,CAAQ,iBAAA,EAAA,wBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAoHxD,uCAAwC,SAAA,CAAU,uBACpD,kBAAkB;;uBAEJ,KAAA,CAAM,MAAM;;0BAET,KAAA,CAAM,MAAM;MACrC,KAAA,CAAA,oBAAA,eAAA,CAAA"}
1
+ {"version":3,"file":"MimicServer.d.cts","names":[],"sources":["../src/MimicServer.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;UA6BiB,kCAAkC,SAAA,CAAU;;;;;EAA5C,SAAA,QAAA,CAAA,EAKK,SALY;EAAiB;;;EAmB7B,SAAS,MAAA,EAVZ,OAUY;EAUc;;;AAO7C;EAAqD,SAAU,qBAAA,CAAA,EAAA,MAAA;EACf;;;;EAClC,SAAA,QAAA,CAAA,EAnBQ,QAAA,CAAS,WAmBjB;EAyGD;;;;;;;;;EAMV,SAAA,OAAA,CAAA,EAxHkB,SAAA,CAAU,aAwH5B,CAxH0C,OAwH1C,CAAA;;;;;cAjHU,uCAAwC,SAAA,CAAU,uBACpD,yBAAqC,aAC7C,KAAA,CAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyGF,uCAAwC,SAAA,CAAU,uBACpD,kBAAkB;;uBAEJ,KAAA,CAAM,MAAM;;0BAET,KAAA,CAAM,MAAM;MACrC,KAAA,CAAA,oBAAA,eAAA,CAAA"}
@@ -2,25 +2,15 @@ import { MimicServerConfigOptions } from "./MimicConfig.mjs";
2
2
  import { MimicDataStorageTag } from "./MimicDataStorage.mjs";
3
3
  import { DocumentManagerTag } from "./DocumentManager.mjs";
4
4
  import { MimicAuthServiceTag } from "./MimicAuthService.mjs";
5
- import * as Effect from "effect/Effect";
6
5
  import * as Layer from "effect/Layer";
7
- import * as Context from "effect/Context";
8
- import * as _effect_platform_SocketServer0 from "@effect/platform/SocketServer";
9
- import { SocketServer } from "@effect/platform/SocketServer";
10
6
  import { Presence, Primitive } from "@voidhash/mimic";
11
7
  import { HttpLayerRouter } from "@effect/platform";
12
- import * as Socket from "@effect/platform/Socket";
13
8
  import { PathInput } from "@effect/platform/HttpRouter";
14
9
 
15
10
  //#region src/MimicServer.d.ts
16
11
  declare namespace MimicServer_d_exports {
17
- export { MimicLayerOptions, MimicWebSocketHandler, documentManagerLayer, handlerLayer, layer, layerHttpLayerRouter, run };
12
+ export { MimicLayerOptions, documentManagerLayer, layerHttpLayerRouter };
18
13
  }
19
- declare const MimicWebSocketHandler_base: Context.TagClass<MimicWebSocketHandler, "@voidhash/mimic-server-effect/MimicWebSocketHandler", (socket: Socket.Socket, documentId: string) => Effect.Effect<void, unknown>>;
20
- /**
21
- * Tag for the WebSocket handler function.
22
- */
23
- declare class MimicWebSocketHandler extends MimicWebSocketHandler_base {}
24
14
  /**
25
15
  * Options for creating a Mimic server layer.
26
16
  */
@@ -44,97 +34,21 @@ interface MimicLayerOptions<TSchema extends Primitive.AnyPrimitive> {
44
34
  * When provided, enables presence features on WebSocket connections.
45
35
  */
46
36
  readonly presence?: Presence.AnyPresence;
37
+ /**
38
+ * Initial state for new documents.
39
+ * Used when a document is created and no existing state is found in storage.
40
+ *
41
+ * Type-safe: required fields (without defaults) must be provided,
42
+ * while optional fields and fields with defaults can be omitted.
43
+ *
44
+ * @default undefined (documents start empty or use schema defaults)
45
+ */
46
+ readonly initial?: Primitive.InferSetInput<TSchema>;
47
47
  }
48
- /**
49
- * Create a Mimic WebSocket handler layer.
50
- *
51
- * This layer provides a handler function that can be used with any WebSocket server
52
- * implementation. The handler takes a socket and document ID and manages the
53
- * document synchronization.
54
- *
55
- * By default, uses in-memory storage and no authentication.
56
- * Override these by providing MimicDataStorage and MimicAuthService layers.
57
- *
58
- * @example
59
- * ```typescript
60
- * import { MimicServer, MimicAuthService } from "@voidhash/mimic-effect";
61
- * import { Primitive } from "@voidhash/mimic";
62
- *
63
- * const TodoSchema = Primitive.Struct({
64
- * title: Primitive.String(),
65
- * completed: Primitive.Boolean(),
66
- * });
67
- *
68
- * // Create the handler layer with defaults
69
- * const HandlerLayer = MimicServer.layer({
70
- * basePath: "/mimic/todo",
71
- * schema: TodoSchema
72
- * });
73
- *
74
- * // Or with custom auth
75
- * const HandlerLayerWithAuth = MimicServer.layer({
76
- * basePath: "/mimic/todo",
77
- * schema: TodoSchema
78
- * }).pipe(
79
- * Layer.provideMerge(MimicAuthService.layer({
80
- * authHandler: (token) => ({ success: true, userId: "user-123" })
81
- * }))
82
- * );
83
- * ```
84
- */
85
- declare const layer: <TSchema extends Primitive.AnyPrimitive>(options: MimicLayerOptions<TSchema>) => Layer.Layer<MimicWebSocketHandler | DocumentManagerTag>;
86
- /**
87
- * Create the Mimic server handler layer.
88
- * This layer provides the WebSocket handler that can be used with any WebSocket server.
89
- *
90
- * @example
91
- * ```typescript
92
- * import { MimicServer } from "@voidhash/mimic-server-effect";
93
- * import { SocketServer } from "@effect/platform/SocketServer";
94
- * import { Primitive } from "@voidhash/mimic";
95
- *
96
- * // Define your document schema
97
- * const TodoSchema = Primitive.Struct({
98
- * title: Primitive.String(),
99
- * completed: Primitive.Boolean(),
100
- * });
101
- *
102
- * // Create the server layer
103
- * const serverLayer = MimicServer.handlerLayer({
104
- * schema: TodoSchema,
105
- * });
106
- *
107
- * // Run with your socket server
108
- * Effect.gen(function* () {
109
- * const handler = yield* MimicServer.MimicWebSocketHandler;
110
- * const server = yield* SocketServer;
111
- *
112
- * yield* server.run((socket) =>
113
- * // Extract document ID from request and call handler
114
- * handler(socket, "my-document-id")
115
- * );
116
- * }).pipe(
117
- * Effect.provide(serverLayer),
118
- * Effect.provide(YourSocketServerLayer),
119
- * );
120
- * ```
121
- */
122
- declare const handlerLayer: <TSchema extends Primitive.AnyPrimitive>(options: MimicServerConfigOptions<TSchema>) => Layer.Layer<MimicWebSocketHandler>;
123
48
  /**
124
49
  * Create the document manager layer.
125
50
  */
126
51
  declare const documentManagerLayer: <TSchema extends Primitive.AnyPrimitive>(options: MimicServerConfigOptions<TSchema>) => Layer.Layer<DocumentManagerTag>;
127
- /**
128
- * Run a Mimic WebSocket server with the provided handler.
129
- *
130
- * This is a helper that:
131
- * 1. Gets the WebSocket handler from context
132
- * 2. Runs the socket server with the handler
133
- *
134
- * Note: The document ID extraction from socket is implementation-specific.
135
- * You may need to customize this based on your socket server.
136
- */
137
- declare const run: (extractDocumentId: (socket: Socket.Socket) => Effect.Effect<string>) => Effect.Effect<void, _effect_platform_SocketServer0.SocketServerError, MimicWebSocketHandler | SocketServer>;
138
52
  /**
139
53
  * Create a Mimic server layer that integrates with HttpLayerRouter.
140
54
  *
@@ -1 +1 @@
1
- {"version":3,"file":"MimicServer.d.mts","names":[],"sources":["../src/MimicServer.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;cAoBwD,oIAa7C,MAAA,CAAO,+BAA+B,MAAA,CAAO;;;;cAJ3C,qBAAA,SAA8B,0BAAA;;;;AATa,UAuBvC,iBAV4D,CAAA,gBAU1B,SAAA,CAAU,YAVgB,CAAA,CAAA;;;;;sBAevD;EAnBT;AAcb;;EAKsB,SAAA,MAAA,EAIH,OAJG;EAIH;;;AAsDnB;EAAsC,SAAU,qBAAA,CAAA,EAAA,MAAA;EACnB;;;;EAC1B,SAAM,QAAA,CAAA,EA9Ca,QAAA,CAAS,WA8CtB;;AA2DT;;;;;;;AAeA;;;;;;;AAwBA;;;;;;;;AAqHA;;;;;;;;;;;;;;;cAzNa,wBAAyB,SAAA,CAAU,uBACrC,kBAAkB,aAC1B,KAAA,CAAM,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA2D1B,+BAAgC,SAAA,CAAU,uBAC5C,yBAAqC,aAC7C,KAAA,CAAM,MAAM;;;;cAaF,uCAAwC,SAAA,CAAU,uBACpD,yBAAqC,aAC7C,KAAA,CAAM,MAAM;;;;;;;;;;;cAsBF,kCACiB,MAAA,CAAO,WAAW,MAAA,CAAO,mBAAc,MAAA,CAAA,aAAR,8BAAA,CAAQ,iBAAA,EAAA,wBAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAoHxD,uCAAwC,SAAA,CAAU,uBACpD,kBAAkB;;uBAEJ,KAAA,CAAM,MAAM;;0BAET,KAAA,CAAM,MAAM;MACrC,KAAA,CAAA,oBAAA,eAAA,CAAA"}
1
+ {"version":3,"file":"MimicServer.d.mts","names":[],"sources":["../src/MimicServer.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;UA6BiB,kCAAkC,SAAA,CAAU;;;;;EAA5C,SAAA,QAAA,CAAA,EAKK,SALY;EAAiB;;;EAmB7B,SAAS,MAAA,EAVZ,OAUY;EAUc;;;AAO7C;EAAqD,SAAU,qBAAA,CAAA,EAAA,MAAA;EACf;;;;EAClC,SAAA,QAAA,CAAA,EAnBQ,QAAA,CAAS,WAmBjB;EAyGD;;;;;;;;;EAMV,SAAA,OAAA,CAAA,EAxHkB,SAAA,CAAU,aAwH5B,CAxH0C,OAwH1C,CAAA;;;;;cAjHU,uCAAwC,SAAA,CAAU,uBACpD,yBAAqC,aAC7C,KAAA,CAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAyGF,uCAAwC,SAAA,CAAU,uBACpD,kBAAkB;;uBAEJ,KAAA,CAAM,MAAM;;0BAET,KAAA,CAAM,MAAM;MACrC,KAAA,CAAA,oBAAA,eAAA,CAAA"}
@@ -1,15 +1,13 @@
1
1
  import { __export } from "./_virtual/rolldown_runtime.mjs";
2
- import { MimicServerConfigTag, layer as layer$1 } from "./MimicConfig.mjs";
3
- import { DocumentManagerTag, layer as layer$2 } from "./DocumentManager.mjs";
2
+ import { MimicServerConfigTag, layer } from "./MimicConfig.mjs";
3
+ import { DocumentManagerTag, layer as layer$1 } from "./DocumentManager.mjs";
4
4
  import { MimicAuthServiceTag } from "./MimicAuthService.mjs";
5
- import { PresenceManagerTag, layer as layer$3 } from "./PresenceManager.mjs";
6
- import { extractDocumentId, handleConnection, makeHandler } from "./WebSocketHandler.mjs";
5
+ import { PresenceManagerTag, layer as layer$2 } from "./PresenceManager.mjs";
6
+ import { extractDocumentId, handleConnection } from "./WebSocketHandler.mjs";
7
7
  import { layerDefault } from "./storage/InMemoryDataStorage.mjs";
8
8
  import { layerDefault as layerDefault$1 } from "./auth/NoAuth.mjs";
9
9
  import * as Effect from "effect/Effect";
10
10
  import * as Layer from "effect/Layer";
11
- import * as Context from "effect/Context";
12
- import { SocketServer } from "@effect/platform/SocketServer";
13
11
  import { HttpLayerRouter, HttpServerRequest, HttpServerResponse } from "@effect/platform";
14
12
 
15
13
  //#region src/MimicServer.ts
@@ -18,119 +16,13 @@ import { HttpLayerRouter, HttpServerRequest, HttpServerResponse } from "@effect/
18
16
  * Mimic server layer composition.
19
17
  */
20
18
  var MimicServer_exports = /* @__PURE__ */ __export({
21
- MimicWebSocketHandler: () => MimicWebSocketHandler,
22
19
  documentManagerLayer: () => documentManagerLayer,
23
- handlerLayer: () => handlerLayer,
24
- layer: () => layer,
25
- layerHttpLayerRouter: () => layerHttpLayerRouter,
26
- run: () => run
20
+ layerHttpLayerRouter: () => layerHttpLayerRouter
27
21
  });
28
22
  /**
29
- * Tag for the WebSocket handler function.
30
- */
31
- var MimicWebSocketHandler = class extends Context.Tag("@voidhash/mimic-server-effect/MimicWebSocketHandler")() {};
32
- /**
33
- * Create a Mimic WebSocket handler layer.
34
- *
35
- * This layer provides a handler function that can be used with any WebSocket server
36
- * implementation. The handler takes a socket and document ID and manages the
37
- * document synchronization.
38
- *
39
- * By default, uses in-memory storage and no authentication.
40
- * Override these by providing MimicDataStorage and MimicAuthService layers.
41
- *
42
- * @example
43
- * ```typescript
44
- * import { MimicServer, MimicAuthService } from "@voidhash/mimic-effect";
45
- * import { Primitive } from "@voidhash/mimic";
46
- *
47
- * const TodoSchema = Primitive.Struct({
48
- * title: Primitive.String(),
49
- * completed: Primitive.Boolean(),
50
- * });
51
- *
52
- * // Create the handler layer with defaults
53
- * const HandlerLayer = MimicServer.layer({
54
- * basePath: "/mimic/todo",
55
- * schema: TodoSchema
56
- * });
57
- *
58
- * // Or with custom auth
59
- * const HandlerLayerWithAuth = MimicServer.layer({
60
- * basePath: "/mimic/todo",
61
- * schema: TodoSchema
62
- * }).pipe(
63
- * Layer.provideMerge(MimicAuthService.layer({
64
- * authHandler: (token) => ({ success: true, userId: "user-123" })
65
- * }))
66
- * );
67
- * ```
68
- */
69
- const layer = (options) => {
70
- const configLayer = layer$1({
71
- schema: options.schema,
72
- maxTransactionHistory: options.maxTransactionHistory,
73
- presence: options.presence
74
- });
75
- return Layer.merge(Layer.effect(MimicWebSocketHandler, makeHandler).pipe(Layer.provide(layer$2), Layer.provide(layer$3), Layer.provide(configLayer)), layer$2.pipe(Layer.provide(configLayer))).pipe(Layer.provide(layerDefault), Layer.provide(layerDefault$1));
76
- };
77
- /**
78
- * Create the Mimic server handler layer.
79
- * This layer provides the WebSocket handler that can be used with any WebSocket server.
80
- *
81
- * @example
82
- * ```typescript
83
- * import { MimicServer } from "@voidhash/mimic-server-effect";
84
- * import { SocketServer } from "@effect/platform/SocketServer";
85
- * import { Primitive } from "@voidhash/mimic";
86
- *
87
- * // Define your document schema
88
- * const TodoSchema = Primitive.Struct({
89
- * title: Primitive.String(),
90
- * completed: Primitive.Boolean(),
91
- * });
92
- *
93
- * // Create the server layer
94
- * const serverLayer = MimicServer.handlerLayer({
95
- * schema: TodoSchema,
96
- * });
97
- *
98
- * // Run with your socket server
99
- * Effect.gen(function* () {
100
- * const handler = yield* MimicServer.MimicWebSocketHandler;
101
- * const server = yield* SocketServer;
102
- *
103
- * yield* server.run((socket) =>
104
- * // Extract document ID from request and call handler
105
- * handler(socket, "my-document-id")
106
- * );
107
- * }).pipe(
108
- * Effect.provide(serverLayer),
109
- * Effect.provide(YourSocketServerLayer),
110
- * );
111
- * ```
112
- */
113
- const handlerLayer = (options) => Layer.effect(MimicWebSocketHandler, makeHandler).pipe(Layer.provide(layer$2), Layer.provide(layer$3), Layer.provide(layer$1(options)), Layer.provide(layerDefault), Layer.provide(layerDefault$1));
114
- /**
115
23
  * Create the document manager layer.
116
24
  */
117
- const documentManagerLayer = (options) => layer$2.pipe(Layer.provide(layer$1(options)), Layer.provide(layerDefault), Layer.provide(layerDefault$1));
118
- /**
119
- * Run a Mimic WebSocket server with the provided handler.
120
- *
121
- * This is a helper that:
122
- * 1. Gets the WebSocket handler from context
123
- * 2. Runs the socket server with the handler
124
- *
125
- * Note: The document ID extraction from socket is implementation-specific.
126
- * You may need to customize this based on your socket server.
127
- */
128
- const run = (extractDocumentId$1) => Effect.gen(function* () {
129
- const handler = yield* MimicWebSocketHandler;
130
- yield* (yield* SocketServer).run((socket) => Effect.gen(function* () {
131
- yield* handler(socket, yield* extractDocumentId$1(socket));
132
- }).pipe(Effect.catchAll((error) => Effect.logError("Connection error", error))));
133
- });
25
+ const documentManagerLayer = (options) => layer$1.pipe(Layer.provide(layer(options)), Layer.provide(layerDefault), Layer.provide(layerDefault$1));
134
26
  /**
135
27
  * Create the HTTP handler effect for WebSocket upgrade.
136
28
  * This handler:
@@ -203,10 +95,11 @@ const makeMimicHandler = Effect.gen(function* () {
203
95
  const layerHttpLayerRouter = (options) => {
204
96
  var _options$basePath, _options$authLayer, _options$storageLayer;
205
97
  const wsPath = `${(_options$basePath = options.basePath) !== null && _options$basePath !== void 0 ? _options$basePath : "/mimic"}/doc/*`;
206
- const configLayer = layer$1({
98
+ const configLayer = layer({
207
99
  schema: options.schema,
208
100
  maxTransactionHistory: options.maxTransactionHistory,
209
- presence: options.presence
101
+ presence: options.presence,
102
+ initial: options.initial
210
103
  });
211
104
  const authLayer = (_options$authLayer = options.authLayer) !== null && _options$authLayer !== void 0 ? _options$authLayer : layerDefault$1;
212
105
  const storageLayer = (_options$storageLayer = options.storageLayer) !== null && _options$storageLayer !== void 0 ? _options$storageLayer : layerDefault;
@@ -215,7 +108,7 @@ const layerHttpLayerRouter = (options) => {
215
108
  const handler = yield* makeMimicHandler;
216
109
  yield* router.add("GET", wsPath, handler);
217
110
  });
218
- return Layer.scopedDiscard(registerRoute).pipe(Layer.provide(layer$2), Layer.provide(layer$3), Layer.provide(configLayer), Layer.provide(storageLayer), Layer.provide(authLayer));
111
+ return Layer.scopedDiscard(registerRoute).pipe(Layer.provide(layer$1), Layer.provide(layer$2), Layer.provide(configLayer), Layer.provide(storageLayer), Layer.provide(authLayer));
219
112
  };
220
113
 
221
114
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"MimicServer.mjs","names":["MimicConfig.layer","WebSocketHandler.makeHandler","DocumentManager.layer","PresenceManager.layer","InMemoryDataStorage.layerDefault","NoAuth.layerDefault","extractDocumentId","MimicConfig.MimicServerConfigTag","DocumentManager.DocumentManagerTag","PresenceManager.PresenceManagerTag","WebSocketHandler.extractDocumentId","WebSocketHandler.handleConnection","wsPath: PathInput"],"sources":["../src/MimicServer.ts"],"sourcesContent":["/**\n * @since 0.0.1\n * Mimic server layer composition.\n */\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Context from \"effect/Context\";\nimport type * as Socket from \"@effect/platform/Socket\";\nimport { SocketServer } from \"@effect/platform/SocketServer\";\nimport type { Primitive, Presence } from \"@voidhash/mimic\";\n\nimport * as DocumentManager from \"./DocumentManager.js\";\nimport * as WebSocketHandler from \"./WebSocketHandler.js\";\nimport * as MimicConfig from \"./MimicConfig.js\";\nimport { MimicDataStorageTag } from \"./MimicDataStorage.js\";\nimport { MimicAuthServiceTag } from \"./MimicAuthService.js\";\nimport * as PresenceManager from \"./PresenceManager.js\";\nimport * as InMemoryDataStorage from \"./storage/InMemoryDataStorage.js\";\nimport * as NoAuth from \"./auth/NoAuth.js\";\nimport { HttpLayerRouter, HttpServerRequest, HttpServerResponse } from \"@effect/platform\";\nimport { PathInput } from \"@effect/platform/HttpRouter\";\n\n// =============================================================================\n// Handler Tag\n// =============================================================================\n\n/**\n * Tag for the WebSocket handler function.\n */\nexport class MimicWebSocketHandler extends Context.Tag(\n \"@voidhash/mimic-server-effect/MimicWebSocketHandler\"\n)<\n MimicWebSocketHandler,\n (socket: Socket.Socket, documentId: string) => Effect.Effect<void, unknown>\n>() {}\n\n// =============================================================================\n// Layer Composition Options\n// =============================================================================\n\n/**\n * Options for creating a Mimic server layer.\n */\nexport interface MimicLayerOptions<TSchema extends Primitive.AnyPrimitive> {\n /**\n * Base path for document routes (used for path matching).\n * @example \"/mimic/todo\" - documents accessed at \"/mimic/todo/:documentId\"\n */\n readonly basePath?: PathInput;\n /**\n * The schema defining the document structure.\n */\n readonly schema: TSchema;\n /**\n * Maximum number of processed transaction IDs to track for deduplication.\n * @default 1000\n */\n readonly maxTransactionHistory?: number;\n /**\n * Optional presence schema for ephemeral per-user data.\n * When provided, enables presence features on WebSocket connections.\n */\n readonly presence?: Presence.AnyPresence;\n}\n\n// =============================================================================\n// Layer Composition\n// =============================================================================\n\n/**\n * Create a Mimic WebSocket handler layer.\n * \n * This layer provides a handler function that can be used with any WebSocket server\n * implementation. The handler takes a socket and document ID and manages the\n * document synchronization.\n * \n * By default, uses in-memory storage and no authentication.\n * Override these by providing MimicDataStorage and MimicAuthService layers.\n * \n * @example\n * ```typescript\n * import { MimicServer, MimicAuthService } from \"@voidhash/mimic-effect\";\n * import { Primitive } from \"@voidhash/mimic\";\n * \n * const TodoSchema = Primitive.Struct({\n * title: Primitive.String(),\n * completed: Primitive.Boolean(),\n * });\n * \n * // Create the handler layer with defaults\n * const HandlerLayer = MimicServer.layer({\n * basePath: \"/mimic/todo\",\n * schema: TodoSchema\n * });\n * \n * // Or with custom auth\n * const HandlerLayerWithAuth = MimicServer.layer({\n * basePath: \"/mimic/todo\",\n * schema: TodoSchema\n * }).pipe(\n * Layer.provideMerge(MimicAuthService.layer({\n * authHandler: (token) => ({ success: true, userId: \"user-123\" })\n * }))\n * );\n * ```\n */\nexport const layer = <TSchema extends Primitive.AnyPrimitive>(\n options: MimicLayerOptions<TSchema>\n): Layer.Layer<MimicWebSocketHandler | DocumentManager.DocumentManagerTag> => {\n const configLayer = MimicConfig.layer({\n schema: options.schema,\n maxTransactionHistory: options.maxTransactionHistory,\n presence: options.presence,\n });\n\n return Layer.merge(\n // Handler layer\n Layer.effect(MimicWebSocketHandler, WebSocketHandler.makeHandler).pipe(\n Layer.provide(DocumentManager.layer),\n Layer.provide(PresenceManager.layer),\n Layer.provide(configLayer)\n ),\n // Document manager layer\n DocumentManager.layer.pipe(Layer.provide(configLayer))\n ).pipe(\n // Provide defaults if not overridden\n Layer.provide(InMemoryDataStorage.layerDefault),\n Layer.provide(NoAuth.layerDefault)\n );\n};\n\n/**\n * Create the Mimic server handler layer.\n * This layer provides the WebSocket handler that can be used with any WebSocket server.\n *\n * @example\n * ```typescript\n * import { MimicServer } from \"@voidhash/mimic-server-effect\";\n * import { SocketServer } from \"@effect/platform/SocketServer\";\n * import { Primitive } from \"@voidhash/mimic\";\n *\n * // Define your document schema\n * const TodoSchema = Primitive.Struct({\n * title: Primitive.String(),\n * completed: Primitive.Boolean(),\n * });\n *\n * // Create the server layer\n * const serverLayer = MimicServer.handlerLayer({\n * schema: TodoSchema,\n * });\n *\n * // Run with your socket server\n * Effect.gen(function* () {\n * const handler = yield* MimicServer.MimicWebSocketHandler;\n * const server = yield* SocketServer;\n *\n * yield* server.run((socket) =>\n * // Extract document ID from request and call handler\n * handler(socket, \"my-document-id\")\n * );\n * }).pipe(\n * Effect.provide(serverLayer),\n * Effect.provide(YourSocketServerLayer),\n * );\n * ```\n */\nexport const handlerLayer = <TSchema extends Primitive.AnyPrimitive>(\n options: MimicConfig.MimicServerConfigOptions<TSchema>\n): Layer.Layer<MimicWebSocketHandler> =>\n Layer.effect(MimicWebSocketHandler, WebSocketHandler.makeHandler).pipe(\n Layer.provide(DocumentManager.layer),\n Layer.provide(PresenceManager.layer),\n Layer.provide(MimicConfig.layer(options)),\n // Provide defaults\n Layer.provide(InMemoryDataStorage.layerDefault),\n Layer.provide(NoAuth.layerDefault)\n );\n\n/**\n * Create the document manager layer.\n */\nexport const documentManagerLayer = <TSchema extends Primitive.AnyPrimitive>(\n options: MimicConfig.MimicServerConfigOptions<TSchema>\n): Layer.Layer<DocumentManager.DocumentManagerTag> =>\n DocumentManager.layer.pipe(\n Layer.provide(MimicConfig.layer(options)),\n // Provide defaults\n Layer.provide(InMemoryDataStorage.layerDefault),\n Layer.provide(NoAuth.layerDefault)\n );\n\n// =============================================================================\n// Convenience Functions\n// =============================================================================\n\n/**\n * Run a Mimic WebSocket server with the provided handler.\n *\n * This is a helper that:\n * 1. Gets the WebSocket handler from context\n * 2. Runs the socket server with the handler\n *\n * Note: The document ID extraction from socket is implementation-specific.\n * You may need to customize this based on your socket server.\n */\nexport const run = (\n extractDocumentId: (socket: Socket.Socket) => Effect.Effect<string>\n) =>\n Effect.gen(function* () {\n const handler = yield* MimicWebSocketHandler;\n const server = yield* SocketServer;\n\n yield* server.run((socket) =>\n Effect.gen(function* () {\n const documentId = yield* extractDocumentId(socket);\n yield* handler(socket, documentId);\n }).pipe(\n Effect.catchAll((error) =>\n Effect.logError(\"Connection error\", error)\n )\n )\n );\n });\n\n\n/**\n * Create the HTTP handler effect for WebSocket upgrade.\n * This handler:\n * 1. Extracts the document ID from the URL path\n * 2. Upgrades the HTTP connection to WebSocket\n * 3. Delegates to the WebSocketHandler for document sync\n */\nconst makeMimicHandler = Effect.gen(function* () {\n const config = yield* MimicConfig.MimicServerConfigTag;\n const authService = yield* MimicAuthServiceTag;\n const documentManager = yield* DocumentManager.DocumentManagerTag;\n const presenceManager = yield* PresenceManager.PresenceManagerTag;\n\n return Effect.gen(function* () {\n const request = yield* HttpServerRequest.HttpServerRequest;\n\n // Extract document ID from the URL path\n // Expected format: /basePath/doc/{documentId}\n const documentId = yield* WebSocketHandler.extractDocumentId(request.url);\n\n // Upgrade to WebSocket\n const socket = yield* request.upgrade;\n\n // Handle the WebSocket connection\n yield* WebSocketHandler.handleConnection(socket, request.url).pipe(\n Effect.provideService(MimicConfig.MimicServerConfigTag, config),\n Effect.provideService(MimicAuthServiceTag, authService),\n Effect.provideService(DocumentManager.DocumentManagerTag, documentManager),\n Effect.provideService(PresenceManager.PresenceManagerTag, presenceManager),\n Effect.scoped,\n Effect.catchAll((error) =>\n Effect.logError(\"WebSocket connection error\", error)\n )\n );\n\n // Return empty response - the WebSocket upgrade handles the connection\n return HttpServerResponse.empty();\n }).pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logWarning(\"WebSocket upgrade failed\", error);\n return HttpServerResponse.text(\"WebSocket upgrade failed\", {\n status: 400,\n });\n })\n )\n );\n});\n\n\n\n/**\n * Create a Mimic server layer that integrates with HttpLayerRouter.\n *\n * This function creates a layer that:\n * 1. Registers a WebSocket route at the specified base path\n * 2. Handles WebSocket upgrades for document sync\n * 3. Provides all required dependencies (config, auth, storage, document manager)\n *\n * By default, uses in-memory storage and no authentication.\n * To override these defaults, provide custom layers before the defaults:\n *\n * @example\n * ```typescript\n * import { MimicServer, MimicAuthService } from \"@voidhash/mimic-effect\";\n * import { HttpLayerRouter } from \"@effect/platform\";\n * import { Primitive } from \"@voidhash/mimic\";\n *\n * const TodoSchema = Primitive.Struct({\n * title: Primitive.String(),\n * completed: Primitive.Boolean(),\n * });\n *\n * // Create the Mimic route layer with defaults\n * const MimicRoute = MimicServer.layerHttpLayerRouter({\n * basePath: \"/mimic/todo\",\n * schema: TodoSchema\n * });\n *\n * // Or with custom auth - use Layer.provide to inject before defaults\n * const MimicRouteWithAuth = MimicServer.layerHttpLayerRouter({\n * basePath: \"/mimic/todo\",\n * schema: TodoSchema,\n * authLayer: MimicAuthService.layer({\n * authHandler: (token) => ({ success: true, userId: token })\n * })\n * });\n *\n * // Merge with other routes and serve\n * const AllRoutes = Layer.mergeAll(MimicRoute, OtherRoutes);\n * HttpLayerRouter.serve(AllRoutes).pipe(\n * Layer.provide(BunHttpServer.layer({ port: 3000 })),\n * Layer.launch,\n * BunRuntime.runMain\n * );\n * ```\n */\nexport const layerHttpLayerRouter = <TSchema extends Primitive.AnyPrimitive>(\n options: MimicLayerOptions<TSchema> & {\n /** Custom auth layer. Defaults to NoAuth (all connections allowed). */\n readonly authLayer?: Layer.Layer<MimicAuthServiceTag>;\n /** Custom storage layer. Defaults to InMemoryDataStorage. */\n readonly storageLayer?: Layer.Layer<MimicDataStorageTag>;\n }\n) => {\n // Build the base path pattern for WebSocket routes\n // Append /doc/* to match /basePath/doc/{documentId}\n const basePath = options.basePath ?? \"/mimic\";\n const wsPath: PathInput = `${basePath}/doc/*` as PathInput;\n\n // Create the config layer\n const configLayer = MimicConfig.layer({\n schema: options.schema,\n maxTransactionHistory: options.maxTransactionHistory,\n presence: options.presence,\n });\n\n // Use provided layers or defaults\n const authLayer = options.authLayer ?? NoAuth.layerDefault;\n const storageLayer = options.storageLayer ?? InMemoryDataStorage.layerDefault;\n\n // Create the route registration effect\n const registerRoute = Effect.gen(function* () {\n const router = yield* HttpLayerRouter.HttpRouter;\n const handler = yield* makeMimicHandler;\n yield* router.add(\"GET\", wsPath, handler);\n });\n\n // Build the layer with all dependencies\n return Layer.scopedDiscard(registerRoute).pipe(\n Layer.provide(DocumentManager.layer),\n Layer.provide(PresenceManager.layer),\n Layer.provide(configLayer),\n Layer.provide(storageLayer),\n Layer.provide(authLayer)\n );\n};"],"mappings":"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"}
1
+ {"version":3,"file":"MimicServer.mjs","names":["MimicConfig.layer","InMemoryDataStorage.layerDefault","NoAuth.layerDefault","MimicConfig.MimicServerConfigTag","DocumentManager.DocumentManagerTag","PresenceManager.PresenceManagerTag","WebSocketHandler.extractDocumentId","WebSocketHandler.handleConnection","wsPath: PathInput","DocumentManager.layer","PresenceManager.layer"],"sources":["../src/MimicServer.ts"],"sourcesContent":["/**\n * @since 0.0.1\n * Mimic server layer composition.\n */\nimport * as Effect from \"effect/Effect\";\nimport * as Layer from \"effect/Layer\";\nimport * as Context from \"effect/Context\";\nimport type * as Socket from \"@effect/platform/Socket\";\nimport { SocketServer } from \"@effect/platform/SocketServer\";\nimport type { Primitive, Presence } from \"@voidhash/mimic\";\n\nimport * as DocumentManager from \"./DocumentManager.js\";\nimport * as WebSocketHandler from \"./WebSocketHandler.js\";\nimport * as MimicConfig from \"./MimicConfig.js\";\nimport { MimicDataStorageTag } from \"./MimicDataStorage.js\";\nimport { MimicAuthServiceTag } from \"./MimicAuthService.js\";\nimport * as PresenceManager from \"./PresenceManager.js\";\nimport * as InMemoryDataStorage from \"./storage/InMemoryDataStorage.js\";\nimport * as NoAuth from \"./auth/NoAuth.js\";\nimport { HttpLayerRouter, HttpServerRequest, HttpServerResponse } from \"@effect/platform\";\nimport { PathInput } from \"@effect/platform/HttpRouter\";\n\n// =============================================================================\n// Layer Composition Options\n// =============================================================================\n\n/**\n * Options for creating a Mimic server layer.\n */\nexport interface MimicLayerOptions<TSchema extends Primitive.AnyPrimitive> {\n /**\n * Base path for document routes (used for path matching).\n * @example \"/mimic/todo\" - documents accessed at \"/mimic/todo/:documentId\"\n */\n readonly basePath?: PathInput;\n /**\n * The schema defining the document structure.\n */\n readonly schema: TSchema;\n /**\n * Maximum number of processed transaction IDs to track for deduplication.\n * @default 1000\n */\n readonly maxTransactionHistory?: number;\n /**\n * Optional presence schema for ephemeral per-user data.\n * When provided, enables presence features on WebSocket connections.\n */\n readonly presence?: Presence.AnyPresence;\n /**\n * Initial state for new documents.\n * Used when a document is created and no existing state is found in storage.\n *\n * Type-safe: required fields (without defaults) must be provided,\n * while optional fields and fields with defaults can be omitted.\n *\n * @default undefined (documents start empty or use schema defaults)\n */\n readonly initial?: Primitive.InferSetInput<TSchema>;\n}\n\n\n/**\n * Create the document manager layer.\n */\nexport const documentManagerLayer = <TSchema extends Primitive.AnyPrimitive>(\n options: MimicConfig.MimicServerConfigOptions<TSchema>\n): Layer.Layer<DocumentManager.DocumentManagerTag> =>\n DocumentManager.layer.pipe(\n Layer.provide(MimicConfig.layer(options)),\n // Provide defaults\n Layer.provide(InMemoryDataStorage.layerDefault),\n Layer.provide(NoAuth.layerDefault)\n );\n\n/**\n * Create the HTTP handler effect for WebSocket upgrade.\n * This handler:\n * 1. Extracts the document ID from the URL path\n * 2. Upgrades the HTTP connection to WebSocket\n * 3. Delegates to the WebSocketHandler for document sync\n */\nconst makeMimicHandler = Effect.gen(function* () {\n const config = yield* MimicConfig.MimicServerConfigTag;\n const authService = yield* MimicAuthServiceTag;\n const documentManager = yield* DocumentManager.DocumentManagerTag;\n const presenceManager = yield* PresenceManager.PresenceManagerTag;\n\n return Effect.gen(function* () {\n const request = yield* HttpServerRequest.HttpServerRequest;\n\n // Extract document ID from the URL path\n // Expected format: /basePath/doc/{documentId}\n const documentId = yield* WebSocketHandler.extractDocumentId(request.url);\n\n // Upgrade to WebSocket\n const socket = yield* request.upgrade;\n\n // Handle the WebSocket connection\n yield* WebSocketHandler.handleConnection(socket, request.url).pipe(\n Effect.provideService(MimicConfig.MimicServerConfigTag, config),\n Effect.provideService(MimicAuthServiceTag, authService),\n Effect.provideService(DocumentManager.DocumentManagerTag, documentManager),\n Effect.provideService(PresenceManager.PresenceManagerTag, presenceManager),\n Effect.scoped,\n Effect.catchAll((error) =>\n Effect.logError(\"WebSocket connection error\", error)\n )\n );\n\n // Return empty response - the WebSocket upgrade handles the connection\n return HttpServerResponse.empty();\n }).pipe(\n Effect.catchAll((error) =>\n Effect.gen(function* () {\n yield* Effect.logWarning(\"WebSocket upgrade failed\", error);\n return HttpServerResponse.text(\"WebSocket upgrade failed\", {\n status: 400,\n });\n })\n )\n );\n});\n\n\n\n/**\n * Create a Mimic server layer that integrates with HttpLayerRouter.\n *\n * This function creates a layer that:\n * 1. Registers a WebSocket route at the specified base path\n * 2. Handles WebSocket upgrades for document sync\n * 3. Provides all required dependencies (config, auth, storage, document manager)\n *\n * By default, uses in-memory storage and no authentication.\n * To override these defaults, provide custom layers before the defaults:\n *\n * @example\n * ```typescript\n * import { MimicServer, MimicAuthService } from \"@voidhash/mimic-effect\";\n * import { HttpLayerRouter } from \"@effect/platform\";\n * import { Primitive } from \"@voidhash/mimic\";\n *\n * const TodoSchema = Primitive.Struct({\n * title: Primitive.String(),\n * completed: Primitive.Boolean(),\n * });\n *\n * // Create the Mimic route layer with defaults\n * const MimicRoute = MimicServer.layerHttpLayerRouter({\n * basePath: \"/mimic/todo\",\n * schema: TodoSchema\n * });\n *\n * // Or with custom auth - use Layer.provide to inject before defaults\n * const MimicRouteWithAuth = MimicServer.layerHttpLayerRouter({\n * basePath: \"/mimic/todo\",\n * schema: TodoSchema,\n * authLayer: MimicAuthService.layer({\n * authHandler: (token) => ({ success: true, userId: token })\n * })\n * });\n *\n * // Merge with other routes and serve\n * const AllRoutes = Layer.mergeAll(MimicRoute, OtherRoutes);\n * HttpLayerRouter.serve(AllRoutes).pipe(\n * Layer.provide(BunHttpServer.layer({ port: 3000 })),\n * Layer.launch,\n * BunRuntime.runMain\n * );\n * ```\n */\nexport const layerHttpLayerRouter = <TSchema extends Primitive.AnyPrimitive>(\n options: MimicLayerOptions<TSchema> & {\n /** Custom auth layer. Defaults to NoAuth (all connections allowed). */\n readonly authLayer?: Layer.Layer<MimicAuthServiceTag>;\n /** Custom storage layer. Defaults to InMemoryDataStorage. */\n readonly storageLayer?: Layer.Layer<MimicDataStorageTag>;\n }\n) => {\n // Build the base path pattern for WebSocket routes\n // Append /doc/* to match /basePath/doc/{documentId}\n const basePath = options.basePath ?? \"/mimic\";\n const wsPath: PathInput = `${basePath}/doc/*` as PathInput;\n\n // Create the config layer\n const configLayer = MimicConfig.layer({\n schema: options.schema,\n maxTransactionHistory: options.maxTransactionHistory,\n presence: options.presence,\n initial: options.initial,\n });\n\n // Use provided layers or defaults\n const authLayer = options.authLayer ?? NoAuth.layerDefault;\n const storageLayer = options.storageLayer ?? InMemoryDataStorage.layerDefault;\n\n // Create the route registration effect\n const registerRoute = Effect.gen(function* () {\n const router = yield* HttpLayerRouter.HttpRouter;\n const handler = yield* makeMimicHandler;\n yield* router.add(\"GET\", wsPath, handler);\n });\n\n // Build the layer with all dependencies\n return Layer.scopedDiscard(registerRoute).pipe(\n Layer.provide(DocumentManager.layer),\n Layer.provide(PresenceManager.layer),\n Layer.provide(configLayer),\n Layer.provide(storageLayer),\n Layer.provide(authLayer)\n );\n};"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAiEA,MAAa,wBACX,oBAEsB,KACpB,MAAM,QAAQA,MAAkB,QAAQ,CAAC,EAEzC,MAAM,QAAQC,aAAiC,EAC/C,MAAM,QAAQC,eAAoB,CACnC;;;;;;;;AASH,MAAM,mBAAmB,OAAO,IAAI,aAAa;CAC/C,MAAM,SAAS,OAAOC;CACtB,MAAM,cAAc,OAAO;CAC3B,MAAM,kBAAkB,OAAOC;CAC/B,MAAM,kBAAkB,OAAOC;AAE/B,QAAO,OAAO,IAAI,aAAa;EAC7B,MAAM,UAAU,OAAO,kBAAkB;AAItB,SAAOC,kBAAmC,QAAQ,IAAI;EAGzE,MAAM,SAAS,OAAO,QAAQ;AAG9B,SAAOC,iBAAkC,QAAQ,QAAQ,IAAI,CAAC,KAC5D,OAAO,eAAeJ,sBAAkC,OAAO,EAC/D,OAAO,eAAe,qBAAqB,YAAY,EACvD,OAAO,eAAeC,oBAAoC,gBAAgB,EAC1E,OAAO,eAAeC,oBAAoC,gBAAgB,EAC1E,OAAO,QACP,OAAO,UAAU,UACf,OAAO,SAAS,8BAA8B,MAAM,CACrD,CACF;AAGD,SAAO,mBAAmB,OAAO;GACjC,CAAC,KACD,OAAO,UAAU,UACf,OAAO,IAAI,aAAa;AACtB,SAAO,OAAO,WAAW,4BAA4B,MAAM;AAC3D,SAAO,mBAAmB,KAAK,4BAA4B,EACzD,QAAQ,KACT,CAAC;GACF,CACH,CACF;EACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDF,MAAa,wBACX,YAMG;;CAIH,MAAMG,SAAoB,wBADT,QAAQ,yEAAY,SACC;CAGtC,MAAM,cAAcR,MAAkB;EACpC,QAAQ,QAAQ;EAChB,uBAAuB,QAAQ;EAC/B,UAAU,QAAQ;EAClB,SAAS,QAAQ;EAClB,CAAC;CAGF,MAAM,kCAAY,QAAQ,4EAAaE;CACvC,MAAM,wCAAe,QAAQ,qFAAgBD;CAG7C,MAAM,gBAAgB,OAAO,IAAI,aAAa;EAC5C,MAAM,SAAS,OAAO,gBAAgB;EACtC,MAAM,UAAU,OAAO;AACvB,SAAO,OAAO,IAAI,OAAO,QAAQ,QAAQ;GACzC;AAGF,QAAO,MAAM,cAAc,cAAc,CAAC,KACxC,MAAM,QAAQQ,QAAsB,EACpC,MAAM,QAAQC,QAAsB,EACpC,MAAM,QAAQ,YAAY,EAC1B,MAAM,QAAQ,aAAa,EAC3B,MAAM,QAAQ,UAAU,CACzB"}
@@ -3,14 +3,14 @@ let effect_Effect = require("effect/Effect");
3
3
  effect_Effect = require_rolldown_runtime.__toESM(effect_Effect);
4
4
  let effect_Layer = require("effect/Layer");
5
5
  effect_Layer = require_rolldown_runtime.__toESM(effect_Layer);
6
- let effect_Context = require("effect/Context");
7
- effect_Context = require_rolldown_runtime.__toESM(effect_Context);
8
6
  let effect_PubSub = require("effect/PubSub");
9
7
  effect_PubSub = require_rolldown_runtime.__toESM(effect_PubSub);
10
8
  let effect_Ref = require("effect/Ref");
11
9
  effect_Ref = require_rolldown_runtime.__toESM(effect_Ref);
12
10
  let effect_HashMap = require("effect/HashMap");
13
11
  effect_HashMap = require_rolldown_runtime.__toESM(effect_HashMap);
12
+ let effect_Context = require("effect/Context");
13
+ effect_Context = require_rolldown_runtime.__toESM(effect_Context);
14
14
  let effect_Stream = require("effect/Stream");
15
15
  effect_Stream = require_rolldown_runtime.__toESM(effect_Stream);
16
16
 
@@ -1,5 +1,5 @@
1
- import * as Effect from "effect/Effect";
2
1
  import * as Layer from "effect/Layer";
2
+ import * as Effect from "effect/Effect";
3
3
  import * as Context from "effect/Context";
4
4
  import * as Scope from "effect/Scope";
5
5
  import * as Stream from "effect/Stream";
@@ -1,10 +1,10 @@
1
1
  import { __export } from "./_virtual/rolldown_runtime.mjs";
2
2
  import * as Effect from "effect/Effect";
3
3
  import * as Layer from "effect/Layer";
4
- import * as Context from "effect/Context";
5
4
  import * as PubSub from "effect/PubSub";
6
5
  import * as Ref from "effect/Ref";
7
6
  import * as HashMap from "effect/HashMap";
7
+ import * as Context from "effect/Context";
8
8
  import * as Stream from "effect/Stream";
9
9
 
10
10
  //#region src/PresenceManager.ts
@@ -11,9 +11,9 @@ let effect_Stream = require("effect/Stream");
11
11
  effect_Stream = require_rolldown_runtime.__toESM(effect_Stream);
12
12
  let effect_Duration = require("effect/Duration");
13
13
  effect_Duration = require_rolldown_runtime.__toESM(effect_Duration);
14
+ let _voidhash_mimic = require("@voidhash/mimic");
14
15
  let effect_Fiber = require("effect/Fiber");
15
16
  effect_Fiber = require_rolldown_runtime.__toESM(effect_Fiber);
16
- let _voidhash_mimic = require("@voidhash/mimic");
17
17
 
18
18
  //#region src/WebSocketHandler.ts
19
19
  /**
@@ -362,5 +362,4 @@ Object.defineProperty(exports, 'WebSocketHandler_exports', {
362
362
  }
363
363
  });
364
364
  exports.extractDocumentId = extractDocumentId;
365
- exports.handleConnection = handleConnection;
366
- exports.makeHandler = makeHandler;
365
+ exports.handleConnection = handleConnection;
@@ -4,8 +4,8 @@ import { MimicAuthServiceTag } from "./MimicAuthService.cjs";
4
4
  import { PresenceManagerTag } from "./PresenceManager.cjs";
5
5
  import { MessageParseError, MissingDocumentIdError } from "./errors.cjs";
6
6
  import * as Effect from "effect/Effect";
7
- import * as Socket from "@effect/platform/Socket";
8
7
  import * as Scope from "effect/Scope";
8
+ import * as Socket from "@effect/platform/Socket";
9
9
 
10
10
  //#region src/WebSocketHandler.d.ts
11
11
  declare namespace WebSocketHandler_d_exports {
@@ -4,8 +4,8 @@ import { MimicAuthServiceTag } from "./MimicAuthService.mjs";
4
4
  import { PresenceManagerTag } from "./PresenceManager.mjs";
5
5
  import { MessageParseError, MissingDocumentIdError } from "./errors.mjs";
6
6
  import * as Effect from "effect/Effect";
7
- import * as Socket from "@effect/platform/Socket";
8
7
  import * as Scope from "effect/Scope";
8
+ import * as Socket from "@effect/platform/Socket";
9
9
 
10
10
  //#region src/WebSocketHandler.d.ts
11
11
  declare namespace WebSocketHandler_d_exports {
@@ -8,8 +8,8 @@ import { _objectSpread2 } from "./_virtual/_@oxc-project_runtime@0.103.0/helpers
8
8
  import * as Effect from "effect/Effect";
9
9
  import * as Stream from "effect/Stream";
10
10
  import * as Duration from "effect/Duration";
11
- import * as Fiber from "effect/Fiber";
12
11
  import { Presence, Transaction } from "@voidhash/mimic";
12
+ import * as Fiber from "effect/Fiber";
13
13
 
14
14
  //#region src/WebSocketHandler.ts
15
15
  /**
@@ -351,5 +351,5 @@ const handleConnectionWithDocumentId = (socket, documentId) => Effect.gen(functi
351
351
  });
352
352
 
353
353
  //#endregion
354
- export { WebSocketHandler_exports, extractDocumentId, handleConnection, makeHandler };
354
+ export { WebSocketHandler_exports, extractDocumentId, handleConnection };
355
355
  //# sourceMappingURL=WebSocketHandler.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voidhash/mimic-effect",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -24,11 +24,11 @@
24
24
  "typescript": "5.8.3",
25
25
  "vite-tsconfig-paths": "^5.1.4",
26
26
  "vitest": "^3.2.4",
27
- "@voidhash/tsconfig": "0.0.3"
27
+ "@voidhash/tsconfig": "0.0.4"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "effect": "^3.19.12",
31
- "@voidhash/mimic": "0.0.3"
31
+ "@voidhash/mimic": "0.0.4"
32
32
  },
33
33
  "scripts": {
34
34
  "build": "tsdown",
@@ -113,10 +113,10 @@ const makeDocumentManager = Effect.gen(function* () {
113
113
  () => Effect.succeed(undefined)
114
114
  );
115
115
 
116
- // Transform loaded state with onLoad hook
116
+ // Transform loaded state with onLoad hook, or use configured initial state for new docs
117
117
  const initialState = rawState !== undefined
118
118
  ? yield* storage.onLoad(rawState)
119
- : undefined;
119
+ : config.initial;
120
120
 
121
121
  // Create PubSub for broadcasting
122
122
  const pubsub = yield* PubSub.unbounded<Protocol.ServerBroadcast>();