@tailor-platform/sdk 0.16.3 → 0.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +75 -8
  3. package/dist/cli/api.d.mts +35 -31
  4. package/dist/cli/api.mjs +2 -2
  5. package/dist/cli/api.mjs.map +1 -1
  6. package/dist/cli/index.mjs +51 -75
  7. package/dist/cli/index.mjs.map +1 -1
  8. package/dist/configure/index.d.mts +3 -3
  9. package/dist/{index-Bin7-j3v.d.mts → index-BWqIQ4iC.d.mts} +2 -2
  10. package/dist/job-CL8myeqs.mjs.map +1 -1
  11. package/dist/{resume-kyHIaNvK.mjs → resume-ChDChtAZ.mjs} +200 -137
  12. package/dist/{resume-kyHIaNvK.mjs.map → resume-ChDChtAZ.mjs.map} +1 -1
  13. package/dist/{types-Da_WnvA0.d.mts → types-DgaCdTug.d.mts} +21 -13
  14. package/dist/utils/test/index.d.mts +9 -3
  15. package/dist/utils/test/index.mjs +8 -6
  16. package/dist/utils/test/index.mjs.map +1 -1
  17. package/docs/cli/application.md +136 -0
  18. package/docs/cli/auth.md +110 -0
  19. package/docs/cli/secret.md +125 -0
  20. package/docs/cli/user.md +183 -0
  21. package/docs/cli/workflow.md +144 -0
  22. package/docs/cli/workspace.md +122 -0
  23. package/docs/cli-reference.md +80 -801
  24. package/docs/configuration.md +62 -32
  25. package/docs/generator/builtin.md +194 -0
  26. package/docs/generator/custom.md +150 -0
  27. package/docs/generator/index.md +56 -0
  28. package/docs/quickstart.md +9 -4
  29. package/docs/services/auth.md +244 -0
  30. package/docs/services/executor.md +304 -0
  31. package/docs/services/idp.md +106 -0
  32. package/docs/services/resolver.md +213 -0
  33. package/docs/services/secret.md +116 -0
  34. package/docs/services/staticwebsite.md +132 -0
  35. package/docs/services/tailordb.md +325 -0
  36. package/docs/services/workflow.md +176 -0
  37. package/docs/testing.md +3 -1
  38. package/package.json +9 -8
  39. package/docs/core-concepts.md +0 -609
@@ -0,0 +1,244 @@
1
+ # Auth
2
+
3
+ Auth is a service for configuring authentication and authorization in your Tailor Platform application.
4
+
5
+ ## Overview
6
+
7
+ Auth provides:
8
+
9
+ - User profile mapping to TailorDB types
10
+ - Machine users for service-to-service authentication
11
+ - OAuth 2.0 client configuration
12
+ - Identity provider integration
13
+
14
+ For the official Tailor Platform documentation, see [Auth Guide](https://docs.tailor.tech/guides/auth/overview).
15
+
16
+ ## Configuration
17
+
18
+ Configure Auth service using `defineAuth()`:
19
+
20
+ ```typescript
21
+ import { defineAuth } from "@tailor-platform/sdk";
22
+ import { user } from "./tailordb/user";
23
+
24
+ const auth = defineAuth("my-auth", {
25
+ userProfile: {
26
+ type: user,
27
+ usernameField: "email",
28
+ attributes: { role: true },
29
+ },
30
+ machineUsers: {
31
+ "admin-machine-user": {
32
+ attributes: { role: "ADMIN" },
33
+ },
34
+ },
35
+ oauth2Clients: {
36
+ "my-oauth2-client": {
37
+ redirectURIs: ["https://example.com/callback"],
38
+ grantTypes: ["authorization_code", "refresh_token"],
39
+ },
40
+ },
41
+ idProvider: idp.provider("my-provider", "my-client"),
42
+ });
43
+
44
+ export default defineConfig({
45
+ auth,
46
+ });
47
+ ```
48
+
49
+ ## User Profile
50
+
51
+ Maps authenticated identities to a TailorDB type:
52
+
53
+ ```typescript
54
+ userProfile: {
55
+ type: user, // TailorDB type for user records
56
+ usernameField: "email", // Field used as username (must be unique)
57
+ attributes: {
58
+ role: true, // Enable 'role' as a user attribute
59
+ },
60
+ },
61
+ ```
62
+
63
+ Example TailorDB type for user profile:
64
+
65
+ ```typescript
66
+ // tailordb/user.ts
67
+ import { db } from "@tailor-platform/sdk";
68
+
69
+ export const user = db.type("User", {
70
+ email: db.string().unique(), // usernameField must have unique constraint
71
+ role: db.enum(["admin", "user"]),
72
+ ...db.fields.timestamps(),
73
+ });
74
+ ```
75
+
76
+ **type**: The TailorDB type that stores user records.
77
+
78
+ **usernameField**: The field in the TailorDB type used as the username. This field must have a unique constraint (`.unique()`) since it is used to uniquely identify users.
79
+
80
+ **attributes**: Specifies which fields from the TailorDB type are used as user attributes. Set to `true` to enable a field. Enabled attributes must be assigned values in all machine user definitions.
81
+
82
+ ## Machine Users
83
+
84
+ Service accounts for automated access without user interaction:
85
+
86
+ ```typescript
87
+ machineUsers: {
88
+ "admin-machine-user": {
89
+ attributes: { role: "ADMIN" },
90
+ },
91
+ "readonly-machine-user": {
92
+ attributes: { role: "READER" },
93
+ },
94
+ },
95
+ ```
96
+
97
+ **attributes**: Values for attributes enabled in `userProfile.attributes`. All fields marked as `true` in `userProfile.attributes` must be set here. These values are accessible via `user.attributes`:
98
+
99
+ ```typescript
100
+ // In a resolver
101
+ body: (context) => {
102
+ const role = context.user.attributes?.role;
103
+ },
104
+
105
+ // In TailorDB hooks
106
+ .hooks({
107
+ field: {
108
+ create: ({ user }) => user.attributes?.role === "ADMIN" ? "default" : null,
109
+ },
110
+ })
111
+
112
+ // In TailorDB validate
113
+ .validate({
114
+ field: [
115
+ ({ user }) => user.attributes?.role === "ADMIN",
116
+ "Only admins can set this field",
117
+ ],
118
+ })
119
+ ```
120
+
121
+ Machine users are useful for:
122
+
123
+ - CI/CD pipelines
124
+ - Background jobs
125
+ - Service-to-service communication
126
+ - E2E testing
127
+
128
+ Get a machine user token using the CLI:
129
+
130
+ ```bash
131
+ tailor-sdk machineuser token <name>
132
+ ```
133
+
134
+ ### Using auth.invoker()
135
+
136
+ The `auth.invoker()` method creates a type-safe reference to a machine user for use in workflow triggers. This specifies which machine user's permissions should be used when executing the workflow.
137
+
138
+ ```typescript
139
+ // tailor.config.ts
140
+ export const auth = defineAuth("my-auth", {
141
+ machineUsers: {
142
+ "admin-machine-user": {
143
+ attributes: { role: "ADMIN" },
144
+ },
145
+ },
146
+ // ... other config
147
+ });
148
+ ```
149
+
150
+ ```typescript
151
+ // resolvers/trigger-workflow.ts
152
+ import { createResolver, t } from "@tailor-platform/sdk";
153
+ import { auth } from "../tailor.config";
154
+ import myWorkflow from "../workflows/my-workflow";
155
+
156
+ export default createResolver({
157
+ name: "triggerMyWorkflow",
158
+ operation: "mutation",
159
+ input: {
160
+ id: t.string(),
161
+ },
162
+ body: async ({ input }) => {
163
+ // Trigger workflow with machine user permissions
164
+ const workflowRunId = await myWorkflow.trigger(
165
+ { id: input.id },
166
+ { authInvoker: auth.invoker("admin-machine-user") },
167
+ );
168
+ return { workflowRunId };
169
+ },
170
+ output: t.object({
171
+ workflowRunId: t.string(),
172
+ }),
173
+ });
174
+ ```
175
+
176
+ The `invoker()` method is type-safe and only accepts machine user names defined in the auth configuration.
177
+
178
+ ## OAuth 2.0 Clients
179
+
180
+ Configure OAuth 2.0 clients for third-party applications:
181
+
182
+ ```typescript
183
+ oauth2Clients: {
184
+ "my-oauth2-client": {
185
+ redirectURIs: [
186
+ "https://example.com/callback",
187
+ `${website.url}/callback`, // Type-safe URL from StaticWebsite
188
+ ],
189
+ description: "My OAuth2 client",
190
+ grantTypes: ["authorization_code", "refresh_token"],
191
+ accessTokenLifetimeSeconds: 3600, // 1 hour
192
+ refreshTokenLifetimeSeconds: 604800, // 7 days
193
+ },
194
+ },
195
+ ```
196
+
197
+ **redirectURIs**: Allowed redirect URIs after authentication.
198
+
199
+ **description**: Optional description of the client.
200
+
201
+ **grantTypes**: Supported OAuth 2.0 grant types:
202
+
203
+ - `authorization_code` - Standard OAuth 2.0 authorization code flow
204
+ - `refresh_token` - Allow refreshing access tokens
205
+
206
+ **accessTokenLifetimeSeconds**: Optional access token lifetime in seconds. Minimum: 60 seconds, Maximum: 86400 seconds (1 day). If not specified, uses platform default.
207
+
208
+ **refreshTokenLifetimeSeconds**: Optional refresh token lifetime in seconds. Minimum: 60 seconds, Maximum: 604800 seconds (7 days). If not specified, uses platform default.
209
+
210
+ Get OAuth2 client credentials using the CLI:
211
+
212
+ ```bash
213
+ tailor-sdk oauth2client get <name>
214
+ ```
215
+
216
+ ## Identity Provider
217
+
218
+ Connect to an external identity provider:
219
+
220
+ ```typescript
221
+ idProvider: idp.provider("my-provider", "my-client"),
222
+ ```
223
+
224
+ See [IdP](./idp.md) for configuring identity providers.
225
+
226
+ ## CLI Commands
227
+
228
+ Manage Auth resources using the CLI:
229
+
230
+ ```bash
231
+ # List machine users
232
+ tailor-sdk machineuser list
233
+
234
+ # Get machine user token
235
+ tailor-sdk machineuser token <name>
236
+
237
+ # List OAuth2 clients
238
+ tailor-sdk oauth2client list
239
+
240
+ # Get OAuth2 client credentials
241
+ tailor-sdk oauth2client get <name>
242
+ ```
243
+
244
+ See [Auth Resource Commands](../cli/auth.md) for full documentation.
@@ -0,0 +1,304 @@
1
+ # Executor
2
+
3
+ Executors are event-driven handlers that automatically trigger in response to data changes, schedules, or external events.
4
+
5
+ ## Overview
6
+
7
+ Executors provide:
8
+
9
+ - Automatic triggers on record changes (create, update, delete)
10
+ - Scheduled execution via cron expressions
11
+ - Incoming webhook handlers
12
+ - Post-resolver execution hooks
13
+ - Multiple execution targets (functions, webhooks, GraphQL)
14
+
15
+ For the official Tailor Platform documentation, see [Executor Guide](https://docs.tailor.tech/guides/executor/overview).
16
+
17
+ ## Creating an Executor
18
+
19
+ Define executors in files matching glob patterns specified in `tailor.config.ts`.
20
+
21
+ ```typescript
22
+ import { createExecutor, recordCreatedTrigger, t } from "@tailor-platform/sdk";
23
+ import { user } from "../tailordb/user";
24
+
25
+ export default createExecutor({
26
+ name: "user-welcome",
27
+ description: "Send welcome email to new users",
28
+ trigger: recordCreatedTrigger({
29
+ type: user,
30
+ condition: ({ newRecord }) => !!newRecord.email && newRecord.isActive,
31
+ }),
32
+ operation: {
33
+ kind: "function",
34
+ body: async ({ newRecord }) => {
35
+ // Send welcome email logic here
36
+ },
37
+ },
38
+ });
39
+ ```
40
+
41
+ ## Trigger Types
42
+
43
+ ### Record Triggers
44
+
45
+ Fire when records are created, updated, or deleted:
46
+
47
+ - `recordCreatedTrigger()`: Fires when a new record is created
48
+ - `recordUpdatedTrigger()`: Fires when a record is updated
49
+ - `recordDeletedTrigger()`: Fires when a record is deleted
50
+
51
+ Each trigger can include an optional filter function:
52
+
53
+ ```typescript
54
+ recordUpdatedTrigger({
55
+ type: order,
56
+ condition: ({ newRecord, oldRecord }) =>
57
+ newRecord.status === "completed" && oldRecord.status !== "completed",
58
+ });
59
+ ```
60
+
61
+ ### Schedule Trigger
62
+
63
+ Fires on a cron schedule:
64
+
65
+ ```typescript
66
+ scheduleTrigger({ cron: "*/5 * * * *" }); // Every 5 minutes
67
+ scheduleTrigger({ cron: "0 9 * * 1" }); // Every Monday at 9am
68
+ scheduleTrigger({ cron: "0 0 1 * *" }); // First day of every month
69
+ scheduleTrigger({ cron: "0 * * * *", timezone: "Asia/Tokyo" });
70
+ ```
71
+
72
+ ### Incoming Webhook Trigger
73
+
74
+ Fires when an external webhook is received:
75
+
76
+ ```typescript
77
+ incomingWebhookTrigger<WebhookPayload>();
78
+ ```
79
+
80
+ ### Resolver Executed Trigger
81
+
82
+ Fires when a resolver is executed:
83
+
84
+ ```typescript
85
+ resolverExecutedTrigger({
86
+ resolver: createOrderResolver,
87
+ condition: ({ result, error }) => !error && result?.order?.id,
88
+ });
89
+ ```
90
+
91
+ ## Execution Targets
92
+
93
+ ### Function Execution
94
+
95
+ Execute JavaScript/TypeScript functions:
96
+
97
+ ```typescript
98
+ createExecutor({
99
+ operation: {
100
+ kind: "function",
101
+ body: async ({ newRecord }) => {
102
+ console.log("New record created:", newRecord);
103
+ },
104
+ },
105
+ });
106
+ ```
107
+
108
+ ### Webhook Execution
109
+
110
+ Call external webhooks with dynamic data:
111
+
112
+ ```typescript
113
+ createExecutor({
114
+ operation: {
115
+ kind: "webhook",
116
+ url: ({ newRecord }) =>
117
+ `https://api.example.com/webhooks/${newRecord.type}`,
118
+ headers: {
119
+ "Content-Type": "application/json",
120
+ "X-API-Key": { vault: "api-keys", key: "external-api" },
121
+ },
122
+ requestBody: ({ newRecord }) => ({
123
+ id: newRecord.id,
124
+ timestamp: new Date(),
125
+ data: newRecord,
126
+ }),
127
+ },
128
+ });
129
+ ```
130
+
131
+ ### GraphQL Execution
132
+
133
+ Execute GraphQL queries and mutations:
134
+
135
+ ```typescript
136
+ import { gql } from "@tailor-platform/sdk";
137
+
138
+ createExecutor({
139
+ operation: {
140
+ kind: "graphql",
141
+ appName: "my-app",
142
+ query: gql`
143
+ mutation UpdateUserStatus($id: ID!, $status: String!) {
144
+ updateUser(id: $id, input: { status: $status }) {
145
+ id
146
+ status
147
+ updatedAt
148
+ }
149
+ }
150
+ `,
151
+ variables: ({ newRecord }) => ({
152
+ id: newRecord.userId,
153
+ status: "active",
154
+ }),
155
+ },
156
+ });
157
+ ```
158
+
159
+ ## Event Payloads
160
+
161
+ Each trigger type provides specific context data in the callback functions.
162
+
163
+ ### Record Event Payloads
164
+
165
+ Record triggers receive context based on the operation type:
166
+
167
+ #### Created Event
168
+
169
+ ```typescript
170
+ interface RecordCreatedContext<T> {
171
+ workspaceId: string; // Workspace identifier
172
+ namespaceName: string; // Application/namespace name
173
+ typeName: string; // TailorDB type name
174
+ newRecord: T; // The newly created record
175
+ }
176
+ ```
177
+
178
+ #### Updated Event
179
+
180
+ ```typescript
181
+ interface RecordUpdatedContext<T> {
182
+ workspaceId: string;
183
+ namespaceName: string;
184
+ typeName: string;
185
+ oldRecord: T; // Previous record state
186
+ newRecord: T; // Current record state
187
+ }
188
+ ```
189
+
190
+ #### Deleted Event
191
+
192
+ ```typescript
193
+ interface RecordDeletedContext<T> {
194
+ workspaceId: string;
195
+ namespaceName: string;
196
+ typeName: string;
197
+ oldRecord: T; // The deleted record
198
+ }
199
+ ```
200
+
201
+ **Usage Example:**
202
+
203
+ ```typescript
204
+ import { createExecutor, recordUpdatedTrigger, t } from "@tailor-platform/sdk";
205
+ import { order } from "../tailordb/order";
206
+
207
+ export default createExecutor({
208
+ name: "order-status-changed",
209
+ trigger: recordUpdatedTrigger({
210
+ type: order,
211
+ condition: ({ oldRecord, newRecord }) =>
212
+ oldRecord.status !== newRecord.status,
213
+ }),
214
+ operation: {
215
+ kind: "function",
216
+ body: async ({ oldRecord, newRecord, typeName }) => {
217
+ console.log(`${typeName} status changed:`);
218
+ console.log(` From: ${oldRecord.status}`);
219
+ console.log(` To: ${newRecord.status}`);
220
+ },
221
+ },
222
+ });
223
+ ```
224
+
225
+ ### Schedule Event Payload
226
+
227
+ Schedule triggers receive minimal context:
228
+
229
+ ```typescript
230
+ interface ScheduleContext {
231
+ scheduledTime: string; // ISO 8601 timestamp
232
+ }
233
+ ```
234
+
235
+ ### Incoming Webhook Payload
236
+
237
+ Webhook triggers receive HTTP request data:
238
+
239
+ ```typescript
240
+ interface WebhookContext<T = unknown> {
241
+ body: T; // Parsed request body
242
+ headers: Record<string, string>; // Request headers
243
+ method: string; // HTTP method (POST, etc.)
244
+ rawBody: string; // Raw request body as string
245
+ }
246
+ ```
247
+
248
+ **Usage Example:**
249
+
250
+ ```typescript
251
+ import { createExecutor, incomingWebhookTrigger } from "@tailor-platform/sdk";
252
+
253
+ interface StripeWebhook {
254
+ type: string;
255
+ data: { object: { id: string; amount: number } };
256
+ }
257
+
258
+ export default createExecutor({
259
+ name: "stripe-webhook",
260
+ trigger: incomingWebhookTrigger<StripeWebhook>(),
261
+ operation: {
262
+ kind: "function",
263
+ body: async ({ body, headers }) => {
264
+ const signature = headers["stripe-signature"];
265
+ console.log(`Received ${body.type} event`);
266
+ // Process webhook...
267
+ },
268
+ },
269
+ });
270
+ ```
271
+
272
+ ### Resolver Executed Payload
273
+
274
+ Resolver triggers receive the resolver's result or error:
275
+
276
+ ```typescript
277
+ interface ResolverExecutedContext<TResult> {
278
+ resolverName: string; // Name of the executed resolver
279
+ result?: TResult; // Return value (on success)
280
+ error?: Error; // Error object (on failure)
281
+ }
282
+ ```
283
+
284
+ **Usage Example:**
285
+
286
+ ```typescript
287
+ import { createExecutor, resolverExecutedTrigger } from "@tailor-platform/sdk";
288
+ import { createOrderResolver } from "../resolvers/create-order";
289
+
290
+ export default createExecutor({
291
+ name: "order-created-notification",
292
+ trigger: resolverExecutedTrigger({
293
+ resolver: createOrderResolver,
294
+ condition: ({ result, error }) => !error && !!result?.order,
295
+ }),
296
+ operation: {
297
+ kind: "function",
298
+ body: async ({ result, resolverName }) => {
299
+ console.log(`${resolverName} completed successfully`);
300
+ console.log(`Order ID: ${result.order.id}`);
301
+ },
302
+ },
303
+ });
304
+ ```
@@ -0,0 +1,106 @@
1
+ # IdP (Identity Provider)
2
+
3
+ IdP is a built-in identity provider service for managing user authentication.
4
+
5
+ ## Overview
6
+
7
+ The Built-in IdP provides:
8
+
9
+ - User registration and authentication
10
+ - OAuth client management
11
+ - Integration with Auth service
12
+
13
+ For the official Tailor Platform documentation, see [Identity Provider Setup](https://docs.tailor.tech/tutorials/setup-auth/setup-identity-provider).
14
+
15
+ ## Configuration
16
+
17
+ Configure the Built-in IdP using `defineIdp()`:
18
+
19
+ ```typescript
20
+ import { defineIdp, defineConfig } from "@tailor-platform/sdk";
21
+
22
+ const idp = defineIdp("my-idp", {
23
+ authorization: "loggedIn",
24
+ clients: ["my-client"],
25
+ });
26
+
27
+ export default defineConfig({
28
+ idp: [idp],
29
+ });
30
+ ```
31
+
32
+ ## Options
33
+
34
+ ### authorization
35
+
36
+ User management permissions. Controls who can manage users in the IdP.
37
+
38
+ ```typescript
39
+ defineIdp("my-idp", {
40
+ authorization: "loggedIn", // Only logged-in users can manage
41
+ });
42
+
43
+ defineIdp("my-idp", {
44
+ authorization: "insecure", // Anyone can manage (development only)
45
+ });
46
+
47
+ defineIdp("my-idp", {
48
+ authorization: "user.role == 'admin'", // CEL expression
49
+ });
50
+ ```
51
+
52
+ **Values:**
53
+
54
+ - `"insecure"` - No authentication required (use only for development)
55
+ - `"loggedIn"` - Requires authenticated user
56
+ - CEL expression - Custom authorization logic
57
+
58
+ ### clients
59
+
60
+ OAuth client names that can use this IdP:
61
+
62
+ ```typescript
63
+ defineIdp("my-idp", {
64
+ clients: ["default-client", "mobile-client"],
65
+ });
66
+ ```
67
+
68
+ ## Using idp.provider()
69
+
70
+ The `idp.provider()` method creates a type-safe reference to the IdP for use in Auth configuration. The client name is validated at compile time against the clients defined in the IdP.
71
+
72
+ ```typescript
73
+ import { defineIdp, defineAuth, defineConfig } from "@tailor-platform/sdk";
74
+ import { user } from "./tailordb/user";
75
+
76
+ const idp = defineIdp("my-idp", {
77
+ authorization: "loggedIn",
78
+ clients: ["default-client", "mobile-client"],
79
+ });
80
+
81
+ const auth = defineAuth("my-auth", {
82
+ userProfile: {
83
+ type: user,
84
+ usernameField: "email",
85
+ attributes: { role: true },
86
+ },
87
+ // Type-safe: only "default-client" or "mobile-client" are allowed
88
+ idProvider: idp.provider("my-provider", "default-client"),
89
+ });
90
+
91
+ export default defineConfig({
92
+ idp: [idp],
93
+ auth,
94
+ });
95
+ ```
96
+
97
+ **Parameters:**
98
+
99
+ ```typescript
100
+ idp.provider(
101
+ "provider-name", // Name for the provider reference
102
+ "client-name", // Must be one of the clients defined in the IdP
103
+ );
104
+ ```
105
+
106
+ The second argument only accepts client names that were defined in the `clients` array of the IdP configuration.