@oselvar/sveltekit-add-worker-exports 0.2.0 → 0.3.1
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 +41 -7
- package/dist/bridge/dev-handler.d.ts +27 -0
- package/dist/bridge/dev-handler.js +88 -0
- package/dist/bridge/runtime-hook.d.ts +32 -0
- package/dist/bridge/runtime-hook.js +105 -0
- package/dist/bridge/setup.d.ts +31 -0
- package/dist/bridge/setup.js +66 -0
- package/dist/hooks.d.ts +13 -0
- package/dist/hooks.js +13 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +157 -18
- package/package.json +63 -50
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A Vite plugin that makes Durable Objects and Workflows work with SvelteKit on Cl
|
|
|
4
4
|
|
|
5
5
|
**Build mode:** SvelteKit's `adapter-cloudflare` generates `_worker.js` with only a default export (the fetch handler). Cloudflare Workers requires Durable Object and Workflow classes to be **named exports**. This plugin post-processes the build output to merge your named exports with SvelteKit's default export.
|
|
6
6
|
|
|
7
|
-
**Dev mode:** `getPlatformProxy` (used by `adapter-cloudflare` in dev) can't run internal Durable Objects. This plugin starts a separate wrangler dev server that runs the real DO worker with hot-reload. Clients connect directly to
|
|
7
|
+
**Dev mode:** `getPlatformProxy` (used by `adapter-cloudflare` in dev) can't run internal Durable Objects or Workflows. This plugin starts a separate wrangler dev server that runs the real DO/Workflow worker with hot-reload. SvelteKit `+server.ts` handlers call DOs through `platform.env.MY_DO.<rpc>()` as usual — the plugin rewrites those bindings to point at the sidecar via wrangler's dev registry, so cross-worker calls Just Work. Clients can also connect directly to the sidecar via WebSocket on a separate port (see below).
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -87,7 +87,7 @@ export default defineConfig({
|
|
|
87
87
|
});
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
Point `adapter-cloudflare`'s platform proxy at the generated `.platform-proxy-wrangler.jsonc`.
|
|
90
|
+
Point `adapter-cloudflare`'s platform proxy at the generated `.platform-proxy-wrangler.jsonc`. The plugin writes this file with internal Durable Object bindings rewritten to cross-worker form (each gets a `script_name` pointing at the sidecar). Workflows can't survive `getPlatformProxy` (wrangler unconditionally deletes them), so the plugin replaces them with a service binding pointing at the sidecar; a small SvelteKit hook synthesizes the missing `Workflow` API on top of that bridge — see [Dev mode: calling Workflows](#dev-mode-calling-workflows) below. Without this config path, `getPlatformProxy` would try to run the DO classes itself and warn that it can't:
|
|
91
91
|
|
|
92
92
|
```javascript
|
|
93
93
|
// svelte.config.js
|
|
@@ -129,7 +129,41 @@ declare global {
|
|
|
129
129
|
}
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
The plugin auto-discovers your `wrangler.jsonc` (or `wrangler.toml`) and reads DO bindings, migrations, and compatibility settings from it. It overrides only the `main` entry point to use your
|
|
132
|
+
The plugin auto-discovers your `wrangler.jsonc` (or `wrangler.toml`) and reads DO bindings, workflows, migrations, and compatibility settings from it. It overrides only the `main` entry point to use a generated wrapper (in `node_modules/.cache/sveltekit-add-worker-exports/`) that re-exports your classes and adds the workflow bridge routes.
|
|
133
|
+
|
|
134
|
+
### Dev mode: calling Workflows
|
|
135
|
+
|
|
136
|
+
Workflow bindings can't be passed through `getPlatformProxy` — wrangler unconditionally strips them ([source](https://github.com/cloudflare/workers-sdk/blob/main/packages/wrangler/src/api/integrations/platform/index.ts)). The plugin works around this by adding a service binding to the sidecar and shipping a SvelteKit `Handle` that synthesizes `Workflow`-shaped objects on `platform.env`.
|
|
137
|
+
|
|
138
|
+
Wire it up in `src/hooks.server.ts`:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
export { handle } from '@oselvar/sveltekit-add-worker-exports/hooks';
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
If you already have a `handle`, compose with `sequence`:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
import { sequence } from '@sveltejs/kit/hooks';
|
|
148
|
+
import { handle as sweHandle } from '@oselvar/sveltekit-add-worker-exports/hooks';
|
|
149
|
+
import { handle as myHandle } from './my-handle';
|
|
150
|
+
|
|
151
|
+
export const handle = sequence(sweHandle, myHandle);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
After that, `+server.ts` can call workflows the same way it does in production:
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
export const POST: RequestHandler = async ({ params, request, platform }) => {
|
|
158
|
+
const userMessage = await request.text();
|
|
159
|
+
const instance = await platform!.env.MY_WORKFLOW.create({
|
|
160
|
+
params: { ... }
|
|
161
|
+
});
|
|
162
|
+
return new Response(instance.id);
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
In production the hook is a no-op — it reads its config from runtime globals that only the dev plugin sets, and `platform.env.MY_WORKFLOW` is the real Cloudflare binding.
|
|
133
167
|
|
|
134
168
|
### Testing the production build locally
|
|
135
169
|
|
|
@@ -191,10 +225,10 @@ The plugin reads your wrangler config, creates a temporary config with `main` po
|
|
|
191
225
|
|
|
192
226
|
### Generating typed bindings
|
|
193
227
|
|
|
194
|
-
The dev plugin creates a temporary `.
|
|
228
|
+
The dev plugin creates a temporary `.types-worker-wrangler.jsonc` with `main` pointing to your source entry point. Use it to generate fully generic Cloudflare types:
|
|
195
229
|
|
|
196
230
|
```bash
|
|
197
|
-
wrangler types --config .
|
|
231
|
+
wrangler types --config .types-worker-wrangler.jsonc
|
|
198
232
|
```
|
|
199
233
|
|
|
200
234
|
This produces typed DO bindings like `DurableObjectNamespace<MyDurableObject>` instead of the untyped `DurableObjectNamespace` you get from the default `wrangler.jsonc` (whose `main` points to the SvelteKit build output, which doesn't exist during dev).
|
|
@@ -204,12 +238,12 @@ Add this to your `package.json` scripts for convenience:
|
|
|
204
238
|
```json
|
|
205
239
|
{
|
|
206
240
|
"scripts": {
|
|
207
|
-
"types": "wrangler types --config .
|
|
241
|
+
"types": "wrangler types --config .types-worker-wrangler.jsonc"
|
|
208
242
|
}
|
|
209
243
|
}
|
|
210
244
|
```
|
|
211
245
|
|
|
212
|
-
Note: the `.
|
|
246
|
+
Note: the `.types-worker-wrangler.jsonc` file is generated when the dev server starts. Run `pnpm dev` at least once before running `wrangler types`. (The plugin also writes `.dev-worker-wrangler.jsonc` for the runtime sidecar, but its `main` points at a generated bridge wrapper in `node_modules/.cache/`, which can't be used for type generation — wrangler doesn't follow `export *` re-exports out of node_modules.)
|
|
213
247
|
|
|
214
248
|
## Why this exists
|
|
215
249
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workerd-side bridge handler. Bundled into the dev sidecar by wrangler via
|
|
3
|
+
* the cache wrapper at `node_modules/.cache/sveltekit-add-worker-exports/`.
|
|
4
|
+
*
|
|
5
|
+
* The wrapper imports `createBridgeFetch` from this file and uses it as the
|
|
6
|
+
* default fetch handler. Routes `/__swe/wf/*` are handled here; anything else
|
|
7
|
+
* delegates to the user's own default fetch handler.
|
|
8
|
+
*
|
|
9
|
+
* This file is part of the workflow-bridge fallback that exists because
|
|
10
|
+
* `getPlatformProxy()` in unpatched wrangler/miniflare strips workflow
|
|
11
|
+
* bindings. Once the upstream patch lands (cloudflare/workers-sdk#7459),
|
|
12
|
+
* the entire `src/bridge/` directory can be deleted.
|
|
13
|
+
*/
|
|
14
|
+
type CtxLike = {
|
|
15
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
16
|
+
};
|
|
17
|
+
type UserFetch = (request: Request, env: unknown, ctx: CtxLike) => Promise<Response> | Response;
|
|
18
|
+
export interface BridgeOptions {
|
|
19
|
+
workflowBindings: readonly string[];
|
|
20
|
+
userFetch?: UserFetch;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Returns a `fetch` handler that intercepts `/__swe/wf/*` and forwards
|
|
24
|
+
* everything else to `userFetch`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createBridgeFetch(options: BridgeOptions): (request: Request, env: unknown, ctx: CtxLike) => Promise<Response>;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workerd-side bridge handler. Bundled into the dev sidecar by wrangler via
|
|
3
|
+
* the cache wrapper at `node_modules/.cache/sveltekit-add-worker-exports/`.
|
|
4
|
+
*
|
|
5
|
+
* The wrapper imports `createBridgeFetch` from this file and uses it as the
|
|
6
|
+
* default fetch handler. Routes `/__swe/wf/*` are handled here; anything else
|
|
7
|
+
* delegates to the user's own default fetch handler.
|
|
8
|
+
*
|
|
9
|
+
* This file is part of the workflow-bridge fallback that exists because
|
|
10
|
+
* `getPlatformProxy()` in unpatched wrangler/miniflare strips workflow
|
|
11
|
+
* bindings. Once the upstream patch lands (cloudflare/workers-sdk#7459),
|
|
12
|
+
* the entire `src/bridge/` directory can be deleted.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Returns a `fetch` handler that intercepts `/__swe/wf/*` and forwards
|
|
16
|
+
* everything else to `userFetch`.
|
|
17
|
+
*/
|
|
18
|
+
export function createBridgeFetch(options) {
|
|
19
|
+
const bindings = new Set(options.workflowBindings);
|
|
20
|
+
return async (request, env, ctx) => {
|
|
21
|
+
const url = new URL(request.url);
|
|
22
|
+
if (url.pathname.startsWith('/__swe/wf/')) {
|
|
23
|
+
return handleWf(url.pathname.slice('/__swe/wf/'.length), request, env, bindings);
|
|
24
|
+
}
|
|
25
|
+
if (options.userFetch) {
|
|
26
|
+
return options.userFetch(request, env, ctx);
|
|
27
|
+
}
|
|
28
|
+
return new Response('Not found', { status: 404 });
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function handleWf(rest, request, env, bindings) {
|
|
32
|
+
const parts = rest.split('/').map(decodeURIComponent);
|
|
33
|
+
const [binding, op, ...tail] = parts;
|
|
34
|
+
if (!binding || !bindings.has(binding)) {
|
|
35
|
+
return new Response('unknown workflow binding: ' + binding, { status: 404 });
|
|
36
|
+
}
|
|
37
|
+
const wf = env[binding];
|
|
38
|
+
if (!wf) {
|
|
39
|
+
return new Response('binding ' + binding + ' missing on sidecar', { status: 500 });
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
if (op === 'create' && request.method === 'POST') {
|
|
43
|
+
const opts = await request.json();
|
|
44
|
+
const inst = await wf.create(opts);
|
|
45
|
+
return Response.json({ id: inst.id });
|
|
46
|
+
}
|
|
47
|
+
if (op === 'createBatch' && request.method === 'POST') {
|
|
48
|
+
const batch = (await request.json());
|
|
49
|
+
const insts = await wf.createBatch(batch);
|
|
50
|
+
return Response.json(insts.map((i) => ({ id: i.id })));
|
|
51
|
+
}
|
|
52
|
+
if (op === 'get' && tail.length === 1) {
|
|
53
|
+
const inst = await wf.get(tail[0]);
|
|
54
|
+
return Response.json({ id: inst.id });
|
|
55
|
+
}
|
|
56
|
+
if (op === 'instance' && tail.length === 2) {
|
|
57
|
+
const [id, method] = tail;
|
|
58
|
+
const inst = await wf.get(id);
|
|
59
|
+
switch (method) {
|
|
60
|
+
case 'pause':
|
|
61
|
+
await inst.pause();
|
|
62
|
+
return new Response(null, { status: 204 });
|
|
63
|
+
case 'resume':
|
|
64
|
+
await inst.resume();
|
|
65
|
+
return new Response(null, { status: 204 });
|
|
66
|
+
case 'terminate':
|
|
67
|
+
await inst.terminate();
|
|
68
|
+
return new Response(null, { status: 204 });
|
|
69
|
+
case 'restart':
|
|
70
|
+
await inst.restart();
|
|
71
|
+
return new Response(null, { status: 204 });
|
|
72
|
+
case 'status':
|
|
73
|
+
return Response.json(await inst.status());
|
|
74
|
+
case 'sendEvent': {
|
|
75
|
+
const body = (await request.json());
|
|
76
|
+
await inst.sendEvent(body);
|
|
77
|
+
return new Response(null, { status: 204 });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return new Response('unknown method: ' + method, { status: 404 });
|
|
81
|
+
}
|
|
82
|
+
return new Response('unknown op: ' + op, { status: 404 });
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
86
|
+
return new Response('error: ' + message, { status: 500 });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit `Handle` that injects fake Workflow bindings into `event.platform.env`
|
|
3
|
+
* during `vite dev`. In production this is a no-op.
|
|
4
|
+
*
|
|
5
|
+
* Why: wrangler's `getPlatformProxy` (used by `adapter-cloudflare` in dev) deletes
|
|
6
|
+
* workflow bindings before they reach miniflare, so `+server.ts` can't call
|
|
7
|
+
* `platform.env.MY_WORKFLOW.create(...)` directly. The companion vite plugin
|
|
8
|
+
* exposes a service binding (`__SWE_BRIDGE`) that fetches into a sidecar wrangler
|
|
9
|
+
* dev worker which has the real workflow binding. This hook synthesizes a
|
|
10
|
+
* `Workflow`-shaped object per declared workflow that proxies API calls through
|
|
11
|
+
* that bridge.
|
|
12
|
+
*
|
|
13
|
+
* Usage in `src/hooks.server.ts`:
|
|
14
|
+
*
|
|
15
|
+
* export { handle } from '@oselvar/sveltekit-add-worker-exports/hooks';
|
|
16
|
+
*
|
|
17
|
+
* If you already have a `handle`, compose with `sequence`:
|
|
18
|
+
*
|
|
19
|
+
* import { sequence } from '@sveltejs/kit/hooks';
|
|
20
|
+
* import { handle as sweHandle } from '@oselvar/sveltekit-add-worker-exports/hooks';
|
|
21
|
+
* export const handle = sequence(sweHandle, myHandle);
|
|
22
|
+
*/
|
|
23
|
+
import type { Handle } from '@sveltejs/kit';
|
|
24
|
+
/**
|
|
25
|
+
* Reads bridge config from `globalThis`, set by the vite dev plugin at startup.
|
|
26
|
+
*
|
|
27
|
+
* We can't rely on vite `define` / compile-time substitution here because this
|
|
28
|
+
* file ships in node_modules and vite doesn't transform external modules in
|
|
29
|
+
* SSR by default. Plain runtime globals dodge that entirely and stay
|
|
30
|
+
* `undefined` in production (workerd), making this hook a no-op there.
|
|
31
|
+
*/
|
|
32
|
+
export declare const handle: Handle;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit `Handle` that injects fake Workflow bindings into `event.platform.env`
|
|
3
|
+
* during `vite dev`. In production this is a no-op.
|
|
4
|
+
*
|
|
5
|
+
* Why: wrangler's `getPlatformProxy` (used by `adapter-cloudflare` in dev) deletes
|
|
6
|
+
* workflow bindings before they reach miniflare, so `+server.ts` can't call
|
|
7
|
+
* `platform.env.MY_WORKFLOW.create(...)` directly. The companion vite plugin
|
|
8
|
+
* exposes a service binding (`__SWE_BRIDGE`) that fetches into a sidecar wrangler
|
|
9
|
+
* dev worker which has the real workflow binding. This hook synthesizes a
|
|
10
|
+
* `Workflow`-shaped object per declared workflow that proxies API calls through
|
|
11
|
+
* that bridge.
|
|
12
|
+
*
|
|
13
|
+
* Usage in `src/hooks.server.ts`:
|
|
14
|
+
*
|
|
15
|
+
* export { handle } from '@oselvar/sveltekit-add-worker-exports/hooks';
|
|
16
|
+
*
|
|
17
|
+
* If you already have a `handle`, compose with `sequence`:
|
|
18
|
+
*
|
|
19
|
+
* import { sequence } from '@sveltejs/kit/hooks';
|
|
20
|
+
* import { handle as sweHandle } from '@oselvar/sveltekit-add-worker-exports/hooks';
|
|
21
|
+
* export const handle = sequence(sweHandle, myHandle);
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Reads bridge config from `globalThis`, set by the vite dev plugin at startup.
|
|
25
|
+
*
|
|
26
|
+
* We can't rely on vite `define` / compile-time substitution here because this
|
|
27
|
+
* file ships in node_modules and vite doesn't transform external modules in
|
|
28
|
+
* SSR by default. Plain runtime globals dodge that entirely and stay
|
|
29
|
+
* `undefined` in production (workerd), making this hook a no-op there.
|
|
30
|
+
*/
|
|
31
|
+
export const handle = async ({ event, resolve }) => {
|
|
32
|
+
const g = globalThis;
|
|
33
|
+
const bridgeName = g.__SWE_BRIDGE_NAME__;
|
|
34
|
+
const workflows = g.__SWE_WORKFLOWS__;
|
|
35
|
+
if (!bridgeName || !workflows || workflows.length === 0)
|
|
36
|
+
return resolve(event);
|
|
37
|
+
const env = event.platform?.env;
|
|
38
|
+
if (!env)
|
|
39
|
+
return resolve(event);
|
|
40
|
+
const bridge = env[bridgeName];
|
|
41
|
+
if (!bridge)
|
|
42
|
+
return resolve(event);
|
|
43
|
+
for (const name of workflows) {
|
|
44
|
+
if (env[name])
|
|
45
|
+
continue;
|
|
46
|
+
env[name] = makeFakeWorkflow(bridge, name);
|
|
47
|
+
}
|
|
48
|
+
return resolve(event);
|
|
49
|
+
};
|
|
50
|
+
function makeFakeWorkflow(bridge, binding) {
|
|
51
|
+
const base = `http://swe/__swe/wf/${encodeURIComponent(binding)}`;
|
|
52
|
+
return {
|
|
53
|
+
async create(opts) {
|
|
54
|
+
const { id } = await postJson(bridge, `${base}/create`, opts ?? {});
|
|
55
|
+
return makeFakeInstance(bridge, binding, id);
|
|
56
|
+
},
|
|
57
|
+
async createBatch(batch) {
|
|
58
|
+
const ids = await postJson(bridge, `${base}/createBatch`, batch);
|
|
59
|
+
return ids.map(({ id }) => makeFakeInstance(bridge, binding, id));
|
|
60
|
+
},
|
|
61
|
+
async get(id) {
|
|
62
|
+
await getOk(bridge, `${base}/get/${encodeURIComponent(id)}`);
|
|
63
|
+
return makeFakeInstance(bridge, binding, id);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function makeFakeInstance(bridge, binding, id) {
|
|
68
|
+
const base = `http://swe/__swe/wf/${encodeURIComponent(binding)}/instance/${encodeURIComponent(id)}`;
|
|
69
|
+
const post = async (method, body) => {
|
|
70
|
+
const res = await bridge.fetch(`${base}/${method}`, {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
73
|
+
});
|
|
74
|
+
if (!res.ok) {
|
|
75
|
+
throw new Error(`workflow ${method} failed: ${res.status} ${await res.text()}`);
|
|
76
|
+
}
|
|
77
|
+
const text = await res.text();
|
|
78
|
+
return text ? JSON.parse(text) : undefined;
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
id,
|
|
82
|
+
pause: () => post('pause').then(() => undefined),
|
|
83
|
+
resume: () => post('resume').then(() => undefined),
|
|
84
|
+
terminate: () => post('terminate').then(() => undefined),
|
|
85
|
+
restart: () => post('restart').then(() => undefined),
|
|
86
|
+
status: () => post('status'),
|
|
87
|
+
sendEvent: (opts) => post('sendEvent', opts).then(() => undefined)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// Pass URL string + init (not a pre-built Request): miniflare's internal undici
|
|
91
|
+
// won't accept a Request from a different realm — it stringifies it and tries
|
|
92
|
+
// to parse `[object Request]` as a URL.
|
|
93
|
+
async function postJson(bridge, url, body) {
|
|
94
|
+
const res = await bridge.fetch(url, { method: 'POST', body: JSON.stringify(body) });
|
|
95
|
+
if (!res.ok) {
|
|
96
|
+
throw new Error(`bridge POST ${url} failed: ${res.status} ${await res.text()}`);
|
|
97
|
+
}
|
|
98
|
+
return (await res.json());
|
|
99
|
+
}
|
|
100
|
+
async function getOk(bridge, url) {
|
|
101
|
+
const res = await bridge.fetch(url);
|
|
102
|
+
if (!res.ok) {
|
|
103
|
+
throw new Error(`bridge GET ${url} failed: ${res.status} ${await res.text()}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite-plugin-side bridge setup. Called from `src/index.ts` while the workflow
|
|
3
|
+
* bridge exists. Encapsulates everything bridge-specific:
|
|
4
|
+
*
|
|
5
|
+
* - generates the cache wrapper at `node_modules/.cache/...` so the dev
|
|
6
|
+
* sidecar serves the `/__swe/wf/*` routes used by the runtime hook
|
|
7
|
+
* - publishes config on `globalThis` for the SvelteKit `handle` to read
|
|
8
|
+
* - returns the proxy-config service binding to add and a disposer
|
|
9
|
+
*
|
|
10
|
+
* Once miniflare ships cross-worker workflow routing
|
|
11
|
+
* (cloudflare/workers-sdk#7459), delete `src/bridge/` and the call to
|
|
12
|
+
* `setupBridge` in `src/index.ts`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const BRIDGE_BINDING = "__SWE_BRIDGE";
|
|
15
|
+
export interface BridgeContext {
|
|
16
|
+
/** Path to the generated sidecar wrapper. Use as the dev config's `main`. */
|
|
17
|
+
wrapperPath: string;
|
|
18
|
+
/** Service binding entry to merge into the platform-proxy wrangler config. */
|
|
19
|
+
serviceBinding: {
|
|
20
|
+
binding: string;
|
|
21
|
+
service: string;
|
|
22
|
+
};
|
|
23
|
+
/** Best-effort cleanup of generated artifacts. */
|
|
24
|
+
dispose(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export interface SetupBridgeOptions {
|
|
27
|
+
userEntryAbs: string;
|
|
28
|
+
workflowBindings: readonly string[];
|
|
29
|
+
sidecarName: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function setupBridge(options: SetupBridgeOptions): Promise<BridgeContext>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite-plugin-side bridge setup. Called from `src/index.ts` while the workflow
|
|
3
|
+
* bridge exists. Encapsulates everything bridge-specific:
|
|
4
|
+
*
|
|
5
|
+
* - generates the cache wrapper at `node_modules/.cache/...` so the dev
|
|
6
|
+
* sidecar serves the `/__swe/wf/*` routes used by the runtime hook
|
|
7
|
+
* - publishes config on `globalThis` for the SvelteKit `handle` to read
|
|
8
|
+
* - returns the proxy-config service binding to add and a disposer
|
|
9
|
+
*
|
|
10
|
+
* Once miniflare ships cross-worker workflow routing
|
|
11
|
+
* (cloudflare/workers-sdk#7459), delete `src/bridge/` and the call to
|
|
12
|
+
* `setupBridge` in `src/index.ts`.
|
|
13
|
+
*/
|
|
14
|
+
import { mkdir, unlink, writeFile } from 'node:fs/promises';
|
|
15
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
16
|
+
export const BRIDGE_BINDING = '__SWE_BRIDGE';
|
|
17
|
+
const CACHE_DIR_REL = 'node_modules/.cache/sveltekit-add-worker-exports';
|
|
18
|
+
const WRAPPER_FILENAME = 'dev-worker-entry.ts';
|
|
19
|
+
export async function setupBridge(options) {
|
|
20
|
+
const cacheDir = resolve(CACHE_DIR_REL);
|
|
21
|
+
await mkdir(cacheDir, { recursive: true });
|
|
22
|
+
const wrapperPath = join(cacheDir, WRAPPER_FILENAME);
|
|
23
|
+
const userEntryRel = relative(dirname(wrapperPath), options.userEntryAbs)
|
|
24
|
+
.replace(/\\/g, '/')
|
|
25
|
+
.replace(/\.(ts|tsx|js|jsx|mjs|mts)$/, '');
|
|
26
|
+
await writeFile(wrapperPath, generateWrapperSource(userEntryRel, options.workflowBindings));
|
|
27
|
+
// The runtime hook reads these from globalThis. We can't use vite's
|
|
28
|
+
// `define` because dist/hooks.js lives in node_modules and vite doesn't
|
|
29
|
+
// transform external modules in SSR by default — substitutions wouldn't
|
|
30
|
+
// reach the file.
|
|
31
|
+
globalThis.__SWE_BRIDGE_NAME__ = BRIDGE_BINDING;
|
|
32
|
+
globalThis.__SWE_WORKFLOWS__ = options.workflowBindings;
|
|
33
|
+
return {
|
|
34
|
+
wrapperPath,
|
|
35
|
+
serviceBinding: { binding: BRIDGE_BINDING, service: options.sidecarName },
|
|
36
|
+
dispose: async () => {
|
|
37
|
+
await unlink(wrapperPath).catch(() => { });
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Tiny glue file that wrangler bundles into the dev sidecar. The substantive
|
|
43
|
+
* bridge logic lives in `./dev-handler.ts`, which the wrapper imports as a
|
|
44
|
+
* package subpath. Keeping the template this small makes it unlikely to
|
|
45
|
+
* harbour TypeScript errors that wouldn't be caught by tsc on the rest of
|
|
46
|
+
* the package.
|
|
47
|
+
*/
|
|
48
|
+
function generateWrapperSource(userEntryRel, workflowBindings) {
|
|
49
|
+
const importPath = JSON.stringify(userEntryRel);
|
|
50
|
+
const bindingList = JSON.stringify(workflowBindings);
|
|
51
|
+
return `// Auto-generated by @oselvar/sveltekit-add-worker-exports.
|
|
52
|
+
// Bridges Workflow bindings to SvelteKit dev. Do not edit.
|
|
53
|
+
import * as user from ${importPath};
|
|
54
|
+
export * from ${importPath};
|
|
55
|
+
import { createBridgeFetch } from '@oselvar/sveltekit-add-worker-exports/dev-bridge';
|
|
56
|
+
|
|
57
|
+
const userDefault = (user as { default?: { fetch?: ExportedHandlerFetchHandler } }).default;
|
|
58
|
+
|
|
59
|
+
export default {
|
|
60
|
+
\tfetch: createBridgeFetch({
|
|
61
|
+
\t\tworkflowBindings: ${bindingList},
|
|
62
|
+
\t\tuserFetch: userDefault?.fetch?.bind(userDefault)
|
|
63
|
+
\t})
|
|
64
|
+
} satisfies ExportedHandler;
|
|
65
|
+
`;
|
|
66
|
+
}
|
package/dist/hooks.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit `Handle` re-exported for users.
|
|
3
|
+
*
|
|
4
|
+
* Implementation lives in `./bridge/runtime-hook` while the workflow bridge
|
|
5
|
+
* exists. Once miniflare ships cross-worker workflow routing
|
|
6
|
+
* (cloudflare/workers-sdk#7459), replace this file with a no-op handle:
|
|
7
|
+
*
|
|
8
|
+
* import type { Handle } from '@sveltejs/kit';
|
|
9
|
+
* export const handle: Handle = ({ event, resolve }) => resolve(event);
|
|
10
|
+
*
|
|
11
|
+
* and delete `src/bridge/`.
|
|
12
|
+
*/
|
|
13
|
+
export { handle } from './bridge/runtime-hook.js';
|
package/dist/hooks.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit `Handle` re-exported for users.
|
|
3
|
+
*
|
|
4
|
+
* Implementation lives in `./bridge/runtime-hook` while the workflow bridge
|
|
5
|
+
* exists. Once miniflare ships cross-worker workflow routing
|
|
6
|
+
* (cloudflare/workers-sdk#7459), replace this file with a no-op handle:
|
|
7
|
+
*
|
|
8
|
+
* import type { Handle } from '@sveltejs/kit';
|
|
9
|
+
* export const handle: Handle = ({ event, resolve }) => resolve(event);
|
|
10
|
+
*
|
|
11
|
+
* and delete `src/bridge/`.
|
|
12
|
+
*/
|
|
13
|
+
export { handle } from './bridge/runtime-hook.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,15 @@
|
|
|
11
11
|
* server via `unstable_startWorker` that runs the real DO worker. Clients
|
|
12
12
|
* connect directly to it via WebSocket on a separate port.
|
|
13
13
|
*
|
|
14
|
+
* Workflows in dev are best-effort: if the installed wrangler/miniflare
|
|
15
|
+
* supports cross-worker workflow routing (cloudflare/workers-sdk#7459),
|
|
16
|
+
* `platform.env.MY_WORKFLOW.create(...)` works directly. Otherwise the bridge
|
|
17
|
+
* in `src/bridge/` synthesises the binding via an HTTP fallback. Once the
|
|
18
|
+
* upstream patch lands, delete `src/bridge/`, drop the `setupBridge` import
|
|
19
|
+
* and call below, replace `wrapperPath` with `options.entryPoint`, remove
|
|
20
|
+
* the `serviceBinding` insertion, and replace `src/hooks.ts` with a no-op
|
|
21
|
+
* handle.
|
|
22
|
+
*
|
|
14
23
|
* Usage in vite.config.ts:
|
|
15
24
|
* addWorkerExports({ entryPoint: 'src/lib/server/index.ts' })
|
|
16
25
|
*
|
package/dist/index.js
CHANGED
|
@@ -11,16 +11,57 @@
|
|
|
11
11
|
* server via `unstable_startWorker` that runs the real DO worker. Clients
|
|
12
12
|
* connect directly to it via WebSocket on a separate port.
|
|
13
13
|
*
|
|
14
|
+
* Workflows in dev are best-effort: if the installed wrangler/miniflare
|
|
15
|
+
* supports cross-worker workflow routing (cloudflare/workers-sdk#7459),
|
|
16
|
+
* `platform.env.MY_WORKFLOW.create(...)` works directly. Otherwise the bridge
|
|
17
|
+
* in `src/bridge/` synthesises the binding via an HTTP fallback. Once the
|
|
18
|
+
* upstream patch lands, delete `src/bridge/`, drop the `setupBridge` import
|
|
19
|
+
* and call below, replace `wrapperPath` with `options.entryPoint`, remove
|
|
20
|
+
* the `serviceBinding` insertion, and replace `src/hooks.ts` with a no-op
|
|
21
|
+
* handle.
|
|
22
|
+
*
|
|
14
23
|
* Usage in vite.config.ts:
|
|
15
24
|
* addWorkerExports({ entryPoint: 'src/lib/server/index.ts' })
|
|
16
25
|
*
|
|
17
26
|
* @see https://github.com/sveltejs/kit/issues/1712
|
|
18
27
|
*/
|
|
19
28
|
import { build } from 'esbuild';
|
|
29
|
+
import { existsSync } from 'node:fs';
|
|
20
30
|
import { access, readFile, rename, writeFile, unlink } from 'node:fs/promises';
|
|
21
|
-
import {
|
|
31
|
+
import { homedir } from 'node:os';
|
|
32
|
+
import { join, resolve } from 'node:path';
|
|
22
33
|
import { parse as parseJsonc } from 'jsonc-parser';
|
|
34
|
+
import { setupBridge } from './bridge/setup.js';
|
|
23
35
|
const DEFAULT_DEV_PORT = 8787;
|
|
36
|
+
const NODE_BUILTINS = [
|
|
37
|
+
'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'console',
|
|
38
|
+
'constants', 'crypto', 'dgram', 'diagnostics_channel', 'dns', 'domain',
|
|
39
|
+
'events', 'fs', 'fs/promises', 'http', 'http2', 'https', 'inspector',
|
|
40
|
+
'module', 'net', 'os', 'path', 'path/posix', 'path/win32', 'perf_hooks',
|
|
41
|
+
'process', 'punycode', 'querystring', 'readline', 'repl', 'stream',
|
|
42
|
+
'stream/consumers', 'stream/promises', 'stream/web', 'string_decoder',
|
|
43
|
+
'sys', 'timers', 'timers/promises', 'tls', 'trace_events', 'tty', 'url',
|
|
44
|
+
'util', 'util/types', 'v8', 'vm', 'wasi', 'worker_threads', 'zlib'
|
|
45
|
+
];
|
|
46
|
+
/**
|
|
47
|
+
* Mirrors wrangler's internal getRegistryPath() — wrangler doesn't export it.
|
|
48
|
+
* Workers register themselves under this path so cross-worker `script_name`
|
|
49
|
+
* bindings can find each other.
|
|
50
|
+
*/
|
|
51
|
+
function getWranglerRegistryPath() {
|
|
52
|
+
if (process.env.WRANGLER_REGISTRY_PATH)
|
|
53
|
+
return process.env.WRANGLER_REGISTRY_PATH;
|
|
54
|
+
const legacy = join(homedir(), '.wrangler');
|
|
55
|
+
if (existsSync(legacy))
|
|
56
|
+
return join(legacy, 'registry');
|
|
57
|
+
if (process.platform === 'darwin') {
|
|
58
|
+
return join(homedir(), 'Library', 'Preferences', '.wrangler', 'registry');
|
|
59
|
+
}
|
|
60
|
+
if (process.platform === 'win32') {
|
|
61
|
+
return join(process.env.APPDATA ?? join(homedir(), 'AppData', 'Roaming'), '.wrangler', 'registry');
|
|
62
|
+
}
|
|
63
|
+
return join(process.env.XDG_CONFIG_HOME ?? join(homedir(), '.config'), '.wrangler', 'registry');
|
|
64
|
+
}
|
|
24
65
|
/**
|
|
25
66
|
* Returns two Vite plugins: one for build (patches _worker.js) and one for
|
|
26
67
|
* dev (starts a wrangler dev server for Durable Objects).
|
|
@@ -56,14 +97,30 @@ function buildPlugin(options) {
|
|
|
56
97
|
if (!(await exists(workerPath))) {
|
|
57
98
|
return;
|
|
58
99
|
}
|
|
59
|
-
// Bundle the named exports
|
|
100
|
+
// Bundle the named exports.
|
|
101
|
+
//
|
|
102
|
+
// `conditions: ['workerd', 'worker', 'browser']` is the Cloudflare-
|
|
103
|
+
// recommended set for bundlers targeting Workers — it picks the
|
|
104
|
+
// workerd-specific or browser-shimmed variants of packages over
|
|
105
|
+
// their Node variants (e.g. nanoid's webcrypto-via-`globalThis.crypto`
|
|
106
|
+
// browser build instead of the `node:crypto`-importing main build).
|
|
107
|
+
//
|
|
108
|
+
// Node built-ins are externalised so transitive deps that do
|
|
109
|
+
// `require('path')` or `import 'node:async_hooks'` survive bundling;
|
|
110
|
+
// the Workers runtime resolves them when `nodejs_compat` is enabled
|
|
111
|
+
// in wrangler.jsonc.
|
|
60
112
|
await build({
|
|
61
113
|
entryPoints: [options.entryPoint],
|
|
62
114
|
bundle: true,
|
|
63
115
|
format: 'esm',
|
|
64
116
|
sourcemap: true,
|
|
65
117
|
target: 'esnext',
|
|
66
|
-
|
|
118
|
+
conditions: ['workerd', 'worker', 'browser'],
|
|
119
|
+
external: [
|
|
120
|
+
'cloudflare:*',
|
|
121
|
+
...NODE_BUILTINS,
|
|
122
|
+
...NODE_BUILTINS.map((m) => `node:${m}`)
|
|
123
|
+
],
|
|
67
124
|
outfile: exportsPath
|
|
68
125
|
});
|
|
69
126
|
// Rename original worker and create merged entry point
|
|
@@ -77,6 +134,19 @@ function devPlugin(options) {
|
|
|
77
134
|
let worker = null;
|
|
78
135
|
let tempConfigPath = null;
|
|
79
136
|
let proxyConfigPath = null;
|
|
137
|
+
let typesConfigPath = null;
|
|
138
|
+
let bridgeDispose = null;
|
|
139
|
+
let cached = null;
|
|
140
|
+
async function readConfig() {
|
|
141
|
+
if (cached)
|
|
142
|
+
return cached;
|
|
143
|
+
const { unstable_readConfig } = await import('wrangler');
|
|
144
|
+
const parsed = unstable_readConfig(options.wranglerConfig ? { config: options.wranglerConfig } : {});
|
|
145
|
+
const rawJson = await readFile(parsed.configPath, 'utf-8');
|
|
146
|
+
const workflowBindings = (parsed.workflows ?? []).map((w) => w.binding);
|
|
147
|
+
cached = { rawJson, workflowBindings };
|
|
148
|
+
return cached;
|
|
149
|
+
}
|
|
80
150
|
return {
|
|
81
151
|
name: 'add-worker-exports-dev',
|
|
82
152
|
apply: 'serve',
|
|
@@ -88,34 +158,75 @@ function devPlugin(options) {
|
|
|
88
158
|
};
|
|
89
159
|
},
|
|
90
160
|
async configureServer(server) {
|
|
91
|
-
const {
|
|
92
|
-
|
|
93
|
-
const
|
|
161
|
+
const { unstable_startWorker } = await import('wrangler');
|
|
162
|
+
const { rawJson, workflowBindings } = await readConfig();
|
|
163
|
+
const sidecarName = `${parseJsonc(rawJson).name ?? 'sveltekit'}-dev-worker`;
|
|
164
|
+
// Set up the workflow HTTP bridge (see src/bridge/). This is the
|
|
165
|
+
// fallback used when the installed wrangler/miniflare strips
|
|
166
|
+
// workflow bindings from getPlatformProxy. When the upstream
|
|
167
|
+
// patch lands (cloudflare/workers-sdk#7459), delete src/bridge,
|
|
168
|
+
// remove this call, and use options.entryPoint as the dev
|
|
169
|
+
// config's `main` directly (no service binding either).
|
|
170
|
+
const bridge = await setupBridge({
|
|
171
|
+
userEntryAbs: resolve(options.entryPoint),
|
|
172
|
+
workflowBindings,
|
|
173
|
+
sidecarName
|
|
174
|
+
});
|
|
175
|
+
bridgeDispose = bridge.dispose;
|
|
94
176
|
// Copy the raw config and override main, name, and dev port
|
|
95
|
-
const rawJson = await readFile(wranglerConfig.configPath, 'utf-8');
|
|
96
177
|
const devConfig = parseJsonc(rawJson);
|
|
97
|
-
devConfig.name =
|
|
98
|
-
devConfig.main =
|
|
178
|
+
devConfig.name = sidecarName;
|
|
179
|
+
devConfig.main = bridge.wrapperPath;
|
|
99
180
|
devConfig.dev = { ...devConfig.dev, port: devPort };
|
|
100
181
|
delete devConfig.assets;
|
|
101
182
|
tempConfigPath = resolve('.dev-worker-wrangler.jsonc');
|
|
102
183
|
await writeFile(tempConfigPath, JSON.stringify(devConfig, null, '\t'));
|
|
103
|
-
//
|
|
184
|
+
// Write a wrangler config for adapter-cloudflare's getPlatformProxy
|
|
104
185
|
// (used by vite dev for platform.env). It can't run internal DOs or
|
|
105
|
-
// Workflows -- those are served by the sidecar above.
|
|
106
|
-
//
|
|
186
|
+
// Workflows itself -- those are served by the sidecar above. Rewrite
|
|
187
|
+
// internal DO bindings as cross-worker bindings (script_name pointing
|
|
188
|
+
// at the sidecar) so platform.env.MY_DO calls in +server.ts reach the
|
|
189
|
+
// sidecar via the wrangler dev registry. Workflows get the same
|
|
190
|
+
// rewrite; on patched wrangler/miniflare miniflare routes them via
|
|
191
|
+
// the dev-registry-proxy. On unpatched, wrangler strips them and the
|
|
192
|
+
// bridge service binding (added below) drives the SvelteKit hook
|
|
193
|
+
// fallback.
|
|
107
194
|
const proxyConfig = parseJsonc(rawJson);
|
|
108
195
|
if (proxyConfig.durable_objects?.bindings) {
|
|
109
|
-
proxyConfig.durable_objects.bindings = proxyConfig.durable_objects.bindings.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
}
|
|
196
|
+
proxyConfig.durable_objects.bindings = proxyConfig.durable_objects.bindings.map((b) => b.script_name ? b : { ...b, script_name: sidecarName });
|
|
197
|
+
}
|
|
198
|
+
if (Array.isArray(proxyConfig.workflows)) {
|
|
199
|
+
proxyConfig.workflows = proxyConfig.workflows.map((w) => w.script_name ? w : { ...w, script_name: sidecarName });
|
|
200
|
+
}
|
|
201
|
+
if (workflowBindings.length > 0) {
|
|
202
|
+
proxyConfig.services = [
|
|
203
|
+
...(proxyConfig.services ?? []),
|
|
204
|
+
bridge.serviceBinding
|
|
205
|
+
];
|
|
113
206
|
}
|
|
114
|
-
delete proxyConfig.workflows;
|
|
115
207
|
delete proxyConfig.migrations;
|
|
116
208
|
proxyConfigPath = resolve('.platform-proxy-wrangler.jsonc');
|
|
117
209
|
await writeFile(proxyConfigPath, JSON.stringify(proxyConfig, null, '\t'));
|
|
118
|
-
|
|
210
|
+
// A third config used only by `wrangler types`. Identical to the dev
|
|
211
|
+
// config except `main` points at the user's source entry, so wrangler
|
|
212
|
+
// can resolve typed bindings (DurableObjectNamespace<EchoDO>, etc.).
|
|
213
|
+
// Pointing types at our generated wrapper produces untyped bindings
|
|
214
|
+
// because wrangler's type resolver doesn't follow `export *` re-exports
|
|
215
|
+
// out of node_modules.
|
|
216
|
+
const typesConfig = parseJsonc(rawJson);
|
|
217
|
+
typesConfig.name = sidecarName;
|
|
218
|
+
typesConfig.main = options.entryPoint;
|
|
219
|
+
typesConfig.dev = { ...typesConfig.dev, port: devPort };
|
|
220
|
+
delete typesConfig.assets;
|
|
221
|
+
typesConfigPath = resolve('.types-worker-wrangler.jsonc');
|
|
222
|
+
await writeFile(typesConfigPath, JSON.stringify(typesConfig, null, '\t'));
|
|
223
|
+
worker = await unstable_startWorker({
|
|
224
|
+
config: tempConfigPath,
|
|
225
|
+
dev: { registry: getWranglerRegistryPath() },
|
|
226
|
+
build: {
|
|
227
|
+
nodejsCompatMode: (parsedConfig) => getNodejsCompatMode(parsedConfig.compatibility_date, parsedConfig.compatibility_flags)
|
|
228
|
+
}
|
|
229
|
+
});
|
|
119
230
|
server.httpServer?.on('close', async () => {
|
|
120
231
|
if (worker) {
|
|
121
232
|
await worker.dispose();
|
|
@@ -127,6 +238,13 @@ function devPlugin(options) {
|
|
|
127
238
|
if (proxyConfigPath) {
|
|
128
239
|
await unlink(proxyConfigPath).catch(() => { });
|
|
129
240
|
}
|
|
241
|
+
if (typesConfigPath) {
|
|
242
|
+
await unlink(typesConfigPath).catch(() => { });
|
|
243
|
+
}
|
|
244
|
+
if (bridgeDispose) {
|
|
245
|
+
await bridgeDispose();
|
|
246
|
+
bridgeDispose = null;
|
|
247
|
+
}
|
|
130
248
|
});
|
|
131
249
|
}
|
|
132
250
|
};
|
|
@@ -140,3 +258,24 @@ async function exists(path) {
|
|
|
140
258
|
return false;
|
|
141
259
|
}
|
|
142
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Mirrors miniflare's `getNodeCompat` mode resolution. wrangler's
|
|
263
|
+
* `unstable_startWorker` does not derive this from the config flags
|
|
264
|
+
* automatically — without it, wrangler falls back to the legacy nodejs
|
|
265
|
+
* compat plugin and warns about `node:*` imports even when
|
|
266
|
+
* `nodejs_compat` is enabled.
|
|
267
|
+
*/
|
|
268
|
+
function getNodejsCompatMode(compatibilityDate, compatibilityFlags = []) {
|
|
269
|
+
const hasCompat = compatibilityFlags.includes('nodejs_compat');
|
|
270
|
+
const hasCompatV2 = compatibilityFlags.includes('nodejs_compat_v2');
|
|
271
|
+
const hasNoCompatV2 = compatibilityFlags.includes('no_nodejs_compat_v2');
|
|
272
|
+
const hasAls = compatibilityFlags.includes('nodejs_als');
|
|
273
|
+
const date = compatibilityDate ?? '2000-01-01';
|
|
274
|
+
if (hasCompatV2 || (hasCompat && date >= '2024-09-23' && !hasNoCompatV2))
|
|
275
|
+
return 'v2';
|
|
276
|
+
if (hasCompat)
|
|
277
|
+
return 'v1';
|
|
278
|
+
if (hasAls)
|
|
279
|
+
return 'als';
|
|
280
|
+
return null;
|
|
281
|
+
}
|
package/package.json
CHANGED
|
@@ -1,51 +1,64 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
2
|
+
"name": "@oselvar/sveltekit-add-worker-exports",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Vite plugin that adds Durable Object and Workflow exports to SvelteKit Cloudflare workers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./hooks": {
|
|
15
|
+
"types": "./dist/hooks.d.ts",
|
|
16
|
+
"import": "./dist/hooks.js"
|
|
17
|
+
},
|
|
18
|
+
"./dev-bridge": {
|
|
19
|
+
"types": "./dist/bridge/dev-handler.d.ts",
|
|
20
|
+
"import": "./dist/bridge/dev-handler.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/oselvar/sveltekit-add-worker-exports.git"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"sveltekit",
|
|
33
|
+
"cloudflare",
|
|
34
|
+
"workers",
|
|
35
|
+
"durable-objects",
|
|
36
|
+
"workflows",
|
|
37
|
+
"vite-plugin"
|
|
38
|
+
],
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"@sveltejs/kit": ">=2",
|
|
41
|
+
"esbuild": ">=0.17",
|
|
42
|
+
"miniflare": ">=4",
|
|
43
|
+
"vite": ">=5",
|
|
44
|
+
"wrangler": ">=4"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@sveltejs/kit": "^2.61.0",
|
|
48
|
+
"@types/node": "^22.19.19",
|
|
49
|
+
"esbuild": "^0.25.12",
|
|
50
|
+
"miniflare": "^4.20260521.0",
|
|
51
|
+
"np": "^11.2.1",
|
|
52
|
+
"typescript": "^5.9.3",
|
|
53
|
+
"vite": "^6.4.2",
|
|
54
|
+
"wrangler": "^4.94.0"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc",
|
|
58
|
+
"test": "tsc --noEmit",
|
|
59
|
+
"prepublishOnly": "tsc"
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"jsonc-parser": "^3.3.1"
|
|
63
|
+
}
|
|
64
|
+
}
|