@kodycodes/cli 1.26.1 → 1.26.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-4FW6GCLG.js +26 -0
- package/dist/auth-4FW6GCLG.js.map +6 -0
- package/dist/bin.js +27 -3
- package/dist/bin.js.map +6 -1
- package/dist/chunk-46IJPEID.js +30 -0
- package/dist/chunk-46IJPEID.js.map +6 -0
- package/dist/chunk-4D6ORNXY.js +24404 -0
- package/dist/chunk-4D6ORNXY.js.map +6 -0
- package/dist/chunk-64IM6G4Z.js +341 -0
- package/dist/chunk-64IM6G4Z.js.map +6 -0
- package/dist/{package-local-runtime-source.js → chunk-64XN367G.js} +373 -52
- package/dist/chunk-64XN367G.js.map +6 -0
- package/dist/chunk-6XQP5SWX.js +26 -0
- package/dist/chunk-6XQP5SWX.js.map +6 -0
- package/dist/chunk-75RZUXQL.js +62 -0
- package/dist/chunk-75RZUXQL.js.map +6 -0
- package/dist/chunk-BISUL7CE.js +106 -0
- package/dist/chunk-BISUL7CE.js.map +6 -0
- package/dist/chunk-BPGY4IE7.js +57 -0
- package/dist/chunk-BPGY4IE7.js.map +6 -0
- package/dist/chunk-CASGRYOF.js +21 -0
- package/dist/chunk-CASGRYOF.js.map +6 -0
- package/dist/chunk-CWWHR4FH.js +19 -0
- package/dist/chunk-CWWHR4FH.js.map +6 -0
- package/dist/chunk-D55XPY3T.js +1382 -0
- package/dist/chunk-D55XPY3T.js.map +6 -0
- package/dist/chunk-EOCV74B2.js +948 -0
- package/dist/chunk-EOCV74B2.js.map +6 -0
- package/dist/chunk-FBVNFWR6.js +437 -0
- package/dist/chunk-FBVNFWR6.js.map +6 -0
- package/dist/chunk-G4YN6XP5.js +14 -0
- package/dist/chunk-G4YN6XP5.js.map +6 -0
- package/dist/chunk-G6LJWROP.js +18 -0
- package/dist/chunk-G6LJWROP.js.map +6 -0
- package/dist/chunk-IHP6PV6X.js +49 -0
- package/dist/chunk-IHP6PV6X.js.map +6 -0
- package/dist/chunk-JWEFKKAD.js +24 -0
- package/dist/chunk-JWEFKKAD.js.map +6 -0
- package/dist/chunk-LWNB26KO.js +147 -0
- package/dist/chunk-LWNB26KO.js.map +6 -0
- package/dist/chunk-OVGXPRSY.js +20 -0
- package/dist/chunk-OVGXPRSY.js.map +6 -0
- package/dist/chunk-PDWCKWQF.js +453 -0
- package/dist/chunk-PDWCKWQF.js.map +6 -0
- package/dist/chunk-QHBCP4OB.js +44 -0
- package/dist/chunk-QHBCP4OB.js.map +6 -0
- package/dist/chunk-R4IUV5P5.js +664 -0
- package/dist/chunk-R4IUV5P5.js.map +6 -0
- package/dist/chunk-RM34N3KI.js +525 -0
- package/dist/chunk-RM34N3KI.js.map +6 -0
- package/dist/chunk-RTWUNV76.js +309 -0
- package/dist/chunk-RTWUNV76.js.map +6 -0
- package/dist/chunk-SMURF26I.js +23 -0
- package/dist/chunk-SMURF26I.js.map +6 -0
- package/dist/chunk-SXHULGL4.js +426 -0
- package/dist/chunk-SXHULGL4.js.map +6 -0
- package/dist/chunk-TIL35OWA.js +1959 -0
- package/dist/chunk-TIL35OWA.js.map +6 -0
- package/dist/chunk-VQS5YSCI.js +54 -0
- package/dist/chunk-VQS5YSCI.js.map +6 -0
- package/dist/chunk-XDCOWU5R.js +696 -0
- package/dist/chunk-XDCOWU5R.js.map +6 -0
- package/dist/chunk-XOPPGRUP.js +605 -0
- package/dist/chunk-XOPPGRUP.js.map +6 -0
- package/dist/cli.js +74 -1500
- package/dist/cli.js.map +6 -1
- package/dist/dev/dev-watcher.d.ts +5 -1
- package/dist/dev-command-3LX234N6.js +4900 -0
- package/dist/dev-command-3LX234N6.js.map +6 -0
- package/dist/git-credential-FUE3JE3T.js +163 -0
- package/dist/git-credential-FUE3JE3T.js.map +6 -0
- package/dist/install-ZML2TCDG.js +10694 -0
- package/dist/install-ZML2TCDG.js.map +6 -0
- package/dist/local-execute-SZV6XN4T.js +368 -0
- package/dist/local-execute-SZV6XN4T.js.map +6 -0
- package/dist/local-package-run-2TMCAZZ2.js +23 -0
- package/dist/local-package-run-2TMCAZZ2.js.map +6 -0
- package/dist/mcp-G2AWTIXR.js +21 -0
- package/dist/mcp-G2AWTIXR.js.map +6 -0
- package/dist/mock-dep-resolve-TVABDNR7.js +52 -0
- package/dist/mock-dep-resolve-TVABDNR7.js.map +6 -0
- package/dist/mock-fetch-gateway-B5TFGGQS.js +34 -0
- package/dist/mock-fetch-gateway-B5TFGGQS.js.map +6 -0
- package/dist/mock-local-deps-5SZT3PWT.js +197 -0
- package/dist/mock-local-deps-5SZT3PWT.js.map +6 -0
- package/dist/mock-server-SV2IKC4I.js +21 -0
- package/dist/mock-server-SV2IKC4I.js.map +6 -0
- package/dist/open-api-client-DVVMLY7P.js +42 -0
- package/dist/open-api-client-DVVMLY7P.js.map +6 -0
- package/dist/org-X7B5BI4R.js +132 -0
- package/dist/org-X7B5BI4R.js.map +6 -0
- package/dist/package-manifest-QH2RU64C.js +14 -0
- package/dist/package-manifest-QH2RU64C.js.map +6 -0
- package/dist/remote-execute-QMQDVHOY.js +110 -0
- package/dist/remote-execute-QMQDVHOY.js.map +6 -0
- package/dist/setup-git-5KCUBYPB.js +88 -0
- package/dist/setup-git-5KCUBYPB.js.map +6 -0
- package/dist/skill-ENPATRIW.js +43 -0
- package/dist/skill-ENPATRIW.js.map +6 -0
- package/dist/store-WTMRH527.js +48 -0
- package/dist/store-WTMRH527.js.map +6 -0
- package/dist/structured-error-C65GQ53Z.js +13 -0
- package/dist/structured-error-C65GQ53Z.js.map +6 -0
- package/dist/target-3QHY7JT4.js +45 -0
- package/dist/target-3QHY7JT4.js.map +6 -0
- package/dist/webapi-NTVP4BO3.js +2482 -0
- package/dist/webapi-NTVP4BO3.js.map +6 -0
- package/package.json +8 -8
- package/dist/add-mcp-install.js +0 -59
- package/dist/add-mcp-install.js.map +0 -1
- package/dist/api-token-store.js +0 -120
- package/dist/api-token-store.js.map +0 -1
- package/dist/api-token.js +0 -238
- package/dist/api-token.js.map +0 -1
- package/dist/auth-bootstrap.js +0 -373
- package/dist/auth-bootstrap.js.map +0 -1
- package/dist/auth.js +0 -386
- package/dist/auth.js.map +0 -1
- package/dist/capability-proxy.js +0 -527
- package/dist/capability-proxy.js.map +0 -1
- package/dist/credential-call-map.js +0 -155
- package/dist/credential-call-map.js.map +0 -1
- package/dist/credential-client-runtime-source.js +0 -9
- package/dist/credential-client-runtime-source.js.map +0 -1
- package/dist/credentialed-fetch-scan.js +0 -98
- package/dist/credentialed-fetch-scan.js.map +0 -1
- package/dist/defaults.js +0 -34
- package/dist/defaults.js.map +0 -1
- package/dist/detect-running-hosts.js +0 -13
- package/dist/detect-running-hosts.js.map +0 -1
- package/dist/dev/dev-assets.js +0 -202
- package/dist/dev/dev-assets.js.map +0 -1
- package/dist/dev/dev-bundler.js +0 -65
- package/dist/dev/dev-bundler.js.map +0 -1
- package/dist/dev/dev-events.js +0 -94
- package/dist/dev/dev-events.js.map +0 -1
- package/dist/dev/dev-port.js +0 -80
- package/dist/dev/dev-port.js.map +0 -1
- package/dist/dev/dev-protocol.js +0 -14
- package/dist/dev/dev-protocol.js.map +0 -1
- package/dist/dev/dev-registry.js +0 -95
- package/dist/dev/dev-registry.js.map +0 -1
- package/dist/dev/dev-watcher.js +0 -156
- package/dist/dev/dev-watcher.js.map +0 -1
- package/dist/dev/error-page.js +0 -64
- package/dist/dev/error-page.js.map +0 -1
- package/dist/dev/live-reload.js +0 -148
- package/dist/dev/live-reload.js.map +0 -1
- package/dist/dev/prebuild.js +0 -102
- package/dist/dev/prebuild.js.map +0 -1
- package/dist/dev/process-reaper.js +0 -151
- package/dist/dev/process-reaper.js.map +0 -1
- package/dist/dev/stack-trace.js +0 -56
- package/dist/dev/stack-trace.js.map +0 -1
- package/dist/dev/workerd-process.js +0 -118
- package/dist/dev/workerd-process.js.map +0 -1
- package/dist/dev-command.js +0 -672
- package/dist/dev-command.js.map +0 -1
- package/dist/discover-login-identity.js +0 -77
- package/dist/discover-login-identity.js.map +0 -1
- package/dist/discover-org.js +0 -62
- package/dist/discover-org.js.map +0 -1
- package/dist/git-credential.js +0 -147
- package/dist/git-credential.js.map +0 -1
- package/dist/help.js +0 -333
- package/dist/help.js.map +0 -1
- package/dist/host-catalog.js +0 -427
- package/dist/host-catalog.js.map +0 -1
- package/dist/host-config.js +0 -80
- package/dist/host-config.js.map +0 -1
- package/dist/http-error-body.js +0 -35
- package/dist/http-error-body.js.map +0 -1
- package/dist/install-hosts.js +0 -328
- package/dist/install-hosts.js.map +0 -1
- package/dist/install.js +0 -120
- package/dist/install.js.map +0 -1
- package/dist/invoke-passthrough.js +0 -60
- package/dist/invoke-passthrough.js.map +0 -1
- package/dist/local-bundle.js +0 -200
- package/dist/local-bundle.js.map +0 -1
- package/dist/local-execute-auth.js +0 -53
- package/dist/local-execute-auth.js.map +0 -1
- package/dist/local-execute.js +0 -338
- package/dist/local-execute.js.map +0 -1
- package/dist/local-gateway-fetch-forward.js +0 -135
- package/dist/local-gateway-fetch-forward.js.map +0 -1
- package/dist/local-host-runtime-surface.js +0 -75
- package/dist/local-host-runtime-surface.js.map +0 -1
- package/dist/local-package-graph.js +0 -405
- package/dist/local-package-graph.js.map +0 -1
- package/dist/local-package-run.js +0 -307
- package/dist/local-package-run.js.map +0 -1
- package/dist/local-runtime-bridge.js +0 -132
- package/dist/local-runtime-bridge.js.map +0 -1
- package/dist/local-runtime-source.js +0 -541
- package/dist/local-runtime-source.js.map +0 -1
- package/dist/login-callback-assets.js +0 -10
- package/dist/login-callback-assets.js.map +0 -1
- package/dist/login-callback-page.js +0 -362
- package/dist/login-callback-page.js.map +0 -1
- package/dist/mcp.js +0 -134
- package/dist/mcp.js.map +0 -1
- package/dist/mock/ensure-msw.js +0 -215
- package/dist/mock/ensure-msw.js.map +0 -1
- package/dist/mock/install-mock-fetch-shim.js +0 -36
- package/dist/mock/install-mock-fetch-shim.js.map +0 -1
- package/dist/mock/load-package-mocks.js +0 -136
- package/dist/mock/load-package-mocks.js.map +0 -1
- package/dist/mock/mock-fetch-gateway.js +0 -343
- package/dist/mock/mock-fetch-gateway.js.map +0 -1
- package/dist/mock/mock-gateway-fetch-shim.js +0 -104
- package/dist/mock/mock-gateway-fetch-shim.js.map +0 -1
- package/dist/mock/mock-server.js +0 -499
- package/dist/mock/mock-server.js.map +0 -1
- package/dist/mock/mock-storage.js +0 -186
- package/dist/mock/mock-storage.js.map +0 -1
- package/dist/mock/mock-supported.js +0 -63
- package/dist/mock/mock-supported.js.map +0 -1
- package/dist/mock-dep-resolve.js +0 -47
- package/dist/mock-dep-resolve.js.map +0 -1
- package/dist/mock-local-deps.js +0 -207
- package/dist/mock-local-deps.js.map +0 -1
- package/dist/network-error.js +0 -11
- package/dist/network-error.js.map +0 -1
- package/dist/node-engine.js +0 -21
- package/dist/node-engine.js.map +0 -1
- package/dist/oauth-provider.js +0 -107
- package/dist/oauth-provider.js.map +0 -1
- package/dist/onboarding-prompt.js +0 -15
- package/dist/onboarding-prompt.js.map +0 -1
- package/dist/open-api-client.js +0 -432
- package/dist/open-api-client.js.map +0 -1
- package/dist/open-url.js +0 -21
- package/dist/open-url.js.map +0 -1
- package/dist/org-resolve.js +0 -16
- package/dist/org-resolve.js.map +0 -1
- package/dist/org-slug.js +0 -11
- package/dist/org-slug.js.map +0 -1
- package/dist/org.js +0 -100
- package/dist/org.js.map +0 -1
- package/dist/package-app-dev.js +0 -905
- package/dist/package-app-dev.js.map +0 -1
- package/dist/package-collaborators.js +0 -179
- package/dist/package-collaborators.js.map +0 -1
- package/dist/package-info.js +0 -19
- package/dist/package-info.js.map +0 -1
- package/dist/package-local-runtime-source.js.map +0 -1
- package/dist/package-manifest.js +0 -364
- package/dist/package-manifest.js.map +0 -1
- package/dist/process-info.js +0 -14
- package/dist/process-info.js.map +0 -1
- package/dist/redact.js +0 -16
- package/dist/redact.js.map +0 -1
- package/dist/remote-execute.js +0 -108
- package/dist/remote-execute.js.map +0 -1
- package/dist/setup-git.js +0 -676
- package/dist/setup-git.js.map +0 -1
- package/dist/skill.js +0 -35
- package/dist/skill.js.map +0 -1
- package/dist/store.js +0 -597
- package/dist/store.js.map +0 -1
- package/dist/structured-error.js +0 -57
- package/dist/structured-error.js.map +0 -1
- package/dist/target.js +0 -52
- package/dist/target.js.map +0 -1
- package/dist/tool-result.js +0 -19
- package/dist/tool-result.js.map +0 -1
- package/dist/which.js +0 -22
- package/dist/which.js.map +0 -1
- package/dist/workerd-binary.js +0 -98
- package/dist/workerd-binary.js.map +0 -1
package/dist/package-app-dev.js
DELETED
|
@@ -1,905 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Long-running `kody dev` app server: bundles `kody.app.entry` the same way
|
|
3
|
-
* local-bundle/publish does for esbuild, serves via workerd behind a Node
|
|
4
|
-
* proxy that strips the mount, and rebuilds on file changes.
|
|
5
|
-
*
|
|
6
|
-
* Each successful rebuild starts a new workerd "generation" and only swaps the
|
|
7
|
-
* proxy over once it is listening; the previous generation drains in-flight
|
|
8
|
-
* requests and is then stopped. Requests that arrive mid-rebuild wait for it,
|
|
9
|
-
* so a save is never answered by a 503 or a stale bundle.
|
|
10
|
-
*/
|
|
11
|
-
import { randomBytes } from 'node:crypto';
|
|
12
|
-
import { rmSync } from 'node:fs';
|
|
13
|
-
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
14
|
-
import { createServer, request as httpRequest, } from 'node:http';
|
|
15
|
-
import { tmpdir } from 'node:os';
|
|
16
|
-
import { join, relative, resolve, sep } from 'node:path';
|
|
17
|
-
import { assertTokenSafeApiUrl, callCapabilityProxy, } from './capability-proxy.js';
|
|
18
|
-
import { apiTokenEnvVar } from './defaults.js';
|
|
19
|
-
import { createDevClientBundler, parseDevAssetPath, serveDevAsset, } from './dev/dev-assets.js';
|
|
20
|
-
import { forwardLocalGatewayFetchStream } from './local-gateway-fetch-forward.js';
|
|
21
|
-
import { startLocalRuntimeBridge, } from './local-runtime-bridge.js';
|
|
22
|
-
import { createDevBundler } from './dev/dev-bundler.js';
|
|
23
|
-
import { parseWorkerdStdoutLine, runtimeErrorFix, } from './dev/dev-events.js';
|
|
24
|
-
import { devErrorHeader, devRequestIdHeader } from './dev/dev-protocol.js';
|
|
25
|
-
import { listenDevServer } from './dev/dev-port.js';
|
|
26
|
-
import { devStatusPath } from './dev/dev-registry.js';
|
|
27
|
-
import { createDevWatcher } from './dev/dev-watcher.js';
|
|
28
|
-
import { sendDevError } from './dev/error-page.js';
|
|
29
|
-
import { createLiveReloadHub, injectLiveReloadScript, liveReloadClientPath, liveReloadClientSource, liveReloadEventsPath, liveReloadScriptTag, shouldInjectLiveReload, } from './dev/live-reload.js';
|
|
30
|
-
import { devWorkDirPrefix, startProcessReaper, sweepStaleDevDirs, } from './dev/process-reaper.js';
|
|
31
|
-
import { runPrebuild } from './dev/prebuild.js';
|
|
32
|
-
import { createStackMapper } from './dev/stack-trace.js';
|
|
33
|
-
import { cleanWorkerdStderrLine, startWorkerd, } from './dev/workerd-process.js';
|
|
34
|
-
import { BundleError, formatBundleDiagnostic } from './local-bundle.js';
|
|
35
|
-
import { localExecuteGatewayFetchShimModuleName, resolveLocalPackageGraph, writePackageModuleFiles, } from './local-package-graph.js';
|
|
36
|
-
import { createRuntimeFlatAliasSource, createWorkerdConfig, localWorkerModuleNames, } from './local-runtime-source.js';
|
|
37
|
-
import { buildLocalPackageContext } from './local-package-run.js';
|
|
38
|
-
import { installMockFetchShimModules } from './mock/install-mock-fetch-shim.js';
|
|
39
|
-
import { resolveMockFetchGateway, tryHandleMockGatewayFetchCall, } from './mock/mock-fetch-gateway.js';
|
|
40
|
-
import { createPackageAppEntrySource, createPackageLocalRuntimeModuleSource, runSecretEnvVar, runSecretHeader, } from './package-local-runtime-source.js';
|
|
41
|
-
import { resolvePackagePath } from './package-manifest.js';
|
|
42
|
-
import { redact } from './redact.js';
|
|
43
|
-
import { ensureWorkerdBinary } from './workerd-binary.js';
|
|
44
|
-
const defaultDebounceMs = 30;
|
|
45
|
-
/** Watcher events this soon after a prebuild finishes are its own writes, not edits. */
|
|
46
|
-
const prebuildSettleMs = 150;
|
|
47
|
-
/** Longest a request waits for an in-progress rebuild before the old build answers. */
|
|
48
|
-
const rebuildGateMs = 10_000;
|
|
49
|
-
/** Longest a retired generation may keep draining in-flight requests. */
|
|
50
|
-
const drainTimeoutMs = 10_000;
|
|
51
|
-
export async function startPackageAppDev(options) {
|
|
52
|
-
if (!options.manifest.app?.entry) {
|
|
53
|
-
throw new Error('This package has no kody.app.entry. Add `"kody": { "app": { "entry": "./app/router.ts" } }` or use `kody dev job|webhook|emit|check`.');
|
|
54
|
-
}
|
|
55
|
-
assertTokenSafeApiUrl(options.apiUrl);
|
|
56
|
-
const host = options.host ?? '127.0.0.1';
|
|
57
|
-
const appBasePath = normalizeBasePath(options.appBasePath ?? '');
|
|
58
|
-
const root = options.manifest.root;
|
|
59
|
-
const runSecret = randomBytes(32).toString('hex');
|
|
60
|
-
const emit = (event) => options.onEvent?.(event);
|
|
61
|
-
const liveReload = options.liveReload ?? options.watch !== false;
|
|
62
|
-
const errorPageTail = liveReload
|
|
63
|
-
? `<script>globalThis.__kodyDevErrorPage = true</script>${liveReloadScriptTag}`
|
|
64
|
-
: '';
|
|
65
|
-
void sweepStaleDevDirs().catch(() => { });
|
|
66
|
-
const workDir = await mkdtemp(join(tmpdir(), devWorkDirPrefix));
|
|
67
|
-
const reaper = await startProcessReaper({ workDir });
|
|
68
|
-
const workerdPath = options.workerdPath ??
|
|
69
|
-
(await ensureWorkerdBinary({
|
|
70
|
-
onDownload: (url) => options.onStatus?.(`Downloading workerd from ${url}…`),
|
|
71
|
-
}));
|
|
72
|
-
const client = {
|
|
73
|
-
apiUrl: options.apiUrl,
|
|
74
|
-
token: options.token,
|
|
75
|
-
fetchFn: options.fetchFn,
|
|
76
|
-
...(options.org ? { org: options.org } : {}),
|
|
77
|
-
};
|
|
78
|
-
const generations = new Set();
|
|
79
|
-
let active;
|
|
80
|
-
let buildFailure = null;
|
|
81
|
-
let generationCounter = 0;
|
|
82
|
-
let requestCounter = 0;
|
|
83
|
-
let closed = false;
|
|
84
|
-
let buildLoop = null;
|
|
85
|
-
let rebuildAgain = false;
|
|
86
|
-
const changedFiles = new Set();
|
|
87
|
-
/** True while the watcher debounce timer has paths waiting to rebuild. */
|
|
88
|
-
let debouncePending = false;
|
|
89
|
-
/** Resolves when the current debounce window flushes into `requestBuild`. */
|
|
90
|
-
let debounceFlush = null;
|
|
91
|
-
let resolveDebounceFlush = null;
|
|
92
|
-
let debounceTimer;
|
|
93
|
-
const liveReloadHub = createLiveReloadHub({
|
|
94
|
-
state: () => ({
|
|
95
|
-
buildId: active?.id ?? null,
|
|
96
|
-
error: buildFailure ? buildErrorView(buildFailure) : null,
|
|
97
|
-
}),
|
|
98
|
-
});
|
|
99
|
-
const startedAt = new Date().toISOString();
|
|
100
|
-
let lastRebuild = null;
|
|
101
|
-
let lastRuntimeError = null;
|
|
102
|
-
let buildFailureAt = startedAt;
|
|
103
|
-
let markStarted = () => { };
|
|
104
|
-
const started = new Promise((resolve) => {
|
|
105
|
-
markStarted = resolve;
|
|
106
|
-
});
|
|
107
|
-
const killAllSync = () => {
|
|
108
|
-
for (const generation of generations) {
|
|
109
|
-
try {
|
|
110
|
-
process.kill(generation.workerd.pid, 'SIGKILL');
|
|
111
|
-
}
|
|
112
|
-
catch { }
|
|
113
|
-
}
|
|
114
|
-
try {
|
|
115
|
-
rmSync(workDir, { recursive: true, force: true });
|
|
116
|
-
}
|
|
117
|
-
catch { }
|
|
118
|
-
};
|
|
119
|
-
process.once('exit', killAllSync);
|
|
120
|
-
const proxy = createServer((req, res) => {
|
|
121
|
-
void handleRequest(req, res);
|
|
122
|
-
});
|
|
123
|
-
try {
|
|
124
|
-
await listenDevServer(proxy, {
|
|
125
|
-
host,
|
|
126
|
-
port: options.port ?? options.defaultPort ?? 0,
|
|
127
|
-
explicit: options.port !== undefined,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
process.off('exit', killAllSync);
|
|
132
|
-
reaper.close();
|
|
133
|
-
await rm(workDir, { recursive: true, force: true });
|
|
134
|
-
throw error;
|
|
135
|
-
}
|
|
136
|
-
const address = proxy.address();
|
|
137
|
-
const hostedUrl = `http://${host}:${address.port}`;
|
|
138
|
-
try {
|
|
139
|
-
await options.onListening?.({
|
|
140
|
-
port: address.port,
|
|
141
|
-
hostedUrl,
|
|
142
|
-
appBasePath,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
// Port is bound but startPackageAppDev has not returned yet — close the
|
|
147
|
-
// listen handle now or the process stays alive after the throw.
|
|
148
|
-
process.off('exit', killAllSync);
|
|
149
|
-
reaper.close();
|
|
150
|
-
proxy.closeAllConnections();
|
|
151
|
-
await new Promise((resolve) => {
|
|
152
|
-
proxy.close(() => resolve());
|
|
153
|
-
});
|
|
154
|
-
await rm(workDir, { recursive: true, force: true });
|
|
155
|
-
throw error;
|
|
156
|
-
}
|
|
157
|
-
const contextFor = (client) => buildLocalPackageContext({
|
|
158
|
-
kodyId: options.manifest.kodyId,
|
|
159
|
-
packageId: `local:${options.manifest.kodyId}`,
|
|
160
|
-
hostedUrl,
|
|
161
|
-
appBasePath,
|
|
162
|
-
clientModuleUrl: client ? clientModuleUrlFor(client) : null,
|
|
163
|
-
});
|
|
164
|
-
const clientModuleUrlFor = (client) => `${hostedUrl}${appBasePath}/_assets/${client.name}`;
|
|
165
|
-
const mockFetchGateway = await resolveMockFetchGateway({
|
|
166
|
-
target: options.target,
|
|
167
|
-
packageRoot: root,
|
|
168
|
-
passthroughHosts: options.passthroughHosts,
|
|
169
|
-
allowPrivateNetwork: options.allowPrivateNetwork,
|
|
170
|
-
onStatus: options.onStatus,
|
|
171
|
-
});
|
|
172
|
-
const bridge = await startLocalRuntimeBridge({
|
|
173
|
-
runSecret,
|
|
174
|
-
forwardCall: async (call, signal) => {
|
|
175
|
-
const mocked = tryHandleMockGatewayFetchCall({
|
|
176
|
-
gateway: mockFetchGateway,
|
|
177
|
-
path: call.path,
|
|
178
|
-
args: call.args,
|
|
179
|
-
signal,
|
|
180
|
-
});
|
|
181
|
-
if (mocked)
|
|
182
|
-
return await mocked;
|
|
183
|
-
return await callCapabilityProxy({
|
|
184
|
-
...client,
|
|
185
|
-
...call,
|
|
186
|
-
signal,
|
|
187
|
-
});
|
|
188
|
-
},
|
|
189
|
-
forwardGatewayFetchStream: async ({ request, response, signal }) => {
|
|
190
|
-
await forwardLocalGatewayFetchStream({
|
|
191
|
-
request,
|
|
192
|
-
response,
|
|
193
|
-
signal,
|
|
194
|
-
client,
|
|
195
|
-
...(mockFetchGateway ? { mockFetchGateway } : {}),
|
|
196
|
-
});
|
|
197
|
-
},
|
|
198
|
-
});
|
|
199
|
-
const app = options.manifest.app;
|
|
200
|
-
const entryPath = resolvePackagePath(options.manifest, app.entry);
|
|
201
|
-
const bundler = createDevBundler({ entryPath, root });
|
|
202
|
-
const clientBundler = app.client
|
|
203
|
-
? createDevClientBundler({
|
|
204
|
-
entryPath: resolvePackagePath(options.manifest, app.client),
|
|
205
|
-
root,
|
|
206
|
-
externals: app.clientExternals,
|
|
207
|
-
})
|
|
208
|
-
: null;
|
|
209
|
-
const assetsDir = app.assets ? resolve(root, app.assets) : null;
|
|
210
|
-
const prebuild = options.manifest.dev?.prebuild;
|
|
211
|
-
let prebuildRunning = false;
|
|
212
|
-
let prebuildSettledAt = 0;
|
|
213
|
-
let prebuildAbort;
|
|
214
|
-
const workerdEnv = { ...process.env, [runSecretEnvVar]: runSecret };
|
|
215
|
-
delete workerdEnv[apiTokenEnvVar];
|
|
216
|
-
function requestBuild(paths) {
|
|
217
|
-
if (closed)
|
|
218
|
-
return Promise.resolve();
|
|
219
|
-
for (const path of paths)
|
|
220
|
-
changedFiles.add(path);
|
|
221
|
-
if (buildLoop) {
|
|
222
|
-
rebuildAgain = true;
|
|
223
|
-
return buildLoop;
|
|
224
|
-
}
|
|
225
|
-
buildLoop = (async () => {
|
|
226
|
-
do {
|
|
227
|
-
rebuildAgain = false;
|
|
228
|
-
const files = [...changedFiles];
|
|
229
|
-
changedFiles.clear();
|
|
230
|
-
await buildOnce(files);
|
|
231
|
-
} while (rebuildAgain && !closed);
|
|
232
|
-
})().finally(() => {
|
|
233
|
-
buildLoop = null;
|
|
234
|
-
});
|
|
235
|
-
return buildLoop;
|
|
236
|
-
}
|
|
237
|
-
async function buildOnce(files) {
|
|
238
|
-
const started = performance.now();
|
|
239
|
-
emit({ type: 'rebuild_start', files: files.map((file) => relative(root, file) || file) });
|
|
240
|
-
const assetsChanged = assetsDir !== null &&
|
|
241
|
-
files.some((file) => file === assetsDir || file.startsWith(`${assetsDir}${sep}`));
|
|
242
|
-
try {
|
|
243
|
-
if (prebuild) {
|
|
244
|
-
await runPrebuildStep(prebuild);
|
|
245
|
-
}
|
|
246
|
-
const [bundle, client] = await Promise.all([
|
|
247
|
-
bundler.build(),
|
|
248
|
-
clientBundler ? clientBundler.build() : Promise.resolve(null),
|
|
249
|
-
]);
|
|
250
|
-
const midBuildEdits = (await watcher?.track([...bundle.inputs, ...(client?.inputs ?? []), options.manifest.packageJsonPath], { ignoreChanges: files })) ?? [];
|
|
251
|
-
// Queue mid-build edits for the next loop iteration directly — do not
|
|
252
|
-
// call onChange (debounced); chokidar may already have the same paths
|
|
253
|
-
// pending and would double-schedule a rebuild after debounce.
|
|
254
|
-
if (midBuildEdits.length > 0) {
|
|
255
|
-
for (const path of midBuildEdits)
|
|
256
|
-
changedFiles.add(path);
|
|
257
|
-
rebuildAgain = true;
|
|
258
|
-
}
|
|
259
|
-
if (active &&
|
|
260
|
-
!buildFailure &&
|
|
261
|
-
bundle.code === active.code &&
|
|
262
|
-
client?.name === active.client?.name) {
|
|
263
|
-
// Still stamp lastRebuild so agents polling lastRebuild.at see
|
|
264
|
-
// the no-op rebuild finish (status already flipped building→ready).
|
|
265
|
-
lastRebuild = { ms: elapsed(started), at: new Date().toISOString() };
|
|
266
|
-
emit({
|
|
267
|
-
type: 'rebuild_ok',
|
|
268
|
-
ms: lastRebuild.ms,
|
|
269
|
-
buildId: active.id,
|
|
270
|
-
restarted: false,
|
|
271
|
-
});
|
|
272
|
-
if (assetsChanged || prebuild) {
|
|
273
|
-
liveReloadHub.broadcast({ event: 'reload', data: { buildId: active.id } });
|
|
274
|
-
}
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
const generation = await startGeneration(bundle, client);
|
|
278
|
-
if (closed) {
|
|
279
|
-
await stopGeneration(generation);
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
const previous = active;
|
|
283
|
-
active = generation;
|
|
284
|
-
buildFailure = null;
|
|
285
|
-
if (previous)
|
|
286
|
-
retireGeneration(previous);
|
|
287
|
-
lastRuntimeError = null;
|
|
288
|
-
lastRebuild = { ms: elapsed(started), at: new Date().toISOString() };
|
|
289
|
-
emit({ type: 'rebuild_ok', ms: lastRebuild.ms, buildId: generation.id, restarted: true });
|
|
290
|
-
liveReloadHub.broadcast({ event: 'reload', data: { buildId: generation.id } });
|
|
291
|
-
}
|
|
292
|
-
catch (error) {
|
|
293
|
-
buildFailure = toBuildFailure(error);
|
|
294
|
-
buildFailureAt = new Date().toISOString();
|
|
295
|
-
const [first] = buildFailure.diagnostics;
|
|
296
|
-
emit({
|
|
297
|
-
type: 'build_error',
|
|
298
|
-
ms: elapsed(started),
|
|
299
|
-
message: buildFailure.message,
|
|
300
|
-
file: first?.file ?? null,
|
|
301
|
-
line: first?.line ?? null,
|
|
302
|
-
col: first?.col ?? null,
|
|
303
|
-
diagnostics: buildFailure.diagnostics,
|
|
304
|
-
});
|
|
305
|
-
liveReloadHub.broadcast({ event: 'build_error', data: buildErrorView(buildFailure) });
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
let clearWatcherPending = null;
|
|
309
|
-
async function runPrebuildStep(command) {
|
|
310
|
-
prebuildRunning = true;
|
|
311
|
-
prebuildAbort = new AbortController();
|
|
312
|
-
let failed = false;
|
|
313
|
-
try {
|
|
314
|
-
await runPrebuild({
|
|
315
|
-
command,
|
|
316
|
-
cwd: root,
|
|
317
|
-
signal: prebuildAbort.signal,
|
|
318
|
-
onSpawn: (pid) => reaper.trackGroup(pid),
|
|
319
|
-
onExit: (pid) => reaper.untrackGroup(pid),
|
|
320
|
-
onLine: (line, stream) => emit({
|
|
321
|
-
type: 'log',
|
|
322
|
-
source: 'prebuild',
|
|
323
|
-
level: stream === 'stderr' ? 'warn' : 'log',
|
|
324
|
-
message: redact(line),
|
|
325
|
-
request: null,
|
|
326
|
-
}),
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
catch (error) {
|
|
330
|
-
failed = true;
|
|
331
|
-
throw error;
|
|
332
|
-
}
|
|
333
|
-
finally {
|
|
334
|
-
prebuildAbort = undefined;
|
|
335
|
-
prebuildRunning = false;
|
|
336
|
-
prebuildSettledAt = performance.now();
|
|
337
|
-
// Absorb writes even when prebuild fails — otherwise the 1s poll
|
|
338
|
-
// treats partial/failed output as new edits and loops rebuilds.
|
|
339
|
-
await watcher?.rebaseline();
|
|
340
|
-
if (failed) {
|
|
341
|
-
// Drop chokidar echoes of the failed prebuild / trigger burst so
|
|
342
|
-
// they cannot restart the loop after buildLoop clears.
|
|
343
|
-
changedFiles.clear();
|
|
344
|
-
rebuildAgain = false;
|
|
345
|
-
clearWatcherPending?.();
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
async function startGeneration(bundle, client) {
|
|
350
|
-
const id = ++generationCounter;
|
|
351
|
-
const dir = join(workDir, `g${id}`);
|
|
352
|
-
await writeWorkerFiles({
|
|
353
|
-
workDir: dir,
|
|
354
|
-
code: bundle.code,
|
|
355
|
-
packageContext: contextFor(client),
|
|
356
|
-
packageRoot: root,
|
|
357
|
-
mockStorage: options.target === 'mock',
|
|
358
|
-
bridgePort: bridge.port,
|
|
359
|
-
allowPrivateNetwork: options.allowPrivateNetwork,
|
|
360
|
-
apiUrl: options.apiUrl,
|
|
361
|
-
token: options.token,
|
|
362
|
-
org: options.org,
|
|
363
|
-
fetchFn: options.fetchFn,
|
|
364
|
-
depResolve: options.depResolve,
|
|
365
|
-
mockFetchGateway,
|
|
366
|
-
onStatus: options.onStatus,
|
|
367
|
-
});
|
|
368
|
-
let trackedPid;
|
|
369
|
-
let workerd;
|
|
370
|
-
try {
|
|
371
|
-
workerd = await startWorkerd({
|
|
372
|
-
workerdPath,
|
|
373
|
-
configPath: join(dir, 'config.capnp'),
|
|
374
|
-
cwd: dir,
|
|
375
|
-
env: workerdEnv,
|
|
376
|
-
onSpawn: (pid) => {
|
|
377
|
-
trackedPid = pid;
|
|
378
|
-
reaper.track(pid);
|
|
379
|
-
},
|
|
380
|
-
onStdoutLine: (line) => emit(parseWorkerdStdoutLine(line)),
|
|
381
|
-
onStderrLine: (line) => {
|
|
382
|
-
const cleaned = cleanWorkerdStderrLine(line);
|
|
383
|
-
if (cleaned === null)
|
|
384
|
-
return;
|
|
385
|
-
emit({
|
|
386
|
-
type: 'log',
|
|
387
|
-
source: 'workerd',
|
|
388
|
-
level: 'error',
|
|
389
|
-
message: redact(cleaned),
|
|
390
|
-
request: null,
|
|
391
|
-
});
|
|
392
|
-
},
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
catch (error) {
|
|
396
|
-
// onSpawn tracks before listen; a failed start never reaches the
|
|
397
|
-
// exited/untrack path, so drop the pid here before pid reuse.
|
|
398
|
-
if (trackedPid !== undefined)
|
|
399
|
-
reaper.untrack(trackedPid);
|
|
400
|
-
await rm(dir, { recursive: true, force: true }).catch(() => { });
|
|
401
|
-
throw error;
|
|
402
|
-
}
|
|
403
|
-
const generation = {
|
|
404
|
-
id,
|
|
405
|
-
dir,
|
|
406
|
-
workerd,
|
|
407
|
-
code: bundle.code,
|
|
408
|
-
client,
|
|
409
|
-
mapStack: createStackMapper({
|
|
410
|
-
sourceMap: bundle.sourceMap,
|
|
411
|
-
userModule: localWorkerModuleNames.user,
|
|
412
|
-
}),
|
|
413
|
-
inflight: 0,
|
|
414
|
-
retired: false,
|
|
415
|
-
stopped: false,
|
|
416
|
-
};
|
|
417
|
-
generations.add(generation);
|
|
418
|
-
void workerd.exited.then((detail) => {
|
|
419
|
-
reaper.untrack(workerd.pid);
|
|
420
|
-
if (closed || generation.retired || active !== generation)
|
|
421
|
-
return;
|
|
422
|
-
active = undefined;
|
|
423
|
-
buildFailure = {
|
|
424
|
-
message: `workerd stopped unexpectedly (${detail}). Save a file to restart it.`,
|
|
425
|
-
diagnostics: [],
|
|
426
|
-
};
|
|
427
|
-
options.onError?.(buildFailure.message);
|
|
428
|
-
});
|
|
429
|
-
return generation;
|
|
430
|
-
}
|
|
431
|
-
function retireGeneration(generation) {
|
|
432
|
-
generation.retired = true;
|
|
433
|
-
if (generation.inflight === 0) {
|
|
434
|
-
void stopGeneration(generation);
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
setTimeout(() => void stopGeneration(generation), drainTimeoutMs).unref();
|
|
438
|
-
}
|
|
439
|
-
async function stopGeneration(generation) {
|
|
440
|
-
if (generation.stopped)
|
|
441
|
-
return;
|
|
442
|
-
generation.stopped = true;
|
|
443
|
-
generation.retired = true;
|
|
444
|
-
await generation.workerd.kill();
|
|
445
|
-
reaper.untrack(generation.workerd.pid);
|
|
446
|
-
generations.delete(generation);
|
|
447
|
-
await rm(generation.dir, { recursive: true, force: true });
|
|
448
|
-
}
|
|
449
|
-
async function waitForBuild() {
|
|
450
|
-
// Flush any watcher debounce first so a save → immediate fetch cannot
|
|
451
|
-
// slip through on the previous generation while the timer is still open.
|
|
452
|
-
const flush = debounceFlush;
|
|
453
|
-
if (flush)
|
|
454
|
-
await flush;
|
|
455
|
-
const pending = buildLoop ?? (active || buildFailure ? null : started);
|
|
456
|
-
if (!pending)
|
|
457
|
-
return;
|
|
458
|
-
await Promise.race([
|
|
459
|
-
pending.catch(() => { }),
|
|
460
|
-
new Promise((resolve) => setTimeout(resolve, rebuildGateMs).unref()),
|
|
461
|
-
]);
|
|
462
|
-
}
|
|
463
|
-
function status() {
|
|
464
|
-
const [first] = buildFailure?.diagnostics ?? [];
|
|
465
|
-
return {
|
|
466
|
-
ok: buildFailure === null && active !== undefined,
|
|
467
|
-
state: buildLoop || debouncePending
|
|
468
|
-
? 'building'
|
|
469
|
-
: buildFailure
|
|
470
|
-
? 'build_error'
|
|
471
|
-
: active
|
|
472
|
-
? 'ready'
|
|
473
|
-
: 'starting',
|
|
474
|
-
buildId: active?.id ?? null,
|
|
475
|
-
url: `${hostedUrl}${appBasePath || '/'}`,
|
|
476
|
-
port: address.port,
|
|
477
|
-
basePath: appBasePath,
|
|
478
|
-
target: options.target,
|
|
479
|
-
package: {
|
|
480
|
-
name: options.manifest.name,
|
|
481
|
-
kodyId: options.manifest.kodyId,
|
|
482
|
-
root,
|
|
483
|
-
},
|
|
484
|
-
pid: process.pid,
|
|
485
|
-
startedAt,
|
|
486
|
-
lastRebuild,
|
|
487
|
-
lastError: buildFailure
|
|
488
|
-
? {
|
|
489
|
-
kind: 'build',
|
|
490
|
-
message: buildFailure.message,
|
|
491
|
-
file: first?.file ?? null,
|
|
492
|
-
line: first?.line ?? null,
|
|
493
|
-
col: first?.col ?? null,
|
|
494
|
-
at: buildFailureAt,
|
|
495
|
-
}
|
|
496
|
-
: lastRuntimeError,
|
|
497
|
-
};
|
|
498
|
-
}
|
|
499
|
-
function handleDevRoute(req, res) {
|
|
500
|
-
const pathname = stripMount(new URL(req.url ?? '/', hostedUrl).pathname, appBasePath);
|
|
501
|
-
if (pathname === devStatusPath) {
|
|
502
|
-
res.writeHead(200, {
|
|
503
|
-
'content-type': 'application/json; charset=utf-8',
|
|
504
|
-
'cache-control': 'no-store',
|
|
505
|
-
});
|
|
506
|
-
res.end(`${JSON.stringify(status(), null, 2)}\n`);
|
|
507
|
-
return true;
|
|
508
|
-
}
|
|
509
|
-
if (!liveReload)
|
|
510
|
-
return false;
|
|
511
|
-
if (pathname === liveReloadEventsPath) {
|
|
512
|
-
liveReloadHub.handleEvents(req, res);
|
|
513
|
-
return true;
|
|
514
|
-
}
|
|
515
|
-
if (pathname === liveReloadClientPath) {
|
|
516
|
-
res.writeHead(200, {
|
|
517
|
-
'content-type': 'text/javascript; charset=utf-8',
|
|
518
|
-
'cache-control': 'no-store',
|
|
519
|
-
});
|
|
520
|
-
res.end(liveReloadClientSource);
|
|
521
|
-
return true;
|
|
522
|
-
}
|
|
523
|
-
return false;
|
|
524
|
-
}
|
|
525
|
-
async function handleRequest(req, res) {
|
|
526
|
-
try {
|
|
527
|
-
if (handleDevRoute(req, res))
|
|
528
|
-
return;
|
|
529
|
-
await waitForBuild();
|
|
530
|
-
const assetPath = parseDevAssetPath(stripMount(new URL(req.url ?? '/', hostedUrl).pathname, appBasePath));
|
|
531
|
-
if (assetPath !== null) {
|
|
532
|
-
const client = active?.client ?? null;
|
|
533
|
-
await serveDevAsset({
|
|
534
|
-
req,
|
|
535
|
-
res,
|
|
536
|
-
relativePath: assetPath,
|
|
537
|
-
assetsDir,
|
|
538
|
-
client,
|
|
539
|
-
clientModuleUrl: client ? clientModuleUrlFor(client) : null,
|
|
540
|
-
appBasePath,
|
|
541
|
-
});
|
|
542
|
-
return;
|
|
543
|
-
}
|
|
544
|
-
if (buildFailure) {
|
|
545
|
-
sendDevError(req, res, 500, buildErrorView(buildFailure), {
|
|
546
|
-
htmlTail: errorPageTail,
|
|
547
|
-
});
|
|
548
|
-
return;
|
|
549
|
-
}
|
|
550
|
-
const generation = active;
|
|
551
|
-
if (!generation) {
|
|
552
|
-
res.writeHead(503, { 'content-type': 'text/plain; charset=utf-8' });
|
|
553
|
-
res.end(closed ? 'kody dev is shutting down.\n' : 'kody dev is still starting.\n');
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
generation.inflight += 1;
|
|
557
|
-
try {
|
|
558
|
-
await forwardRequest(generation, req, res);
|
|
559
|
-
}
|
|
560
|
-
finally {
|
|
561
|
-
generation.inflight -= 1;
|
|
562
|
-
if (generation.retired && generation.inflight === 0) {
|
|
563
|
-
void stopGeneration(generation);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
catch (error) {
|
|
568
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
569
|
-
options.onError?.(`Dev proxy error: ${message}`);
|
|
570
|
-
if (!res.headersSent) {
|
|
571
|
-
res.writeHead(502, { 'content-type': 'text/plain; charset=utf-8' });
|
|
572
|
-
res.end(`Dev proxy error: ${message}\n`);
|
|
573
|
-
}
|
|
574
|
-
else if (!res.writableEnded) {
|
|
575
|
-
res.destroy();
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
function forwardRequest(generation, req, res) {
|
|
580
|
-
const incomingUrl = new URL(req.url ?? '/', hostedUrl);
|
|
581
|
-
const restPath = stripMount(incomingUrl.pathname, appBasePath);
|
|
582
|
-
const forwardUrl = new URL(restPath + incomingUrl.search, `http://127.0.0.1:${generation.workerd.port}`);
|
|
583
|
-
const tag = {
|
|
584
|
-
id: String(++requestCounter),
|
|
585
|
-
method: req.method ?? 'GET',
|
|
586
|
-
path: restPath + incomingUrl.search,
|
|
587
|
-
};
|
|
588
|
-
const headers = {
|
|
589
|
-
...req.headers,
|
|
590
|
-
host: `127.0.0.1:${generation.workerd.port}`,
|
|
591
|
-
[runSecretHeader]: runSecret,
|
|
592
|
-
[devRequestIdHeader]: tag.id,
|
|
593
|
-
};
|
|
594
|
-
return new Promise((resolve, reject) => {
|
|
595
|
-
const upstream = httpRequest(forwardUrl, { method: req.method, headers }, (upstreamRes) => {
|
|
596
|
-
if (upstreamRes.headers[devErrorHeader]) {
|
|
597
|
-
void readStream(upstreamRes)
|
|
598
|
-
.then((raw) => {
|
|
599
|
-
respondWithRuntimeError(generation, req, res, tag, raw);
|
|
600
|
-
resolve();
|
|
601
|
-
})
|
|
602
|
-
.catch(reject);
|
|
603
|
-
return;
|
|
604
|
-
}
|
|
605
|
-
const status = upstreamRes.statusCode ?? 502;
|
|
606
|
-
if (status >= 500) {
|
|
607
|
-
emit({
|
|
608
|
-
type: 'log',
|
|
609
|
-
source: 'app',
|
|
610
|
-
level: 'warn',
|
|
611
|
-
message: `responded HTTP ${status}`,
|
|
612
|
-
request: tag,
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
if (liveReload &&
|
|
616
|
-
shouldInjectLiveReload({
|
|
617
|
-
method: req.method,
|
|
618
|
-
accept: req.headers.accept,
|
|
619
|
-
status,
|
|
620
|
-
headers: upstreamRes.headers,
|
|
621
|
-
})) {
|
|
622
|
-
void readStream(upstreamRes)
|
|
623
|
-
.then((html) => {
|
|
624
|
-
const body = Buffer.from(injectLiveReloadScript(html), 'utf8');
|
|
625
|
-
const headers = { ...upstreamRes.headers };
|
|
626
|
-
delete headers['transfer-encoding'];
|
|
627
|
-
headers['content-length'] = String(body.length);
|
|
628
|
-
res.writeHead(status, headers);
|
|
629
|
-
res.end(body);
|
|
630
|
-
resolve();
|
|
631
|
-
})
|
|
632
|
-
.catch(reject);
|
|
633
|
-
return;
|
|
634
|
-
}
|
|
635
|
-
res.writeHead(status, upstreamRes.headers);
|
|
636
|
-
upstreamRes.pipe(res);
|
|
637
|
-
upstreamRes.on('end', () => resolve());
|
|
638
|
-
upstreamRes.on('error', reject);
|
|
639
|
-
});
|
|
640
|
-
upstream.on('error', reject);
|
|
641
|
-
res.on('close', () => {
|
|
642
|
-
if (!res.writableFinished)
|
|
643
|
-
upstream.destroy();
|
|
644
|
-
resolve();
|
|
645
|
-
});
|
|
646
|
-
req.pipe(upstream);
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
function respondWithRuntimeError(generation, req, res, tag, raw) {
|
|
650
|
-
let message = 'Uncaught error';
|
|
651
|
-
let stack = '';
|
|
652
|
-
try {
|
|
653
|
-
const parsed = JSON.parse(raw);
|
|
654
|
-
message = `${parsed.name ?? 'Error'}: ${parsed.message ?? ''}`;
|
|
655
|
-
stack = parsed.stack ?? message;
|
|
656
|
-
}
|
|
657
|
-
catch {
|
|
658
|
-
stack = raw;
|
|
659
|
-
}
|
|
660
|
-
const mapped = redact(generation.mapStack(stack));
|
|
661
|
-
const fix = runtimeErrorFix(message);
|
|
662
|
-
lastRuntimeError = {
|
|
663
|
-
kind: 'runtime',
|
|
664
|
-
message: redact(message),
|
|
665
|
-
stack: mapped,
|
|
666
|
-
request: tag,
|
|
667
|
-
...(fix ? { fix } : {}),
|
|
668
|
-
at: new Date().toISOString(),
|
|
669
|
-
};
|
|
670
|
-
emit({
|
|
671
|
-
type: 'runtime_error',
|
|
672
|
-
message: redact(message),
|
|
673
|
-
stack: mapped,
|
|
674
|
-
request: tag,
|
|
675
|
-
...(fix ? { fix } : {}),
|
|
676
|
-
});
|
|
677
|
-
const view = {
|
|
678
|
-
kind: 'runtime',
|
|
679
|
-
title: redact(message),
|
|
680
|
-
detail: fix ? `${mapped}\n\nfix: ${fix}` : mapped,
|
|
681
|
-
request: `${tag.method} ${tag.path}`,
|
|
682
|
-
};
|
|
683
|
-
liveReloadHub.broadcast({ event: 'runtime_error', data: view });
|
|
684
|
-
sendDevError(req, res, 500, view, { htmlTail: errorPageTail });
|
|
685
|
-
}
|
|
686
|
-
const watcher = options.watch === false
|
|
687
|
-
? null
|
|
688
|
-
: (() => {
|
|
689
|
-
const pending = new Set();
|
|
690
|
-
clearWatcherPending = () => {
|
|
691
|
-
pending.clear();
|
|
692
|
-
clearTimeout(debounceTimer);
|
|
693
|
-
debouncePending = false;
|
|
694
|
-
const resolve = resolveDebounceFlush;
|
|
695
|
-
resolveDebounceFlush = null;
|
|
696
|
-
debounceFlush = null;
|
|
697
|
-
resolve?.();
|
|
698
|
-
};
|
|
699
|
-
return createDevWatcher({
|
|
700
|
-
root,
|
|
701
|
-
ignore: options.manifest.dev?.ignore,
|
|
702
|
-
onChange: (path) => {
|
|
703
|
-
if (closed)
|
|
704
|
-
return;
|
|
705
|
-
if (prebuildRunning ||
|
|
706
|
-
performance.now() - prebuildSettledAt < prebuildSettleMs) {
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
// Fold mid-build watcher events into the active loop
|
|
710
|
-
// (including another save of a file already building).
|
|
711
|
-
// Debouncing them instead schedules a second rebuild
|
|
712
|
-
// after buildLoop clears (often a no-op echo).
|
|
713
|
-
if (buildLoop) {
|
|
714
|
-
changedFiles.add(path);
|
|
715
|
-
rebuildAgain = true;
|
|
716
|
-
return;
|
|
717
|
-
}
|
|
718
|
-
pending.add(path);
|
|
719
|
-
debouncePending = true;
|
|
720
|
-
if (!debounceFlush) {
|
|
721
|
-
debounceFlush = new Promise((resolve) => {
|
|
722
|
-
resolveDebounceFlush = resolve;
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
clearTimeout(debounceTimer);
|
|
726
|
-
debounceTimer = setTimeout(() => {
|
|
727
|
-
const paths = [...pending];
|
|
728
|
-
pending.clear();
|
|
729
|
-
debouncePending = false;
|
|
730
|
-
// Start the build before releasing waiters so
|
|
731
|
-
// waitForBuild sees buildLoop, not a ready gap.
|
|
732
|
-
const build = requestBuild(paths);
|
|
733
|
-
const resolve = resolveDebounceFlush;
|
|
734
|
-
resolveDebounceFlush = null;
|
|
735
|
-
debounceFlush = null;
|
|
736
|
-
resolve?.();
|
|
737
|
-
void build;
|
|
738
|
-
}, options.debounceMs ?? defaultDebounceMs);
|
|
739
|
-
},
|
|
740
|
-
});
|
|
741
|
-
})();
|
|
742
|
-
const close = async () => {
|
|
743
|
-
if (closed)
|
|
744
|
-
return;
|
|
745
|
-
closed = true;
|
|
746
|
-
process.off('exit', killAllSync);
|
|
747
|
-
clearTimeout(debounceTimer);
|
|
748
|
-
debouncePending = false;
|
|
749
|
-
const resolve = resolveDebounceFlush;
|
|
750
|
-
resolveDebounceFlush = null;
|
|
751
|
-
debounceFlush = null;
|
|
752
|
-
resolve?.();
|
|
753
|
-
prebuildAbort?.abort();
|
|
754
|
-
await watcher?.close();
|
|
755
|
-
await buildLoop?.catch(() => { });
|
|
756
|
-
await bundler.dispose();
|
|
757
|
-
await clientBundler?.dispose();
|
|
758
|
-
await Promise.all([...generations].map((generation) => stopGeneration(generation)));
|
|
759
|
-
reaper.close();
|
|
760
|
-
await bridge.close();
|
|
761
|
-
liveReloadHub.close();
|
|
762
|
-
proxy.closeAllConnections();
|
|
763
|
-
await new Promise((resolve) => {
|
|
764
|
-
proxy.close(() => resolve());
|
|
765
|
-
});
|
|
766
|
-
await rm(workDir, { recursive: true, force: true });
|
|
767
|
-
};
|
|
768
|
-
try {
|
|
769
|
-
await Promise.all([requestBuild([]), watcher?.ready]);
|
|
770
|
-
}
|
|
771
|
-
catch (error) {
|
|
772
|
-
await close();
|
|
773
|
-
throw error;
|
|
774
|
-
}
|
|
775
|
-
finally {
|
|
776
|
-
markStarted();
|
|
777
|
-
}
|
|
778
|
-
if (options.watch === false && buildFailure) {
|
|
779
|
-
const message = buildFailure.message;
|
|
780
|
-
await close();
|
|
781
|
-
throw new Error(message);
|
|
782
|
-
}
|
|
783
|
-
if (active)
|
|
784
|
-
options.onStatus?.(`App ready at ${hostedUrl}${appBasePath || '/'}`);
|
|
785
|
-
const fetchPath = async (path, init = {}) => {
|
|
786
|
-
const url = new URL(joinUrlPath(appBasePath, path), hostedUrl);
|
|
787
|
-
const response = await fetch(url, {
|
|
788
|
-
method: init.method ?? 'GET',
|
|
789
|
-
headers: init.headers,
|
|
790
|
-
body: init.body,
|
|
791
|
-
});
|
|
792
|
-
const body = await response.text();
|
|
793
|
-
const headers = {};
|
|
794
|
-
response.headers.forEach((value, key) => {
|
|
795
|
-
headers[key] = value;
|
|
796
|
-
});
|
|
797
|
-
return { status: response.status, headers, body };
|
|
798
|
-
};
|
|
799
|
-
return {
|
|
800
|
-
url: hostedUrl,
|
|
801
|
-
port: address.port,
|
|
802
|
-
hostedUrl,
|
|
803
|
-
appBasePath,
|
|
804
|
-
get packageContext() {
|
|
805
|
-
return contextFor(active?.client ?? null);
|
|
806
|
-
},
|
|
807
|
-
fetchPath,
|
|
808
|
-
status,
|
|
809
|
-
close,
|
|
810
|
-
};
|
|
811
|
-
}
|
|
812
|
-
function elapsed(started) {
|
|
813
|
-
return Math.round(performance.now() - started);
|
|
814
|
-
}
|
|
815
|
-
function toBuildFailure(error) {
|
|
816
|
-
if (error instanceof BundleError) {
|
|
817
|
-
return { message: error.message, diagnostics: error.diagnostics };
|
|
818
|
-
}
|
|
819
|
-
return {
|
|
820
|
-
message: redact(error instanceof Error ? error.message : String(error)),
|
|
821
|
-
diagnostics: [],
|
|
822
|
-
};
|
|
823
|
-
}
|
|
824
|
-
function buildErrorView(failure) {
|
|
825
|
-
const [first] = failure.diagnostics;
|
|
826
|
-
return {
|
|
827
|
-
kind: 'build',
|
|
828
|
-
title: first
|
|
829
|
-
? `${first.file ?? 'bundle'}${first.line !== null ? `:${first.line}:${first.col}` : ''} ${first.message}`
|
|
830
|
-
: (failure.message.split('\n')[0] ?? 'Build failed'),
|
|
831
|
-
detail: failure.diagnostics.length > 0
|
|
832
|
-
? failure.diagnostics.map(formatBundleDiagnostic).join('\n\n')
|
|
833
|
-
: failure.message,
|
|
834
|
-
};
|
|
835
|
-
}
|
|
836
|
-
async function readStream(stream) {
|
|
837
|
-
const chunks = [];
|
|
838
|
-
for await (const chunk of stream) {
|
|
839
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
840
|
-
}
|
|
841
|
-
return Buffer.concat(chunks).toString('utf8');
|
|
842
|
-
}
|
|
843
|
-
async function writeWorkerFiles(input) {
|
|
844
|
-
await mkdir(input.workDir, { recursive: true });
|
|
845
|
-
const packageGraph = await resolveLocalPackageGraph({
|
|
846
|
-
code: input.code,
|
|
847
|
-
apiUrl: input.apiUrl,
|
|
848
|
-
token: input.token,
|
|
849
|
-
...(input.org ? { org: input.org } : {}),
|
|
850
|
-
fetchFn: input.fetchFn,
|
|
851
|
-
...(input.depResolve ? { depResolve: input.depResolve } : {}),
|
|
852
|
-
...(input.packageRoot ? { packageRoot: input.packageRoot } : {}),
|
|
853
|
-
onStatus: input.onStatus,
|
|
854
|
-
});
|
|
855
|
-
const files = { entry: 'entry.js', user: 'main.js', runtime: 'runtime.js' };
|
|
856
|
-
let packageModules = await writePackageModuleFiles(input.workDir, packageGraph, writeFile, join);
|
|
857
|
-
let gatewayFetchShimModules = packageGraph.modules
|
|
858
|
-
.map((module) => module.name)
|
|
859
|
-
.filter((name) => name === localExecuteGatewayFetchShimModuleName);
|
|
860
|
-
if (input.mockFetchGateway) {
|
|
861
|
-
const installed = await installMockFetchShimModules({
|
|
862
|
-
workDir: input.workDir,
|
|
863
|
-
packageModules,
|
|
864
|
-
});
|
|
865
|
-
packageModules = installed.packageModules;
|
|
866
|
-
gatewayFetchShimModules = installed.sideEffectModules;
|
|
867
|
-
}
|
|
868
|
-
await writeFile(join(input.workDir, files.entry), createPackageAppEntrySource({ sideEffectModules: gatewayFetchShimModules }));
|
|
869
|
-
await writeFile(join(input.workDir, files.user), input.code);
|
|
870
|
-
await writeFile(join(input.workDir, files.runtime), createPackageLocalRuntimeModuleSource({
|
|
871
|
-
packageContext: input.packageContext,
|
|
872
|
-
mockStorage: input.mockStorage,
|
|
873
|
-
}));
|
|
874
|
-
await writeFile(join(input.workDir, localWorkerModuleNames.runtimeFlatAlias), createRuntimeFlatAliasSource());
|
|
875
|
-
await writeFile(join(input.workDir, 'config.capnp'), createWorkerdConfig({
|
|
876
|
-
bridgePort: input.bridgePort,
|
|
877
|
-
files,
|
|
878
|
-
packageModules,
|
|
879
|
-
allowPrivateNetwork: input.allowPrivateNetwork,
|
|
880
|
-
}));
|
|
881
|
-
}
|
|
882
|
-
function normalizeBasePath(value) {
|
|
883
|
-
const trimmed = value.trim();
|
|
884
|
-
if (!trimmed || trimmed === '/')
|
|
885
|
-
return '';
|
|
886
|
-
const withSlash = trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
887
|
-
return withSlash.replace(/\/+$/, '');
|
|
888
|
-
}
|
|
889
|
-
function stripMount(pathname, appBasePath) {
|
|
890
|
-
if (!appBasePath)
|
|
891
|
-
return pathname || '/';
|
|
892
|
-
if (pathname === appBasePath)
|
|
893
|
-
return '/';
|
|
894
|
-
if (pathname.startsWith(`${appBasePath}/`)) {
|
|
895
|
-
return pathname.slice(appBasePath.length) || '/';
|
|
896
|
-
}
|
|
897
|
-
return pathname || '/';
|
|
898
|
-
}
|
|
899
|
-
function joinUrlPath(base, path) {
|
|
900
|
-
const rest = path.startsWith('/') ? path : `/${path}`;
|
|
901
|
-
if (!base)
|
|
902
|
-
return rest;
|
|
903
|
-
return `${base}${rest === '/' ? '' : rest}` || base;
|
|
904
|
-
}
|
|
905
|
-
//# sourceMappingURL=package-app-dev.js.map
|