devflare 1.0.0-next.0 → 1.0.0-next.10
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/LLM.md +1114 -0
- package/R2.md +200 -0
- package/README.md +285 -514
- package/bin/devflare.js +8 -8
- package/dist/{account-rvrj687w.js → account-8psavtg6.js} +27 -4
- package/dist/bridge/miniflare.d.ts +6 -0
- package/dist/bridge/miniflare.d.ts.map +1 -1
- package/dist/bridge/proxy.d.ts +5 -6
- package/dist/bridge/proxy.d.ts.map +1 -1
- package/dist/bridge/server.d.ts.map +1 -1
- package/dist/browser.d.ts +50 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/{build-mnf6v8gd.js → build-k36xrzvy.js} +26 -7
- package/dist/bundler/do-bundler.d.ts +7 -0
- package/dist/bundler/do-bundler.d.ts.map +1 -1
- package/dist/cli/commands/account.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/deploy.d.ts.map +1 -1
- package/dist/cli/commands/dev.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/types.d.ts.map +1 -1
- package/dist/cli/config-path.d.ts +5 -0
- package/dist/cli/config-path.d.ts.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/package-metadata.d.ts +16 -0
- package/dist/cli/package-metadata.d.ts.map +1 -0
- package/dist/config/compiler.d.ts +7 -0
- package/dist/config/compiler.d.ts.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/schema.d.ts +2575 -1221
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/{deploy-nhceck39.js → deploy-dbvfq8vq.js} +33 -15
- package/dist/{dev-qnxet3j9.js → dev-rk8p6pse.js} +900 -234
- package/dist/dev-server/miniflare-log.d.ts +12 -0
- package/dist/dev-server/miniflare-log.d.ts.map +1 -0
- package/dist/dev-server/runtime-stdio.d.ts +8 -0
- package/dist/dev-server/runtime-stdio.d.ts.map +1 -0
- package/dist/dev-server/server.d.ts +2 -0
- package/dist/dev-server/server.d.ts.map +1 -1
- package/dist/dev-server/vite-utils.d.ts +37 -0
- package/dist/dev-server/vite-utils.d.ts.map +1 -0
- package/dist/{doctor-e8fy6fj5.js → doctor-06y8nxd4.js} +73 -50
- package/dist/{durable-object-t4kbb0yt.js → durable-object-yt8v1dyn.js} +1 -1
- package/dist/index-05fyzwne.js +195 -0
- package/dist/index-1p814k7s.js +227 -0
- package/dist/{index-hcex3rgh.js → index-1phx14av.js} +84 -7
- package/dist/{index-tk6ej9dj.js → index-2q3pmzrx.js} +12 -16
- package/dist/{index-pf5s73n9.js → index-59df49vn.js} +11 -281
- package/dist/index-5yxg30va.js +304 -0
- package/dist/index-62b3gt2g.js +12 -0
- package/dist/index-6h8xbs75.js +44 -0
- package/dist/{index-67qcae0f.js → index-6v3wjg1r.js} +16 -1
- package/dist/index-8gtqgb3q.js +529 -0
- package/dist/{index-gz1gndna.js → index-9wt9x09k.js} +42 -62
- package/dist/index-fef08w43.js +231 -0
- package/dist/{index-ep3445yc.js → index-jht2j546.js} +393 -170
- package/dist/index-k7r18na8.js +0 -0
- package/dist/{index-m2q41jwa.js → index-n932ytmq.js} +9 -1
- package/dist/index-pwgyy2q9.js +39 -0
- package/dist/{index-07q6yxyc.js → index-v8vvsn9x.js} +1 -0
- package/dist/index-vky23txa.js +70 -0
- package/dist/index-vs49yxn4.js +322 -0
- package/dist/{index-z14anrqp.js → index-wfbfz02q.js} +14 -15
- package/dist/index-ws68xvq2.js +311 -0
- package/dist/index-y1d8za14.js +196 -0
- package/dist/{init-f9mgmew3.js → init-na2atvz2.js} +42 -55
- package/dist/router/types.d.ts +24 -0
- package/dist/router/types.d.ts.map +1 -0
- package/dist/runtime/context.d.ts +249 -8
- package/dist/runtime/context.d.ts.map +1 -1
- package/dist/runtime/exports.d.ts +50 -55
- package/dist/runtime/exports.d.ts.map +1 -1
- package/dist/runtime/index.d.ts +8 -1
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/middleware.d.ts +77 -60
- package/dist/runtime/middleware.d.ts.map +1 -1
- package/dist/runtime/router.d.ts +7 -0
- package/dist/runtime/router.d.ts.map +1 -0
- package/dist/runtime/validation.d.ts +1 -1
- package/dist/runtime/validation.d.ts.map +1 -1
- package/dist/src/browser.js +150 -0
- package/dist/src/cli/index.js +10 -0
- package/dist/{cloudflare → src/cloudflare}/index.js +3 -3
- package/dist/{decorators → src/decorators}/index.js +2 -2
- package/dist/src/index.js +132 -0
- package/dist/src/runtime/index.js +111 -0
- package/dist/{sveltekit → src/sveltekit}/index.js +14 -6
- package/dist/{test → src/test}/index.js +22 -13
- package/dist/{vite → src/vite}/index.js +128 -59
- package/dist/sveltekit/platform.d.ts.map +1 -1
- package/dist/test/bridge-context.d.ts +5 -2
- package/dist/test/bridge-context.d.ts.map +1 -1
- package/dist/test/cf.d.ts +25 -11
- package/dist/test/cf.d.ts.map +1 -1
- package/dist/test/email.d.ts +16 -7
- package/dist/test/email.d.ts.map +1 -1
- package/dist/test/queue.d.ts.map +1 -1
- package/dist/test/resolve-service-bindings.d.ts.map +1 -1
- package/dist/test/scheduled.d.ts.map +1 -1
- package/dist/test/simple-context.d.ts +1 -1
- package/dist/test/simple-context.d.ts.map +1 -1
- package/dist/test/tail.d.ts +2 -1
- package/dist/test/tail.d.ts.map +1 -1
- package/dist/test/worker.d.ts +6 -0
- package/dist/test/worker.d.ts.map +1 -1
- package/dist/transform/durable-object.d.ts.map +1 -1
- package/dist/transform/worker-entrypoint.d.ts.map +1 -1
- package/dist/{types-5nyrz1sz.js → types-x9q7t491.js} +30 -16
- package/dist/utils/entrypoint-discovery.d.ts +6 -3
- package/dist/utils/entrypoint-discovery.d.ts.map +1 -1
- package/dist/utils/send-email.d.ts +15 -0
- package/dist/utils/send-email.d.ts.map +1 -0
- package/dist/vite/plugin.d.ts.map +1 -1
- package/dist/worker-entry/composed-worker.d.ts +13 -0
- package/dist/worker-entry/composed-worker.d.ts.map +1 -0
- package/dist/worker-entry/routes.d.ts +22 -0
- package/dist/worker-entry/routes.d.ts.map +1 -0
- package/dist/{worker-entrypoint-m9th0rg0.js → worker-entrypoint-c259fmfs.js} +1 -1
- package/package.json +22 -19
- package/dist/index.js +0 -298
- package/dist/runtime/index.js +0 -111
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import {
|
|
2
|
+
discoverRoutes
|
|
3
|
+
} from "./index-1p814k7s.js";
|
|
4
|
+
import {
|
|
5
|
+
__require
|
|
6
|
+
} from "./index-37x76zdn.js";
|
|
7
|
+
|
|
8
|
+
// src/worker-entry/composed-worker.ts
|
|
9
|
+
import { defu } from "defu";
|
|
10
|
+
import { dirname, relative, resolve } from "pathe";
|
|
11
|
+
var DEFAULT_FETCH_ENTRY_FILES = [
|
|
12
|
+
"src/fetch.ts",
|
|
13
|
+
"src/fetch.js",
|
|
14
|
+
"src/fetch.mts",
|
|
15
|
+
"src/fetch.mjs"
|
|
16
|
+
];
|
|
17
|
+
var DEFAULT_QUEUE_ENTRY_FILES = [
|
|
18
|
+
"src/queue.ts",
|
|
19
|
+
"src/queue.js",
|
|
20
|
+
"src/queue.mts",
|
|
21
|
+
"src/queue.mjs"
|
|
22
|
+
];
|
|
23
|
+
var DEFAULT_SCHEDULED_ENTRY_FILES = [
|
|
24
|
+
"src/scheduled.ts",
|
|
25
|
+
"src/scheduled.js",
|
|
26
|
+
"src/scheduled.mts",
|
|
27
|
+
"src/scheduled.mjs"
|
|
28
|
+
];
|
|
29
|
+
var DEFAULT_EMAIL_ENTRY_FILES = [
|
|
30
|
+
"src/email.ts",
|
|
31
|
+
"src/email.js",
|
|
32
|
+
"src/email.mts",
|
|
33
|
+
"src/email.mjs"
|
|
34
|
+
];
|
|
35
|
+
function resolveConfigForEnvironment(config, environment) {
|
|
36
|
+
if (environment && config.env?.[environment]) {
|
|
37
|
+
return defu(config.env[environment], config);
|
|
38
|
+
}
|
|
39
|
+
return config;
|
|
40
|
+
}
|
|
41
|
+
async function resolveWorkerHandlerPath(cwd, configuredPath, defaultEntries) {
|
|
42
|
+
if (configuredPath === false) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const fs = await import("node:fs/promises");
|
|
46
|
+
const candidates = new Set;
|
|
47
|
+
if (typeof configuredPath === "string" && configuredPath) {
|
|
48
|
+
candidates.add(configuredPath);
|
|
49
|
+
}
|
|
50
|
+
for (const defaultEntry of defaultEntries) {
|
|
51
|
+
candidates.add(defaultEntry);
|
|
52
|
+
}
|
|
53
|
+
for (const candidate of candidates) {
|
|
54
|
+
const absolutePath = resolve(cwd, candidate);
|
|
55
|
+
try {
|
|
56
|
+
await fs.access(absolutePath);
|
|
57
|
+
return absolutePath;
|
|
58
|
+
} catch {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
async function resolveWorkerSurfacePaths(cwd, config) {
|
|
65
|
+
return {
|
|
66
|
+
fetch: await resolveWorkerHandlerPath(cwd, config.files?.fetch, DEFAULT_FETCH_ENTRY_FILES),
|
|
67
|
+
queue: await resolveWorkerHandlerPath(cwd, config.files?.queue, DEFAULT_QUEUE_ENTRY_FILES),
|
|
68
|
+
scheduled: await resolveWorkerHandlerPath(cwd, config.files?.scheduled, DEFAULT_SCHEDULED_ENTRY_FILES),
|
|
69
|
+
email: await resolveWorkerHandlerPath(cwd, config.files?.email, DEFAULT_EMAIL_ENTRY_FILES)
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function toImportSpecifier(fromFilePath, toFilePath) {
|
|
73
|
+
const specifier = relative(dirname(fromFilePath), toFilePath).replace(/\\/g, "/");
|
|
74
|
+
return specifier.startsWith(".") ? specifier : `./${specifier}`;
|
|
75
|
+
}
|
|
76
|
+
function createGeneratedRouteModuleImports(entryPath, routeDiscovery) {
|
|
77
|
+
if (!routeDiscovery) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
return routeDiscovery.routes.map((route, index) => ({
|
|
81
|
+
identifier: `__devflareRouteModule${index}`,
|
|
82
|
+
importPath: toImportSpecifier(entryPath, route.absolutePath),
|
|
83
|
+
filePath: route.filePath,
|
|
84
|
+
routePath: route.routePath,
|
|
85
|
+
segmentsJson: JSON.stringify(route.segments)
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
function needsComposedWorkerEntrypoint(surfacePaths, routeDiscovery) {
|
|
89
|
+
return Boolean(surfacePaths.fetch || surfacePaths.queue || surfacePaths.scheduled || surfacePaths.email || routeDiscovery?.routes.length);
|
|
90
|
+
}
|
|
91
|
+
function getComposedWorkerEntrypointSource(surfaceImportPaths, configuredLocalSendEmailBindings = {}, routeImports = [], options = {}) {
|
|
92
|
+
const importLines = [`import { createEmailEvent, createFetchEvent, createQueueEvent, createRouteResolve, createScheduledEvent, invokeFetchModule, matchFetchRoute, runWithEventContext, setLocalSendEmailBindings } from 'devflare/runtime'`];
|
|
93
|
+
const moduleFallbackLines = [];
|
|
94
|
+
const localSendEmailBindings = JSON.stringify(configuredLocalSendEmailBindings);
|
|
95
|
+
const routeManifestEntries = routeImports.map(({ identifier, filePath, routePath, segmentsJson }) => {
|
|
96
|
+
return ` { filePath: ${JSON.stringify(filePath)}, routePath: ${JSON.stringify(routePath)}, segments: ${segmentsJson}, module: ${identifier} }`;
|
|
97
|
+
});
|
|
98
|
+
const registerSurfaceModule = (identifier, importPath) => {
|
|
99
|
+
if (importPath) {
|
|
100
|
+
importLines.push(`import * as ${identifier} from '${importPath}'`);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
moduleFallbackLines.push(`const ${identifier} = {}`);
|
|
104
|
+
};
|
|
105
|
+
registerSurfaceModule("__devflareFetchModule", surfaceImportPaths.fetch);
|
|
106
|
+
registerSurfaceModule("__devflareQueueModule", surfaceImportPaths.queue);
|
|
107
|
+
registerSurfaceModule("__devflareScheduledModule", surfaceImportPaths.scheduled);
|
|
108
|
+
registerSurfaceModule("__devflareEmailModule", surfaceImportPaths.email);
|
|
109
|
+
for (const routeImport of routeImports) {
|
|
110
|
+
importLines.push(`import * as ${routeImport.identifier} from '${routeImport.importPath}'`);
|
|
111
|
+
}
|
|
112
|
+
const includeDevInternalEmail = options.devInternalEmail === true;
|
|
113
|
+
const devInternalEmailHelpers = includeDevInternalEmail ? `
|
|
114
|
+
function __devflareCreateEmailHeaders(rawBody) {
|
|
115
|
+
const headers = new Headers()
|
|
116
|
+
const lines = rawBody.split(/\\r?\\n/)
|
|
117
|
+
|
|
118
|
+
for (const line of lines) {
|
|
119
|
+
if (line.trim() === '') {
|
|
120
|
+
break
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const colonIndex = line.indexOf(':')
|
|
124
|
+
if (colonIndex <= 0) {
|
|
125
|
+
continue
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
headers.append(line.slice(0, colonIndex).trim(), line.slice(colonIndex + 1).trim())
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return headers
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function __devflareCreateEmailRawStream(rawBody) {
|
|
135
|
+
return new ReadableStream({
|
|
136
|
+
start(controller) {
|
|
137
|
+
controller.enqueue(new TextEncoder().encode(rawBody))
|
|
138
|
+
controller.close()
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function __devflareHandleInternalEmail(request, env, ctx) {
|
|
144
|
+
if (!__devflareEmailHandler) {
|
|
145
|
+
return new Response('Email handler not configured', { status: 501 })
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const from = request.headers.get('x-devflare-email-from') || 'unknown@example.com'
|
|
149
|
+
const to = request.headers.get('x-devflare-email-to') || 'worker@example.com'
|
|
150
|
+
const rawBody = await request.text()
|
|
151
|
+
const emailMessage = {
|
|
152
|
+
from,
|
|
153
|
+
to,
|
|
154
|
+
headers: __devflareCreateEmailHeaders(rawBody),
|
|
155
|
+
raw: __devflareCreateEmailRawStream(rawBody),
|
|
156
|
+
rawSize: rawBody.length,
|
|
157
|
+
setReject(reason) {
|
|
158
|
+
console.warn('[Devflare email rejected]', reason)
|
|
159
|
+
},
|
|
160
|
+
async forward(rcptTo) {
|
|
161
|
+
console.log('[Devflare email forwarded]', rcptTo)
|
|
162
|
+
return Promise.resolve()
|
|
163
|
+
},
|
|
164
|
+
async reply(message) {
|
|
165
|
+
console.log('[Devflare email reply sent]', message?.from)
|
|
166
|
+
return Promise.resolve()
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const __devflareEvent = createEmailEvent(emailMessage, env, ctx)
|
|
171
|
+
|
|
172
|
+
await runWithEventContext(
|
|
173
|
+
__devflareEvent,
|
|
174
|
+
() => __devflareEmailHandler(__devflareEvent, env, ctx)
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return new Response(JSON.stringify({ ok: true, from, to }), {
|
|
178
|
+
headers: { 'Content-Type': 'application/json' }
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
` : "";
|
|
182
|
+
return `
|
|
183
|
+
${importLines.join(`
|
|
184
|
+
`)}
|
|
185
|
+
${moduleFallbackLines.join(`
|
|
186
|
+
`)}
|
|
187
|
+
|
|
188
|
+
setLocalSendEmailBindings(${localSendEmailBindings})
|
|
189
|
+
|
|
190
|
+
const __devflareHasFetchModule = ${surfaceImportPaths.fetch ? "true" : "false"}
|
|
191
|
+
const __devflareRoutes = [
|
|
192
|
+
${routeManifestEntries.join(`,
|
|
193
|
+
`)}
|
|
194
|
+
]
|
|
195
|
+
const __devflareHasRoutes = __devflareRoutes.length > 0
|
|
196
|
+
|
|
197
|
+
const __devflareResolveHandler = (module, namedExport) => {
|
|
198
|
+
const defaultExport = module.default
|
|
199
|
+
|
|
200
|
+
if (typeof defaultExport === 'function') {
|
|
201
|
+
return defaultExport
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (defaultExport && typeof defaultExport[namedExport] === 'function') {
|
|
205
|
+
return defaultExport[namedExport].bind(defaultExport)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (typeof module[namedExport] === 'function') {
|
|
209
|
+
return module[namedExport]
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return null
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const __devflareQueueHandler = __devflareResolveHandler(__devflareQueueModule, 'queue')
|
|
216
|
+
const __devflareScheduledHandler = __devflareResolveHandler(__devflareScheduledModule, 'scheduled')
|
|
217
|
+
const __devflareEmailHandler = __devflareResolveHandler(__devflareEmailModule, 'email')
|
|
218
|
+
${devInternalEmailHelpers}
|
|
219
|
+
|
|
220
|
+
export default {
|
|
221
|
+
...(${surfaceImportPaths.fetch || routeImports.length > 0 || includeDevInternalEmail ? "true" : "false"}
|
|
222
|
+
? {
|
|
223
|
+
async fetch(request, env, ctx) {
|
|
224
|
+
${includeDevInternalEmail ? `const url = new URL(request.url)
|
|
225
|
+
|
|
226
|
+
if (
|
|
227
|
+
request.headers.get('x-devflare-event') === 'email'
|
|
228
|
+
&& url.pathname === '/_devflare/internal/email'
|
|
229
|
+
) {
|
|
230
|
+
return __devflareHandleInternalEmail(request, env, ctx)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
` : ""}const __devflareInitialRouteMatch = __devflareHasRoutes ? matchFetchRoute(__devflareRoutes, request) : null
|
|
234
|
+
const __devflareEvent = createFetchEvent(request, env, ctx, {
|
|
235
|
+
params: __devflareInitialRouteMatch?.params ?? {}
|
|
236
|
+
})
|
|
237
|
+
return runWithEventContext(
|
|
238
|
+
__devflareEvent,
|
|
239
|
+
() => invokeFetchModule(
|
|
240
|
+
__devflareFetchModule,
|
|
241
|
+
__devflareEvent,
|
|
242
|
+
__devflareHasRoutes
|
|
243
|
+
? createRouteResolve(__devflareRoutes, __devflareEvent)
|
|
244
|
+
: undefined
|
|
245
|
+
)
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
: {}),
|
|
250
|
+
...(__devflareQueueHandler
|
|
251
|
+
? {
|
|
252
|
+
async queue(batch, env, ctx) {
|
|
253
|
+
const __devflareEvent = createQueueEvent(batch, env, ctx)
|
|
254
|
+
return runWithEventContext(
|
|
255
|
+
__devflareEvent,
|
|
256
|
+
() => __devflareQueueHandler(__devflareEvent, env, ctx)
|
|
257
|
+
)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
: {}),
|
|
261
|
+
...(__devflareScheduledHandler
|
|
262
|
+
? {
|
|
263
|
+
async scheduled(controller, env, ctx) {
|
|
264
|
+
const __devflareEvent = createScheduledEvent(controller, env, ctx)
|
|
265
|
+
return runWithEventContext(
|
|
266
|
+
__devflareEvent,
|
|
267
|
+
() => __devflareScheduledHandler(__devflareEvent, env, ctx)
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
: {}),
|
|
272
|
+
...(__devflareEmailHandler
|
|
273
|
+
? {
|
|
274
|
+
async email(message, env, ctx) {
|
|
275
|
+
const __devflareEvent = createEmailEvent(message, env, ctx)
|
|
276
|
+
return runWithEventContext(
|
|
277
|
+
__devflareEvent,
|
|
278
|
+
() => __devflareEmailHandler(__devflareEvent, env, ctx)
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
: {})
|
|
283
|
+
}
|
|
284
|
+
`.trimStart();
|
|
285
|
+
}
|
|
286
|
+
async function prepareComposedWorkerEntrypoint(cwd, config, environment, options = {}) {
|
|
287
|
+
const resolvedConfig = resolveConfigForEnvironment(config, environment);
|
|
288
|
+
if (resolvedConfig.wrangler?.passthrough && Object.prototype.hasOwnProperty.call(resolvedConfig.wrangler.passthrough, "main")) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const surfacePaths = await resolveWorkerSurfacePaths(cwd, resolvedConfig);
|
|
292
|
+
const routeDiscovery = await discoverRoutes(cwd, resolvedConfig);
|
|
293
|
+
if (!needsComposedWorkerEntrypoint(surfacePaths, routeDiscovery)) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
const fs = await import("node:fs/promises");
|
|
297
|
+
const entryDir = resolve(cwd, ".devflare", "worker-entrypoints");
|
|
298
|
+
const entryPath = resolve(entryDir, "main.ts");
|
|
299
|
+
await fs.mkdir(entryDir, { recursive: true });
|
|
300
|
+
const surfaceImportPaths = {
|
|
301
|
+
fetch: surfacePaths.fetch ? toImportSpecifier(entryPath, surfacePaths.fetch) : null,
|
|
302
|
+
queue: surfacePaths.queue ? toImportSpecifier(entryPath, surfacePaths.queue) : null,
|
|
303
|
+
scheduled: surfacePaths.scheduled ? toImportSpecifier(entryPath, surfacePaths.scheduled) : null,
|
|
304
|
+
email: surfacePaths.email ? toImportSpecifier(entryPath, surfacePaths.email) : null
|
|
305
|
+
};
|
|
306
|
+
const routeImports = createGeneratedRouteModuleImports(entryPath, routeDiscovery);
|
|
307
|
+
await fs.writeFile(entryPath, getComposedWorkerEntrypointSource(surfaceImportPaths, resolvedConfig.bindings?.sendEmail ?? {}, routeImports, options));
|
|
308
|
+
return ".devflare/worker-entrypoints/main.ts";
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export { prepareComposedWorkerEntrypoint };
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require
|
|
3
|
+
} from "./index-37x76zdn.js";
|
|
4
|
+
|
|
5
|
+
// src/dev-server/vite-utils.ts
|
|
6
|
+
import { resolve } from "pathe";
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
var VITE_CONFIG_FILES = [
|
|
9
|
+
"vite.config.ts",
|
|
10
|
+
"vite.config.js",
|
|
11
|
+
"vite.config.mts",
|
|
12
|
+
"vite.config.mjs",
|
|
13
|
+
"vite.config.cts",
|
|
14
|
+
"vite.config.cjs"
|
|
15
|
+
];
|
|
16
|
+
var ANSI_REGEX = /\x1b\[[0-9;]*m/g;
|
|
17
|
+
var LOCAL_VITE_URL_REGEX = /https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?\/?/i;
|
|
18
|
+
async function getNodeFs() {
|
|
19
|
+
return await import("node:fs/promises");
|
|
20
|
+
}
|
|
21
|
+
function safeParsePackageJson(content) {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(content);
|
|
24
|
+
} catch {
|
|
25
|
+
return {};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function readDependencyFlag(pkg, name) {
|
|
29
|
+
const dependencies = pkg.dependencies;
|
|
30
|
+
const devDependencies = pkg.devDependencies;
|
|
31
|
+
return Boolean(dependencies?.[name] ?? devDependencies?.[name]);
|
|
32
|
+
}
|
|
33
|
+
async function detectViteProject(cwd, fs) {
|
|
34
|
+
const fileSystem = fs ?? await getNodeFs();
|
|
35
|
+
let viteConfigPath = null;
|
|
36
|
+
for (const configName of VITE_CONFIG_FILES) {
|
|
37
|
+
const absolutePath = resolve(cwd, configName);
|
|
38
|
+
try {
|
|
39
|
+
await fileSystem.access(absolutePath);
|
|
40
|
+
viteConfigPath = absolutePath;
|
|
41
|
+
break;
|
|
42
|
+
} catch {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
let pkg = {};
|
|
47
|
+
try {
|
|
48
|
+
const packageJson = await fileSystem.readFile(resolve(cwd, "package.json"), "utf-8");
|
|
49
|
+
pkg = safeParsePackageJson(packageJson);
|
|
50
|
+
} catch {
|
|
51
|
+
pkg = {};
|
|
52
|
+
}
|
|
53
|
+
const hasLocalViteDependency = readDependencyFlag(pkg, "vite");
|
|
54
|
+
const hasLocalCloudflareVitePluginDependency = readDependencyFlag(pkg, "@cloudflare/vite-plugin");
|
|
55
|
+
const wantsViteIntegration = Boolean(viteConfigPath || hasLocalViteDependency || hasLocalCloudflareVitePluginDependency);
|
|
56
|
+
return {
|
|
57
|
+
viteConfigPath,
|
|
58
|
+
hasLocalViteDependency,
|
|
59
|
+
hasLocalCloudflareVitePluginDependency,
|
|
60
|
+
shouldStartVite: Boolean(viteConfigPath),
|
|
61
|
+
wantsViteIntegration
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function stripAnsi(value) {
|
|
65
|
+
return value.replace(ANSI_REGEX, "");
|
|
66
|
+
}
|
|
67
|
+
function extractViteReadyUrl(output) {
|
|
68
|
+
const cleaned = stripAnsi(output);
|
|
69
|
+
const lines = cleaned.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
70
|
+
for (const line of lines) {
|
|
71
|
+
if (!line.toLowerCase().includes("local:")) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const match = line.match(LOCAL_VITE_URL_REGEX);
|
|
75
|
+
if (match) {
|
|
76
|
+
return match[0];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const fallbackMatch = cleaned.match(LOCAL_VITE_URL_REGEX);
|
|
80
|
+
return fallbackMatch?.[0] ?? null;
|
|
81
|
+
}
|
|
82
|
+
async function waitForViteReady(process, options = {}) {
|
|
83
|
+
const {
|
|
84
|
+
timeoutMs = 15000,
|
|
85
|
+
onStdout,
|
|
86
|
+
onStderr
|
|
87
|
+
} = options;
|
|
88
|
+
let combinedOutput = "";
|
|
89
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
90
|
+
let settled = false;
|
|
91
|
+
let timeout;
|
|
92
|
+
const settle = (resolver) => {
|
|
93
|
+
if (settled) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
settled = true;
|
|
97
|
+
clearTimeout(timeout);
|
|
98
|
+
resolver();
|
|
99
|
+
};
|
|
100
|
+
const inspectChunk = (chunk) => {
|
|
101
|
+
combinedOutput += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
|
|
102
|
+
const readyUrl = extractViteReadyUrl(combinedOutput);
|
|
103
|
+
if (readyUrl) {
|
|
104
|
+
settle(() => resolvePromise(readyUrl));
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
process.stdout?.on("data", (chunk) => {
|
|
108
|
+
onStdout?.(chunk);
|
|
109
|
+
inspectChunk(chunk);
|
|
110
|
+
});
|
|
111
|
+
process.stderr?.on("data", (chunk) => {
|
|
112
|
+
onStderr?.(chunk);
|
|
113
|
+
inspectChunk(chunk);
|
|
114
|
+
});
|
|
115
|
+
process.on("error", (error) => {
|
|
116
|
+
settle(() => rejectPromise(error));
|
|
117
|
+
});
|
|
118
|
+
process.on("exit", (code, signal) => {
|
|
119
|
+
settle(() => {
|
|
120
|
+
const reason = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
|
|
121
|
+
rejectPromise(new Error(`Vite exited before reporting a ready URL (${reason})`));
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
timeout = setTimeout(() => {
|
|
125
|
+
settle(() => resolvePromise(null));
|
|
126
|
+
}, timeoutMs);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async function defaultRunCommand(command, args) {
|
|
130
|
+
await new Promise((resolvePromise, rejectPromise) => {
|
|
131
|
+
const child = spawn(command, args, {
|
|
132
|
+
stdio: "ignore",
|
|
133
|
+
windowsHide: true
|
|
134
|
+
});
|
|
135
|
+
child.on("error", rejectPromise);
|
|
136
|
+
child.on("exit", () => resolvePromise());
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function waitForProcessExit(process, timeoutMs) {
|
|
140
|
+
if (process.killed) {
|
|
141
|
+
return Promise.resolve(true);
|
|
142
|
+
}
|
|
143
|
+
return new Promise((resolvePromise) => {
|
|
144
|
+
let settled = false;
|
|
145
|
+
let timeout;
|
|
146
|
+
const settle = (value) => {
|
|
147
|
+
if (settled) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
settled = true;
|
|
151
|
+
clearTimeout(timeout);
|
|
152
|
+
resolvePromise(value);
|
|
153
|
+
};
|
|
154
|
+
process.on("exit", () => settle(true));
|
|
155
|
+
timeout = setTimeout(() => {
|
|
156
|
+
settle(false);
|
|
157
|
+
}, timeoutMs);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
async function stopSpawnedProcessTree(process, options = {}) {
|
|
161
|
+
const {
|
|
162
|
+
platform = globalThis.process?.platform ?? "linux",
|
|
163
|
+
timeoutMs = 3000,
|
|
164
|
+
runCommand = defaultRunCommand
|
|
165
|
+
} = options;
|
|
166
|
+
if (platform === "win32" && process.pid) {
|
|
167
|
+
try {
|
|
168
|
+
await runCommand("taskkill", ["/pid", String(process.pid), "/t", "/f"]);
|
|
169
|
+
} catch {
|
|
170
|
+
try {
|
|
171
|
+
process.kill("SIGTERM");
|
|
172
|
+
} catch {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
await waitForProcessExit(process, timeoutMs);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
process.kill("SIGTERM");
|
|
181
|
+
} catch {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const exited = await waitForProcessExit(process, timeoutMs);
|
|
185
|
+
if (exited) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
process.kill("SIGKILL");
|
|
190
|
+
} catch {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
await waitForProcessExit(process, timeoutMs);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export { detectViteProject, waitForViteReady, stopSpawnedProcessTree };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getDependencies
|
|
3
3
|
} from "./index-1xpj0m4r.js";
|
|
4
|
+
import {
|
|
5
|
+
getInitDependencyVersions
|
|
6
|
+
} from "./index-6h8xbs75.js";
|
|
4
7
|
import"./index-37x76zdn.js";
|
|
5
8
|
|
|
6
9
|
// src/cli/commands/init.ts
|
|
@@ -14,14 +17,20 @@ var MINIMAL_TEMPLATE = {
|
|
|
14
17
|
export default defineConfig({
|
|
15
18
|
name: '{{PROJECT_NAME}}',
|
|
16
19
|
compatibilityDate: '${new Date().toISOString().split("T")[0]}',
|
|
20
|
+
files: {
|
|
21
|
+
fetch: 'src/fetch.ts'
|
|
22
|
+
}
|
|
17
23
|
})
|
|
18
24
|
`,
|
|
19
|
-
"src/
|
|
25
|
+
"src/fetch.ts": `import type { FetchEvent } from 'devflare/runtime'
|
|
20
26
|
|
|
21
|
-
export
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
27
|
+
export async function fetch({ request }: FetchEvent): Promise<Response> {
|
|
28
|
+
const url = new URL(request.url)
|
|
29
|
+
return new Response(
|
|
30
|
+
url.pathname === '/'
|
|
31
|
+
? 'Hello from Devflare'
|
|
32
|
+
: \`Hello from Devflare: \${url.pathname}\`
|
|
33
|
+
)
|
|
25
34
|
}
|
|
26
35
|
`,
|
|
27
36
|
"package.json": `{
|
|
@@ -36,8 +45,10 @@ export default {
|
|
|
36
45
|
"types": "devflare types"
|
|
37
46
|
},
|
|
38
47
|
"devDependencies": {
|
|
39
|
-
"
|
|
40
|
-
"
|
|
48
|
+
"@cloudflare/workers-types": "{{WORKERS_TYPES_VERSION}}",
|
|
49
|
+
"devflare": "{{DEVFLARE_VERSION}}",
|
|
50
|
+
"typescript": "{{TYPESCRIPT_VERSION}}",
|
|
51
|
+
"wrangler": "{{WRANGLER_VERSION}}"
|
|
41
52
|
}
|
|
42
53
|
}
|
|
43
54
|
`,
|
|
@@ -50,91 +61,65 @@ export default {
|
|
|
50
61
|
"skipLibCheck": true,
|
|
51
62
|
"types": ["@cloudflare/workers-types"]
|
|
52
63
|
},
|
|
53
|
-
"include": ["src/**/*", "devflare.config.ts"]
|
|
64
|
+
"include": ["src/**/*", "env.d.ts", "devflare.config.ts"]
|
|
54
65
|
}
|
|
55
66
|
`
|
|
56
67
|
}
|
|
57
68
|
};
|
|
58
69
|
var API_TEMPLATE = {
|
|
59
70
|
name: "api",
|
|
60
|
-
description: "API starter with middleware
|
|
71
|
+
description: "API starter with request-wide middleware",
|
|
61
72
|
files: {
|
|
62
73
|
"devflare.config.ts": `import { defineConfig } from 'devflare'
|
|
63
74
|
|
|
64
75
|
export default defineConfig({
|
|
65
76
|
name: '{{PROJECT_NAME}}',
|
|
66
77
|
compatibilityDate: '${new Date().toISOString().split("T")[0]}',
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// kv: [{ binding: 'CACHE' }],
|
|
70
|
-
// d1: [{ binding: 'DB', database_name: 'my-db' }],
|
|
78
|
+
files: {
|
|
79
|
+
fetch: 'src/fetch.ts'
|
|
71
80
|
}
|
|
72
81
|
})
|
|
73
82
|
`,
|
|
74
|
-
"src/
|
|
75
|
-
import {
|
|
76
|
-
import {
|
|
77
|
-
|
|
78
|
-
const handler = sequence(
|
|
79
|
-
corsMiddleware
|
|
80
|
-
)(
|
|
81
|
-
resolve(
|
|
82
|
-
apiRouter,
|
|
83
|
-
async () => new Response('Not Found', { status: 404 })
|
|
84
|
-
)
|
|
85
|
-
)
|
|
83
|
+
"src/fetch.ts": `import { sequence } from 'devflare/runtime'
|
|
84
|
+
import { corsHandle } from './middleware/cors'
|
|
85
|
+
import { appFetch } from './app'
|
|
86
86
|
|
|
87
|
-
export
|
|
88
|
-
async fetch(request: Request, env: unknown, ctx: ExecutionContext): Promise<Response> {
|
|
89
|
-
return handler()
|
|
90
|
-
}
|
|
91
|
-
}
|
|
87
|
+
export const handle = sequence(corsHandle, appFetch)
|
|
92
88
|
`,
|
|
93
|
-
"src/middleware/cors.ts": `import type {
|
|
94
|
-
import { event } from 'devflare/runtime'
|
|
89
|
+
"src/middleware/cors.ts": `import type { FetchEvent, ResolveFetch } from 'devflare/runtime'
|
|
95
90
|
|
|
96
|
-
export
|
|
91
|
+
export async function corsHandle(event: FetchEvent, resolve: ResolveFetch): Promise<Response> {
|
|
97
92
|
// Handle preflight
|
|
98
|
-
if (event.request
|
|
93
|
+
if (event.request.method === 'OPTIONS') {
|
|
99
94
|
return new Response(null, {
|
|
100
95
|
headers: {
|
|
101
96
|
'Access-Control-Allow-Origin': '*',
|
|
102
97
|
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
|
|
103
|
-
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
|
|
98
|
+
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
|
|
104
99
|
}
|
|
105
100
|
})
|
|
106
101
|
}
|
|
107
102
|
|
|
108
|
-
const response = await
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
return
|
|
103
|
+
const response = await resolve(event)
|
|
104
|
+
const next = new Response(response.body, response)
|
|
105
|
+
next.headers.set('Access-Control-Allow-Origin', '*')
|
|
106
|
+
return next
|
|
112
107
|
}
|
|
113
108
|
`,
|
|
114
|
-
"src/
|
|
115
|
-
import { event, env, locals } from 'devflare/runtime'
|
|
116
|
-
|
|
117
|
-
export const apiRouter: Handler = async () => {
|
|
118
|
-
const request = event.request
|
|
119
|
-
if (!request) return null
|
|
109
|
+
"src/app.ts": `import type { FetchEvent } from 'devflare/runtime'
|
|
120
110
|
|
|
111
|
+
export async function appFetch({ request }: FetchEvent): Promise<Response> {
|
|
121
112
|
const url = new URL(request.url)
|
|
122
113
|
|
|
123
114
|
if (url.pathname === '/api/health') {
|
|
124
|
-
return
|
|
125
|
-
headers: { 'Content-Type': 'application/json' }
|
|
126
|
-
})
|
|
115
|
+
return Response.json({ status: 'ok' })
|
|
127
116
|
}
|
|
128
117
|
|
|
129
118
|
if (url.pathname.startsWith('/api/')) {
|
|
130
|
-
return
|
|
131
|
-
status: 404,
|
|
132
|
-
headers: { 'Content-Type': 'application/json' }
|
|
133
|
-
})
|
|
119
|
+
return Response.json({ error: 'Not found' }, { status: 404 })
|
|
134
120
|
}
|
|
135
121
|
|
|
136
|
-
|
|
137
|
-
return null
|
|
122
|
+
return new Response('Not Found', { status: 404 })
|
|
138
123
|
}
|
|
139
124
|
`,
|
|
140
125
|
"package.json": MINIMAL_TEMPLATE.files["package.json"],
|
|
@@ -157,6 +142,7 @@ async function runInitCommand(parsed, logger, options) {
|
|
|
157
142
|
return { exitCode: 1 };
|
|
158
143
|
}
|
|
159
144
|
const projectDir = resolve(cwd, projectName);
|
|
145
|
+
const dependencyVersions = await getInitDependencyVersions();
|
|
160
146
|
const { fs } = await getDependencies();
|
|
161
147
|
try {
|
|
162
148
|
await fs.access(projectDir);
|
|
@@ -168,7 +154,7 @@ async function runInitCommand(parsed, logger, options) {
|
|
|
168
154
|
const fullPath = join(projectDir, filePath);
|
|
169
155
|
const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
170
156
|
await fs.mkdir(dir, { recursive: true }).catch(() => {});
|
|
171
|
-
const processedContent = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName);
|
|
157
|
+
const processedContent = content.replace(/\{\{PROJECT_NAME\}\}/g, projectName).replace(/\{\{DEVFLARE_VERSION\}\}/g, dependencyVersions.devflare).replace(/\{\{TYPESCRIPT_VERSION\}\}/g, dependencyVersions.typescript).replace(/\{\{WRANGLER_VERSION\}\}/g, dependencyVersions.wrangler).replace(/\{\{WORKERS_TYPES_VERSION\}\}/g, dependencyVersions.workersTypes);
|
|
172
158
|
await fs.writeFile(fullPath, processedContent, "utf-8");
|
|
173
159
|
logger.info(` Created: ${filePath}`);
|
|
174
160
|
}
|
|
@@ -178,6 +164,7 @@ Project created successfully!`);
|
|
|
178
164
|
Next steps:`);
|
|
179
165
|
logger.info(` cd ${projectName}`);
|
|
180
166
|
logger.info(` bun install`);
|
|
167
|
+
logger.info(` bun run types`);
|
|
181
168
|
logger.info(` bun run dev`);
|
|
182
169
|
return { exitCode: 0 };
|
|
183
170
|
}
|