@tailorkit/app 0.1.0-beta.35 → 0.1.0-beta.38

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.
package/README.md CHANGED
@@ -1,12 +1,10 @@
1
- # TailorKit App
1
+ # TailorKit app SDK
2
2
 
3
- The SDK for building TailorKit extensions.
4
-
5
- Apps require Preact 11. Install `preact@^11` alongside the SDK.
3
+ Use `@tailorkit/app` to build TailorKit extensions. Apps require Preact 11; install `preact@^11` alongside the SDK.
6
4
 
7
5
  ## File routing
8
6
 
9
- New apps register views from `src/slots` automatically. Only files ending in `.view.tsx` are views, so supporting components can live beside them.
7
+ The builder registers views from `src/slots` automatically. Only files ending in `.view.tsx` register views, so supporting components can live beside them:
10
8
 
11
9
  ```text
12
10
  src/
@@ -22,10 +20,13 @@ src/
22
20
  customer-card.tsx
23
21
  ```
24
22
 
25
- The slot directory is its literal host slot name, including dots in names such as `panel.links`. Dots in a view filename separate route segments: `customers.details.view.tsx` registers `/customers/details`. Subdirectories also separate segments. `customer-card.tsx` is an ordinary component and is ignored unless imported. Duplicate view paths in a slot fail the build.
23
+ The slot directory is its literal host slot name, including dots in names such as `panel.links`. Dots in a view filename separate route segments: `customers.details.view.tsx` registers `/customers/details`. Subdirectories also separate segments. `customer-card.tsx` is an ordinary component and is ignored unless imported.
24
+
25
+ Duplicate view paths in a slot fail the build.
26
+
27
+ For example, `src/slots/panel/customers.details.view.tsx` registers `/customers/details`:
26
28
 
27
29
  ```tsx
28
- // src/slots/panel/customers.details.view.tsx
29
30
  import { defineView } from "tailorkit/client";
30
31
 
31
32
  import CustomerCard from "./customer-card";
@@ -33,10 +34,9 @@ import CustomerCard from "./customer-card";
33
34
  export default defineView({ component: CustomerCard });
34
35
  ```
35
36
 
36
- The builder supplies the slot and route before compiling. An explicit `view` must match the file path and gives precise host context typing:
37
+ The builder supplies the slot and route before compiling. In `src/slots/panel/index.view.tsx`, an explicit `view` gives typed host context and must match `/`:
37
38
 
38
39
  ```tsx
39
- // src/slots/panel/index.view.tsx
40
40
  import { defineView } from "tailorkit/client";
41
41
 
42
42
  const view = defineView({ view: "/", component: Home });
@@ -49,7 +49,11 @@ function Home() {
49
49
  export default view;
50
50
  ```
51
51
 
52
- `index.view.tsx` maps to `/`. A final `index` segment is omitted, so `customers/index.view.tsx` and `customers.index.view.tsx` both map to `/customers`. Other segments stay literal: `index.details.view.tsx` maps to `/index/details`. An explicit `view` or `slot` must be a matching string literal; mismatches fail the build. Use named properties in the inline `defineView` options so the build can check them. Multi-instance views provide `instances: { dataSchema, resolve }`; resolvers are extracted into the private server bundle. Host slot/view support and multiplicity are validated when publishing. An explicit slot also retains the source-level TypeScript checks for that slot's supported views and instances.
52
+ `index.view.tsx` maps to `/`. A final `index` segment is omitted, so `customers/index.view.tsx` and `customers.index.view.tsx` both map to `/customers`. Other segments stay literal: `index.details.view.tsx` maps to `/index/details`.
53
+
54
+ An explicit `view` or `slot` must be a matching string literal; mismatches fail the build. Use named properties in the inline `defineView` options so the build can check them.
55
+
56
+ For multi-instance views, provide `instances: { dataSchema, resolve }`. The builder extracts resolvers into the private server bundle. Host slot/view support and multiplicity are validated when publishing. An explicit slot also retains the source-level TypeScript checks for that slot's supported views and instances.
53
57
 
54
58
  ## Roots and layouts
55
59
 
@@ -71,7 +75,11 @@ export default defineRoute({ shellComponent: Shell });
71
75
 
72
76
  Each slot can also have a `root.tsx` exporting `defineRoute({ shellComponent })`. It wraps every view in that slot, inside the app shell. A shell can render its `children` prop instead of `<Route />`.
73
77
 
74
- `layout.tsx` wraps its directory path: at the slot root it wraps the entire slot; `members/layout.tsx` wraps `/members` and its descendants. `customers.layout.tsx` wraps `/customers` and its descendants, with matching at segment boundaries. Unlike view paths, layout paths retain a final `index` segment: `index.layout.tsx` maps to `/index`, and `members/index.layout.tsx` maps to `/members/index`. Layouts do not register views themselves. A layout default-exports an ordinary component (or a `defineRoute({ shellComponent })` definition):
78
+ `layout.tsx` wraps its directory path: at the slot root it wraps the entire slot; `members/layout.tsx` wraps `/members` and its descendants. `customers.layout.tsx` wraps `/customers` and its descendants, with matching at segment boundaries.
79
+
80
+ Unlike view paths, layout paths retain a final `index` segment: `index.layout.tsx` maps to `/index`, and `members/index.layout.tsx` maps to `/members/index`. Layouts do not register views themselves.
81
+
82
+ Export a component as the layout’s default export, or use a `defineRoute({ shellComponent })` definition:
75
83
 
76
84
  ```tsx
77
85
  import { Route } from "tailorkit/client";
@@ -269,12 +269,7 @@ var createClient = (options = {}) => {
269
269
  },
270
270
  headers: { authorization: `Bearer ${session.token}` },
271
271
  origin: url.origin,
272
- // SAFETY: URL.pathname always starts with a slash for this HTTP session URL, satisfying the transport's absolute route-path type.
273
- url: (
274
- /* oxlint-disable typescript/no-unsafe-type-assertion -- URL.pathname always starts with a slash for this HTTP session URL, satisfying the transport's absolute route-path type. */
275
- url.pathname
276
- )
277
- /* oxlint-enable typescript/no-unsafe-type-assertion */
272
+ url: `/${url.pathname.slice(1)}`
278
273
  })
279
274
  );
280
275
  if (kind === "mutations") {
@@ -344,7 +339,7 @@ var createClient = (options = {}) => {
344
339
  query: async (ref, ...[args]) => await /* oxlint-disable typescript/no-unsafe-type-assertion -- The query reference owns its output type, and the server validates that registered query before the shared transport returns its erased result. */
345
340
  call("queries", { args, name: ref.name }),
346
341
  /* oxlint-enable typescript/no-unsafe-type-assertion */
347
- subscribe: (ref, args, next, settings = {}) => {
342
+ subscribe: (ref, args, onValue, settings = {}) => {
348
343
  if (closed) {
349
344
  throw new AppError("UNAVAILABLE", "App client closed");
350
345
  }
@@ -365,7 +360,7 @@ var createClient = (options = {}) => {
365
360
  if (controller.signal.aborted || closed) {
366
361
  break;
367
362
  }
368
- next(
363
+ onValue(
369
364
  /* oxlint-disable typescript/no-unsafe-type-assertion -- This subscription was opened with ref.name and args; its listener receives only results from that same registered query, whose output generic is erased by the transport. */
370
365
  value
371
366
  /* oxlint-enable typescript/no-unsafe-type-assertion */
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createClient,
3
3
  reference
4
- } from "./chunk-PJBDA2RU.js";
4
+ } from "./chunk-5B5RGL5W.js";
5
5
  import {
6
6
  AppError,
7
7
  appError
@@ -194,11 +194,7 @@ var QueryStore = class {
194
194
  return;
195
195
  }
196
196
  publish({
197
- data: (
198
- /* oxlint-disable typescript/no-unsafe-type-assertion -- The entry is created and updated by this query reference's typed subscription; the shared cache erases its output generic. */
199
- this.state.get().get(key)?.data
200
- ),
201
- /* oxlint-enable typescript/no-unsafe-type-assertion */
197
+ data: this.state.get().get(key)?.data,
202
198
  error,
203
199
  status: "error"
204
200
  });
@@ -404,10 +400,9 @@ var useCall = (kind, ref, options) => {
404
400
  (...args) => {
405
401
  void (async () => {
406
402
  try {
407
- return await runAsync(...args);
403
+ await runAsync(...args);
408
404
  } catch {
409
405
  }
410
- return void 0;
411
406
  })();
412
407
  },
413
408
  [runAsync]
@@ -480,7 +475,8 @@ var createFileClient = (options) => {
480
475
  ...layout,
481
476
  shell: shellComponent(layout, false)
482
477
  }));
483
- const definitions = /* @__PURE__ */ Object.create(null);
478
+ const definitions = {};
479
+ Object.setPrototypeOf(definitions, null);
484
480
  for (const module of options.views) {
485
481
  const view = (
486
482
  /* oxlint-disable typescript/no-unsafe-type-assertion -- The generated module registry owns these component and view declarations; the runtime adapter preserves their exported implementations. */
@@ -513,7 +509,8 @@ var createFileClient = (options) => {
513
509
  }
514
510
  slot[view.path] = view;
515
511
  }
516
- const slots = /* @__PURE__ */ Object.create(null);
512
+ const slots = {};
513
+ Object.setPrototypeOf(slots, null);
517
514
  for (const [slot, views] of Object.entries(definitions)) {
518
515
  const slotLayouts = layouts.filter((layout) => layout.slot === slot).toSorted(
519
516
  (a, b) => a.path.split("/").filter(Boolean).length - b.path.split("/").filter(Boolean).length
@@ -3,7 +3,7 @@ import {
3
3
  createSessionProvider,
4
4
  parseSession,
5
5
  reference
6
- } from "./chunk-PJBDA2RU.js";
6
+ } from "./chunk-5B5RGL5W.js";
7
7
  import {
8
8
  AppError
9
9
  } from "./chunk-7ZQPXG7O.js";
package/dist/client.js CHANGED
@@ -9,13 +9,13 @@ import {
9
9
  useAction,
10
10
  useMutation,
11
11
  useQuery
12
- } from "./chunk-2JZOHWYW.js";
12
+ } from "./chunk-Q6X2VQKX.js";
13
13
  import {
14
14
  createApi,
15
15
  createClient,
16
16
  createSessionProvider,
17
17
  reference
18
- } from "./chunk-PJBDA2RU.js";
18
+ } from "./chunk-5B5RGL5W.js";
19
19
  import {
20
20
  AppError,
21
21
  appError
package/dist/index.js CHANGED
@@ -9,13 +9,13 @@ import {
9
9
  useAction,
10
10
  useMutation,
11
11
  useQuery
12
- } from "./chunk-2JZOHWYW.js";
12
+ } from "./chunk-Q6X2VQKX.js";
13
13
  import {
14
14
  createApi,
15
15
  createClient,
16
16
  createSessionProvider,
17
17
  reference
18
- } from "./chunk-PJBDA2RU.js";
18
+ } from "./chunk-5B5RGL5W.js";
19
19
  import {
20
20
  action,
21
21
  and,
@@ -2,7 +2,7 @@ import type { AnyRelations, EmptyRelations } from "drizzle-orm/relations";
2
2
  import { z } from "zod";
3
3
  import type { DatabaseDefinition } from "#database/definition";
4
4
  import type { MutationDatabase, QueryDatabase } from "#database/types";
5
- import type { ActionContext, FunctionKind, Functions, Identity } from "./functions";
5
+ import type { ActionContext, EmptyFunctions, FunctionKind, Functions, Identity } from "./functions";
6
6
  type HandlerContext<K extends FunctionKind, A extends z.ZodType, F extends Functions, D extends AnyRelations> = {
7
7
  input: z.output<A>;
8
8
  } & (K extends "action" ? ActionContext<F> : {
@@ -24,7 +24,7 @@ type BuiltFunction<K extends FunctionKind, A extends z.ZodType, R, O, F extends
24
24
  readonly functions: F;
25
25
  } : unknown);
26
26
  /** Immutable builders preserve the validated input and wire output types at every step. */
27
- declare class FunctionBuilder<K extends FunctionKind, A extends z.ZodType, R extends z.ZodType | undefined = undefined, F extends Functions = Record<never, never>, D extends AnyRelations = EmptyRelations> {
27
+ declare class FunctionBuilder<K extends FunctionKind, A extends z.ZodType, R extends z.ZodType | undefined = undefined, F extends Functions = EmptyFunctions, D extends AnyRelations = EmptyRelations> {
28
28
  private readonly kind;
29
29
  private readonly args;
30
30
  private readonly result;
@@ -3,6 +3,7 @@ import type { z } from "zod";
3
3
  import type { TailorKitServerTools } from "#client/tools";
4
4
  import type { DatabaseDefinition } from "#database/definition";
5
5
  import type { QueryDatabase, MutationDatabase } from "#database/types";
6
+ export type EmptyFunctions = Record<never, never>;
6
7
  export interface Identity {
7
8
  readonly subjectId?: string;
8
9
  readonly scope: {
@@ -36,7 +37,7 @@ export type FunctionCalls<F, K extends "query" | "mutation"> = {
36
37
  requestId?: string;
37
38
  }]) => Promise<FunctionResult<F[N]>> : (...args: undefined extends z.input<A> ? [args?: z.input<A>] : [args: z.input<A>]) => Promise<FunctionResult<F[N]>> : F[N] extends Functions ? FunctionCalls<F[N], K> : never;
38
39
  };
39
- export interface ActionContext<F extends Functions = Record<never, never>> {
40
+ export interface ActionContext<F extends Functions = EmptyFunctions> {
40
41
  readonly identity: Identity;
41
42
  readonly tools: TailorKitServerTools;
42
43
  readonly requestId: string;
@@ -45,7 +46,7 @@ export interface ActionContext<F extends Functions = Record<never, never>> {
45
46
  readonly queries: FunctionCalls<F, "query">;
46
47
  readonly mutations: FunctionCalls<F, "mutation">;
47
48
  }
48
- export interface FunctionDefinition<K extends FunctionKind, A extends z.ZodType, O, F extends Functions = Record<never, never>, D extends AnyRelations = EmptyRelations> {
49
+ export interface FunctionDefinition<K extends FunctionKind, A extends z.ZodType, O, F extends Functions = EmptyFunctions, D extends AnyRelations = EmptyRelations> {
49
50
  readonly kind: K;
50
51
  readonly args: A;
51
52
  readonly database?: K extends "action" ? never : DatabaseDefinition<D>;
@@ -57,25 +58,25 @@ export interface FunctionDefinition<K extends FunctionKind, A extends z.ZodType,
57
58
  identity: Identity;
58
59
  })) => K extends "action" ? O | Promise<O> : O;
59
60
  }
60
- export declare const query: <A extends z.ZodType, O, const D extends AnyRelations = EmptyRelations>(definition: Omit<FunctionDefinition<"query", A, O, Record<never, never>, D>, "kind"> & {
61
- handler: FunctionDefinition<"query", A, O, Record<never, never>, D>["handler"] & ([O] extends [never] ? unknown : O extends PromiseLike<unknown> ? never : unknown);
61
+ export declare const query: <A extends z.ZodType, O, const D extends AnyRelations = EmptyRelations>(definition: Omit<FunctionDefinition<"query", A, O, EmptyFunctions, D>, "kind"> & {
62
+ handler: FunctionDefinition<"query", A, O, EmptyFunctions, D>["handler"] & ([O] extends [never] ? unknown : O extends PromiseLike<unknown> ? never : unknown);
62
63
  }) => Readonly<{
63
64
  args: A;
64
65
  database?: DatabaseDefinition<D> | undefined;
65
66
  result?: z.ZodType<O, unknown, z.core.$ZodTypeInternals<O, unknown>> | undefined;
66
- handler: FunctionDefinition<"query", A, O, Record<never, never>, D>["handler"] & ([O] extends [never] ? unknown : O extends PromiseLike<unknown> ? never : unknown);
67
+ handler: FunctionDefinition<"query", A, O, EmptyFunctions, D>["handler"] & ([O] extends [never] ? unknown : O extends PromiseLike<unknown> ? never : unknown);
67
68
  kind: "query";
68
69
  }>;
69
- export declare const mutation: <A extends z.ZodType, O, const D extends AnyRelations = EmptyRelations>(definition: Omit<FunctionDefinition<"mutation", A, O, Record<never, never>, D>, "kind"> & {
70
- handler: FunctionDefinition<"mutation", A, O, Record<never, never>, D>["handler"] & ([O] extends [never] ? unknown : O extends PromiseLike<unknown> ? never : unknown);
70
+ export declare const mutation: <A extends z.ZodType, O, const D extends AnyRelations = EmptyRelations>(definition: Omit<FunctionDefinition<"mutation", A, O, EmptyFunctions, D>, "kind"> & {
71
+ handler: FunctionDefinition<"mutation", A, O, EmptyFunctions, D>["handler"] & ([O] extends [never] ? unknown : O extends PromiseLike<unknown> ? never : unknown);
71
72
  }) => Readonly<{
72
73
  args: A;
73
74
  database?: DatabaseDefinition<D> | undefined;
74
75
  result?: z.ZodType<O, unknown, z.core.$ZodTypeInternals<O, unknown>> | undefined;
75
- handler: FunctionDefinition<"mutation", A, O, Record<never, never>, D>["handler"] & ([O] extends [never] ? unknown : O extends PromiseLike<unknown> ? never : unknown);
76
+ handler: FunctionDefinition<"mutation", A, O, EmptyFunctions, D>["handler"] & ([O] extends [never] ? unknown : O extends PromiseLike<unknown> ? never : unknown);
76
77
  kind: "mutation";
77
78
  }>;
78
- export declare const action: <A extends z.ZodType, O, const F extends Functions = Record<never, never>>(definition: Omit<FunctionDefinition<"action", A, O, F>, "kind"> & {
79
+ export declare const action: <A extends z.ZodType, O, const F extends Functions = EmptyFunctions>(definition: Omit<FunctionDefinition<"action", A, O, F>, "kind"> & {
79
80
  functions?: F;
80
81
  }) => Readonly<{
81
82
  args: A;
package/dist/server.d.ts CHANGED
@@ -4,7 +4,7 @@ export type { DatabaseDefinition } from "./database/definition";
4
4
  export { fn } from "./server/builder";
5
5
  export { withInstanceResolvers } from "./server/instances";
6
6
  export type { QueryDatabase, MutationDatabase } from "./database/types";
7
- export type { Identity, FunctionDefinition, AppDefinition, ActionContext, FunctionKind, } from "./server/functions";
7
+ export type { EmptyFunctions, Identity, FunctionDefinition, AppDefinition, ActionContext, FunctionKind, } from "./server/functions";
8
8
  export { table, text, integer, real, boolean, eq, ne, gt, gte, lt, lte, and, or, asc, desc, count, isNull, isNotNull, inArray, } from "./database/schema";
9
9
  export { AppError } from "./errors";
10
10
  export type { ErrorCode } from "./errors";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailorkit/app",
3
- "version": "0.1.0-beta.35",
3
+ "version": "0.1.0-beta.38",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",