@luckystack/devkit 0.13.0 → 0.15.0
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/AGENTS.md +1 -1
- package/CHANGELOG.md +27 -0
- package/dist/chunk-FWE6YJ3G.js +17 -0
- package/dist/chunk-FWE6YJ3G.js.map +1 -0
- package/dist/devServerRestart.d.ts +12 -0
- package/dist/index.js +157 -118
- package/dist/index.js.map +1 -1
- package/dist/supervisor.d.ts +5 -0
- package/dist/supervisor.js +17 -2
- package/dist/supervisor.js.map +1 -1
- package/dist/templateInjector.d.ts +5 -1
- package/dist/templates/api.template.ts +2 -1
- package/dist/templates/page_dashboard.template.tsx +3 -7
- package/dist/templates/page_plain.template.tsx +4 -9
- package/dist/templates/sync_client.template.ts +3 -2
- package/dist/templates/sync_client_paired.template.ts +2 -1
- package/dist/templates/sync_client_standalone.template.ts +2 -1
- package/dist/templates/sync_server.template.ts +2 -1
- package/docs/hot-reload.md +2 -2
- package/docs/supervisor.md +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
requestDevServerRestart
|
|
3
|
+
} from "./chunk-FWE6YJ3G.js";
|
|
1
4
|
import {
|
|
2
5
|
validateDeploy
|
|
3
6
|
} from "./chunk-BJN4XIUX.js";
|
|
@@ -64,9 +67,6 @@ var isSyncFileName = (fileName) => {
|
|
|
64
67
|
const stem = fileName.slice(0, -3);
|
|
65
68
|
return getRoutingRules().syncVersionRegex.test(stem);
|
|
66
69
|
};
|
|
67
|
-
var isRouteTestFile = (fileNameOrPath) => {
|
|
68
|
-
return fileNameOrPath.endsWith(".tests.ts");
|
|
69
|
-
};
|
|
70
70
|
var isNonRouteDirectory = (directoryName) => directoryName.startsWith(getRoutingRules().privateFolderPrefix) || isTestDirectory(directoryName);
|
|
71
71
|
var validatePagePath = (srcRelativePath) => {
|
|
72
72
|
const rules2 = getRoutingRules();
|
|
@@ -129,54 +129,56 @@ var isInsidePrivateRouteSubfolder = (fullPath) => {
|
|
|
129
129
|
return segments.slice(markerIndex + 1).some((segment) => segment.startsWith(privateFolderPrefix));
|
|
130
130
|
};
|
|
131
131
|
var isRouteSurfaceFile = (fullPath) => !isInsidePrivateRouteSubfolder(fullPath) && !isTestFile(fullPath);
|
|
132
|
-
var
|
|
132
|
+
var toSrcMarkerPath = (srcDir, filePath) => `/${normalizePath(path.relative(srcDir, filePath))}`;
|
|
133
|
+
var walkRouteFiles = (srcDir, dir = srcDir, results = []) => {
|
|
133
134
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
134
135
|
const apiSeg = apiMarkerSegment();
|
|
135
136
|
const syncSeg = syncMarkerSegment();
|
|
136
137
|
const { ignore } = getRoutingRules();
|
|
137
138
|
for (const entry of entries) {
|
|
138
139
|
const fullPath = path.join(dir, entry.name);
|
|
139
|
-
const
|
|
140
|
+
const srcMarkerPath = toSrcMarkerPath(srcDir, fullPath);
|
|
140
141
|
if (ignore(toRel(fullPath))) continue;
|
|
141
|
-
if (isInsidePrivateRouteSubfolder(
|
|
142
|
+
if (isInsidePrivateRouteSubfolder(srcMarkerPath)) continue;
|
|
142
143
|
if (entry.isDirectory()) {
|
|
143
144
|
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
144
145
|
continue;
|
|
145
146
|
}
|
|
146
|
-
walkRouteFiles(fullPath, results);
|
|
147
|
+
walkRouteFiles(srcDir, fullPath, results);
|
|
147
148
|
continue;
|
|
148
149
|
}
|
|
149
150
|
if (!entry.isFile() || !entry.name.endsWith(".ts")) {
|
|
150
151
|
continue;
|
|
151
152
|
}
|
|
152
|
-
if (
|
|
153
|
+
if (!isRouteSurfaceFile(srcMarkerPath)) {
|
|
153
154
|
continue;
|
|
154
155
|
}
|
|
155
|
-
if (
|
|
156
|
+
if (srcMarkerPath.includes(apiSeg) || srcMarkerPath.includes(syncSeg)) {
|
|
156
157
|
results.push(fullPath);
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
return results;
|
|
160
161
|
};
|
|
161
162
|
var getFileRouteToken = ({
|
|
162
|
-
|
|
163
|
+
srcMarkerPath,
|
|
163
164
|
marker
|
|
164
165
|
}) => {
|
|
165
|
-
const markerIndex =
|
|
166
|
+
const markerIndex = srcMarkerPath.indexOf(marker);
|
|
166
167
|
if (markerIndex === -1) {
|
|
167
168
|
return "";
|
|
168
169
|
}
|
|
169
170
|
const tokenStart = markerIndex + marker.length;
|
|
170
|
-
return
|
|
171
|
+
return srcMarkerPath.slice(tokenStart, srcMarkerPath.length - ".ts".length);
|
|
171
172
|
};
|
|
172
|
-
var validateRouteFilePath = (filePath) => {
|
|
173
|
+
var validateRouteFilePath = (srcDir, filePath) => {
|
|
173
174
|
const issues = [];
|
|
174
175
|
const normalizedFilePath = normalizePath(path.resolve(filePath));
|
|
176
|
+
const srcMarkerPath = toSrcMarkerPath(srcDir, filePath);
|
|
175
177
|
const fileName = path.basename(filePath);
|
|
176
178
|
const apiSeg = apiMarkerSegment();
|
|
177
179
|
const syncSeg = syncMarkerSegment();
|
|
178
|
-
if (
|
|
179
|
-
const apiRouteToken = getFileRouteToken({
|
|
180
|
+
if (srcMarkerPath.includes(apiSeg)) {
|
|
181
|
+
const apiRouteToken = getFileRouteToken({ srcMarkerPath, marker: apiSeg });
|
|
180
182
|
if (apiRouteToken.includes("/")) {
|
|
181
183
|
issues.push({
|
|
182
184
|
kind: "api",
|
|
@@ -194,8 +196,8 @@ var validateRouteFilePath = (filePath) => {
|
|
|
194
196
|
});
|
|
195
197
|
}
|
|
196
198
|
}
|
|
197
|
-
if (
|
|
198
|
-
const syncRouteToken = getFileRouteToken({
|
|
199
|
+
if (srcMarkerPath.includes(syncSeg)) {
|
|
200
|
+
const syncRouteToken = getFileRouteToken({ srcMarkerPath, marker: syncSeg });
|
|
199
201
|
if (syncRouteToken.includes("/")) {
|
|
200
202
|
issues.push({
|
|
201
203
|
kind: "sync",
|
|
@@ -259,14 +261,14 @@ var resolveSyncRouteKey = ({
|
|
|
259
261
|
const kind = syncMatch[1];
|
|
260
262
|
const version = `v${syncMatch[2]}`;
|
|
261
263
|
const syncName = rawSyncName.replace(rules2.syncVersionRegex, "");
|
|
262
|
-
const routeBaseKey =
|
|
264
|
+
const routeBaseKey = `sync/${pageLocation || "system"}/${syncName}/${version}`;
|
|
263
265
|
return `${routeBaseKey}_${kind}`;
|
|
264
266
|
};
|
|
265
267
|
var collectInvalidRouteNamingIssues = (srcDir) => {
|
|
266
268
|
const allRouteFiles = walkRouteFiles(srcDir);
|
|
267
269
|
const issues = [];
|
|
268
270
|
for (const filePath of allRouteFiles) {
|
|
269
|
-
issues.push(...validateRouteFilePath(filePath));
|
|
271
|
+
issues.push(...validateRouteFilePath(srcDir, filePath));
|
|
270
272
|
}
|
|
271
273
|
return issues.toSorted((a, b) => a.filePath.localeCompare(b.filePath));
|
|
272
274
|
};
|
|
@@ -278,7 +280,8 @@ var collectDuplicateNormalizedRouteKeyIssues = (srcDir) => {
|
|
|
278
280
|
const syncSeg = syncMarkerSegment();
|
|
279
281
|
for (const filePath of allRouteFiles) {
|
|
280
282
|
const normalizedFilePath = normalizePath(path.resolve(filePath));
|
|
281
|
-
|
|
283
|
+
const srcMarkerPath = toSrcMarkerPath(srcDir, filePath);
|
|
284
|
+
if (srcMarkerPath.includes(apiSeg)) {
|
|
282
285
|
const routeKey = resolveApiRouteKey({ srcDir, filePath });
|
|
283
286
|
if (!routeKey) {
|
|
284
287
|
continue;
|
|
@@ -287,7 +290,7 @@ var collectDuplicateNormalizedRouteKeyIssues = (srcDir) => {
|
|
|
287
290
|
routeKeyKinds.set(routeKey, "api");
|
|
288
291
|
continue;
|
|
289
292
|
}
|
|
290
|
-
if (
|
|
293
|
+
if (srcMarkerPath.includes(syncSeg)) {
|
|
291
294
|
const routeKey = resolveSyncRouteKey({ srcDir, filePath });
|
|
292
295
|
if (!routeKey) {
|
|
293
296
|
continue;
|
|
@@ -4079,11 +4082,15 @@ import path15 from "path";
|
|
|
4079
4082
|
import fs9 from "fs";
|
|
4080
4083
|
import path12 from "path";
|
|
4081
4084
|
import { fileURLToPath, pathToFileURL as pathToFileURL2 } from "url";
|
|
4082
|
-
import {
|
|
4085
|
+
import {
|
|
4086
|
+
ScriptKind as ScriptKind3
|
|
4087
|
+
} from "typescript-7-api/ast";
|
|
4083
4088
|
import {
|
|
4084
4089
|
isIdentifier as isIdentifier8,
|
|
4085
4090
|
isInterfaceDeclaration as isInterfaceDeclaration6,
|
|
4086
4091
|
isPropertySignatureDeclaration as isPropertySignatureDeclaration4,
|
|
4092
|
+
isStringLiteral as isStringLiteral7,
|
|
4093
|
+
isTypeAliasDeclaration as isTypeAliasDeclaration6,
|
|
4087
4094
|
isTypeLiteralNode as isTypeLiteralNode3
|
|
4088
4095
|
} from "typescript-7-api/ast/is";
|
|
4089
4096
|
import { ROOT_DIR as ROOT_DIR7, getGeneratedSocketTypesPath as getGeneratedSocketTypesPath6, getSrcDir as getSrcDir4 } from "@luckystack/core";
|
|
@@ -4156,23 +4163,22 @@ var isEmptyFile = (filePath) => {
|
|
|
4156
4163
|
return false;
|
|
4157
4164
|
}
|
|
4158
4165
|
};
|
|
4159
|
-
var
|
|
4166
|
+
var INJECTED_GUIDANCE_PATTERN = /^\/\/ Invalid (?:API|sync) filename: [^\r\n]*$/;
|
|
4167
|
+
var isInjectedGuidanceOnlyFile = (filePath) => {
|
|
4160
4168
|
try {
|
|
4161
4169
|
const content = fs9.readFileSync(filePath, "utf8");
|
|
4162
|
-
|
|
4163
|
-
const withoutLineComments = withoutBlockComments.replaceAll(/(^|\s)\/\/.*$/gm, "$1");
|
|
4164
|
-
return withoutLineComments.trim().length === 0;
|
|
4170
|
+
return INJECTED_GUIDANCE_PATTERN.test(content.trim());
|
|
4165
4171
|
} catch {
|
|
4166
4172
|
return false;
|
|
4167
4173
|
}
|
|
4168
4174
|
};
|
|
4169
4175
|
var isInApiFolder = (filePath) => {
|
|
4170
4176
|
const normalized = filePath.replaceAll("\\", "/");
|
|
4171
|
-
return normalized.includes(apiMarkerSegment()) && filePath.endsWith(".ts") &&
|
|
4177
|
+
return normalized.includes(apiMarkerSegment()) && filePath.endsWith(".ts") && isRouteSurfaceFile(normalized);
|
|
4172
4178
|
};
|
|
4173
4179
|
var isInSyncFolder = (filePath) => {
|
|
4174
4180
|
const normalized = filePath.replaceAll("\\", "/");
|
|
4175
|
-
return normalized.includes(syncMarkerSegment()) && filePath.endsWith(".ts") &&
|
|
4181
|
+
return normalized.includes(syncMarkerSegment()) && filePath.endsWith(".ts") && isRouteSurfaceFile(normalized);
|
|
4176
4182
|
};
|
|
4177
4183
|
var isPageFile = (filePath) => {
|
|
4178
4184
|
const normalized = filePath.replaceAll("\\", "/");
|
|
@@ -4318,22 +4324,10 @@ var hasPairedFile = (filePath) => {
|
|
|
4318
4324
|
if (!pairedPath) return false;
|
|
4319
4325
|
return fs9.existsSync(pairedPath);
|
|
4320
4326
|
};
|
|
4321
|
-
var
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
if (/(?:^|\/)src\/_sync\//.test(normalized)) return "system";
|
|
4326
|
-
return "";
|
|
4327
|
-
};
|
|
4328
|
-
var extractSyncName2 = (filePath) => {
|
|
4329
|
-
const normalized = filePath.replaceAll("\\", "/");
|
|
4330
|
-
const match = /_sync\/(.+)\.ts$/.exec(normalized);
|
|
4331
|
-
if (!match) {
|
|
4332
|
-
const basename = path12.basename(filePath, ".ts");
|
|
4333
|
-
return basename.replace(/_server_v\d+$/, "").replace(/_client_v\d+$/, "");
|
|
4334
|
-
}
|
|
4335
|
-
return (match[1] ?? "").replace(/_server_v\d+$/, "").replace(/_client_v\d+$/, "");
|
|
4336
|
-
};
|
|
4327
|
+
var toSrcRelativeOrSelf = (filePath) => computeSrcRelativePath(filePath) ?? filePath.replaceAll("\\", "/");
|
|
4328
|
+
var extractSyncPagePath2 = (filePath) => extractSyncPagePath(path12.resolve(filePath).replaceAll("\\", "/"));
|
|
4329
|
+
var extractSyncName2 = (filePath) => extractSyncName(toSrcRelativeOrSelf(filePath));
|
|
4330
|
+
var extractSyncVersion2 = (filePath) => extractSyncVersion(toSrcRelativeOrSelf(filePath));
|
|
4337
4331
|
var extractClientInputFromFile = (filePath) => {
|
|
4338
4332
|
try {
|
|
4339
4333
|
const content = fs9.readFileSync(filePath, "utf8");
|
|
@@ -4364,43 +4358,32 @@ var extractClientInputFromFile = (filePath) => {
|
|
|
4364
4358
|
return null;
|
|
4365
4359
|
}
|
|
4366
4360
|
};
|
|
4367
|
-
var
|
|
4361
|
+
var propertyKeyText = (name) => isIdentifier8(name) || isStringLiteral7(name) ? name.text : null;
|
|
4362
|
+
var findTypeLiteralMemberType = (typeNode, key) => {
|
|
4363
|
+
if (!typeNode || !isTypeLiteralNode3(typeNode)) return void 0;
|
|
4364
|
+
for (const member of typeNode.members) {
|
|
4365
|
+
if (isPropertySignatureDeclaration4(member) && propertyKeyText(member.name) === key) {
|
|
4366
|
+
return member.type;
|
|
4367
|
+
}
|
|
4368
|
+
}
|
|
4369
|
+
return void 0;
|
|
4370
|
+
};
|
|
4371
|
+
var extractClientInputFromGeneratedTypes = (pagePath, syncName, version) => {
|
|
4368
4372
|
try {
|
|
4369
4373
|
const generatedTypesPath = getGeneratedSocketTypesPath6();
|
|
4370
4374
|
const content = fs9.readFileSync(generatedTypesPath, "utf8");
|
|
4371
|
-
const
|
|
4372
|
-
const
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
const
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
const pageBlock = pageBlockMatch[1];
|
|
4381
|
-
const syncEntryPattern = new RegExp(String.raw`'${escapedSyncName}':\s*\{\s*clientInput:\s*`);
|
|
4382
|
-
const match = pageBlock.match(syncEntryPattern);
|
|
4383
|
-
if (!match || typeof match.index !== "number") {
|
|
4384
|
-
console.log(`[TemplateInjector] Could not find sync entry for ${pagePath}/${syncName}`);
|
|
4375
|
+
const sourceFile = parseSourceText(path12.basename(generatedTypesPath), content, ScriptKind3.TS);
|
|
4376
|
+
const syncTypeMap = sourceFile.statements.find(
|
|
4377
|
+
(statement) => isTypeAliasDeclaration6(statement) && statement.name.text === "_ProjectSyncTypeMap"
|
|
4378
|
+
);
|
|
4379
|
+
const pageType = findTypeLiteralMemberType(syncTypeMap?.type, pagePath);
|
|
4380
|
+
const versionType = findTypeLiteralMemberType(findTypeLiteralMemberType(pageType, syncName), version);
|
|
4381
|
+
const clientInputType = findTypeLiteralMemberType(versionType, "clientInput");
|
|
4382
|
+
if (!clientInputType) {
|
|
4383
|
+
console.log(`[TemplateInjector] Could not find sync entry for ${pagePath}/${syncName}/${version}`);
|
|
4385
4384
|
return null;
|
|
4386
4385
|
}
|
|
4387
|
-
const
|
|
4388
|
-
const globalMatchIndex = pageStart + match.index;
|
|
4389
|
-
const searchStart = globalMatchIndex + match[0].length;
|
|
4390
|
-
const braceStart = content.indexOf("{", searchStart - 1);
|
|
4391
|
-
if (braceStart === -1) return null;
|
|
4392
|
-
let depth = 0;
|
|
4393
|
-
let endIndex = -1;
|
|
4394
|
-
for (let i = braceStart; i < content.length; i++) {
|
|
4395
|
-
if (content[i] === "{") depth++;
|
|
4396
|
-
else if (content[i] === "}") depth--;
|
|
4397
|
-
if (depth === 0) {
|
|
4398
|
-
endIndex = i;
|
|
4399
|
-
break;
|
|
4400
|
-
}
|
|
4401
|
-
}
|
|
4402
|
-
if (endIndex === -1) return null;
|
|
4403
|
-
const extracted = content.slice(braceStart, endIndex + 1);
|
|
4386
|
+
const extracted = content.slice(clientInputType.getStart(sourceFile), clientInputType.getEnd());
|
|
4404
4387
|
console.log(`[TemplateInjector] Extracted clientInput types: ${extracted}`);
|
|
4405
4388
|
return extracted;
|
|
4406
4389
|
} catch (error) {
|
|
@@ -4458,10 +4441,16 @@ var checkPagePlacement = (filePath, srcRelativePath) => {
|
|
|
4458
4441
|
}
|
|
4459
4442
|
return null;
|
|
4460
4443
|
};
|
|
4444
|
+
var TEMPLATE_LINT_HEADER = /^(?:\/\* eslint-disable(?: unicorn\/no-abusive-eslint-disable)? \*\/[^\S\r\n]*\r?\n)+(?:[^\S\r\n]*\r?\n)?/;
|
|
4445
|
+
var BYTE_ORDER_MARK = String.fromCodePoint(65279);
|
|
4446
|
+
var stripTemplateLintHeader = (content) => {
|
|
4447
|
+
const unmarked = content.startsWith(BYTE_ORDER_MARK) ? content.slice(1) : content;
|
|
4448
|
+
return TEMPLATE_LINT_HEADER.test(unmarked) ? unmarked.replace(TEMPLATE_LINT_HEADER, "") : content;
|
|
4449
|
+
};
|
|
4461
4450
|
var applyTemplatePlaceholders = (content, filePath, fileKind) => {
|
|
4462
4451
|
const relPath = calculateRelativePath(filePath);
|
|
4463
4452
|
const pragmaPattern = /\/\/\s*@ts-(?:ignore|expect-error).*\r?\n(.*)\{\{REL_PATH\}\}/g;
|
|
4464
|
-
let result = content.replaceAll(pragmaPattern, (_, prefix) => `${prefix}${relPath}`);
|
|
4453
|
+
let result = stripTemplateLintHeader(content).replaceAll(pragmaPattern, (_, prefix) => `${prefix}${relPath}`);
|
|
4465
4454
|
result = result.replaceAll("{{REL_PATH}}", () => relPath);
|
|
4466
4455
|
if (fileKind === "sync_client" || fileKind === "sync_server") {
|
|
4467
4456
|
const pagePath = extractSyncPagePath2(filePath);
|
|
@@ -4518,7 +4507,7 @@ var shouldInjectTemplate = (filePath, options = {}) => {
|
|
|
4518
4507
|
return false;
|
|
4519
4508
|
}
|
|
4520
4509
|
if (isEmptyFile(filePath)) return true;
|
|
4521
|
-
if (options.isNewFile) return
|
|
4510
|
+
if (options.isNewFile) return isInjectedGuidanceOnlyFile(filePath);
|
|
4522
4511
|
return false;
|
|
4523
4512
|
};
|
|
4524
4513
|
var ensureImportedTypes = (content, clientFilePath) => {
|
|
@@ -4685,11 +4674,12 @@ var injectServerTemplateWithClientInput = async (serverFilePath, clientInputType
|
|
|
4685
4674
|
try {
|
|
4686
4675
|
await ensureConsumerTemplateConfigLoaded();
|
|
4687
4676
|
const relPath = calculateRelativePath(serverFilePath);
|
|
4688
|
-
|
|
4689
|
-
if (
|
|
4677
|
+
const rawContent = resolveTemplateContent("sync_server");
|
|
4678
|
+
if (rawContent === null) {
|
|
4690
4679
|
console.error(`[TemplateInjector] No sync_server template content available for: ${serverFilePath}`);
|
|
4691
4680
|
return false;
|
|
4692
4681
|
}
|
|
4682
|
+
let content = stripTemplateLintHeader(rawContent);
|
|
4693
4683
|
const pragmaPattern = /\/\/\s*@ts-(?:ignore|expect-error).*\r?\n(.*)\{\{REL_PATH\}\}/g;
|
|
4694
4684
|
content = content.replaceAll(pragmaPattern, (_, prefix) => {
|
|
4695
4685
|
return `${prefix}${relPath}`;
|
|
@@ -4712,6 +4702,7 @@ var injectServerTemplateWithClientInput = async (serverFilePath, clientInputType
|
|
|
4712
4702
|
import fs10 from "fs";
|
|
4713
4703
|
import path13 from "path";
|
|
4714
4704
|
import { ROOT_DIR as ROOT_DIR8, getServerFunctionDirs as getServerFunctionDirs2, getSharedDir, getSrcDir as getSrcDir5 } from "@luckystack/core";
|
|
4705
|
+
var srcDirFromRoot = () => path13.relative(ROOT_DIR8, getSrcDir5()).replaceAll("\\", "/");
|
|
4715
4706
|
var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mts", ".cts"];
|
|
4716
4707
|
var normalizePath4 = (value) => path13.resolve(value).replaceAll("\\", "/");
|
|
4717
4708
|
var isSupportedScriptFile = (value) => {
|
|
@@ -4829,9 +4820,12 @@ var resolveImportToFile = (importerPath, specifier) => {
|
|
|
4829
4820
|
const relativeBase = path13.resolve(path13.dirname(importerPath), specifier);
|
|
4830
4821
|
return tryResolveWithExtensions(relativeBase);
|
|
4831
4822
|
}
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4823
|
+
const srcFromRoot = srcDirFromRoot();
|
|
4824
|
+
const srcAliases = ["src/", "@/"];
|
|
4825
|
+
if (srcFromRoot && !srcFromRoot.startsWith("..")) srcAliases.push(`${srcFromRoot}/`);
|
|
4826
|
+
const srcAlias = srcAliases.find((alias) => specifier.startsWith(alias));
|
|
4827
|
+
if (srcAlias) {
|
|
4828
|
+
return tryResolveWithExtensions(path13.join(getSrcDir5(), specifier.slice(srcAlias.length)));
|
|
4835
4829
|
}
|
|
4836
4830
|
if (specifier.startsWith("shared/")) {
|
|
4837
4831
|
return tryResolveWithExtensions(path13.join(getSharedDir(), specifier.slice(7)));
|
|
@@ -4839,7 +4833,10 @@ var resolveImportToFile = (importerPath, specifier) => {
|
|
|
4839
4833
|
return null;
|
|
4840
4834
|
};
|
|
4841
4835
|
var isRouteFile = (filePath) => {
|
|
4842
|
-
|
|
4836
|
+
const relative = path13.relative(getSrcDir5(), filePath).replaceAll("\\", "/");
|
|
4837
|
+
if (relative.startsWith("..") || path13.isAbsolute(relative)) return false;
|
|
4838
|
+
const markerPath = `/${relative}`;
|
|
4839
|
+
return (markerPath.includes(apiMarkerSegment()) || markerPath.includes(syncMarkerSegment())) && isRouteSurfaceFile(markerPath);
|
|
4843
4840
|
};
|
|
4844
4841
|
var collectScopedFiles = () => {
|
|
4845
4842
|
const now = Date.now();
|
|
@@ -4932,26 +4929,36 @@ var runPrismaGenerate = async () => tryCatch2(
|
|
|
4932
4929
|
);
|
|
4933
4930
|
|
|
4934
4931
|
// src/hotReload.ts
|
|
4935
|
-
import {
|
|
4932
|
+
import {
|
|
4933
|
+
tryCatch as tryCatch3,
|
|
4934
|
+
getProjectConfig,
|
|
4935
|
+
getLocaleReloader,
|
|
4936
|
+
isProductionRuntime,
|
|
4937
|
+
getGeneratedSocketTypesPath as getGeneratedSocketTypesPath7,
|
|
4938
|
+
getGeneratedApiSchemasPath as getGeneratedApiSchemasPath2,
|
|
4939
|
+
getGeneratedApiDocsPath as getGeneratedApiDocsPath2
|
|
4940
|
+
} from "@luckystack/core";
|
|
4936
4941
|
var normalizeFsPath = (value) => path15.resolve(value).replaceAll("\\", "/");
|
|
4937
4942
|
var isGeneratedPath = (normalizedPath) => {
|
|
4938
|
-
|
|
4943
|
+
if (normalizedPath.includes(".generated.")) return true;
|
|
4944
|
+
return [getGeneratedSocketTypesPath7(), getGeneratedApiSchemasPath2(), getGeneratedApiDocsPath2()].some((generatedPath) => normalizeFsPath(generatedPath) === normalizedPath);
|
|
4939
4945
|
};
|
|
4940
4946
|
var createTypeMapQueue = () => {
|
|
4941
4947
|
const queue = { pending: false, running: false };
|
|
4942
4948
|
const run = () => {
|
|
4943
4949
|
queue.running = true;
|
|
4944
4950
|
queue.pending = false;
|
|
4945
|
-
const startedAt = Date.now();
|
|
4946
4951
|
setImmediate(() => {
|
|
4947
4952
|
void (async () => {
|
|
4953
|
+
const startedAt = Date.now();
|
|
4948
4954
|
const [err] = await tryCatch3(() => {
|
|
4949
4955
|
generateTypeMapFile({ quiet: true });
|
|
4950
4956
|
});
|
|
4957
|
+
const durationMs = Date.now() - startedAt;
|
|
4951
4958
|
if (err) {
|
|
4952
|
-
console.log(`[HotReload] type map regeneration failed: ${String(err)}`, "red");
|
|
4959
|
+
console.log(`[HotReload] type map regeneration failed after ${durationMs}ms: ${String(err)}`, "red");
|
|
4953
4960
|
} else {
|
|
4954
|
-
console.log(`[HotReload] type map
|
|
4961
|
+
console.log(`[HotReload] type map regenerated in ${durationMs}ms (the server answered no requests meanwhile)`, "green");
|
|
4955
4962
|
}
|
|
4956
4963
|
queue.running = false;
|
|
4957
4964
|
if (queue.pending) {
|
|
@@ -4973,7 +4980,12 @@ var createPendingChangeSets = () => ({
|
|
|
4973
4980
|
apiUpserts: /* @__PURE__ */ new Set(),
|
|
4974
4981
|
apiDeletes: /* @__PURE__ */ new Set(),
|
|
4975
4982
|
syncUpserts: /* @__PURE__ */ new Set(),
|
|
4976
|
-
syncDeletes: /* @__PURE__ */ new Set()
|
|
4983
|
+
syncDeletes: /* @__PURE__ */ new Set(),
|
|
4984
|
+
//? Deleted sync SERVER files whose paired client still needs its types
|
|
4985
|
+
//? inlined. A set the sync task drains, not a closure handed to the
|
|
4986
|
+
//? scheduler: any later sync event in the debounce window replaces the
|
|
4987
|
+
//? scheduled task, and a closure would be dropped with it.
|
|
4988
|
+
deletedSyncServers: /* @__PURE__ */ new Set()
|
|
4977
4989
|
});
|
|
4978
4990
|
var buildPathSegments = () => {
|
|
4979
4991
|
const rules2 = getRoutingRules();
|
|
@@ -4994,10 +5006,11 @@ var buildPathSegments = () => {
|
|
|
4994
5006
|
};
|
|
4995
5007
|
};
|
|
4996
5008
|
var makeIsInServerFunctionsDir = (segments) => (normalizedPath) => segments.serverFunctionsSegments.some((seg) => normalizedPath.includes(seg));
|
|
4997
|
-
var
|
|
5009
|
+
var makeIsRouteFile = (segments) => (normalizedPath) => (normalizedPath.includes(segments.apiMarkerSlash) || normalizedPath.includes(segments.syncMarkerSlash)) && isRouteSurfaceFile(normalizedPath);
|
|
5010
|
+
var makeIsRouteDependencyFile = (segments, isRouteFile2) => (normalizedPath) => {
|
|
4998
5011
|
if (!normalizedPath.endsWith(".ts") && !normalizedPath.endsWith(".tsx")) return false;
|
|
4999
5012
|
if (!normalizedPath.includes(segments.srcSegment)) return false;
|
|
5000
|
-
if (
|
|
5013
|
+
if (isRouteFile2(normalizedPath)) return false;
|
|
5001
5014
|
if (isGeneratedPath(normalizedPath)) return false;
|
|
5002
5015
|
return true;
|
|
5003
5016
|
};
|
|
@@ -5006,10 +5019,10 @@ var makeIsSharedDependencyFile = (segments, isInServerFunctionsDir) => (normaliz
|
|
|
5006
5019
|
if (normalizedPath.includes(segments.sharedSegment)) return true;
|
|
5007
5020
|
return isInServerFunctionsDir(normalizedPath);
|
|
5008
5021
|
};
|
|
5009
|
-
var makeIsTypeMapRelevantFile = (segments) => (normalizedPath) => {
|
|
5022
|
+
var makeIsTypeMapRelevantFile = (segments, isRouteFile2) => (normalizedPath) => {
|
|
5010
5023
|
if (isGeneratedPath(normalizedPath)) return false;
|
|
5011
5024
|
if (!(normalizedPath.endsWith(".ts") || normalizedPath.endsWith(".tsx"))) return false;
|
|
5012
|
-
if (
|
|
5025
|
+
if (isRouteFile2(normalizedPath)) return false;
|
|
5013
5026
|
return normalizedPath.includes(segments.srcSegment) || normalizedPath.endsWith("/config.ts") || normalizedPath.includes(segments.sharedSegment);
|
|
5014
5027
|
};
|
|
5015
5028
|
var makeIsLocaleFile = (segments) => (normalizedPath) => normalizedPath.includes(segments.localesSegment) && normalizedPath.endsWith(".json");
|
|
@@ -5047,9 +5060,10 @@ var setupWatchers = () => {
|
|
|
5047
5060
|
if (!isDevMode) return;
|
|
5048
5061
|
const segments = buildPathSegments();
|
|
5049
5062
|
const isInServerFunctionsDir = makeIsInServerFunctionsDir(segments);
|
|
5050
|
-
const
|
|
5063
|
+
const isRouteFile2 = makeIsRouteFile(segments);
|
|
5064
|
+
const isRouteDependencyFile = makeIsRouteDependencyFile(segments, isRouteFile2);
|
|
5051
5065
|
const isSharedDependencyFile = makeIsSharedDependencyFile(segments, isInServerFunctionsDir);
|
|
5052
|
-
const isTypeMapRelevantFile = makeIsTypeMapRelevantFile(segments);
|
|
5066
|
+
const isTypeMapRelevantFile = makeIsTypeMapRelevantFile(segments, isRouteFile2);
|
|
5053
5067
|
const isLocaleFile = makeIsLocaleFile(segments);
|
|
5054
5068
|
const typeMap = createTypeMapQueue();
|
|
5055
5069
|
const pending = createPendingChangeSets();
|
|
@@ -5068,11 +5082,31 @@ var setupWatchers = () => {
|
|
|
5068
5082
|
console.log(`[HotReload] API removed: ${deletePath}`, "yellow");
|
|
5069
5083
|
}
|
|
5070
5084
|
for (const upsertPath of upsertPaths) {
|
|
5085
|
+
const startedAt = Date.now();
|
|
5071
5086
|
await upsertApiFromFile(upsertPath);
|
|
5072
|
-
console.log(`[HotReload] API reloaded: ${upsertPath}`, "green");
|
|
5087
|
+
console.log(`[HotReload] API reloaded in ${Date.now() - startedAt}ms: ${upsertPath}`, "green");
|
|
5088
|
+
}
|
|
5089
|
+
};
|
|
5090
|
+
const migrateClientsOfDeletedSyncServers = async () => {
|
|
5091
|
+
const serverPaths = [...pending.deletedSyncServers];
|
|
5092
|
+
pending.deletedSyncServers.clear();
|
|
5093
|
+
for (const serverPath of serverPaths) {
|
|
5094
|
+
if (fs12.existsSync(serverPath)) continue;
|
|
5095
|
+
const clientPath = getPairedSyncFile(serverPath);
|
|
5096
|
+
if (!clientPath || !fs12.existsSync(clientPath)) continue;
|
|
5097
|
+
const clientInputTypes = extractClientInputFromGeneratedTypes(
|
|
5098
|
+
extractSyncPagePath2(serverPath),
|
|
5099
|
+
extractSyncName2(serverPath),
|
|
5100
|
+
extractSyncVersion2(serverPath)
|
|
5101
|
+
);
|
|
5102
|
+
await updateClientFileForDeletedServer(
|
|
5103
|
+
clientPath,
|
|
5104
|
+
clientInputTypes ?? "{\n // Types were in _server.ts - please add them here\n }"
|
|
5105
|
+
);
|
|
5073
5106
|
}
|
|
5074
5107
|
};
|
|
5075
5108
|
const processPendingSyncChanges = async ({ regenerateTypeMap = false } = {}) => {
|
|
5109
|
+
await migrateClientsOfDeletedSyncServers();
|
|
5076
5110
|
const deletePaths = [...pending.syncDeletes];
|
|
5077
5111
|
const upsertPaths = [...pending.syncUpserts];
|
|
5078
5112
|
pending.syncDeletes.clear();
|
|
@@ -5086,16 +5120,28 @@ var setupWatchers = () => {
|
|
|
5086
5120
|
console.log(`[HotReload] Sync removed: ${deletePath}`, "yellow");
|
|
5087
5121
|
}
|
|
5088
5122
|
for (const upsertPath of upsertPaths) {
|
|
5123
|
+
const startedAt = Date.now();
|
|
5089
5124
|
await upsertSyncFromFile(upsertPath);
|
|
5090
|
-
console.log(`[HotReload] Sync reloaded: ${upsertPath}`, "green");
|
|
5125
|
+
console.log(`[HotReload] Sync reloaded in ${Date.now() - startedAt}ms: ${upsertPath}`, "green");
|
|
5091
5126
|
}
|
|
5092
5127
|
};
|
|
5093
5128
|
const enqueueAffectedRoutesFromDependency = (changedPath) => {
|
|
5094
5129
|
const affectedRoutes = findDependentRouteFiles(changedPath);
|
|
5095
5130
|
if (affectedRoutes.size === 0) {
|
|
5096
5131
|
console.log(`[HotReload] No API/Sync routes depend on: ${changedPath}`, "yellow");
|
|
5097
|
-
return;
|
|
5132
|
+
return false;
|
|
5133
|
+
}
|
|
5134
|
+
if (requestDevServerRestart(changedPath)) {
|
|
5135
|
+
console.log(
|
|
5136
|
+
`[HotReload] Dependency changed: ${changedPath} -> restarting the dev server (${affectedRoutes.size} route(s) import it)`,
|
|
5137
|
+
"blue"
|
|
5138
|
+
);
|
|
5139
|
+
return true;
|
|
5098
5140
|
}
|
|
5141
|
+
console.log(
|
|
5142
|
+
`[HotReload] ${changedPath} changed, but routes that import it keep running its old code until you restart the dev server (the supervised \`npm run server\` restarts automatically)`,
|
|
5143
|
+
"yellow"
|
|
5144
|
+
);
|
|
5099
5145
|
let queuedApiCount = 0;
|
|
5100
5146
|
let queuedSyncCount = 0;
|
|
5101
5147
|
for (const routePath of affectedRoutes) {
|
|
@@ -5123,6 +5169,7 @@ var setupWatchers = () => {
|
|
|
5123
5169
|
await processPendingSyncChanges();
|
|
5124
5170
|
});
|
|
5125
5171
|
}
|
|
5172
|
+
return false;
|
|
5126
5173
|
};
|
|
5127
5174
|
const handleAdd = async (filePath) => {
|
|
5128
5175
|
const normalizedPath = normalizeFsPath(filePath);
|
|
@@ -5162,7 +5209,8 @@ var setupWatchers = () => {
|
|
|
5162
5209
|
return;
|
|
5163
5210
|
}
|
|
5164
5211
|
}
|
|
5165
|
-
|
|
5212
|
+
const isRoute = isRouteFile2(normalizedPath);
|
|
5213
|
+
if (isRoute && normalizedPath.includes(segments.apiMarkerNoLead)) {
|
|
5166
5214
|
pending.apiDeletes.delete(normalizedPath);
|
|
5167
5215
|
pending.apiUpserts.add(normalizedPath);
|
|
5168
5216
|
scheduleReload("api", async () => {
|
|
@@ -5170,7 +5218,7 @@ var setupWatchers = () => {
|
|
|
5170
5218
|
});
|
|
5171
5219
|
return;
|
|
5172
5220
|
}
|
|
5173
|
-
if (normalizedPath.includes(segments.syncMarkerNoLead)) {
|
|
5221
|
+
if (isRoute && normalizedPath.includes(segments.syncMarkerNoLead)) {
|
|
5174
5222
|
pending.syncDeletes.delete(normalizedPath);
|
|
5175
5223
|
pending.syncUpserts.add(normalizedPath);
|
|
5176
5224
|
scheduleReload("sync", async () => {
|
|
@@ -5212,11 +5260,11 @@ var setupWatchers = () => {
|
|
|
5212
5260
|
return;
|
|
5213
5261
|
}
|
|
5214
5262
|
if (isRouteDependencyFile(normalizedPath)) {
|
|
5263
|
+
if (enqueueAffectedRoutesFromDependency(normalizedPath)) return;
|
|
5215
5264
|
scheduleReload("typemap", () => {
|
|
5216
5265
|
console.log(`[HotReload] Route dependency changed, scheduling type map regeneration`, "blue");
|
|
5217
5266
|
typeMap.request();
|
|
5218
5267
|
});
|
|
5219
|
-
enqueueAffectedRoutesFromDependency(normalizedPath);
|
|
5220
5268
|
return;
|
|
5221
5269
|
}
|
|
5222
5270
|
if (isTypeMapRelevantFile(normalizedPath)) {
|
|
@@ -5250,13 +5298,13 @@ var setupWatchers = () => {
|
|
|
5250
5298
|
const handleFunctionChange = (changedPath) => {
|
|
5251
5299
|
const normalizedPath = normalizeFsPath(changedPath);
|
|
5252
5300
|
invalidateGraphForFile(normalizedPath);
|
|
5301
|
+
if (isSharedDependencyFile(normalizedPath) && enqueueAffectedRoutesFromDependency(normalizedPath)) {
|
|
5302
|
+
return;
|
|
5303
|
+
}
|
|
5253
5304
|
scheduleReload("functions", async () => {
|
|
5254
5305
|
typeMap.request();
|
|
5255
5306
|
await initializeFunctions();
|
|
5256
5307
|
});
|
|
5257
|
-
if (isSharedDependencyFile(normalizedPath)) {
|
|
5258
|
-
enqueueAffectedRoutesFromDependency(normalizedPath);
|
|
5259
|
-
}
|
|
5260
5308
|
};
|
|
5261
5309
|
const handleDelete = (filePath) => {
|
|
5262
5310
|
const normalizedPath = normalizeFsPath(filePath);
|
|
@@ -5271,11 +5319,11 @@ var setupWatchers = () => {
|
|
|
5271
5319
|
return;
|
|
5272
5320
|
}
|
|
5273
5321
|
if (isRouteDependencyFile(normalizedPath)) {
|
|
5322
|
+
if (enqueueAffectedRoutesFromDependency(normalizedPath)) return;
|
|
5274
5323
|
scheduleReload("typemap", () => {
|
|
5275
5324
|
console.log(`[HotReload] Route dependency deleted, scheduling type map regeneration`, "blue");
|
|
5276
5325
|
typeMap.request();
|
|
5277
5326
|
});
|
|
5278
|
-
enqueueAffectedRoutesFromDependency(normalizedPath);
|
|
5279
5327
|
return;
|
|
5280
5328
|
}
|
|
5281
5329
|
if (isTypeMapRelevantFile(normalizedPath)) {
|
|
@@ -5301,19 +5349,10 @@ var setupWatchers = () => {
|
|
|
5301
5349
|
});
|
|
5302
5350
|
pending.syncUpserts.delete(normalizedPath);
|
|
5303
5351
|
pending.syncDeletes.add(normalizedPath);
|
|
5352
|
+
if (isSyncServerFile(normalizedPath)) {
|
|
5353
|
+
pending.deletedSyncServers.add(normalizedPath);
|
|
5354
|
+
}
|
|
5304
5355
|
scheduleReload("sync", async () => {
|
|
5305
|
-
if (isSyncServerFile(normalizedPath)) {
|
|
5306
|
-
const clientPath = getPairedSyncFile(normalizedPath);
|
|
5307
|
-
if (clientPath && fs12.existsSync(clientPath)) {
|
|
5308
|
-
const pagePath = extractSyncPagePath2(normalizedPath);
|
|
5309
|
-
const syncName = extractSyncName2(normalizedPath);
|
|
5310
|
-
const clientInputTypes = extractClientInputFromGeneratedTypes(pagePath, syncName);
|
|
5311
|
-
await updateClientFileForDeletedServer(
|
|
5312
|
-
clientPath,
|
|
5313
|
-
clientInputTypes ?? "{\n // Types were in _server.ts - please add them here\n }"
|
|
5314
|
-
);
|
|
5315
|
-
}
|
|
5316
|
-
}
|
|
5317
5356
|
await processPendingSyncChanges();
|
|
5318
5357
|
});
|
|
5319
5358
|
}
|