@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.
- package/README.md +683 -56
- package/dist/README.md +683 -56
- package/dist/{deno-LZU5JBGL.js → deno-DV3633IH.js} +8 -2
- package/dist/deno-DV3633IH.js.map +1 -0
- package/dist/index.d.ts +15 -17
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/package.json +2 -2
- package/package.json +2 -2
- package/dist/deno-LZU5JBGL.js.map +0 -1
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coderbuzz/ken",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"import": "./index.js"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
|
-
"description": "The modern standard for TypeScript backends
|
|
13
|
+
"description": "The modern standard for TypeScript backends - runtime-agnostic HTTP framework for Bun, Node.js, and Deno.",
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"keywords": [
|
|
16
16
|
"http",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coderbuzz/ken",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "The modern standard for TypeScript backends
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "The modern standard for TypeScript backends - runtime-agnostic HTTP framework for Bun, Node.js, and Deno.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"http",
|
|
@@ -1 +0,0 @@
|
|
|
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 // 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, info.remoteAddr.hostname);\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"]}
|