@vrowzer/service-worker-server 0.0.0 → 0.1.0-beta.0

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/dist/index.d.ts CHANGED
@@ -1,239 +1,212 @@
1
+ import { SvcWorkerOptions } from "@vrowzer/service-worker/worker";
1
2
  import { Emittable } from "@kazupon/jts-utils/event/emitter";
2
-
3
- //#region ../service-worker/src/worker.d.ts
4
-
5
- /**
6
- * Service Worker options for {@link createSvcWorker}
7
- */
8
- interface SvcWorkerOptions {
9
- /**
10
- * The version of this service worker
11
- * This is used to identify the service worker when communicating with {@link SvcWorkerController}
12
- */
13
- version: string;
14
- /**
15
- * Heartbeat interval in milliseconds
16
- * @default 30000
17
- */
18
- heartbeatInterval?: number;
19
- /**
20
- * Timeout after which a session is considered stale (no PONG received)
21
- * @default 60000
22
- */
23
- sessionTimeout?: number;
24
- /**
25
- * Debug logger function
26
- */
27
- debug?: Console["debug"];
28
- }
29
- //#endregion
30
3
  //#region src/index.d.ts
31
4
  /**
32
- * Service worker server error
33
- */
5
+ * Service worker server error
6
+ */
34
7
  declare class SvcWorkerServerError extends Error {
35
8
  name: string;
36
9
  constructor(message: string, cause?: Error);
37
10
  }
38
11
  /**
39
- * The {@link SvcWorkerServer} constructor options
40
- */
12
+ * The {@link SvcWorkerServer} constructor options
13
+ */
41
14
  interface SvcWorkerServerOptions extends SvcWorkerOptions {
42
15
  /**
43
- * Automatically call `clients.claim()` on `activate` event.
44
- */
16
+ * Automatically call `clients.claim()` on `activate` event.
17
+ */
45
18
  claimOnActivate?: boolean;
46
19
  }
47
20
  /**
48
- * Extend {@link ServiceWorkerState} with additional states
49
- *
50
- * - 'suspended': State when {@link SvcWorker | service worker} is suspended.
51
- */
21
+ * Extend {@link ServiceWorkerState} with additional states
22
+ *
23
+ * - 'suspended': State when {@link SvcWorker | service worker} is suspended.
24
+ */
52
25
  type SvcWorkerServerState = ServiceWorkerState | "suspended";
53
26
  /**
54
- * Options for the {@link SvcWorkerServer.listen} method
55
- */
27
+ * Options for the {@link SvcWorkerServer.listen} method
28
+ */
56
29
  interface ListenOptions {
57
30
  /**
58
- * Timeout in milliseconds for waiting for the activate event.
59
- * If the timeout is exceeded, an 'error' event is emitted.
60
- * @default 30000 (30 seconds)
61
- */
31
+ * Timeout in milliseconds for waiting for the activate event.
32
+ * If the timeout is exceeded, an 'error' event is emitted.
33
+ * @default 30000 (30 seconds)
34
+ */
62
35
  activateTimeout?: number;
63
36
  /**
64
- * Enable listening for MessageChannel port connections.
65
- * If set to true, the server will accept connections via `message` events from clients.
66
- * @default false
67
- */
37
+ * Enable listening for MessageChannel port connections.
38
+ * If set to true, the server will accept connections via `message` events from clients.
39
+ * @default false
40
+ */
68
41
  enableListenConnections?: boolean;
69
42
  }
70
43
  /**
71
- * Connection event payload for {@link MessageChannel} connections.
72
- *
73
- * This interface represents a connection event that is emitted when a client
74
- * sends a message with {@link MessagePort | MessagePorts} (typically for establishing a MessageChannel connection).
75
- *
76
- * @typeParam T - The type of the message data. Defaults to `unknown`.
77
- *
78
- * @example
79
- * ```ts
80
- * interface MyMessage {
81
- * type: 'greeting' | 'farewell'
82
- * payload: string
83
- * }
84
- *
85
- * const server = createSvcWorkerServer<MyMessage>(self, options)
86
- * server.on('connection', (event) => {
87
- * // event.data is typed as MyMessage
88
- * console.log(event.data.type, event.data.payload)
89
- * // Access the MessagePorts
90
- * console.log(event.ports)
91
- * })
92
- * ```
93
- */
44
+ * Connection event payload for {@link MessageChannel} connections.
45
+ *
46
+ * This interface represents a connection event that is emitted when a client
47
+ * sends a message with {@link MessagePort | MessagePorts} (typically for establishing a MessageChannel connection).
48
+ *
49
+ * @typeParam T - The type of the message data. Defaults to `unknown`.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * interface MyMessage {
54
+ * type: 'greeting' | 'farewell'
55
+ * payload: string
56
+ * }
57
+ *
58
+ * const server = createSvcWorkerServer<MyMessage>(self, options)
59
+ * server.on('connection', (event) => {
60
+ * // event.data is typed as MyMessage
61
+ * console.log(event.data.type, event.data.payload)
62
+ * // Access the MessagePorts
63
+ * console.log(event.ports)
64
+ * })
65
+ * ```
66
+ */
94
67
  interface ConnectionEvent<T = unknown> {
95
68
  /**
96
- * The MessagePorts received from the client.
97
- */
69
+ * The MessagePorts received from the client.
70
+ */
98
71
  readonly ports: readonly MessagePort[];
99
72
  /**
100
- * The source of the message (Client, ServiceWorker, or MessagePort).
101
- */
73
+ * The source of the message (Client, ServiceWorker, or MessagePort).
74
+ */
102
75
  readonly source: Client | ServiceWorker | MessagePort | null;
103
76
  /**
104
- * The message data with type safety.
105
- */
77
+ * The message data with type safety.
78
+ */
106
79
  readonly data: T;
107
80
  /**
108
- * The client ID if the source is a Client.
109
- */
81
+ * The client ID if the source is a Client.
82
+ */
110
83
  readonly clientId?: string;
111
84
  }
112
85
  /**
113
- * Event map for {@link SvcWorkerServer}.
114
- *
115
- * This type defines the payload types for each event.
116
- *
117
- * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.
118
- */
86
+ * Event map for {@link SvcWorkerServer}.
87
+ *
88
+ * This type defines the payload types for each event.
89
+ *
90
+ * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.
91
+ */
119
92
  type SvcWorkerServerEventMap<MessageData = unknown> = {
120
93
  /**
121
- * Emitted when the server starts listening for fetch events.
122
- */
94
+ * Emitted when the server starts listening for fetch events.
95
+ */
123
96
  listening: void;
124
97
  /**
125
- * Emitted when a client connects via MessageChannel.
126
- * This event is fired only when the message contains MessagePorts.
127
- */
98
+ * Emitted when a client connects via MessageChannel.
99
+ * This event is fired only when the message contains MessagePorts.
100
+ */
128
101
  connection: ConnectionEvent<MessageData>;
129
102
  /**
130
- * Emitted when the server is closed.
131
- */
103
+ * Emitted when the server is closed.
104
+ */
132
105
  close: void;
133
106
  /**
134
- * Emitted when an error occurs.
135
- */
107
+ * Emitted when an error occurs.
108
+ */
136
109
  error: Error;
137
110
  };
138
111
  /**
139
- * The Server for service worker environment
140
- *
141
- * This interface has like Node.js HTTP Server interfaces.
142
- * This will be used as server that runs within a Service Worker environment.
143
- *
144
- * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.
145
- */
112
+ * The Server for service worker environment
113
+ *
114
+ * This interface has like Node.js HTTP Server interfaces.
115
+ * This will be used as server that runs within a Service Worker environment.
116
+ *
117
+ * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.
118
+ */
146
119
  interface SvcWorkerServer<MessageData = unknown> extends Emittable<SvcWorkerServerEventMap<MessageData>>, Disposable, AsyncDisposable {
147
120
  /**
148
- * The current state of the server
149
- */
121
+ * The current state of the server
122
+ */
150
123
  readonly state: SvcWorkerServerState;
151
124
  /**
152
- * Set a fetch event handler
153
- * @param handler - A function to handle fetch events
154
- */
125
+ * Set a fetch event handler
126
+ * @param handler - A function to handle fetch events
127
+ */
155
128
  setFetchHandler(handler: (event: FetchEvent) => void): void;
156
129
  /**
157
- * Start a server listening for service worker fetch events
158
- *
159
- * When the service worker fetch event handler is bound, the 'listening' event will be emitted.
160
- * If `enableListenConnections` option is set to `true`, server will be started to listen MessageChannel connection too via {@link SvcWorkerServer.listenConnections} internally.
161
- *
162
- * @param options - Options for listening
163
- * @returns The server instance
164
- * @throws {SvcWorkerServerError} When the server is already listening or fetch handler is not set
165
- */
130
+ * Start a server listening for service worker fetch events
131
+ *
132
+ * When the service worker fetch event handler is bound, the 'listening' event will be emitted.
133
+ * If `enableListenConnections` option is set to `true`, server will be started to listen MessageChannel connection too via {@link SvcWorkerServer.listenConnections} internally.
134
+ *
135
+ * @param options - Options for listening
136
+ * @returns The server instance
137
+ * @throws {SvcWorkerServerError} When the server is already listening or fetch handler is not set
138
+ */
166
139
  listen(options?: ListenOptions): SvcWorkerServer<MessageData>;
167
140
  /**
168
- * Start a MessageChannel port connections listening with `message` events from clients.
169
- *
170
- * @returns The server instance
171
- */
141
+ * Start a MessageChannel port connections listening with `message` events from clients.
142
+ *
143
+ * @returns The server instance
144
+ */
172
145
  listenConnections(): SvcWorkerServer<MessageData>;
173
146
  /**
174
- * Stops the server from accepting new fetch event and close {@link MessageChannel} port connections
175
- *
176
- * When it will be finished, the optional callback `fn` will be called, and trigger 'close' event.
177
- *
178
- * @param cb - An optional callback function which will be called when the server is closed
179
- * @param stopConnectionListening - If `true`, also stops listening for MessageChannel port connections too via {@link SvcWorkerServer.closeConnections}. Defaults to `false`.
180
- * @returns The server instance
181
- */
147
+ * Stops the server from accepting new fetch event and close {@link MessageChannel} port connections
148
+ *
149
+ * When it will be finished, the optional callback `fn` will be called, and trigger 'close' event.
150
+ *
151
+ * @param cb - An optional callback function which will be called when the server is closed
152
+ * @param stopConnectionListening - If `true`, also stops listening for MessageChannel port connections too via {@link SvcWorkerServer.closeConnections}. Defaults to `false`.
153
+ * @returns The server instance
154
+ */
182
155
  close(cb?: (err?: Error) => void, stopConnectionListening?: boolean): SvcWorkerServer<MessageData>;
183
156
  /**
184
- * Closes {@link MessageChannel} port connections connected to this server.
185
- *
186
- * @param cb - An optional callback function which will be called when MessageChannel port connections are closed
187
- * @returns The server instance
188
- */
157
+ * Closes {@link MessageChannel} port connections connected to this server.
158
+ *
159
+ * @param cb - An optional callback function which will be called when MessageChannel port connections are closed
160
+ * @returns The server instance
161
+ */
189
162
  closeConnections(cb?: (err?: Error) => void): SvcWorkerServer<MessageData>;
190
163
  /**
191
- * Returns the bound service worker address
192
- *
193
- * the address service worker script URL, or `null` if the server is not listening.
194
- *
195
- * @returns The service worker script URL or `null`
196
- */
164
+ * Returns the bound service worker address
165
+ *
166
+ * the address service worker script URL, or `null` if the server is not listening.
167
+ *
168
+ * @returns The service worker script URL or `null`
169
+ */
197
170
  address(): URL | null;
198
171
  /**
199
- * Asynchronously get the number of concurrent {@link MessageChannel} port connections on the server.
200
- */
172
+ * Asynchronously get the number of concurrent {@link MessageChannel} port connections on the server.
173
+ */
201
174
  getConnections(cb: (error: Error | null, count: number) => void): SvcWorkerServer<MessageData>;
202
175
  /**
203
- * `Symbol.dispose` for `using` syntax support (TypeScript 5.2+)
204
- */
176
+ * `Symbol.dispose` for `using` syntax support (TypeScript 5.2+)
177
+ */
205
178
  [Symbol.dispose](): void;
206
179
  /**
207
- * Calls `close()` and returns a promise that fulfills when the server has closed.
208
- */
180
+ * Calls `close()` and returns a promise that fulfills when the server has closed.
181
+ */
209
182
  [Symbol.asyncDispose](): Promise<void>;
210
183
  }
211
184
  /**
212
- * Create a {@link SvcWorkerServer | Service worker server} instance.
213
- *
214
- * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.
215
- * @param self - The {@link ServiceWorkerGlobalScope} instance (typically `self` in a service worker)
216
- * @param options - {@link SvcWorkerServerOptions | Service worker server options}
217
- * @returns {@link SvcWorkerServer | Service worker server instance}
218
- *
219
- * @example
220
- * ```ts
221
- * interface MyMessage {
222
- * type: 'greeting' | 'farewell'
223
- * payload: string
224
- * }
225
- *
226
- * const server = createSvcWorkerServer<MyMessage>(self, { version: '1.0.0' })
227
- * server.on('connection', (event) => {
228
- * // event.data is typed as MyMessage
229
- * console.log(event.data.type, event.data.payload)
230
- * // Access the MessagePorts
231
- * console.log(event.ports)
232
- * // Access client ID if available
233
- * console.log(event.clientId)
234
- * })
235
- * ```
236
- */
185
+ * Create a {@link SvcWorkerServer | Service worker server} instance.
186
+ *
187
+ * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.
188
+ * @param self - The {@link ServiceWorkerGlobalScope} instance (typically `self` in a service worker)
189
+ * @param options - {@link SvcWorkerServerOptions | Service worker server options}
190
+ * @returns {@link SvcWorkerServer | Service worker server instance}
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * interface MyMessage {
195
+ * type: 'greeting' | 'farewell'
196
+ * payload: string
197
+ * }
198
+ *
199
+ * const server = createSvcWorkerServer<MyMessage>(self, { version: '1.0.0' })
200
+ * server.on('connection', (event) => {
201
+ * // event.data is typed as MyMessage
202
+ * console.log(event.data.type, event.data.payload)
203
+ * // Access the MessagePorts
204
+ * console.log(event.ports)
205
+ * // Access client ID if available
206
+ * console.log(event.clientId)
207
+ * })
208
+ * ```
209
+ */
237
210
  declare function createSvcWorkerServer<MessageData = unknown>(self: ServiceWorkerGlobalScope, options: SvcWorkerServerOptions): SvcWorkerServer<MessageData>;
238
211
  //#endregion
239
212
  export { ConnectionEvent, ListenOptions, SvcWorkerServer, SvcWorkerServerError, SvcWorkerServerEventMap, SvcWorkerServerOptions, SvcWorkerServerState, createSvcWorkerServer };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../service-worker/src/worker.ts","../src/index.ts"],"sourcesContent":[],"mappings":";;;;ACoBA;AAUA;AAYA;AAKiB,UDiDA,gBAAA,CCjDA;EAuCjB;;;;EAQ4C,OAAA,EAAA,MAAA;EAI3B;;AAcjB;;EASc,iBAAA,CAAA,EAAA,MAAA;EAQL;;AAgBT;;EACoB,cAAA,CAAA,EAAA,MAAA;EAIF;;;EAkBiC,KAAA,CAAA,EDlDzC,OCkDyC,CAAA,OAAA,CAAA;;;;;ADxEnD;;cC5Ea,oBAAA,SAA6B,KAAA;;EAA1C,WAAa,CAAA,OAAA,EAAA,MAAA,EAAA,KAE0B,CAF1B,EAE0B,KAAA;AAQvC;AAYA;AAKA;AAuCA;AAI2B,UA5DV,sBAAA,SAA+B,gBA4DrB,CAAA;EAIR;;;EAIF,eAAA,CAAA,EAAA,OAAA;;AAcjB;;;;;AAiCiB,KAvGL,oBAAA,GAAuB,kBAuGlB,GAAA,WAAA;;;;AAWkB,UA7GlB,aAAA,CA6GkB;EAYhB;;;;;EAkBC,eAAA,CAAA,EAAA,MAAA;EAAoE;;;;;EAiB3E,uBAAA,CAAA,EAAA,OAAA;;;;;;;;;AA4Cb;;;;;;;;;;;;;;;;;UAjKiB;;;;2BAIU;;;;mBAIR,SAAS,gBAAgB;;;;iBAI3B;;;;;;;;;;;;;KAcL;;;;;;;;;cASE,gBAAgB;;;;;;;;SAQrB;;;;;;;;;;UAgBQ,+CACP,UAAU,wBAAwB,eAAe,YAAY;;;;kBAIrD;;;;;mCAMiB;;;;;;;;;;;mBAYhB,gBAAgB,gBAAgB;;;;;;uBAO5B,gBAAgB;;;;;;;;;;oBAWnB,oDAAoD,gBAAgB;;;;;;;+BAQzD,iBAAiB,gBAAgB;;;;;;;;aASnD;;;;6BAKgB,uCAAuC,gBAAgB;;;;;;;;2BAUzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6BX,mDACR,mCACG,yBACR,gBAAgB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;cAoBa,6BAA6B;EACxC;EACA,YAAY,iBAAiB,QAAQ;;;;;UAQtB,+BAA+B;;;;EAI9C;;;;;;;KAQU,uBAAuB;;;;UAKlB;;;;;;EAMf;;;;;;EAMA;;;;;;;;;;;;;;;;;;;;;;;;;;UA2Be,gBAAgB;;;;WAItB,gBAAgB;;;;WAIhB,QAAQ,SAAS,gBAAgB;;;;WAIjC,MAAM;;;;WAIN;;;;;;;;;KAUC,wBAAwB;;;;EAIlC;;;;;EAKA,YAAY,gBAAgB;;;;EAI5B;;;;EAIA,OAAO;;;;;;;;;;UAgBQ,gBAAgB,+BACvB,UAAU,wBAAwB,eAAe,YAAY;;;;WAI5D,OAAO;;;;;EAMhB,gBAAgB,UAAU,OAAO;;;;;;;;;;;EAYjC,OAAO,UAAU,gBAAgB,gBAAgB;;;;;;EAOjD,qBAAqB,gBAAgB;;;;;;;;;;EAWrC,MAAM,MAAM,MAAM,gBAAgB,oCAAoC,gBAAgB;;;;;;;EAQtF,iBAAiB,MAAM,MAAM,iBAAiB,gBAAgB;;;;;;;;EAS9D,WAAW;;;;EAKX,eAAe,KAAK,OAAO,cAAc,yBAAyB,gBAAgB;;;;GAKjF,OAAO;;;;GAKP,OAAO,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6BX,sBAAsB,uBACpC,MAAM,0BACN,SAAS,yBACR,gBAAgB"}
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Emitter } from "@kazupon/jts-utils/event";
2
2
  import { createSvcWorker } from "@vrowzer/service-worker/worker";
3
-
4
3
  //#region src/index.ts
5
4
  /**
6
5
  * This entry file is for service worker server
@@ -219,7 +218,7 @@ function createSvcWorkerServer(self, options) {
219
218
  };
220
219
  return instance;
221
220
  }
222
-
223
221
  //#endregion
224
222
  export { SvcWorkerServerError, createSvcWorkerServer };
223
+
225
224
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_svcWorker: SvcWorker","_ports: Set<MessagePort>","_fetchHandler: ((event: FetchEvent) => void) | null","_boundFetchHandler: ((event: FetchEvent) => void) | null","_activateHandler: ((event: ExtendableEvent) => void) | null","_activateTimeoutId: ReturnType<typeof setTimeout> | null","_messageHandler: ((event: ExtendableMessageEvent) => void) | null","connectionEvent: ConnectionEvent<MessageData>","instance: SvcWorkerServer<MessageData>"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * This entry file is for service worker server\n *\n * @module service-worker-server\n */\n\n/**\n * @author kazuya kawaguchi (a.k.a. kazupon)\n * @license MIT\n */\n\nimport { Emitter } from '@kazupon/jts-utils/event'\nimport { createSvcWorker } from '@vrowzer/service-worker/worker'\n\nimport type { Emittable } from '@kazupon/jts-utils/event/emitter'\nimport type { SvcWorker, SvcWorkerOptions } from '@vrowzer/service-worker/worker'\n\n/**\n * Service worker server error\n */\nexport class SvcWorkerServerError extends Error {\n name = 'SvcWorkerServerError'\n constructor(message: string, cause?: Error) {\n super(message, { cause })\n }\n}\n\n/**\n * The {@link SvcWorkerServer} constructor options\n */\nexport interface SvcWorkerServerOptions extends SvcWorkerOptions {\n /**\n * Automatically call `clients.claim()` on `activate` event.\n */\n claimOnActivate?: boolean\n}\n\n/**\n * Extend {@link ServiceWorkerState} with additional states\n *\n * - 'suspended': State when {@link SvcWorker | service worker} is suspended.\n */\nexport type SvcWorkerServerState = ServiceWorkerState | 'suspended'\n\n/**\n * Options for the {@link SvcWorkerServer.listen} method\n */\nexport interface ListenOptions {\n /**\n * Timeout in milliseconds for waiting for the activate event.\n * If the timeout is exceeded, an 'error' event is emitted.\n * @default 30000 (30 seconds)\n */\n activateTimeout?: number\n /**\n * Enable listening for MessageChannel port connections.\n * If set to true, the server will accept connections via `message` events from clients.\n * @default false\n */\n enableListenConnections?: boolean\n}\n\n/**\n * Connection event payload for {@link MessageChannel} connections.\n *\n * This interface represents a connection event that is emitted when a client\n * sends a message with {@link MessagePort | MessagePorts} (typically for establishing a MessageChannel connection).\n *\n * @typeParam T - The type of the message data. Defaults to `unknown`.\n *\n * @example\n * ```ts\n * interface MyMessage {\n * type: 'greeting' | 'farewell'\n * payload: string\n * }\n *\n * const server = createSvcWorkerServer<MyMessage>(self, options)\n * server.on('connection', (event) => {\n * // event.data is typed as MyMessage\n * console.log(event.data.type, event.data.payload)\n * // Access the MessagePorts\n * console.log(event.ports)\n * })\n * ```\n */\nexport interface ConnectionEvent<T = unknown> {\n /**\n * The MessagePorts received from the client.\n */\n readonly ports: readonly MessagePort[]\n /**\n * The source of the message (Client, ServiceWorker, or MessagePort).\n */\n readonly source: Client | ServiceWorker | MessagePort | null\n /**\n * The message data with type safety.\n */\n readonly data: T\n /**\n * The client ID if the source is a Client.\n */\n readonly clientId?: string\n}\n\n/**\n * Event map for {@link SvcWorkerServer}.\n *\n * This type defines the payload types for each event.\n *\n * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.\n */\nexport type SvcWorkerServerEventMap<MessageData = unknown> = {\n /**\n * Emitted when the server starts listening for fetch events.\n */\n listening: void\n /**\n * Emitted when a client connects via MessageChannel.\n * This event is fired only when the message contains MessagePorts.\n */\n connection: ConnectionEvent<MessageData>\n /**\n * Emitted when the server is closed.\n */\n close: void\n /**\n * Emitted when an error occurs.\n */\n error: Error\n}\n\n/**\n * Default timeout for waiting for the activate event (30 seconds)\n */\nconst DEFAULT_ACTIVATE_TIMEOUT = 30000\n\n/**\n * The Server for service worker environment\n *\n * This interface has like Node.js HTTP Server interfaces.\n * This will be used as server that runs within a Service Worker environment.\n *\n * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.\n */\nexport interface SvcWorkerServer<MessageData = unknown>\n extends Emittable<SvcWorkerServerEventMap<MessageData>>, Disposable, AsyncDisposable {\n /**\n * The current state of the server\n */\n readonly state: SvcWorkerServerState\n\n /**\n * Set a fetch event handler\n * @param handler - A function to handle fetch events\n */\n setFetchHandler(handler: (event: FetchEvent) => void): void\n\n /**\n * Start a server listening for service worker fetch events\n *\n * When the service worker fetch event handler is bound, the 'listening' event will be emitted.\n * If `enableListenConnections` option is set to `true`, server will be started to listen MessageChannel connection too via {@link SvcWorkerServer.listenConnections} internally.\n *\n * @param options - Options for listening\n * @returns The server instance\n * @throws {SvcWorkerServerError} When the server is already listening or fetch handler is not set\n */\n listen(options?: ListenOptions): SvcWorkerServer<MessageData>\n\n /**\n * Start a MessageChannel port connections listening with `message` events from clients.\n *\n * @returns The server instance\n */\n listenConnections(): SvcWorkerServer<MessageData>\n\n /**\n * Stops the server from accepting new fetch event and close {@link MessageChannel} port connections\n *\n * When it will be finished, the optional callback `fn` will be called, and trigger 'close' event.\n *\n * @param cb - An optional callback function which will be called when the server is closed\n * @param stopConnectionListening - If `true`, also stops listening for MessageChannel port connections too via {@link SvcWorkerServer.closeConnections}. Defaults to `false`.\n * @returns The server instance\n */\n close(cb?: (err?: Error) => void, stopConnectionListening?: boolean): SvcWorkerServer<MessageData>\n\n /**\n * Closes {@link MessageChannel} port connections connected to this server.\n *\n * @param cb - An optional callback function which will be called when MessageChannel port connections are closed\n * @returns The server instance\n */\n closeConnections(cb?: (err?: Error) => void): SvcWorkerServer<MessageData>\n\n /**\n * Returns the bound service worker address\n *\n * the address service worker script URL, or `null` if the server is not listening.\n *\n * @returns The service worker script URL or `null`\n */\n address(): URL | null\n\n /**\n * Asynchronously get the number of concurrent {@link MessageChannel} port connections on the server.\n */\n getConnections(cb: (error: Error | null, count: number) => void): SvcWorkerServer<MessageData>\n\n /**\n * `Symbol.dispose` for `using` syntax support (TypeScript 5.2+)\n */\n [Symbol.dispose](): void\n\n /**\n * Calls `close()` and returns a promise that fulfills when the server has closed.\n */\n [Symbol.asyncDispose](): Promise<void>\n}\n\n/**\n * Create a {@link SvcWorkerServer | Service worker server} instance.\n *\n * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.\n * @param self - The {@link ServiceWorkerGlobalScope} instance (typically `self` in a service worker)\n * @param options - {@link SvcWorkerServerOptions | Service worker server options}\n * @returns {@link SvcWorkerServer | Service worker server instance}\n *\n * @example\n * ```ts\n * interface MyMessage {\n * type: 'greeting' | 'farewell'\n * payload: string\n * }\n *\n * const server = createSvcWorkerServer<MyMessage>(self, { version: '1.0.0' })\n * server.on('connection', (event) => {\n * // event.data is typed as MyMessage\n * console.log(event.data.type, event.data.payload)\n * // Access the MessagePorts\n * console.log(event.ports)\n * // Access client ID if available\n * console.log(event.clientId)\n * })\n * ```\n */\nexport function createSvcWorkerServer<MessageData = unknown>(\n self: ServiceWorkerGlobalScope,\n options: SvcWorkerServerOptions\n): SvcWorkerServer<MessageData> {\n const _emitter = Emitter<SvcWorkerServerEventMap<MessageData>>()\n const _svcWorker: SvcWorker = createSvcWorker(self, options)\n const _options = options\n\n const _ports: Set<MessagePort> = new Set()\n\n let _listening = false\n let _listeningConnections = false\n let _fetchHandler: ((event: FetchEvent) => void) | null = null\n let _boundFetchHandler: ((event: FetchEvent) => void) | null = null\n let _activateHandler: ((event: ExtendableEvent) => void) | null = null\n let _activateTimeoutId: ReturnType<typeof setTimeout> | null = null\n let _messageHandler: ((event: ExtendableMessageEvent) => void) | null = null\n\n /**\n * Cleanup activate waiting state (timeout and handler)\n */\n function cleanupActivateWaiting(): void {\n if (_activateTimeoutId !== null) {\n clearTimeout(_activateTimeoutId)\n _activateTimeoutId = null\n }\n if (_activateHandler) {\n _svcWorker.removeEventListener('activate', _activateHandler)\n _activateHandler = null\n }\n }\n\n function listenConnections(): SvcWorkerServer<MessageData> {\n // Already listening for connections -> do nothing\n if (_listeningConnections) {\n return instance\n }\n\n // Register message handler for connection events\n _messageHandler = (event: ExtendableMessageEvent) => {\n // Only emit connection event when ports are present\n if (event.ports && event.ports.length > 0) {\n // Register ports to the Set\n for (const port of event.ports) {\n _ports.add(port)\n }\n\n const clientId = (event.source as Client | null)?.id\n const connectionEvent: ConnectionEvent<MessageData> = {\n ports: event.ports,\n source: event.source,\n data: event.data as MessageData,\n ...(clientId !== undefined && { clientId })\n }\n _emitter.emit('connection', connectionEvent)\n }\n }\n self.addEventListener('message', _messageHandler)\n\n _listeningConnections = true\n\n return instance\n }\n\n function setFetchHandler(handler: (event: FetchEvent) => void): void {\n if (typeof handler !== 'function') {\n throw new SvcWorkerServerError('fetch handler must be a function')\n }\n\n // If already registered, remove previous handler first\n if (_boundFetchHandler) {\n _svcWorker.removeEventListener('fetch', _boundFetchHandler)\n }\n\n // Store user's handler\n _fetchHandler = handler\n\n // Create wrapper with suspended/listening check\n // This wrapper is registered immediately but only calls user's handler when listening\n _boundFetchHandler = (event: FetchEvent) => {\n // Don't call user's handler if not listening or suspended\n if (!_listening || _svcWorker.suspended) {\n return // Fall through to network\n }\n try {\n _fetchHandler!(event)\n } catch (err) {\n _emitter.emit('error', err as Error)\n }\n }\n\n // Register fetch handler immediately (required by Service Worker spec)\n // IMPORTANT: Service Workers require fetch event listeners to be added during\n // the initial script execution, not asynchronously during event callbacks.\n _svcWorker.addEventListener('fetch', _boundFetchHandler)\n }\n\n function listen(listenOptions?: ListenOptions): SvcWorkerServer<MessageData> {\n // Prevent double listen\n if (_listening) {\n queueMicrotask(() =>\n _emitter.emit('error', new SvcWorkerServerError('Server is already listening'))\n )\n return instance\n }\n\n // Validate fetch handler is set\n if (!_fetchHandler) {\n queueMicrotask(() =>\n _emitter.emit(\n 'error',\n new SvcWorkerServerError('Fetch handler not set. Call setFetchHandler() first.')\n )\n )\n return instance\n }\n\n // Resolve options\n const activateTimeout = listenOptions?.activateTimeout ?? DEFAULT_ACTIVATE_TIMEOUT\n const enableListenConnections = listenOptions?.enableListenConnections ?? false\n\n // Update state - this enables the fetch handler wrapper to call user's handler\n _listening = true\n\n // NOTE: addEventListener('fetch') is already registered in setFetchHandler()\n\n // Register message handler if enableListenConnections is true\n if (enableListenConnections) {\n listenConnections()\n }\n\n // Check activated state\n const sw = _svcWorker as unknown as ServiceWorkerGlobalScope\n const isActivated = sw.registration.active !== null\n\n if (isActivated) {\n // Already activated -> emit 'listening' immediately (async)\n queueMicrotask(() => {\n if (_listening) {\n _emitter.emit('listening')\n }\n })\n } else {\n // Not activated -> wait for activate event with timeout\n\n // Set timeout\n _activateTimeoutId = setTimeout(() => {\n cleanupActivateWaiting()\n if (_listening) {\n _listening = false\n _fetchHandler = null\n _boundFetchHandler = null\n _emitter.emit(\n 'error',\n new SvcWorkerServerError(\n `Activate timeout: Service Worker did not activate within ${activateTimeout}ms`\n )\n )\n }\n }, activateTimeout)\n\n // Set activate handler\n _activateHandler = (event: ExtendableEvent) => {\n // Cleanup timeout and handler\n cleanupActivateWaiting()\n\n // Call `clients.claim()` if `claimOnActivate` is true\n if (_options.claimOnActivate) {\n const serviceWorkerScope = _svcWorker as unknown as ServiceWorkerGlobalScope\n event.waitUntil(serviceWorkerScope.clients.claim())\n }\n\n // Emit listening event after activation\n if (_listening) {\n _emitter.emit('listening')\n }\n }\n _svcWorker.addEventListener('activate', _activateHandler)\n }\n\n return instance\n }\n\n function closeConnections(cb?: (err?: Error) => void): SvcWorkerServer<MessageData> {\n // Remove message event listener\n if (_messageHandler) {\n self.removeEventListener('message', _messageHandler)\n _messageHandler = null\n }\n\n // Close all MessagePort connections\n closeAllConnections()\n\n // Update state\n _listeningConnections = false\n\n // Emit callback (async)\n queueMicrotask(() => {\n cb?.()\n })\n\n return instance\n }\n\n function close(\n cb?: (err?: Error) => void,\n stopConnectionListening?: boolean\n ): SvcWorkerServer<MessageData> {\n // Emit callback and 'close' event even if not listening\n if (!_listening) {\n queueMicrotask(() => {\n cb?.()\n _emitter.emit('close')\n })\n return instance\n }\n\n // Cleanup activate waiting state (timeout and handler)\n cleanupActivateWaiting()\n\n // Remove fetch event listener\n if (_boundFetchHandler) {\n _svcWorker.removeEventListener('fetch', _boundFetchHandler)\n _boundFetchHandler = null\n }\n\n // Stop connection listening if requested (via closeConnections)\n if (stopConnectionListening) {\n closeConnections()\n }\n\n // Clear handler reference\n _fetchHandler = null\n\n // Update state\n _listening = false\n\n // Emit callback and 'close' event (async)\n queueMicrotask(() => {\n cb?.()\n _emitter.emit('close')\n })\n\n return instance\n }\n\n function address(): URL | null {\n // TODO: implement\n return null\n }\n\n function getConnections(\n cb: (error: Error | null, count: number) => void\n ): SvcWorkerServer<MessageData> {\n queueMicrotask(() => cb(null, _ports.size))\n return instance\n }\n\n function closeAllConnections(): void {\n for (const port of _ports) {\n port.close()\n }\n _ports.clear()\n }\n\n function dispose(): void {\n close()\n }\n\n async function asyncDispose(): Promise<void> {\n return new Promise((resolve, reject) => {\n close(err => {\n if (err) {\n reject(err)\n } else {\n resolve()\n }\n })\n })\n }\n\n const instance: SvcWorkerServer<MessageData> = {\n ..._emitter,\n get state(): SvcWorkerServerState {\n // TODO:\n return 'installing'\n },\n setFetchHandler,\n listen,\n listenConnections,\n close,\n closeConnections,\n address,\n getConnections,\n [Symbol.dispose]: dispose,\n [Symbol.asyncDispose]: asyncDispose\n } as SvcWorkerServer<MessageData>\n\n return instance\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAoBA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAO;CACP,YAAY,SAAiB,OAAe;AAC1C,QAAM,SAAS,EAAE,OAAO,CAAC;;;;;;AAgH7B,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgHjC,SAAgB,sBACd,MACA,SAC8B;CAC9B,MAAM,WAAW,SAA+C;CAChE,MAAMA,aAAwB,gBAAgB,MAAM,QAAQ;CAC5D,MAAM,WAAW;CAEjB,MAAMC,yBAA2B,IAAI,KAAK;CAE1C,IAAI,aAAa;CACjB,IAAI,wBAAwB;CAC5B,IAAIC,gBAAsD;CAC1D,IAAIC,qBAA2D;CAC/D,IAAIC,mBAA8D;CAClE,IAAIC,qBAA2D;CAC/D,IAAIC,kBAAoE;;;;CAKxE,SAAS,yBAA+B;AACtC,MAAI,uBAAuB,MAAM;AAC/B,gBAAa,mBAAmB;AAChC,wBAAqB;;AAEvB,MAAI,kBAAkB;AACpB,cAAW,oBAAoB,YAAY,iBAAiB;AAC5D,sBAAmB;;;CAIvB,SAAS,oBAAkD;AAEzD,MAAI,sBACF,QAAO;AAIT,qBAAmB,UAAkC;AAEnD,OAAI,MAAM,SAAS,MAAM,MAAM,SAAS,GAAG;AAEzC,SAAK,MAAM,QAAQ,MAAM,MACvB,QAAO,IAAI,KAAK;IAGlB,MAAM,WAAY,MAAM,QAA0B;IAClD,MAAMC,kBAAgD;KACpD,OAAO,MAAM;KACb,QAAQ,MAAM;KACd,MAAM,MAAM;KACZ,GAAI,aAAa,UAAa,EAAE,UAAU;KAC3C;AACD,aAAS,KAAK,cAAc,gBAAgB;;;AAGhD,OAAK,iBAAiB,WAAW,gBAAgB;AAEjD,0BAAwB;AAExB,SAAO;;CAGT,SAAS,gBAAgB,SAA4C;AACnE,MAAI,OAAO,YAAY,WACrB,OAAM,IAAI,qBAAqB,mCAAmC;AAIpE,MAAI,mBACF,YAAW,oBAAoB,SAAS,mBAAmB;AAI7D,kBAAgB;AAIhB,wBAAsB,UAAsB;AAE1C,OAAI,CAAC,cAAc,WAAW,UAC5B;AAEF,OAAI;AACF,kBAAe,MAAM;YACd,KAAK;AACZ,aAAS,KAAK,SAAS,IAAa;;;AAOxC,aAAW,iBAAiB,SAAS,mBAAmB;;CAG1D,SAAS,OAAO,eAA6D;AAE3E,MAAI,YAAY;AACd,wBACE,SAAS,KAAK,SAAS,IAAI,qBAAqB,8BAA8B,CAAC,CAChF;AACD,UAAO;;AAIT,MAAI,CAAC,eAAe;AAClB,wBACE,SAAS,KACP,SACA,IAAI,qBAAqB,uDAAuD,CACjF,CACF;AACD,UAAO;;EAIT,MAAM,kBAAkB,eAAe,mBAAmB;EAC1D,MAAM,0BAA0B,eAAe,2BAA2B;AAG1E,eAAa;AAKb,MAAI,wBACF,oBAAmB;AAOrB,MAHW,WACY,aAAa,WAAW,KAI7C,sBAAqB;AACnB,OAAI,WACF,UAAS,KAAK,YAAY;IAE5B;OACG;AAIL,wBAAqB,iBAAiB;AACpC,4BAAwB;AACxB,QAAI,YAAY;AACd,kBAAa;AACb,qBAAgB;AAChB,0BAAqB;AACrB,cAAS,KACP,SACA,IAAI,qBACF,4DAA4D,gBAAgB,IAC7E,CACF;;MAEF,gBAAgB;AAGnB,uBAAoB,UAA2B;AAE7C,4BAAwB;AAGxB,QAAI,SAAS,iBAAiB;KAC5B,MAAM,qBAAqB;AAC3B,WAAM,UAAU,mBAAmB,QAAQ,OAAO,CAAC;;AAIrD,QAAI,WACF,UAAS,KAAK,YAAY;;AAG9B,cAAW,iBAAiB,YAAY,iBAAiB;;AAG3D,SAAO;;CAGT,SAAS,iBAAiB,IAA0D;AAElF,MAAI,iBAAiB;AACnB,QAAK,oBAAoB,WAAW,gBAAgB;AACpD,qBAAkB;;AAIpB,uBAAqB;AAGrB,0BAAwB;AAGxB,uBAAqB;AACnB,SAAM;IACN;AAEF,SAAO;;CAGT,SAAS,MACP,IACA,yBAC8B;AAE9B,MAAI,CAAC,YAAY;AACf,wBAAqB;AACnB,UAAM;AACN,aAAS,KAAK,QAAQ;KACtB;AACF,UAAO;;AAIT,0BAAwB;AAGxB,MAAI,oBAAoB;AACtB,cAAW,oBAAoB,SAAS,mBAAmB;AAC3D,wBAAqB;;AAIvB,MAAI,wBACF,mBAAkB;AAIpB,kBAAgB;AAGhB,eAAa;AAGb,uBAAqB;AACnB,SAAM;AACN,YAAS,KAAK,QAAQ;IACtB;AAEF,SAAO;;CAGT,SAAS,UAAsB;AAE7B,SAAO;;CAGT,SAAS,eACP,IAC8B;AAC9B,uBAAqB,GAAG,MAAM,OAAO,KAAK,CAAC;AAC3C,SAAO;;CAGT,SAAS,sBAA4B;AACnC,OAAK,MAAM,QAAQ,OACjB,MAAK,OAAO;AAEd,SAAO,OAAO;;CAGhB,SAAS,UAAgB;AACvB,SAAO;;CAGT,eAAe,eAA8B;AAC3C,SAAO,IAAI,SAAS,SAAS,WAAW;AACtC,UAAM,QAAO;AACX,QAAI,IACF,QAAO,IAAI;QAEX,UAAS;KAEX;IACF;;CAGJ,MAAMC,WAAyC;EAC7C,GAAG;EACH,IAAI,QAA8B;AAEhC,UAAO;;EAET;EACA;EACA;EACA;EACA;EACA;EACA;GACC,OAAO,UAAU;GACjB,OAAO,eAAe;EACxB;AAED,QAAO"}
1
+ {"version":3,"file":"index.js","names":["sw"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * This entry file is for service worker server\n *\n * @module service-worker-server\n */\n\n/**\n * @author kazuya kawaguchi (a.k.a. kazupon)\n * @license MIT\n */\n\nimport { Emitter } from '@kazupon/jts-utils/event'\nimport { createSvcWorker } from '@vrowzer/service-worker/worker'\n\nimport type { Emittable } from '@kazupon/jts-utils/event/emitter'\nimport type { SvcWorker, SvcWorkerOptions } from '@vrowzer/service-worker/worker'\n\n/**\n * Service worker server error\n */\nexport class SvcWorkerServerError extends Error {\n name = 'SvcWorkerServerError'\n constructor(message: string, cause?: Error) {\n super(message, { cause })\n }\n}\n\n/**\n * The {@link SvcWorkerServer} constructor options\n */\nexport interface SvcWorkerServerOptions extends SvcWorkerOptions {\n /**\n * Automatically call `clients.claim()` on `activate` event.\n */\n claimOnActivate?: boolean\n}\n\n/**\n * Extend {@link ServiceWorkerState} with additional states\n *\n * - 'suspended': State when {@link SvcWorker | service worker} is suspended.\n */\nexport type SvcWorkerServerState = ServiceWorkerState | 'suspended'\n\n/**\n * Options for the {@link SvcWorkerServer.listen} method\n */\nexport interface ListenOptions {\n /**\n * Timeout in milliseconds for waiting for the activate event.\n * If the timeout is exceeded, an 'error' event is emitted.\n * @default 30000 (30 seconds)\n */\n activateTimeout?: number\n /**\n * Enable listening for MessageChannel port connections.\n * If set to true, the server will accept connections via `message` events from clients.\n * @default false\n */\n enableListenConnections?: boolean\n}\n\n/**\n * Connection event payload for {@link MessageChannel} connections.\n *\n * This interface represents a connection event that is emitted when a client\n * sends a message with {@link MessagePort | MessagePorts} (typically for establishing a MessageChannel connection).\n *\n * @typeParam T - The type of the message data. Defaults to `unknown`.\n *\n * @example\n * ```ts\n * interface MyMessage {\n * type: 'greeting' | 'farewell'\n * payload: string\n * }\n *\n * const server = createSvcWorkerServer<MyMessage>(self, options)\n * server.on('connection', (event) => {\n * // event.data is typed as MyMessage\n * console.log(event.data.type, event.data.payload)\n * // Access the MessagePorts\n * console.log(event.ports)\n * })\n * ```\n */\nexport interface ConnectionEvent<T = unknown> {\n /**\n * The MessagePorts received from the client.\n */\n readonly ports: readonly MessagePort[]\n /**\n * The source of the message (Client, ServiceWorker, or MessagePort).\n */\n readonly source: Client | ServiceWorker | MessagePort | null\n /**\n * The message data with type safety.\n */\n readonly data: T\n /**\n * The client ID if the source is a Client.\n */\n readonly clientId?: string\n}\n\n/**\n * Event map for {@link SvcWorkerServer}.\n *\n * This type defines the payload types for each event.\n *\n * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.\n */\nexport type SvcWorkerServerEventMap<MessageData = unknown> = {\n /**\n * Emitted when the server starts listening for fetch events.\n */\n listening: void\n /**\n * Emitted when a client connects via MessageChannel.\n * This event is fired only when the message contains MessagePorts.\n */\n connection: ConnectionEvent<MessageData>\n /**\n * Emitted when the server is closed.\n */\n close: void\n /**\n * Emitted when an error occurs.\n */\n error: Error\n}\n\n/**\n * Default timeout for waiting for the activate event (30 seconds)\n */\nconst DEFAULT_ACTIVATE_TIMEOUT = 30000\n\n/**\n * The Server for service worker environment\n *\n * This interface has like Node.js HTTP Server interfaces.\n * This will be used as server that runs within a Service Worker environment.\n *\n * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.\n */\nexport interface SvcWorkerServer<MessageData = unknown>\n extends Emittable<SvcWorkerServerEventMap<MessageData>>, Disposable, AsyncDisposable {\n /**\n * The current state of the server\n */\n readonly state: SvcWorkerServerState\n\n /**\n * Set a fetch event handler\n * @param handler - A function to handle fetch events\n */\n setFetchHandler(handler: (event: FetchEvent) => void): void\n\n /**\n * Start a server listening for service worker fetch events\n *\n * When the service worker fetch event handler is bound, the 'listening' event will be emitted.\n * If `enableListenConnections` option is set to `true`, server will be started to listen MessageChannel connection too via {@link SvcWorkerServer.listenConnections} internally.\n *\n * @param options - Options for listening\n * @returns The server instance\n * @throws {SvcWorkerServerError} When the server is already listening or fetch handler is not set\n */\n listen(options?: ListenOptions): SvcWorkerServer<MessageData>\n\n /**\n * Start a MessageChannel port connections listening with `message` events from clients.\n *\n * @returns The server instance\n */\n listenConnections(): SvcWorkerServer<MessageData>\n\n /**\n * Stops the server from accepting new fetch event and close {@link MessageChannel} port connections\n *\n * When it will be finished, the optional callback `fn` will be called, and trigger 'close' event.\n *\n * @param cb - An optional callback function which will be called when the server is closed\n * @param stopConnectionListening - If `true`, also stops listening for MessageChannel port connections too via {@link SvcWorkerServer.closeConnections}. Defaults to `false`.\n * @returns The server instance\n */\n close(cb?: (err?: Error) => void, stopConnectionListening?: boolean): SvcWorkerServer<MessageData>\n\n /**\n * Closes {@link MessageChannel} port connections connected to this server.\n *\n * @param cb - An optional callback function which will be called when MessageChannel port connections are closed\n * @returns The server instance\n */\n closeConnections(cb?: (err?: Error) => void): SvcWorkerServer<MessageData>\n\n /**\n * Returns the bound service worker address\n *\n * the address service worker script URL, or `null` if the server is not listening.\n *\n * @returns The service worker script URL or `null`\n */\n address(): URL | null\n\n /**\n * Asynchronously get the number of concurrent {@link MessageChannel} port connections on the server.\n */\n getConnections(cb: (error: Error | null, count: number) => void): SvcWorkerServer<MessageData>\n\n /**\n * `Symbol.dispose` for `using` syntax support (TypeScript 5.2+)\n */\n [Symbol.dispose](): void\n\n /**\n * Calls `close()` and returns a promise that fulfills when the server has closed.\n */\n [Symbol.asyncDispose](): Promise<void>\n}\n\n/**\n * Create a {@link SvcWorkerServer | Service worker server} instance.\n *\n * @typeParam MessageData - The type of the message data for the `connection` event. Defaults to `unknown`.\n * @param self - The {@link ServiceWorkerGlobalScope} instance (typically `self` in a service worker)\n * @param options - {@link SvcWorkerServerOptions | Service worker server options}\n * @returns {@link SvcWorkerServer | Service worker server instance}\n *\n * @example\n * ```ts\n * interface MyMessage {\n * type: 'greeting' | 'farewell'\n * payload: string\n * }\n *\n * const server = createSvcWorkerServer<MyMessage>(self, { version: '1.0.0' })\n * server.on('connection', (event) => {\n * // event.data is typed as MyMessage\n * console.log(event.data.type, event.data.payload)\n * // Access the MessagePorts\n * console.log(event.ports)\n * // Access client ID if available\n * console.log(event.clientId)\n * })\n * ```\n */\nexport function createSvcWorkerServer<MessageData = unknown>(\n self: ServiceWorkerGlobalScope,\n options: SvcWorkerServerOptions\n): SvcWorkerServer<MessageData> {\n const _emitter = Emitter<SvcWorkerServerEventMap<MessageData>>()\n const _svcWorker: SvcWorker = createSvcWorker(self, options)\n const _options = options\n\n const _ports: Set<MessagePort> = new Set()\n\n let _listening = false\n let _listeningConnections = false\n let _fetchHandler: ((event: FetchEvent) => void) | null = null\n let _boundFetchHandler: ((event: FetchEvent) => void) | null = null\n let _activateHandler: ((event: ExtendableEvent) => void) | null = null\n let _activateTimeoutId: ReturnType<typeof setTimeout> | null = null\n let _messageHandler: ((event: ExtendableMessageEvent) => void) | null = null\n\n /**\n * Cleanup activate waiting state (timeout and handler)\n */\n function cleanupActivateWaiting(): void {\n if (_activateTimeoutId !== null) {\n clearTimeout(_activateTimeoutId)\n _activateTimeoutId = null\n }\n if (_activateHandler) {\n _svcWorker.removeEventListener('activate', _activateHandler)\n _activateHandler = null\n }\n }\n\n function listenConnections(): SvcWorkerServer<MessageData> {\n // Already listening for connections -> do nothing\n if (_listeningConnections) {\n return instance\n }\n\n // Register message handler for connection events\n _messageHandler = (event: ExtendableMessageEvent) => {\n // Only emit connection event when ports are present\n if (event.ports && event.ports.length > 0) {\n // Register ports to the Set\n for (const port of event.ports) {\n _ports.add(port)\n }\n\n const clientId = (event.source as Client | null)?.id\n const connectionEvent: ConnectionEvent<MessageData> = {\n ports: event.ports,\n source: event.source,\n data: event.data as MessageData,\n ...(clientId !== undefined && { clientId })\n }\n _emitter.emit('connection', connectionEvent)\n }\n }\n self.addEventListener('message', _messageHandler)\n\n _listeningConnections = true\n\n return instance\n }\n\n function setFetchHandler(handler: (event: FetchEvent) => void): void {\n if (typeof handler !== 'function') {\n throw new SvcWorkerServerError('fetch handler must be a function')\n }\n\n // If already registered, remove previous handler first\n if (_boundFetchHandler) {\n _svcWorker.removeEventListener('fetch', _boundFetchHandler)\n }\n\n // Store user's handler\n _fetchHandler = handler\n\n // Create wrapper with suspended/listening check\n // This wrapper is registered immediately but only calls user's handler when listening\n _boundFetchHandler = (event: FetchEvent) => {\n // Don't call user's handler if not listening or suspended\n if (!_listening || _svcWorker.suspended) {\n return // Fall through to network\n }\n try {\n _fetchHandler!(event)\n } catch (err) {\n _emitter.emit('error', err as Error)\n }\n }\n\n // Register fetch handler immediately (required by Service Worker spec)\n // IMPORTANT: Service Workers require fetch event listeners to be added during\n // the initial script execution, not asynchronously during event callbacks.\n _svcWorker.addEventListener('fetch', _boundFetchHandler)\n }\n\n function listen(listenOptions?: ListenOptions): SvcWorkerServer<MessageData> {\n // Prevent double listen\n if (_listening) {\n queueMicrotask(() =>\n _emitter.emit('error', new SvcWorkerServerError('Server is already listening'))\n )\n return instance\n }\n\n // Validate fetch handler is set\n if (!_fetchHandler) {\n queueMicrotask(() =>\n _emitter.emit(\n 'error',\n new SvcWorkerServerError('Fetch handler not set. Call setFetchHandler() first.')\n )\n )\n return instance\n }\n\n // Resolve options\n const activateTimeout = listenOptions?.activateTimeout ?? DEFAULT_ACTIVATE_TIMEOUT\n const enableListenConnections = listenOptions?.enableListenConnections ?? false\n\n // Update state - this enables the fetch handler wrapper to call user's handler\n _listening = true\n\n // NOTE: addEventListener('fetch') is already registered in setFetchHandler()\n\n // Register message handler if enableListenConnections is true\n if (enableListenConnections) {\n listenConnections()\n }\n\n // Check activated state\n const sw = _svcWorker as unknown as ServiceWorkerGlobalScope\n const isActivated = sw.registration.active !== null\n\n if (isActivated) {\n // Already activated -> emit 'listening' immediately (async)\n queueMicrotask(() => {\n if (_listening) {\n _emitter.emit('listening')\n }\n })\n } else {\n // Not activated -> wait for activate event with timeout\n\n // Set timeout\n _activateTimeoutId = setTimeout(() => {\n cleanupActivateWaiting()\n if (_listening) {\n _listening = false\n _fetchHandler = null\n _boundFetchHandler = null\n _emitter.emit(\n 'error',\n new SvcWorkerServerError(\n `Activate timeout: Service Worker did not activate within ${activateTimeout}ms`\n )\n )\n }\n }, activateTimeout)\n\n // Set activate handler\n _activateHandler = (event: ExtendableEvent) => {\n // Cleanup timeout and handler\n cleanupActivateWaiting()\n\n // Call `clients.claim()` if `claimOnActivate` is true\n if (_options.claimOnActivate) {\n const serviceWorkerScope = _svcWorker as unknown as ServiceWorkerGlobalScope\n event.waitUntil(serviceWorkerScope.clients.claim())\n }\n\n // Emit listening event after activation\n if (_listening) {\n _emitter.emit('listening')\n }\n }\n _svcWorker.addEventListener('activate', _activateHandler)\n }\n\n return instance\n }\n\n function closeConnections(cb?: (err?: Error) => void): SvcWorkerServer<MessageData> {\n // Remove message event listener\n if (_messageHandler) {\n self.removeEventListener('message', _messageHandler)\n _messageHandler = null\n }\n\n // Close all MessagePort connections\n closeAllConnections()\n\n // Update state\n _listeningConnections = false\n\n // Emit callback (async)\n queueMicrotask(() => {\n cb?.()\n })\n\n return instance\n }\n\n function close(\n cb?: (err?: Error) => void,\n stopConnectionListening?: boolean\n ): SvcWorkerServer<MessageData> {\n // Emit callback and 'close' event even if not listening\n if (!_listening) {\n queueMicrotask(() => {\n cb?.()\n _emitter.emit('close')\n })\n return instance\n }\n\n // Cleanup activate waiting state (timeout and handler)\n cleanupActivateWaiting()\n\n // Remove fetch event listener\n if (_boundFetchHandler) {\n _svcWorker.removeEventListener('fetch', _boundFetchHandler)\n _boundFetchHandler = null\n }\n\n // Stop connection listening if requested (via closeConnections)\n if (stopConnectionListening) {\n closeConnections()\n }\n\n // Clear handler reference\n _fetchHandler = null\n\n // Update state\n _listening = false\n\n // Emit callback and 'close' event (async)\n queueMicrotask(() => {\n cb?.()\n _emitter.emit('close')\n })\n\n return instance\n }\n\n function address(): URL | null {\n // TODO: implement\n return null\n }\n\n function getConnections(\n cb: (error: Error | null, count: number) => void\n ): SvcWorkerServer<MessageData> {\n queueMicrotask(() => cb(null, _ports.size))\n return instance\n }\n\n function closeAllConnections(): void {\n for (const port of _ports) {\n port.close()\n }\n _ports.clear()\n }\n\n function dispose(): void {\n close()\n }\n\n async function asyncDispose(): Promise<void> {\n return new Promise((resolve, reject) => {\n close(err => {\n if (err) {\n reject(err)\n } else {\n resolve()\n }\n })\n })\n }\n\n const instance: SvcWorkerServer<MessageData> = {\n ..._emitter,\n get state(): SvcWorkerServerState {\n // TODO:\n return 'installing'\n },\n setFetchHandler,\n listen,\n listenConnections,\n close,\n closeConnections,\n address,\n getConnections,\n [Symbol.dispose]: dispose,\n [Symbol.asyncDispose]: asyncDispose\n } as SvcWorkerServer<MessageData>\n\n return instance\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vrowzer/service-worker-server",
3
3
  "description": "Serverized service worker with the Node Server interface",
4
- "version": "0.0.0",
4
+ "version": "0.1.0-beta.0",
5
5
  "author": {
6
6
  "name": "kazuya kawaguchi",
7
7
  "email": "kawakazu80@gmail.com"
@@ -21,7 +21,7 @@
21
21
  "vrowzer",
22
22
  "server"
23
23
  ],
24
- "homepage": "https://github.com/kazupon/vrowzer/packages/service-worker-server/README.md",
24
+ "homepage": "https://github.com/kazupon/vrowzer/tree/main/packages/service-worker-server#readme",
25
25
  "publishConfig": {
26
26
  "access": "public"
27
27
  },
@@ -49,19 +49,16 @@
49
49
  },
50
50
  "dependencies": {
51
51
  "@kazupon/jts-utils": "^0.17.0",
52
- "@vrowzer/service-worker": "0.0.0"
52
+ "@vrowzer/service-worker": "0.1.0-beta.0"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@playwright/test": "1.57.0",
56
- "get-port-please": "^3.2.0",
57
56
  "publint": "^0.3.18",
58
- "tsdown": "0.18.4",
59
- "typedoc": "^0.28.17",
60
- "vite": "^8.0.0"
57
+ "vite": "npm:@voidzero-dev/vite-plus-core@0.2.6"
61
58
  },
62
59
  "scripts": {
63
- "typecheck": "tsgo --noEmit -p tsconfig.json",
64
- "build": "tsdown",
65
- "build:docs": "typedoc --excludeInternal"
60
+ "typecheck": "tsc --noEmit -p tsconfig.json",
61
+ "build": "vp pack",
62
+ "build:docs": "tsx ../../scripts/api-references.ts"
66
63
  }
67
64
  }