@ai-matrx/data 0.22.33 → 0.24.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 +46 -0
- package/README.md +34 -0
- package/bin/direct-db.mjs +80 -0
- package/bin/emit.mjs +380 -0
- package/bin/generate.mjs +225 -0
- package/bin/matrx-data.mjs +49 -0
- package/description/admin.json.gz +0 -0
- package/description/agent.json.gz +0 -0
- package/description/ai.json.gz +0 -0
- package/description/api.json.gz +0 -0
- package/description/app.json.gz +0 -0
- package/description/assignment.json.gz +0 -0
- package/description/audit.json.gz +0 -0
- package/description/batch.json.gz +0 -0
- package/description/billing.json.gz +0 -0
- package/description/browser.json.gz +0 -0
- package/description/canvas.json.gz +0 -0
- package/description/chat.json.gz +0 -0
- package/description/code.json.gz +0 -0
- package/description/commerce.json.gz +0 -0
- package/description/communication.json.gz +0 -0
- package/description/content.json.gz +0 -0
- package/description/content_ir.json.gz +0 -0
- package/description/context.json.gz +0 -0
- package/description/crm.json.gz +0 -0
- package/description/custom.json.gz +0 -0
- package/description/dictionary.json.gz +0 -0
- package/description/docproc.json.gz +0 -0
- package/description/education.json.gz +0 -0
- package/description/esign.json.gz +0 -0
- package/description/extend.json.gz +0 -0
- package/description/files.json.gz +0 -0
- package/description/growth.json.gz +0 -0
- package/description/hindsight.json.gz +0 -0
- package/description/history.json.gz +0 -0
- package/description/iam.json.gz +0 -0
- package/description/index.json.gz +0 -0
- package/description/interview.json.gz +0 -0
- package/description/knowledge.json.gz +0 -0
- package/description/legal.json.gz +0 -0
- package/description/mandate.json.gz +0 -0
- package/description/marketing.json.gz +0 -0
- package/description/media.json.gz +0 -0
- package/description/meta.json.gz +0 -0
- package/description/ops.json.gz +0 -0
- package/description/pdf.json.gz +0 -0
- package/description/plan.json.gz +0 -0
- package/description/platform.json.gz +0 -0
- package/description/podcast.json.gz +0 -0
- package/description/projects.json.gz +0 -0
- package/description/public.json.gz +0 -0
- package/description/rag.json.gz +0 -0
- package/description/research.json.gz +0 -0
- package/description/runtime.json.gz +0 -0
- package/description/scheduler.json.gz +0 -0
- package/description/scraper.json.gz +0 -0
- package/description/seo.json.gz +0 -0
- package/description/skill.json.gz +0 -0
- package/description/social.json.gz +0 -0
- package/description/tool.json.gz +0 -0
- package/description/transcripts.json.gz +0 -0
- package/description/ui.json.gz +0 -0
- package/description/users.json.gz +0 -0
- package/description/web.json.gz +0 -0
- package/description/work.json.gz +0 -0
- package/description/workbench.json.gz +0 -0
- package/description/workflow.json.gz +0 -0
- package/dist/db.cjs +274 -19
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +270 -3
- package/dist/db.d.ts +270 -3
- package/dist/db.js +270 -15
- package/dist/db.js.map +1 -1
- package/package.json +9 -4
package/dist/db.cjs
CHANGED
|
@@ -7,11 +7,11 @@ var __export = (target, all) => {
|
|
|
7
7
|
for (var name in all)
|
|
8
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
9
|
};
|
|
10
|
-
var __copyProps = (to,
|
|
11
|
-
if (
|
|
12
|
-
for (let key of __getOwnPropNames(
|
|
10
|
+
var __copyProps = (to, from2, except, desc) => {
|
|
11
|
+
if (from2 && typeof from2 === "object" || typeof from2 === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from2))
|
|
13
13
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () =>
|
|
14
|
+
__defProp(to, key, { get: () => from2[key], enumerable: !(desc = __getOwnPropDesc(from2, key)) || desc.enumerable });
|
|
15
15
|
}
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
@@ -24,35 +24,53 @@ __export(db_exports, {
|
|
|
24
24
|
DEFAULT_ACTIVE_ORG_COOKIE_MAX_AGE: () => DEFAULT_ACTIVE_ORG_COOKIE_MAX_AGE,
|
|
25
25
|
DEFAULT_ACTIVE_ORG_COOKIE_NAME: () => DEFAULT_ACTIVE_ORG_COOKIE_NAME,
|
|
26
26
|
DEFAULT_AUTH_COOKIE_NAME: () => DEFAULT_AUTH_COOKIE_NAME,
|
|
27
|
+
DatabaseError: () => DatabaseError,
|
|
28
|
+
DoorRefusedError: () => DoorRefusedError,
|
|
27
29
|
IncompleteReadError: () => IncompleteReadError,
|
|
28
30
|
RecordUnavailableError: () => RecordUnavailableError,
|
|
29
31
|
SessionUnavailableError: () => SessionUnavailableError,
|
|
30
32
|
WriteDidNotLandError: () => WriteDidNotLandError,
|
|
31
33
|
WriteRefusedError: () => WriteRefusedError,
|
|
34
|
+
archive: () => archive,
|
|
32
35
|
asJsonObject: () => asJsonObject,
|
|
36
|
+
assertDoor: () => assertDoor,
|
|
33
37
|
assertWriteLanded: () => assertWriteLanded,
|
|
38
|
+
call: () => call,
|
|
39
|
+
changesOf: () => changesOf,
|
|
40
|
+
count: () => count,
|
|
34
41
|
createActiveOrgCookie: () => createActiveOrgCookie,
|
|
35
42
|
createAuthCookie: () => createAuthCookie,
|
|
43
|
+
createDb: () => createDb,
|
|
36
44
|
createOAuthRefreshFetch: () => createOAuthRefreshFetch,
|
|
45
|
+
createServiceDb: () => createServiceDb,
|
|
37
46
|
createSessionRetry: () => createSessionRetry,
|
|
38
47
|
decodeActiveOrgSelection: () => decodeActiveOrgSelection,
|
|
39
48
|
decodeOAuthRefreshClaims: () => decodeOAuthRefreshClaims,
|
|
40
49
|
describeWriteFailure: () => describeWriteFailure,
|
|
41
50
|
encodeActiveOrgSelection: () => encodeActiveOrgSelection,
|
|
42
51
|
guardedUpdate: () => guardedUpdate,
|
|
52
|
+
insert: () => insert,
|
|
43
53
|
isMissingSessionError: () => isMissingSessionError,
|
|
44
54
|
isRecordUnavailableError: () => isRecordUnavailableError,
|
|
55
|
+
listAll: () => listAll,
|
|
56
|
+
loadTableByName: () => loadTableByName,
|
|
45
57
|
mergeJsonColumn: () => mergeJsonColumn,
|
|
58
|
+
page: () => page,
|
|
46
59
|
parseCookieHeader: () => parseCookieHeader,
|
|
47
60
|
personSentence: () => personSentence,
|
|
61
|
+
read: () => read,
|
|
48
62
|
readAllRows: () => readAllRows,
|
|
49
63
|
readAllRowsRest: () => readAllRowsRest,
|
|
50
64
|
recordUnavailableMessage: () => recordUnavailableMessage,
|
|
65
|
+
remove: () => remove,
|
|
66
|
+
restore: () => restore,
|
|
51
67
|
serverMessageFromBody: () => serverMessageFromBody,
|
|
68
|
+
tableByName: () => tableByName,
|
|
52
69
|
tryReadAllRows: () => tryReadAllRows,
|
|
53
70
|
tryReadAllRowsRest: () => tryReadAllRowsRest,
|
|
54
71
|
tryWriteOne: () => tryWriteOne,
|
|
55
72
|
uniqueChannelTopic: () => import_realtime.uniqueChannelTopic,
|
|
73
|
+
update: () => update,
|
|
56
74
|
writeFailureStatus: () => writeFailureStatus,
|
|
57
75
|
writeOne: () => writeOne,
|
|
58
76
|
writeOneRow: () => writeOneRow
|
|
@@ -127,18 +145,18 @@ async function readAllRows(query, opts) {
|
|
|
127
145
|
const maxRows = opts.maxRows ?? DEFAULT_MAX_ROWS;
|
|
128
146
|
const rows = [];
|
|
129
147
|
let total = null;
|
|
130
|
-
for (let
|
|
131
|
-
const res = await query({ from, to:
|
|
148
|
+
for (let from2 = 0; ; from2 += pageSize) {
|
|
149
|
+
const res = await query({ from: from2, to: from2 + pageSize - 1 });
|
|
132
150
|
if (res.error) {
|
|
133
151
|
throw new Error(
|
|
134
152
|
`readAllRows(${opts.label}): query failed \u2014 ${res.error.message}`
|
|
135
153
|
);
|
|
136
154
|
}
|
|
137
|
-
const
|
|
138
|
-
rows.push(...
|
|
155
|
+
const page2 = res.data ?? [];
|
|
156
|
+
rows.push(...page2);
|
|
139
157
|
if (typeof res.count === "number") total = res.count;
|
|
140
158
|
if (total === null) {
|
|
141
|
-
if (
|
|
159
|
+
if (page2.length < pageSize) return rows;
|
|
142
160
|
throw new IncompleteReadError(
|
|
143
161
|
opts.label,
|
|
144
162
|
rows.length,
|
|
@@ -147,7 +165,7 @@ async function readAllRows(query, opts) {
|
|
|
147
165
|
);
|
|
148
166
|
}
|
|
149
167
|
if (rows.length >= total) break;
|
|
150
|
-
if (
|
|
168
|
+
if (page2.length === 0) {
|
|
151
169
|
throw new IncompleteReadError(
|
|
152
170
|
opts.label,
|
|
153
171
|
rows.length,
|
|
@@ -190,7 +208,7 @@ async function readAllRowsRest(opts) {
|
|
|
190
208
|
const endpoint = `${opts.url.replace(/\/$/, "")}/rest/v1/${opts.path}`;
|
|
191
209
|
const rows = [];
|
|
192
210
|
let total = null;
|
|
193
|
-
for (let
|
|
211
|
+
for (let from2 = 0; ; from2 += pageSize) {
|
|
194
212
|
const res = await fetch(endpoint, {
|
|
195
213
|
headers: {
|
|
196
214
|
apikey: opts.key,
|
|
@@ -201,7 +219,7 @@ async function readAllRowsRest(opts) {
|
|
|
201
219
|
// no total, which is unverifiable and therefore refused below. This is
|
|
202
220
|
// the REST twin of supabase-js's `{ count: "exact" }`.
|
|
203
221
|
Prefer: "count=exact",
|
|
204
|
-
Range: `${
|
|
222
|
+
Range: `${from2}-${from2 + pageSize - 1}`,
|
|
205
223
|
"Range-Unit": "items"
|
|
206
224
|
}
|
|
207
225
|
});
|
|
@@ -210,12 +228,12 @@ async function readAllRowsRest(opts) {
|
|
|
210
228
|
`readAllRowsRest(${opts.label}): HTTP ${res.status} \u2014 ${await res.text()}`
|
|
211
229
|
);
|
|
212
230
|
}
|
|
213
|
-
const
|
|
214
|
-
rows.push(...
|
|
231
|
+
const page2 = await res.json();
|
|
232
|
+
rows.push(...page2);
|
|
215
233
|
const totalPart = res.headers.get("content-range")?.split("/")[1];
|
|
216
234
|
if (totalPart && totalPart !== "*") total = Number(totalPart);
|
|
217
235
|
if (total === null) {
|
|
218
|
-
if (
|
|
236
|
+
if (page2.length < pageSize) return rows;
|
|
219
237
|
throw new IncompleteReadError(
|
|
220
238
|
opts.label,
|
|
221
239
|
rows.length,
|
|
@@ -224,7 +242,7 @@ async function readAllRowsRest(opts) {
|
|
|
224
242
|
);
|
|
225
243
|
}
|
|
226
244
|
if (rows.length >= total) break;
|
|
227
|
-
if (
|
|
245
|
+
if (page2.length === 0) {
|
|
228
246
|
throw new IncompleteReadError(
|
|
229
247
|
opts.label,
|
|
230
248
|
rows.length,
|
|
@@ -360,9 +378,9 @@ function belongsToStorageKey(name, storageKey) {
|
|
|
360
378
|
if (!name.startsWith(`${storageKey}.`)) return false;
|
|
361
379
|
return /^(0|[1-9][0-9]*)$/.test(name.slice(storageKey.length + 1));
|
|
362
380
|
}
|
|
363
|
-
function renamedCookie(cookie,
|
|
364
|
-
if (cookie.name ===
|
|
365
|
-
const prefix = `${
|
|
381
|
+
function renamedCookie(cookie, from2, to) {
|
|
382
|
+
if (cookie.name === from2) return { ...cookie, name: to };
|
|
383
|
+
const prefix = `${from2}.`;
|
|
366
384
|
if (!cookie.name.startsWith(prefix)) return null;
|
|
367
385
|
const chunk = cookie.name.slice(prefix.length);
|
|
368
386
|
if (!/^(0|[1-9][0-9]*)$/.test(chunk)) return null;
|
|
@@ -955,4 +973,241 @@ function recordUnavailableMessage(entity, reason) {
|
|
|
955
973
|
function isRecordUnavailableError(value) {
|
|
956
974
|
return value instanceof RecordUnavailableError;
|
|
957
975
|
}
|
|
976
|
+
|
|
977
|
+
// src/db/doors.ts
|
|
978
|
+
function credentialsOf(client) {
|
|
979
|
+
return {
|
|
980
|
+
async get() {
|
|
981
|
+
if (!client.auth) return null;
|
|
982
|
+
const { data } = await client.auth.getSession();
|
|
983
|
+
return data.session ? { kind: "user", accessToken: data.session.access_token } : null;
|
|
984
|
+
},
|
|
985
|
+
onChange(cb) {
|
|
986
|
+
if (!client.auth) return () => {
|
|
987
|
+
};
|
|
988
|
+
const { data } = client.auth.onAuthStateChange(() => cb());
|
|
989
|
+
return () => data.subscription.unsubscribe();
|
|
990
|
+
}
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
function createDb(options) {
|
|
994
|
+
const { client, organization } = options;
|
|
995
|
+
return {
|
|
996
|
+
client,
|
|
997
|
+
role: "user",
|
|
998
|
+
activeOrganization: () => organization?.() ?? null,
|
|
999
|
+
credentials: credentialsOf(client)
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1002
|
+
function createServiceDb(options) {
|
|
1003
|
+
if (typeof globalThis.window !== "undefined") {
|
|
1004
|
+
throw new DoorRefusedError("createServiceDb", "the service role never runs in a browser");
|
|
1005
|
+
}
|
|
1006
|
+
return { client: options.client, role: "service", activeOrganization: () => null, credentials: credentialsOf(options.client) };
|
|
1007
|
+
}
|
|
1008
|
+
var DoorRefusedError = class extends Error {
|
|
1009
|
+
constructor(door, reason) {
|
|
1010
|
+
super(`${door}: ${reason}`);
|
|
1011
|
+
this.door = door;
|
|
1012
|
+
this.reason = reason;
|
|
1013
|
+
this.name = "DoorRefusedError";
|
|
1014
|
+
}
|
|
1015
|
+
door;
|
|
1016
|
+
reason;
|
|
1017
|
+
};
|
|
1018
|
+
var DatabaseError = class extends Error {
|
|
1019
|
+
constructor(door, cause) {
|
|
1020
|
+
super(`${door}: ${cause.message}${cause.code ? ` (${cause.code})` : ""}`);
|
|
1021
|
+
this.door = door;
|
|
1022
|
+
this.cause = cause;
|
|
1023
|
+
this.name = "DatabaseError";
|
|
1024
|
+
}
|
|
1025
|
+
door;
|
|
1026
|
+
cause;
|
|
1027
|
+
};
|
|
1028
|
+
var CLIENT_DOORS = {
|
|
1029
|
+
entity: ["read", "insert", "update", "remove", "archive"],
|
|
1030
|
+
detail: ["read", "insert", "update", "remove", "archive"],
|
|
1031
|
+
ledger: ["read", "insert"],
|
|
1032
|
+
reference: ["read"],
|
|
1033
|
+
system: ["read"],
|
|
1034
|
+
restricted: [],
|
|
1035
|
+
deprecated: []
|
|
1036
|
+
};
|
|
1037
|
+
var qualified = (t) => `${t.schema}.${t.name}`;
|
|
1038
|
+
function assertDoor(db, table, op) {
|
|
1039
|
+
const door = `${op} ${qualified(table)}`;
|
|
1040
|
+
if (table.type === "deprecated") throw new DoorRefusedError(door, "the table is deprecated \u2014 no door opens on it");
|
|
1041
|
+
if (table.kind !== "table" && op !== "read") throw new DoorRefusedError(door, `a ${table.kind.replace("_", " ")} is read-only`);
|
|
1042
|
+
if (db.role === "service") return;
|
|
1043
|
+
if (table.type && !CLIENT_DOORS[table.type].includes(op))
|
|
1044
|
+
throw new DoorRefusedError(door, `a ${table.type} table opens only ${CLIENT_DOORS[table.type].join(", ") || "service"} doors to a client`);
|
|
1045
|
+
if (op !== "read" && table.readOnly) throw new DoorRefusedError(door, "the table is read-only to clients (client_read_only)");
|
|
1046
|
+
if (op === "remove" && table.deletesRefused) throw new DoorRefusedError(door, "clients may not delete from this table (client_deletes_refused)");
|
|
1047
|
+
}
|
|
1048
|
+
function check(door, res) {
|
|
1049
|
+
if (res.error) throw new DatabaseError(door, res.error);
|
|
1050
|
+
return res.data;
|
|
1051
|
+
}
|
|
1052
|
+
var from = (db, t) => db.client.schema(t.schema).from(t.name);
|
|
1053
|
+
function byPk(q, t, id) {
|
|
1054
|
+
if (t.pk.length === 1) return q.eq(t.pk[0], id);
|
|
1055
|
+
const key = id;
|
|
1056
|
+
return t.pk.reduce((acc, col) => acc.eq(col, key[col]), q);
|
|
1057
|
+
}
|
|
1058
|
+
var selectOf = (columns) => columns && columns.length ? columns.join(",") : "*";
|
|
1059
|
+
function live(q, table, includeDeleted) {
|
|
1060
|
+
return table.softDelete && !includeDeleted ? q.is("deleted_at", null) : q;
|
|
1061
|
+
}
|
|
1062
|
+
function ordered(q, table, orderBy, ascending = true) {
|
|
1063
|
+
const cols = orderBy ? [orderBy, ...table.pk.filter((c) => c !== orderBy)] : table.pk.length ? table.pk : ["id"];
|
|
1064
|
+
return cols.reduce((acc, c) => acc.order(c, { ascending }), q);
|
|
1065
|
+
}
|
|
1066
|
+
async function read(db, table, id, opts = {}) {
|
|
1067
|
+
assertDoor(db, table, "read");
|
|
1068
|
+
const q = live(byPk(from(db, table).select(selectOf(opts.columns)), table, id), table, opts.includeDeleted);
|
|
1069
|
+
return check(`read ${qualified(table)}`, await q.maybeSingle());
|
|
1070
|
+
}
|
|
1071
|
+
async function listAll(db, table, where, opts = {}) {
|
|
1072
|
+
assertDoor(db, table, "read");
|
|
1073
|
+
return readAllRows(
|
|
1074
|
+
({ from: lo, to: hi }) => {
|
|
1075
|
+
let q = live(from(db, table).select(selectOf(opts.columns), { count: "exact" }), table, opts.includeDeleted);
|
|
1076
|
+
if (where) q = where(q);
|
|
1077
|
+
return ordered(q, table, opts.orderBy).range(lo, hi);
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
label: `listAll ${qualified(table)}`,
|
|
1081
|
+
...opts.pageSize !== void 0 ? { pageSize: opts.pageSize } : {},
|
|
1082
|
+
...opts.maxRows !== void 0 ? { maxRows: opts.maxRows } : {}
|
|
1083
|
+
}
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
1086
|
+
async function page(db, table, window2) {
|
|
1087
|
+
assertDoor(db, table, "read");
|
|
1088
|
+
let q = live(from(db, table).select(selectOf(window2.columns), { count: "exact" }), table, window2.includeDeleted);
|
|
1089
|
+
if (window2.where) q = window2.where(q);
|
|
1090
|
+
const res = await ordered(q, table, window2.orderBy, window2.ascending ?? true).range(window2.from, window2.to);
|
|
1091
|
+
return { rows: check(`page ${qualified(table)}`, res) ?? [], total: res.count ?? null };
|
|
1092
|
+
}
|
|
1093
|
+
async function count(db, table, where, opts = {}) {
|
|
1094
|
+
assertDoor(db, table, "read");
|
|
1095
|
+
let q = live(from(db, table).select("*", { count: "exact", head: true }), table, opts.includeDeleted);
|
|
1096
|
+
if (where) q = where(q);
|
|
1097
|
+
const res = await q;
|
|
1098
|
+
check(`count ${qualified(table)}`, res);
|
|
1099
|
+
return res.count ?? 0;
|
|
1100
|
+
}
|
|
1101
|
+
function withOrganization(db, table, values) {
|
|
1102
|
+
const door = `insert ${qualified(table)}`;
|
|
1103
|
+
const org = table.org;
|
|
1104
|
+
if (org.rule === "parent" && values[org.via] != null) {
|
|
1105
|
+
return values;
|
|
1106
|
+
}
|
|
1107
|
+
if (org.rule === "binding" || org.rule === "parent") {
|
|
1108
|
+
if (values.organization_id != null) return values;
|
|
1109
|
+
const active = db.activeOrganization();
|
|
1110
|
+
if (!active) {
|
|
1111
|
+
throw new DoorRefusedError(
|
|
1112
|
+
door,
|
|
1113
|
+
db.role === "service" ? "a service insert names its organization_id" : "no organization: pass organization_id or bind createDb({ organization })"
|
|
1114
|
+
);
|
|
1115
|
+
}
|
|
1116
|
+
return { ...values, organization_id: active };
|
|
1117
|
+
}
|
|
1118
|
+
return values;
|
|
1119
|
+
}
|
|
1120
|
+
async function insert(db, table, values) {
|
|
1121
|
+
assertDoor(db, table, "insert");
|
|
1122
|
+
const many = Array.isArray(values);
|
|
1123
|
+
const rows = (many ? values : [values]).map((v) => withOrganization(db, table, v));
|
|
1124
|
+
const res = await from(db, table).insert(rows).select("*");
|
|
1125
|
+
const stored = check(`insert ${qualified(table)}`, res);
|
|
1126
|
+
return many ? stored : stored[0];
|
|
1127
|
+
}
|
|
1128
|
+
async function writeRow(db, table, id, values, door, guard) {
|
|
1129
|
+
const expected = guard && "expectedVersion" in guard ? guard.expectedVersion : void 0;
|
|
1130
|
+
if (expected !== void 0 && !table.versioned) {
|
|
1131
|
+
throw new DoorRefusedError(door, "expectedVersion on a table that is not versioned \u2014 nothing would guard it; pass no guard");
|
|
1132
|
+
}
|
|
1133
|
+
if (table.versioned && expected === void 0 && !(guard && "overwrite" in guard && guard.overwrite)) {
|
|
1134
|
+
throw new DoorRefusedError(door, "a versioned table takes { expectedVersion } or { overwrite: true }");
|
|
1135
|
+
}
|
|
1136
|
+
if (expected !== void 0) {
|
|
1137
|
+
return await guardedUpdate({
|
|
1138
|
+
expectedVersion: expected,
|
|
1139
|
+
applyUpdate: ({ expectedVersion, nextVersion }) => byPk(from(db, table).update({ ...values, version: nextVersion }), table, id).eq("version", expectedVersion).select("*").maybeSingle(),
|
|
1140
|
+
fetchCurrent: () => byPk(from(db, table).select("*"), table, id).maybeSingle()
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
const row = check(door, await byPk(from(db, table).update(values), table, id).select("*").maybeSingle());
|
|
1144
|
+
return row ? { status: "saved", row } : { status: "not_found" };
|
|
1145
|
+
}
|
|
1146
|
+
async function update(db, table, id, patch, guard) {
|
|
1147
|
+
assertDoor(db, table, "update");
|
|
1148
|
+
const door = `update ${qualified(table)}`;
|
|
1149
|
+
const values = patch;
|
|
1150
|
+
if (db.role === "user") {
|
|
1151
|
+
const blocked = table.readOnlyColumns.filter((c) => c in values);
|
|
1152
|
+
if (blocked.length) throw new DoorRefusedError(door, `read-only to clients: ${blocked.join(", ")}`);
|
|
1153
|
+
}
|
|
1154
|
+
return writeRow(db, table, id, values, door, guard);
|
|
1155
|
+
}
|
|
1156
|
+
async function remove(db, table, id, guard) {
|
|
1157
|
+
assertDoor(db, table, "remove");
|
|
1158
|
+
const door = `remove ${qualified(table)}`;
|
|
1159
|
+
if (table.softDelete) {
|
|
1160
|
+
const res = await writeRow(db, table, id, { deleted_at: (/* @__PURE__ */ new Date()).toISOString() }, door, guard);
|
|
1161
|
+
return res.status === "saved" ? { status: "soft_deleted" } : res.status === "conflict" ? { status: "conflict", currentVersion: res.currentVersion } : res;
|
|
1162
|
+
}
|
|
1163
|
+
if (table.archive) throw new DoorRefusedError(door, "this table archives instead of deleting \u2014 use archive()");
|
|
1164
|
+
const expected = guard && "expectedVersion" in guard ? guard.expectedVersion : void 0;
|
|
1165
|
+
if (expected !== void 0 && !table.versioned) throw new DoorRefusedError(door, "expectedVersion on a table that is not versioned");
|
|
1166
|
+
if (table.versioned && expected === void 0 && !(guard && "overwrite" in guard)) {
|
|
1167
|
+
throw new DoorRefusedError(door, "a versioned table takes { expectedVersion } or { overwrite: true }");
|
|
1168
|
+
}
|
|
1169
|
+
let q = byPk(from(db, table).delete(), table, id);
|
|
1170
|
+
if (expected !== void 0) q = q.eq("version", expected);
|
|
1171
|
+
const rows = check(door, await q.select("*"));
|
|
1172
|
+
if (rows && rows.length) return { status: "deleted" };
|
|
1173
|
+
if (expected !== void 0) {
|
|
1174
|
+
const current = check(door, await byPk(from(db, table).select("version"), table, id).maybeSingle());
|
|
1175
|
+
if (current) return { status: "conflict", currentVersion: current.version };
|
|
1176
|
+
}
|
|
1177
|
+
return { status: "not_found" };
|
|
1178
|
+
}
|
|
1179
|
+
async function archive(db, table, id, opts = {}) {
|
|
1180
|
+
assertDoor(db, table, "archive");
|
|
1181
|
+
const door = `${opts.restore ? "restore" : "archive"} ${qualified(table)}`;
|
|
1182
|
+
let values;
|
|
1183
|
+
if (table.archive === "archived_at") values = { archived_at: opts.restore ? null : (/* @__PURE__ */ new Date()).toISOString() };
|
|
1184
|
+
else if (table.archive === "is_archived") values = { is_archived: !opts.restore };
|
|
1185
|
+
else if (table.softDelete && opts.restore) values = { deleted_at: null };
|
|
1186
|
+
else throw new DoorRefusedError(door, "the table has no archive column");
|
|
1187
|
+
return writeRow(db, table, id, values, door, opts.guard);
|
|
1188
|
+
}
|
|
1189
|
+
var restore = (db, table, id, guard) => archive(db, table, id, guard ? { restore: true, guard } : { restore: true });
|
|
1190
|
+
async function call(db, fn, args) {
|
|
1191
|
+
const door = `call ${fn.schema}.${fn.name}`;
|
|
1192
|
+
const role = db.role === "service" ? "service_role" : "authenticated";
|
|
1193
|
+
if (!fn.roles.includes(role) && !(role === "authenticated" && fn.roles.includes("anon"))) {
|
|
1194
|
+
throw new DoorRefusedError(door, `not executable by ${role} (executable by: ${fn.roles.join(", ") || "nobody"})`);
|
|
1195
|
+
}
|
|
1196
|
+
return check(door, await db.client.schema(fn.schema).rpc(fn.name, args));
|
|
1197
|
+
}
|
|
1198
|
+
function tableByName(index, name) {
|
|
1199
|
+
const t = index[name];
|
|
1200
|
+
if (!t) throw new DoorRefusedError(`tableByName ${name}`, "no such table in the database description (schema-qualify it: schema.table)");
|
|
1201
|
+
return t;
|
|
1202
|
+
}
|
|
1203
|
+
async function loadTableByName(loaders, name) {
|
|
1204
|
+
const schema = name.slice(0, name.indexOf("."));
|
|
1205
|
+
const load = schema ? loaders[schema] : void 0;
|
|
1206
|
+
if (!load) throw new DoorRefusedError(`tableByName ${name}`, "no such schema in the database description (schema-qualify it: schema.table)");
|
|
1207
|
+
return tableByName(await load(), name);
|
|
1208
|
+
}
|
|
1209
|
+
function changesOf(table) {
|
|
1210
|
+
if (!table.realtime) throw new DoorRefusedError(`changesOf ${qualified(table)}`, "the table is not in the supabase_realtime publication");
|
|
1211
|
+
return { schema: table.schema, table: table.name };
|
|
1212
|
+
}
|
|
958
1213
|
//# sourceMappingURL=db.cjs.map
|