@exponential_app/eui 0.0.0-stage → 0.2.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 (272) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +54 -0
  3. package/README.md +377 -2
  4. package/catalog/a11y.json +705 -0
  5. package/catalog/basic-map.json +104 -0
  6. package/catalog/code.json +58 -0
  7. package/catalog/core.catalog.json +5190 -0
  8. package/catalog/core.schema.json +24542 -0
  9. package/catalog/host.json +95 -0
  10. package/catalog/layout.json +20 -0
  11. package/catalog/limits.json +9 -0
  12. package/catalog/locale.json +48 -0
  13. package/catalog/macros.json +4152 -0
  14. package/catalog/recipes.json +64 -0
  15. package/catalog/strings.json +84 -0
  16. package/catalog/style.json +180 -0
  17. package/catalog/theme.schema.json +47754 -0
  18. package/catalog/tokens.json +47 -0
  19. package/conformance/README.md +218 -0
  20. package/conformance/baseline.ts +101 -0
  21. package/conformance/browser-page.ts +146 -0
  22. package/conformance/browser-suites.ts +699 -0
  23. package/conformance/compare.ts +201 -0
  24. package/conformance/dom.ts +97 -0
  25. package/conformance/dump.ts +163 -0
  26. package/conformance/fonts.json +157 -0
  27. package/conformance/manifest.json +233 -0
  28. package/conformance/parity-compare.ts +191 -0
  29. package/conformance/parity-report.schema.json +73 -0
  30. package/conformance/parity.ts +412 -0
  31. package/conformance/pixel.ts +177 -0
  32. package/conformance/primitives-page.ts +49 -0
  33. package/conformance/report.schema.json +66 -0
  34. package/conformance/run.ts +118 -0
  35. package/conformance/voice-wave-child.ts +102 -0
  36. package/dist/chunks/index-5fmaa0xq.js +8384 -0
  37. package/dist/chunks/index-5fmaa0xq.js.map +10 -0
  38. package/dist/chunks/index-62yzr94z.js +2784 -0
  39. package/dist/chunks/index-62yzr94z.js.map +10 -0
  40. package/dist/chunks/index-bg2jsgjq.js +8541 -0
  41. package/dist/chunks/index-bg2jsgjq.js.map +15 -0
  42. package/dist/chunks/index-fy7y2nz8.js +186 -0
  43. package/dist/chunks/index-fy7y2nz8.js.map +9 -0
  44. package/dist/chunks/index-gtk2gwsb.js +4555 -0
  45. package/dist/chunks/index-gtk2gwsb.js.map +31 -0
  46. package/dist/chunks/index-t6qz1770.js +95 -0
  47. package/dist/chunks/index-t6qz1770.js.map +11 -0
  48. package/dist/conformance.js +230462 -0
  49. package/dist/conformance.js.map +10 -0
  50. package/dist/entries/prompt.js +251 -0
  51. package/dist/entries/prompt.js.map +11 -0
  52. package/dist/entries/schema.js +1725 -0
  53. package/dist/entries/schema.js.map +11 -0
  54. package/dist/host/index.js +194 -0
  55. package/dist/host/index.js.map +9 -0
  56. package/dist/index.js +3840 -0
  57. package/dist/index.js.map +29 -0
  58. package/dist/types/src/a11y.d.ts +21 -0
  59. package/dist/types/src/animation.d.ts +76 -0
  60. package/dist/types/src/basic-map.d.ts +38 -0
  61. package/dist/types/src/builder.d.ts +50 -0
  62. package/dist/types/src/catalog.d.ts +54 -0
  63. package/dist/types/src/catalog.described.d.ts +33 -0
  64. package/dist/types/src/catalog.generated.d.ts +904 -0
  65. package/dist/types/src/chart.d.ts +46 -0
  66. package/dist/types/src/code.d.ts +44 -0
  67. package/dist/types/src/color.d.ts +20 -0
  68. package/dist/types/src/conformance.d.ts +39 -0
  69. package/dist/types/src/connector/app.d.ts +14 -0
  70. package/dist/types/src/connector/connector.d.ts +77 -0
  71. package/dist/types/src/connector/index.d.ts +4 -0
  72. package/dist/types/src/css.d.ts +27 -0
  73. package/dist/types/src/define.d.ts +66 -0
  74. package/dist/types/src/direction.d.ts +16 -0
  75. package/dist/types/src/dynamic.d.ts +161 -0
  76. package/dist/types/src/entries/prompt.d.ts +11 -0
  77. package/dist/types/src/entries/schema.d.ts +8 -0
  78. package/dist/types/src/expr.d.ts +71 -0
  79. package/dist/types/src/extension.d.ts +4 -0
  80. package/dist/types/src/format.d.ts +112 -0
  81. package/dist/types/src/geometry.d.ts +40 -0
  82. package/dist/types/src/host/contract.d.ts +225 -0
  83. package/dist/types/src/host/decoders.d.ts +61 -0
  84. package/dist/types/src/host/index.d.ts +15 -0
  85. package/dist/types/src/host/package.d.ts +102 -0
  86. package/dist/types/src/host/policy.d.ts +107 -0
  87. package/dist/types/src/host/record-store.d.ts +103 -0
  88. package/dist/types/src/host/records.d.ts +45 -0
  89. package/dist/types/src/host/router.d.ts +38 -0
  90. package/dist/types/src/host/runtime.d.ts +213 -0
  91. package/dist/types/src/host/signature.d.ts +52 -0
  92. package/dist/types/src/host/sources.d.ts +22 -0
  93. package/dist/types/src/host/tools.d.ts +42 -0
  94. package/dist/types/src/host/transports.d.ts +109 -0
  95. package/dist/types/src/index.d.ts +69 -0
  96. package/dist/types/src/layout.d.ts +20 -0
  97. package/dist/types/src/limits.d.ts +21 -0
  98. package/dist/types/src/list.d.ts +133 -0
  99. package/dist/types/src/locale.d.ts +22 -0
  100. package/dist/types/src/macros.d.ts +29 -0
  101. package/dist/types/src/overlay.d.ts +27 -0
  102. package/dist/types/src/prompt.d.ts +44 -0
  103. package/dist/types/src/qr-code.d.ts +30 -0
  104. package/dist/types/src/recipes.d.ts +17 -0
  105. package/dist/types/src/reducer.d.ts +41 -0
  106. package/dist/types/src/resizable.d.ts +38 -0
  107. package/dist/types/src/schema.d.ts +7 -0
  108. package/dist/types/src/strings.d.ts +13 -0
  109. package/dist/types/src/style.d.ts +201 -0
  110. package/dist/types/src/test-preload.d.ts +1 -0
  111. package/dist/types/src/text-shimmer.d.ts +24 -0
  112. package/dist/types/src/theme-types.d.ts +162 -0
  113. package/dist/types/src/theme.d.ts +75 -0
  114. package/dist/types/src/themes.d.ts +22 -0
  115. package/dist/types/src/tree-guides.d.ts +17 -0
  116. package/dist/types/src/types.d.ts +320 -0
  117. package/dist/types/src/validate.d.ts +31 -0
  118. package/dist/types/src/voice-wave.d.ts +181 -0
  119. package/dist/types/src/web/base-css.d.ts +1 -0
  120. package/dist/types/src/web/box-css.d.ts +63 -0
  121. package/dist/types/src/web/coerce.d.ts +32 -0
  122. package/dist/types/src/web/custom-icons.generated.d.ts +4 -0
  123. package/dist/types/src/web/data.d.ts +107 -0
  124. package/dist/types/src/web/dates.d.ts +12 -0
  125. package/dist/types/src/web/form.d.ts +44 -0
  126. package/dist/types/src/web/host-types.d.ts +126 -0
  127. package/dist/types/src/web/index.d.ts +35 -0
  128. package/dist/types/src/web/inputs.d.ts +55 -0
  129. package/dist/types/src/web/list.d.ts +16 -0
  130. package/dist/types/src/web/listbox.d.ts +14 -0
  131. package/dist/types/src/web/markdown.d.ts +96 -0
  132. package/dist/types/src/web/media.d.ts +63 -0
  133. package/dist/types/src/web/parts.d.ts +4 -0
  134. package/dist/types/src/web/primitives/alert-dialog.d.ts +10 -0
  135. package/dist/types/src/web/primitives/alert.d.ts +9 -0
  136. package/dist/types/src/web/primitives/avatar-color.d.ts +2 -0
  137. package/dist/types/src/web/primitives/avatar.d.ts +13 -0
  138. package/dist/types/src/web/primitives/badge.d.ts +10 -0
  139. package/dist/types/src/web/primitives/breadcrumb.d.ts +10 -0
  140. package/dist/types/src/web/primitives/button.d.ts +6 -0
  141. package/dist/types/src/web/primitives/calendar.d.ts +43 -0
  142. package/dist/types/src/web/primitives/card.d.ts +9 -0
  143. package/dist/types/src/web/primitives/checkbox.d.ts +5 -0
  144. package/dist/types/src/web/primitives/choice-tiles.d.ts +32 -0
  145. package/dist/types/src/web/primitives/cn.d.ts +3 -0
  146. package/dist/types/src/web/primitives/code-block.d.ts +24 -0
  147. package/dist/types/src/web/primitives/command.d.ts +134 -0
  148. package/dist/types/src/web/primitives/context-ring.d.ts +24 -0
  149. package/dist/types/src/web/primitives/dialog-arms.d.ts +6 -0
  150. package/dist/types/src/web/primitives/dialog.d.ts +24 -0
  151. package/dist/types/src/web/primitives/disclosure-header.d.ts +5 -0
  152. package/dist/types/src/web/primitives/dock.d.ts +42 -0
  153. package/dist/types/src/web/primitives/dropdown-menu.d.ts +14 -0
  154. package/dist/types/src/web/primitives/empty-state.d.ts +15 -0
  155. package/dist/types/src/web/primitives/glass-card.d.ts +4 -0
  156. package/dist/types/src/web/primitives/hover-card.d.ts +7 -0
  157. package/dist/types/src/web/primitives/icon-disc.d.ts +12 -0
  158. package/dist/types/src/web/primitives/index.d.ts +50 -0
  159. package/dist/types/src/web/primitives/input.d.ts +5 -0
  160. package/dist/types/src/web/primitives/kbd.d.ts +4 -0
  161. package/dist/types/src/web/primitives/label.d.ts +3 -0
  162. package/dist/types/src/web/primitives/measure.d.ts +16 -0
  163. package/dist/types/src/web/primitives/menu-surface.d.ts +17 -0
  164. package/dist/types/src/web/primitives/meter.d.ts +21 -0
  165. package/dist/types/src/web/primitives/popover.d.ts +3 -0
  166. package/dist/types/src/web/primitives/progress-ring.d.ts +5 -0
  167. package/dist/types/src/web/primitives/progress.d.ts +8 -0
  168. package/dist/types/src/web/primitives/scroll-area.d.ts +49 -0
  169. package/dist/types/src/web/primitives/segmented-control.d.ts +5 -0
  170. package/dist/types/src/web/primitives/select.d.ts +47 -0
  171. package/dist/types/src/web/primitives/separator.d.ts +3 -0
  172. package/dist/types/src/web/primitives/sheet-chrome.d.ts +4 -0
  173. package/dist/types/src/web/primitives/sheet.d.ts +20 -0
  174. package/dist/types/src/web/primitives/skeleton.d.ts +3 -0
  175. package/dist/types/src/web/primitives/spinner.d.ts +3 -0
  176. package/dist/types/src/web/primitives/switch.d.ts +4 -0
  177. package/dist/types/src/web/primitives/table.d.ts +11 -0
  178. package/dist/types/src/web/primitives/tabs.d.ts +13 -0
  179. package/dist/types/src/web/primitives/textarea.d.ts +3 -0
  180. package/dist/types/src/web/primitives/toast.d.ts +163 -0
  181. package/dist/types/src/web/primitives/tooltip.d.ts +3 -0
  182. package/dist/types/src/web/primitives/truncate.d.ts +7 -0
  183. package/dist/types/src/web/primitives/typeahead-portal.d.ts +12 -0
  184. package/dist/types/src/web/primitives/voice-wave.d.ts +50 -0
  185. package/dist/types/src/web/round5.d.ts +107 -0
  186. package/dist/types/src/web/share.d.ts +6 -0
  187. package/dist/types/src/web/table.d.ts +20 -0
  188. package/dist/types/src/web/theme-css.d.ts +69 -0
  189. package/dist/types/src/web/urls.d.ts +21 -0
  190. package/dist/web/index.js +2565 -0
  191. package/dist/web/index.js.map +28 -0
  192. package/dist/web/primitives/index.js +1476 -0
  193. package/dist/web/primitives/index.js.map +57 -0
  194. package/docs/components.generated.json +6783 -0
  195. package/docs/package-format.md +182 -0
  196. package/docs/round-1-contract.md +679 -0
  197. package/docs/round-2-contract.md +476 -0
  198. package/docs/round-3-contract.md +174 -0
  199. package/docs/round-5-contract.md +268 -0
  200. package/docs/themes.generated.json +3647 -0
  201. package/fixtures/animations.json +2890 -0
  202. package/fixtures/bench-list.json +58 -0
  203. package/fixtures/bind-time.json +54734 -0
  204. package/fixtures/catalog-basic-map.json +1692 -0
  205. package/fixtures/catalog-components.json +10293 -0
  206. package/fixtures/catalog-extension.json +620 -0
  207. package/fixtures/catalog-macros.json +51805 -0
  208. package/fixtures/code-tokens.json +1993 -0
  209. package/fixtures/conformance-baseline.json +59016 -0
  210. package/fixtures/conformance-cases.json +49 -0
  211. package/fixtures/conformance-known.json +2111 -0
  212. package/fixtures/control-geometry.json +5129 -0
  213. package/fixtures/dashboard.data.json +74 -0
  214. package/fixtures/dashboard.json +781 -0
  215. package/fixtures/demo-surface.json +47 -0
  216. package/fixtures/format.json +870 -0
  217. package/fixtures/host-package.json +1262 -0
  218. package/fixtures/host-policy.json +1209 -0
  219. package/fixtures/host-router.json +2034 -0
  220. package/fixtures/host-transport.json +590 -0
  221. package/fixtures/interactions-round1.json +1058 -0
  222. package/fixtures/kitchen-sink.expanded.json +11972 -0
  223. package/fixtures/kitchen-sink.json +3140 -0
  224. package/fixtures/layout-geometry-round1.json +7278 -0
  225. package/fixtures/layout-geometry.json +2072 -0
  226. package/fixtures/overlay-geometry.json +272 -0
  227. package/fixtures/pointer.json +89 -0
  228. package/fixtures/primitive-specimens.json +59 -0
  229. package/fixtures/prompt-budget.json +33 -0
  230. package/fixtures/qr-code.json +480 -0
  231. package/fixtures/resizable.json +714 -0
  232. package/fixtures/round4-contract.json +2985 -0
  233. package/fixtures/specimens.json +11168 -0
  234. package/fixtures/style-conditions.json +336 -0
  235. package/fixtures/template-items.json +2215 -0
  236. package/fixtures/text-direction.json +309 -0
  237. package/fixtures/text-shimmer.json +96 -0
  238. package/fixtures/theme-extends.json +573 -0
  239. package/fixtures/theme-invalid.json +1300 -0
  240. package/fixtures/theme-recipes.json +61762 -0
  241. package/fixtures/theme-resolved.json +25969 -0
  242. package/fixtures/toast-stack.json +215 -0
  243. package/fixtures/tree-guides.json +224 -0
  244. package/fixtures/virtual-list.json +733 -0
  245. package/fixtures/voice-wave.json +19236 -0
  246. package/generated/ExponentialUICatalog.generated.kt +67 -0
  247. package/generated/ExponentialUICatalog.generated.swift +67 -0
  248. package/generated/ExponentialUIThemes.generated.kt +23 -0
  249. package/generated/ExponentialUIThemes.generated.swift +23 -0
  250. package/generated/catalog.descriptions.generated.rs +6 -0
  251. package/generated/catalog.generated.rs +80 -0
  252. package/generated/catalog.themes.generated.rs +34 -0
  253. package/generated/core.descriptions.json +2726 -0
  254. package/generated/core.runtime.json +3944 -0
  255. package/package.json +87 -4
  256. package/themes/exponential.recipes.json +49 -0
  257. package/themes/exponential.theme.json +768 -0
  258. package/themes/neutral.theme.json +6178 -0
  259. package/themes/orange.theme.json +43 -0
  260. package/themes/playful.theme.json +219 -0
  261. package/vendor/a2ui/LICENSE.txt +203 -0
  262. package/vendor/a2ui/README.md +27 -0
  263. package/vendor/a2ui/v0_9/basic_catalog.json +1387 -0
  264. package/vendor/a2ui/v0_9/basic_catalog_rules.txt +5 -0
  265. package/vendor/a2ui/v0_9/client_capabilities.json +97 -0
  266. package/vendor/a2ui/v0_9/client_to_server.json +104 -0
  267. package/vendor/a2ui/v0_9/common_types.json +315 -0
  268. package/vendor/a2ui/v0_9/server_to_client.json +132 -0
  269. package/vendor/json-render/LICENSE.txt +201 -0
  270. package/vendor/json-render/README.md +13 -0
  271. package/vendor/nayuki-qr/LICENSE.txt +20 -0
  272. package/vendor/nayuki-qr/README.md +10 -0
@@ -0,0 +1,182 @@
1
+ # The package format (eApps)
2
+
3
+ VAPP-161. One format for an Exponential app and a spezl block: a declarative
4
+ Exponential UI package (VAPP-82: data, never code) plus the file it travels
5
+ in. The format is transport-neutral: it names what a host provides (a record
6
+ store, tool runners, extensions), never how (Exponential serves records from
7
+ its synced store, spezl from a p2p store over eNet). `catalog/host.json`
8
+ `package` is the machine-readable contract; this page is the prose spec other
9
+ docs link to (spezl `docs/spec/blocks.md`). The TS reference is `src/host/`
10
+ (`package.ts`, `records.ts`, `record-store.ts`, `tools.ts`, `signature.ts`);
11
+ the Rust core (`apps/desktop/crates/eui-core/src/host/`) mirrors every
12
+ pure rule. Fixtures: `fixtures/host-router.json` (package validation, replayed
13
+ by every renderer through the core) and `fixtures/host-package.json` (records
14
+ queries and values, tool consent, extension compatibility, canonical JSON,
15
+ signatures).
16
+
17
+ ## Versions
18
+
19
+ A package MAY carry `formatVersion` (a positive integer; absent = 1). This
20
+ document is format version **2** (`catalog/host.json` `package.formatVersion`).
21
+ Version 2 only ADDS optional keys: every version-1 package is a valid
22
+ version-2 package, unchanged. A host refuses a package whose `formatVersion`
23
+ is newer than its own (`/formatVersion: format version 3 is newer than this
24
+ host (2)`); it never guesses at keys it does not know. The catalog a package
25
+ renders against keeps its own version in its id (`catalogId`,
26
+ `…/catalogs/core/v1`) and is negotiated as before (`supportedCatalogIds`).
27
+
28
+ ## The package
29
+
30
+ ```jsonc
31
+ {
32
+ "formatVersion": 2, // optional, default 1
33
+ "id": "acme.hours", "name": "Working hours", "version": "1.2.0",
34
+ "catalogId": "https://ui.exponential.at/catalogs/core/v1",
35
+ "templates": { "<id>": { "components": [/* flat, one root */], "data": {}, "bindings": [{ "path": "/entries", "source": "records:entry?sort=date" }] } },
36
+ "functions": ["records.*", "tools.weather.*"], // allowlist: listed = allow, else deny
37
+ "sources": ["records:*"], // allowlist for bindings, unset = any
38
+ "records": { "entry": { "title": "Entry", "schema": { "type": "object", "properties": { "date": { "type": "string", "format": "date" } } } } },
39
+ "tools": { "weather": { "kind": "mcp", "title": "Weather", "url": "https://mcp.example.com/weather" } },
40
+ "extensions": [{ "id": "https://acme.example/catalogs/charts/v1", "version": "1.4.0", "components": ["Gantt"] }],
41
+ "theme": "exponential", "icon": { "glyph": "clock" }, "description": "…"
42
+ }
43
+ ```
44
+
45
+ Required: `id`, `name`, `version`, `catalogId`, `templates`. Everything else
46
+ is optional and keeps its version-1 meaning (`functions`, `sources`, `theme`,
47
+ `icon`, `description`, `records` kinds: `catalog/host.json` `package`).
48
+
49
+ ## Records
50
+
51
+ An app's own data. `records: {<kind>: {schema, title?, description?}}`
52
+ declares every kind (VAPP-122: the kind pattern, the JSON Schema subset and
53
+ the reserved row keys are in `catalog/host.json` `package.records`). The
54
+ host provides the store; the format fixes what a surface sees and calls.
55
+
56
+ **Read** = the binding source `records:<kind>[?query]`. The value is
57
+ `{rows: [{…data, id, createdAt, updatedAt, createdBy, author}], count}`:
58
+ `count` = the matching rows before `limit`. The neutral query:
59
+
60
+ | key | meaning |
61
+ | --- | --- |
62
+ | `mine=1` | only the viewer's rows (`createdBy` = the viewer) |
63
+ | `sort=<field\|createdAt\|updatedAt>` | default `createdAt` |
64
+ | `order=asc\|desc` | default `desc` (newest first) |
65
+ | `limit=<n>` | default 100, capped at 500 |
66
+ | `<field>=v` | a data field equals `v` (as text) |
67
+ | `<field>.gt\|gte\|lt\|lte=v` | numbers when both parse, else text (code points) |
68
+
69
+ Ties sort by `id`. The keys `kind`, `app`, `user`, `sum`, `by`, `month` are
70
+ RESERVED for host extensions (Exponential implements them: `sum`, the month
71
+ view, another app's rows; `packages/domain-contract/fixtures/app-records.json`);
72
+ a host that does not implement one ignores it, never filters a field by it.
73
+ A template binding to `records:<kind>` names a declared kind (else an install
74
+ issue). A package with a `sources` allowlist lists `records:<kind>` or
75
+ `records:*`.
76
+
77
+ **Write** = two host functions, listed in `functions` like any other (exact
78
+ or `records.*`), never behind a consent card (the app's own rows):
79
+
80
+ - `records.upsert {kind, data, id?}` → `{id}`: creates a record, or with `id`
81
+ shallow-patches that record's `data`. The host validates the result against
82
+ the kind's schema (`validateRecord`) BEFORE it stores anything; a refusal
83
+ fails the call (the host's toast).
84
+ - `records.delete {id}`: deletes one record.
85
+
86
+ Every write lands in every live `records:` binding of the package (on every
87
+ peer, for a p2p store). `RecordStore` (`src/host/record-store.ts`) is the
88
+ interface a host implements; `MemoryRecordStore` + `recordsHost(pkg, store)`
89
+ are the reference (resolver + both functions), `recordsValue` the derivation
90
+ `fixtures/host-package.json` `recordsValue` locks.
91
+
92
+ Exponential: `records:<kind>?q` = its `exp:records?kind=<kind>&q` (the name
93
+ wins over a `kind` param) and `records.*` = `harness.records.*`; both spellings
94
+ stay valid on all four clients.
95
+
96
+ ## Tools
97
+
98
+ `tools: {<id>: Tool}` registers MCP servers or scripts a package's functions
99
+ call. A tool id follows `^[a-z][a-z0-9_-]{0,31}$`.
100
+
101
+ | kind | keys | runs |
102
+ | --- | --- | --- |
103
+ | `mcp` (remote) | `title`, `description?`, `url` (absolute `https:`; `http:` only for a private host the host's URL policy opts in) | an MCP server over Streamable HTTP |
104
+ | `mcp` (local) | `title`, `description?`, `command`, `args?: [string]`, `env?: [NAME]` | an MCP server over stdio, a local process |
105
+ | `script` | `title`, `description?`, `command`, `args?: [string]`, `env?: [NAME]` | one process per call: the call's `args` as JSON on stdin, its stdout (JSON) is the result |
106
+
107
+ An `mcp` tool has exactly one of `url` / `command`. `env` lists variable
108
+ NAMES the host passes through from its own environment; a package never
109
+ carries values or secrets. Functions: an MCP tool's tool `<name>` is the host
110
+ function `tools.<id>.<name>` (args = its arguments); a script is
111
+ `tools.<id>`. They are listed in `functions` like any other.
112
+
113
+ **Consent (the host MUST show it).** No tool runs before the person allowed
114
+ it. Before a tool's FIRST call the host shows a consent card with the tool's
115
+ row from `toolConsent(pkg)`: `{id, kind, transport: http|stdio|script,
116
+ title, description, target, env}`, `target` = the url, or the command line
117
+ exactly as it will run (`command` then every arg, an arg with a space, quote
118
+ or backslash JSON-quoted). Choices: allow (remembered) or deny (the call
119
+ fails `FUNCTION_DENIED`). The remembered grant is keyed by
120
+ `toolConsentKey(packageId, toolId, tool)` = `<packageId>/<toolId>:` + the
121
+ canonical JSON of the tool: ANY change to the definition in a later version
122
+ asks again. A tool call is never `allow` by policy alone; a host that cannot
123
+ run a kind (a browser cannot run a command) refuses its calls with
124
+ `FUNCTION_NOT_FOUND` and says so on the card instead of an allow button.
125
+ Exponential's app hosts run no package tools: its server refuses a package
126
+ with `tools` (an app reaches tools through `exponential.<noun>.<op>` and
127
+ `harness.mcp`).
128
+
129
+ ## Extensions
130
+
131
+ `extensions: [{id, version, components?}]` declares the custom component
132
+ catalogs (eUI extensions, VAPP-85: `defineExtension`) a package needs beyond
133
+ its `catalogId`. `id` = the extension catalog's id, `version` = the minimum
134
+ `MAJOR.MINOR.PATCH` it needs (caret: the host's version has the same major and
135
+ is not lower), `components` = the names the package uses from it. A host
136
+ registers its extensions with a version (`ExtensionDef.version`); install:
137
+
138
+ - an id the host has not registered → `/extensions/<i>/id: extension <id> is
139
+ not available on this host`;
140
+ - a registered version that does not satisfy it → `/extensions/<i>/version:
141
+ extension <id> <have> does not satisfy ^<want>` (an unversioned
142
+ registration satisfies any version);
143
+ - a listed component the registered extension does not define →
144
+ `/extensions/<i>/components/<j>: extension <id> has no component <name>`.
145
+
146
+ The package's own `catalogId` may itself be an extension id (the Exponential
147
+ app extension); it needs no entry.
148
+
149
+ ## The package file
150
+
151
+ A package travels as ONE JSON object holding it under `package`:
152
+ Exponential's export (`<slug>.app.json`, `{format: "exponential-app/1", app,
153
+ package, records?}`, `packages/domain-contract/fixtures/app-export.json`) or
154
+ any other host's envelope. Two optional keys make it attributable:
155
+
156
+ ```jsonc
157
+ {
158
+ "format": "exponential-app/1", "app": { … }, "package": { … }, "records": [ … ],
159
+ "author": { "name": "Ada", "key": "ed25519:<base64url, 32 bytes>" },
160
+ "signature": { "alg": "ed25519", "value": "<base64url, 64 bytes>" }
161
+ }
162
+ ```
163
+
164
+ - `author.name` is a display name (1–80 characters); `author.key` the
165
+ author's Ed25519 public key, `ed25519:` + unpadded base64url.
166
+ - The SIGNED BYTES are UTF-8 of `exponential-ui/package-file/v1\n` followed by
167
+ the canonical JSON of the whole file WITHOUT `signature` (so `author` is
168
+ signed too). Canonical JSON = RFC 8785 (JCS): no whitespace, object keys
169
+ sorted by UTF-16 code units, strings with the minimal JSON escapes, numbers
170
+ in ECMAScript's shortest form (`1`, not `1.0`; `1e+21`).
171
+ - `signature.value` = the Ed25519 signature (RFC 8032) over the signed
172
+ bytes, unpadded base64url.
173
+
174
+ `verifyPackageFile(file)` → `{status: "unsigned"}` (no `signature`; an
175
+ `author` alone is an unverified claim), `{status: "valid", author}` or
176
+ `{status: "invalid", issues}` (a malformed `author`/`signature`, a key or
177
+ signature of the wrong length, or bytes that do not verify). A host refuses
178
+ to import an invalid file and may show a valid one's author;
179
+ `signPackageFile(file, {name, seed})` is the reference signer. The
180
+ fixtures sign with the RFC 8032 §7.1 TEST 1 keypair (never a real key).
181
+ Exponential's own export is unsigned (its members hold no keys); its import
182
+ verifies every signed file on the server (`apps.validateImport`).