@ai-matrx/records 0.3.3 → 0.5.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 +68 -18
- package/dist/core/index.cjs +53 -0
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +35 -3
- package/dist/core/index.d.ts +35 -3
- package/dist/core/index.js +53 -0
- 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 +23 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +16 -0
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +23 -1
- package/dist/react/index.d.ts +23 -1
- package/dist/react/index.js +16 -0
- package/dist/react/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,33 +1,83 @@
|
|
|
1
1
|
# Changelog — @ai-matrx/records
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.5.1
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
a hard statement timeout for genuinely abandoned transactions.
|
|
5
|
+
Refreshes the generated store contract to the live 240-door registry caught by
|
|
6
|
+
the blocking release guard after 0.5.0 was tagged.
|
|
8
7
|
|
|
9
8
|
### Consumer action
|
|
10
9
|
|
|
11
|
-
None.
|
|
12
|
-
|
|
13
|
-
## 0.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
None. The two new door entries are additive generated contract data.
|
|
11
|
+
|
|
12
|
+
## 0.5.0
|
|
13
|
+
|
|
14
|
+
**Two refusal classes the store really raises, which this package answered with
|
|
15
|
+
"something this package does not recognise".** Both were found by walking the
|
|
16
|
+
real product on 2026-09-19, and in both the screen showed the store's own
|
|
17
|
+
sentence — honest, but the class was nameable and this package had not named it.
|
|
18
|
+
|
|
19
|
+
- **`57014` — the store cancelled the statement at its own timeout.** Seen on an
|
|
20
|
+
organization whose Table kernel is large enough for `custom.read_records` to
|
|
21
|
+
run out of time. It is now `timed_out`, which is, with `stale_read`, one of
|
|
22
|
+
only two refusals in the vocabulary worth REPEATING: nothing was refused on
|
|
23
|
+
its merits and nothing was written, so a screen can offer "try again" honestly
|
|
24
|
+
instead of showing a failure a person cannot act on.
|
|
25
|
+
- **`22P02` — a value that does not fit the type the store holds for it.** Seen
|
|
26
|
+
as `invalid input syntax for type uuid: "open"`, writing the text `open` into
|
|
27
|
+
an organization's copy of a package Table whose `status` Field was uuid-shaped.
|
|
28
|
+
It is `invalid_argument`, which is what it is: the CALL is wrong for the shape
|
|
29
|
+
the store holds, and the store's own message names the value and the type.
|
|
30
|
+
|
|
31
|
+
Both are proved against the LIVE store in `src/__tests__/real-doors.test.ts`:
|
|
32
|
+
the SQLSTATEs are raised by the real database inside the suite's own
|
|
33
|
+
rolled-back transaction and read back out of psql's verbose report, and the only
|
|
34
|
+
thing asserted about this package is what it makes of them. Each case is RED
|
|
35
|
+
without its map entry (`expected 'internal' to be 'timed_out'`).
|
|
19
36
|
|
|
20
37
|
### Consumer action
|
|
21
38
|
|
|
22
|
-
|
|
39
|
+
`RecordsErrorCode` gains one member, `timed_out`. A host that switches
|
|
40
|
+
exhaustively over the union must add an arm for it; every other host needs
|
|
41
|
+
nothing beyond taking `latest`. A host that was special-casing `internal` to
|
|
42
|
+
recognise a timeout by its message text should branch on `timed_out` instead.
|
|
23
43
|
|
|
24
|
-
## 0.
|
|
44
|
+
## 0.4.1
|
|
25
45
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
46
|
+
Carries the live Supabase adapter proof through the shared npm publishing lane
|
|
47
|
+
by supplying its existing main-database HTTP URL and publishable-key secrets to
|
|
48
|
+
the verification step.
|
|
49
|
+
|
|
50
|
+
### Consumer action
|
|
29
51
|
|
|
30
|
-
|
|
52
|
+
None beyond taking `latest`; the 0.4.0 API is unchanged.
|
|
53
|
+
|
|
54
|
+
## 0.4.0
|
|
55
|
+
|
|
56
|
+
**The browser can reach the store again — `supabaseDataSource`.** Every screen
|
|
57
|
+
of the record store was dead from a browser, for everybody, and the cause was a
|
|
58
|
+
single silent drop. `RecordsDataSource.rpc(fn, args, { schema })` says the
|
|
59
|
+
schema out loud, because every door is `custom.<name>` and every trust door is
|
|
60
|
+
`iam.<name>`. supabase-js's own `rpc()` has NO schema option — its third
|
|
61
|
+
argument is `{ head, get, count }` — so a host that bound its client as a bare
|
|
62
|
+
structural cast handed the option to a function that dropped it, every door call
|
|
63
|
+
went to PostgREST's default profile, and the store answered, correctly and
|
|
64
|
+
uselessly, `PGRST202 — Could not find the function public.table_kernel_id in the
|
|
65
|
+
schema cache`. Independent verdict, 2026-09-19.
|
|
66
|
+
|
|
67
|
+
The fix is ONE adapter in the headless core, exported from `/core`, that every
|
|
68
|
+
host inherits — never three hosts (web, desktop, extension) each remembering the
|
|
69
|
+
same thing. It routes through `client.schema(name).rpc(...)`, which is the one
|
|
70
|
+
way supabase-js offers, and it refuses two things by name rather than sending
|
|
71
|
+
them: a call with no schema (which would reach `public`), and a client with no
|
|
72
|
+
`.schema()` method (which would throw inside a render).
|
|
73
|
+
|
|
74
|
+
**The test that would have caught it**, `src/__tests__/supabase-adapter.test.ts`:
|
|
75
|
+
a real supabase-js client against the MAIN database, signed in as `test@test.com`,
|
|
76
|
+
calling a real door. A raw `fetch` to `/rest/v1/rpc/...` would NOT have caught
|
|
77
|
+
this — the bug is in supabase-js's option handling, so only a real client
|
|
78
|
+
exercises it. The RED half reconstructs the bare cast that shipped and asserts
|
|
79
|
+
the store's own PGRST202 naming `public`; the GREEN half is the same call
|
|
80
|
+
through the adapter answering the kernel id.
|
|
31
81
|
|
|
32
82
|
## 0.3.0
|
|
33
83
|
|
package/dist/core/index.cjs
CHANGED
|
@@ -90,6 +90,7 @@ __export(core_exports, {
|
|
|
90
90
|
predictValueRefusals: () => predictValueRefusals,
|
|
91
91
|
predictWriteRefusals: () => predictWriteRefusals,
|
|
92
92
|
staleWriteDetail: () => staleWriteDetail,
|
|
93
|
+
supabaseDataSource: () => supabaseDataSource,
|
|
93
94
|
toAoa: () => toAoa
|
|
94
95
|
});
|
|
95
96
|
module.exports = __toCommonJS(core_exports);
|
|
@@ -281,6 +282,8 @@ var STORE_DOORS = [
|
|
|
281
282
|
{ name: "doc_unresolved_tokens", args: "p_organization_id uuid, p_table_id uuid, p_body text", returns: "TABLE(raw text, field_id uuid, why text)", security: "invoker" },
|
|
282
283
|
{ name: "doors_not_deciding_the_caller", args: "", returns: "TABLE(function_name text, identity_args text)", security: "invoker" },
|
|
283
284
|
{ name: "doors_not_deciding_the_record", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
|
|
285
|
+
{ name: "doors_not_on_one_ladder", args: "", returns: "TABLE(function_name text, identity_args text, why text)", security: "invoker" },
|
|
286
|
+
{ name: "effective_level", args: "p_user_id uuid, p_organization_id uuid, p_id uuid, p_type text DEFAULT 'record'::text", returns: "permission_level", security: "definer" },
|
|
284
287
|
{ name: "export_records", args: "p_organization_id uuid, p_table_id uuid, p_limit integer DEFAULT 1000", returns: "TABLE(id uuid, document jsonb)", security: "invoker" },
|
|
285
288
|
{ name: "external_foreign_table_findings", args: "", returns: "SETOF text", security: "definer" },
|
|
286
289
|
{ name: "external_history_event", args: "p_organization_id uuid, p_link_id uuid, p_operation text", returns: "bigint", security: "definer" },
|
|
@@ -1712,6 +1715,13 @@ var BY_SQLSTATE = {
|
|
|
1712
1715
|
"23514": "refused_by_rule",
|
|
1713
1716
|
"22004": "invalid_argument",
|
|
1714
1717
|
"22023": "invalid_argument",
|
|
1718
|
+
// 22P02 — a value does not fit the type the store holds for it. The class is
|
|
1719
|
+
// real and was hit live: an organization whose copy of a package table grew
|
|
1720
|
+
// `status` as a uuid-valued Field was sent the text "open", and the store
|
|
1721
|
+
// answered `invalid input syntax for type uuid: "open"`. It is the CALL that
|
|
1722
|
+
// is wrong for the shape the store holds, which is what `invalid_argument`
|
|
1723
|
+
// already means — the store's own sentence names the value and the type.
|
|
1724
|
+
"22P02": "invalid_argument",
|
|
1715
1725
|
"02000": "not_found",
|
|
1716
1726
|
"23503": "missing_reference",
|
|
1717
1727
|
"23505": "already_exists",
|
|
@@ -1723,6 +1733,13 @@ var BY_SQLSTATE = {
|
|
|
1723
1733
|
// they just lost access to. It is retryable on a fresher connection, which is
|
|
1724
1734
|
// a different instruction from every other refusal here.
|
|
1725
1735
|
"40001": "stale_read",
|
|
1736
|
+
// 57014 — the store cancelled the statement at its own timeout. Like
|
|
1737
|
+
// `stale_read` and unlike every other refusal here, the call was never
|
|
1738
|
+
// refused on its merits: the same call on a smaller page, or once the
|
|
1739
|
+
// organization's kernel is not being rewritten, can succeed. It gets its own
|
|
1740
|
+
// code so a screen can offer "try again" honestly instead of showing a
|
|
1741
|
+
// failure sentence the caller cannot act on.
|
|
1742
|
+
"57014": "timed_out",
|
|
1726
1743
|
// PostgREST's own two: the store is not being SERVED, which is a different
|
|
1727
1744
|
// thing from the store refusing. `custom` absent from `pgrst.db_schemas`, or
|
|
1728
1745
|
// the grants not copied, land here.
|
|
@@ -2575,6 +2592,42 @@ function asWriteConflict(error, recordId) {
|
|
|
2575
2592
|
};
|
|
2576
2593
|
}
|
|
2577
2594
|
|
|
2595
|
+
// src/core/supabase.ts
|
|
2596
|
+
function refuse(code, message, hint) {
|
|
2597
|
+
return { data: null, error: { code, message, hint, details: "" } };
|
|
2598
|
+
}
|
|
2599
|
+
function supabaseDataSource(client) {
|
|
2600
|
+
const supabase = client;
|
|
2601
|
+
const hasSchema = typeof supabase.schema === "function";
|
|
2602
|
+
return {
|
|
2603
|
+
rpc(fn, args, options) {
|
|
2604
|
+
if (!hasSchema) {
|
|
2605
|
+
return Promise.resolve(
|
|
2606
|
+
refuse(
|
|
2607
|
+
"data_source_unbound",
|
|
2608
|
+
`The records client was given something that is not a supabase client: it has no schema() method, so the door ${fn} cannot be called in the schema it lives in.`,
|
|
2609
|
+
"Pass a supabase-js v2 client (createClient(...)) to supabaseDataSource()."
|
|
2610
|
+
)
|
|
2611
|
+
);
|
|
2612
|
+
}
|
|
2613
|
+
const name = options?.schema;
|
|
2614
|
+
if (!name) {
|
|
2615
|
+
return Promise.resolve(
|
|
2616
|
+
refuse(
|
|
2617
|
+
"schema_unsaid",
|
|
2618
|
+
`The door ${fn} was called without saying which schema it lives in. Every door of this store is custom.${fn} and every trust door is iam.${fn}; an unqualified call reaches PostgREST's default profile (public) and is refused there.`,
|
|
2619
|
+
"This is a bug in the caller, not in your data: /core says the schema on every call."
|
|
2620
|
+
)
|
|
2621
|
+
);
|
|
2622
|
+
}
|
|
2623
|
+
return supabase.schema(name).rpc(fn, args);
|
|
2624
|
+
},
|
|
2625
|
+
schema(name) {
|
|
2626
|
+
return supabase.schema(name);
|
|
2627
|
+
}
|
|
2628
|
+
};
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2578
2631
|
// src/core/validation.ts
|
|
2579
2632
|
var DEFAULT_VALUE_MAX_BYTES = 1e5;
|
|
2580
2633
|
var DEFAULT_DOCUMENT_MAX_BYTES = 1048576;
|