void 0.7.3 → 0.7.4
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/dist/{better-auth-shared-APuDaPqW.mjs → better-auth-shared-BrfZ78iY.mjs} +55 -5
- package/dist/cli/cli.mjs +8 -8
- package/dist/{db-ClNu7vYQ.mjs → db-RqxhOT2E.mjs} +1 -1
- package/dist/{deploy-BkjqNk9U.mjs → deploy-CRIz77mw.mjs} +243 -56
- package/dist/index.mjs +56 -22
- package/dist/{init-CPny6w9D.mjs → init-FMZ29UZW.mjs} +2 -2
- package/dist/{plugin-inference-oZ6Ybu2_.mjs → plugin-inference-CCtRkt9O.mjs} +41 -12
- package/dist/{prepare-DKkx-2Kt.mjs → prepare-PqAbhLte.mjs} +2 -2
- package/dist/{preset-DFvePt0l.mjs → preset-jKn1hQwP.mjs} +1 -1
- package/dist/runtime/better-auth-pg.mjs +1 -1
- package/dist/runtime/better-auth.mjs +1 -1
- package/dist/runtime/live-client.d.mts +34 -0
- package/dist/runtime/live-client.mjs +283 -0
- package/dist/runtime/live-server.d.mts +13 -0
- package/dist/runtime/live-server.mjs +417 -0
- package/dist/runtime/live.d.mts +107 -0
- package/dist/runtime/live.mjs +409 -0
- package/dist/runtime/migration-handler.mjs +34 -1
- package/dist/runtime/sse-client.d.mts +22 -0
- package/dist/runtime/sse-client.mjs +36 -0
- package/dist/runtime/sse.d.mts +35 -0
- package/dist/runtime/sse.mjs +172 -0
- package/dist/{scan-C6HMEIdW.mjs → scan-QtRTdh94.mjs} +1 -1
- package/package.json +27 -2
- package/skills/void/docs/guide/live.md +230 -0
- package/skills/void/docs/guide/sse.md +187 -0
- package/skills/void/docs/index.md +12 -15
- package/skills/void/docs/reference/api.md +4 -0
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
//#region src/runtime/live-client.ts
|
|
2
|
+
function connectLiveStream(url, options = {}) {
|
|
3
|
+
const EventSourceCtor = options.eventSource ?? globalThis.EventSource;
|
|
4
|
+
if (!EventSourceCtor) throw new Error("live: EventSource is not available in this runtime.");
|
|
5
|
+
const ResolvedEventSource = EventSourceCtor;
|
|
6
|
+
const fetchImpl = options.fetch ?? fetch;
|
|
7
|
+
const connectionId = crypto.randomUUID();
|
|
8
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
9
|
+
const subscriptionVersions = /* @__PURE__ */ new Map();
|
|
10
|
+
let source = null;
|
|
11
|
+
let openPromise = null;
|
|
12
|
+
let rejectOpen = null;
|
|
13
|
+
let reconnectTimer = null;
|
|
14
|
+
let resubscribeOnNextOpen = false;
|
|
15
|
+
let resubscribeWithNextFlush = false;
|
|
16
|
+
let closed = false;
|
|
17
|
+
let pendingOperations = [];
|
|
18
|
+
let pendingFlush = null;
|
|
19
|
+
let flushChain = Promise.resolve();
|
|
20
|
+
let nextSubscriptionVersion = 0;
|
|
21
|
+
const retryDelay = options.retryDelay ?? 1e3;
|
|
22
|
+
if (!Number.isFinite(retryDelay) || retryDelay < 0) throw new Error("live: retryDelay must be a non-negative finite number.");
|
|
23
|
+
function streamUrl() {
|
|
24
|
+
const resolved = new URL(String(url), globalThis.location?.href);
|
|
25
|
+
resolved.searchParams.set("connectionId", connectionId);
|
|
26
|
+
return resolved.href;
|
|
27
|
+
}
|
|
28
|
+
function ensureOpen() {
|
|
29
|
+
if (closed) return Promise.reject(/* @__PURE__ */ new Error("live: stream is closed."));
|
|
30
|
+
const shouldResubscribe = resubscribeOnNextOpen;
|
|
31
|
+
if (reconnectTimer != null) {
|
|
32
|
+
clearTimeout(reconnectTimer);
|
|
33
|
+
reconnectTimer = null;
|
|
34
|
+
}
|
|
35
|
+
if (openPromise) return openPromise;
|
|
36
|
+
resubscribeOnNextOpen = false;
|
|
37
|
+
if (shouldResubscribe) resubscribeWithNextFlush = true;
|
|
38
|
+
return openSource(false);
|
|
39
|
+
}
|
|
40
|
+
function openSource(resubscribeOnOpen) {
|
|
41
|
+
const current = new ResolvedEventSource(streamUrl(), { withCredentials: options.withCredentials });
|
|
42
|
+
source = current;
|
|
43
|
+
let opened = false;
|
|
44
|
+
openPromise = new Promise((resolve, reject) => {
|
|
45
|
+
rejectOpen = reject;
|
|
46
|
+
const onOpen = () => {
|
|
47
|
+
if (source !== current) return;
|
|
48
|
+
if (!opened) {
|
|
49
|
+
opened = true;
|
|
50
|
+
rejectOpen = null;
|
|
51
|
+
resolve();
|
|
52
|
+
if (resubscribeOnOpen) resubscribeAll().catch(reportError);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
resubscribeAll().catch(reportError);
|
|
56
|
+
};
|
|
57
|
+
const onError = (event) => {
|
|
58
|
+
reportError(event);
|
|
59
|
+
if (source !== current) return;
|
|
60
|
+
if (!opened) {
|
|
61
|
+
current.removeEventListener("open", onOpen);
|
|
62
|
+
current.removeEventListener("error", onError);
|
|
63
|
+
current.removeEventListener("message", onMessage);
|
|
64
|
+
current.close();
|
|
65
|
+
source = null;
|
|
66
|
+
openPromise = null;
|
|
67
|
+
rejectOpen = null;
|
|
68
|
+
reject(/* @__PURE__ */ new Error("live: stream failed to open."));
|
|
69
|
+
if (resubscribeOnOpen) scheduleReconnectTimer();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
scheduleReconnect(current);
|
|
73
|
+
};
|
|
74
|
+
current.addEventListener("open", onOpen);
|
|
75
|
+
current.addEventListener("error", onError);
|
|
76
|
+
current.addEventListener("message", onMessage);
|
|
77
|
+
});
|
|
78
|
+
return openPromise;
|
|
79
|
+
}
|
|
80
|
+
function scheduleReconnect(current) {
|
|
81
|
+
if (closed || reconnectTimer != null) return;
|
|
82
|
+
current.close();
|
|
83
|
+
if (source === current) {
|
|
84
|
+
source = null;
|
|
85
|
+
openPromise = null;
|
|
86
|
+
}
|
|
87
|
+
if (!options.keepOpen && subscriptions.size === 0) return;
|
|
88
|
+
scheduleReconnectTimer();
|
|
89
|
+
}
|
|
90
|
+
function scheduleReconnectTimer() {
|
|
91
|
+
if (closed || reconnectTimer != null || !options.keepOpen && subscriptions.size === 0) return;
|
|
92
|
+
resubscribeOnNextOpen = true;
|
|
93
|
+
reconnectTimer = setTimeout(() => {
|
|
94
|
+
reconnectTimer = null;
|
|
95
|
+
if (closed || !options.keepOpen && subscriptions.size === 0) {
|
|
96
|
+
resubscribeOnNextOpen = false;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
resubscribeOnNextOpen = false;
|
|
100
|
+
openSource(true).catch((error) => {
|
|
101
|
+
if (!closed) reportError(error);
|
|
102
|
+
});
|
|
103
|
+
}, retryDelay);
|
|
104
|
+
}
|
|
105
|
+
function reportError(error) {
|
|
106
|
+
if (error instanceof Event || error instanceof Error) options.onError?.(error);
|
|
107
|
+
else options.onError?.(new Error(String(error)));
|
|
108
|
+
}
|
|
109
|
+
function onMessage(raw) {
|
|
110
|
+
const message = raw;
|
|
111
|
+
let event;
|
|
112
|
+
try {
|
|
113
|
+
event = JSON.parse(String(message.data));
|
|
114
|
+
} catch (error) {
|
|
115
|
+
reportError(error);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
const subscription = subscriptions.get(event.subscriptionId);
|
|
119
|
+
if (!subscription) return;
|
|
120
|
+
if (subscription.topic !== event.topic) return;
|
|
121
|
+
if (event.eventId) subscription.lastEventId = event.eventId;
|
|
122
|
+
subscription.onEvent?.(event);
|
|
123
|
+
}
|
|
124
|
+
function enqueue(operation) {
|
|
125
|
+
const promise = new Promise((resolve, reject) => {
|
|
126
|
+
pendingOperations.push({
|
|
127
|
+
operation,
|
|
128
|
+
resolve,
|
|
129
|
+
reject
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
scheduleFlush();
|
|
133
|
+
return promise;
|
|
134
|
+
}
|
|
135
|
+
function scheduleFlush() {
|
|
136
|
+
if (pendingFlush) return;
|
|
137
|
+
const scheduled = flushChain.then(flush);
|
|
138
|
+
pendingFlush = scheduled;
|
|
139
|
+
flushChain = scheduled.catch(() => {});
|
|
140
|
+
scheduled.finally(() => {
|
|
141
|
+
if (pendingFlush === scheduled) pendingFlush = null;
|
|
142
|
+
if (pendingOperations.length > 0) scheduleFlush();
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
async function flush() {
|
|
146
|
+
const pending = pendingOperations;
|
|
147
|
+
pendingOperations = [];
|
|
148
|
+
if (pending.length === 0) return;
|
|
149
|
+
try {
|
|
150
|
+
await ensureOpen();
|
|
151
|
+
let operations = pending.map((entry) => entry.operation);
|
|
152
|
+
if (resubscribeWithNextFlush) {
|
|
153
|
+
resubscribeWithNextFlush = false;
|
|
154
|
+
const pendingIds = new Set(operations.map((operation) => operation.id));
|
|
155
|
+
operations = [...[...subscriptions.values()].filter((subscription) => !pendingIds.has(subscription.id)).map((subscription) => ({
|
|
156
|
+
kind: "subscribe",
|
|
157
|
+
id: subscription.id,
|
|
158
|
+
topic: subscription.topic,
|
|
159
|
+
...subscription.lastEventId !== void 0 && { lastEventId: subscription.lastEventId }
|
|
160
|
+
})), ...operations];
|
|
161
|
+
}
|
|
162
|
+
const headers = new Headers(typeof options.headers === "function" ? await options.headers() : options.headers);
|
|
163
|
+
headers.set("content-type", "application/json");
|
|
164
|
+
const response = await fetchImpl(String(url), {
|
|
165
|
+
method: "POST",
|
|
166
|
+
headers,
|
|
167
|
+
credentials: options.withCredentials ? "include" : "same-origin",
|
|
168
|
+
body: JSON.stringify({
|
|
169
|
+
connectionId,
|
|
170
|
+
operations
|
|
171
|
+
})
|
|
172
|
+
});
|
|
173
|
+
const result = await response.json();
|
|
174
|
+
if (!response.ok || !result.accepted) throw new Error(result.accepted ? response.statusText : result.error.message);
|
|
175
|
+
const remaining = [...result.results];
|
|
176
|
+
for (const entry of pending) {
|
|
177
|
+
const index = remaining.findIndex((item) => item.id === entry.operation.id && item.kind === entry.operation.kind);
|
|
178
|
+
const item = index === -1 ? void 0 : remaining.splice(index, 1)[0];
|
|
179
|
+
if (!item) entry.reject(/* @__PURE__ */ new Error(`live: missing control result for ${entry.operation.id}.`));
|
|
180
|
+
else if (item.ok) entry.resolve();
|
|
181
|
+
else entry.reject(new Error(item.error.message));
|
|
182
|
+
}
|
|
183
|
+
} catch (error) {
|
|
184
|
+
for (const entry of pending) entry.reject(error);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
async function resubscribeAll() {
|
|
188
|
+
const activeSubscriptions = [...subscriptions.values()];
|
|
189
|
+
if (activeSubscriptions.length === 0) return;
|
|
190
|
+
await Promise.all(activeSubscriptions.map((subscription) => enqueue({
|
|
191
|
+
kind: "subscribe",
|
|
192
|
+
id: subscription.id,
|
|
193
|
+
topic: subscription.topic,
|
|
194
|
+
...subscription.lastEventId !== void 0 && { lastEventId: subscription.lastEventId }
|
|
195
|
+
})));
|
|
196
|
+
}
|
|
197
|
+
function closeIfIdle() {
|
|
198
|
+
if (!options.keepOpen && subscriptions.size === 0) {
|
|
199
|
+
if (reconnectTimer != null) {
|
|
200
|
+
clearTimeout(reconnectTimer);
|
|
201
|
+
reconnectTimer = null;
|
|
202
|
+
}
|
|
203
|
+
resubscribeOnNextOpen = false;
|
|
204
|
+
resubscribeWithNextFlush = false;
|
|
205
|
+
source?.close();
|
|
206
|
+
source = null;
|
|
207
|
+
openPromise = null;
|
|
208
|
+
rejectOpen = null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
connectionId,
|
|
213
|
+
async subscribe(subscribeOptions) {
|
|
214
|
+
const version = ++nextSubscriptionVersion;
|
|
215
|
+
const previousSubscription = subscriptions.get(subscribeOptions.id);
|
|
216
|
+
const previousVersion = subscriptionVersions.get(subscribeOptions.id);
|
|
217
|
+
subscriptionVersions.set(subscribeOptions.id, version);
|
|
218
|
+
const subscription = {
|
|
219
|
+
id: subscribeOptions.id,
|
|
220
|
+
topic: subscribeOptions.topic,
|
|
221
|
+
lastEventId: subscribeOptions.lastEventId,
|
|
222
|
+
onEvent: subscribeOptions.onEvent
|
|
223
|
+
};
|
|
224
|
+
subscriptions.set(subscription.id, subscription);
|
|
225
|
+
try {
|
|
226
|
+
await enqueue({
|
|
227
|
+
kind: "subscribe",
|
|
228
|
+
id: subscription.id,
|
|
229
|
+
topic: subscription.topic,
|
|
230
|
+
...subscription.lastEventId !== void 0 && { lastEventId: subscription.lastEventId }
|
|
231
|
+
});
|
|
232
|
+
} catch (error) {
|
|
233
|
+
if (subscriptionVersions.get(subscription.id) === version) if (previousSubscription) {
|
|
234
|
+
subscriptions.set(subscription.id, previousSubscription);
|
|
235
|
+
if (previousVersion != null) subscriptionVersions.set(subscription.id, previousVersion);
|
|
236
|
+
else subscriptionVersions.delete(subscription.id);
|
|
237
|
+
} else {
|
|
238
|
+
subscriptions.delete(subscription.id);
|
|
239
|
+
subscriptionVersions.delete(subscription.id);
|
|
240
|
+
}
|
|
241
|
+
queueMicrotask(closeIfIdle);
|
|
242
|
+
throw error;
|
|
243
|
+
}
|
|
244
|
+
if (closed) throw new Error("live: stream is closed.");
|
|
245
|
+
let unsubscribed = false;
|
|
246
|
+
return async () => {
|
|
247
|
+
if (unsubscribed) return;
|
|
248
|
+
unsubscribed = true;
|
|
249
|
+
if (subscriptionVersions.get(subscription.id) !== version || subscriptions.get(subscription.id) !== subscription) return;
|
|
250
|
+
await enqueue({
|
|
251
|
+
kind: "unsubscribe",
|
|
252
|
+
id: subscription.id
|
|
253
|
+
});
|
|
254
|
+
if (subscriptions.get(subscription.id) === subscription) {
|
|
255
|
+
subscriptions.delete(subscription.id);
|
|
256
|
+
subscriptionVersions.delete(subscription.id);
|
|
257
|
+
}
|
|
258
|
+
closeIfIdle();
|
|
259
|
+
};
|
|
260
|
+
},
|
|
261
|
+
close() {
|
|
262
|
+
const closeError = /* @__PURE__ */ new Error("live: stream is closed.");
|
|
263
|
+
closed = true;
|
|
264
|
+
subscriptions.clear();
|
|
265
|
+
subscriptionVersions.clear();
|
|
266
|
+
if (reconnectTimer != null) {
|
|
267
|
+
clearTimeout(reconnectTimer);
|
|
268
|
+
reconnectTimer = null;
|
|
269
|
+
}
|
|
270
|
+
resubscribeOnNextOpen = false;
|
|
271
|
+
resubscribeWithNextFlush = false;
|
|
272
|
+
for (const entry of pendingOperations) entry.reject(closeError);
|
|
273
|
+
pendingOperations = [];
|
|
274
|
+
rejectOpen?.(closeError);
|
|
275
|
+
rejectOpen = null;
|
|
276
|
+
source?.close();
|
|
277
|
+
source = null;
|
|
278
|
+
openPromise = null;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
//#endregion
|
|
283
|
+
export { connectLiveStream };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
+
//#region src/runtime/live-server.d.ts
|
|
3
|
+
type LiveDurableObjectEnv = Record<string, unknown>;
|
|
4
|
+
interface LiveDurableObjectInstance {
|
|
5
|
+
fetch(request: Request): Promise<Response>;
|
|
6
|
+
alarm?(): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
interface LiveDurableObjectClass {
|
|
9
|
+
new (state: DurableObjectState, env: LiveDurableObjectEnv): LiveDurableObjectInstance;
|
|
10
|
+
}
|
|
11
|
+
declare function createLiveDurableObject(): LiveDurableObjectClass;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { LiveDurableObjectClass, LiveDurableObjectInstance, createLiveDurableObject };
|