@voltro/database 0.84.0 → 0.86.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 +1215 -0
- package/THIRD-PARTY-NOTICES.md +5 -89
- package/dist/actorSnapshot.js +24 -0
- package/dist/arrayCodec.js +32 -0
- package/dist/branchExecute.js +92 -0
- package/dist/branching.js +106 -0
- package/dist/bulkInsertLimits.js +25 -0
- package/dist/cdcOffsetsTables.js +19 -0
- package/dist/changeEvent.js +41 -0
- package/dist/changeIdentity.js +65 -0
- package/dist/changeListenerCeiling.js +6 -0
- package/dist/columnReference.js +17 -0
- package/dist/columns.js +326 -0
- package/dist/committedChanges.js +12 -0
- package/dist/connectionIdentity.js +36 -0
- package/dist/coreTables.js +16 -0
- package/dist/coreTablesRegistry.js +10 -0
- package/dist/dataTransfers.js +22 -0
- package/dist/dbCause.js +222 -0
- package/dist/dbMetrics.js +65 -0
- package/dist/decimalComparison.js +27 -0
- package/dist/derivedRowId.js +5 -0
- package/dist/dialect.js +13 -0
- package/dist/enumRenames.js +14 -0
- package/dist/expiresMixin.js +10 -0
- package/dist/fieldEncryption.js +98 -0
- package/dist/frameworkTables.js +130 -0
- package/dist/ginIndex.js +10 -0
- package/dist/hybridSearch.js +32 -0
- package/dist/idGenerator.js +57 -0
- package/dist/identifierLimits.js +32 -0
- package/dist/index.d.ts +122 -64
- package/dist/index.js +81 -2080
- package/dist/indexAudit.js +61 -0
- package/dist/indexStorage.js +58 -0
- package/dist/joinCompiler.js +160 -0
- package/dist/jsonEagerCompiler.js +436 -0
- package/dist/jsonPatch.js +78 -0
- package/dist/jsonPatchAssignments.js +13 -0
- package/dist/jsonPath.js +31 -0
- package/dist/localFirstMixin.js +12 -0
- package/dist/migrate.js +624 -0
- package/dist/migration.js +18 -0
- package/dist/migrations/appliedAtValue.js +8 -0
- package/dist/migrations/applier.js +1085 -0
- package/dist/migrations/boot.js +196 -0
- package/dist/migrations/branchRehearsal.js +122 -0
- package/dist/migrations/columnEquivalence.js +85 -0
- package/dist/migrations/ddlError.js +63 -0
- package/dist/migrations/declaredSchema.js +162 -0
- package/dist/migrations/deployLedger.js +19 -0
- package/dist/migrations/fileBased.js +57 -0
- package/dist/migrations/fileContext.js +482 -0
- package/dist/migrations/fileDiscovery.js +318 -0
- package/dist/migrations/fileSkipProbes.js +117 -0
- package/dist/migrations/fingerprint.js +46 -0
- package/dist/migrations/fkCycles.js +13 -0
- package/dist/migrations/frameworkLiveTables.js +25 -0
- package/dist/migrations/idempotentDdl.js +37 -0
- package/dist/migrations/indexPredicate.js +50 -0
- package/dist/migrations/introspect.js +799 -0
- package/dist/migrations/ledgerRows.js +4 -0
- package/dist/migrations/lock.js +91 -0
- package/dist/migrations/migrationTableExists.js +9 -0
- package/dist/migrations/mssqlColumnDependencies.js +76 -0
- package/dist/migrations/mysqlEngine.js +11 -0
- package/dist/migrations/namespaceCharset.js +51 -0
- package/dist/migrations/planner.js +775 -0
- package/dist/migrations/postgresEnumCheck.js +19 -0
- package/dist/migrations/reactiveTriggerDrift.js +58 -0
- package/dist/migrations/reactiveTriggerName.js +7 -0
- package/dist/migrations/renameMssqlCheck.js +21 -0
- package/dist/migrations/restoreSnapshots.js +206 -0
- package/dist/migrations/resumeLedger.js +86 -0
- package/dist/migrations/rollingDeploy.js +106 -0
- package/dist/migrations/schemaOwner.js +46 -0
- package/dist/migrations/schemaOwnerTable.js +4 -0
- package/dist/migrations/softDropSnapshot.js +20 -0
- package/dist/migrations/sqlLimit.js +8 -0
- package/dist/migrations/sqliteConstraintIdentity.js +97 -0
- package/dist/migrations/sqliteDecimalBoot.js +22 -0
- package/dist/migrations/sqliteDecimalPublication.js +257 -0
- package/dist/migrations/sqliteDecimalReview.js +30 -0
- package/dist/migrations/sqliteDecimalReviewStore.js +188 -0
- package/dist/migrations/sqliteDecimalReviewWitness.js +38 -0
- package/dist/migrations/sqliteDecimalSource.js +69 -0
- package/dist/migrations/sqliteDecimalStage.js +135 -0
- package/dist/migrations/sqliteForeignKeys.js +38 -0
- package/dist/migrations/sqliteMigrationBatch.js +37 -0
- package/dist/migrations/sqliteRetainedSource.js +106 -0
- package/dist/migrations/sqliteRowIdentity.js +63 -0
- package/dist/migrations/sqliteSchemaEpoch.js +12 -0
- package/dist/migrations/sqliteSnapshotGuard.js +10 -0
- package/dist/migrations/sqliteTableContents.js +34 -0
- package/dist/migrations/sqliteTableCopy.js +25 -0
- package/dist/migrations/sqliteTableSchema.js +19 -0
- package/dist/migrations/sqliteWitnessProtection.js +8 -0
- package/dist/migrations/squash.js +81 -0
- package/dist/migrations/storeCharset.js +66 -0
- package/dist/migrations/transactionCause.js +10 -0
- package/dist/migrations/undeclaredCharset.js +40 -0
- package/dist/migrations/uniqueActiveLowering.js +39 -0
- package/dist/mixins.js +22 -0
- package/dist/mssqlDecimalDistinct.js +51 -0
- package/dist/mssqlJsonValueCheck.js +42 -0
- package/dist/mssqlTextStorage.js +9 -0
- package/dist/namespace.js +21 -0
- package/dist/{wire-B28cPjEp.js → optimisticVersion.js} +2 -2
- package/dist/pendingAttribution.js +79 -0
- package/dist/pluginRef.js +17 -0
- package/dist/predicate.js +266 -0
- package/dist/predicateCoercion.js +13 -0
- package/dist/projectedColumn.js +37 -0
- package/dist/queryBuilder.js +382 -0
- package/dist/rawSql.js +8 -0
- package/dist/relations.js +69 -0
- package/dist/relationsRegistry.js +38 -0
- package/dist/replaceInProgress.js +53 -0
- package/dist/requiredColumns.js +26 -0
- package/dist/residency.js +52 -0
- package/dist/retention.js +62 -0
- package/dist/rowDecoder.js +123 -0
- package/dist/rowKey.js +8 -0
- package/dist/rowSchema.js +31 -0
- package/dist/scopeKey.js +8 -0
- package/dist/seed.js +33 -0
- package/dist/snowflake.js +26 -0
- package/dist/sql.d.ts +58 -29
- package/dist/sql.js +41 -6661
- package/dist/sqlCompiler.js +343 -0
- package/dist/sqlError.js +8 -0
- package/dist/sqlPoolCapacity.js +12 -0
- package/dist/sqliteDecimal.js +22 -0
- package/dist/sqliteDecimalAggregateSql.js +61 -0
- package/dist/sqliteDecimalColumnSql.js +108 -0
- package/dist/sqliteDecimalConversion.js +15 -0
- package/dist/sqliteDecimalCte.js +154 -0
- package/dist/sqliteDecimalEncodeSql.js +32 -0
- package/dist/sqliteDecimalOutputs.js +74 -0
- package/dist/sqliteDecimalPredicate.js +66 -0
- package/dist/sqliteDecimalQuery.js +183 -0
- package/dist/sqliteDecimalQueryPlan.js +37 -0
- package/dist/sqliteDecimalResultSql.js +44 -0
- package/dist/sqliteDecimalRowQuery.js +63 -0
- package/dist/sqliteDecimalSetQuery.js +50 -0
- package/dist/sqliteDecimalSource.js +63 -0
- package/dist/sqliteDecimalStorage.js +29 -0
- package/dist/sqliteDecimalSubquery.js +19 -0
- package/dist/sqliteDecimalWindowQuery.js +196 -0
- package/dist/sqliteValueCoercion.js +4 -0
- package/dist/stampId.js +21 -0
- package/dist/storeErrors.js +9 -0
- package/dist/storeRefusal.js +20 -0
- package/dist/stream.js +36 -0
- package/dist/subjectGraph.js +175 -0
- package/dist/table.js +394 -0
- package/dist/tableRegistry.js +16 -0
- package/dist/tenantSelection.js +27 -0
- package/dist/transactionOutcome.js +97 -0
- package/dist/transientContention.js +36 -0
- package/dist/typedStore.js +16 -0
- package/dist/upsertUpdate.js +20 -0
- package/dist/vectorEmbedding.js +31 -0
- package/dist/view.js +39 -0
- package/dist/wire.d.ts +9 -10
- package/dist/wire.js +6 -2
- package/dist/writeAttribution.js +16 -0
- package/dist/writeRecorder.js +37 -0
- package/package.json +4 -6
- package/dist/replaceInProgress-DUHl5JEz.js +0 -3557
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Context as e, Metric as t } from "effect";
|
|
2
|
+
//#region src/dbMetrics.ts
|
|
3
|
+
var n = t.exponentialBoundaries({
|
|
4
|
+
start: 5e-4,
|
|
5
|
+
factor: 2,
|
|
6
|
+
count: 16
|
|
7
|
+
}), r = t.counter("voltro_db_queries_total", { description: "Database operations executed, by dialect and operation kind." }), i = t.histogram("voltro_db_query_duration_seconds", {
|
|
8
|
+
boundaries: n,
|
|
9
|
+
description: "Database operation duration in seconds, by dialect and operation kind."
|
|
10
|
+
}), a = t.counter("voltro_db_errors_total", { description: "Database operations that threw, by dialect and operation kind." }), o = t.gauge("voltro_db_operations_in_flight", { description: "Database operations currently executing, by dialect. An upper bound on connections the framework holds; NOT the driver pool's waiting count." }), s = t.counter("voltro_db_eager_fallback_total", { description: "Eager-load queries that degraded from the single-roundtrip JSON-agg path to the multi-query walker, by dialect and reason." }), c = e.empty(), l = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map(), d = /* @__PURE__ */ new Map(), f = (e, n) => {
|
|
11
|
+
let o = `${e}\u0000${n}`, s = l.get(o);
|
|
12
|
+
if (s !== void 0) return s;
|
|
13
|
+
let c = (r) => t.withAttributes(t.withAttributes(r, { dialect: e }), { op: n }), u = {
|
|
14
|
+
count: c(r),
|
|
15
|
+
duration: c(i),
|
|
16
|
+
errors: c(a)
|
|
17
|
+
};
|
|
18
|
+
return l.set(o, u), u;
|
|
19
|
+
}, p = () => {
|
|
20
|
+
l.clear(), u.clear(), d.clear();
|
|
21
|
+
}, m = () => l.size + u.size + d.size, h = /* @__PURE__ */ new Map(), g = (e, n) => {
|
|
22
|
+
let r = Math.max(0, (h.get(e) ?? 0) + n);
|
|
23
|
+
r === 0 ? h.delete(e) : h.set(e, r);
|
|
24
|
+
let i = u.get(e);
|
|
25
|
+
i === void 0 && (i = t.withAttributes(o, { dialect: e }), u.set(e, i)), i.updateUnsafe(r, c);
|
|
26
|
+
}, _ = (e) => h.get(e) ?? 0, v = (e) => {
|
|
27
|
+
let t = f(String(e.dialect), e.op);
|
|
28
|
+
t.count.updateUnsafe(1, c), t.duration.updateUnsafe(e.durationMs / 1e3, c), e.status === "error" && t.errors.updateUnsafe(1, c);
|
|
29
|
+
}, y = async (e, t, n) => {
|
|
30
|
+
let r = performance.now(), i = String(e);
|
|
31
|
+
g(i, 1);
|
|
32
|
+
let a = "ok";
|
|
33
|
+
try {
|
|
34
|
+
return await n();
|
|
35
|
+
} catch (e) {
|
|
36
|
+
throw a = "error", e;
|
|
37
|
+
} finally {
|
|
38
|
+
g(i, -1), v({
|
|
39
|
+
dialect: e,
|
|
40
|
+
op: t,
|
|
41
|
+
durationMs: performance.now() - r,
|
|
42
|
+
status: a
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}, b = 3e5, x = (e) => {
|
|
46
|
+
if (e == null || e === "") return;
|
|
47
|
+
let t = Number(e);
|
|
48
|
+
return Number.isFinite(t) && t >= 0 ? Math.floor(t) : void 0;
|
|
49
|
+
}, S = (e, t = process.env) => x(t.VOLTRO_DB_EAGER_FALLBACK_WARN_INTERVAL_MS) ?? x(e) ?? 3e5, C = (e, n = {}) => {
|
|
50
|
+
let r = S(n.warnIntervalMs), i = n.now ?? (() => Date.now()), a = /* @__PURE__ */ new Map();
|
|
51
|
+
return (n) => {
|
|
52
|
+
let o = `${n.dialect} ${n.reason}`, l = d.get(o);
|
|
53
|
+
l === void 0 && (l = t.withAttributes(t.withAttributes(s, { dialect: String(n.dialect) }), { reason: n.reason }), d.set(o, l)), l.updateUnsafe(1, c);
|
|
54
|
+
let u = `${n.table}\u0000${n.reason}`, f = a.get(u), p = f === void 0 || r > 0 && i() - f >= r, m = {
|
|
55
|
+
table: n.table,
|
|
56
|
+
dialect: String(n.dialect),
|
|
57
|
+
reason: n.reason,
|
|
58
|
+
metric: "voltro_db_eager_fallback_total",
|
|
59
|
+
...n.error === void 0 ? {} : { err: n.error }
|
|
60
|
+
};
|
|
61
|
+
p ? (a.set(u, i()), e.warn(n.reason === "execute-failed" ? "eager-load JSON-agg statement FAILED and was re-run on the multi-query walker — this query pays both paths on every call. Counted as voltro_db_eager_fallback_total{reason=\"execute-failed\"}." : "eager-load could not be compiled to a single JSON-agg roundtrip and is running on the multi-query walker — one round trip per relation level, on every call. Counted as voltro_db_eager_fallback_total{reason=\"not-compilable\"}.", m)) : e.debug("eager-load is still running on the walker (rate-limited; the counter is not)", m);
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
//#endregion
|
|
65
|
+
export { b as DEFAULT_EAGER_FALLBACK_WARN_INTERVAL_MS, m as dbMetricTagCacheSizeForTests, _ as dbOperationsInFlight, C as makeEagerFallbackReporter, y as observeDbOp, v as recordDbOp, p as resetDbMetricTagCacheForTests, S as resolveEagerFallbackWarnIntervalMs };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/decimalComparison.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (typeof e != "string" || !/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/.test(e)) return null;
|
|
4
|
+
let [t = "", n = ""] = e.replace(/^[+-]/, "").split("."), r = t.replace(/^0+/, "") || "0";
|
|
5
|
+
return {
|
|
6
|
+
negative: e.startsWith("-") && /[1-9]/.test(r + n),
|
|
7
|
+
whole: r,
|
|
8
|
+
fraction: n
|
|
9
|
+
};
|
|
10
|
+
}, t = (t, n) => {
|
|
11
|
+
let r = e(t), i = e(n);
|
|
12
|
+
if (!r || !i) return null;
|
|
13
|
+
if (r.negative !== i.negative) return r.negative ? -1 : 1;
|
|
14
|
+
let a = r.whole.length - i.whole.length;
|
|
15
|
+
if (a === 0 && (a = r.whole === i.whole ? 0 : r.whole > i.whole ? 1 : -1), a === 0) {
|
|
16
|
+
let e = Math.max(r.fraction.length, i.fraction.length), t = r.fraction.padEnd(e, "0"), n = i.fraction.padEnd(e, "0");
|
|
17
|
+
a = t === n ? 0 : t > n ? 1 : -1;
|
|
18
|
+
}
|
|
19
|
+
return a === 0 ? 0 : (a > 0 ? 1 : -1) * (r.negative ? -1 : 1);
|
|
20
|
+
}, n = (t) => {
|
|
21
|
+
let n = e(t);
|
|
22
|
+
if (n === null) return null;
|
|
23
|
+
let r = n.fraction.replace(/0+$/, "");
|
|
24
|
+
return `${n.negative ? "-" : ""}${n.whole}${r ? "." + r : ""}`;
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { t as compareDecimal, n as decimalEqualityKey };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createHash as e } from "node:crypto";
|
|
2
|
+
//#region src/derivedRowId.ts
|
|
3
|
+
var t = 64, n = "\0", r = 32, i = (t, ...i) => `${t}_${e("sha256").update(i.map(String).join(n)).digest("hex").slice(0, r)}`, a = (e) => e.length + 1 + r;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { t as ID_COLUMN_MAX_LENGTH, i as derivedRowId, a as derivedRowIdLength };
|
package/dist/dialect.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/dialect.ts
|
|
2
|
+
var e = (e) => e === "sqlite" || e === "turso", t = (e) => e === "mysql" || e === "mariadb", n = (e, t) => {
|
|
3
|
+
switch (t) {
|
|
4
|
+
case "mysql":
|
|
5
|
+
case "mariadb": return `\`${e.replace(/`/g, "``")}\``;
|
|
6
|
+
case "mssql": return `[${e.replace(/\]/g, "]]")}]`;
|
|
7
|
+
case "postgres":
|
|
8
|
+
case "sqlite":
|
|
9
|
+
case "turso": return `"${e.replace(/"/g, "\"\"")}"`;
|
|
10
|
+
}
|
|
11
|
+
}, r = 1e4;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { r as DEFAULT_ACQUIRE_TIMEOUT_MS, t as isMysqlFamily, e as isSqliteFamily, n as quoteIdent };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/enumRenames.ts
|
|
2
|
+
var e = /* @__PURE__ */ new Map(), t = (t, n) => {
|
|
3
|
+
if (n.from === n.to) throw Error(`declareEnumRename('${t}'): \`from\` and \`to\` are both '${n.from}' — a rename must change the value.`);
|
|
4
|
+
let r = e.get(t) ?? [];
|
|
5
|
+
for (let e of r) {
|
|
6
|
+
if (e.from === n.from && e.to === n.to) return;
|
|
7
|
+
if (e.from === n.from && e.to !== n.to) throw Error(`declareEnumRename('${t}'): value '${n.from}' is already declared as renamed to '${e.to}', cannot also rename it to '${n.to}'.`);
|
|
8
|
+
}
|
|
9
|
+
r.push(n), e.set(t, r);
|
|
10
|
+
}, n = (t) => e.get(t) ?? [], r = () => e, i = () => {
|
|
11
|
+
e.clear();
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { r as allEnumRenames, i as clearEnumRenames, t as declareEnumRename, n as getEnumRenames };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { timestamp as e } from "./columns.js";
|
|
2
|
+
import { defineMixin as t } from "./mixins.js";
|
|
3
|
+
//#region src/expiresMixin.ts
|
|
4
|
+
var n = "voltro/expires", r = () => t({
|
|
5
|
+
id: n,
|
|
6
|
+
fields: { expiresAt: e().nullable() },
|
|
7
|
+
behaviors: { defaultWhere: () => "expiresAt IS NULL OR expiresAt > now()" }
|
|
8
|
+
});
|
|
9
|
+
//#endregion
|
|
10
|
+
export { n as VOLTRO_EXPIRES_MIXIN_ID, r as expires };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
//#region src/fieldEncryption.ts
|
|
2
|
+
var e = "enc:v1:", t = "enc:v2:", n = (e, t, n) => {
|
|
3
|
+
let r = `${e}:${t}`, i = n == null || n === "" ? void 0 : String(n);
|
|
4
|
+
return i === void 0 ? { column: r } : {
|
|
5
|
+
column: r,
|
|
6
|
+
row: `${r}:${i}`
|
|
7
|
+
};
|
|
8
|
+
}, r = (e) => typeof e == "string" && e.startsWith("enc:v2:"), i = class extends Error {
|
|
9
|
+
_tag = "FieldDecryptionError";
|
|
10
|
+
table;
|
|
11
|
+
column;
|
|
12
|
+
reason;
|
|
13
|
+
constructor(e) {
|
|
14
|
+
super(`column "${e.table}.${e.column}" is .encrypted() but could not be decrypted (${e.reason}) — the stored value was most likely encrypted under a different key`), this.name = "FieldDecryptionError", this.table = e.table, this.column = e.column, this.reason = e.reason;
|
|
15
|
+
}
|
|
16
|
+
}, a = (e) => typeof e == "object" && !!e && e._tag === "FieldDecryptionError", o = (e) => typeof e == "string" && (e.startsWith("enc:v1:") || e.startsWith("enc:v2:")), s = (e, t, n) => e.encrypt(JSON.stringify(t), n), c = /* @__PURE__ */ new Set([
|
|
17
|
+
"text",
|
|
18
|
+
"id",
|
|
19
|
+
"reference",
|
|
20
|
+
"enum",
|
|
21
|
+
"uuid",
|
|
22
|
+
"email",
|
|
23
|
+
"url"
|
|
24
|
+
]), l = (e, t, n, r) => {
|
|
25
|
+
let i = e.decrypt(t, r), a;
|
|
26
|
+
try {
|
|
27
|
+
a = JSON.parse(i);
|
|
28
|
+
} catch {
|
|
29
|
+
return i;
|
|
30
|
+
}
|
|
31
|
+
return typeof a == "string" ? a : n === void 0 || c.has(n) ? i : a;
|
|
32
|
+
}, u = (e, t, n, r) => {
|
|
33
|
+
let i = e.decrypt(t, r);
|
|
34
|
+
try {
|
|
35
|
+
return typeof JSON.parse(i) == "string" ? !1 : n === void 0 || c.has(n) ? !0 : void 0;
|
|
36
|
+
} catch {
|
|
37
|
+
return !0;
|
|
38
|
+
}
|
|
39
|
+
}, d = (e, t) => e.fields[t]?.type, f = (e) => {
|
|
40
|
+
let t = [];
|
|
41
|
+
for (let [n, r] of Object.entries(e.fields)) r.encrypted === !0 && t.push(n);
|
|
42
|
+
return t;
|
|
43
|
+
}, p = "id", m = (e, t, n, r) => {
|
|
44
|
+
if (!t) return e;
|
|
45
|
+
let i = f(t);
|
|
46
|
+
return i.length === 0 ? e : g(e, i, t.tableName ?? "?", n, r);
|
|
47
|
+
}, h = (e, t, n) => {
|
|
48
|
+
if (t === void 0 || e.length === 0) return e;
|
|
49
|
+
let r = f(t);
|
|
50
|
+
if (r.length === 0) return e;
|
|
51
|
+
let i = t.tableName ?? "?";
|
|
52
|
+
return e.map((e) => g(e, r, i, n));
|
|
53
|
+
}, g = (e, t, r, i, a) => {
|
|
54
|
+
let c = a ?? e[p], l = { ...e };
|
|
55
|
+
for (let e of t) {
|
|
56
|
+
let t = l[e];
|
|
57
|
+
if (!(t == null || o(t))) {
|
|
58
|
+
if (!i) throw Error(`column "${r}.${e}" is .encrypted() but no field cipher is registered — set VOLTRO_FIELD_ENCRYPTION_KEY (\`voltro dev\` mints one; \`voltro serve\` refuses to boot without it); in a test, pass \`fieldEncryptionKey\` to makeTestContext`);
|
|
59
|
+
l[e] = s(i, t, n(r, e, c));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return l;
|
|
63
|
+
}, _ = (e, t, r, a) => {
|
|
64
|
+
if (!t) return e;
|
|
65
|
+
let s = f(t);
|
|
66
|
+
if (s.length === 0 || !r) return e;
|
|
67
|
+
let c = a?.onError ?? "throw", u = t.tableName ?? "?";
|
|
68
|
+
return e.map((e) => {
|
|
69
|
+
let f;
|
|
70
|
+
for (let m of s) {
|
|
71
|
+
let s = e[m];
|
|
72
|
+
if (o(s)) {
|
|
73
|
+
f ??= { ...e };
|
|
74
|
+
try {
|
|
75
|
+
f[m] = l(r, s, d(t, m), n(u, m, a?.rowId ?? e[p]));
|
|
76
|
+
} catch (e) {
|
|
77
|
+
let t = String(e?.message ?? e);
|
|
78
|
+
if (c === "null") {
|
|
79
|
+
f[m] = null, a?.warn?.({
|
|
80
|
+
table: u,
|
|
81
|
+
column: m,
|
|
82
|
+
reason: t
|
|
83
|
+
});
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
throw new i({
|
|
87
|
+
table: u,
|
|
88
|
+
column: m,
|
|
89
|
+
reason: t
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return f ?? e;
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
//#endregion
|
|
98
|
+
export { t as BOUND_ENCRYPTED_PREFIX, e as ENCRYPTED_PREFIX, i as FieldDecryptionError, l as decodeFieldValue, _ as decryptFieldsOnRead, s as encodeFieldValue, m as encryptFieldsForWrite, h as encryptFieldsForWriteBatch, f as encryptedColumnsOf, n as fieldBinding, r as isBoundCiphertext, o as isEncrypted, a as isFieldDecryptionError, u as isRawEncoding };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { id as e, integer as t, json as n, text as r, timestamp as i } from "./columns.js";
|
|
2
|
+
import { table as a } from "./table.js";
|
|
3
|
+
//#region src/frameworkTables.ts
|
|
4
|
+
var o = a("_voltro_migrations", {
|
|
5
|
+
id: e({ prefix: "mig" }),
|
|
6
|
+
name: r(),
|
|
7
|
+
hash: r(),
|
|
8
|
+
status: r(),
|
|
9
|
+
appliedAt: i().nullable(),
|
|
10
|
+
durationMs: t().nullable(),
|
|
11
|
+
errorMessage: r().nullable(),
|
|
12
|
+
errorStack: r().nullable(),
|
|
13
|
+
workflowRunId: r().nullable(),
|
|
14
|
+
createdAt: i().default("now"),
|
|
15
|
+
updatedAt: i().default("now").onUpdate("now")
|
|
16
|
+
}).index(["status"]), s = a("_voltro_seeds", {
|
|
17
|
+
id: e({ prefix: "seed" }),
|
|
18
|
+
name: r(),
|
|
19
|
+
lifecycle: r(),
|
|
20
|
+
fingerprint: r(),
|
|
21
|
+
cronSchedule: r().nullable(),
|
|
22
|
+
watchedTables: n().nullable(),
|
|
23
|
+
nextRunAt: i().nullable(),
|
|
24
|
+
lastRunStatus: r().nullable(),
|
|
25
|
+
lastRunAt: i().nullable(),
|
|
26
|
+
lastRunDurationMs: t().nullable(),
|
|
27
|
+
lastRunRowsTouched: t().nullable(),
|
|
28
|
+
lastError: r().nullable(),
|
|
29
|
+
workflowRunId: r().nullable(),
|
|
30
|
+
createdAt: i().default("now"),
|
|
31
|
+
updatedAt: i().default("now").onUpdate("now")
|
|
32
|
+
}).index(["lifecycle"]).index(["nextRunAt"]), c = a("_voltro_schema_owner", {
|
|
33
|
+
id: e({ prefix: "own" }),
|
|
34
|
+
appName: r(),
|
|
35
|
+
projectName: r().nullable(),
|
|
36
|
+
frameworkVersion: r().nullable(),
|
|
37
|
+
claimedAt: i().default("now")
|
|
38
|
+
}), l = a("_voltro_plugin_migrations", {
|
|
39
|
+
id: e({ prefix: "plm" }),
|
|
40
|
+
plugin_name: r(),
|
|
41
|
+
migration_id: r(),
|
|
42
|
+
description: r().nullable(),
|
|
43
|
+
applied_at: r()
|
|
44
|
+
}), u = a("_voltro_migration_plans", {
|
|
45
|
+
id: e({ prefix: "plan" }),
|
|
46
|
+
fingerprint: r(),
|
|
47
|
+
liveFingerprint: r().nullable(),
|
|
48
|
+
operations: n(),
|
|
49
|
+
rollbackPlan: n().nullable(),
|
|
50
|
+
appliedBy: r(),
|
|
51
|
+
environment: r(),
|
|
52
|
+
source: r(),
|
|
53
|
+
onlineStrategy: r().nullable(),
|
|
54
|
+
durationMs: t(),
|
|
55
|
+
notes: r().nullable(),
|
|
56
|
+
squashedAt: i().nullable(),
|
|
57
|
+
appliedAt: i().default("now"),
|
|
58
|
+
createdAt: i().default("now"),
|
|
59
|
+
updatedAt: i().default("now").onUpdate("now")
|
|
60
|
+
}).index(["fingerprint"]).index(["environment"]), d = a("_voltro_idempotency", {
|
|
61
|
+
id: e({ prefix: "idem" }),
|
|
62
|
+
scope: r(),
|
|
63
|
+
key: r(),
|
|
64
|
+
status: r(),
|
|
65
|
+
response: n().nullable(),
|
|
66
|
+
createdAt: i().default("now")
|
|
67
|
+
}).unique(["scope", "key"]).index(["createdAt"]), f = a("_voltro_devices", {
|
|
68
|
+
id: e({ prefix: "device" }),
|
|
69
|
+
tenantId: r(),
|
|
70
|
+
name: r(),
|
|
71
|
+
scopes: n().nullable(),
|
|
72
|
+
pairingHash: r().maxLength(64).nullable(),
|
|
73
|
+
pairingExpiresAt: i().nullable(),
|
|
74
|
+
accessHash: r().maxLength(64).nullable(),
|
|
75
|
+
accessExpiresAt: i().nullable(),
|
|
76
|
+
refreshHash: r().maxLength(64).nullable(),
|
|
77
|
+
refreshExpiresAt: i().nullable(),
|
|
78
|
+
previousRefreshHash: r().maxLength(64).nullable(),
|
|
79
|
+
generation: t().default(0),
|
|
80
|
+
pairedAt: i().nullable(),
|
|
81
|
+
lastSeenAt: i().nullable(),
|
|
82
|
+
revokedAt: i().nullable(),
|
|
83
|
+
revokedReason: r().nullable(),
|
|
84
|
+
createdBy: r().nullable(),
|
|
85
|
+
metadata: n().nullable(),
|
|
86
|
+
createdAt: i()
|
|
87
|
+
}).index(["tenantId"]).index(["pairingHash"]).index(["accessHash"]).index(["refreshHash"]).index(["previousRefreshHash"]), p = a("_voltro_tenant_selections", {
|
|
88
|
+
id: e({ prefix: "tsel" }),
|
|
89
|
+
subjectType: r().maxLength(32),
|
|
90
|
+
subjectId: r(),
|
|
91
|
+
tenantId: r(),
|
|
92
|
+
selectedAt: i()
|
|
93
|
+
}).primaryKey(["id"]).nonReactive(), m = a("_voltro_kv", {
|
|
94
|
+
id: e({ prefix: "kv" }),
|
|
95
|
+
key: r().unique(),
|
|
96
|
+
value: r().nullable(),
|
|
97
|
+
expiresAt: i().nullable(),
|
|
98
|
+
createdAt: i().default("now"),
|
|
99
|
+
updatedAt: i().default("now").onUpdate("now")
|
|
100
|
+
}).index(["expiresAt"]), h = a("_voltro_api_keys", {
|
|
101
|
+
id: e({ prefix: "apikey" }),
|
|
102
|
+
tenantId: r().nullable(),
|
|
103
|
+
name: r(),
|
|
104
|
+
hashedKey: r().maxLength(64).unique(),
|
|
105
|
+
keyPrefix: r(),
|
|
106
|
+
scopes: n().nullable(),
|
|
107
|
+
lastUsedAt: i().nullable(),
|
|
108
|
+
requestCount: t().default(0),
|
|
109
|
+
expiresAt: i().nullable(),
|
|
110
|
+
revokedAt: i().nullable(),
|
|
111
|
+
createdBy: r().nullable(),
|
|
112
|
+
onBehalfOf: r().nullable(),
|
|
113
|
+
metadata: n().nullable(),
|
|
114
|
+
createdAt: i().default("now")
|
|
115
|
+
}).index("byApiKeyTenant", ["tenantId"]), g = a("_voltro_replica_observations", {
|
|
116
|
+
id: e({ prefix: "robs" }),
|
|
117
|
+
replicaId: r().maxLength(191),
|
|
118
|
+
startedAt: i(),
|
|
119
|
+
version: r().maxLength(64).nullable(),
|
|
120
|
+
kind: r().maxLength(64),
|
|
121
|
+
payload: r().nullable(),
|
|
122
|
+
reachableAt: r().maxLength(255).nullable(),
|
|
123
|
+
writtenAt: i().default("now").onUpdate("now")
|
|
124
|
+
}).unique(["replicaId", "kind"]).index(["kind"]), _ = [
|
|
125
|
+
o,
|
|
126
|
+
s,
|
|
127
|
+
u
|
|
128
|
+
];
|
|
129
|
+
//#endregion
|
|
130
|
+
export { h as _voltroApiKeysTable, f as _voltroDevicesTable, d as _voltroIdempotencyTable, m as _voltroKvTable, u as _voltroMigrationPlansTable, o as _voltroMigrationsTable, l as _voltroPluginMigrationsTable, g as _voltroReplicaObservationsTable, c as _voltroSchemaOwnerTable, s as _voltroSeedsTable, p as _voltroTenantSelectionsTable, _ as frameworkTables };
|
package/dist/ginIndex.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/ginIndex.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
let t = e?.gin?.opclass;
|
|
4
|
+
if (t !== void 0) {
|
|
5
|
+
if (!/^[a-z_][a-z0-9_$]*(?:\.[a-z_][a-z0-9_$]*)?$/i.test(t)) throw Error("GIN opclass must be an unquoted, optionally schema-qualified identifier");
|
|
6
|
+
return t.toLowerCase().replace(/^public\./, "");
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { e as resolveGinOpclass };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { resolveFullTextIndex as e } from "./queryBuilder.js";
|
|
2
|
+
//#region src/hybridSearch.ts
|
|
3
|
+
var t = (t) => {
|
|
4
|
+
let n = t.alpha ?? .5;
|
|
5
|
+
if (n < 0 || n > 1) throw Error(`hybridSearch: alpha must be in [0, 1], got ${n}`);
|
|
6
|
+
return (r) => {
|
|
7
|
+
let i = Array.isArray(t.vector.query) ? {
|
|
8
|
+
column: t.vector.col,
|
|
9
|
+
queryVector: t.vector.query,
|
|
10
|
+
distance: t.vector.distance ?? "cosine",
|
|
11
|
+
alpha: n
|
|
12
|
+
} : {
|
|
13
|
+
column: t.vector.col,
|
|
14
|
+
queryText: t.vector.query,
|
|
15
|
+
distance: t.vector.distance ?? "cosine",
|
|
16
|
+
alpha: n
|
|
17
|
+
}, a = e(r.table, t.fts.indexName, r.fullTextIndexes);
|
|
18
|
+
return {
|
|
19
|
+
...r,
|
|
20
|
+
annClause: i,
|
|
21
|
+
fullTextSearch: {
|
|
22
|
+
indexName: t.fts.indexName,
|
|
23
|
+
query: t.fts.query,
|
|
24
|
+
columns: a.columns,
|
|
25
|
+
...a.config === void 0 ? {} : { config: a.config },
|
|
26
|
+
...a.weights === void 0 ? {} : { weights: a.weights }
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { t as hybridSearch };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { validateTypeIdPrefix as e } from "./identifierLimits.js";
|
|
2
|
+
import { generateSnowflake as t } from "./snowflake.js";
|
|
3
|
+
import { typeid as n } from "typeid-js";
|
|
4
|
+
import { ulid as r } from "ulid";
|
|
5
|
+
//#region src/idGenerator.ts
|
|
6
|
+
var i = (t) => {
|
|
7
|
+
let n = t.toLowerCase();
|
|
8
|
+
if (n.startsWith("_")) throw Error(`cannot derive a typeid prefix for table '${t}' (table names starting with '_' are not valid typeid prefixes). Pick an explicit prefix via id({ prefix: '...' }) or use a different scheme like id({ scheme: 'numeric' }) for internal tables.`);
|
|
9
|
+
if (!/^[a-z][a-z0-9_]*$/.test(n)) throw Error(`cannot derive a typeid prefix from table name '${t}' (must match [a-z][a-z0-9_]*). Pick an explicit prefix via id({ prefix: '...' }).`);
|
|
10
|
+
let r = n.endsWith("ies") && n.length > 3 ? n.slice(0, -3) + "y" : n.endsWith("ses") || n.endsWith("xes") || n.endsWith("zes") || n.endsWith("shes") || n.endsWith("ches") ? n.slice(0, -2) : n.endsWith("s") && n.length > 1 ? n.slice(0, -1) : n;
|
|
11
|
+
return e(r, {
|
|
12
|
+
kind: "derived",
|
|
13
|
+
tableName: t
|
|
14
|
+
}), r;
|
|
15
|
+
}, a = (t, n) => {
|
|
16
|
+
if (t === void 0) return {
|
|
17
|
+
kind: "typeid",
|
|
18
|
+
prefix: i(n)
|
|
19
|
+
};
|
|
20
|
+
if ("prefix" in t && !("scheme" in t)) return e(t.prefix, {
|
|
21
|
+
kind: "explicit",
|
|
22
|
+
tableName: n
|
|
23
|
+
}), {
|
|
24
|
+
kind: "typeid",
|
|
25
|
+
prefix: t.prefix
|
|
26
|
+
};
|
|
27
|
+
if (!("scheme" in t)) throw Error("invalid id() options: no scheme or prefix");
|
|
28
|
+
switch (t.scheme) {
|
|
29
|
+
case "typeid": {
|
|
30
|
+
let r = t.prefix ?? i(n);
|
|
31
|
+
return t.prefix !== void 0 && e(t.prefix, {
|
|
32
|
+
kind: "explicit",
|
|
33
|
+
tableName: n
|
|
34
|
+
}), {
|
|
35
|
+
kind: "typeid",
|
|
36
|
+
prefix: r
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
case "ulid": return { kind: "ulid" };
|
|
40
|
+
case "numeric": return { kind: "numeric" };
|
|
41
|
+
case "snowflake": return { kind: "snowflake" };
|
|
42
|
+
case "custom": return {
|
|
43
|
+
kind: "custom",
|
|
44
|
+
generate: t.generate
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}, o = (e, i) => {
|
|
48
|
+
switch (e.kind) {
|
|
49
|
+
case "typeid": return n(e.prefix).toString();
|
|
50
|
+
case "ulid": return r();
|
|
51
|
+
case "numeric": return null;
|
|
52
|
+
case "snowflake": return t();
|
|
53
|
+
case "custom": return e.generate(i);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
//#endregion
|
|
57
|
+
export { i as deriveTypeIdPrefix, o as generateId, a as resolveIdScheme };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//#region src/identifierLimits.ts
|
|
2
|
+
var e = 63, t = 60, n = /* @__PURE__ */ new Set(), r = (e) => {
|
|
3
|
+
n.add(e);
|
|
4
|
+
}, i = () => {
|
|
5
|
+
let e = [...n];
|
|
6
|
+
return n.clear(), e;
|
|
7
|
+
}, a = /^[a-zA-Z_][a-zA-Z0-9_]*$/, o = (e, t) => {
|
|
8
|
+
if (t.length === 0) throw Error(`${e} cannot be empty.`);
|
|
9
|
+
if (!a.test(t)) throw Error(`${e} '${t}' contains characters outside [A-Za-z0-9_] or starts with a digit. Dialect-portable identifiers must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`);
|
|
10
|
+
}, s = (e) => {
|
|
11
|
+
if (o("table name", e), e.length > 63) throw Error(`table name '${e}' is ${e.length} chars — exceeds the 63-byte cross-dialect limit (Postgres floor). Shorten the name; long table names also cascade into auto-named indexes and FK constraints that would themselves exceed the limit.`);
|
|
12
|
+
e.length > 60 && r(`table name '${e}' is ${e.length} chars — ${63 - e.length} from the Postgres 63-byte limit. Auto-named indexes on this table will run out of room fast.`);
|
|
13
|
+
}, c = (e, t) => {
|
|
14
|
+
if (o("column name", t), t.length > 63) throw Error(`column '${t}' on table '${e}' is ${t.length} chars — exceeds the 63-byte cross-dialect limit (Postgres floor). Rename it.`);
|
|
15
|
+
t.length > 60 && r(`column '${t}' on table '${e}' is ${t.length} chars — close to the 63-byte limit.`);
|
|
16
|
+
}, l = (e, t, n, i) => {
|
|
17
|
+
if (o("index name", t), t.length > 63) throw Error(n ? `auto-named index '${t}' on table '${e}' is ${t.length} chars — exceeds the 63-byte cross-dialect limit (Postgres floor). Supply an explicit short name: .index('<shortName>', ${JSON.stringify([...i])}).` : `index name '${t}' on table '${e}' is ${t.length} chars — exceeds the 63-byte cross-dialect limit (Postgres floor). Shorten it.`);
|
|
18
|
+
t.length > 60 && r(`index '${t}' on table '${e}' is ${t.length} chars — ${63 - t.length} from the 63-byte limit. ${n ? `Consider .index('<shortName>', ${JSON.stringify([...i])}) before it grows.` : ""}`);
|
|
19
|
+
}, u = (e, t) => {
|
|
20
|
+
if (e.length === 0) throw Error(`typeid prefix on table '${t.tableName}' cannot be empty.`);
|
|
21
|
+
if (!/^[a-z][a-z0-9_]*$/.test(e)) {
|
|
22
|
+
let n = t.kind === "derived" ? "the derived prefix doesn't match typeid's required shape — supply an explicit one via id({ prefix: '...' })." : "the prefix must match typeid's required shape /^[a-z][a-z0-9_]*$/.";
|
|
23
|
+
throw Error(`typeid prefix '${e}' on table '${t.tableName}' is invalid — ${n}`);
|
|
24
|
+
}
|
|
25
|
+
if (e.length > 63) {
|
|
26
|
+
let n = t.kind === "derived" ? "shorten the table name, or supply an explicit short prefix via id({ prefix: '...' })." : "pick a shorter prefix.";
|
|
27
|
+
throw Error(`typeid prefix '${e}' on table '${t.tableName}' is ${e.length} chars — exceeds the 63-byte limit; ${n}`);
|
|
28
|
+
}
|
|
29
|
+
e.length > 60 && r(`typeid prefix '${e}' on table '${t.tableName}' is ${e.length} chars — close to the 63-byte limit. Generated ids will be even longer (prefix + '_' + 26).`);
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { e as MAX_IDENTIFIER_LENGTH, t as WARN_IDENTIFIER_LENGTH, i as drainIdentifierWarnings, c as validateColumnName, l as validateIndexName, s as validateTableName, u as validateTypeIdPrefix };
|