@weft-js/start 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 (213) hide show
  1. package/README.md +36 -3
  2. package/crate/Cargo.lock +1347 -0
  3. package/crate/Cargo.toml +72 -0
  4. package/crate/rust-toolchain.toml +3 -0
  5. package/crate/src/build/emit.rs +103 -0
  6. package/crate/src/build.rs +367 -0
  7. package/crate/src/ctx.rs +186 -0
  8. package/crate/src/envelope.rs +163 -0
  9. package/crate/src/functions.rs +173 -0
  10. package/crate/src/lib.rs +118 -0
  11. package/crate/src/native.rs +212 -0
  12. package/crate/src/otel.rs +62 -0
  13. package/crate/src/server.rs +203 -0
  14. package/package.json +46 -37
  15. package/src/app.mjs +51 -10
  16. package/src/asset-receipt.d.mts +13 -0
  17. package/src/asset-receipt.mjs +61 -0
  18. package/src/auth/better-auth.ts +215 -17
  19. package/src/auth/drizzle.ts +1 -1
  20. package/src/auth.ts +21 -6
  21. package/src/boot.ts +19 -8
  22. package/src/bus/postgres.ts +32 -19
  23. package/src/bus.ts +7 -4
  24. package/src/{capture.mjs → capture.ts} +34 -1
  25. package/src/changes-sql.d.mts +8 -2
  26. package/src/changes-sql.mjs +26 -10
  27. package/src/changes.ts +165 -66
  28. package/src/channel/connections.ts +216 -0
  29. package/src/channel/socket.ts +396 -0
  30. package/src/channel-fake.ts +19 -4
  31. package/src/channel.ts +124 -490
  32. package/src/client.tsx +9 -2
  33. package/src/contract/describe.mjs +231 -0
  34. package/src/contract.mjs +146 -155
  35. package/src/data/cache.ts +354 -0
  36. package/src/data/definitions.ts +94 -0
  37. package/src/data/draft.ts +104 -0
  38. package/src/data/foundation.ts +95 -0
  39. package/src/data/live-api.ts +22 -0
  40. package/src/data/mutation.ts +138 -0
  41. package/src/data/primitives.ts +135 -0
  42. package/src/data/query.ts +106 -0
  43. package/src/data/transport.ts +121 -0
  44. package/src/data/types.ts +303 -0
  45. package/src/data.ts +69 -894
  46. package/src/db/bun-sqlite.d.ts +4 -1
  47. package/src/db/changes-mysql.ts +61 -21
  48. package/src/db/changes-postgres.ts +197 -118
  49. package/src/db/changes-sqlite.ts +131 -64
  50. package/src/db/core.ts +38 -13
  51. package/src/db/index.ts +20 -4
  52. package/src/db/mysql.ts +22 -6
  53. package/src/db/postgres.ts +49 -13
  54. package/src/db/sqlite.ts +53 -27
  55. package/src/derive.d.mts +4 -1
  56. package/src/derive.mjs +136 -39
  57. package/src/dev-runtime.mjs +8 -4
  58. package/src/exec/errors.ts +57 -0
  59. package/src/exec/landing.ts +66 -0
  60. package/src/exec/scope.ts +174 -0
  61. package/src/exec/touch.ts +80 -0
  62. package/src/exec/validation.ts +176 -0
  63. package/src/exec.ts +191 -341
  64. package/src/extension.ts +8 -2
  65. package/src/first-paint.ts +26 -9
  66. package/src/form/value.ts +15 -0
  67. package/src/form.tsx +132 -43
  68. package/src/hub/channels.ts +102 -0
  69. package/src/hub/connections.ts +147 -0
  70. package/src/hub/delivery.ts +62 -0
  71. package/src/hub/feed.ts +168 -0
  72. package/src/hub/presence.ts +64 -0
  73. package/src/hub/route.ts +158 -0
  74. package/src/hub/subscriptions.ts +212 -0
  75. package/src/hub/topic.ts +98 -0
  76. package/src/hub/tracked.ts +12 -0
  77. package/src/hub/types.ts +190 -0
  78. package/src/hub/view.ts +147 -0
  79. package/src/hub.ts +132 -758
  80. package/src/index.ts +84 -10
  81. package/src/inline.mjs +356 -0
  82. package/src/inspect/compare.mjs +162 -0
  83. package/src/inspect/routes.mjs +154 -0
  84. package/src/inspect/samples.mjs +59 -0
  85. package/src/inspect/url.mjs +2 -0
  86. package/src/inspect.mjs +146 -187
  87. package/src/link/election.ts +178 -0
  88. package/src/link/lines.ts +27 -0
  89. package/src/link.ts +97 -168
  90. package/src/list-drizzle.ts +104 -18
  91. package/src/list.ts +127 -36
  92. package/src/listen.ts +32 -6
  93. package/src/live/api.ts +18 -0
  94. package/src/live/backoff.ts +6 -0
  95. package/src/live/frames.ts +42 -0
  96. package/src/live/read.ts +77 -0
  97. package/src/live/sub-types.ts +24 -0
  98. package/src/live/transport.ts +86 -0
  99. package/src/live/types.ts +52 -0
  100. package/src/live-fake.ts +20 -5
  101. package/src/live-target.mjs +113 -35
  102. package/src/live.ts +116 -225
  103. package/src/media.ts +8 -1
  104. package/src/migrations.mjs +14 -6
  105. package/src/mux.ts +161 -64
  106. package/src/og/DefaultCard.tsx +40 -9
  107. package/src/og/fonts.mjs +16 -8
  108. package/src/og/images.mjs +43 -22
  109. package/src/og/index.mjs +119 -43
  110. package/src/og/native.mjs +11 -4
  111. package/src/range.mjs +15 -3
  112. package/src/router.ts +56 -6
  113. package/src/routes.mjs +73 -22
  114. package/src/run/admission.ts +80 -0
  115. package/src/run/boot.tsx +115 -0
  116. package/src/run/cache-presentation.ts +67 -0
  117. package/src/run/cache.ts +254 -0
  118. package/src/run/helpers.ts +197 -0
  119. package/src/run/listeners.ts +155 -0
  120. package/src/run/navigation.ts +382 -0
  121. package/src/run/page-skeleton.tsx +35 -0
  122. package/src/run/prefetch.ts +128 -0
  123. package/src/run/retain-view.ts +18 -0
  124. package/src/run/shape-preparation.ts +97 -0
  125. package/src/run/shape-styles.ts +72 -0
  126. package/src/run/source-context/pin.ts +124 -0
  127. package/src/run/source-context.ts +311 -0
  128. package/src/run.tsx +50 -174
  129. package/src/rust/common.ts +163 -0
  130. package/src/rust/native.ts +282 -0
  131. package/src/rust.ts +103 -229
  132. package/src/server/card.tsx +65 -0
  133. package/src/server/compression.ts +115 -0
  134. package/src/server/core.ts +70 -0
  135. package/src/server/dispatch.ts +70 -0
  136. package/src/server/form.ts +85 -0
  137. package/src/server/functions.ts +129 -0
  138. package/src/server/handler.ts +39 -0
  139. package/src/server/head.ts +96 -0
  140. package/src/server/media.ts +60 -0
  141. package/src/server/navigation-cache.ts +80 -0
  142. package/src/server/navigation.tsx +85 -0
  143. package/src/server/page-cold.ts +95 -0
  144. package/src/server/page-stream.tsx +181 -0
  145. package/src/server/page-types.ts +51 -0
  146. package/src/server/page-warm.ts +130 -0
  147. package/src/server/page.ts +69 -0
  148. package/src/server/payload.ts +89 -0
  149. package/src/server/prerender.ts +60 -0
  150. package/src/server/preview.tsx +67 -0
  151. package/src/server/render.ts +167 -0
  152. package/src/server/request.ts +98 -0
  153. package/src/server/resolver.ts +228 -0
  154. package/src/server/routes.ts +150 -0
  155. package/src/server/services.ts +69 -0
  156. package/src/server/text.ts +29 -0
  157. package/src/server/types.ts +160 -0
  158. package/src/server.tsx +82 -964
  159. package/src/shape.mjs +30 -6
  160. package/src/share/display.ts +50 -0
  161. package/src/share/network.ts +119 -0
  162. package/src/share/receive.ts +70 -0
  163. package/src/share/state.ts +30 -0
  164. package/src/share/tab-queue.ts +28 -0
  165. package/src/share-server.ts +128 -43
  166. package/src/share.ts +103 -209
  167. package/src/sheets.mjs +30 -18
  168. package/src/sidecar/build.mjs +170 -0
  169. package/src/sidecar/cargo.mjs +164 -0
  170. package/src/sidecar/common.mjs +17 -0
  171. package/src/sidecar/dev-build.mjs +91 -0
  172. package/src/sidecar/dev-watch.mjs +88 -0
  173. package/src/sidecar/manifest.mjs +19 -0
  174. package/src/sidecar/process.mjs +58 -0
  175. package/src/sidecar/refresh.mjs +19 -0
  176. package/src/sidecar.mjs +75 -416
  177. package/src/socket/check.ts +50 -0
  178. package/src/socket/deliver.ts +16 -0
  179. package/src/socket/publish.ts +56 -0
  180. package/src/socket/rooms.ts +41 -0
  181. package/src/socket/route.ts +79 -0
  182. package/src/socket/shared.ts +26 -0
  183. package/src/socket/types.ts +48 -0
  184. package/src/socket.ts +205 -194
  185. package/src/stream.ts +10 -1
  186. package/src/verify/app.ts +39 -0
  187. package/src/verify/cleanup.ts +27 -0
  188. package/src/verify/database.ts +11 -0
  189. package/src/verify/live.ts +63 -0
  190. package/src/verify/notify.ts +35 -0
  191. package/src/verify/skip.ts +19 -0
  192. package/src/verify/support.ts +149 -0
  193. package/src/verify/timing.ts +15 -0
  194. package/src/verify/trigger.ts +14 -0
  195. package/src/verify.ts +77 -176
  196. package/src/view.tsx +96 -11
  197. package/src/vite/asset-bytes.mjs +95 -0
  198. package/src/vite/assets.mjs +117 -0
  199. package/src/vite/config-hooks.mjs +166 -0
  200. package/src/vite/dev-hooks.mjs +103 -0
  201. package/src/vite/dev.mjs +102 -0
  202. package/src/vite/entries.mjs +145 -0
  203. package/src/vite/module-hooks.mjs +288 -0
  204. package/src/vite/route-modules.mjs +289 -0
  205. package/src/vite/server-functions.mjs +222 -0
  206. package/src/vite/shape-entry-css.mjs +187 -0
  207. package/src/vite/shape-override.mjs +226 -0
  208. package/src/vite/shared.mjs +51 -0
  209. package/src/vite/sheets.mjs +92 -0
  210. package/src/vite/state.mjs +89 -0
  211. package/src/vite/syntax.mjs +139 -0
  212. package/src/vite.mjs +152 -853
  213. package/src/capture.d.mts +0 -1
@@ -0,0 +1,176 @@
1
+ import { fns, StartError, type Fn, type SchemaIssue } from '../data'
2
+ import type { Scope } from './scope'
3
+
4
+ type Obj = Record<PropertyKey, unknown>
5
+
6
+ // ---- validation and checks ------------------------------------------------------------------------------------
7
+
8
+ export async function validate(fn: Fn, input: unknown): Promise<unknown> {
9
+ const schema = fn.def.input
10
+ if (!schema) return input
11
+ const r = await schema['~standard'].validate(input)
12
+ if (!r.issues) return r.value
13
+ throw rejected(fn, r.issues)
14
+ }
15
+
16
+ const plainPath = (i: SchemaIssue) => (i.path ?? []).map((p) => (typeof p === 'object' ? p.key : p))
17
+
18
+ function rejected(fn: Fn, list: readonly SchemaIssue[]) {
19
+ const issues = list.map((i) => ({
20
+ message: i.message,
21
+ path: i.path && plainPath(i),
22
+ })) as (SchemaIssue & { path?: PropertyKey[] })[]
23
+ const where = issues
24
+ .map((i) => `${i.path?.length ? i.path.map(String).join('.') + ': ' : ''}${i.message}`)
25
+ .join('; ')
26
+ return new StartError(
27
+ 'Q002',
28
+ `\`${fn.$id}\` rejected its input: ${where}`,
29
+ 'pass what the schema accepts',
30
+ { status: 400, issues },
31
+ )
32
+ }
33
+ /** A form's string as the type it may stand for (research 29 §5): the schema says whether it was wrong. */
34
+ function reading(s: string): unknown {
35
+ if (s === '') return undefined
36
+ if (s === 'on' || s === 'true') return true
37
+ if (s === 'false') return false
38
+ return /^-?\d+(\.\d+)?$/.test(s) ? Number(s) : s
39
+ }
40
+ /**
41
+ * A form sends strings and a schema may want numbers or booleans, and Standard Schema can't say which: each issue
42
+ * on a string tries its obvious reading, then the input is validated again. Fields a reading fixed report nothing; the
43
+ * rest report what the schema says of what was typed (an empty field: its "required", not "expected a string").
44
+ */
45
+ export async function formInput(fn: Fn, input: unknown): Promise<unknown> {
46
+ const schema = fn.def.input
47
+ if (!schema || !input || typeof input !== 'object') return validate(fn, input)
48
+ const value: Obj = { ...input }
49
+ let left: readonly SchemaIssue[] = []
50
+ for (let i = 0; i < 3; i++) {
51
+ const r = await schema['~standard'].validate(value)
52
+ if (!r.issues) return r.value
53
+ left = r.issues
54
+ let changed = false
55
+ for (const issue of r.issues) {
56
+ const path = plainPath(issue)
57
+ if (!path.length) continue
58
+ let at: Obj | undefined = value
59
+ for (const p of path.slice(0, -1)) {
60
+ const inner: unknown = at?.[p]
61
+ if (!inner || typeof inner !== 'object') {
62
+ at = undefined
63
+ break
64
+ }
65
+ at = at[p] = (Array.isArray(inner) ? [...inner] : { ...inner }) as Obj
66
+ }
67
+ const k = path.at(-1)!
68
+ const typed = at?.[k]
69
+ if (typeof typed !== 'string') continue
70
+ const next = reading(typed)
71
+ if (next === typed) continue
72
+ if (next === undefined) delete at![k]
73
+ else at![k] = next
74
+ changed = true
75
+ }
76
+ if (!changed) break
77
+ }
78
+ const first = await schema['~standard'].validate(input)
79
+ const where = (i: SchemaIssue) => JSON.stringify(plainPath(i))
80
+ throw rejected(
81
+ fn,
82
+ left.map((i) => first.issues?.find((o) => where(o) === where(i)) ?? i),
83
+ )
84
+ }
85
+ /** Dev and tests: the value against `output` (C002), and what JSON would change (Q005). */
86
+ export async function checked(v: unknown, fn: Fn, scope: Scope) {
87
+ serializable(v, fn, scope)
88
+ const schema = fn.def.output
89
+ if (!schema || fn.def.impl) return // `impl`: rust.ts checked what came back, on every call
90
+ const r = await schema['~standard'].validate(v)
91
+ if (r.issues)
92
+ throw new StartError(
93
+ 'C002',
94
+ `\`${fn.$id}\` returned a value its \`output\` schema rejects: ${r.issues.map((i) => `${i.path?.map((p) => (typeof p === 'object' ? p.key : p)).join('.') ?? ''}: ${i.message}`).join('; ')}`,
95
+ 'fix `run`, or the schema',
96
+ { status: 500 },
97
+ )
98
+ }
99
+ /** Q005 (dev): what JSON would change on the way to the client. */
100
+ function serializable(v: unknown, fn: Fn, scope: Scope) {
101
+ const bad = (x: unknown, path: string): string | undefined => {
102
+ if (x === null || typeof x === 'string' || typeof x === 'boolean') return undefined
103
+ if (typeof x === 'number') return Number.isFinite(x) ? undefined : `${path} is ${x}`
104
+ if (x === undefined) return undefined
105
+ if (typeof x !== 'object') return `${path} is a ${typeof x}`
106
+ if (Array.isArray(x)) {
107
+ for (let i = 0; i < x.length; i++) {
108
+ if (x[i] === undefined) return `${path}[${i}] is undefined (JSON sends null)`
109
+ const b = bad(x[i], `${path}[${i}]`)
110
+ if (b) return b
111
+ }
112
+ return undefined
113
+ }
114
+ const proto: unknown = Object.getPrototypeOf(x)
115
+ if (proto !== Object.prototype && proto !== null)
116
+ return `${path} is a ${(x as { constructor?: { name?: string } }).constructor?.name ?? 'class instance'}`
117
+ for (const k of Object.keys(x)) {
118
+ const b = bad((x as Obj)[k], `${path}.${k}`)
119
+ if (b) return b
120
+ }
121
+ return undefined
122
+ }
123
+ const b = bad(v, 'result')
124
+ if (b)
125
+ scope.options.onDiagnostic?.({
126
+ code: 'Q005',
127
+ severity: 'warning',
128
+ message: `\`${fn.$id}\`'s ${b}: the client gets a different value than the server rendered with. Send plain data (ISO strings, arrays, objects)`,
129
+ })
130
+ }
131
+ /**
132
+ * Q008 (dev, once): each mutation's static `invalidates` against the tags queries declare. A tags function is called
133
+ * with an input whose every field reads `*`, so `todo:${id}` declares `todo:*`.
134
+ */
135
+ export function checkTags(
136
+ report: (d: { code: string; severity: string; message: string }) => void,
137
+ ) {
138
+ const star: unknown = new Proxy(
139
+ {},
140
+ { get: (_, k) => (k === Symbol.toPrimitive ? () => '*' : '*') },
141
+ )
142
+ const declared: string[] = []
143
+ for (const f of fns.values()) {
144
+ if (f.kind !== 'query') continue
145
+ try {
146
+ declared.push(...(typeof f.def.tags === 'function' ? f.def.tags(star) : (f.def.tags ?? [])))
147
+ } catch {}
148
+ }
149
+ const matches = (tag: string) =>
150
+ declared.some(
151
+ (d) =>
152
+ d === tag ||
153
+ (d.includes('*') &&
154
+ new RegExp(`^${d.replace(/[.+?^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '[^]*')}$`).test(
155
+ tag,
156
+ )) ||
157
+ (tag.includes('*') && d.startsWith(tag.slice(0, tag.indexOf('*')))),
158
+ )
159
+ for (const f of fns.values()) {
160
+ if (f.kind !== 'mutation' || !f.def.invalidates) continue
161
+ let tags: readonly string[]
162
+ try {
163
+ tags =
164
+ typeof f.def.invalidates === 'function' ? f.def.invalidates(star, star) : f.def.invalidates
165
+ } catch {
166
+ continue
167
+ }
168
+ for (const t of tags)
169
+ if (!matches(t))
170
+ report({
171
+ code: 'Q008',
172
+ severity: 'warning',
173
+ message: `\`${f.$id}\` invalidates \`${t}\`, a tag no query declares: nothing refreshes. Fix the tag, or add it to the query's \`tags\``,
174
+ })
175
+ }
176
+ }