@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.
Files changed (74) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +34 -0
  3. package/bin/direct-db.mjs +80 -0
  4. package/bin/emit.mjs +380 -0
  5. package/bin/generate.mjs +225 -0
  6. package/bin/matrx-data.mjs +49 -0
  7. package/description/admin.json.gz +0 -0
  8. package/description/agent.json.gz +0 -0
  9. package/description/ai.json.gz +0 -0
  10. package/description/api.json.gz +0 -0
  11. package/description/app.json.gz +0 -0
  12. package/description/assignment.json.gz +0 -0
  13. package/description/audit.json.gz +0 -0
  14. package/description/batch.json.gz +0 -0
  15. package/description/billing.json.gz +0 -0
  16. package/description/browser.json.gz +0 -0
  17. package/description/canvas.json.gz +0 -0
  18. package/description/chat.json.gz +0 -0
  19. package/description/code.json.gz +0 -0
  20. package/description/commerce.json.gz +0 -0
  21. package/description/communication.json.gz +0 -0
  22. package/description/content.json.gz +0 -0
  23. package/description/content_ir.json.gz +0 -0
  24. package/description/context.json.gz +0 -0
  25. package/description/crm.json.gz +0 -0
  26. package/description/custom.json.gz +0 -0
  27. package/description/dictionary.json.gz +0 -0
  28. package/description/docproc.json.gz +0 -0
  29. package/description/education.json.gz +0 -0
  30. package/description/esign.json.gz +0 -0
  31. package/description/extend.json.gz +0 -0
  32. package/description/files.json.gz +0 -0
  33. package/description/growth.json.gz +0 -0
  34. package/description/hindsight.json.gz +0 -0
  35. package/description/history.json.gz +0 -0
  36. package/description/iam.json.gz +0 -0
  37. package/description/index.json.gz +0 -0
  38. package/description/interview.json.gz +0 -0
  39. package/description/knowledge.json.gz +0 -0
  40. package/description/legal.json.gz +0 -0
  41. package/description/mandate.json.gz +0 -0
  42. package/description/marketing.json.gz +0 -0
  43. package/description/media.json.gz +0 -0
  44. package/description/meta.json.gz +0 -0
  45. package/description/ops.json.gz +0 -0
  46. package/description/pdf.json.gz +0 -0
  47. package/description/plan.json.gz +0 -0
  48. package/description/platform.json.gz +0 -0
  49. package/description/podcast.json.gz +0 -0
  50. package/description/projects.json.gz +0 -0
  51. package/description/public.json.gz +0 -0
  52. package/description/rag.json.gz +0 -0
  53. package/description/research.json.gz +0 -0
  54. package/description/runtime.json.gz +0 -0
  55. package/description/scheduler.json.gz +0 -0
  56. package/description/scraper.json.gz +0 -0
  57. package/description/seo.json.gz +0 -0
  58. package/description/skill.json.gz +0 -0
  59. package/description/social.json.gz +0 -0
  60. package/description/tool.json.gz +0 -0
  61. package/description/transcripts.json.gz +0 -0
  62. package/description/ui.json.gz +0 -0
  63. package/description/users.json.gz +0 -0
  64. package/description/web.json.gz +0 -0
  65. package/description/work.json.gz +0 -0
  66. package/description/workbench.json.gz +0 -0
  67. package/description/workflow.json.gz +0 -0
  68. package/dist/db.cjs +274 -19
  69. package/dist/db.cjs.map +1 -1
  70. package/dist/db.d.cts +270 -3
  71. package/dist/db.d.ts +270 -3
  72. package/dist/db.js +270 -15
  73. package/dist/db.js.map +1 -1
  74. package/package.json +9 -4
package/dist/db.js CHANGED
@@ -66,18 +66,18 @@ async function readAllRows(query, opts) {
66
66
  const maxRows = opts.maxRows ?? DEFAULT_MAX_ROWS;
67
67
  const rows = [];
68
68
  let total = null;
69
- for (let from = 0; ; from += pageSize) {
70
- const res = await query({ from, to: from + pageSize - 1 });
69
+ for (let from2 = 0; ; from2 += pageSize) {
70
+ const res = await query({ from: from2, to: from2 + pageSize - 1 });
71
71
  if (res.error) {
72
72
  throw new Error(
73
73
  `readAllRows(${opts.label}): query failed \u2014 ${res.error.message}`
74
74
  );
75
75
  }
76
- const page = res.data ?? [];
77
- rows.push(...page);
76
+ const page2 = res.data ?? [];
77
+ rows.push(...page2);
78
78
  if (typeof res.count === "number") total = res.count;
79
79
  if (total === null) {
80
- if (page.length < pageSize) return rows;
80
+ if (page2.length < pageSize) return rows;
81
81
  throw new IncompleteReadError(
82
82
  opts.label,
83
83
  rows.length,
@@ -86,7 +86,7 @@ async function readAllRows(query, opts) {
86
86
  );
87
87
  }
88
88
  if (rows.length >= total) break;
89
- if (page.length === 0) {
89
+ if (page2.length === 0) {
90
90
  throw new IncompleteReadError(
91
91
  opts.label,
92
92
  rows.length,
@@ -129,7 +129,7 @@ async function readAllRowsRest(opts) {
129
129
  const endpoint = `${opts.url.replace(/\/$/, "")}/rest/v1/${opts.path}`;
130
130
  const rows = [];
131
131
  let total = null;
132
- for (let from = 0; ; from += pageSize) {
132
+ for (let from2 = 0; ; from2 += pageSize) {
133
133
  const res = await fetch(endpoint, {
134
134
  headers: {
135
135
  apikey: opts.key,
@@ -140,7 +140,7 @@ async function readAllRowsRest(opts) {
140
140
  // no total, which is unverifiable and therefore refused below. This is
141
141
  // the REST twin of supabase-js's `{ count: "exact" }`.
142
142
  Prefer: "count=exact",
143
- Range: `${from}-${from + pageSize - 1}`,
143
+ Range: `${from2}-${from2 + pageSize - 1}`,
144
144
  "Range-Unit": "items"
145
145
  }
146
146
  });
@@ -149,12 +149,12 @@ async function readAllRowsRest(opts) {
149
149
  `readAllRowsRest(${opts.label}): HTTP ${res.status} \u2014 ${await res.text()}`
150
150
  );
151
151
  }
152
- const page = await res.json();
153
- rows.push(...page);
152
+ const page2 = await res.json();
153
+ rows.push(...page2);
154
154
  const totalPart = res.headers.get("content-range")?.split("/")[1];
155
155
  if (totalPart && totalPart !== "*") total = Number(totalPart);
156
156
  if (total === null) {
157
- if (page.length < pageSize) return rows;
157
+ if (page2.length < pageSize) return rows;
158
158
  throw new IncompleteReadError(
159
159
  opts.label,
160
160
  rows.length,
@@ -163,7 +163,7 @@ async function readAllRowsRest(opts) {
163
163
  );
164
164
  }
165
165
  if (rows.length >= total) break;
166
- if (page.length === 0) {
166
+ if (page2.length === 0) {
167
167
  throw new IncompleteReadError(
168
168
  opts.label,
169
169
  rows.length,
@@ -299,9 +299,9 @@ function belongsToStorageKey(name, storageKey) {
299
299
  if (!name.startsWith(`${storageKey}.`)) return false;
300
300
  return /^(0|[1-9][0-9]*)$/.test(name.slice(storageKey.length + 1));
301
301
  }
302
- function renamedCookie(cookie, from, to) {
303
- if (cookie.name === from) return { ...cookie, name: to };
304
- const prefix = `${from}.`;
302
+ function renamedCookie(cookie, from2, to) {
303
+ if (cookie.name === from2) return { ...cookie, name: to };
304
+ const prefix = `${from2}.`;
305
305
  if (!cookie.name.startsWith(prefix)) return null;
306
306
  const chunk = cookie.name.slice(prefix.length);
307
307
  if (!/^(0|[1-9][0-9]*)$/.test(chunk)) return null;
@@ -894,40 +894,295 @@ function recordUnavailableMessage(entity, reason) {
894
894
  function isRecordUnavailableError(value) {
895
895
  return value instanceof RecordUnavailableError;
896
896
  }
897
+
898
+ // src/db/doors.ts
899
+ function credentialsOf(client) {
900
+ return {
901
+ async get() {
902
+ if (!client.auth) return null;
903
+ const { data } = await client.auth.getSession();
904
+ return data.session ? { kind: "user", accessToken: data.session.access_token } : null;
905
+ },
906
+ onChange(cb) {
907
+ if (!client.auth) return () => {
908
+ };
909
+ const { data } = client.auth.onAuthStateChange(() => cb());
910
+ return () => data.subscription.unsubscribe();
911
+ }
912
+ };
913
+ }
914
+ function createDb(options) {
915
+ const { client, organization } = options;
916
+ return {
917
+ client,
918
+ role: "user",
919
+ activeOrganization: () => organization?.() ?? null,
920
+ credentials: credentialsOf(client)
921
+ };
922
+ }
923
+ function createServiceDb(options) {
924
+ if (typeof globalThis.window !== "undefined") {
925
+ throw new DoorRefusedError("createServiceDb", "the service role never runs in a browser");
926
+ }
927
+ return { client: options.client, role: "service", activeOrganization: () => null, credentials: credentialsOf(options.client) };
928
+ }
929
+ var DoorRefusedError = class extends Error {
930
+ constructor(door, reason) {
931
+ super(`${door}: ${reason}`);
932
+ this.door = door;
933
+ this.reason = reason;
934
+ this.name = "DoorRefusedError";
935
+ }
936
+ door;
937
+ reason;
938
+ };
939
+ var DatabaseError = class extends Error {
940
+ constructor(door, cause) {
941
+ super(`${door}: ${cause.message}${cause.code ? ` (${cause.code})` : ""}`);
942
+ this.door = door;
943
+ this.cause = cause;
944
+ this.name = "DatabaseError";
945
+ }
946
+ door;
947
+ cause;
948
+ };
949
+ var CLIENT_DOORS = {
950
+ entity: ["read", "insert", "update", "remove", "archive"],
951
+ detail: ["read", "insert", "update", "remove", "archive"],
952
+ ledger: ["read", "insert"],
953
+ reference: ["read"],
954
+ system: ["read"],
955
+ restricted: [],
956
+ deprecated: []
957
+ };
958
+ var qualified = (t) => `${t.schema}.${t.name}`;
959
+ function assertDoor(db, table, op) {
960
+ const door = `${op} ${qualified(table)}`;
961
+ if (table.type === "deprecated") throw new DoorRefusedError(door, "the table is deprecated \u2014 no door opens on it");
962
+ if (table.kind !== "table" && op !== "read") throw new DoorRefusedError(door, `a ${table.kind.replace("_", " ")} is read-only`);
963
+ if (db.role === "service") return;
964
+ if (table.type && !CLIENT_DOORS[table.type].includes(op))
965
+ throw new DoorRefusedError(door, `a ${table.type} table opens only ${CLIENT_DOORS[table.type].join(", ") || "service"} doors to a client`);
966
+ if (op !== "read" && table.readOnly) throw new DoorRefusedError(door, "the table is read-only to clients (client_read_only)");
967
+ if (op === "remove" && table.deletesRefused) throw new DoorRefusedError(door, "clients may not delete from this table (client_deletes_refused)");
968
+ }
969
+ function check(door, res) {
970
+ if (res.error) throw new DatabaseError(door, res.error);
971
+ return res.data;
972
+ }
973
+ var from = (db, t) => db.client.schema(t.schema).from(t.name);
974
+ function byPk(q, t, id) {
975
+ if (t.pk.length === 1) return q.eq(t.pk[0], id);
976
+ const key = id;
977
+ return t.pk.reduce((acc, col) => acc.eq(col, key[col]), q);
978
+ }
979
+ var selectOf = (columns) => columns && columns.length ? columns.join(",") : "*";
980
+ function live(q, table, includeDeleted) {
981
+ return table.softDelete && !includeDeleted ? q.is("deleted_at", null) : q;
982
+ }
983
+ function ordered(q, table, orderBy, ascending = true) {
984
+ const cols = orderBy ? [orderBy, ...table.pk.filter((c) => c !== orderBy)] : table.pk.length ? table.pk : ["id"];
985
+ return cols.reduce((acc, c) => acc.order(c, { ascending }), q);
986
+ }
987
+ async function read(db, table, id, opts = {}) {
988
+ assertDoor(db, table, "read");
989
+ const q = live(byPk(from(db, table).select(selectOf(opts.columns)), table, id), table, opts.includeDeleted);
990
+ return check(`read ${qualified(table)}`, await q.maybeSingle());
991
+ }
992
+ async function listAll(db, table, where, opts = {}) {
993
+ assertDoor(db, table, "read");
994
+ return readAllRows(
995
+ ({ from: lo, to: hi }) => {
996
+ let q = live(from(db, table).select(selectOf(opts.columns), { count: "exact" }), table, opts.includeDeleted);
997
+ if (where) q = where(q);
998
+ return ordered(q, table, opts.orderBy).range(lo, hi);
999
+ },
1000
+ {
1001
+ label: `listAll ${qualified(table)}`,
1002
+ ...opts.pageSize !== void 0 ? { pageSize: opts.pageSize } : {},
1003
+ ...opts.maxRows !== void 0 ? { maxRows: opts.maxRows } : {}
1004
+ }
1005
+ );
1006
+ }
1007
+ async function page(db, table, window2) {
1008
+ assertDoor(db, table, "read");
1009
+ let q = live(from(db, table).select(selectOf(window2.columns), { count: "exact" }), table, window2.includeDeleted);
1010
+ if (window2.where) q = window2.where(q);
1011
+ const res = await ordered(q, table, window2.orderBy, window2.ascending ?? true).range(window2.from, window2.to);
1012
+ return { rows: check(`page ${qualified(table)}`, res) ?? [], total: res.count ?? null };
1013
+ }
1014
+ async function count(db, table, where, opts = {}) {
1015
+ assertDoor(db, table, "read");
1016
+ let q = live(from(db, table).select("*", { count: "exact", head: true }), table, opts.includeDeleted);
1017
+ if (where) q = where(q);
1018
+ const res = await q;
1019
+ check(`count ${qualified(table)}`, res);
1020
+ return res.count ?? 0;
1021
+ }
1022
+ function withOrganization(db, table, values) {
1023
+ const door = `insert ${qualified(table)}`;
1024
+ const org = table.org;
1025
+ if (org.rule === "parent" && values[org.via] != null) {
1026
+ return values;
1027
+ }
1028
+ if (org.rule === "binding" || org.rule === "parent") {
1029
+ if (values.organization_id != null) return values;
1030
+ const active = db.activeOrganization();
1031
+ if (!active) {
1032
+ throw new DoorRefusedError(
1033
+ door,
1034
+ db.role === "service" ? "a service insert names its organization_id" : "no organization: pass organization_id or bind createDb({ organization })"
1035
+ );
1036
+ }
1037
+ return { ...values, organization_id: active };
1038
+ }
1039
+ return values;
1040
+ }
1041
+ async function insert(db, table, values) {
1042
+ assertDoor(db, table, "insert");
1043
+ const many = Array.isArray(values);
1044
+ const rows = (many ? values : [values]).map((v) => withOrganization(db, table, v));
1045
+ const res = await from(db, table).insert(rows).select("*");
1046
+ const stored = check(`insert ${qualified(table)}`, res);
1047
+ return many ? stored : stored[0];
1048
+ }
1049
+ async function writeRow(db, table, id, values, door, guard) {
1050
+ const expected = guard && "expectedVersion" in guard ? guard.expectedVersion : void 0;
1051
+ if (expected !== void 0 && !table.versioned) {
1052
+ throw new DoorRefusedError(door, "expectedVersion on a table that is not versioned \u2014 nothing would guard it; pass no guard");
1053
+ }
1054
+ if (table.versioned && expected === void 0 && !(guard && "overwrite" in guard && guard.overwrite)) {
1055
+ throw new DoorRefusedError(door, "a versioned table takes { expectedVersion } or { overwrite: true }");
1056
+ }
1057
+ if (expected !== void 0) {
1058
+ return await guardedUpdate({
1059
+ expectedVersion: expected,
1060
+ applyUpdate: ({ expectedVersion, nextVersion }) => byPk(from(db, table).update({ ...values, version: nextVersion }), table, id).eq("version", expectedVersion).select("*").maybeSingle(),
1061
+ fetchCurrent: () => byPk(from(db, table).select("*"), table, id).maybeSingle()
1062
+ });
1063
+ }
1064
+ const row = check(door, await byPk(from(db, table).update(values), table, id).select("*").maybeSingle());
1065
+ return row ? { status: "saved", row } : { status: "not_found" };
1066
+ }
1067
+ async function update(db, table, id, patch, guard) {
1068
+ assertDoor(db, table, "update");
1069
+ const door = `update ${qualified(table)}`;
1070
+ const values = patch;
1071
+ if (db.role === "user") {
1072
+ const blocked = table.readOnlyColumns.filter((c) => c in values);
1073
+ if (blocked.length) throw new DoorRefusedError(door, `read-only to clients: ${blocked.join(", ")}`);
1074
+ }
1075
+ return writeRow(db, table, id, values, door, guard);
1076
+ }
1077
+ async function remove(db, table, id, guard) {
1078
+ assertDoor(db, table, "remove");
1079
+ const door = `remove ${qualified(table)}`;
1080
+ if (table.softDelete) {
1081
+ const res = await writeRow(db, table, id, { deleted_at: (/* @__PURE__ */ new Date()).toISOString() }, door, guard);
1082
+ return res.status === "saved" ? { status: "soft_deleted" } : res.status === "conflict" ? { status: "conflict", currentVersion: res.currentVersion } : res;
1083
+ }
1084
+ if (table.archive) throw new DoorRefusedError(door, "this table archives instead of deleting \u2014 use archive()");
1085
+ const expected = guard && "expectedVersion" in guard ? guard.expectedVersion : void 0;
1086
+ if (expected !== void 0 && !table.versioned) throw new DoorRefusedError(door, "expectedVersion on a table that is not versioned");
1087
+ if (table.versioned && expected === void 0 && !(guard && "overwrite" in guard)) {
1088
+ throw new DoorRefusedError(door, "a versioned table takes { expectedVersion } or { overwrite: true }");
1089
+ }
1090
+ let q = byPk(from(db, table).delete(), table, id);
1091
+ if (expected !== void 0) q = q.eq("version", expected);
1092
+ const rows = check(door, await q.select("*"));
1093
+ if (rows && rows.length) return { status: "deleted" };
1094
+ if (expected !== void 0) {
1095
+ const current = check(door, await byPk(from(db, table).select("version"), table, id).maybeSingle());
1096
+ if (current) return { status: "conflict", currentVersion: current.version };
1097
+ }
1098
+ return { status: "not_found" };
1099
+ }
1100
+ async function archive(db, table, id, opts = {}) {
1101
+ assertDoor(db, table, "archive");
1102
+ const door = `${opts.restore ? "restore" : "archive"} ${qualified(table)}`;
1103
+ let values;
1104
+ if (table.archive === "archived_at") values = { archived_at: opts.restore ? null : (/* @__PURE__ */ new Date()).toISOString() };
1105
+ else if (table.archive === "is_archived") values = { is_archived: !opts.restore };
1106
+ else if (table.softDelete && opts.restore) values = { deleted_at: null };
1107
+ else throw new DoorRefusedError(door, "the table has no archive column");
1108
+ return writeRow(db, table, id, values, door, opts.guard);
1109
+ }
1110
+ var restore = (db, table, id, guard) => archive(db, table, id, guard ? { restore: true, guard } : { restore: true });
1111
+ async function call(db, fn, args) {
1112
+ const door = `call ${fn.schema}.${fn.name}`;
1113
+ const role = db.role === "service" ? "service_role" : "authenticated";
1114
+ if (!fn.roles.includes(role) && !(role === "authenticated" && fn.roles.includes("anon"))) {
1115
+ throw new DoorRefusedError(door, `not executable by ${role} (executable by: ${fn.roles.join(", ") || "nobody"})`);
1116
+ }
1117
+ return check(door, await db.client.schema(fn.schema).rpc(fn.name, args));
1118
+ }
1119
+ function tableByName(index, name) {
1120
+ const t = index[name];
1121
+ if (!t) throw new DoorRefusedError(`tableByName ${name}`, "no such table in the database description (schema-qualify it: schema.table)");
1122
+ return t;
1123
+ }
1124
+ async function loadTableByName(loaders, name) {
1125
+ const schema = name.slice(0, name.indexOf("."));
1126
+ const load = schema ? loaders[schema] : void 0;
1127
+ if (!load) throw new DoorRefusedError(`tableByName ${name}`, "no such schema in the database description (schema-qualify it: schema.table)");
1128
+ return tableByName(await load(), name);
1129
+ }
1130
+ function changesOf(table) {
1131
+ if (!table.realtime) throw new DoorRefusedError(`changesOf ${qualified(table)}`, "the table is not in the supabase_realtime publication");
1132
+ return { schema: table.schema, table: table.name };
1133
+ }
897
1134
  export {
898
1135
  BulkWriteError,
899
1136
  DEFAULT_ACTIVE_ORG_COOKIE_MAX_AGE,
900
1137
  DEFAULT_ACTIVE_ORG_COOKIE_NAME,
901
1138
  DEFAULT_AUTH_COOKIE_NAME,
1139
+ DatabaseError,
1140
+ DoorRefusedError,
902
1141
  IncompleteReadError,
903
1142
  RecordUnavailableError,
904
1143
  SessionUnavailableError,
905
1144
  WriteDidNotLandError,
906
1145
  WriteRefusedError,
1146
+ archive,
907
1147
  asJsonObject,
1148
+ assertDoor,
908
1149
  assertWriteLanded,
1150
+ call,
1151
+ changesOf,
1152
+ count,
909
1153
  createActiveOrgCookie,
910
1154
  createAuthCookie,
1155
+ createDb,
911
1156
  createOAuthRefreshFetch,
1157
+ createServiceDb,
912
1158
  createSessionRetry,
913
1159
  decodeActiveOrgSelection,
914
1160
  decodeOAuthRefreshClaims,
915
1161
  describeWriteFailure,
916
1162
  encodeActiveOrgSelection,
917
1163
  guardedUpdate,
1164
+ insert,
918
1165
  isMissingSessionError,
919
1166
  isRecordUnavailableError,
1167
+ listAll,
1168
+ loadTableByName,
920
1169
  mergeJsonColumn,
1170
+ page,
921
1171
  parseCookieHeader,
922
1172
  personSentence,
1173
+ read,
923
1174
  readAllRows,
924
1175
  readAllRowsRest,
925
1176
  recordUnavailableMessage,
1177
+ remove,
1178
+ restore,
926
1179
  serverMessageFromBody,
1180
+ tableByName,
927
1181
  tryReadAllRows,
928
1182
  tryReadAllRowsRest,
929
1183
  tryWriteOne,
930
1184
  uniqueChannelTopic,
1185
+ update,
931
1186
  writeFailureStatus,
932
1187
  writeOne,
933
1188
  writeOneRow