zitejs 0.10.0-start.6 → 0.10.0-start.7

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 (46) hide show
  1. package/dist/cjs/backend/index.d.ts +115 -3
  2. package/dist/cjs/backend/index.test.js +58 -0
  3. package/dist/cjs/integrations/rules.d.ts +13 -0
  4. package/dist/cjs/integrations/rules.js +29 -0
  5. package/dist/cjs/integrations/rules.test.js +1 -0
  6. package/dist/cjs/sync/lib.js +6 -6
  7. package/dist/esm/backend/index.d.ts +115 -3
  8. package/dist/esm/backend/index.test.js +58 -0
  9. package/dist/esm/integrations/rules.d.ts +13 -0
  10. package/dist/esm/integrations/rules.js +29 -0
  11. package/dist/esm/integrations/rules.test.js +1 -0
  12. package/dist/esm/start/authHooks.d.ts +7 -0
  13. package/dist/esm/start/authHooks.js +10 -0
  14. package/dist/esm/start/authHooksModule.d.ts +1 -0
  15. package/dist/esm/start/authHooksModule.js +3 -0
  16. package/dist/esm/start/clientErrorMessage.test.d.ts +1 -0
  17. package/dist/esm/start/clientErrorMessage.test.js +105 -0
  18. package/dist/esm/start/describe.d.ts +17 -1
  19. package/dist/esm/start/describe.js +27 -5
  20. package/dist/esm/start/errors.d.ts +46 -0
  21. package/dist/esm/start/errors.js +99 -0
  22. package/dist/esm/start/errors.test.d.ts +1 -0
  23. package/dist/esm/start/errors.test.js +23 -0
  24. package/dist/esm/start/index.d.ts +3 -19
  25. package/dist/esm/start/index.js +28 -36
  26. package/dist/esm/start/instance.d.ts +1 -2
  27. package/dist/esm/start/instance.js +11 -4
  28. package/dist/esm/start/previewClaim.d.ts +10 -0
  29. package/dist/esm/start/previewClaim.js +32 -0
  30. package/dist/esm/start/redactSecrets.d.ts +7 -0
  31. package/dist/esm/start/redactSecrets.js +131 -0
  32. package/dist/esm/start/redactSecrets.test.d.ts +1 -0
  33. package/dist/esm/start/redactSecrets.test.js +151 -0
  34. package/dist/esm/start/router.d.ts +6 -3
  35. package/dist/esm/start/router.js +47 -7
  36. package/dist/esm/start/runLog.d.ts +7 -4
  37. package/dist/esm/start/runLog.js +64 -6
  38. package/dist/esm/start/server.d.ts +7 -3
  39. package/dist/esm/start/server.js +74 -21
  40. package/dist/esm/start/types.d.ts +28 -3
  41. package/dist/esm/start/version.d.ts +1 -0
  42. package/dist/esm/start/version.js +2 -0
  43. package/dist/esm/start/vite.js +31 -3
  44. package/dist/esm/start/workflowRun.js +2 -1
  45. package/dist/esm/sync/lib.js +6 -6
  46. package/package.json +16 -8
@@ -1,8 +1,10 @@
1
- import { ZiteError, ZITE_ERROR_STATUS } from "./index.js";
1
+ import { asZiteError, isZiteErrorCode, ZiteError, ZITE_ERROR_STATUS } from "./errors.js";
2
2
  import { describeApp } from "./describe.js";
3
3
  import { runRegistration } from "./registration.js";
4
- import { preview } from "./runLog.js";
5
- import { getHost, requireScope, runWithHost } from "./scope.js";
4
+ import { isAuthHookName, loadAuthHooks } from "./authHooks.js";
5
+ import { errorOf, preview } from "./runLog.js";
6
+ import { getHost, requireScope, runInScope, runWithHost } from "./scope.js";
7
+ import { ZITEJS_VERSION } from "./version.js";
6
8
  import { loadWorkflows, loggedInput, runWorkflow } from "./workflowRun.js";
7
9
  export { runWithHost } from "./scope.js";
8
10
  export { describeApp } from "./describe.js";
@@ -23,8 +25,8 @@ export function installPlatformTransport() {
23
25
  const result = await (await host.session).call({ integrationId, className, methodName, params, access: scope.kind });
24
26
  if ("value" in result)
25
27
  return result.value;
26
- const { code, message } = result.error;
27
- throw new ZiteError(code in ZITE_ERROR_STATUS ? code : "INTERNAL_ERROR", message);
28
+ const { code, message, userFacingMessage } = result.error;
29
+ throw new ZiteError({ code: isZiteErrorCode(code) ? code : "INTERNAL_ERROR", message, userFacingMessage });
28
30
  };
29
31
  globalThis.__wrapSdkCall = sdkCall;
30
32
  watchOutboundFetches();
@@ -53,7 +55,9 @@ const watchOutboundFetches = () => {
53
55
  };
54
56
  };
55
57
  const decodeUser = (value) => JSON.parse(new TextDecoder().decode(Uint8Array.from(atob(value.replace(/-/g, "+").replace(/_/g, "/")), (c) => c.charCodeAt(0))));
56
- const INVOKE_KINDS = new Set(["webhook", "describe", "workflow", "register", "warm"]);
58
+ const INVOKE_KINDS = new Set(["webhook", "describe", "workflow", "register", "warm", "authHook"]);
59
+ // What a request without props may ask for: neither runs app code on anyone's behalf.
60
+ const UNHOSTED_INVOKE_KINDS = new Set(["warm", "describe"]);
57
61
  /** What the host dispatched this request with. Headers are ignored: props are the only thing it alone can set. */
58
62
  export function hostContextFromProps(request, props) {
59
63
  return {
@@ -62,32 +66,48 @@ export function hostContextFromProps(request, props) {
62
66
  user: props.user,
63
67
  mode: props.mode,
64
68
  invoke: props.invoke,
69
+ appUrl: props.appUrl,
70
+ baseId: props.baseId,
71
+ previewClaim: props.previewClaim,
65
72
  runs: [],
66
73
  platform: props.platform,
67
74
  };
68
75
  }
76
+ // Classic sets these per run. Node and workerd both refuse getters on process.env, so each request writes what the
77
+ // host sent, which is the same for every request a build serves: the live URL even on a demo.
78
+ const setRequestEnv = ({ appUrl, baseId }) => {
79
+ const env = globalThis.process?.env;
80
+ if (!env)
81
+ return;
82
+ if (appUrl)
83
+ env.ZITE_APP_URL = appUrl;
84
+ if (baseId)
85
+ env.ZITE_BASE_ID = baseId;
86
+ };
69
87
  /**
70
- * A request the host didn't dispatch: `zitejs describe` under `vite preview`,
71
- * and tests, which pass their own platform. Deployed builds have no public URL,
72
- * so in production every request carries props.
88
+ * A request the host didn't dispatch: the host's warm-up, `zitejs describe` under `vite preview`, and tests. Only the
89
+ * host can set props, so without them a build answers warm and describe and nobody is signed in. An entry that passes
90
+ * its own platform (tests, local dev) owns its requests and may say who is calling in `x-zite-*` headers.
73
91
  */
74
92
  export function hostContextFromRequest(request, platform) {
75
93
  const { headers } = request;
76
- const user = headers.get("x-zite-user");
94
+ const trusted = platform !== undefined;
95
+ const user = trusted ? headers.get("x-zite-user") : null;
77
96
  const [kind, name = ""] = headers.get("x-zite-invoke")?.split(":") ?? [];
97
+ const kinds = trusted ? INVOKE_KINDS : UNHOSTED_INVOKE_KINDS;
78
98
  return {
79
- requestId: headers.get("x-zite-request-id") ?? crypto.randomUUID(),
99
+ requestId: (trusted && headers.get("x-zite-request-id")) || crypto.randomUUID(),
80
100
  url: request.url,
81
101
  user: user ? decodeUser(user) : null,
82
102
  mode: "live",
83
- invoke: INVOKE_KINDS.has(kind) ? { kind: kind, name } : null,
103
+ invoke: kinds.has(kind) ? { kind: kind, name } : null,
84
104
  runs: [],
85
105
  platform,
86
106
  };
87
107
  }
88
108
  /** Every server function TanStack compiled, written in by `zite()` at build. Empty in dev, where TanStack doesn't call its id hook. */
89
109
  export const builtFunctionIds = () => "__ZITE_FN_IDS__".split(",").filter((id) => id && !id.startsWith("__ZITE"));
90
- const parseDescriptions = (json) => {
110
+ const parseBuiltJson = (json) => {
91
111
  try {
92
112
  return JSON.parse(json);
93
113
  }
@@ -96,7 +116,9 @@ const parseDescriptions = (json) => {
96
116
  }
97
117
  };
98
118
  /** Each server function's `description` option, written in by `zite()` at build. */
99
- export const builtFunctionDescriptions = () => parseDescriptions("__ZITE_FN_DESCRIPTIONS__");
119
+ export const builtFunctionDescriptions = () => parseBuiltJson("__ZITE_FN_DESCRIPTIONS__");
120
+ /** Each route's file, by route id, written in by `zite()` at build. */
121
+ export const builtRouteFiles = () => parseBuiltJson("__ZITE_ROUTE_FILES__");
100
122
  // Server functions also run while a streamed page renders, so the run log is
101
123
  // complete only once the body has been read to the end.
102
124
  const onBodyEnd = (response, done) => {
@@ -107,6 +129,8 @@ const onBodyEnd = (response, done) => {
107
129
  return new Response(response.body.pipeThrough(new TransformStream({ flush: done })), response);
108
130
  };
109
131
  const INVOKE_PATH = "/_zite/invoke";
132
+ /** On describe's answer: the zitejs this build's server code was bundled from. */
133
+ export const RUNTIME_VERSION_HEADER = "x-zitejs-version";
110
134
  // The host sends `{ input }`; a platform-fired run's input carries the runner's
111
135
  // `__cron`, `__poll` or `__webhook` state, exactly as for classic endpoints.
112
136
  async function invokeWorkflow(request, host, workflows) {
@@ -143,13 +167,35 @@ async function invokeRegistration(request, host, workflows) {
143
167
  }
144
168
  return Response.json(result, { status: result.ok ? 200 : 500 });
145
169
  }
146
- const isZiteError = (error) => error instanceof Error && error.name === "ZiteError" && error.code in ZITE_ERROR_STATUS;
170
+ // The host sends `{ input }`, the same fields classic hooks get. A hook runs as
171
+ // a workflow does: no user, and the app's data and integrations through its platform.
172
+ async function invokeAuthHook(request, host) {
173
+ if (request.method !== "POST" || new URL(request.url).pathname !== INVOKE_PATH)
174
+ return new Response("Not found", { status: 404 });
175
+ const name = host.invoke?.name ?? "";
176
+ const hook = isAuthHookName(name) ? (await loadAuthHooks())[name] : undefined;
177
+ if (!hook) {
178
+ return Response.json({ ok: false, error: { code: "NOT_FOUND", message: `No auth hook named ${name}` } }, { status: 404 });
179
+ }
180
+ const input = (await request.json().catch(() => ({})))?.input ?? {};
181
+ const startedAt = Date.now();
182
+ try {
183
+ const output = await runInScope({ kind: "workflow", user: null }, () => hook(input));
184
+ host.runs.push({ fn: `authHook:${name}`, name, nested: false, startedAt, durationMs: Date.now() - startedAt, input: preview(input), output: preview(output) });
185
+ return Response.json({ ok: true, output: output ?? null });
186
+ }
187
+ catch (error) {
188
+ const failed = errorOf(error);
189
+ host.runs.push({ fn: `authHook:${name}`, name, nested: false, startedAt, durationMs: Date.now() - startedAt, input: preview(input), error: failed });
190
+ return Response.json({ ok: false, error: failed }, { status: 500 });
191
+ }
192
+ }
147
193
  // TanStack renders any loader error as a 500. A page refused with a ZiteError
148
194
  // (a missing role, a record that isn't there) answers with that error's status.
149
195
  const pageStatus = (host) => {
150
196
  const matches = host.router?.state?.matches;
151
- const failed = matches?.find((match) => match.status === "error")?.error;
152
- return isZiteError(failed) ? ZITE_ERROR_STATUS[failed.code] : undefined;
197
+ const failed = asZiteError(matches?.find((match) => match.status === "error")?.error);
198
+ return failed ? ZITE_ERROR_STATUS[failed.code] : undefined;
153
199
  };
154
200
  /**
155
201
  * The handlers of a Start app's server entry. A request the host dispatched
@@ -168,6 +214,7 @@ export function createZiteHandlers(options) {
168
214
  : hostContextFromRequest(request, options.platform);
169
215
  if (watch)
170
216
  host.watch = watch;
217
+ setRequestEnv(host);
171
218
  // Starting this isolate was the point: the platform warms a build before its
172
219
  // first visitors, and no app code runs.
173
220
  if (host.invoke?.kind === "warm")
@@ -176,26 +223,32 @@ export function createZiteHandlers(options) {
176
223
  return Response.json(await describeApp({
177
224
  fnIds: builtFunctionIds(),
178
225
  descriptions: builtFunctionDescriptions(),
226
+ routeFiles: builtRouteFiles(),
179
227
  getRouter: options.getRouter,
180
228
  request,
181
229
  workflows: await loadedWorkflows(),
182
- }));
230
+ }), { headers: { [RUNTIME_VERSION_HEADER]: ZITEJS_VERSION } });
183
231
  }
184
232
  let response = await runWithHost(host, async () => host.invoke?.kind === "workflow"
185
233
  ? invokeWorkflow(request, host, await loadedWorkflows())
186
234
  : host.invoke?.kind === "register"
187
235
  ? invokeRegistration(request, host, await loadedWorkflows())
188
- : options.handler.fetch(request));
236
+ : host.invoke?.kind === "authHook"
237
+ ? invokeAuthHook(request, host)
238
+ : options.handler.fetch(request));
189
239
  const status = response.status === 500 ? pageStatus(host) : undefined;
190
240
  if (status)
191
241
  response = new Response(response.body, { status, headers: response.headers });
192
242
  return onBodyEnd(response, () => {
193
243
  const { platform } = host;
194
- if (!host.runs.length || !platform)
244
+ if ((!host.runs.length && !host.pending?.length) || !platform)
195
245
  return;
196
- const batch = { runs: host.runs };
197
246
  // On the request's session when it has one: one call, not another binding round trip.
198
247
  const flushed = (async () => {
248
+ await Promise.all(host.pending ?? []);
249
+ if (!host.runs.length)
250
+ return;
251
+ const batch = { runs: host.runs };
199
252
  const session = host.session ? await host.session : undefined;
200
253
  await (session?.runs ? session.runs(batch) : platform.runs(batch));
201
254
  })().catch((error) => {
@@ -1,8 +1,19 @@
1
+ export type Role = {
2
+ id: string;
3
+ name: string;
4
+ };
5
+ /** As classic's `context.user`, plus `name`. */
1
6
  export type User = {
2
7
  id: string;
3
8
  email: string;
9
+ /** First and last name, or the email when neither is set. */
4
10
  name: string;
5
- roles: ReadonlyArray<string>;
11
+ firstName?: string;
12
+ lastName?: string;
13
+ /** The built-in roles, then the ones assigned on the Members tab. */
14
+ roles: ReadonlyArray<Role>;
15
+ /** A member of the workspace's team, not an external user. */
16
+ isInternal: boolean;
6
17
  };
7
18
  /** One server function call, as the platform's run log shows it. Input and output are truncated JSON. */
8
19
  export type RunRecord = {
@@ -16,6 +27,7 @@ export type RunRecord = {
16
27
  error?: {
17
28
  code: string;
18
29
  message: string;
30
+ stack?: string;
19
31
  };
20
32
  };
21
33
  export type AccessKind = "signedIn" | "anyone" | "webhook" | "workflow";
@@ -38,6 +50,7 @@ export type PlatformCallResult = {
38
50
  error: {
39
51
  code: string;
40
52
  message: string;
53
+ userFacingMessage?: string;
41
54
  };
42
55
  };
43
56
  export type PlatformSession = {
@@ -63,9 +76,10 @@ export type PlatformBinding = {
63
76
  runs: RunRecord[];
64
77
  }): Promise<void>;
65
78
  };
66
- export type HostMode = "live" | "preview" | "validate";
79
+ /** A demo is the published build serving a read-only visitor: as live, but every write is refused. */
80
+ export type HostMode = "live" | "preview" | "demo" | "validate";
67
81
  export type HostInvoke = {
68
- kind: "webhook" | "describe" | "workflow" | "register" | "warm";
82
+ kind: "webhook" | "describe" | "workflow" | "register" | "warm" | "authHook";
69
83
  name: string;
70
84
  };
71
85
  /** The per-request props the host dispatches with. Only the host can set them. */
@@ -75,6 +89,12 @@ export type HostProps = {
75
89
  user: User | null;
76
90
  mode: HostMode;
77
91
  invoke: HostInvoke | null;
92
+ /** The app's live URL, demo included: `process.env.ZITE_APP_URL`. Hosts before 0.10.0-start.7 don't send it. */
93
+ appUrl?: string;
94
+ /** The app's database: `process.env.ZITE_BASE_ID`. */
95
+ baseId?: string;
96
+ /** An editor preview's access, which zitejs keeps on the app's links and calls. */
97
+ previewClaim?: string;
78
98
  };
79
99
  /** What the host resolved for this request. Set by the generated server entry, never by the browser. */
80
100
  export type ZiteRequestContext = {
@@ -83,8 +103,13 @@ export type ZiteRequestContext = {
83
103
  user: User | null;
84
104
  mode: HostMode;
85
105
  invoke: HostInvoke | null;
106
+ appUrl?: string;
107
+ baseId?: string;
108
+ previewClaim?: string;
86
109
  /** Filled by run capture, flushed to the platform once the response ends. */
87
110
  runs: RunRecord[];
111
+ /** Records still reading a copy of a body; the flush waits for them. */
112
+ pending?: Promise<void>[];
88
113
  platform?: PlatformBinding;
89
114
  session?: Promise<PlatformSession>;
90
115
  /** Set when the host renders a page it may cache. */
@@ -0,0 +1 @@
1
+ export declare const ZITEJS_VERSION = "0.10.0-start.7";
@@ -0,0 +1,2 @@
1
+ // Written by scripts/write-version.mjs from package.json.
2
+ export const ZITEJS_VERSION = "0.10.0-start.7";
@@ -1,3 +1,4 @@
1
+ import { existsSync } from "node:fs";
1
2
  import path from "node:path";
2
3
  import { tanstackStart } from "@tanstack/react-start/plugin/vite";
3
4
  import viteReact from "@vitejs/plugin-react";
@@ -7,8 +8,14 @@ import { hasAppStart, renderStartInstance, renderStartServerEntry, renderWorkflo
7
8
  // Must match the literals in ./server.ts, which the build rewrites.
8
9
  const FN_IDS_TOKEN = "__ZITE_FN_IDS__";
9
10
  const FN_DESCRIPTIONS_LITERAL = /(["'`])__ZITE_FN_DESCRIPTIONS__\1/;
11
+ const ROUTE_FILES_LITERAL = /(["'`])__ZITE_ROUTE_FILES__\1/;
12
+ // TanStack's generator writes each route file's id into its createFileRoute call and keeps it in step.
13
+ const FILE_ROUTE_ID = /\bcreateFileRoute\(\s*(["'`])([^"'`]+)\1\s*\)/;
10
14
  // zitejs's empty registry, which the build replaces with the app's.
11
15
  const WORKFLOW_REGISTRY = /[\\/]zitejs[\\/]dist[\\/]esm[\\/]start[\\/]workflowModules\.js$/;
16
+ // zitejs's null auth-hooks module, which the build points at the app's `zite.auth.ts`.
17
+ const AUTH_HOOKS_REGISTRY = /[\\/]zitejs[\\/]dist[\\/]esm[\\/]start[\\/]authHooksModule\.js$/;
18
+ const AUTH_HOOKS_FILE = "zite.auth.ts";
12
19
  // Platform-pinned Worker settings. The deploy uses its own fixed template, so
13
20
  // these only have to match it; apps don't carry a wrangler config.
14
21
  const WORKER_COMPATIBILITY_DATE = "2026-09-25";
@@ -71,14 +78,21 @@ export function zite(options = {}) {
71
78
  // time; Vite leaves SSR output unminified.
72
79
  configEnvironment: (name, config) => name === "ssr" && options.cloudflare !== false && config.build?.minify === undefined ? { build: { minify: true } } : undefined,
73
80
  };
74
- // Each server function's `description` option, by name, for the editor.
81
+ // Each server function's `description` option, by name, and each route's file, by route id: for the editor.
75
82
  const descriptions = new Map();
83
+ const routeFiles = new Map();
76
84
  const srcDir = `${path.join(appDir, "src")}${path.sep}`;
77
85
  const functionIds = {
78
86
  name: "zite:function-ids",
79
87
  apply: "build",
80
88
  transform(code, id) {
81
- if (this.environment?.config.consumer !== "server" || !id.startsWith(srcDir) || !code.includes("description"))
89
+ if (this.environment?.config.consumer !== "server" || !id.startsWith(srcDir))
90
+ return;
91
+ const file = id.split("?")[0];
92
+ const routeId = FILE_ROUTE_ID.exec(code)?.[2];
93
+ if (routeId && !id.includes("?"))
94
+ routeFiles.set(routeId, path.relative(appDir, file).split(path.sep).join("/"));
95
+ if (!code.includes("description"))
82
96
  return;
83
97
  try {
84
98
  for (const [name, text] of factoryDescriptions(this.parse(code)))
@@ -95,7 +109,9 @@ export function zite(options = {}) {
95
109
  continue;
96
110
  if (chunk.code.includes(FN_IDS_TOKEN))
97
111
  chunk.code = chunk.code.replace(FN_IDS_TOKEN, [...ids.keys()].join(","));
98
- chunk.code = chunk.code.replace(FN_DESCRIPTIONS_LITERAL, () => JSON.stringify(JSON.stringify(described)));
112
+ chunk.code = chunk.code
113
+ .replace(FN_DESCRIPTIONS_LITERAL, () => JSON.stringify(JSON.stringify(described)))
114
+ .replace(ROUTE_FILES_LITERAL, () => JSON.stringify(JSON.stringify(Object.fromEntries(routeFiles))));
99
115
  }
100
116
  },
101
117
  };
@@ -103,6 +119,17 @@ export function zite(options = {}) {
103
119
  name: "zite:workflow-registry",
104
120
  load: (id) => (WORKFLOW_REGISTRY.test(id.split("?")[0]) ? renderWorkflowModules(appDir, workflowFiles(appDir)) : undefined),
105
121
  };
122
+ const authHooksRegistry = {
123
+ name: "zite:auth-hooks",
124
+ load: (id) => {
125
+ if (!AUTH_HOOKS_REGISTRY.test(id.split("?")[0]))
126
+ return undefined;
127
+ const file = path.join(appDir, AUTH_HOOKS_FILE);
128
+ return existsSync(file)
129
+ ? `export const authHooksModule = () => import(${JSON.stringify(file)});\n`
130
+ : "export const authHooksModule = null;\n";
131
+ },
132
+ };
106
133
  return [
107
134
  tanstackStart({
108
135
  // TanStack resolves these from `src/`.
@@ -140,5 +167,6 @@ export function zite(options = {}) {
140
167
  compileZitejs,
141
168
  functionIds,
142
169
  workflowRegistry,
170
+ authHooksRegistry,
143
171
  ];
144
172
  }
@@ -23,7 +23,8 @@ const idOf = (id) => {
23
23
  */
24
24
  export function triggerContext(workflow, rawInput) {
25
25
  const raw = asRecord(rawInput);
26
- const { __cron, __poll, __webhook, ...input } = raw ?? {};
26
+ // `__cron` stays in the input, as on classic: scheduled code reads its scheduleId and scheduledAt there.
27
+ const { __poll, __webhook, ...input } = raw ?? {};
27
28
  const declared = workflow.config.trigger;
28
29
  if (!declared)
29
30
  return { input: raw ? input : rawInput };
@@ -509,7 +509,7 @@ export function generateDbTs(inputSchema) {
509
509
  lines.push('// `not: null` means "is set". An empty `in: []` matches nothing; an', "// empty `notIn: []` applies no filter.");
510
510
  lines.push("// sort is currently IGNORED here — it is stripped before the request.", "// (it does work on zite.auth.findAllUsers). Order in SQL instead.");
511
511
  lines.push("// limit defaults to 500, max 2000; offset is a row count (a number)");
512
- lines.push('// a filter value of `undefined` is REJECTED (it would query unfiltered', '// and match an arbitrary record). Check the value first.');
512
+ lines.push("// a filter value of `undefined` is REJECTED (it would query unfiltered", "// and match an arbitrary record). Check the value first.");
513
513
  lines.push("// .findOne({ id?, filters?, fields? }) → T | undefined");
514
514
  lines.push("// .create({ record }) → T");
515
515
  lines.push("// .update({ id, record }) → { id: string, fields: Partial<T> }");
@@ -1217,13 +1217,13 @@ export function generateBackendWrapperTs(envVarNames = []) {
1217
1217
  "// Auto-generated type-narrowing wrapper. Do not edit manually.",
1218
1218
  "// Re-exports createEndpoint with context.user typed to the app User.",
1219
1219
  "",
1220
- "import type { ZiteRequestContext as _ZiteRequestContext, ZiteScheduledContext, ZiteErrorCode, ZiteSchedule, ZiteStep, ZiteStreamInterface, ZiteTrigger, ZiteTriggerContext, ZiteWebhook } from 'zitejs/backend/base';",
1220
+ "import type { ZiteRequestContext as _ZiteRequestContext, ZiteScheduledContext, ZiteErrorCode, ZiteSchedule, ZiteStep, ZiteStreamInterface, ZiteTrigger, ZiteTriggerContext, ZiteEndpointInput, ZiteWebhook } from 'zitejs/backend/base';",
1221
1221
  "import type { User } from 'zitejs/auth';",
1222
1222
  "",
1223
1223
  "export type { ZiteErrorCode, ZiteSchedule, ZiteScheduledContext, ZiteStep, ZiteStreamInterface, ZiteTrigger, ZiteWebhook };",
1224
1224
  // A trigger's registration exports are typed against these, and they
1225
1225
  // only reach app code through this file.
1226
- "export type { ZiteTriggerContext, ZiteTriggerDeliveryInfo, ZiteTriggerDeliveryRun, ZiteTriggerRun, ZiteTriggerSubscribe, ZiteTriggerSubscribeInput, ZiteTriggerSubscribeResult, ZiteTriggerUnsubscribe, ZiteTriggerUnsubscribeInput } from 'zitejs/backend/base';",
1226
+ "export type { ZiteDatabaseTriggerEvent, ZiteDatabaseTriggerInput, ZiteFormTriggerInput, ZiteTriggerContext, ZiteTriggerDeliveryInfo, ZiteTriggerDeliveryRun, ZiteTriggerRun, ZiteTriggerSubscribe, ZiteTriggerSubscribeInput, ZiteTriggerSubscribeResult, ZiteTriggerUnsubscribe, ZiteTriggerUnsubscribeInput } from 'zitejs/backend/base';",
1227
1227
  // The pre-monorepo SDK put this in scope for every endpoint, so migrated
1228
1228
  // code can name it. `createEndpoint` infers the same thing without it.
1229
1229
  "export type InferSchemaType<T> = T extends { _output: infer U } ? U : T;",
@@ -1311,12 +1311,12 @@ export function generateBackendWrapperTs(envVarNames = []) {
1311
1311
  " schedule?: TSchedule;",
1312
1312
  " /** When set, an inbound webhook can also trigger this endpoint. Like `schedule`, it widens `context` — a webhook fire has no session. */",
1313
1313
  " webhook?: TWebhook;",
1314
- " /** When set, a connection's events (registered by this file's own `subscribe` export) or a poll (`every`) also fire this endpoint. Like `webhook`, it widens `context` — a trigger fire has no session. */",
1314
+ " /** When set, a connection's events (registered by this file's own `subscribe` export), a poll (`every`), a change to one of the project's tables (`table`) or a submission to one of its forms (`form`) also fire this endpoint. Like `webhook`, it widens `context` — a trigger fire has no session. */",
1315
1315
  " trigger?: TTrigger;",
1316
1316
  " execute: (",
1317
1317
  " params: {",
1318
- " input: TInput;",
1319
- " /** Durable steps: step.run(name, fn) runs fn once per logical run — its result is saved before anything after it executes, and a resumed run replays completed steps from their saved results. Provided by the platform; never define a local stand-in. */",
1318
+ " input: ZiteEndpointInput<TInput, TTrigger>;",
1319
+ " /** Durable steps: step.run(name, fn) runs fn once per logical run — its result is saved before anything after it executes, and a resumed run replays completed steps from their saved results. In a run fired by a schedule, webhook or trigger, step.sleep(name, \"2d\") pauses the run and a failed step is tried again. Provided by the platform; never define a local stand-in. */",
1320
1320
  " step: ZiteStep;",
1321
1321
  " context: TSchedule extends ZiteSchedule ? ZiteRequestContext | ZiteScheduledContext : TWebhook extends ZiteWebhook ? ZiteRequestContext | ZiteScheduledContext : TTrigger extends ZiteTrigger ? ZiteRequestContext | ZiteScheduledContext : ZiteRequestContext;",
1322
1322
  // Mirrors the base module: a trigger's run gets `trigger`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zitejs",
3
- "version": "0.10.0-start.6",
3
+ "version": "0.10.0-start.7",
4
4
  "description": "The Zite framework — build apps on Zite Database",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -123,11 +123,13 @@
123
123
  }
124
124
  },
125
125
  "scripts": {
126
- "build": "tsc && tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
126
+ "build": "node scripts/write-version.mjs && tsc && tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json",
127
127
  "test": "vitest run",
128
128
  "test:start": "node tests/start/run-contract.mjs",
129
129
  "test:watch": "vitest",
130
130
  "typecheck": "tsc --noEmit",
131
+ "version": "node scripts/write-version.mjs && git add src/start/version.ts",
132
+ "release": "node ./scripts/release.mjs",
131
133
  "prepublishOnly": "npm run build"
132
134
  },
133
135
  "files": [
@@ -177,14 +179,15 @@
177
179
  }
178
180
  },
179
181
  "peerDependencies": {
180
- "@tanstack/react-query": ">=5",
181
- "react": ">=18",
182
- "vite": ">=5",
182
+ "@cloudflare/vite-plugin": ">=1",
183
+ "@tanstack/react-query": ">=5.102.0",
184
+ "@tanstack/react-router": "1.170.41",
185
+ "@tanstack/react-router-ssr-query": "1.167.3",
183
186
  "@tanstack/react-start": "1.168.60",
184
187
  "@tanstack/start-storage-context": "1.167.36",
185
188
  "@vitejs/plugin-react": ">=5",
186
- "@cloudflare/vite-plugin": ">=1",
187
- "@tanstack/react-router": "1.170.41"
189
+ "react": ">=18",
190
+ "vite": ">=5"
188
191
  },
189
192
  "peerDependenciesMeta": {
190
193
  "react": {
@@ -210,11 +213,16 @@
210
213
  },
211
214
  "@tanstack/react-router": {
212
215
  "optional": true
216
+ },
217
+ "@tanstack/react-router-ssr-query": {
218
+ "optional": true
213
219
  }
214
220
  },
215
221
  "devDependencies": {
216
- "@tanstack/react-query": "^5.100.14",
222
+ "@tanstack/query-core": "5.104.0",
223
+ "@tanstack/react-query": "5.104.0",
217
224
  "@tanstack/react-router": "1.170.41",
225
+ "@tanstack/react-router-ssr-query": "1.167.3",
218
226
  "@tanstack/react-start": "1.168.60",
219
227
  "@tanstack/start-storage-context": "1.167.36",
220
228
  "@types/node": "^25.9.1",