experimental-ash 0.24.1 → 0.24.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/CHANGELOG.md +7 -0
- package/dist/src/chunks/authored-module-loader-DcCfCiBm.js +4 -0
- package/dist/src/chunks/client-DLHAGI2g.js +4 -0
- package/dist/src/chunks/dev-authored-source-watcher-CBID_Dwh.js +1 -0
- package/dist/src/chunks/{errors-DsO9xmQL.js → errors-HYWjHxV6.js} +1 -1
- package/dist/src/chunks/{gray-matter-BxS7ZG-J.js → gray-matter-D-9jHwOT.js} +4 -4
- package/dist/src/chunks/host-zBy9FyyX.js +70 -0
- package/dist/src/chunks/{jsdist-M7JFZoA4.js → jsdist-BkeWZ7EZ.js} +61 -61
- package/dist/src/chunks/package-HUaeub_D.js +1 -0
- package/dist/src/chunks/{paths-jcVjBqc3.js → paths-CebY5GCi.js} +2 -2
- package/dist/src/chunks/{picocolors-Bq-tZK9u.js → picocolors-aAkqW4On.js} +1 -1
- package/dist/src/chunks/token-D98SQdvs.js +1 -0
- package/dist/src/chunks/{url-BVRhVE2O.js → url-JdCGA634.js} +1 -1
- package/dist/src/cli/commands/info.js +1 -1
- package/dist/src/cli/dev/environment.d.ts +16 -2
- package/dist/src/cli/dev/environment.js +1 -1
- package/dist/src/cli/dev/input-requests.js +1 -1
- package/dist/src/cli/dev/repl.js +3 -3
- package/dist/src/cli/dev/url.js +1 -1
- package/dist/src/cli/run.js +1 -1
- package/dist/src/cli/ui/output.js +1 -1
- package/dist/src/client/index.d.ts +1 -0
- package/dist/src/client/index.js +1 -0
- package/dist/src/compiled/.vendor-stamp.json +7 -6
- package/dist/src/compiled/@ai-sdk/anthropic/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/google/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/openai/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/otel/index.js +1 -1
- package/dist/src/compiled/@chat-adapter/slack/_slack-web-api.d.ts +7 -0
- package/dist/src/compiled/@chat-adapter/slack/index.d.ts +418 -109
- package/dist/src/compiled/@chat-adapter/slack/index.js +31 -27
- package/dist/src/compiled/@chat-adapter/slack/package.json +1 -1
- package/dist/src/compiled/@chat-adapter/state-memory/index.d.ts +8 -2
- package/dist/src/compiled/@chat-adapter/state-memory/index.js +1 -1
- package/dist/src/compiled/@chat-adapter/state-memory/package.json +1 -1
- package/dist/src/compiled/@opentelemetry/api/index.js +1 -1
- package/dist/src/compiled/@vercel/sandbox/index.js +19 -17
- package/dist/src/compiled/@vercel/sandbox/package.json +1 -1
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/runtime.js +22 -22
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/errors/index.js +1 -1
- package/dist/src/compiled/_chunks/node/auth-ZhCJAHxl.js +2 -0
- package/dist/src/compiled/_chunks/node/{dist-BdWHjlRQ.js → dist-BQYUcBqu.js} +31 -31
- package/dist/src/compiled/_chunks/node/{chunk-Dd2tEFlW.js → dist-BdTs18CF.js} +1 -1
- package/dist/src/compiled/_chunks/node/retry-DkR2H1Y0.js +1 -0
- package/dist/src/compiled/_chunks/node/token-CoIbMZkq.js +1 -0
- package/dist/src/compiled/_chunks/node/{version-BMyZn3Y2.js → version-D4IYmfaS.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/coerce-BhzIW-Hm.js +1 -0
- package/dist/src/compiled/_chunks/workflow/{compat-CIROS3w4.js → compat-DcEvieoj.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/{core-DOVmxHH8.js → core-XWIi7wKc.js} +3 -3
- package/dist/src/compiled/_chunks/workflow/{dist-C7wPwOI9.js → dist-DO14ZaQj.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/{dist-CpUQh3NH.js → dist-DZZY3Zyp.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/resume-hook-DOMbNs-S.js +51 -0
- package/dist/src/compiled/_chunks/workflow/{schemas-DFZoEyCn.js → schemas-DmgDnhW3.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/sleep-CRjce49s.js +1 -0
- package/dist/src/compiled/_chunks/workflow/{src-ClRYdO4-.js → src-B54rYDvB.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/symbols-D8paKc8P.js +9 -0
- package/dist/src/compiled/_chunks/workflow/{token-CsNmv7KW.js → token-D9z1dMB6.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/{token-j5Cl4rrs.js → token-DV7rQw_t.js} +1 -1
- package/dist/src/compiled/chat/index.d.ts +6 -3143
- package/dist/src/compiled/chat/index.js +1 -1
- package/dist/src/compiled/chat/{jsx-runtime-DxGwoLu2.d.ts → jsx-runtime-CFq1K_Ve.d.ts} +1 -1
- package/dist/src/compiled/chat/package.json +1 -1
- package/dist/src/compiled/jose/index.js +2 -2
- package/dist/src/compiled/jsonc-parser/LICENSE.md +21 -0
- package/dist/src/compiled/jsonc-parser/index.d.ts +13 -0
- package/dist/src/compiled/jsonc-parser/index.js +15 -0
- package/dist/src/compiled/jsonc-parser/package.json +7 -0
- package/dist/src/compiled/just-bash/index.js +773 -773
- package/dist/src/compiled/just-bash/package.json +1 -1
- package/dist/src/compiled/turndown/index.js +1 -1
- package/dist/src/compiled/zod/index.js +1 -1
- package/dist/src/compiled/zod-validation-error/index.js +1 -1
- package/dist/src/evals/cli/eval.js +1 -1
- package/dist/src/evals/loaders/yaml.js +1 -1
- package/dist/src/evals/runner/discover.js +1 -1
- package/dist/src/evals/runner/execute-suite.js +1 -1
- package/dist/src/evals/runner/reporters/console.js +1 -1
- package/dist/src/evals/scorers/autoevals-client.js +1 -1
- package/dist/src/evals/scorers/autoevals.js +1 -1
- package/dist/src/evals/scorers/json.js +1 -1
- package/dist/src/evals/scorers/run.js +1 -1
- package/dist/src/evals/scorers/sql.js +1 -1
- package/dist/src/evals/scorers/text.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-asset-import-plugin.d.ts +5 -0
- package/dist/src/internal/authored-asset-import-plugin.js +141 -0
- package/dist/src/internal/authored-module-bundle.d.ts +4 -0
- package/dist/src/internal/authored-module-bundle.js +19 -0
- package/dist/src/internal/authored-module-loader.d.ts +6 -0
- package/dist/src/internal/authored-module-loader.js +114 -125
- package/dist/src/internal/authored-package-tsconfig-paths.d.ts +9 -0
- package/dist/src/internal/authored-package-tsconfig-paths.js +209 -0
- package/dist/src/internal/nitro/host/channel-routes.d.ts +9 -2
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.d.ts +12 -1
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +19 -3
- package/dist/src/internal/nitro/host/schedule-task-routes.d.ts +7 -3
- package/dist/src/internal/nitro/host/start-development-server.js +2 -0
- package/package.json +17 -17
- package/dist/src/chunks/authored-module-loader-XcFLnl49.js +0 -2
- package/dist/src/chunks/client-nshDsWNF.js +0 -4
- package/dist/src/chunks/dev-authored-source-watcher-CApkYfee.js +0 -7
- package/dist/src/chunks/host-3sfHdmXL.js +0 -65
- package/dist/src/chunks/package-DmsQgn4v.js +0 -1
- package/dist/src/chunks/prewarm-DslujbK5.js +0 -6
- package/dist/src/chunks/token-DtoyQZy2.js +0 -1
- package/dist/src/chunks/token-util-CHjOk3A7.js +0 -1
- package/dist/src/compiled/_chunks/node/auth-vbe4XEEK.js +0 -2
- package/dist/src/compiled/_chunks/node/dist-DMSq2ehP.js +0 -1
- package/dist/src/compiled/_chunks/node/retry-BOcy5BbJ.js +0 -1
- package/dist/src/compiled/_chunks/node/token-D-BTJHoU.js +0 -1
- package/dist/src/compiled/_chunks/workflow/coerce-Dh0wa7P9.js +0 -1
- package/dist/src/compiled/_chunks/workflow/context-errors-Bbvvp-li.js +0 -6
- package/dist/src/compiled/_chunks/workflow/dist-C_oiE-l7.js +0 -40
- package/dist/src/compiled/_chunks/workflow/resume-hook-C3VWUPii.js +0 -12
- package/dist/src/compiled/_chunks/workflow/sleep-QTkC1VFe.js +0 -1
- package/dist/src/compiled/_chunks/workflow/symbols-QezhMuLg.js +0 -4
- package/dist/src/compiled/chat/_workflow-serde.d.ts +0 -5
- /package/dist/src/chunks/{chunk-8L7ocgPr.js → chunk-DSjMdhoD.js} +0 -0
- /package/dist/src/chunks/{guards-CjJ3lmju.js → guards-26p6sOw3.js} +0 -0
- /package/dist/src/chunks/{input-requests-BsBi7_5K.js → input-requests-DJiy6dG9.js} +0 -0
- /package/dist/src/chunks/{runtime-model-BWu6M_hq.js → runtime-model-Dh0Nz64z.js} +0 -0
- /package/dist/src/chunks/{types-MZUhN0Zy.js → types-DDA2QUED.js} +0 -0
- /package/dist/src/compiled/_chunks/workflow/{chunk-DHhdAPOb.js → chunk-DSjMdhoD.js} +0 -0
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync, mkdirSync,
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve, sep } from "node:path";
|
|
4
|
+
import { createAuthoredAssetImportPlugin } from "#internal/authored-asset-import-plugin.js";
|
|
5
|
+
import { createAuthoredModuleBundleError } from "#internal/authored-module-bundle.js";
|
|
6
|
+
import { createAuthoredPackageTsConfigPathsPlugin } from "#internal/authored-package-tsconfig-paths.js";
|
|
4
7
|
import { expectObjectRecord } from "#internal/authored-module.js";
|
|
5
8
|
import { buildWithNitroRolldown, getSingleRolldownChunk, } from "#internal/bundler/nitro-rolldown.js";
|
|
6
9
|
import { createNodeEsmCompatBannerPlugin } from "#internal/node-esm-compat-banner.js";
|
|
@@ -17,22 +20,42 @@ const RESOLVE_EXTENSIONS = [
|
|
|
17
20
|
".cjs",
|
|
18
21
|
".json",
|
|
19
22
|
];
|
|
23
|
+
const CHANNEL_MODULE_CACHE_KEY = "__ashChannelModuleCache__";
|
|
24
|
+
const CACHED_CHANNEL_PREFIX = "ash-cached-channel:";
|
|
25
|
+
/**
|
|
26
|
+
* Registers a loaded channel module in the global cache so Rolldown-
|
|
27
|
+
* bundled schedule modules that import the same channel get the exact
|
|
28
|
+
* same route object instance.
|
|
29
|
+
*/
|
|
30
|
+
export function registerChannelModuleInCache(absolutePath, moduleDefault) {
|
|
31
|
+
const cache = (globalThis[CHANNEL_MODULE_CACHE_KEY] ??= new Map());
|
|
32
|
+
cache.set(resolve(absolutePath), moduleDefault);
|
|
33
|
+
}
|
|
34
|
+
function getChannelModuleCache() {
|
|
35
|
+
return globalThis[CHANNEL_MODULE_CACHE_KEY];
|
|
36
|
+
}
|
|
20
37
|
/**
|
|
21
38
|
* In-flight load deduplication map keyed by the absolute module path.
|
|
22
39
|
*
|
|
23
|
-
* The compiler walks every authored slot concurrently
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
40
|
+
* The compiler walks every authored slot concurrently
|
|
41
|
+
* (`compileChannelDefinition` and `buildChannelRouteIdentityMap` both
|
|
42
|
+
* load the same channel module via `Promise.all`), so the same module
|
|
43
|
+
* path is frequently loaded twice in parallel. Without dedup, both
|
|
44
|
+
* callers race the bundler write/import pipeline against the
|
|
45
|
+
* same `node_modules/.cache/.../<hash>.mjs` file: one call's
|
|
46
|
+
* `writeFile` can truncate the bundle while another's `import()` is
|
|
47
|
+
* still resolving it, surfacing as intermittent
|
|
29
48
|
* "Expected … to match the public Ash shape" failures during
|
|
30
49
|
* compilation.
|
|
31
50
|
*
|
|
32
51
|
* The map only holds in-flight promises; once a load settles the entry
|
|
33
|
-
* is cleared so subsequent compiles
|
|
34
|
-
* the
|
|
35
|
-
* URL for
|
|
52
|
+
* is cleared so subsequent compiles (e.g. a dev-server reload after
|
|
53
|
+
* the author edits a file) re-run the bundle pipeline against the
|
|
54
|
+
* fresh source. Node's ESM cache then dedupes by content-hashed URL for
|
|
55
|
+
* unchanged files. The companion "skip write when the cache file already
|
|
56
|
+
* exists" check inside {@link loadBundledAuthoredModule} eliminates the
|
|
57
|
+
* write/read race even when two non-concurrent compile passes overlap on
|
|
58
|
+
* the same hashed bundle path.
|
|
36
59
|
*/
|
|
37
60
|
const inFlightModuleLoads = new Map();
|
|
38
61
|
/**
|
|
@@ -74,33 +97,77 @@ function createFileImportSpecifier(modulePath) {
|
|
|
74
97
|
return normalizedPath;
|
|
75
98
|
}
|
|
76
99
|
async function loadBundledAuthoredModule(modulePath) {
|
|
100
|
+
const channelCache = getChannelModuleCache();
|
|
77
101
|
const packageRoot = resolveAuthoredPackageRoot(modulePath);
|
|
78
|
-
const tsconfigPath =
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
102
|
+
const tsconfigPath = resolveAuthoredTsConfigPath(packageRoot);
|
|
103
|
+
const channelIdentityPlugin = channelCache && channelCache.size > 0
|
|
104
|
+
? {
|
|
105
|
+
name: "ash-channel-identity",
|
|
106
|
+
async resolveId(source, importer, options) {
|
|
107
|
+
if (!/channels[/\\]/.test(source) || options.kind !== "import-statement") {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
const resolved = await this.resolve(source, importer, {
|
|
111
|
+
kind: options.kind,
|
|
112
|
+
skipSelf: true,
|
|
113
|
+
});
|
|
114
|
+
if (resolved === null || typeof resolved.id !== "string") {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
const resolvedPath = resolve(resolved.id);
|
|
118
|
+
if (!channelCache.has(resolvedPath)) {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
return { id: `${CACHED_CHANNEL_PREFIX}${resolvedPath}` };
|
|
122
|
+
},
|
|
123
|
+
load(id) {
|
|
124
|
+
if (!id.startsWith(CACHED_CHANNEL_PREFIX)) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
const cachedPath = id.slice(CACHED_CHANNEL_PREFIX.length);
|
|
128
|
+
return {
|
|
129
|
+
code: [
|
|
130
|
+
`const cache = globalThis["${CHANNEL_MODULE_CACHE_KEY}"];`,
|
|
131
|
+
`export default cache.get(${JSON.stringify(cachedPath)});`,
|
|
132
|
+
].join("\n"),
|
|
133
|
+
moduleType: "js",
|
|
134
|
+
};
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
: null;
|
|
82
138
|
const plugins = [
|
|
139
|
+
createAuthoredAssetImportPlugin(),
|
|
140
|
+
createAuthoredPackageTsConfigPathsPlugin({
|
|
141
|
+
appPackageRoot: packageRoot,
|
|
142
|
+
extensions: RESOLVE_EXTENSIONS,
|
|
143
|
+
}),
|
|
83
144
|
createNodeEsmCompatBannerPlugin({ includeRequire: true }),
|
|
84
145
|
createPackageBoundaryPlugin(packageRoot),
|
|
85
|
-
|
|
146
|
+
channelIdentityPlugin,
|
|
86
147
|
].filter((plugin) => plugin !== null);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
148
|
+
let outputFile;
|
|
149
|
+
try {
|
|
150
|
+
const result = await buildWithNitroRolldown({
|
|
151
|
+
cwd: packageRoot,
|
|
152
|
+
input: modulePath,
|
|
153
|
+
platform: "node",
|
|
154
|
+
plugins,
|
|
155
|
+
resolve: {
|
|
156
|
+
extensions: [...RESOLVE_EXTENSIONS],
|
|
157
|
+
},
|
|
158
|
+
tsconfig: tsconfigPath,
|
|
159
|
+
write: false,
|
|
160
|
+
output: {
|
|
161
|
+
comments: false,
|
|
162
|
+
format: "esm",
|
|
163
|
+
sourcemap: "inline",
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
outputFile = getSingleRolldownChunk(result, `authored module for "${modulePath}"`);
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
throw createAuthoredModuleBundleError(modulePath, error);
|
|
170
|
+
}
|
|
104
171
|
const bundleHash = createHash("sha1")
|
|
105
172
|
.update(modulePath)
|
|
106
173
|
.update("\0")
|
|
@@ -108,12 +175,6 @@ async function loadBundledAuthoredModule(modulePath) {
|
|
|
108
175
|
.digest("hex");
|
|
109
176
|
const bundleDirectoryPath = join(packageRoot, AUTHORED_MODULE_BUNDLE_DIRECTORY_PATH);
|
|
110
177
|
const bundlePath = join(bundleDirectoryPath, `${bundleHash}.mjs`);
|
|
111
|
-
// The bundle filename is the content hash, so if the file already
|
|
112
|
-
// exists it must already hold the correct bytes. Skipping the write
|
|
113
|
-
// avoids re-truncating the file underneath any in-flight `import()`
|
|
114
|
-
// that's still reading the previous compile's bytes. Sync I/O keeps
|
|
115
|
-
// the writer atomic from JS's perspective: nothing else on this
|
|
116
|
-
// event loop can touch the file between mkdir and writeFile.
|
|
117
178
|
if (!existsSync(bundlePath)) {
|
|
118
179
|
mkdirSync(bundleDirectoryPath, { recursive: true });
|
|
119
180
|
writeFileSync(bundlePath, outputFile.code);
|
|
@@ -133,7 +194,11 @@ function createPackageBoundaryPlugin(packageRoot) {
|
|
|
133
194
|
id: source,
|
|
134
195
|
};
|
|
135
196
|
}
|
|
136
|
-
const importerPath = importer === undefined ||
|
|
197
|
+
const importerPath = importer === undefined ||
|
|
198
|
+
importer.startsWith("\0") ||
|
|
199
|
+
importer.startsWith(CACHED_CHANNEL_PREFIX)
|
|
200
|
+
? undefined
|
|
201
|
+
: resolve(importer);
|
|
137
202
|
// Keep package imports authored directly by the app external by
|
|
138
203
|
// default, but let symlinked/file workspace packages compile as
|
|
139
204
|
// source. Those packages often export `.ts` files and rely on the
|
|
@@ -160,91 +225,6 @@ function createPackageBoundaryPlugin(packageRoot) {
|
|
|
160
225
|
},
|
|
161
226
|
};
|
|
162
227
|
}
|
|
163
|
-
function createTsconfigPathAliasPlugin(input) {
|
|
164
|
-
const aliases = readTsconfigPathAliases(input);
|
|
165
|
-
if (aliases.length === 0) {
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
168
|
-
return {
|
|
169
|
-
name: "ash-tsconfig-path-alias",
|
|
170
|
-
resolveId(source) {
|
|
171
|
-
for (const alias of aliases) {
|
|
172
|
-
const matched = matchTsconfigPathAlias(alias.pattern, source);
|
|
173
|
-
if (matched === null) {
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
for (const target of alias.targets) {
|
|
177
|
-
const candidate = resolveTsconfigPathAliasTarget(target, matched);
|
|
178
|
-
if (candidate !== null) {
|
|
179
|
-
return candidate;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return undefined;
|
|
184
|
-
},
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
function readTsconfigPathAliases(input) {
|
|
188
|
-
if (!existsSync(input.tsconfigPath)) {
|
|
189
|
-
return [];
|
|
190
|
-
}
|
|
191
|
-
try {
|
|
192
|
-
const tsconfig = JSON.parse(readFileSync(input.tsconfigPath, "utf8"));
|
|
193
|
-
const paths = tsconfig.compilerOptions?.paths;
|
|
194
|
-
if (paths === null || typeof paths !== "object" || Array.isArray(paths)) {
|
|
195
|
-
return [];
|
|
196
|
-
}
|
|
197
|
-
const baseUrl = typeof tsconfig.compilerOptions?.baseUrl === "string"
|
|
198
|
-
? tsconfig.compilerOptions.baseUrl
|
|
199
|
-
: ".";
|
|
200
|
-
const baseDirectory = resolve(dirname(input.tsconfigPath), baseUrl);
|
|
201
|
-
return Object.entries(paths).flatMap(([pattern, rawTargets]) => {
|
|
202
|
-
if (!Array.isArray(rawTargets)) {
|
|
203
|
-
return [];
|
|
204
|
-
}
|
|
205
|
-
const targets = rawTargets.flatMap((rawTarget) => typeof rawTarget === "string" ? [resolve(baseDirectory, rawTarget)] : []);
|
|
206
|
-
return targets.length === 0 ? [] : [{ pattern, targets }];
|
|
207
|
-
});
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
return [];
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
function matchTsconfigPathAlias(pattern, source) {
|
|
214
|
-
const wildcardIndex = pattern.indexOf("*");
|
|
215
|
-
if (wildcardIndex === -1) {
|
|
216
|
-
return pattern === source ? "" : null;
|
|
217
|
-
}
|
|
218
|
-
const prefix = pattern.slice(0, wildcardIndex);
|
|
219
|
-
const suffix = pattern.slice(wildcardIndex + 1);
|
|
220
|
-
if (!source.startsWith(prefix) || !source.endsWith(suffix)) {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
return source.slice(prefix.length, source.length - suffix.length);
|
|
224
|
-
}
|
|
225
|
-
function resolveTsconfigPathAliasTarget(targetPattern, matched) {
|
|
226
|
-
const targetPath = targetPattern.replace("*", matched);
|
|
227
|
-
const directMatch = resolveExistingPath(targetPath);
|
|
228
|
-
if (directMatch !== null) {
|
|
229
|
-
return directMatch;
|
|
230
|
-
}
|
|
231
|
-
for (const extension of RESOLVE_EXTENSIONS) {
|
|
232
|
-
const extensionMatch = resolveExistingPath(`${targetPath}${extension}`);
|
|
233
|
-
if (extensionMatch !== null) {
|
|
234
|
-
return extensionMatch;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
for (const extension of RESOLVE_EXTENSIONS) {
|
|
238
|
-
const indexMatch = resolveExistingPath(join(targetPath, `index${extension}`));
|
|
239
|
-
if (indexMatch !== null) {
|
|
240
|
-
return indexMatch;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
return null;
|
|
244
|
-
}
|
|
245
|
-
function resolveExistingPath(path) {
|
|
246
|
-
return existsSync(path) ? path : null;
|
|
247
|
-
}
|
|
248
228
|
function isPackageImport(source) {
|
|
249
229
|
if (source.startsWith(".") || source.startsWith("/") || /^[A-Za-z]:[\\/]/.test(source)) {
|
|
250
230
|
return false;
|
|
@@ -255,7 +235,7 @@ function isPackageImport(source) {
|
|
|
255
235
|
if (source.startsWith("@/")) {
|
|
256
236
|
return false;
|
|
257
237
|
}
|
|
258
|
-
return
|
|
238
|
+
return !source.startsWith(CACHED_CHANNEL_PREFIX);
|
|
259
239
|
}
|
|
260
240
|
function isAshFrameworkImport(source) {
|
|
261
241
|
return source === "experimental-ash" || source.startsWith("experimental-ash/");
|
|
@@ -268,6 +248,15 @@ function isPathInsideOrEqual(path, directory) {
|
|
|
268
248
|
const resolvedDirectory = resolve(directory);
|
|
269
249
|
return (resolvedPath === resolvedDirectory || resolvedPath.startsWith(`${resolvedDirectory}${sep}`));
|
|
270
250
|
}
|
|
251
|
+
function resolveAuthoredTsConfigPath(packageRoot) {
|
|
252
|
+
for (const fileName of ["tsconfig.json", "jsconfig.json"]) {
|
|
253
|
+
const path = join(packageRoot, fileName);
|
|
254
|
+
if (existsSync(path)) {
|
|
255
|
+
return path;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
271
260
|
function resolveAuthoredPackageRoot(modulePath) {
|
|
272
261
|
let currentDirectory = dirname(modulePath);
|
|
273
262
|
while (true) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves tsconfig `paths` for authored source imported from linked
|
|
3
|
+
* workspace packages. Rolldown handles the root app tsconfig; this only
|
|
4
|
+
* fills the package-local config gap for sources outside the app root.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createAuthoredPackageTsConfigPathsPlugin(input: {
|
|
7
|
+
appPackageRoot: string;
|
|
8
|
+
extensions: readonly string[];
|
|
9
|
+
}): Record<string, unknown>;
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, resolve, sep } from "node:path";
|
|
3
|
+
import { parse as parseJsonc } from "#compiled/jsonc-parser/index.js";
|
|
4
|
+
const packageTsConfigPathsCache = new Map();
|
|
5
|
+
const nearestPackageRootCache = new Map();
|
|
6
|
+
/**
|
|
7
|
+
* Resolves tsconfig `paths` for authored source imported from linked
|
|
8
|
+
* workspace packages. Rolldown handles the root app tsconfig; this only
|
|
9
|
+
* fills the package-local config gap for sources outside the app root.
|
|
10
|
+
*/
|
|
11
|
+
export function createAuthoredPackageTsConfigPathsPlugin(input) {
|
|
12
|
+
return {
|
|
13
|
+
name: "ash-package-tsconfig-paths",
|
|
14
|
+
async resolveId(source, importer, options) {
|
|
15
|
+
if (importer === undefined || !isPackageImport(source)) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const importerPath = resolve(importer);
|
|
19
|
+
if (isPathInsideOrEqual(importerPath, input.appPackageRoot)) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const packageRoot = await resolveNearestPackageRoot(importerPath);
|
|
23
|
+
if (packageRoot === undefined || isPathInsideOrEqual(packageRoot, input.appPackageRoot)) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const config = await loadPackageTsConfigPaths(packageRoot);
|
|
27
|
+
if (config === undefined) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
for (const candidate of createTsConfigPathCandidates(source, config)) {
|
|
31
|
+
const resolved = await this.resolve(candidate, importer, {
|
|
32
|
+
kind: options.kind,
|
|
33
|
+
skipSelf: true,
|
|
34
|
+
});
|
|
35
|
+
if (resolved !== null) {
|
|
36
|
+
return resolved;
|
|
37
|
+
}
|
|
38
|
+
const existingPath = await resolveExistingPath(candidate, input.extensions);
|
|
39
|
+
if (existingPath !== undefined) {
|
|
40
|
+
return { id: existingPath };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function loadPackageTsConfigPaths(packageRoot) {
|
|
48
|
+
const cached = packageTsConfigPathsCache.get(packageRoot);
|
|
49
|
+
if (cached !== undefined) {
|
|
50
|
+
return cached;
|
|
51
|
+
}
|
|
52
|
+
const promise = readPackageTsConfigPaths(packageRoot);
|
|
53
|
+
packageTsConfigPathsCache.set(packageRoot, promise);
|
|
54
|
+
return promise;
|
|
55
|
+
}
|
|
56
|
+
async function readPackageTsConfigPaths(packageRoot) {
|
|
57
|
+
const configFile = await readPackageConfig(packageRoot);
|
|
58
|
+
if (configFile === undefined) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const errors = [];
|
|
62
|
+
const parsed = parseJsonc(configFile.source, errors, {
|
|
63
|
+
allowTrailingComma: true,
|
|
64
|
+
});
|
|
65
|
+
if (errors.length > 0 || !isObjectRecord(parsed)) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
const compilerOptions = parsed.compilerOptions;
|
|
69
|
+
if (!isObjectRecord(compilerOptions) || !isObjectRecord(compilerOptions.paths)) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
const configDirectory = dirname(configFile.path);
|
|
73
|
+
const baseDirectory = typeof compilerOptions.baseUrl === "string"
|
|
74
|
+
? resolve(configDirectory, compilerOptions.baseUrl)
|
|
75
|
+
: configDirectory;
|
|
76
|
+
const entries = Object.entries(compilerOptions.paths)
|
|
77
|
+
.flatMap(([pattern, targets]) => {
|
|
78
|
+
if (!Array.isArray(targets) || !targets.every((target) => typeof target === "string")) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
return [{ pattern, targets }];
|
|
82
|
+
})
|
|
83
|
+
.sort((left, right) => right.pattern.length - left.pattern.length);
|
|
84
|
+
if (entries.length === 0) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
return { baseDirectory, entries };
|
|
88
|
+
}
|
|
89
|
+
async function readPackageConfig(packageRoot) {
|
|
90
|
+
for (const fileName of ["tsconfig.json", "jsconfig.json"]) {
|
|
91
|
+
const configPath = join(packageRoot, fileName);
|
|
92
|
+
try {
|
|
93
|
+
return {
|
|
94
|
+
path: configPath,
|
|
95
|
+
source: await readFile(configPath, "utf8"),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (!isPathNotFoundError(error)) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
function createTsConfigPathCandidates(source, config) {
|
|
107
|
+
const candidates = [];
|
|
108
|
+
for (const entry of config.entries) {
|
|
109
|
+
const match = matchTsConfigPathPattern(source, entry.pattern);
|
|
110
|
+
if (match === undefined) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
for (const target of entry.targets) {
|
|
114
|
+
const targetPath = target.includes("*") ? target.replaceAll("*", match) : target;
|
|
115
|
+
candidates.push(resolve(config.baseDirectory, targetPath));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return candidates;
|
|
119
|
+
}
|
|
120
|
+
function matchTsConfigPathPattern(source, pattern) {
|
|
121
|
+
const wildcardIndex = pattern.indexOf("*");
|
|
122
|
+
if (wildcardIndex === -1) {
|
|
123
|
+
return source === pattern ? "" : undefined;
|
|
124
|
+
}
|
|
125
|
+
const prefix = pattern.slice(0, wildcardIndex);
|
|
126
|
+
const suffix = pattern.slice(wildcardIndex + 1);
|
|
127
|
+
if (!source.startsWith(prefix) || !source.endsWith(suffix)) {
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
return source.slice(prefix.length, source.length - suffix.length);
|
|
131
|
+
}
|
|
132
|
+
async function resolveExistingPath(path, extensions) {
|
|
133
|
+
if (await existsAsFile(path)) {
|
|
134
|
+
return path;
|
|
135
|
+
}
|
|
136
|
+
for (const extension of extensions) {
|
|
137
|
+
const candidate = `${path}${extension}`;
|
|
138
|
+
if (await existsAsFile(candidate)) {
|
|
139
|
+
return candidate;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
for (const extension of extensions) {
|
|
143
|
+
const candidate = join(path, `index${extension}`);
|
|
144
|
+
if (await existsAsFile(candidate)) {
|
|
145
|
+
return candidate;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
async function existsAsFile(path) {
|
|
151
|
+
try {
|
|
152
|
+
return (await stat(path)).isFile();
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function resolveNearestPackageRoot(path) {
|
|
159
|
+
const startDirectory = dirname(path);
|
|
160
|
+
const cached = nearestPackageRootCache.get(startDirectory);
|
|
161
|
+
if (cached !== undefined) {
|
|
162
|
+
return cached;
|
|
163
|
+
}
|
|
164
|
+
const promise = findNearestPackageRoot(startDirectory);
|
|
165
|
+
nearestPackageRootCache.set(startDirectory, promise);
|
|
166
|
+
return promise;
|
|
167
|
+
}
|
|
168
|
+
async function findNearestPackageRoot(startDirectory) {
|
|
169
|
+
let currentDirectory = startDirectory;
|
|
170
|
+
while (true) {
|
|
171
|
+
if (await pathExists(join(currentDirectory, "package.json"))) {
|
|
172
|
+
return currentDirectory;
|
|
173
|
+
}
|
|
174
|
+
const parentDirectory = dirname(currentDirectory);
|
|
175
|
+
if (parentDirectory === currentDirectory) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
currentDirectory = parentDirectory;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async function pathExists(path) {
|
|
182
|
+
try {
|
|
183
|
+
await stat(path);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function isPathNotFoundError(error) {
|
|
191
|
+
return (typeof error === "object" &&
|
|
192
|
+
error !== null &&
|
|
193
|
+
"code" in error &&
|
|
194
|
+
(error.code === "ENOENT" || error.code === "ENOTDIR"));
|
|
195
|
+
}
|
|
196
|
+
function isPackageImport(source) {
|
|
197
|
+
if (source.startsWith(".") || source.startsWith("/") || /^[A-Za-z]:[\\/]/.test(source)) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
return !/^(?:node|data|file):/.test(source);
|
|
201
|
+
}
|
|
202
|
+
function isObjectRecord(value) {
|
|
203
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
204
|
+
}
|
|
205
|
+
function isPathInsideOrEqual(path, directory) {
|
|
206
|
+
const resolvedPath = resolve(path);
|
|
207
|
+
const resolvedDirectory = resolve(directory);
|
|
208
|
+
return (resolvedPath === resolvedDirectory || resolvedPath.startsWith(`${resolvedDirectory}${sep}`));
|
|
209
|
+
}
|
|
@@ -2,6 +2,12 @@ import type { Nitro } from "nitro/types";
|
|
|
2
2
|
import type { ChannelMethod } from "#public/definitions/channel.js";
|
|
3
3
|
import type { NitroArtifactsConfigInput } from "#internal/nitro/host/artifacts-config.js";
|
|
4
4
|
import type { PreparedApplicationHost } from "#internal/nitro/host/types.js";
|
|
5
|
+
interface ChannelRouteNitro {
|
|
6
|
+
options: Pick<Nitro["options"], "handlers" | "virtual">;
|
|
7
|
+
routing: {
|
|
8
|
+
sync(): void;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
5
11
|
/**
|
|
6
12
|
* One Nitro route registration for an Ash channel.
|
|
7
13
|
*/
|
|
@@ -16,7 +22,7 @@ export declare function computeChannelRouteRegistrations(preparedHost: PreparedA
|
|
|
16
22
|
/**
|
|
17
23
|
* Registers virtual Nitro handlers for the provided Ash channel routes.
|
|
18
24
|
*/
|
|
19
|
-
export declare function registerChannelVirtualHandlers(nitro:
|
|
25
|
+
export declare function registerChannelVirtualHandlers(nitro: Pick<ChannelRouteNitro, "options">, input: {
|
|
20
26
|
readonly artifactsConfig: NitroArtifactsConfigInput;
|
|
21
27
|
readonly registrations: readonly NitroChannelRouteRegistration[];
|
|
22
28
|
}): void;
|
|
@@ -24,8 +30,9 @@ export declare function registerChannelVirtualHandlers(nitro: Nitro, input: {
|
|
|
24
30
|
* Replaces the currently-mounted Ash channel virtual handlers when the route
|
|
25
31
|
* set changes.
|
|
26
32
|
*/
|
|
27
|
-
export declare function syncChannelVirtualHandlers(nitro:
|
|
33
|
+
export declare function syncChannelVirtualHandlers(nitro: ChannelRouteNitro, input: {
|
|
28
34
|
readonly artifactsConfig: NitroArtifactsConfigInput;
|
|
29
35
|
readonly next: readonly NitroChannelRouteRegistration[];
|
|
30
36
|
readonly previous: readonly NitroChannelRouteRegistration[];
|
|
31
37
|
}): boolean;
|
|
38
|
+
export {};
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { Nitro } from "nitro/types";
|
|
2
2
|
import type { PreparedApplicationHost } from "#internal/nitro/host/types.js";
|
|
3
|
+
type DevelopmentWatcherNitroOptions = Pick<Nitro["options"], "experimental" | "handlers" | "scheduledTasks" | "tasks" | "virtual"> & Partial<Pick<Nitro["options"], "dev" | "preset">>;
|
|
4
|
+
interface DevelopmentWatcherNitro {
|
|
5
|
+
hooks: {
|
|
6
|
+
callHook: Nitro["hooks"]["callHook"];
|
|
7
|
+
};
|
|
8
|
+
options: DevelopmentWatcherNitroOptions;
|
|
9
|
+
routing: {
|
|
10
|
+
sync(): void;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
3
13
|
/**
|
|
4
14
|
* Handle for the authored-source development watcher.
|
|
5
15
|
*/
|
|
@@ -13,7 +23,8 @@ export interface AuthoredSourceWatcherHandle {
|
|
|
13
23
|
* triggers Nitro rebuild reloads only when structural runtime wiring changes.
|
|
14
24
|
*/
|
|
15
25
|
export declare function startAuthoredSourceWatcher(input: {
|
|
16
|
-
nitro:
|
|
26
|
+
nitro: DevelopmentWatcherNitro;
|
|
17
27
|
preparedHost: PreparedApplicationHost;
|
|
18
28
|
schedulesEnabled?: boolean;
|
|
19
29
|
}): Promise<AuthoredSourceWatcherHandle>;
|
|
30
|
+
export {};
|
|
@@ -3,7 +3,7 @@ import { readdir, readFile } from "node:fs/promises";
|
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
5
|
import { watch } from "chokidar";
|
|
6
|
-
import { parse as parseJsonc } from "jsonc-parser";
|
|
6
|
+
import { parse as parseJsonc } from "#compiled/jsonc-parser/index.js";
|
|
7
7
|
import { clearCompiledRuntimeAgentBundleCache } from "#runtime/sessions/compiled-agent-cache.js";
|
|
8
8
|
import { toErrorMessage } from "#shared/errors.js";
|
|
9
9
|
import { resolvePackageSourceFilePath } from "#internal/application/package.js";
|
|
@@ -12,6 +12,7 @@ import { computeChannelRouteRegistrations, syncChannelVirtualHandlers, } from "#
|
|
|
12
12
|
import { prepareApplicationHost } from "#internal/nitro/host/prepare-application-host.js";
|
|
13
13
|
import { prewarmAppSandboxes } from "#execution/sandbox/prewarm.js";
|
|
14
14
|
import { syncScheduleTaskHandlers } from "#internal/nitro/host/schedule-task-routes.js";
|
|
15
|
+
import { getDevelopmentEnvironmentFilePaths, reloadDevelopmentEnvironmentFiles, } from "#cli/dev/environment.js";
|
|
15
16
|
const DEBOUNCE_MS = 120;
|
|
16
17
|
const WATCHED_LOCKFILE_NAMES = [
|
|
17
18
|
"pnpm-lock.yaml",
|
|
@@ -44,6 +45,7 @@ export async function startAuthoredSourceWatcher(input) {
|
|
|
44
45
|
let queue = Promise.resolve();
|
|
45
46
|
let debounceTimer;
|
|
46
47
|
const pendingEvents = new Set();
|
|
48
|
+
const pendingChangedPaths = new Set();
|
|
47
49
|
const initialWatchPaths = await resolveAuthoredWatchPaths(currentHost);
|
|
48
50
|
let currentWatchPathsByKey = createWatchPathMap(initialWatchPaths);
|
|
49
51
|
const watcher = watch(initialWatchPaths, {
|
|
@@ -66,10 +68,16 @@ export async function startAuthoredSourceWatcher(input) {
|
|
|
66
68
|
return;
|
|
67
69
|
}
|
|
68
70
|
const eventSummary = pendingEvents.size;
|
|
71
|
+
const changedPaths = [...pendingChangedPaths];
|
|
69
72
|
pendingEvents.clear();
|
|
73
|
+
pendingChangedPaths.clear();
|
|
70
74
|
const previousHost = currentHost;
|
|
75
|
+
const hasEnvironmentChange = hasDevelopmentEnvironmentFileChange(previousHost.appRoot, changedPaths);
|
|
71
76
|
console.log(`[ash:dev] change detected (${eventSummary} event${eventSummary === 1 ? "" : "s"}), rebuilding authored artifacts...`);
|
|
72
77
|
try {
|
|
78
|
+
if (hasEnvironmentChange) {
|
|
79
|
+
reloadDevelopmentEnvironmentFiles(previousHost.appRoot);
|
|
80
|
+
}
|
|
73
81
|
const nextHost = await prepareApplicationHost(previousHost.appRoot);
|
|
74
82
|
await prewarmAppSandboxes({
|
|
75
83
|
appRoot: nextHost.appRoot,
|
|
@@ -77,7 +85,7 @@ export async function startAuthoredSourceWatcher(input) {
|
|
|
77
85
|
});
|
|
78
86
|
const artifactsConfig = createNitroArtifactsConfig({
|
|
79
87
|
appRoot: nextHost.appRoot,
|
|
80
|
-
dev: input.nitro.options.dev,
|
|
88
|
+
dev: input.nitro.options.dev === true,
|
|
81
89
|
});
|
|
82
90
|
const hasChannelRouteChanged = syncChannelVirtualHandlers(input.nitro, {
|
|
83
91
|
artifactsConfig,
|
|
@@ -92,7 +100,7 @@ export async function startAuthoredSourceWatcher(input) {
|
|
|
92
100
|
});
|
|
93
101
|
clearCompiledRuntimeAgentBundleCache();
|
|
94
102
|
currentHost = nextHost;
|
|
95
|
-
const hasStructuralChange = hasChannelRouteChanged || hasScheduleRegistrationsChanged;
|
|
103
|
+
const hasStructuralChange = hasChannelRouteChanged || hasScheduleRegistrationsChanged || hasEnvironmentChange;
|
|
96
104
|
if (hasStructuralChange) {
|
|
97
105
|
console.log("[ash:dev] structural change detected, reloading Nitro worker...");
|
|
98
106
|
await input.nitro.hooks.callHook("rollup:reload");
|
|
@@ -120,6 +128,7 @@ export async function startAuthoredSourceWatcher(input) {
|
|
|
120
128
|
return;
|
|
121
129
|
}
|
|
122
130
|
pendingEvents.add(`${event}:${changedPath}`);
|
|
131
|
+
pendingChangedPaths.add(changedPath);
|
|
123
132
|
if (debounceTimer !== undefined) {
|
|
124
133
|
clearTimeout(debounceTimer);
|
|
125
134
|
}
|
|
@@ -160,6 +169,9 @@ async function resolveAuthoredWatchPaths(host) {
|
|
|
160
169
|
join(host.appRoot, TS_CONFIG_GLOB_NAME),
|
|
161
170
|
]);
|
|
162
171
|
const tsconfigPaths = await resolveTsConfigWatchPaths(host.appRoot);
|
|
172
|
+
for (const envFilePath of getDevelopmentEnvironmentFilePaths(host.appRoot)) {
|
|
173
|
+
watchPaths.add(envFilePath);
|
|
174
|
+
}
|
|
163
175
|
for (const path of tsconfigPaths) {
|
|
164
176
|
watchPaths.add(path);
|
|
165
177
|
}
|
|
@@ -202,6 +214,10 @@ function syncWatcherPaths(input) {
|
|
|
202
214
|
function toWatchPathKey(path) {
|
|
203
215
|
return path.replaceAll("\\", "/");
|
|
204
216
|
}
|
|
217
|
+
function hasDevelopmentEnvironmentFileChange(appRoot, changedPaths) {
|
|
218
|
+
const environmentFilePathKeys = new Set(getDevelopmentEnvironmentFilePaths(appRoot).map((path) => toWatchPathKey(resolve(path))));
|
|
219
|
+
return changedPaths.some((path) => environmentFilePathKeys.has(toWatchPathKey(resolve(path))));
|
|
220
|
+
}
|
|
205
221
|
function resolveLockfileSearchDirectories(appRoot) {
|
|
206
222
|
const directories = [];
|
|
207
223
|
let currentDirectory = resolve(appRoot);
|