@ai-matrx/records 0.11.0 → 0.17.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/CHANGELOG.md +154 -0
- package/dist/core/index.cjs +364 -34
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +157 -8
- package/dist/core/index.d.ts +157 -8
- package/dist/core/index.js +364 -34
- package/dist/core/index.js.map +1 -1
- package/dist/index.cjs +134 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +719 -11
- package/dist/index.d.ts +719 -11
- package/dist/index.js +134 -8
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +361 -31
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +855 -16
- package/dist/react/index.d.ts +855 -16
- package/dist/react/index.js +361 -31
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,159 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records
|
|
2
2
|
|
|
3
|
+
## 0.17.0
|
|
4
|
+
|
|
5
|
+
**A list is a door, never a grant on the thing behind it.**
|
|
6
|
+
|
|
7
|
+
`docTemplates`, `docRenders` and `docSignatures` read `custom.doc_template` (a
|
|
8
|
+
view), `custom.doc_render` and `custom.doc_signature` (tables) with a direct
|
|
9
|
+
PostgREST `.from()`. **None of those three holds a client SELECT**, and none ever
|
|
10
|
+
should — so every plural act of document generation returned 403, and the
|
|
11
|
+
try-everything page photographed *"permission denied for view doc_template"* on
|
|
12
|
+
2026-09-20. A person could save a template they could never list and render a
|
|
13
|
+
document they could never find again.
|
|
14
|
+
|
|
15
|
+
All three now call doors that narrow inside the definer, after the ladder has
|
|
16
|
+
spoken: `custom.doc_templates` and `custom.doc_renders` / `custom.doc_signatures`
|
|
17
|
+
(viewer on the Table, viewer on the record). Two acts that had no door at all
|
|
18
|
+
arrive with them:
|
|
19
|
+
|
|
20
|
+
- **`docTemplateDelete({ template_id })`** — retire one template. Editor on the
|
|
21
|
+
Table it renders, because a template is that Table's wording. Soft only:
|
|
22
|
+
documents already rendered keep their frozen bytes and their seals, so
|
|
23
|
+
retiring a template can never invalidate a signature (VAL-10).
|
|
24
|
+
- **`subscriptionCadences()`** — the cadences a subscription may be written
|
|
25
|
+
with, through the door a PERSON may call. `aggSubscriptionCadences` is the
|
|
26
|
+
notifier's own and holds no client grant, so every screen that asked for it
|
|
27
|
+
was refused and fell back to a word typed into the screen; this one delegates
|
|
28
|
+
to the same array, so a picker can never offer a cadence the digest runner
|
|
29
|
+
does not honour.
|
|
30
|
+
|
|
31
|
+
`DocTemplateRow` drops `organization_id`, which the door does not answer and no
|
|
32
|
+
caller read — the client already holds the organization. The door names its key
|
|
33
|
+
`template_id` / `render_id` / `signature_id`; the package keeps `id`, mapped once
|
|
34
|
+
here rather than renamed in four screens.
|
|
35
|
+
|
|
36
|
+
`store.generated.ts` regenerated from the live store: **387 → 401 doors**.
|
|
37
|
+
|
|
38
|
+
**Consumer action:** none for `docTemplates` / `docRenders` / `docSignatures` —
|
|
39
|
+
same names, same row shapes, they simply stop being refused. The five doors they
|
|
40
|
+
need are live on the main database (`doorstwo_the_document_and_cadence_doors.sql`
|
|
41
|
+
+ its grant file, applied 2026-09-20 13:43Z), so this version requires no
|
|
42
|
+
migration of its own.
|
|
43
|
+
|
|
44
|
+
## 0.16.0
|
|
45
|
+
|
|
46
|
+
**A column is declared, and a client type can finally say so.**
|
|
47
|
+
|
|
48
|
+
`NewFieldDeclaration` now names what `custom.field_declare` has actually taken
|
|
49
|
+
since 2026-09-20: `type` (the one word every agent, script and import reaches
|
|
50
|
+
for — the store resolves the thirteen parity types, the five behaviours and the
|
|
51
|
+
plain synonyms, and refuses a word that means nothing by name), `config` (a long
|
|
52
|
+
text's `multiline`, a list's existing options table — the door always read it and
|
|
53
|
+
no client could send it), `relation_target` and `on_target_delete` (a column that
|
|
54
|
+
points at another of this organization's own tables, which no client type could
|
|
55
|
+
express at all), and `format` (the one shape `custom.doc_sign` accepts).
|
|
56
|
+
|
|
57
|
+
`FieldPatch` gains the door's BEHAVIOUR arm — `parity_type`, `plain`, `type`,
|
|
58
|
+
`multi` — plus `relation_target`, `on_target_delete`, `promoted`, `unique` and
|
|
59
|
+
`depends_on`. It named only the settings, so the one caller that needed to move a
|
|
60
|
+
column back onto the behaviour it is written against had no door and reached for
|
|
61
|
+
`custom.record_update` instead, writing the document *under* the guards rather
|
|
62
|
+
than through them. **`multi` is read only inside that arm: send the behaviour
|
|
63
|
+
word with it or nothing happens.**
|
|
64
|
+
|
|
65
|
+
**The columns come back in the order they were declared.** `custom.applicable_fields`
|
|
66
|
+
answers a SET — its order is the plan's and it moves between calls — so every
|
|
67
|
+
consumer of `client.fields()` was drawing columns in an arbitrary order. A table
|
|
68
|
+
declared Title, Day rate, Due came back Day rate, Title, Due. The Field's own
|
|
69
|
+
`sort` is applied once, here, so every screen, export, form and agent inherits it.
|
|
70
|
+
|
|
71
|
+
**22007 is mapped.** The live-door census caught `custom.dashboard_window_sql`
|
|
72
|
+
raising it; it reads as `invalid_argument`, like 42703 before it.
|
|
73
|
+
|
|
74
|
+
**The live-door suite declared its own fixture the way the store no longer
|
|
75
|
+
allows** — `custom.record_write` into the field kernel — so eighteen of its
|
|
76
|
+
thirty-three clauses were red on `main` against the live store. It uses
|
|
77
|
+
`custom.field_declare`. 33/33.
|
|
78
|
+
## 0.15.0
|
|
79
|
+
|
|
80
|
+
**A client portal has an owner's side, and this package can reach it.**
|
|
81
|
+
`custom.portals`, `custom.portal_card`, `custom.portal_declare`,
|
|
82
|
+
`custom.portal_invite`, `custom.portal_revoke` and `custom.portal_preview` have
|
|
83
|
+
been live on the database and no client could call them, so the six doors that
|
|
84
|
+
decide who signs in from outside an organization — and what they see — existed
|
|
85
|
+
with nothing able to ask them. `store.generated.ts` was regenerated from the
|
|
86
|
+
live store (372 → 387 doors) and the six are now on `client`:
|
|
87
|
+
|
|
88
|
+
- `client.portals()` — every portal over this organization, with its client
|
|
89
|
+
Table, how many Tables it exposes, how many people are invited and how many
|
|
90
|
+
have actually signed in. The store filters the list on whether you may open
|
|
91
|
+
the client Table, so it never reveals a Table.
|
|
92
|
+
- `client.portalCard({ portal_id })` — one portal in full: each exposed Table
|
|
93
|
+
with the relation Field that says whose a record is and the fields a client
|
|
94
|
+
sees and may change, every person with `signed_in` and `is_active` kept
|
|
95
|
+
APART, and `external_lane_open`.
|
|
96
|
+
- `client.portalDeclare(...)` — create or RE-STATE one. Re-stating replaces
|
|
97
|
+
what the portal exposes and leaves the people alone.
|
|
98
|
+
- `client.portalInvite({ portal_id, client_record_id, email })` — and it takes
|
|
99
|
+
no `user_id` on purpose. From a screen that value is always null: an
|
|
100
|
+
invitation confers NOTHING until the person follows their own sign-in link,
|
|
101
|
+
which is what the door's own `say` sentence states. A client that passed an
|
|
102
|
+
id would be granting access on somebody else's behalf.
|
|
103
|
+
- `client.portalRevoke({ portal_id, principal_id })` — the answer's `say` names
|
|
104
|
+
the consequence in the past tense.
|
|
105
|
+
- `client.portalPreview({ portal_id, principal_id, table_id })` — "view as this
|
|
106
|
+
client". The door asks `custom.visible_set` for HER user id, the same call
|
|
107
|
+
`custom.read_records` makes when she opens the page, so it cannot disagree
|
|
108
|
+
with what she sees. It REFUSES (`02000`, mapped to `not_found`) when she has
|
|
109
|
+
not signed in, rather than answering an empty list.
|
|
110
|
+
|
|
111
|
+
New module `portal`, exported from the root: `PortalSummary`,
|
|
112
|
+
`PortalTableExposure`, `PortalPrincipal`, `PortalCard`, `PortalInvitation`,
|
|
113
|
+
`PortalRevocation`, `PortalPreviewRow`, and `portalPath(slug)` — the one place
|
|
114
|
+
`/portal/c/<slug>` is written down.
|
|
115
|
+
|
|
116
|
+
**Consumer action:** none required; every addition is new surface. A host that
|
|
117
|
+
already builds a portal address by hand should use `portalPath` so there is one
|
|
118
|
+
spelling of it.
|
|
119
|
+
|
|
120
|
+
## 0.13.0
|
|
121
|
+
|
|
122
|
+
**A choice value is the choice's own word, and this package says what that means.**
|
|
123
|
+
A list Field's cell used to hold the option RECORD'S ID, so every read, filter,
|
|
124
|
+
group-by, export and agent got back a uuid — the seventh independent pass failed
|
|
125
|
+
acceptance test T8 on exactly that. The store now holds the option's own stable
|
|
126
|
+
key, the read doors hand back the LABEL and name the key beside it in
|
|
127
|
+
`_choices`, and a caller may write the label, the key or (so nothing that worked
|
|
128
|
+
yesterday breaks) the option's id.
|
|
129
|
+
|
|
130
|
+
New module `choice`, exported from the root: `optionKey`, `optionLabel`,
|
|
131
|
+
`isTheChosen`, `choiceValuesOf`, `choicesOf`, `holdsARetiredChoice`,
|
|
132
|
+
`choiceSlug`, `looksLikeAnId`, and the `ChoiceOption` type. `isTheChosen` is the
|
|
133
|
+
one a control wants: it recognises a choice by its key, its label or its option
|
|
134
|
+
id, which is what lets one picker read a document from any of the three eras.
|
|
135
|
+
|
|
136
|
+
**Consumer action:** a control that compared a cell to `option.id` must use
|
|
137
|
+
`isTheChosen` and write `optionKey(option)` — comparing against the id alone now
|
|
138
|
+
shows nothing selected, because the read door hands back the label.
|
|
139
|
+
|
|
140
|
+
## 0.12.0
|
|
141
|
+
|
|
142
|
+
**A person can see what they are being told about, and switch one off.**
|
|
143
|
+
`custom.subscriptions` and `custom.subscription_mute` have been live on the
|
|
144
|
+
database since 20 September and no client could call them, so a form's "tell me
|
|
145
|
+
when somebody answers" could be turned ON by an agent and never turned off by
|
|
146
|
+
the person it was telling. `client.subscriptions({ table_id })` answers mine
|
|
147
|
+
plus anyone's over a Table I hold admin on — narrowed to Tables I can already
|
|
148
|
+
open, so the list never reveals one — and `client.subscriptionMute({ rule_id,
|
|
149
|
+
muted })` is the switch. `MySubscription` carries the two things a screen needs
|
|
150
|
+
and the notifier does not: `muted`, and `i_may_mute`.
|
|
151
|
+
|
|
152
|
+
`aggSubscriptions` is unchanged and is still the NOTIFIER's reader, which no
|
|
153
|
+
client can call. Muting is honoured inside that one reader, so a screen can
|
|
154
|
+
never say a subscription is off while it keeps firing.
|
|
155
|
+
|
|
156
|
+
|
|
3
157
|
## 0.11.0
|
|
4
158
|
|
|
5
159
|
**The publish gate stops red-lighting on other lanes' migrations.** `the
|