@oselvar/sveltekit-add-worker-exports 0.3.1 → 0.3.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/README.md +5 -23
- package/dist/hooks.d.ts +6 -9
- package/dist/hooks.js +5 -9
- package/dist/index.d.ts +7 -12
- package/dist/index.js +18 -58
- package/package.json +12 -14
- package/dist/bridge/dev-handler.d.ts +0 -27
- package/dist/bridge/dev-handler.js +0 -88
- package/dist/bridge/runtime-hook.d.ts +0 -32
- package/dist/bridge/runtime-hook.js +0 -105
- package/dist/bridge/setup.d.ts +0 -31
- package/dist/bridge/setup.js +0 -66
package/README.md
CHANGED
|
@@ -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`. The plugin writes this file with internal Durable Object bindings rewritten to cross-worker form (each gets a `script_name` pointing at the sidecar)
|
|
90
|
+
Point `adapter-cloudflare`'s platform proxy at the generated `.platform-proxy-wrangler.jsonc`. The plugin writes this file with internal Durable Object and Workflow bindings rewritten to cross-worker form (each gets a `script_name` pointing at the sidecar), so `platform.env.MY_DO` and `platform.env.MY_WORKFLOW` calls in `+server.ts` reach the sidecar via the wrangler dev registry. Without this config path, `getPlatformProxy` would try to run the DO/Workflow classes itself and warn that it can't:
|
|
91
91
|
|
|
92
92
|
```javascript
|
|
93
93
|
// svelte.config.js
|
|
@@ -129,29 +129,11 @@ declare global {
|
|
|
129
129
|
}
|
|
130
130
|
```
|
|
131
131
|
|
|
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
|
|
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 point at your source entry.
|
|
133
133
|
|
|
134
134
|
### Dev mode: calling Workflows
|
|
135
135
|
|
|
136
|
-
|
|
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:
|
|
136
|
+
`+server.ts` calls workflows the same way it does in production:
|
|
155
137
|
|
|
156
138
|
```typescript
|
|
157
139
|
export const POST: RequestHandler = async ({ params, request, platform }) => {
|
|
@@ -163,7 +145,7 @@ export const POST: RequestHandler = async ({ params, request, platform }) => {
|
|
|
163
145
|
};
|
|
164
146
|
```
|
|
165
147
|
|
|
166
|
-
|
|
148
|
+
The sidecar runs the real `WorkflowEntrypoint` class; calls reach it via the `script_name` rewrite in the platform-proxy config. This requires `wrangler >= 4.98.0` ([cloudflare/workers-sdk#13863](https://github.com/cloudflare/workers-sdk/pull/13863)).
|
|
167
149
|
|
|
168
150
|
### Testing the production build locally
|
|
169
151
|
|
|
@@ -243,7 +225,7 @@ Add this to your `package.json` scripts for convenience:
|
|
|
243
225
|
}
|
|
244
226
|
```
|
|
245
227
|
|
|
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`.
|
|
228
|
+
Note: the `.types-worker-wrangler.jsonc` file is generated when the dev server starts. Run `pnpm dev` at least once before running `wrangler types`.
|
|
247
229
|
|
|
248
230
|
## Why this exists
|
|
249
231
|
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SvelteKit `Handle` re-exported for users.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* (cloudflare/workers-sdk#
|
|
7
|
-
*
|
|
8
|
-
* import type { Handle } from '@sveltejs/kit';
|
|
9
|
-
* export const handle: Handle = ({ event, resolve }) => resolve(event);
|
|
10
|
-
*
|
|
11
|
-
* and delete `src/bridge/`.
|
|
4
|
+
* Kept as a no-op for backwards compatibility. Wrangler 4.98.0 fixed
|
|
5
|
+
* cross-worker workflow routing in `getPlatformProxy`
|
|
6
|
+
* (cloudflare/workers-sdk#13863), so `platform.env.MY_WORKFLOW` is now a
|
|
7
|
+
* real binding in both dev and production — no synthesis required.
|
|
12
8
|
*/
|
|
13
|
-
|
|
9
|
+
import type { Handle } from '@sveltejs/kit';
|
|
10
|
+
export declare const handle: Handle;
|
package/dist/hooks.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SvelteKit `Handle` re-exported for users.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* (cloudflare/workers-sdk#
|
|
7
|
-
*
|
|
8
|
-
* import type { Handle } from '@sveltejs/kit';
|
|
9
|
-
* export const handle: Handle = ({ event, resolve }) => resolve(event);
|
|
10
|
-
*
|
|
11
|
-
* and delete `src/bridge/`.
|
|
4
|
+
* Kept as a no-op for backwards compatibility. Wrangler 4.98.0 fixed
|
|
5
|
+
* cross-worker workflow routing in `getPlatformProxy`
|
|
6
|
+
* (cloudflare/workers-sdk#13863), so `platform.env.MY_WORKFLOW` is now a
|
|
7
|
+
* real binding in both dev and production — no synthesis required.
|
|
12
8
|
*/
|
|
13
|
-
export
|
|
9
|
+
export const handle = ({ event, resolve }) => resolve(event);
|
package/dist/index.d.ts
CHANGED
|
@@ -7,18 +7,13 @@
|
|
|
7
7
|
* exports. This plugin post-processes the build output to merge them.
|
|
8
8
|
*
|
|
9
9
|
* **Dev mode:** `getPlatformProxy` (used by adapter-cloudflare in dev) can't
|
|
10
|
-
* run internal Durable Objects. This plugin starts a separate
|
|
11
|
-
* server via `unstable_startWorker` that runs the real
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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.
|
|
10
|
+
* run internal Durable Objects or Workflows. This plugin starts a separate
|
|
11
|
+
* wrangler dev server via `unstable_startWorker` that runs the real
|
|
12
|
+
* DO/Workflow worker. Internal DO and Workflow bindings in the platform-proxy
|
|
13
|
+
* config get a `script_name` pointing at that sidecar; miniflare routes calls
|
|
14
|
+
* across the dev registry (cloudflare/workers-sdk#7459, fixed in wrangler
|
|
15
|
+
* 4.98.0). Clients connect directly to the sidecar via WebSocket on a
|
|
16
|
+
* separate port.
|
|
22
17
|
*
|
|
23
18
|
* Usage in vite.config.ts:
|
|
24
19
|
* addWorkerExports({ entryPoint: 'src/lib/server/index.ts' })
|
package/dist/index.js
CHANGED
|
@@ -7,18 +7,13 @@
|
|
|
7
7
|
* exports. This plugin post-processes the build output to merge them.
|
|
8
8
|
*
|
|
9
9
|
* **Dev mode:** `getPlatformProxy` (used by adapter-cloudflare in dev) can't
|
|
10
|
-
* run internal Durable Objects. This plugin starts a separate
|
|
11
|
-
* server via `unstable_startWorker` that runs the real
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
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.
|
|
10
|
+
* run internal Durable Objects or Workflows. This plugin starts a separate
|
|
11
|
+
* wrangler dev server via `unstable_startWorker` that runs the real
|
|
12
|
+
* DO/Workflow worker. Internal DO and Workflow bindings in the platform-proxy
|
|
13
|
+
* config get a `script_name` pointing at that sidecar; miniflare routes calls
|
|
14
|
+
* across the dev registry (cloudflare/workers-sdk#7459, fixed in wrangler
|
|
15
|
+
* 4.98.0). Clients connect directly to the sidecar via WebSocket on a
|
|
16
|
+
* separate port.
|
|
22
17
|
*
|
|
23
18
|
* Usage in vite.config.ts:
|
|
24
19
|
* addWorkerExports({ entryPoint: 'src/lib/server/index.ts' })
|
|
@@ -31,7 +26,6 @@ import { access, readFile, rename, writeFile, unlink } from 'node:fs/promises';
|
|
|
31
26
|
import { homedir } from 'node:os';
|
|
32
27
|
import { join, resolve } from 'node:path';
|
|
33
28
|
import { parse as parseJsonc } from 'jsonc-parser';
|
|
34
|
-
import { setupBridge } from './bridge/setup.js';
|
|
35
29
|
const DEFAULT_DEV_PORT = 8787;
|
|
36
30
|
const NODE_BUILTINS = [
|
|
37
31
|
'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'console',
|
|
@@ -135,17 +129,10 @@ function devPlugin(options) {
|
|
|
135
129
|
let tempConfigPath = null;
|
|
136
130
|
let proxyConfigPath = null;
|
|
137
131
|
let typesConfigPath = null;
|
|
138
|
-
|
|
139
|
-
let cached = null;
|
|
140
|
-
async function readConfig() {
|
|
141
|
-
if (cached)
|
|
142
|
-
return cached;
|
|
132
|
+
async function readRawConfig() {
|
|
143
133
|
const { unstable_readConfig } = await import('wrangler');
|
|
144
134
|
const parsed = unstable_readConfig(options.wranglerConfig ? { config: options.wranglerConfig } : {});
|
|
145
|
-
|
|
146
|
-
const workflowBindings = (parsed.workflows ?? []).map((w) => w.binding);
|
|
147
|
-
cached = { rawJson, workflowBindings };
|
|
148
|
-
return cached;
|
|
135
|
+
return readFile(parsed.configPath, 'utf-8');
|
|
149
136
|
}
|
|
150
137
|
return {
|
|
151
138
|
name: 'add-worker-exports-dev',
|
|
@@ -159,24 +146,12 @@ function devPlugin(options) {
|
|
|
159
146
|
},
|
|
160
147
|
async configureServer(server) {
|
|
161
148
|
const { unstable_startWorker } = await import('wrangler');
|
|
162
|
-
const
|
|
149
|
+
const rawJson = await readRawConfig();
|
|
163
150
|
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;
|
|
176
151
|
// Copy the raw config and override main, name, and dev port
|
|
177
152
|
const devConfig = parseJsonc(rawJson);
|
|
178
153
|
devConfig.name = sidecarName;
|
|
179
|
-
devConfig.main =
|
|
154
|
+
devConfig.main = options.entryPoint;
|
|
180
155
|
devConfig.dev = { ...devConfig.dev, port: devPort };
|
|
181
156
|
delete devConfig.assets;
|
|
182
157
|
tempConfigPath = resolve('.dev-worker-wrangler.jsonc');
|
|
@@ -184,13 +159,10 @@ function devPlugin(options) {
|
|
|
184
159
|
// Write a wrangler config for adapter-cloudflare's getPlatformProxy
|
|
185
160
|
// (used by vite dev for platform.env). It can't run internal DOs or
|
|
186
161
|
// Workflows itself -- those are served by the sidecar above. Rewrite
|
|
187
|
-
// internal DO bindings as cross-worker bindings
|
|
188
|
-
// at the sidecar) so platform.env.MY_DO
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
// the dev-registry-proxy. On unpatched, wrangler strips them and the
|
|
192
|
-
// bridge service binding (added below) drives the SvelteKit hook
|
|
193
|
-
// fallback.
|
|
162
|
+
// internal DO and Workflow bindings as cross-worker bindings
|
|
163
|
+
// (script_name pointing at the sidecar) so platform.env.MY_DO and
|
|
164
|
+
// platform.env.MY_WORKFLOW calls in +server.ts reach the sidecar via
|
|
165
|
+
// the wrangler dev registry.
|
|
194
166
|
const proxyConfig = parseJsonc(rawJson);
|
|
195
167
|
if (proxyConfig.durable_objects?.bindings) {
|
|
196
168
|
proxyConfig.durable_objects.bindings = proxyConfig.durable_objects.bindings.map((b) => b.script_name ? b : { ...b, script_name: sidecarName });
|
|
@@ -198,21 +170,13 @@ function devPlugin(options) {
|
|
|
198
170
|
if (Array.isArray(proxyConfig.workflows)) {
|
|
199
171
|
proxyConfig.workflows = proxyConfig.workflows.map((w) => w.script_name ? w : { ...w, script_name: sidecarName });
|
|
200
172
|
}
|
|
201
|
-
if (workflowBindings.length > 0) {
|
|
202
|
-
proxyConfig.services = [
|
|
203
|
-
...(proxyConfig.services ?? []),
|
|
204
|
-
bridge.serviceBinding
|
|
205
|
-
];
|
|
206
|
-
}
|
|
207
173
|
delete proxyConfig.migrations;
|
|
208
174
|
proxyConfigPath = resolve('.platform-proxy-wrangler.jsonc');
|
|
209
175
|
await writeFile(proxyConfigPath, JSON.stringify(proxyConfig, null, '\t'));
|
|
210
176
|
// A third config used only by `wrangler types`. Identical to the dev
|
|
211
|
-
// config
|
|
212
|
-
//
|
|
213
|
-
//
|
|
214
|
-
// because wrangler's type resolver doesn't follow `export *` re-exports
|
|
215
|
-
// out of node_modules.
|
|
177
|
+
// config but kept separate so the user can run `wrangler types
|
|
178
|
+
// --config .types-worker-wrangler.jsonc` to get typed bindings like
|
|
179
|
+
// DurableObjectNamespace<EchoDO> resolved from the source entry.
|
|
216
180
|
const typesConfig = parseJsonc(rawJson);
|
|
217
181
|
typesConfig.name = sidecarName;
|
|
218
182
|
typesConfig.main = options.entryPoint;
|
|
@@ -241,10 +205,6 @@ function devPlugin(options) {
|
|
|
241
205
|
if (typesConfigPath) {
|
|
242
206
|
await unlink(typesConfigPath).catch(() => { });
|
|
243
207
|
}
|
|
244
|
-
if (bridgeDispose) {
|
|
245
|
-
await bridgeDispose();
|
|
246
|
-
bridgeDispose = null;
|
|
247
|
-
}
|
|
248
208
|
});
|
|
249
209
|
}
|
|
250
210
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oselvar/sveltekit-add-worker-exports",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Vite plugin that adds Durable Object and Workflow exports to SvelteKit Cloudflare workers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
"./hooks": {
|
|
15
15
|
"types": "./dist/hooks.d.ts",
|
|
16
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
17
|
}
|
|
22
18
|
},
|
|
23
19
|
"files": [
|
|
@@ -44,19 +40,21 @@
|
|
|
44
40
|
"wrangler": ">=4"
|
|
45
41
|
},
|
|
46
42
|
"devDependencies": {
|
|
47
|
-
"@
|
|
48
|
-
"@
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
43
|
+
"@release-it/conventional-changelog": "^11.0.1",
|
|
44
|
+
"@sveltejs/kit": "^2.62.0",
|
|
45
|
+
"@types/node": "^25.9.1",
|
|
46
|
+
"esbuild": "^0.28.0",
|
|
47
|
+
"miniflare": "^4.20260601.0",
|
|
48
|
+
"release-it": "^20.2.0",
|
|
49
|
+
"typescript": "^6.0.3",
|
|
50
|
+
"vite": "^8.0.16",
|
|
51
|
+
"wrangler": "^4.98.0"
|
|
55
52
|
},
|
|
56
53
|
"scripts": {
|
|
57
54
|
"build": "tsc",
|
|
58
55
|
"test": "tsc --noEmit",
|
|
59
|
-
"prepublishOnly": "tsc"
|
|
56
|
+
"prepublishOnly": "tsc",
|
|
57
|
+
"release": "release-it"
|
|
60
58
|
},
|
|
61
59
|
"dependencies": {
|
|
62
60
|
"jsonc-parser": "^3.3.1"
|
|
@@ -1,27 +0,0 @@
|
|
|
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 {};
|
|
@@ -1,88 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
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;
|
|
@@ -1,105 +0,0 @@
|
|
|
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
|
-
}
|
package/dist/bridge/setup.d.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
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>;
|
package/dist/bridge/setup.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
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
|
-
}
|