deepspace 0.6.0 → 0.6.2
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/CHANGELOG.md +23 -0
- package/dist/cli.js +318 -123
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +28 -3
- package/dist/index.js +124 -13
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +53 -1
- package/dist/server.js +86 -1
- package/dist/server.js.map +1 -1
- package/dist/worker.d.ts +53 -1
- package/dist/worker.js +86 -1
- package/dist/worker.js.map +1 -1
- package/features/ai-chat/src/ChatPanel.tsx +14 -12
- package/features/cron/src/CronLogPage.tsx +3 -3
- package/package.json +2 -1
package/dist/worker.d.ts
CHANGED
|
@@ -898,6 +898,8 @@ declare function encode<M extends BaseMessage<string, unknown>>(message: M): str
|
|
|
898
898
|
* - Raw SQLite access via this.sql
|
|
899
899
|
* - Broadcast helpers: broadcast(), sendTo()
|
|
900
900
|
* - HTTP fetch handler with WebSocket upgrade detection
|
|
901
|
+
* - Internal control-plane endpoint: POST /internal/disconnect-sockets
|
|
902
|
+
* (force every client to reconnect and resync after out-of-band writes)
|
|
901
903
|
*
|
|
902
904
|
* Subclasses implement lifecycle hooks:
|
|
903
905
|
* onConnect, onMessage, onBinaryMessage, onDisconnect, onRequest, onAlarm
|
|
@@ -917,6 +919,21 @@ declare abstract class BaseRoom<E = Record<string, unknown>> {
|
|
|
917
919
|
protected sql: SqlStorage;
|
|
918
920
|
constructor(state: DurableObjectState, env: unknown);
|
|
919
921
|
fetch(request: Request): Promise<Response>;
|
|
922
|
+
/**
|
|
923
|
+
* Handle built-in `/internal/*` control-plane routes shared by every room
|
|
924
|
+
* type. Returns a `Response` if the request was an internal route, or `null`
|
|
925
|
+
* to let the caller continue normal dispatch.
|
|
926
|
+
*
|
|
927
|
+
* Currently:
|
|
928
|
+
* - `POST /internal/disconnect-sockets` — close every live WebSocket so
|
|
929
|
+
* clients reconnect and resync. Optional JSON body `{ code?, reason? }`
|
|
930
|
+
* overrides the defaults (1012 / 'state-refresh'). Responds with
|
|
931
|
+
* `{ success: true, closed: <n> }`.
|
|
932
|
+
*
|
|
933
|
+
* See the security note on `fetch()`: this path is only reachable via DO
|
|
934
|
+
* stub fetch from the app worker, never from the public internet.
|
|
935
|
+
*/
|
|
936
|
+
protected handleInternalRequest(request: Request, url: URL): Promise<Response | null>;
|
|
920
937
|
private handleWebSocketUpgrade;
|
|
921
938
|
webSocketMessage(ws: WebSocket, message: ArrayBuffer | string): Promise<void>;
|
|
922
939
|
webSocketClose(ws: WebSocket, _code: number, _reason: string): Promise<void>;
|
|
@@ -955,6 +972,33 @@ declare abstract class BaseRoom<E = Record<string, unknown>> {
|
|
|
955
972
|
* Get all connected WebSockets.
|
|
956
973
|
*/
|
|
957
974
|
protected getWebSockets(): WebSocket[];
|
|
975
|
+
/**
|
|
976
|
+
* Force every connected client to reconnect and resync by closing all live
|
|
977
|
+
* WebSockets. Returns the number of sockets closed.
|
|
978
|
+
*
|
|
979
|
+
* Use this after an **out-of-band, server-side write** to the room's records
|
|
980
|
+
* — an admin import route, a migration script, a cron job, or a server
|
|
981
|
+
* action — that connected clients have no way to learn about. Without it, a
|
|
982
|
+
* browser tab holding stale in-memory state keeps operating on (and may
|
|
983
|
+
* autosave over) data that changed underneath it. Closing the socket makes
|
|
984
|
+
* the client SDK reconnect and pull fresh query results.
|
|
985
|
+
*
|
|
986
|
+
* The default close code is 1012 ("service restart") with reason
|
|
987
|
+
* 'state-refresh'. The DeepSpace client treats *any* close as a reconnect
|
|
988
|
+
* trigger (it does not special-case clean/1000 closes), so on reconnect it
|
|
989
|
+
* re-subscribes every active query and receives fresh `QUERY_RESULT`s —
|
|
990
|
+
* `useQuery` consumers see the new data without re-subscribing.
|
|
991
|
+
*
|
|
992
|
+
* Each close is guarded so one already-closing socket can't abort the sweep.
|
|
993
|
+
*
|
|
994
|
+
* @param options.code WebSocket close code (default 1012).
|
|
995
|
+
* @param options.reason WebSocket close reason (default 'state-refresh').
|
|
996
|
+
* @returns the number of sockets that were closed.
|
|
997
|
+
*/
|
|
998
|
+
disconnectAllSockets(options?: {
|
|
999
|
+
code?: number;
|
|
1000
|
+
reason?: string;
|
|
1001
|
+
}): number;
|
|
958
1002
|
/**
|
|
959
1003
|
* Get the user attachment for a WebSocket.
|
|
960
1004
|
*/
|
|
@@ -1401,6 +1445,14 @@ declare class RecordRoom<E = Record<string, unknown>> extends BaseRoom<E> {
|
|
|
1401
1445
|
* truthy value on the worker to opt in). Off by default.
|
|
1402
1446
|
*/
|
|
1403
1447
|
private get perfLogEnabled();
|
|
1448
|
+
/**
|
|
1449
|
+
* The HTTP debug API (`/api/debug/*`) runs arbitrary SQL and role changes
|
|
1450
|
+
* with no auth of its own, so it is gated here at the DO's single ingress.
|
|
1451
|
+
* Off unless a deployment opts in with `ALLOW_DEBUG_ROUTES=true`
|
|
1452
|
+
* (`deepspace dev`/`test` set it automatically). Deployments holding shared
|
|
1453
|
+
* data override this to always return false.
|
|
1454
|
+
*/
|
|
1455
|
+
protected get debugRoutesEnabled(): boolean;
|
|
1404
1456
|
constructor(state: DurableObjectState, env: unknown, schemas?: CollectionSchema[], config?: RecordRoomConfig);
|
|
1405
1457
|
private getPermissionContext;
|
|
1406
1458
|
fetch(request: Request): Promise<Response>;
|
|
@@ -2955,7 +3007,7 @@ declare function createDeepSpaceAI(env: DeepSpaceAIEnv, provider: Provider, opti
|
|
|
2955
3007
|
* const jwt = c.req.header('Authorization')!.slice(7)
|
|
2956
3008
|
* const tools = await composioTools(c.env, { toolkit: 'gmail', authToken: jwt })
|
|
2957
3009
|
* const ai = createDeepSpaceAI(c.env, 'anthropic', { authToken: jwt })
|
|
2958
|
-
* const result = streamText({ model: ai('claude-sonnet-
|
|
3010
|
+
* const result = streamText({ model: ai('claude-sonnet-5'), prompt, tools })
|
|
2959
3011
|
*
|
|
2960
3012
|
* Merge with your own tools: `tools: { ...buildTools(executor), ...composio }`.
|
|
2961
3013
|
*/
|
package/dist/worker.js
CHANGED
|
@@ -16,6 +16,8 @@ var BaseRoom = class {
|
|
|
16
16
|
// ==========================================================================
|
|
17
17
|
async fetch(request) {
|
|
18
18
|
const url = new URL(request.url);
|
|
19
|
+
const internal = await this.handleInternalRequest(request, url);
|
|
20
|
+
if (internal) return internal;
|
|
19
21
|
if (request.headers.get("Upgrade") === "websocket") {
|
|
20
22
|
return this.handleWebSocketUpgrade(request, url);
|
|
21
23
|
}
|
|
@@ -25,6 +27,36 @@ var BaseRoom = class {
|
|
|
25
27
|
return new Response("Not Found", { status: 404 });
|
|
26
28
|
}
|
|
27
29
|
// ==========================================================================
|
|
30
|
+
// Internal Control-Plane Endpoints
|
|
31
|
+
// ==========================================================================
|
|
32
|
+
/**
|
|
33
|
+
* Handle built-in `/internal/*` control-plane routes shared by every room
|
|
34
|
+
* type. Returns a `Response` if the request was an internal route, or `null`
|
|
35
|
+
* to let the caller continue normal dispatch.
|
|
36
|
+
*
|
|
37
|
+
* Currently:
|
|
38
|
+
* - `POST /internal/disconnect-sockets` — close every live WebSocket so
|
|
39
|
+
* clients reconnect and resync. Optional JSON body `{ code?, reason? }`
|
|
40
|
+
* overrides the defaults (1012 / 'state-refresh'). Responds with
|
|
41
|
+
* `{ success: true, closed: <n> }`.
|
|
42
|
+
*
|
|
43
|
+
* See the security note on `fetch()`: this path is only reachable via DO
|
|
44
|
+
* stub fetch from the app worker, never from the public internet.
|
|
45
|
+
*/
|
|
46
|
+
async handleInternalRequest(request, url) {
|
|
47
|
+
if (request.method === "POST" && url.pathname === "/internal/disconnect-sockets") {
|
|
48
|
+
let options;
|
|
49
|
+
try {
|
|
50
|
+
const text = await request.text();
|
|
51
|
+
if (text) options = JSON.parse(text);
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
const closed = this.disconnectAllSockets(options);
|
|
55
|
+
return Response.json({ success: true, closed });
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
// ==========================================================================
|
|
28
60
|
// WebSocket Connection
|
|
29
61
|
// ==========================================================================
|
|
30
62
|
async handleWebSocketUpgrade(request, url) {
|
|
@@ -111,6 +143,42 @@ var BaseRoom = class {
|
|
|
111
143
|
getWebSockets() {
|
|
112
144
|
return this.state.getWebSockets();
|
|
113
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Force every connected client to reconnect and resync by closing all live
|
|
148
|
+
* WebSockets. Returns the number of sockets closed.
|
|
149
|
+
*
|
|
150
|
+
* Use this after an **out-of-band, server-side write** to the room's records
|
|
151
|
+
* — an admin import route, a migration script, a cron job, or a server
|
|
152
|
+
* action — that connected clients have no way to learn about. Without it, a
|
|
153
|
+
* browser tab holding stale in-memory state keeps operating on (and may
|
|
154
|
+
* autosave over) data that changed underneath it. Closing the socket makes
|
|
155
|
+
* the client SDK reconnect and pull fresh query results.
|
|
156
|
+
*
|
|
157
|
+
* The default close code is 1012 ("service restart") with reason
|
|
158
|
+
* 'state-refresh'. The DeepSpace client treats *any* close as a reconnect
|
|
159
|
+
* trigger (it does not special-case clean/1000 closes), so on reconnect it
|
|
160
|
+
* re-subscribes every active query and receives fresh `QUERY_RESULT`s —
|
|
161
|
+
* `useQuery` consumers see the new data without re-subscribing.
|
|
162
|
+
*
|
|
163
|
+
* Each close is guarded so one already-closing socket can't abort the sweep.
|
|
164
|
+
*
|
|
165
|
+
* @param options.code WebSocket close code (default 1012).
|
|
166
|
+
* @param options.reason WebSocket close reason (default 'state-refresh').
|
|
167
|
+
* @returns the number of sockets that were closed.
|
|
168
|
+
*/
|
|
169
|
+
disconnectAllSockets(options) {
|
|
170
|
+
const code = options?.code ?? 1012;
|
|
171
|
+
const reason = options?.reason ?? "state-refresh";
|
|
172
|
+
let closed = 0;
|
|
173
|
+
for (const ws of this.state.getWebSockets()) {
|
|
174
|
+
try {
|
|
175
|
+
ws.close(code, reason);
|
|
176
|
+
closed++;
|
|
177
|
+
} catch {
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return closed;
|
|
181
|
+
}
|
|
114
182
|
/**
|
|
115
183
|
* Get the user attachment for a WebSocket.
|
|
116
184
|
*/
|
|
@@ -2670,6 +2738,16 @@ var RecordRoom = class extends BaseRoom {
|
|
|
2670
2738
|
get perfLogEnabled() {
|
|
2671
2739
|
return !!this.env?.DEEPSPACE_DO_PERF;
|
|
2672
2740
|
}
|
|
2741
|
+
/**
|
|
2742
|
+
* The HTTP debug API (`/api/debug/*`) runs arbitrary SQL and role changes
|
|
2743
|
+
* with no auth of its own, so it is gated here at the DO's single ingress.
|
|
2744
|
+
* Off unless a deployment opts in with `ALLOW_DEBUG_ROUTES=true`
|
|
2745
|
+
* (`deepspace dev`/`test` set it automatically). Deployments holding shared
|
|
2746
|
+
* data override this to always return false.
|
|
2747
|
+
*/
|
|
2748
|
+
get debugRoutesEnabled() {
|
|
2749
|
+
return this.env?.ALLOW_DEBUG_ROUTES === "true";
|
|
2750
|
+
}
|
|
2673
2751
|
constructor(state, env, schemas = [], config = {}) {
|
|
2674
2752
|
super(state, env);
|
|
2675
2753
|
this.schemaRegistry = new SchemaRegistry([
|
|
@@ -2705,14 +2783,21 @@ var RecordRoom = class extends BaseRoom {
|
|
|
2705
2783
|
// HTTP Entry Point (overrides BaseRoom.fetch)
|
|
2706
2784
|
// ============================================================================
|
|
2707
2785
|
async fetch(request) {
|
|
2786
|
+
const url = new URL(request.url);
|
|
2787
|
+
if (url.pathname.startsWith("/internal/")) {
|
|
2788
|
+
const internal = await this.handleInternalRequest(request, url);
|
|
2789
|
+
if (internal) return internal;
|
|
2790
|
+
}
|
|
2708
2791
|
const fetchStart = Date.now();
|
|
2709
2792
|
const isColdStart = this.freshConstruct;
|
|
2710
2793
|
const needsInit = !this.initPromise;
|
|
2711
2794
|
this.freshConstruct = false;
|
|
2712
2795
|
await this.ensureInitialized();
|
|
2713
2796
|
const initMs = Date.now() - fetchStart;
|
|
2714
|
-
const url = new URL(request.url);
|
|
2715
2797
|
if (url.pathname.startsWith("/api/")) {
|
|
2798
|
+
if (url.pathname.startsWith("/api/debug/") && !this.debugRoutesEnabled) {
|
|
2799
|
+
return new Response("Not Found", { status: 404 });
|
|
2800
|
+
}
|
|
2716
2801
|
return handleApiRequest(this.createHandlerContext(), request, url);
|
|
2717
2802
|
}
|
|
2718
2803
|
if (request.headers.get("Upgrade") === "websocket") {
|