@tailorkit/app 0.1.0-beta.2 → 0.1.0-beta.20

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 (54) hide show
  1. package/LICENSE.md +201 -0
  2. package/README.md +184 -0
  3. package/dist/builder/client-views.d.ts +16 -0
  4. package/dist/builder/drizzle.d.ts +2 -0
  5. package/dist/builder/generate-migrations.d.ts +6 -0
  6. package/dist/builder/index.d.ts +1 -2
  7. package/dist/builder/instances.d.ts +19 -0
  8. package/dist/builder/migrations.d.ts +6 -0
  9. package/dist/builder/schema-check.d.ts +2 -0
  10. package/dist/builder/server.d.ts +6 -0
  11. package/dist/builder/upload-manifest.d.ts +13 -3
  12. package/dist/builder.js +986 -21
  13. package/dist/chunk-7NOEYJOB.js +197 -0
  14. package/dist/{chunk-7L6ZZHCK.js → chunk-DEU6RITM.js} +6 -1
  15. package/dist/chunk-GVB2PAK7.js +28 -0
  16. package/dist/chunk-IJBQ77AH.js +35 -0
  17. package/dist/chunk-RHCGWGSG.js +645 -0
  18. package/dist/client/connection.d.ts +31 -0
  19. package/dist/client/query-store.d.ts +23 -0
  20. package/dist/client/reference.d.ts +20 -0
  21. package/dist/client/session.d.ts +14 -0
  22. package/dist/client.d.ts +7 -0
  23. package/dist/client.js +32 -0
  24. package/dist/config/config.d.ts +88 -4
  25. package/dist/config/index.d.ts +0 -1
  26. package/dist/config/loader.d.ts +0 -1
  27. package/dist/config-loader.js +2 -2
  28. package/dist/config.js +1 -1
  29. package/dist/database/schema.d.ts +78 -0
  30. package/dist/database/types.d.ts +7 -0
  31. package/dist/errors.d.ts +6 -0
  32. package/dist/index.d.ts +2 -72
  33. package/dist/index.js +81 -76
  34. package/dist/preact-version.d.ts +0 -1
  35. package/dist/preact.d.ts +52 -0
  36. package/dist/protocol.d.ts +74 -0
  37. package/dist/protocol.js +28 -0
  38. package/dist/server/builder.d.ts +40 -0
  39. package/dist/server/bundle.d.ts +17 -0
  40. package/dist/server/functions.d.ts +89 -0
  41. package/dist/server/instances.d.ts +16 -0
  42. package/dist/server.d.ts +9 -0
  43. package/dist/server.js +58 -0
  44. package/dist/views.d.ts +139 -0
  45. package/package.json +30 -23
  46. package/LICENSE +0 -674
  47. package/dist/builder/index.d.ts.map +0 -1
  48. package/dist/builder/upload-manifest.d.ts.map +0 -1
  49. package/dist/chunk-AGGRUUWG.js +0 -22
  50. package/dist/config/config.d.ts.map +0 -1
  51. package/dist/config/index.d.ts.map +0 -1
  52. package/dist/config/loader.d.ts.map +0 -1
  53. package/dist/index.d.ts.map +0 -1
  54. package/dist/preact-version.d.ts.map +0 -1
package/LICENSE.md ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # @tailorkit/app
2
+
3
+ Apache-2.0 app SDK. The implementation lives here; `tailorkit/client` reexports the browser API and `tailorkit/server` reexports backend definitions. The package root also exports `defineServer`. Define SQLite tables, synchronous queries/mutations and async actions with Zod arguments. Drizzle and oRPC v2 run underneath; app code uses this package's APIs.
4
+
5
+ ```ts
6
+ import { defineServer, table, text, tk } from "tailorkit/server";
7
+ import { z } from "zod";
8
+
9
+ const notes = table("notes", { id: text().primaryKey(), title: text().notNull() });
10
+ const functions = {
11
+ list: tk.query.handler(({ db }) => db.select().from(notes).all()),
12
+ add: tk.mutation
13
+ .input(z.object({ title: z.string().min(1) }))
14
+ .handler(({ db, input }) =>
15
+ db.insert(notes).values({ id: crypto.randomUUID(), title: input.title }).returning().all(),
16
+ ),
17
+ };
18
+ export default defineServer(functions);
19
+ ```
20
+
21
+ Use `tk.query`, `tk.mutation` and `tk.action` with `.handler(fn)`. Both `.input(schema)` and `.output(schema)` are optional and can be chained in either order. Without `.input()`, handler `input` is `undefined` and callers omit the input; supplying a value is rejected. Without `.output()`, return values are allowed and their types are inferred from the handler, including awaited action results. There is no default output schema. When supplied, `.output()` constrains handler returns in TypeScript and validates them at runtime; nonconforming results throw `Invalid function result`. Output transformations determine the types returned to clients and action callbacks. Builders are immutable. The original object-form `query`, `mutation` and `action` helpers remain supported.
22
+
23
+ Chained handlers receive validated `input`, `db`, and verified `identity` (`userId`, `projectId`, `appId`, `installationId`, `deploymentId`, `expiresAt`). Queries expose selection builders; mutations additionally expose insert/update/delete. Use synchronous `.all()`, `.get()` and `.run()`. Async query/mutation handlers are rejected: writes, output validation and the accepted-write receipt commit in one synchronous transaction. `.output(schema)` validates the output before commit. Throw `AppError` for an intentional public error; unexpected errors are hidden.
24
+
25
+ Schema exports include `table`, `text`, `integer`, `real`, `boolean` and common comparison/order operators. This is a small supported surface. Apps can import Drizzle for advanced configurations, but those features are not guaranteed to work with tracking or this driver.
26
+
27
+ ## Queries, mutations and actions
28
+
29
+ | Type | Database access | External calls | Automatic query reruns |
30
+ | -------- | --------------------------------------- | -------------- | ------------------------------------------- |
31
+ | Query | Read only | Blocked | When subscribed |
32
+ | Mutation | Read/write in one atomic transaction | Blocked | Invalidates affected queries after commit |
33
+ | Action | Through `ctx.queries` / `ctx.mutations` | Async HTTPS | One-off calls; no subscription invalidation |
34
+
35
+ Use `tk.action` for external API calls. Action handlers receive validated `input`, verified `identity`, an abort `signal`, and typed `ctx.queries.<name>(args)` / `ctx.mutations.<name>(args)` methods. They have no `db` handle. Actions can be synchronous or async; query/mutation handlers remain synchronous.
36
+
37
+ Pass a shared query/mutation collection to `.functions(functions)`, and register that same collection under the same names in `defineServer`. The namespaces expose only the declared queries and mutations; their argument and result types are inferred from the definitions. No generated client references are needed on the server. Actions with no database calls can omit `.functions()`.
38
+
39
+ To extend the example above, add this action and include it in the app:
40
+
41
+ ```ts
42
+ const importNote = tk.action
43
+ .functions(functions)
44
+ .input(z.object({ url: z.url() }))
45
+ .handler(async (ctx) => {
46
+ await ctx.queries.list();
47
+ const response = await fetch(ctx.input.url, { signal: ctx.signal });
48
+ const data = z.object({ title: z.string() }).parse(await response.json());
49
+ return ctx.mutations.add({ title: data.title });
50
+ });
51
+ export default defineServer({ ...functions, importNote });
52
+ ```
53
+
54
+ Clients call `await client.action(api.importNote, { url })`. Actions are one-shot calls, never subscriptions, and are not automatically retried. Every query/mutation call executes separately; the action as a whole is not a transaction. An earlier mutation stays committed if later external work or result validation fails. Combine related database writes into one mutation when they must be atomic. External writes need the provider's idempotency mechanism before retrying an action. Mutation methods accept an optional second argument `{ requestId }`, for example `ctx.mutations.add({ title }, { requestId })`, to reuse the normal mutation receipt when explicitly retrying a database step.
55
+
56
+ Cloudflare runs queries, mutations and actions in one dynamic SQLite facet. The server runtime installs an ALS-backed global fetch guard before importing app modules. Ordinary fetch works in actions, including SDKs that capture fetch at import time; queries and mutations reject it. This is a DX guard, not a security boundary between handlers. Actions call queries and mutations directly in the same facet, with fresh database contexts and no application call-count limit. A scoped RPC capability handles outbound HTTP and reports committed tables to refresh subscriptions before the action continues. Platform credentials remain trusted, native networking stays disabled, and external I/O does not hold the database queue. Actions share module state with other handlers.
57
+
58
+ Cloudflare CPU and subrequest limits still apply (10 ms CPU and 64 worker subrequests). Local database calls do not consume RPC subrequests. There are no application concurrency or call-count quotas or separate action timeout; token expiry bounds action lifetime. The SDK stops its database methods after completion or cancellation, and database execution checks token expiry. Publication is checked when admitting external calls; deployment replacement cancels active actions. Already committed writes and accepted external effects remain committed. Actions are not durable jobs. Nested action calls, scheduling, internal-only functions and app-secret management are deferred.
59
+
60
+ ## Source layout
61
+
62
+ App projects keep UI views in `src/views/`, backend implementations in `src/functions/`, and database tables in `src/schema.ts`. `src/server.ts` imports functions and registers them with `defineServer`; `src/client.ts` registers views and configures the root provider. `tailorkit init` generates this layout, a sample query, and the provider setup. With the umbrella package, import backend definitions from `tailorkit/server` and Preact hooks from `tailorkit/client`.
63
+
64
+ Export the function type from `src/server.ts`:
65
+
66
+ ```ts
67
+ const app = defineServer({ ...functions, importNote });
68
+ export default app;
69
+ ```
70
+
71
+ The shared `#tailorkit` module exposes a browser API inferred from that type:
72
+
73
+ ```ts
74
+ import { createApi } from "tailorkit/client";
75
+ import type app from "./server";
76
+
77
+ export const api = createApi<typeof app.functions>();
78
+ ```
79
+
80
+ Views import `api` from `#tailorkit`. Adding functions or changing their input/output schemas updates types immediately through the type-only import: no backend type generation or build is needed. `createApi` creates references by function name without importing or evaluating server implementations. Init sets up this link. Host schema generation includes it when the configured server entry exists (default `src/server.ts`), including default detection with no server configuration. It resolves the import relative to the generated file, including custom output paths. Missing server files omit the backend API export. Enable backend builds with `server: {}` in config. Client and server entry points default to `src/client.ts` and `src/server.ts`. Configure `client.entry` and `server.entry` in `tailorkit.config.ts` to change them; paths are relative to that config file. API type generation and browser import protection follow the configured server entry. CLI entry overrides are unsupported.
81
+
82
+ The SDK itself uses these directories:
83
+
84
+ - `src/database/`: SQLite schema builders, database types and the tracked Drizzle driver.
85
+ - `src/server/`: query/mutation/action definitions, atomic database execution, async action execution, realtime coordination and server RPC transport. Tests live beside the implementation.
86
+ - `src/client/`: browser WebSocket connection, typed references and session fetching/caching in `session.ts`.
87
+ - `src/auth/`: shared token policy, signing/verification, public-key validation and trusted platform key fetching/caching. Change token lifetime and renewal timing in `policy.ts`.
88
+
89
+ The root `index.ts`, `client.ts`, `server.ts` and `protocol.ts` files expose the public entry points. `views.ts` implements remote views and `preact.ts` implements the provider and hooks. `errors.ts` is shared by the client and server. Private execution and Cloudflare hosting live in `apps/apps-worker`; JWT helpers live in the private `@tailorkit/api-utils/app-auth` module.
90
+
91
+ Auth signing and verification use Effect v4. `issueAppTokenEffect`, `appTokenVerifierEffect` and `createAppRuntimeVerifierEffect` compose with `Effect.gen`; their Promise counterparts run those programs at the caller boundary. The runtime verifier takes configured public JWKS via `publicKeys` and never fetches signing keys. The Cloudflare adapter supplies its `APP_RUNTIME_PUBLIC_KEYS` variable. Signing and verification share Effect's clock, including JWT expiry checks.
92
+
93
+ ## Build and upload
94
+
95
+ Add `server: {}` to `tailorkit.config.ts` to build the backend from `src/server.ts`. The client builds from `src/client.ts` by default. `client.entry` and `server.entry` override these source entry points while output filenames stay the same. `tailorkit build` emits `.tailorkit/client/client.js` and `.tailorkit/server/server.js`, and copies committed Drizzle migration files into `.tailorkit/migrations/`. Intermediate server entries are created under the output root’s `tmp/` directory and removed after builds or when the watcher closes; `server/` contains the upload artifact. The server exports the application definition and embedded migrations; Cloudflare bootstrap code belongs to the runtime worker. The builder writes no backend reference source files. The browser builder rejects server implementation imports. `build.outDir` and `--out-dir` change the common output root for all artifacts; preview serves only its `client/` directory.
96
+
97
+ `tailorkit deploy` gzips the client and private server artifacts before uploading them through platform-issued blob upload URLs. Checksums and content lengths describe the compressed bytes stored in R2. The runtime verifies and decompresses server code before loading it; client delivery serves gzip to browsers that accept it. The platform checks that decoded client bundles fit within 3 MiB before publication, and decoded delivery streams enforce the same limit. Existing uncompressed deployments remain supported. Apps need no Cloudflare credentials. R2 stores them under separate `client/` and `server/` prefixes; only client assets are public. Client-only apps continue to build without a server artifact. Watch mode watches both builds.
98
+
99
+ The legacy `app-storage` SDK, `storage` config and storage CLI commands have been removed. Use `server` config and this SDK. The host session endpoint `/backend/session` uses the existing host `authenticate` callback. The platform verifies scope access and resolves the installation and runtime URL automatically; no extra host backend configuration is required.
100
+
101
+ ## Preact hooks
102
+
103
+ Configure the provider once in `src/client.ts`:
104
+
105
+ ```ts
106
+ import { ClientProvider, defineClient } from "tailorkit/client";
107
+ import defaultView from "./views/default";
108
+
109
+ export default defineClient({
110
+ component: ClientProvider,
111
+ slots: { panel: { "/": defaultView } },
112
+ });
113
+ ```
114
+
115
+ Views use `useQuery(api.list)`, `useMutation(api.add)` and `useAction(api.importNote)` from `tailorkit/client`. Queries return `data`, `error`, `status`, `isLoading`, `isPending`, `isSuccess` and `isError`. TanStack Store manages query and call state, with selectors keeping unrelated query updates from rerendering other observers. Matching active queries share one live subscription; inline input objects do not cause resubscription when their values are unchanged. Changing inputs clears stale data, fresh snapshots clear subscription errors, and unmounting the last consumer unsubscribes. `{ enabled: false }` as the third argument disables a query.
116
+
117
+ Mutations expose `mutate(input)` and `mutateAsync(input)`; actions expose `execute(input)` and `executeAsync(input)`. Both expose `data`, `error`, `status`, `isPending`, `isSuccess`, `isError` and `reset()`, and accept `{ onSuccess, onError }` callbacks. Calls start only when invoked. The latest invocation determines the displayed state, and late responses cannot overwrite a newer invocation or a reset. Fire-and-forget methods capture errors in hook state; async methods additionally reject for caller-controlled workflows. Mutations automatically retry connection failures and temporary backend unavailability with exponential backoff from one second up to thirty seconds, retaining their request ID and original arguments. They stay pending during retries and stop when the client closes or a permanent error occurs. Rejected authentication triggers one session refresh before failing. Actions are never automatically retried.
118
+
119
+ `ClientProvider` creates and closes its client automatically. A custom wrapper can pass a caller-owned `client` and/or a global `onError` callback; caller-owned clients remain open when the provider unmounts. The root `component` stays mounted when the host switches views and unmounts when the app root is cleared. No manual client creation, subscriptions or effect cleanup is needed in views.
120
+
121
+ ## Imperative client
122
+
123
+ ```ts
124
+ import { createClient } from "tailorkit/client";
125
+ import { api } from "#tailorkit";
126
+
127
+ const client = createClient();
128
+ const stop = client.subscribe(api.list, undefined, (notes) => render(notes));
129
+ await client.mutate(api.add, { title: "Shared with every active client" });
130
+ stop(); // Abort this query stream and unregister its subscription.
131
+ client.close(); // Close the client's connection when it is no longer needed.
132
+ ```
133
+
134
+ Shared oRPC fetch procedures carry one-off calls; an oRPC WebSocket carries full query snapshots. The SDK derives its client types from the public oRPC contract in `@tailorkit/app/protocol`. Iterator cancellation unregisters subscriptions. The sandbox bridge supplies scoped JWTs only; backend traffic connects directly to the host-authorized runtime origin. Platform-issued tokens last five minutes. The host SDK caches sessions until one minute before expiry. The socket reconnects one minute before expiry, resubscribes active queries and receives fresh snapshots. No subscription pings or per-query expiry leases are required. A broken connection drops server subscriptions; reconnect creates new subscriptions. Inactive/unsubscribed queries receive no updates.
135
+
136
+ Automatic mutation retries reuse the original UUID. The atomic receipt returns the original result without writing or invalidating again. For explicit retries across separate `client.mutate` calls, retain a UUID and pass `{ requestId }` to each call. Reusing that UUID with different arguments or identity is rejected. Retry delays can be configured through `createClient({ retryDelayMs })`; query subscriptions use this delay too.
137
+
138
+ ## Reactivity and provider boundary
139
+
140
+ The Drizzle driver records tables read by each query, including empty selections and joins, and tables changed by successful writes. Only committed writes invalidate. The supervisor reruns affected active queries as their original verified users and replaces each dependency set. Initial subscription registration and mutations share a queue, avoiding an initial-snapshot race. Slow consumers retain the latest complete pending snapshot.
141
+
142
+ The host provides the `/rpc` base URL. `client.query`, `client.mutate` and `client.action` POST to `/rpc/queries`, `/rpc/mutations` and `/rpc/actions` respectively, with the session JWT in the Authorization header. `client.subscribe` opens `/rpc/queries` as a WebSocket and reconnects before token expiry. The trusted installation Durable Object owns subscriptions and invalidates them after both client and action mutations. The isolated SQLite facet returns a serializable response, touched tables and commit status over direct RPC, including table metadata on errors. Rebuild existing clients alongside server bundles when adopting these routes.
143
+
144
+ Nested groups are supported in `defineServer({ todos: { list, add }, tasks: { importTodos } })` and inferred by `createApi<typeof app.functions>()`. Calls such as `client.query(api.todos.list)` preserve the wire name `todos.list`. An action declaring `.functions({ todos: { list, add } })` receives `ctx.queries.todos.list()` and `ctx.mutations.todos.add(...)`.
145
+
146
+ `@tailorkit/app/protocol` defines the public oRPC contract and application migration input types. The private BUSL-1.1 worker in `apps/apps-worker` owns execution, ALS and the fetch guard, database transactions and receipts, authentication, subscriptions and Cloudflare hosting. The public Apache-2.0 SDK contains app definitions, schema helpers, clients, hooks and build tooling. App authors and browser clients do not need Effect.
147
+
148
+ ## Local validation and current limits
149
+
150
+ ```sh
151
+ pnpm --filter @tailorkit/app build
152
+ pnpm --filter tailorkit build
153
+ pnpm --filter backend-todo build
154
+ pnpm --filter @tailorkit/app test
155
+ pnpm --filter @tailorkit/apps-worker test
156
+ ```
157
+
158
+ The runtime test runs disposable local Wrangler/workerd/R2 state and two clients against the example's real backend, including an external API action and writes continuing while it waits. It checks persistent writes, atomic replay protection, realtime snapshots, JWT renewal and recovery after restart. It needs no Cloudflare account and deploys nothing. See `examples/apps/backend-todo` and the runtime README.
159
+
160
+ ## Database migrations
161
+
162
+ Generate app migrations with Drizzle Kit v1 and commit the generated files. `table()` defines a Drizzle-compatible schema; schema changes take effect through these migrations.
163
+
164
+ ```sh
165
+ pnpm db:generate
166
+ # Or run directly, with an optional migration name:
167
+ pnpm exec tailorkit db generate --name add_notes
168
+ ```
169
+
170
+ Run `pnpm db:generate` after changing `src/schema.ts`, review and commit the generated migrations, then build and deploy normally. Init and the todo examples include matching Drizzle v1 development dependencies and this script. No `drizzle.config.ts` is needed: generation uses SQLite, `src/schema.ts`, and root `migrations/` by default. `tailorkit.config.ts` is the only framework config; `server.migrations` changes the directory for both generation and builds. No database connection is needed to generate migrations. Drizzle handles generation and rename prompts; TailorKit supplies the paths.
171
+
172
+ The builder reads Drizzle v1's `migrations/<timestamp>_<name>/migration.sql` folders, splits their statement breakpoints and embeds the SQL with SHA-256 checksums in the private server artifact. To use another directory, set `server.migrations` in `tailorkit.config.ts`. An explicitly configured directory must exist. An absent default `./migrations` directory is allowed only when there are no schema tables to migrate. Older `_journal.json` migration layouts are unsupported.
173
+
174
+ Before bundling, the builder uses Drizzle Kit to generate a fresh snapshot of `src/schema.ts` in a temporary directory and compares its schema entities with the latest committed migration snapshot. Missing or stale migrations fail the build with a `tailorkit db generate` instruction. This check does not write to migration history, connect to a database, or check deployed database state. Generating migrations stays an explicit step so SQL can be reviewed. The builder watches the schema and migration files in watch mode.
175
+
176
+ When an installation's SQLite facet starts, the framework synchronously checks its `tailorkit_migrations` journal and applies missing migrations before exposing queries or mutations. The entire pending upgrade and its journal entries run in one storage transaction. Failed upgrades roll back and prevent that facet from serving database calls. Each installation upgrades independently when accessed, including installations created after deployment. Actions that call queries or mutations use this same initialized facet.
177
+
178
+ Migration history is append-only: never edit, delete or insert migrations before already applied entries. Their IDs and checksums must match the stored history. Republishing code with an older migration history is rejected; automatic database downgrades are unsupported. Keep migrations small enough for the runtime's existing 10 ms CPU limit; large backfills need a separate workflow. Existing databases created outside this migration flow are not automatically adopted.
179
+
180
+ Subscriptions use oRPC with Durable Object hibernation. The trusted installation persists query registrations and dependencies, restores them after wake-up, and uses durable alarms for token expiry. Each installation serializes database calls and query reruns in its trusted realtime coordinator; action database calls pass through the trusted bridge into that same coordinator, with limits of 128 connections and 256 active queries. CPU/subrequest limits apply to isolated app code; installation quotas and receipt retention remain future work. It supports one live deployment per installation, full snapshots and table-level tracking. Offline sync, optimistic updates, middleware, Redis notification delivery and advanced dependency tracking are deferred.
181
+
182
+ Application bundles export a `runtimeManifest` alongside the default application definition and migrations. The SDK builder emits `{ apiVersion: 1, requires: ["database", "actions"] }`. The facet validates the exports, API version and required features before touching SQLite. Unsupported bundles fail with `INCOMPATIBLE_VERSION`. Breaking handler/module changes increment `apiVersion`; additive capabilities can be named in `requires`. Bundles only require a runtime upgrade when their declared interface or required features are unsupported. The shared `ApplicationModule` and `RuntimeManifest` types are exported by `@tailorkit/app/server`.
183
+
184
+ Server builds inline dynamic imports into the single uploaded `server/server.js` file. Deployment type checking covers both configured client and server entries. Existing mounted clients reconnect after server updates without losing their UI state; server changes must remain compatible with those clients.
@@ -0,0 +1,16 @@
1
+ import type { InstanceRegistration } from "./instances";
2
+ export declare function readClientViews(filename: string): Promise<{
3
+ slot: string;
4
+ path: string;
5
+ instances?: true | undefined;
6
+ disabled?: true | undefined;
7
+ }[]>;
8
+ export declare function readClientManifest(filename: string): Promise<{
9
+ views: {
10
+ slot: string;
11
+ path: string;
12
+ instances?: true | undefined;
13
+ disabled?: true | undefined;
14
+ }[];
15
+ instanceResolvers: InstanceRegistration[];
16
+ }>;
@@ -0,0 +1,2 @@
1
+ /** Use the app's Drizzle version with explicit flags; no Drizzle config file is needed. */
2
+ export declare function drizzleGenerateArguments(root: string, output: string, name?: string): Promise<string[]>;
@@ -0,0 +1,6 @@
1
+ export interface GenerateAppMigrationsOptions {
2
+ configPath?: string;
3
+ cwd?: string;
4
+ name?: string;
5
+ }
6
+ export declare function generateAppMigrations(options?: GenerateAppMigrationsOptions): Promise<string>;
@@ -1,11 +1,10 @@
1
1
  export { createTailorKitUploadManifest, tailorkitUploadManifestSchema, type TailorKitUploadManifest, } from "./upload-manifest";
2
+ export { generateAppMigrations, type GenerateAppMigrationsOptions } from "./generate-migrations";
2
3
  export interface BuildAppOptions {
3
4
  configPath?: string;
4
5
  cwd?: string;
5
- entry?: string;
6
6
  mode?: string;
7
7
  outDir?: string;
8
8
  watch?: boolean;
9
9
  }
10
10
  export declare const buildApp: (options?: BuildAppOptions) => Promise<unknown>;
11
- //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,19 @@
1
+ import type { Plugin } from "vite";
2
+ export interface InstanceModule {
3
+ filename: string;
4
+ names: string[];
5
+ }
6
+ export interface InstanceRegistration {
7
+ slot: string;
8
+ path: string;
9
+ resolver: string;
10
+ }
11
+ export declare function extractInstances(filename: string, source: string, root: string, includedNames?: string[]): Promise<{
12
+ names: string[];
13
+ server: string;
14
+ browser: string;
15
+ } | undefined>;
16
+ export declare function instanceExtractionPlugin(root: string, serverConfigured: boolean, modules: Map<string, InstanceModule>): Plugin;
17
+ export declare function instanceServerPlugin(root: string, modules: InstanceModule[]): Plugin;
18
+ export declare function instanceServerImports(modules: InstanceModule[]): string;
19
+ export declare function instanceServerBindings(modules: InstanceModule[], registrations: InstanceRegistration[]): string;
@@ -0,0 +1,6 @@
1
+ import type { AppMigration } from "../protocol";
2
+ /** Read the timestamped migration folders produced by the workspace's Drizzle Kit version. */
3
+ export declare function readAppMigrations(directory: string, optional?: boolean): Promise<{
4
+ migrations: AppMigration[];
5
+ files: string[];
6
+ }>;
@@ -0,0 +1,2 @@
1
+ /** Generate a fresh snapshot with Drizzle in disposable storage, leaving committed history unchanged. */
2
+ export declare function checkAppSchema(root: string, migrationsDirectory: string): Promise<void>;
@@ -0,0 +1,6 @@
1
+ import type { LoadedTailorKitConfig } from "../config/loader";
2
+ import type { InstanceModule, InstanceRegistration } from "./instances";
3
+ /** Bundle the private app backend and migrations. */
4
+ export declare function buildServer(loaded: LoadedTailorKitConfig, watch?: boolean, buildOutDir?: string, instances?: InstanceModule[], registrations?: InstanceRegistration[]): Promise<import("@voidzero-dev/vite-plus-core/rolldown").RolldownOutput[] | import("@voidzero-dev/vite-plus-core/rolldown").RolldownOutput | import("@voidzero-dev/vite-plus-core/rolldown").RolldownWatcher | undefined>;
5
+ /** Check before either build can empty an output directory. */
6
+ export declare function validateServerBuildOutput(loaded: LoadedTailorKitConfig, output: string): void;
@@ -1,10 +1,20 @@
1
1
  import { z } from "zod";
2
2
  export declare const tailorkitUploadManifestSchema: z.ZodObject<{
3
3
  assets: z.ZodObject<{
4
- client: z.ZodLiteral<"client.js">;
4
+ client: z.ZodLiteral<"client/client.js">;
5
+ server: z.ZodOptional<z.ZodLiteral<"server/server.js">>;
6
+ logos: z.ZodOptional<z.ZodObject<{
7
+ dark: z.ZodOptional<z.ZodString>;
8
+ light: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strip>>;
5
10
  }, z.core.$strip>;
11
+ views: z.ZodOptional<z.ZodArray<z.ZodObject<{
12
+ slot: z.ZodString;
13
+ path: z.ZodString;
14
+ instances: z.ZodOptional<z.ZodLiteral<true>>;
15
+ disabled: z.ZodOptional<z.ZodLiteral<true>>;
16
+ }, z.core.$strip>>>;
6
17
  version: z.ZodLiteral<1>;
7
18
  }, z.core.$strip>;
8
19
  export type TailorKitUploadManifest = z.output<typeof tailorkitUploadManifestSchema>;
9
- export declare const createTailorKitUploadManifest: () => TailorKitUploadManifest;
10
- //# sourceMappingURL=upload-manifest.d.ts.map
20
+ export declare const createTailorKitUploadManifest: (logos?: TailorKitUploadManifest["assets"]["logos"], server?: boolean, views?: TailorKitUploadManifest["views"]) => TailorKitUploadManifest;