@lark-apaas/fullstack-cli 1.1.22-alpha.10 → 1.1.22-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +229 -50
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1041,6 +1041,8 @@ async function fetchColumnComments(connectionString, options = {}) {
|
|
|
1041
1041
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1042
1042
|
const url = new URL(connectionString);
|
|
1043
1043
|
const schemaName = url.searchParams.get("schema") ?? "public";
|
|
1044
|
+
const start = Date.now();
|
|
1045
|
+
console.log(`[fetchColumnComments] \u2192 Querying pg_description for schema=${schemaName} (timeout=${timeoutMs}ms)`);
|
|
1044
1046
|
const sql = postgres(connectionString, {
|
|
1045
1047
|
connect_timeout: Math.ceil(timeoutMs / 1e3),
|
|
1046
1048
|
idle_timeout: Math.ceil(timeoutMs / 1e3)
|
|
@@ -1069,6 +1071,7 @@ async function fetchColumnComments(connectionString, options = {}) {
|
|
|
1069
1071
|
const key = `${row.tableName}.${row.columnName}`;
|
|
1070
1072
|
commentMap.set(key, row.comment);
|
|
1071
1073
|
}
|
|
1074
|
+
console.log(`[fetchColumnComments] \u2190 Fetched ${commentMap.size} column comments (${Date.now() - start}ms)`);
|
|
1072
1075
|
return commentMap;
|
|
1073
1076
|
} finally {
|
|
1074
1077
|
await sql.end().catch(() => {
|
|
@@ -1167,6 +1170,79 @@ function addJsonbTypeComments(source, columnComments) {
|
|
|
1167
1170
|
return { text: result.join("\n"), added };
|
|
1168
1171
|
}
|
|
1169
1172
|
|
|
1173
|
+
// src/commands/db/gen-dbschema/transforms/text/synced-table-comments.ts
|
|
1174
|
+
var TABLE_COMMENT = "Synced table: data is auto-synced from external source. Do not rename or delete this table.";
|
|
1175
|
+
var FIELD_COMMENT = "Synced field: auto-synced, do not modify or delete";
|
|
1176
|
+
var TABLE_DEF_REGEX = /^(export const\s+\w+\s*=\s*(?:pgTable|pgView|pgMaterializedView)\(\s*["'`])([^"'`]+)(["'`])/;
|
|
1177
|
+
var FIELD_WITH_NAME_REGEX = /^\s*[\w"']+\s*:\s*\w+\(\s*["'`]([^"'`]+)["'`]/;
|
|
1178
|
+
var FIELD_PROP_NAME_REGEX = /^\s*([\w]+)\s*:/;
|
|
1179
|
+
function addSyncedTableComments(source, syncedTableMap) {
|
|
1180
|
+
if (!syncedTableMap || syncedTableMap.size === 0) {
|
|
1181
|
+
return { text: source, added: 0 };
|
|
1182
|
+
}
|
|
1183
|
+
const lines = source.split("\n");
|
|
1184
|
+
const result = [];
|
|
1185
|
+
let added = 0;
|
|
1186
|
+
let currentSyncedFields = null;
|
|
1187
|
+
let insideTableBody = false;
|
|
1188
|
+
let braceDepth = 0;
|
|
1189
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1190
|
+
const line = lines[i];
|
|
1191
|
+
const tableMatch = line.match(TABLE_DEF_REGEX);
|
|
1192
|
+
if (tableMatch) {
|
|
1193
|
+
const tableName = tableMatch[2];
|
|
1194
|
+
const syncedFields = syncedTableMap.get(tableName);
|
|
1195
|
+
if (syncedFields) {
|
|
1196
|
+
currentSyncedFields = syncedFields;
|
|
1197
|
+
insideTableBody = true;
|
|
1198
|
+
braceDepth = 0;
|
|
1199
|
+
const prevLine = result[result.length - 1]?.trim() ?? "";
|
|
1200
|
+
if (!prevLine.includes("Synced table")) {
|
|
1201
|
+
const indentMatch = line.match(/^\s*/);
|
|
1202
|
+
const indent = indentMatch ? indentMatch[0] : "";
|
|
1203
|
+
result.push(`${indent}// ${TABLE_COMMENT}`);
|
|
1204
|
+
added++;
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
if (insideTableBody) {
|
|
1209
|
+
for (const ch of line) {
|
|
1210
|
+
if (ch === "{") braceDepth++;
|
|
1211
|
+
if (ch === "}") braceDepth--;
|
|
1212
|
+
}
|
|
1213
|
+
if (braceDepth <= 0) {
|
|
1214
|
+
insideTableBody = false;
|
|
1215
|
+
currentSyncedFields = null;
|
|
1216
|
+
}
|
|
1217
|
+
if (currentSyncedFields && braceDepth >= 1 && !tableMatch) {
|
|
1218
|
+
const columnName = extractColumnName2(line);
|
|
1219
|
+
if (columnName && currentSyncedFields.has(columnName)) {
|
|
1220
|
+
const prevLine = result[result.length - 1]?.trim() ?? "";
|
|
1221
|
+
if (!prevLine.includes("Synced field")) {
|
|
1222
|
+
const indentMatch = line.match(/^\s*/);
|
|
1223
|
+
const indent = indentMatch ? indentMatch[0] : "";
|
|
1224
|
+
result.push(`${indent}// ${FIELD_COMMENT}`);
|
|
1225
|
+
added++;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
result.push(line);
|
|
1231
|
+
}
|
|
1232
|
+
return { text: result.join("\n"), added };
|
|
1233
|
+
}
|
|
1234
|
+
function extractColumnName2(line) {
|
|
1235
|
+
const withNameMatch = line.match(FIELD_WITH_NAME_REGEX);
|
|
1236
|
+
if (withNameMatch) {
|
|
1237
|
+
return withNameMatch[1];
|
|
1238
|
+
}
|
|
1239
|
+
const propMatch = line.match(FIELD_PROP_NAME_REGEX);
|
|
1240
|
+
if (propMatch) {
|
|
1241
|
+
return propMatch[1];
|
|
1242
|
+
}
|
|
1243
|
+
return null;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1170
1246
|
// src/commands/db/gen-dbschema/transforms/text/table-aliases.ts
|
|
1171
1247
|
var TABLE_ALIAS_MARKER = "// table aliases";
|
|
1172
1248
|
function generateTableAliases(source) {
|
|
@@ -1215,13 +1291,16 @@ function postprocessSchema(rawSource, options = {}) {
|
|
|
1215
1291
|
source = inlineCustomTypes(source);
|
|
1216
1292
|
const jsonbCommentsResult = addJsonbTypeComments(source, options.columnComments);
|
|
1217
1293
|
source = jsonbCommentsResult.text;
|
|
1294
|
+
const syncedCommentsResult = addSyncedTableComments(source, options.syncedTableMap);
|
|
1295
|
+
source = syncedCommentsResult.text;
|
|
1218
1296
|
source = generateTableAliases(source);
|
|
1219
1297
|
source = formatSource(source);
|
|
1220
1298
|
return {
|
|
1221
1299
|
source,
|
|
1222
1300
|
astStats,
|
|
1223
1301
|
patchedDefects: patchResult.fixed,
|
|
1224
|
-
addedJsonbComments: jsonbCommentsResult.added
|
|
1302
|
+
addedJsonbComments: jsonbCommentsResult.added,
|
|
1303
|
+
addedSyncedComments: syncedCommentsResult.added
|
|
1225
1304
|
};
|
|
1226
1305
|
}
|
|
1227
1306
|
function logStats(result, prefix = "[postprocess]") {
|
|
@@ -1271,6 +1350,9 @@ function logStats(result, prefix = "[postprocess]") {
|
|
|
1271
1350
|
if (result.addedJsonbComments > 0) {
|
|
1272
1351
|
console.info(`${prefix} Added ${result.addedJsonbComments} JSDoc comments for jsonb fields`);
|
|
1273
1352
|
}
|
|
1353
|
+
if (result.addedSyncedComments > 0) {
|
|
1354
|
+
console.info(`${prefix} Added ${result.addedSyncedComments} comments for synced tables/fields`);
|
|
1355
|
+
}
|
|
1274
1356
|
}
|
|
1275
1357
|
|
|
1276
1358
|
// src/commands/db/gen-dbschema/index.ts
|
|
@@ -1281,7 +1363,10 @@ async function postprocessDrizzleSchema(targetPath, options = {}) {
|
|
|
1281
1363
|
return void 0;
|
|
1282
1364
|
}
|
|
1283
1365
|
const rawSource = fs3.readFileSync(resolvedPath, "utf8");
|
|
1284
|
-
const result = postprocessSchema(rawSource, {
|
|
1366
|
+
const result = postprocessSchema(rawSource, {
|
|
1367
|
+
columnComments: options.columnComments,
|
|
1368
|
+
syncedTableMap: options.syncedTableMap
|
|
1369
|
+
});
|
|
1285
1370
|
fs3.writeFileSync(resolvedPath, result.source, "utf8");
|
|
1286
1371
|
logStats(result, "[postprocess-drizzle-schema]");
|
|
1287
1372
|
return {
|
|
@@ -1291,10 +1376,107 @@ async function postprocessDrizzleSchema(targetPath, options = {}) {
|
|
|
1291
1376
|
patchedDefects: result.patchedDefects,
|
|
1292
1377
|
replacedTimestamps: result.astStats.replacedTimestamp,
|
|
1293
1378
|
replacedDefaultNow: result.astStats.replacedDefaultNow,
|
|
1294
|
-
addedJsonbComments: result.addedJsonbComments
|
|
1379
|
+
addedJsonbComments: result.addedJsonbComments,
|
|
1380
|
+
addedSyncedComments: result.addedSyncedComments
|
|
1295
1381
|
};
|
|
1296
1382
|
}
|
|
1297
1383
|
|
|
1384
|
+
// src/utils/http-client.ts
|
|
1385
|
+
import { HttpClient } from "@lark-apaas/http-client";
|
|
1386
|
+
var clientInstance = null;
|
|
1387
|
+
function getHttpClient() {
|
|
1388
|
+
if (!clientInstance) {
|
|
1389
|
+
clientInstance = new HttpClient({
|
|
1390
|
+
timeout: 3e4,
|
|
1391
|
+
platform: {
|
|
1392
|
+
enabled: true
|
|
1393
|
+
}
|
|
1394
|
+
});
|
|
1395
|
+
const canaryEnv = process.env.FORCE_FRAMEWORK_CLI_CANARY_ENV;
|
|
1396
|
+
if (canaryEnv) {
|
|
1397
|
+
clientInstance.interceptors.request.use((req) => {
|
|
1398
|
+
req.headers["x-tt-env"] = canaryEnv;
|
|
1399
|
+
return req;
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
return clientInstance;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
// src/commands/db/gen-dbschema/utils/fetch-synced-tables.ts
|
|
1407
|
+
var DEFAULT_TIMEOUT_MS2 = 1e4;
|
|
1408
|
+
async function fetchSyncedTables(appId, workspace) {
|
|
1409
|
+
try {
|
|
1410
|
+
const client = getHttpClient();
|
|
1411
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
1412
|
+
setTimeout(
|
|
1413
|
+
() => reject(new Error(`Timeout after ${DEFAULT_TIMEOUT_MS2}ms`)),
|
|
1414
|
+
DEFAULT_TIMEOUT_MS2
|
|
1415
|
+
);
|
|
1416
|
+
});
|
|
1417
|
+
const start = Date.now();
|
|
1418
|
+
console.log(
|
|
1419
|
+
`[fetchSyncedTables] \u2192 GET listTableView (dbBranch=main) appId=${appId ? "set" : "unset"} workspace=${workspace ? "set" : "unset"}`
|
|
1420
|
+
);
|
|
1421
|
+
const response = await Promise.race([
|
|
1422
|
+
client.get(
|
|
1423
|
+
`/api/v1/dataloom/inner/app/${appId}/workspaces/${workspace}/listTableView`,
|
|
1424
|
+
{ params: { dbBranch: "dev" } }
|
|
1425
|
+
),
|
|
1426
|
+
timeoutPromise
|
|
1427
|
+
]);
|
|
1428
|
+
console.log(
|
|
1429
|
+
`[fetchSyncedTables] \u2190 listTableView response: ${response.status} ${response.statusText} (${Date.now() - start}ms) with logId=${response.headers.get("x-tt-log-id")}`
|
|
1430
|
+
);
|
|
1431
|
+
if (!response.ok) {
|
|
1432
|
+
throw new Error(
|
|
1433
|
+
`listTableView API failed: ${response.status} ${response.statusText}`
|
|
1434
|
+
);
|
|
1435
|
+
}
|
|
1436
|
+
const json = await response.json();
|
|
1437
|
+
const tableView = json?.data?.data;
|
|
1438
|
+
console.log(
|
|
1439
|
+
"[fetchSyncedTables] listTableView raw response:",
|
|
1440
|
+
JSON.stringify(json, null, 2)
|
|
1441
|
+
);
|
|
1442
|
+
if (!tableView) {
|
|
1443
|
+
console.warn(
|
|
1444
|
+
"[fetchSyncedTables] \u26A0 listTableView response missing data.data, returning empty map"
|
|
1445
|
+
);
|
|
1446
|
+
return /* @__PURE__ */ new Map();
|
|
1447
|
+
}
|
|
1448
|
+
const syncedMap = extractSyncedTableMap(tableView);
|
|
1449
|
+
const totalCount = (tableView.table?.data?.length ?? 0) + (tableView.view?.data?.length ?? 0) + (tableView.materializedView?.data?.length ?? 0);
|
|
1450
|
+
console.log(
|
|
1451
|
+
`[fetchSyncedTables] \u2713 Extracted synced tables: ${syncedMap.size}/${totalCount} (elapsed ${Date.now() - start}ms)`
|
|
1452
|
+
);
|
|
1453
|
+
return syncedMap;
|
|
1454
|
+
} catch (error) {
|
|
1455
|
+
console.error(
|
|
1456
|
+
"[fetchSyncedTables] \u274C Error fetching synced tables:",
|
|
1457
|
+
error
|
|
1458
|
+
);
|
|
1459
|
+
return void 0;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
function extractSyncedTableMap(tableView) {
|
|
1463
|
+
const syncedMap = /* @__PURE__ */ new Map();
|
|
1464
|
+
const allTables = [
|
|
1465
|
+
...tableView.table?.data ?? [],
|
|
1466
|
+
...tableView.view?.data ?? [],
|
|
1467
|
+
...tableView.materializedView?.data ?? []
|
|
1468
|
+
];
|
|
1469
|
+
for (const table of allTables) {
|
|
1470
|
+
if (table.bitableSyncTask && table.bitableSyncTask.fieldApiNameList?.length > 0) {
|
|
1471
|
+
syncedMap.set(
|
|
1472
|
+
table.tableName,
|
|
1473
|
+
new Set(table.bitableSyncTask.fieldApiNameList)
|
|
1474
|
+
);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
return syncedMap;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1298
1480
|
// src/commands/db/gen-nest-resource/generator.ts
|
|
1299
1481
|
import { pluralize } from "inflection";
|
|
1300
1482
|
|
|
@@ -2017,15 +2199,52 @@ async function run(options = {}) {
|
|
|
2017
2199
|
throw new Error("Unable to locate drizzle-kit package root");
|
|
2018
2200
|
};
|
|
2019
2201
|
let columnComments;
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2202
|
+
let syncedTableMap;
|
|
2203
|
+
const appId = process.env.app_id;
|
|
2204
|
+
const workspace = process.env.suda_workspace_id;
|
|
2205
|
+
console.log(
|
|
2206
|
+
`[gen-db-schema] Pre-fetch info: columnComments=enabled, syncedTables=${appId && workspace ? "enabled" : "skipped"} (app_id=${appId ? "set" : "unset"}, suda_workspace_id=${workspace ? "set" : "unset"})`
|
|
2207
|
+
);
|
|
2208
|
+
const columnCommentsTask = (async () => {
|
|
2209
|
+
const start = Date.now();
|
|
2210
|
+
console.log("[gen-db-schema] \u2192 Fetching column comments...");
|
|
2211
|
+
const res = await fetchColumnComments(databaseUrl, { timeoutMs: 1e4 });
|
|
2212
|
+
console.log(`[gen-db-schema] \u2190 Fetched column comments: ${res.size} items (${Date.now() - start}ms)`);
|
|
2213
|
+
return res;
|
|
2214
|
+
})();
|
|
2215
|
+
const syncedTablesTask = appId && workspace ? (async () => {
|
|
2216
|
+
const start = Date.now();
|
|
2217
|
+
console.log("[gen-db-schema] \u2192 Fetching synced tables from listTableView...");
|
|
2218
|
+
const res = await fetchSyncedTables(appId, workspace);
|
|
2219
|
+
console.log(`[gen-db-schema] \u2190 Fetched synced tables: ${res?.size} tables (${Date.now() - start}ms)`);
|
|
2220
|
+
return res;
|
|
2221
|
+
})() : void 0;
|
|
2222
|
+
const fetchTasks = await Promise.allSettled([
|
|
2223
|
+
columnCommentsTask,
|
|
2224
|
+
...syncedTablesTask ? [syncedTablesTask] : []
|
|
2225
|
+
]);
|
|
2226
|
+
if (fetchTasks[0].status === "fulfilled") {
|
|
2227
|
+
columnComments = fetchTasks[0].value;
|
|
2228
|
+
console.log(`[gen-db-schema] \u2713 Column comments ready: ${columnComments.size}`);
|
|
2229
|
+
} else {
|
|
2024
2230
|
console.warn(
|
|
2025
2231
|
"[gen-db-schema] \u26A0 Failed to fetch column comments (skipping):",
|
|
2026
|
-
|
|
2232
|
+
fetchTasks[0].reason instanceof Error ? fetchTasks[0].reason.message : String(fetchTasks[0].reason)
|
|
2027
2233
|
);
|
|
2028
2234
|
}
|
|
2235
|
+
if (appId && workspace) {
|
|
2236
|
+
if (fetchTasks[1]?.status === "fulfilled") {
|
|
2237
|
+
syncedTableMap = fetchTasks[1].value;
|
|
2238
|
+
console.log(`[gen-db-schema] \u2713 Synced tables ready: ${syncedTableMap.size}`);
|
|
2239
|
+
} else if (fetchTasks[1]?.status === "rejected") {
|
|
2240
|
+
console.warn(
|
|
2241
|
+
"[gen-db-schema] \u26A0 Failed to fetch synced tables (skipping):",
|
|
2242
|
+
fetchTasks[1].reason instanceof Error ? fetchTasks[1].reason.message : String(fetchTasks[1].reason)
|
|
2243
|
+
);
|
|
2244
|
+
}
|
|
2245
|
+
} else {
|
|
2246
|
+
console.info("[gen-db-schema] \u2139 Skipping synced table detection (app_id or suda_workspace_id not set)");
|
|
2247
|
+
}
|
|
2029
2248
|
try {
|
|
2030
2249
|
const env = {
|
|
2031
2250
|
...process.env,
|
|
@@ -2050,7 +2269,8 @@ async function run(options = {}) {
|
|
|
2050
2269
|
throw new Error("drizzle-kit introspect failed to generate schema.ts");
|
|
2051
2270
|
}
|
|
2052
2271
|
const stats = await postprocessDrizzleSchema(generatedSchema, {
|
|
2053
|
-
columnComments
|
|
2272
|
+
columnComments,
|
|
2273
|
+
syncedTableMap
|
|
2054
2274
|
});
|
|
2055
2275
|
if (stats?.unmatchedUnknown?.length) {
|
|
2056
2276
|
console.warn("[gen-db-schema] Unmatched custom types detected:", stats.unmatchedUnknown);
|
|
@@ -2419,28 +2639,6 @@ var syncCommand = {
|
|
|
2419
2639
|
}
|
|
2420
2640
|
};
|
|
2421
2641
|
|
|
2422
|
-
// src/utils/http-client.ts
|
|
2423
|
-
import { HttpClient } from "@lark-apaas/http-client";
|
|
2424
|
-
var clientInstance = null;
|
|
2425
|
-
function getHttpClient() {
|
|
2426
|
-
if (!clientInstance) {
|
|
2427
|
-
clientInstance = new HttpClient({
|
|
2428
|
-
timeout: 3e4,
|
|
2429
|
-
platform: {
|
|
2430
|
-
enabled: true
|
|
2431
|
-
}
|
|
2432
|
-
});
|
|
2433
|
-
const canaryEnv = process.env.FORCE_FRAMEWORK_CLI_CANARY_ENV;
|
|
2434
|
-
if (canaryEnv) {
|
|
2435
|
-
clientInstance.interceptors.request.use((req) => {
|
|
2436
|
-
req.headers["x-tt-env"] = canaryEnv;
|
|
2437
|
-
return req;
|
|
2438
|
-
});
|
|
2439
|
-
}
|
|
2440
|
-
}
|
|
2441
|
-
return clientInstance;
|
|
2442
|
-
}
|
|
2443
|
-
|
|
2444
2642
|
// src/utils/telemetry.ts
|
|
2445
2643
|
async function reportEvents(events) {
|
|
2446
2644
|
if (events.length === 0) {
|
|
@@ -2547,21 +2745,6 @@ function gitAddUpgradeFiles(cwd = process.cwd(), filesToStage) {
|
|
|
2547
2745
|
throw new Error(`git add failed: ${errorMsg}`);
|
|
2548
2746
|
}
|
|
2549
2747
|
}
|
|
2550
|
-
function hasStagedChanges(cwd = process.cwd()) {
|
|
2551
|
-
const result = spawnSync2("git", ["diff", "--cached", "--quiet"], {
|
|
2552
|
-
cwd,
|
|
2553
|
-
stdio: "pipe",
|
|
2554
|
-
encoding: "utf-8"
|
|
2555
|
-
});
|
|
2556
|
-
if (result.status === 0) {
|
|
2557
|
-
return false;
|
|
2558
|
-
}
|
|
2559
|
-
if (result.status === 1) {
|
|
2560
|
-
return true;
|
|
2561
|
-
}
|
|
2562
|
-
const errorMsg = result.stderr || result.error?.message || "Unknown error";
|
|
2563
|
-
throw new Error(`Failed to check staged changes: ${errorMsg}`);
|
|
2564
|
-
}
|
|
2565
2748
|
function gitCommit(message, cwd = process.cwd()) {
|
|
2566
2749
|
const result = spawnSync2("git", ["commit", "-m", message], {
|
|
2567
2750
|
cwd,
|
|
@@ -2585,10 +2768,6 @@ function autoCommitUpgradeChanges(version, cwd, filesToStage, commitMessage) {
|
|
|
2585
2768
|
}
|
|
2586
2769
|
try {
|
|
2587
2770
|
gitAddUpgradeFiles(cwd, filesToStage);
|
|
2588
|
-
if (!hasStagedChanges(cwd)) {
|
|
2589
|
-
console.log("[fullstack-cli] No upgrade changes to commit");
|
|
2590
|
-
return false;
|
|
2591
|
-
}
|
|
2592
2771
|
const message = commitMessage || `chore(upgrade): auto-upgrade by fullstack-cli
|
|
2593
2772
|
|
|
2594
2773
|
- Sync template files
|