@beignet/cli 0.0.42 → 0.0.44
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 +24 -0
- package/README.md +21 -5
- package/dist/analysis/source-index.d.ts +1 -1
- package/dist/analysis/source-index.d.ts.map +1 -1
- package/dist/analysis/source-index.js +4 -2
- package/dist/analysis/source-index.js.map +1 -1
- package/dist/analysis/workspace.d.ts +3 -2
- package/dist/analysis/workspace.d.ts.map +1 -1
- package/dist/analysis/workspace.js +51 -39
- package/dist/analysis/workspace.js.map +1 -1
- package/dist/app-map.d.ts.map +1 -1
- package/dist/app-map.js +65 -4
- package/dist/app-map.js.map +1 -1
- package/dist/inspect.d.ts +5 -0
- package/dist/inspect.d.ts.map +1 -1
- package/dist/inspect.js +32 -135
- package/dist/inspect.js.map +1 -1
- package/dist/make/inbox.js +4 -4
- package/dist/make/payments.js +6 -6
- package/dist/make/tenancy.d.ts.map +1 -1
- package/dist/make/tenancy.js +12 -14
- package/dist/make/tenancy.js.map +1 -1
- package/dist/make.d.ts.map +1 -1
- package/dist/make.js +33 -23
- package/dist/make.js.map +1 -1
- package/dist/registry-edits.d.ts +7 -1
- package/dist/registry-edits.d.ts.map +1 -1
- package/dist/registry-edits.js +61 -43
- package/dist/registry-edits.js.map +1 -1
- package/dist/templates/agents.d.ts.map +1 -1
- package/dist/templates/agents.js +10 -3
- package/dist/templates/agents.js.map +1 -1
- package/dist/templates/base.d.ts.map +1 -1
- package/dist/templates/base.js +4 -2
- package/dist/templates/base.js.map +1 -1
- package/dist/templates/db/mysql.js +3 -3
- package/dist/templates/db/postgres.js +3 -3
- package/dist/templates/db/sqlite.js +3 -3
- package/dist/templates/server.js +4 -4
- package/dist/templates/server.js.map +1 -1
- package/dist/templates/todos.js +2 -2
- package/package.json +2 -2
- package/skills/app-structure/SKILL.md +9 -0
- package/src/analysis/source-index.ts +12 -3
- package/src/analysis/workspace.ts +94 -52
- package/src/app-map.ts +82 -4
- package/src/inspect.ts +40 -150
- package/src/make/inbox.ts +4 -4
- package/src/make/payments.ts +6 -6
- package/src/make/tenancy.ts +12 -14
- package/src/make.ts +36 -24
- package/src/registry-edits.ts +81 -39
- package/src/templates/agents.ts +10 -3
- package/src/templates/base.ts +4 -2
- package/src/templates/db/mysql.ts +3 -3
- package/src/templates/db/postgres.ts +3 -3
- package/src/templates/db/sqlite.ts +3 -3
- package/src/templates/server.ts +4 -4
- package/src/templates/todos.ts +2 -2
|
@@ -2,7 +2,6 @@ import { readdir, readFile, stat } from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import ts from "typescript";
|
|
4
4
|
import {
|
|
5
|
-
directoryPath,
|
|
6
5
|
loadBeignetConfig,
|
|
7
6
|
normalizePath,
|
|
8
7
|
type ResolvedBeignetConfig,
|
|
@@ -22,7 +21,7 @@ export type AnalysisWorkspace = {
|
|
|
22
21
|
files: string[];
|
|
23
22
|
fileSet: Set<string>;
|
|
24
23
|
config: ResolvedBeignetConfig;
|
|
25
|
-
|
|
24
|
+
compilerOptions: ts.CompilerOptions;
|
|
26
25
|
readSource(file: string): Promise<string>;
|
|
27
26
|
readSourceFile(file: string): Promise<ts.SourceFile>;
|
|
28
27
|
};
|
|
@@ -35,7 +34,7 @@ export async function createAnalysisWorkspace(
|
|
|
35
34
|
const files = await listProjectFiles(targetDir);
|
|
36
35
|
const fileSet = new Set(files);
|
|
37
36
|
const config = await loadBeignetConfig(targetDir, files);
|
|
38
|
-
const
|
|
37
|
+
const compilerOptions = resolveCompilerOptions(targetDir);
|
|
39
38
|
const sources = new Map<string, string>();
|
|
40
39
|
const sourceFiles = new Map<string, ts.SourceFile>();
|
|
41
40
|
|
|
@@ -53,7 +52,7 @@ export async function createAnalysisWorkspace(
|
|
|
53
52
|
files,
|
|
54
53
|
fileSet,
|
|
55
54
|
config,
|
|
56
|
-
|
|
55
|
+
compilerOptions,
|
|
57
56
|
readSource,
|
|
58
57
|
async readSourceFile(file) {
|
|
59
58
|
const cached = sourceFiles.get(file);
|
|
@@ -110,66 +109,109 @@ export async function listProjectFiles(targetDir: string): Promise<string[]> {
|
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
export function resolveLocalSourceFile(
|
|
113
|
-
workspace: Pick<
|
|
112
|
+
workspace: Pick<
|
|
113
|
+
AnalysisWorkspace,
|
|
114
|
+
"compilerOptions" | "fileSet" | "targetDir"
|
|
115
|
+
>,
|
|
114
116
|
importerFile: string,
|
|
115
117
|
importPath: string,
|
|
116
118
|
): string | undefined {
|
|
117
|
-
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
const resolved = resolveModule(workspace, importerFile, importPath);
|
|
120
|
+
if (!resolved) return undefined;
|
|
121
|
+
|
|
122
|
+
const file = normalizePath(
|
|
123
|
+
path.relative(workspace.targetDir, resolved.resolvedFileName),
|
|
124
|
+
);
|
|
125
|
+
if (file === ".." || file.startsWith("../")) return undefined;
|
|
126
|
+
return workspace.fileSet.has(file) ? file : undefined;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function isLocalModuleSpecifier(
|
|
130
|
+
workspace: Pick<
|
|
131
|
+
AnalysisWorkspace,
|
|
132
|
+
"compilerOptions" | "fileSet" | "targetDir"
|
|
133
|
+
>,
|
|
134
|
+
importerFile: string,
|
|
135
|
+
importPath: string,
|
|
136
|
+
): boolean {
|
|
137
|
+
const extension = path.posix.extname(importPath);
|
|
138
|
+
if (
|
|
139
|
+
extension &&
|
|
140
|
+
![".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"].includes(
|
|
141
|
+
extension,
|
|
142
|
+
)
|
|
143
|
+
) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
if (importPath.startsWith(".")) return true;
|
|
147
|
+
|
|
148
|
+
const resolved = resolveModule(workspace, importerFile, importPath);
|
|
149
|
+
if (resolved) {
|
|
150
|
+
const file = normalizePath(
|
|
151
|
+
path.relative(workspace.targetDir, resolved.resolvedFileName),
|
|
122
152
|
);
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
path.join(path.dirname(importerFile), importPath),
|
|
153
|
+
return (
|
|
154
|
+
file !== ".." && !file.startsWith("../") && workspace.fileSet.has(file)
|
|
126
155
|
);
|
|
127
|
-
} else {
|
|
128
|
-
return undefined;
|
|
129
156
|
}
|
|
130
157
|
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
158
|
+
const pathPatterns = Object.keys(workspace.compilerOptions.paths ?? {});
|
|
159
|
+
if (
|
|
160
|
+
pathPatterns.some(
|
|
161
|
+
(pattern) =>
|
|
162
|
+
// A catch-all also matches every bare package name. Local matches for
|
|
163
|
+
// it resolve above or have an app-owned baseUrl prefix below.
|
|
164
|
+
pattern !== "*" && modulePatternMatches(pattern, importPath),
|
|
165
|
+
)
|
|
166
|
+
) {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const baseUrl = workspace.compilerOptions.baseUrl;
|
|
171
|
+
if (!baseUrl) return false;
|
|
172
|
+
const firstSegment = importPath.split("/")[0];
|
|
173
|
+
const prefix = normalizePath(
|
|
174
|
+
path.relative(workspace.targetDir, path.resolve(baseUrl, firstSegment)),
|
|
175
|
+
);
|
|
176
|
+
for (const file of workspace.fileSet) {
|
|
177
|
+
if (file === prefix || file.startsWith(`${prefix}/`)) return true;
|
|
178
|
+
}
|
|
179
|
+
return false;
|
|
145
180
|
}
|
|
146
181
|
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
182
|
+
function resolveModule(
|
|
183
|
+
workspace: Pick<AnalysisWorkspace, "compilerOptions" | "targetDir">,
|
|
184
|
+
importerFile: string,
|
|
185
|
+
importPath: string,
|
|
186
|
+
): ts.ResolvedModuleFull | undefined {
|
|
187
|
+
return ts.resolveModuleName(
|
|
188
|
+
importPath,
|
|
189
|
+
path.join(workspace.targetDir, importerFile),
|
|
190
|
+
workspace.compilerOptions,
|
|
191
|
+
ts.sys,
|
|
192
|
+
).resolvedModule;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function modulePatternMatches(pattern: string, importPath: string): boolean {
|
|
196
|
+
const wildcard = pattern.indexOf("*");
|
|
197
|
+
if (wildcard === -1) return pattern === importPath;
|
|
198
|
+
return (
|
|
199
|
+
importPath.startsWith(pattern.slice(0, wildcard)) &&
|
|
200
|
+
importPath.endsWith(pattern.slice(wildcard + 1))
|
|
155
201
|
);
|
|
156
|
-
|
|
157
|
-
if (!aliasTarget) return "";
|
|
202
|
+
}
|
|
158
203
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
204
|
+
function resolveCompilerOptions(targetDir: string): ts.CompilerOptions {
|
|
205
|
+
return (
|
|
206
|
+
ts.getParsedCommandLineOfConfigFile(
|
|
207
|
+
path.join(targetDir, "tsconfig.json"),
|
|
208
|
+
{},
|
|
209
|
+
{
|
|
210
|
+
...ts.sys,
|
|
211
|
+
onUnRecoverableConfigFileDiagnostic: () => {},
|
|
212
|
+
},
|
|
213
|
+
)?.options ?? {}
|
|
163
214
|
);
|
|
164
|
-
if (
|
|
165
|
-
relativeTarget === "" ||
|
|
166
|
-
relativeTarget === "." ||
|
|
167
|
-
relativeTarget === ".." ||
|
|
168
|
-
relativeTarget.startsWith("../")
|
|
169
|
-
) {
|
|
170
|
-
return "";
|
|
171
|
-
}
|
|
172
|
-
return directoryPath(relativeTarget);
|
|
173
215
|
}
|
|
174
216
|
|
|
175
217
|
function scriptKind(file: string): ts.ScriptKind {
|
package/src/app-map.ts
CHANGED
|
@@ -276,6 +276,13 @@ export async function mapApp(
|
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
await addUnresolvedContractDeclarations({
|
|
280
|
+
workspace,
|
|
281
|
+
sourceIndex,
|
|
282
|
+
contractIds,
|
|
283
|
+
unresolved,
|
|
284
|
+
});
|
|
285
|
+
|
|
279
286
|
const routeIds = new Map<string, string>();
|
|
280
287
|
for (const route of inspection.routes) {
|
|
281
288
|
const contractId = contractIds.get(symbolKey(route.file, route.exportName));
|
|
@@ -647,6 +654,7 @@ export async function mapApp(
|
|
|
647
654
|
});
|
|
648
655
|
|
|
649
656
|
await addTables({ workspace, sourceIndex, addNode });
|
|
657
|
+
await addUnresolvedLocalImports({ workspace, unresolved });
|
|
650
658
|
await addFeatureDependencies({
|
|
651
659
|
workspace,
|
|
652
660
|
featuresPath,
|
|
@@ -894,8 +902,8 @@ async function addRouteGroups(args: {
|
|
|
894
902
|
const missing = args.diagnostics.some(
|
|
895
903
|
(diagnostic) =>
|
|
896
904
|
diagnostic.code === "BEIGNET_ROUTE_GROUP_UNREGISTERED" &&
|
|
897
|
-
diagnostic.
|
|
898
|
-
diagnostic.
|
|
905
|
+
diagnostic.subject?.file === file &&
|
|
906
|
+
diagnostic.subject.exportName === exportName,
|
|
899
907
|
);
|
|
900
908
|
args.addNode({
|
|
901
909
|
id,
|
|
@@ -1221,6 +1229,7 @@ async function addFeatureDependencies(args: {
|
|
|
1221
1229
|
const from = featureForFile(file, args.featuresPath);
|
|
1222
1230
|
if (!from || !args.featureNames.has(from)) continue;
|
|
1223
1231
|
for (const reference of await localImportReferences(args.workspace, file)) {
|
|
1232
|
+
if (!reference.resolvedFile) continue;
|
|
1224
1233
|
const to = featureForFile(reference.resolvedFile, args.featuresPath);
|
|
1225
1234
|
if (!to || to === from || !args.featureNames.has(to)) continue;
|
|
1226
1235
|
const key = `${from}->${to}`;
|
|
@@ -1261,6 +1270,75 @@ async function addFeatureDependencies(args: {
|
|
|
1261
1270
|
}
|
|
1262
1271
|
}
|
|
1263
1272
|
|
|
1273
|
+
async function addUnresolvedLocalImports(args: {
|
|
1274
|
+
workspace: AnalysisWorkspace;
|
|
1275
|
+
unresolved: AppMapUnresolvedReference[];
|
|
1276
|
+
}): Promise<void> {
|
|
1277
|
+
for (const file of args.workspace.files.filter(isTypeScriptSource)) {
|
|
1278
|
+
for (const reference of await localImportReferences(args.workspace, file)) {
|
|
1279
|
+
if (reference.resolvedFile) continue;
|
|
1280
|
+
args.unresolved.push({
|
|
1281
|
+
code: "local_import_unresolved",
|
|
1282
|
+
message: `Could not resolve local module ${JSON.stringify(reference.importPath)} imported by ${file}.`,
|
|
1283
|
+
source: {
|
|
1284
|
+
file,
|
|
1285
|
+
line: reference.line,
|
|
1286
|
+
column: reference.column,
|
|
1287
|
+
},
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
async function addUnresolvedContractDeclarations(args: {
|
|
1294
|
+
workspace: AnalysisWorkspace;
|
|
1295
|
+
sourceIndex: ReturnType<typeof createSourceIndex>;
|
|
1296
|
+
contractIds: Map<string, string>;
|
|
1297
|
+
unresolved: AppMapUnresolvedReference[];
|
|
1298
|
+
}): Promise<void> {
|
|
1299
|
+
for (const file of appMapContractSourceFiles(args.workspace)) {
|
|
1300
|
+
const sourceFile = await args.workspace.readSourceFile(file);
|
|
1301
|
+
for (const { exportName, declaration } of exportedVariableDeclarations(
|
|
1302
|
+
sourceFile,
|
|
1303
|
+
)) {
|
|
1304
|
+
if (args.contractIds.has(symbolKey(file, exportName))) continue;
|
|
1305
|
+
const call = declaration.initializer
|
|
1306
|
+
? findCall(declaration.initializer, new Set(["defineContract"]))
|
|
1307
|
+
: undefined;
|
|
1308
|
+
if (!call) continue;
|
|
1309
|
+
|
|
1310
|
+
args.unresolved.push({
|
|
1311
|
+
code: "contract_declaration_unresolved",
|
|
1312
|
+
message: `Could not resolve the HTTP method and path for contract ${exportName}.`,
|
|
1313
|
+
source: await args.sourceIndex.sourceLocation(
|
|
1314
|
+
file,
|
|
1315
|
+
declaration,
|
|
1316
|
+
exportName,
|
|
1317
|
+
),
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
function appMapContractSourceFiles(workspace: AnalysisWorkspace): string[] {
|
|
1324
|
+
const contractsPath = directoryPath(workspace.config.paths.contracts);
|
|
1325
|
+
const featureOwned =
|
|
1326
|
+
contractsPath === directoryPath(workspace.config.paths.features);
|
|
1327
|
+
|
|
1328
|
+
return workspace.files.filter((file) => {
|
|
1329
|
+
if (!file.endsWith(".ts") || file.endsWith(".test.ts")) return false;
|
|
1330
|
+
if (featureOwned) {
|
|
1331
|
+
const prefix = `${contractsPath}/`;
|
|
1332
|
+
if (!file.startsWith(prefix)) return false;
|
|
1333
|
+
const parts = file.slice(prefix.length).split("/");
|
|
1334
|
+
return parts.length === 2 && parts[1] === "contracts.ts";
|
|
1335
|
+
}
|
|
1336
|
+
return (
|
|
1337
|
+
file === `${contractsPath}.ts` || file.startsWith(`${contractsPath}/`)
|
|
1338
|
+
);
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1264
1342
|
async function registryRecord(args: {
|
|
1265
1343
|
workspace: AnalysisWorkspace;
|
|
1266
1344
|
sourceIndex: ReturnType<typeof createSourceIndex>;
|
|
@@ -1488,8 +1566,8 @@ function definitionStatus(
|
|
|
1488
1566
|
return diagnostics.some(
|
|
1489
1567
|
(diagnostic) =>
|
|
1490
1568
|
relevant.includes(diagnostic.code) &&
|
|
1491
|
-
diagnostic.
|
|
1492
|
-
diagnostic.
|
|
1569
|
+
diagnostic.subject?.file === file &&
|
|
1570
|
+
diagnostic.subject.exportName === exportName,
|
|
1493
1571
|
)
|
|
1494
1572
|
? "missing"
|
|
1495
1573
|
: "registered";
|
package/src/inspect.ts
CHANGED
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
appendToNamedArray,
|
|
60
60
|
appendToOutboxRegistryArray,
|
|
61
61
|
arrayInitializerInfo,
|
|
62
|
+
codeCharacterIndexes,
|
|
62
63
|
identifiersFromArrayExpression,
|
|
63
64
|
insertAfterImports,
|
|
64
65
|
matchingDelimiterIndex,
|
|
@@ -130,6 +131,11 @@ export type InspectDiagnostic = {
|
|
|
130
131
|
message: string;
|
|
131
132
|
file?: string;
|
|
132
133
|
contract?: string;
|
|
134
|
+
/** Stable declaration identity for diagnostics about a named app concept. */
|
|
135
|
+
subject?: {
|
|
136
|
+
file: string;
|
|
137
|
+
exportName: string;
|
|
138
|
+
};
|
|
133
139
|
};
|
|
134
140
|
|
|
135
141
|
export type { InspectFix } from "./doctor-fixes.js";
|
|
@@ -1065,73 +1071,19 @@ function balancedObjectSource(
|
|
|
1065
1071
|
startIndex: number,
|
|
1066
1072
|
): string | undefined {
|
|
1067
1073
|
if (source[startIndex] !== "{") return undefined;
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
let quote: '"' | "'" | "`" | undefined;
|
|
1071
|
-
let escaped = false;
|
|
1072
|
-
|
|
1073
|
-
for (let index = startIndex; index < source.length; index += 1) {
|
|
1074
|
-
const char = source[index];
|
|
1075
|
-
|
|
1076
|
-
if (quote) {
|
|
1077
|
-
if (escaped) {
|
|
1078
|
-
escaped = false;
|
|
1079
|
-
continue;
|
|
1080
|
-
}
|
|
1081
|
-
if (char === "\\") {
|
|
1082
|
-
escaped = true;
|
|
1083
|
-
continue;
|
|
1084
|
-
}
|
|
1085
|
-
if (char === quote) quote = undefined;
|
|
1086
|
-
continue;
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
1090
|
-
quote = char;
|
|
1091
|
-
continue;
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
if (char === "{") {
|
|
1095
|
-
depth += 1;
|
|
1096
|
-
continue;
|
|
1097
|
-
}
|
|
1098
|
-
|
|
1099
|
-
if (char === "}") {
|
|
1100
|
-
depth -= 1;
|
|
1101
|
-
if (depth === 0) return source.slice(startIndex, index + 1);
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
return undefined;
|
|
1074
|
+
const endIndex = matchingDelimiterIndex(source, startIndex, "{", "}");
|
|
1075
|
+
return endIndex === -1 ? undefined : source.slice(startIndex, endIndex + 1);
|
|
1106
1076
|
}
|
|
1107
1077
|
|
|
1108
1078
|
function topLevelObjectKeys(body: string): string[] {
|
|
1109
1079
|
const keys: string[] = [];
|
|
1110
1080
|
let depth = 0;
|
|
1111
|
-
let
|
|
1112
|
-
let escaped = false;
|
|
1081
|
+
let skipUntil = 0;
|
|
1113
1082
|
|
|
1114
|
-
for (
|
|
1083
|
+
for (const index of codeCharacterIndexes(body)) {
|
|
1084
|
+
if (index < skipUntil) continue;
|
|
1115
1085
|
const char = body[index];
|
|
1116
1086
|
|
|
1117
|
-
if (quote) {
|
|
1118
|
-
if (escaped) {
|
|
1119
|
-
escaped = false;
|
|
1120
|
-
continue;
|
|
1121
|
-
}
|
|
1122
|
-
if (char === "\\") {
|
|
1123
|
-
escaped = true;
|
|
1124
|
-
continue;
|
|
1125
|
-
}
|
|
1126
|
-
if (char === quote) quote = undefined;
|
|
1127
|
-
continue;
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
1131
|
-
quote = char;
|
|
1132
|
-
continue;
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
1087
|
if (char === "{" || char === "[" || char === "(") {
|
|
1136
1088
|
depth += 1;
|
|
1137
1089
|
continue;
|
|
@@ -1150,8 +1102,7 @@ function topLevelObjectKeys(body: string): string[] {
|
|
|
1150
1102
|
const name = identifier[0];
|
|
1151
1103
|
const next = body.slice(index + name.length).match(/^\s*:/);
|
|
1152
1104
|
if (next) keys.push(name);
|
|
1153
|
-
|
|
1154
|
-
index += name.length - 1;
|
|
1105
|
+
skipUntil = index + name.length;
|
|
1155
1106
|
}
|
|
1156
1107
|
|
|
1157
1108
|
return keys;
|
|
@@ -4018,6 +3969,7 @@ async function inspectWorkflowRegistrationDrift(
|
|
|
4018
3969
|
severity: "error",
|
|
4019
3970
|
code,
|
|
4020
3971
|
file: centralExists ? centralFile : registry.indexFile,
|
|
3972
|
+
subject: workflowArtifactSubject(registry, member),
|
|
4021
3973
|
message: centralExists
|
|
4022
3974
|
? `${workflowArtifactOrigin(registry, member)}, but it is not registered in ${registrationTarget} in ${centralFile}, so the ${noun} never runs. Import ${registry.registryName} and spread it into the ${kind} list.`
|
|
4023
3975
|
: `${workflowArtifactOrigin(registry, member)}, but ${centralFile} does not exist, so the ${noun} never runs. Register ${registry.registryName} in ${centralFile} (or run \`${makeCommand}\` to create it).`,
|
|
@@ -4033,6 +3985,7 @@ async function inspectWorkflowRegistrationDrift(
|
|
|
4033
3985
|
severity: "warning",
|
|
4034
3986
|
code: "BEIGNET_OUTBOX_EVENT_UNREGISTERED",
|
|
4035
3987
|
file: config.paths.outbox,
|
|
3988
|
+
subject: workflowArtifactSubject(registry, member),
|
|
4036
3989
|
message: `${workflowArtifactOrigin(registry, member)} and listeners react to it, but it is not registered in the events list of defineOutboxRegistry({...}) in ${config.paths.outbox}, so outbox drain cannot deliver it. Import ${registry.registryName} and spread it into the events list.`,
|
|
4037
3990
|
});
|
|
4038
3991
|
}
|
|
@@ -4044,6 +3997,7 @@ async function inspectWorkflowRegistrationDrift(
|
|
|
4044
3997
|
severity: "warning",
|
|
4045
3998
|
code: "BEIGNET_OUTBOX_JOB_UNREGISTERED",
|
|
4046
3999
|
file: config.paths.outbox,
|
|
4000
|
+
subject: workflowArtifactSubject(registry, member),
|
|
4047
4001
|
message: `${workflowArtifactOrigin(registry, member)}, but it is not registered in the jobs list of defineOutboxRegistry({...}) in ${config.paths.outbox}, so outbox drain cannot deliver it. Import ${registry.registryName} and spread it into the jobs list.`,
|
|
4048
4002
|
});
|
|
4049
4003
|
}
|
|
@@ -4065,6 +4019,7 @@ async function inspectWorkflowRegistrationDrift(
|
|
|
4065
4019
|
drift.listeners.wiringFile ??
|
|
4066
4020
|
drift.listeners.eventBusFile ??
|
|
4067
4021
|
registry.indexFile,
|
|
4022
|
+
subject: workflowArtifactSubject(registry, member),
|
|
4068
4023
|
message: `${workflowArtifactOrigin(registry, member)}, but no registerListeners(...) call references it, so the listener never receives events. Register ${registry.registryName} with registerListeners(...) in ${listenerTarget}.`,
|
|
4069
4024
|
});
|
|
4070
4025
|
}
|
|
@@ -4170,6 +4125,16 @@ function workflowArtifactOrigin(
|
|
|
4170
4125
|
return `${memberFile} declares ${member} (exported through ${registry.registryName} in ${registry.indexFile})`;
|
|
4171
4126
|
}
|
|
4172
4127
|
|
|
4128
|
+
function workflowArtifactSubject(
|
|
4129
|
+
registry: FeatureWorkflowRegistry,
|
|
4130
|
+
member: string,
|
|
4131
|
+
): NonNullable<InspectDiagnostic["subject"]> {
|
|
4132
|
+
return {
|
|
4133
|
+
file: registry.memberFiles.get(member) ?? registry.indexFile,
|
|
4134
|
+
exportName: member,
|
|
4135
|
+
};
|
|
4136
|
+
}
|
|
4137
|
+
|
|
4173
4138
|
async function workflowRegistrationDrift(
|
|
4174
4139
|
targetDir: string,
|
|
4175
4140
|
files: string[],
|
|
@@ -5651,26 +5616,9 @@ function splitTopLevelArguments(source: string): string[] {
|
|
|
5651
5616
|
const args: string[] = [];
|
|
5652
5617
|
let start = 0;
|
|
5653
5618
|
let depth = 0;
|
|
5654
|
-
let inString: string | undefined;
|
|
5655
|
-
let escaped = false;
|
|
5656
5619
|
|
|
5657
|
-
for (
|
|
5620
|
+
for (const index of codeCharacterIndexes(source)) {
|
|
5658
5621
|
const char = source[index];
|
|
5659
|
-
if (inString) {
|
|
5660
|
-
if (escaped) {
|
|
5661
|
-
escaped = false;
|
|
5662
|
-
} else if (char === "\\") {
|
|
5663
|
-
escaped = true;
|
|
5664
|
-
} else if (char === inString) {
|
|
5665
|
-
inString = undefined;
|
|
5666
|
-
}
|
|
5667
|
-
continue;
|
|
5668
|
-
}
|
|
5669
|
-
|
|
5670
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
5671
|
-
inString = char;
|
|
5672
|
-
continue;
|
|
5673
|
-
}
|
|
5674
5622
|
if (char === "(" || char === "{" || char === "[") {
|
|
5675
5623
|
depth += 1;
|
|
5676
5624
|
continue;
|
|
@@ -6455,6 +6403,8 @@ function dedupeDiagnostics(
|
|
|
6455
6403
|
diagnostic.code,
|
|
6456
6404
|
diagnostic.file ?? "",
|
|
6457
6405
|
diagnostic.contract ?? "",
|
|
6406
|
+
diagnostic.subject?.file ?? "",
|
|
6407
|
+
diagnostic.subject?.exportName ?? "",
|
|
6458
6408
|
diagnostic.message,
|
|
6459
6409
|
].join(":");
|
|
6460
6410
|
if (seen.has(key)) continue;
|
|
@@ -6644,6 +6594,10 @@ async function inspectFeatureRouteRegistration(
|
|
|
6644
6594
|
code: "BEIGNET_ROUTE_GROUP_UNREGISTERED",
|
|
6645
6595
|
file: config.paths.server,
|
|
6646
6596
|
contract: routeGroupContract.exportName,
|
|
6597
|
+
subject: {
|
|
6598
|
+
file: routeGroup.file,
|
|
6599
|
+
exportName: routeGroup.name,
|
|
6600
|
+
},
|
|
6647
6601
|
message: contract
|
|
6648
6602
|
? `${routeGroup.file} declares ${routeGroup.name} for ${contract.exportName} (${contract.method} ${contract.path}), but ${routeGroup.name} is not registered in defineRoutes([...]) in ${config.paths.server}. Import ${routeGroup.name} and add it to the central route list.`
|
|
6649
6603
|
: `${routeGroup.file} declares ${routeGroup.name} for ${routeGroupContract.exportName}, but ${routeGroup.name} is not registered in defineRoutes([...]) in ${config.paths.server}. Import ${routeGroup.name} and add it to the central route list.`,
|
|
@@ -6765,44 +6719,8 @@ function balancedArraySource(
|
|
|
6765
6719
|
startIndex: number,
|
|
6766
6720
|
): string | undefined {
|
|
6767
6721
|
if (source[startIndex] !== "[") return undefined;
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
let quote: '"' | "'" | "`" | undefined;
|
|
6771
|
-
let escaped = false;
|
|
6772
|
-
|
|
6773
|
-
for (let index = startIndex; index < source.length; index += 1) {
|
|
6774
|
-
const char = source[index];
|
|
6775
|
-
|
|
6776
|
-
if (quote) {
|
|
6777
|
-
if (escaped) {
|
|
6778
|
-
escaped = false;
|
|
6779
|
-
continue;
|
|
6780
|
-
}
|
|
6781
|
-
if (char === "\\") {
|
|
6782
|
-
escaped = true;
|
|
6783
|
-
continue;
|
|
6784
|
-
}
|
|
6785
|
-
if (char === quote) quote = undefined;
|
|
6786
|
-
continue;
|
|
6787
|
-
}
|
|
6788
|
-
|
|
6789
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
6790
|
-
quote = char;
|
|
6791
|
-
continue;
|
|
6792
|
-
}
|
|
6793
|
-
|
|
6794
|
-
if (char === "[") {
|
|
6795
|
-
depth += 1;
|
|
6796
|
-
continue;
|
|
6797
|
-
}
|
|
6798
|
-
|
|
6799
|
-
if (char === "]") {
|
|
6800
|
-
depth -= 1;
|
|
6801
|
-
if (depth === 0) return source.slice(startIndex, index + 1);
|
|
6802
|
-
}
|
|
6803
|
-
}
|
|
6804
|
-
|
|
6805
|
-
return undefined;
|
|
6722
|
+
const endIndex = matchingDelimiterIndex(source, startIndex, "[", "]");
|
|
6723
|
+
return endIndex === -1 ? undefined : source.slice(startIndex, endIndex + 1);
|
|
6806
6724
|
}
|
|
6807
6725
|
|
|
6808
6726
|
function routeGroupContractRef(
|
|
@@ -6832,21 +6750,10 @@ function routeGroupContractRef(
|
|
|
6832
6750
|
}
|
|
6833
6751
|
|
|
6834
6752
|
function registeredRouteGroups(source: string): Set<string> {
|
|
6835
|
-
const
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
const defineRoutesEnd = defineRoutesSource.indexOf("]),");
|
|
6840
|
-
const searchSource =
|
|
6841
|
-
defineRoutesEnd === -1
|
|
6842
|
-
? defineRoutesSource
|
|
6843
|
-
: defineRoutesSource.slice(0, defineRoutesEnd);
|
|
6844
|
-
|
|
6845
|
-
return new Set(
|
|
6846
|
-
[...searchSource.matchAll(/\b([A-Za-z_$][\w$]*)\b/g)].map(
|
|
6847
|
-
(match) => match[1],
|
|
6848
|
-
),
|
|
6849
|
-
);
|
|
6753
|
+
const routes = firstDefineRoutesArgInfo(source);
|
|
6754
|
+
return routes?.text.startsWith("[")
|
|
6755
|
+
? identifiersFromArrayExpression(routes.text)
|
|
6756
|
+
: new Set();
|
|
6850
6757
|
}
|
|
6851
6758
|
|
|
6852
6759
|
async function registeredRouteGroupsForServer(
|
|
@@ -7699,26 +7606,9 @@ function firstCallArgInfo(
|
|
|
7699
7606
|
argStart: number,
|
|
7700
7607
|
): { text: string; start: number; end: number } | undefined {
|
|
7701
7608
|
let depth = 0;
|
|
7702
|
-
let inString: string | undefined;
|
|
7703
|
-
let escaped = false;
|
|
7704
7609
|
|
|
7705
|
-
for (
|
|
7610
|
+
for (const index of codeCharacterIndexes(source, argStart)) {
|
|
7706
7611
|
const char = source[index];
|
|
7707
|
-
if (inString) {
|
|
7708
|
-
if (escaped) {
|
|
7709
|
-
escaped = false;
|
|
7710
|
-
} else if (char === "\\") {
|
|
7711
|
-
escaped = true;
|
|
7712
|
-
} else if (char === inString) {
|
|
7713
|
-
inString = undefined;
|
|
7714
|
-
}
|
|
7715
|
-
continue;
|
|
7716
|
-
}
|
|
7717
|
-
|
|
7718
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
7719
|
-
inString = char;
|
|
7720
|
-
continue;
|
|
7721
|
-
}
|
|
7722
7612
|
|
|
7723
7613
|
if (char === "[" || char === "(" || char === "{") {
|
|
7724
7614
|
depth++;
|
package/src/make/inbox.ts
CHANGED
|
@@ -1437,17 +1437,17 @@ export const inboxNotifications = ${dialect.tableFunction}(
|
|
|
1437
1437
|
\t\treadAt: ${column("read_at")},
|
|
1438
1438
|
\t\tcreatedAt: ${column("created_at")}.notNull(),
|
|
1439
1439
|
\t},
|
|
1440
|
-
\t(table) =>
|
|
1441
|
-
\t\
|
|
1440
|
+
\t(table) => [
|
|
1441
|
+
\t\tindex("inbox_notifications_unread_idx").on(
|
|
1442
1442
|
\t\t\ttable.userId,
|
|
1443
1443
|
\t\t\ttable.readAt,
|
|
1444
1444
|
\t\t),
|
|
1445
|
-
\t\
|
|
1445
|
+
\t\tindex("inbox_notifications_cursor_idx").on(
|
|
1446
1446
|
\t\t\ttable.userId,
|
|
1447
1447
|
\t\t\ttable.createdAt,
|
|
1448
1448
|
\t\t\ttable.id,
|
|
1449
1449
|
\t\t),
|
|
1450
|
-
\t
|
|
1450
|
+
\t],
|
|
1451
1451
|
);
|
|
1452
1452
|
`;
|
|
1453
1453
|
}
|
package/src/make/payments.ts
CHANGED
|
@@ -680,11 +680,11 @@ export const createCheckoutSessionInputSchema = z.object({
|
|
|
680
680
|
|
|
681
681
|
export const createCheckoutSessionOutputSchema = z.object({
|
|
682
682
|
\tsessionId: z.string(),
|
|
683
|
-
\turl: z.
|
|
683
|
+
\turl: z.url(),
|
|
684
684
|
});
|
|
685
685
|
|
|
686
686
|
export const createBillingPortalSessionOutputSchema = z.object({
|
|
687
|
-
\turl: z.
|
|
687
|
+
\turl: z.url(),
|
|
688
688
|
});
|
|
689
689
|
|
|
690
690
|
export const billingStatusOutputSchema = z.object({
|
|
@@ -1800,14 +1800,14 @@ export const billingAccounts = ${dialect.tableFunction}(
|
|
|
1800
1800
|
\t\tlastEventId: ${idColumn("last_event_id")},
|
|
1801
1801
|
\t\tupdatedAt: ${idColumn("updated_at")}.notNull(),
|
|
1802
1802
|
\t},
|
|
1803
|
-
\t(table) =>
|
|
1804
|
-
\t\
|
|
1803
|
+
\t(table) => [
|
|
1804
|
+
\t\tuniqueIndex(
|
|
1805
1805
|
\t\t\t"billing_accounts_provider_customer_unique",
|
|
1806
1806
|
\t\t).on(table.provider, table.customerId),
|
|
1807
|
-
\t\
|
|
1807
|
+
\t\tuniqueIndex(
|
|
1808
1808
|
\t\t\t"billing_accounts_provider_subscription_unique",
|
|
1809
1809
|
\t\t).on(table.provider, table.subscriptionId),
|
|
1810
|
-
\t
|
|
1810
|
+
\t],
|
|
1811
1811
|
);
|
|
1812
1812
|
`;
|
|
1813
1813
|
}
|