@tailor-platform/sdk 0.16.2 → 0.17.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 (38) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +75 -8
  3. package/dist/cli/api.d.mts +6 -2
  4. package/dist/cli/api.mjs +1 -1
  5. package/dist/cli/index.mjs +51 -75
  6. package/dist/cli/index.mjs.map +1 -1
  7. package/dist/configure/index.d.mts +2 -2
  8. package/dist/{index-DOA9RfBq.d.mts → index-Bin7-j3v.d.mts} +2 -2
  9. package/dist/{resume-Yw6OGEYO.mjs → resume-B2ba5opn.mjs} +165 -122
  10. package/dist/{resume-Yw6OGEYO.mjs.map → resume-B2ba5opn.mjs.map} +1 -1
  11. package/dist/{types-DUYX8rv-.d.mts → types-Da_WnvA0.d.mts} +15 -1
  12. package/dist/utils/test/index.d.mts +9 -3
  13. package/dist/utils/test/index.mjs +8 -6
  14. package/dist/utils/test/index.mjs.map +1 -1
  15. package/docs/cli/application.md +136 -0
  16. package/docs/cli/auth.md +110 -0
  17. package/docs/cli/secret.md +125 -0
  18. package/docs/cli/user.md +183 -0
  19. package/docs/cli/workflow.md +144 -0
  20. package/docs/cli/workspace.md +122 -0
  21. package/docs/cli-reference.md +80 -801
  22. package/docs/configuration.md +36 -32
  23. package/docs/generator/builtin.md +194 -0
  24. package/docs/generator/custom.md +150 -0
  25. package/docs/generator/index.md +56 -0
  26. package/docs/quickstart.md +9 -4
  27. package/docs/services/auth.md +225 -0
  28. package/docs/services/executor.md +304 -0
  29. package/docs/services/idp.md +106 -0
  30. package/docs/services/resolver.md +213 -0
  31. package/docs/services/secret.md +116 -0
  32. package/docs/services/staticwebsite.md +132 -0
  33. package/docs/services/tailordb.md +305 -0
  34. package/docs/services/workflow.md +176 -0
  35. package/docs/testing.md +3 -1
  36. package/package.json +4 -3
  37. package/postinstall.mjs +1 -0
  38. package/docs/core-concepts.md +0 -609
@@ -0,0 +1,305 @@
1
+ # TailorDB
2
+
3
+ TailorDB is a type-safe database service for defining and managing data models on the Tailor Platform.
4
+
5
+ ## Overview
6
+
7
+ TailorDB provides:
8
+
9
+ - Type-safe schema definitions using TypeScript
10
+ - Automatic GraphQL API generation (CRUD operations)
11
+ - Relations between types with automatic index and foreign key constraints
12
+ - Permission system for access control
13
+ - Field-level hooks and validations
14
+
15
+ For the official Tailor Platform documentation, see [TailorDB Guide](https://docs.tailor.tech/guides/tailordb/overview).
16
+
17
+ ## Type Definition
18
+
19
+ Define TailorDB Types in files matching glob patterns specified in `tailor.config.ts`.
20
+
21
+ ```typescript
22
+ import { db } from "@tailor-platform/sdk";
23
+
24
+ export const user = db.type("User", {
25
+ name: db.string(),
26
+ email: db.string().unique(),
27
+ age: db.int(),
28
+ ...db.fields.timestamps(),
29
+ });
30
+ ```
31
+
32
+ Specify plural form by passing an array as first argument:
33
+
34
+ ```typescript
35
+ db.type(["User", "UserList"], {
36
+ name: db.string(),
37
+ });
38
+ ```
39
+
40
+ Pass a description as second argument:
41
+
42
+ ```typescript
43
+ db.type("User", "User in the system", {
44
+ name: db.string(),
45
+ });
46
+ ```
47
+
48
+ ## Field Types
49
+
50
+ | Method | TailorDB | TypeScript |
51
+ | ------------------------------- | -------- | -------------- |
52
+ | `db.string()` | String | string |
53
+ | `db.int()` | Integer | number |
54
+ | `db.float()` | Float | number |
55
+ | `db.bool()` | Boolean | boolean |
56
+ | `db.date()` | Date | string |
57
+ | `db.datetime()` | DateTime | string \| Date |
58
+ | `db.time()` | Time | string |
59
+ | `db.uuid()` | UUID | string |
60
+ | [`db.enum()`](#enum-fields) | Enum | string |
61
+ | [`db.object()`](#object-fields) | Nested | object |
62
+
63
+ ### Optional and Array Fields
64
+
65
+ ```typescript
66
+ db.string({ optional: true });
67
+ db.string({ array: true });
68
+ db.string({ optional: true, array: true });
69
+ ```
70
+
71
+ ### Enum Fields
72
+
73
+ ```typescript
74
+ db.enum(["red", "green", "blue"]);
75
+ db.enum([
76
+ { value: "active", description: "Active status" },
77
+ { value: "inactive", description: "Inactive status" },
78
+ ]);
79
+ ```
80
+
81
+ ### Object Fields
82
+
83
+ ```typescript
84
+ db.object({
85
+ street: db.string(),
86
+ city: db.string(),
87
+ country: db.string(),
88
+ });
89
+ ```
90
+
91
+ ## Field Modifiers
92
+
93
+ ### Description
94
+
95
+ ```typescript
96
+ db.string().description("User's full name");
97
+ ```
98
+
99
+ ### Index / Unique
100
+
101
+ ```typescript
102
+ db.string().index();
103
+ db.string().unique();
104
+ ```
105
+
106
+ ### Relations
107
+
108
+ Add a relation to field with automatic index and foreign key constraint:
109
+
110
+ ```typescript
111
+ const role = db.type("Role", {
112
+ name: db.string(),
113
+ });
114
+
115
+ const user = db.type("User", {
116
+ name: db.string(),
117
+ roleId: db.uuid().relation({
118
+ type: "n-1",
119
+ toward: { type: role },
120
+ }),
121
+ });
122
+ ```
123
+
124
+ For one-to-one relations, use `type: "1-1"`:
125
+
126
+ ```typescript
127
+ const userProfile = db.type("UserProfile", {
128
+ userId: db.uuid().relation({
129
+ type: "1-1",
130
+ toward: { type: user },
131
+ }),
132
+ bio: db.string(),
133
+ });
134
+ ```
135
+
136
+ For foreign key constraint without creating a relation, use `type: "keyOnly"`:
137
+
138
+ ```typescript
139
+ const user = db.type("User", {
140
+ roleId: db.uuid().relation({
141
+ type: "keyOnly",
142
+ toward: { type: role },
143
+ }),
144
+ });
145
+ ```
146
+
147
+ Create relations against different fields using `toward.key`:
148
+
149
+ ```typescript
150
+ const user = db.type("User", {
151
+ email: db.string().unique(),
152
+ });
153
+
154
+ const userProfile = db.type("UserProfile", {
155
+ userEmail: db.string().relation({
156
+ type: "1-1",
157
+ toward: { type: user, key: "email" },
158
+ }),
159
+ });
160
+ ```
161
+
162
+ Customize relation names using `toward.as` / `backward` options:
163
+
164
+ ```typescript
165
+ const userProfile = db.type("UserProfile", {
166
+ userId: db.uuid().relation({
167
+ type: "1-1",
168
+ toward: { type: user, as: "base" },
169
+ backward: "profile",
170
+ }),
171
+ });
172
+ ```
173
+
174
+ This generates the following GraphQL types:
175
+
176
+ ```graphql
177
+ type UserProfile {
178
+ userId: ID!
179
+ base: User # toward.as: access User from UserProfile
180
+ }
181
+
182
+ type User {
183
+ id: ID!
184
+ profile: UserProfile # backward: access UserProfile from User
185
+ }
186
+ ```
187
+
188
+ - `toward.as` - Customizes the field name for accessing the related type from this type
189
+ - `backward` - Customizes the field name for accessing this type from the related type
190
+
191
+ ### Hooks
192
+
193
+ Add hooks to execute functions during data creation or update:
194
+
195
+ ```typescript
196
+ db.datetime().hooks({
197
+ create: () => new Date(),
198
+ update: () => new Date(),
199
+ });
200
+ ```
201
+
202
+ Function arguments include: `value` (field value), `data` (entire record value), `user` (user performing the operation).
203
+
204
+ ### Validation
205
+
206
+ ```typescript
207
+ db.string().validate(
208
+ ({ value }) => value.length > 5,
209
+ [
210
+ ({ value }) => value.length < 10,
211
+ "Value must be shorter than 10 characters",
212
+ ],
213
+ );
214
+ ```
215
+
216
+ ### Vector Search
217
+
218
+ ```typescript
219
+ db.string().vector();
220
+ ```
221
+
222
+ ### Serial / Auto-increment
223
+
224
+ ```typescript
225
+ db.int().serial({
226
+ start: 0,
227
+ maxValue: 100,
228
+ });
229
+
230
+ db.string().serial({
231
+ start: 0,
232
+ format: "CUST_%d",
233
+ });
234
+ ```
235
+
236
+ ### Common Fields
237
+
238
+ ```typescript
239
+ export const user = db.type("User", {
240
+ name: db.string(),
241
+ ...db.fields.timestamps(),
242
+ });
243
+ ```
244
+
245
+ ## Type Modifiers
246
+
247
+ ### Composite Indexes
248
+
249
+ ```typescript
250
+ db.type("User", {
251
+ firstName: db.string(),
252
+ lastName: db.string(),
253
+ }).indexes({
254
+ fields: ["firstName", "lastName"],
255
+ unique: true,
256
+ name: "user_name_idx",
257
+ });
258
+ ```
259
+
260
+ ### File Fields
261
+
262
+ ```typescript
263
+ db.type("User", {
264
+ name: db.string(),
265
+ }).files({
266
+ avatar: "profile image",
267
+ });
268
+ ```
269
+
270
+ ### Features
271
+
272
+ ```typescript
273
+ db.type("User", {
274
+ name: db.string(),
275
+ }).features({
276
+ aggregation: true,
277
+ bulkUpsert: true,
278
+ });
279
+ ```
280
+
281
+ ### Permissions
282
+
283
+ Configure Permission and GQLPermission. For details, see the [TailorDB Permission documentation](https://docs.tailor.tech/guides/tailordb/permission).
284
+
285
+ ```typescript
286
+ db.type("User", {
287
+ name: db.string(),
288
+ role: db.enum(["admin", "user"]).index(),
289
+ })
290
+ .permission({
291
+ create: [[{ user: "role" }, "=", "admin"]],
292
+ read: [
293
+ [{ user: "role" }, "=", "admin"],
294
+ [{ record: "id" }, "=", { user: "id" }],
295
+ ],
296
+ update: [[{ user: "role" }, "=", "admin"]],
297
+ delete: [[{ user: "role" }, "=", "admin"]],
298
+ })
299
+ .gqlPermission([
300
+ { conditions: [[{ user: "role" }, "=", "admin"]], actions: "all" },
301
+ { conditions: [[{ user: "role" }, "=", "user"]], actions: ["read"] },
302
+ ]);
303
+ ```
304
+
305
+ Following the secure-by-default principle, all operations are denied if permissions are not configured.
@@ -0,0 +1,176 @@
1
+ # Workflow
2
+
3
+ Workflows orchestrate multiple jobs that can depend on each other, enabling complex multi-step operations with durable execution.
4
+
5
+ ## Overview
6
+
7
+ Workflows provide:
8
+
9
+ - Job orchestration with dependencies
10
+ - Durable execution with automatic state management
11
+ - Resume capabilities from failure points
12
+ - Access to TailorDB via Kysely query builder
13
+ - Job triggering for parallel or sequential execution
14
+
15
+ For the official Tailor Platform documentation, see [Workflow Guide](https://docs.tailor.tech/guides/workflow).
16
+
17
+ ## Workflow Rules
18
+
19
+ All workflow components must follow these rules:
20
+
21
+ | Rule | Description |
22
+ | ---------------------------------------------- | --------------------------------------------------- |
23
+ | `createWorkflow` result must be default export | Workflow files must export the workflow as default |
24
+ | All jobs must be named exports | Every job used in a workflow must be a named export |
25
+ | Job names must be unique | Job names must be unique across the entire project |
26
+ | `mainJob` is required | Every workflow must specify a `mainJob` |
27
+ | Jobs in `deps` must be job objects | Pass job objects, not strings |
28
+
29
+ ## Creating a Workflow Job
30
+
31
+ Define workflow jobs using `createWorkflowJob`:
32
+
33
+ ```typescript
34
+ import { createWorkflowJob } from "@tailor-platform/sdk";
35
+ import { getDB } from "../generated/tailordb";
36
+
37
+ // All jobs must be named exports
38
+ export const fetchCustomer = createWorkflowJob({
39
+ name: "fetch-customer",
40
+ body: async (input: { customerId: string }) => {
41
+ const db = getDB("tailordb");
42
+ const customer = await db
43
+ .selectFrom("Customer")
44
+ .selectAll()
45
+ .where("id", "=", input.customerId)
46
+ .executeTakeFirst();
47
+ return customer;
48
+ },
49
+ });
50
+ ```
51
+
52
+ ## Job Dependencies
53
+
54
+ Jobs can depend on other jobs using the `deps` array. Dependent jobs are accessible via the second argument of `body` function with hyphens replaced by underscores:
55
+
56
+ ```typescript
57
+ import { createWorkflowJob } from "@tailor-platform/sdk";
58
+ import { fetchCustomer } from "./jobs/fetch-customer";
59
+ import { sendNotification } from "./jobs/send-notification";
60
+
61
+ // All jobs must be named exports - including jobs with dependencies
62
+ export const processOrder = createWorkflowJob({
63
+ name: "process-order",
64
+ deps: [fetchCustomer, sendNotification],
65
+ body: async (input: { orderId: string; customerId: string }, { jobs }) => {
66
+ // Access dependent jobs with hyphens replaced by underscores
67
+ // "fetch-customer" -> jobs.fetch_customer()
68
+ // "send-notification" -> jobs.send_notification()
69
+ const customer = await jobs.fetch_customer({
70
+ customerId: input.customerId,
71
+ });
72
+
73
+ const notification = await jobs.send_notification({
74
+ message: `Order ${input.orderId} is being processed`,
75
+ recipient: customer.email,
76
+ });
77
+
78
+ return {
79
+ orderId: input.orderId,
80
+ customerEmail: customer.email,
81
+ notificationSent: notification.sent,
82
+ };
83
+ },
84
+ });
85
+ ```
86
+
87
+ ## Triggering Jobs
88
+
89
+ Use `.trigger()` to start other jobs from within a job:
90
+
91
+ ```typescript
92
+ export const mainJob = createWorkflowJob({
93
+ name: "main-job",
94
+ deps: [fetchCustomer, sendNotification],
95
+ body: (input: { customerId: string }, { jobs }) => {
96
+ // .trigger() is synchronous on server - do NOT use await
97
+ // "fetch-customer" -> jobs.fetch_customer
98
+ const customer = jobs.fetch_customer.trigger({
99
+ customerId: input.customerId,
100
+ });
101
+ const notification = jobs.send_notification.trigger({
102
+ message: "Order processed",
103
+ recipient: customer.email,
104
+ });
105
+ return { customer, notification };
106
+ },
107
+ });
108
+ ```
109
+
110
+ **Important:** `.trigger()` is synchronous on the server. Do NOT use `await` with it.
111
+
112
+ ## Workflow Definition
113
+
114
+ Define a workflow using `createWorkflow` and export it as default:
115
+
116
+ ```typescript
117
+ import { createWorkflow, createWorkflowJob } from "@tailor-platform/sdk";
118
+ import { fetchCustomer } from "./jobs/fetch-customer";
119
+ import { sendNotification } from "./jobs/send-notification";
120
+
121
+ // Jobs must be named exports
122
+ export const processOrder = createWorkflowJob({
123
+ name: "process-order",
124
+ deps: [fetchCustomer, sendNotification],
125
+ body: async (input, { jobs }) => {
126
+ // ... job logic
127
+ },
128
+ });
129
+
130
+ // Workflow must be default export
131
+ export default createWorkflow({
132
+ name: "order-processing",
133
+ mainJob: processOrder,
134
+ });
135
+ ```
136
+
137
+ ## File Organization
138
+
139
+ Recommended file structure for workflows:
140
+
141
+ ```
142
+ workflows/
143
+ ├── jobs/
144
+ │ ├── fetch-customer.ts # export const fetchCustomer = createWorkflowJob(...)
145
+ │ └── send-notification.ts # export const sendNotification = createWorkflowJob(...)
146
+ └── order-processing.ts # export const processOrder = createWorkflowJob(...)
147
+ # export default createWorkflow(...)
148
+ ```
149
+
150
+ All jobs can be in a single file or split across multiple files, as long as they are named exports.
151
+
152
+ ## CLI Commands
153
+
154
+ Manage workflows using the CLI:
155
+
156
+ ```bash
157
+ # List workflows
158
+ tailor-sdk workflow list
159
+
160
+ # Get workflow details
161
+ tailor-sdk workflow get <name>
162
+
163
+ # Start a workflow
164
+ tailor-sdk workflow start <name> -m <machine-user> -g '{"key": "value"}'
165
+
166
+ # List executions
167
+ tailor-sdk workflow executions
168
+
169
+ # Get execution details with logs
170
+ tailor-sdk workflow executions <execution-id> --logs
171
+
172
+ # Resume a failed execution
173
+ tailor-sdk workflow resume <execution-id>
174
+ ```
175
+
176
+ See [Workflow CLI Commands](../cli/workflow.md) for full documentation.
package/docs/testing.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Testing Guide
2
2
 
3
- This guide covers testing patterns for Tailor Platform SDK applications using [Vitest](https://vitest.dev/). For a complete working example with full test code, use:
3
+ This guide covers testing patterns for Tailor Platform SDK applications using [Vitest](https://vitest.dev/).
4
+
5
+ For a complete working example with full test code, use the `testing` template:
4
6
 
5
7
  ```bash
6
8
  npm create @tailor-platform/sdk <your-project-name> --template testing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk",
3
- "version": "0.16.2",
3
+ "version": "0.17.0",
4
4
  "description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
5
5
  "license": "MIT",
6
6
  "main": "./dist/configure/index.mjs",
@@ -50,6 +50,7 @@
50
50
  "citty": "0.1.6",
51
51
  "confbox": "0.2.2",
52
52
  "consola": "3.4.2",
53
+ "date-fns": "4.1.0",
53
54
  "es-toolkit": "1.42.0",
54
55
  "inflection": "3.0.2",
55
56
  "madge": "8.0.0",
@@ -74,13 +75,13 @@
74
75
  "@types/node": "22.19.2",
75
76
  "cross-env": "10.1.0",
76
77
  "eslint": "9.39.1",
77
- "eslint-plugin-jsdoc": "61.4.1",
78
+ "eslint-plugin-jsdoc": "61.5.0",
78
79
  "globals": "16.5.0",
79
80
  "sonda": "0.10.1",
80
81
  "tsdown": "0.15.6",
81
82
  "typescript": "5.9.3",
82
83
  "typescript-eslint": "8.49.0",
83
- "vitest": "4.0.14"
84
+ "vitest": "4.0.15"
84
85
  },
85
86
  "scripts": {
86
87
  "test": "vitest",
package/postinstall.mjs CHANGED
@@ -48,6 +48,7 @@ async function install() {
48
48
  );
49
49
  const { config } = await loadConfig(configPath);
50
50
  await generateUserTypes(config, configPath);
51
+ return;
51
52
  } catch (error) {
52
53
  console.warn("⚠️ Failed to generate types from config:", error.message);
53
54
  // Fall through to create empty type definition