@coderbuzz/ken 0.1.4 → 0.2.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.
@@ -75,6 +75,12 @@ function createDenoWsHandler(handler, options = {}) {
75
75
  const peers = /* @__PURE__ */ new Set();
76
76
  let heartbeatInterval = null;
77
77
  async function handleUpgrade(req, info) {
78
+ let clientHostname;
79
+ try {
80
+ clientHostname = info.remoteAddr.hostname;
81
+ } catch {
82
+ clientHostname = "unknown";
83
+ }
78
84
  let data = void 0;
79
85
  if (handler.upgrade) {
80
86
  try {
@@ -88,7 +94,7 @@ function createDenoWsHandler(handler, options = {}) {
88
94
  }
89
95
  }
90
96
  const { socket, response } = Deno.upgradeWebSocket(req);
91
- const peer = new DenoWsPeer(socket, data, hub, info.remoteAddr.hostname);
97
+ const peer = new DenoWsPeer(socket, data, hub, clientHostname);
92
98
  peers.add(peer);
93
99
  socket.onopen = () => {
94
100
  try {
@@ -247,4 +253,4 @@ function server({ port, hostname, router }) {
247
253
  export {
248
254
  server
249
255
  };
250
- //# sourceMappingURL=deno-LZU5JBGL.js.map
256
+ //# sourceMappingURL=deno-DV3633IH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ws/deno.ts","../src/runtime/deno.ts"],"sourcesContent":["/**\n * Ken Framework - Deno WebSocket Adapter\n * Uses Deno's native WebSocket upgrade support\n * \n * MIT License - Copyright (c) 2025 Indra Gunawan\n */\n\nimport {\n type WsPeer,\n type WsHandler,\n type WsOptions,\n type WsMessageData,\n type WsReadyStateValue,\n WsReadyState,\n WS_DEFAULTS,\n} from './types';\n\ndeclare const Deno: any;\nimport { PubSubHub, type PubSubPeer } from './pubsub';\n\n// ==================== DenoWsPeer ====================\n\n/** Pre-allocated app-level ping payload — reused across all heartbeat calls */\nconst DENO_PING_MSG = '{\"type\":\"ping\"}';\n\n/**\n * Deno WebSocket peer.\n * Wraps a standard WebSocket instance with Ken's peer interface and pub/sub.\n *\n * NOTE: Deno's WebSocket follows the DOM spec which does not expose protocol-level\n * ping/pong control frames. As a result:\n * - ping() sends an application-level {\"type\":\"ping\"} message (app-level keepalive)\n * - pong() is a no-op (no protocol pong to send)\n * - WsHandler.ping / WsHandler.pong callbacks are NEVER called on Deno\n */\nclass DenoWsPeer<T> implements WsPeer<T>, PubSubPeer {\n public data: T;\n public remoteAddress: string;\n /** Timestamp of last received message — used for heartbeat dead-peer detection */\n public lastActivity: number = Date.now();\n\n private ws: WebSocket;\n private hub: PubSubHub;\n\n constructor(ws: WebSocket, data: T, hub: PubSubHub, remoteAddress: string) {\n this.ws = ws;\n this.data = data;\n this.hub = hub;\n this.remoteAddress = remoteAddress;\n }\n\n get readyState(): WsReadyStateValue {\n return this.ws.readyState as WsReadyStateValue;\n }\n\n send(data: WsMessageData, _compress?: boolean): number {\n try {\n this.ws.send(data as any);\n return typeof data === 'string' ? data.length : (data as ArrayBuffer | Uint8Array).byteLength;\n } catch {\n return -1;\n }\n }\n\n close(code?: number, reason?: string): void {\n try {\n this.ws.close(code, reason);\n } catch { /* ignore */ }\n }\n\n subscribe(topic: string): void {\n this.hub.subscribe(this, topic);\n }\n\n unsubscribe(topic: string): void {\n this.hub.unsubscribe(this, topic);\n }\n\n publish(topic: string, data: WsMessageData, compress?: boolean): void {\n this.hub.publish(this, topic, data, compress);\n }\n\n isSubscribed(topic: string): boolean {\n return this.hub.isSubscribed(this, topic);\n }\n\n ping(_data?: WsMessageData): void {\n // Deno's DOM WebSocket does not expose protocol-level PING frames.\n // Send an application-level keepalive message. Clients using Ken's WSClient\n // (or any client that handles {\"type\":\"ping\"}) will respond with {\"type\":\"pong\"}.\n if (this.ws.readyState !== 1 /* OPEN */) return;\n try {\n this.ws.send(DENO_PING_MSG);\n } catch { /* ignore */ }\n }\n\n pong(_data?: WsMessageData): void {\n // Deno's DOM WebSocket does not expose protocol-level PONG frames.\n // handler.pong is never triggered on Deno — see class comment.\n }\n}\n\n// ==================== Deno WebSocket Handler ====================\n\n/**\n * Create a Deno WebSocket upgrade handler.\n * Called by the Deno runtime adapter.\n */\nexport function createDenoWsHandler<T>(\n handler: WsHandler<T>,\n options: WsOptions = {},\n): {\n hub: PubSubHub;\n peers: Set<DenoWsPeer<T>>;\n handleUpgrade: (req: Request, info: { remoteAddr: { hostname: string; }; }) => Promise<Response>;\n startHeartbeat: () => void;\n stopHeartbeat: () => void;\n} {\n const opts: Required<WsOptions> = { ...WS_DEFAULTS, ...options };\n const hub = new PubSubHub();\n const peers = new Set<DenoWsPeer<T>>();\n\n let heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n\n async function handleUpgrade(req: Request, info: { remoteAddr: { hostname: string; }; }): Promise<Response> {\n // Capture remoteAddr early before upgradeWebSocket closes the request\n let clientHostname: string;\n try {\n clientHostname = info.remoteAddr.hostname;\n } catch {\n clientHostname = 'unknown';\n }\n\n // Run upgrade handler if provided\n let data: T = undefined as T;\n if (handler.upgrade) {\n try {\n const result = await handler.upgrade(req);\n if (result instanceof Response) {\n return result;\n }\n data = result;\n } catch {\n return new Response('Upgrade failed', { status: 500 });\n }\n }\n\n // Perform the upgrade using Deno.upgradeWebSocket\n const { socket, response } = (Deno as any).upgradeWebSocket(req);\n\n const peer = new DenoWsPeer<T>(socket, data, hub, clientHostname);\n peers.add(peer);\n\n socket.onopen = () => {\n try {\n handler.open?.(peer);\n } catch { /* ignore */ }\n };\n\n socket.onmessage = (event: MessageEvent) => {\n // Update last-activity timestamp for dead peer detection\n peer.lastActivity = Date.now();\n // Update hub liveness — on Deno any inbound message counts as alive\n // since protocol-level pong is unavailable\n hub.markAlive(peer);\n try {\n handler.message(peer, event.data);\n } catch { /* ignore */ }\n };\n\n socket.onclose = (event: CloseEvent) => {\n peers.delete(peer);\n hub.removeAll(peer);\n try {\n handler.close?.(peer, event.code, event.reason);\n } catch { /* ignore */ }\n };\n\n socket.onerror = (_event: Event) => {\n try {\n handler.error?.(peer, new Error('WebSocket error'));\n } catch { /* ignore */ }\n };\n\n return response;\n }\n\n function startHeartbeat(): void {\n if (opts.pingInterval <= 0) return;\n if (heartbeatInterval) return;\n\n // Dead peer threshold: no message received within pingInterval + pongTimeout seconds.\n // Since Deno cannot do protocol ping/pong, we track last inbound message time.\n const deadThresholdMs = (opts.pingInterval + opts.pongTimeout) * 1000;\n\n heartbeatInterval = setInterval(() => {\n const now = Date.now();\n for (const peer of peers) {\n if (peer.readyState !== WsReadyState.OPEN) {\n peers.delete(peer);\n hub.removeAll(peer);\n continue;\n }\n // Close peers that have been silent longer than the dead threshold.\n // Note: this only catches peers that never send messages; a purely\n // listening peer is indistinguishable from a dead one on Deno without\n // protocol-level ping/pong. Use Ken's WSClient for reliable liveness.\n if (now - peer.lastActivity > deadThresholdMs) {\n try { peer.close(1001, 'ping timeout'); } catch { /* ignore */ }\n peers.delete(peer);\n hub.removeAll(peer);\n continue;\n }\n // Send app-level ping — clients can reply with {\"type\":\"pong\"}\n peer.ping();\n }\n }, opts.pingInterval * 1000);\n }\n\n function stopHeartbeat(): void {\n if (heartbeatInterval) {\n clearInterval(heartbeatInterval);\n heartbeatInterval = null;\n }\n }\n\n return { hub, peers, handleUpgrade, startHeartbeat, stopHeartbeat };\n}\n","/**\n * Ken Framework - Deno Runtime\n * Uses Web Standard APIs natively\n * \n * MIT License - Copyright (c) 2025 Indra Gunawan\n */\n\nimport { Router } from '../core/router';\nimport { WebContext } from '../context/web';\nimport { type Schema, type GetRemoteInfo } from '../context/types';\nimport { createExecutor, createNotFoundExecutor, type ContextFactory } from './compiler';\nimport { toResponse } from '../utils/response';\nimport { getPathname } from '../utils/pathname';\nimport { type WsRoute } from '../ws/types';\nimport { createDenoWsHandler } from '../ws/deno';\n\ndeclare const Deno: {\n serve(options: {\n port?: number;\n hostname?: string;\n signal?: AbortSignal;\n onListen?: (event: { hostname: string; port: number; }) => void;\n }, handler: (request: Request, info: { remoteAddr: { hostname: string; port: number; }; }) => Response | Promise<Response>): void;\n};\n\n/**\n * WebContext factory for Deno runtime\n */\nconst webContextFactory: ContextFactory<Request, WebContext> = (\n req: Request,\n params: Record<string, string>,\n getRemoteInfo: GetRemoteInfo,\n schema?: Schema\n) => new WebContext(req, params, getRemoteInfo, schema);\n\nexport function server({ port, hostname, router }: {\n port?: number;\n hostname?: string;\n router: Router;\n}) {\n let ac: AbortController | undefined = undefined;\n\n // Compile routes with executors\n const compiledRouter = new Router();\n\n for (const route of router.routes) {\n // Get merged schema\n let mergedSchema = route.schema;\n if (typeof (router as any).matchMiddleware === 'function' && typeof (router as any).mergeSchemas === 'function') {\n const matchedMiddleware = (router as any).matchMiddleware(route.path);\n mergedSchema = (router as any).mergeSchemas(matchedMiddleware, route.schema);\n }\n\n if (route.handler) {\n const nativeHandler = createExecutor(webContextFactory, route.handler, mergedSchema);\n compiledRouter.registerCompiled(route.method, route.path, nativeHandler, mergedSchema);\n } else if (route.staticValue !== undefined) {\n const cachedResponse = toResponse(route.staticValue);\n compiledRouter.registerCompiled(route.method, route.path, () => cachedResponse.clone(), mergedSchema, cachedResponse);\n }\n }\n\n // Hoist matcher\n const match = compiledRouter.matcher();\n\n // Pre-compile 404 handler with global middleware\n const notFoundExecutor = createNotFoundExecutor(router, webContextFactory);\n const NOT_FOUND_RESPONSE = new Response('Not Found', { status: 404 });\n\n // WebSocket routes\n const wsRoutes: WsRoute<any>[] = (router as any).wsRoutes || [];\n const wsHandlers = new Map<string, ReturnType<typeof createDenoWsHandler>>();\n for (const wsRoute of wsRoutes) {\n wsHandlers.set(wsRoute.path, createDenoWsHandler(wsRoute.handler, wsRoute.options));\n }\n\n return {\n async run(): Promise<{ hostname: string; port: number; }> {\n ac?.abort();\n ac = new AbortController();\n\n // Start heartbeat for all WS handlers\n for (const wsHandler of wsHandlers.values()) {\n wsHandler.startHeartbeat();\n }\n\n return new Promise((resolve) => {\n Deno.serve({\n port,\n hostname,\n signal: ac?.signal,\n onListen: ({ hostname, port }) => {\n resolve({ hostname, port });\n },\n }, (request, info) => {\n const pathname = getPathname(request.url);\n\n // Check for WebSocket upgrade\n if (request.headers.get('upgrade') === 'websocket') {\n const wsHandler = wsHandlers.get(pathname);\n if (wsHandler) {\n return wsHandler.handleUpgrade(request, info);\n }\n return new Response('Not Found', { status: 404 });\n }\n\n const matchResult = match(request.method, pathname);\n\n if (matchResult !== undefined) {\n // Fast path: static route (skip getRemoteInfo, handler call, toResponse)\n if (matchResult.response !== undefined) {\n return matchResult.response.clone();\n }\n\n // Dynamic route\n const getRemoteInfo: GetRemoteInfo = () => ({\n address: info.remoteAddr.hostname,\n port: info.remoteAddr.port,\n });\n\n const result = matchResult.handler(request, matchResult.params, getRemoteInfo);\n\n // Handle async results\n if (result && typeof result.then === 'function') {\n return result.then(toResponse);\n }\n return toResponse(result);\n }\n\n // Execute 404 with middleware if available\n if (notFoundExecutor) {\n const getRemoteInfo: GetRemoteInfo = () => ({\n address: info.remoteAddr.hostname,\n port: info.remoteAddr.port,\n });\n const result = notFoundExecutor(request, getRemoteInfo, pathname);\n if (result && typeof result.then === 'function') {\n return result.then(toResponse);\n }\n return toResponse(result);\n }\n\n return NOT_FOUND_RESPONSE.clone();\n });\n });\n },\n\n stop() {\n for (const wsHandler of wsHandlers.values()) {\n wsHandler.stopHeartbeat();\n }\n ac?.abort('STOP');\n ac = undefined;\n }\n };\n}\n\n// console.log('Deno runtime module loaded.');"],"mappings":"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","names":["hostname","port"]}
package/dist/index.d.ts CHANGED
@@ -905,59 +905,57 @@ declare function memoize<Args extends unknown[], R>(fn: (...args: Args) => R, op
905
905
  * Output is base64url-encoded (no +, /, or = characters) — safe for
906
906
  * cookies, URLs, and JSON values without escaping.
907
907
  *
908
- * Default format is `brotli` — best compression ratio for cookie/session
909
- * storage where every byte counts.
908
+ * Default format is `gzip` — standard Web API `CompressionFormat`,
909
+ * compatible with all runtimes including Deno Deploy.
910
910
  *
911
911
  * MIT License - Copyright (c) 2025 Indra Gunawan
912
912
  */
913
- /** Supported compression formats — extends the Web Standard with brotli (supported by Bun, Node.js, Deno). */
914
- type SupportedCompressionFormat = CompressionFormat | 'brotli';
913
+ /** Supported compression formats — standard Web API `CompressionFormat`. */
914
+ type SupportedCompressionFormat = CompressionFormat;
915
915
  /**
916
916
  * Options for {@link compressString}.
917
917
  *
918
918
  * The `level` range depends on the chosen `encoding`:
919
- * - **`brotli`**: 0–11 (default: `11` — best compression, slowest)
920
919
  * - **`deflate` / `gzip` / `deflate-raw`**: 0–9 (default: runtime default, typically `6`)
921
920
  *
922
921
  * Lower values = faster encoding + larger output.
923
922
  * Higher values = slower encoding + smaller output.
924
923
  */
925
924
  interface CompressOptions$1 {
926
- /** Compression format. Default: `'brotli'`. */
925
+ /** Compression format. Default: `'gzip'`. */
927
926
  encoding?: SupportedCompressionFormat;
928
927
  /**
929
928
  * Compression quality level.
930
- * - brotli: 0–11 (default 11)
931
929
  * - deflate / gzip / deflate-raw: 0–9 (default ~6)
932
930
  */
933
931
  level?: number;
934
932
  }
935
933
  /** Options for {@link decompressString}. */
936
934
  interface DecompressOptions {
937
- /** Compression format used during compression. Default: `'brotli'`. */
935
+ /** Compression format used during compression. Default: `'gzip'`. */
938
936
  encoding?: SupportedCompressionFormat;
939
937
  }
940
938
  /**
941
939
  * Compress a string and return a base64url-encoded result.
942
940
  * Output is safe for cookies, URLs, and JSON values (no +, /, or = characters).
943
941
  *
944
- * Uses `brotli` by default for best compression ratio produces smaller
945
- * output than `deflate` or `gzip`, ideal for cookie/session storage.
942
+ * Uses `gzip` by default a standard Web API `CompressionFormat`
943
+ * compatible with all runtimes including Deno Deploy.
946
944
  *
947
945
  * @param input - The string to compress
948
- * @param options - Compression options: `encoding` (default `'brotli'`) and optional `level`
946
+ * @param options - Compression options: `encoding` (default `'gzip'`) and optional `level`
949
947
  * @returns Base64url-encoded compressed string
950
948
  *
951
949
  * @example
952
950
  * ```ts
953
- * // Best compression (default brotli)
951
+ * // Default gzip
954
952
  * const compressed = await compressString('Hello, World!');
955
953
  *
956
- * // Faster, lighter brotli
957
- * const fast = await compressString('Hello, World!', { level: 4 });
958
- *
959
954
  * // gzip with max compression
960
955
  * const gz = await compressString('Hello, World!', { encoding: 'gzip', level: 9 });
956
+ *
957
+ * // deflate
958
+ * const df = await compressString('Hello, World!', { encoding: 'deflate' });
961
959
  * ```
962
960
  */
963
961
  declare function compressString(input: string, options?: CompressOptions$1): Promise<string>;
@@ -965,7 +963,7 @@ declare function compressString(input: string, options?: CompressOptions$1): Pro
965
963
  * Decompress a base64url-encoded compressed string back to the original.
966
964
  *
967
965
  * @param compressed - Base64url-encoded compressed string from {@link compressString}
968
- * @param options - Decompression options: `encoding` must match what was used to compress (default `'brotli'`)
966
+ * @param options - Decompression options: `encoding` must match what was used to compress (default `'gzip'`)
969
967
  * @returns The original decompressed string
970
968
  *
971
969
  * @example
@@ -973,7 +971,7 @@ declare function compressString(input: string, options?: CompressOptions$1): Pro
973
971
  * const original = await decompressString(compressed);
974
972
  * // 'Hello, World!'
975
973
  *
976
- * const original = await decompressString(compressed, { encoding: 'gzip' });
974
+ * const original = await decompressString(compressed, { encoding: 'deflate' });
977
975
  * ```
978
976
  */
979
977
  declare function decompressString(compressed: string, options?: DecompressOptions): Promise<string>;
package/dist/index.js CHANGED
@@ -425,7 +425,7 @@ async function resolveNodeRuntime() {
425
425
  }
426
426
  async function server(options) {
427
427
  if (isDeno) {
428
- const { server: server2 } = await import("./deno-LZU5JBGL.js");
428
+ const { server: server2 } = await import("./deno-DV3633IH.js");
429
429
  return server2(options);
430
430
  }
431
431
  if (isBun) {
@@ -729,7 +729,7 @@ async function readAllBytes(readable) {
729
729
  return result;
730
730
  }
731
731
  async function compressString(input, options) {
732
- const encoding = options?.encoding ?? "brotli";
732
+ const encoding = options?.encoding ?? "gzip";
733
733
  const cs = options?.level !== void 0 ? new CompressionStream(encoding, { level: options.level }) : new CompressionStream(encoding);
734
734
  const writer = cs.writable.getWriter();
735
735
  writer.write(encoder.encode(input)).catch(() => {
@@ -739,7 +739,7 @@ async function compressString(input, options) {
739
739
  return encodeBase64Url(await readAllBytes(cs.readable));
740
740
  }
741
741
  async function decompressString(compressed, options) {
742
- const encoding = options?.encoding ?? "brotli";
742
+ const encoding = options?.encoding ?? "gzip";
743
743
  const ds = new DecompressionStream(encoding);
744
744
  const writer = ds.writable.getWriter();
745
745
  writer.write(decodeBase64Url(compressed)).catch(() => {