@trypattern/sdk 0.1.0 → 0.1.2

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 (93) hide show
  1. package/dist/api.d.ts +17 -7
  2. package/dist/api.js +34 -8
  3. package/dist/app.d.ts +12 -3
  4. package/dist/app.js +49 -7
  5. package/dist/appInfo.d.ts +35 -0
  6. package/dist/appInfo.js +67 -0
  7. package/dist/appTitle.d.ts +6 -0
  8. package/dist/appTitle.js +3 -0
  9. package/dist/auth/sessionApi.js +2 -1
  10. package/dist/builtins/AppSettings.d.ts +12 -0
  11. package/dist/builtins/AppSettings.js +31 -0
  12. package/dist/builtins/Toasts.d.ts +1 -1
  13. package/dist/builtins/Toasts.js +2 -1
  14. package/dist/cli/app.js +91 -14
  15. package/dist/cli/publishing.d.ts +21 -0
  16. package/dist/cli/publishing.js +502 -0
  17. package/dist/clock.d.ts +6 -0
  18. package/dist/clock.js +31 -0
  19. package/dist/components/AppFrame.js +3 -3
  20. package/dist/components/Button.d.ts +2 -1
  21. package/dist/components/Button.js +6 -3
  22. package/dist/components/CopyButton.d.ts +11 -0
  23. package/dist/components/CopyButton.js +16 -0
  24. package/dist/components/Divider.d.ts +2 -1
  25. package/dist/components/Divider.js +19 -4
  26. package/dist/components/IconButton.js +2 -2
  27. package/dist/components/Link.d.ts +8 -3
  28. package/dist/components/Link.js +11 -2
  29. package/dist/components/ListRow.js +2 -2
  30. package/dist/components/Menu.js +2 -2
  31. package/dist/components/RadioGroup.d.ts +18 -0
  32. package/dist/components/RadioGroup.js +85 -0
  33. package/dist/components/SegmentedControl.js +2 -2
  34. package/dist/components/Sidebar.js +2 -3
  35. package/dist/components/SignInScreen.js +3 -3
  36. package/dist/components/Switch.js +2 -1
  37. package/dist/components/controlLook.d.ts +10 -0
  38. package/dist/components/controlLook.js +14 -1
  39. package/dist/components/icons.d.ts +4 -3
  40. package/dist/components/icons.js +9 -3
  41. package/dist/components/interaction.d.ts +1 -1
  42. package/dist/flows/accessFlows.js +19 -3
  43. package/dist/flows/browser.d.ts +3 -1
  44. package/dist/flows/browser.js +6 -3
  45. package/dist/flows/flowBrowser.d.ts +3 -1
  46. package/dist/flows/flowBrowser.js +4 -2
  47. package/dist/flows/flows.d.ts +6 -0
  48. package/dist/flows/flows.js +32 -5
  49. package/dist/hooks/appContext.d.ts +2 -1
  50. package/dist/index.d.ts +6 -2
  51. package/dist/index.js +4 -2
  52. package/dist/publishWire.d.ts +271 -0
  53. package/dist/publishWire.js +168 -0
  54. package/dist/react.d.ts +3 -0
  55. package/dist/react.js +2 -0
  56. package/dist/registered.d.ts +6 -0
  57. package/dist/registered.js +2 -0
  58. package/dist/rules/checkAllFiles.js +10 -2
  59. package/dist/rules/lintPlugin.js +2 -0
  60. package/dist/rules/messages.d.ts +2 -2
  61. package/dist/rules/messages.js +2 -2
  62. package/dist/schema.d.ts +2 -0
  63. package/dist/schema.js +1 -0
  64. package/dist/server/auth.js +8 -2
  65. package/dist/server/createServer.d.ts +48 -3
  66. package/dist/server/createServer.js +25 -5
  67. package/dist/server/env.d.ts +2 -2
  68. package/dist/server/index.d.ts +6 -1
  69. package/dist/server/index.js +5 -1
  70. package/dist/server/services.d.ts +9 -0
  71. package/dist/server/services.js +47 -0
  72. package/dist/server/session.d.ts +1 -0
  73. package/dist/server/session.js +11 -0
  74. package/dist/server/settings.d.ts +49 -0
  75. package/dist/server/settings.js +25 -0
  76. package/dist/server/signInWire.d.ts +1 -0
  77. package/dist/server/signInWire.js +2 -1
  78. package/dist/serviceClients.d.ts +5 -0
  79. package/dist/serviceClients.js +70 -0
  80. package/dist/services.d.ts +53 -0
  81. package/dist/services.js +30 -0
  82. package/dist/start.js +30 -6
  83. package/dist/store.d.ts +5 -3
  84. package/dist/store.js +13 -3
  85. package/dist/table.d.ts +1 -1
  86. package/dist/vite/localWorker.d.ts +1 -1
  87. package/dist/vite/localWorker.js +5 -4
  88. package/dist/vite/projectFile.d.ts +9 -0
  89. package/dist/vite/projectFile.js +17 -0
  90. package/dist/vite/vite.d.ts +2 -1
  91. package/dist/vite/vite.js +10 -3
  92. package/package.json +5 -1
  93. package/presets/register.d.ts +2 -0
@@ -0,0 +1,53 @@
1
+ import { z } from 'zod';
2
+ import type { SameOnTheWire } from './wire.ts';
3
+ type Shape = z.ZodRawShape;
4
+ type NoShape = Record<never, never>;
5
+ type ParamNames<Path extends string> = Path extends `${string}:${infer Param}/${infer Rest}` ? Param | ParamNames<`/${Rest}`> : Path extends `${string}:${infer Param}` ? Param : never;
6
+ export type ParamsOf<Path extends string> = {
7
+ readonly [Name in ParamNames<Path>]: string;
8
+ };
9
+ export type ServiceCall<Path extends string = string, S extends Shape = Shape, Reply extends z.ZodType = z.ZodType> = {
10
+ readonly method: 'get' | 'post';
11
+ readonly path: Path;
12
+ readonly input: z.ZodObject<S>;
13
+ readonly reply: Reply;
14
+ };
15
+ type StaticTypeError<Message extends string> = Message;
16
+ type NotText = StaticTypeError<'A get call sends its input in the address, where everything is text: use z.string() or z.enum() here, or make it a post call'>;
17
+ type TextOnly<S> = {
18
+ [Key in keyof S]: S[Key] extends z.ZodType ? z.output<S[Key]> extends string | undefined ? S[Key] : NotText : S[Key];
19
+ };
20
+ type CallOptions<Path extends string, S extends Shape, Reply extends z.ZodType> = {
21
+ get: Path;
22
+ input?: TextOnly<S> & SameOnTheWire<S>;
23
+ reply: Reply;
24
+ } | {
25
+ post: Path;
26
+ input?: SameOnTheWire<S>;
27
+ reply: Reply;
28
+ };
29
+ export declare function call<Path extends string, Reply extends z.ZodType, S extends Shape = NoShape>(options: CallOptions<Path, S, Reply>): NoInfer<ServiceCall<Path, S, Reply>>;
30
+ export type Services = Readonly<Record<string, Readonly<Record<string, ServiceCall>>>>;
31
+ export declare function defineServices<const Group extends Services>(services: Group): Group;
32
+ export type CallInput<Call> = Call extends ServiceCall<infer Path, infer S, z.ZodType> ? ParamsOf<Path> & (keyof S extends never ? NoShape : z.output<z.ZodObject<S>>) : never;
33
+ export type CallReply<Call> = Call extends ServiceCall<string, Shape, infer Reply> ? z.output<Reply> : never;
34
+ type ClientCall<Call> = keyof CallInput<Call> extends never ? (input?: CallInput<Call>) => Promise<CallReply<Call>> : (input: CallInput<Call>) => Promise<CallReply<Call>>;
35
+ export type ServiceClient<Group extends Services> = {
36
+ readonly [Name in keyof Group]: {
37
+ readonly [Call in keyof Group[Name]]: ClientCall<Group[Name][Call]>;
38
+ };
39
+ };
40
+ export type MemoryHandler<Call, World> = (world: World, input: CallInput<Call>) => CallReply<Call>;
41
+ export type ServiceMemory<Group extends Services, World> = {
42
+ readonly [Name in keyof Group]: {
43
+ readonly [Call in keyof Group[Name]]: MemoryHandler<Group[Name][Call], World>;
44
+ };
45
+ };
46
+ export declare class ServiceRefused extends Error {
47
+ readonly status: number;
48
+ constructor(status: number, message: string);
49
+ }
50
+ export declare function refused(status: number, message: string): ServiceRefused;
51
+ export declare function paramNamesOf(path: string): readonly string[];
52
+ export declare function serviceCallNames(services: Services): readonly string[];
53
+ export {};
@@ -0,0 +1,30 @@
1
+ import { z } from 'zod';
2
+ export function call(options) {
3
+ const method = 'get' in options ? 'get' : 'post';
4
+ const path = 'get' in options ? options.get : options.post;
5
+ return {
6
+ method,
7
+ path,
8
+ input: z.object((options.input ?? {})),
9
+ reply: options.reply
10
+ };
11
+ }
12
+ export function defineServices(services) {
13
+ return services;
14
+ }
15
+ export class ServiceRefused extends Error {
16
+ status;
17
+ constructor(status, message) {
18
+ super(message);
19
+ this.status = status;
20
+ }
21
+ }
22
+ export function refused(status, message) {
23
+ return new ServiceRefused(status, message);
24
+ }
25
+ export function paramNamesOf(path) {
26
+ return [...path.matchAll(/:(\w+)/g)].map((match) => match[1] ?? '');
27
+ }
28
+ export function serviceCallNames(services) {
29
+ return Object.entries(services).flatMap(([group, calls]) => Object.keys(calls).map((name) => `${group}.${name}`));
30
+ }
package/dist/start.js CHANGED
@@ -8,12 +8,14 @@ import { browserApi } from "./api.js";
8
8
  import { Cache } from "./cache.js";
9
9
  import { setAppIcons } from "./components/icons.js";
10
10
  import { setInteractionSink } from "./components/interaction.js";
11
+ import { manualClock, realClock } from "./clock.js";
11
12
  import { Gate } from "./gate.js";
12
13
  import { AppProvider } from "./hooks/appContext.js";
13
14
  import { routeObjects } from "./routes.js";
14
15
  import { borders, breakpoints, colors, controls, fontFeatures, fontSizes, fontWeights, fonts, iconSizes, lineHeights, radii, shadows, space, widths } from "./theme/tokens.stylex.js";
15
16
  const TEST_SEED = 'patternSeed';
16
17
  const TEST_ADMINS = 'patternAdmins';
18
+ const TEST_WORLD = 'patternWorld';
17
19
  function testSeed() {
18
20
  const seed = Reflect.get(window, TEST_SEED);
19
21
  return typeof seed === 'object' && seed !== null ? seed : {};
@@ -32,20 +34,26 @@ export function startApp(App, { theme = [], icons = {}, onInteraction } = {}) {
32
34
  const gate = new Gate(testParams.getAll('fail'));
33
35
  for (const call of testParams.getAll('hold'))
34
36
  gate.hold(call);
35
- const { tables, routes } = App.definition;
37
+ const { tables, routes, services, memory } = App.definition;
36
38
  const inMemory = testParams.has('memory');
39
+ const world = inMemory ? (Reflect.get(window, TEST_WORLD) ?? {}) : {};
37
40
  const router = createBrowserRouter(routeObjects(routes));
38
41
  const app = new App(router, {
39
42
  api: browserApi(tables, inMemory ? testSeed() : {}, gate, {
40
43
  inMemory,
41
- admins: inMemory ? testAdmins() : []
44
+ admins: inMemory ? testAdmins() : [],
45
+ ...(services === undefined ? {} : { services }),
46
+ ...(memory === undefined ? {} : { memory }),
47
+ world
42
48
  }),
43
49
  cache: Cache.local(),
44
- gate
50
+ gate,
51
+ clock: inMemory ? manualClock() : realClock()
45
52
  });
46
53
  if (hot)
47
- exposeToDevTools(app, gate, hot);
54
+ exposeToDevTools(app, gate, hot, world);
48
55
  followAppearance(app);
56
+ followTitle(app);
49
57
  if (onInteraction !== undefined) {
50
58
  setInteractionSink((interaction) => onInteraction({
51
59
  ...interaction,
@@ -71,7 +79,17 @@ function followAppearance(app) {
71
79
  account.subscribe(apply);
72
80
  apply();
73
81
  }
74
- function exposeToDevTools(app, gate, hot) {
82
+ function followTitle(app) {
83
+ const store = app.stores.app;
84
+ const apply = () => {
85
+ const { title } = store.currentState;
86
+ if (title !== '')
87
+ document.title = title;
88
+ };
89
+ store.subscribe(apply);
90
+ apply();
91
+ }
92
+ function exposeToDevTools(app, gate, hot, world) {
75
93
  async function snapshotWhenIdle() {
76
94
  await app.whenIdle();
77
95
  return app.getSnapshot();
@@ -89,7 +107,13 @@ function exposeToDevTools(app, gate, hot) {
89
107
  send: dispatch,
90
108
  snapshot: snapshotWhenIdle,
91
109
  hold: (call) => gate.hold(call),
92
- release: (call) => gate.release(call)
110
+ release: (call) => gate.release(call),
111
+ tick: () => app.tick(),
112
+ world: (patch) => {
113
+ if (typeof world === 'object' && world !== null) {
114
+ Object.assign(world, patch);
115
+ }
116
+ }
93
117
  }
94
118
  });
95
119
  if (navigator.webdriver)
package/dist/store.d.ts CHANGED
@@ -26,13 +26,15 @@ export type StoreConfig<S extends StateSpec, P extends readonly (keyof S & strin
26
26
  state?: S;
27
27
  persist?: P;
28
28
  };
29
- export declare abstract class DeclaredStore<State extends object> extends StoreBase<State> {
29
+ export declare abstract class DeclaredStore<State extends object, Client = Record<never, never>> extends StoreBase<State> {
30
+ protected readonly services: Client;
31
+ constructor(services: Client);
30
32
  protected initialState(): State;
31
33
  }
32
- export type StoreClass<S extends StateSpec, P extends readonly (keyof S & string)[]> = (abstract new (persisted: Persisted) => DeclaredStore<StateOf<S>>) & {
34
+ export type StoreClass<S extends StateSpec, P extends readonly (keyof S & string)[], Client = Record<never, never>> = (abstract new (persisted: Persisted, services: Client) => DeclaredStore<StateOf<S>, Client>) & {
33
35
  readonly config: StoreConfig<S, P>;
34
36
  };
35
- export declare function Store<S extends StateSpec = Record<never, never>, const P extends readonly (keyof S & string)[] = []>(config: StoreConfig<S, P>): StoreClass<S, P>;
37
+ export declare function defineStore<Client>(): <S extends StateSpec = Record<never, never>, const P extends readonly (keyof S & string)[] = []>(config: StoreConfig<S, P>) => StoreClass<S, P, Client>;
36
38
  export type Snapshots<Group> = {
37
39
  [Key in keyof Group]: Group[Key] extends {
38
40
  readonly state: infer State;
package/dist/store.js CHANGED
@@ -163,17 +163,27 @@ export class StoreBase {
163
163
  }
164
164
  }
165
165
  export class DeclaredStore extends StoreBase {
166
+ services;
167
+ constructor(services) {
168
+ super();
169
+ this.services = services;
170
+ }
166
171
  initialState() {
167
172
  throw new Error(`${this.constructor.name} must extend Store({ state }) so its first state comes from the config`);
168
173
  }
169
174
  }
170
- export function Store(config) {
175
+ export function defineStore() {
176
+ return function Store(config) {
177
+ return declaredStore(config);
178
+ };
179
+ }
180
+ function declaredStore(config) {
171
181
  const persist = config.persist ?? [];
172
182
  class Declared extends DeclaredStore {
173
183
  static config = config;
174
184
  #persisted;
175
- constructor(persisted) {
176
- super();
185
+ constructor(persisted, services) {
186
+ super(services);
177
187
  this.#persisted = persisted;
178
188
  }
179
189
  initialState() {
package/dist/table.d.ts CHANGED
@@ -134,7 +134,7 @@ type CheckedColumns<C> = {
134
134
  type CheckedTable<Definition> = {
135
135
  [Key in keyof Definition]: Key extends 'columns' ? CheckedColumns<SameOnTheWire<Definition[Key] & z.ZodRawShape>> : Key extends 'access' ? CheckedAccess<Definition, Definition[Key]> : Key extends 'writes' ? HasUnique<Definition> extends true ? Definition[Key] extends 'confirmed' ? Definition[Key] : UniqueNeedsConfirmed : Definition[Key] : Key extends 'public' ? ReadOf<Definition> extends 'anyone' ? PublicNeedsPrivateRead : Definition[Key] & readonly (ColumnOf<Definition> | 'createdAt')[] : Key extends 'unique' ? Definition[Key] & readonly (readonly ColumnOf<Definition>[])[] : Definition[Key];
136
136
  } & Missing<Definition, 'access', AccessIsRequired> & Missing<Definition, 'writes', WritesIsRequired>;
137
- export declare function defineTables<const Definitions extends Record<string, DraftTable>>(definitions: {
137
+ export declare function defineTables<const Definitions extends Record<string, DraftTable> = Record<never, never>>(definitions: {
138
138
  [Key in keyof Definitions]: CheckedTable<Definitions[Key]>;
139
139
  }): TablesOf<Definitions>;
140
140
  export declare function ownerIdOf(email: string): string;
@@ -1,4 +1,4 @@
1
1
  import type { Plugin } from 'vite';
2
2
  import type { Seed, Tables } from '../table.ts';
3
3
  export declare function resetLocalDatabase(root: string, tables: Tables, seed: Seed<Tables>): void;
4
- export declare function localWorker<Group extends Tables>(tables: Group, seed: Seed<Group>): Plugin;
4
+ export declare function localWorker<Group extends Tables>(tables: Group, seed: Seed<Group>, title: string): Plugin;
@@ -2,6 +2,7 @@ import { execFileSync } from 'node:child_process';
2
2
  import { randomBytes } from 'node:crypto';
3
3
  import { appendFileSync, existsSync, readFileSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
+ import { seedTitleSql } from "../server/settings.js";
5
6
  import { seedSql } from "../server/tables.js";
6
7
  import { snakeCase } from "../table.js";
7
8
  import { toolBin } from "../cli/tools.js";
@@ -34,7 +35,7 @@ export function resetLocalDatabase(root, tables, seed) {
34
35
  ].join('\n')
35
36
  ]);
36
37
  }
37
- function prepareLocalDatabase(root, tables, seed) {
38
+ function prepareLocalDatabase(root, tables, seed, title) {
38
39
  wrangler(root, ['d1', 'migrations', 'apply', 'DB', '--local']);
39
40
  wrangler(root, [
40
41
  'd1',
@@ -42,10 +43,10 @@ function prepareLocalDatabase(root, tables, seed) {
42
43
  'DB',
43
44
  '--local',
44
45
  '--command',
45
- seedSql(tables, seed)
46
+ [seedTitleSql(title), seedSql(tables, seed)].join('\n')
46
47
  ]);
47
48
  }
48
- export function localWorker(tables, seed) {
49
+ export function localWorker(tables, seed, title) {
49
50
  return {
50
51
  name: 'pattern-local-worker',
51
52
  config(config, { command }) {
@@ -53,7 +54,7 @@ export function localWorker(tables, seed) {
53
54
  return;
54
55
  const root = config.root ?? process.cwd();
55
56
  ensureLocalSessionSecret(root);
56
- prepareLocalDatabase(root, tables, seed);
57
+ prepareLocalDatabase(root, tables, seed, title);
57
58
  }
58
59
  };
59
60
  }
@@ -0,0 +1,9 @@
1
+ import { z } from 'zod';
2
+ export declare const PROJECT_FILE = "pattern.json";
3
+ declare const projectFile: z.ZodObject<{
4
+ name: z.ZodString;
5
+ title: z.ZodString;
6
+ }, z.core.$strip>;
7
+ export type ProjectFile = z.output<typeof projectFile>;
8
+ export declare function readProjectFile(root: string): ProjectFile;
9
+ export {};
@@ -0,0 +1,17 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { z } from 'zod';
4
+ import { appTitle } from "../appTitle.js";
5
+ export const PROJECT_FILE = 'pattern.json';
6
+ const projectFile = z.object({ name: z.string().min(1), title: appTitle });
7
+ export function readProjectFile(root) {
8
+ const path = join(root, PROJECT_FILE);
9
+ if (!existsSync(path)) {
10
+ throw new Error(`${PROJECT_FILE} is missing. It holds the app's address and title: { "name": "acme", "title": "Acme" }`);
11
+ }
12
+ const parsed = projectFile.safeParse(JSON.parse(readFileSync(path, 'utf8')));
13
+ if (!parsed.success) {
14
+ throw new Error(`${PROJECT_FILE} needs "name" (the address) and "title" (1 to 60 characters): ${z.prettifyError(parsed.error)}`);
15
+ }
16
+ return parsed.data;
17
+ }
@@ -3,5 +3,6 @@ export type PatternOptions<Group extends Tables> = {
3
3
  tables: Group;
4
4
  admins: readonly string[];
5
5
  seed?: Seed<Group>;
6
+ world?: object;
6
7
  };
7
- export declare function pattern<Group extends Tables>({ tables, admins, seed }: PatternOptions<Group>): import("vite").UserConfig;
8
+ export declare function pattern<Group extends Tables>({ tables, admins, seed, world }: PatternOptions<Group>): import("vite").UserConfig;
package/dist/vite/vite.js CHANGED
@@ -8,6 +8,7 @@ import { defineConfig } from 'vitest/config';
8
8
  import { commandBridge } from "./commandBridge.js";
9
9
  import { designManifest } from "./designManifest.js";
10
10
  import { localWorker } from "./localWorker.js";
11
+ import { readProjectFile } from "./projectFile.js";
11
12
  import { rootAlias } from "./rootAlias.js";
12
13
  const DEV_SERVER_PORT = 5173;
13
14
  const VISUAL_FLOW_TIMEOUT_MS = 30_000;
@@ -25,8 +26,9 @@ const reactCompilerSkippingUnchangedRendersAndLoggingWhereItCannot = {
25
26
  compiler: { logDiagnostics: true }
26
27
  };
27
28
  const FLOW_SETUP = fileURLToPath(new URL(`../flows/flowSetup${extname(import.meta.filename)}`, import.meta.url));
28
- export function pattern({ tables, admins, seed = {} }) {
29
+ export function pattern({ tables, admins, seed = {}, world = {} }) {
29
30
  const isVitest = process.env['VITEST'] !== undefined;
31
+ const { title } = readProjectFile(process.cwd());
30
32
  const isVisualFlowRun = process.env['PATTERN_VISUAL_URL'] !== undefined;
31
33
  const stylexPlugin = stylex.vite({
32
34
  useCSSLayers: { before: CSS_LAYERS_BEFORE_STYLEX },
@@ -46,7 +48,7 @@ export function pattern({ tables, admins, seed = {} }) {
46
48
  ];
47
49
  const workerServingApiInDevAndBuild = isVitest
48
50
  ? []
49
- : [localWorker(tables, seed), cloudflare()];
51
+ : [localWorker(tables, seed, title), cloudflare()];
50
52
  return defineConfig({
51
53
  plugins: [
52
54
  ...stylexBeforeReactToKeepFastRefresh,
@@ -67,7 +69,12 @@ export function pattern({ tables, admins, seed = {} }) {
67
69
  test: {
68
70
  include: ['flows/**/*.flow.ts'],
69
71
  server: { deps: { inline: ['@trypattern/sdk'] } },
70
- provide: { patternSeed: seed, patternAdmins: admins },
72
+ provide: {
73
+ patternSeed: seed,
74
+ patternAdmins: admins,
75
+ patternTitle: title,
76
+ patternWorld: world
77
+ },
71
78
  ...(isVisualFlowRun && {
72
79
  globalSetup: [FLOW_SETUP],
73
80
  testTimeout: VISUAL_FLOW_TIMEOUT_MS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trypattern/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -26,6 +26,10 @@
26
26
  "types": "./dist/server/index.d.ts",
27
27
  "default": "./dist/server/index.js"
28
28
  },
29
+ "./publish": {
30
+ "types": "./dist/publishWire.d.ts",
31
+ "default": "./dist/publishWire.js"
32
+ },
29
33
  "./flows": {
30
34
  "types": "./dist/flows/flows.d.ts",
31
35
  "default": "./dist/flows/flows.js"
@@ -4,6 +4,7 @@ import type { tables } from '@/schema.ts'
4
4
  import type { actionGroups } from '@/src/actions/index.ts'
5
5
  import type { models } from '@/src/models/index.ts'
6
6
  import type { routes } from '@/src/routes.tsx'
7
+ import type { services } from '@/src/services/index.ts'
7
8
  import type { stores } from '@/src/stores/index.ts'
8
9
  import type { icons } from '@/src/theme/icons.ts'
9
10
 
@@ -14,6 +15,7 @@ declare module '@trypattern/sdk' {
14
15
  tables: typeof tables
15
16
  stores: typeof stores
16
17
  routes: typeof routes
18
+ services: typeof services
17
19
  icons: typeof icons
18
20
  }
19
21
  }