@sveltebase/sync 1.4.0 → 1.4.3
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 +97 -83
- package/dist/cloudflare/handler.d.ts +14 -0
- package/dist/cloudflare/handler.d.ts.map +1 -0
- package/dist/cloudflare/handler.js +108 -0
- package/dist/cloudflare/index.d.ts +5 -11
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +12 -104
- package/dist/server/dev-engine.d.ts +22 -0
- package/dist/server/dev-engine.d.ts.map +1 -0
- package/dist/server/dev-engine.js +165 -0
- package/dist/server/engine.d.ts.map +1 -1
- package/dist/server/handler.d.ts +0 -2
- package/dist/server/handler.d.ts.map +1 -1
- package/dist/server/handler.js +12 -29
- package/dist/server/index.d.ts +0 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +0 -1
- package/dist/sveltekit/index.d.ts +3 -6
- package/dist/sveltekit/index.d.ts.map +1 -1
- package/dist/sveltekit/index.js +14 -20
- package/dist/vite.d.ts +8 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +56 -0
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -1,32 +1,28 @@
|
|
|
1
1
|
# @sveltebase/sync
|
|
2
2
|
|
|
3
|
-
Reactive, local-first database synchronization for Svelte 5
|
|
3
|
+
Reactive, local-first database synchronization for Svelte 5 on Cloudflare Workers.
|
|
4
4
|
|
|
5
5
|
## Architecture
|
|
6
6
|
|
|
7
|
-
`@sveltebase/sync`
|
|
7
|
+
`@sveltebase/sync` uses one Cloudflare Worker:
|
|
8
8
|
|
|
9
9
|
```txt
|
|
10
10
|
browser
|
|
11
11
|
-> SvelteKit app Worker
|
|
12
|
-
/api/sync ->
|
|
13
|
-
|
|
14
|
-
owns SyncEngine Durable Object
|
|
15
|
-
owns websocket upgrades
|
|
16
|
-
owns broadcasts
|
|
17
|
-
owns sync database/runtime bindings
|
|
18
|
-
owns sync auth verification
|
|
12
|
+
/api/sync -> SyncEngine Durable Object
|
|
13
|
+
server writes -> platform.env.SYNC_ENGINE
|
|
19
14
|
```
|
|
20
15
|
|
|
21
|
-
The
|
|
16
|
+
The production Worker wraps the official `@sveltejs/adapter-cloudflare` output and exports the `SyncEngine` Durable Object. Vite dev uses `syncDevPlugin()` for the WebSocket broker and `adapter-cloudflare` platform proxy for local Cloudflare bindings.
|
|
22
17
|
|
|
23
18
|
## Imports
|
|
24
19
|
|
|
25
20
|
```ts
|
|
26
21
|
import { SyncClient, createLiveQuery } from "@sveltebase/sync/client";
|
|
27
22
|
import { defineSync, createPublisher } from "@sveltebase/sync/server";
|
|
28
|
-
import {
|
|
29
|
-
import {
|
|
23
|
+
import { syncEngineRoute } from "@sveltebase/sync/sveltekit";
|
|
24
|
+
import { createSyncAppWorker, SyncEngine } from "@sveltebase/sync/cloudflare";
|
|
25
|
+
import { syncDevPlugin } from "@sveltebase/sync/vite";
|
|
30
26
|
```
|
|
31
27
|
|
|
32
28
|
## Client
|
|
@@ -35,16 +31,7 @@ import { defineSyncWorker, SyncEngine } from "@sveltebase/sync/cloudflare";
|
|
|
35
31
|
// src/lib/sync-client.ts
|
|
36
32
|
import { SyncClient } from "@sveltebase/sync/client";
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
todos: {
|
|
40
|
-
id: string;
|
|
41
|
-
title: string;
|
|
42
|
-
completed: boolean;
|
|
43
|
-
updatedAt: string;
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export const sync = new SyncClient<AppSchema>({
|
|
34
|
+
export const sync = new SyncClient({
|
|
48
35
|
name: "app-sync",
|
|
49
36
|
url: "/api/sync",
|
|
50
37
|
tables: {
|
|
@@ -58,7 +45,7 @@ export const sync = new SyncClient<AppSchema>({
|
|
|
58
45
|
|
|
59
46
|
## Sync Handlers
|
|
60
47
|
|
|
61
|
-
Handlers run in the sync
|
|
48
|
+
Handlers run in the sync engine. Use `ctx.platform.env` for Cloudflare bindings, `ctx.auth` for verified auth data, and `ctx.identity` for ownership/scoped fanout.
|
|
62
49
|
|
|
63
50
|
```ts
|
|
64
51
|
// src/lib/server/sync-handlers.ts
|
|
@@ -69,14 +56,11 @@ export const todoSync = defineSync({
|
|
|
69
56
|
|
|
70
57
|
fetch: async (ctx, since) => {
|
|
71
58
|
const db = ctx.platform.env.DB;
|
|
72
|
-
// Query any database here.
|
|
73
59
|
return [];
|
|
74
60
|
},
|
|
75
61
|
|
|
76
62
|
authorize: async (ctx) => {
|
|
77
|
-
if (!ctx.auth)
|
|
78
|
-
throw new Error("Unauthorized");
|
|
79
|
-
}
|
|
63
|
+
if (!ctx.auth) throw new Error("Unauthorized");
|
|
80
64
|
},
|
|
81
65
|
|
|
82
66
|
scope: (ctx) => {
|
|
@@ -87,97 +71,113 @@ export const todoSync = defineSync({
|
|
|
87
71
|
export const handlers = [todoSync];
|
|
88
72
|
```
|
|
89
73
|
|
|
90
|
-
##
|
|
91
|
-
|
|
92
|
-
Create a standalone Worker entrypoint that owns the Durable Object:
|
|
74
|
+
## SvelteKit Route For Vite Dev
|
|
93
75
|
|
|
94
76
|
```ts
|
|
95
|
-
// src/
|
|
77
|
+
// src/routes/api/sync/+server.ts
|
|
96
78
|
import { jwtCookieAuth } from "@sveltebase/auth/sync";
|
|
97
|
-
import {
|
|
79
|
+
import { syncEngineRoute } from "@sveltebase/sync/sveltekit";
|
|
98
80
|
import { handlers } from "$lib/server/sync-handlers";
|
|
99
81
|
|
|
100
|
-
export
|
|
82
|
+
export const { GET } = syncEngineRoute({
|
|
101
83
|
handlers,
|
|
102
84
|
auth: jwtCookieAuth(),
|
|
85
|
+
allowUnauthenticated: true,
|
|
103
86
|
});
|
|
104
|
-
|
|
105
|
-
export { SyncEngine };
|
|
106
87
|
```
|
|
107
88
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
- `GET /api/sync`: public websocket upgrade endpoint
|
|
111
|
-
- `POST /broadcast`: publish one external change
|
|
112
|
-
- `POST /broadcast-batch`: publish a batch of external changes
|
|
113
|
-
|
|
114
|
-
`GET /websocket` is internal to the sync Worker and Durable Object.
|
|
115
|
-
|
|
116
|
-
## SvelteKit Proxy Route
|
|
117
|
-
|
|
118
|
-
Keep browsers connecting to the app origin so existing cookies are sent:
|
|
89
|
+
## Worker Wrapper For Wrangler And Production
|
|
119
90
|
|
|
120
91
|
```ts
|
|
121
|
-
// src/
|
|
122
|
-
import
|
|
123
|
-
import {
|
|
92
|
+
// src/worker/app.ts
|
|
93
|
+
import app from "../../.svelte-kit/cloudflare/_worker.js";
|
|
94
|
+
import { jwtCookieAuth } from "@sveltebase/auth/sync";
|
|
95
|
+
import { createSyncAppWorker, SyncEngine } from "@sveltebase/sync/cloudflare";
|
|
96
|
+
import { handlers } from "$lib/server/sync-handlers";
|
|
124
97
|
|
|
125
|
-
export
|
|
126
|
-
|
|
98
|
+
export default createSyncAppWorker(app, {
|
|
99
|
+
handlers,
|
|
100
|
+
auth: jwtCookieAuth(),
|
|
101
|
+
allowUnauthenticated: true,
|
|
127
102
|
});
|
|
103
|
+
|
|
104
|
+
export { SyncEngine };
|
|
128
105
|
```
|
|
129
106
|
|
|
130
|
-
|
|
107
|
+
`createSyncAppWorker()` handles `GET /api/sync` and internal broadcast routes, then delegates all other requests to the adapter output.
|
|
131
108
|
|
|
132
109
|
## Publishing Server Events
|
|
133
110
|
|
|
134
|
-
Publishing is explicit.
|
|
111
|
+
Publishing is explicit and targets the one-worker Durable Object binding. During Vite dev, `syncDevPlugin()` provides an in-process broker fallback.
|
|
135
112
|
|
|
136
113
|
```ts
|
|
137
114
|
import { createPublisher } from "@sveltebase/sync/server";
|
|
138
115
|
|
|
139
|
-
|
|
140
|
-
todos: { id: string; title: string; updatedAt: string };
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const publish = createPublisher<AppSchema>({
|
|
116
|
+
const publish = createPublisher({
|
|
144
117
|
platform: ctx.platform,
|
|
145
|
-
binding: "SYNC_WORKER",
|
|
146
|
-
fallbackUrl: env.SYNC_WORKER_URL,
|
|
147
118
|
});
|
|
148
119
|
|
|
149
120
|
await publish("todos", "update", todo.id, todo);
|
|
150
121
|
```
|
|
151
122
|
|
|
152
|
-
|
|
123
|
+
## Vite Dev
|
|
153
124
|
|
|
154
|
-
|
|
125
|
+
```ts
|
|
126
|
+
// vite.config.ts
|
|
127
|
+
import { sveltekit } from "@sveltejs/kit/vite";
|
|
128
|
+
import { syncDevPlugin } from "@sveltebase/sync/vite";
|
|
129
|
+
import { jwtCookieAuth } from "@sveltebase/auth/sync";
|
|
130
|
+
import { defineConfig } from "vite";
|
|
131
|
+
|
|
132
|
+
export default defineConfig({
|
|
133
|
+
plugins: [
|
|
134
|
+
syncDevPlugin({
|
|
135
|
+
auth: jwtCookieAuth(),
|
|
136
|
+
allowUnauthenticated: true,
|
|
137
|
+
wranglerConfigPath: "wrangler.local.jsonc",
|
|
138
|
+
}),
|
|
139
|
+
sveltekit(),
|
|
140
|
+
],
|
|
141
|
+
});
|
|
142
|
+
```
|
|
155
143
|
|
|
156
|
-
|
|
144
|
+
## Svelte Config
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
// svelte.config.js
|
|
148
|
+
import adapter from "@sveltejs/adapter-cloudflare";
|
|
149
|
+
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
|
|
150
|
+
|
|
151
|
+
export default {
|
|
152
|
+
preprocess: vitePreprocess(),
|
|
153
|
+
kit: {
|
|
154
|
+
adapter: adapter({
|
|
155
|
+
platformProxy: {
|
|
156
|
+
configPath: "wrangler.local.jsonc",
|
|
157
|
+
},
|
|
158
|
+
}),
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Wrangler Configuration
|
|
164
|
+
|
|
165
|
+
Main config for Wrangler dev with remote bindings and production deploy:
|
|
157
166
|
|
|
158
167
|
```jsonc
|
|
168
|
+
// wrangler.jsonc
|
|
159
169
|
{
|
|
160
170
|
"name": "my-app",
|
|
161
|
-
"main": "
|
|
171
|
+
"main": "src/worker/app.ts",
|
|
162
172
|
"compatibility_date": "2026-06-07",
|
|
163
173
|
"compatibility_flags": ["nodejs_compat"],
|
|
164
|
-
"
|
|
174
|
+
"d1_databases": [
|
|
165
175
|
{
|
|
166
|
-
"binding": "
|
|
167
|
-
"
|
|
176
|
+
"binding": "DB",
|
|
177
|
+
"database_name": "my-app",
|
|
178
|
+
"database_id": "..."
|
|
168
179
|
}
|
|
169
|
-
]
|
|
170
|
-
}
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Sync Worker:
|
|
174
|
-
|
|
175
|
-
```jsonc
|
|
176
|
-
{
|
|
177
|
-
"name": "my-app-sync",
|
|
178
|
-
"main": "./src/worker/sync.ts",
|
|
179
|
-
"compatibility_date": "2026-06-07",
|
|
180
|
-
"compatibility_flags": ["nodejs_compat"],
|
|
180
|
+
],
|
|
181
181
|
"durable_objects": {
|
|
182
182
|
"bindings": [
|
|
183
183
|
{
|
|
@@ -195,9 +195,23 @@ Sync Worker:
|
|
|
195
195
|
}
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
-
|
|
198
|
+
Local config for adapter platform proxy in Vite dev:
|
|
199
199
|
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
|
|
200
|
+
```jsonc
|
|
201
|
+
// wrangler.local.jsonc
|
|
202
|
+
{
|
|
203
|
+
"name": "my-app-local",
|
|
204
|
+
"main": ".svelte-kit/cloudflare/_worker.js",
|
|
205
|
+
"compatibility_date": "2026-06-07",
|
|
206
|
+
"compatibility_flags": ["nodejs_compat"],
|
|
207
|
+
"d1_databases": [
|
|
208
|
+
{
|
|
209
|
+
"binding": "DB",
|
|
210
|
+
"database_name": "my-app",
|
|
211
|
+
"database_id": "..."
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
}
|
|
203
215
|
```
|
|
216
|
+
|
|
217
|
+
Use `wrangler secret put JWT_SECRET --config wrangler.jsonc` for remote/prod secrets. Use `.env` for Vite dev secrets loaded by the platform proxy.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type SyncAuthResult } from "../server/handler.js";
|
|
2
|
+
import type { SyncHandler, SyncPlatform } from "../server/index.js";
|
|
3
|
+
export declare function configureSyncEngine(handlers: SyncHandler[]): void;
|
|
4
|
+
export declare function getSyncEngineHandlers(): SyncHandler<any, any>[];
|
|
5
|
+
export type SyncWorkerOptions<TAuth = unknown> = {
|
|
6
|
+
handlers: SyncHandler[];
|
|
7
|
+
durableObjectBinding?: string;
|
|
8
|
+
websocketPath?: string;
|
|
9
|
+
auth?: (request: Request, platform: SyncPlatform) => Promise<SyncAuthResult<TAuth>> | SyncAuthResult<TAuth>;
|
|
10
|
+
identity?: (auth: TAuth) => string | number | bigint | null | undefined;
|
|
11
|
+
allowUnauthenticated?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export declare function handleSyncRequest<TAuth = unknown>(request: Request, env: Record<string, unknown>, ctx: ExecutionContext, options: SyncWorkerOptions<TAuth>): Promise<Response>;
|
|
14
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/cloudflare/handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AA2CpE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,WAAW,EAAE,QAE1D;AAED,wBAAgB,qBAAqB,4BAEpC;AAED,MAAM,MAAM,iBAAiB,CAAC,KAAK,GAAG,OAAO,IAAI;IAC/C,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,CACL,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,YAAY,KACnB,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;IAC5D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxE,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,CAAC;AA6FF,wBAAsB,iBAAiB,CAAC,KAAK,GAAG,OAAO,EACrD,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,GAAG,EAAE,gBAAgB,EACrB,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,qBA2ClC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { INTERNAL_AUTH_HEADER, } from "../server/handler.js";
|
|
2
|
+
let activeHandlers = [];
|
|
3
|
+
function defaultIdentity(auth) {
|
|
4
|
+
const value = auth?.identity ?? auth?.user?.id ?? auth?.userId;
|
|
5
|
+
return value == null ? null : String(value);
|
|
6
|
+
}
|
|
7
|
+
function serializeConnectionAuth(auth, identity) {
|
|
8
|
+
const payload = { auth, identity };
|
|
9
|
+
return btoa(unescape(encodeURIComponent(JSON.stringify(payload))));
|
|
10
|
+
}
|
|
11
|
+
function createPlatform(request, env, ctx) {
|
|
12
|
+
return {
|
|
13
|
+
env,
|
|
14
|
+
ctx,
|
|
15
|
+
context: ctx,
|
|
16
|
+
caches,
|
|
17
|
+
cf: request.cf,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function withPath(request, pathname) {
|
|
21
|
+
const url = new URL(request.url);
|
|
22
|
+
url.pathname = pathname;
|
|
23
|
+
return url.toString();
|
|
24
|
+
}
|
|
25
|
+
function isWebSocketRequest(request) {
|
|
26
|
+
return request.headers.get("Upgrade")?.toLowerCase() === "websocket";
|
|
27
|
+
}
|
|
28
|
+
export function configureSyncEngine(handlers) {
|
|
29
|
+
activeHandlers = handlers;
|
|
30
|
+
}
|
|
31
|
+
export function getSyncEngineHandlers() {
|
|
32
|
+
return activeHandlers;
|
|
33
|
+
}
|
|
34
|
+
async function forwardToEngine(request, env, durableObjectBinding) {
|
|
35
|
+
const namespace = env[durableObjectBinding];
|
|
36
|
+
if (!namespace) {
|
|
37
|
+
return new Response(`Missing ${durableObjectBinding} Durable Object binding`, { status: 500 });
|
|
38
|
+
}
|
|
39
|
+
const id = namespace.idFromName("global");
|
|
40
|
+
return namespace.get(id).fetch(request);
|
|
41
|
+
}
|
|
42
|
+
async function handleWebSocket(request, env, ctx, options) {
|
|
43
|
+
if (!isWebSocketRequest(request)) {
|
|
44
|
+
return new Response("Expected Upgrade: websocket", { status: 426 });
|
|
45
|
+
}
|
|
46
|
+
const publicHeaders = new Headers(request.headers);
|
|
47
|
+
publicHeaders.delete(INTERNAL_AUTH_HEADER);
|
|
48
|
+
const publicRequest = new Request(request, {
|
|
49
|
+
headers: publicHeaders,
|
|
50
|
+
});
|
|
51
|
+
const platform = createPlatform(publicRequest, env, ctx);
|
|
52
|
+
let resolvedAuth = null;
|
|
53
|
+
let identity = null;
|
|
54
|
+
if (options.auth) {
|
|
55
|
+
resolvedAuth = (await options.auth(publicRequest, platform)) ?? null;
|
|
56
|
+
if (!resolvedAuth && options.allowUnauthenticated === false) {
|
|
57
|
+
return new Response("Unauthorized", { status: 401 });
|
|
58
|
+
}
|
|
59
|
+
if (resolvedAuth) {
|
|
60
|
+
const identityValue = options.identity
|
|
61
|
+
? options.identity(resolvedAuth)
|
|
62
|
+
: defaultIdentity(resolvedAuth);
|
|
63
|
+
identity = identityValue == null ? null : String(identityValue);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (options.allowUnauthenticated === false) {
|
|
67
|
+
return new Response("Unauthorized", { status: 401 });
|
|
68
|
+
}
|
|
69
|
+
const forwardedHeaders = new Headers(publicRequest.headers);
|
|
70
|
+
forwardedHeaders.delete(INTERNAL_AUTH_HEADER);
|
|
71
|
+
if (resolvedAuth) {
|
|
72
|
+
forwardedHeaders.set(INTERNAL_AUTH_HEADER, serializeConnectionAuth(resolvedAuth, identity));
|
|
73
|
+
}
|
|
74
|
+
const forwardedRequest = new Request(withPath(publicRequest, "/websocket"), publicRequest);
|
|
75
|
+
for (const [key, value] of forwardedHeaders) {
|
|
76
|
+
forwardedRequest.headers.set(key, value);
|
|
77
|
+
}
|
|
78
|
+
return forwardToEngine(forwardedRequest, env, options.durableObjectBinding);
|
|
79
|
+
}
|
|
80
|
+
export async function handleSyncRequest(request, env, ctx, options) {
|
|
81
|
+
configureSyncEngine(options.handlers);
|
|
82
|
+
const url = new URL(request.url);
|
|
83
|
+
const durableObjectBinding = options.durableObjectBinding ?? "SYNC_ENGINE";
|
|
84
|
+
const websocketPath = options.websocketPath ?? "/api/sync";
|
|
85
|
+
const authMetadata = options.auth;
|
|
86
|
+
const allowUnauthenticated = options.allowUnauthenticated ??
|
|
87
|
+
authMetadata?.allowUnauthenticated ??
|
|
88
|
+
true;
|
|
89
|
+
if (url.pathname === websocketPath && request.method === "GET") {
|
|
90
|
+
return handleWebSocket(request, env, ctx, {
|
|
91
|
+
...options,
|
|
92
|
+
durableObjectBinding,
|
|
93
|
+
websocketPath,
|
|
94
|
+
allowUnauthenticated,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (url.pathname === "/websocket") {
|
|
98
|
+
return new Response("Not found", { status: 404 });
|
|
99
|
+
}
|
|
100
|
+
if ((url.pathname === "/broadcast" ||
|
|
101
|
+
url.pathname === "/broadcast-batch") &&
|
|
102
|
+
request.method === "POST") {
|
|
103
|
+
const headers = new Headers(request.headers);
|
|
104
|
+
headers.delete(INTERNAL_AUTH_HEADER);
|
|
105
|
+
return forwardToEngine(new Request(request, { headers }), env, durableObjectBinding);
|
|
106
|
+
}
|
|
107
|
+
return new Response("Not found", { status: 404 });
|
|
108
|
+
}
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import { SyncEngineBase } from "../server/engine.js";
|
|
2
|
-
import { type
|
|
3
|
-
|
|
4
|
-
export type
|
|
5
|
-
|
|
6
|
-
durableObjectBinding?: string;
|
|
7
|
-
websocketPath?: string;
|
|
8
|
-
auth?: (request: Request, platform: SyncPlatform) => Promise<SyncAuthResult<TAuth>> | SyncAuthResult<TAuth>;
|
|
9
|
-
identity?: (auth: TAuth) => string | number | bigint | null | undefined;
|
|
10
|
-
allowUnauthenticated?: boolean;
|
|
2
|
+
import { type SyncWorkerOptions } from "./handler.js";
|
|
3
|
+
export { configureSyncEngine, handleSyncRequest, type SyncWorkerOptions, } from "./handler.js";
|
|
4
|
+
export type SyncAppWorker = {
|
|
5
|
+
fetch: NonNullable<ExportedHandler["fetch"]>;
|
|
11
6
|
};
|
|
12
|
-
export declare function
|
|
13
|
-
export declare function defineSyncWorker<TAuth = unknown>(options: SyncWorkerOptions<TAuth>): ExportedHandler;
|
|
7
|
+
export declare function createSyncAppWorker<TAuth = unknown>(app: SyncAppWorker, options: SyncWorkerOptions<TAuth>): ExportedHandler;
|
|
14
8
|
export declare class SyncEngine extends SyncEngineBase {
|
|
15
9
|
constructor(ctx: DurableObjectState, env: Record<string, unknown>);
|
|
16
10
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloudflare/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,aAAa,GAAG;IAC1B,KAAK,EAAE,WAAW,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;CAC9C,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,KAAK,GAAG,OAAO,EACjD,GAAG,EAAE,aAAa,EAClB,OAAO,EAAE,iBAAiB,CAAC,KAAK,CAAC,GAChC,eAAe,CAwBjB;AAED,qBAAa,UAAW,SAAQ,cAAc;gBAChC,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAGlE"}
|
package/dist/cloudflare/index.js
CHANGED
|
@@ -1,116 +1,24 @@
|
|
|
1
1
|
import { SyncEngineBase } from "../server/engine.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
function
|
|
5
|
-
|
|
6
|
-
return value == null ? null : String(value);
|
|
7
|
-
}
|
|
8
|
-
function serializeConnectionAuth(auth, identity) {
|
|
9
|
-
const payload = { auth, identity };
|
|
10
|
-
return btoa(unescape(encodeURIComponent(JSON.stringify(payload))));
|
|
11
|
-
}
|
|
12
|
-
function createPlatform(request, env, ctx) {
|
|
13
|
-
return {
|
|
14
|
-
env,
|
|
15
|
-
ctx,
|
|
16
|
-
context: ctx,
|
|
17
|
-
caches,
|
|
18
|
-
cf: request.cf,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
function withPath(request, pathname) {
|
|
22
|
-
const url = new URL(request.url);
|
|
23
|
-
url.pathname = pathname;
|
|
24
|
-
return url.toString();
|
|
25
|
-
}
|
|
26
|
-
function isWebSocketRequest(request) {
|
|
27
|
-
return request.headers.get("Upgrade")?.toLowerCase() === "websocket";
|
|
28
|
-
}
|
|
29
|
-
async function forwardToEngine(request, env, durableObjectBinding) {
|
|
30
|
-
const namespace = env[durableObjectBinding];
|
|
31
|
-
if (!namespace) {
|
|
32
|
-
return new Response(`Missing ${durableObjectBinding} Durable Object binding`, { status: 500 });
|
|
33
|
-
}
|
|
34
|
-
const id = namespace.idFromName("global");
|
|
35
|
-
return namespace.get(id).fetch(request);
|
|
36
|
-
}
|
|
37
|
-
async function handleWebSocket(request, env, ctx, options) {
|
|
38
|
-
if (!isWebSocketRequest(request)) {
|
|
39
|
-
return new Response("Expected Upgrade: websocket", { status: 426 });
|
|
40
|
-
}
|
|
41
|
-
const publicHeaders = new Headers(request.headers);
|
|
42
|
-
publicHeaders.delete(INTERNAL_AUTH_HEADER);
|
|
43
|
-
const publicRequest = new Request(request, {
|
|
44
|
-
headers: publicHeaders,
|
|
45
|
-
});
|
|
46
|
-
const platform = createPlatform(publicRequest, env, ctx);
|
|
47
|
-
let resolvedAuth = null;
|
|
48
|
-
let identity = null;
|
|
49
|
-
if (options.auth) {
|
|
50
|
-
resolvedAuth = (await options.auth(publicRequest, platform)) ?? null;
|
|
51
|
-
if (!resolvedAuth && options.allowUnauthenticated === false) {
|
|
52
|
-
return new Response("Unauthorized", { status: 401 });
|
|
53
|
-
}
|
|
54
|
-
if (resolvedAuth) {
|
|
55
|
-
const identityValue = options.identity
|
|
56
|
-
? options.identity(resolvedAuth)
|
|
57
|
-
: defaultIdentity(resolvedAuth);
|
|
58
|
-
identity = identityValue == null ? null : String(identityValue);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else if (options.allowUnauthenticated === false) {
|
|
62
|
-
return new Response("Unauthorized", { status: 401 });
|
|
63
|
-
}
|
|
64
|
-
const forwardedHeaders = new Headers(publicRequest.headers);
|
|
65
|
-
forwardedHeaders.delete(INTERNAL_AUTH_HEADER);
|
|
66
|
-
if (resolvedAuth) {
|
|
67
|
-
forwardedHeaders.set(INTERNAL_AUTH_HEADER, serializeConnectionAuth(resolvedAuth, identity));
|
|
68
|
-
}
|
|
69
|
-
const forwardedRequest = new Request(withPath(publicRequest, "/websocket"), publicRequest);
|
|
70
|
-
for (const [key, value] of forwardedHeaders) {
|
|
71
|
-
forwardedRequest.headers.set(key, value);
|
|
72
|
-
}
|
|
73
|
-
return forwardToEngine(forwardedRequest, env, options.durableObjectBinding);
|
|
74
|
-
}
|
|
75
|
-
export function createSyncWorker(options) {
|
|
76
|
-
activeHandlers = options.handlers;
|
|
77
|
-
const durableObjectBinding = options.durableObjectBinding ?? "SYNC_ENGINE";
|
|
78
|
-
const websocketPath = options.websocketPath ?? "/api/sync";
|
|
79
|
-
const authMetadata = options.auth;
|
|
80
|
-
const allowUnauthenticated = options.allowUnauthenticated ??
|
|
81
|
-
authMetadata?.allowUnauthenticated ??
|
|
82
|
-
true;
|
|
2
|
+
import { configureSyncEngine, getSyncEngineHandlers, handleSyncRequest, } from "./handler.js";
|
|
3
|
+
export { configureSyncEngine, handleSyncRequest, } from "./handler.js";
|
|
4
|
+
export function createSyncAppWorker(app, options) {
|
|
5
|
+
configureSyncEngine(options.handlers);
|
|
83
6
|
return {
|
|
84
7
|
async fetch(request, env, ctx) {
|
|
85
8
|
const url = new URL(request.url);
|
|
86
|
-
const
|
|
87
|
-
if (url.pathname === websocketPath && request.method === "GET")
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
allowUnauthenticated,
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
if (url.pathname === "/websocket") {
|
|
96
|
-
return new Response("Not found", { status: 404 });
|
|
9
|
+
const websocketPath = options.websocketPath ?? "/api/sync";
|
|
10
|
+
if ((url.pathname === websocketPath && request.method === "GET") ||
|
|
11
|
+
((url.pathname === "/broadcast" ||
|
|
12
|
+
url.pathname === "/broadcast-batch") &&
|
|
13
|
+
request.method === "POST")) {
|
|
14
|
+
return handleSyncRequest(request, env, ctx, options);
|
|
97
15
|
}
|
|
98
|
-
|
|
99
|
-
url.pathname === "/broadcast-batch") &&
|
|
100
|
-
request.method === "POST") {
|
|
101
|
-
const headers = new Headers(request.headers);
|
|
102
|
-
headers.delete(INTERNAL_AUTH_HEADER);
|
|
103
|
-
return forwardToEngine(new Request(request, { headers }), workerEnv, durableObjectBinding);
|
|
104
|
-
}
|
|
105
|
-
return new Response("Not found", { status: 404 });
|
|
16
|
+
return app.fetch(request, env, ctx);
|
|
106
17
|
},
|
|
107
18
|
};
|
|
108
19
|
}
|
|
109
|
-
export function defineSyncWorker(options) {
|
|
110
|
-
return createSyncWorker(options);
|
|
111
|
-
}
|
|
112
20
|
export class SyncEngine extends SyncEngineBase {
|
|
113
21
|
constructor(ctx, env) {
|
|
114
|
-
super(ctx, env,
|
|
22
|
+
super(ctx, env, getSyncEngineHandlers());
|
|
115
23
|
}
|
|
116
24
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { IncomingMessage } from "node:http";
|
|
2
|
+
import type { SyncHandler, SyncPlatform } from "./index.js";
|
|
3
|
+
export type SyncDevAuthOptions<TAuth = unknown> = {
|
|
4
|
+
auth?: (request: Request, platform: SyncPlatform) => Promise<TAuth | null | undefined> | TAuth | null | undefined;
|
|
5
|
+
identity?: (auth: TAuth) => string | number | bigint | null | undefined;
|
|
6
|
+
allowUnauthenticated?: boolean;
|
|
7
|
+
platform?: SyncPlatform | (() => Promise<SyncPlatform> | SyncPlatform);
|
|
8
|
+
wranglerConfigPath?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare function setHandlers(handlers: SyncHandler[]): void;
|
|
11
|
+
export declare function addClient(ws: {
|
|
12
|
+
send: (data: string) => void;
|
|
13
|
+
close: (code?: number, reason?: string) => void;
|
|
14
|
+
on: (event: string, listener: (...args: any[]) => void) => void;
|
|
15
|
+
}, req: IncomingMessage, options?: SyncDevAuthOptions): Promise<boolean>;
|
|
16
|
+
export declare function broadcastExternalChange(channel: string, action: "create" | "update" | "delete", key: string | undefined, data: any): Promise<void>;
|
|
17
|
+
export declare function broadcastExternalBatchChange(channel: string, changes: Array<{
|
|
18
|
+
action: "create" | "update" | "delete";
|
|
19
|
+
key?: string;
|
|
20
|
+
data?: any;
|
|
21
|
+
}>): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=dev-engine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dev-engine.d.ts","sourceRoot":"","sources":["dev-engine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAW5D,MAAM,MAAM,kBAAkB,CAAC,KAAK,GAAG,OAAO,IAAI;IAChD,IAAI,CAAC,EAAE,CACL,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,YAAY,KACnB,OAAO,CAAC,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;IAClE,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACxE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,EAAE,YAAY,GAAG,CAAC,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAC,CAAC;IACvE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAkBF,wBAAgB,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,QAWlD;AA4ED,wBAAsB,SAAS,CAC7B,EAAE,EAAE;IACF,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,KAAK,IAAI,CAAC;CACjE,EACD,GAAG,EAAE,eAAe,EACpB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,OAAO,CAAC,CA2ElB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,EACtC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,IAAI,EAAE,GAAG,iBAIV;AAED,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,CAAC,iBAIH"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { SyncBroker } from "./broker.js";
|
|
2
|
+
const GLOBAL_BROKER_KEY = "__sveltebase_sync_dev_broker__";
|
|
3
|
+
const GLOBAL_PLATFORM_KEY = "__sveltebase_sync_dev_platform__";
|
|
4
|
+
let devBroker = null;
|
|
5
|
+
function setGlobalBroker(state) {
|
|
6
|
+
const globalObject = globalThis;
|
|
7
|
+
globalObject[GLOBAL_BROKER_KEY] = state;
|
|
8
|
+
}
|
|
9
|
+
function getGlobalBroker() {
|
|
10
|
+
const globalObject = globalThis;
|
|
11
|
+
return globalObject[GLOBAL_BROKER_KEY];
|
|
12
|
+
}
|
|
13
|
+
export function setHandlers(handlers) {
|
|
14
|
+
const existing = getGlobalBroker();
|
|
15
|
+
if (!existing) {
|
|
16
|
+
const state = { broker: new SyncBroker(handlers) };
|
|
17
|
+
setGlobalBroker(state);
|
|
18
|
+
devBroker = state.broker;
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
existing.broker.setHandlers(handlers);
|
|
22
|
+
devBroker = existing.broker;
|
|
23
|
+
}
|
|
24
|
+
function getDevBroker() {
|
|
25
|
+
if (devBroker)
|
|
26
|
+
return devBroker;
|
|
27
|
+
const existing = getGlobalBroker();
|
|
28
|
+
if (existing) {
|
|
29
|
+
devBroker = existing.broker;
|
|
30
|
+
return existing.broker;
|
|
31
|
+
}
|
|
32
|
+
throw new Error("Sync dev broker not initialized. Call setHandlers first.");
|
|
33
|
+
}
|
|
34
|
+
function getHeaderValue(value) {
|
|
35
|
+
if (Array.isArray(value))
|
|
36
|
+
return value[0];
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
function headersFromIncomingMessage(req) {
|
|
40
|
+
const headers = new Headers();
|
|
41
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
42
|
+
if (value === undefined)
|
|
43
|
+
continue;
|
|
44
|
+
if (Array.isArray(value)) {
|
|
45
|
+
for (const item of value)
|
|
46
|
+
headers.append(key, item);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
headers.set(key, value);
|
|
50
|
+
}
|
|
51
|
+
return headers;
|
|
52
|
+
}
|
|
53
|
+
function requestFromIncomingMessage(req) {
|
|
54
|
+
const host = getHeaderValue(req.headers.host) ?? "localhost";
|
|
55
|
+
const url = new URL(req.url ?? "", `http://${host}`);
|
|
56
|
+
return new Request(url.toString(), {
|
|
57
|
+
headers: headersFromIncomingMessage(req),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async function resolvePlatform(options) {
|
|
61
|
+
if (options?.platform) {
|
|
62
|
+
return typeof options.platform === "function"
|
|
63
|
+
? await options.platform()
|
|
64
|
+
: options.platform;
|
|
65
|
+
}
|
|
66
|
+
const globalObject = globalThis;
|
|
67
|
+
const existing = globalObject[GLOBAL_PLATFORM_KEY];
|
|
68
|
+
if (existing)
|
|
69
|
+
return existing.platform;
|
|
70
|
+
try {
|
|
71
|
+
const { getPlatformProxy } = await import("wrangler");
|
|
72
|
+
const proxy = await getPlatformProxy(options?.wranglerConfigPath
|
|
73
|
+
? { configPath: options.wranglerConfigPath }
|
|
74
|
+
: undefined);
|
|
75
|
+
const platform = proxy;
|
|
76
|
+
globalObject[GLOBAL_PLATFORM_KEY] = { platform };
|
|
77
|
+
return platform;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
const platform = { env: {} };
|
|
81
|
+
globalObject[GLOBAL_PLATFORM_KEY] = { platform };
|
|
82
|
+
return platform;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function defaultIdentity(auth) {
|
|
86
|
+
const value = auth?.identity ?? auth?.user?.id ?? auth?.userId;
|
|
87
|
+
return value == null ? null : String(value);
|
|
88
|
+
}
|
|
89
|
+
export async function addClient(ws, req, options) {
|
|
90
|
+
const broker = getDevBroker();
|
|
91
|
+
const request = requestFromIncomingMessage(req);
|
|
92
|
+
const platform = await resolvePlatform(options);
|
|
93
|
+
const subscribedChannels = new Set();
|
|
94
|
+
let auth = null;
|
|
95
|
+
let identity = null;
|
|
96
|
+
try {
|
|
97
|
+
if (options?.auth) {
|
|
98
|
+
auth = (await options.auth(request, platform)) ?? null;
|
|
99
|
+
if (!auth && options.allowUnauthenticated === false) {
|
|
100
|
+
ws.close(1008, "Unauthorized");
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
if (auth) {
|
|
104
|
+
const identityValue = options.identity
|
|
105
|
+
? options.identity(auth)
|
|
106
|
+
: defaultIdentity(auth);
|
|
107
|
+
identity = identityValue == null ? null : String(identityValue);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
ws.close(1011, "Internal server error");
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
const conn = {
|
|
116
|
+
send(data) {
|
|
117
|
+
ws.send(data);
|
|
118
|
+
},
|
|
119
|
+
close(code, reason) {
|
|
120
|
+
ws.close(code, reason);
|
|
121
|
+
},
|
|
122
|
+
getAuth() {
|
|
123
|
+
return auth;
|
|
124
|
+
},
|
|
125
|
+
setAuth(newAuth) {
|
|
126
|
+
auth = newAuth;
|
|
127
|
+
},
|
|
128
|
+
getIdentity() {
|
|
129
|
+
return identity;
|
|
130
|
+
},
|
|
131
|
+
setIdentity(newIdentity) {
|
|
132
|
+
identity = newIdentity;
|
|
133
|
+
},
|
|
134
|
+
getSubscribedChannels() {
|
|
135
|
+
return subscribedChannels;
|
|
136
|
+
},
|
|
137
|
+
headers: request.headers,
|
|
138
|
+
url: request.url,
|
|
139
|
+
};
|
|
140
|
+
broker.registerConnection(conn);
|
|
141
|
+
ws.on("message", async (data) => {
|
|
142
|
+
const message = typeof data === "string" ? data : String(data);
|
|
143
|
+
try {
|
|
144
|
+
await broker.handleMessage(conn, message, platform, request);
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
console.error("sync dev engine: error handling message", err);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
ws.on("close", () => {
|
|
151
|
+
broker.removeConnection(conn);
|
|
152
|
+
});
|
|
153
|
+
ws.on("error", () => {
|
|
154
|
+
broker.removeConnection(conn);
|
|
155
|
+
});
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
export async function broadcastExternalChange(channel, action, key, data) {
|
|
159
|
+
const broker = getDevBroker();
|
|
160
|
+
await broker.handleExternalChange(channel, action, key, data);
|
|
161
|
+
}
|
|
162
|
+
export async function broadcastExternalBatchChange(channel, changes) {
|
|
163
|
+
const broker = getDevBroker();
|
|
164
|
+
await broker.handleExternalBatchChange(channel, changes);
|
|
165
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAE5D,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAoE7C,qBAAa,cAAe,SAAQ,aAAa,CAAC,aAAa,CAAC;IAC9D,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC;IAC7B,OAAO,CAAC,OAAO,CAAkD;gBAG/D,GAAG,EAAE,kBAAkB,EACvB,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,WAAW,EAAE;IAMnB,KAAK,CAAC,OAAO,EAAE,OAAO;IAoC5B,OAAO,CAAC,gBAAgB;IA4BlB,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW;IAoBnE,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAa1D,cAAc,CAAC,EAAE,EAAE,SAAS;CAO7B"}
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/server/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAC;AAE/D,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAE5D,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAoE7C,qBAAa,cAAe,SAAQ,aAAa,CAAC,aAAa,CAAC;IAC9D,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC;IAC7B,OAAO,CAAC,OAAO,CAAkD;gBAG/D,GAAG,EAAE,kBAAkB,EACvB,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,WAAW,EAAE;IAMnB,KAAK,CAAC,OAAO,EAAE,OAAO;IAoC5B,OAAO,CAAC,gBAAgB;IA4BlB,gBAAgB,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,WAAW;IAoBnE,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAa1D,cAAc,CAAC,EAAE,EAAE,SAAS;CAO7B"}
|
package/dist/server/handler.d.ts
CHANGED
|
@@ -8,8 +8,6 @@ export type InferSchemaFromHandlers<T extends SyncHandler[]> = {
|
|
|
8
8
|
[K in T[number] as K["config"]["channel"] extends string ? K["config"]["channel"] : K["config"]["channel"] extends (...args: any[]) => infer R ? R extends string ? R : string : string]: K extends SyncHandler<infer TRow> ? TRow : never;
|
|
9
9
|
};
|
|
10
10
|
export type SyncPublisherOptions = {
|
|
11
|
-
binding?: string;
|
|
12
|
-
fallbackUrl?: string;
|
|
13
11
|
durableObjectBinding?: string;
|
|
14
12
|
platform?: SyncPlatform;
|
|
15
13
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,MAAM,cAAc,CAAC,KAAK,IAAI,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;AAE7D,eAAO,MAAM,oBAAoB,2BAA2B,CAAC;AAE7D,MAAM,MAAM,gBAAgB,CAC1B,OAAO,EACP,OAAO,SAAS,QAAQ,GAAG,QAAQ,GAAG,QAAQ,IAC5C,OAAO,SAAS,QAAQ,GACxB,OAAO,GACP,OAAO,SAAS,QAAQ,GACtB,OAAO,CAAC,OAAO,CAAC,GAChB;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC;AAEzC,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,WAAW,EAAE,IAAI;KAC5D,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,SAAS,MAAM,GACpD,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,GACtB,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GACxD,CAAC,SAAS,MAAM,GACd,CAAC,GACD,MAAM,GACR,MAAM,GAAG,CAAC,SAAS,WAAW,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK;CAChE,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["handler.ts"],"names":[],"mappings":"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"}
|
package/dist/server/handler.js
CHANGED
|
@@ -2,8 +2,9 @@ export const INTERNAL_AUTH_HEADER = "x-sveltebase-sync-auth";
|
|
|
2
2
|
function getEnv(options) {
|
|
3
3
|
return options.platform?.env;
|
|
4
4
|
}
|
|
5
|
-
function
|
|
6
|
-
|
|
5
|
+
function hasDevBroker() {
|
|
6
|
+
const globalObject = globalThis;
|
|
7
|
+
return Boolean(globalObject.__sveltebase_sync_dev_broker__);
|
|
7
8
|
}
|
|
8
9
|
async function publishToDurableObject(platform, durableObjectBinding, pathname, body) {
|
|
9
10
|
const namespace = platform.env[durableObjectBinding];
|
|
@@ -21,44 +22,26 @@ async function publishToDurableObject(platform, durableObjectBinding, pathname,
|
|
|
21
22
|
throw new Error(await response.text());
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
|
-
async function
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
if (!response.ok) {
|
|
31
|
-
throw new Error(await response.text());
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
async function publishToFallbackUrl(fallbackUrl, pathname, body) {
|
|
35
|
-
const response = await fetch(normalizeEndpoint(fallbackUrl, pathname), {
|
|
36
|
-
method: "POST",
|
|
37
|
-
headers: { "Content-Type": "application/json" },
|
|
38
|
-
body: JSON.stringify(body),
|
|
39
|
-
});
|
|
40
|
-
if (!response.ok) {
|
|
41
|
-
throw new Error(await response.text());
|
|
25
|
+
async function publishToDevBroker(pathname, body) {
|
|
26
|
+
const devEngine = await import("./dev-engine.js");
|
|
27
|
+
if (pathname === "/broadcast-batch") {
|
|
28
|
+
await devEngine.broadcastExternalBatchChange(String(body.channel), Array.isArray(body.changes) ? body.changes : []);
|
|
29
|
+
return;
|
|
42
30
|
}
|
|
31
|
+
await devEngine.broadcastExternalChange(String(body.channel), body.action, body.key, body.data);
|
|
43
32
|
}
|
|
44
33
|
async function publish(options, pathname, body) {
|
|
45
34
|
const env = getEnv(options);
|
|
46
35
|
const durableObjectBinding = options.durableObjectBinding ?? "SYNC_ENGINE";
|
|
47
|
-
const bindingName = options.binding ?? "SYNC_WORKER";
|
|
48
36
|
if (options.platform && env?.[durableObjectBinding]) {
|
|
49
37
|
await publishToDurableObject(options.platform, durableObjectBinding, pathname, body);
|
|
50
38
|
return;
|
|
51
39
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
await publishToServiceBinding(serviceBinding, pathname, body);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (options.fallbackUrl) {
|
|
58
|
-
await publishToFallbackUrl(options.fallbackUrl, pathname, body);
|
|
40
|
+
if (hasDevBroker()) {
|
|
41
|
+
await publishToDevBroker(pathname, body);
|
|
59
42
|
return;
|
|
60
43
|
}
|
|
61
|
-
throw new Error(`Missing sync publisher target: provide platform.env.${durableObjectBinding}
|
|
44
|
+
throw new Error(`Missing sync publisher target: provide platform.env.${durableObjectBinding} or run vite dev with syncDevPlugin()`);
|
|
62
45
|
}
|
|
63
46
|
export function createPublisher(options, handlers) {
|
|
64
47
|
void handlers;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -35,5 +35,4 @@ export interface SyncHandler<TRow = any, TAuth = any> {
|
|
|
35
35
|
export declare function defineSync<TRow = any, TAuth = any>(config: SyncHandlerConfig<TRow, TAuth>): SyncHandler<TRow, TAuth>;
|
|
36
36
|
export { createBulkPublisher, createPublisher, INTERNAL_AUTH_HEADER, } from "./handler.js";
|
|
37
37
|
export type { BulkPublishFn, InferSchemaFromHandlers, PublishEventData, PublishFn, SyncAuthResult, SyncPublisherOptions, } from "./handler.js";
|
|
38
|
-
export { SyncEngineBase } from "./engine.js";
|
|
39
38
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { RequestHandler } from "@sveltejs/kit";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
6
|
-
export declare function syncProxy(options?: SyncProxyOptions): {
|
|
2
|
+
import { type SyncWorkerOptions } from "../cloudflare/handler.js";
|
|
3
|
+
export type SyncEngineRouteOptions<TAuth = unknown> = SyncWorkerOptions<TAuth>;
|
|
4
|
+
export declare function syncEngineRoute<TAuth = unknown>(options: SyncEngineRouteOptions<TAuth>): {
|
|
7
5
|
GET: RequestHandler;
|
|
8
|
-
POST: RequestHandler;
|
|
9
6
|
};
|
|
10
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sveltekit/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sveltekit/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAElC,MAAM,MAAM,sBAAsB,CAAC,KAAK,GAAG,OAAO,IAChD,iBAAiB,CAAC,KAAK,CAAC,CAAC;AAkB3B,wBAAgB,eAAe,CAAC,KAAK,GAAG,OAAO,EAC7C,OAAO,EAAE,sBAAsB,CAAC,KAAK,CAAC,GACrC;IACD,GAAG,EAAE,cAAc,CAAC;CACrB,CAuBA"}
|
package/dist/sveltekit/index.js
CHANGED
|
@@ -1,29 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
});
|
|
1
|
+
import { handleSyncRequest, } from "../cloudflare/handler.js";
|
|
2
|
+
function getExecutionContext(platform) {
|
|
3
|
+
const context = platform?.context ?? platform?.ctx;
|
|
4
|
+
if (context)
|
|
5
|
+
return context;
|
|
6
|
+
return {
|
|
7
|
+
waitUntil() { },
|
|
8
|
+
passThroughOnException() { },
|
|
9
|
+
};
|
|
11
10
|
}
|
|
12
|
-
export function
|
|
13
|
-
const bindingName = options?.binding ?? "SYNC_WORKER";
|
|
11
|
+
export function syncEngineRoute(options) {
|
|
14
12
|
const handler = async (event) => {
|
|
15
13
|
const platform = event.platform;
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
18
|
-
return
|
|
19
|
-
}
|
|
20
|
-
if (options?.fallbackUrl) {
|
|
21
|
-
return fetch(buildFallbackRequest(event.request, options.fallbackUrl));
|
|
14
|
+
const env = platform?.env;
|
|
15
|
+
if (!env) {
|
|
16
|
+
return new Response("Missing Cloudflare platform env. Configure adapter-cloudflare platformProxy for Vite dev or run under wrangler.", { status: 500 });
|
|
22
17
|
}
|
|
23
|
-
return
|
|
18
|
+
return handleSyncRequest(event.request, env, getExecutionContext(platform), options);
|
|
24
19
|
};
|
|
25
20
|
return {
|
|
26
21
|
GET: handler,
|
|
27
|
-
POST: handler,
|
|
28
22
|
};
|
|
29
23
|
}
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import type { SyncDevAuthOptions } from "./server/dev-engine.js";
|
|
3
|
+
export type SyncDevPluginOptions<TAuth = unknown> = SyncDevAuthOptions<TAuth> & {
|
|
4
|
+
handlersPath?: string;
|
|
5
|
+
path?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function syncDevPlugin<TAuth = unknown>(options?: SyncDevPluginOptions<TAuth>): Plugin;
|
|
8
|
+
//# sourceMappingURL=vite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAajE,MAAM,MAAM,oBAAoB,CAAC,KAAK,GAAG,OAAO,IAAI,kBAAkB,CAAC,KAAK,CAAC,GAAG;IAC9E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,wBAAgB,aAAa,CAAC,KAAK,GAAG,OAAO,EAC3C,OAAO,CAAC,EAAE,oBAAoB,CAAC,KAAK,CAAC,GACpC,MAAM,CA6ER"}
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const DEFAULT_SYNC_PATH = "/api/sync";
|
|
2
|
+
export function syncDevPlugin(options) {
|
|
3
|
+
const handlersPath = options?.handlersPath ?? "/src/lib/server/sync-handlers.ts";
|
|
4
|
+
const syncPath = options?.path ?? DEFAULT_SYNC_PATH;
|
|
5
|
+
return {
|
|
6
|
+
name: "sveltebase-sync-dev-websocket",
|
|
7
|
+
apply: "serve",
|
|
8
|
+
async configureServer(server) {
|
|
9
|
+
const { WebSocketServer } = (await import("ws"));
|
|
10
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
11
|
+
server.httpServer?.on("upgrade", (request, socket, head) => {
|
|
12
|
+
const url = new URL(request.url ?? "", `http://${request.headers.host ?? "localhost"}`);
|
|
13
|
+
if (url.pathname !== syncPath) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
wss.handleUpgrade(request, socket, head, (client) => {
|
|
17
|
+
const messageQueue = [];
|
|
18
|
+
const onMessage = (data) => {
|
|
19
|
+
messageQueue.push(data);
|
|
20
|
+
};
|
|
21
|
+
client.on("message", onMessage);
|
|
22
|
+
void (async () => {
|
|
23
|
+
try {
|
|
24
|
+
const handlersModule = await server.ssrLoadModule(handlersPath);
|
|
25
|
+
const devEngine = await server.ssrLoadModule("@sveltebase/sync/server/dev-engine");
|
|
26
|
+
devEngine.setHandlers(handlersModule.handlers);
|
|
27
|
+
client.off("message", onMessage);
|
|
28
|
+
const connected = await devEngine.addClient(client, request, {
|
|
29
|
+
auth: options?.auth,
|
|
30
|
+
identity: options?.identity,
|
|
31
|
+
allowUnauthenticated: options?.allowUnauthenticated,
|
|
32
|
+
platform: options?.platform,
|
|
33
|
+
wranglerConfigPath: options?.wranglerConfigPath,
|
|
34
|
+
});
|
|
35
|
+
if (!connected)
|
|
36
|
+
return;
|
|
37
|
+
for (const message of messageQueue) {
|
|
38
|
+
client.emit("message", message);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
console.error("sync dev plugin: websocket upgrade failed", err);
|
|
43
|
+
try {
|
|
44
|
+
client.off("message", onMessage);
|
|
45
|
+
client.close(1011, "Internal server error");
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Ignore close errors.
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
})();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltebase/sync",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"types": "./dist/server/index.d.ts",
|
|
26
26
|
"default": "./dist/server/index.js"
|
|
27
27
|
},
|
|
28
|
+
"./server/dev-engine": {
|
|
29
|
+
"types": "./dist/server/dev-engine.d.ts",
|
|
30
|
+
"default": "./dist/server/dev-engine.js"
|
|
31
|
+
},
|
|
28
32
|
"./sveltekit": {
|
|
29
33
|
"types": "./dist/sveltekit/index.d.ts",
|
|
30
34
|
"default": "./dist/sveltekit/index.js"
|
|
@@ -32,10 +36,15 @@
|
|
|
32
36
|
"./cloudflare": {
|
|
33
37
|
"types": "./dist/cloudflare/index.d.ts",
|
|
34
38
|
"default": "./dist/cloudflare/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./vite": {
|
|
41
|
+
"types": "./dist/vite.d.ts",
|
|
42
|
+
"default": "./dist/vite.js"
|
|
35
43
|
}
|
|
36
44
|
},
|
|
37
45
|
"dependencies": {
|
|
38
|
-
"dexie": "^4.0.8"
|
|
46
|
+
"dexie": "^4.0.8",
|
|
47
|
+
"ws": "^8.18.3"
|
|
39
48
|
},
|
|
40
49
|
"peerDependencies": {
|
|
41
50
|
"svelte": "^5.0.0",
|