@tailor-platform/sdk 1.17.1 → 1.18.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 +16 -0
- package/dist/application-Csj7Ow5Q.mjs +8 -0
- package/dist/{application-BMDE8KqK.mjs → application-gWUyKuzv.mjs} +120 -1618
- package/dist/application-gWUyKuzv.mjs.map +1 -0
- package/dist/brand-BZJCv6UY.mjs +28 -0
- package/dist/brand-BZJCv6UY.mjs.map +1 -0
- package/dist/cli/index.mjs +38 -20
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/lib.d.mts +10 -33
- package/dist/cli/lib.mjs +10 -5
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/configure/index.d.mts +4 -4
- package/dist/configure/index.mjs +10 -19
- package/dist/configure/index.mjs.map +1 -1
- package/dist/enum-constants-Cwd4qdpa.mjs +115 -0
- package/dist/enum-constants-Cwd4qdpa.mjs.map +1 -0
- package/dist/file-utils-cqcpFk87.mjs +139 -0
- package/dist/file-utils-cqcpFk87.mjs.map +1 -0
- package/dist/index-BKXch-td.d.mts +18 -0
- package/dist/index-C3Ib7pFc.d.mts +18 -0
- package/dist/{index-CVcYqZSf.d.mts → index-DP8EB9FK.d.mts} +12 -5
- package/dist/index-SqWgrTnF.d.mts +20 -0
- package/dist/index-sSDpuVQY.d.mts +18 -0
- package/dist/{jiti-BrELlEYT.mjs → jiti-DHlauMCo.mjs} +2 -2
- package/dist/{jiti-BrELlEYT.mjs.map → jiti-DHlauMCo.mjs.map} +1 -1
- package/dist/{job-CULA2Pvf.mjs → job-2Q82qQ6N.mjs} +27 -5
- package/dist/job-2Q82qQ6N.mjs.map +1 -0
- package/dist/kysely-type-DtUUoAi3.mjs +259 -0
- package/dist/kysely-type-DtUUoAi3.mjs.map +1 -0
- package/dist/plugin/builtin/enum-constants/index.d.mts +4 -0
- package/dist/plugin/builtin/enum-constants/index.mjs +3 -0
- package/dist/plugin/builtin/file-utils/index.d.mts +4 -0
- package/dist/plugin/builtin/file-utils/index.mjs +3 -0
- package/dist/plugin/builtin/kysely-type/index.d.mts +4 -0
- package/dist/plugin/builtin/kysely-type/index.mjs +3 -0
- package/dist/plugin/builtin/seed/index.d.mts +4 -0
- package/dist/plugin/builtin/seed/index.mjs +3 -0
- package/dist/plugin/index.d.mts +3 -3
- package/dist/plugin/index.mjs +11 -11
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/{schema-R5TxC5Pn.mjs → schema-WDvc7Zel.mjs} +4 -3
- package/dist/schema-WDvc7Zel.mjs.map +1 -0
- package/dist/seed-Dm7lrGZ3.mjs +1050 -0
- package/dist/seed-Dm7lrGZ3.mjs.map +1 -0
- package/dist/{src-DMROgdcL.mjs → src-i4uqS1G4.mjs} +2 -2
- package/dist/{src-DMROgdcL.mjs.map → src-i4uqS1G4.mjs.map} +1 -1
- package/dist/types-Bhl_wAM2.d.mts +151 -0
- package/dist/{types-b-ig8nW_.mjs → types-ClK_HJ0G.mjs} +1 -1
- package/dist/{types-b-ig8nW_.mjs.map → types-ClK_HJ0G.mjs.map} +1 -1
- package/dist/{types-CZZBCaxB.d.mts → types-DdvTxFiD.d.mts} +1324 -988
- package/dist/{update-CUBVjZbL.mjs → update-BoNKMti-.mjs} +268 -97
- package/dist/update-BoNKMti-.mjs.map +1 -0
- package/dist/utils/test/index.d.mts +4 -4
- package/dist/utils/test/index.mjs +3 -2
- package/dist/utils/test/index.mjs.map +1 -1
- package/docs/cli/application.md +106 -14
- package/docs/cli/auth.md +92 -12
- package/docs/cli/completion.md +18 -2
- package/docs/cli/executor.md +122 -14
- package/docs/cli/function.md +32 -4
- package/docs/cli/secret.md +134 -18
- package/docs/cli/staticwebsite.md +60 -8
- package/docs/cli/tailordb.md +148 -20
- package/docs/cli/user.md +154 -22
- package/docs/cli/workflow.md +100 -12
- package/docs/cli/workspace.md +274 -38
- package/docs/generator/custom.md +2 -2
- package/docs/plugin/custom.md +270 -163
- package/docs/plugin/index.md +48 -2
- package/package.json +22 -2
- package/dist/application-BMDE8KqK.mjs.map +0 -1
- package/dist/application-Dni_W16P.mjs +0 -4
- package/dist/job-CULA2Pvf.mjs.map +0 -1
- package/dist/schema-R5TxC5Pn.mjs.map +0 -1
- package/dist/types-DthzUFfx.d.mts +0 -372
- package/dist/update-CUBVjZbL.mjs.map +0 -1
- /package/dist/{chunk-GMkBE123.mjs → chunk-CqAI0b6X.mjs} +0 -0
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-
|
|
2
|
-
import { t as isPluginGeneratedType } from "./types-
|
|
1
|
+
import { a as __toCommonJS, i as __require, n as __esmMin, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-CqAI0b6X.mjs";
|
|
2
|
+
import { t as isPluginGeneratedType } from "./types-ClK_HJ0G.mjs";
|
|
3
|
+
import { n as isSdkBranded } from "./brand-BZJCv6UY.mjs";
|
|
4
|
+
import { n as enumConstantsPlugin, t as EnumConstantsGeneratorID } from "./enum-constants-Cwd4qdpa.mjs";
|
|
5
|
+
import { n as fileUtilsPlugin, t as FileUtilsGeneratorID } from "./file-utils-cqcpFk87.mjs";
|
|
6
|
+
import { n as kyselyTypePlugin, t as KyselyGeneratorID } from "./kysely-type-DtUUoAi3.mjs";
|
|
7
|
+
import { n as seedPlugin, t as SeedGeneratorID } from "./seed-Dm7lrGZ3.mjs";
|
|
3
8
|
import Module, { createRequire } from "node:module";
|
|
4
9
|
import { z } from "zod";
|
|
5
10
|
import * as fs$15 from "node:fs";
|
|
@@ -1065,6 +1070,7 @@ function formatRequestParams(message) {
|
|
|
1065
1070
|
return "(unable to serialize request)";
|
|
1066
1071
|
}
|
|
1067
1072
|
}
|
|
1073
|
+
const MAX_PAGE_SIZE = 1e3;
|
|
1068
1074
|
/**
|
|
1069
1075
|
* Fetch all paginated resources by repeatedly calling the given function.
|
|
1070
1076
|
* @template T
|
|
@@ -1075,7 +1081,7 @@ async function fetchAll(fn) {
|
|
|
1075
1081
|
const items = [];
|
|
1076
1082
|
let pageToken = "";
|
|
1077
1083
|
while (true) {
|
|
1078
|
-
const [batch, nextPageToken] = await fn(pageToken);
|
|
1084
|
+
const [batch, nextPageToken] = await fn(pageToken, MAX_PAGE_SIZE);
|
|
1079
1085
|
items.push(...batch);
|
|
1080
1086
|
if (!nextPageToken) break;
|
|
1081
1087
|
pageToken = nextPageToken;
|
|
@@ -87395,7 +87401,7 @@ var require_config_loader = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
87395
87401
|
* @returns {Promise<{createJiti: Function|undefined, version: string;}>} A promise that fulfills with an object containing the jiti module's createJiti function and version.
|
|
87396
87402
|
*/
|
|
87397
87403
|
static async loadJiti() {
|
|
87398
|
-
const { createJiti } = await import("./jiti-
|
|
87404
|
+
const { createJiti } = await import("./jiti-DHlauMCo.mjs");
|
|
87399
87405
|
return {
|
|
87400
87406
|
createJiti,
|
|
87401
87407
|
version: require_package$1().version
|
|
@@ -87737,7 +87743,7 @@ var require_eslint_helpers = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
87737
87743
|
*/
|
|
87738
87744
|
async function globMatch({ basePath, pattern }) {
|
|
87739
87745
|
let found = false;
|
|
87740
|
-
const { hfs } = await import("./src-
|
|
87746
|
+
const { hfs } = await import("./src-i4uqS1G4.mjs");
|
|
87741
87747
|
const matcher = new Minimatch(normalizeToPosix(path$9.relative(basePath, pattern)), MINIMATCH_OPTIONS);
|
|
87742
87748
|
const walkSettings = {
|
|
87743
87749
|
directoryFilter(entry) {
|
|
@@ -87784,7 +87790,7 @@ var require_eslint_helpers = /* @__PURE__ */ __commonJSMin(((exports, module) =>
|
|
|
87784
87790
|
return new Minimatch(patternToUse, MINIMATCH_OPTIONS);
|
|
87785
87791
|
});
|
|
87786
87792
|
const unmatchedPatterns = new Set([...relativeToPatterns.keys()]);
|
|
87787
|
-
const { hfs } = await import("./src-
|
|
87793
|
+
const { hfs } = await import("./src-i4uqS1G4.mjs");
|
|
87788
87794
|
const walk = hfs.walk(basePath, {
|
|
87789
87795
|
async directoryFilter(entry) {
|
|
87790
87796
|
if (!matchers.some((matcher) => matcher.match(entry.path, true))) return false;
|
|
@@ -98970,8 +98976,7 @@ function createTailorDBService(params) {
|
|
|
98970
98976
|
const exportedValue = module$1[exportName];
|
|
98971
98977
|
const result = TailorDBTypeSchema.safeParse(exportedValue);
|
|
98972
98978
|
if (!result.success) {
|
|
98973
|
-
|
|
98974
|
-
if (gqlPermissionIssue) throw new Error(gqlPermissionIssue.message);
|
|
98979
|
+
if (isSdkBranded(exportedValue)) throw result.error;
|
|
98975
98980
|
continue;
|
|
98976
98981
|
}
|
|
98977
98982
|
const relativePath = path$20.relative(process.cwd(), typeFile);
|
|
@@ -99447,6 +99452,7 @@ function createExecutorService(params) {
|
|
|
99447
99452
|
executors[executorFile] = result.data;
|
|
99448
99453
|
return result.data;
|
|
99449
99454
|
}
|
|
99455
|
+
if (isSdkBranded(executorModule.default)) throw result.error;
|
|
99450
99456
|
} catch (error) {
|
|
99451
99457
|
const relativePath = path$20.relative(process.cwd(), executorFile);
|
|
99452
99458
|
logger.error(`Failed to load executor from ${styles.bold(relativePath)}`);
|
|
@@ -99507,6 +99513,7 @@ function createResolverService(namespace, config) {
|
|
|
99507
99513
|
resolvers[resolverFile] = result.data;
|
|
99508
99514
|
return result.data;
|
|
99509
99515
|
}
|
|
99516
|
+
if (isSdkBranded(resolverModule.default)) throw result.error;
|
|
99510
99517
|
} catch (error) {
|
|
99511
99518
|
const relativePath = path$20.relative(process.cwd(), resolverFile);
|
|
99512
99519
|
logger.error(`Failed to load resolver from ${styles.bold(relativePath)}`);
|
|
@@ -99653,6 +99660,7 @@ async function loadFileContent(filePath) {
|
|
|
99653
99660
|
if (exportName === "default") {
|
|
99654
99661
|
const workflowResult = WorkflowSchema.safeParse(exportValue);
|
|
99655
99662
|
if (workflowResult.success) workflow = workflowResult.data;
|
|
99663
|
+
else if (isSdkBranded(exportValue)) throw workflowResult.error;
|
|
99656
99664
|
continue;
|
|
99657
99665
|
}
|
|
99658
99666
|
const jobResult = WorkflowJobSchema.safeParse(exportValue);
|
|
@@ -99661,6 +99669,7 @@ async function loadFileContent(filePath) {
|
|
|
99661
99669
|
exportName,
|
|
99662
99670
|
sourceFile: filePath
|
|
99663
99671
|
});
|
|
99672
|
+
else if (isSdkBranded(exportValue)) throw jobResult.error;
|
|
99664
99673
|
}
|
|
99665
99674
|
} catch (error) {
|
|
99666
99675
|
const relativePath = path$20.relative(process.cwd(), filePath);
|
|
@@ -100528,6 +100537,74 @@ async function bundleSingleResolver(resolver, outputDir, tsconfig, triggerContex
|
|
|
100528
100537
|
}));
|
|
100529
100538
|
}
|
|
100530
100539
|
|
|
100540
|
+
//#endregion
|
|
100541
|
+
//#region src/cli/bundler/runtime-args.ts
|
|
100542
|
+
/**
|
|
100543
|
+
* Runtime args transformation for all services.
|
|
100544
|
+
*
|
|
100545
|
+
* Each service transforms server-side args/context into SDK-friendly format:
|
|
100546
|
+
* - Executor: server-side expression evaluated by platform before calling function
|
|
100547
|
+
* - Resolver: operationHook expression evaluated by platform before calling function
|
|
100548
|
+
* - Workflow: JS code embedded in bundled entry file (uses tailorUserMap directly)
|
|
100549
|
+
*
|
|
100550
|
+
* The user field mapping (server → SDK) shared across services is defined in
|
|
100551
|
+
* `@/parser/service/tailordb` as `tailorUserMap`.
|
|
100552
|
+
*/
|
|
100553
|
+
/**
|
|
100554
|
+
* Actor field transformation expression.
|
|
100555
|
+
*
|
|
100556
|
+
* Transforms the server's actor object to match the SDK's TailorActor type:
|
|
100557
|
+
* server `attributeMap` → SDK `attributes`
|
|
100558
|
+
* server `attributes` → SDK `attributeList`
|
|
100559
|
+
* other fields → passed through
|
|
100560
|
+
* null/undefined actor → null
|
|
100561
|
+
*/
|
|
100562
|
+
const ACTOR_TRANSFORM_EXPR = "actor: args.actor ? (({ attributeMap, attributes: attrList, ...rest }) => ({ ...rest, attributes: attributeMap, attributeList: attrList }))(args.actor) : null";
|
|
100563
|
+
/**
|
|
100564
|
+
* Build the JavaScript expression that transforms server-format executor event
|
|
100565
|
+
* args into SDK-format args at runtime.
|
|
100566
|
+
*
|
|
100567
|
+
* The Tailor Platform server delivers event args with server-side field names.
|
|
100568
|
+
* The SDK exposes different field names to user code. This function produces a
|
|
100569
|
+
* JavaScript expression string that performs the mapping when evaluated
|
|
100570
|
+
* server-side.
|
|
100571
|
+
* @param triggerKind - The trigger kind discriminant from the parsed executor
|
|
100572
|
+
* @param env - Application env record to embed in the expression
|
|
100573
|
+
* @returns A JavaScript expression string, e.g. `({ ...args, ... })`
|
|
100574
|
+
*/
|
|
100575
|
+
function buildExecutorArgsExpr(triggerKind, env) {
|
|
100576
|
+
const envExpr = `env: ${JSON.stringify(env)}`;
|
|
100577
|
+
switch (triggerKind) {
|
|
100578
|
+
case "schedule":
|
|
100579
|
+
case "recordCreated":
|
|
100580
|
+
case "recordUpdated":
|
|
100581
|
+
case "recordDeleted":
|
|
100582
|
+
case "idpUserCreated":
|
|
100583
|
+
case "idpUserUpdated":
|
|
100584
|
+
case "idpUserDeleted":
|
|
100585
|
+
case "authAccessTokenIssued":
|
|
100586
|
+
case "authAccessTokenRefreshed":
|
|
100587
|
+
case "authAccessTokenRevoked": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, ${envExpr} })`;
|
|
100588
|
+
case "resolverExecuted": return `({ ...args, appNamespace: args.namespaceName, ${ACTOR_TRANSFORM_EXPR}, success: !!args.succeeded, result: args.succeeded?.result.resolver, error: args.failed?.error, ${envExpr} })`;
|
|
100589
|
+
case "incomingWebhook": return `({ ...args, appNamespace: args.namespaceName, rawBody: args.raw_body, ${envExpr} })`;
|
|
100590
|
+
default: throw new Error(`Unknown trigger kind for args expression: ${triggerKind}`);
|
|
100591
|
+
}
|
|
100592
|
+
}
|
|
100593
|
+
/**
|
|
100594
|
+
* Build the operationHook expression for resolver pipelines.
|
|
100595
|
+
*
|
|
100596
|
+
* Transforms server context to SDK resolver context:
|
|
100597
|
+
* context.args → input
|
|
100598
|
+
* context.pipeline → spread into result
|
|
100599
|
+
* user (global var) → TailorUser (via tailorUserMap: workspace_id→workspaceId, attribute_map→attributes, attributes→attributeList)
|
|
100600
|
+
* env → injected as JSON
|
|
100601
|
+
* @param env - Application env record to embed in the expression
|
|
100602
|
+
* @returns A JavaScript expression string for the operationHook
|
|
100603
|
+
*/
|
|
100604
|
+
function buildResolverOperationHookExpr(env) {
|
|
100605
|
+
return `({ ...context.pipeline, input: context.args, user: ${tailorUserMap}, env: ${JSON.stringify(env)} });`;
|
|
100606
|
+
}
|
|
100607
|
+
|
|
100531
100608
|
//#endregion
|
|
100532
100609
|
//#region src/cli/bundler/workflow/source-transformer.ts
|
|
100533
100610
|
/**
|
|
@@ -100796,10 +100873,10 @@ async function bundleSingleJob(job, allJobs, outputDir, tsconfig, env, triggerCo
|
|
|
100796
100873
|
const entryContent = ml`
|
|
100797
100874
|
import { ${job.exportName} } from "${absoluteSourcePath}";
|
|
100798
100875
|
|
|
100799
|
-
const env = ${JSON.stringify(env)};
|
|
100800
|
-
|
|
100801
100876
|
export async function main(input) {
|
|
100802
|
-
|
|
100877
|
+
const env = ${JSON.stringify(env)};
|
|
100878
|
+
const _user = ${tailorUserMap};
|
|
100879
|
+
return await ${job.exportName}.body(input, { env, user: _user });
|
|
100803
100880
|
}
|
|
100804
100881
|
`;
|
|
100805
100882
|
fs$15.writeFileSync(entryPath, entryContent);
|
|
@@ -100876,12 +100953,17 @@ const BaseGeneratorConfigSchema = z.union([
|
|
|
100876
100953
|
const CustomPluginSchema = z.object({
|
|
100877
100954
|
id: z.string(),
|
|
100878
100955
|
description: z.string(),
|
|
100879
|
-
importPath: z.string(),
|
|
100956
|
+
importPath: z.string().optional(),
|
|
100880
100957
|
pluginConfig: z.unknown().optional(),
|
|
100881
|
-
|
|
100882
|
-
|
|
100883
|
-
|
|
100884
|
-
|
|
100958
|
+
typeConfigRequired: z.union([z.boolean(), functionSchema]).optional(),
|
|
100959
|
+
onTypeLoaded: functionSchema.optional(),
|
|
100960
|
+
onNamespaceLoaded: functionSchema.optional(),
|
|
100961
|
+
onTailorDBReady: functionSchema.optional(),
|
|
100962
|
+
onResolverReady: functionSchema.optional(),
|
|
100963
|
+
onExecutorReady: functionSchema.optional()
|
|
100964
|
+
}).passthrough().refine((p) => {
|
|
100965
|
+
return !(p.onTypeLoaded || p.onNamespaceLoaded) || !!p.importPath;
|
|
100966
|
+
}, { message: "importPath is required when plugin has definition-time hooks (onTypeLoaded/onNamespaceLoaded)" });
|
|
100885
100967
|
/**
|
|
100886
100968
|
* Creates a PluginConfigSchema for custom plugins
|
|
100887
100969
|
* @returns Plugin config schema that validates and transforms Plugin instances
|
|
@@ -100890,1584 +100972,6 @@ function createPluginConfigSchema() {
|
|
|
100890
100972
|
return CustomPluginSchema.transform((plugin) => plugin);
|
|
100891
100973
|
}
|
|
100892
100974
|
|
|
100893
|
-
//#endregion
|
|
100894
|
-
//#region src/cli/generator/types.ts
|
|
100895
|
-
/**
|
|
100896
|
-
* Type guard to check if a generator has a specific dependency.
|
|
100897
|
-
* @template D
|
|
100898
|
-
* @param generator - Code generator instance
|
|
100899
|
-
* @param dependency - Dependency kind to check
|
|
100900
|
-
* @returns True if the generator has the dependency
|
|
100901
|
-
*/
|
|
100902
|
-
function hasDependency(generator, dependency) {
|
|
100903
|
-
return generator.dependencies.includes(dependency);
|
|
100904
|
-
}
|
|
100905
|
-
|
|
100906
|
-
//#endregion
|
|
100907
|
-
//#region src/cli/generator/builtin/enum-constants/generate-enum-constants.ts
|
|
100908
|
-
/**
|
|
100909
|
-
* Generate enum constant definitions from collected metadata.
|
|
100910
|
-
* @param allEnums - All collected enum definitions
|
|
100911
|
-
* @returns Generated enum constant definitions
|
|
100912
|
-
*/
|
|
100913
|
-
function generateUnifiedEnumConstants(allEnums) {
|
|
100914
|
-
if (allEnums.length === 0) return "";
|
|
100915
|
-
const enumMap = /* @__PURE__ */ new Map();
|
|
100916
|
-
for (const enumDef of allEnums) enumMap.set(enumDef.name, enumDef);
|
|
100917
|
-
const enumDefs = Array.from(enumMap.values()).map((e) => {
|
|
100918
|
-
const members = e.values.map((v) => {
|
|
100919
|
-
return ` "${v.value.replace(/[-\s]/g, "_")}": "${v.value}"`;
|
|
100920
|
-
}).join(",\n");
|
|
100921
|
-
const hasDescriptions = e.values.some((v) => v.description);
|
|
100922
|
-
let jsDoc = "";
|
|
100923
|
-
if (e.fieldDescription || hasDescriptions) {
|
|
100924
|
-
const lines = [];
|
|
100925
|
-
if (e.fieldDescription) {
|
|
100926
|
-
lines.push(` * ${e.fieldDescription}`);
|
|
100927
|
-
if (hasDescriptions) lines.push(" *");
|
|
100928
|
-
}
|
|
100929
|
-
if (hasDescriptions) {
|
|
100930
|
-
const propertyDocs = e.values.map((v) => {
|
|
100931
|
-
return ` * @property ${[v.value.replace(/[-\s]/g, "_"), v.description].filter(Boolean).join(" - ")}`;
|
|
100932
|
-
});
|
|
100933
|
-
lines.push(...propertyDocs);
|
|
100934
|
-
}
|
|
100935
|
-
if (lines.length > 0) jsDoc = `/**\n${lines.join("\n")}\n */\n`;
|
|
100936
|
-
}
|
|
100937
|
-
return `${`${jsDoc}export const ${e.name} = {\n${members}\n} as const;`}\n${`export type ${e.name} = (typeof ${e.name})[keyof typeof ${e.name}];`}`;
|
|
100938
|
-
}).join("\n\n");
|
|
100939
|
-
if (!enumDefs) return "";
|
|
100940
|
-
return enumDefs + "\n";
|
|
100941
|
-
}
|
|
100942
|
-
|
|
100943
|
-
//#endregion
|
|
100944
|
-
//#region src/cli/generator/builtin/enum-constants/process-enum-type.ts
|
|
100945
|
-
function capitalizeFirst(str) {
|
|
100946
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
100947
|
-
}
|
|
100948
|
-
function collectEnums(type) {
|
|
100949
|
-
const enums = [];
|
|
100950
|
-
for (const [fieldName, parsedField] of Object.entries(type.fields)) {
|
|
100951
|
-
if (parsedField.config.type === "enum" && parsedField.config.allowedValues) {
|
|
100952
|
-
const enumTypeName = `${type.name}${capitalizeFirst(fieldName)}`;
|
|
100953
|
-
enums.push({
|
|
100954
|
-
name: enumTypeName,
|
|
100955
|
-
values: parsedField.config.allowedValues,
|
|
100956
|
-
fieldDescription: parsedField.config.description
|
|
100957
|
-
});
|
|
100958
|
-
}
|
|
100959
|
-
if (parsedField.config.type === "nested" && parsedField.config.fields) {
|
|
100960
|
-
for (const [nestedFieldName, nestedFieldConfig] of Object.entries(parsedField.config.fields)) if (nestedFieldConfig.type === "enum" && nestedFieldConfig.allowedValues) {
|
|
100961
|
-
const fullFieldName = `${fieldName}${capitalizeFirst(nestedFieldName)}`;
|
|
100962
|
-
const enumTypeName = `${type.name}${capitalizeFirst(fullFieldName)}`;
|
|
100963
|
-
enums.push({
|
|
100964
|
-
name: enumTypeName,
|
|
100965
|
-
values: nestedFieldConfig.allowedValues,
|
|
100966
|
-
fieldDescription: nestedFieldConfig.description
|
|
100967
|
-
});
|
|
100968
|
-
}
|
|
100969
|
-
}
|
|
100970
|
-
}
|
|
100971
|
-
return enums;
|
|
100972
|
-
}
|
|
100973
|
-
/**
|
|
100974
|
-
* Process a TailorDB type and extract enum metadata.
|
|
100975
|
-
* @param type - The parsed TailorDB type to process
|
|
100976
|
-
* @returns Enum constant metadata for the type
|
|
100977
|
-
*/
|
|
100978
|
-
async function processEnumType(type) {
|
|
100979
|
-
const enums = collectEnums(type);
|
|
100980
|
-
return {
|
|
100981
|
-
name: type.name,
|
|
100982
|
-
enums
|
|
100983
|
-
};
|
|
100984
|
-
}
|
|
100985
|
-
|
|
100986
|
-
//#endregion
|
|
100987
|
-
//#region src/cli/generator/builtin/enum-constants/index.ts
|
|
100988
|
-
const EnumConstantsGeneratorID = "@tailor-platform/enum-constants";
|
|
100989
|
-
/**
|
|
100990
|
-
* Create an enum constants generator from TailorDB type definitions.
|
|
100991
|
-
* @param options - Generator options
|
|
100992
|
-
* @param options.distPath - Output file path
|
|
100993
|
-
* @returns TailorDB generator instance
|
|
100994
|
-
*/
|
|
100995
|
-
function createEnumConstantsGenerator(options) {
|
|
100996
|
-
return {
|
|
100997
|
-
id: EnumConstantsGeneratorID,
|
|
100998
|
-
description: "Generates enum constants from TailorDB type definitions",
|
|
100999
|
-
dependencies: ["tailordb"],
|
|
101000
|
-
async processType(args) {
|
|
101001
|
-
return await processEnumType(args.type);
|
|
101002
|
-
},
|
|
101003
|
-
async processTailorDBNamespace(args) {
|
|
101004
|
-
const allEnums = [];
|
|
101005
|
-
for (const enumConstantMetadata of Object.values(args.types)) allEnums.push(...enumConstantMetadata.enums);
|
|
101006
|
-
return {
|
|
101007
|
-
namespace: args.namespace,
|
|
101008
|
-
enums: allEnums
|
|
101009
|
-
};
|
|
101010
|
-
},
|
|
101011
|
-
aggregate(args) {
|
|
101012
|
-
const files = [];
|
|
101013
|
-
const allEnums = [];
|
|
101014
|
-
for (const nsResult of args.input.tailordb) if (nsResult.types && nsResult.types.enums.length > 0) allEnums.push(...nsResult.types.enums);
|
|
101015
|
-
if (allEnums.length > 0) {
|
|
101016
|
-
const content = generateUnifiedEnumConstants(allEnums);
|
|
101017
|
-
files.push({
|
|
101018
|
-
path: options.distPath,
|
|
101019
|
-
content
|
|
101020
|
-
});
|
|
101021
|
-
}
|
|
101022
|
-
return { files };
|
|
101023
|
-
}
|
|
101024
|
-
};
|
|
101025
|
-
}
|
|
101026
|
-
|
|
101027
|
-
//#endregion
|
|
101028
|
-
//#region src/cli/generator/builtin/file-utils/generate-file-utils.ts
|
|
101029
|
-
/**
|
|
101030
|
-
* Generate unified file utility functions from collected metadata.
|
|
101031
|
-
* @param namespaceData - Namespace data with file utility metadata
|
|
101032
|
-
* @returns Generated file utility code
|
|
101033
|
-
*/
|
|
101034
|
-
function generateUnifiedFileUtils(namespaceData) {
|
|
101035
|
-
if (namespaceData.length === 0) return "";
|
|
101036
|
-
const typeNamespaceMap = /* @__PURE__ */ new Map();
|
|
101037
|
-
const typeFieldsMap = /* @__PURE__ */ new Map();
|
|
101038
|
-
for (const { namespace, types: types$2 } of namespaceData) for (const type of types$2) {
|
|
101039
|
-
typeNamespaceMap.set(type.name, namespace);
|
|
101040
|
-
typeFieldsMap.set(type.name, type.fileFields);
|
|
101041
|
-
}
|
|
101042
|
-
if (typeNamespaceMap.size === 0) return "";
|
|
101043
|
-
return [
|
|
101044
|
-
ml`
|
|
101045
|
-
export interface TypeWithFiles {
|
|
101046
|
-
${Array.from(typeFieldsMap.entries()).map(([typeName, fields]) => {
|
|
101047
|
-
return ` ${typeName}: {\n fields: ${fields.map((field) => `"${field}"`).join(" | ")};\n };`;
|
|
101048
|
-
}).join("\n")}
|
|
101049
|
-
}
|
|
101050
|
-
` + "\n",
|
|
101051
|
-
ml`
|
|
101052
|
-
const namespaces: Record<keyof TypeWithFiles, string> = {
|
|
101053
|
-
${Array.from(typeNamespaceMap.entries()).map(([typeName, namespace]) => ` ${typeName}: "${namespace}"`).join(",\n")},
|
|
101054
|
-
};
|
|
101055
|
-
` + "\n",
|
|
101056
|
-
ml`
|
|
101057
|
-
export async function downloadFile<T extends keyof TypeWithFiles>(
|
|
101058
|
-
type: T,
|
|
101059
|
-
field: TypeWithFiles[T]["fields"],
|
|
101060
|
-
recordId: string,
|
|
101061
|
-
) {
|
|
101062
|
-
return await tailordb.file.download(namespaces[type], type, field, recordId);
|
|
101063
|
-
}
|
|
101064
|
-
` + "\n",
|
|
101065
|
-
ml`
|
|
101066
|
-
export async function uploadFile<T extends keyof TypeWithFiles>(
|
|
101067
|
-
type: T,
|
|
101068
|
-
field: TypeWithFiles[T]["fields"],
|
|
101069
|
-
recordId: string,
|
|
101070
|
-
data: string | ArrayBuffer | Uint8Array<ArrayBufferLike> | number[],
|
|
101071
|
-
options?: FileUploadOptions,
|
|
101072
|
-
): Promise<FileUploadResponse> {
|
|
101073
|
-
return await tailordb.file.upload(namespaces[type], type, field, recordId, data, options);
|
|
101074
|
-
}
|
|
101075
|
-
` + "\n",
|
|
101076
|
-
ml`
|
|
101077
|
-
export async function deleteFile<T extends keyof TypeWithFiles>(
|
|
101078
|
-
type: T,
|
|
101079
|
-
field: TypeWithFiles[T]["fields"],
|
|
101080
|
-
recordId: string,
|
|
101081
|
-
): Promise<void> {
|
|
101082
|
-
return await tailordb.file.delete(namespaces[type], type, field, recordId);
|
|
101083
|
-
}
|
|
101084
|
-
` + "\n",
|
|
101085
|
-
ml`
|
|
101086
|
-
export async function getFileMetadata<T extends keyof TypeWithFiles>(
|
|
101087
|
-
type: T,
|
|
101088
|
-
field: TypeWithFiles[T]["fields"],
|
|
101089
|
-
recordId: string,
|
|
101090
|
-
): Promise<FileMetadata> {
|
|
101091
|
-
return await tailordb.file.getMetadata(namespaces[type], type, field, recordId);
|
|
101092
|
-
}
|
|
101093
|
-
` + "\n",
|
|
101094
|
-
ml`
|
|
101095
|
-
export async function openFileDownloadStream<T extends keyof TypeWithFiles>(
|
|
101096
|
-
type: T,
|
|
101097
|
-
field: TypeWithFiles[T]["fields"],
|
|
101098
|
-
recordId: string,
|
|
101099
|
-
): Promise<FileStreamIterator> {
|
|
101100
|
-
return await tailordb.file.openDownloadStream(namespaces[type], type, field, recordId);
|
|
101101
|
-
}
|
|
101102
|
-
` + "\n"
|
|
101103
|
-
].join("\n");
|
|
101104
|
-
}
|
|
101105
|
-
|
|
101106
|
-
//#endregion
|
|
101107
|
-
//#region src/cli/generator/builtin/file-utils/process-file-type.ts
|
|
101108
|
-
/**
|
|
101109
|
-
* Process a TailorDB type and extract file field metadata.
|
|
101110
|
-
* @param type - The parsed TailorDB type to process
|
|
101111
|
-
* @returns File utility metadata for the type
|
|
101112
|
-
*/
|
|
101113
|
-
async function processFileType(type) {
|
|
101114
|
-
const fileFields = [];
|
|
101115
|
-
if (type.files) for (const fileFieldName of Object.keys(type.files)) fileFields.push(fileFieldName);
|
|
101116
|
-
return {
|
|
101117
|
-
name: type.name,
|
|
101118
|
-
fileFields
|
|
101119
|
-
};
|
|
101120
|
-
}
|
|
101121
|
-
|
|
101122
|
-
//#endregion
|
|
101123
|
-
//#region src/cli/generator/builtin/file-utils/index.ts
|
|
101124
|
-
const FileUtilsGeneratorID = "@tailor-platform/file-utils";
|
|
101125
|
-
/**
|
|
101126
|
-
* Create a file utilities generator from TailorDB type definitions.
|
|
101127
|
-
* @param options - Generator options
|
|
101128
|
-
* @param options.distPath - Output file path
|
|
101129
|
-
* @returns TailorDB generator instance
|
|
101130
|
-
*/
|
|
101131
|
-
function createFileUtilsGenerator(options) {
|
|
101132
|
-
return {
|
|
101133
|
-
id: FileUtilsGeneratorID,
|
|
101134
|
-
description: "Generates TypeWithFiles interface from TailorDB type definitions",
|
|
101135
|
-
dependencies: ["tailordb"],
|
|
101136
|
-
async processType(args) {
|
|
101137
|
-
return await processFileType(args.type);
|
|
101138
|
-
},
|
|
101139
|
-
async processTailorDBNamespace(args) {
|
|
101140
|
-
const typesWithFiles = Object.values(args.types).filter((t) => t.fileFields.length > 0);
|
|
101141
|
-
if (typesWithFiles.length === 0) return "";
|
|
101142
|
-
return JSON.stringify({
|
|
101143
|
-
namespace: args.namespace,
|
|
101144
|
-
types: typesWithFiles
|
|
101145
|
-
});
|
|
101146
|
-
},
|
|
101147
|
-
aggregate(args) {
|
|
101148
|
-
const files = [];
|
|
101149
|
-
const allNamespaceData = [];
|
|
101150
|
-
for (const nsResult of args.input.tailordb) if (nsResult.types) try {
|
|
101151
|
-
const parsed = JSON.parse(nsResult.types);
|
|
101152
|
-
if (parsed.namespace && parsed.types) allNamespaceData.push(parsed);
|
|
101153
|
-
} catch {}
|
|
101154
|
-
if (allNamespaceData.length > 0) {
|
|
101155
|
-
const content = generateUnifiedFileUtils(allNamespaceData);
|
|
101156
|
-
if (content) files.push({
|
|
101157
|
-
path: options.distPath,
|
|
101158
|
-
content
|
|
101159
|
-
});
|
|
101160
|
-
}
|
|
101161
|
-
return { files };
|
|
101162
|
-
}
|
|
101163
|
-
};
|
|
101164
|
-
}
|
|
101165
|
-
|
|
101166
|
-
//#endregion
|
|
101167
|
-
//#region src/cli/generator/builtin/kysely-type/type-processor.ts
|
|
101168
|
-
/**
|
|
101169
|
-
* Get the enum type definition.
|
|
101170
|
-
* @param fieldConfig - The field configuration
|
|
101171
|
-
* @returns The enum type as a string union
|
|
101172
|
-
*/
|
|
101173
|
-
function getEnumType(fieldConfig) {
|
|
101174
|
-
const allowedValues = fieldConfig.allowedValues;
|
|
101175
|
-
if (allowedValues && Array.isArray(allowedValues)) return allowedValues.map((v) => {
|
|
101176
|
-
return `"${typeof v === "string" ? v : v.value}"`;
|
|
101177
|
-
}).join(" | ");
|
|
101178
|
-
return "string";
|
|
101179
|
-
}
|
|
101180
|
-
/**
|
|
101181
|
-
* Get the nested object type definition.
|
|
101182
|
-
* @param fieldConfig - The field configuration
|
|
101183
|
-
* @returns The nested type with used utility types
|
|
101184
|
-
*/
|
|
101185
|
-
function getNestedType(fieldConfig) {
|
|
101186
|
-
const fields = fieldConfig.fields;
|
|
101187
|
-
if (!fields || typeof fields !== "object") return {
|
|
101188
|
-
type: "string",
|
|
101189
|
-
usedUtilityTypes: {
|
|
101190
|
-
Timestamp: false,
|
|
101191
|
-
Serial: false
|
|
101192
|
-
}
|
|
101193
|
-
};
|
|
101194
|
-
const fieldResults = Object.entries(fields).map(([fieldName, nestedOperatorFieldConfig]) => ({
|
|
101195
|
-
fieldName,
|
|
101196
|
-
...generateFieldType(nestedOperatorFieldConfig)
|
|
101197
|
-
}));
|
|
101198
|
-
const fieldTypes = fieldResults.map((result) => `${result.fieldName}: ${result.type}`);
|
|
101199
|
-
const aggregatedUtilityTypes = fieldResults.reduce((acc, result) => ({
|
|
101200
|
-
Timestamp: acc.Timestamp || result.usedUtilityTypes.Timestamp,
|
|
101201
|
-
Serial: acc.Serial || result.usedUtilityTypes.Serial
|
|
101202
|
-
}), {
|
|
101203
|
-
Timestamp: false,
|
|
101204
|
-
Serial: false
|
|
101205
|
-
});
|
|
101206
|
-
return {
|
|
101207
|
-
type: `{\n ${fieldTypes.join(";\n ")}${fieldTypes.length > 0 ? ";" : ""}\n}`,
|
|
101208
|
-
usedUtilityTypes: aggregatedUtilityTypes
|
|
101209
|
-
};
|
|
101210
|
-
}
|
|
101211
|
-
/**
|
|
101212
|
-
* Get the base Kysely type for a field (without array/null modifiers).
|
|
101213
|
-
* @param fieldConfig - The field configuration
|
|
101214
|
-
* @returns The base type with used utility types
|
|
101215
|
-
*/
|
|
101216
|
-
function getBaseType(fieldConfig) {
|
|
101217
|
-
const fieldType = fieldConfig.type;
|
|
101218
|
-
const usedUtilityTypes = {
|
|
101219
|
-
Timestamp: false,
|
|
101220
|
-
Serial: false
|
|
101221
|
-
};
|
|
101222
|
-
let type;
|
|
101223
|
-
switch (fieldType) {
|
|
101224
|
-
case "uuid":
|
|
101225
|
-
case "string":
|
|
101226
|
-
type = "string";
|
|
101227
|
-
break;
|
|
101228
|
-
case "integer":
|
|
101229
|
-
case "float":
|
|
101230
|
-
type = "number";
|
|
101231
|
-
break;
|
|
101232
|
-
case "date":
|
|
101233
|
-
case "datetime":
|
|
101234
|
-
usedUtilityTypes.Timestamp = true;
|
|
101235
|
-
type = "Timestamp";
|
|
101236
|
-
break;
|
|
101237
|
-
case "bool":
|
|
101238
|
-
case "boolean":
|
|
101239
|
-
type = "boolean";
|
|
101240
|
-
break;
|
|
101241
|
-
case "enum":
|
|
101242
|
-
type = getEnumType(fieldConfig);
|
|
101243
|
-
break;
|
|
101244
|
-
case "nested": return getNestedType(fieldConfig);
|
|
101245
|
-
default:
|
|
101246
|
-
type = "string";
|
|
101247
|
-
break;
|
|
101248
|
-
}
|
|
101249
|
-
return {
|
|
101250
|
-
type,
|
|
101251
|
-
usedUtilityTypes
|
|
101252
|
-
};
|
|
101253
|
-
}
|
|
101254
|
-
/**
|
|
101255
|
-
* Generate the complete field type including array and null modifiers.
|
|
101256
|
-
* @param fieldConfig - The field configuration
|
|
101257
|
-
* @returns The complete field type with used utility types
|
|
101258
|
-
*/
|
|
101259
|
-
function generateFieldType(fieldConfig) {
|
|
101260
|
-
const baseTypeResult = getBaseType(fieldConfig);
|
|
101261
|
-
const usedUtilityTypes = { ...baseTypeResult.usedUtilityTypes };
|
|
101262
|
-
const isArray$1 = fieldConfig.array === true;
|
|
101263
|
-
const isNullable = fieldConfig.required !== true;
|
|
101264
|
-
let finalType = baseTypeResult.type;
|
|
101265
|
-
if (isArray$1) finalType = fieldConfig.type === "enum" ? `(${baseTypeResult.type})[]` : `${baseTypeResult.type}[]`;
|
|
101266
|
-
if (isNullable) finalType = `${finalType} | null`;
|
|
101267
|
-
if (fieldConfig.serial) {
|
|
101268
|
-
usedUtilityTypes.Serial = true;
|
|
101269
|
-
finalType = `Serial<${finalType}>`;
|
|
101270
|
-
}
|
|
101271
|
-
if (fieldConfig.hooks?.create) finalType = `Generated<${finalType}>`;
|
|
101272
|
-
return {
|
|
101273
|
-
type: finalType,
|
|
101274
|
-
usedUtilityTypes
|
|
101275
|
-
};
|
|
101276
|
-
}
|
|
101277
|
-
/**
|
|
101278
|
-
* Generate the table interface.
|
|
101279
|
-
* @param type - The parsed TailorDB type
|
|
101280
|
-
* @returns The type definition and used utility types
|
|
101281
|
-
*/
|
|
101282
|
-
function generateTableInterface(type) {
|
|
101283
|
-
const fieldResults = Object.entries(type.fields).filter(([fieldName]) => fieldName !== "id").map(([fieldName, parsedField]) => ({
|
|
101284
|
-
fieldName,
|
|
101285
|
-
...generateFieldType(parsedField.config)
|
|
101286
|
-
}));
|
|
101287
|
-
const fields = ["id: Generated<string>;", ...fieldResults.map((result) => `${result.fieldName}: ${result.type};`)];
|
|
101288
|
-
const aggregatedUtilityTypes = fieldResults.reduce((acc, result) => ({
|
|
101289
|
-
Timestamp: acc.Timestamp || result.usedUtilityTypes.Timestamp,
|
|
101290
|
-
Serial: acc.Serial || result.usedUtilityTypes.Serial
|
|
101291
|
-
}), {
|
|
101292
|
-
Timestamp: false,
|
|
101293
|
-
Serial: false
|
|
101294
|
-
});
|
|
101295
|
-
return {
|
|
101296
|
-
typeDef: ml`
|
|
101297
|
-
${type.name}: {
|
|
101298
|
-
${fields.join("\n")}
|
|
101299
|
-
}
|
|
101300
|
-
`,
|
|
101301
|
-
usedUtilityTypes: aggregatedUtilityTypes
|
|
101302
|
-
};
|
|
101303
|
-
}
|
|
101304
|
-
/**
|
|
101305
|
-
* Convert a TailorDBType into KyselyTypeMetadata.
|
|
101306
|
-
* @param type - Parsed TailorDB type
|
|
101307
|
-
* @returns Generated Kysely type metadata
|
|
101308
|
-
*/
|
|
101309
|
-
async function processKyselyType(type) {
|
|
101310
|
-
const result = generateTableInterface(type);
|
|
101311
|
-
return {
|
|
101312
|
-
name: type.name,
|
|
101313
|
-
typeDef: result.typeDef,
|
|
101314
|
-
usedUtilityTypes: result.usedUtilityTypes
|
|
101315
|
-
};
|
|
101316
|
-
}
|
|
101317
|
-
/**
|
|
101318
|
-
* Generate unified types file from multiple namespaces.
|
|
101319
|
-
* @param namespaceData - Namespace metadata
|
|
101320
|
-
* @returns Generated types file contents
|
|
101321
|
-
*/
|
|
101322
|
-
function generateUnifiedKyselyTypes(namespaceData) {
|
|
101323
|
-
if (namespaceData.length === 0) return "";
|
|
101324
|
-
const globalUsedUtilityTypes = namespaceData.reduce((acc, ns) => ({
|
|
101325
|
-
Timestamp: acc.Timestamp || ns.usedUtilityTypes.Timestamp,
|
|
101326
|
-
Serial: acc.Serial || ns.usedUtilityTypes.Serial
|
|
101327
|
-
}), {
|
|
101328
|
-
Timestamp: false,
|
|
101329
|
-
Serial: false
|
|
101330
|
-
});
|
|
101331
|
-
const utilityTypeImports = ["type Generated"];
|
|
101332
|
-
if (globalUsedUtilityTypes.Timestamp) utilityTypeImports.push("type Timestamp");
|
|
101333
|
-
if (globalUsedUtilityTypes.Serial) utilityTypeImports.push("type Serial");
|
|
101334
|
-
return [
|
|
101335
|
-
ml`
|
|
101336
|
-
import {
|
|
101337
|
-
createGetDB,
|
|
101338
|
-
${utilityTypeImports.join(",\n")},
|
|
101339
|
-
type NamespaceDB,
|
|
101340
|
-
type NamespaceInsertable,
|
|
101341
|
-
type NamespaceSelectable,
|
|
101342
|
-
type NamespaceTable,
|
|
101343
|
-
type NamespaceTableName,
|
|
101344
|
-
type NamespaceTransaction,
|
|
101345
|
-
type NamespaceUpdateable,
|
|
101346
|
-
} from "@tailor-platform/sdk/kysely";
|
|
101347
|
-
`,
|
|
101348
|
-
`export interface Namespace {\n${namespaceData.map(({ namespace, types: types$2 }) => {
|
|
101349
|
-
return ` "${namespace}": {\n${types$2.map((type) => {
|
|
101350
|
-
return type.typeDef.split("\n").map((line) => line.trim() ? ` ${line}` : "").join("\n");
|
|
101351
|
-
}).join("\n\n")}\n }`;
|
|
101352
|
-
}).join(",\n")}\n}`,
|
|
101353
|
-
ml`
|
|
101354
|
-
export const getDB = createGetDB<Namespace>();
|
|
101355
|
-
|
|
101356
|
-
export type DB<N extends keyof Namespace = keyof Namespace> = NamespaceDB<Namespace, N>;
|
|
101357
|
-
`,
|
|
101358
|
-
ml`
|
|
101359
|
-
export type Transaction<K extends keyof Namespace | DB = keyof Namespace> =
|
|
101360
|
-
NamespaceTransaction<Namespace, K>;
|
|
101361
|
-
|
|
101362
|
-
type TableName = NamespaceTableName<Namespace>;
|
|
101363
|
-
export type Table<T extends TableName> = NamespaceTable<Namespace, T>;
|
|
101364
|
-
|
|
101365
|
-
export type Insertable<T extends TableName> = NamespaceInsertable<Namespace, T>;
|
|
101366
|
-
export type Selectable<T extends TableName> = NamespaceSelectable<Namespace, T>;
|
|
101367
|
-
export type Updateable<T extends TableName> = NamespaceUpdateable<Namespace, T>;
|
|
101368
|
-
`
|
|
101369
|
-
].join("\n\n") + "\n";
|
|
101370
|
-
}
|
|
101371
|
-
|
|
101372
|
-
//#endregion
|
|
101373
|
-
//#region src/cli/generator/builtin/kysely-type/index.ts
|
|
101374
|
-
const KyselyGeneratorID = "@tailor-platform/kysely-type";
|
|
101375
|
-
/**
|
|
101376
|
-
* Create a Kysely type generator for TailorDB types.
|
|
101377
|
-
* @param options - Generator options
|
|
101378
|
-
* @param options.distPath - Output file path
|
|
101379
|
-
* @returns TailorDB generator instance
|
|
101380
|
-
*/
|
|
101381
|
-
function createKyselyGenerator(options) {
|
|
101382
|
-
return {
|
|
101383
|
-
id: KyselyGeneratorID,
|
|
101384
|
-
description: "Generates Kysely type definitions for TailorDB types",
|
|
101385
|
-
dependencies: ["tailordb"],
|
|
101386
|
-
async processType(args) {
|
|
101387
|
-
return await processKyselyType(args.type);
|
|
101388
|
-
},
|
|
101389
|
-
async processTailorDBNamespace(args) {
|
|
101390
|
-
const typesList = Object.values(args.types);
|
|
101391
|
-
const usedUtilityTypes = typesList.reduce((acc, type) => ({
|
|
101392
|
-
Timestamp: acc.Timestamp || type.usedUtilityTypes.Timestamp,
|
|
101393
|
-
Serial: acc.Serial || type.usedUtilityTypes.Serial
|
|
101394
|
-
}), {
|
|
101395
|
-
Timestamp: false,
|
|
101396
|
-
Serial: false
|
|
101397
|
-
});
|
|
101398
|
-
return {
|
|
101399
|
-
namespace: args.namespace,
|
|
101400
|
-
types: typesList,
|
|
101401
|
-
usedUtilityTypes
|
|
101402
|
-
};
|
|
101403
|
-
},
|
|
101404
|
-
aggregate(args) {
|
|
101405
|
-
const files = [];
|
|
101406
|
-
const allNamespaceData = [];
|
|
101407
|
-
for (const nsResult of args.input.tailordb) if (nsResult.types && nsResult.types.types.length > 0) allNamespaceData.push(nsResult.types);
|
|
101408
|
-
if (allNamespaceData.length > 0) {
|
|
101409
|
-
const content = generateUnifiedKyselyTypes(allNamespaceData);
|
|
101410
|
-
files.push({
|
|
101411
|
-
path: options.distPath,
|
|
101412
|
-
content
|
|
101413
|
-
});
|
|
101414
|
-
}
|
|
101415
|
-
return { files };
|
|
101416
|
-
}
|
|
101417
|
-
};
|
|
101418
|
-
}
|
|
101419
|
-
|
|
101420
|
-
//#endregion
|
|
101421
|
-
//#region src/cli/generator/builtin/seed/idp-user-processor.ts
|
|
101422
|
-
/**
|
|
101423
|
-
* Processes auth configuration to generate IdP user seed metadata
|
|
101424
|
-
* @param auth - Auth configuration from generator
|
|
101425
|
-
* @returns IdP user metadata or undefined if not applicable
|
|
101426
|
-
*/
|
|
101427
|
-
function processIdpUser(auth) {
|
|
101428
|
-
if (auth.idProvider?.kind !== "BuiltInIdP" || !auth.userProfile) return;
|
|
101429
|
-
const { typeName, usernameField } = auth.userProfile;
|
|
101430
|
-
return {
|
|
101431
|
-
name: "_User",
|
|
101432
|
-
dependencies: [typeName],
|
|
101433
|
-
dataFile: "data/_User.jsonl",
|
|
101434
|
-
idpNamespace: auth.idProvider.namespace,
|
|
101435
|
-
schema: {
|
|
101436
|
-
usernameField,
|
|
101437
|
-
userTypeName: typeName
|
|
101438
|
-
}
|
|
101439
|
-
};
|
|
101440
|
-
}
|
|
101441
|
-
/**
|
|
101442
|
-
* Generates the server-side IDP seed script code for testExecScript execution.
|
|
101443
|
-
* Uses the global tailor.idp.Client - no bundling required.
|
|
101444
|
-
* @param idpNamespace - The IDP namespace name
|
|
101445
|
-
* @returns Script code string
|
|
101446
|
-
*/
|
|
101447
|
-
function generateIdpSeedScriptCode(idpNamespace) {
|
|
101448
|
-
return ml`
|
|
101449
|
-
export async function main(input) {
|
|
101450
|
-
const client = new tailor.idp.Client({ namespace: "${idpNamespace}" });
|
|
101451
|
-
const errors = [];
|
|
101452
|
-
let processed = 0;
|
|
101453
|
-
|
|
101454
|
-
for (let i = 0; i < input.users.length; i++) {
|
|
101455
|
-
try {
|
|
101456
|
-
await client.createUser(input.users[i]);
|
|
101457
|
-
processed++;
|
|
101458
|
-
console.log(\`[_User] \${i + 1}/\${input.users.length}: \${input.users[i].name}\`);
|
|
101459
|
-
} catch (error) {
|
|
101460
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
101461
|
-
errors.push(\`Row \${i} (\${input.users[i].name}): \${message}\`);
|
|
101462
|
-
console.error(\`[_User] Row \${i} failed: \${message}\`);
|
|
101463
|
-
}
|
|
101464
|
-
}
|
|
101465
|
-
|
|
101466
|
-
return {
|
|
101467
|
-
success: errors.length === 0,
|
|
101468
|
-
processed,
|
|
101469
|
-
errors,
|
|
101470
|
-
};
|
|
101471
|
-
}
|
|
101472
|
-
`;
|
|
101473
|
-
}
|
|
101474
|
-
/**
|
|
101475
|
-
* Generates the server-side IDP truncation script code for testExecScript execution.
|
|
101476
|
-
* Lists all users with pagination and deletes each one.
|
|
101477
|
-
* @param idpNamespace - The IDP namespace name
|
|
101478
|
-
* @returns Script code string
|
|
101479
|
-
*/
|
|
101480
|
-
function generateIdpTruncateScriptCode(idpNamespace) {
|
|
101481
|
-
return ml`
|
|
101482
|
-
export async function main() {
|
|
101483
|
-
const client = new tailor.idp.Client({ namespace: "${idpNamespace}" });
|
|
101484
|
-
const errors = [];
|
|
101485
|
-
let deleted = 0;
|
|
101486
|
-
|
|
101487
|
-
// List all users with pagination
|
|
101488
|
-
let nextToken = undefined;
|
|
101489
|
-
const allUsers = [];
|
|
101490
|
-
do {
|
|
101491
|
-
const response = await client.users(nextToken ? { nextToken } : undefined);
|
|
101492
|
-
allUsers.push(...(response.users || []));
|
|
101493
|
-
nextToken = response.nextToken;
|
|
101494
|
-
} while (nextToken);
|
|
101495
|
-
|
|
101496
|
-
console.log(\`Found \${allUsers.length} IDP users to delete\`);
|
|
101497
|
-
|
|
101498
|
-
for (const user of allUsers) {
|
|
101499
|
-
try {
|
|
101500
|
-
await client.deleteUser(user.id);
|
|
101501
|
-
deleted++;
|
|
101502
|
-
console.log(\`[_User] Deleted \${deleted}/\${allUsers.length}: \${user.name}\`);
|
|
101503
|
-
} catch (error) {
|
|
101504
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
101505
|
-
errors.push(\`User \${user.id} (\${user.name}): \${message}\`);
|
|
101506
|
-
console.error(\`[_User] Delete failed for \${user.name}: \${message}\`);
|
|
101507
|
-
}
|
|
101508
|
-
}
|
|
101509
|
-
|
|
101510
|
-
return {
|
|
101511
|
-
success: errors.length === 0,
|
|
101512
|
-
deleted,
|
|
101513
|
-
total: allUsers.length,
|
|
101514
|
-
errors,
|
|
101515
|
-
};
|
|
101516
|
-
}
|
|
101517
|
-
`;
|
|
101518
|
-
}
|
|
101519
|
-
/**
|
|
101520
|
-
* Generates the schema file content for IdP users with foreign key
|
|
101521
|
-
* @param usernameField - Username field name
|
|
101522
|
-
* @param userTypeName - TailorDB user type name
|
|
101523
|
-
* @returns Schema file contents
|
|
101524
|
-
*/
|
|
101525
|
-
function generateIdpUserSchemaFile(usernameField, userTypeName) {
|
|
101526
|
-
return ml`
|
|
101527
|
-
import { t } from "@tailor-platform/sdk";
|
|
101528
|
-
import { createStandardSchema } from "@tailor-platform/sdk/test";
|
|
101529
|
-
import { defineSchema } from "@toiroakr/lines-db";
|
|
101530
|
-
|
|
101531
|
-
const schemaType = t.object({
|
|
101532
|
-
name: t.string(),
|
|
101533
|
-
password: t.string(),
|
|
101534
|
-
});
|
|
101535
|
-
|
|
101536
|
-
// Simple identity hook for _User (no TailorDB backing type)
|
|
101537
|
-
const hook = <T>(data: unknown) => data as T;
|
|
101538
|
-
|
|
101539
|
-
export const schema = defineSchema(
|
|
101540
|
-
createStandardSchema(schemaType, hook),
|
|
101541
|
-
{
|
|
101542
|
-
primaryKey: "name",
|
|
101543
|
-
indexes: [
|
|
101544
|
-
{ name: "_user_name_unique_idx", columns: ["name"], unique: true },
|
|
101545
|
-
],
|
|
101546
|
-
foreignKeys: [
|
|
101547
|
-
{
|
|
101548
|
-
column: "name",
|
|
101549
|
-
references: {
|
|
101550
|
-
table: "${userTypeName}",
|
|
101551
|
-
column: "${usernameField}",
|
|
101552
|
-
},
|
|
101553
|
-
},
|
|
101554
|
-
],
|
|
101555
|
-
}
|
|
101556
|
-
);
|
|
101557
|
-
|
|
101558
|
-
`;
|
|
101559
|
-
}
|
|
101560
|
-
|
|
101561
|
-
//#endregion
|
|
101562
|
-
//#region src/cli/generator/builtin/seed/lines-db-processor.ts
|
|
101563
|
-
/**
|
|
101564
|
-
* Processes TailorDB types to generate lines-db metadata
|
|
101565
|
-
* @param type - Parsed TailorDB type
|
|
101566
|
-
* @param source - Source file info
|
|
101567
|
-
* @returns Generated lines-db metadata
|
|
101568
|
-
*/
|
|
101569
|
-
function processLinesDb(type, source) {
|
|
101570
|
-
if (isPluginGeneratedType(source)) return processLinesDbForPluginType(type, source);
|
|
101571
|
-
if (!source.filePath) throw new Error(`Missing source info for type ${type.name}`);
|
|
101572
|
-
if (!source.exportName) throw new Error(`Missing export name for type ${type.name}`);
|
|
101573
|
-
const { optionalFields, omitFields, indexes, foreignKeys } = extractFieldMetadata(type);
|
|
101574
|
-
return {
|
|
101575
|
-
typeName: type.name,
|
|
101576
|
-
exportName: source.exportName,
|
|
101577
|
-
importPath: source.filePath,
|
|
101578
|
-
optionalFields,
|
|
101579
|
-
omitFields,
|
|
101580
|
-
foreignKeys,
|
|
101581
|
-
indexes
|
|
101582
|
-
};
|
|
101583
|
-
}
|
|
101584
|
-
/**
|
|
101585
|
-
* Process lines-db metadata for plugin-generated types
|
|
101586
|
-
* @param type - Parsed TailorDB type
|
|
101587
|
-
* @param source - Plugin-generated type source info
|
|
101588
|
-
* @returns Generated lines-db metadata with plugin source
|
|
101589
|
-
*/
|
|
101590
|
-
function processLinesDbForPluginType(type, source) {
|
|
101591
|
-
const { optionalFields, omitFields, indexes, foreignKeys } = extractFieldMetadata(type);
|
|
101592
|
-
return {
|
|
101593
|
-
typeName: type.name,
|
|
101594
|
-
exportName: source.exportName,
|
|
101595
|
-
importPath: "",
|
|
101596
|
-
optionalFields,
|
|
101597
|
-
omitFields,
|
|
101598
|
-
foreignKeys,
|
|
101599
|
-
indexes,
|
|
101600
|
-
pluginSource: source
|
|
101601
|
-
};
|
|
101602
|
-
}
|
|
101603
|
-
/**
|
|
101604
|
-
* Extract field metadata from TailorDB type
|
|
101605
|
-
* @param type - Parsed TailorDB type
|
|
101606
|
-
* @returns Field metadata including optional fields, omit fields, indexes, and foreign keys
|
|
101607
|
-
*/
|
|
101608
|
-
function extractFieldMetadata(type) {
|
|
101609
|
-
const optionalFields = ["id"];
|
|
101610
|
-
const omitFields = [];
|
|
101611
|
-
const indexes = [];
|
|
101612
|
-
const foreignKeys = [];
|
|
101613
|
-
for (const [fieldName, field] of Object.entries(type.fields)) {
|
|
101614
|
-
if (field.config.hooks?.create) optionalFields.push(fieldName);
|
|
101615
|
-
if (field.config.serial) omitFields.push(fieldName);
|
|
101616
|
-
if (field.config.unique) indexes.push({
|
|
101617
|
-
name: `${type.name.toLowerCase()}_${fieldName}_unique_idx`,
|
|
101618
|
-
columns: [fieldName],
|
|
101619
|
-
unique: true
|
|
101620
|
-
});
|
|
101621
|
-
}
|
|
101622
|
-
if (type.indexes) for (const [indexName, indexDef] of Object.entries(type.indexes)) indexes.push({
|
|
101623
|
-
name: indexName,
|
|
101624
|
-
columns: indexDef.fields,
|
|
101625
|
-
unique: indexDef.unique
|
|
101626
|
-
});
|
|
101627
|
-
for (const [fieldName, field] of Object.entries(type.fields)) if (field.relation) foreignKeys.push({
|
|
101628
|
-
column: fieldName,
|
|
101629
|
-
references: {
|
|
101630
|
-
table: field.relation.targetType,
|
|
101631
|
-
column: field.relation.key
|
|
101632
|
-
}
|
|
101633
|
-
});
|
|
101634
|
-
return {
|
|
101635
|
-
optionalFields,
|
|
101636
|
-
omitFields,
|
|
101637
|
-
indexes,
|
|
101638
|
-
foreignKeys
|
|
101639
|
-
};
|
|
101640
|
-
}
|
|
101641
|
-
/**
|
|
101642
|
-
* Generate schema options code for lines-db
|
|
101643
|
-
* @param foreignKeys - Foreign key definitions
|
|
101644
|
-
* @param indexes - Index definitions
|
|
101645
|
-
* @returns Schema options code string
|
|
101646
|
-
*/
|
|
101647
|
-
function generateSchemaOptions(foreignKeys, indexes) {
|
|
101648
|
-
const schemaOptions = [];
|
|
101649
|
-
if (foreignKeys.length > 0) {
|
|
101650
|
-
schemaOptions.push(`foreignKeys: [`);
|
|
101651
|
-
foreignKeys.forEach((fk) => {
|
|
101652
|
-
schemaOptions.push(` ${JSON.stringify(fk)},`);
|
|
101653
|
-
});
|
|
101654
|
-
schemaOptions.push(`],`);
|
|
101655
|
-
}
|
|
101656
|
-
if (indexes.length > 0) {
|
|
101657
|
-
schemaOptions.push(`indexes: [`);
|
|
101658
|
-
indexes.forEach((index$1) => {
|
|
101659
|
-
schemaOptions.push(` ${JSON.stringify(index$1)},`);
|
|
101660
|
-
});
|
|
101661
|
-
schemaOptions.push("],");
|
|
101662
|
-
}
|
|
101663
|
-
return schemaOptions.length > 0 ? [
|
|
101664
|
-
"\n {",
|
|
101665
|
-
...schemaOptions.map((option) => ` ${option}`),
|
|
101666
|
-
" }"
|
|
101667
|
-
].join("\n") : "";
|
|
101668
|
-
}
|
|
101669
|
-
/**
|
|
101670
|
-
* Generates the schema file content for lines-db (for user-defined types with import)
|
|
101671
|
-
* @param metadata - lines-db metadata
|
|
101672
|
-
* @param importPath - Import path for the TailorDB type
|
|
101673
|
-
* @returns Schema file contents
|
|
101674
|
-
*/
|
|
101675
|
-
function generateLinesDbSchemaFile(metadata, importPath) {
|
|
101676
|
-
const { exportName, optionalFields, omitFields, foreignKeys, indexes } = metadata;
|
|
101677
|
-
return ml`
|
|
101678
|
-
import { t } from "@tailor-platform/sdk";
|
|
101679
|
-
import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
|
|
101680
|
-
import { defineSchema } from "@toiroakr/lines-db";
|
|
101681
|
-
import { ${exportName} } from "${importPath}";
|
|
101682
|
-
|
|
101683
|
-
${ml`
|
|
101684
|
-
const schemaType = t.object({
|
|
101685
|
-
...${exportName}.pickFields(${JSON.stringify(optionalFields)}, { optional: true }),
|
|
101686
|
-
...${exportName}.omitFields(${JSON.stringify([...optionalFields, ...omitFields])}),
|
|
101687
|
-
});
|
|
101688
|
-
`}
|
|
101689
|
-
|
|
101690
|
-
const hook = createTailorDBHook(${exportName});
|
|
101691
|
-
|
|
101692
|
-
export const schema = defineSchema(
|
|
101693
|
-
createStandardSchema(schemaType, hook),${generateSchemaOptions(foreignKeys, indexes)}
|
|
101694
|
-
);
|
|
101695
|
-
|
|
101696
|
-
`;
|
|
101697
|
-
}
|
|
101698
|
-
/**
|
|
101699
|
-
* Generates the schema file content using getGeneratedType API
|
|
101700
|
-
* (for plugin-generated types)
|
|
101701
|
-
* @param metadata - lines-db metadata (must have pluginSource)
|
|
101702
|
-
* @param params - Plugin import paths
|
|
101703
|
-
* @returns Schema file contents
|
|
101704
|
-
*/
|
|
101705
|
-
function generateLinesDbSchemaFileWithPluginAPI(metadata, params) {
|
|
101706
|
-
const { typeName, exportName, optionalFields, omitFields, foreignKeys, indexes, pluginSource } = metadata;
|
|
101707
|
-
if (!pluginSource) throw new Error(`pluginSource is required for plugin-generated type "${typeName}"`);
|
|
101708
|
-
const { configImportPath, originalImportPath } = params;
|
|
101709
|
-
const schemaTypeCode = ml`
|
|
101710
|
-
const schemaType = t.object({
|
|
101711
|
-
...${exportName}.pickFields(${JSON.stringify(optionalFields)}, { optional: true }),
|
|
101712
|
-
...${exportName}.omitFields(${JSON.stringify([...optionalFields, ...omitFields])}),
|
|
101713
|
-
});
|
|
101714
|
-
`;
|
|
101715
|
-
const schemaOptionsCode = generateSchemaOptions(foreignKeys, indexes);
|
|
101716
|
-
if (pluginSource.originalExportName && originalImportPath && pluginSource.generatedTypeKind) return ml`
|
|
101717
|
-
import { join } from "node:path";
|
|
101718
|
-
import { t } from "@tailor-platform/sdk";
|
|
101719
|
-
import { getGeneratedType } from "@tailor-platform/sdk/plugin";
|
|
101720
|
-
import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
|
|
101721
|
-
import { defineSchema } from "@toiroakr/lines-db";
|
|
101722
|
-
import { ${pluginSource.originalExportName} } from "${originalImportPath}";
|
|
101723
|
-
|
|
101724
|
-
const configPath = join(import.meta.dirname, "${configImportPath}");
|
|
101725
|
-
const ${exportName} = await getGeneratedType(configPath, "${pluginSource.pluginId}", ${pluginSource.originalExportName}, "${pluginSource.generatedTypeKind}");
|
|
101726
|
-
|
|
101727
|
-
${schemaTypeCode}
|
|
101728
|
-
|
|
101729
|
-
const hook = createTailorDBHook(${exportName});
|
|
101730
|
-
|
|
101731
|
-
export const schema = defineSchema(
|
|
101732
|
-
createStandardSchema(schemaType, hook),${schemaOptionsCode}
|
|
101733
|
-
);
|
|
101734
|
-
|
|
101735
|
-
`;
|
|
101736
|
-
if (!pluginSource.generatedTypeKind) throw new Error(`Namespace plugin "${pluginSource.pluginId}" must provide generatedTypeKind for type "${typeName}"`);
|
|
101737
|
-
return ml`
|
|
101738
|
-
import { join } from "node:path";
|
|
101739
|
-
import { t } from "@tailor-platform/sdk";
|
|
101740
|
-
import { getGeneratedType } from "@tailor-platform/sdk/plugin";
|
|
101741
|
-
import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
|
|
101742
|
-
import { defineSchema } from "@toiroakr/lines-db";
|
|
101743
|
-
|
|
101744
|
-
const configPath = join(import.meta.dirname, "${configImportPath}");
|
|
101745
|
-
const ${exportName} = await getGeneratedType(configPath, "${pluginSource.pluginId}", null, "${pluginSource.generatedTypeKind}");
|
|
101746
|
-
|
|
101747
|
-
${schemaTypeCode}
|
|
101748
|
-
|
|
101749
|
-
const hook = createTailorDBHook(${exportName});
|
|
101750
|
-
|
|
101751
|
-
export const schema = defineSchema(
|
|
101752
|
-
createStandardSchema(schemaType, hook),${schemaOptionsCode}
|
|
101753
|
-
);
|
|
101754
|
-
|
|
101755
|
-
`;
|
|
101756
|
-
}
|
|
101757
|
-
|
|
101758
|
-
//#endregion
|
|
101759
|
-
//#region src/cli/generator/builtin/seed/seed-type-processor.ts
|
|
101760
|
-
/**
|
|
101761
|
-
* Processes TailorDB types to extract seed type information
|
|
101762
|
-
* @param type - Parsed TailorDB type
|
|
101763
|
-
* @param namespace - Namespace of the type
|
|
101764
|
-
* @returns Seed type information
|
|
101765
|
-
*/
|
|
101766
|
-
function processSeedTypeInfo(type, namespace) {
|
|
101767
|
-
const dependencies = Array.from(Object.values(type.fields).reduce((set$1, field) => {
|
|
101768
|
-
const targetType = field.relation?.targetType ?? field.config.foreignKeyType;
|
|
101769
|
-
if (targetType && targetType !== type.name) set$1.add(targetType);
|
|
101770
|
-
return set$1;
|
|
101771
|
-
}, /* @__PURE__ */ new Set()));
|
|
101772
|
-
return {
|
|
101773
|
-
name: type.name,
|
|
101774
|
-
namespace,
|
|
101775
|
-
dependencies,
|
|
101776
|
-
dataFile: `data/${type.name}.jsonl`
|
|
101777
|
-
};
|
|
101778
|
-
}
|
|
101779
|
-
|
|
101780
|
-
//#endregion
|
|
101781
|
-
//#region src/cli/generator/builtin/seed/index.ts
|
|
101782
|
-
const SeedGeneratorID = "@tailor-platform/seed";
|
|
101783
|
-
/**
|
|
101784
|
-
* Generate the IdP user seed function code using tailor.idp.Client via testExecScript
|
|
101785
|
-
* @param hasIdpUser - Whether IdP user is included
|
|
101786
|
-
* @param idpNamespace - The IDP namespace name
|
|
101787
|
-
* @returns JavaScript code for IdP user seeding function
|
|
101788
|
-
*/
|
|
101789
|
-
function generateIdpUserSeedFunction(hasIdpUser, idpNamespace) {
|
|
101790
|
-
if (!hasIdpUser || !idpNamespace) return "";
|
|
101791
|
-
return ml`
|
|
101792
|
-
// Seed _User via tailor.idp.Client (server-side)
|
|
101793
|
-
const seedIdpUser = async () => {
|
|
101794
|
-
console.log(styleText("cyan", " Seeding _User via tailor.idp.Client..."));
|
|
101795
|
-
const dataDir = join(configDir, "data");
|
|
101796
|
-
const data = loadSeedData(dataDir, ["_User"]);
|
|
101797
|
-
const rows = data["_User"] || [];
|
|
101798
|
-
if (rows.length === 0) {
|
|
101799
|
-
console.log(styleText("dim", " No _User data to seed"));
|
|
101800
|
-
return { success: true };
|
|
101801
|
-
}
|
|
101802
|
-
console.log(styleText("dim", \` Processing \${rows.length} _User records...\`));
|
|
101803
|
-
|
|
101804
|
-
const idpSeedCode = \/* js *\/\`${generateIdpSeedScriptCode(idpNamespace).replace(/`/g, "\\`").replace(/\$/g, "\\$")}\`;
|
|
101805
|
-
|
|
101806
|
-
const result = await executeScript({
|
|
101807
|
-
client: operatorClient,
|
|
101808
|
-
workspaceId,
|
|
101809
|
-
name: "seed-idp-user.ts",
|
|
101810
|
-
code: idpSeedCode,
|
|
101811
|
-
arg: JSON.stringify({ users: rows }),
|
|
101812
|
-
invoker: {
|
|
101813
|
-
namespace: authNamespace,
|
|
101814
|
-
machineUserName,
|
|
101815
|
-
},
|
|
101816
|
-
});
|
|
101817
|
-
|
|
101818
|
-
if (result.logs) {
|
|
101819
|
-
for (const line of result.logs.split("\\n").filter(Boolean)) {
|
|
101820
|
-
console.log(styleText("dim", \` \${line}\`));
|
|
101821
|
-
}
|
|
101822
|
-
}
|
|
101823
|
-
|
|
101824
|
-
if (result.success) {
|
|
101825
|
-
let parsed;
|
|
101826
|
-
try {
|
|
101827
|
-
parsed = JSON.parse(result.result || "{}");
|
|
101828
|
-
} catch (e) {
|
|
101829
|
-
console.error(styleText("red", \` ✗ Failed to parse seed result: \${e.message}\`));
|
|
101830
|
-
return { success: false };
|
|
101831
|
-
}
|
|
101832
|
-
|
|
101833
|
-
if (parsed.processed) {
|
|
101834
|
-
console.log(styleText("green", \` ✓ _User: \${parsed.processed} rows processed\`));
|
|
101835
|
-
}
|
|
101836
|
-
|
|
101837
|
-
if (!parsed.success) {
|
|
101838
|
-
const errors = Array.isArray(parsed.errors) ? parsed.errors : [];
|
|
101839
|
-
for (const err of errors) {
|
|
101840
|
-
console.error(styleText("red", \` ✗ \${err}\`));
|
|
101841
|
-
}
|
|
101842
|
-
return { success: false };
|
|
101843
|
-
}
|
|
101844
|
-
|
|
101845
|
-
return { success: true };
|
|
101846
|
-
} else {
|
|
101847
|
-
console.error(styleText("red", \` ✗ Seed failed: \${result.error}\`));
|
|
101848
|
-
return { success: false };
|
|
101849
|
-
}
|
|
101850
|
-
};
|
|
101851
|
-
`;
|
|
101852
|
-
}
|
|
101853
|
-
/**
|
|
101854
|
-
* Generate the IdP user seed call code
|
|
101855
|
-
* @param hasIdpUser - Whether IdP user is included
|
|
101856
|
-
* @returns JavaScript code for calling IdP user seeding
|
|
101857
|
-
*/
|
|
101858
|
-
function generateIdpUserSeedCall(hasIdpUser) {
|
|
101859
|
-
if (!hasIdpUser) return "";
|
|
101860
|
-
return ml`
|
|
101861
|
-
// Seed _User if included and not skipped
|
|
101862
|
-
const shouldSeedUser = !skipIdp && (!entitiesToProcess || entitiesToProcess.includes("_User"));
|
|
101863
|
-
if (hasIdpUser && shouldSeedUser) {
|
|
101864
|
-
const result = await seedIdpUser();
|
|
101865
|
-
if (!result.success) {
|
|
101866
|
-
allSuccess = false;
|
|
101867
|
-
}
|
|
101868
|
-
}
|
|
101869
|
-
`;
|
|
101870
|
-
}
|
|
101871
|
-
/**
|
|
101872
|
-
* Generate the IdP user truncation function code using tailor.idp.Client via testExecScript
|
|
101873
|
-
* @param hasIdpUser - Whether IdP user is included
|
|
101874
|
-
* @param idpNamespace - The IDP namespace name
|
|
101875
|
-
* @returns JavaScript code for IdP user truncation function
|
|
101876
|
-
*/
|
|
101877
|
-
function generateIdpUserTruncateFunction(hasIdpUser, idpNamespace) {
|
|
101878
|
-
if (!hasIdpUser || !idpNamespace) return "";
|
|
101879
|
-
return ml`
|
|
101880
|
-
// Truncate _User via tailor.idp.Client (server-side)
|
|
101881
|
-
const truncateIdpUser = async () => {
|
|
101882
|
-
console.log(styleText("cyan", "Truncating _User via tailor.idp.Client..."));
|
|
101883
|
-
|
|
101884
|
-
const idpTruncateCode = \/* js *\/\`${generateIdpTruncateScriptCode(idpNamespace).replace(/`/g, "\\`").replace(/\$/g, "\\$")}\`;
|
|
101885
|
-
|
|
101886
|
-
const result = await executeScript({
|
|
101887
|
-
client: operatorClient,
|
|
101888
|
-
workspaceId,
|
|
101889
|
-
name: "truncate-idp-user.ts",
|
|
101890
|
-
code: idpTruncateCode,
|
|
101891
|
-
arg: JSON.stringify({}),
|
|
101892
|
-
invoker: {
|
|
101893
|
-
namespace: authNamespace,
|
|
101894
|
-
machineUserName,
|
|
101895
|
-
},
|
|
101896
|
-
});
|
|
101897
|
-
|
|
101898
|
-
if (result.logs) {
|
|
101899
|
-
for (const line of result.logs.split("\\n").filter(Boolean)) {
|
|
101900
|
-
console.log(styleText("dim", \` \${line}\`));
|
|
101901
|
-
}
|
|
101902
|
-
}
|
|
101903
|
-
|
|
101904
|
-
if (result.success) {
|
|
101905
|
-
let parsed;
|
|
101906
|
-
try {
|
|
101907
|
-
parsed = JSON.parse(result.result || "{}");
|
|
101908
|
-
} catch (e) {
|
|
101909
|
-
console.error(styleText("red", \` ✗ Failed to parse truncation result: \${e.message}\`));
|
|
101910
|
-
return { success: false };
|
|
101911
|
-
}
|
|
101912
|
-
|
|
101913
|
-
if (parsed.deleted !== undefined) {
|
|
101914
|
-
console.log(styleText("green", \` ✓ _User: \${parsed.deleted} users deleted\`));
|
|
101915
|
-
}
|
|
101916
|
-
|
|
101917
|
-
if (!parsed.success) {
|
|
101918
|
-
const errors = Array.isArray(parsed.errors) ? parsed.errors : [];
|
|
101919
|
-
for (const err of errors) {
|
|
101920
|
-
console.error(styleText("red", \` ✗ \${err}\`));
|
|
101921
|
-
}
|
|
101922
|
-
return { success: false };
|
|
101923
|
-
}
|
|
101924
|
-
|
|
101925
|
-
return { success: true };
|
|
101926
|
-
} else {
|
|
101927
|
-
console.error(styleText("red", \` ✗ Truncation failed: \${result.error}\`));
|
|
101928
|
-
return { success: false };
|
|
101929
|
-
}
|
|
101930
|
-
};
|
|
101931
|
-
`;
|
|
101932
|
-
}
|
|
101933
|
-
/**
|
|
101934
|
-
* Generate the IdP user truncation call code within the truncate block
|
|
101935
|
-
* @param hasIdpUser - Whether IdP user is included
|
|
101936
|
-
* @returns JavaScript code for calling IdP user truncation
|
|
101937
|
-
*/
|
|
101938
|
-
function generateIdpUserTruncateCall(hasIdpUser) {
|
|
101939
|
-
if (!hasIdpUser) return "";
|
|
101940
|
-
return ml`
|
|
101941
|
-
// Truncate _User if applicable
|
|
101942
|
-
const shouldTruncateUser = !skipIdp && !hasNamespace && (!hasTypes || entitiesToProcess.includes("_User"));
|
|
101943
|
-
if (hasIdpUser && shouldTruncateUser) {
|
|
101944
|
-
const truncResult = await truncateIdpUser();
|
|
101945
|
-
if (!truncResult.success) {
|
|
101946
|
-
console.error(styleText("red", "IDP user truncation failed."));
|
|
101947
|
-
process.exit(1);
|
|
101948
|
-
}
|
|
101949
|
-
}
|
|
101950
|
-
`;
|
|
101951
|
-
}
|
|
101952
|
-
/**
|
|
101953
|
-
* Generates the exec.mjs script content using testExecScript API for TailorDB types
|
|
101954
|
-
* and tailor.idp.Client for _User (IdP managed)
|
|
101955
|
-
* @param defaultMachineUserName - Default machine user name from generator config (can be overridden at runtime)
|
|
101956
|
-
* @param relativeConfigPath - Config path relative to exec script
|
|
101957
|
-
* @param namespaceConfigs - Namespace configurations with types and dependencies
|
|
101958
|
-
* @param hasIdpUser - Whether _User is included
|
|
101959
|
-
* @param idpNamespace - The IDP namespace name, or null if not applicable
|
|
101960
|
-
* @returns exec.mjs file contents
|
|
101961
|
-
*/
|
|
101962
|
-
function generateExecScript(defaultMachineUserName, relativeConfigPath, namespaceConfigs, hasIdpUser, idpNamespace) {
|
|
101963
|
-
const namespaceEntitiesEntries = namespaceConfigs.map(({ namespace, types: types$2 }) => {
|
|
101964
|
-
return ` "${namespace}": [\n${types$2.map((e) => ` "${e}",`).join("\n")}\n ]`;
|
|
101965
|
-
}).join(",\n");
|
|
101966
|
-
const namespaceDepsEntries = namespaceConfigs.map(({ namespace, dependencies }) => {
|
|
101967
|
-
return ` "${namespace}": {\n${Object.entries(dependencies).map(([type, deps]) => ` "${type}": [${deps.map((d) => `"${d}"`).join(", ")}]`).join(",\n")}\n }`;
|
|
101968
|
-
}).join(",\n");
|
|
101969
|
-
return ml`
|
|
101970
|
-
import { readFileSync } from "node:fs";
|
|
101971
|
-
import { join } from "node:path";
|
|
101972
|
-
import { parseArgs, styleText } from "node:util";
|
|
101973
|
-
import { createInterface } from "node:readline";
|
|
101974
|
-
import {
|
|
101975
|
-
show,
|
|
101976
|
-
truncate,
|
|
101977
|
-
bundleSeedScript,
|
|
101978
|
-
chunkSeedData,
|
|
101979
|
-
executeScript,
|
|
101980
|
-
initOperatorClient,
|
|
101981
|
-
loadAccessToken,
|
|
101982
|
-
loadWorkspaceId,
|
|
101983
|
-
} from "@tailor-platform/sdk/cli";
|
|
101984
|
-
|
|
101985
|
-
// Parse command-line arguments
|
|
101986
|
-
const { values, positionals } = parseArgs({
|
|
101987
|
-
options: {
|
|
101988
|
-
"machine-user": { type: "string", short: "m" },
|
|
101989
|
-
namespace: { type: "string", short: "n" },
|
|
101990
|
-
"skip-idp": { type: "boolean", default: false },
|
|
101991
|
-
truncate: { type: "boolean", default: false },
|
|
101992
|
-
yes: { type: "boolean", default: false },
|
|
101993
|
-
profile: { type: "string", short: "p" },
|
|
101994
|
-
help: { type: "boolean", short: "h", default: false },
|
|
101995
|
-
},
|
|
101996
|
-
allowPositionals: true,
|
|
101997
|
-
});
|
|
101998
|
-
|
|
101999
|
-
if (values.help) {
|
|
102000
|
-
console.log(\`
|
|
102001
|
-
Usage: node exec.mjs [options] [types...]
|
|
102002
|
-
|
|
102003
|
-
Options:
|
|
102004
|
-
-m, --machine-user <name> Machine user name for authentication (required if not configured)
|
|
102005
|
-
-n, --namespace <ns> Process all types in specified namespace (excludes _User)
|
|
102006
|
-
--skip-idp Skip IdP user (_User) entity
|
|
102007
|
-
--truncate Truncate tables before seeding
|
|
102008
|
-
--yes Skip confirmation prompts (for truncate)
|
|
102009
|
-
-p, --profile <name> Workspace profile name
|
|
102010
|
-
-h, --help Show help
|
|
102011
|
-
|
|
102012
|
-
Examples:
|
|
102013
|
-
node exec.mjs -m admin # Process all types with machine user
|
|
102014
|
-
node exec.mjs --namespace <namespace> # Process tailordb namespace only (no _User)
|
|
102015
|
-
node exec.mjs User Order # Process specific types only
|
|
102016
|
-
node exec.mjs --skip-idp # Process all except _User
|
|
102017
|
-
node exec.mjs --truncate # Truncate all tables, then seed all
|
|
102018
|
-
node exec.mjs --truncate --yes # Truncate all tables without confirmation, then seed all
|
|
102019
|
-
node exec.mjs --truncate --namespace <namespace> # Truncate tailordb, then seed tailordb
|
|
102020
|
-
node exec.mjs --truncate User Order # Truncate User and Order, then seed them
|
|
102021
|
-
\`);
|
|
102022
|
-
process.exit(0);
|
|
102023
|
-
}
|
|
102024
|
-
|
|
102025
|
-
// Helper function to prompt for y/n confirmation
|
|
102026
|
-
const promptConfirmation = (question) => {
|
|
102027
|
-
const rl = createInterface({
|
|
102028
|
-
input: process.stdin,
|
|
102029
|
-
output: process.stdout,
|
|
102030
|
-
});
|
|
102031
|
-
|
|
102032
|
-
return new Promise((resolve) => {
|
|
102033
|
-
rl.question(styleText("yellow", question), (answer) => {
|
|
102034
|
-
rl.close();
|
|
102035
|
-
resolve(answer.toLowerCase().trim());
|
|
102036
|
-
});
|
|
102037
|
-
});
|
|
102038
|
-
};
|
|
102039
|
-
|
|
102040
|
-
const configDir = import.meta.dirname;
|
|
102041
|
-
const configPath = join(configDir, "${relativeConfigPath}");
|
|
102042
|
-
|
|
102043
|
-
// Determine machine user name (CLI argument takes precedence over config default)
|
|
102044
|
-
const defaultMachineUser = ${defaultMachineUserName ? `"${defaultMachineUserName}"` : "undefined"};
|
|
102045
|
-
const machineUserName = values["machine-user"] || defaultMachineUser;
|
|
102046
|
-
|
|
102047
|
-
if (!machineUserName) {
|
|
102048
|
-
console.error(styleText("red", "Error: Machine user name is required."));
|
|
102049
|
-
console.error(styleText("yellow", "Specify --machine-user <name> or configure machineUserName in generator options."));
|
|
102050
|
-
process.exit(1);
|
|
102051
|
-
}
|
|
102052
|
-
|
|
102053
|
-
// Entity configuration
|
|
102054
|
-
const namespaceEntities = {
|
|
102055
|
-
${namespaceEntitiesEntries}
|
|
102056
|
-
};
|
|
102057
|
-
const namespaceDeps = {
|
|
102058
|
-
${namespaceDepsEntries}
|
|
102059
|
-
};
|
|
102060
|
-
const entities = Object.values(namespaceEntities).flat();
|
|
102061
|
-
const hasIdpUser = ${String(hasIdpUser)};
|
|
102062
|
-
|
|
102063
|
-
// Determine which entities to process
|
|
102064
|
-
let entitiesToProcess = null;
|
|
102065
|
-
|
|
102066
|
-
const hasNamespace = !!values.namespace;
|
|
102067
|
-
const hasTypes = positionals.length > 0;
|
|
102068
|
-
const skipIdp = values["skip-idp"];
|
|
102069
|
-
|
|
102070
|
-
// Validate mutually exclusive options
|
|
102071
|
-
const optionCount = [hasNamespace, hasTypes].filter(Boolean).length;
|
|
102072
|
-
if (optionCount > 1) {
|
|
102073
|
-
console.error(styleText("red", "Error: Options --namespace and type names are mutually exclusive."));
|
|
102074
|
-
process.exit(1);
|
|
102075
|
-
}
|
|
102076
|
-
|
|
102077
|
-
// --skip-idp and --namespace are redundant (namespace already excludes _User)
|
|
102078
|
-
if (skipIdp && hasNamespace) {
|
|
102079
|
-
console.warn(styleText("yellow", "Warning: --skip-idp is redundant with --namespace (namespace filtering already excludes _User)."));
|
|
102080
|
-
}
|
|
102081
|
-
|
|
102082
|
-
// Filter by namespace (automatically excludes _User as it has no namespace)
|
|
102083
|
-
if (hasNamespace) {
|
|
102084
|
-
const namespace = values.namespace;
|
|
102085
|
-
entitiesToProcess = namespaceEntities[namespace];
|
|
102086
|
-
|
|
102087
|
-
if (!entitiesToProcess || entitiesToProcess.length === 0) {
|
|
102088
|
-
console.error(styleText("red", \`Error: No entities found in namespace "\${namespace}"\`));
|
|
102089
|
-
console.error(styleText("yellow", \`Available namespaces: \${Object.keys(namespaceEntities).join(", ")}\`));
|
|
102090
|
-
process.exit(1);
|
|
102091
|
-
}
|
|
102092
|
-
|
|
102093
|
-
console.log(styleText("cyan", \`Filtering by namespace: \${namespace}\`));
|
|
102094
|
-
console.log(styleText("dim", \`Entities: \${entitiesToProcess.join(", ")}\`));
|
|
102095
|
-
}
|
|
102096
|
-
|
|
102097
|
-
// Filter by specific types
|
|
102098
|
-
if (hasTypes) {
|
|
102099
|
-
const requestedTypes = positionals;
|
|
102100
|
-
const notFoundTypes = [];
|
|
102101
|
-
const allTypes = hasIdpUser ? [...entities, "_User"] : entities;
|
|
102102
|
-
|
|
102103
|
-
entitiesToProcess = requestedTypes.filter((type) => {
|
|
102104
|
-
if (!allTypes.includes(type)) {
|
|
102105
|
-
notFoundTypes.push(type);
|
|
102106
|
-
return false;
|
|
102107
|
-
}
|
|
102108
|
-
return true;
|
|
102109
|
-
});
|
|
102110
|
-
|
|
102111
|
-
if (notFoundTypes.length > 0) {
|
|
102112
|
-
console.error(styleText("red", \`Error: The following types were not found: \${notFoundTypes.join(", ")}\`));
|
|
102113
|
-
console.error(styleText("yellow", \`Available types: \${allTypes.join(", ")}\`));
|
|
102114
|
-
process.exit(1);
|
|
102115
|
-
}
|
|
102116
|
-
|
|
102117
|
-
console.log(styleText("cyan", \`Filtering by types: \${entitiesToProcess.join(", ")}\`));
|
|
102118
|
-
}
|
|
102119
|
-
|
|
102120
|
-
// Apply --skip-idp filter
|
|
102121
|
-
if (skipIdp) {
|
|
102122
|
-
if (entitiesToProcess) {
|
|
102123
|
-
entitiesToProcess = entitiesToProcess.filter((entity) => entity !== "_User");
|
|
102124
|
-
} else {
|
|
102125
|
-
entitiesToProcess = entities.filter((entity) => entity !== "_User");
|
|
102126
|
-
}
|
|
102127
|
-
}
|
|
102128
|
-
|
|
102129
|
-
// Get application info
|
|
102130
|
-
const appInfo = await show({ configPath, profile: values.profile });
|
|
102131
|
-
const authNamespace = appInfo.auth;
|
|
102132
|
-
|
|
102133
|
-
// Initialize operator client (once for all namespaces)
|
|
102134
|
-
const accessToken = await loadAccessToken({ profile: values.profile, useProfile: true });
|
|
102135
|
-
const workspaceId = await loadWorkspaceId({ profile: values.profile });
|
|
102136
|
-
const operatorClient = await initOperatorClient(accessToken);
|
|
102137
|
-
|
|
102138
|
-
${generateIdpUserTruncateFunction(hasIdpUser, idpNamespace)}
|
|
102139
|
-
|
|
102140
|
-
// Truncate tables if requested
|
|
102141
|
-
if (values.truncate) {
|
|
102142
|
-
const answer = values.yes ? "y" : await promptConfirmation("Are you sure you want to truncate? (y/n): ");
|
|
102143
|
-
if (answer !== "y") {
|
|
102144
|
-
console.log(styleText("yellow", "Truncate cancelled."));
|
|
102145
|
-
process.exit(0);
|
|
102146
|
-
}
|
|
102147
|
-
|
|
102148
|
-
console.log(styleText("cyan", "Truncating tables..."));
|
|
102149
|
-
|
|
102150
|
-
try {
|
|
102151
|
-
if (hasNamespace) {
|
|
102152
|
-
await truncate({
|
|
102153
|
-
configPath,
|
|
102154
|
-
profile: values.profile,
|
|
102155
|
-
namespace: values.namespace,
|
|
102156
|
-
});
|
|
102157
|
-
} else if (hasTypes) {
|
|
102158
|
-
const typesToTruncate = entitiesToProcess.filter((t) => t !== "_User");
|
|
102159
|
-
if (typesToTruncate.length > 0) {
|
|
102160
|
-
await truncate({
|
|
102161
|
-
configPath,
|
|
102162
|
-
profile: values.profile,
|
|
102163
|
-
types: typesToTruncate,
|
|
102164
|
-
});
|
|
102165
|
-
} else {
|
|
102166
|
-
console.log(styleText("dim", "No TailorDB types to truncate (only _User was specified)."));
|
|
102167
|
-
}
|
|
102168
|
-
} else {
|
|
102169
|
-
await truncate({
|
|
102170
|
-
configPath,
|
|
102171
|
-
profile: values.profile,
|
|
102172
|
-
all: true,
|
|
102173
|
-
});
|
|
102174
|
-
}
|
|
102175
|
-
} catch (error) {
|
|
102176
|
-
console.error(styleText("red", \`Truncate failed: \${error.message}\`));
|
|
102177
|
-
process.exit(1);
|
|
102178
|
-
}
|
|
102179
|
-
|
|
102180
|
-
${generateIdpUserTruncateCall(hasIdpUser)}
|
|
102181
|
-
|
|
102182
|
-
console.log(styleText("green", "Truncate completed."));
|
|
102183
|
-
}
|
|
102184
|
-
|
|
102185
|
-
console.log(styleText("cyan", "\\nStarting seed data generation..."));
|
|
102186
|
-
if (skipIdp) {
|
|
102187
|
-
console.log(styleText("dim", \` Skipping IdP user (_User)\`));
|
|
102188
|
-
}
|
|
102189
|
-
|
|
102190
|
-
// Load seed data from JSONL files
|
|
102191
|
-
const loadSeedData = (dataDir, typeNames) => {
|
|
102192
|
-
const data = {};
|
|
102193
|
-
for (const typeName of typeNames) {
|
|
102194
|
-
const jsonlPath = join(dataDir, \`\${typeName}.jsonl\`);
|
|
102195
|
-
try {
|
|
102196
|
-
const content = readFileSync(jsonlPath, "utf-8").trim();
|
|
102197
|
-
if (content) {
|
|
102198
|
-
data[typeName] = content.split("\\n").map((line) => JSON.parse(line));
|
|
102199
|
-
} else {
|
|
102200
|
-
data[typeName] = [];
|
|
102201
|
-
}
|
|
102202
|
-
} catch (error) {
|
|
102203
|
-
if (error.code === "ENOENT") {
|
|
102204
|
-
data[typeName] = [];
|
|
102205
|
-
} else {
|
|
102206
|
-
throw error;
|
|
102207
|
-
}
|
|
102208
|
-
}
|
|
102209
|
-
}
|
|
102210
|
-
return data;
|
|
102211
|
-
};
|
|
102212
|
-
|
|
102213
|
-
// Topological sort for dependency order
|
|
102214
|
-
const topologicalSort = (types, deps) => {
|
|
102215
|
-
const visited = new Set();
|
|
102216
|
-
const result = [];
|
|
102217
|
-
|
|
102218
|
-
const visit = (type) => {
|
|
102219
|
-
if (visited.has(type)) return;
|
|
102220
|
-
visited.add(type);
|
|
102221
|
-
const typeDeps = deps[type] || [];
|
|
102222
|
-
for (const dep of typeDeps) {
|
|
102223
|
-
if (types.includes(dep)) {
|
|
102224
|
-
visit(dep);
|
|
102225
|
-
}
|
|
102226
|
-
}
|
|
102227
|
-
result.push(type);
|
|
102228
|
-
};
|
|
102229
|
-
|
|
102230
|
-
for (const type of types) {
|
|
102231
|
-
visit(type);
|
|
102232
|
-
}
|
|
102233
|
-
return result;
|
|
102234
|
-
};
|
|
102235
|
-
|
|
102236
|
-
// Seed TailorDB types via testExecScript
|
|
102237
|
-
const seedViaTestExecScript = async (namespace, typesToSeed, deps) => {
|
|
102238
|
-
const dataDir = join(configDir, "data");
|
|
102239
|
-
const sortedTypes = topologicalSort(typesToSeed, deps);
|
|
102240
|
-
const data = loadSeedData(dataDir, sortedTypes);
|
|
102241
|
-
|
|
102242
|
-
// Skip if no data
|
|
102243
|
-
const typesWithData = sortedTypes.filter((t) => data[t] && data[t].length > 0);
|
|
102244
|
-
if (typesWithData.length === 0) {
|
|
102245
|
-
console.log(styleText("dim", \` [\${namespace}] No data to seed\`));
|
|
102246
|
-
return { success: true, processed: {} };
|
|
102247
|
-
}
|
|
102248
|
-
|
|
102249
|
-
console.log(styleText("cyan", \` [\${namespace}] Seeding \${typesWithData.length} types via Kysely batch insert...\`));
|
|
102250
|
-
|
|
102251
|
-
// Bundle seed script
|
|
102252
|
-
const bundled = await bundleSeedScript(namespace, typesWithData);
|
|
102253
|
-
|
|
102254
|
-
// Chunk seed data to fit within gRPC message size limits
|
|
102255
|
-
const chunks = chunkSeedData({
|
|
102256
|
-
data,
|
|
102257
|
-
order: sortedTypes,
|
|
102258
|
-
codeByteSize: new TextEncoder().encode(bundled.bundledCode).length,
|
|
102259
|
-
});
|
|
102260
|
-
|
|
102261
|
-
if (chunks.length === 0) {
|
|
102262
|
-
console.log(styleText("dim", \` [\${namespace}] No data to seed\`));
|
|
102263
|
-
return { success: true, processed: {} };
|
|
102264
|
-
}
|
|
102265
|
-
|
|
102266
|
-
if (chunks.length > 1) {
|
|
102267
|
-
console.log(styleText("dim", \` Split into \${chunks.length} chunks\`));
|
|
102268
|
-
}
|
|
102269
|
-
|
|
102270
|
-
const allProcessed = {};
|
|
102271
|
-
let hasError = false;
|
|
102272
|
-
const allErrors = [];
|
|
102273
|
-
|
|
102274
|
-
for (const chunk of chunks) {
|
|
102275
|
-
if (chunks.length > 1) {
|
|
102276
|
-
console.log(styleText("dim", \` Chunk \${chunk.index + 1}/\${chunk.total}: \${chunk.order.join(", ")}\`));
|
|
102277
|
-
}
|
|
102278
|
-
|
|
102279
|
-
// Execute seed script for this chunk
|
|
102280
|
-
const result = await executeScript({
|
|
102281
|
-
client: operatorClient,
|
|
102282
|
-
workspaceId,
|
|
102283
|
-
name: \`seed-\${namespace}.ts\`,
|
|
102284
|
-
code: bundled.bundledCode,
|
|
102285
|
-
arg: JSON.stringify({ data: chunk.data, order: chunk.order }),
|
|
102286
|
-
invoker: {
|
|
102287
|
-
namespace: authNamespace,
|
|
102288
|
-
machineUserName,
|
|
102289
|
-
},
|
|
102290
|
-
});
|
|
102291
|
-
|
|
102292
|
-
// Parse result and display logs
|
|
102293
|
-
if (result.logs) {
|
|
102294
|
-
for (const line of result.logs.split("\\n").filter(Boolean)) {
|
|
102295
|
-
console.log(styleText("dim", \` \${line}\`));
|
|
102296
|
-
}
|
|
102297
|
-
}
|
|
102298
|
-
|
|
102299
|
-
if (result.success) {
|
|
102300
|
-
let parsed;
|
|
102301
|
-
try {
|
|
102302
|
-
const parsedResult = JSON.parse(result.result || "{}");
|
|
102303
|
-
parsed = parsedResult && typeof parsedResult === "object" ? parsedResult : {};
|
|
102304
|
-
} catch (error) {
|
|
102305
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
102306
|
-
console.error(styleText("red", \` ✗ Failed to parse seed result: \${message}\`));
|
|
102307
|
-
hasError = true;
|
|
102308
|
-
allErrors.push(message);
|
|
102309
|
-
continue;
|
|
102310
|
-
}
|
|
102311
|
-
|
|
102312
|
-
const processed = parsed.processed || {};
|
|
102313
|
-
for (const [type, count] of Object.entries(processed)) {
|
|
102314
|
-
allProcessed[type] = (allProcessed[type] || 0) + count;
|
|
102315
|
-
console.log(styleText("green", \` ✓ \${type}: \${count} rows inserted\`));
|
|
102316
|
-
}
|
|
102317
|
-
|
|
102318
|
-
if (!parsed.success) {
|
|
102319
|
-
const errors = Array.isArray(parsed.errors) ? parsed.errors : [];
|
|
102320
|
-
const errorMessage =
|
|
102321
|
-
errors.length > 0 ? errors.join("\\n ") : "Seed script reported failure";
|
|
102322
|
-
console.error(styleText("red", \` ✗ Seed failed:\\n \${errorMessage}\`));
|
|
102323
|
-
hasError = true;
|
|
102324
|
-
allErrors.push(errorMessage);
|
|
102325
|
-
}
|
|
102326
|
-
} else {
|
|
102327
|
-
console.error(styleText("red", \` ✗ Seed failed: \${result.error}\`));
|
|
102328
|
-
hasError = true;
|
|
102329
|
-
allErrors.push(result.error);
|
|
102330
|
-
}
|
|
102331
|
-
}
|
|
102332
|
-
|
|
102333
|
-
if (hasError) {
|
|
102334
|
-
return { success: false, error: allErrors.join("\\n") };
|
|
102335
|
-
}
|
|
102336
|
-
return { success: true, processed: allProcessed };
|
|
102337
|
-
};
|
|
102338
|
-
|
|
102339
|
-
${generateIdpUserSeedFunction(hasIdpUser, idpNamespace)}
|
|
102340
|
-
|
|
102341
|
-
// Main execution
|
|
102342
|
-
try {
|
|
102343
|
-
let allSuccess = true;
|
|
102344
|
-
|
|
102345
|
-
// Determine which namespaces and types to process
|
|
102346
|
-
const namespacesToProcess = hasNamespace
|
|
102347
|
-
? [values.namespace]
|
|
102348
|
-
: Object.keys(namespaceEntities);
|
|
102349
|
-
|
|
102350
|
-
for (const namespace of namespacesToProcess) {
|
|
102351
|
-
const nsTypes = namespaceEntities[namespace] || [];
|
|
102352
|
-
const nsDeps = namespaceDeps[namespace] || {};
|
|
102353
|
-
|
|
102354
|
-
// Filter types if specific types requested
|
|
102355
|
-
let typesToSeed = entitiesToProcess
|
|
102356
|
-
? nsTypes.filter((t) => entitiesToProcess.includes(t))
|
|
102357
|
-
: nsTypes;
|
|
102358
|
-
|
|
102359
|
-
if (typesToSeed.length === 0) continue;
|
|
102360
|
-
|
|
102361
|
-
const result = await seedViaTestExecScript(namespace, typesToSeed, nsDeps);
|
|
102362
|
-
if (!result.success) {
|
|
102363
|
-
allSuccess = false;
|
|
102364
|
-
}
|
|
102365
|
-
}
|
|
102366
|
-
|
|
102367
|
-
${generateIdpUserSeedCall(hasIdpUser)}
|
|
102368
|
-
|
|
102369
|
-
if (allSuccess) {
|
|
102370
|
-
console.log(styleText("green", "\\n✓ Seed data generation completed successfully"));
|
|
102371
|
-
} else {
|
|
102372
|
-
console.error(styleText("red", "\\n✗ Seed data generation completed with errors"));
|
|
102373
|
-
process.exit(1);
|
|
102374
|
-
}
|
|
102375
|
-
} catch (error) {
|
|
102376
|
-
console.error(styleText("red", \`\\n✗ Seed data generation failed: \${error.message}\`));
|
|
102377
|
-
process.exit(1);
|
|
102378
|
-
}
|
|
102379
|
-
|
|
102380
|
-
`;
|
|
102381
|
-
}
|
|
102382
|
-
/**
|
|
102383
|
-
* Factory function to create a Seed generator.
|
|
102384
|
-
* Combines Kysely batch insert and lines-db schema generation.
|
|
102385
|
-
* @param options - Seed generator options
|
|
102386
|
-
* @returns Seed generator
|
|
102387
|
-
*/
|
|
102388
|
-
function createSeedGenerator(options) {
|
|
102389
|
-
return {
|
|
102390
|
-
id: SeedGeneratorID,
|
|
102391
|
-
description: "Generates seed data files (Kysely batch insert + tailor.idp.Client for _User)",
|
|
102392
|
-
dependencies: ["tailordb"],
|
|
102393
|
-
processType: ({ type, source, namespace }) => {
|
|
102394
|
-
return {
|
|
102395
|
-
typeInfo: processSeedTypeInfo(type, namespace),
|
|
102396
|
-
linesDb: processLinesDb(type, source)
|
|
102397
|
-
};
|
|
102398
|
-
},
|
|
102399
|
-
processTailorDBNamespace: ({ types: types$2 }) => types$2,
|
|
102400
|
-
aggregate: ({ input, configPath }) => {
|
|
102401
|
-
const files = [];
|
|
102402
|
-
const namespaceConfigs = [];
|
|
102403
|
-
for (const nsResult of input.tailordb) {
|
|
102404
|
-
if (!nsResult.types) continue;
|
|
102405
|
-
const outputBaseDir = options.distPath;
|
|
102406
|
-
const types$2 = [];
|
|
102407
|
-
const dependencies = {};
|
|
102408
|
-
for (const [_typeName, metadata] of Object.entries(nsResult.types)) {
|
|
102409
|
-
const { typeInfo, linesDb } = metadata;
|
|
102410
|
-
types$2.push(typeInfo.name);
|
|
102411
|
-
dependencies[typeInfo.name] = typeInfo.dependencies;
|
|
102412
|
-
files.push({
|
|
102413
|
-
path: path$20.join(outputBaseDir, typeInfo.dataFile),
|
|
102414
|
-
content: "",
|
|
102415
|
-
skipIfExists: true
|
|
102416
|
-
});
|
|
102417
|
-
const schemaOutputPath = path$20.join(outputBaseDir, "data", `${linesDb.typeName}.schema.ts`);
|
|
102418
|
-
if (linesDb.pluginSource && linesDb.pluginSource.pluginImportPath) {
|
|
102419
|
-
let originalImportPath;
|
|
102420
|
-
if (linesDb.pluginSource.originalFilePath && linesDb.pluginSource.originalExportName) {
|
|
102421
|
-
const relativePath = path$20.relative(path$20.dirname(schemaOutputPath), linesDb.pluginSource.originalFilePath);
|
|
102422
|
-
originalImportPath = relativePath.replace(/\.ts$/, "").startsWith(".") ? relativePath.replace(/\.ts$/, "") : `./${relativePath.replace(/\.ts$/, "")}`;
|
|
102423
|
-
}
|
|
102424
|
-
const schemaContent = generateLinesDbSchemaFileWithPluginAPI(linesDb, {
|
|
102425
|
-
configImportPath: path$20.relative(path$20.dirname(schemaOutputPath), configPath),
|
|
102426
|
-
originalImportPath
|
|
102427
|
-
});
|
|
102428
|
-
files.push({
|
|
102429
|
-
path: schemaOutputPath,
|
|
102430
|
-
content: schemaContent
|
|
102431
|
-
});
|
|
102432
|
-
} else {
|
|
102433
|
-
const relativePath = path$20.relative(path$20.dirname(schemaOutputPath), linesDb.importPath);
|
|
102434
|
-
const schemaContent = generateLinesDbSchemaFile(linesDb, relativePath.replace(/\.ts$/, "").startsWith(".") ? relativePath.replace(/\.ts$/, "") : `./${relativePath.replace(/\.ts$/, "")}`);
|
|
102435
|
-
files.push({
|
|
102436
|
-
path: schemaOutputPath,
|
|
102437
|
-
content: schemaContent
|
|
102438
|
-
});
|
|
102439
|
-
}
|
|
102440
|
-
}
|
|
102441
|
-
namespaceConfigs.push({
|
|
102442
|
-
namespace: nsResult.namespace,
|
|
102443
|
-
types: types$2,
|
|
102444
|
-
dependencies
|
|
102445
|
-
});
|
|
102446
|
-
}
|
|
102447
|
-
const idpUser = input.auth ? processIdpUser(input.auth) : null;
|
|
102448
|
-
const hasIdpUser = idpUser !== null;
|
|
102449
|
-
if (idpUser) {
|
|
102450
|
-
const outputBaseDir = options.distPath;
|
|
102451
|
-
files.push({
|
|
102452
|
-
path: path$20.join(outputBaseDir, idpUser.dataFile),
|
|
102453
|
-
content: "",
|
|
102454
|
-
skipIfExists: true
|
|
102455
|
-
});
|
|
102456
|
-
files.push({
|
|
102457
|
-
path: path$20.join(outputBaseDir, "data", `${idpUser.name}.schema.ts`),
|
|
102458
|
-
content: generateIdpUserSchemaFile(idpUser.schema.usernameField, idpUser.schema.userTypeName)
|
|
102459
|
-
});
|
|
102460
|
-
}
|
|
102461
|
-
const relativeConfigPath = path$20.relative(options.distPath, configPath);
|
|
102462
|
-
files.push({
|
|
102463
|
-
path: path$20.join(options.distPath, "exec.mjs"),
|
|
102464
|
-
content: generateExecScript(options.machineUserName, relativeConfigPath, namespaceConfigs, hasIdpUser, idpUser?.idpNamespace ?? null)
|
|
102465
|
-
});
|
|
102466
|
-
return { files };
|
|
102467
|
-
}
|
|
102468
|
-
};
|
|
102469
|
-
}
|
|
102470
|
-
|
|
102471
100975
|
//#endregion
|
|
102472
100976
|
//#region src/cli/mock.ts
|
|
102473
100977
|
globalThis.tailordb = { Client: class {
|
|
@@ -102481,26 +100985,13 @@ globalThis.tailordb = { Client: class {
|
|
|
102481
100985
|
|
|
102482
100986
|
//#endregion
|
|
102483
100987
|
//#region src/cli/config-loader.ts
|
|
102484
|
-
const
|
|
102485
|
-
|
|
102486
|
-
|
|
102487
|
-
|
|
102488
|
-
|
|
102489
|
-
|
|
102490
|
-
|
|
102491
|
-
if (!Array.isArray(gen)) return gen;
|
|
102492
|
-
const [id, options] = gen;
|
|
102493
|
-
switch (id) {
|
|
102494
|
-
case KyselyGeneratorID: return createKyselyGenerator(options);
|
|
102495
|
-
case SeedGeneratorID: return createSeedGenerator(options);
|
|
102496
|
-
case EnumConstantsGeneratorID: return createEnumConstantsGenerator(options);
|
|
102497
|
-
case FileUtilsGeneratorID: return createFileUtilsGenerator(options);
|
|
102498
|
-
default: {
|
|
102499
|
-
const _exhaustive = id;
|
|
102500
|
-
throw new Error(`Unknown generator ID: ${_exhaustive}`);
|
|
102501
|
-
}
|
|
102502
|
-
}
|
|
102503
|
-
}).brand("CodeGenerator");
|
|
100988
|
+
const builtinPlugins = new Map([
|
|
100989
|
+
[KyselyGeneratorID, (options) => kyselyTypePlugin(options)],
|
|
100990
|
+
[SeedGeneratorID, (options) => seedPlugin(options)],
|
|
100991
|
+
[EnumConstantsGeneratorID, (options) => enumConstantsPlugin(options)],
|
|
100992
|
+
[FileUtilsGeneratorID, (options) => fileUtilsPlugin(options)]
|
|
100993
|
+
]);
|
|
100994
|
+
const GeneratorConfigSchema = CodeGeneratorSchema.brand("CodeGenerator");
|
|
102504
100995
|
const PluginConfigSchema = createPluginConfigSchema();
|
|
102505
100996
|
/**
|
|
102506
100997
|
* Load Tailor configuration file and associated generators and plugins.
|
|
@@ -102519,16 +101010,27 @@ async function loadConfig(configPath) {
|
|
|
102519
101010
|
for (const value of Object.values(configModule)) if (Array.isArray(value)) {
|
|
102520
101011
|
const generatorParsed = value.reduce((acc, item) => {
|
|
102521
101012
|
if (!acc.success) return acc;
|
|
101013
|
+
const baseResult = BaseGeneratorConfigSchema.safeParse(item);
|
|
101014
|
+
if (baseResult.success && Array.isArray(baseResult.data)) {
|
|
101015
|
+
const [id, options] = baseResult.data;
|
|
101016
|
+
const pluginFactory = builtinPlugins.get(id);
|
|
101017
|
+
if (pluginFactory) {
|
|
101018
|
+
acc.convertedPlugins.push(pluginFactory(options));
|
|
101019
|
+
return acc;
|
|
101020
|
+
}
|
|
101021
|
+
}
|
|
102522
101022
|
const result = GeneratorConfigSchema.safeParse(item);
|
|
102523
101023
|
if (result.success) acc.items.push(result.data);
|
|
102524
101024
|
else acc.success = false;
|
|
102525
101025
|
return acc;
|
|
102526
101026
|
}, {
|
|
102527
101027
|
success: true,
|
|
102528
|
-
items: []
|
|
101028
|
+
items: [],
|
|
101029
|
+
convertedPlugins: []
|
|
102529
101030
|
});
|
|
102530
|
-
if (generatorParsed.success && generatorParsed.items.length > 0) {
|
|
101031
|
+
if (generatorParsed.success && (generatorParsed.items.length > 0 || generatorParsed.convertedPlugins.length > 0)) {
|
|
102531
101032
|
allGenerators.push(...generatorParsed.items);
|
|
101033
|
+
allPlugins.push(...generatorParsed.convertedPlugins);
|
|
102532
101034
|
continue;
|
|
102533
101035
|
}
|
|
102534
101036
|
const pluginParsed = value.reduce((acc, item) => {
|
|
@@ -103389,5 +101891,5 @@ async function loadApplication(params) {
|
|
|
103389
101891
|
}
|
|
103390
101892
|
|
|
103391
101893
|
//#endregion
|
|
103392
|
-
export { UserProfileProviderConfig_UserProfileProviderType as $, TailorDBGQLPermission_Action as A, ExecutorJobStatus as B, platformBaseUrl as C, WorkspacePlatformUserRole as D, readPackageJson as E, TailorDBType_PermitAction as F, AuthOAuth2Client_ClientType as G, ExecutorTriggerType as H, PipelineResolver_OperationType as I, AuthSCIMAttribute_Type as J, AuthOAuth2Client_GrantType as K, IdPLang as L, TailorDBGQLPermission_Permit as M, TailorDBType_Permission_Operator as N, WorkflowExecution_Status as O, TailorDBType_Permission_Permit as P, TenantProviderConfig_TenantProviderType as Q, FunctionExecution_Status as R, initOperatorClient as S, userAgent as T, AuthIDPConfig_AuthType as U, ExecutorTargetType as V, AuthInvokerSchema$1 as W, AuthSCIMConfig_AuthorizationType as X, AuthSCIMAttribute_Uniqueness as Y, PATScope as Z, writePlatformConfig as _,
|
|
103393
|
-
//# sourceMappingURL=application-
|
|
101894
|
+
export { UserProfileProviderConfig_UserProfileProviderType as $, TailorDBGQLPermission_Action as A, ExecutorJobStatus as B, platformBaseUrl as C, WorkspacePlatformUserRole as D, readPackageJson as E, TailorDBType_PermitAction as F, AuthOAuth2Client_ClientType as G, ExecutorTriggerType as H, PipelineResolver_OperationType as I, AuthSCIMAttribute_Type as J, AuthOAuth2Client_GrantType as K, IdPLang as L, TailorDBGQLPermission_Permit as M, TailorDBType_Permission_Operator as N, WorkflowExecution_Status as O, TailorDBType_Permission_Permit as P, TenantProviderConfig_TenantProviderType as Q, FunctionExecution_Status as R, initOperatorClient as S, userAgent as T, AuthIDPConfig_AuthType as U, ExecutorTargetType as V, AuthInvokerSchema$1 as W, AuthSCIMConfig_AuthorizationType as X, AuthSCIMAttribute_Uniqueness as Y, PATScope as Z, writePlatformConfig as _, buildExecutorArgsExpr as a, ApplicationSchemaUpdateAttemptStatus as at, fetchUserInfo as b, createExecutorService as c, styles as ct, fetchLatestToken as d, GetApplicationSchemaHealthResponse_ApplicationSchemaHealthStatus as et, loadAccessToken as f, readPlatformConfig as g, loadWorkspaceId as h, loadConfig as i, PageDirection as it, TailorDBGQLPermission_Operator as j, WorkflowJobExecution_Status as k, OAuth2ClientSchema as l, symbols as lt, loadOrganizationId as m, generatePluginFilesIfNeeded as n, Condition_Operator as nt, buildResolverOperationHookExpr as o, Subgraph_ServiceType as ot, loadFolderId as p, AuthSCIMAttribute_Mutability as q, loadApplication as r, FilterSchema as rt, getDistDir as s, logger as st, defineApplication as t, ConditionSchema as tt, stringifyFunction as u, fetchAll as v, resolveStaticWebsiteUrls as w, initOAuth2Client as x, fetchMachineUserToken as y, FunctionExecution_Type as z };
|
|
101895
|
+
//# sourceMappingURL=application-gWUyKuzv.mjs.map
|