@trypattern/sdk 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/README.md +127 -2
  2. package/dist/access.d.ts +31 -0
  3. package/dist/access.js +72 -0
  4. package/dist/actions.d.ts +57 -0
  5. package/dist/actions.js +198 -0
  6. package/dist/api.d.ts +20 -0
  7. package/dist/api.js +34 -0
  8. package/dist/app.d.ts +106 -0
  9. package/dist/app.js +224 -0
  10. package/dist/appearance.d.ts +7 -0
  11. package/dist/appearance.js +2 -0
  12. package/dist/auth/sessionApi.d.ts +41 -0
  13. package/dist/auth/sessionApi.js +158 -0
  14. package/dist/auth/sessionStore.d.ts +20 -0
  15. package/dist/auth/sessionStore.js +40 -0
  16. package/dist/auth/user.d.ts +11 -0
  17. package/dist/auth/user.js +9 -0
  18. package/dist/builtins/Account.d.ts +25 -0
  19. package/dist/builtins/Account.js +15 -0
  20. package/dist/builtins/Palette.d.ts +29 -0
  21. package/dist/builtins/Palette.js +63 -0
  22. package/dist/builtins/SignIn.d.ts +28 -0
  23. package/dist/builtins/SignIn.js +60 -0
  24. package/dist/builtins/Toasts.d.ts +32 -0
  25. package/dist/builtins/Toasts.js +24 -0
  26. package/dist/builtins/actions.d.ts +2 -0
  27. package/dist/builtins/actions.js +45 -0
  28. package/dist/cache.d.ts +24 -0
  29. package/dist/cache.js +112 -0
  30. package/dist/cli/app.d.ts +2 -0
  31. package/dist/cli/app.js +1329 -0
  32. package/dist/cli/screenshot.d.ts +1 -0
  33. package/dist/cli/screenshot.js +96 -0
  34. package/dist/cli/tools.d.ts +12 -0
  35. package/dist/cli/tools.js +35 -0
  36. package/dist/components/AppFrame.d.ts +14 -0
  37. package/dist/components/AppFrame.js +64 -0
  38. package/dist/components/AppearancePicker.d.ts +1 -0
  39. package/dist/components/AppearancePicker.js +12 -0
  40. package/dist/components/Avatar.d.ts +9 -0
  41. package/dist/components/Avatar.js +63 -0
  42. package/dist/components/Badge.d.ts +11 -0
  43. package/dist/components/Badge.js +87 -0
  44. package/dist/components/Button.d.ts +23 -0
  45. package/dist/components/Button.js +249 -0
  46. package/dist/components/Card.d.ts +12 -0
  47. package/dist/components/Card.js +38 -0
  48. package/dist/components/CommandMenu.d.ts +23 -0
  49. package/dist/components/CommandMenu.js +214 -0
  50. package/dist/components/CommandPalette.d.ts +1 -0
  51. package/dist/components/CommandPalette.js +7 -0
  52. package/dist/components/Content.d.ts +7 -0
  53. package/dist/components/Content.js +24 -0
  54. package/dist/components/ContextMenu.d.ts +8 -0
  55. package/dist/components/ContextMenu.js +23 -0
  56. package/dist/components/Dialog.d.ts +11 -0
  57. package/dist/components/Dialog.js +81 -0
  58. package/dist/components/Divider.d.ts +6 -0
  59. package/dist/components/Divider.js +15 -0
  60. package/dist/components/EmptyState.d.ts +8 -0
  61. package/dist/components/EmptyState.js +24 -0
  62. package/dist/components/Form.d.ts +9 -0
  63. package/dist/components/Form.js +23 -0
  64. package/dist/components/Icon.d.ts +10 -0
  65. package/dist/components/Icon.js +22 -0
  66. package/dist/components/IconButton.d.ts +14 -0
  67. package/dist/components/IconButton.js +53 -0
  68. package/dist/components/Kbd.d.ts +6 -0
  69. package/dist/components/Kbd.js +67 -0
  70. package/dist/components/Link.d.ts +9 -0
  71. package/dist/components/Link.js +35 -0
  72. package/dist/components/ListRow.d.ts +12 -0
  73. package/dist/components/ListRow.js +62 -0
  74. package/dist/components/LoadingRows.d.ts +5 -0
  75. package/dist/components/LoadingRows.js +6 -0
  76. package/dist/components/Menu.d.ts +12 -0
  77. package/dist/components/Menu.js +33 -0
  78. package/dist/components/MenuItems.d.ts +21 -0
  79. package/dist/components/MenuItems.js +32 -0
  80. package/dist/components/Placement.d.ts +21 -0
  81. package/dist/components/Placement.js +1 -0
  82. package/dist/components/Popup.d.ts +8 -0
  83. package/dist/components/Popup.js +43 -0
  84. package/dist/components/PopupItem.d.ts +8 -0
  85. package/dist/components/PopupItem.js +51 -0
  86. package/dist/components/PropertyRow.d.ts +7 -0
  87. package/dist/components/PropertyRow.js +23 -0
  88. package/dist/components/Row.d.ts +16 -0
  89. package/dist/components/Row.js +27 -0
  90. package/dist/components/Screen.d.ts +13 -0
  91. package/dist/components/Screen.js +56 -0
  92. package/dist/components/Scrim.d.ts +8 -0
  93. package/dist/components/Scrim.js +40 -0
  94. package/dist/components/ScrollArea.d.ts +15 -0
  95. package/dist/components/ScrollArea.js +13 -0
  96. package/dist/components/SegmentedControl.d.ts +17 -0
  97. package/dist/components/SegmentedControl.js +68 -0
  98. package/dist/components/Select.d.ts +17 -0
  99. package/dist/components/Select.js +107 -0
  100. package/dist/components/SettingsRow.d.ts +8 -0
  101. package/dist/components/SettingsRow.js +32 -0
  102. package/dist/components/Sidebar.d.ts +20 -0
  103. package/dist/components/Sidebar.js +138 -0
  104. package/dist/components/SignInScreen.d.ts +1 -0
  105. package/dist/components/SignInScreen.js +40 -0
  106. package/dist/components/Size.d.ts +1 -0
  107. package/dist/components/Size.js +1 -0
  108. package/dist/components/Skeleton.d.ts +8 -0
  109. package/dist/components/Skeleton.js +48 -0
  110. package/dist/components/Spinner.d.ts +6 -0
  111. package/dist/components/Spinner.js +54 -0
  112. package/dist/components/Stack.d.ts +14 -0
  113. package/dist/components/Stack.js +19 -0
  114. package/dist/components/Switch.d.ts +10 -0
  115. package/dist/components/Switch.js +71 -0
  116. package/dist/components/Text.d.ts +21 -0
  117. package/dist/components/Text.js +77 -0
  118. package/dist/components/TextField.d.ts +25 -0
  119. package/dist/components/TextField.js +68 -0
  120. package/dist/components/Toaster.d.ts +1 -0
  121. package/dist/components/Toaster.js +83 -0
  122. package/dist/components/Tooltip.d.ts +8 -0
  123. package/dist/components/Tooltip.js +43 -0
  124. package/dist/components/controlLook.d.ts +60 -0
  125. package/dist/components/controlLook.js +67 -0
  126. package/dist/components/frame.d.ts +4 -0
  127. package/dist/components/frame.js +2 -0
  128. package/dist/components/icons.d.ts +58 -0
  129. package/dist/components/icons.js +105 -0
  130. package/dist/components/interaction.d.ts +12 -0
  131. package/dist/components/interaction.js +22 -0
  132. package/dist/components/spacing.d.ts +118 -0
  133. package/dist/components/spacing.js +46 -0
  134. package/dist/components/tones.d.ts +28 -0
  135. package/dist/components/tones.js +12 -0
  136. package/dist/entityStore.d.ts +46 -0
  137. package/dist/entityStore.js +160 -0
  138. package/dist/flows/accessFlows.d.ts +9 -0
  139. package/dist/flows/accessFlows.js +151 -0
  140. package/dist/flows/browser.d.ts +32 -0
  141. package/dist/flows/browser.js +164 -0
  142. package/dist/flows/contactSheet.d.ts +1 -0
  143. package/dist/flows/contactSheet.js +63 -0
  144. package/dist/flows/flowBrowser.d.ts +23 -0
  145. package/dist/flows/flowBrowser.js +21 -0
  146. package/dist/flows/flowSetup.d.ts +3 -0
  147. package/dist/flows/flowSetup.js +35 -0
  148. package/dist/flows/flows.d.ts +41 -0
  149. package/dist/flows/flows.js +148 -0
  150. package/dist/flows/screenshotName.d.ts +1 -0
  151. package/dist/flows/screenshotName.js +6 -0
  152. package/dist/gate.d.ts +8 -0
  153. package/dist/gate.js +52 -0
  154. package/dist/hooks/appContext.d.ts +14 -0
  155. package/dist/hooks/appContext.js +5 -0
  156. package/dist/hooks/appHooks.d.ts +21 -0
  157. package/dist/hooks/appHooks.js +24 -0
  158. package/dist/hooks/useAnimatesOnChange.d.ts +1 -0
  159. package/dist/hooks/useAnimatesOnChange.js +14 -0
  160. package/dist/hooks/useStoreState.d.ts +6 -0
  161. package/dist/hooks/useStoreState.js +5 -0
  162. package/dist/index.d.ts +40 -0
  163. package/dist/index.js +19 -0
  164. package/dist/memoryApi.d.ts +19 -0
  165. package/dist/memoryApi.js +42 -0
  166. package/dist/model.d.ts +94 -0
  167. package/dist/model.js +243 -0
  168. package/dist/page.d.ts +11 -0
  169. package/dist/page.js +9 -0
  170. package/dist/platform.d.ts +1 -0
  171. package/dist/platform.js +5 -0
  172. package/dist/react.d.ts +46 -0
  173. package/dist/react.js +38 -0
  174. package/dist/registered.d.ts +54 -0
  175. package/dist/registered.js +17 -0
  176. package/dist/routes.d.ts +38 -0
  177. package/dist/routes.js +21 -0
  178. package/dist/rules/checkAllFiles.d.ts +1 -0
  179. package/dist/rules/checkAllFiles.js +741 -0
  180. package/dist/rules/checkApiRouting.d.ts +1 -0
  181. package/dist/rules/checkApiRouting.js +112 -0
  182. package/dist/rules/lintPlugin.d.ts +252 -0
  183. package/dist/rules/lintPlugin.js +1157 -0
  184. package/dist/rules/messages.d.ts +48 -0
  185. package/dist/rules/messages.js +48 -0
  186. package/dist/rules/themeTokens.d.ts +6 -0
  187. package/dist/rules/themeTokens.js +64 -0
  188. package/dist/schema.d.ts +2 -0
  189. package/dist/schema.js +1 -0
  190. package/dist/server/auth.d.ts +115 -0
  191. package/dist/server/auth.js +131 -0
  192. package/dist/server/authService.d.ts +9 -0
  193. package/dist/server/authService.js +50 -0
  194. package/dist/server/createServer.d.ts +357 -0
  195. package/dist/server/createServer.js +62 -0
  196. package/dist/server/env.d.ts +15 -0
  197. package/dist/server/env.js +1 -0
  198. package/dist/server/index.d.ts +8 -0
  199. package/dist/server/index.js +5 -0
  200. package/dist/server/session.d.ts +28 -0
  201. package/dist/server/session.js +54 -0
  202. package/dist/server/sessions.d.ts +92 -0
  203. package/dist/server/sessions.js +47 -0
  204. package/dist/server/signInWire.d.ts +52 -0
  205. package/dist/server/signInWire.js +22 -0
  206. package/dist/server/tables.d.ts +242 -0
  207. package/dist/server/tables.js +246 -0
  208. package/dist/server/users.d.ts +189 -0
  209. package/dist/server/users.js +49 -0
  210. package/dist/shortcuts.d.ts +3 -0
  211. package/dist/shortcuts.js +40 -0
  212. package/dist/start.d.ts +20 -0
  213. package/dist/start.js +121 -0
  214. package/dist/state.d.ts +14 -0
  215. package/dist/state.js +17 -0
  216. package/dist/store.d.ts +43 -0
  217. package/dist/store.js +198 -0
  218. package/dist/subscribers.d.ts +5 -0
  219. package/dist/subscribers.js +13 -0
  220. package/dist/table.d.ts +143 -0
  221. package/dist/table.js +91 -0
  222. package/dist/tables.d.ts +77 -0
  223. package/dist/tables.js +216 -0
  224. package/dist/theme/reset.css +84 -0
  225. package/dist/theme/scales.d.ts +76 -0
  226. package/dist/theme/scales.js +82 -0
  227. package/dist/theme/tokens.stylex.d.ts +218 -0
  228. package/dist/theme/tokens.stylex.js +233 -0
  229. package/dist/vite/commandBridge.d.ts +2 -0
  230. package/dist/vite/commandBridge.js +46 -0
  231. package/dist/vite/designManifest.d.ts +25 -0
  232. package/dist/vite/designManifest.js +191 -0
  233. package/dist/vite/localWorker.d.ts +4 -0
  234. package/dist/vite/localWorker.js +59 -0
  235. package/dist/vite/rootAlias.d.ts +2 -0
  236. package/dist/vite/rootAlias.js +15 -0
  237. package/dist/vite/vite.d.ts +7 -0
  238. package/dist/vite/vite.js +88 -0
  239. package/dist/wire.d.ts +7 -0
  240. package/dist/wire.js +1 -0
  241. package/package.json +99 -3
  242. package/presets/lintPlugin.js +7 -0
  243. package/presets/oxlint.json +167 -0
  244. package/presets/register.d.ts +19 -0
  245. package/presets/server.d.ts +2 -0
  246. package/presets/tsconfig.app.json +29 -0
  247. package/presets/tsconfig.server.json +27 -0
@@ -0,0 +1,94 @@
1
+ import { z } from 'zod';
2
+ import { StoreBase } from './store.ts';
3
+ import type { Persisted, StateOf, StateSpec } from './state.ts';
4
+ import type { SameOnTheWire } from './wire.ts';
5
+ type Shape = z.ZodRawShape;
6
+ type NoInput = Record<never, never>;
7
+ export type InputOf<S extends Shape> = keyof S extends never ? NoInput : z.output<z.ZodObject<S>>;
8
+ export type CommandResult = void | Promise<void>;
9
+ type Handler<S extends Shape, Result> = keyof S extends never ? () => Result : (input: InputOf<S>) => Result;
10
+ export type RouteParams = Readonly<Record<string, string | undefined>>;
11
+ declare const INPUT: unique symbol;
12
+ export type Command<S extends Shape, Result extends CommandResult> = Handler<S, Result> & {
13
+ readonly [INPUT]: z.ZodObject<S>;
14
+ };
15
+ type AnyCommand = {
16
+ readonly [INPUT]: z.ZodType;
17
+ };
18
+ export type CommandOptions<S extends Shape> = {
19
+ input: SameOnTheWire<S>;
20
+ };
21
+ export declare function command<Result extends CommandResult>(run: () => Result): Command<NoInput, Result>;
22
+ export declare function command<S extends Shape, Result extends CommandResult>(options: CommandOptions<S>, run: (input: InputOf<S>) => Result): Command<S, Result>;
23
+ export declare function commandFromSchema(schema: z.ZodType, run: (input: never) => CommandResult): AnyCommand;
24
+ export declare function commandsOf(model: object): Record<string, z.ZodType>;
25
+ export declare function answerNamesOf(model: object): readonly string[];
26
+ export declare abstract class ModelBase<State extends object, Stores, Services> extends StoreBase<State> {
27
+ #private;
28
+ protected readonly stores: Stores;
29
+ protected readonly app: Services;
30
+ constructor(stores: Stores, app: Services);
31
+ onPageOpen(_params: RouteParams): void | Promise<void>;
32
+ protected get params(): RouteParams;
33
+ protected initialState(): State;
34
+ get snapshot(): object;
35
+ get published(): object;
36
+ protected changed(): void;
37
+ }
38
+ type BaseMember = keyof ModelBase<object, unknown, unknown>;
39
+ export type DerivedOf<Model> = {
40
+ readonly [Key in keyof Model as Key extends BaseMember ? never : Model[Key] extends (...args: never[]) => unknown ? never : Key]: Model[Key];
41
+ };
42
+ export type SnapshotOf<Model> = Model extends {
43
+ readonly state: infer State;
44
+ } ? Readonly<State> & DerivedOf<Model> : never;
45
+ type Fired<Command> = Command extends (...args: infer Input) => unknown ? (...args: Input) => void : never;
46
+ export type PublishedCommands<Model> = {
47
+ readonly [Key in CommandKeys<Model>]: Fired<Model[Key]>;
48
+ };
49
+ export type PublishedOf<Model> = SnapshotOf<Model> & PublishedCommands<Model>;
50
+ export type ModelSnapshots<Models> = {
51
+ [Key in keyof Models]: SnapshotOf<Models[Key]>;
52
+ };
53
+ export declare function modelSnapshotsOf<Models extends Record<string, {
54
+ readonly snapshot: object;
55
+ }>>(models: Models): ModelSnapshots<Models>;
56
+ export type ModelConfig<S extends StateSpec, P extends readonly (keyof S & string)[]> = {
57
+ state?: S;
58
+ persist?: P;
59
+ };
60
+ export type ModelClass<Registry, Services, S extends StateSpec, P extends readonly (keyof S & string)[]> = (abstract new (stores: Registry, app: Services, device: Persisted) => ModelBase<StateOf<S>, Registry, Services>) & {
61
+ readonly config: ModelConfig<S, P>;
62
+ };
63
+ export declare function defineModel<Registry, Services>(): <S extends StateSpec = Record<never, never>, const P extends readonly (keyof S & string)[] = []>(config?: ModelConfig<S, P>) => ModelClass<Registry, Services, S, P>;
64
+ export type AnyModel = ModelBase<object, unknown, unknown>;
65
+ export type ModelClassLike = new (stores: never, app: never, device: Persisted) => AnyModel;
66
+ export type Instances<Classes extends Record<string, ModelClassLike>> = {
67
+ [Key in keyof Classes]: InstanceType<Classes[Key]>;
68
+ };
69
+ export declare function createModels<Classes extends Record<string, ModelClassLike>>(classes: Classes, stores: object, services: object, persistedFor: (model: string) => Persisted): Instances<Classes>;
70
+ export type CommandKeys<Model> = {
71
+ [Key in keyof Model]: Model[Key] extends AnyCommand ? Key : never;
72
+ }[keyof Model];
73
+ type ShapeOf<Value> = Value extends {
74
+ readonly [INPUT]: z.ZodObject<infer S>;
75
+ } ? S : never;
76
+ export type MessagesOf<Models extends Record<string, object>> = {
77
+ [Group in keyof Models & string]: {
78
+ [Name in CommandKeys<Models[Group]> & string]: {
79
+ type: `${Group}.${Name}`;
80
+ } & InputOf<ShapeOf<Models[Group][Name]>>;
81
+ }[CommandKeys<Models[Group]> & string];
82
+ }[keyof Models & string];
83
+ export type Message = {
84
+ readonly type: string;
85
+ };
86
+ export declare function splitType(type: string): {
87
+ group: string;
88
+ name: string;
89
+ };
90
+ export declare function parseMessage<Parsed extends Message>(raw: unknown, models: Readonly<Record<string, object>>): Parsed | {
91
+ error: string;
92
+ };
93
+ export declare function sendMessage(models: Readonly<Record<string, object>>, { type, ...input }: Message): Promise<void>;
94
+ export {};
package/dist/model.js ADDED
@@ -0,0 +1,243 @@
1
+ var _a;
2
+ import { z } from 'zod';
3
+ import { PageStore } from "./page.js";
4
+ import { StoreBase, isDevelopment, keepEqualParts, mergeReads, plainJsonProblem, readsAreCurrent, tracked, whileBuilding } from "./store.js";
5
+ import { restore } from "./state.js";
6
+ const INPUT = Symbol('pattern.commandInput');
7
+ export function command(first, second) {
8
+ const run = typeof first === 'function' ? first : second;
9
+ if (typeof run !== 'function')
10
+ throw new Error('command() needs a handler');
11
+ const options = typeof first === 'function' ? {} : first;
12
+ const shape = typeof options === 'object' && options !== null
13
+ ? Reflect.get(options, 'input')
14
+ : undefined;
15
+ return Object.assign((input) => run(input), {
16
+ [INPUT]: z.object((shape ?? {}))
17
+ });
18
+ }
19
+ export function commandFromSchema(schema, run) {
20
+ return Object.assign((input) => run(input), {
21
+ [INPUT]: schema
22
+ });
23
+ }
24
+ function isCommand(value) {
25
+ return typeof value === 'function' && INPUT in value;
26
+ }
27
+ export function commandsOf(model) {
28
+ const found = {};
29
+ for (const [name, value] of Object.entries(model)) {
30
+ if (isCommand(value))
31
+ found[name] = value[INPUT];
32
+ }
33
+ return found;
34
+ }
35
+ function sameEntries(previous, next) {
36
+ const previousKeys = Object.keys(previous);
37
+ const nextKeys = Object.keys(next);
38
+ return (previousKeys.length === nextKeys.length &&
39
+ nextKeys.every((key) => Object.is(Reflect.get(previous, key), Reflect.get(next, key))));
40
+ }
41
+ const answerNames = new WeakMap();
42
+ export function answerNamesOf(model) {
43
+ return answerNames.get(model) ?? [];
44
+ }
45
+ function getterOf(instance, name) {
46
+ let prototype = Object.getPrototypeOf(instance);
47
+ while (prototype !== null) {
48
+ const getter = Object.getOwnPropertyDescriptor(prototype, name)?.get;
49
+ if (getter !== undefined)
50
+ return getter;
51
+ prototype = Object.getPrototypeOf(prototype);
52
+ }
53
+ return undefined;
54
+ }
55
+ export class ModelBase extends StoreBase {
56
+ stores;
57
+ app;
58
+ #memos = new Map();
59
+ #snapshot;
60
+ #published;
61
+ #isDirty = true;
62
+ constructor(stores, app) {
63
+ super();
64
+ this.stores = stores;
65
+ this.app = app;
66
+ const answers = this.#derived();
67
+ answerNames.set(this, answers);
68
+ for (const derived of answers) {
69
+ const compute = getterOf(this, derived);
70
+ if (compute === undefined)
71
+ continue;
72
+ Object.defineProperty(this, derived, {
73
+ configurable: true,
74
+ enumerable: false,
75
+ get: () => this.#evaluate(derived, compute)
76
+ });
77
+ }
78
+ for (const store of Object.values(stores)) {
79
+ store.subscribe(() => this.changed());
80
+ }
81
+ }
82
+ onPageOpen(_params) {
83
+ return undefined;
84
+ }
85
+ get params() {
86
+ const page = Reflect.get(this.stores, 'page');
87
+ return page instanceof PageStore ? page.state.params : {};
88
+ }
89
+ initialState() {
90
+ throw new Error(`${this.constructor.name} must extend Model({ state }) so its first state comes from the config`);
91
+ }
92
+ get snapshot() {
93
+ if (this.#snapshot === undefined || this.#isDirty) {
94
+ const next = this.#buildSnapshot();
95
+ const kept = this.#snapshot !== undefined && sameEntries(this.#snapshot, next)
96
+ ? this.#snapshot
97
+ : next;
98
+ if (kept !== this.#snapshot)
99
+ this.#published = undefined;
100
+ this.#snapshot = kept;
101
+ this.#isDirty = false;
102
+ }
103
+ return this.#snapshot;
104
+ }
105
+ get published() {
106
+ const snapshot = this.snapshot;
107
+ this.#published ??= this.#buildPublished(snapshot);
108
+ return this.#published;
109
+ }
110
+ changed() {
111
+ this.#isDirty = true;
112
+ const previous = this.#snapshot;
113
+ if (this.snapshot === previous)
114
+ return;
115
+ super.changed();
116
+ }
117
+ #evaluate(name, compute) {
118
+ const memo = this.#memos.get(name);
119
+ if (memo !== undefined && readsAreCurrent(memo.reads)) {
120
+ mergeReads(memo.reads);
121
+ return memo.value;
122
+ }
123
+ const { value, reads } = whileBuilding(() => tracked(() => compute.call(this)));
124
+ if (isDevelopment()) {
125
+ this.#checkPure(name, compute, value);
126
+ const problem = plainJsonProblem(value, `${name}`);
127
+ if (problem !== undefined) {
128
+ throw new Error(`${this.constructor.name} must publish plain JSON from its getters, because flows compare it: ${problem}`);
129
+ }
130
+ }
131
+ const kept = memo === undefined ? value : keepEqualParts(memo.value, value);
132
+ this.#memos.set(name, { value: kept, reads });
133
+ mergeReads(reads);
134
+ return kept;
135
+ }
136
+ #checkPure(name, compute, value) {
137
+ const again = whileBuilding(() => tracked(() => compute.call(this)).value);
138
+ if (JSON.stringify(value) !== JSON.stringify(again)) {
139
+ throw new Error(`${this.constructor.name}.${name} gave two different answers for the same state and stores, so it is not a pure getter. Getters must not read the clock, randomness or a private field.`);
140
+ }
141
+ }
142
+ #buildSnapshot() {
143
+ const snapshot = {
144
+ ...this.currentState
145
+ };
146
+ for (const name of this.#derived()) {
147
+ snapshot[name] = Reflect.get(this, name);
148
+ }
149
+ return snapshot;
150
+ }
151
+ #buildPublished(snapshot) {
152
+ const published = { ...snapshot };
153
+ for (const [name, value] of Object.entries(this)) {
154
+ if (isCommand(value))
155
+ published[name] = value;
156
+ }
157
+ return Object.freeze(published);
158
+ }
159
+ #derived() {
160
+ const names = [];
161
+ let prototype = Object.getPrototypeOf(this);
162
+ while (prototype !== null && prototype !== _a.prototype) {
163
+ for (const [name, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(prototype))) {
164
+ if (descriptor.get !== undefined && !names.includes(name)) {
165
+ names.push(name);
166
+ }
167
+ }
168
+ prototype = Object.getPrototypeOf(prototype);
169
+ }
170
+ return names;
171
+ }
172
+ }
173
+ _a = ModelBase;
174
+ export function modelSnapshotsOf(models) {
175
+ return Object.fromEntries(Object.entries(models).map(([key, model]) => [key, model.snapshot]));
176
+ }
177
+ export function defineModel() {
178
+ return function Model(config = {}) {
179
+ const persist = config.persist ?? [];
180
+ class Bound extends ModelBase {
181
+ static config = config;
182
+ #device;
183
+ constructor(stores, app, device) {
184
+ super(stores, app);
185
+ this.#device = device;
186
+ }
187
+ initialState() {
188
+ return restore(config.state ?? {}, persist, this.#device);
189
+ }
190
+ set(patch) {
191
+ super.set(patch);
192
+ for (const key of persist) {
193
+ if (key in patch)
194
+ this.#device.write(key, this.state[key]);
195
+ }
196
+ }
197
+ }
198
+ return Bound;
199
+ };
200
+ }
201
+ export function createModels(classes, stores, services, persistedFor) {
202
+ const entries = Object.entries(classes).map(([key, Class]) => {
203
+ const create = Class;
204
+ return [key, new create(stores, services, persistedFor(key))];
205
+ });
206
+ return Object.fromEntries(entries);
207
+ }
208
+ export function splitType(type) {
209
+ const dot = type.indexOf('.');
210
+ return dot === -1
211
+ ? { group: '', name: type }
212
+ : { group: type.slice(0, dot), name: type.slice(dot + 1) };
213
+ }
214
+ export function parseMessage(raw, models) {
215
+ const specs = Object.entries(models).map(([group, model]) => [group, commandsOf(model)]);
216
+ const known = specs.flatMap(([group, spec]) => Object.keys(spec).map((name) => `${group}.${name}`));
217
+ const unknown = `Unknown command ${JSON.stringify(raw)}. Commands: ${known.join(', ')}`;
218
+ if (typeof raw !== 'object' || raw === null || !('type' in raw)) {
219
+ return { error: unknown };
220
+ }
221
+ const { type, ...input } = raw;
222
+ if (typeof type !== 'string')
223
+ return { error: unknown };
224
+ const { group, name } = splitType(type);
225
+ const schema = specs.find(([key]) => key === group)?.[1][name];
226
+ if (schema === undefined)
227
+ return { error: unknown };
228
+ const parsed = schema.safeParse(input);
229
+ if (!parsed.success) {
230
+ return { error: `Command ${type}: ${z.prettifyError(parsed.error)}` };
231
+ }
232
+ return { type, ...parsed.data };
233
+ }
234
+ export function sendMessage(models, { type, ...input }) {
235
+ const { group, name } = splitType(type);
236
+ const model = models[group];
237
+ const target = model === undefined ? undefined : Reflect.get(model, name);
238
+ if (!isCommand(target)) {
239
+ return Promise.reject(new Error(`Unknown command ${type}`));
240
+ }
241
+ const run = target;
242
+ return Promise.resolve(run(input));
243
+ }
package/dist/page.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import type { RouteParams } from './model.ts';
2
+ import { StoreBase } from './store.ts';
3
+ type PageState = {
4
+ page: string | null;
5
+ params: RouteParams;
6
+ };
7
+ export declare class PageStore extends StoreBase<PageState> {
8
+ protected initialState(): PageState;
9
+ moved(page: string | null, params: RouteParams): void;
10
+ }
11
+ export {};
package/dist/page.js ADDED
@@ -0,0 +1,9 @@
1
+ import { StoreBase } from "./store.js";
2
+ export class PageStore extends StoreBase {
3
+ initialState() {
4
+ return { page: null, params: {} };
5
+ }
6
+ moved(page, params) {
7
+ this.set({ page, params });
8
+ }
9
+ }
@@ -0,0 +1 @@
1
+ export declare function isApplePlatform(): boolean;
@@ -0,0 +1,5 @@
1
+ export function isApplePlatform() {
2
+ if (typeof navigator === 'undefined')
3
+ return false;
4
+ return /Mac|iPhone|iPad/.test(navigator.userAgent);
5
+ }
@@ -0,0 +1,46 @@
1
+ export { AppProvider, useModel } from './hooks/appContext.ts';
2
+ export { AppFrame } from './components/AppFrame.tsx';
3
+ export { AppearancePicker } from './components/AppearancePicker.tsx';
4
+ export { Avatar } from './components/Avatar.tsx';
5
+ export { Badge } from './components/Badge.tsx';
6
+ export { Button } from './components/Button.tsx';
7
+ export { Card } from './components/Card.tsx';
8
+ export { CommandMenu } from './components/CommandMenu.tsx';
9
+ export { CommandPalette } from './components/CommandPalette.tsx';
10
+ export type { CommandMenuItem } from './components/CommandMenu.tsx';
11
+ export { Content } from './components/Content.tsx';
12
+ export { ContextMenu } from './components/ContextMenu.tsx';
13
+ export { Dialog } from './components/Dialog.tsx';
14
+ export { Divider } from './components/Divider.tsx';
15
+ export { EmptyState } from './components/EmptyState.tsx';
16
+ export { Form } from './components/Form.tsx';
17
+ export { Icon } from './components/Icon.tsx';
18
+ export { IconButton } from './components/IconButton.tsx';
19
+ export type { IconName } from './components/icons.ts';
20
+ export { Kbd } from './components/Kbd.tsx';
21
+ export { Link } from './components/Link.tsx';
22
+ export { ListRow } from './components/ListRow.tsx';
23
+ export { LoadingRows } from './components/LoadingRows.tsx';
24
+ export { Menu } from './components/Menu.tsx';
25
+ export type { MenuEntry } from './components/MenuItems.tsx';
26
+ export type { SidebarLink } from './components/Sidebar.tsx';
27
+ export type { Placement } from './components/Placement.ts';
28
+ export { PropertyRow } from './components/PropertyRow.tsx';
29
+ export { Row } from './components/Row.tsx';
30
+ export { Screen } from './components/Screen.tsx';
31
+ export { ScrollArea } from './components/ScrollArea.tsx';
32
+ export { SegmentedControl } from './components/SegmentedControl.tsx';
33
+ export type { SegmentedOption } from './components/SegmentedControl.tsx';
34
+ export { Select } from './components/Select.tsx';
35
+ export type { SelectOption } from './components/Select.tsx';
36
+ export { SettingsRow } from './components/SettingsRow.tsx';
37
+ export { SignInScreen } from './components/SignInScreen.tsx';
38
+ export { Skeleton } from './components/Skeleton.tsx';
39
+ export type { SpaceName } from './components/spacing.ts';
40
+ export { Spinner } from './components/Spinner.tsx';
41
+ export { Stack } from './components/Stack.tsx';
42
+ export { Switch } from './components/Switch.tsx';
43
+ export { Text } from './components/Text.tsx';
44
+ export { TextField } from './components/TextField.tsx';
45
+ export { Toaster } from './components/Toaster.tsx';
46
+ export { Tooltip } from './components/Tooltip.tsx';
package/dist/react.js ADDED
@@ -0,0 +1,38 @@
1
+ export { AppProvider, useModel } from "./hooks/appContext.js";
2
+ export { AppFrame } from "./components/AppFrame.js";
3
+ export { AppearancePicker } from "./components/AppearancePicker.js";
4
+ export { Avatar } from "./components/Avatar.js";
5
+ export { Badge } from "./components/Badge.js";
6
+ export { Button } from "./components/Button.js";
7
+ export { Card } from "./components/Card.js";
8
+ export { CommandMenu } from "./components/CommandMenu.js";
9
+ export { CommandPalette } from "./components/CommandPalette.js";
10
+ export { Content } from "./components/Content.js";
11
+ export { ContextMenu } from "./components/ContextMenu.js";
12
+ export { Dialog } from "./components/Dialog.js";
13
+ export { Divider } from "./components/Divider.js";
14
+ export { EmptyState } from "./components/EmptyState.js";
15
+ export { Form } from "./components/Form.js";
16
+ export { Icon } from "./components/Icon.js";
17
+ export { IconButton } from "./components/IconButton.js";
18
+ export { Kbd } from "./components/Kbd.js";
19
+ export { Link } from "./components/Link.js";
20
+ export { ListRow } from "./components/ListRow.js";
21
+ export { LoadingRows } from "./components/LoadingRows.js";
22
+ export { Menu } from "./components/Menu.js";
23
+ export { PropertyRow } from "./components/PropertyRow.js";
24
+ export { Row } from "./components/Row.js";
25
+ export { Screen } from "./components/Screen.js";
26
+ export { ScrollArea } from "./components/ScrollArea.js";
27
+ export { SegmentedControl } from "./components/SegmentedControl.js";
28
+ export { Select } from "./components/Select.js";
29
+ export { SettingsRow } from "./components/SettingsRow.js";
30
+ export { SignInScreen } from "./components/SignInScreen.js";
31
+ export { Skeleton } from "./components/Skeleton.js";
32
+ export { Spinner } from "./components/Spinner.js";
33
+ export { Stack } from "./components/Stack.js";
34
+ export { Switch } from "./components/Switch.js";
35
+ export { Text } from "./components/Text.js";
36
+ export { TextField } from "./components/TextField.js";
37
+ export { Toaster } from "./components/Toaster.js";
38
+ export { Tooltip } from "./components/Tooltip.js";
@@ -0,0 +1,54 @@
1
+ import type { AppSnapshotShape, ModelServicesOf, NavigateCommand, PressKeyCommand, StoreClasses, StoreInstances, StoresOf } from './app.ts';
2
+ import { z } from 'zod';
3
+ import type { Action, DefineActions } from './actions.ts';
4
+ import type { Instances, MessagesOf, ModelClassLike, ModelSnapshots } from './model.ts';
5
+ import type { BUILT_IN_GROUPS } from './builtins/actions.ts';
6
+ import type { Account } from './builtins/Account.ts';
7
+ import type { Palette } from './builtins/Palette.ts';
8
+ import type { SignIn } from './builtins/SignIn.ts';
9
+ import type { IconName } from './components/icons.ts';
10
+ import type { PageOf, PathOf, RouteShape } from './routes.ts';
11
+ import type { Tables } from './table.ts';
12
+ export interface Register {
13
+ }
14
+ type Registered<Key extends string, Fallback> = Key extends keyof Register ? Register[Key] : Fallback;
15
+ type Empty = Record<never, never>;
16
+ type RegisteredModels = Registered<'models', Empty> extends infer Classes extends Record<string, ModelClassLike> ? Classes : Empty;
17
+ type RegisteredTables = Registered<'tables', Empty> extends infer Group extends Tables ? Group : Empty;
18
+ type RegisteredStores = Registered<'stores', Empty> extends infer Classes extends StoreClasses ? Classes : Empty;
19
+ type RegisteredActionGroups = Registered<'actionGroups', readonly string[]> extends infer Groups extends readonly string[] ? Groups : readonly string[];
20
+ export type AppActionGroup = RegisteredActionGroups[number] | (typeof BUILT_IN_GROUPS)[number];
21
+ export type AppAction = Action & {
22
+ group: AppActionGroup;
23
+ icon: IconName;
24
+ };
25
+ type RegisteredAction = AppAction;
26
+ type RegisteredRoutes = Registered<'routes', readonly []> extends infer Routes extends readonly RouteShape[] ? Routes : readonly [];
27
+ type RegisteredIcons = Registered<'icons', Empty> extends infer Icons extends Record<string, unknown> ? Icons : Empty;
28
+ export type AppIconName = keyof RegisteredIcons & string;
29
+ export type BuiltInModels = {
30
+ account: typeof Account;
31
+ palette: typeof Palette;
32
+ signIn: typeof SignIn;
33
+ };
34
+ export type AppModels = Instances<BuiltInModels & RegisteredModels>;
35
+ export type AppPath = PathOf<RegisteredRoutes>;
36
+ export type AppPage = PageOf<RegisteredRoutes>;
37
+ export type AppCommand = MessagesOf<AppModels> | NavigateCommand<AppPath> | PressKeyCommand;
38
+ export type AppStores = StoresOf<RegisteredTables, StoreInstances<RegisteredStores>, RegisteredAction>;
39
+ export type AppSnapshot = AppSnapshotShape<AppModels, AppStores, AppPage>;
40
+ export type ActionContext = {
41
+ readonly page: AppPage | null;
42
+ readonly models: ModelSnapshots<AppModels>;
43
+ };
44
+ export type ModelServices = ModelServicesOf<AppPath>;
45
+ export declare const Model: <S extends import("./state.ts").StateSpec = Record<never, never>, const P extends readonly (keyof S & string)[] = []>(config?: import("./model.ts").ModelConfig<S, P>) => import("./model.ts").ModelClass<AppStores, ModelServices, S, P>;
46
+ export declare const defineActions: DefineActions<ActionContext, RegisteredAction, AppCommand>;
47
+ export declare const appPath: z.ZodCustom<AppPath, AppPath>;
48
+ type ActionInput = Pick<AppAction, 'id' | 'label' | 'group' | 'icon'> & Partial<Pick<AppAction, 'keys' | 'keywords' | 'isDanger' | 'isSearchOnly' | 'isHidden'>> & {
49
+ send: readonly AppCommand[];
50
+ };
51
+ export declare function action(input: ActionInput): AppAction & {
52
+ send: readonly AppCommand[];
53
+ };
54
+ export {};
@@ -0,0 +1,17 @@
1
+ import { z } from 'zod';
2
+ import { bindActions } from "./actions.js";
3
+ import { defineModel } from "./model.js";
4
+ import { isRoutedPath } from "./routes.js";
5
+ export const Model = defineModel();
6
+ export const defineActions = bindActions();
7
+ export const appPath = z.custom((value) => typeof value === 'string' && isRoutedPath(value), { error: 'Not a page in src/routes.tsx' });
8
+ export function action(input) {
9
+ return {
10
+ keys: [],
11
+ keywords: '',
12
+ isDanger: false,
13
+ isSearchOnly: false,
14
+ isHidden: false,
15
+ ...input
16
+ };
17
+ }
@@ -0,0 +1,38 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { RouteObject } from 'react-router';
3
+ export type RouteDefinition = {
4
+ readonly id?: string;
5
+ readonly path?: string;
6
+ readonly index?: boolean;
7
+ readonly Component?: ComponentType;
8
+ readonly children?: readonly RouteDefinition[];
9
+ };
10
+ type IdsOf<Route> = (Route extends {
11
+ readonly id: infer Id extends string;
12
+ } ? Id : never) | (Route extends {
13
+ readonly children: infer Children;
14
+ } ? PageOf<Children> : never);
15
+ export type PageOf<Routes> = Routes extends readonly (infer Route)[] ? IdsOf<Route> : never;
16
+ export type RouteShape = {
17
+ readonly id?: string;
18
+ readonly path?: string;
19
+ readonly index?: boolean;
20
+ readonly Component?: unknown;
21
+ readonly children?: readonly RouteShape[];
22
+ };
23
+ export declare function defineRoutes<const Routes extends readonly RouteShape[]>(routes: Routes): Routes;
24
+ export declare function pageIds(routes: readonly RouteDefinition[]): readonly string[];
25
+ export declare function registerRoutes(routes: readonly RouteDefinition[]): void;
26
+ export declare function isRoutedPath(path: string): boolean;
27
+ export declare function routeObjects(routes: readonly RouteDefinition[]): RouteObject[];
28
+ type Joined<Parent extends string, Path extends string> = Path extends `/${string}` ? Path : Parent extends '' | '/' ? `/${Path}` : `${Parent}/${Path}`;
29
+ type Pattern<Path extends string> = Path extends `${infer Head}:${infer Rest}` ? Rest extends `${string}/${infer Tail}` ? `${Head}${string}/${Pattern<Tail>}` : `${Head}${string}` : Path;
30
+ type PathsOfRoute<Route, Parent extends string> = Route extends {
31
+ readonly path: infer Path extends string;
32
+ } ? (Path extends '*' ? never : Pattern<Joined<Parent, Path>>) | (Route extends {
33
+ readonly children: infer Children;
34
+ } ? PathOf<Children, Joined<Parent, Path>> : never) : Route extends {
35
+ readonly children: infer Children;
36
+ } ? PathOf<Children, Parent> : never;
37
+ export type PathOf<Routes, Parent extends string = ''> = Routes extends readonly (infer Route)[] ? PathsOfRoute<Route, Parent> : never;
38
+ export {};
package/dist/routes.js ADDED
@@ -0,0 +1,21 @@
1
+ import { matchRoutes } from 'react-router';
2
+ export function defineRoutes(routes) {
3
+ return routes;
4
+ }
5
+ export function pageIds(routes) {
6
+ return routes.flatMap((route) => [
7
+ ...(route.id === undefined ? [] : [route.id]),
8
+ ...pageIds(route.children ?? [])
9
+ ]);
10
+ }
11
+ let registeredRoutes = [];
12
+ export function registerRoutes(routes) {
13
+ registeredRoutes = routeObjects(routes);
14
+ }
15
+ export function isRoutedPath(path) {
16
+ const match = matchRoutes(registeredRoutes, path)?.at(-1);
17
+ return match !== undefined && match.route.path !== '*';
18
+ }
19
+ export function routeObjects(routes) {
20
+ return routes;
21
+ }
@@ -0,0 +1 @@
1
+ export {};