@voltro/protocol 0.85.0 → 0.87.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 +5987 -0
- package/README.md +14 -0
- package/THIRD-PARTY-NOTICES.md +1122 -31
- package/dist/apiRoleEndpoints.js +108 -0
- package/dist/apiRoleObservation.js +68 -0
- package/dist/apikey.d.ts +10 -0
- package/dist/approval.js +64 -0
- package/dist/approvalDescriptors.js +26 -0
- package/dist/auth.js +389 -0
- package/dist/boundedRing.js +27 -0
- package/dist/businessRule.js +11 -0
- package/dist/canonicalJson.js +14 -0
- package/dist/connection.js +73 -0
- package/dist/devActivity.js +4 -0
- package/dist/errorSchema.js +24 -0
- package/dist/errorValue.js +21 -0
- package/dist/event.js +110 -0
- package/dist/formCapture.js +12 -0
- package/dist/httpStreamMaxDuration.js +9 -0
- package/dist/idempotency.js +121 -0
- package/dist/idempotencyInput.js +123 -0
- package/dist/identity.js +5 -9
- package/dist/index.d.ts +1095 -139
- package/dist/index.js +54 -1700
- package/dist/inspect.d.ts +1 -1
- package/dist/inspect.js +14 -240
- package/dist/inspectBackfill.js +52 -0
- package/dist/inspectCommandRejection.js +21 -0
- package/dist/inspectProjection.js +133 -0
- package/dist/inspectStorageProjection.js +86 -0
- package/dist/inspectValueIdentity.js +4 -0
- package/dist/inspectWorkflowExecution.js +34 -0
- package/dist/inspectWorkflowQueuedStart.js +31 -0
- package/dist/jsonSchema.js +54 -0
- package/dist/jwt.d.ts +10 -0
- package/dist/jwt.js +1 -1
- package/dist/outbox.js +10 -0
- package/dist/pairing.js +75 -0
- package/dist/plugin.js +87 -0
- package/dist/pluginAccountMerge.js +88 -0
- package/dist/pluginNaming.js +32 -0
- package/dist/pluginPrivacy.js +166 -0
- package/dist/procedure.js +280 -0
- package/dist/publicApi.js +325 -0
- package/dist/queryOptionalSources.js +14 -0
- package/dist/reactivityChannel.js +34 -0
- package/dist/rest.d.ts +260 -64
- package/dist/rest.js +345 -499
- package/dist/restFormat.js +163 -0
- package/dist/restReceipt.js +43 -0
- package/dist/revalidate.js +13 -0
- package/dist/rowEquality.js +31 -0
- package/dist/rowPatch.js +182 -0
- package/dist/schemaShape.js +67 -0
- package/dist/scopes.js +273 -0
- package/dist/secretWindows.js +71 -0
- package/dist/serverErrorBus.js +15 -0
- package/dist/serviceCall.js +14 -0
- package/dist/session.d.ts +89 -6
- package/dist/session.js +62 -63
- package/dist/{sessionHeader-DriTZhmv.js → sessionHeader.js} +1 -1
- package/dist/ssrfPolicy.js +30 -0
- package/dist/storageAccess.js +14 -0
- package/dist/storeErrors.js +66 -0
- package/dist/storeScreenshots.js +90 -0
- package/dist/strictInput.js +27 -0
- package/dist/subscriptionEvent.js +37 -0
- package/dist/tenantSelection.js +40 -0
- package/dist/time.js +7 -0
- package/dist/undo.js +38 -0
- package/dist/validation.js +39 -0
- package/dist/webSocketGateway.js +16 -0
- package/dist/workflow.js +297 -0
- package/dist/workflowAccess.js +61 -0
- package/dist/workflowRestart.js +45 -0
- package/dist/workflowRetry.js +44 -0
- package/dist/workflowStartOutcome.js +30 -0
- package/package.json +5 -3
- package/dist/restFormat-BlgTLxm1.js +0 -298
- package/dist/scopes-ClywBij8.js +0 -548
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/boundedRing.ts
|
|
2
|
+
var e = class {
|
|
3
|
+
slots = [];
|
|
4
|
+
head = 0;
|
|
5
|
+
size = 0;
|
|
6
|
+
capacity;
|
|
7
|
+
constructor(e) {
|
|
8
|
+
this.capacity = Number.isNaN(e) ? Infinity : Math.max(0, Math.floor(e));
|
|
9
|
+
}
|
|
10
|
+
get length() {
|
|
11
|
+
return this.size;
|
|
12
|
+
}
|
|
13
|
+
get(e) {
|
|
14
|
+
if (!(!Number.isInteger(e) || e < 0 || e >= this.size)) return this.slots[(this.head + e) % this.capacity];
|
|
15
|
+
}
|
|
16
|
+
push(e) {
|
|
17
|
+
this.capacity !== 0 && (this.size < this.capacity ? (this.slots[(this.head + this.size) % this.capacity] = e, this.size++) : (this.slots[this.head] = e, this.head = (this.head + 1) % this.capacity));
|
|
18
|
+
}
|
|
19
|
+
clear() {
|
|
20
|
+
this.slots.length = 0, this.head = 0, this.size = 0;
|
|
21
|
+
}
|
|
22
|
+
*[Symbol.iterator]() {
|
|
23
|
+
for (let e = 0; e < this.size; e++) yield this.get(e);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { e as BoundedRing };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Schema as e } from "effect";
|
|
2
|
+
//#region src/businessRule.ts
|
|
3
|
+
var t = class extends e.TaggedError()("BusinessRuleViolation", {
|
|
4
|
+
rule: e.String,
|
|
5
|
+
params: e.optional(e.Record(e.String, e.Unknown)),
|
|
6
|
+
field: e.optional(e.String),
|
|
7
|
+
message: e.optional(e.String),
|
|
8
|
+
severity: e.Literals(["error", "warning"])
|
|
9
|
+
}) {};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { t as BusinessRuleViolation };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/canonicalJson.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
let t = (e) => {
|
|
4
|
+
if (Array.isArray(e)) return e.map(t);
|
|
5
|
+
if (typeof e == "object" && e) {
|
|
6
|
+
let n = e;
|
|
7
|
+
return Object.fromEntries(Object.keys(n).sort().map((e) => [e, t(n[e])]));
|
|
8
|
+
}
|
|
9
|
+
return e;
|
|
10
|
+
};
|
|
11
|
+
return JSON.stringify(t(e) ?? null);
|
|
12
|
+
};
|
|
13
|
+
//#endregion
|
|
14
|
+
export { e as canonicalJson };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { defineAction as e, defineMutation as t, defineQuery as n } from "./procedure.js";
|
|
2
|
+
import { Schema as r } from "effect";
|
|
3
|
+
//#region src/connection.ts
|
|
4
|
+
var i = "__voltro.connections.list", a = "__voltro.connections.start", o = "__voltro.connections.submitToken", s = "__voltro.connections.disconnect", c = r.Literals(["oauth2", "pat"]), l = r.Literals([
|
|
5
|
+
"disconnected",
|
|
6
|
+
"connected",
|
|
7
|
+
"expired",
|
|
8
|
+
"revoked",
|
|
9
|
+
"error"
|
|
10
|
+
]), u = r.Struct({
|
|
11
|
+
connectionId: r.String,
|
|
12
|
+
kind: c,
|
|
13
|
+
label: r.String,
|
|
14
|
+
status: l,
|
|
15
|
+
accountId: r.NullOr(r.String),
|
|
16
|
+
accountLabel: r.NullOr(r.String),
|
|
17
|
+
scopes: r.Array(r.String),
|
|
18
|
+
expiresAt: r.NullOr(r.String),
|
|
19
|
+
lastError: r.NullOr(r.String),
|
|
20
|
+
connectedAt: r.NullOr(r.String)
|
|
21
|
+
}), d = class extends r.TaggedError()("ConnectionNotDeclared", { connectionId: r.String }) {}, f = class extends r.TaggedError()("ConnectionSubjectRequired", { connectionId: r.String }) {}, p = class extends r.TaggedError()("ConnectionKindMismatch", {
|
|
22
|
+
connectionId: r.String,
|
|
23
|
+
expected: c,
|
|
24
|
+
actual: c
|
|
25
|
+
}) {}, m = class extends r.TaggedError()("ConnectionHandshakeFailed", {
|
|
26
|
+
connectionId: r.String,
|
|
27
|
+
reason: r.String,
|
|
28
|
+
transient: r.Boolean
|
|
29
|
+
}) {
|
|
30
|
+
get message() {
|
|
31
|
+
return this.reason;
|
|
32
|
+
}
|
|
33
|
+
}, h = r.Union([
|
|
34
|
+
d,
|
|
35
|
+
f,
|
|
36
|
+
p,
|
|
37
|
+
m
|
|
38
|
+
]), g = n({
|
|
39
|
+
name: i,
|
|
40
|
+
source: "_voltro_connections",
|
|
41
|
+
input: r.Struct({}),
|
|
42
|
+
output: r.Array(u),
|
|
43
|
+
openAccess: "self-scoped read: projects the declared connections for the calling subject only (its own connect/disconnect state)"
|
|
44
|
+
}), _ = e({
|
|
45
|
+
name: a,
|
|
46
|
+
input: r.Struct({
|
|
47
|
+
connectionId: r.String,
|
|
48
|
+
redirectTo: r.optional(r.String)
|
|
49
|
+
}),
|
|
50
|
+
output: r.Struct({
|
|
51
|
+
authorizeUrl: r.String,
|
|
52
|
+
state: r.String
|
|
53
|
+
}),
|
|
54
|
+
error: h,
|
|
55
|
+
openAccess: "self-service: begins an oauth handshake that stores a credential for the calling subject only; anonymous callers fail typed with ConnectionSubjectRequired"
|
|
56
|
+
}), v = t({
|
|
57
|
+
name: o,
|
|
58
|
+
input: r.Struct({
|
|
59
|
+
connectionId: r.String,
|
|
60
|
+
token: r.String
|
|
61
|
+
}),
|
|
62
|
+
output: r.Struct({ ok: r.Boolean }),
|
|
63
|
+
error: h,
|
|
64
|
+
openAccess: "self-service: stores a pasted token as the calling subject's own credential; anonymous callers fail typed with ConnectionSubjectRequired"
|
|
65
|
+
}), y = t({
|
|
66
|
+
name: s,
|
|
67
|
+
input: r.Struct({ connectionId: r.String }),
|
|
68
|
+
output: r.Struct({ ok: r.Boolean }),
|
|
69
|
+
error: h,
|
|
70
|
+
openAccess: "self-service: deletes only the calling subject's own credential row for this connection"
|
|
71
|
+
});
|
|
72
|
+
//#endregion
|
|
73
|
+
export { i as CONNECTIONS_LIST_TAG, s as CONNECTION_DISCONNECT_TAG, a as CONNECTION_START_TAG, o as CONNECTION_SUBMIT_TOKEN_TAG, m as ConnectionHandshakeFailed, c as ConnectionKind, p as ConnectionKindMismatch, d as ConnectionNotDeclared, u as ConnectionState, l as ConnectionStatus, f as ConnectionSubjectRequired, y as connectionDisconnectDescriptor, _ as connectionStartDescriptor, v as connectionSubmitTokenDescriptor, g as connectionsListQueryDescriptor };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Schema as e } from "effect";
|
|
2
|
+
import * as t from "effect/SchemaAST";
|
|
3
|
+
//#region src/errorSchema.ts
|
|
4
|
+
var n = (e) => {
|
|
5
|
+
let n = /* @__PURE__ */ new Set();
|
|
6
|
+
if (e === void 0) return n;
|
|
7
|
+
let r = (e) => {
|
|
8
|
+
if (t.isUnion(e)) for (let t of e.types) r(t);
|
|
9
|
+
else if (e.encoding !== void 0 && r(t.toEncoded(e)), t.isObjects(e)) {
|
|
10
|
+
let r = e.propertySignatures.find((e) => e.name === "_tag");
|
|
11
|
+
r !== void 0 && t.isLiteral(r.type) && typeof r.type.literal == "string" && n.add(r.type.literal);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
return r(e.ast), n;
|
|
15
|
+
}, r = (r, i) => {
|
|
16
|
+
if (r === void 0) return;
|
|
17
|
+
let a = t.isUnion(r.ast) ? r.ast.types : [r.ast];
|
|
18
|
+
for (let t of a) {
|
|
19
|
+
let r = e.make(t);
|
|
20
|
+
if (n(r).has(i)) return r;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { n as declaredErrorTags, r as errorMemberSchema };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/errorValue.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (typeof e != "object" || !e) return;
|
|
4
|
+
let t = e._tag;
|
|
5
|
+
return typeof t == "string" ? t : void 0;
|
|
6
|
+
}, t = (t) => {
|
|
7
|
+
if (typeof t == "string") return t;
|
|
8
|
+
if (typeof t == "object" && t) {
|
|
9
|
+
let n = t.message;
|
|
10
|
+
if (typeof n == "string" && n !== "") return n;
|
|
11
|
+
let r = e(t);
|
|
12
|
+
if (r !== void 0) return r;
|
|
13
|
+
}
|
|
14
|
+
return String(t);
|
|
15
|
+
}, n = (n) => {
|
|
16
|
+
if (n instanceof Error) return n;
|
|
17
|
+
let r = Error(t(n), { cause: n });
|
|
18
|
+
return r.name = e(n) ?? "NonErrorThrown", r;
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { t as errorMessage, e as errorTag, n as reportableError };
|
package/dist/event.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { RequestedTenantRefused as e } from "./tenantSelection.js";
|
|
2
|
+
import { Unauthenticated as t } from "./auth.js";
|
|
3
|
+
import { NoSuchResource as n, ScopeError as r, declaresResourceGuard as i, isOpenAccess as a, openAccessSpec as o } from "./scopes.js";
|
|
4
|
+
import { strictInput as s } from "./strictInput.js";
|
|
5
|
+
import { hasEnforcedGuard as c } from "./procedure.js";
|
|
6
|
+
import { Context as l, Schema as u } from "effect";
|
|
7
|
+
import { Rpc as d } from "effect/rpc";
|
|
8
|
+
//#region src/event.ts
|
|
9
|
+
var f = 7500, p = (e) => typeof e == "object" && !!e && e.kind === "event", m = (e) => {
|
|
10
|
+
if (e.clientPolicy !== void 0) {
|
|
11
|
+
if (!/^[A-Za-z][A-Za-z0-9_.:-]{0,255}$/.test(e.clientPolicy)) throw Error("defineEvent: invalid client policy ID");
|
|
12
|
+
if (e.openAccess !== void 0 || !c(e.guards)) throw Error("defineEvent: a client policy requires explicit enforced guards");
|
|
13
|
+
if (e.webhook !== void 0) throw Error("defineEvent: private client policies do not authorize webhook recipients");
|
|
14
|
+
}
|
|
15
|
+
if (e.name.length === 0) throw Error("defineEvent: `name` must not be empty");
|
|
16
|
+
if (/\s/.test(e.name)) throw Error(`defineEvent("${e.name}"): \`name\` must not contain whitespace.\n The name is used as a broker subject segment. NATS refuses a subject with
|
|
17
|
+
whitespace and delivers nothing — silently, and only on that broker, so an
|
|
18
|
+
app that works on Redis stops working when the transport changes.
|
|
19
|
+
Use a dot for namespacing: "orders.paid".`);
|
|
20
|
+
if (e.guards !== void 0 && e.guards.length === 0) throw Error(`defineEvent("${e.name}"): \`guards: []\` is empty, so it enforces nothing —\n but it reads at the call site as if the event were protected. Omit the field
|
|
21
|
+
for an unguarded event, or list the scopes that may subscribe.`);
|
|
22
|
+
if (e.openAccess !== void 0) {
|
|
23
|
+
if (e.openAccess.trim() === "") throw Error(`defineEvent("${e.name}"): \`openAccess\` needs a REASON, not an empty string. It is\n the sentence a reviewer reads to decide whether anyone should really be able to
|
|
24
|
+
subscribe without an authorization check — e.g. \`openAccess: 'public scoreboard,
|
|
25
|
+
no caller data'\`.`);
|
|
26
|
+
if (e.guards !== void 0 && e.guards.length > 0) throw Error(`defineEvent("${e.name}"): \`openAccess\` and \`guards\` are two different access\n decisions, so declaring both says the event is protected AND open. Keep the guards
|
|
27
|
+
if a subscriber must hold a scope; drop them if anyone may listen.`);
|
|
28
|
+
}
|
|
29
|
+
if (e.webhook?.rateLimit !== void 0 && e.webhook.rateLimit.perMinute < 1) throw Error(`defineEvent("${e.name}"): \`webhook.rateLimit.perMinute\` is ${e.webhook.rateLimit.perMinute}, which defers every delivery forever.\n There is no "unlimited" spelling here — omit \`rateLimit\` for no ceiling.`);
|
|
30
|
+
if (e.webhook?.version !== void 0 && e.webhook.version < 1) throw Error(`defineEvent("${e.name}"): \`webhook.version\` must be >= 1 (default 1).\n A subscriber pinned to 1 would read this event as BEHIND its own version,
|
|
31
|
+
which is the opposite of what a version bump is for.`);
|
|
32
|
+
if (e.delivery === "latest" && e.webhook !== void 0) throw Error(`defineEvent(${e.name}): \`delivery: 'latest'\` cannot be combined with \`webhook\`.\n \`latest\` means a superseded delivery did not matter — but a webhook delivery is a
|
|
33
|
+
durable side effect at a third party, and one already sent cannot be superseded.
|
|
34
|
+
A high-rate event with an HTTP audience is also 60 deliveries per second per target;
|
|
35
|
+
the rate limit DEFERS the excess as pending rows, so it grows a table instead of failing.
|
|
36
|
+
Split them: publish the high-rate event for clients, and publish a separate, coarser
|
|
37
|
+
event (a summary, a state change) for the outside world.`);
|
|
38
|
+
return {
|
|
39
|
+
kind: "event",
|
|
40
|
+
name: e.name,
|
|
41
|
+
key: e.key,
|
|
42
|
+
payload: e.payload,
|
|
43
|
+
guards: e.openAccess === void 0 ? e.guards : [o(e.openAccess.trim())],
|
|
44
|
+
openAccess: e.openAccess,
|
|
45
|
+
rewind: e.rewind,
|
|
46
|
+
webhook: e.webhook,
|
|
47
|
+
delivery: e.delivery,
|
|
48
|
+
...e.clientPolicy === void 0 ? {} : { clientPolicy: e.clientPolicy }
|
|
49
|
+
};
|
|
50
|
+
}, h = (e) => u.Struct({
|
|
51
|
+
_tag: u.Literal("event"),
|
|
52
|
+
origin: u.String,
|
|
53
|
+
n: u.Number,
|
|
54
|
+
emittedAt: u.Number,
|
|
55
|
+
payload: e
|
|
56
|
+
}), g = u.Struct({
|
|
57
|
+
_tag: u.Literal("gap"),
|
|
58
|
+
missed: u.Number,
|
|
59
|
+
reason: u.Literals(["buffer", "resume"])
|
|
60
|
+
}), _ = u.Struct({ _tag: u.Literal("attached") }), v = (e) => u.Union([
|
|
61
|
+
_,
|
|
62
|
+
h(e),
|
|
63
|
+
g
|
|
64
|
+
]), y = u.Struct({
|
|
65
|
+
origin: u.String,
|
|
66
|
+
n: u.Number
|
|
67
|
+
}), b = (e) => u.Struct({
|
|
68
|
+
key: e,
|
|
69
|
+
resume: u.optional(u.Array(y))
|
|
70
|
+
}), x = l.Service("@voltro/protocol/EventRpcWorkload"), S = (o, l) => {
|
|
71
|
+
let f = o.guards !== void 0 && o.guards.some((e) => !a(e)) ? u.Union([
|
|
72
|
+
r,
|
|
73
|
+
t,
|
|
74
|
+
e
|
|
75
|
+
]) : u.Union([t, e]), p = i(o.guards) ? u.Union([f, n]) : f, m = l && l.length > 0 ? u.Union([p, ...l]) : p;
|
|
76
|
+
return d.make(o.name, {
|
|
77
|
+
payload: s(b(o.key), o.name, c(o.guards)),
|
|
78
|
+
success: v(o.payload),
|
|
79
|
+
error: m,
|
|
80
|
+
stream: !0
|
|
81
|
+
}).annotate(x, !0);
|
|
82
|
+
}, C = class extends u.TaggedError()("EventPayloadInvalid", {
|
|
83
|
+
event: u.String,
|
|
84
|
+
message: u.String
|
|
85
|
+
}) {}, w = class extends u.TaggedError()("EventKeyInvalid", {
|
|
86
|
+
event: u.String,
|
|
87
|
+
message: u.String
|
|
88
|
+
}) {}, T = class extends u.TaggedError()("EventPayloadTooLarge", {
|
|
89
|
+
event: u.String,
|
|
90
|
+
bytes: u.Number,
|
|
91
|
+
limit: u.Number
|
|
92
|
+
}) {}, E = (e) => {
|
|
93
|
+
if (typeof e != "object" || !e) return JSON.stringify(e) ?? "null";
|
|
94
|
+
let t = Object.entries(e), n = 0;
|
|
95
|
+
for (let e of t) e[1] !== void 0 && (t[n++] = e);
|
|
96
|
+
return t.length = n, t.sort(([e], [t]) => e < t ? -1 : +(e > t)), JSON.stringify(t);
|
|
97
|
+
}, D = "\0", O = (e, t, n) => [
|
|
98
|
+
e ?? "~",
|
|
99
|
+
t,
|
|
100
|
+
E(n)
|
|
101
|
+
].join("\0"), k = (e) => {
|
|
102
|
+
let [t = "~", n = "", r = ""] = e.split("\0");
|
|
103
|
+
return {
|
|
104
|
+
tenantId: t === "~" ? null : t,
|
|
105
|
+
event: n,
|
|
106
|
+
key: r
|
|
107
|
+
};
|
|
108
|
+
}, A = (e) => e.split("\0").join(" · ");
|
|
109
|
+
//#endregion
|
|
110
|
+
export { D as EVENT_ROUTE_SEP, w as EventKeyInvalid, C as EventPayloadInvalid, T as EventPayloadTooLarge, x as EventRpcWorkload, f as MAX_EVENT_ENVELOPE_BYTES, m as defineEvent, E as encodeEventKey, _ as eventAttached, h as eventEnvelope, g as eventGap, y as eventResumePoint, O as eventRoute, v as eventStreamEvent, b as eventSubscribeInput, S as eventToRpc, A as formatEventRoute, p as isEventDescriptor, k as parseEventRoute };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
//#region src/formCapture.ts
|
|
2
|
+
var e = "__voltro_capture", t = "voltro:form-source", n = (e) => typeof e == "string" && e.length === 261 && /^1(?:\.[a-f0-9]{64}){4}$/.test(e) ? e : void 0, r = (e, t) => {
|
|
3
|
+
let r = n(e + "." + t);
|
|
4
|
+
if (r === void 0) throw Error("Native form source unavailable");
|
|
5
|
+
return r;
|
|
6
|
+
}, i = (e = globalThis.document) => {
|
|
7
|
+
if (e === void 0) return;
|
|
8
|
+
let r = e.querySelectorAll(`meta[name="${t}"]`);
|
|
9
|
+
return r.length === 1 ? n(r[0].getAttribute("content")) : void 0;
|
|
10
|
+
};
|
|
11
|
+
//#endregion
|
|
12
|
+
export { e as FORM_CAPTURE_FIELD, t as FORM_CAPTURE_META_NAME, r as encodeNativeFormCapture, n as formCaptureSource, i as readFormCaptureSource };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/httpStreamMaxDuration.ts
|
|
2
|
+
var e = (e) => {
|
|
3
|
+
if (e !== void 0) {
|
|
4
|
+
if (typeof e != "number" || !Number.isSafeInteger(e) || e < 1 || e > 2147483647) throw RangeError("SSE maxDurationMs must be an integer between 1 and 2147483647.");
|
|
5
|
+
return e;
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
9
|
+
export { e as validateHttpStreamMaxDuration };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Schema as e } from "effect";
|
|
2
|
+
//#region src/idempotency.ts
|
|
3
|
+
var t = (e, t, n) => `${e ?? "(global)"}|${t.toUpperCase()}|${n}`, n = (e, t, n, r) => r === void 0 ? `${e ?? "(global)"}|${t ?? "(anon)"}|WS|${n}` : `WS-connection:${JSON.stringify([
|
|
4
|
+
e ?? null,
|
|
5
|
+
t ?? null,
|
|
6
|
+
n,
|
|
7
|
+
r
|
|
8
|
+
])}`, r = class extends e.TaggedError()("MutationConnectionRequired", { traceId: e.String }) {
|
|
9
|
+
get message() {
|
|
10
|
+
return "this mutation requires a live native WebSocket connection";
|
|
11
|
+
}
|
|
12
|
+
}, i = async (e, t, n, r, i, o, s = a) => {
|
|
13
|
+
if (!/^[0-9a-f]{64}$/.test(r)) throw Error("Invalid idempotency input fingerprint");
|
|
14
|
+
let c = await e.claim(t, n, r, o, i, s);
|
|
15
|
+
if (c.kind === "claimed") {
|
|
16
|
+
let e = c.claim;
|
|
17
|
+
if (typeof e.id != "string" || e.id.length === 0 || e.scope !== t || e.key !== n || e.inputHash !== r) throw Error("Idempotency store returned an invalid claim identity");
|
|
18
|
+
return {
|
|
19
|
+
kind: "fresh",
|
|
20
|
+
claim: Object.freeze({
|
|
21
|
+
scope: t,
|
|
22
|
+
key: n,
|
|
23
|
+
id: e.id,
|
|
24
|
+
inputHash: r
|
|
25
|
+
})
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (c.kind === "existing") {
|
|
29
|
+
if (c.record.scope !== t || c.record.key !== n) throw Error("Idempotency store returned an invalid receipt identity");
|
|
30
|
+
return typeof c.record.inputHash == "string" ? c.record.inputHash === r ? c.record.status === "completed" && c.record.response ? {
|
|
31
|
+
kind: "replay",
|
|
32
|
+
response: c.record.response
|
|
33
|
+
} : { kind: "conflict" } : { kind: "input-conflict" } : { kind: "input-unbound" };
|
|
34
|
+
}
|
|
35
|
+
if (c.kind === "conflict") return { kind: "conflict" };
|
|
36
|
+
throw Error("Idempotency store returned an invalid acquisition result");
|
|
37
|
+
}, a = 3e4, o = (e, t, n = a, r = Date.now) => {
|
|
38
|
+
let i = Object.freeze({
|
|
39
|
+
scope: t.scope,
|
|
40
|
+
key: t.key,
|
|
41
|
+
id: t.id,
|
|
42
|
+
inputHash: t.inputHash
|
|
43
|
+
}), o = !1, s = setInterval(() => {
|
|
44
|
+
o || (o = !0, e.renew(i, r()).then((e) => {
|
|
45
|
+
e || clearInterval(s);
|
|
46
|
+
}, () => {}).finally(() => {
|
|
47
|
+
o = !1;
|
|
48
|
+
}));
|
|
49
|
+
}, Math.max(1, Math.floor(n / 3)));
|
|
50
|
+
return s.unref?.(), () => clearInterval(s);
|
|
51
|
+
}, s = (e, t, n, r) => e.complete(t, n, r), c = (e, t) => e.release(t), l = 0n, u = () => {
|
|
52
|
+
let e = /* @__PURE__ */ new Map(), t = (e, t) => JSON.stringify([e, t]), n = (n) => {
|
|
53
|
+
let r = e.get(t(n.scope, n.key));
|
|
54
|
+
return r?.status === "in_flight" && r.id === n.id && r.inputHash === n.inputHash ? r : void 0;
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
get: async (n, r) => e.get(t(n, r)) ?? null,
|
|
58
|
+
claim: async (n, r, i, a, o, s) => {
|
|
59
|
+
let c = e.get(t(n, r));
|
|
60
|
+
if (c && c.inputHash !== i || c && a - c.createdAt < d(c.status, o, s)) return {
|
|
61
|
+
kind: "existing",
|
|
62
|
+
record: c
|
|
63
|
+
};
|
|
64
|
+
let u = `memory:${(++l).toString(36)}`;
|
|
65
|
+
return e.set(t(n, r), {
|
|
66
|
+
id: u,
|
|
67
|
+
scope: n,
|
|
68
|
+
key: r,
|
|
69
|
+
inputHash: i,
|
|
70
|
+
status: "in_flight",
|
|
71
|
+
response: null,
|
|
72
|
+
createdAt: a
|
|
73
|
+
}), {
|
|
74
|
+
kind: "claimed",
|
|
75
|
+
claim: Object.freeze({
|
|
76
|
+
id: u,
|
|
77
|
+
scope: n,
|
|
78
|
+
key: r,
|
|
79
|
+
inputHash: i
|
|
80
|
+
})
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
complete: async (r, i, a) => {
|
|
84
|
+
let o = n(r);
|
|
85
|
+
return o ? (e.set(t(r.scope, r.key), {
|
|
86
|
+
...o,
|
|
87
|
+
status: "completed",
|
|
88
|
+
response: i,
|
|
89
|
+
createdAt: a
|
|
90
|
+
}), !0) : !1;
|
|
91
|
+
},
|
|
92
|
+
release: async (r) => n(r) ? e.delete(t(r.scope, r.key)) : !1,
|
|
93
|
+
renew: async (r, i) => {
|
|
94
|
+
let a = n(r);
|
|
95
|
+
return a ? (e.set(t(r.scope, r.key), {
|
|
96
|
+
...a,
|
|
97
|
+
createdAt: i
|
|
98
|
+
}), !0) : !1;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
}, d = (e, t, n) => e === "completed" ? t : Math.min(t, n), f = class extends e.TaggedError()("MutationInFlight", {
|
|
102
|
+
traceId: e.String,
|
|
103
|
+
retryAfterMs: e.Number
|
|
104
|
+
}) {
|
|
105
|
+
get message() {
|
|
106
|
+
return `a request with this idempotency key is still in flight — replay the same key after ${this.retryAfterMs}ms`;
|
|
107
|
+
}
|
|
108
|
+
}, p = 1e3, m = class extends e.TaggedError()("MutationIdempotencyRefused", {
|
|
109
|
+
traceId: e.String,
|
|
110
|
+
reason: e.Literals([
|
|
111
|
+
"input-conflict",
|
|
112
|
+
"input-unbound",
|
|
113
|
+
"input-unavailable"
|
|
114
|
+
])
|
|
115
|
+
}) {
|
|
116
|
+
get message() {
|
|
117
|
+
return this.reason === "input-unavailable" ? "This request input could not be captured safely. This attempt was stopped before execution." : "This request cannot be safely matched to the original operation. Check its current state before starting another action.";
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
//#endregion
|
|
121
|
+
export { a as DEFAULT_IN_FLIGHT_LEASE_MS, p as MUTATION_IN_FLIGHT_RETRY_AFTER_MS, r as MutationConnectionRequired, m as MutationIdempotencyRefused, f as MutationInFlight, i as beginIdempotent, c as failIdempotent, s as finishIdempotent, d as freshFor, o as holdIdempotentClaim, t as idempotencyScope, u as memoryIdempotencyStore, n as wsMutationIdempotencyScope };
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { canonicalJson as e } from "./canonicalJson.js";
|
|
2
|
+
import { Schema as t } from "effect";
|
|
3
|
+
//#region src/idempotencyInput.ts
|
|
4
|
+
var n = (t) => {
|
|
5
|
+
let n = /* @__PURE__ */ new WeakMap(), r = 0, i = (e, t = () => !1) => {
|
|
6
|
+
if (Object.getOwnPropertySymbols(e).length) throw Error("Unsupported wire fields");
|
|
7
|
+
return Object.getOwnPropertyNames(e).sort().filter((e) => !t(e)).map((t) => {
|
|
8
|
+
let n = Object.getOwnPropertyDescriptor(e, t);
|
|
9
|
+
if (!("value" in n)) throw Error("Unsupported wire accessor");
|
|
10
|
+
return [t, o(n.value)];
|
|
11
|
+
});
|
|
12
|
+
}, a = (e, t = 0, n = e.byteLength) => {
|
|
13
|
+
let r = "";
|
|
14
|
+
for (let i of new Uint8Array(e, t, n)) r += i.toString(16).padStart(2, "0");
|
|
15
|
+
return r;
|
|
16
|
+
}, o = (e) => {
|
|
17
|
+
if (e === null) return ["null"];
|
|
18
|
+
if (e === void 0) return ["undefined"];
|
|
19
|
+
if (typeof e == "string" || typeof e == "boolean") return [typeof e, e];
|
|
20
|
+
if (typeof e == "number") return ["number", Object.is(e, -0) ? "-0" : String(e)];
|
|
21
|
+
if (typeof e == "bigint") return ["bigint", String(e)];
|
|
22
|
+
if (typeof e != "object") throw Error("Unsupported wire value");
|
|
23
|
+
let t = n.get(e);
|
|
24
|
+
if (t !== void 0) return ["reference", t];
|
|
25
|
+
let s = r++;
|
|
26
|
+
if (n.set(e, s), Array.isArray(e)) {
|
|
27
|
+
if (Object.getPrototypeOf(e) !== Array.prototype) throw Error("Unsupported wire array prototype");
|
|
28
|
+
return [
|
|
29
|
+
"array",
|
|
30
|
+
s,
|
|
31
|
+
e.length,
|
|
32
|
+
i(e, (e) => e === "length")
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
if (Object.getPrototypeOf(e) === Date.prototype) return [
|
|
36
|
+
"date",
|
|
37
|
+
s,
|
|
38
|
+
String(Date.prototype.getTime.call(e)),
|
|
39
|
+
i(e)
|
|
40
|
+
];
|
|
41
|
+
if (Object.getPrototypeOf(e) === Map.prototype) return [
|
|
42
|
+
"map",
|
|
43
|
+
s,
|
|
44
|
+
Array.from(Map.prototype.entries.call(e), ([e, t]) => [o(e), o(t)]),
|
|
45
|
+
i(e)
|
|
46
|
+
];
|
|
47
|
+
if (Object.getPrototypeOf(e) === Set.prototype) return [
|
|
48
|
+
"set",
|
|
49
|
+
s,
|
|
50
|
+
Array.from(Set.prototype.values.call(e), o),
|
|
51
|
+
i(e)
|
|
52
|
+
];
|
|
53
|
+
if (Object.getPrototypeOf(e) === ArrayBuffer.prototype) return [
|
|
54
|
+
"buffer",
|
|
55
|
+
s,
|
|
56
|
+
a(e),
|
|
57
|
+
i(e)
|
|
58
|
+
];
|
|
59
|
+
if (ArrayBuffer.isView(e)) {
|
|
60
|
+
if (!(e.buffer instanceof ArrayBuffer)) throw Error("Shared wire memory is not a snapshot");
|
|
61
|
+
let t = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(e), "constructor")?.value;
|
|
62
|
+
if (typeof t != "function" || ![
|
|
63
|
+
"DataView",
|
|
64
|
+
"Int8Array",
|
|
65
|
+
"Uint8Array",
|
|
66
|
+
"Uint8ClampedArray",
|
|
67
|
+
"Int16Array",
|
|
68
|
+
"Uint16Array",
|
|
69
|
+
"Int32Array",
|
|
70
|
+
"Uint32Array",
|
|
71
|
+
"Float16Array",
|
|
72
|
+
"Float32Array",
|
|
73
|
+
"Float64Array",
|
|
74
|
+
"BigInt64Array",
|
|
75
|
+
"BigUint64Array"
|
|
76
|
+
].includes(t.name) || globalThis[t.name] !== t) throw Error("Unsupported wire view prototype");
|
|
77
|
+
return [
|
|
78
|
+
"view",
|
|
79
|
+
s,
|
|
80
|
+
t.name,
|
|
81
|
+
o(e.buffer),
|
|
82
|
+
e.byteOffset,
|
|
83
|
+
e.byteLength,
|
|
84
|
+
i(e, (t) => !(e instanceof DataView) && /^(0|[1-9]\d*)$/.test(t))
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
let c = Object.getPrototypeOf(e);
|
|
88
|
+
if (c !== null && c !== Object.prototype) throw Error("Unsupported wire object");
|
|
89
|
+
return [
|
|
90
|
+
"object",
|
|
91
|
+
s,
|
|
92
|
+
i(e)
|
|
93
|
+
];
|
|
94
|
+
};
|
|
95
|
+
return e(o(t));
|
|
96
|
+
}, r = async (r, i, a, o = void 0) => {
|
|
97
|
+
try {
|
|
98
|
+
let s = t.encodeUnknownSync(r), c = t.decodeUnknownSync(r), l = s(i), u = n(l), d = c(structuredClone(l));
|
|
99
|
+
if (n(s(d)) !== u) throw Error("Input does not round trip");
|
|
100
|
+
let f = e({
|
|
101
|
+
protocol: "voltro-idempotency-input-v1",
|
|
102
|
+
principal: {
|
|
103
|
+
type: a.type,
|
|
104
|
+
id: a.id,
|
|
105
|
+
tenantId: a.tenantId,
|
|
106
|
+
kind: a.type === "user" ? a.kind ?? null : null,
|
|
107
|
+
service: a.type === "service" ? a.service : null,
|
|
108
|
+
auditActor: a.type === "serviceAccount" ? a.auditActorId === void 0 ? ["implicit"] : ["explicit", a.auditActorId] : null
|
|
109
|
+
},
|
|
110
|
+
wire: u,
|
|
111
|
+
transport: n(o)
|
|
112
|
+
}), p = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(f)), m = "";
|
|
113
|
+
for (let e of new Uint8Array(p)) m += e.toString(16).padStart(2, "0");
|
|
114
|
+
return Object.freeze({
|
|
115
|
+
input: d,
|
|
116
|
+
fingerprint: m
|
|
117
|
+
});
|
|
118
|
+
} catch {
|
|
119
|
+
throw Error("Mutation input cannot be captured for idempotent execution");
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
//#endregion
|
|
123
|
+
export { r as prepareIdempotentInput };
|
package/dist/identity.js
CHANGED
|
@@ -33,15 +33,11 @@ var a = e({ scope: "voltro:identity" }), o = Symbol.for("@voltro/runtime/process
|
|
|
33
33
|
} catch {}
|
|
34
34
|
return l.version;
|
|
35
35
|
}, m = (e) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
l.bootPath = e;
|
|
36
|
+
l.frozen !== void 0 && l.frozen.bootPath !== e ? a.warn(`process identity was already resolved as ${l.frozen.replicaId} (bootPath=${l.frozen.bootPath}); keeping it rather than becoming ${e}. Call setProcessBootPath before anything reads the identity.`, {
|
|
37
|
+
resolved: l.frozen.replicaId,
|
|
38
|
+
was: l.frozen.bootPath,
|
|
39
|
+
requested: e
|
|
40
|
+
}) : l.bootPath = e;
|
|
45
41
|
}, h = (e) => {
|
|
46
42
|
l.appVersion = e, l.frozen !== void 0 && (l.frozen = {
|
|
47
43
|
...l.frozen,
|