@rdlabo/workers-hono-kit 0.7.2 → 0.8.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 +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.js +0 -1
- package/dist/realtime/index.d.ts +0 -2
- package/dist/realtime/index.js +0 -1
- package/package.json +2 -2
- package/scripts/clean-dist.mjs +3 -0
- package/dist/realtime/legacy-sse.d.ts +0 -25
- package/dist/realtime/legacy-sse.js +0 -110
package/README.md
CHANGED
|
@@ -85,7 +85,6 @@ npm install ai ai-gateway-provider # createAiGatewayProvider
|
|
|
85
85
|
| `DeferExecutor` / `defaultDefer` / `createWaitUntilDefer(ctx)` | Fire-and-forget executor for Workers: `defaultDefer` swallows rejections (tests); `createWaitUntilDefer` registers work via `ctx.waitUntil`. |
|
|
86
86
|
| `configureHibernationAutoResponse` / `upgradeHibernationWebSocket` / `broadcastHibernationWebSockets` | Hibernation WebSocket room primitives: runtime ping/pong without waking JavaScript, attachment-before-accept upgrade, and broadcast through sockets restored by `getWebSockets()`. |
|
|
87
87
|
| `acknowledgeHibernationWebSocketClose` / `closeHibernationWebSocket` | Safe close helpers, including normalization of reserved received-only close codes. |
|
|
88
|
-
| `createLegacySseBridge(options)` | Migration adapter from legacy SSE clients to one or more Hibernation WebSocket rooms. Downstream cancellation aborts pending upgrades and closes late-arriving sockets. |
|
|
89
88
|
| `retryDurableObjectOperation(operation, options?)` / `isRetryableDurableObjectError(error)` | Retry idempotent DO work only for `retryable && !overloaded`, with jittered exponential backoff. `operation` runs per attempt so callers create a fresh stub after an exception. |
|
|
90
89
|
| `createAiGatewayProvider(config)` / `AiGatewayConfig` / `AiGatewayProvider` | Route `@ai-sdk` models through the Cloudflare AI Gateway, via either a Workers `AI` binding or REST credentials (`accountId` / `gateway` / `token`). |
|
|
91
90
|
| `KVCache` / `KVNamespace` / `KVCacheOptions` | Workers-KV cache-aside helper (key `appName+version+table_type_column`, sha256 for string ids, TTL clamped ≥60s). Set `appName` / `version` per application. |
|
package/dist/index.d.ts
CHANGED
|
@@ -49,8 +49,6 @@ export { createSentryErrorReporter } from './http/http-error.js';
|
|
|
49
49
|
export type { SentryExceptionReporterLike } from './http/http-error.js';
|
|
50
50
|
export { acknowledgeHibernationWebSocketClose, broadcastHibernationWebSockets, closeHibernationWebSocket, configureHibernationAutoResponse, upgradeHibernationWebSocket, } from './realtime/hibernation.js';
|
|
51
51
|
export type { HibernationAutoResponseOptions, HibernationUpgradeOptions, HibernationWebSocketLike, HibernationWebSocketStateLike, WebSocketAutoResponsePairFactory, WebSocketPairFactory, } from './realtime/hibernation.js';
|
|
52
|
-
export { createLegacySseBridge } from './realtime/legacy-sse.js';
|
|
53
|
-
export type { LegacySseBridgeOptions, RealtimeDurableObjectNamespaceLike } from './realtime/legacy-sse.js';
|
|
54
52
|
export { isRetryableDurableObjectError, retryDurableObjectOperation } from './realtime/retry.js';
|
|
55
53
|
export type { DurableObjectErrorLike, DurableObjectRetryOptions } from './realtime/retry.js';
|
|
56
54
|
export { KVCache } from './cache/kv-cache.js';
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,6 @@ export { defaultDefer, createWaitUntilDefer } from './http/defer.js';
|
|
|
37
37
|
export { createSentryErrorReporter } from './http/http-error.js';
|
|
38
38
|
// realtime
|
|
39
39
|
export { acknowledgeHibernationWebSocketClose, broadcastHibernationWebSockets, closeHibernationWebSocket, configureHibernationAutoResponse, upgradeHibernationWebSocket, } from './realtime/hibernation.js';
|
|
40
|
-
export { createLegacySseBridge } from './realtime/legacy-sse.js';
|
|
41
40
|
export { isRetryableDurableObjectError, retryDurableObjectOperation } from './realtime/retry.js';
|
|
42
41
|
// cache
|
|
43
42
|
export { KVCache } from './cache/kv-cache.js';
|
package/dist/realtime/index.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export { acknowledgeHibernationWebSocketClose, broadcastHibernationWebSockets, closeHibernationWebSocket, configureHibernationAutoResponse, upgradeHibernationWebSocket, } from './hibernation.js';
|
|
2
2
|
export type { HibernationAutoResponseOptions, HibernationUpgradeOptions, HibernationWebSocketLike, HibernationWebSocketStateLike, WebSocketAutoResponsePairFactory, WebSocketPairFactory, } from './hibernation.js';
|
|
3
|
-
export { createLegacySseBridge } from './legacy-sse.js';
|
|
4
|
-
export type { LegacySseBridgeOptions, RealtimeDurableObjectNamespaceLike } from './legacy-sse.js';
|
|
5
3
|
export { isRetryableDurableObjectError, retryDurableObjectOperation } from './retry.js';
|
|
6
4
|
export type { DurableObjectErrorLike, DurableObjectRetryOptions } from './retry.js';
|
package/dist/realtime/index.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
export { acknowledgeHibernationWebSocketClose, broadcastHibernationWebSockets, closeHibernationWebSocket, configureHibernationAutoResponse, upgradeHibernationWebSocket, } from './hibernation.js';
|
|
2
|
-
export { createLegacySseBridge } from './legacy-sse.js';
|
|
3
2
|
export { isRetryableDurableObjectError, retryDurableObjectOperation } from './retry.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rdlabo/workers-hono-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
73
|
"scripts": {
|
|
74
|
-
"build": "tsc -p tsconfig.build.json",
|
|
74
|
+
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
|
|
75
75
|
"prepare": "npm run build",
|
|
76
76
|
"typecheck": "tsc --noEmit",
|
|
77
77
|
"test": "vitest run",
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/** Minimal Durable Object namespace needed by the legacy SSE bridge. */
|
|
2
|
-
export interface RealtimeDurableObjectNamespaceLike<TId = unknown> {
|
|
3
|
-
idFromName(name: string): TId;
|
|
4
|
-
get(id: TId): {
|
|
5
|
-
fetch(input: string | URL | Request, init?: RequestInit): Promise<Response>;
|
|
6
|
-
};
|
|
7
|
-
}
|
|
8
|
-
/** Options for bridging legacy SSE clients to Hibernation WebSocket rooms. */
|
|
9
|
-
export interface LegacySseBridgeOptions<TId = unknown> {
|
|
10
|
-
namespace: RealtimeDurableObjectNamespaceLike<TId>;
|
|
11
|
-
roomNames: readonly string[];
|
|
12
|
-
signal: AbortSignal;
|
|
13
|
-
protocol: string;
|
|
14
|
-
clientId?: string;
|
|
15
|
-
heartbeatMs?: number;
|
|
16
|
-
pong?: string;
|
|
17
|
-
connectUrl?: string;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Bridge legacy SSE clients to one or more Hibernation WebSocket rooms.
|
|
21
|
-
*
|
|
22
|
-
* The heartbeat lives in the outer Worker only; Durable Objects remain hibernatable. Aborting the
|
|
23
|
-
* downstream request also aborts pending upgrades, including the late-upgrade race during teardown.
|
|
24
|
-
*/
|
|
25
|
-
export declare function createLegacySseBridge<TId>(options: LegacySseBridgeOptions<TId>): Response;
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bridge legacy SSE clients to one or more Hibernation WebSocket rooms.
|
|
3
|
-
*
|
|
4
|
-
* The heartbeat lives in the outer Worker only; Durable Objects remain hibernatable. Aborting the
|
|
5
|
-
* downstream request also aborts pending upgrades, including the late-upgrade race during teardown.
|
|
6
|
-
*/
|
|
7
|
-
export function createLegacySseBridge(options) {
|
|
8
|
-
const encoder = new TextEncoder();
|
|
9
|
-
const sockets = new Set();
|
|
10
|
-
const heartbeatMs = options.heartbeatMs ?? 25_000;
|
|
11
|
-
const pong = options.pong ?? 'pong';
|
|
12
|
-
const connectUrl = options.connectUrl ?? 'https://do/connect';
|
|
13
|
-
let heartbeat;
|
|
14
|
-
let closeStream;
|
|
15
|
-
const stream = new ReadableStream({
|
|
16
|
-
start(controller) {
|
|
17
|
-
let closed = false;
|
|
18
|
-
const upstreamAbort = new AbortController();
|
|
19
|
-
const close = () => {
|
|
20
|
-
if (closed) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
closed = true;
|
|
24
|
-
upstreamAbort.abort();
|
|
25
|
-
if (heartbeat) {
|
|
26
|
-
clearInterval(heartbeat);
|
|
27
|
-
}
|
|
28
|
-
for (const socket of sockets) {
|
|
29
|
-
try {
|
|
30
|
-
socket.close(1000, 'legacy SSE closed');
|
|
31
|
-
}
|
|
32
|
-
catch {
|
|
33
|
-
// already closed
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
sockets.clear();
|
|
37
|
-
try {
|
|
38
|
-
controller.close();
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
// already closed
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
closeStream = close;
|
|
45
|
-
if (options.signal.aborted) {
|
|
46
|
-
close();
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
options.signal.addEventListener('abort', close, { once: true });
|
|
50
|
-
heartbeat = setInterval(() => {
|
|
51
|
-
try {
|
|
52
|
-
controller.enqueue(encoder.encode('event: ping\ndata: ping\n\n'));
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
close();
|
|
56
|
-
}
|
|
57
|
-
}, heartbeatMs);
|
|
58
|
-
const connect = async (roomName) => {
|
|
59
|
-
const id = options.namespace.idFromName(roomName);
|
|
60
|
-
const response = (await options.namespace.get(id).fetch(connectUrl, {
|
|
61
|
-
signal: upstreamAbort.signal,
|
|
62
|
-
headers: {
|
|
63
|
-
Upgrade: 'websocket',
|
|
64
|
-
'Sec-WebSocket-Protocol': options.protocol,
|
|
65
|
-
...(options.clientId ? { 'x-client-id': options.clientId } : {}),
|
|
66
|
-
},
|
|
67
|
-
}));
|
|
68
|
-
const socket = response.webSocket;
|
|
69
|
-
if (response.status !== 101 || !socket) {
|
|
70
|
-
socket?.close(1011, 'legacy SSE upgrade failed');
|
|
71
|
-
throw new Error('Legacy realtime WebSocket upgrade failed');
|
|
72
|
-
}
|
|
73
|
-
if (closed) {
|
|
74
|
-
socket.close(1000, 'legacy SSE already closed');
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
sockets.add(socket);
|
|
78
|
-
socket.accept();
|
|
79
|
-
socket.addEventListener('message', ({ data }) => {
|
|
80
|
-
if (typeof data !== 'string' || data === pong) {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
try {
|
|
84
|
-
const parsed = JSON.parse(data);
|
|
85
|
-
for (const event of Array.isArray(parsed) ? parsed : [parsed]) {
|
|
86
|
-
controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`));
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
// Ignore malformed upstream messages.
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
socket.addEventListener('close', close, { once: true });
|
|
94
|
-
socket.addEventListener('error', close, { once: true });
|
|
95
|
-
};
|
|
96
|
-
void Promise.all(options.roomNames.map((roomName) => connect(roomName))).catch(close);
|
|
97
|
-
},
|
|
98
|
-
cancel() {
|
|
99
|
-
closeStream?.();
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
return new Response(stream, {
|
|
103
|
-
headers: {
|
|
104
|
-
'Content-Type': 'text/event-stream',
|
|
105
|
-
'Cache-Control': 'no-cache',
|
|
106
|
-
Connection: 'keep-alive',
|
|
107
|
-
'X-Accel-Buffering': 'no',
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
}
|