@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,189 @@
1
+ import type { D1Database } from '@cloudflare/workers-types';
2
+ import type { StoredUser } from '../auth/user.ts';
3
+ export declare const users: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
4
+ name: "users";
5
+ schema: undefined;
6
+ columns: {
7
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
8
+ name: "id";
9
+ tableName: "users";
10
+ dataType: "string";
11
+ columnType: "SQLiteText";
12
+ data: string;
13
+ driverParam: string;
14
+ notNull: true;
15
+ hasDefault: false;
16
+ isPrimaryKey: true;
17
+ isAutoincrement: false;
18
+ hasRuntimeDefault: false;
19
+ enumValues: [string, ...string[]];
20
+ baseColumn: never;
21
+ identity: undefined;
22
+ generated: undefined;
23
+ }, {}, {
24
+ length: number | undefined;
25
+ }>;
26
+ email: import("drizzle-orm/sqlite-core").SQLiteColumn<{
27
+ name: "email";
28
+ tableName: "users";
29
+ dataType: "string";
30
+ columnType: "SQLiteText";
31
+ data: string;
32
+ driverParam: string;
33
+ notNull: true;
34
+ hasDefault: false;
35
+ isPrimaryKey: false;
36
+ isAutoincrement: false;
37
+ hasRuntimeDefault: false;
38
+ enumValues: [string, ...string[]];
39
+ baseColumn: never;
40
+ identity: undefined;
41
+ generated: undefined;
42
+ }, {}, {
43
+ length: number | undefined;
44
+ }>;
45
+ name: import("drizzle-orm/sqlite-core").SQLiteColumn<{
46
+ name: "name";
47
+ tableName: "users";
48
+ dataType: "string";
49
+ columnType: "SQLiteText";
50
+ data: string;
51
+ driverParam: string;
52
+ notNull: true;
53
+ hasDefault: false;
54
+ isPrimaryKey: false;
55
+ isAutoincrement: false;
56
+ hasRuntimeDefault: false;
57
+ enumValues: [string, ...string[]];
58
+ baseColumn: never;
59
+ identity: undefined;
60
+ generated: undefined;
61
+ }, {}, {
62
+ length: number | undefined;
63
+ }>;
64
+ avatarUrl: import("drizzle-orm/sqlite-core").SQLiteColumn<{
65
+ name: "avatar_url";
66
+ tableName: "users";
67
+ dataType: "string";
68
+ columnType: "SQLiteText";
69
+ data: string;
70
+ driverParam: string;
71
+ notNull: false;
72
+ hasDefault: false;
73
+ isPrimaryKey: false;
74
+ isAutoincrement: false;
75
+ hasRuntimeDefault: false;
76
+ enumValues: [string, ...string[]];
77
+ baseColumn: never;
78
+ identity: undefined;
79
+ generated: undefined;
80
+ }, {}, {
81
+ length: number | undefined;
82
+ }>;
83
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
84
+ name: "created_at";
85
+ tableName: "users";
86
+ dataType: "string";
87
+ columnType: "SQLiteText";
88
+ data: string;
89
+ driverParam: string;
90
+ notNull: true;
91
+ hasDefault: true;
92
+ isPrimaryKey: false;
93
+ isAutoincrement: false;
94
+ hasRuntimeDefault: false;
95
+ enumValues: [string, ...string[]];
96
+ baseColumn: never;
97
+ identity: undefined;
98
+ generated: undefined;
99
+ }, {}, {
100
+ length: number | undefined;
101
+ }>;
102
+ };
103
+ dialect: "sqlite";
104
+ }>;
105
+ export declare const userColumns: {
106
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
107
+ name: "id";
108
+ tableName: "users";
109
+ dataType: "string";
110
+ columnType: "SQLiteText";
111
+ data: string;
112
+ driverParam: string;
113
+ notNull: true;
114
+ hasDefault: false;
115
+ isPrimaryKey: true;
116
+ isAutoincrement: false;
117
+ hasRuntimeDefault: false;
118
+ enumValues: [string, ...string[]];
119
+ baseColumn: never;
120
+ identity: undefined;
121
+ generated: undefined;
122
+ }, {}, {
123
+ length: number | undefined;
124
+ }>;
125
+ email: import("drizzle-orm/sqlite-core").SQLiteColumn<{
126
+ name: "email";
127
+ tableName: "users";
128
+ dataType: "string";
129
+ columnType: "SQLiteText";
130
+ data: string;
131
+ driverParam: string;
132
+ notNull: true;
133
+ hasDefault: false;
134
+ isPrimaryKey: false;
135
+ isAutoincrement: false;
136
+ hasRuntimeDefault: false;
137
+ enumValues: [string, ...string[]];
138
+ baseColumn: never;
139
+ identity: undefined;
140
+ generated: undefined;
141
+ }, {}, {
142
+ length: number | undefined;
143
+ }>;
144
+ name: import("drizzle-orm/sqlite-core").SQLiteColumn<{
145
+ name: "name";
146
+ tableName: "users";
147
+ dataType: "string";
148
+ columnType: "SQLiteText";
149
+ data: string;
150
+ driverParam: string;
151
+ notNull: true;
152
+ hasDefault: false;
153
+ isPrimaryKey: false;
154
+ isAutoincrement: false;
155
+ hasRuntimeDefault: false;
156
+ enumValues: [string, ...string[]];
157
+ baseColumn: never;
158
+ identity: undefined;
159
+ generated: undefined;
160
+ }, {}, {
161
+ length: number | undefined;
162
+ }>;
163
+ avatarUrl: import("drizzle-orm/sqlite-core").SQLiteColumn<{
164
+ name: "avatar_url";
165
+ tableName: "users";
166
+ dataType: "string";
167
+ columnType: "SQLiteText";
168
+ data: string;
169
+ driverParam: string;
170
+ notNull: false;
171
+ hasDefault: false;
172
+ isPrimaryKey: false;
173
+ isAutoincrement: false;
174
+ hasRuntimeDefault: false;
175
+ enumValues: [string, ...string[]];
176
+ baseColumn: never;
177
+ identity: undefined;
178
+ generated: undefined;
179
+ }, {}, {
180
+ length: number | undefined;
181
+ }>;
182
+ };
183
+ export declare function findUser(d1: D1Database, id: string): Promise<StoredUser | undefined>;
184
+ export type SignedInPerson = {
185
+ email: string;
186
+ name: string | null;
187
+ avatarUrl: string | null;
188
+ };
189
+ export declare function saveUser(d1: D1Database, person: SignedInPerson): Promise<StoredUser>;
@@ -0,0 +1,49 @@
1
+ import { eq, sql } from 'drizzle-orm';
2
+ import { drizzle } from 'drizzle-orm/d1';
3
+ import { sqliteTable, text } from 'drizzle-orm/sqlite-core';
4
+ export const users = sqliteTable('users', {
5
+ id: text('id').primaryKey(),
6
+ email: text('email').notNull().unique(),
7
+ name: text('name').notNull(),
8
+ avatarUrl: text('avatar_url'),
9
+ createdAt: text('created_at')
10
+ .notNull()
11
+ .default(sql `(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))`)
12
+ });
13
+ export const userColumns = {
14
+ id: users.id,
15
+ email: users.email,
16
+ name: users.name,
17
+ avatarUrl: users.avatarUrl
18
+ };
19
+ export async function findUser(d1, id) {
20
+ return drizzle(d1)
21
+ .select(userColumns)
22
+ .from(users)
23
+ .where(eq(users.id, id))
24
+ .get();
25
+ }
26
+ function nameFromEmail(email) {
27
+ const local = email.split('@')[0] ?? email;
28
+ return local.charAt(0).toUpperCase() + local.slice(1);
29
+ }
30
+ export async function saveUser(d1, person) {
31
+ const email = person.email.toLowerCase();
32
+ return drizzle(d1)
33
+ .insert(users)
34
+ .values({
35
+ id: crypto.randomUUID(),
36
+ email,
37
+ name: person.name ?? nameFromEmail(email),
38
+ avatarUrl: person.avatarUrl
39
+ })
40
+ .onConflictDoUpdate({
41
+ target: users.email,
42
+ set: {
43
+ name: person.name === null ? sql `${users.name}` : sql `excluded.name`,
44
+ avatarUrl: sql `coalesce(excluded.avatar_url, ${users.avatarUrl})`
45
+ }
46
+ })
47
+ .returning(userColumns)
48
+ .get();
49
+ }
@@ -0,0 +1,3 @@
1
+ type PressKey = (key: string) => Promise<void> | undefined;
2
+ export declare function useShortcuts(pressKey: PressKey): void;
3
+ export {};
@@ -0,0 +1,40 @@
1
+ import { useEffect } from 'react';
2
+ const MODIFIER_KEYS = new Set(['Shift', 'Meta', 'Control', 'Alt', 'CapsLock']);
3
+ const OWNS_KEYS = 'input, textarea, select, [contenteditable], [role=menu], [role=listbox], [role=dialog]';
4
+ function isApplePlatform() {
5
+ if (typeof navigator === 'undefined')
6
+ return false;
7
+ return /Mac|iPhone|iPad/.test(navigator.userAgent);
8
+ }
9
+ function isOwnedByControl(target) {
10
+ return target instanceof Element && target.closest(OWNS_KEYS) !== null;
11
+ }
12
+ function shortcutOf(event) {
13
+ if (event.defaultPrevented || event.isComposing)
14
+ return undefined;
15
+ const hasMod = isApplePlatform() ? event.metaKey : event.ctrlKey;
16
+ if (hasMod && !event.altKey)
17
+ return `mod+${event.key.toLowerCase()}`;
18
+ if (event.metaKey || event.ctrlKey || event.altKey || event.repeat) {
19
+ return undefined;
20
+ }
21
+ if (MODIFIER_KEYS.has(event.key) || isOwnedByControl(event.target)) {
22
+ return undefined;
23
+ }
24
+ return event.key;
25
+ }
26
+ export function useShortcuts(pressKey) {
27
+ useEffect(() => {
28
+ const onKeyDown = (event) => {
29
+ const shortcut = shortcutOf(event);
30
+ if (shortcut === undefined)
31
+ return;
32
+ const ran = pressKey(shortcut);
33
+ if (ran !== undefined && shortcut.startsWith('mod+')) {
34
+ event.preventDefault();
35
+ }
36
+ };
37
+ window.addEventListener('keydown', onKeyDown);
38
+ return () => window.removeEventListener('keydown', onKeyDown);
39
+ }, [pressKey]);
40
+ }
@@ -0,0 +1,20 @@
1
+ import type { Theme } from '@stylexjs/stylex';
2
+ import './theme/reset.css';
3
+ import type { AppClass, RunningApp } from './app.ts';
4
+ import type { IconDrawing } from './components/icons.ts';
5
+ import type { Interaction } from './components/interaction.ts';
6
+ import type { ReactApp } from './hooks/appContext.ts';
7
+ import type { Tables } from './table.ts';
8
+ import { borders, colors, controls, fontSizes, fonts, iconSizes, lineHeights, radii, shadows, space, widths } from './theme/tokens.stylex.ts';
9
+ type Themeable = typeof colors | typeof radii | typeof fonts | typeof shadows | typeof space | typeof fontSizes | typeof lineHeights | typeof controls | typeof iconSizes | typeof borders | typeof widths;
10
+ export type StartOptions = {
11
+ theme?: readonly Theme<Themeable>[];
12
+ icons?: Readonly<Record<string, IconDrawing>>;
13
+ onInteraction?: (interaction: Interaction) => void;
14
+ };
15
+ type AnyRunningApp = RunningApp<unknown, {
16
+ readonly path: string;
17
+ }>;
18
+ type RenderableApp = AnyRunningApp & ReactApp;
19
+ export declare function startApp<Group extends Tables, Instance extends RenderableApp>(App: AppClass<Group, Instance>, { theme, icons, onInteraction }?: StartOptions): Instance;
20
+ export {};
package/dist/start.js ADDED
@@ -0,0 +1,121 @@
1
+ import * as stylex from '@stylexjs/stylex';
2
+ import { StrictMode, createElement } from 'react';
3
+ import { createRoot } from 'react-dom/client';
4
+ import { createBrowserRouter } from 'react-router';
5
+ import { RouterProvider } from 'react-router/dom';
6
+ import './theme/reset.css';
7
+ import { browserApi } from "./api.js";
8
+ import { Cache } from "./cache.js";
9
+ import { setAppIcons } from "./components/icons.js";
10
+ import { setInteractionSink } from "./components/interaction.js";
11
+ import { Gate } from "./gate.js";
12
+ import { AppProvider } from "./hooks/appContext.js";
13
+ import { routeObjects } from "./routes.js";
14
+ import { borders, breakpoints, colors, controls, fontFeatures, fontSizes, fontWeights, fonts, iconSizes, lineHeights, radii, shadows, space, widths } from "./theme/tokens.stylex.js";
15
+ const TEST_SEED = 'patternSeed';
16
+ const TEST_ADMINS = 'patternAdmins';
17
+ function testSeed() {
18
+ const seed = Reflect.get(window, TEST_SEED);
19
+ return typeof seed === 'object' && seed !== null ? seed : {};
20
+ }
21
+ function testAdmins() {
22
+ const admins = Reflect.get(window, TEST_ADMINS);
23
+ return Array.isArray(admins)
24
+ ? admins.filter((email) => typeof email === 'string')
25
+ : [];
26
+ }
27
+ export function startApp(App, { theme = [], icons = {}, onInteraction } = {}) {
28
+ setAppIcons(icons);
29
+ document.body.className = stylex.props(base.body, theme).className ?? '';
30
+ const hot = import.meta.hot;
31
+ const testParams = new URLSearchParams(hot ? location.search : '');
32
+ const gate = new Gate(testParams.getAll('fail'));
33
+ for (const call of testParams.getAll('hold'))
34
+ gate.hold(call);
35
+ const { tables, routes } = App.definition;
36
+ const inMemory = testParams.has('memory');
37
+ const router = createBrowserRouter(routeObjects(routes));
38
+ const app = new App(router, {
39
+ api: browserApi(tables, inMemory ? testSeed() : {}, gate, {
40
+ inMemory,
41
+ admins: inMemory ? testAdmins() : []
42
+ }),
43
+ cache: Cache.local(),
44
+ gate
45
+ });
46
+ if (hot)
47
+ exposeToDevTools(app, gate, hot);
48
+ followAppearance(app);
49
+ if (onInteraction !== undefined) {
50
+ setInteractionSink((interaction) => onInteraction({
51
+ ...interaction,
52
+ page: app.router.state.matches.at(-1)?.route.id ?? null
53
+ }));
54
+ }
55
+ const root = document.getElementById('root');
56
+ if (root === null)
57
+ throw new Error('index.html needs a <div id="root">');
58
+ createRoot(root).render(createElement(StrictMode, null, createElement(AppProvider, {
59
+ app,
60
+ children: createElement(RouterProvider, { router: app.router })
61
+ })));
62
+ return app;
63
+ }
64
+ function followAppearance(app) {
65
+ const account = app.models.account;
66
+ const apply = () => {
67
+ const { appearance } = account.currentState;
68
+ document.documentElement.style.colorScheme =
69
+ appearance === 'system' ? 'light dark' : appearance;
70
+ };
71
+ account.subscribe(apply);
72
+ apply();
73
+ }
74
+ function exposeToDevTools(app, gate, hot) {
75
+ async function snapshotWhenIdle() {
76
+ await app.whenIdle();
77
+ return app.getSnapshot();
78
+ }
79
+ function dispatch(raw) {
80
+ const command = app.parse(raw);
81
+ if (typeof command === 'object' && command !== null && 'error' in command) {
82
+ return { error: String(command.error) };
83
+ }
84
+ void app.send(command);
85
+ return { ok: true };
86
+ }
87
+ Object.assign(window, {
88
+ pattern: {
89
+ send: dispatch,
90
+ snapshot: snapshotWhenIdle,
91
+ hold: (call) => gate.hold(call),
92
+ release: (call) => gate.release(call)
93
+ }
94
+ });
95
+ if (navigator.webdriver)
96
+ return;
97
+ hot.on('pattern:command', async (message) => {
98
+ const sent = dispatch(message.command);
99
+ hot.send('pattern:reply', {
100
+ id: message.id,
101
+ ...('error' in sent ? sent : { snapshot: await snapshotWhenIdle() })
102
+ });
103
+ });
104
+ }
105
+ const base = stylex.create({
106
+ body: {
107
+ fontFamily: fonts.sans,
108
+ fontSize: {
109
+ default: fontSizes.bodySm,
110
+ [breakpoints.compact]: fontSizes.bodyBase
111
+ },
112
+ fontWeight: fontWeights.normal,
113
+ fontFeatureSettings: fontFeatures.sans,
114
+ lineHeight: {
115
+ default: lineHeights.bodySm,
116
+ [breakpoints.compact]: lineHeights.body
117
+ },
118
+ color: colors.primaryForeground,
119
+ backgroundColor: colors.shell
120
+ }
121
+ });
@@ -0,0 +1,14 @@
1
+ import type { z } from 'zod';
2
+ export type Json = string | number | boolean | null | readonly Json[] | {
3
+ readonly [key: string]: Json;
4
+ };
5
+ export type StateSpec = Record<string, z.ZodDefault<z.ZodType<Json>>>;
6
+ export type StateOf<Spec extends StateSpec> = {
7
+ [Key in keyof Spec]: z.output<Spec[Key]>;
8
+ };
9
+ export type Persisted = {
10
+ read: (key: string) => unknown;
11
+ write: (key: string, value: unknown) => void;
12
+ };
13
+ export declare function defaultsOf<Spec extends StateSpec>(spec: Spec): StateOf<Spec>;
14
+ export declare function restore<Spec extends StateSpec>(spec: Spec, persist: readonly (keyof Spec & string)[], device: Persisted): StateOf<Spec>;
package/dist/state.js ADDED
@@ -0,0 +1,17 @@
1
+ export function defaultsOf(spec) {
2
+ const entries = Object.entries(spec).map(([key, schema]) => [
3
+ key,
4
+ schema.parse(undefined)
5
+ ]);
6
+ return Object.fromEntries(entries);
7
+ }
8
+ export function restore(spec, persist, device) {
9
+ const state = defaultsOf(spec);
10
+ for (const key of persist) {
11
+ const parsed = spec[key]?.safeParse(device.read(key));
12
+ if (parsed?.success) {
13
+ state[key] = parsed.data;
14
+ }
15
+ }
16
+ return state;
17
+ }
@@ -0,0 +1,43 @@
1
+ import type { Persisted, StateOf, StateSpec } from './state.ts';
2
+ export declare function isDevelopment(): boolean;
3
+ export declare function plainJsonProblem(value: unknown, path: string): string | undefined;
4
+ export declare function keepEqualParts<Value>(previous: unknown, next: Value): Value;
5
+ export type Reads = Map<StoreBase<object, unknown>, Map<string, unknown>>;
6
+ export declare function tracked<Value>(run: () => Value): {
7
+ value: Value;
8
+ reads: Reads;
9
+ };
10
+ export declare function mergeReads(from: Reads): void;
11
+ export declare function readsAreCurrent(reads: Reads): boolean;
12
+ export declare function whileBuilding<Value>(run: () => Value): Value;
13
+ export declare function assertNotBuilding(what: string): void;
14
+ export declare abstract class StoreBase<State extends object, Deps = undefined> {
15
+ #private;
16
+ protected readonly deps: Deps;
17
+ constructor(...args: Deps extends undefined ? [] : [deps: Deps]);
18
+ protected abstract initialState(): State;
19
+ get state(): State;
20
+ get currentState(): State;
21
+ readonly subscribe: (listener: () => void) => (() => void);
22
+ protected set(patch: Partial<State>): void;
23
+ protected changed(): void;
24
+ }
25
+ export type StoreConfig<S extends StateSpec, P extends readonly (keyof S & string)[]> = {
26
+ state?: S;
27
+ persist?: P;
28
+ };
29
+ export declare abstract class DeclaredStore<State extends object> extends StoreBase<State> {
30
+ protected initialState(): State;
31
+ }
32
+ export type StoreClass<S extends StateSpec, P extends readonly (keyof S & string)[]> = (abstract new (persisted: Persisted) => DeclaredStore<StateOf<S>>) & {
33
+ readonly config: StoreConfig<S, P>;
34
+ };
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>;
36
+ export type Snapshots<Group> = {
37
+ [Key in keyof Group]: Group[Key] extends {
38
+ readonly state: infer State;
39
+ } ? State : never;
40
+ };
41
+ export declare function snapshotsOf<Group extends Record<string, {
42
+ readonly state: object;
43
+ }>>(group: Group): Snapshots<Group>;