@tailor-platform/create-sdk 1.20.0 → 1.22.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.
Files changed (151) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/index.js +7 -2
  3. package/package.json +4 -3
  4. package/templates/executor/README.md +32 -0
  5. package/templates/{testing → executor}/eslint.config.js +0 -5
  6. package/templates/{testing → executor}/package.json +2 -4
  7. package/templates/executor/src/db/auditLog.ts +24 -0
  8. package/templates/executor/src/db/notification.ts +27 -0
  9. package/templates/executor/src/db/user.ts +22 -0
  10. package/templates/executor/src/executor/dailyCleanup.ts +16 -0
  11. package/templates/executor/src/executor/externalWebhook.ts +18 -0
  12. package/templates/executor/src/executor/onDataProcessed.ts +26 -0
  13. package/templates/executor/src/executor/onIdpUserCreated.ts +19 -0
  14. package/templates/executor/src/executor/onIdpUserDeleted.ts +19 -0
  15. package/templates/executor/src/executor/onIdpUserUpdated.ts +19 -0
  16. package/templates/executor/src/executor/onTokenIssued.ts +19 -0
  17. package/templates/executor/src/executor/onTokenRefreshed.ts +19 -0
  18. package/templates/executor/src/executor/onTokenRevoked.ts +19 -0
  19. package/templates/executor/src/executor/onUserCreated.ts +23 -0
  20. package/templates/executor/src/executor/onUserDeleted.ts +22 -0
  21. package/templates/executor/src/executor/onUserUpdated.ts +22 -0
  22. package/templates/executor/src/executor/shared.test.ts +36 -0
  23. package/templates/executor/src/executor/shared.ts +13 -0
  24. package/templates/executor/src/generated/db.ts +59 -0
  25. package/templates/executor/src/resolver/processData.ts +22 -0
  26. package/templates/executor/src/workflow/cleanup.ts +13 -0
  27. package/templates/executor/tailor.config.ts +40 -0
  28. package/templates/executor/vitest.config.ts +15 -0
  29. package/templates/generators/.oxfmtrc.json +3 -0
  30. package/templates/generators/.oxlintrc.json +197 -0
  31. package/templates/generators/.prettierignore +1 -0
  32. package/templates/generators/.prettierrc +1 -0
  33. package/templates/generators/README.md +30 -0
  34. package/templates/generators/__dot__gitignore +3 -0
  35. package/templates/generators/eslint.config.js +24 -0
  36. package/templates/generators/package.json +30 -0
  37. package/templates/generators/src/db/category.ts +25 -0
  38. package/templates/generators/src/db/order.ts +38 -0
  39. package/templates/generators/src/db/product.ts +34 -0
  40. package/templates/generators/src/db/user.ts +26 -0
  41. package/templates/generators/src/generated/db.ts +68 -0
  42. package/templates/generators/src/generated/enums.ts +39 -0
  43. package/templates/generators/src/generated/files.ts +51 -0
  44. package/templates/generators/src/resolver/getProduct.test.ts +92 -0
  45. package/templates/generators/src/resolver/getProduct.ts +53 -0
  46. package/templates/generators/src/seed/data/Category.jsonl +0 -0
  47. package/templates/generators/src/seed/data/Category.schema.ts +23 -0
  48. package/templates/generators/src/seed/data/Order.jsonl +0 -0
  49. package/templates/generators/src/seed/data/Order.schema.ts +21 -0
  50. package/templates/generators/src/seed/data/Product.jsonl +0 -0
  51. package/templates/generators/src/seed/data/Product.schema.ts +23 -0
  52. package/templates/generators/src/seed/data/User.jsonl +0 -0
  53. package/templates/generators/src/seed/data/User.schema.ts +20 -0
  54. package/templates/generators/src/seed/exec.mjs +419 -0
  55. package/templates/generators/tailor.config.ts +36 -0
  56. package/templates/generators/tsconfig.json +16 -0
  57. package/templates/generators/vitest.config.ts +15 -0
  58. package/templates/hello-world/package.json +1 -1
  59. package/templates/inventory-management/package.json +1 -1
  60. package/templates/inventory-management/user-defined.d.ts +15 -0
  61. package/templates/multi-application/package.json +1 -1
  62. package/templates/resolver/.oxfmtrc.json +3 -0
  63. package/templates/resolver/.oxlintrc.json +197 -0
  64. package/templates/resolver/.prettierrc +1 -0
  65. package/templates/resolver/README.md +31 -0
  66. package/templates/resolver/__dot__gitignore +3 -0
  67. package/templates/resolver/eslint.config.js +24 -0
  68. package/templates/resolver/package.json +32 -0
  69. package/templates/resolver/src/resolver/add.test.ts +23 -0
  70. package/templates/{testing/src/resolver/mockTailordb.test.ts → resolver/src/resolver/queryUser.test.ts} +5 -6
  71. package/templates/{testing/src/resolver/mockTailordb.ts → resolver/src/resolver/queryUser.ts} +0 -5
  72. package/templates/resolver/src/resolver/showEnv.test.ts +14 -0
  73. package/templates/resolver/src/resolver/showEnv.ts +19 -0
  74. package/templates/resolver/src/resolver/showUserInfo.test.ts +37 -0
  75. package/templates/resolver/src/resolver/showUserInfo.ts +21 -0
  76. package/templates/{testing/src/resolver/wrapTailordb.test.ts → resolver/src/resolver/updateUser.test.ts} +3 -5
  77. package/templates/{testing/src/resolver/wrapTailordb.ts → resolver/src/resolver/updateUser.ts} +0 -5
  78. package/templates/resolver/tailor.config.ts +26 -0
  79. package/templates/resolver/tests/bundled.test.ts +97 -0
  80. package/templates/resolver/tsconfig.json +16 -0
  81. package/templates/resolver/user-defined.d.ts +18 -0
  82. package/templates/resolver/vitest.config.ts +21 -0
  83. package/templates/static-web-site/.oxfmtrc.json +3 -0
  84. package/templates/static-web-site/.oxlintrc.json +197 -0
  85. package/templates/static-web-site/.prettierrc +1 -0
  86. package/templates/static-web-site/README.md +21 -0
  87. package/templates/static-web-site/__dot__gitignore +3 -0
  88. package/templates/static-web-site/eslint.config.js +24 -0
  89. package/templates/static-web-site/package.json +27 -0
  90. package/templates/static-web-site/public/callback.html +34 -0
  91. package/templates/static-web-site/public/index.html +55 -0
  92. package/templates/static-web-site/public/style.css +62 -0
  93. package/templates/static-web-site/src/db/user.ts +22 -0
  94. package/templates/static-web-site/tailor.config.ts +55 -0
  95. package/templates/static-web-site/tsconfig.json +16 -0
  96. package/templates/tailordb/.oxfmtrc.json +3 -0
  97. package/templates/tailordb/.oxlintrc.json +197 -0
  98. package/templates/tailordb/.prettierrc +1 -0
  99. package/templates/tailordb/README.md +29 -0
  100. package/templates/tailordb/__dot__gitignore +3 -0
  101. package/templates/tailordb/eslint.config.js +24 -0
  102. package/templates/tailordb/package.json +30 -0
  103. package/templates/tailordb/src/db/category.ts +15 -0
  104. package/templates/tailordb/src/db/comment.ts +26 -0
  105. package/templates/tailordb/src/db/permission.ts +43 -0
  106. package/templates/tailordb/src/db/task.test.ts +41 -0
  107. package/templates/tailordb/src/db/task.ts +58 -0
  108. package/templates/tailordb/src/db/user.ts +19 -0
  109. package/templates/tailordb/src/generated/db.ts +75 -0
  110. package/templates/tailordb/tailor.config.ts +26 -0
  111. package/templates/tailordb/tsconfig.json +16 -0
  112. package/templates/tailordb/user-defined.d.ts +15 -0
  113. package/templates/tailordb/vitest.config.ts +15 -0
  114. package/templates/workflow/.oxfmtrc.json +3 -0
  115. package/templates/workflow/.oxlintrc.json +197 -0
  116. package/templates/workflow/.prettierrc +1 -0
  117. package/templates/workflow/README.md +24 -0
  118. package/templates/workflow/__dot__gitignore +3 -0
  119. package/templates/{testing → workflow}/e2e/globalSetup.ts +5 -5
  120. package/templates/workflow/e2e/resolver.test.ts +90 -0
  121. package/templates/workflow/e2e/workflow.test.ts +31 -0
  122. package/templates/workflow/eslint.config.js +24 -0
  123. package/templates/workflow/package.json +35 -0
  124. package/templates/workflow/src/db/order.ts +22 -0
  125. package/templates/workflow/src/db/user.ts +22 -0
  126. package/templates/workflow/src/generated/db.ts +48 -0
  127. package/templates/workflow/src/resolver/incrementAge.ts +40 -0
  128. package/templates/workflow/src/workflow/order-fulfillment.test.ts +133 -0
  129. package/templates/workflow/src/workflow/order-fulfillment.ts +69 -0
  130. package/templates/{testing/src/workflow/wrapTailordb.test.ts → workflow/src/workflow/sync-profile.test.ts} +1 -1
  131. package/templates/{testing → workflow}/tailor.config.ts +1 -1
  132. package/templates/workflow/tests/bundled.test.ts +145 -0
  133. package/templates/workflow/tsconfig.json +16 -0
  134. package/templates/workflow/user-defined.d.ts +15 -0
  135. package/templates/{testing → workflow}/vitest.config.ts +6 -0
  136. package/templates/testing/README.md +0 -130
  137. package/templates/testing/e2e/resolver.test.ts +0 -57
  138. package/templates/testing/e2e/workflow.test.ts +0 -47
  139. package/templates/testing/src/resolver/simple.test.ts +0 -14
  140. package/templates/testing/src/workflow/simple.test.ts +0 -88
  141. package/templates/testing/src/workflow/simple.ts +0 -36
  142. package/templates/testing/src/workflow/trigger.test.ts +0 -104
  143. /package/templates/{testing → executor}/.oxfmtrc.json +0 -0
  144. /package/templates/{testing → executor}/.oxlintrc.json +0 -0
  145. /package/templates/{testing → executor}/.prettierrc +0 -0
  146. /package/templates/{testing → executor}/__dot__gitignore +0 -0
  147. /package/templates/{testing → executor}/tsconfig.json +0 -0
  148. /package/templates/{testing → resolver}/src/db/user.ts +0 -0
  149. /package/templates/{testing → resolver}/src/generated/db.ts +0 -0
  150. /package/templates/{testing/src/resolver/simple.ts → resolver/src/resolver/add.ts} +0 -0
  151. /package/templates/{testing/src/workflow/wrapTailordb.ts → workflow/src/workflow/sync-profile.ts} +0 -0
@@ -0,0 +1,92 @@
1
+ import { unauthenticatedTailorUser } from "@tailor-platform/sdk/test";
2
+ import { afterAll, afterEach, beforeAll, describe, expect, test, vi } from "vitest";
3
+ import resolver from "./getProduct";
4
+
5
+ describe("getProduct resolver", () => {
6
+ const mockQueryObject = vi.fn();
7
+ beforeAll(() => {
8
+ vi.stubGlobal("tailordb", {
9
+ Client: vi.fn(
10
+ class {
11
+ connect = vi.fn();
12
+ end = vi.fn();
13
+ queryObject = mockQueryObject;
14
+ },
15
+ ),
16
+ });
17
+ });
18
+ afterAll(() => {
19
+ vi.unstubAllGlobals();
20
+ });
21
+ afterEach(() => {
22
+ mockQueryObject.mockReset();
23
+ });
24
+
25
+ test("returns product with category", async () => {
26
+ // Select product
27
+ mockQueryObject.mockResolvedValueOnce({
28
+ rows: [
29
+ {
30
+ id: "product-1",
31
+ name: "Widget",
32
+ price: 9.99,
33
+ status: "ACTIVE",
34
+ categoryId: "cat-1",
35
+ description: null,
36
+ createdAt: new Date(),
37
+ updatedAt: null,
38
+ },
39
+ ],
40
+ });
41
+ // Select category
42
+ mockQueryObject.mockResolvedValueOnce({
43
+ rows: [{ name: "Gadgets" }],
44
+ });
45
+
46
+ const result = await resolver.body({
47
+ input: { productId: "product-1" },
48
+ user: unauthenticatedTailorUser,
49
+ env: {},
50
+ });
51
+
52
+ expect(result).toEqual({
53
+ name: "Widget",
54
+ price: 9.99,
55
+ status: "ACTIVE",
56
+ categoryName: "Gadgets",
57
+ });
58
+ expect(mockQueryObject).toHaveBeenCalledTimes(2);
59
+ });
60
+
61
+ test("returns product without category", async () => {
62
+ // Select product (no categoryId)
63
+ mockQueryObject.mockResolvedValueOnce({
64
+ rows: [
65
+ {
66
+ id: "product-2",
67
+ name: "Standalone Item",
68
+ price: 19.99,
69
+ status: "DRAFT",
70
+ categoryId: null,
71
+ description: null,
72
+ createdAt: new Date(),
73
+ updatedAt: null,
74
+ },
75
+ ],
76
+ });
77
+
78
+ const result = await resolver.body({
79
+ input: { productId: "product-2" },
80
+ user: unauthenticatedTailorUser,
81
+ env: {},
82
+ });
83
+
84
+ expect(result).toEqual({
85
+ name: "Standalone Item",
86
+ price: 19.99,
87
+ status: "DRAFT",
88
+ categoryName: null,
89
+ });
90
+ expect(mockQueryObject).toHaveBeenCalledTimes(1);
91
+ });
92
+ });
@@ -0,0 +1,53 @@
1
+ import { createResolver, t } from "@tailor-platform/sdk";
2
+ import { getDB } from "../generated/db";
3
+
4
+ const resolver = createResolver({
5
+ name: "getProduct",
6
+ description: "Retrieves a product by ID with its category",
7
+ operation: "query",
8
+ input: {
9
+ productId: t.uuid(),
10
+ },
11
+ body: async (context) => {
12
+ const db = getDB("main-db");
13
+
14
+ const product = await db
15
+ .selectFrom("Product")
16
+ .where("id", "=", context.input.productId)
17
+ .selectAll()
18
+ .executeTakeFirstOrThrow();
19
+
20
+ const result: {
21
+ name: string;
22
+ price: number;
23
+ status: string;
24
+ categoryName: string | null;
25
+ } = {
26
+ name: product.name,
27
+ price: product.price,
28
+ status: product.status,
29
+ categoryName: null,
30
+ };
31
+
32
+ if (product.categoryId) {
33
+ const category = await db
34
+ .selectFrom("Category")
35
+ .where("id", "=", product.categoryId)
36
+ .select("name")
37
+ .executeTakeFirst();
38
+ if (category) {
39
+ result.categoryName = category.name;
40
+ }
41
+ }
42
+
43
+ return result;
44
+ },
45
+ output: t.object({
46
+ name: t.string(),
47
+ price: t.float(),
48
+ status: t.string(),
49
+ categoryName: t.string({ optional: true }),
50
+ }),
51
+ });
52
+
53
+ export default resolver;
@@ -0,0 +1,23 @@
1
+ import { t } from "@tailor-platform/sdk";
2
+ import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
3
+ import { defineSchema } from "@toiroakr/lines-db";
4
+ import { category } from "../../db/category";
5
+
6
+ const schemaType = t.object({
7
+ ...category.pickFields(["id"], { optional: true }),
8
+ ...category.omitFields(["id"]),
9
+ });
10
+
11
+ const hook = createTailorDBHook(category);
12
+
13
+ export const schema = defineSchema(
14
+ createStandardSchema(schemaType, hook),
15
+ {
16
+ foreignKeys: [
17
+ {"column":"parentCategoryId","references":{"table":"Category","column":"id"}},
18
+ ],
19
+ indexes: [
20
+ {"name":"category_slug_unique_idx","columns":["slug"],"unique":true},
21
+ ],
22
+ }
23
+ );
File without changes
@@ -0,0 +1,21 @@
1
+ import { t } from "@tailor-platform/sdk";
2
+ import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
3
+ import { defineSchema } from "@toiroakr/lines-db";
4
+ import { order } from "../../db/order";
5
+
6
+ const schemaType = t.object({
7
+ ...order.pickFields(["id","createdAt"], { optional: true }),
8
+ ...order.omitFields(["id","createdAt"]),
9
+ });
10
+
11
+ const hook = createTailorDBHook(order);
12
+
13
+ export const schema = defineSchema(
14
+ createStandardSchema(schemaType, hook),
15
+ {
16
+ foreignKeys: [
17
+ {"column":"productId","references":{"table":"Product","column":"id"}},
18
+ {"column":"userId","references":{"table":"User","column":"id"}},
19
+ ],
20
+ }
21
+ );
@@ -0,0 +1,23 @@
1
+ import { t } from "@tailor-platform/sdk";
2
+ import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
3
+ import { defineSchema } from "@toiroakr/lines-db";
4
+ import { product } from "../../db/product";
5
+
6
+ const schemaType = t.object({
7
+ ...product.pickFields(["id","createdAt"], { optional: true }),
8
+ ...product.omitFields(["id","createdAt"]),
9
+ });
10
+
11
+ const hook = createTailorDBHook(product);
12
+
13
+ export const schema = defineSchema(
14
+ createStandardSchema(schemaType, hook),
15
+ {
16
+ foreignKeys: [
17
+ {"column":"categoryId","references":{"table":"Category","column":"id"}},
18
+ ],
19
+ indexes: [
20
+ {"name":"idx_status_categoryId","columns":["status","categoryId"],"unique":false},
21
+ ],
22
+ }
23
+ );
File without changes
@@ -0,0 +1,20 @@
1
+ import { t } from "@tailor-platform/sdk";
2
+ import { createTailorDBHook, createStandardSchema } from "@tailor-platform/sdk/test";
3
+ import { defineSchema } from "@toiroakr/lines-db";
4
+ import { user } from "../../db/user";
5
+
6
+ const schemaType = t.object({
7
+ ...user.pickFields(["id","createdAt"], { optional: true }),
8
+ ...user.omitFields(["id","createdAt"]),
9
+ });
10
+
11
+ const hook = createTailorDBHook(user);
12
+
13
+ export const schema = defineSchema(
14
+ createStandardSchema(schemaType, hook),
15
+ {
16
+ indexes: [
17
+ {"name":"user_email_unique_idx","columns":["email"],"unique":true},
18
+ ],
19
+ }
20
+ );
@@ -0,0 +1,419 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { parseArgs, styleText } from "node:util";
4
+ import { createInterface } from "node:readline";
5
+ import {
6
+ show,
7
+ truncate,
8
+ bundleSeedScript,
9
+ chunkSeedData,
10
+ executeScript,
11
+ initOperatorClient,
12
+ loadAccessToken,
13
+ loadWorkspaceId,
14
+ } from "@tailor-platform/sdk/cli";
15
+
16
+ // Parse command-line arguments
17
+ const { values, positionals } = parseArgs({
18
+ options: {
19
+ "machine-user": { type: "string", short: "m" },
20
+ namespace: { type: "string", short: "n" },
21
+ "skip-idp": { type: "boolean", default: false },
22
+ truncate: { type: "boolean", default: false },
23
+ yes: { type: "boolean", default: false },
24
+ profile: { type: "string", short: "p" },
25
+ help: { type: "boolean", short: "h", default: false },
26
+ },
27
+ allowPositionals: true,
28
+ });
29
+
30
+ if (values.help) {
31
+ console.log(`
32
+ Usage: node exec.mjs [options] [types...]
33
+
34
+ Options:
35
+ -m, --machine-user <name> Machine user name for authentication (required if not configured)
36
+ -n, --namespace <ns> Process all types in specified namespace (excludes _User)
37
+ --skip-idp Skip IdP user (_User) entity
38
+ --truncate Truncate tables before seeding
39
+ --yes Skip confirmation prompts (for truncate)
40
+ -p, --profile <name> Workspace profile name
41
+ -h, --help Show help
42
+
43
+ Examples:
44
+ node exec.mjs -m admin # Process all types with machine user
45
+ node exec.mjs --namespace <namespace> # Process tailordb namespace only (no _User)
46
+ node exec.mjs User Order # Process specific types only
47
+ node exec.mjs --skip-idp # Process all except _User
48
+ node exec.mjs --truncate # Truncate all tables, then seed all
49
+ node exec.mjs --truncate --yes # Truncate all tables without confirmation, then seed all
50
+ node exec.mjs --truncate --namespace <namespace> # Truncate tailordb, then seed tailordb
51
+ node exec.mjs --truncate User Order # Truncate User and Order, then seed them
52
+ `);
53
+ process.exit(0);
54
+ }
55
+
56
+ // Helper function to prompt for y/n confirmation
57
+ const promptConfirmation = (question) => {
58
+ const rl = createInterface({
59
+ input: process.stdin,
60
+ output: process.stdout,
61
+ });
62
+
63
+ return new Promise((resolve) => {
64
+ rl.question(styleText("yellow", question), (answer) => {
65
+ rl.close();
66
+ resolve(answer.toLowerCase().trim());
67
+ });
68
+ });
69
+ };
70
+
71
+ const configDir = import.meta.dirname;
72
+ const configPath = join(configDir, "../../tailor.config.ts");
73
+
74
+ // Determine machine user name (CLI argument takes precedence over config default)
75
+ const defaultMachineUser = "admin";
76
+ const machineUserName = values["machine-user"] || defaultMachineUser;
77
+
78
+ if (!machineUserName) {
79
+ console.error(styleText("red", "Error: Machine user name is required."));
80
+ console.error(styleText("yellow", "Specify --machine-user <name> or configure machineUserName in generator options."));
81
+ process.exit(1);
82
+ }
83
+
84
+ // Entity configuration
85
+ const namespaceEntities = {
86
+ "main-db": [
87
+ "Category",
88
+ "Order",
89
+ "Product",
90
+ "User",
91
+ ]
92
+ };
93
+ const namespaceDeps = {
94
+ "main-db": {
95
+ "Category": [],
96
+ "Order": ["Product", "User"],
97
+ "Product": ["Category"],
98
+ "User": []
99
+ }
100
+ };
101
+ const entities = Object.values(namespaceEntities).flat();
102
+ const hasIdpUser = false;
103
+
104
+ // Determine which entities to process
105
+ let entitiesToProcess = null;
106
+
107
+ const hasNamespace = !!values.namespace;
108
+ const hasTypes = positionals.length > 0;
109
+ const skipIdp = values["skip-idp"];
110
+
111
+ // Validate mutually exclusive options
112
+ const optionCount = [hasNamespace, hasTypes].filter(Boolean).length;
113
+ if (optionCount > 1) {
114
+ console.error(styleText("red", "Error: Options --namespace and type names are mutually exclusive."));
115
+ process.exit(1);
116
+ }
117
+
118
+ // --skip-idp and --namespace are redundant (namespace already excludes _User)
119
+ if (skipIdp && hasNamespace) {
120
+ console.warn(styleText("yellow", "Warning: --skip-idp is redundant with --namespace (namespace filtering already excludes _User)."));
121
+ }
122
+
123
+ // Filter by namespace (automatically excludes _User as it has no namespace)
124
+ if (hasNamespace) {
125
+ const namespace = values.namespace;
126
+ entitiesToProcess = namespaceEntities[namespace];
127
+
128
+ if (!entitiesToProcess || entitiesToProcess.length === 0) {
129
+ console.error(styleText("red", `Error: No entities found in namespace "${namespace}"`));
130
+ console.error(styleText("yellow", `Available namespaces: ${Object.keys(namespaceEntities).join(", ")}`));
131
+ process.exit(1);
132
+ }
133
+
134
+ console.log(styleText("cyan", `Filtering by namespace: ${namespace}`));
135
+ console.log(styleText("dim", `Entities: ${entitiesToProcess.join(", ")}`));
136
+ }
137
+
138
+ // Filter by specific types
139
+ if (hasTypes) {
140
+ const requestedTypes = positionals;
141
+ const notFoundTypes = [];
142
+ const allTypes = hasIdpUser ? [...entities, "_User"] : entities;
143
+
144
+ entitiesToProcess = requestedTypes.filter((type) => {
145
+ if (!allTypes.includes(type)) {
146
+ notFoundTypes.push(type);
147
+ return false;
148
+ }
149
+ return true;
150
+ });
151
+
152
+ if (notFoundTypes.length > 0) {
153
+ console.error(styleText("red", `Error: The following types were not found: ${notFoundTypes.join(", ")}`));
154
+ console.error(styleText("yellow", `Available types: ${allTypes.join(", ")}`));
155
+ process.exit(1);
156
+ }
157
+
158
+ console.log(styleText("cyan", `Filtering by types: ${entitiesToProcess.join(", ")}`));
159
+ }
160
+
161
+ // Apply --skip-idp filter
162
+ if (skipIdp) {
163
+ if (entitiesToProcess) {
164
+ entitiesToProcess = entitiesToProcess.filter((entity) => entity !== "_User");
165
+ } else {
166
+ entitiesToProcess = entities.filter((entity) => entity !== "_User");
167
+ }
168
+ }
169
+
170
+ // Get application info
171
+ const appInfo = await show({ configPath, profile: values.profile });
172
+ const authNamespace = appInfo.auth;
173
+
174
+ // Initialize operator client (once for all namespaces)
175
+ const accessToken = await loadAccessToken({ profile: values.profile, useProfile: true });
176
+ const workspaceId = await loadWorkspaceId({ profile: values.profile });
177
+ const operatorClient = await initOperatorClient(accessToken);
178
+
179
+
180
+
181
+ // Truncate tables if requested
182
+ if (values.truncate) {
183
+ const answer = values.yes ? "y" : await promptConfirmation("Are you sure you want to truncate? (y/n): ");
184
+ if (answer !== "y") {
185
+ console.log(styleText("yellow", "Truncate cancelled."));
186
+ process.exit(0);
187
+ }
188
+
189
+ console.log(styleText("cyan", "Truncating tables..."));
190
+
191
+ try {
192
+ if (hasNamespace) {
193
+ await truncate({
194
+ configPath,
195
+ profile: values.profile,
196
+ namespace: values.namespace,
197
+ });
198
+ } else if (hasTypes) {
199
+ const typesToTruncate = entitiesToProcess.filter((t) => t !== "_User");
200
+ if (typesToTruncate.length > 0) {
201
+ await truncate({
202
+ configPath,
203
+ profile: values.profile,
204
+ types: typesToTruncate,
205
+ });
206
+ } else {
207
+ console.log(styleText("dim", "No TailorDB types to truncate (only _User was specified)."));
208
+ }
209
+ } else {
210
+ await truncate({
211
+ configPath,
212
+ profile: values.profile,
213
+ all: true,
214
+ });
215
+ }
216
+ } catch (error) {
217
+ console.error(styleText("red", `Truncate failed: ${error.message}`));
218
+ process.exit(1);
219
+ }
220
+
221
+
222
+
223
+ console.log(styleText("green", "Truncate completed."));
224
+ }
225
+
226
+ console.log(styleText("cyan", "\nStarting seed data generation..."));
227
+ if (skipIdp) {
228
+ console.log(styleText("dim", ` Skipping IdP user (_User)`));
229
+ }
230
+
231
+ // Load seed data from JSONL files
232
+ const loadSeedData = (dataDir, typeNames) => {
233
+ const data = {};
234
+ for (const typeName of typeNames) {
235
+ const jsonlPath = join(dataDir, `${typeName}.jsonl`);
236
+ try {
237
+ const content = readFileSync(jsonlPath, "utf-8").trim();
238
+ if (content) {
239
+ data[typeName] = content.split("\n").map((line) => JSON.parse(line));
240
+ } else {
241
+ data[typeName] = [];
242
+ }
243
+ } catch (error) {
244
+ if (error.code === "ENOENT") {
245
+ data[typeName] = [];
246
+ } else {
247
+ throw error;
248
+ }
249
+ }
250
+ }
251
+ return data;
252
+ };
253
+
254
+ // Topological sort for dependency order
255
+ const topologicalSort = (types, deps) => {
256
+ const visited = new Set();
257
+ const result = [];
258
+
259
+ const visit = (type) => {
260
+ if (visited.has(type)) return;
261
+ visited.add(type);
262
+ const typeDeps = deps[type] || [];
263
+ for (const dep of typeDeps) {
264
+ if (types.includes(dep)) {
265
+ visit(dep);
266
+ }
267
+ }
268
+ result.push(type);
269
+ };
270
+
271
+ for (const type of types) {
272
+ visit(type);
273
+ }
274
+ return result;
275
+ };
276
+
277
+ // Seed TailorDB types via testExecScript
278
+ const seedViaTestExecScript = async (namespace, typesToSeed, deps) => {
279
+ const dataDir = join(configDir, "data");
280
+ const sortedTypes = topologicalSort(typesToSeed, deps);
281
+ const data = loadSeedData(dataDir, sortedTypes);
282
+
283
+ // Skip if no data
284
+ const typesWithData = sortedTypes.filter((t) => data[t] && data[t].length > 0);
285
+ if (typesWithData.length === 0) {
286
+ console.log(styleText("dim", ` [${namespace}] No data to seed`));
287
+ return { success: true, processed: {} };
288
+ }
289
+
290
+ console.log(styleText("cyan", ` [${namespace}] Seeding ${typesWithData.length} types via Kysely batch insert...`));
291
+
292
+ // Bundle seed script
293
+ const bundled = await bundleSeedScript(namespace, typesWithData);
294
+
295
+ // Chunk seed data to fit within gRPC message size limits
296
+ const chunks = chunkSeedData({
297
+ data,
298
+ order: sortedTypes,
299
+ codeByteSize: new TextEncoder().encode(bundled.bundledCode).length,
300
+ });
301
+
302
+ if (chunks.length === 0) {
303
+ console.log(styleText("dim", ` [${namespace}] No data to seed`));
304
+ return { success: true, processed: {} };
305
+ }
306
+
307
+ if (chunks.length > 1) {
308
+ console.log(styleText("dim", ` Split into ${chunks.length} chunks`));
309
+ }
310
+
311
+ const allProcessed = {};
312
+ let hasError = false;
313
+ const allErrors = [];
314
+
315
+ for (const chunk of chunks) {
316
+ if (chunks.length > 1) {
317
+ console.log(styleText("dim", ` Chunk ${chunk.index + 1}/${chunk.total}: ${chunk.order.join(", ")}`));
318
+ }
319
+
320
+ // Execute seed script for this chunk
321
+ const result = await executeScript({
322
+ client: operatorClient,
323
+ workspaceId,
324
+ name: `seed-${namespace}.ts`,
325
+ code: bundled.bundledCode,
326
+ arg: JSON.stringify({ data: chunk.data, order: chunk.order }),
327
+ invoker: {
328
+ namespace: authNamespace,
329
+ machineUserName,
330
+ },
331
+ });
332
+
333
+ // Parse result and display logs
334
+ if (result.logs) {
335
+ for (const line of result.logs.split("\n").filter(Boolean)) {
336
+ console.log(styleText("dim", ` ${line}`));
337
+ }
338
+ }
339
+
340
+ if (result.success) {
341
+ let parsed;
342
+ try {
343
+ const parsedResult = JSON.parse(result.result || "{}");
344
+ parsed = parsedResult && typeof parsedResult === "object" ? parsedResult : {};
345
+ } catch (error) {
346
+ const message = error instanceof Error ? error.message : String(error);
347
+ console.error(styleText("red", ` ✗ Failed to parse seed result: ${message}`));
348
+ hasError = true;
349
+ allErrors.push(message);
350
+ continue;
351
+ }
352
+
353
+ const processed = parsed.processed || {};
354
+ for (const [type, count] of Object.entries(processed)) {
355
+ allProcessed[type] = (allProcessed[type] || 0) + count;
356
+ console.log(styleText("green", ` ✓ ${type}: ${count} rows inserted`));
357
+ }
358
+
359
+ if (!parsed.success) {
360
+ const errors = Array.isArray(parsed.errors) ? parsed.errors : [];
361
+ const errorMessage =
362
+ errors.length > 0 ? errors.join("\n ") : "Seed script reported failure";
363
+ console.error(styleText("red", ` ✗ Seed failed:\n ${errorMessage}`));
364
+ hasError = true;
365
+ allErrors.push(errorMessage);
366
+ }
367
+ } else {
368
+ console.error(styleText("red", ` ✗ Seed failed: ${result.error}`));
369
+ hasError = true;
370
+ allErrors.push(result.error);
371
+ }
372
+ }
373
+
374
+ if (hasError) {
375
+ return { success: false, error: allErrors.join("\n") };
376
+ }
377
+ return { success: true, processed: allProcessed };
378
+ };
379
+
380
+
381
+
382
+ // Main execution
383
+ try {
384
+ let allSuccess = true;
385
+
386
+ // Determine which namespaces and types to process
387
+ const namespacesToProcess = hasNamespace
388
+ ? [values.namespace]
389
+ : Object.keys(namespaceEntities);
390
+
391
+ for (const namespace of namespacesToProcess) {
392
+ const nsTypes = namespaceEntities[namespace] || [];
393
+ const nsDeps = namespaceDeps[namespace] || {};
394
+
395
+ // Filter types if specific types requested
396
+ let typesToSeed = entitiesToProcess
397
+ ? nsTypes.filter((t) => entitiesToProcess.includes(t))
398
+ : nsTypes;
399
+
400
+ if (typesToSeed.length === 0) continue;
401
+
402
+ const result = await seedViaTestExecScript(namespace, typesToSeed, nsDeps);
403
+ if (!result.success) {
404
+ allSuccess = false;
405
+ }
406
+ }
407
+
408
+
409
+
410
+ if (allSuccess) {
411
+ console.log(styleText("green", "\n✓ Seed data generation completed successfully"));
412
+ } else {
413
+ console.error(styleText("red", "\n✗ Seed data generation completed with errors"));
414
+ process.exit(1);
415
+ }
416
+ } catch (error) {
417
+ console.error(styleText("red", `\n✗ Seed data generation failed: ${error.message}`));
418
+ process.exit(1);
419
+ }
@@ -0,0 +1,36 @@
1
+ import { defineAuth, defineConfig, defineIdp, definePlugins, t } from "@tailor-platform/sdk";
2
+ import { enumConstantsPlugin } from "@tailor-platform/sdk/plugin/enum-constants";
3
+ import { fileUtilsPlugin } from "@tailor-platform/sdk/plugin/file-utils";
4
+ import { kyselyTypePlugin } from "@tailor-platform/sdk/plugin/kysely-type";
5
+ import { seedPlugin } from "@tailor-platform/sdk/plugin/seed";
6
+
7
+ const idp = defineIdp("main-idp", {
8
+ authorization: "loggedIn",
9
+ clients: ["default-idp-client"],
10
+ });
11
+
12
+ export default defineConfig({
13
+ name: "generators",
14
+ auth: defineAuth("main-auth", {
15
+ machineUserAttributes: {
16
+ role: t.string(),
17
+ },
18
+ machineUsers: {
19
+ admin: {
20
+ attributes: {
21
+ role: "admin",
22
+ },
23
+ },
24
+ },
25
+ }),
26
+ idp: [idp],
27
+ db: { "main-db": { files: ["./src/db/*.ts"] } },
28
+ resolver: { "main-resolver": { files: ["./src/resolver/*.ts"] } },
29
+ });
30
+
31
+ export const plugins = definePlugins(
32
+ kyselyTypePlugin({ distPath: "./src/generated/db.ts" }),
33
+ enumConstantsPlugin({ distPath: "./src/generated/enums.ts" }),
34
+ fileUtilsPlugin({ distPath: "./src/generated/files.ts" }),
35
+ seedPlugin({ distPath: "./src/seed", machineUserName: "admin" }),
36
+ );