svelte-adapter-uws 0.2.19 → 0.2.20

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/README.md CHANGED
@@ -737,12 +737,21 @@ The WebSocket upgrade is an HTTP request. The browser treats it like any other r
737
737
 
738
738
  Available in server hooks, load functions, form actions, API routes, and WebSocket hooks (`hooks.ws`).
739
739
 
740
- ### `platform.publish(topic, event, data)`
740
+ ### `platform.publish(topic, event, data, options?)`
741
741
 
742
742
  Send a message to all WebSocket clients subscribed to a topic.
743
743
 
744
744
  Topic and event names are validated before being written into the JSON envelope -- quotes, backslashes, and control characters will throw. This prevents JSON injection when names are built from dynamic values like user IDs (`platform.publish(\`user:\${id}\`, ...)`). The validation is a single-pass char scan and adds no measurable overhead.
745
745
 
746
+ In cluster mode, the message is automatically relayed to all other workers. Pass `{ relay: false }` to skip the relay when the message originates from an external pub/sub source (Redis, Postgres LISTEN/NOTIFY, etc.) that already delivers to every process:
747
+
748
+ ```js
749
+ // Redis subscriber running on every worker -- relay would cause duplicates
750
+ sub.on('message', (channel, payload) => {
751
+ platform.publish(channel, 'update', JSON.parse(payload), { relay: false });
752
+ });
753
+ ```
754
+
746
755
  ```js
747
756
  // src/routes/todos/+page.server.js
748
757
  export const actions = {
@@ -2085,7 +2094,9 @@ If a worker crashes, it is automatically restarted with exponential backoff. On
2085
2094
 
2086
2095
  ### WebSocket + clustering
2087
2096
 
2088
- `platform.publish()` is automatically relayed across all workers via the primary thread, so subscribers on any worker receive the message. This is built in - no external pub/sub needed.
2097
+ `platform.publish()` is automatically relayed across all workers via the primary thread, so subscribers on any worker receive the message. This is built in -- no external pub/sub needed.
2098
+
2099
+ If you add your own cross-process messaging (Redis, Postgres LISTEN/NOTIFY, etc.), pass `{ relay: false }` to prevent duplicate delivery -- your external source already fans out to every worker, so the built-in relay would double it.
2089
2100
 
2090
2101
  Per-worker limitations (acceptable for most apps):
2091
2102
  - `platform.connections` - returns the count for the local worker only
package/files/handler.js CHANGED
@@ -239,11 +239,14 @@ const platform = {
239
239
  * Auto-wraps in a { topic, event, data } envelope that the client store understands.
240
240
  * No-op if no clients are subscribed - safe to call unconditionally.
241
241
  */
242
- publish(topic, event, data) {
242
+ publish(topic, event, data, options) {
243
243
  const envelope = '{"topic":' + esc(topic) + ',"event":' + esc(event) + ',"data":' + JSON.stringify(data) + '}';
244
244
  const result = app.publish(topic, envelope, false, false);
245
- // Relay to other workers via main thread (no-op in single-process mode)
246
- if (parentPort) {
245
+ // Relay to other workers via main thread (no-op in single-process mode).
246
+ // Pass { relay: false } when the message originates from an external
247
+ // pub/sub source (Redis, Postgres, etc.) that already fans out to
248
+ // every process -- relaying would cause duplicate delivery.
249
+ if (parentPort && (!options || options.relay !== false)) {
247
250
  parentPort.postMessage({ type: 'publish', topic, envelope });
248
251
  }
249
252
  return result;
package/index.d.ts CHANGED
@@ -340,6 +340,9 @@ export interface Platform {
340
340
  * @param topic - Topic string (e.g. `'todos'`, `'user:123'`, `'org:456'`)
341
341
  * @param event - Event name (e.g. `'created'`, `'updated'`, `'deleted'`)
342
342
  * @param data - Payload (will be JSON-serialized)
343
+ * @param options - Optional. Pass `{ relay: false }` to skip cross-worker relay
344
+ * (use this when the message comes from an external pub/sub source like Redis
345
+ * or Postgres that already delivers to every process).
343
346
  *
344
347
  * @example
345
348
  * ```js
@@ -350,7 +353,7 @@ export interface Platform {
350
353
  * }
351
354
  * ```
352
355
  */
353
- publish(topic: string, event: string, data?: unknown): boolean;
356
+ publish(topic: string, event: string, data?: unknown, options?: { relay?: boolean }): boolean;
354
357
 
355
358
  /**
356
359
  * Send a message to a single WebSocket connection.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svelte-adapter-uws",
3
- "version": "0.2.19",
3
+ "version": "0.2.20",
4
4
  "description": "SvelteKit adapter for uWebSockets.js - high-performance C++ HTTP server with built-in WebSocket support",
5
5
  "author": "Kevin Radziszewski",
6
6
  "license": "MIT",
package/vite.js CHANGED
@@ -100,9 +100,10 @@ export default function uws(options = {}) {
100
100
  * @param {string} topic
101
101
  * @param {string} event
102
102
  * @param {unknown} [data]
103
+ * @param {{ relay?: boolean }} [_options] - Accepted for API parity with production; ignored in dev (single-process).
103
104
  * @returns {boolean}
104
105
  */
105
- function publish(topic, event, data) {
106
+ function publish(topic, event, data, _options) {
106
107
  const envelope = '{"topic":' + esc(topic) + ',"event":' + esc(event) + ',"data":' + JSON.stringify(data) + '}';
107
108
  let sent = false;
108
109
  for (const [ws, topics] of subscriptions) {