@luckystack/devkit 0.14.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 +20 -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 +147 -115
- 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/docs/hot-reload.md +2 -2
- package/docs/supervisor.md +1 -1
- package/package.json +2 -2
package/AGENTS.md
CHANGED
|
@@ -6,4 +6,4 @@ Generated route contracts must preserve transport-safe types. A source file miss
|
|
|
6
6
|
|
|
7
7
|
The one deliberate diagnostics exception — an absent optional sync side — must stay scoped to that side's own field and run after the thrown-extraction check (ADR 0057). Server-backed sync routes share the API side's auth/rate-limit extractors and schema converter so the test-runner can sweep them (ADR 0064). See `docs/type-map-generation.md`.
|
|
8
8
|
|
|
9
|
-
Hot reload
|
|
9
|
+
Hot reload does pause request handling while it builds the TypeScript Program and regenerates the type map: that work is synchronous, and deferring it only lets the current event finish. The pause is accepted for development; keep its duration logged and keep generation off the boot path so the server listens first. Do not describe it as non-blocking (see `docs/hot-reload.md`). Avoid invalidating the shared Program on initial population without cause; do invalidate when source changes. Consumer-owned template overrides intentionally outlive the installed devkit's bundled defaults; do not overwrite them on upgrade.
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ All notable changes to `@luckystack/devkit` are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.15.0] - 2026-10-19
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- **Editing a file that a route imports restarts the supervised dev server** (`npm run server`), so the new code actually runs; connected clients reconnect (ADR 0079). Before, the route was re-imported but kept running the old dependency code. The supervisor now starts the dev server with an IPC channel for this (Node; Bun on Linux and macOS). Without the supervisor, a warning says a restart is needed. Editing a route file itself still reloads it in place.
|
|
13
|
+
- **Hot reload logs how long type-map regeneration and each route reload took.** The docs now say the dev server answers no requests during that time (ADR 0080).
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **The dev server starts, and type generation runs, when a `.test.ts` or `.spec.ts` file sits next to a route.**
|
|
18
|
+
- **A project checked out under a folder named `_api` or `_sync` boots again.** Route naming is validated relative to the source folder.
|
|
19
|
+
- **The duplicate-route check reports a root sync** (`src/_sync/x_server_v1.ts`) that collides with `src/system/_sync/x_server_v1.ts`, as it already did for APIs.
|
|
20
|
+
- **Deleting a sync `_server` file moves the real `clientInput` type into the paired client** instead of an empty placeholder, and that client rewrite is no longer lost when another sync file is saved within the reload debounce window.
|
|
21
|
+
- **Helpers in a private folder under `_api`/`_sync`** (for example `_api/_lib/helpers.ts`) **and test files next to routes are no longer treated as misnamed routes:** a new empty helper gets no guidance comment written into it, there is no false "ignored by route loading" warning, and editing a helper regenerates types and reloads the routes that use it.
|
|
22
|
+
- **The paired-sync rewrite writes the correct `PagePath`** when the project lives under a folder named `src`, uses a different source folder, or uses a custom sync marker.
|
|
23
|
+
- **A fully commented-out route or page file that arrives by rename, move, `git checkout` or `stash pop` is no longer overwritten with the starter template.** Only empty files, or files that still hold only the injector's guidance line, receive a template.
|
|
24
|
+
- **Route reloads after a dependency change honour a custom source folder and custom route markers.**
|
|
25
|
+
- **Writing the generated Zod schema file no longer triggers a second full type-map generation.**
|
|
26
|
+
- **Saving a watched file while the supervisor waits to restart a crashed server no longer starts two server processes.**
|
|
27
|
+
|
|
8
28
|
## [0.14.0] - 2026-10-16
|
|
9
29
|
|
|
10
30
|
### Fixed
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/devServerRestart.ts
|
|
2
|
+
var DEV_RESTART_MESSAGE_TYPE = "luckystack:dev-restart";
|
|
3
|
+
var isDevRestartMessage = (value) => typeof value === "object" && value !== null && "type" in value && value.type === DEV_RESTART_MESSAGE_TYPE && "reason" in value && typeof value.reason === "string";
|
|
4
|
+
var requestDevServerRestart = (reason) => {
|
|
5
|
+
if (process.env.LUCKYSTACK_CORE_SUPERVISED !== "true") return false;
|
|
6
|
+
if (typeof process.send !== "function" || !process.connected) return false;
|
|
7
|
+
const message = { type: DEV_RESTART_MESSAGE_TYPE, reason };
|
|
8
|
+
return process.send(message, void 0, void 0, (error) => {
|
|
9
|
+
if (error) console.log(`[HotReload] Could not ask the supervisor to restart: ${String(error)}`, "red");
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
isDevRestartMessage,
|
|
15
|
+
requestDevServerRestart
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=chunk-FWE6YJ3G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/devServerRestart.ts"],"sourcesContent":["//? Restart request from the dev server (child) to the supervisor (parent).\n//?\n//? Why a restart and not a reload: hot reload re-imports a route with a `?v=`\n//? query, but the ESM loader caches the route's own imports by their plain URL.\n//? After a helper the route imports changes, the re-imported route still links\n//? to the cached OLD helper, so only a fresh process runs the new code. No\n//? loader hook can carry the query down the import graph under both tsx and\n//? Bun, so the supervisor restarts the child, the same way it does for a\n//? `config.ts` edit.\n//?\n//? This module is bundled into the supervisor entry, so it must import nothing\n//? from `@luckystack/core` (see the env invariant in `supervisor.ts`).\n\nexport const DEV_RESTART_MESSAGE_TYPE = 'luckystack:dev-restart';\n\nexport interface DevRestartMessage {\n type: typeof DEV_RESTART_MESSAGE_TYPE;\n reason: string;\n}\n\nexport const isDevRestartMessage = (value: unknown): value is DevRestartMessage =>\n typeof value === 'object'\n && value !== null\n && 'type' in value\n && value.type === DEV_RESTART_MESSAGE_TYPE\n && 'reason' in value\n && typeof value.reason === 'string';\n\n/**\n * Ask the supervisor to restart this dev server. Returns false when nothing\n * can restart it (started without the supervisor, or no IPC channel), so the\n * caller can tell the developer to restart by hand.\n */\nexport const requestDevServerRestart = (reason: string): boolean => {\n if (process.env.LUCKYSTACK_CORE_SUPERVISED !== 'true') return false;\n if (typeof process.send !== 'function' || !process.connected) return false;\n\n const message: DevRestartMessage = { type: DEV_RESTART_MESSAGE_TYPE, reason };\n //? The callback keeps a failed send from surfacing as an unhandled 'error'.\n return process.send(message, undefined, undefined, (error: Error | null) => {\n if (error) console.log(`[HotReload] Could not ask the supervisor to restart: ${String(error)}`, 'red');\n });\n};\n"],"mappings":";AAaO,IAAM,2BAA2B;AAOjC,IAAM,sBAAsB,CAAC,UAClC,OAAO,UAAU,YACd,UAAU,QACV,UAAU,SACV,MAAM,SAAS,4BACf,YAAY,SACZ,OAAO,MAAM,WAAW;AAOtB,IAAM,0BAA0B,CAAC,WAA4B;AAClE,MAAI,QAAQ,IAAI,+BAA+B,OAAQ,QAAO;AAC9D,MAAI,OAAO,QAAQ,SAAS,cAAc,CAAC,QAAQ,UAAW,QAAO;AAErE,QAAM,UAA6B,EAAE,MAAM,0BAA0B,OAAO;AAE5E,SAAO,QAAQ,KAAK,SAAS,QAAW,QAAW,CAAC,UAAwB;AAC1E,QAAI,MAAO,SAAQ,IAAI,wDAAwD,OAAO,KAAK,CAAC,IAAI,KAAK;AAAA,EACvG,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const DEV_RESTART_MESSAGE_TYPE = "luckystack:dev-restart";
|
|
2
|
+
export interface DevRestartMessage {
|
|
3
|
+
type: typeof DEV_RESTART_MESSAGE_TYPE;
|
|
4
|
+
reason: string;
|
|
5
|
+
}
|
|
6
|
+
export declare const isDevRestartMessage: (value: unknown) => value is DevRestartMessage;
|
|
7
|
+
/**
|
|
8
|
+
* Ask the supervisor to restart this dev server. Returns false when nothing
|
|
9
|
+
* can restart it (started without the supervisor, or no IPC channel), so the
|
|
10
|
+
* caller can tell the developer to restart by hand.
|
|
11
|
+
*/
|
|
12
|
+
export declare const requestDevServerRestart: (reason: string) => boolean;
|
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) {
|
|
@@ -4524,7 +4507,7 @@ var shouldInjectTemplate = (filePath, options = {}) => {
|
|
|
4524
4507
|
return false;
|
|
4525
4508
|
}
|
|
4526
4509
|
if (isEmptyFile(filePath)) return true;
|
|
4527
|
-
if (options.isNewFile) return
|
|
4510
|
+
if (options.isNewFile) return isInjectedGuidanceOnlyFile(filePath);
|
|
4528
4511
|
return false;
|
|
4529
4512
|
};
|
|
4530
4513
|
var ensureImportedTypes = (content, clientFilePath) => {
|
|
@@ -4719,6 +4702,7 @@ var injectServerTemplateWithClientInput = async (serverFilePath, clientInputType
|
|
|
4719
4702
|
import fs10 from "fs";
|
|
4720
4703
|
import path13 from "path";
|
|
4721
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("\\", "/");
|
|
4722
4706
|
var SUPPORTED_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mts", ".cts"];
|
|
4723
4707
|
var normalizePath4 = (value) => path13.resolve(value).replaceAll("\\", "/");
|
|
4724
4708
|
var isSupportedScriptFile = (value) => {
|
|
@@ -4836,9 +4820,12 @@ var resolveImportToFile = (importerPath, specifier) => {
|
|
|
4836
4820
|
const relativeBase = path13.resolve(path13.dirname(importerPath), specifier);
|
|
4837
4821
|
return tryResolveWithExtensions(relativeBase);
|
|
4838
4822
|
}
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
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)));
|
|
4842
4829
|
}
|
|
4843
4830
|
if (specifier.startsWith("shared/")) {
|
|
4844
4831
|
return tryResolveWithExtensions(path13.join(getSharedDir(), specifier.slice(7)));
|
|
@@ -4846,7 +4833,10 @@ var resolveImportToFile = (importerPath, specifier) => {
|
|
|
4846
4833
|
return null;
|
|
4847
4834
|
};
|
|
4848
4835
|
var isRouteFile = (filePath) => {
|
|
4849
|
-
|
|
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);
|
|
4850
4840
|
};
|
|
4851
4841
|
var collectScopedFiles = () => {
|
|
4852
4842
|
const now = Date.now();
|
|
@@ -4939,26 +4929,36 @@ var runPrismaGenerate = async () => tryCatch2(
|
|
|
4939
4929
|
);
|
|
4940
4930
|
|
|
4941
4931
|
// src/hotReload.ts
|
|
4942
|
-
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";
|
|
4943
4941
|
var normalizeFsPath = (value) => path15.resolve(value).replaceAll("\\", "/");
|
|
4944
4942
|
var isGeneratedPath = (normalizedPath) => {
|
|
4945
|
-
|
|
4943
|
+
if (normalizedPath.includes(".generated.")) return true;
|
|
4944
|
+
return [getGeneratedSocketTypesPath7(), getGeneratedApiSchemasPath2(), getGeneratedApiDocsPath2()].some((generatedPath) => normalizeFsPath(generatedPath) === normalizedPath);
|
|
4946
4945
|
};
|
|
4947
4946
|
var createTypeMapQueue = () => {
|
|
4948
4947
|
const queue = { pending: false, running: false };
|
|
4949
4948
|
const run = () => {
|
|
4950
4949
|
queue.running = true;
|
|
4951
4950
|
queue.pending = false;
|
|
4952
|
-
const startedAt = Date.now();
|
|
4953
4951
|
setImmediate(() => {
|
|
4954
4952
|
void (async () => {
|
|
4953
|
+
const startedAt = Date.now();
|
|
4955
4954
|
const [err] = await tryCatch3(() => {
|
|
4956
4955
|
generateTypeMapFile({ quiet: true });
|
|
4957
4956
|
});
|
|
4957
|
+
const durationMs = Date.now() - startedAt;
|
|
4958
4958
|
if (err) {
|
|
4959
|
-
console.log(`[HotReload] type map regeneration failed: ${String(err)}`, "red");
|
|
4959
|
+
console.log(`[HotReload] type map regeneration failed after ${durationMs}ms: ${String(err)}`, "red");
|
|
4960
4960
|
} else {
|
|
4961
|
-
console.log(`[HotReload] type map
|
|
4961
|
+
console.log(`[HotReload] type map regenerated in ${durationMs}ms (the server answered no requests meanwhile)`, "green");
|
|
4962
4962
|
}
|
|
4963
4963
|
queue.running = false;
|
|
4964
4964
|
if (queue.pending) {
|
|
@@ -4980,7 +4980,12 @@ var createPendingChangeSets = () => ({
|
|
|
4980
4980
|
apiUpserts: /* @__PURE__ */ new Set(),
|
|
4981
4981
|
apiDeletes: /* @__PURE__ */ new Set(),
|
|
4982
4982
|
syncUpserts: /* @__PURE__ */ new Set(),
|
|
4983
|
-
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()
|
|
4984
4989
|
});
|
|
4985
4990
|
var buildPathSegments = () => {
|
|
4986
4991
|
const rules2 = getRoutingRules();
|
|
@@ -5001,10 +5006,11 @@ var buildPathSegments = () => {
|
|
|
5001
5006
|
};
|
|
5002
5007
|
};
|
|
5003
5008
|
var makeIsInServerFunctionsDir = (segments) => (normalizedPath) => segments.serverFunctionsSegments.some((seg) => normalizedPath.includes(seg));
|
|
5004
|
-
var
|
|
5009
|
+
var makeIsRouteFile = (segments) => (normalizedPath) => (normalizedPath.includes(segments.apiMarkerSlash) || normalizedPath.includes(segments.syncMarkerSlash)) && isRouteSurfaceFile(normalizedPath);
|
|
5010
|
+
var makeIsRouteDependencyFile = (segments, isRouteFile2) => (normalizedPath) => {
|
|
5005
5011
|
if (!normalizedPath.endsWith(".ts") && !normalizedPath.endsWith(".tsx")) return false;
|
|
5006
5012
|
if (!normalizedPath.includes(segments.srcSegment)) return false;
|
|
5007
|
-
if (
|
|
5013
|
+
if (isRouteFile2(normalizedPath)) return false;
|
|
5008
5014
|
if (isGeneratedPath(normalizedPath)) return false;
|
|
5009
5015
|
return true;
|
|
5010
5016
|
};
|
|
@@ -5013,10 +5019,10 @@ var makeIsSharedDependencyFile = (segments, isInServerFunctionsDir) => (normaliz
|
|
|
5013
5019
|
if (normalizedPath.includes(segments.sharedSegment)) return true;
|
|
5014
5020
|
return isInServerFunctionsDir(normalizedPath);
|
|
5015
5021
|
};
|
|
5016
|
-
var makeIsTypeMapRelevantFile = (segments) => (normalizedPath) => {
|
|
5022
|
+
var makeIsTypeMapRelevantFile = (segments, isRouteFile2) => (normalizedPath) => {
|
|
5017
5023
|
if (isGeneratedPath(normalizedPath)) return false;
|
|
5018
5024
|
if (!(normalizedPath.endsWith(".ts") || normalizedPath.endsWith(".tsx"))) return false;
|
|
5019
|
-
if (
|
|
5025
|
+
if (isRouteFile2(normalizedPath)) return false;
|
|
5020
5026
|
return normalizedPath.includes(segments.srcSegment) || normalizedPath.endsWith("/config.ts") || normalizedPath.includes(segments.sharedSegment);
|
|
5021
5027
|
};
|
|
5022
5028
|
var makeIsLocaleFile = (segments) => (normalizedPath) => normalizedPath.includes(segments.localesSegment) && normalizedPath.endsWith(".json");
|
|
@@ -5054,9 +5060,10 @@ var setupWatchers = () => {
|
|
|
5054
5060
|
if (!isDevMode) return;
|
|
5055
5061
|
const segments = buildPathSegments();
|
|
5056
5062
|
const isInServerFunctionsDir = makeIsInServerFunctionsDir(segments);
|
|
5057
|
-
const
|
|
5063
|
+
const isRouteFile2 = makeIsRouteFile(segments);
|
|
5064
|
+
const isRouteDependencyFile = makeIsRouteDependencyFile(segments, isRouteFile2);
|
|
5058
5065
|
const isSharedDependencyFile = makeIsSharedDependencyFile(segments, isInServerFunctionsDir);
|
|
5059
|
-
const isTypeMapRelevantFile = makeIsTypeMapRelevantFile(segments);
|
|
5066
|
+
const isTypeMapRelevantFile = makeIsTypeMapRelevantFile(segments, isRouteFile2);
|
|
5060
5067
|
const isLocaleFile = makeIsLocaleFile(segments);
|
|
5061
5068
|
const typeMap = createTypeMapQueue();
|
|
5062
5069
|
const pending = createPendingChangeSets();
|
|
@@ -5075,11 +5082,31 @@ var setupWatchers = () => {
|
|
|
5075
5082
|
console.log(`[HotReload] API removed: ${deletePath}`, "yellow");
|
|
5076
5083
|
}
|
|
5077
5084
|
for (const upsertPath of upsertPaths) {
|
|
5085
|
+
const startedAt = Date.now();
|
|
5078
5086
|
await upsertApiFromFile(upsertPath);
|
|
5079
|
-
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
|
+
);
|
|
5080
5106
|
}
|
|
5081
5107
|
};
|
|
5082
5108
|
const processPendingSyncChanges = async ({ regenerateTypeMap = false } = {}) => {
|
|
5109
|
+
await migrateClientsOfDeletedSyncServers();
|
|
5083
5110
|
const deletePaths = [...pending.syncDeletes];
|
|
5084
5111
|
const upsertPaths = [...pending.syncUpserts];
|
|
5085
5112
|
pending.syncDeletes.clear();
|
|
@@ -5093,16 +5120,28 @@ var setupWatchers = () => {
|
|
|
5093
5120
|
console.log(`[HotReload] Sync removed: ${deletePath}`, "yellow");
|
|
5094
5121
|
}
|
|
5095
5122
|
for (const upsertPath of upsertPaths) {
|
|
5123
|
+
const startedAt = Date.now();
|
|
5096
5124
|
await upsertSyncFromFile(upsertPath);
|
|
5097
|
-
console.log(`[HotReload] Sync reloaded: ${upsertPath}`, "green");
|
|
5125
|
+
console.log(`[HotReload] Sync reloaded in ${Date.now() - startedAt}ms: ${upsertPath}`, "green");
|
|
5098
5126
|
}
|
|
5099
5127
|
};
|
|
5100
5128
|
const enqueueAffectedRoutesFromDependency = (changedPath) => {
|
|
5101
5129
|
const affectedRoutes = findDependentRouteFiles(changedPath);
|
|
5102
5130
|
if (affectedRoutes.size === 0) {
|
|
5103
5131
|
console.log(`[HotReload] No API/Sync routes depend on: ${changedPath}`, "yellow");
|
|
5104
|
-
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;
|
|
5105
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
|
+
);
|
|
5106
5145
|
let queuedApiCount = 0;
|
|
5107
5146
|
let queuedSyncCount = 0;
|
|
5108
5147
|
for (const routePath of affectedRoutes) {
|
|
@@ -5130,6 +5169,7 @@ var setupWatchers = () => {
|
|
|
5130
5169
|
await processPendingSyncChanges();
|
|
5131
5170
|
});
|
|
5132
5171
|
}
|
|
5172
|
+
return false;
|
|
5133
5173
|
};
|
|
5134
5174
|
const handleAdd = async (filePath) => {
|
|
5135
5175
|
const normalizedPath = normalizeFsPath(filePath);
|
|
@@ -5169,7 +5209,8 @@ var setupWatchers = () => {
|
|
|
5169
5209
|
return;
|
|
5170
5210
|
}
|
|
5171
5211
|
}
|
|
5172
|
-
|
|
5212
|
+
const isRoute = isRouteFile2(normalizedPath);
|
|
5213
|
+
if (isRoute && normalizedPath.includes(segments.apiMarkerNoLead)) {
|
|
5173
5214
|
pending.apiDeletes.delete(normalizedPath);
|
|
5174
5215
|
pending.apiUpserts.add(normalizedPath);
|
|
5175
5216
|
scheduleReload("api", async () => {
|
|
@@ -5177,7 +5218,7 @@ var setupWatchers = () => {
|
|
|
5177
5218
|
});
|
|
5178
5219
|
return;
|
|
5179
5220
|
}
|
|
5180
|
-
if (normalizedPath.includes(segments.syncMarkerNoLead)) {
|
|
5221
|
+
if (isRoute && normalizedPath.includes(segments.syncMarkerNoLead)) {
|
|
5181
5222
|
pending.syncDeletes.delete(normalizedPath);
|
|
5182
5223
|
pending.syncUpserts.add(normalizedPath);
|
|
5183
5224
|
scheduleReload("sync", async () => {
|
|
@@ -5219,11 +5260,11 @@ var setupWatchers = () => {
|
|
|
5219
5260
|
return;
|
|
5220
5261
|
}
|
|
5221
5262
|
if (isRouteDependencyFile(normalizedPath)) {
|
|
5263
|
+
if (enqueueAffectedRoutesFromDependency(normalizedPath)) return;
|
|
5222
5264
|
scheduleReload("typemap", () => {
|
|
5223
5265
|
console.log(`[HotReload] Route dependency changed, scheduling type map regeneration`, "blue");
|
|
5224
5266
|
typeMap.request();
|
|
5225
5267
|
});
|
|
5226
|
-
enqueueAffectedRoutesFromDependency(normalizedPath);
|
|
5227
5268
|
return;
|
|
5228
5269
|
}
|
|
5229
5270
|
if (isTypeMapRelevantFile(normalizedPath)) {
|
|
@@ -5257,13 +5298,13 @@ var setupWatchers = () => {
|
|
|
5257
5298
|
const handleFunctionChange = (changedPath) => {
|
|
5258
5299
|
const normalizedPath = normalizeFsPath(changedPath);
|
|
5259
5300
|
invalidateGraphForFile(normalizedPath);
|
|
5301
|
+
if (isSharedDependencyFile(normalizedPath) && enqueueAffectedRoutesFromDependency(normalizedPath)) {
|
|
5302
|
+
return;
|
|
5303
|
+
}
|
|
5260
5304
|
scheduleReload("functions", async () => {
|
|
5261
5305
|
typeMap.request();
|
|
5262
5306
|
await initializeFunctions();
|
|
5263
5307
|
});
|
|
5264
|
-
if (isSharedDependencyFile(normalizedPath)) {
|
|
5265
|
-
enqueueAffectedRoutesFromDependency(normalizedPath);
|
|
5266
|
-
}
|
|
5267
5308
|
};
|
|
5268
5309
|
const handleDelete = (filePath) => {
|
|
5269
5310
|
const normalizedPath = normalizeFsPath(filePath);
|
|
@@ -5278,11 +5319,11 @@ var setupWatchers = () => {
|
|
|
5278
5319
|
return;
|
|
5279
5320
|
}
|
|
5280
5321
|
if (isRouteDependencyFile(normalizedPath)) {
|
|
5322
|
+
if (enqueueAffectedRoutesFromDependency(normalizedPath)) return;
|
|
5281
5323
|
scheduleReload("typemap", () => {
|
|
5282
5324
|
console.log(`[HotReload] Route dependency deleted, scheduling type map regeneration`, "blue");
|
|
5283
5325
|
typeMap.request();
|
|
5284
5326
|
});
|
|
5285
|
-
enqueueAffectedRoutesFromDependency(normalizedPath);
|
|
5286
5327
|
return;
|
|
5287
5328
|
}
|
|
5288
5329
|
if (isTypeMapRelevantFile(normalizedPath)) {
|
|
@@ -5308,19 +5349,10 @@ var setupWatchers = () => {
|
|
|
5308
5349
|
});
|
|
5309
5350
|
pending.syncUpserts.delete(normalizedPath);
|
|
5310
5351
|
pending.syncDeletes.add(normalizedPath);
|
|
5352
|
+
if (isSyncServerFile(normalizedPath)) {
|
|
5353
|
+
pending.deletedSyncServers.add(normalizedPath);
|
|
5354
|
+
}
|
|
5311
5355
|
scheduleReload("sync", async () => {
|
|
5312
|
-
if (isSyncServerFile(normalizedPath)) {
|
|
5313
|
-
const clientPath = getPairedSyncFile(normalizedPath);
|
|
5314
|
-
if (clientPath && fs12.existsSync(clientPath)) {
|
|
5315
|
-
const pagePath = extractSyncPagePath2(normalizedPath);
|
|
5316
|
-
const syncName = extractSyncName2(normalizedPath);
|
|
5317
|
-
const clientInputTypes = extractClientInputFromGeneratedTypes(pagePath, syncName);
|
|
5318
|
-
await updateClientFileForDeletedServer(
|
|
5319
|
-
clientPath,
|
|
5320
|
-
clientInputTypes ?? "{\n // Types were in _server.ts - please add them here\n }"
|
|
5321
|
-
);
|
|
5322
|
-
}
|
|
5323
|
-
}
|
|
5324
5356
|
await processPendingSyncChanges();
|
|
5325
5357
|
});
|
|
5326
5358
|
}
|