@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.
- package/LICENSE +201 -0
- package/NOTICE +54 -0
- package/README.md +377 -2
- package/catalog/a11y.json +705 -0
- package/catalog/basic-map.json +104 -0
- package/catalog/code.json +58 -0
- package/catalog/core.catalog.json +5190 -0
- package/catalog/core.schema.json +24542 -0
- package/catalog/host.json +95 -0
- package/catalog/layout.json +20 -0
- package/catalog/limits.json +9 -0
- package/catalog/locale.json +48 -0
- package/catalog/macros.json +4152 -0
- package/catalog/recipes.json +64 -0
- package/catalog/strings.json +84 -0
- package/catalog/style.json +180 -0
- package/catalog/theme.schema.json +47754 -0
- package/catalog/tokens.json +47 -0
- package/conformance/README.md +218 -0
- package/conformance/baseline.ts +101 -0
- package/conformance/browser-page.ts +146 -0
- package/conformance/browser-suites.ts +699 -0
- package/conformance/compare.ts +201 -0
- package/conformance/dom.ts +97 -0
- package/conformance/dump.ts +163 -0
- package/conformance/fonts.json +157 -0
- package/conformance/manifest.json +233 -0
- package/conformance/parity-compare.ts +191 -0
- package/conformance/parity-report.schema.json +73 -0
- package/conformance/parity.ts +412 -0
- package/conformance/pixel.ts +177 -0
- package/conformance/primitives-page.ts +49 -0
- package/conformance/report.schema.json +66 -0
- package/conformance/run.ts +118 -0
- package/conformance/voice-wave-child.ts +102 -0
- package/dist/chunks/index-5fmaa0xq.js +8384 -0
- package/dist/chunks/index-5fmaa0xq.js.map +10 -0
- package/dist/chunks/index-62yzr94z.js +2784 -0
- package/dist/chunks/index-62yzr94z.js.map +10 -0
- package/dist/chunks/index-bg2jsgjq.js +8541 -0
- package/dist/chunks/index-bg2jsgjq.js.map +15 -0
- package/dist/chunks/index-fy7y2nz8.js +186 -0
- package/dist/chunks/index-fy7y2nz8.js.map +9 -0
- package/dist/chunks/index-gtk2gwsb.js +4555 -0
- package/dist/chunks/index-gtk2gwsb.js.map +31 -0
- package/dist/chunks/index-t6qz1770.js +95 -0
- package/dist/chunks/index-t6qz1770.js.map +11 -0
- package/dist/conformance.js +230462 -0
- package/dist/conformance.js.map +10 -0
- package/dist/entries/prompt.js +251 -0
- package/dist/entries/prompt.js.map +11 -0
- package/dist/entries/schema.js +1725 -0
- package/dist/entries/schema.js.map +11 -0
- package/dist/host/index.js +194 -0
- package/dist/host/index.js.map +9 -0
- package/dist/index.js +3840 -0
- package/dist/index.js.map +29 -0
- package/dist/types/src/a11y.d.ts +21 -0
- package/dist/types/src/animation.d.ts +76 -0
- package/dist/types/src/basic-map.d.ts +38 -0
- package/dist/types/src/builder.d.ts +50 -0
- package/dist/types/src/catalog.d.ts +54 -0
- package/dist/types/src/catalog.described.d.ts +33 -0
- package/dist/types/src/catalog.generated.d.ts +904 -0
- package/dist/types/src/chart.d.ts +46 -0
- package/dist/types/src/code.d.ts +44 -0
- package/dist/types/src/color.d.ts +20 -0
- package/dist/types/src/conformance.d.ts +39 -0
- package/dist/types/src/connector/app.d.ts +14 -0
- package/dist/types/src/connector/connector.d.ts +77 -0
- package/dist/types/src/connector/index.d.ts +4 -0
- package/dist/types/src/css.d.ts +27 -0
- package/dist/types/src/define.d.ts +66 -0
- package/dist/types/src/direction.d.ts +16 -0
- package/dist/types/src/dynamic.d.ts +161 -0
- package/dist/types/src/entries/prompt.d.ts +11 -0
- package/dist/types/src/entries/schema.d.ts +8 -0
- package/dist/types/src/expr.d.ts +71 -0
- package/dist/types/src/extension.d.ts +4 -0
- package/dist/types/src/format.d.ts +112 -0
- package/dist/types/src/geometry.d.ts +40 -0
- package/dist/types/src/host/contract.d.ts +225 -0
- package/dist/types/src/host/decoders.d.ts +61 -0
- package/dist/types/src/host/index.d.ts +15 -0
- package/dist/types/src/host/package.d.ts +102 -0
- package/dist/types/src/host/policy.d.ts +107 -0
- package/dist/types/src/host/record-store.d.ts +103 -0
- package/dist/types/src/host/records.d.ts +45 -0
- package/dist/types/src/host/router.d.ts +38 -0
- package/dist/types/src/host/runtime.d.ts +213 -0
- package/dist/types/src/host/signature.d.ts +52 -0
- package/dist/types/src/host/sources.d.ts +22 -0
- package/dist/types/src/host/tools.d.ts +42 -0
- package/dist/types/src/host/transports.d.ts +109 -0
- package/dist/types/src/index.d.ts +69 -0
- package/dist/types/src/layout.d.ts +20 -0
- package/dist/types/src/limits.d.ts +21 -0
- package/dist/types/src/list.d.ts +133 -0
- package/dist/types/src/locale.d.ts +22 -0
- package/dist/types/src/macros.d.ts +29 -0
- package/dist/types/src/overlay.d.ts +27 -0
- package/dist/types/src/prompt.d.ts +44 -0
- package/dist/types/src/qr-code.d.ts +30 -0
- package/dist/types/src/recipes.d.ts +17 -0
- package/dist/types/src/reducer.d.ts +41 -0
- package/dist/types/src/resizable.d.ts +38 -0
- package/dist/types/src/schema.d.ts +7 -0
- package/dist/types/src/strings.d.ts +13 -0
- package/dist/types/src/style.d.ts +201 -0
- package/dist/types/src/test-preload.d.ts +1 -0
- package/dist/types/src/text-shimmer.d.ts +24 -0
- package/dist/types/src/theme-types.d.ts +162 -0
- package/dist/types/src/theme.d.ts +75 -0
- package/dist/types/src/themes.d.ts +22 -0
- package/dist/types/src/tree-guides.d.ts +17 -0
- package/dist/types/src/types.d.ts +320 -0
- package/dist/types/src/validate.d.ts +31 -0
- package/dist/types/src/voice-wave.d.ts +181 -0
- package/dist/types/src/web/base-css.d.ts +1 -0
- package/dist/types/src/web/box-css.d.ts +63 -0
- package/dist/types/src/web/coerce.d.ts +32 -0
- package/dist/types/src/web/custom-icons.generated.d.ts +4 -0
- package/dist/types/src/web/data.d.ts +107 -0
- package/dist/types/src/web/dates.d.ts +12 -0
- package/dist/types/src/web/form.d.ts +44 -0
- package/dist/types/src/web/host-types.d.ts +126 -0
- package/dist/types/src/web/index.d.ts +35 -0
- package/dist/types/src/web/inputs.d.ts +55 -0
- package/dist/types/src/web/list.d.ts +16 -0
- package/dist/types/src/web/listbox.d.ts +14 -0
- package/dist/types/src/web/markdown.d.ts +96 -0
- package/dist/types/src/web/media.d.ts +63 -0
- package/dist/types/src/web/parts.d.ts +4 -0
- package/dist/types/src/web/primitives/alert-dialog.d.ts +10 -0
- package/dist/types/src/web/primitives/alert.d.ts +9 -0
- package/dist/types/src/web/primitives/avatar-color.d.ts +2 -0
- package/dist/types/src/web/primitives/avatar.d.ts +13 -0
- package/dist/types/src/web/primitives/badge.d.ts +10 -0
- package/dist/types/src/web/primitives/breadcrumb.d.ts +10 -0
- package/dist/types/src/web/primitives/button.d.ts +6 -0
- package/dist/types/src/web/primitives/calendar.d.ts +43 -0
- package/dist/types/src/web/primitives/card.d.ts +9 -0
- package/dist/types/src/web/primitives/checkbox.d.ts +5 -0
- package/dist/types/src/web/primitives/choice-tiles.d.ts +32 -0
- package/dist/types/src/web/primitives/cn.d.ts +3 -0
- package/dist/types/src/web/primitives/code-block.d.ts +24 -0
- package/dist/types/src/web/primitives/command.d.ts +134 -0
- package/dist/types/src/web/primitives/context-ring.d.ts +24 -0
- package/dist/types/src/web/primitives/dialog-arms.d.ts +6 -0
- package/dist/types/src/web/primitives/dialog.d.ts +24 -0
- package/dist/types/src/web/primitives/disclosure-header.d.ts +5 -0
- package/dist/types/src/web/primitives/dock.d.ts +42 -0
- package/dist/types/src/web/primitives/dropdown-menu.d.ts +14 -0
- package/dist/types/src/web/primitives/empty-state.d.ts +15 -0
- package/dist/types/src/web/primitives/glass-card.d.ts +4 -0
- package/dist/types/src/web/primitives/hover-card.d.ts +7 -0
- package/dist/types/src/web/primitives/icon-disc.d.ts +12 -0
- package/dist/types/src/web/primitives/index.d.ts +50 -0
- package/dist/types/src/web/primitives/input.d.ts +5 -0
- package/dist/types/src/web/primitives/kbd.d.ts +4 -0
- package/dist/types/src/web/primitives/label.d.ts +3 -0
- package/dist/types/src/web/primitives/measure.d.ts +16 -0
- package/dist/types/src/web/primitives/menu-surface.d.ts +17 -0
- package/dist/types/src/web/primitives/meter.d.ts +21 -0
- package/dist/types/src/web/primitives/popover.d.ts +3 -0
- package/dist/types/src/web/primitives/progress-ring.d.ts +5 -0
- package/dist/types/src/web/primitives/progress.d.ts +8 -0
- package/dist/types/src/web/primitives/scroll-area.d.ts +49 -0
- package/dist/types/src/web/primitives/segmented-control.d.ts +5 -0
- package/dist/types/src/web/primitives/select.d.ts +47 -0
- package/dist/types/src/web/primitives/separator.d.ts +3 -0
- package/dist/types/src/web/primitives/sheet-chrome.d.ts +4 -0
- package/dist/types/src/web/primitives/sheet.d.ts +20 -0
- package/dist/types/src/web/primitives/skeleton.d.ts +3 -0
- package/dist/types/src/web/primitives/spinner.d.ts +3 -0
- package/dist/types/src/web/primitives/switch.d.ts +4 -0
- package/dist/types/src/web/primitives/table.d.ts +11 -0
- package/dist/types/src/web/primitives/tabs.d.ts +13 -0
- package/dist/types/src/web/primitives/textarea.d.ts +3 -0
- package/dist/types/src/web/primitives/toast.d.ts +163 -0
- package/dist/types/src/web/primitives/tooltip.d.ts +3 -0
- package/dist/types/src/web/primitives/truncate.d.ts +7 -0
- package/dist/types/src/web/primitives/typeahead-portal.d.ts +12 -0
- package/dist/types/src/web/primitives/voice-wave.d.ts +50 -0
- package/dist/types/src/web/round5.d.ts +107 -0
- package/dist/types/src/web/share.d.ts +6 -0
- package/dist/types/src/web/table.d.ts +20 -0
- package/dist/types/src/web/theme-css.d.ts +69 -0
- package/dist/types/src/web/urls.d.ts +21 -0
- package/dist/web/index.js +2565 -0
- package/dist/web/index.js.map +28 -0
- package/dist/web/primitives/index.js +1476 -0
- package/dist/web/primitives/index.js.map +57 -0
- package/docs/components.generated.json +6783 -0
- package/docs/package-format.md +182 -0
- package/docs/round-1-contract.md +679 -0
- package/docs/round-2-contract.md +476 -0
- package/docs/round-3-contract.md +174 -0
- package/docs/round-5-contract.md +268 -0
- package/docs/themes.generated.json +3647 -0
- package/fixtures/animations.json +2890 -0
- package/fixtures/bench-list.json +58 -0
- package/fixtures/bind-time.json +54734 -0
- package/fixtures/catalog-basic-map.json +1692 -0
- package/fixtures/catalog-components.json +10293 -0
- package/fixtures/catalog-extension.json +620 -0
- package/fixtures/catalog-macros.json +51805 -0
- package/fixtures/code-tokens.json +1993 -0
- package/fixtures/conformance-baseline.json +59016 -0
- package/fixtures/conformance-cases.json +49 -0
- package/fixtures/conformance-known.json +2111 -0
- package/fixtures/control-geometry.json +5129 -0
- package/fixtures/dashboard.data.json +74 -0
- package/fixtures/dashboard.json +781 -0
- package/fixtures/demo-surface.json +47 -0
- package/fixtures/format.json +870 -0
- package/fixtures/host-package.json +1262 -0
- package/fixtures/host-policy.json +1209 -0
- package/fixtures/host-router.json +2034 -0
- package/fixtures/host-transport.json +590 -0
- package/fixtures/interactions-round1.json +1058 -0
- package/fixtures/kitchen-sink.expanded.json +11972 -0
- package/fixtures/kitchen-sink.json +3140 -0
- package/fixtures/layout-geometry-round1.json +7278 -0
- package/fixtures/layout-geometry.json +2072 -0
- package/fixtures/overlay-geometry.json +272 -0
- package/fixtures/pointer.json +89 -0
- package/fixtures/primitive-specimens.json +59 -0
- package/fixtures/prompt-budget.json +33 -0
- package/fixtures/qr-code.json +480 -0
- package/fixtures/resizable.json +714 -0
- package/fixtures/round4-contract.json +2985 -0
- package/fixtures/specimens.json +11168 -0
- package/fixtures/style-conditions.json +336 -0
- package/fixtures/template-items.json +2215 -0
- package/fixtures/text-direction.json +309 -0
- package/fixtures/text-shimmer.json +96 -0
- package/fixtures/theme-extends.json +573 -0
- package/fixtures/theme-invalid.json +1300 -0
- package/fixtures/theme-recipes.json +61762 -0
- package/fixtures/theme-resolved.json +25969 -0
- package/fixtures/toast-stack.json +215 -0
- package/fixtures/tree-guides.json +224 -0
- package/fixtures/virtual-list.json +733 -0
- package/fixtures/voice-wave.json +19236 -0
- package/generated/ExponentialUICatalog.generated.kt +67 -0
- package/generated/ExponentialUICatalog.generated.swift +67 -0
- package/generated/ExponentialUIThemes.generated.kt +23 -0
- package/generated/ExponentialUIThemes.generated.swift +23 -0
- package/generated/catalog.descriptions.generated.rs +6 -0
- package/generated/catalog.generated.rs +80 -0
- package/generated/catalog.themes.generated.rs +34 -0
- package/generated/core.descriptions.json +2726 -0
- package/generated/core.runtime.json +3944 -0
- package/package.json +87 -4
- package/themes/exponential.recipes.json +49 -0
- package/themes/exponential.theme.json +768 -0
- package/themes/neutral.theme.json +6178 -0
- package/themes/orange.theme.json +43 -0
- package/themes/playful.theme.json +219 -0
- package/vendor/a2ui/LICENSE.txt +203 -0
- package/vendor/a2ui/README.md +27 -0
- package/vendor/a2ui/v0_9/basic_catalog.json +1387 -0
- package/vendor/a2ui/v0_9/basic_catalog_rules.txt +5 -0
- package/vendor/a2ui/v0_9/client_capabilities.json +97 -0
- package/vendor/a2ui/v0_9/client_to_server.json +104 -0
- package/vendor/a2ui/v0_9/common_types.json +315 -0
- package/vendor/a2ui/v0_9/server_to_client.json +132 -0
- package/vendor/json-render/LICENSE.txt +201 -0
- package/vendor/json-render/README.md +13 -0
- package/vendor/nayuki-qr/LICENSE.txt +20 -0
- 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`).
|