@silasdevs/transport 1.0.0 → 1.1.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/README.md CHANGED
@@ -121,7 +121,7 @@ import type { TransportError } from '@silasdevs/transport';
121
121
  try {
122
122
  const res = await transport.request(
123
123
  { channel: 'usuario', data: { id: 5 } },
124
- { timeout: 10_000 },
124
+ { timeout: 10_000, flattenOutgoing: false }, // override schema default for this call
125
125
  );
126
126
  console.log(res.code); // 'OK'
127
127
  console.log(res.data); // server payload
@@ -171,6 +171,9 @@ unsub();
171
171
 
172
172
  ```ts
173
173
  transport.send({ channel: 'ping' });
174
+
175
+ // Override flattenOutgoing for this call only
176
+ transport.send({ channel: 'cmd', data: { id: 1 } }, { flattenOutgoing: false });
174
177
  ```
175
178
 
176
179
  ## Handlers
@@ -243,7 +246,7 @@ All fields are optional. When the entire `codes` object is omitted, all response
243
246
  | `generateId` | Yes | Function that generates a unique numeric message ID. |
244
247
  | `encode` | Yes | Serialize a message object to a string for the wire. |
245
248
  | `decode` | Yes | Deserialize a raw wire string to an object (return `null` on failure). |
246
- | `flattenOutgoing` | Yes | `true` = spread data onto root; `false` = nest under payload field. |
249
+ | `flattenOutgoing` | No | Default `true`/`false` spread data onto root or nest under payload field. Can be overridden per call. |
247
250
  | `includeIdInRequest` | No | `true` = include messageId on the wire; `false` (default) = ID used internally only. |
248
251
 
249
252
  ### Example: Channel-based Protocol
@@ -453,9 +456,9 @@ transport.connect();
453
456
  |---|---|
454
457
  | `connect()` | Open WebSocket (idempotent) |
455
458
  | `disconnect({ clean? })` | Close WebSocket |
456
- | `request(msg, opts?)` | Promise-based send |
457
- | `fire(msg, cb, opts?)` | Callback-based send |
458
- | `send(msg)` | Fire-and-forget send |
459
+ | `request(msg, opts?)` | Promise-based send (`RequestOptions`: `timeout`, `flattenOutgoing`) |
460
+ | `fire(msg, cb, opts?)` | Callback-based send (`FireOptions`: `flattenOutgoing`) |
461
+ | `send(msg, opts?)` | Fire-and-forget send (`SendOptions`: `flattenOutgoing`) |
459
462
  | `addHandler(channel, name, cb)` | Register persistent handler |
460
463
  | `removeHandler(channel, name)` | Remove persistent handler |
461
464
  | `on(event, cb)` | Subscribe to lifecycle event |
@@ -501,6 +504,7 @@ import type {
501
504
  ReconnectOptions,
502
505
  RequestOptions,
503
506
  FireOptions,
507
+ SendOptions,
504
508
  } from '@silasdevs/transport';
505
509
  ```
506
510
 
package/dist/index.d.ts CHANGED
@@ -192,9 +192,33 @@ interface ReconnectOptions {
192
192
  interface RequestOptions {
193
193
  /** Timeout in ms. 0 = no timeout (default: 30_000). */
194
194
  timeout?: number;
195
+ /**
196
+ * Override the schema-level `flattenOutgoing` for this request only.
197
+ * When true, data keys are spread onto the root message object.
198
+ * When false, data is nested under the payload field.
199
+ * When omitted, the schema default is used.
200
+ */
201
+ flattenOutgoing?: boolean;
195
202
  }
196
203
  /** Options for fire() — callback-based send. */
197
204
  interface FireOptions {
205
+ /**
206
+ * Override the schema-level `flattenOutgoing` for this call only.
207
+ * When true, data keys are spread onto the root message object.
208
+ * When false, data is nested under the payload field.
209
+ * When omitted, the schema default is used.
210
+ */
211
+ flattenOutgoing?: boolean;
212
+ }
213
+ /** Options for send() — fire-and-forget send. */
214
+ interface SendOptions {
215
+ /**
216
+ * Override the schema-level `flattenOutgoing` for this call only.
217
+ * When true, data keys are spread onto the root message object.
218
+ * When false, data is nested under the payload field.
219
+ * When omitted, the schema default is used.
220
+ */
221
+ flattenOutgoing?: boolean;
198
222
  }
199
223
  /**
200
224
  * Connection state of the transport.
@@ -271,7 +295,7 @@ interface Transport {
271
295
  * Fire-and-forget send.
272
296
  * Use request() for Promise-based responses or fire() for callbacks.
273
297
  */
274
- send<PData = Record<string, unknown>>(msg: OutgoingMessage<PData>): void;
298
+ send<PData = Record<string, unknown>>(msg: OutgoingMessage<PData>, opts?: SendOptions): void;
275
299
  /**
276
300
  * Promise-based send. Resolves on success, rejects on failure or timeout.
277
301
  * Handles interim responses transparently.
@@ -332,8 +356,11 @@ declare function normalizeIncoming(raw: Record<string, unknown>, schema: Resolve
332
356
  * alongside the channel and message ID fields.
333
357
  *
334
358
  * If false, data is nested under the data field name.
359
+ *
360
+ * The optional `flattenOutgoing` parameter overrides the schema-level default
361
+ * for a single call. When omitted, `schema.flattenOutgoing` is used.
335
362
  */
336
- declare function buildOutgoing<PData = Record<string, unknown>>(msg: OutgoingMessage<PData>, messageId: number, schema: ResolvedProtocolSchema): Record<string, unknown>;
363
+ declare function buildOutgoing<PData = Record<string, unknown>>(msg: OutgoingMessage<PData>, messageId: number, schema: ResolvedProtocolSchema, flattenOutgoing?: boolean): Record<string, unknown>;
337
364
 
338
365
  /** Generic typed event emitter. */
339
366
  interface Emitter<TEvents extends object = Record<string, unknown>> {
@@ -393,4 +420,4 @@ declare function createHandlerStore(): HandlerStore;
393
420
  /** A pre-bound Emitter type for transport lifecycle events. */
394
421
  type TransportEmitter = Emitter<TransportEvents>;
395
422
 
396
- export { type Emitter, type FireOptions, type Handler, type HandlerCallback, type HandlerStore, type IncomingMessage, type OutgoingMessage, type ProtocolCodes, type ProtocolFields, type ProtocolSchema, type ReconnectOptions, type RequestOptions, type ResolvedProtocolSchema, type Transport, type TransportEmitter, type TransportError, type TransportEvents, type TransportOptions, type TransportState, buildOutgoing, createEmitter, createHandlerStore, createTransport, normalizeIncoming, resolveSchema };
423
+ export { type Emitter, type FireOptions, type Handler, type HandlerCallback, type HandlerStore, type IncomingMessage, type OutgoingMessage, type ProtocolCodes, type ProtocolFields, type ProtocolSchema, type ReconnectOptions, type RequestOptions, type ResolvedProtocolSchema, type SendOptions, type Transport, type TransportEmitter, type TransportError, type TransportEvents, type TransportOptions, type TransportState, buildOutgoing, createEmitter, createHandlerStore, createTransport, normalizeIncoming, resolveSchema };
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ function normalizeIncoming(raw, schema) {
49
49
  raw
50
50
  };
51
51
  }
52
- function buildOutgoing(msg, messageId, schema) {
52
+ function buildOutgoing(msg, messageId, schema, flattenOutgoing) {
53
53
  const f = schema.fields;
54
54
  const wire = {};
55
55
  if (f.requestChannel) {
@@ -60,7 +60,8 @@ function buildOutgoing(msg, messageId, schema) {
60
60
  }
61
61
  if (msg.data) {
62
62
  const data = msg.data;
63
- if (schema.flattenOutgoing) {
63
+ const shouldFlatten = flattenOutgoing ?? schema.flattenOutgoing;
64
+ if (shouldFlatten) {
64
65
  for (const key of Object.keys(data)) {
65
66
  wire[key] = data[key];
66
67
  }
@@ -327,7 +328,7 @@ function createConnection(deps) {
327
328
  return;
328
329
  }
329
330
  const message = normalizeIncoming(parsed, schema);
330
- log("\u2190", message.channel, message.messageId, message.code);
331
+ log("(Received) \u2190 ", parsed);
331
332
  emitter.emit("message:parsed", message);
332
333
  if (!message.channel && message.messageId === 0) {
333
334
  log("Message missing channel and messageId, dropping");
@@ -402,7 +403,7 @@ function createConnection(deps) {
402
403
  return;
403
404
  }
404
405
  const encoded = schema.encode(payload);
405
- log("\u2192", payload);
406
+ log("(Sent) \u2192", payload);
406
407
  ws.send(encoded);
407
408
  emitter.emit("send:after", { payload });
408
409
  }
@@ -453,10 +454,10 @@ function createTransport(options) {
453
454
  `Failed to generate a unique message ID for channel "${channel}" after ${MAX_ATTEMPTS} attempts. Check your generateId() implementation.`
454
455
  );
455
456
  }
456
- function send(msg) {
457
+ function send(msg, opts) {
457
458
  const channel = resolveChannel(msg);
458
459
  const id = newMessageId(channel);
459
- const wire = buildOutgoing(msg, id, schema);
460
+ const wire = buildOutgoing(msg, id, schema, opts?.flattenOutgoing);
460
461
  connection.send(wire);
461
462
  }
462
463
  function request(msg, opts) {
@@ -508,18 +509,18 @@ function createTransport(options) {
508
509
  ));
509
510
  }, timeout);
510
511
  }
511
- const wire = buildOutgoing(msg, id, schema);
512
+ const wire = buildOutgoing(msg, id, schema, opts?.flattenOutgoing);
512
513
  connection.send(wire);
513
514
  });
514
515
  }
515
- function fire(msg, callback, _opts) {
516
+ function fire(msg, callback, opts) {
516
517
  const channel = resolveChannel(msg);
517
518
  const id = newMessageId(channel);
518
519
  const unsub = handlers.add(channel, id, {
519
520
  type: "ephemeral",
520
521
  callback
521
522
  });
522
- const wire = buildOutgoing(msg, id, schema);
523
+ const wire = buildOutgoing(msg, id, schema, opts?.flattenOutgoing);
523
524
  connection.send(wire);
524
525
  return unsub;
525
526
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/protocol.ts","../src/events.ts","../src/handlers.ts","../src/connection.ts","../src/transport.ts"],"names":["error"],"mappings":"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","file":"index.js","sourcesContent":["// =============================================================================\n// @silas/transport — Protocol\n//\n// Protocol schema helpers for normalizing incoming and building outgoing\n// wire-format messages. Includes `resolveSchema()` which applies sensible\n// defaults so consumers can provide a minimal (or empty) schema.\n// =============================================================================\n\nimport type {\n ProtocolSchema,\n ResolvedProtocolSchema,\n IncomingMessage,\n OutgoingMessage,\n} from './types.js';\n\n// ======================== DEFAULTS ===========================================\n\n/** Cryptographically random 32-bit unsigned integer. */\nfunction defaultGenerateId(): number {\n return crypto.getRandomValues(new Uint32Array(1))[0];\n}\n\nfunction defaultEncode(message: Record<string, unknown>): string {\n return JSON.stringify(message);\n}\n\nfunction defaultDecode(raw: string): Record<string, unknown> | null {\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n// ======================== RESOLVE ============================================\n\n/**\n * Apply defaults to a partial `ProtocolSchema`, producing a fully\n * resolved schema ready for internal use.\n */\nexport function resolveSchema(input?: ProtocolSchema): ResolvedProtocolSchema {\n return {\n fields: input?.fields ?? {},\n codes: input?.codes,\n generateId: input?.generateId ?? defaultGenerateId,\n encode: input?.encode ?? defaultEncode,\n decode: input?.decode ?? defaultDecode,\n flattenOutgoing: input?.flattenOutgoing ?? false,\n includeIdInRequest: input?.includeIdInRequest ?? false,\n };\n}\n\n// ======================== NORMALIZE / BUILD ==================================\n\n/**\n * Transform a raw wire message into the canonical IncomingMessage shape.\n * Reads field names from the protocol schema so the rest of the library\n * can work with a stable, protocol-agnostic structure.\n */\nexport function normalizeIncoming(\n raw: Record<string, unknown>,\n schema: ResolvedProtocolSchema,\n): IncomingMessage {\n const f = schema.fields;\n\n // Channel resolution: responseChannel → subscriptionChannel → '*'\n let channel = '';\n if (f.responseChannel) {\n channel = String(raw[f.responseChannel] ?? '');\n }\n if (!channel && f.subscriptionChannel) {\n channel = String(raw[f.subscriptionChannel] ?? '');\n }\n if (!channel) {\n channel = '*';\n }\n\n const rawId = f.messageId ? Number(raw[f.messageId] ?? 0) : 0;\n const messageId = Number.isNaN(rawId) ? 0 : rawId;\n\n // Event detection: has a resolved channel but no messageId.\n // For events, prefer eventBody over body.\n const isEvent = !messageId && channel !== '*';\n const bodyField = isEvent && f.eventBody ? f.eventBody : f.body;\n\n return {\n channel,\n messageId,\n code: f.code ? String(raw[f.code] ?? '') : '',\n description: f.description ? String(raw[f.description] ?? '') : '',\n error: f.error ? raw[f.error] : undefined,\n data: bodyField ? (raw[bodyField] as Record<string, unknown>) ?? {} : {},\n raw,\n };\n}\n\n/**\n * Build a wire-format message object from an OutgoingMessage.\n *\n * If `flattenOutgoing` is true, data keys are spread onto the root\n * alongside the channel and message ID fields.\n *\n * If false, data is nested under the data field name.\n */\nexport function buildOutgoing<PData = Record<string, unknown>>(\n msg: OutgoingMessage<PData>,\n messageId: number,\n schema: ResolvedProtocolSchema,\n): Record<string, unknown> {\n const f = schema.fields;\n const wire: Record<string, unknown> = {};\n\n // Only include the channel field when the schema defines a requestChannel.\n if (f.requestChannel) {\n wire[f.requestChannel] = msg.channel ?? '*';\n }\n\n // Only include the messageId on the wire when the schema opts in or use a default \"id\" falback field.\n if (schema.includeIdInRequest) {\n wire[f.messageId ?? 'id'] = messageId;\n }\n\n if (msg.data) {\n const data = msg.data as Record<string, unknown>;\n if (schema.flattenOutgoing) {\n // Flatten: spread data keys onto the root object.\n for (const key of Object.keys(data)) {\n wire[key] = data[key];\n }\n } else if (f.payload) {\n // Nested: data goes under its own field.\n wire[f.payload] = data;\n }\n }\n\n return wire;\n}\n","// =============================================================================\n// @silas/transport — Typed Event Emitter\n//\n// Minimal typed emitter (~50 lines). Replaces the 16 hook/set_hook pairs\n// Replaces setter-based hooks (e.g. set_hook / hook pattern)\n// with a standard event system:\n// transport.on('connected', fn) instead of set_al_abrir_conexion(fn)\n// =============================================================================\n\n/** Generic typed event emitter. */\nexport interface Emitter<TEvents extends object = Record<string, unknown>> {\n on<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): () => void;\n\n once<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): () => void;\n\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void;\n\n off<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): void;\n\n removeAll(event?: keyof TEvents): void;\n}\n\ntype Listener = (data: never) => void;\n\n/**\n * Create a minimal typed event emitter.\n *\n * ```ts\n * const ee = createEmitter<TransportEvents>();\n * const unsub = ee.on('connected', (evt) => { ... });\n * ee.emit('connected', evt);\n * unsub(); // or ee.off('connected', callback)\n * ```\n */\nexport function createEmitter<\n TEvents extends object = Record<string, unknown>,\n>(): Emitter<TEvents> {\n const listeners = new Map<keyof TEvents, Set<Listener>>();\n\n function getSet(event: keyof TEvents): Set<Listener> {\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n return set;\n }\n\n function on<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): () => void {\n const set = getSet(event);\n const cb = callback as Listener;\n set.add(cb);\n return () => { set.delete(cb); };\n }\n\n function once<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): () => void {\n const wrapper = (data: TEvents[K]): void => {\n off(event, wrapper);\n callback(data);\n };\n return on(event, wrapper);\n }\n\n function emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n const set = listeners.get(event);\n if (!set) return;\n // Iterate a snapshot so listeners can safely remove themselves.\n for (const cb of [...set]) {\n (cb as (data: TEvents[K]) => void)(data);\n }\n }\n\n function off<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): void {\n const set = listeners.get(event);\n if (set) set.delete(callback as Listener);\n }\n\n function removeAll(event?: keyof TEvents): void {\n if (event !== undefined) {\n listeners.delete(event);\n } else {\n listeners.clear();\n }\n }\n\n return { on, once, emit, off, removeAll };\n}\n","// =============================================================================\n// @silas/transport — Unified Handler Registry\n//\n// Replaces separate persistent and ephemeral handler systems with a single\n// registry.\n//\n// Routing priority:\n// 1. Ephemeral handler matched by (channel, messageId) — exact match\n// 2. Persistent handlers matched by (channel) — all executed\n// 3. If nothing matched → message is unhandled\n//\n// Ephemeral handlers auto-remove after a definitive response (callback\n// returns true or void). Return false to keep alive (interim pattern).\n// =============================================================================\n\nimport type { Handler, IncomingMessage } from './types.js';\n\n// ======================== HANDLER STORE ======================================\n\nexport interface HandlerStore {\n /**\n * Register a handler.\n * - Persistent: key is the handler name (string).\n * - Ephemeral: key is the messageId (number).\n * Returns an unsubscribe function.\n */\n add(channel: string, key: string | number, handler: Handler): () => void;\n\n /** Remove a handler by channel + key. */\n remove(channel: string, key: string | number): boolean;\n\n /**\n * Route an incoming message to the appropriate handler(s).\n * Returns true if at least one handler processed the message.\n */\n execute(message: IncomingMessage): boolean;\n\n /** Check if an ephemeral handler exists for (channel, messageId). */\n hasEphemeral(channel: string, messageId: number): boolean;\n\n /** Look up the channel for a given messageId via the secondary index. */\n findChannelByMessageId(messageId: number): string | undefined;\n\n /** Clear all handlers. */\n clear(): void;\n\n /**\n * Clear stale ephemeral handlers for a given channel (or all channels).\n */\n clearStale(channel?: string): void;\n}\n\n// ======================== IMPLEMENTATION =====================================\n\n/**\n * Create a new handler store.\n *\n * Internal structure:\n * ephemeral: Map< channel, Map< messageId (number), Handler > >\n * persistent: Map< channel, Map< name (string), Handler > >\n */\nexport function createHandlerStore(): HandlerStore {\n const ephemeral = new Map<string, Map<number, Handler>>();\n const persistent = new Map<string, Map<string, Handler>>();\n /** Secondary index: messageId → channel for O(1) ID-only lookups. */\n const idToChannel = new Map<number, string>();\n\n // ---- helpers ----\n\n function getEphemeralMap(channel: string): Map<number, Handler> {\n let map = ephemeral.get(channel);\n if (!map) { map = new Map(); ephemeral.set(channel, map); }\n return map;\n }\n\n function getPersistentMap(channel: string): Map<string, Handler> {\n let map = persistent.get(channel);\n if (!map) { map = new Map(); persistent.set(channel, map); }\n return map;\n }\n\n // ---- public API ----\n\n function add(\n channel: string,\n key: string | number,\n handler: Handler,\n ): () => void {\n if (handler.type === 'ephemeral' && typeof key === 'number') {\n getEphemeralMap(channel).set(key, handler);\n idToChannel.set(key, channel);\n } else if (handler.type === 'persistent' && typeof key === 'string') {\n getPersistentMap(channel).set(key, handler);\n } else {\n throw new Error(\n `Invalid handler registration: type=${handler.type}, key type=${typeof key}. ` +\n `Ephemeral handlers require a numeric key (messageId), persistent require a string key (name).`,\n );\n }\n\n // Return unsubscribe.\n return () => { remove(channel, key); };\n }\n\n function remove(channel: string, key: string | number): boolean {\n if (typeof key === 'number') {\n const map = ephemeral.get(channel);\n if (!map) return false;\n const deleted = map.delete(key);\n if (deleted) idToChannel.delete(key);\n if (map.size === 0) ephemeral.delete(channel);\n return deleted;\n } else {\n const map = persistent.get(channel);\n if (!map) return false;\n const deleted = map.delete(key);\n if (map.size === 0) persistent.delete(channel);\n return deleted;\n }\n }\n\n function execute(message: IncomingMessage): boolean {\n const channel = message.channel;\n const msgId = message.messageId;\n\n // 1. Try ephemeral handler (exact channel + messageId match).\n const ephMap = ephemeral.get(channel);\n if (ephMap && msgId !== 0) {\n const handler = ephMap.get(msgId);\n if (handler) {\n const result = handler.callback(message);\n // Auto-remove unless callback explicitly returns false (interim).\n if (result !== false) {\n ephMap.delete(msgId);\n idToChannel.delete(msgId);\n if (ephMap.size === 0) ephemeral.delete(channel);\n }\n return true;\n }\n }\n\n // 2. Fall through to persistent handlers.\n const perMap = persistent.get(channel);\n if (perMap && perMap.size > 0) {\n for (const handler of perMap.values()) {\n handler.callback(message);\n }\n return true;\n }\n\n // 3. ID-only fallback: response arrived with no channel (or wrong channel)\n // but has a messageId — look up the original channel via secondary index.\n if (msgId !== 0) {\n const resolvedChannel = idToChannel.get(msgId);\n if (resolvedChannel && resolvedChannel !== channel) {\n const fallbackMap = ephemeral.get(resolvedChannel);\n if (fallbackMap) {\n const handler = fallbackMap.get(msgId);\n if (handler) {\n const result = handler.callback(message);\n if (result !== false) {\n fallbackMap.delete(msgId);\n idToChannel.delete(msgId);\n if (fallbackMap.size === 0) ephemeral.delete(resolvedChannel);\n }\n return true;\n }\n }\n }\n }\n\n // 4. Unhandled.\n return false;\n }\n\n function hasEphemeral(channel: string, messageId: number): boolean {\n return ephemeral.get(channel)?.has(messageId) ?? false;\n }\n\n function clear(): void {\n ephemeral.clear();\n persistent.clear();\n idToChannel.clear();\n }\n\n function clearStale(channel?: string): void {\n if (channel) {\n // Remove index entries for this channel's ephemeral handlers.\n const map = ephemeral.get(channel);\n if (map) {\n for (const msgId of map.keys()) {\n idToChannel.delete(msgId);\n }\n }\n ephemeral.delete(channel);\n } else {\n // Clear all ephemeral + index.\n ephemeral.clear();\n idToChannel.clear();\n }\n }\n\n function findChannelByMessageId(messageId: number): string | undefined {\n return idToChannel.get(messageId);\n }\n\n return { add, remove, execute, hasEphemeral, findChannelByMessageId, clear, clearStale };\n}\n","// =============================================================================\n// @silas/transport — Connection Manager\n//\n// Encapsulates all WebSocket lifecycle: connect, disconnect, send, receive,\n// auto-reconnect.\n//\n// Features:\n// - Configurable reconnect (delay, max attempts, backoff)\n// - Event-based lifecycle\n// - Idempotent connect\n// - Stale handler cleanup on disconnect\n// =============================================================================\n\nimport type {\n ResolvedProtocolSchema,\n TransportState,\n TransportEvents,\n ReconnectOptions,\n IncomingMessage,\n} from './types.js';\nimport type { Emitter } from './events.js';\nimport type { HandlerStore } from './handlers.js';\nimport { normalizeIncoming } from './protocol.js';\n\n// ======================== TYPES ==============================================\n\n/** @internal */\nexport interface ConnectionDeps {\n /** Resolved protocol schema. */\n schema: ResolvedProtocolSchema;\n /** Event emitter. */\n emitter: Emitter<TransportEvents>;\n /** Handler store for routing inbound messages. */\n handlers: HandlerStore;\n /** Resolved reconnect config (undefined = disabled). */\n reconnect: Required<ReconnectOptions> | undefined;\n /** URL string or lazy getter. */\n url: string | (() => string);\n /** Debug flag reference (getter so it reads the live value). */\n isDebug: () => boolean;\n}\n\nexport interface Connection {\n connect(): void;\n disconnect(options?: { clean?: boolean }): void;\n send(payload: Record<string, unknown>): void;\n getState(): TransportState;\n destroy(): void;\n}\n\n// ======================== IMPLEMENTATION =====================================\n\n/** WebSocket readyState constants (mirrors the spec). */\nconst WS_CONNECTING = 0;\nconst WS_OPEN = 1;\nconst WS_CLOSING = 2;\nconst WS_CLOSED = 3;\n\nexport function createConnection(deps: ConnectionDeps): Connection {\n const { schema, emitter, handlers } = deps;\n\n let ws: WebSocket | null = null;\n let state: TransportState = 'disconnected';\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempt = 0;\n let destroyed = false;\n\n // ---- helpers ----\n\n function resolveUrl(): string {\n return typeof deps.url === 'function' ? deps.url() : deps.url;\n }\n\n function log(...args: unknown[]): void {\n if (deps.isDebug()) {\n console.log('[silas/transport]', ...args);\n }\n }\n\n function setState(next: TransportState): void {\n state = next;\n }\n\n function clearReconnectTimer(): void {\n if (reconnectTimer !== null) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n }\n\n function computeDelay(): number {\n if (!deps.reconnect) return 0;\n const { delayMs, backoff } = deps.reconnect;\n if (backoff === 'exponential') {\n // Exponential backoff capped at 60s.\n return Math.min(delayMs * Math.pow(2, reconnectAttempt), 60_000);\n }\n return delayMs;\n }\n\n function scheduleReconnect(): void {\n if (!deps.reconnect || !deps.reconnect.auto || destroyed) return;\n if (reconnectAttempt >= deps.reconnect.maxAttempts) {\n log('Max reconnect attempts reached:', deps.reconnect.maxAttempts);\n return;\n }\n\n const delay = computeDelay();\n reconnectAttempt++;\n setState('reconnecting');\n emitter.emit('reconnecting', { attempt: reconnectAttempt, delayMs: delay });\n log(`Reconnecting in ${delay}ms (attempt ${reconnectAttempt})`);\n\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n connect();\n }, delay);\n }\n\n // ---- WebSocket event handlers ----\n\n function onOpen(evt: Event): void {\n reconnectAttempt = 0;\n setState('connected');\n log('Connected');\n emitter.emit('connected', evt);\n }\n\n function onClose(evt: CloseEvent): void {\n ws = null;\n const prev = state;\n setState('disconnected');\n log('Disconnected', evt.code, evt.reason);\n emitter.emit('disconnected', {\n code: evt.code,\n reason: evt.reason,\n wasClean: evt.wasClean,\n });\n\n // Auto-reconnect if not intentionally disconnected.\n if (prev !== 'disconnected' && !destroyed) {\n scheduleReconnect();\n }\n }\n\n function onError(evt: Event): void {\n log('WebSocket error', evt);\n emitter.emit('error', evt);\n }\n\n function onMessage(evt: MessageEvent): void {\n const raw = typeof evt.data === 'string' ? evt.data : String(evt.data);\n emitter.emit('message:raw', { data: raw });\n\n // Decode.\n const parsed = schema.decode(raw);\n if (!parsed) {\n log('Failed to decode message:', raw);\n return;\n }\n\n // Normalize to canonical shape.\n const message: IncomingMessage = normalizeIncoming(parsed, schema);\n log('←', message.channel, message.messageId, message.code);\n emitter.emit('message:parsed', message);\n\n // Validate minimum fields.\n // Allow messages through if they have a channel OR a messageId (for ID-only\n // fallback routing — e.g. responses that omit the channel field).\n if (!message.channel && message.messageId === 0) {\n log('Message missing channel and messageId, dropping');\n return;\n }\n\n // Route to handlers.\n const handled = handlers.execute(message);\n if (handled) {\n log('Handler matched:', message.channel, message.messageId);\n } else {\n emitter.emit('message:unhandled', message);\n log('Unhandled message:', message.channel, message.messageId);\n }\n }\n\n // ---- public API ----\n\n function connect(): void {\n if (destroyed) return;\n\n // Idempotent: don't re-open if already connecting or connected.\n if (ws) {\n const rs = ws.readyState;\n if (rs === WS_OPEN || rs === WS_CONNECTING) {\n log('Already connected/connecting, skipping');\n return;\n }\n }\n\n clearReconnectTimer();\n const url = resolveUrl();\n log('Connecting to', url);\n setState('connecting');\n emitter.emit('connecting', undefined);\n\n try {\n ws = new WebSocket(url);\n } catch (err) {\n log('WebSocket constructor error:', err);\n emitter.emit('error', new Event('error'));\n scheduleReconnect();\n return;\n }\n\n ws.onopen = onOpen;\n ws.onclose = onClose;\n ws.onerror = onError;\n ws.onmessage = onMessage;\n }\n\n function disconnect(options?: { clean?: boolean }): void {\n clearReconnectTimer();\n reconnectAttempt = 0;\n\n if (options?.clean) {\n handlers.clearStale();\n }\n\n if (ws) {\n const rs = ws.readyState;\n if (rs !== WS_CLOSED && rs !== WS_CLOSING) {\n log('Closing WebSocket');\n ws.close();\n }\n ws = null;\n }\n\n setState('disconnected');\n }\n\n function send(payload: Record<string, unknown>): void {\n emitter.emit('send:before', { payload });\n\n if (!ws || ws.readyState !== WS_OPEN) {\n const reason = ws\n ? `WebSocket readyState=${ws.readyState}`\n : 'No WebSocket instance';\n log('Send failed:', reason);\n emitter.emit('send:error', { payload, reason });\n\n // Attempt reconnect on send failure.\n if (!ws || ws.readyState === WS_CLOSED || ws.readyState === WS_CLOSING) {\n if (deps.reconnect?.auto && !destroyed) {\n clearReconnectTimer();\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n connect();\n }, 1_000);\n }\n }\n return;\n }\n\n const encoded = schema.encode(payload);\n log('→', payload);\n ws.send(encoded);\n emitter.emit('send:after', { payload });\n }\n\n function getState(): TransportState {\n return state;\n }\n\n function destroy(): void {\n destroyed = true;\n disconnect();\n handlers.clear();\n }\n\n return { connect, disconnect, send, getState, destroy };\n}\n","// =============================================================================\n// @silas/transport — Main Factory\n//\n// createTransport() composes connection + handlers + events + protocol into\n// the unified Transport API. This is the primary public entry point.\n//\n// Three sending modes:\n// request(msg) → Promise<IncomingMessage> (modern async)\n// fire(msg, callback) → () => void (callback pattern)\n// send(msg) → void (fire-and-forget)\n// =============================================================================\n\nimport type {\n Transport,\n TransportOptions,\n TransportEvents,\n TransportError,\n IncomingMessage,\n OutgoingMessage,\n RequestOptions,\n FireOptions,\n HandlerCallback,\n ReconnectOptions,\n} from './types.js';\nimport { buildOutgoing, resolveSchema } from './protocol.js';\nimport { createEmitter } from './events.js';\nimport { createHandlerStore } from './handlers.js';\nimport { createConnection } from './connection.js';\n\n// ======================== DEFAULT RECONNECT ==================================\n\nconst DEFAULT_RECONNECT: Required<ReconnectOptions> = {\n auto: true,\n delayMs: 10_000,\n maxAttempts: Infinity,\n backoff: 'fixed',\n};\n\n// ======================== FACTORY ============================================\n\n/**\n * Create a Transport instance.\n *\n * ```ts\n * const transport = createTransport({\n * url: 'wss://api.example.com/ws',\n * protocol: myProtocol,\n * });\n *\n * transport.connect();\n * const res = await transport.request({ channel: 'getUser', data: { id: 5 } });\n * ```\n */\nexport function createTransport(options: TransportOptions): Transport {\n // ---- resolve config ----\n const schema = resolveSchema(options.protocol);\n const emitter = createEmitter<TransportEvents>();\n const handlers = createHandlerStore();\n\n let debugEnabled = options.debug ?? false;\n\n const reconnectConfig: Required<ReconnectOptions> | undefined =\n options.reconnect === false\n ? undefined\n : { ...DEFAULT_RECONNECT, ...(options.reconnect ?? {}) };\n\n const connection = createConnection({\n schema,\n emitter,\n handlers,\n reconnect: reconnectConfig,\n url: options.url,\n isDebug: () => debugEnabled,\n });\n\n // ---- generate unique message ID with collision avoidance ----\n\n function resolveChannel(msg: OutgoingMessage<unknown>): string {\n return msg.channel ?? '*';\n }\n\n function newMessageId(channel: string): number {\n const MAX_ATTEMPTS = 10;\n for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {\n const id = schema.generateId();\n if (id > 0 && handlers.findChannelByMessageId(id) === undefined) {\n return id;\n }\n }\n throw new Error(\n `Failed to generate a unique message ID for channel \"${channel}\" after ${MAX_ATTEMPTS} attempts. ` +\n `Check your generateId() implementation.`,\n );\n }\n\n // ---- public API ----\n\n function send<PData = Record<string, unknown>>(msg: OutgoingMessage<PData>): void {\n const channel = resolveChannel(msg);\n const id = newMessageId(channel);\n const wire = buildOutgoing(msg, id, schema);\n connection.send(wire);\n }\n\n function request<BData = Record<string, unknown>, PData = Record<string, unknown>, E = unknown>(\n msg: OutgoingMessage<PData>,\n opts?: RequestOptions,\n ): Promise<IncomingMessage<BData, E>> {\n const timeout = opts?.timeout ?? 30_000;\n\n return new Promise<IncomingMessage<BData, E>>((resolve, reject) => {\n const channel = resolveChannel(msg);\n const id = newMessageId(channel);\n \n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const unsub = handlers.add(channel, id, {\n type: 'ephemeral',\n callback(response: IncomingMessage): boolean | void {\n const codes = schema.codes;\n\n // 1. Interim — keep listening.\n if (codes?.interim && response.code === codes.interim) {\n return false;\n }\n\n // Definitive response — clean up timer.\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n\n // 2. Explicit error match — reject.\n if (codes?.error && codes.error.includes(response.code)) {\n const error: TransportError = {\n code: response.code,\n error: response.error,\n data: response.data,\n response,\n };\n reject(error);\n return; // auto-remove\n }\n\n // 3. Success: explicit match OR no success code defined (treat all as success).\n if (!codes?.success || response.code === codes.success) {\n resolve(response as IncomingMessage<BData, E>);\n return; // auto-remove\n }\n\n // 4. Success code is defined but response doesn't match — treat as error.\n const error: TransportError = {\n code: response.code,\n error: response.error,\n data: response.data,\n response,\n };\n reject(error);\n // Return void → auto-remove handler.\n },\n });\n\n // Timeout.\n if (timeout > 0) {\n timer = setTimeout(() => {\n timer = null;\n unsub();\n reject(new Error(\n `Request timeout after ${timeout}ms: ${channel}`,\n ));\n }, timeout);\n }\n\n // Send.\n const wire = buildOutgoing(msg, id, schema);\n connection.send(wire);\n });\n }\n\n function fire<BData = Record<string, unknown>, PData = Record<string, unknown>, E = unknown>(\n msg: OutgoingMessage<PData>,\n callback: HandlerCallback<BData, E>,\n _opts?: FireOptions,\n ): () => void {\n const channel = resolveChannel(msg);\n const id = newMessageId(channel);\n\n const unsub = handlers.add(channel, id, {\n type: 'ephemeral',\n callback: callback as HandlerCallback,\n });\n\n const wire = buildOutgoing(msg, id, schema);\n connection.send(wire);\n\n return unsub;\n }\n\n function addHandler<BData = Record<string, unknown>, E = unknown>(\n channel: string,\n name: string,\n callback: HandlerCallback<BData, E>,\n ): () => void {\n return handlers.add(channel, name, {\n type: 'persistent',\n callback: callback as HandlerCallback,\n name,\n });\n }\n\n function removeHandler(channel: string, name: string): boolean {\n return handlers.remove(channel, name);\n }\n\n function on<K extends keyof TransportEvents>(\n event: K,\n callback: (data: TransportEvents[K]) => void,\n ): () => void {\n return emitter.on(event, callback);\n }\n\n function once<K extends keyof TransportEvents>(\n event: K,\n callback: (data: TransportEvents[K]) => void,\n ): () => void {\n return emitter.once(event, callback);\n }\n\n function debug(enabled: boolean): void {\n debugEnabled = enabled;\n }\n\n function destroy(): void {\n connection.destroy();\n emitter.removeAll();\n }\n\n // ---- compose the Transport object ----\n\n const transport: Transport = {\n connect: () => connection.connect(),\n disconnect: (opts) => connection.disconnect(opts),\n get state() { return connection.getState(); },\n\n send,\n request,\n fire,\n\n addHandler,\n removeHandler,\n\n on,\n once,\n\n protocol: schema,\n debug,\n destroy,\n };\n\n return transport;\n}\n"]}
1
+ {"version":3,"sources":["../src/protocol.ts","../src/events.ts","../src/handlers.ts","../src/connection.ts","../src/transport.ts"],"names":["error"],"mappings":"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","file":"index.js","sourcesContent":["// =============================================================================\n// @silas/transport — Protocol\n//\n// Protocol schema helpers for normalizing incoming and building outgoing\n// wire-format messages. Includes `resolveSchema()` which applies sensible\n// defaults so consumers can provide a minimal (or empty) schema.\n// =============================================================================\n\nimport type {\n ProtocolSchema,\n ResolvedProtocolSchema,\n IncomingMessage,\n OutgoingMessage,\n} from './types.js';\n\n// ======================== DEFAULTS ===========================================\n\n/** Cryptographically random 32-bit unsigned integer. */\nfunction defaultGenerateId(): number {\n return crypto.getRandomValues(new Uint32Array(1))[0];\n}\n\nfunction defaultEncode(message: Record<string, unknown>): string {\n return JSON.stringify(message);\n}\n\nfunction defaultDecode(raw: string): Record<string, unknown> | null {\n try {\n return JSON.parse(raw) as Record<string, unknown>;\n } catch {\n return null;\n }\n}\n\n// ======================== RESOLVE ============================================\n\n/**\n * Apply defaults to a partial `ProtocolSchema`, producing a fully\n * resolved schema ready for internal use.\n */\nexport function resolveSchema(input?: ProtocolSchema): ResolvedProtocolSchema {\n return {\n fields: input?.fields ?? {},\n codes: input?.codes,\n generateId: input?.generateId ?? defaultGenerateId,\n encode: input?.encode ?? defaultEncode,\n decode: input?.decode ?? defaultDecode,\n flattenOutgoing: input?.flattenOutgoing ?? false,\n includeIdInRequest: input?.includeIdInRequest ?? false,\n };\n}\n\n// ======================== NORMALIZE / BUILD ==================================\n\n/**\n * Transform a raw wire message into the canonical IncomingMessage shape.\n * Reads field names from the protocol schema so the rest of the library\n * can work with a stable, protocol-agnostic structure.\n */\nexport function normalizeIncoming(\n raw: Record<string, unknown>,\n schema: ResolvedProtocolSchema,\n): IncomingMessage {\n const f = schema.fields;\n\n // Channel resolution: responseChannel → subscriptionChannel → '*'\n let channel = '';\n if (f.responseChannel) {\n channel = String(raw[f.responseChannel] ?? '');\n }\n if (!channel && f.subscriptionChannel) {\n channel = String(raw[f.subscriptionChannel] ?? '');\n }\n if (!channel) {\n channel = '*';\n }\n\n const rawId = f.messageId ? Number(raw[f.messageId] ?? 0) : 0;\n const messageId = Number.isNaN(rawId) ? 0 : rawId;\n\n // Event detection: has a resolved channel but no messageId.\n // For events, prefer eventBody over body.\n const isEvent = !messageId && channel !== '*';\n const bodyField = isEvent && f.eventBody ? f.eventBody : f.body;\n\n return {\n channel,\n messageId,\n code: f.code ? String(raw[f.code] ?? '') : '',\n description: f.description ? String(raw[f.description] ?? '') : '',\n error: f.error ? raw[f.error] : undefined,\n data: bodyField ? (raw[bodyField] as Record<string, unknown>) ?? {} : {},\n raw,\n };\n}\n\n/**\n * Build a wire-format message object from an OutgoingMessage.\n *\n * If `flattenOutgoing` is true, data keys are spread onto the root\n * alongside the channel and message ID fields.\n *\n * If false, data is nested under the data field name.\n *\n * The optional `flattenOutgoing` parameter overrides the schema-level default\n * for a single call. When omitted, `schema.flattenOutgoing` is used.\n */\nexport function buildOutgoing<PData = Record<string, unknown>>(\n msg: OutgoingMessage<PData>,\n messageId: number,\n schema: ResolvedProtocolSchema,\n flattenOutgoing?: boolean,\n): Record<string, unknown> {\n const f = schema.fields;\n const wire: Record<string, unknown> = {};\n\n // Only include the channel field when the schema defines a requestChannel.\n if (f.requestChannel) {\n wire[f.requestChannel] = msg.channel ?? '*';\n }\n\n // Only include the messageId on the wire when the schema opts in or use a default \"id\" falback field.\n if (schema.includeIdInRequest) {\n wire[f.messageId ?? 'id'] = messageId;\n }\n\n if (msg.data) {\n const data = msg.data as Record<string, unknown>;\n const shouldFlatten = flattenOutgoing ?? schema.flattenOutgoing;\n if (shouldFlatten) {\n // Flatten: spread data keys onto the root object.\n for (const key of Object.keys(data)) {\n wire[key] = data[key];\n }\n } else if (f.payload) {\n // Nested: data goes under its own field.\n wire[f.payload] = data;\n }\n }\n\n return wire;\n}\n","// =============================================================================\n// @silas/transport — Typed Event Emitter\n//\n// Minimal typed emitter (~50 lines). Replaces the 16 hook/set_hook pairs\n// Replaces setter-based hooks (e.g. set_hook / hook pattern)\n// with a standard event system:\n// transport.on('connected', fn) instead of set_al_abrir_conexion(fn)\n// =============================================================================\n\n/** Generic typed event emitter. */\nexport interface Emitter<TEvents extends object = Record<string, unknown>> {\n on<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): () => void;\n\n once<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): () => void;\n\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void;\n\n off<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): void;\n\n removeAll(event?: keyof TEvents): void;\n}\n\ntype Listener = (data: never) => void;\n\n/**\n * Create a minimal typed event emitter.\n *\n * ```ts\n * const ee = createEmitter<TransportEvents>();\n * const unsub = ee.on('connected', (evt) => { ... });\n * ee.emit('connected', evt);\n * unsub(); // or ee.off('connected', callback)\n * ```\n */\nexport function createEmitter<\n TEvents extends object = Record<string, unknown>,\n>(): Emitter<TEvents> {\n const listeners = new Map<keyof TEvents, Set<Listener>>();\n\n function getSet(event: keyof TEvents): Set<Listener> {\n let set = listeners.get(event);\n if (!set) {\n set = new Set();\n listeners.set(event, set);\n }\n return set;\n }\n\n function on<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): () => void {\n const set = getSet(event);\n const cb = callback as Listener;\n set.add(cb);\n return () => { set.delete(cb); };\n }\n\n function once<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): () => void {\n const wrapper = (data: TEvents[K]): void => {\n off(event, wrapper);\n callback(data);\n };\n return on(event, wrapper);\n }\n\n function emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n const set = listeners.get(event);\n if (!set) return;\n // Iterate a snapshot so listeners can safely remove themselves.\n for (const cb of [...set]) {\n (cb as (data: TEvents[K]) => void)(data);\n }\n }\n\n function off<K extends keyof TEvents>(\n event: K,\n callback: (data: TEvents[K]) => void,\n ): void {\n const set = listeners.get(event);\n if (set) set.delete(callback as Listener);\n }\n\n function removeAll(event?: keyof TEvents): void {\n if (event !== undefined) {\n listeners.delete(event);\n } else {\n listeners.clear();\n }\n }\n\n return { on, once, emit, off, removeAll };\n}\n","// =============================================================================\n// @silas/transport — Unified Handler Registry\n//\n// Replaces separate persistent and ephemeral handler systems with a single\n// registry.\n//\n// Routing priority:\n// 1. Ephemeral handler matched by (channel, messageId) — exact match\n// 2. Persistent handlers matched by (channel) — all executed\n// 3. If nothing matched → message is unhandled\n//\n// Ephemeral handlers auto-remove after a definitive response (callback\n// returns true or void). Return false to keep alive (interim pattern).\n// =============================================================================\n\nimport type { Handler, IncomingMessage } from './types.js';\n\n// ======================== HANDLER STORE ======================================\n\nexport interface HandlerStore {\n /**\n * Register a handler.\n * - Persistent: key is the handler name (string).\n * - Ephemeral: key is the messageId (number).\n * Returns an unsubscribe function.\n */\n add(channel: string, key: string | number, handler: Handler): () => void;\n\n /** Remove a handler by channel + key. */\n remove(channel: string, key: string | number): boolean;\n\n /**\n * Route an incoming message to the appropriate handler(s).\n * Returns true if at least one handler processed the message.\n */\n execute(message: IncomingMessage): boolean;\n\n /** Check if an ephemeral handler exists for (channel, messageId). */\n hasEphemeral(channel: string, messageId: number): boolean;\n\n /** Look up the channel for a given messageId via the secondary index. */\n findChannelByMessageId(messageId: number): string | undefined;\n\n /** Clear all handlers. */\n clear(): void;\n\n /**\n * Clear stale ephemeral handlers for a given channel (or all channels).\n */\n clearStale(channel?: string): void;\n}\n\n// ======================== IMPLEMENTATION =====================================\n\n/**\n * Create a new handler store.\n *\n * Internal structure:\n * ephemeral: Map< channel, Map< messageId (number), Handler > >\n * persistent: Map< channel, Map< name (string), Handler > >\n */\nexport function createHandlerStore(): HandlerStore {\n const ephemeral = new Map<string, Map<number, Handler>>();\n const persistent = new Map<string, Map<string, Handler>>();\n /** Secondary index: messageId → channel for O(1) ID-only lookups. */\n const idToChannel = new Map<number, string>();\n\n // ---- helpers ----\n\n function getEphemeralMap(channel: string): Map<number, Handler> {\n let map = ephemeral.get(channel);\n if (!map) { map = new Map(); ephemeral.set(channel, map); }\n return map;\n }\n\n function getPersistentMap(channel: string): Map<string, Handler> {\n let map = persistent.get(channel);\n if (!map) { map = new Map(); persistent.set(channel, map); }\n return map;\n }\n\n // ---- public API ----\n\n function add(\n channel: string,\n key: string | number,\n handler: Handler,\n ): () => void {\n if (handler.type === 'ephemeral' && typeof key === 'number') {\n getEphemeralMap(channel).set(key, handler);\n idToChannel.set(key, channel);\n } else if (handler.type === 'persistent' && typeof key === 'string') {\n getPersistentMap(channel).set(key, handler);\n } else {\n throw new Error(\n `Invalid handler registration: type=${handler.type}, key type=${typeof key}. ` +\n `Ephemeral handlers require a numeric key (messageId), persistent require a string key (name).`,\n );\n }\n\n // Return unsubscribe.\n return () => { remove(channel, key); };\n }\n\n function remove(channel: string, key: string | number): boolean {\n if (typeof key === 'number') {\n const map = ephemeral.get(channel);\n if (!map) return false;\n const deleted = map.delete(key);\n if (deleted) idToChannel.delete(key);\n if (map.size === 0) ephemeral.delete(channel);\n return deleted;\n } else {\n const map = persistent.get(channel);\n if (!map) return false;\n const deleted = map.delete(key);\n if (map.size === 0) persistent.delete(channel);\n return deleted;\n }\n }\n\n function execute(message: IncomingMessage): boolean {\n const channel = message.channel;\n const msgId = message.messageId;\n\n // 1. Try ephemeral handler (exact channel + messageId match).\n const ephMap = ephemeral.get(channel);\n if (ephMap && msgId !== 0) {\n const handler = ephMap.get(msgId);\n if (handler) {\n const result = handler.callback(message);\n // Auto-remove unless callback explicitly returns false (interim).\n if (result !== false) {\n ephMap.delete(msgId);\n idToChannel.delete(msgId);\n if (ephMap.size === 0) ephemeral.delete(channel);\n }\n return true;\n }\n }\n\n // 2. Fall through to persistent handlers.\n const perMap = persistent.get(channel);\n if (perMap && perMap.size > 0) {\n for (const handler of perMap.values()) {\n handler.callback(message);\n }\n return true;\n }\n\n // 3. ID-only fallback: response arrived with no channel (or wrong channel)\n // but has a messageId — look up the original channel via secondary index.\n if (msgId !== 0) {\n const resolvedChannel = idToChannel.get(msgId);\n if (resolvedChannel && resolvedChannel !== channel) {\n const fallbackMap = ephemeral.get(resolvedChannel);\n if (fallbackMap) {\n const handler = fallbackMap.get(msgId);\n if (handler) {\n const result = handler.callback(message);\n if (result !== false) {\n fallbackMap.delete(msgId);\n idToChannel.delete(msgId);\n if (fallbackMap.size === 0) ephemeral.delete(resolvedChannel);\n }\n return true;\n }\n }\n }\n }\n\n // 4. Unhandled.\n return false;\n }\n\n function hasEphemeral(channel: string, messageId: number): boolean {\n return ephemeral.get(channel)?.has(messageId) ?? false;\n }\n\n function clear(): void {\n ephemeral.clear();\n persistent.clear();\n idToChannel.clear();\n }\n\n function clearStale(channel?: string): void {\n if (channel) {\n // Remove index entries for this channel's ephemeral handlers.\n const map = ephemeral.get(channel);\n if (map) {\n for (const msgId of map.keys()) {\n idToChannel.delete(msgId);\n }\n }\n ephemeral.delete(channel);\n } else {\n // Clear all ephemeral + index.\n ephemeral.clear();\n idToChannel.clear();\n }\n }\n\n function findChannelByMessageId(messageId: number): string | undefined {\n return idToChannel.get(messageId);\n }\n\n return { add, remove, execute, hasEphemeral, findChannelByMessageId, clear, clearStale };\n}\n","// =============================================================================\n// @silas/transport — Connection Manager\n//\n// Encapsulates all WebSocket lifecycle: connect, disconnect, send, receive,\n// auto-reconnect.\n//\n// Features:\n// - Configurable reconnect (delay, max attempts, backoff)\n// - Event-based lifecycle\n// - Idempotent connect\n// - Stale handler cleanup on disconnect\n// =============================================================================\n\nimport type {\n ResolvedProtocolSchema,\n TransportState,\n TransportEvents,\n ReconnectOptions,\n IncomingMessage,\n} from './types.js';\nimport type { Emitter } from './events.js';\nimport type { HandlerStore } from './handlers.js';\nimport { normalizeIncoming } from './protocol.js';\n\n// ======================== TYPES ==============================================\n\n/** @internal */\nexport interface ConnectionDeps {\n /** Resolved protocol schema. */\n schema: ResolvedProtocolSchema;\n /** Event emitter. */\n emitter: Emitter<TransportEvents>;\n /** Handler store for routing inbound messages. */\n handlers: HandlerStore;\n /** Resolved reconnect config (undefined = disabled). */\n reconnect: Required<ReconnectOptions> | undefined;\n /** URL string or lazy getter. */\n url: string | (() => string);\n /** Debug flag reference (getter so it reads the live value). */\n isDebug: () => boolean;\n}\n\nexport interface Connection {\n connect(): void;\n disconnect(options?: { clean?: boolean }): void;\n send(payload: Record<string, unknown>): void;\n getState(): TransportState;\n destroy(): void;\n}\n\n// ======================== IMPLEMENTATION =====================================\n\n/** WebSocket readyState constants (mirrors the spec). */\nconst WS_CONNECTING = 0;\nconst WS_OPEN = 1;\nconst WS_CLOSING = 2;\nconst WS_CLOSED = 3;\n\nexport function createConnection(deps: ConnectionDeps): Connection {\n const { schema, emitter, handlers } = deps;\n\n let ws: WebSocket | null = null;\n let state: TransportState = 'disconnected';\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let reconnectAttempt = 0;\n let destroyed = false;\n\n // ---- helpers ----\n\n function resolveUrl(): string {\n return typeof deps.url === 'function' ? deps.url() : deps.url;\n }\n\n function log(...args: unknown[]): void {\n if (deps.isDebug()) {\n console.log('[silas/transport]', ...args);\n }\n }\n\n function setState(next: TransportState): void {\n state = next;\n }\n\n function clearReconnectTimer(): void {\n if (reconnectTimer !== null) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n }\n\n function computeDelay(): number {\n if (!deps.reconnect) return 0;\n const { delayMs, backoff } = deps.reconnect;\n if (backoff === 'exponential') {\n // Exponential backoff capped at 60s.\n return Math.min(delayMs * Math.pow(2, reconnectAttempt), 60_000);\n }\n return delayMs;\n }\n\n function scheduleReconnect(): void {\n if (!deps.reconnect || !deps.reconnect.auto || destroyed) return;\n if (reconnectAttempt >= deps.reconnect.maxAttempts) {\n log('Max reconnect attempts reached:', deps.reconnect.maxAttempts);\n return;\n }\n\n const delay = computeDelay();\n reconnectAttempt++;\n setState('reconnecting');\n emitter.emit('reconnecting', { attempt: reconnectAttempt, delayMs: delay });\n log(`Reconnecting in ${delay}ms (attempt ${reconnectAttempt})`);\n\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n connect();\n }, delay);\n }\n\n // ---- WebSocket event handlers ----\n\n function onOpen(evt: Event): void {\n reconnectAttempt = 0;\n setState('connected');\n log('Connected');\n emitter.emit('connected', evt);\n }\n\n function onClose(evt: CloseEvent): void {\n ws = null;\n const prev = state;\n setState('disconnected');\n log('Disconnected', evt.code, evt.reason);\n emitter.emit('disconnected', {\n code: evt.code,\n reason: evt.reason,\n wasClean: evt.wasClean,\n });\n\n // Auto-reconnect if not intentionally disconnected.\n if (prev !== 'disconnected' && !destroyed) {\n scheduleReconnect();\n }\n }\n\n function onError(evt: Event): void {\n log('WebSocket error', evt);\n emitter.emit('error', evt);\n }\n\n function onMessage(evt: MessageEvent): void {\n const raw = typeof evt.data === 'string' ? evt.data : String(evt.data);\n emitter.emit('message:raw', { data: raw });\n\n // Decode.\n const parsed = schema.decode(raw);\n if (!parsed) {\n log('Failed to decode message:', raw);\n return;\n }\n\n // Normalize to canonical shape.\n const message: IncomingMessage = normalizeIncoming(parsed, schema);\n log('(Received) ← ', parsed);\n emitter.emit('message:parsed', message);\n\n // Validate minimum fields.\n // Allow messages through if they have a channel OR a messageId (for ID-only\n // fallback routing — e.g. responses that omit the channel field).\n if (!message.channel && message.messageId === 0) {\n log('Message missing channel and messageId, dropping');\n return;\n }\n\n // Route to handlers.\n const handled = handlers.execute(message);\n if (handled) {\n log('Handler matched:', message.channel, message.messageId);\n } else {\n emitter.emit('message:unhandled', message);\n log('Unhandled message:', message.channel, message.messageId);\n }\n }\n\n // ---- public API ----\n\n function connect(): void {\n if (destroyed) return;\n\n // Idempotent: don't re-open if already connecting or connected.\n if (ws) {\n const rs = ws.readyState;\n if (rs === WS_OPEN || rs === WS_CONNECTING) {\n log('Already connected/connecting, skipping');\n return;\n }\n }\n\n clearReconnectTimer();\n const url = resolveUrl();\n log('Connecting to', url);\n setState('connecting');\n emitter.emit('connecting', undefined);\n\n try {\n ws = new WebSocket(url);\n } catch (err) {\n log('WebSocket constructor error:', err);\n emitter.emit('error', new Event('error'));\n scheduleReconnect();\n return;\n }\n\n ws.onopen = onOpen;\n ws.onclose = onClose;\n ws.onerror = onError;\n ws.onmessage = onMessage;\n }\n\n function disconnect(options?: { clean?: boolean }): void {\n clearReconnectTimer();\n reconnectAttempt = 0;\n\n if (options?.clean) {\n handlers.clearStale();\n }\n\n if (ws) {\n const rs = ws.readyState;\n if (rs !== WS_CLOSED && rs !== WS_CLOSING) {\n log('Closing WebSocket');\n ws.close();\n }\n ws = null;\n }\n\n setState('disconnected');\n }\n\n function send(payload: Record<string, unknown>): void {\n emitter.emit('send:before', { payload });\n\n if (!ws || ws.readyState !== WS_OPEN) {\n const reason = ws\n ? `WebSocket readyState=${ws.readyState}`\n : 'No WebSocket instance';\n log('Send failed:', reason);\n emitter.emit('send:error', { payload, reason });\n\n // Attempt reconnect on send failure.\n if (!ws || ws.readyState === WS_CLOSED || ws.readyState === WS_CLOSING) {\n if (deps.reconnect?.auto && !destroyed) {\n clearReconnectTimer();\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n connect();\n }, 1_000);\n }\n }\n return;\n }\n\n const encoded = schema.encode(payload);\n log('(Sent) →', payload);\n ws.send(encoded);\n emitter.emit('send:after', { payload });\n }\n\n function getState(): TransportState {\n return state;\n }\n\n function destroy(): void {\n destroyed = true;\n disconnect();\n handlers.clear();\n }\n\n return { connect, disconnect, send, getState, destroy };\n}\n","// =============================================================================\n// @silas/transport — Main Factory\n//\n// createTransport() composes connection + handlers + events + protocol into\n// the unified Transport API. This is the primary public entry point.\n//\n// Three sending modes:\n// request(msg) → Promise<IncomingMessage> (modern async)\n// fire(msg, callback) → () => void (callback pattern)\n// send(msg) → void (fire-and-forget)\n// =============================================================================\n\nimport type {\n Transport,\n TransportOptions,\n TransportEvents,\n TransportError,\n IncomingMessage,\n OutgoingMessage,\n RequestOptions,\n FireOptions,\n SendOptions,\n HandlerCallback,\n ReconnectOptions,\n} from './types.js';\nimport { buildOutgoing, resolveSchema } from './protocol.js';\nimport { createEmitter } from './events.js';\nimport { createHandlerStore } from './handlers.js';\nimport { createConnection } from './connection.js';\n\n// ======================== DEFAULT RECONNECT ==================================\n\nconst DEFAULT_RECONNECT: Required<ReconnectOptions> = {\n auto: true,\n delayMs: 10_000,\n maxAttempts: Infinity,\n backoff: 'fixed',\n};\n\n// ======================== FACTORY ============================================\n\n/**\n * Create a Transport instance.\n *\n * ```ts\n * const transport = createTransport({\n * url: 'wss://api.example.com/ws',\n * protocol: myProtocol,\n * });\n *\n * transport.connect();\n * const res = await transport.request({ channel: 'getUser', data: { id: 5 } });\n * ```\n */\nexport function createTransport(options: TransportOptions): Transport {\n // ---- resolve config ----\n const schema = resolveSchema(options.protocol);\n const emitter = createEmitter<TransportEvents>();\n const handlers = createHandlerStore();\n\n let debugEnabled = options.debug ?? false;\n\n const reconnectConfig: Required<ReconnectOptions> | undefined =\n options.reconnect === false\n ? undefined\n : { ...DEFAULT_RECONNECT, ...(options.reconnect ?? {}) };\n\n const connection = createConnection({\n schema,\n emitter,\n handlers,\n reconnect: reconnectConfig,\n url: options.url,\n isDebug: () => debugEnabled,\n });\n\n // ---- generate unique message ID with collision avoidance ----\n\n function resolveChannel(msg: OutgoingMessage<unknown>): string {\n return msg.channel ?? '*';\n }\n\n function newMessageId(channel: string): number {\n const MAX_ATTEMPTS = 10;\n for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {\n const id = schema.generateId();\n if (id > 0 && handlers.findChannelByMessageId(id) === undefined) {\n return id;\n }\n }\n throw new Error(\n `Failed to generate a unique message ID for channel \"${channel}\" after ${MAX_ATTEMPTS} attempts. ` +\n `Check your generateId() implementation.`,\n );\n }\n\n // ---- public API ----\n\n function send<PData = Record<string, unknown>>(msg: OutgoingMessage<PData>, opts?: SendOptions): void {\n const channel = resolveChannel(msg);\n const id = newMessageId(channel);\n const wire = buildOutgoing(msg, id, schema, opts?.flattenOutgoing);\n connection.send(wire);\n }\n\n function request<BData = Record<string, unknown>, PData = Record<string, unknown>, E = unknown>(\n msg: OutgoingMessage<PData>,\n opts?: RequestOptions,\n ): Promise<IncomingMessage<BData, E>> {\n const timeout = opts?.timeout ?? 30_000;\n\n return new Promise<IncomingMessage<BData, E>>((resolve, reject) => {\n const channel = resolveChannel(msg);\n const id = newMessageId(channel);\n \n let timer: ReturnType<typeof setTimeout> | null = null;\n\n const unsub = handlers.add(channel, id, {\n type: 'ephemeral',\n callback(response: IncomingMessage): boolean | void {\n const codes = schema.codes;\n\n // 1. Interim — keep listening.\n if (codes?.interim && response.code === codes.interim) {\n return false;\n }\n\n // Definitive response — clean up timer.\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n\n // 2. Explicit error match — reject.\n if (codes?.error && codes.error.includes(response.code)) {\n const error: TransportError = {\n code: response.code,\n error: response.error,\n data: response.data,\n response,\n };\n reject(error);\n return; // auto-remove\n }\n\n // 3. Success: explicit match OR no success code defined (treat all as success).\n if (!codes?.success || response.code === codes.success) {\n resolve(response as IncomingMessage<BData, E>);\n return; // auto-remove\n }\n\n // 4. Success code is defined but response doesn't match — treat as error.\n const error: TransportError = {\n code: response.code,\n error: response.error,\n data: response.data,\n response,\n };\n reject(error);\n // Return void → auto-remove handler.\n },\n });\n\n // Timeout.\n if (timeout > 0) {\n timer = setTimeout(() => {\n timer = null;\n unsub();\n reject(new Error(\n `Request timeout after ${timeout}ms: ${channel}`,\n ));\n }, timeout);\n }\n\n // Send.\n const wire = buildOutgoing(msg, id, schema, opts?.flattenOutgoing);\n connection.send(wire);\n });\n }\n\n function fire<BData = Record<string, unknown>, PData = Record<string, unknown>, E = unknown>(\n msg: OutgoingMessage<PData>,\n callback: HandlerCallback<BData, E>,\n opts?: FireOptions,\n ): () => void {\n const channel = resolveChannel(msg);\n const id = newMessageId(channel);\n\n const unsub = handlers.add(channel, id, {\n type: 'ephemeral',\n callback: callback as HandlerCallback,\n });\n\n const wire = buildOutgoing(msg, id, schema, opts?.flattenOutgoing);\n connection.send(wire);\n\n return unsub;\n }\n\n function addHandler<BData = Record<string, unknown>, E = unknown>(\n channel: string,\n name: string,\n callback: HandlerCallback<BData, E>,\n ): () => void {\n return handlers.add(channel, name, {\n type: 'persistent',\n callback: callback as HandlerCallback,\n name,\n });\n }\n\n function removeHandler(channel: string, name: string): boolean {\n return handlers.remove(channel, name);\n }\n\n function on<K extends keyof TransportEvents>(\n event: K,\n callback: (data: TransportEvents[K]) => void,\n ): () => void {\n return emitter.on(event, callback);\n }\n\n function once<K extends keyof TransportEvents>(\n event: K,\n callback: (data: TransportEvents[K]) => void,\n ): () => void {\n return emitter.once(event, callback);\n }\n\n function debug(enabled: boolean): void {\n debugEnabled = enabled;\n }\n\n function destroy(): void {\n connection.destroy();\n emitter.removeAll();\n }\n\n // ---- compose the Transport object ----\n\n const transport: Transport = {\n connect: () => connection.connect(),\n disconnect: (opts) => connection.disconnect(opts),\n get state() { return connection.getState(); },\n\n send,\n request,\n fire,\n\n addHandler,\n removeHandler,\n\n on,\n once,\n\n protocol: schema,\n debug,\n destroy,\n };\n\n return transport;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silasdevs/transport",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Generic WebSocket transport with injectable protocol schema and unified handler system.",
5
5
  "type": "module",
6
6
  "engines": {