@voltro/runtime 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 +118 -600
- package/dist/aggregate.js +42 -0
- package/dist/aggregateExtrema.js +80 -0
- package/dist/aggregateIvm.js +115 -0
- package/dist/analyticsMirror.js +228 -0
- package/dist/analyticsSink.js +38 -0
- package/dist/apiKeyUsage.js +33 -0
- package/dist/apiKeys.js +223 -0
- package/dist/apiKeysWiring.js +114 -0
- package/dist/approvalBuiltins.js +10 -0
- package/dist/approvals.js +269 -0
- package/dist/authMiddlewareLayer.js +47 -0
- package/dist/bindEvent.js +72 -0
- package/dist/bootListener.js +76 -0
- package/dist/bootRefusal.js +7 -0
- package/dist/bootStoreCodec.js +70 -0
- package/dist/businessRules.js +67 -0
- package/dist/changeClaimsTable.js +12 -0
- package/dist/circuitBreaker.js +72 -0
- package/dist/columnOnUpdate.js +23 -0
- package/dist/composeAnalytics.js +108 -0
- package/dist/computedQuery.js +4 -0
- package/dist/connectionBuiltins.js +81 -0
- package/dist/connectionCredentials.js +66 -0
- package/dist/connectionState.js +34 -0
- package/dist/connectionVault.js +410 -0
- package/dist/connectionsFacade.js +54 -0
- package/dist/coordinatedSchedule.js +139 -0
- package/dist/crdtHistory.js +138 -0
- package/dist/crdtMerge.js +179 -0
- package/dist/crdtVersionsTable.js +25 -0
- package/dist/credentialBound.js +12 -0
- package/dist/crud.js +72 -0
- package/dist/dataStore.js +679 -0
- package/dist/dataloader.js +61 -0
- package/dist/declaredTablesGuard.js +48 -0
- package/dist/defineExecutor.js +4 -0
- package/dist/dependencyGraph.js +32 -0
- package/dist/devices.js +228 -0
- package/dist/devicesWiring.js +168 -0
- package/dist/dialectReplicationAdapter.js +29 -0
- package/dist/dispatcher.js +447 -0
- package/dist/effectStore.js +71 -0
- package/dist/eventBus.js +260 -0
- package/dist/eventPublish.js +49 -0
- package/dist/events.js +193 -0
- package/dist/expectation.js +52 -0
- package/dist/expectationEvaluator.js +308 -0
- package/dist/experiment.js +96 -0
- package/dist/experimentEvaluator.js +245 -0
- package/dist/externalizedTasks.js +25 -0
- package/dist/fieldCipher.js +61 -0
- package/dist/fingerprint.js +21 -0
- package/dist/finops.js +42 -0
- package/dist/finopsAccountant.js +216 -0
- package/dist/handlerBody.js +8 -0
- package/dist/healthProbes.js +55 -0
- package/dist/httpClientSsrf.js +49 -0
- package/dist/httpClientTracing.js +11 -0
- package/dist/httpCompression.js +76 -0
- package/dist/httpKeepAlive.js +12 -0
- package/dist/httpRouteMounts.js +47 -0
- package/dist/idempotencyStore.js +70 -0
- package/dist/idleDetector.js +21 -0
- package/dist/index.d.ts +252 -233
- package/dist/index.js +144 -14405
- package/dist/insertRequiredColumns.js +19 -0
- package/dist/inspectWorkflow.js +1 -0
- package/dist/instanceMembership.js +98 -0
- package/dist/ivm.js +125 -0
- package/dist/kvDataStore.js +86 -0
- package/dist/kvFacade.js +32 -0
- package/dist/matcher.js +304 -0
- package/dist/memoryColumnDefaults.js +11 -0
- package/dist/memoryQueryJoins.js +114 -0
- package/dist/metrics.js +161 -0
- package/dist/observability.js +123 -0
- package/dist/observedGraph.js +52 -0
- package/dist/originGuard.js +116 -0
- package/dist/outbox.js +352 -0
- package/dist/pluginRefRules.js +65 -0
- package/dist/policyGuardResolver.js +55 -0
- package/dist/preview.js +62 -0
- package/dist/projectedRows.js +12 -0
- package/dist/provenance.js +63 -0
- package/dist/rangeIndex.js +89 -0
- package/dist/rawReadScope.js +17 -0
- package/dist/reaction.js +85 -0
- package/dist/reactiveConfig.js +11 -0
- package/dist/readClassification.js +57 -0
- package/dist/readRecorder.js +66 -0
- package/dist/rebac.js +104 -0
- package/dist/rebacInterceptor.js +81 -0
- package/dist/registry.js +29 -0
- package/dist/relevantFields.js +65 -0
- package/dist/replicaHealth.js +42 -0
- package/dist/replicaLocality.js +44 -0
- package/dist/replicaObservations.js +121 -0
- package/dist/replicaSelection.js +32 -0
- package/dist/replicatedDataStore.js +239 -0
- package/dist/requestLoader.js +7 -0
- package/dist/resumeCensus.js +28 -0
- package/dist/revalidation.js +22 -0
- package/dist/rowFilter.js +65 -0
- package/dist/rowStateBytes.js +45 -0
- package/dist/rpcBodyCap.js +63 -0
- package/dist/rpcConnections.js +83 -0
- package/dist/rpcDefectDiagnostics.js +15 -0
- package/dist/rpcServer.js +992 -0
- package/dist/runAsSystem.js +23 -0
- package/dist/rywPositionStore.js +84 -0
- package/dist/schedule.js +23 -0
- package/dist/scheduleBackfillRequests.js +151 -0
- package/dist/scheduleClaimsTable.js +11 -0
- package/dist/scheduleRunsTable.js +37 -0
- package/dist/scheduler.js +835 -0
- package/dist/schemaRegistry.js +65 -0
- package/dist/secretsResolver.js +35 -0
- package/dist/securityHeaders.js +33 -0
- package/dist/servePipeline.js +305 -0
- package/dist/serverOnlyAudit.js +66 -0
- package/dist/serverTracer.js +15 -0
- package/dist/serviceCredentials.js +40 -0
- package/dist/singleNodeOrchestrator.js +91 -0
- package/dist/sourceResolution.js +42 -0
- package/dist/storeMiddleware.js +880 -0
- package/dist/storeQuery.js +204 -0
- package/dist/storeRead.js +10 -0
- package/dist/subscriber.js +7 -0
- package/dist/subscriptionOutbox.js +139 -0
- package/dist/subscriptionRegistry.js +82 -0
- package/dist/subscriptionResume.js +132 -0
- package/dist/subscriptionSocketMetrics.js +65 -0
- package/dist/systemSubject.js +5 -0
- package/dist/tenantScope.js +23 -0
- package/dist/tenantSelection.js +27 -0
- package/dist/timeline.js +105 -0
- package/dist/traceContext.js +5 -0
- package/dist/traceSink.js +63 -0
- package/dist/traceSpansTable.js +29 -0
- package/dist/traceparent.js +34 -0
- package/dist/transactionSubject.js +12 -0
- package/dist/trustedProxy.js +155 -0
- package/dist/undo.js +129 -0
- package/dist/undoBuiltins.js +69 -0
- package/dist/undoCapture.js +74 -0
- package/dist/undoLogTable.js +16 -0
- package/dist/upsertBinding.js +20 -0
- package/dist/wakeOrchestrator.js +34 -0
- package/dist/wakeRegistry.js +71 -0
- package/dist/wakeRouter.js +63 -0
- package/dist/wakeSupervisor.js +62 -0
- package/dist/wakeupsTable.js +12 -0
- package/dist/webSocketGatewayRuntime.js +114 -0
- package/dist/webhookVerification.js +18 -0
- package/dist/wireColumnStrip.js +84 -0
- package/dist/workflowReadBuiltins.js +87 -0
- package/dist/workflowRuntime.js +708 -0
- package/package.json +10 -13
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TENANT_SELECTIONS_TABLE as e, deleteTenantSelection as t, readTenantSelection as n, tenantSelectionId as r, writeTenantSelection as i } from "@voltro/database";
|
|
2
|
+
import { isTenantSelectable as a, selectSubjectTenant as o } from "@voltro/protocol";
|
|
3
|
+
//#region src/tenantSelection.ts
|
|
4
|
+
var s = (e) => {
|
|
5
|
+
let r = () => {
|
|
6
|
+
let t = e();
|
|
7
|
+
if (t === void 0) throw Error("the data store is not built yet");
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return {
|
|
11
|
+
read: (e) => n(r(), e),
|
|
12
|
+
clear: (e) => t(r(), e)
|
|
13
|
+
};
|
|
14
|
+
}, c = async (e, t, n, r) => {
|
|
15
|
+
let s = o(t, n, r);
|
|
16
|
+
return a(s) && await i(e, {
|
|
17
|
+
type: s.type,
|
|
18
|
+
id: s.id
|
|
19
|
+
}, n), s;
|
|
20
|
+
}, l = async (e, n) => {
|
|
21
|
+
a(n) && await t(e, {
|
|
22
|
+
type: n.type,
|
|
23
|
+
id: n.id
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { e as TENANT_SELECTIONS_TABLE, l as clearTenantSelection, c as selectTenant, r as tenantSelectionId, s as tenantSelectionStore };
|
package/dist/timeline.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { randomUUID as e } from "node:crypto";
|
|
2
|
+
import { BoundedRing as t } from "@voltro/protocol";
|
|
3
|
+
//#region src/timeline.ts
|
|
4
|
+
var n = (e = process.env) => {
|
|
5
|
+
let t = (e.VOLTRO_TIMELINE ?? "").toLowerCase();
|
|
6
|
+
return t === "off" || t === "0" || t === "false" ? "off" : t === "all" ? "all" : t === "interesting" || t === "on" || t === "1" || t === "true" ? "interesting" : e.NODE_ENV === "production" ? "off" : "interesting";
|
|
7
|
+
}, r = /pass(word)?|secret|token|api[_-]?key|authorization|cookie|ssn|credit[_-]?card|card[_-]?number|cvv|encrypted/i, i = "«redacted»", a = (e) => {
|
|
8
|
+
if (e == null) return null;
|
|
9
|
+
let t = {};
|
|
10
|
+
for (let [n, a] of Object.entries(e)) t[n] = r.test(n) ? i : a;
|
|
11
|
+
return t;
|
|
12
|
+
}, o = (e) => {
|
|
13
|
+
let t = e?.id;
|
|
14
|
+
return typeof t == "string" || typeof t == "number" && Number.isFinite(t) ? t : void 0;
|
|
15
|
+
}, s = (e) => {
|
|
16
|
+
if (e.oversized !== void 0 || e.netChange === !0) throw Error("timeline event has an incomplete or reconstructed row image");
|
|
17
|
+
let t = o(e.op === "delete" ? e.old : e.new);
|
|
18
|
+
if (t === void 0 || e.op === "update" && (e.old == null || o(e.old) === void 0)) throw Error("timeline event lacks a required row image or identity");
|
|
19
|
+
return t;
|
|
20
|
+
}, c = (e, t) => {
|
|
21
|
+
let n = s(t);
|
|
22
|
+
return t.op === "insert" ? e.filter((e) => e.id !== n) : t.op === "update" ? e.map((e) => e.id === n ? t.old : e) : [...e, t.old];
|
|
23
|
+
}, l = (e, t) => {
|
|
24
|
+
if (t.length === 0) return e;
|
|
25
|
+
let n = [...e], r = /* @__PURE__ */ new Map(), i = (e, t) => {
|
|
26
|
+
let n = e.id, i = r.get(n);
|
|
27
|
+
i ? i.add(t) : r.set(n, /* @__PURE__ */ new Set([t]));
|
|
28
|
+
};
|
|
29
|
+
n.forEach((e, t) => {
|
|
30
|
+
e && i(e, t);
|
|
31
|
+
});
|
|
32
|
+
for (let e of t) {
|
|
33
|
+
let t = s(e);
|
|
34
|
+
if (e.op === "delete") {
|
|
35
|
+
i(e.old, n.length), n.push(e.old);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
let a = r.get(t);
|
|
39
|
+
if (a) {
|
|
40
|
+
r.delete(t);
|
|
41
|
+
for (let t of a) e.op === "insert" ? n[t] = void 0 : (n[t] = e.old, i(e.old, t));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
let a = 0;
|
|
45
|
+
for (let e of n) e !== void 0 && (n[a++] = e);
|
|
46
|
+
return n.length = a, n;
|
|
47
|
+
}, u = class {
|
|
48
|
+
mode;
|
|
49
|
+
capacity;
|
|
50
|
+
now;
|
|
51
|
+
historyId = e();
|
|
52
|
+
get recorderId() {
|
|
53
|
+
return this.historyId;
|
|
54
|
+
}
|
|
55
|
+
invalidate() {
|
|
56
|
+
this.historyId = e(), this.ring.clear(), this.seqCounter = 0;
|
|
57
|
+
}
|
|
58
|
+
ring;
|
|
59
|
+
seqCounter = 0;
|
|
60
|
+
constructor(e = "interesting", n = 5e3, r = () => Date.now()) {
|
|
61
|
+
this.mode = e, this.capacity = n, this.now = r, this.ring = new t(n);
|
|
62
|
+
}
|
|
63
|
+
get enabled() {
|
|
64
|
+
return this.mode !== "off";
|
|
65
|
+
}
|
|
66
|
+
record(e) {
|
|
67
|
+
if (this.mode === "off" || e.table === "_voltro_timeline" || this.mode === "interesting" && e.table.startsWith("_voltro")) return -1;
|
|
68
|
+
let t = ++this.seqCounter, n = e.tenantId ?? e.new?.tenantId ?? e.old?.tenantId ?? null;
|
|
69
|
+
return this.ring.push({
|
|
70
|
+
seq: t,
|
|
71
|
+
ts: this.now(),
|
|
72
|
+
table: e.table,
|
|
73
|
+
op: e.op,
|
|
74
|
+
old: a(e.old),
|
|
75
|
+
new: a(e.new),
|
|
76
|
+
tenantId: n,
|
|
77
|
+
...e.netChange === !0 ? { netChange: !0 } : {},
|
|
78
|
+
...e.oversized === void 0 ? {} : { oversized: e.oversized }
|
|
79
|
+
}), t;
|
|
80
|
+
}
|
|
81
|
+
currentSeq() {
|
|
82
|
+
return this.seqCounter;
|
|
83
|
+
}
|
|
84
|
+
snapshot(e = {}) {
|
|
85
|
+
let t = [...this.ring], n = 0;
|
|
86
|
+
for (let r of t) (e.table === void 0 || r.table === e.table) && (e.tenantId === void 0 || r.tenantId === e.tenantId) && (e.from === void 0 || r.seq >= e.from) && (e.to === void 0 || r.seq <= e.to) && (t[n++] = r);
|
|
87
|
+
return t.length = n, e.limit !== void 0 && t.length > e.limit && (t = t.slice(t.length - e.limit)), t;
|
|
88
|
+
}
|
|
89
|
+
replay(e, t, n) {
|
|
90
|
+
let r = [...this.ring], i = 0;
|
|
91
|
+
for (let n of r) n.table === e && n.seq > t && (r[i++] = n);
|
|
92
|
+
return r.length = i, r.sort((e, t) => t.seq - e.seq), l(n, r);
|
|
93
|
+
}
|
|
94
|
+
}, d, f = () => (d === void 0 && (d = new u(n())), d), p = (e) => {
|
|
95
|
+
d = e;
|
|
96
|
+
}, m = (e) => {
|
|
97
|
+
let t = f();
|
|
98
|
+
if (t.enabled) try {
|
|
99
|
+
t.record(e);
|
|
100
|
+
} catch {
|
|
101
|
+
t.invalidate();
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
//#endregion
|
|
105
|
+
export { u as TimelineRecorder, f as getTimelineRecorder, m as recordTimelineEvent, a as redactRow, n as resolveTimelineMode, c as reverseEventOverRows, p as setTimelineRecorderForTest };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { SpanKind as e, SpanStatusCode as t } from "@opentelemetry/api";
|
|
2
|
+
//#region src/traceSink.ts
|
|
3
|
+
var n = {
|
|
4
|
+
[e.INTERNAL]: "internal",
|
|
5
|
+
[e.SERVER]: "server",
|
|
6
|
+
[e.CLIENT]: "client",
|
|
7
|
+
[e.PRODUCER]: "producer",
|
|
8
|
+
[e.CONSUMER]: "consumer"
|
|
9
|
+
}, r = (e) => e[0] * 1e3 + e[1] / 1e6, i = 512, a = 48, o = (e) => {
|
|
10
|
+
let t = {}, n = 0;
|
|
11
|
+
for (let r in e) {
|
|
12
|
+
if (n >= a) break;
|
|
13
|
+
let o = e[r];
|
|
14
|
+
if (typeof o == "string") t[r] = o.length > i ? `${o.slice(0, i)}…` : o;
|
|
15
|
+
else if (typeof o == "number" || typeof o == "boolean" || o == null) t[r] = o;
|
|
16
|
+
else {
|
|
17
|
+
let e;
|
|
18
|
+
try {
|
|
19
|
+
e = JSON.stringify(o);
|
|
20
|
+
} catch {
|
|
21
|
+
e = String(o);
|
|
22
|
+
}
|
|
23
|
+
t[r] = e.length > i ? `${e.slice(0, i)}…` : e;
|
|
24
|
+
}
|
|
25
|
+
n++;
|
|
26
|
+
}
|
|
27
|
+
return t;
|
|
28
|
+
}, s = {
|
|
29
|
+
[t.UNSET]: "unset",
|
|
30
|
+
[t.OK]: "ok",
|
|
31
|
+
[t.ERROR]: "error"
|
|
32
|
+
}, c = (e) => {
|
|
33
|
+
let t = e.spanContext(), i = e.events.length > 0 ? e.events.slice(0, 16).map((e) => ({
|
|
34
|
+
name: e.name,
|
|
35
|
+
tsMs: r(e.time),
|
|
36
|
+
...e.attributes ? { attributes: o(e.attributes) } : {}
|
|
37
|
+
})) : void 0;
|
|
38
|
+
return {
|
|
39
|
+
traceId: t.traceId,
|
|
40
|
+
spanId: t.spanId,
|
|
41
|
+
parentSpanId: e.parentSpanContext?.spanId ?? null,
|
|
42
|
+
name: e.name,
|
|
43
|
+
kind: n[e.kind] ?? "internal",
|
|
44
|
+
attributes: o(e.attributes),
|
|
45
|
+
startMs: r(e.startTime),
|
|
46
|
+
endMs: r(e.endTime),
|
|
47
|
+
durationMs: r(e.duration),
|
|
48
|
+
status: s[e.status.code] ?? "unset",
|
|
49
|
+
...e.status.message ? { statusMessage: e.status.message } : {},
|
|
50
|
+
...i ? { events: i } : {}
|
|
51
|
+
};
|
|
52
|
+
}, l = (e) => ({
|
|
53
|
+
onStart: () => {},
|
|
54
|
+
onEnd: (t) => {
|
|
55
|
+
try {
|
|
56
|
+
e(c(t));
|
|
57
|
+
} catch {}
|
|
58
|
+
},
|
|
59
|
+
forceFlush: () => Promise.resolve(),
|
|
60
|
+
shutdown: () => Promise.resolve()
|
|
61
|
+
});
|
|
62
|
+
//#endregion
|
|
63
|
+
export { l as makeBufferingSpanProcessor };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { id as e, integer as t, json as n, table as r, text as i, timestamp as a } from "@voltro/database";
|
|
2
|
+
//#region src/traceSpansTable.ts
|
|
3
|
+
var o = r("_voltro_traces", {
|
|
4
|
+
id: e({ prefix: "span" }),
|
|
5
|
+
traceId: i(),
|
|
6
|
+
spanId: i(),
|
|
7
|
+
parentSpanId: i().nullable(),
|
|
8
|
+
name: i(),
|
|
9
|
+
kind: i().oneOf([
|
|
10
|
+
"internal",
|
|
11
|
+
"server",
|
|
12
|
+
"client",
|
|
13
|
+
"producer",
|
|
14
|
+
"consumer"
|
|
15
|
+
]).default("internal"),
|
|
16
|
+
status: i().oneOf([
|
|
17
|
+
"ok",
|
|
18
|
+
"error",
|
|
19
|
+
"unset"
|
|
20
|
+
]).default("unset"),
|
|
21
|
+
statusMessage: i().nullable(),
|
|
22
|
+
startedAt: a(),
|
|
23
|
+
endedAt: a(),
|
|
24
|
+
durationMs: t(),
|
|
25
|
+
attributes: n().nullable(),
|
|
26
|
+
events: n().nullable()
|
|
27
|
+
}).index(["traceId", "startedAt"]).index(["startedAt"]).index(["status"]);
|
|
28
|
+
//#endregion
|
|
29
|
+
export { o as _voltroTracesTable };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Tracer as e } from "effect";
|
|
2
|
+
//#region src/traceparent.ts
|
|
3
|
+
var t = /^00-([0-9a-f]{32})-([0-9a-f]{16})-([0-9a-f]{2})$/, n = (e) => `00-${e.traceId}-${e.spanId}-${e.sampled ? "01" : "00"}`, r = (e) => {
|
|
4
|
+
if (typeof e != "string") return null;
|
|
5
|
+
let n = t.exec(e.trim().toLowerCase());
|
|
6
|
+
if (n === null) return null;
|
|
7
|
+
let [, r, i, a] = n;
|
|
8
|
+
return r === "0".repeat(32) || i === "0".repeat(16) ? null : {
|
|
9
|
+
traceId: r,
|
|
10
|
+
spanId: i,
|
|
11
|
+
sampled: (parseInt(a, 16) & 1) == 1
|
|
12
|
+
};
|
|
13
|
+
}, i = (t) => {
|
|
14
|
+
let n = r(t);
|
|
15
|
+
if (n !== null) return e.externalSpan({
|
|
16
|
+
traceId: n.traceId,
|
|
17
|
+
spanId: n.spanId,
|
|
18
|
+
sampled: n.sampled
|
|
19
|
+
});
|
|
20
|
+
}, a = () => {
|
|
21
|
+
let e = globalThis.crypto, t = /* @__PURE__ */ new Uint8Array(16);
|
|
22
|
+
if (e?.getRandomValues !== void 0) e.getRandomValues(t);
|
|
23
|
+
else {
|
|
24
|
+
let e = `${Date.now().toString(16)}${Math.random().toString(16).slice(2)}`;
|
|
25
|
+
for (let n = 0; n < t.length; n += 1) {
|
|
26
|
+
let r = e.slice(n * 2 % e.length, n * 2 % e.length + 2);
|
|
27
|
+
t[n] = (parseInt(r, 16) || n + 1) ^ (Math.random() * 256 | 0);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
let n = Array.from(t, (e) => e.toString(16).padStart(2, "0")).join("");
|
|
31
|
+
return n === "0".repeat(32) ? `${"0".repeat(31)}1` : n;
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { i as externalSpanFromTraceparent, n as formatTraceparent, a as newTraceId, r as parseTraceparent };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { isMachineSubject as e, tenantScopedSubject as t } from "@voltro/protocol";
|
|
2
|
+
//#region src/transactionSubject.ts
|
|
3
|
+
var n = (n, r, i) => {
|
|
4
|
+
if (r === void 0) return n;
|
|
5
|
+
if (r.trim() === "") throw Error("transaction tenantId must be non-empty");
|
|
6
|
+
if (r === n.tenantId) return n;
|
|
7
|
+
if (i) throw Error("transaction cannot change tenant inside an active transaction");
|
|
8
|
+
if (!e(n)) throw Error("only a system context — the framework itself, or another app calling a `service:` procedure — can select another transaction tenant");
|
|
9
|
+
return t(n, r);
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { n as resolveTransactionSubject };
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { bootRefusal as e } from "./bootRefusal.js";
|
|
2
|
+
//#region src/trustedProxy.ts
|
|
3
|
+
var t = {
|
|
4
|
+
entries: [],
|
|
5
|
+
trustAll: !1
|
|
6
|
+
}, n = (e) => {
|
|
7
|
+
let t = e.trim();
|
|
8
|
+
if (t.length === 0) return;
|
|
9
|
+
if (t.startsWith("[")) {
|
|
10
|
+
let e = t.indexOf("]");
|
|
11
|
+
if (e < 0) return;
|
|
12
|
+
t = t.slice(1, e);
|
|
13
|
+
} else (t.match(/:/g) ?? []).length === 1 && t.includes(".") && (t = t.slice(0, t.indexOf(":")));
|
|
14
|
+
let n = t.indexOf("%");
|
|
15
|
+
return n >= 0 && (t = t.slice(0, n)), t = t.toLowerCase(), t.startsWith("::ffff:") && t.includes(".") && (t = t.slice(7)), t.length > 0 ? t : void 0;
|
|
16
|
+
}, r = (e) => {
|
|
17
|
+
let t = e.split(".");
|
|
18
|
+
if (t.length !== 4) return;
|
|
19
|
+
let n = /* @__PURE__ */ new Uint8Array(4);
|
|
20
|
+
for (let e = 0; e < 4; e++) {
|
|
21
|
+
let r = t[e];
|
|
22
|
+
if (!/^\d{1,3}$/.test(r)) return;
|
|
23
|
+
let i = Number(r);
|
|
24
|
+
if (i > 255) return;
|
|
25
|
+
n[e] = i;
|
|
26
|
+
}
|
|
27
|
+
return n;
|
|
28
|
+
}, i = (e) => {
|
|
29
|
+
if (!e.includes(":")) return;
|
|
30
|
+
let t = e.indexOf("::"), n, i;
|
|
31
|
+
if (t >= 0) {
|
|
32
|
+
if (e.indexOf("::", t + 1) >= 0) return;
|
|
33
|
+
n = e.slice(0, t).match(/[^:]+/g) ?? [], i = e.slice(t + 2).match(/[^:]+/g) ?? [];
|
|
34
|
+
} else n = e.split(":"), i = [];
|
|
35
|
+
let a = (e) => {
|
|
36
|
+
if (e.length === 0) return e;
|
|
37
|
+
let t = e[e.length - 1];
|
|
38
|
+
if (!t.includes(".")) return e;
|
|
39
|
+
let n = r(t);
|
|
40
|
+
if (!n) return;
|
|
41
|
+
let i = (n[0] << 8 | n[1]).toString(16), a = (n[2] << 8 | n[3]).toString(16);
|
|
42
|
+
return e[e.length - 1] = i, e.push(a), e;
|
|
43
|
+
}, o = a(n), s = a(i);
|
|
44
|
+
if (!o || !s) return;
|
|
45
|
+
let c = 8 - (o.length + s.length);
|
|
46
|
+
if (t < 0 ? c !== 0 : c < 0) return;
|
|
47
|
+
let l = [
|
|
48
|
+
...o,
|
|
49
|
+
...Array.from({ length: Math.max(0, c) }, () => "0"),
|
|
50
|
+
...s
|
|
51
|
+
];
|
|
52
|
+
if (l.length !== 8) return;
|
|
53
|
+
let u = /* @__PURE__ */ new Uint8Array(16);
|
|
54
|
+
for (let e = 0; e < 8; e++) {
|
|
55
|
+
let t = l[e];
|
|
56
|
+
if (!/^[0-9a-f]{1,4}$/.test(t)) return;
|
|
57
|
+
let n = Number.parseInt(t, 16);
|
|
58
|
+
u[e * 2] = n >> 8 & 255, u[e * 2 + 1] = n & 255;
|
|
59
|
+
}
|
|
60
|
+
return u;
|
|
61
|
+
}, a = (e) => e.includes(":") ? i(e) : r(e), o = (e, t, n) => {
|
|
62
|
+
if (e.length !== t.length || n < 0 || n > e.length * 8) return !1;
|
|
63
|
+
let r = n >> 3;
|
|
64
|
+
for (let n = 0; n < r; n++) if (e[n] !== t[n]) return !1;
|
|
65
|
+
let i = n & 7;
|
|
66
|
+
if (i === 0) return !0;
|
|
67
|
+
let a = 255 << 8 - i & 255;
|
|
68
|
+
return (e[r] & a) === (t[r] & a);
|
|
69
|
+
}, s = {
|
|
70
|
+
loopback: ["127.0.0.0/8", "::1/128"],
|
|
71
|
+
private: [
|
|
72
|
+
"10.0.0.0/8",
|
|
73
|
+
"172.16.0.0/12",
|
|
74
|
+
"192.168.0.0/16",
|
|
75
|
+
"100.64.0.0/10",
|
|
76
|
+
"169.254.0.0/16",
|
|
77
|
+
"fc00::/7",
|
|
78
|
+
"fe80::/10"
|
|
79
|
+
]
|
|
80
|
+
}, c = (e) => {
|
|
81
|
+
let t = e.trim().toLowerCase();
|
|
82
|
+
return t === "private" || t === "uniquelocal" ? s.private : t === "loopback" ? s.loopback : [e.trim()];
|
|
83
|
+
}, l = (e, t) => {
|
|
84
|
+
if (t.trustAll) return !0;
|
|
85
|
+
if (e === void 0) return !1;
|
|
86
|
+
let r = n(e);
|
|
87
|
+
if (r === void 0) return !1;
|
|
88
|
+
let i = a(r);
|
|
89
|
+
if (i === void 0) return !1;
|
|
90
|
+
for (let e of t.entries) for (let t of c(e)) {
|
|
91
|
+
let e = t.indexOf("/"), r = n(e >= 0 ? t.slice(0, e) : t);
|
|
92
|
+
if (r === void 0) continue;
|
|
93
|
+
let s = a(r);
|
|
94
|
+
if (s === void 0) continue;
|
|
95
|
+
let c = e >= 0 ? Number(t.slice(e + 1)) : s.length * 8;
|
|
96
|
+
if (Number.isInteger(c) && o(i, s, c)) return !0;
|
|
97
|
+
}
|
|
98
|
+
return !1;
|
|
99
|
+
}, u = (n, r = process.env, i) => {
|
|
100
|
+
let a = n !== void 0 && n.length > 0 ? n : (r.VOLTRO_TRUSTED_PROXIES ?? "").split(",").map((e) => e.trim()).filter((e) => e.length > 0), o = a.length === 0 ? t : a.length === 1 && a[0] === "*" ? {
|
|
101
|
+
entries: [],
|
|
102
|
+
trustAll: !0
|
|
103
|
+
} : a.length === 1 && /^\d+$/.test(a[0]) ? Number(a[0]) > 0 ? {
|
|
104
|
+
entries: [],
|
|
105
|
+
trustAll: !1,
|
|
106
|
+
hops: Number(a[0])
|
|
107
|
+
} : t : {
|
|
108
|
+
entries: a,
|
|
109
|
+
trustAll: !1
|
|
110
|
+
}, s = d(i, r);
|
|
111
|
+
if (s === void 0) return o;
|
|
112
|
+
if (o === t) throw e(`security.clientAddressHeader is '${s}', but no trusted proxy is declared, so the header would never be believed. Declare the proxy that sets it in security.trustedProxies (or VOLTRO_TRUSTED_PROXIES).`);
|
|
113
|
+
return {
|
|
114
|
+
...o,
|
|
115
|
+
clientAddressHeader: s
|
|
116
|
+
};
|
|
117
|
+
}, d = (t, n) => {
|
|
118
|
+
let r = (t ?? n.VOLTRO_CLIENT_ADDRESS_HEADER ?? "").trim().toLowerCase();
|
|
119
|
+
if (r !== "") {
|
|
120
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(r)) throw e(`security.clientAddressHeader '${r}' is not a valid HTTP header name.`);
|
|
121
|
+
if (r === "x-forwarded-for") throw e("security.clientAddressHeader is 'x-forwarded-for', which is always read as a chain. Remove the option; security.trustedProxies alone governs it.");
|
|
122
|
+
return r;
|
|
123
|
+
}
|
|
124
|
+
}, f = (e) => {
|
|
125
|
+
let { socketAddress: t, xForwardedFor: r, config: i } = e, a = t === void 0 ? void 0 : n(t) ?? t, o = p(e, a);
|
|
126
|
+
if (o !== void 0) return o;
|
|
127
|
+
if (r === void 0 || r.trim() === "") return a;
|
|
128
|
+
let s = r.split(",").map((e) => n(e) ?? e.trim()), c = 0;
|
|
129
|
+
for (let e of s) e.length > 0 && (s[c++] = e);
|
|
130
|
+
if (s.length = c, s.length === 0) return a;
|
|
131
|
+
if (i.trustAll) return s[0];
|
|
132
|
+
if (i.hops !== void 0) {
|
|
133
|
+
let e = s.length + (a === void 0 ? 0 : 1), t = Math.max(0, e - 1 - i.hops);
|
|
134
|
+
return t === s.length ? a : s[t];
|
|
135
|
+
}
|
|
136
|
+
if (!l(a, i)) return a;
|
|
137
|
+
for (let e = s.length - 1; e >= 0; e--) if (!l(s[e], i)) return s[e];
|
|
138
|
+
return s[0];
|
|
139
|
+
}, p = (e, t) => {
|
|
140
|
+
let { config: r, clientAddressHeader: i } = e;
|
|
141
|
+
if (r.clientAddressHeader === void 0 || i === void 0 || !(r.trustAll || r.hops !== void 0 || l(t, r)) || i.includes(",")) return;
|
|
142
|
+
let o = n(i);
|
|
143
|
+
return o !== void 0 && a(o) !== void 0 ? o : void 0;
|
|
144
|
+
}, m = (e) => f({
|
|
145
|
+
socketAddress: e.socketAddress,
|
|
146
|
+
xForwardedFor: e.headers["x-forwarded-for"],
|
|
147
|
+
clientAddressHeader: e.config.clientAddressHeader === void 0 ? void 0 : e.headers[e.config.clientAddressHeader],
|
|
148
|
+
config: e.config
|
|
149
|
+
}), h = (e) => {
|
|
150
|
+
if (e.socketEncrypted) return !0;
|
|
151
|
+
let t = e.xForwardedProto;
|
|
152
|
+
return t === void 0 || t.trim() === "" || !(e.config.trustAll || e.config.hops !== void 0 || l(e.socketAddress, e.config)) ? !1 : t.split(",")[0].trim().toLowerCase() === "https";
|
|
153
|
+
};
|
|
154
|
+
//#endregion
|
|
155
|
+
export { t as NO_TRUSTED_PROXIES, a as ipToBytes, l as isTrustedProxy, n as normalizeIp, f as resolveClientAddress, m as resolveRequestClientAddress, h as resolveRequestIsHttps, u as resolveTrustedProxies };
|
package/dist/undo.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
//#region src/undo.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (e.id !== void 0) return e.id;
|
|
4
|
+
let t = e.next?.id;
|
|
5
|
+
if (typeof t == "string") return t;
|
|
6
|
+
let n = e.prev?.id;
|
|
7
|
+
return typeof n == "string" ? n : void 0;
|
|
8
|
+
}, t = (t) => {
|
|
9
|
+
let n = e(t);
|
|
10
|
+
switch (t.op) {
|
|
11
|
+
case "insert": return n === void 0 ? null : {
|
|
12
|
+
table: t.table,
|
|
13
|
+
op: "delete",
|
|
14
|
+
id: n
|
|
15
|
+
};
|
|
16
|
+
case "update": return n !== void 0 && t.prev != null ? {
|
|
17
|
+
table: t.table,
|
|
18
|
+
op: "update",
|
|
19
|
+
id: n,
|
|
20
|
+
values: t.prev
|
|
21
|
+
} : null;
|
|
22
|
+
case "softDelete": return n === void 0 ? null : {
|
|
23
|
+
table: t.table,
|
|
24
|
+
op: "undelete",
|
|
25
|
+
id: n
|
|
26
|
+
};
|
|
27
|
+
case "delete": return t.prev == null ? null : {
|
|
28
|
+
table: t.table,
|
|
29
|
+
op: "insert",
|
|
30
|
+
row: t.prev
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}, n = (e) => {
|
|
34
|
+
if (e.crossesAction) throw new r(e.invocationId, "action");
|
|
35
|
+
let n = [];
|
|
36
|
+
for (let r = e.changes.length - 1; r >= 0; --r) {
|
|
37
|
+
let i = t(e.changes[r]);
|
|
38
|
+
i !== null && n.push(i);
|
|
39
|
+
}
|
|
40
|
+
return n;
|
|
41
|
+
}, r = class extends Error {
|
|
42
|
+
invocationId;
|
|
43
|
+
boundary;
|
|
44
|
+
_tag = "UndoBoundaryError";
|
|
45
|
+
constructor(e, t) {
|
|
46
|
+
super(t === "action" ? `cannot undo invocation ${e}: it crossed an action (external side effect)` : `cannot undo invocation ${e}: the row changed since (conflict)`), this.invocationId = e, this.boundary = t, this.name = "UndoBoundaryError";
|
|
47
|
+
}
|
|
48
|
+
}, i = (e, t, n = ["updatedAt", "updatedBy"]) => {
|
|
49
|
+
if (t == null) return e == null;
|
|
50
|
+
if (e == null) return !1;
|
|
51
|
+
let r = new Set(n);
|
|
52
|
+
for (let [n, i] of Object.entries(t)) if (!r.has(n) && !Object.is(e[n], i) && JSON.stringify(e[n]) !== JSON.stringify(i)) return !1;
|
|
53
|
+
return !0;
|
|
54
|
+
}, a = class {
|
|
55
|
+
capacity;
|
|
56
|
+
done = [];
|
|
57
|
+
undone = [];
|
|
58
|
+
constructor(e = 100) {
|
|
59
|
+
this.capacity = e;
|
|
60
|
+
}
|
|
61
|
+
push(e) {
|
|
62
|
+
this.done.push(e), this.done.length > this.capacity && this.done.shift(), this.undone = [];
|
|
63
|
+
}
|
|
64
|
+
get canUndo() {
|
|
65
|
+
return this.done.length > 0;
|
|
66
|
+
}
|
|
67
|
+
get canRedo() {
|
|
68
|
+
return this.undone.length > 0;
|
|
69
|
+
}
|
|
70
|
+
peekUndo() {
|
|
71
|
+
return this.done[this.done.length - 1];
|
|
72
|
+
}
|
|
73
|
+
peekRedo() {
|
|
74
|
+
return this.undone[this.undone.length - 1];
|
|
75
|
+
}
|
|
76
|
+
undo() {
|
|
77
|
+
let e = this.done.pop();
|
|
78
|
+
return e !== void 0 && this.undone.push(e), e;
|
|
79
|
+
}
|
|
80
|
+
redo() {
|
|
81
|
+
let e = this.undone.pop();
|
|
82
|
+
return e !== void 0 && this.done.push(e), e;
|
|
83
|
+
}
|
|
84
|
+
snapshot() {
|
|
85
|
+
return {
|
|
86
|
+
undo: [...this.done],
|
|
87
|
+
redo: [...this.undone]
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}, o = (e, t = /* @__PURE__ */ new Set()) => e.op === "insert" ? {
|
|
91
|
+
table: e.table,
|
|
92
|
+
op: "insert",
|
|
93
|
+
next: e.new ?? null
|
|
94
|
+
} : e.op === "update" ? {
|
|
95
|
+
table: e.table,
|
|
96
|
+
op: "update",
|
|
97
|
+
prev: e.old ?? null,
|
|
98
|
+
next: e.new ?? null
|
|
99
|
+
} : t.has(e.table) ? {
|
|
100
|
+
table: e.table,
|
|
101
|
+
op: "softDelete",
|
|
102
|
+
prev: e.old ?? null
|
|
103
|
+
} : {
|
|
104
|
+
table: e.table,
|
|
105
|
+
op: "delete",
|
|
106
|
+
prev: e.old ?? null
|
|
107
|
+
}, s = async (e, t) => {
|
|
108
|
+
switch (t.op) {
|
|
109
|
+
case "delete":
|
|
110
|
+
await e.delete(t.table, t.id);
|
|
111
|
+
return;
|
|
112
|
+
case "update":
|
|
113
|
+
await e.update(t.table, t.id, t.values);
|
|
114
|
+
return;
|
|
115
|
+
case "undelete":
|
|
116
|
+
await e.update(t.table, t.id, {
|
|
117
|
+
deletedAt: null,
|
|
118
|
+
deletedBy: null
|
|
119
|
+
});
|
|
120
|
+
return;
|
|
121
|
+
case "insert":
|
|
122
|
+
await e.insert(t.table, t.row);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}, c = async (e, t) => {
|
|
126
|
+
for (let n of t) await s(e, n);
|
|
127
|
+
};
|
|
128
|
+
//#endregion
|
|
129
|
+
export { r as UndoBoundaryError, a as UndoStack, s as applyInverse, c as applyInverses, o as forwardChangeFromCdc, t as invertChange, i as isSafeToApply, n as synthesizeInverse };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { applyInverses as e, isSafeToApply as t, synthesizeInverse as n } from "./undo.js";
|
|
2
|
+
import { eq as r } from "@voltro/database";
|
|
3
|
+
import { UndoConflict as i, UndoForbidden as a, UndoNotFound as o } from "@voltro/protocol";
|
|
4
|
+
//#region src/undoBuiltins.ts
|
|
5
|
+
var s = (e) => e.request?.subject?.id ?? null, c = (e) => e === !0 || e === 1, l = async (e, t, n) => (await e.query({
|
|
6
|
+
table: t,
|
|
7
|
+
predicate: r("id", n),
|
|
8
|
+
order: []
|
|
9
|
+
}))[0] ?? null, u = (e) => {
|
|
10
|
+
try {
|
|
11
|
+
let t = JSON.parse(String(e ?? "[]"));
|
|
12
|
+
return Array.isArray(t) ? t : [];
|
|
13
|
+
} catch {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
}, d = (e) => e.id ?? e.next?.id ?? e.prev?.id, f = async (e, t) => {
|
|
17
|
+
let n = s(t);
|
|
18
|
+
return [...await t.store.query({
|
|
19
|
+
table: "_voltro_undo_log",
|
|
20
|
+
predicate: r("subjectId", n),
|
|
21
|
+
order: []
|
|
22
|
+
})].sort((e, t) => String(t.id).localeCompare(String(e.id))).slice(0, e.limit ?? 50).map((e) => ({
|
|
23
|
+
id: String(e.id),
|
|
24
|
+
tag: String(e.tag ?? ""),
|
|
25
|
+
label: e.label ?? null,
|
|
26
|
+
undone: c(e.undone),
|
|
27
|
+
crossesAction: c(e.crossesAction),
|
|
28
|
+
createdAt: String(e.createdAt ?? "")
|
|
29
|
+
}));
|
|
30
|
+
}, p = async (e, t) => {
|
|
31
|
+
let n = await l(t.store, "_voltro_undo_log", e.invocationId);
|
|
32
|
+
if (!n) throw new o({ invocationId: e.invocationId });
|
|
33
|
+
if ((n.subjectId ?? null) !== s(t)) throw new a({ invocationId: e.invocationId });
|
|
34
|
+
return n;
|
|
35
|
+
}, m = async (r, a) => {
|
|
36
|
+
let o = await p(r, a);
|
|
37
|
+
if (c(o.undone)) return { ok: !0 };
|
|
38
|
+
if (c(o.crossesAction)) throw new i({
|
|
39
|
+
invocationId: r.invocationId,
|
|
40
|
+
reason: "action"
|
|
41
|
+
});
|
|
42
|
+
let f = u(o.changes);
|
|
43
|
+
for (let e of f) {
|
|
44
|
+
let n = d(e);
|
|
45
|
+
if (n === void 0) continue;
|
|
46
|
+
let o = await l(a.store, e.table, n);
|
|
47
|
+
if (!t(o, e.next ?? null)) throw new i({
|
|
48
|
+
invocationId: r.invocationId,
|
|
49
|
+
reason: "conflict"
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
let m = {
|
|
53
|
+
invocationId: r.invocationId,
|
|
54
|
+
subject: s(a),
|
|
55
|
+
changes: f,
|
|
56
|
+
crossesAction: !1
|
|
57
|
+
};
|
|
58
|
+
return await e(a.store, n(m)), await a.store.update("_voltro_undo_log", r.invocationId, { undone: !0 }), { ok: !0 };
|
|
59
|
+
}, h = async (e, t) => {
|
|
60
|
+
let n = await p(e, t);
|
|
61
|
+
if (!c(n.undone)) return { ok: !0 };
|
|
62
|
+
for (let e of u(n.changes)) {
|
|
63
|
+
let n = d(e);
|
|
64
|
+
e.op === "insert" && e.next ? await t.store.insert(e.table, e.next) : e.op === "update" && n !== void 0 && e.next ? await t.store.update(e.table, n, e.next) : e.op === "delete" && n !== void 0 && await t.store.delete(e.table, n);
|
|
65
|
+
}
|
|
66
|
+
return await t.store.update("_voltro_undo_log", e.invocationId, { undone: !1 }), { ok: !0 };
|
|
67
|
+
};
|
|
68
|
+
//#endregion
|
|
69
|
+
export { m as applyUndoInvocation, h as redoUndoInvocation, f as undoLogExecutor };
|