@tailor-platform/create-sdk 1.83.0 → 1.85.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/CHANGELOG.md +4 -0
- package/package.json +5 -5
- package/templates/executor/package.json +4 -4
- package/templates/generators/package.json +4 -4
- package/templates/generators/src/seed/exec.mjs +108 -34
- package/templates/hello-world/package.json +4 -4
- package/templates/inventory-management/package.json +4 -4
- package/templates/multi-application/package.json +4 -4
- package/templates/resolver/package.json +4 -4
- package/templates/static-web-site/package.json +4 -4
- package/templates/tailordb/package.json +4 -4
- package/templates/workflow/package.json +4 -4
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-platform/create-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.85.0",
|
|
4
4
|
"description": "A CLI tool to quickly create a new Tailor Platform SDK project",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,14 +21,14 @@
|
|
|
21
21
|
"execa": "10.0.0",
|
|
22
22
|
"picocolors": "1.1.1",
|
|
23
23
|
"pkg-types": "2.3.1",
|
|
24
|
-
"politty": "0.11.
|
|
24
|
+
"politty": "0.11.6",
|
|
25
25
|
"zod": "4.4.3"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "24.13.3",
|
|
29
|
-
"oxlint": "1.
|
|
30
|
-
"oxlint-tsgolint": "0.
|
|
31
|
-
"tsdown": "0.22.
|
|
29
|
+
"oxlint": "1.76.0",
|
|
30
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
31
|
+
"tsdown": "0.22.14",
|
|
32
32
|
"typescript": "6.0.3"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
19
|
-
"@tailor-platform/sdk": "1.
|
|
19
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
20
20
|
"@types/node": "24.13.3",
|
|
21
|
-
"oxfmt": "0.
|
|
22
|
-
"oxlint": "1.
|
|
23
|
-
"oxlint-tsgolint": "0.
|
|
21
|
+
"oxfmt": "0.61.0",
|
|
22
|
+
"oxlint": "1.76.0",
|
|
23
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
24
24
|
"typescript": "6.0.3",
|
|
25
25
|
"vitest": "4.1.10"
|
|
26
26
|
}
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
19
|
-
"@tailor-platform/sdk": "1.
|
|
19
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
20
20
|
"@types/node": "24.13.3",
|
|
21
|
-
"oxfmt": "0.
|
|
22
|
-
"oxlint": "1.
|
|
23
|
-
"oxlint-tsgolint": "0.
|
|
21
|
+
"oxfmt": "0.61.0",
|
|
22
|
+
"oxlint": "1.76.0",
|
|
23
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
24
24
|
"typescript": "6.0.3",
|
|
25
25
|
"vitest": "4.1.10"
|
|
26
26
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Do not edit by hand: changes will be overwritten on the next `sdk generate`.
|
|
5
5
|
*/
|
|
6
6
|
import { readFileSync } from "node:fs";
|
|
7
|
-
import { join, isAbsolute } from "node:path";
|
|
7
|
+
import { dirname, join, isAbsolute } from "node:path";
|
|
8
8
|
import { parseArgs, styleText } from "node:util";
|
|
9
9
|
import { createInterface } from "node:readline";
|
|
10
10
|
import {
|
|
@@ -77,6 +77,7 @@ const { values, positionals } = parseArgs({
|
|
|
77
77
|
namespace: { type: "string", short: "n" },
|
|
78
78
|
"skip-idp": { type: "boolean", default: false },
|
|
79
79
|
truncate: { type: "boolean", default: false },
|
|
80
|
+
upsert: { type: "boolean", default: false },
|
|
80
81
|
yes: { type: "boolean", default: false },
|
|
81
82
|
profile: { type: "string", short: "p" },
|
|
82
83
|
help: { type: "boolean", short: "h", default: false },
|
|
@@ -96,6 +97,7 @@ Options:
|
|
|
96
97
|
-n, --namespace <ns> Process all types in specified namespace (excludes _User)
|
|
97
98
|
--skip-idp Skip IdP user (_User) entity
|
|
98
99
|
--truncate Truncate tables before seeding
|
|
100
|
+
--upsert Update existing rows instead of failing on duplicate ids
|
|
99
101
|
--yes Skip confirmation prompts (for truncate)
|
|
100
102
|
-p, --profile <name> Workspace profile name
|
|
101
103
|
-h, --help Show help
|
|
@@ -109,6 +111,7 @@ Examples:
|
|
|
109
111
|
node exec.mjs --truncate --yes # Truncate all tables without confirmation, then seed all
|
|
110
112
|
node exec.mjs --truncate --namespace <namespace> # Truncate tailordb, then seed tailordb
|
|
111
113
|
node exec.mjs --truncate User Order # Truncate User and Order, then seed them
|
|
114
|
+
node exec.mjs --upsert # Seed all, updating rows whose id already exists
|
|
112
115
|
node exec.mjs validate # Validate all seed data
|
|
113
116
|
node exec.mjs validate ./data/User.jsonl # Validate specific file
|
|
114
117
|
`);
|
|
@@ -133,6 +136,47 @@ const promptConfirmation = (question) => {
|
|
|
133
136
|
const configDir = import.meta.dirname;
|
|
134
137
|
const configPath = join(configDir, "../../tailor.config.ts");
|
|
135
138
|
|
|
139
|
+
const loadSeedData = (
|
|
140
|
+
dataDir,
|
|
141
|
+
typeNames,
|
|
142
|
+
{ requireId = false, requiredFieldsByType = {} } = {},
|
|
143
|
+
) => {
|
|
144
|
+
const data = {};
|
|
145
|
+
for (const typeName of typeNames) {
|
|
146
|
+
const jsonlPath = join(dataDir, `${typeName}.jsonl`);
|
|
147
|
+
try {
|
|
148
|
+
const lines = readFileSync(jsonlPath, "utf-8").split("\n");
|
|
149
|
+
const records = [];
|
|
150
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
151
|
+
if (lines[lineIndex].trim() === "") continue;
|
|
152
|
+
const record = JSON.parse(lines[lineIndex]);
|
|
153
|
+
if (requireId && (record?.id === undefined || record?.id === null)) {
|
|
154
|
+
throw new Error(
|
|
155
|
+
`${jsonlPath}:${lineIndex + 1}: \`id\` is required with --upsert`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
const missingRequiredField = (requiredFieldsByType[typeName] || []).find(
|
|
159
|
+
(field) => record?.[field] === undefined || record?.[field] === null,
|
|
160
|
+
);
|
|
161
|
+
if (missingRequiredField) {
|
|
162
|
+
throw new Error(
|
|
163
|
+
`${jsonlPath}:${lineIndex + 1}: field \`${missingRequiredField}\` is required with --upsert`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
records.push(record);
|
|
167
|
+
}
|
|
168
|
+
data[typeName] = records;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (error.code === "ENOENT") {
|
|
171
|
+
data[typeName] = [];
|
|
172
|
+
} else {
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return data;
|
|
178
|
+
};
|
|
179
|
+
|
|
136
180
|
// Determine machine user name (CLI argument takes precedence over config default)
|
|
137
181
|
const defaultMachineUser = "admin";
|
|
138
182
|
const machineUserName = values["machine-user"] || defaultMachineUser;
|
|
@@ -163,6 +207,12 @@ const namespaceDeps = {
|
|
|
163
207
|
const namespaceSelfRefTypes = {
|
|
164
208
|
"main-db": ["Category"]
|
|
165
209
|
};
|
|
210
|
+
const requiredFieldsByType = {
|
|
211
|
+
"Category": ["name","slug"],
|
|
212
|
+
"Order": ["productId","userId","quantity","totalPrice","status"],
|
|
213
|
+
"Product": ["name","price","status"],
|
|
214
|
+
"User": ["name","email","role"]
|
|
215
|
+
};
|
|
166
216
|
const entities = Object.values(namespaceEntities).flat();
|
|
167
217
|
const hasIdpUser = false;
|
|
168
218
|
|
|
@@ -232,6 +282,25 @@ if (skipIdp) {
|
|
|
232
282
|
}
|
|
233
283
|
}
|
|
234
284
|
|
|
285
|
+
const selectedTailorDbTypes = entities.filter(
|
|
286
|
+
(entity) => !entitiesToProcess || entitiesToProcess.includes(entity),
|
|
287
|
+
);
|
|
288
|
+
const loadSelectedTailorDbSeedData = () =>
|
|
289
|
+
loadSeedData(join(configDir, "data"), selectedTailorDbTypes, {
|
|
290
|
+
requireId: values.upsert,
|
|
291
|
+
requiredFieldsByType: values.upsert ? requiredFieldsByType : {},
|
|
292
|
+
});
|
|
293
|
+
let tailorDbSeedData;
|
|
294
|
+
if (values.upsert) {
|
|
295
|
+
try {
|
|
296
|
+
tailorDbSeedData = loadSelectedTailorDbSeedData();
|
|
297
|
+
} catch (error) {
|
|
298
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
299
|
+
console.error(styleText("red", `\n✗ Seed data generation failed: ${message}`));
|
|
300
|
+
process.exit(1);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
235
304
|
// Get application info
|
|
236
305
|
const appInfo = await show({ configPath, profile: values.profile });
|
|
237
306
|
const authNamespace = appInfo.auth;
|
|
@@ -293,29 +362,6 @@ if (skipIdp) {
|
|
|
293
362
|
console.log(styleText("dim", ` Skipping IdP user (_User)`));
|
|
294
363
|
}
|
|
295
364
|
|
|
296
|
-
// Load seed data from JSONL files
|
|
297
|
-
const loadSeedData = (dataDir, typeNames) => {
|
|
298
|
-
const data = {};
|
|
299
|
-
for (const typeName of typeNames) {
|
|
300
|
-
const jsonlPath = join(dataDir, `${typeName}.jsonl`);
|
|
301
|
-
try {
|
|
302
|
-
const content = readFileSync(jsonlPath, "utf-8").trim();
|
|
303
|
-
if (content) {
|
|
304
|
-
data[typeName] = content.split("\n").map((line) => JSON.parse(line));
|
|
305
|
-
} else {
|
|
306
|
-
data[typeName] = [];
|
|
307
|
-
}
|
|
308
|
-
} catch (error) {
|
|
309
|
-
if (error.code === "ENOENT") {
|
|
310
|
-
data[typeName] = [];
|
|
311
|
-
} else {
|
|
312
|
-
throw error;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return data;
|
|
317
|
-
};
|
|
318
|
-
|
|
319
365
|
// Topological sort for dependency order
|
|
320
366
|
const topologicalSort = (types, deps) => {
|
|
321
367
|
const visited = new Set();
|
|
@@ -340,10 +386,17 @@ const topologicalSort = (types, deps) => {
|
|
|
340
386
|
};
|
|
341
387
|
|
|
342
388
|
// Seed TailorDB types via testExecScript
|
|
343
|
-
const seedViaTestExecScript = async (
|
|
344
|
-
|
|
389
|
+
const seedViaTestExecScript = async (
|
|
390
|
+
namespace,
|
|
391
|
+
typesToSeed,
|
|
392
|
+
deps,
|
|
393
|
+
selfRefTypes,
|
|
394
|
+
seedDataByType,
|
|
395
|
+
) => {
|
|
345
396
|
const sortedTypes = topologicalSort(typesToSeed, deps);
|
|
346
|
-
const data =
|
|
397
|
+
const data = Object.fromEntries(
|
|
398
|
+
sortedTypes.map((type) => [type, seedDataByType[type] || []]),
|
|
399
|
+
);
|
|
347
400
|
|
|
348
401
|
// Skip if no data
|
|
349
402
|
const typesWithData = sortedTypes.filter((t) => data[t] && data[t].length > 0);
|
|
@@ -352,10 +405,10 @@ const seedViaTestExecScript = async (namespace, typesToSeed, deps, selfRefTypes)
|
|
|
352
405
|
return { success: true, processed: {} };
|
|
353
406
|
}
|
|
354
407
|
|
|
355
|
-
console.log(styleText("cyan", ` [${namespace}] Seeding ${typesWithData.length} types via Kysely batch insert...`));
|
|
408
|
+
console.log(styleText("cyan", ` [${namespace}] Seeding ${typesWithData.length} types via Kysely batch ${values.upsert ? "upsert" : "insert"}...`));
|
|
356
409
|
|
|
357
410
|
// Bundle seed script
|
|
358
|
-
const bundled = await bundleSeedScript(namespace, typesWithData);
|
|
411
|
+
const bundled = await bundleSeedScript(namespace, typesWithData, dirname(configPath));
|
|
359
412
|
|
|
360
413
|
// Chunk seed data to fit within gRPC message size limits
|
|
361
414
|
const chunks = chunkSeedData({
|
|
@@ -388,7 +441,7 @@ const seedViaTestExecScript = async (namespace, typesToSeed, deps, selfRefTypes)
|
|
|
388
441
|
workspaceId,
|
|
389
442
|
name: `seed-${namespace}.ts`,
|
|
390
443
|
code: bundled.bundledCode,
|
|
391
|
-
arg: JSON.stringify({ data: chunk.data, order: chunk.order, selfRefTypes }),
|
|
444
|
+
arg: JSON.stringify({ data: chunk.data, order: chunk.order, selfRefTypes, upsert: values.upsert }),
|
|
392
445
|
invoker: {
|
|
393
446
|
namespace: authNamespace,
|
|
394
447
|
machineUserName,
|
|
@@ -416,9 +469,23 @@ const seedViaTestExecScript = async (namespace, typesToSeed, deps, selfRefTypes)
|
|
|
416
469
|
}
|
|
417
470
|
|
|
418
471
|
const processed = parsed.processed || {};
|
|
419
|
-
for (const [type,
|
|
420
|
-
|
|
421
|
-
|
|
472
|
+
for (const [type, counts] of Object.entries(processed)) {
|
|
473
|
+
const previous = allProcessed[type] || { inserted: 0, updated: 0, skipped: 0 };
|
|
474
|
+
const current = {
|
|
475
|
+
inserted: Number(counts.inserted) || 0,
|
|
476
|
+
updated: Number(counts.updated) || 0,
|
|
477
|
+
skipped: Number(counts.skipped) || 0,
|
|
478
|
+
};
|
|
479
|
+
allProcessed[type] = {
|
|
480
|
+
inserted: previous.inserted + current.inserted,
|
|
481
|
+
updated: previous.updated + current.updated,
|
|
482
|
+
skipped: previous.skipped + current.skipped,
|
|
483
|
+
};
|
|
484
|
+
const skipped = current.skipped > 0 ? `, ${current.skipped} skipped` : "";
|
|
485
|
+
const message = values.upsert
|
|
486
|
+
? `${current.inserted} inserted, ${current.updated} updated${skipped}`
|
|
487
|
+
: `${current.inserted} rows inserted`;
|
|
488
|
+
console.log(styleText("green", ` ✓ ${type}: ${message}`));
|
|
422
489
|
}
|
|
423
490
|
|
|
424
491
|
if (!parsed.success) {
|
|
@@ -447,6 +514,7 @@ const seedViaTestExecScript = async (namespace, typesToSeed, deps, selfRefTypes)
|
|
|
447
514
|
// Main execution
|
|
448
515
|
try {
|
|
449
516
|
let allSuccess = true;
|
|
517
|
+
tailorDbSeedData ??= loadSelectedTailorDbSeedData();
|
|
450
518
|
|
|
451
519
|
// Determine which namespaces and types to process
|
|
452
520
|
const namespacesToProcess = hasNamespace
|
|
@@ -465,7 +533,13 @@ try {
|
|
|
465
533
|
|
|
466
534
|
if (typesToSeed.length === 0) continue;
|
|
467
535
|
|
|
468
|
-
const result = await seedViaTestExecScript(
|
|
536
|
+
const result = await seedViaTestExecScript(
|
|
537
|
+
namespace,
|
|
538
|
+
typesToSeed,
|
|
539
|
+
nsDeps,
|
|
540
|
+
nsSelfRefTypes,
|
|
541
|
+
tailorDbSeedData,
|
|
542
|
+
);
|
|
469
543
|
if (!result.success) {
|
|
470
544
|
allSuccess = false;
|
|
471
545
|
}
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
17
|
-
"@tailor-platform/sdk": "1.
|
|
17
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
18
18
|
"@types/node": "24.13.3",
|
|
19
|
-
"oxfmt": "0.
|
|
20
|
-
"oxlint": "1.
|
|
21
|
-
"oxlint-tsgolint": "0.
|
|
19
|
+
"oxfmt": "0.61.0",
|
|
20
|
+
"oxlint": "1.76.0",
|
|
21
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
22
22
|
"typescript": "6.0.3"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
17
|
-
"@tailor-platform/sdk": "1.
|
|
17
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
18
18
|
"@types/node": "24.13.3",
|
|
19
|
-
"oxfmt": "0.
|
|
20
|
-
"oxlint": "1.
|
|
21
|
-
"oxlint-tsgolint": "0.
|
|
19
|
+
"oxfmt": "0.61.0",
|
|
20
|
+
"oxlint": "1.76.0",
|
|
21
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
22
22
|
"typescript": "6.0.3"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
17
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
18
|
-
"@tailor-platform/sdk": "1.
|
|
18
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
19
19
|
"@types/node": "24.13.3",
|
|
20
|
-
"oxfmt": "0.
|
|
21
|
-
"oxlint": "1.
|
|
22
|
-
"oxlint-tsgolint": "0.
|
|
20
|
+
"oxfmt": "0.61.0",
|
|
21
|
+
"oxlint": "1.76.0",
|
|
22
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
23
23
|
"typescript": "6.0.3"
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
19
|
-
"@tailor-platform/sdk": "1.
|
|
19
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
20
20
|
"@types/node": "24.13.3",
|
|
21
|
-
"oxfmt": "0.
|
|
22
|
-
"oxlint": "1.
|
|
23
|
-
"oxlint-tsgolint": "0.
|
|
21
|
+
"oxfmt": "0.61.0",
|
|
22
|
+
"oxlint": "1.76.0",
|
|
23
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
24
24
|
"typescript": "6.0.3",
|
|
25
25
|
"vitest": "4.1.10"
|
|
26
26
|
}
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
17
|
-
"@tailor-platform/sdk": "1.
|
|
17
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
18
18
|
"@types/node": "24.13.3",
|
|
19
|
-
"oxfmt": "0.
|
|
20
|
-
"oxlint": "1.
|
|
21
|
-
"oxlint-tsgolint": "0.
|
|
19
|
+
"oxfmt": "0.61.0",
|
|
20
|
+
"oxlint": "1.76.0",
|
|
21
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
22
22
|
"typescript": "6.0.3"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
19
|
-
"@tailor-platform/sdk": "1.
|
|
19
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
20
20
|
"@types/node": "24.13.3",
|
|
21
|
-
"oxfmt": "0.
|
|
22
|
-
"oxlint": "1.
|
|
23
|
-
"oxlint-tsgolint": "0.
|
|
21
|
+
"oxfmt": "0.61.0",
|
|
22
|
+
"oxlint": "1.76.0",
|
|
23
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
24
24
|
"typescript": "6.0.3",
|
|
25
25
|
"vitest": "4.1.10"
|
|
26
26
|
}
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"@tailor-platform/eslint-plugin-sdk": "0.1.0",
|
|
20
|
-
"@tailor-platform/sdk": "1.
|
|
20
|
+
"@tailor-platform/sdk": "1.85.0",
|
|
21
21
|
"@types/node": "24.13.3",
|
|
22
22
|
"graphql": "17.0.2",
|
|
23
23
|
"graphql-request": "7.4.0",
|
|
24
|
-
"oxfmt": "0.
|
|
25
|
-
"oxlint": "1.
|
|
26
|
-
"oxlint-tsgolint": "0.
|
|
24
|
+
"oxfmt": "0.61.0",
|
|
25
|
+
"oxlint": "1.76.0",
|
|
26
|
+
"oxlint-tsgolint": "7.0.2001",
|
|
27
27
|
"typescript": "6.0.3",
|
|
28
28
|
"vitest": "4.1.10"
|
|
29
29
|
}
|