@maelstrom-co/react 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 (74) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +75 -2
  3. package/dist/_testing.d.ts +13 -0
  4. package/dist/_testing.d.ts.map +1 -0
  5. package/dist/_testing.js +1 -0
  6. package/dist/index.d.ts +16 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +5110 -0
  9. package/dist/lib/build-execute-action.d.ts +9 -0
  10. package/dist/lib/build-execute-action.d.ts.map +1 -0
  11. package/dist/lib/chart/chart.d.ts +14 -0
  12. package/dist/lib/chart/chart.d.ts.map +1 -0
  13. package/dist/lib/chart/error-boundary.d.ts +17 -0
  14. package/dist/lib/chart/error-boundary.d.ts.map +1 -0
  15. package/dist/lib/chart/loading.d.ts +14 -0
  16. package/dist/lib/chart/loading.d.ts.map +1 -0
  17. package/dist/lib/chart/motion/flip.d.ts +18 -0
  18. package/dist/lib/chart/motion/flip.d.ts.map +1 -0
  19. package/dist/lib/chart/motion/measure.d.ts +8 -0
  20. package/dist/lib/chart/motion/measure.d.ts.map +1 -0
  21. package/dist/lib/chart/motion/motion-config.d.ts +27 -0
  22. package/dist/lib/chart/motion/motion-config.d.ts.map +1 -0
  23. package/dist/lib/chart/motion/use-chart-motion.d.ts +7 -0
  24. package/dist/lib/chart/motion/use-chart-motion.d.ts.map +1 -0
  25. package/dist/lib/chart/motion/use-exiting-instances.d.ts +9 -0
  26. package/dist/lib/chart/motion/use-exiting-instances.d.ts.map +1 -0
  27. package/dist/lib/config-types.d.ts +29 -0
  28. package/dist/lib/config-types.d.ts.map +1 -0
  29. package/dist/lib/context.d.ts +42 -0
  30. package/dist/lib/context.d.ts.map +1 -0
  31. package/dist/lib/create-maelstrom.d.ts +39 -0
  32. package/dist/lib/create-maelstrom.d.ts.map +1 -0
  33. package/dist/lib/dynamic-vessel-types.d.ts +57 -0
  34. package/dist/lib/dynamic-vessel-types.d.ts.map +1 -0
  35. package/dist/lib/extension-types.d.ts +58 -0
  36. package/dist/lib/extension-types.d.ts.map +1 -0
  37. package/dist/lib/maelstrom-instance-types.d.ts +228 -0
  38. package/dist/lib/maelstrom-instance-types.d.ts.map +1 -0
  39. package/dist/lib/maelstrom-state-types.d.ts +30 -0
  40. package/dist/lib/maelstrom-state-types.d.ts.map +1 -0
  41. package/dist/lib/provider.d.ts +135 -0
  42. package/dist/lib/provider.d.ts.map +1 -0
  43. package/dist/lib/register-vessel.d.ts +13 -0
  44. package/dist/lib/register-vessel.d.ts.map +1 -0
  45. package/dist/lib/require-context.d.ts +9 -0
  46. package/dist/lib/require-context.d.ts.map +1 -0
  47. package/dist/lib/update-vessel.d.ts +21 -0
  48. package/dist/lib/update-vessel.d.ts.map +1 -0
  49. package/dist/lib/use-actions.d.ts +19 -0
  50. package/dist/lib/use-actions.d.ts.map +1 -0
  51. package/dist/lib/use-instance.d.ts +11 -0
  52. package/dist/lib/use-instance.d.ts.map +1 -0
  53. package/dist/lib/use-intent-submission.d.ts +8 -0
  54. package/dist/lib/use-intent-submission.d.ts.map +1 -0
  55. package/dist/lib/use-latest-ref.d.ts +4 -0
  56. package/dist/lib/use-latest-ref.d.ts.map +1 -0
  57. package/dist/lib/use-maelstrom.d.ts +7 -0
  58. package/dist/lib/use-maelstrom.d.ts.map +1 -0
  59. package/dist/lib/use-store-selector.d.ts +17 -0
  60. package/dist/lib/use-store-selector.d.ts.map +1 -0
  61. package/dist/lib/use-vessel-core.d.ts +18 -0
  62. package/dist/lib/use-vessel-core.d.ts.map +1 -0
  63. package/dist/lib/use-vessel.d.ts +7 -0
  64. package/dist/lib/use-vessel.d.ts.map +1 -0
  65. package/dist/lib/vessel-entry-types.d.ts +170 -0
  66. package/dist/lib/vessel-entry-types.d.ts.map +1 -0
  67. package/dist/lib/vessel.d.ts +10 -0
  68. package/dist/lib/vessel.d.ts.map +1 -0
  69. package/dist/lib/warn-once.d.ts +23 -0
  70. package/dist/lib/warn-once.d.ts.map +1 -0
  71. package/dist/warn-once-Cq9ShMdA.js +10 -0
  72. package/package.json +83 -4
  73. package/skills/maelstrom-react-sdk/SKILL.md +29 -0
  74. package/skills/maelstrom-react-sdk/references/common-tasks.md +146 -0
@@ -0,0 +1,170 @@
1
+ import { ActionNames, ActionParams, ActionRunner, VariantNames } from '@maelstrom-co/client';
2
+ import { ActionName, InstanceId, VariantName, VesselDefinition, VesselId, VesselVariantDefinition } from '@maelstrom-co/protocol';
3
+ import { ComponentType } from 'react';
4
+ /**
5
+ * Discriminated union of variant prop shapes for vessel `V`.
6
+ *
7
+ * For each variant `K` in `V`, contributes a member
8
+ * `{ variant: K } & V['variants'][K]['props']`. Components consume this
9
+ * to render different content per variant while preserving literal-type
10
+ * narrowing on the `variant` discriminant.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * function OrdersComponent({ variantProps }: { variantProps: VariantProps<typeof ordersVessel> }) {
15
+ * if (variantProps.variant === 'list') {
16
+ * // variantProps narrowed to the 'list' variant's props
17
+ * }
18
+ * }
19
+ * ```
20
+ */
21
+ export type VariantProps<V extends VesselDefinition> = {
22
+ [K in VariantNames<V>]: {
23
+ variant: K;
24
+ } & V['variants'][K]['props'];
25
+ }[VariantNames<V>];
26
+ /** Typed props delivered to a vessel component */
27
+ export interface TypedVesselProps<V extends VesselDefinition> {
28
+ instanceId: InstanceId;
29
+ variantProps: VariantProps<V>;
30
+ executeAction: <N extends ActionNames<V>>(...args: ActionParams<V, N> extends undefined ? [name: N] : [name: N, params: ActionParams<V, N>]) => void;
31
+ }
32
+ /** Eager vessel entry — component is already loaded */
33
+ export interface VesselEntry<V extends VesselDefinition> {
34
+ vessel: V;
35
+ component: ComponentType<TypedVesselProps<V>>;
36
+ }
37
+ /** Lazy loader function for a vessel component */
38
+ export type LazyVesselComponentLoader<V extends VesselDefinition> = () => Promise<{
39
+ default: ComponentType<TypedVesselProps<V>>;
40
+ }>;
41
+ /** Lazy vessel entry — component is loaded on demand */
42
+ export interface LazyVesselEntry<V extends VesselDefinition> {
43
+ vessel: V;
44
+ component: LazyVesselComponentLoader<V>;
45
+ loadingComponent: ComponentType<{
46
+ vesselId: VesselId;
47
+ }>;
48
+ }
49
+ export type AnyVesselEntry<T extends VesselDefinition = any> = VesselEntry<T> | LazyVesselEntry<T>;
50
+ /** Discriminant: lazy entries carry a loadingComponent, eager ones don't. */
51
+ export declare function isLazyEntry(entry: AnyVesselEntry): entry is LazyVesselEntry<any>;
52
+ /** Extract vessel IDs from a tuple of vessel entries */
53
+ export type VesselIds<TVessels extends readonly AnyVesselEntry[]> = TVessels[number]['vessel']['id'];
54
+ /**
55
+ * Extract the Vessel definition type from a tuple of entries by its literal ID.
56
+ *
57
+ * @example
58
+ * type CalendarVessel = ExtractVesselByIdFromEntries<typeof entries, 'calendar'>;
59
+ */
60
+ export type ExtractVesselByIdFromEntries<T extends readonly AnyVesselEntry[], Id extends VesselIds<T>> = Extract<T[number], {
61
+ vessel: {
62
+ id: Id;
63
+ };
64
+ }>['vessel'];
65
+ /**
66
+ * Pre-computed lookup mapping vessel IDs to their ActionRunner types.
67
+ * Avoids deep generic resolution at call sites (helps tsc --build inference).
68
+ */
69
+ export type ActionRunnerLookup<T extends readonly AnyVesselEntry[]> = {
70
+ [E in T[number] as E['vessel']['id']]: ActionRunner<E['vessel']>;
71
+ };
72
+ /**
73
+ * A vessel definition safe to hand to `m.updateVessel()` or `handle.update()`
74
+ * to republish `V`'s definition without remounting its component.
75
+ *
76
+ * `props` is the crash surface: the rendered component and the hook that
77
+ * feeds it read `props` straight off the store and hand it to the mounted
78
+ * component, so a shape drift throws at render time instead of failing to
79
+ * compile. `actions`, `enum` values, `description`, and `minSize` stay
80
+ * free-form — pinning them too would break the documented republish use
81
+ * case of rebuilding an action's `enum` from live data.
82
+ *
83
+ * `variants` is a `Record<string, ...>`, not a per-key mapped type over
84
+ * `VariantNames<V>`, because `Object.fromEntries` — the documented rebuild
85
+ * idiom — returns a plain index-signature type with no named keys at all.
86
+ * No object type with required named properties can ever accept that
87
+ * return value, regardless of how loosely those properties are typed, so
88
+ * the target has to be an index signature too. The cost: props are checked
89
+ * against the union of every registered variant's props, not the specific
90
+ * variant named at that key, so a value shaped like variant B's props
91
+ * passes at variant A's key. What this still catches is the actual crash —
92
+ * a shape that matches none of the vessel's registered variants.
93
+ */
94
+ export type RepublishableVessel<V extends VesselDefinition> = VesselDefinition & {
95
+ id: V['id'];
96
+ variants: Record<string, VesselVariantDefinition & {
97
+ props: V['variants'][VariantNames<V>]['props'];
98
+ }>;
99
+ };
100
+ /**
101
+ * Payload type for `m.updateVessel({ id, ... })` — `Id` must be one of the
102
+ * vessel IDs declared in `createMaelstrom({ vessels })`, so a typo'd or
103
+ * runtime-only id fails to compile instead of silently skipping the
104
+ * `RepublishableVessel` shape check.
105
+ *
106
+ * `T` only knows the vessels declared in `createMaelstrom({ vessels })` —
107
+ * `registerVessel()` adds ids at runtime that never appear in `T`, so
108
+ * `m.updateVessel()` cannot name them. Republish a runtime-registered
109
+ * vessel through `handle.update()` on the handle `registerVessel()`
110
+ * returns instead — it is typed exactly to that call's inferred vessel
111
+ * definition, with no id lookup needed.
112
+ */
113
+ export type UpdateVesselPayload<T extends readonly AnyVesselEntry[], Id extends VesselIds<T>> = RepublishableVessel<ExtractVesselByIdFromEntries<T, Id>> & {
114
+ id: Id;
115
+ };
116
+ /**
117
+ * Discriminates the recoverable ways `m.updateVessel()` / `handle.update()`
118
+ * can refuse a republish. See {@link UpdateVesselConflict} for the payload
119
+ * each code carries.
120
+ */
121
+ export type UpdateVesselConflictCode = 'variant_dropped' | 'action_dropped' | 'batch_in_flight';
122
+ /**
123
+ * The recoverable reason a republish did not commit — returned as data by
124
+ * `m.updateVessel()` / `handle.update()`, never thrown.
125
+ *
126
+ * `'variant_dropped'` and `'action_dropped'` are ordinary, user-triggerable
127
+ * states, not programmer mistakes — for example a `detail` variant that
128
+ * only exists while its record does, and the user just deleted that
129
+ * record. `'batch_in_flight'` means a command batch was already queued or
130
+ * executing when the republish was attempted: CommandProcessor applies
131
+ * `set_layout` / `execute_actions` through an async queue, so the instance
132
+ * snapshot a conflict scan would read from is not yet trustworthy — that
133
+ * in-flight batch could still land an instance on a variant the republish
134
+ * is about to drop.
135
+ *
136
+ * Branch on `code`, not on `message` text, which this package is free to
137
+ * reword.
138
+ */
139
+ export type UpdateVesselConflict = {
140
+ code: 'variant_dropped';
141
+ vesselId: VesselId;
142
+ instanceId: InstanceId;
143
+ variant: VariantName;
144
+ message: string;
145
+ } | {
146
+ code: 'action_dropped';
147
+ vesselId: VesselId;
148
+ instanceId: InstanceId;
149
+ variant: VariantName;
150
+ missingActionNames: readonly ActionName[];
151
+ message: string;
152
+ } | {
153
+ code: 'batch_in_flight';
154
+ vesselId: VesselId;
155
+ message: string;
156
+ };
157
+ /**
158
+ * Return type of `m.updateVessel()` and `handle.update()`.
159
+ *
160
+ * `ok: false` is an ordinary, user-triggerable outcome, not a bug report —
161
+ * check `result.conflict.code` and decide whether to retry, skip the
162
+ * republish, or surface a message.
163
+ */
164
+ export type UpdateVesselResult = {
165
+ ok: true;
166
+ } | {
167
+ ok: false;
168
+ conflict: UpdateVesselConflict;
169
+ };
170
+ //# sourceMappingURL=vessel-entry-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vessel-entry-types.d.ts","sourceRoot":"","sources":["../../src/lib/vessel-entry-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { VesselDefinition, VesselId } from '@maelstrom-co/protocol';
2
+ import { ComponentType } from 'react';
3
+ import { LazyVesselComponentLoader, LazyVesselEntry, TypedVesselProps, VesselEntry } from './vessel-entry-types.js';
4
+ /** Register a vessel with an eagerly-loaded component */
5
+ export declare function vessel<const V extends VesselDefinition>(definition: V, component: ComponentType<TypedVesselProps<V>>): VesselEntry<V>;
6
+ /** Register a vessel with a lazily-loaded component */
7
+ export declare function vessel<const V extends VesselDefinition>(definition: V, loader: LazyVesselComponentLoader<V>, loadingComponent: ComponentType<{
8
+ vesselId: VesselId;
9
+ }>): LazyVesselEntry<V>;
10
+ //# sourceMappingURL=vessel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vessel.d.ts","sourceRoot":"","sources":["../../src/lib/vessel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EACV,yBAAyB,EACzB,eAAe,EACf,gBAAgB,EAChB,WAAW,EACZ,MAAM,yBAAyB,CAAC;AAEjC,yDAAyD;AACzD,wBAAgB,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,gBAAgB,EACrD,UAAU,EAAE,CAAC,EACb,SAAS,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,GAC5C,WAAW,CAAC,CAAC,CAAC,CAAC;AAElB,uDAAuD;AACvD,wBAAgB,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,gBAAgB,EACrD,UAAU,EAAE,CAAC,EACb,MAAM,EAAE,yBAAyB,CAAC,CAAC,CAAC,EACpC,gBAAgB,EAAE,aAAa,CAAC;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,GACtD,eAAe,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ interface WarnOnceOptions {
2
+ enabled?: boolean;
3
+ }
4
+ /**
5
+ * Emits a console warning for the first enabled call for a key in this loaded
6
+ * module instance. Later enabled calls with the same key are no-ops, regardless
7
+ * of their message. Disabled calls neither emit a warning nor record the key.
8
+ * State is not shared across processes, realms, or separately loaded copies.
9
+ */
10
+ export declare function warnOnce(key: string, message: string, options?: WarnOnceOptions): void;
11
+ /**
12
+ * Clears warning keys recorded by this loaded module instance.
13
+ *
14
+ * An empty-state reset is a no-op. After a reset, the next enabled
15
+ * {@link warnOnce} call for a previously recorded key emits again. The reset is
16
+ * local to this package copy in the current process and does not affect other
17
+ * processes, realms, or separately loaded copies. Application code receives
18
+ * neither warning-state function from the package root; tests can access only
19
+ * this reset through `@maelstrom-co/react/_testing`.
20
+ */
21
+ export declare function resetWarnings(): void;
22
+ export {};
23
+ //# sourceMappingURL=warn-once.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warn-once.d.ts","sourceRoot":"","sources":["../../src/lib/warn-once.ts"],"names":[],"mappings":"AAEA,UAAU,eAAe;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,eAAe,QAM1B;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,SAE5B"}
@@ -0,0 +1,10 @@
1
+ //#region src/lib/warn-once.ts
2
+ var e = /* @__PURE__ */ new Set();
3
+ function t(t, n, r) {
4
+ (r?.enabled ?? !0) && !e.has(t) && (e.add(t), console.warn(n));
5
+ }
6
+ function n() {
7
+ e.clear();
8
+ }
9
+ //#endregion
10
+ export { t as n, n as t };
package/package.json CHANGED
@@ -1,6 +1,85 @@
1
1
  {
2
2
  "name": "@maelstrom-co/react",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "React bindings for Maelstrom: Provider, Chart, connectors, vessel definitions, and hooks for AI-orchestrated dynamic UI.",
5
+ "keywords": [
6
+ "maelstrom",
7
+ "ai",
8
+ "llm",
9
+ "dynamic-ui",
10
+ "generative-ui",
11
+ "react",
12
+ "react-hooks",
13
+ "ui"
14
+ ],
15
+ "license": "MIT",
16
+ "type": "module",
17
+ "sideEffects": false,
18
+ "main": "./dist/index.js",
19
+ "module": "./dist/index.js",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ "./package.json": "./package.json",
23
+ ".": {
24
+ "@maelstrom-co/source": "./src/index.ts",
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js",
27
+ "default": "./dist/index.js"
28
+ },
29
+ "./_testing": {
30
+ "@maelstrom-co/source": "./src/_testing.ts",
31
+ "types": "./dist/_testing.d.ts",
32
+ "import": "./dist/_testing.js",
33
+ "default": "./dist/_testing.js"
34
+ }
35
+ },
36
+ "files": [
37
+ "dist",
38
+ "skills",
39
+ "!**/*.tsbuildinfo"
40
+ ],
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/maelstrom-co/maelstrom.git",
44
+ "directory": "packages/react"
45
+ },
46
+ "homepage": "https://maelstrom-ai.co",
47
+ "bugs": {
48
+ "url": "https://github.com/maelstrom-co/maelstrom/issues"
49
+ },
50
+ "author": "Maelstrom (https://maelstrom-ai.co)",
51
+ "publishConfig": {
52
+ "registry": "https://registry.npmjs.org",
53
+ "access": "public"
54
+ },
55
+ "dependencies": {
56
+ "@maelstrom-co/client": "0.1.0",
57
+ "@maelstrom-co/protocol": "0.1.0",
58
+ "@tanstack/react-store": "^0.9.2"
59
+ },
60
+ "devDependencies": {
61
+ "@sinonjs/fake-timers": "^15.1.1",
62
+ "@testing-library/react": "^16.3.1",
63
+ "happy-dom": "^20.8.4"
64
+ },
65
+ "peerDependencies": {
66
+ "react": ">=18.0.0",
67
+ "react-dom": ">=18.0.0"
68
+ },
69
+ "nx": {
70
+ "targets": {
71
+ "typecheck": {
72
+ "command": "tsc -p tsconfig.lib.json --noEmit && tsc -p tsconfig.spec.json --noEmit",
73
+ "options": {
74
+ "cwd": "{projectRoot}"
75
+ }
76
+ },
77
+ "test": {
78
+ "command": "bun test",
79
+ "options": {
80
+ "cwd": "{projectRoot}"
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: maelstrom-react-sdk
3
+ description: >-
4
+ Version-matched API guide for @maelstrom-co/react. Load when implementing or
5
+ reviewing Maelstrom React bindings and this package is installed; check the owning installed package manifest before relying on API names.
6
+ license: MIT
7
+ metadata:
8
+ author: Maelstrom
9
+ sdkPackage: '@maelstrom-co/react'
10
+ ---
11
+
12
+ # Maelstrom React SDK
13
+
14
+ This guide is published inside its owning package. Before use, read the
15
+ installed package's `package.json` version as the version authority. If the guide
16
+ is not shipped by that exact installed package, do not rely on it: inspect the
17
+ installation's `exports`, declarations, source, and tests instead.
18
+
19
+ The installed public entrypoint exports `createMaelstrom`, `vessel`, and
20
+ `defineVessel`, and exposes the `ChartProps` and `MaelstromProviderProps` types.
21
+ Confirm names and call signatures against the installed entrypoint/declarations
22
+ before use; do not assume `MaelstromProvider` itself is a named export just
23
+ because that type exists. Keep framework-independent lifecycle and connection
24
+ logic in its owning SDK package; application data, authorization, and side
25
+ effects remain application-owned.
26
+
27
+ When registering a Vessel, wiring Provider/Chart, seeding a tiling first screen,
28
+ testing Chart in a DOM, or diagnosing bootstrap errors, read
29
+ [common tasks](references/common-tasks.md) before choosing the integration.
@@ -0,0 +1,146 @@
1
+ # Register a read-only capability
2
+
3
+ Inspect the existing renderer and its data owner first. Keep incidental controls
4
+ inside the capability. This example registers one Variant without Actions; its
5
+ one-cell minimum is illustrative, not a measurement of your application's UI.
6
+
7
+ ```tsx
8
+ import type { EngineConnector } from '@maelstrom-co/client';
9
+ import { createMaelstrom, defineVessel, vessel } from '@maelstrom-co/react';
10
+
11
+ const status = defineVessel({
12
+ id: 'status',
13
+ name: 'Status',
14
+ description: 'Show the application status',
15
+ defaultVariant: 'summary',
16
+ variants: {
17
+ summary: { props: {}, minSize: { width: 1, height: 1 }, actions: [] },
18
+ },
19
+ });
20
+
21
+ function Status() {
22
+ return <section aria-label="Application status">Ready</section>;
23
+ }
24
+
25
+ export const m = createMaelstrom({ vessels: [vessel(status, Status)] });
26
+
27
+ export function StatusChart({ connector }: { connector: EngineConnector }) {
28
+ return <m.Provider connector={connector}><m.Chart /></m.Provider>;
29
+ }
30
+ ```
31
+
32
+ Create the instance outside component rendering. Supply your application's
33
+ configured Connector. The instance owns `Provider` and `Chart`; these are not
34
+ standalone named package exports. Preserve a legacy path when migrating.
35
+
36
+ For Actions, keep authorization, confirmation, and effects in application-owned
37
+ handlers. For definition changes, preserve every existing Variant and Action;
38
+ inspect the returned update conflicts before deciding how to proceed.
39
+
40
+ ## Seed a tiling first screen
41
+
42
+ Use this branch when a registered capability must appear before the first Engine
43
+ response. Keep the configured Connector and scope the Provider to the migrated
44
+ surface. Register the existing renderer statically; the Engine arranges Instances
45
+ of that renderer rather than generating runtime JSX.
46
+ Mount this surface in the application's sized Chart container.
47
+
48
+ ```tsx
49
+ import type { EngineConnector } from '@maelstrom-co/client';
50
+ import {
51
+ InstanceId,
52
+ type TilingLayout,
53
+ VariantName,
54
+ VesselId,
55
+ tilingLeafToken,
56
+ } from '@maelstrom-co/protocol';
57
+ import { createMaelstrom, defineVessel, vessel } from '@maelstrom-co/react';
58
+
59
+ const status = defineVessel({
60
+ id: 'status',
61
+ name: 'Status',
62
+ description: 'Show the application status',
63
+ defaultVariant: 'summary',
64
+ variants: {
65
+ summary: { props: {}, minSize: { width: 1, height: 1 }, actions: [] },
66
+ },
67
+ });
68
+
69
+ function Status() {
70
+ return <section aria-label="Application status">Ready</section>;
71
+ }
72
+
73
+ const m = createMaelstrom({ vessels: [vessel(status, Status)] });
74
+ const instanceId = InstanceId('status-main');
75
+ const initialLayout: TilingLayout = {
76
+ type: 'tiling',
77
+ tree: [tilingLeafToken(instanceId)],
78
+ instances: [{
79
+ instanceId,
80
+ vesselId: VesselId('status'),
81
+ variant: VariantName('summary'),
82
+ }],
83
+ };
84
+
85
+ export function SeededStatusChart({ connector }: { connector: EngineConnector }) {
86
+ return (
87
+ <m.Provider connector={connector} layoutMode="tiling" initialLayout={initialLayout}>
88
+ <m.Chart />
89
+ </m.Provider>
90
+ );
91
+ }
92
+ ```
93
+
94
+ Match each leaf to one seeded Instance, and each Instance to a registered Vessel
95
+ and declared Variant. `initialLayout` is captured on mount; use a new Provider
96
+ session when you need a different seed. Keep application data and effects with
97
+ their existing owners.
98
+
99
+ ## Verify
100
+
101
+ Typecheck against this installation. Test the renderer and the scoped Provider
102
+ separately. Observe `connectionError`, `lastError`, and `lastResponse` through
103
+ `m.useMaelstrom()` when submitting intent. A resolved promise is not sufficient
104
+ evidence of success. Test real Engine selection separately from local rendering.
105
+
106
+ ### Test Chart in a DOM
107
+
108
+ Before mounting `m.Chart`, configure the runner's DOM environment and provide
109
+ `ResizeObserver` in the test setup. jsdom does not supply layout or
110
+ `ResizeObserver`. For sizing or resize assertions, use a real browser with a
111
+ sized Chart container, or a controlled observer that emits meaningful container
112
+ `contentRect` dimensions. Verify the measured geometry as part of that test.
113
+ An inert test-only observer can support control or error tests; label their
114
+ layout behavior unverified. Keep that substitute in test setup and restore any
115
+ replaced globals during teardown.
116
+
117
+ For an intent-failure regression, inject a local test Connector that connects
118
+ successfully and rejects `process` with a known error. Render a probe inside the
119
+ same instance's Provider. Give it a button disabled until
120
+ `connectionStatus === 'connected'` and while `isProcessing`, and display
121
+ `connectionError` and `lastError` from that same `m.useMaelstrom()` call.
122
+
123
+ 1. Register `afterEach` cleanup to unmount the rendered tree and restore test
124
+ observers, mocks, and timers, including when an assertion fails.
125
+ 2. Use a bounded asynchronous assertion to wait for the connected state and the
126
+ enabled button before clicking. Treat a disabled button as a pending
127
+ precondition, rather than skipping the click.
128
+ 3. Click once, then use a bounded asynchronous assertion to check the known
129
+ `lastError` and that processing ends. A resolved `processIntent` promise
130
+ alone does not distinguish success from failure.
131
+ 4. For success tests, observe `lastResponse`, a clear `lastError`, and the
132
+ expected rendered capability. Include meaningful geometry when claiming
133
+ layout correctness.
134
+
135
+ With Testing Library, use `waitFor` with an explicit timeout, such as 1000 ms,
136
+ and an assertion that throws until the expected state appears. Let waits yield
137
+ to DOM updates and timers so a missing error fails within the bound.
138
+
139
+ ## Troubleshoot
140
+
141
+ - Missing `MaelstromProvider`: use the configured instance's `Provider`.
142
+ - Invalid first-screen seed: only tiling mode supports `initialLayout`; seeded
143
+ Instances must name statically registered Vessels and legal Variants.
144
+ - Definition update conflict: retain the complete definition and the app's policy.
145
+ - Runtime source lookup: inspect `dist/index.js`. Declarations under `dist/lib/`
146
+ do not imply separate runtime JavaScript files at those paths.