@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,213 @@
1
+ # Resolver
2
+
3
+ Resolvers are custom GraphQL endpoints with business logic that execute on the Tailor Platform.
4
+
5
+ ## Overview
6
+
7
+ Resolvers provide:
8
+
9
+ - Custom GraphQL queries and mutations
10
+ - Type-safe input/output schemas
11
+ - Access to TailorDB via Kysely query builder
12
+ - User context for authentication/authorization
13
+
14
+ ## Comparison with Tailor Platform Pipeline Resolver
15
+
16
+ The SDK's Resolver is a simplified version of Tailor Platform's [Pipeline Resolver](https://docs.tailor.tech/guides/pipeline).
17
+
18
+ | Pipeline Resolver | SDK Resolver |
19
+ | ---------------------------------------- | --------------------------------- |
20
+ | Multiple steps with different operations | Single `body` function |
21
+ | Declarative step configuration | Imperative TypeScript code |
22
+ | Built-in TailorDB/GraphQL steps | Direct database access via Kysely |
23
+ | CEL expressions for data transformation | Native TypeScript transformations |
24
+
25
+ ### Example Comparison
26
+
27
+ **Pipeline Resolver (Tailor Platform native):**
28
+
29
+ ```yaml
30
+ steps:
31
+ - name: getUser
32
+ operation: tailordb.query
33
+ params:
34
+ type: User
35
+ filter:
36
+ email: { eq: "{{ input.email }}" }
37
+ - name: updateAge
38
+ operation: tailordb.mutation
39
+ params:
40
+ type: User
41
+ id: "{{ steps.getUser.id }}"
42
+ input:
43
+ age: "{{ steps.getUser.age + 1 }}"
44
+ ```
45
+
46
+ **Resolver (SDK):**
47
+
48
+ ```typescript
49
+ createResolver({
50
+ name: "incrementUserAge",
51
+ operation: "mutation",
52
+ input: { email: t.string() },
53
+ body: async (context) => {
54
+ const db = getDB("tailordb");
55
+ const user = await db
56
+ .selectFrom("User")
57
+ .selectAll()
58
+ .where("email", "=", context.input.email)
59
+ .executeTakeFirstOrThrow();
60
+
61
+ await db
62
+ .updateTable("User")
63
+ .set({ age: user.age + 1 })
64
+ .where("id", "=", user.id)
65
+ .execute();
66
+
67
+ return { oldAge: user.age, newAge: user.age + 1 };
68
+ },
69
+ output: t.object({ oldAge: t.int(), newAge: t.int() }),
70
+ });
71
+ ```
72
+
73
+ ## Creating a Resolver
74
+
75
+ Define resolvers in files matching glob patterns specified in `tailor.config.ts`.
76
+
77
+ ```typescript
78
+ import { createResolver, t } from "@tailor-platform/sdk";
79
+
80
+ export default createResolver({
81
+ name: "add",
82
+ operation: "query",
83
+ input: {
84
+ left: t.int(),
85
+ right: t.int(),
86
+ },
87
+ body: (context) => {
88
+ return {
89
+ result: context.input.left + context.input.right,
90
+ };
91
+ },
92
+ output: t.object({
93
+ result: t.int(),
94
+ }),
95
+ });
96
+ ```
97
+
98
+ ## Input/Output Schemas
99
+
100
+ Define input/output schemas using methods of `t` object. Basic usage and supported field types are the same as TailorDB. TailorDB-specific options (e.g., index, relation) are not supported.
101
+
102
+ You can reuse fields defined with `db` object, but note that unsupported options will be ignored:
103
+
104
+ ```typescript
105
+ const user = db.type("User", {
106
+ name: db.string().unique(),
107
+ age: db.int(),
108
+ });
109
+
110
+ createResolver({
111
+ input: {
112
+ name: user.fields.name,
113
+ },
114
+ });
115
+ ```
116
+
117
+ ## Input Validation
118
+
119
+ Add validation rules to input fields using the `validate` method:
120
+
121
+ ```typescript
122
+ createResolver({
123
+ name: "createUser",
124
+ operation: "mutation",
125
+ input: {
126
+ email: t
127
+ .string()
128
+ .validate(
129
+ ({ value }) => value.includes("@"),
130
+ [
131
+ ({ value }) => value.length <= 255,
132
+ "Email must be 255 characters or less",
133
+ ],
134
+ ),
135
+ age: t.int().validate(({ value }) => value >= 0 && value <= 150),
136
+ },
137
+ body: (context) => {
138
+ // Input is validated before body executes
139
+ return { email: context.input.email };
140
+ },
141
+ output: t.object({ email: t.string() }),
142
+ });
143
+ ```
144
+
145
+ Validation functions receive:
146
+
147
+ - `value` - The field value being validated
148
+ - `data` - The entire input object
149
+ - `user` - The user performing the operation
150
+
151
+ You can specify validation as:
152
+
153
+ - A function returning `boolean` (uses default error message)
154
+ - A tuple of `[function, errorMessage]` for custom error messages
155
+ - Multiple validators (pass multiple arguments to `validate`)
156
+
157
+ ## Body Function
158
+
159
+ Define actual resolver logic in the `body` function. Function arguments include:
160
+
161
+ - `input` - Input data from GraphQL request
162
+ - `user` - User performing the operation
163
+
164
+ ### Using Kysely for Database Access
165
+
166
+ If you're generating Kysely types with a generator, you can use `getDB` to execute typed queries:
167
+
168
+ ```typescript
169
+ import { getDB } from "../generated/tailordb";
170
+
171
+ createResolver({
172
+ name: "getUser",
173
+ operation: "query",
174
+ input: {
175
+ name: t.string(),
176
+ },
177
+ body: async (context) => {
178
+ const db = getDB("tailordb");
179
+ const result = await db
180
+ .selectFrom("User")
181
+ .select("id")
182
+ .where("name", "=", context.input.name)
183
+ .limit(1)
184
+ .executeTakeFirstOrThrow();
185
+ return {
186
+ result: result.id,
187
+ };
188
+ },
189
+ output: t.object({
190
+ result: t.uuid(),
191
+ }),
192
+ });
193
+ ```
194
+
195
+ ## Query vs Mutation
196
+
197
+ Use `operation: "query"` for read operations and `operation: "mutation"` for write operations:
198
+
199
+ ```typescript
200
+ // Query - for reading data
201
+ createResolver({
202
+ name: "getUsers",
203
+ operation: "query",
204
+ // ...
205
+ });
206
+
207
+ // Mutation - for creating, updating, or deleting data
208
+ createResolver({
209
+ name: "createUser",
210
+ operation: "mutation",
211
+ // ...
212
+ });
213
+ ```
@@ -0,0 +1,116 @@
1
+ # Secret Manager
2
+
3
+ Secret Manager provides secure storage for sensitive values like API keys, tokens, and credentials that your application needs at runtime.
4
+
5
+ ## Overview
6
+
7
+ Secret Manager provides:
8
+
9
+ - Secure storage for sensitive configuration values
10
+ - Organized secrets within named vaults
11
+ - Runtime access from executors and workflows
12
+ - CLI management for secrets lifecycle
13
+
14
+ ## Concepts
15
+
16
+ ### Vaults
17
+
18
+ Vaults are containers that group related secrets together. Each workspace can have multiple vaults, typically organized by purpose or environment.
19
+
20
+ ```
21
+ workspace/
22
+ ├── vault: api-keys
23
+ │ ├── stripe-secret-key
24
+ │ ├── sendgrid-api-key
25
+ │ └── external-service-token
26
+ └── vault: database
27
+ ├── read-replica-password
28
+ └── analytics-connection-string
29
+ ```
30
+
31
+ ### Secrets
32
+
33
+ Secrets are key-value pairs stored within a vault. Secret values are encrypted at rest and only accessible at runtime by authorized services.
34
+
35
+ ## Using Secrets
36
+
37
+ ### In Webhook Operations
38
+
39
+ Reference secrets in webhook headers using the vault/key syntax:
40
+
41
+ ```typescript
42
+ import { createExecutor, recordCreatedTrigger } from "@tailor-platform/sdk";
43
+ import { order } from "../tailordb/order";
44
+
45
+ export default createExecutor({
46
+ name: "notify-external-service",
47
+ trigger: recordCreatedTrigger({ type: order }),
48
+ operation: {
49
+ kind: "webhook",
50
+ url: "https://api.example.com/orders",
51
+ headers: {
52
+ "Content-Type": "application/json",
53
+ Authorization: { vault: "api-keys", key: "external-api-token" },
54
+ "X-API-Key": { vault: "api-keys", key: "api-secret" },
55
+ },
56
+ requestBody: ({ newRecord }) => ({
57
+ orderId: newRecord.id,
58
+ amount: newRecord.total,
59
+ }),
60
+ },
61
+ });
62
+ ```
63
+
64
+ The secret reference format:
65
+
66
+ ```typescript
67
+ { vault: "vault-name", key: "secret-name" }
68
+ ```
69
+
70
+ At runtime, these references are replaced with the actual secret values.
71
+
72
+ ## CLI Management
73
+
74
+ ### Create a Vault
75
+
76
+ ```bash
77
+ tailor-sdk secret vault create --name api-keys
78
+ ```
79
+
80
+ ### Add Secrets
81
+
82
+ ```bash
83
+ # Create a secret
84
+ tailor-sdk secret create \
85
+ --vault-name api-keys \
86
+ --name stripe-secret-key \
87
+ --value sk_live_xxxxx
88
+
89
+ # Update a secret
90
+ tailor-sdk secret update \
91
+ --vault-name api-keys \
92
+ --name stripe-secret-key \
93
+ --value sk_live_yyyyy
94
+ ```
95
+
96
+ ### List Secrets
97
+
98
+ ```bash
99
+ # List vaults
100
+ tailor-sdk secret vault list
101
+
102
+ # List secrets in a vault (values are hidden)
103
+ tailor-sdk secret list --vault-name api-keys
104
+ ```
105
+
106
+ ### Delete Secrets
107
+
108
+ ```bash
109
+ # Delete a secret
110
+ tailor-sdk secret delete --vault-name api-keys --name old-key --yes
111
+
112
+ # Delete a vault (must be empty)
113
+ tailor-sdk secret vault delete --name old-vault --yes
114
+ ```
115
+
116
+ See [Secret CLI Commands](../cli/secret.md) for full documentation.
@@ -0,0 +1,132 @@
1
+ # Static Website
2
+
3
+ Static Website is a service for hosting static web applications on the Tailor Platform.
4
+
5
+ ## Overview
6
+
7
+ Static Website provides:
8
+
9
+ - Static file hosting
10
+ - Type-safe URL references for configuration
11
+ - IP address restrictions
12
+
13
+ For the official Tailor Platform documentation, see [Static Website Guide](https://docs.tailor.tech/guides/static-website-hosting).
14
+
15
+ ## Configuration
16
+
17
+ Configure static website hosting using `defineStaticWebSite()`:
18
+
19
+ ```typescript
20
+ import { defineStaticWebSite, defineConfig } from "@tailor-platform/sdk";
21
+
22
+ const website = defineStaticWebSite("my-website", {
23
+ description: "My Static Website",
24
+ });
25
+
26
+ export default defineConfig({
27
+ staticWebsites: [website],
28
+ });
29
+ ```
30
+
31
+ ## Options
32
+
33
+ ### description
34
+
35
+ A description of the static website:
36
+
37
+ ```typescript
38
+ defineStaticWebSite("my-website", {
39
+ description: "Frontend application for my service",
40
+ });
41
+ ```
42
+
43
+ ### allowedIPAddresses
44
+
45
+ Restrict access to specific IP addresses in CIDR format:
46
+
47
+ ```typescript
48
+ defineStaticWebSite("my-website", {
49
+ allowedIPAddresses: ["192.168.0.0/24", "10.0.0.0/8"],
50
+ });
51
+ ```
52
+
53
+ ## Type-safe URL References
54
+
55
+ The returned website object provides a `url` property that resolves to the actual URL at deployment time. Use this for type-safe configuration:
56
+
57
+ ### CORS Settings
58
+
59
+ ```typescript
60
+ const website = defineStaticWebSite("my-frontend", {
61
+ description: "Frontend application",
62
+ });
63
+
64
+ export default defineConfig({
65
+ cors: [website.url], // Resolved at deployment
66
+ staticWebsites: [website],
67
+ });
68
+ ```
69
+
70
+ ### OAuth2 Redirect URIs
71
+
72
+ ```typescript
73
+ const website = defineStaticWebSite("my-frontend", {
74
+ description: "Frontend application",
75
+ });
76
+
77
+ const auth = defineAuth("my-auth", {
78
+ oauth2Clients: {
79
+ "my-client": {
80
+ redirectURIs: [
81
+ `${website.url}/callback`, // https://my-frontend.example.com/callback
82
+ `${website.url}/auth/complete`, // https://my-frontend.example.com/auth/complete
83
+ ],
84
+ grantTypes: ["authorization_code", "refresh_token"],
85
+ },
86
+ },
87
+ });
88
+ ```
89
+
90
+ ## Complete Example
91
+
92
+ ```typescript
93
+ import {
94
+ defineConfig,
95
+ defineAuth,
96
+ defineIdp,
97
+ defineStaticWebSite,
98
+ } from "@tailor-platform/sdk";
99
+ import { user } from "./tailordb/user";
100
+
101
+ const website = defineStaticWebSite("my-frontend", {
102
+ description: "Frontend application",
103
+ });
104
+
105
+ const idp = defineIdp("my-idp", {
106
+ authorization: "loggedIn",
107
+ clients: ["default-client"],
108
+ });
109
+
110
+ const auth = defineAuth("my-auth", {
111
+ userProfile: {
112
+ type: user,
113
+ usernameField: "email",
114
+ attributes: { role: true },
115
+ },
116
+ oauth2Clients: {
117
+ "frontend-client": {
118
+ redirectURIs: [`${website.url}/callback`],
119
+ grantTypes: ["authorization_code", "refresh_token"],
120
+ },
121
+ },
122
+ idProvider: idp.provider("default", "default-client"),
123
+ });
124
+
125
+ export default defineConfig({
126
+ name: "my-app",
127
+ cors: [website.url],
128
+ idp: [idp],
129
+ auth,
130
+ staticWebsites: [website],
131
+ });
132
+ ```