@ai-matrx/associations 0.5.2 → 0.6.1
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/CHANGELOG.md +109 -0
- package/README.md +51 -13
- package/dist/CommentThread-E0zSQBbc.d.cts +1905 -0
- package/dist/CommentThread-E0zSQBbc.d.ts +1905 -0
- package/dist/core/index.cjs +23 -6
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +18 -5
- package/dist/core/index.d.ts +18 -5
- package/dist/core/index.js +23 -6
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -17
- package/dist/index.d.ts +66 -17
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +1039 -451
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +79 -1854
- package/dist/react/index.d.ts +79 -1854
- package/dist/react/index.js +1064 -465
- package/dist/react/index.js.map +1 -1
- package/dist/react/lazy/index.cjs +89 -0
- package/dist/react/lazy/index.cjs.map +1 -0
- package/dist/react/lazy/index.d.cts +17 -0
- package/dist/react/lazy/index.d.ts +17 -0
- package/dist/react/lazy/index.js +59 -0
- package/dist/react/lazy/index.js.map +1 -0
- package/package.json +18 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,114 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/associations
|
|
2
2
|
|
|
3
|
+
## 0.6.1 — 2026-08-30 (vocabulary catch-up: commerce_print_order)
|
|
4
|
+
|
|
5
|
+
Regenerated `src/entity-types.generated.ts` from live `platform.entity_types`:
|
|
6
|
+
**655 → 656 tokens**, adding `commerce_print_order` (`commerce.print_order`,
|
|
7
|
+
base tier 1, listed, scopeable) — the print-order entity the @ai-matrx/print
|
|
8
|
+
work landed in the database.
|
|
9
|
+
|
|
10
|
+
WHY THIS IS A RELEASE AND NOT A LOCAL REGENERATION: the vocabulary ships IN
|
|
11
|
+
this package; consumers have no local regeneration path. So a token that
|
|
12
|
+
exists live but not in the published package is not a cosmetic lag — it fails
|
|
13
|
+
`gen:entity-types` in every consumer, and matrx-frontend's release script runs
|
|
14
|
+
that generator as a gate. This one missing token blocked EVERY frontend
|
|
15
|
+
release (reproduced 2026-08-30: `release.sh` refused at "Installed
|
|
16
|
+
@ai-matrx/associations vocabulary (655 tokens) is OUT OF SYNC with
|
|
17
|
+
platform.entity_types (656 live tokens)"). The vocabulary has to be published
|
|
18
|
+
as promptly as the migration that adds a token.
|
|
19
|
+
|
|
20
|
+
No API change. 187 tests and typecheck pass unchanged.
|
|
21
|
+
|
|
22
|
+
## 0.6.0 — 2026-08-30 (C23 — every port ships a working default; the split entry)
|
|
23
|
+
|
|
24
|
+
THE ALL-INCLUSIVE LAW retrofit (register row: associations). The audit found
|
|
25
|
+
seven ports a host had to fill, four UI ports with NO shipped default, and the
|
|
26
|
+
bundle-split concern pushed onto the host as hand-written `next/dynamic` glue.
|
|
27
|
+
All of it now lives in the package.
|
|
28
|
+
|
|
29
|
+
### Ports: defaults, not degradations
|
|
30
|
+
|
|
31
|
+
- **`windowShell` → `DefaultWindowShell` (new).** The absent-port path was a
|
|
32
|
+
fixed, non-draggable card. It is now a REAL window: drag by the header,
|
|
33
|
+
resize from a labelled grip, maximize/restore, viewport-clamped on drag and
|
|
34
|
+
on viewport resize (a window can never be dragged somewhere it cannot be
|
|
35
|
+
dragged back from), Escape-to-close, portalled to `<body>` (a transformed
|
|
36
|
+
ancestor can no longer clip it), non-modal, and a full-width bottom card
|
|
37
|
+
under 640px. Exported as `DefaultWindowShell` for direct use.
|
|
38
|
+
- **`errorSink` is no longer REQUIRED.** `createAssociationsStore` ships
|
|
39
|
+
`createDefaultErrorSink()` (new, `/core`): a tagged `console.error` per
|
|
40
|
+
event that ANNOUNCES ONCE that no sink is bound and names the remedy — the
|
|
41
|
+
default is louder about itself than the old hard failure was. Only
|
|
42
|
+
`dataSource` and `identity` still throw; they ARE app identity.
|
|
43
|
+
- **`entityDoors.DoorControls` → `DoorControlsSlot` (new).** Every face now
|
|
44
|
+
renders doors through one slot: the host port when bound, otherwise a real,
|
|
45
|
+
keyboard-reachable, `aria-label`led `target="_blank"` anchor built from the
|
|
46
|
+
registry overlay's `hrefFor`. A token with no registered route renders
|
|
47
|
+
nothing — honest absence, never a control that goes nowhere.
|
|
48
|
+
- **`capture` → the whole upload flow over one injected primitive.** Bind
|
|
49
|
+
`capture.uploadFile(file, { folderPath, visibility })` and the package ships
|
|
50
|
+
everything else: the file input, whole-body drag-and-drop, sequential
|
|
51
|
+
uploads, the stall watchdog, per-file outcomes, and the loud
|
|
52
|
+
created-but-unattached report. `requestUpload` remains for a host that owns
|
|
53
|
+
a richer pipeline and still wins when both are bound.
|
|
54
|
+
- **`pickerOverrides` needs no default** — the in-package `AssociationPicker`
|
|
55
|
+
IS the default for every token, and it is complete (candidate list, search,
|
|
56
|
+
attach/detach, the create-then-associate "+ New" footer).
|
|
57
|
+
- **`notifier` degradation unchanged** (warn-once, failures always reach the
|
|
58
|
+
errorSink). The package deliberately does NOT ship a toast stack: a toast
|
|
59
|
+
surface needs a host-mounted root, so a "default" would be the silent
|
|
60
|
+
no-op this package exists to prevent.
|
|
61
|
+
|
|
62
|
+
### The bundle split is package-owned
|
|
63
|
+
|
|
64
|
+
- **`@ai-matrx/associations/react/lazy` (new subpath, 3.4 KB)** — every heavy
|
|
65
|
+
face behind a real lazy edge: `AssociationWindow`, `AssociationPicker`,
|
|
66
|
+
`UniversalAssociationPicker`, `AttachedItemsSheet`, `AssociationCard`,
|
|
67
|
+
`AssociationCardGrid`, `AssociationList`, `AssociationCaptureToolbar`,
|
|
68
|
+
`AssociationEntitySelect`, `CategorySelect`, `CategoryTagPicker`,
|
|
69
|
+
`CommentThread`. The loader dynamic-imports this package's own `./react`
|
|
70
|
+
subpath by name (external in our build), so the CONSUMER's bundler emits the
|
|
71
|
+
chunk. Framework-agnostic — `React.lazy` + `Suspense`, no `next/dynamic`,
|
|
72
|
+
no `next` dependency.
|
|
73
|
+
- **`lazyWindowShell(loader)` / `lazyPickerOverride(loader)`** (`/react`) —
|
|
74
|
+
the same seam for a HOST component bound to a port, so a host stops
|
|
75
|
+
hand-writing `next/dynamic({ ssr: false })` glue per binding.
|
|
76
|
+
`lazyPickerOverride` additionally gates on `open`, so an override never
|
|
77
|
+
fetches its chunk until its picker is opened.
|
|
78
|
+
|
|
79
|
+
### Hard parts moved in (C22)
|
|
80
|
+
|
|
81
|
+
- **The demanded-schema boot probe runs in `AssociationsProvider`** — ON in a
|
|
82
|
+
development build, off elsewhere, overridable with `probeSchema`. Every host
|
|
83
|
+
was writing this effect itself (dynamic import, try/catch, hand-rolled
|
|
84
|
+
`demanded_schema_violation` scream). The store now also exposes the bound
|
|
85
|
+
`dataSource` so nothing has to be re-exported to run it.
|
|
86
|
+
- **`useAssociationPickerBridge(props, opts)` (new, `/react`)** — the
|
|
87
|
+
attach-batch / toggle engine a per-token picker override needs: loud partial
|
|
88
|
+
outcomes, created-but-unattached copy naming where the item lives, refusal
|
|
89
|
+
screams on both attach and detach (the inert-click bug class, feedback
|
|
90
|
+
35d311a9), and errorSink routing. Overrides now write two calls instead of
|
|
91
|
+
re-implementing failure semantics.
|
|
92
|
+
|
|
93
|
+
### Consumer action
|
|
94
|
+
|
|
95
|
+
- **Nothing breaks.** `errorSink` moving from required to optional is
|
|
96
|
+
source-compatible; every existing binding keeps working unchanged.
|
|
97
|
+
- **Delete host `next/dynamic` glue** around associations port bindings and
|
|
98
|
+
use `lazyWindowShell` / `lazyPickerOverride` from `@ai-matrx/associations/react`.
|
|
99
|
+
- **Delete the host demanded-schema probe effect** (the `assertDemandedSchema`
|
|
100
|
+
boot check) — the provider owns it. Pass `probeSchema={false}` to opt out.
|
|
101
|
+
- **Delete hand-written attach/detach failure handling** inside picker
|
|
102
|
+
overrides and bind `useAssociationPickerBridge` instead.
|
|
103
|
+
- **A host that binds `windowShell` should re-decide whether it needs to**:
|
|
104
|
+
bind it only for a real window MANAGER (tray docking, workspace
|
|
105
|
+
persistence, cross-window z-order). Otherwise drop the binding and take
|
|
106
|
+
`DefaultWindowShell`.
|
|
107
|
+
- **A host with no upload pipeline** can now get the whole capture flow by
|
|
108
|
+
binding only `capture.uploadFile`.
|
|
109
|
+
- New optional peer `react-dom` (`>=18.0.0`) — the default window portals.
|
|
110
|
+
Any React DOM host already has it.
|
|
111
|
+
|
|
3
112
|
## 0.5.2 — 2026-08-30 (X3 peer retrofit)
|
|
4
113
|
|
|
5
114
|
- `@ai-matrx/design-system` is now a REAL dependency (`^0.3.1`) instead of an
|
package/README.md
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
const store = createAssociationsStore({
|
|
33
33
|
dataSource: supabase, // structural subset of SupabaseClient
|
|
34
34
|
identity: { requireUserId }, // throws when unauthenticated
|
|
35
|
-
errorSink: (e) => report(e), //
|
|
35
|
+
errorSink: (e) => report(e), // OPTIONAL — default screams to console
|
|
36
36
|
entityOverlay: { file: { hrefFor: (id) => `/files/f/${id}` } }, // optional
|
|
37
37
|
});
|
|
38
38
|
|
|
@@ -43,7 +43,8 @@ store.titles.prime("task", taskId, "Renamed");
|
|
|
43
43
|
await store.favorites.setFavorite("note", noteId, true);
|
|
44
44
|
|
|
45
45
|
// Dev/CI boot check for any new environment (zero side effects; selfTest
|
|
46
|
-
// proves the probe can fail before you trust its green)
|
|
46
|
+
// proves the probe can fail before you trust its green). You normally never
|
|
47
|
+
// call this: <AssociationsProvider> runs it for you in a development build.
|
|
47
48
|
await assertDemandedSchema(supabase, { selfTest: true });
|
|
48
49
|
```
|
|
49
50
|
|
|
@@ -61,10 +62,10 @@ import {
|
|
|
61
62
|
<AssociationsProvider
|
|
62
63
|
store={store} // the /core store from createAssociationsStore
|
|
63
64
|
notifier={toastAdapter} // optional — absent warns once, failures still hit errorSink
|
|
64
|
-
windowShell={windowAdapter} // optional — absent
|
|
65
|
-
capture={
|
|
66
|
-
pickerOverrides={{ file: FilePickerWindowAdapter }} // optional
|
|
67
|
-
entityDoors={{ EntityRef, DoorControls, UnresolvedRef }} // optional
|
|
65
|
+
windowShell={windowAdapter} // optional — absent uses the package's OWN draggable window
|
|
66
|
+
capture={{ uploadFile }} // optional — bind ONE primitive, get the whole upload flow
|
|
67
|
+
pickerOverrides={{ file: FilePickerWindowAdapter }} // optional — the in-package picker is the default
|
|
68
|
+
entityDoors={{ EntityRef, DoorControls, UnresolvedRef }} // optional — hrefFor anchors by default
|
|
68
69
|
>
|
|
69
70
|
<PrimaryEntityProvider value={{ type: "organization", id, orgId, label }}>
|
|
70
71
|
<AssociationCardGrid />
|
|
@@ -126,14 +127,51 @@ regenerated by `pnpm gen:entity-types` inside this package. Skew policy:
|
|
|
126
127
|
know renders through the fallback (default icon, raw label, no door) instead
|
|
127
128
|
of crashing.
|
|
128
129
|
|
|
129
|
-
## The
|
|
130
|
+
## The ports — two required, the rest DEFAULTED
|
|
130
131
|
|
|
131
|
-
One `AssociationsConfig`, bound once per host.
|
|
132
|
-
of `SupabaseClient` answering the demanded RPCs)
|
|
133
|
-
are
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
One `AssociationsConfig`, bound once per host. Only **`dataSource`** (a
|
|
133
|
+
structural subset of `SupabaseClient` answering the demanded RPCs) and
|
|
134
|
+
**`identity`** are required — construction throws without them, because they
|
|
135
|
+
ARE your app's identity and no package can invent them.
|
|
136
|
+
|
|
137
|
+
Everything else ships a working default (C23 — you override ports, you never
|
|
138
|
+
have to fill them):
|
|
139
|
+
|
|
140
|
+
| Port | Default when unbound |
|
|
141
|
+
|---|---|
|
|
142
|
+
| `errorSink` | `createDefaultErrorSink()` — tagged `console.error` per event; announces ONCE that no sink is bound and names the remedy. |
|
|
143
|
+
| `windowShell` | `DefaultWindowShell` — a real draggable / resizable / maximizable / viewport-clamped / portalled / non-modal window; full-width bottom card under 640px. Bind this port only for a real window MANAGER (tray docking, workspace persistence). |
|
|
144
|
+
| `capture` | Bind `uploadFile(file, { folderPath, visibility })` alone and the package ships the file input, drag-and-drop, batching, the stall watchdog and every loud outcome. Bind `requestUpload` instead when you own a richer pipeline. Chips with no path behind them are never rendered. |
|
|
145
|
+
| `pickerOverrides` | The in-package `AssociationPicker` serves every token (candidate list, search, attach/detach, create-then-associate footer). |
|
|
146
|
+
| `entityDoors` | `DoorControlsSlot` renders a real labelled `target="_blank"` anchor from the overlay's `hrefFor`; a token with no route renders nothing rather than a door to nowhere. |
|
|
147
|
+
| `entityOverlay` | Convention columns, default icon, `${label}s`, no door. |
|
|
148
|
+
| `notifier` | Warn-once through the errorSink, and every user-facing failure still reaches the errorSink. (No toast stack ships: a toast surface needs a host-mounted root, so a "default" would be the silent no-op this package exists to prevent.) |
|
|
149
|
+
| `authorDisplay` | `cmt_list`'s denormalized author fields, then "Unknown user" — never blank. |
|
|
150
|
+
|
|
151
|
+
## Code splitting — the package owns it
|
|
152
|
+
|
|
153
|
+
Import the heavy faces from **`@ai-matrx/associations/react/lazy`** and each one
|
|
154
|
+
arrives in its own chunk on first render. No `next/dynamic`, no `ssr: false`,
|
|
155
|
+
no host glue:
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
import { AssociationCardGrid } from "@ai-matrx/associations/react/lazy";
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
For a HOST component you bind to a port, use the same seam:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
windowShell: {
|
|
165
|
+
Window: lazyWindowShell(() => import("./hostWindow").then((m) => m.HostWindow)),
|
|
166
|
+
},
|
|
167
|
+
pickerOverrides: {
|
|
168
|
+
file: lazyPickerOverride(() => import("./hostPicker").then((m) => m.HostPicker)),
|
|
169
|
+
},
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
A per-token picker override should bind `useAssociationPickerBridge(props)` for
|
|
173
|
+
its attach/detach writes — it carries the loud partial-outcome, refusal and
|
|
174
|
+
created-but-unattached reporting so an override never re-implements them.
|
|
137
175
|
|
|
138
176
|
## Versioning
|
|
139
177
|
|