@cotal-ai/core 0.85.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/dist/agent-file.d.ts.map +1 -1
- package/dist/agent-file.js +10 -3
- package/dist/agent-file.js.map +1 -1
- package/dist/base64url.d.ts +5 -0
- package/dist/base64url.d.ts.map +1 -0
- package/dist/base64url.js +14 -0
- package/dist/base64url.js.map +1 -0
- package/dist/browser-control.d.ts +97 -0
- package/dist/browser-control.d.ts.map +1 -0
- package/dist/browser-control.js +66 -0
- package/dist/browser-control.js.map +1 -0
- package/dist/browser-validators-build.d.ts +23 -0
- package/dist/browser-validators-build.d.ts.map +1 -0
- package/dist/browser-validators-build.js +149 -0
- package/dist/browser-validators-build.js.map +1 -0
- package/dist/canonical-json.d.ts +14 -0
- package/dist/canonical-json.d.ts.map +1 -0
- package/dist/canonical-json.js +121 -0
- package/dist/canonical-json.js.map +1 -0
- package/dist/canonical.d.ts +2 -10
- package/dist/canonical.d.ts.map +1 -1
- package/dist/canonical.js +2 -108
- package/dist/canonical.js.map +1 -1
- package/dist/checkpoint-answer.d.ts.map +1 -1
- package/dist/checkpoint-answer.js +3 -4
- package/dist/checkpoint-answer.js.map +1 -1
- package/dist/connector-setup.d.ts +10 -1
- package/dist/connector-setup.d.ts.map +1 -1
- package/dist/digest-id.d.ts +4 -0
- package/dist/digest-id.d.ts.map +1 -0
- package/dist/digest-id.js +7 -0
- package/dist/digest-id.js.map +1 -0
- package/dist/endpoint-action.d.ts.map +1 -1
- package/dist/endpoint-action.js +2 -16
- package/dist/endpoint-action.js.map +1 -1
- package/dist/endpoint-auth-digest.d.ts +7 -0
- package/dist/endpoint-auth-digest.d.ts.map +1 -0
- package/dist/endpoint-auth-digest.js +13 -0
- package/dist/endpoint-auth-digest.js.map +1 -0
- package/dist/endpoint-call.d.ts +176 -0
- package/dist/endpoint-call.d.ts.map +1 -0
- package/dist/endpoint-call.js +490 -0
- package/dist/endpoint-call.js.map +1 -0
- package/dist/endpoint-caller.d.ts +113 -0
- package/dist/endpoint-caller.d.ts.map +1 -0
- package/dist/endpoint-caller.js +260 -0
- package/dist/endpoint-caller.js.map +1 -0
- package/dist/endpoint-checkpoint.d.ts.map +1 -1
- package/dist/endpoint-checkpoint.js +5 -14
- package/dist/endpoint-checkpoint.js.map +1 -1
- package/dist/endpoint-envelope.d.ts +0 -6
- package/dist/endpoint-envelope.d.ts.map +1 -1
- package/dist/endpoint-envelope.js +17 -18
- package/dist/endpoint-envelope.js.map +1 -1
- package/dist/endpoint-guard.d.ts.map +1 -1
- package/dist/endpoint-guard.js +2 -10
- package/dist/endpoint-guard.js.map +1 -1
- package/dist/endpoint-invoke.d.ts +36 -119
- package/dist/endpoint-invoke.d.ts.map +1 -1
- package/dist/endpoint-invoke.js +56 -300
- package/dist/endpoint-invoke.js.map +1 -1
- package/dist/endpoint-publish-denial.d.ts +1 -1
- package/dist/endpoint-publish-denial.d.ts.map +1 -1
- package/dist/endpoint-publish-denial.js +1 -1
- package/dist/endpoint-publish-denial.js.map +1 -1
- package/dist/endpoint-receipt.d.ts.map +1 -1
- package/dist/endpoint-receipt.js +2 -16
- package/dist/endpoint-receipt.js.map +1 -1
- package/dist/endpoint-subjects.d.ts.map +1 -1
- package/dist/endpoint-subjects.js.map +1 -1
- package/dist/endpoint-traits.d.ts.map +1 -1
- package/dist/endpoint-traits.js +3 -20
- package/dist/endpoint-traits.js.map +1 -1
- package/dist/endpoint-verbs.d.ts +18 -151
- package/dist/endpoint-verbs.d.ts.map +1 -1
- package/dist/endpoint-verbs.js +4 -500
- package/dist/endpoint-verbs.js.map +1 -1
- package/dist/endpoint-work.d.ts.map +1 -1
- package/dist/endpoint-work.js +2 -17
- package/dist/endpoint-work.js.map +1 -1
- package/dist/endpoint.d.ts +39 -15
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +90 -42
- package/dist/endpoint.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/issued-accepted.d.ts +27 -0
- package/dist/issued-accepted.d.ts.map +1 -0
- package/dist/issued-accepted.js +62 -0
- package/dist/issued-accepted.js.map +1 -0
- package/dist/issued-authority.d.ts +3 -18
- package/dist/issued-authority.d.ts.map +1 -1
- package/dist/issued-authority.js +4 -55
- package/dist/issued-authority.js.map +1 -1
- package/dist/lifecycle-state.d.ts +3 -0
- package/dist/lifecycle-state.d.ts.map +1 -1
- package/dist/lifecycle-state.js +7 -0
- package/dist/lifecycle-state.js.map +1 -1
- package/dist/manager-caller.d.ts.map +1 -1
- package/dist/manager-caller.js +2 -1
- package/dist/manager-caller.js.map +1 -1
- package/dist/one-line.d.ts +6 -0
- package/dist/one-line.d.ts.map +1 -0
- package/dist/one-line.js +8 -0
- package/dist/one-line.js.map +1 -0
- package/dist/peer-label.d.ts +16 -0
- package/dist/peer-label.d.ts.map +1 -0
- package/dist/peer-label.js +15 -0
- package/dist/peer-label.js.map +1 -0
- package/dist/permission-denied.d.ts +8 -0
- package/dist/permission-denied.d.ts.map +1 -0
- package/dist/permission-denied.js +15 -0
- package/dist/permission-denied.js.map +1 -0
- package/dist/presence-text.d.ts +6 -0
- package/dist/presence-text.d.ts.map +1 -0
- package/dist/presence-text.js +25 -0
- package/dist/presence-text.js.map +1 -0
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +8 -2
- package/dist/provision.js.map +1 -1
- package/dist/resolve.d.ts +2 -13
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +2 -12
- package/dist/resolve.js.map +1 -1
- package/dist/run-driver-grants.d.ts +5 -0
- package/dist/run-driver-grants.d.ts.map +1 -1
- package/dist/run-driver-grants.js +16 -4
- package/dist/run-driver-grants.js.map +1 -1
- package/dist/run-migration.d.ts +21 -0
- package/dist/run-migration.d.ts.map +1 -1
- package/dist/run-migration.js +2 -27
- package/dist/run-migration.js.map +1 -1
- package/dist/run-notice.d.ts +20 -0
- package/dist/run-notice.d.ts.map +1 -1
- package/dist/run-notice.js +3 -28
- package/dist/run-notice.js.map +1 -1
- package/dist/schema-bounds.d.ts +24 -0
- package/dist/schema-bounds.d.ts.map +1 -0
- package/dist/schema-bounds.js +74 -0
- package/dist/schema-bounds.js.map +1 -0
- package/dist/schema-profile.d.ts +11 -24
- package/dist/schema-profile.d.ts.map +1 -1
- package/dist/schema-profile.js +16 -73
- package/dist/schema-profile.js.map +1 -1
- package/dist/subjects.d.ts.map +1 -1
- package/dist/subjects.js +1 -2
- package/dist/subjects.js.map +1 -1
- package/dist/turn-contract.d.ts.map +1 -1
- package/dist/turn-contract.js +14 -4
- package/dist/turn-contract.js.map +1 -1
- package/package.json +14 -1
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
/** The node-free call path of the §13.5 verbs (`epCall`, `epCast`, the instance probe), shared by
|
|
2
|
+
* `endpoint-verbs` and the browser entry. Moved unchanged from `endpoint-verbs.ts`. */
|
|
3
|
+
import { base64url } from "./base64url.js";
|
|
4
|
+
import { openPublishDenialWatch } from "./endpoint-publish-denial.js";
|
|
5
|
+
import { spacePrefix } from "./subjects.js";
|
|
6
|
+
import { epRequestSubject, parseEpSubject, callerRailTokens, epPlaneTokens, assertIdToken, assertLifecycleToken, assertBoundedOwner } from "./endpoint-subjects.js";
|
|
7
|
+
import { EpEnvelopeError, EP_UNBOUND_RESPONDER, EP_UNANSWERED, EP_REGISTRY_READ_FAILED, EP_UNDECLARED_ARG, EP_BIND_REFUSED, bindRefusalMarked, parseEndpointReply, assertArgsValid, assertOutputValid } from "./endpoint-envelope.js";
|
|
8
|
+
const nonce = () => base64url(globalThis.crypto.getRandomValues(new Uint8Array(24))); // 32 tokens of [A-Za-z0-9_-], 192 bits
|
|
9
|
+
function subjectTarget(t) {
|
|
10
|
+
if (t.mode === "self")
|
|
11
|
+
return { mode: "self" };
|
|
12
|
+
if (t.mode === "handle" || t.mode === "exact")
|
|
13
|
+
return { mode: t.mode, tOwner: t.owner, tActor: t.actor, tUid: t.lifecycleUid };
|
|
14
|
+
return { mode: t.mode, tOwner: t.owner };
|
|
15
|
+
}
|
|
16
|
+
function bodyTarget(t) {
|
|
17
|
+
if (t.mode === "self")
|
|
18
|
+
return undefined;
|
|
19
|
+
return {
|
|
20
|
+
owner: assertBoundedOwner(t.owner, "target owner"),
|
|
21
|
+
actor: t.actor,
|
|
22
|
+
lifecycleUid: assertLifecycleToken(t.lifecycleUid, "target lifecycleUid"),
|
|
23
|
+
...(t.mappingRevision !== undefined ? { mappingRevision: t.mappingRevision } : {}),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function buildRequest(space, route, op, verb) {
|
|
27
|
+
// §13.7: the caller's own contract gates the args BEFORE publish — the same validator and the
|
|
28
|
+
// same budget the responder runs, so a request this boundary admits pins digests the
|
|
29
|
+
// responder can honor or reject, never digests detached from the payload. The args are gated as
|
|
30
|
+
// the responder will parse them: JSON drops a key whose value is undefined, and validating the
|
|
31
|
+
// object itself refused, against an older responder's closed contract, a key that never reaches it.
|
|
32
|
+
let args;
|
|
33
|
+
try {
|
|
34
|
+
args = op.args === undefined ? undefined : JSON.parse(JSON.stringify(op.args));
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
// A value JSON cannot carry (a BigInt, a cycle, a throwing toJSON) is malformed args that never
|
|
38
|
+
// left this caller: a `not-executed` refusal like the contract check below, never an unknown outcome.
|
|
39
|
+
throw new EpEnvelopeError("bad-request", `args cannot be sent as JSON: ${e instanceof Error ? e.message : String(e)}`, undefined, "not-executed");
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
assertArgsValid(op.contract.input.validate, args);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
if (!(e instanceof EpEnvelopeError))
|
|
46
|
+
throw e;
|
|
47
|
+
// Nothing was published, so the refusal is `not-executed` (§13.3). A key the contract does not
|
|
48
|
+
// declare is marked, so a surface that knows both builds can name the version skew.
|
|
49
|
+
const property = op.contract.input.validate.errors?.[0]?.params?.additionalProperty;
|
|
50
|
+
throw new EpEnvelopeError(e.code, e.message, typeof property === "string" ? [{ kind: EP_UNDECLARED_ARG, property }] : undefined, "not-executed");
|
|
51
|
+
}
|
|
52
|
+
// The responder refuses these too (§13.3), but a caller that would emit an unservable request
|
|
53
|
+
// should not have to learn it from a round trip: `describe` is what produces a bind, and a
|
|
54
|
+
// scatter addresses every incarnation, so neither can carry one.
|
|
55
|
+
if (op.bind !== undefined) {
|
|
56
|
+
if (op.command === "describe")
|
|
57
|
+
throw new EpEnvelopeError("bad-request", "describe carries no bind: it is the bootstrap that produces one (SPEC 13.3)");
|
|
58
|
+
if (route.mode === "all")
|
|
59
|
+
throw new EpEnvelopeError("bad-request", "a scatter addresses every incarnation; a bind would make every member but one refuse (SPEC 13.5)");
|
|
60
|
+
if (route.mode === "inst" && op.bind.instanceId !== route.instanceId)
|
|
61
|
+
throw new EpEnvelopeError("bad-request", `bind.instanceId "${op.bind.instanceId}" contradicts the inst-rail route's instance "${route.instanceId}" (SPEC 13.2)`);
|
|
62
|
+
}
|
|
63
|
+
const n = nonce();
|
|
64
|
+
const subject = epRequestSubject(space, {
|
|
65
|
+
route, endpoint: op.endpoint, command: op.command,
|
|
66
|
+
...(op.target ? { target: subjectTarget(op.target) } : {}),
|
|
67
|
+
caller: op.caller, nonce: n,
|
|
68
|
+
});
|
|
69
|
+
const requestId = op.id !== undefined ? assertIdToken(op.id, "pinned envelope id") : nonce();
|
|
70
|
+
const env = {
|
|
71
|
+
v: 1,
|
|
72
|
+
id: requestId,
|
|
73
|
+
op: {
|
|
74
|
+
endpoint: op.endpoint,
|
|
75
|
+
command: op.command,
|
|
76
|
+
inputDigest: op.contract.input.closureDigest,
|
|
77
|
+
outputDigest: op.contract.output.closureDigest,
|
|
78
|
+
},
|
|
79
|
+
class: "ephemeral", // journal work rides epj submissions, never a rail verb (§13.4/§13.5)
|
|
80
|
+
replyExpected: verb.replyExpected,
|
|
81
|
+
...(op.goalId !== undefined ? { goalId: op.goalId } : {}),
|
|
82
|
+
...(op.target && op.target.mode !== "self" ? { target: bodyTarget(op.target) } : {}),
|
|
83
|
+
...(op.bind !== undefined ? { bind: { instanceId: assertLifecycleToken(op.bind.instanceId, "bind instanceId"), epoch: op.bind.epoch } } : {}),
|
|
84
|
+
...(args !== undefined ? { args } : {}),
|
|
85
|
+
from: { id: `${op.caller.owner}.${op.caller.actor}`, name: op.name ?? op.caller.actor },
|
|
86
|
+
...(verb.deadlineMs !== undefined ? { deadlineMs: verb.deadlineMs } : {}),
|
|
87
|
+
...(op.correlation !== undefined ? { correlation: op.correlation } : {}),
|
|
88
|
+
...(op.auth !== undefined ? { auth: op.auth } : {}),
|
|
89
|
+
};
|
|
90
|
+
return { subject, requestId, n, body: new TextEncoder().encode(JSON.stringify(env)) };
|
|
91
|
+
}
|
|
92
|
+
// Node clamps a `setTimeout` delay beyond 2^31-1 ms (~24.8 days) to 1ms, so an over-large deadline
|
|
93
|
+
// would fire IMMEDIATELY (an unbounded budget masquerading as a huge one). Bound every budget to the
|
|
94
|
+
// timer range so the deadline the caller passes is the deadline the timer honors.
|
|
95
|
+
const MAX_TIMER_MS = 2_147_483_647;
|
|
96
|
+
export function assertDeadline(deadlineMs, what = "deadlineMs") {
|
|
97
|
+
if (!Number.isSafeInteger(deadlineMs) || deadlineMs <= 0 || deadlineMs > MAX_TIMER_MS)
|
|
98
|
+
throw new EpEnvelopeError("bad-request", `${what} ${deadlineMs} must be a positive budget within the timer bound ${MAX_TIMER_MS}ms (SPEC 13.3: bounded, never unbounded; a larger setTimeout clamps to 1ms)`);
|
|
99
|
+
return deadlineMs;
|
|
100
|
+
}
|
|
101
|
+
/** A NATS "no responders" control message: the broker answered that the request subject had zero
|
|
102
|
+
* subscribers (SPEC 13.5: no responder → unavailable), delivered to the publish reply-to as an empty
|
|
103
|
+
* message with a 503 status header — distinct from a responder that exists but missed the deadline.
|
|
104
|
+
* A responder CAN attach a 503 header to its own reply, so this header alone is not proof of broker
|
|
105
|
+
* authorship: callers must trust it ONLY on the reserved no-responders sentinel subject (which carries
|
|
106
|
+
* no responder publish grant), never on a normal reply subject. */
|
|
107
|
+
function isNoRespondersMsg(msg) {
|
|
108
|
+
const h = msg.headers;
|
|
109
|
+
return h != null && (h.code === 503 || h.status === "503");
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Ask the BROKER whether one instance still holds a subscription on its own `inst` rail (§13.2).
|
|
113
|
+
*
|
|
114
|
+
* A serving incarnation subscribes `ep.inst.<endpoint>.<instanceId>.<command>.>` for every command
|
|
115
|
+
* it serves, so a request published there with a reply-to only the broker can reach either draws
|
|
116
|
+
* the broker's no-responders 503 — an affirmative statement that this instance holds no
|
|
117
|
+
* subscription — or draws nothing at all.
|
|
118
|
+
*
|
|
119
|
+
* NOTHING IS `unknown` BUT A REFUSED PUBLISH, AND NOTHING IS EVER DEATH. A slow broker, a responder
|
|
120
|
+
* that receives the request and declines to answer, and a perfectly healthy instance are
|
|
121
|
+
* indistinguishable from here, and every one of them must keep the caller waiting. A REFUSED
|
|
122
|
+
* PUBLISH IS THE ONE EXCEPTION, and it is a refusal rather than a verdict: `nc.publish` returns
|
|
123
|
+
* normally on a violation, so the permission watch (see {@link openPublishDenialWatch}, registered
|
|
124
|
+
* before the publish and released in the `finally`) races the budget and settles the probe
|
|
125
|
+
* `permission-denied` naming the refused subject as soon as the connection reports it — never a
|
|
126
|
+
* silent `unknown` that consumes the full budget on a permission problem. The failure direction is
|
|
127
|
+
* otherwise the whole safety argument: because only a 503 says anything, a short probe budget can
|
|
128
|
+
* never turn a live instance into a fast `missing` — it can only fail to speed up a dead one.
|
|
129
|
+
*
|
|
130
|
+
* It rides `describe` because §13.7 makes every endpoint serve it and it carries no effect, and it
|
|
131
|
+
* rides as a CAST: the verdict comes from the transport, not from an answer, so nothing is read and
|
|
132
|
+
* an instance whose describe is broken still reads as present.
|
|
133
|
+
*/
|
|
134
|
+
export async function epProbeInstanceInterest(nc, space, endpoint, instanceId, caller, opts) {
|
|
135
|
+
const deadlineMs = assertDeadline(opts.deadlineMs);
|
|
136
|
+
const iId = assertLifecycleToken(instanceId, "instanceId");
|
|
137
|
+
const n = nonce();
|
|
138
|
+
const subject = epRequestSubject(space, { route: { mode: "inst", instanceId: iId }, endpoint, command: "describe", caller, nonce: n });
|
|
139
|
+
const env = {
|
|
140
|
+
v: 1, id: nonce(), op: { endpoint, command: "describe" }, class: "ephemeral",
|
|
141
|
+
replyExpected: false, from: { id: `${caller.owner}.${caller.actor}`, name: caller.actor },
|
|
142
|
+
};
|
|
143
|
+
// The SAME reserved sentinel `epCall` uses, for the same reason: no responder holds a publish
|
|
144
|
+
// grant for the `_nr._nr._nr` reply subject (§13.9), so a 503 arriving there is the broker's own
|
|
145
|
+
// control frame and cannot be forged by a recipient that knows the nonce.
|
|
146
|
+
const noRespReplyTo = noRespondersReplyTo(space, caller, n);
|
|
147
|
+
// REGISTER THE PERMISSION WATCH BEFORE THE PUBLISH IT IS WATCHING, and race it against the
|
|
148
|
+
// budget: a refused publish that expired into `unknown` would read a permission problem as "no
|
|
149
|
+
// verdict" and pay the full budget for it — the exact slow masquerade the watch exists to end.
|
|
150
|
+
const denialWatch = openPublishDenialWatch(nc, subject, () => new EpEnvelopeError("permission-denied", `the liveness probe for ${endpoint}.${iId} was REFUSED BY THE BROKER, not unanswered: this caller's credential does not authorize publishing to "${subject}" (the instance rail for ${iId}). The instance may be perfectly healthy; the grant is what is missing (SPEC 13.2)`), "probe");
|
|
151
|
+
let sub;
|
|
152
|
+
let timer;
|
|
153
|
+
try {
|
|
154
|
+
const verdict = new Promise((resolve) => {
|
|
155
|
+
timer = setTimeout(() => resolve("unknown"), deadlineMs);
|
|
156
|
+
// A PROBE MUST NEVER BE THE REASON A PROCESS IS STILL RUNNING. Against a LIVE instance no
|
|
157
|
+
// answer ever comes back — the request is a cast and §13.5 forbids the responder replying to
|
|
158
|
+
// one — so this timer runs its full budget on every healthy instance, every time. Wired into
|
|
159
|
+
// `cotal ps` that was measured at 4.0 extra seconds AFTER the last row was printed (12.8s
|
|
160
|
+
// with the probe against 8.8s without it, on a healthy two-manager mesh): the gather had long
|
|
161
|
+
// since finished, and the only verdict that changes anything is `gone`, which a caller who
|
|
162
|
+
// has already gathered can no longer use. Unref makes the timer stop holding the loop open
|
|
163
|
+
// WITHOUT changing the probe: it still settles `unknown` at the budget for anyone still
|
|
164
|
+
// waiting on it, because the connection this needs is itself an open handle, and a caller
|
|
165
|
+
// still using that connection is therefore still running.
|
|
166
|
+
timer.unref?.();
|
|
167
|
+
sub = nc.subscribe(noRespReplyTo, {
|
|
168
|
+
callback: (err, msg) => { resolve(err === null && isNoRespondersMsg(msg) ? "gone" : "unknown"); },
|
|
169
|
+
});
|
|
170
|
+
nc.publish(subject, new TextEncoder().encode(JSON.stringify(env)), { reply: noRespReplyTo });
|
|
171
|
+
});
|
|
172
|
+
// The refusal settles the probe INSTEAD of the budget: raced here, it rejects the await as the
|
|
173
|
+
// thrown `permission-denied` before the deadline can resolve `unknown`. When the 503 or the
|
|
174
|
+
// budget settles first, the finally below releases the watch and a refusal never observed by
|
|
175
|
+
// anyone is never raised.
|
|
176
|
+
return await Promise.race([verdict, denialWatch.denied]);
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
sub?.unsubscribe();
|
|
180
|
+
if (timer !== undefined)
|
|
181
|
+
clearTimeout(timer);
|
|
182
|
+
denialWatch.release();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/** Race a caller-supplied read against a bounded budget so a never-settling hook cannot exceed the
|
|
186
|
+
* operation deadline (SPEC 13.5: deadline mandatory). Clears its timer on either outcome. */
|
|
187
|
+
export async function raceBounded(read, ms, what, details) {
|
|
188
|
+
let t;
|
|
189
|
+
try {
|
|
190
|
+
return await Promise.race([
|
|
191
|
+
(async () => read())(),
|
|
192
|
+
new Promise((_, reject) => { t = setTimeout(() => reject(new EpEnvelopeError("deadline-exceeded", `${what} did not settle within the ${ms}ms budget (SPEC 13.5)`, details)), ms); }),
|
|
193
|
+
]);
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
if (t !== undefined)
|
|
197
|
+
clearTimeout(t);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/** The {@link EP_UNANSWERED} detail for `op`: set ONLY where this module observed that nothing
|
|
201
|
+
* answered (the broker's no-responders control frame, or the reply deadline elapsing). */
|
|
202
|
+
const unansweredDetail = (op) => ({ kind: EP_UNANSWERED, endpoint: op.endpoint, command: op.command, rail: epPlaneTokens(op.caller).join(".") });
|
|
203
|
+
/** The {@link EP_REGISTRY_READ_FAILED} detail for `op`: set where the scatter's OWN registry read
|
|
204
|
+
* (freeze or reconcile) failed, so the failure is never read as the responders' silence. */
|
|
205
|
+
export const registryReadDetail = (op) => ({ kind: EP_REGISTRY_READ_FAILED, endpoint: op.endpoint, command: op.command });
|
|
206
|
+
/** The caller's per-request reply subscription: its own rail narrowed to exactly this request's
|
|
207
|
+
* nonce (contained in the §13.9 reply-read grant), so concurrent calls never see each other. */
|
|
208
|
+
export function replySubjectFor(space, caller, n) {
|
|
209
|
+
return `${spacePrefix(space)}.${epPlaneTokens(caller).join(".")}.reply.*.*.*.${callerRailTokens(caller).join(".")}.${n}`;
|
|
210
|
+
}
|
|
211
|
+
/** The reserved no-responders sentinel on the caller's OWN rail (SPEC 13.5/13.9): no responder
|
|
212
|
+
* holds a publish grant for `_nr._nr._nr`, so only the broker's control frame reaches it. On the
|
|
213
|
+
* versioned rail the sentinel carries the generation too, inside the caller's read filter. */
|
|
214
|
+
function noRespondersReplyTo(space, caller, n) {
|
|
215
|
+
return `${spacePrefix(space)}.${epPlaneTokens(caller).join(".")}.reply._nr._nr._nr.${callerRailTokens(caller).join(".")}.${n}`;
|
|
216
|
+
}
|
|
217
|
+
/** The stale-epoch refusal, worded by DIRECTION and by what the caller's reference epoch IS, and
|
|
218
|
+
* carrying the {@link EP_UNBOUND_RESPONDER} marker. Both rails reach it after an ATTRIBUTED reply:
|
|
219
|
+
* the responder received the request and answered it, at an epoch other than the caller's reference.
|
|
220
|
+
* The reference has two meanings, and the message must not lend one caller's meaning to the other:
|
|
221
|
+
* - `bind`: the epoch this caller's own resolve bound (the `inst` rail's pinned epoch, or the
|
|
222
|
+
* describe-bound default on `one`). `answered > held` means a SUCCESSOR of the bound incarnation
|
|
223
|
+
* answered (a same-root restart, or a supersession): the caller's handle is the stale side, and
|
|
224
|
+
* re-resolving adopts the successor. `answered < held` means a superseded incarnation still
|
|
225
|
+
* connected answered, and its reply is what is rejected.
|
|
226
|
+
* - `registry`: a currency read of the responder's CURRENT registered epoch (epCall's documented
|
|
227
|
+
* `currentEpoch` contract, {@link serviceEpochReader}). Nothing of the caller's is stale here:
|
|
228
|
+
* `answered > current` means the read lags a restart, `answered < current` a superseded
|
|
229
|
+
* incarnation still answering.
|
|
230
|
+
* Either way the marker says what the code alone cannot: a retry is a second attempt. The kind is
|
|
231
|
+
* explicit rather than inferred because a single wording names the wrong stale side on one of the
|
|
232
|
+
* two paths, whichever meaning it picks. */
|
|
233
|
+
function staleEpochRefusal(op, responder, held, reference, rail) {
|
|
234
|
+
const who = `the ${op.endpoint} instance ${responder.instanceId}`;
|
|
235
|
+
const ahead = responder.epoch > held;
|
|
236
|
+
const situation = reference === "bind"
|
|
237
|
+
? (ahead
|
|
238
|
+
? `${who} answered at epoch ${responder.epoch}, but this handle resolved against it at epoch ${held}: a SUCCESSOR of the bound incarnation answered (a restart or supersession), so the handle is the stale side; re-resolve to adopt it`
|
|
239
|
+
: `${who} answered at epoch ${responder.epoch}, but this handle resolved against it at epoch ${held}: a SUPERSEDED incarnation still connected answered, and its reply is rejected`)
|
|
240
|
+
: (ahead
|
|
241
|
+
? `${who} answered at epoch ${responder.epoch}, but a currency read of its registered epoch returned ${held}: the responder is ahead of the registry read (the read lags a restart), so its reply is rejected until the read catches up; nothing of this caller's is stale`
|
|
242
|
+
: `${who} answered at epoch ${responder.epoch}, but a currency read of its registered epoch returned ${held}: a SUPERSEDED incarnation still connected answered, and its reply is rejected`);
|
|
243
|
+
const detail = {
|
|
244
|
+
kind: EP_UNBOUND_RESPONDER, endpoint: op.endpoint, command: op.command, answeredBy: responder.instanceId,
|
|
245
|
+
...(reference === "bind" ? { boundTo: responder.instanceId } : {}),
|
|
246
|
+
answeredEpoch: responder.epoch, heldEpoch: held, reference, pinned: rail === "inst",
|
|
247
|
+
};
|
|
248
|
+
return new EpEnvelopeError("expired", `${situation}. THIS SAYS NOTHING ABOUT WHETHER THE COMMAND RAN: ${responder.instanceId} received the request and answered it, so if "${op.command}" mutates, that effect may already have landed; verify the outcome ('ps'/'inspect'/roster) before re-issuing (SPEC 13.2, the stale-reply rejection rule)`, [detail]);
|
|
249
|
+
}
|
|
250
|
+
export function parseAttributedReply(space, subject, data, requestId, op, expect) {
|
|
251
|
+
const parsed = parseEpSubject(subject);
|
|
252
|
+
if (!parsed || parsed.plane !== "reply")
|
|
253
|
+
throw new EpEnvelopeError("internal", `a message on the caller's reply rail does not parse as a reply subject: ${subject}`);
|
|
254
|
+
// SPEC §13.2: ACCEPTANCE binds the subject-borne attribution to the INVOKED identity.
|
|
255
|
+
// Reading the endpoint/instance/epoch off the subject is not the same as checking them against the
|
|
256
|
+
// invocation: a truthfully-attributed reply from a DIFFERENT endpoint (or a stale/other instance)
|
|
257
|
+
// is not the requested responder, and nonce possession is addressing, not authorization. A stale
|
|
258
|
+
// process "publishes attributably stale replies that callers reject" — so the caller rejects here.
|
|
259
|
+
if (parsed.endpoint !== op.endpoint)
|
|
260
|
+
throw new EpEnvelopeError("internal", `reply endpoint "${parsed.endpoint}" is not the invoked endpoint "${op.endpoint}" (SPEC 13.2: the caller binds a reply to the requested identity, never trusts the subject alone)`);
|
|
261
|
+
if (expect?.instanceId !== undefined && parsed.instanceId !== expect.instanceId)
|
|
262
|
+
throw new EpEnvelopeError("internal", `reply instance "${parsed.instanceId}" is not the addressed instance "${expect.instanceId}" (SPEC 13.2)`);
|
|
263
|
+
if (expect?.epoch !== undefined && parsed.epoch !== expect.epoch)
|
|
264
|
+
throw staleEpochRefusal(op, { instanceId: parsed.instanceId, epoch: parsed.epoch }, expect.epoch, "bind", "inst");
|
|
265
|
+
// §13.3: an unparseable body is THIS boundary's own structured refusal — the documented catalog
|
|
266
|
+
// (`internal`) holds; a raw SyntaxError must never escape the verb (the watch path already wraps
|
|
267
|
+
// its decode the same way).
|
|
268
|
+
let rawBody;
|
|
269
|
+
try {
|
|
270
|
+
rawBody = JSON.parse(new TextDecoder().decode(data));
|
|
271
|
+
}
|
|
272
|
+
catch (e) {
|
|
273
|
+
throw new EpEnvelopeError("internal", `the reply body on the caller's rail is not JSON (${e instanceof Error ? e.message : String(e)}); an unparseable reply is a responder bug surfaced as the caller boundary's structured refusal (SPEC 13.3)`);
|
|
274
|
+
}
|
|
275
|
+
const reply = parseEndpointReply(rawBody);
|
|
276
|
+
if (reply.id !== requestId)
|
|
277
|
+
throw new EpEnvelopeError("internal", `reply id "${reply.id}" does not echo the request id "${requestId}" on its nonce-scoped rail (SPEC 13.3)`);
|
|
278
|
+
// §13.3: a success payload validates against the pinned output contract at ITS consuming
|
|
279
|
+
// boundary, under the same fixed budget; the responder's bug never parses as caller success.
|
|
280
|
+
if (reply.ok)
|
|
281
|
+
assertOutputValid(op.contract.output.validate, reply.data);
|
|
282
|
+
return { reply, responder: { endpoint: parsed.endpoint, instanceId: parsed.instanceId, epoch: parsed.epoch } };
|
|
283
|
+
}
|
|
284
|
+
// ---- call (§13.5: request/reply, deadline-bounded) ----------------------------------------------
|
|
285
|
+
/**
|
|
286
|
+
* Call one command and await its reply within `deadlineMs`: on the `one` (queue-group anycast) or
|
|
287
|
+
* `inst` (stable incarnation) rail with `replyExpected: true`, subscribe the caller's own
|
|
288
|
+
* nonce-scoped reply subject BEFORE publishing, and resolve the first attributed reply — BOUND to
|
|
289
|
+
* the invoked identity (§13.2, the stale-reply rejection rule: "callers reject" stale-process replies), on BOTH rails:
|
|
290
|
+
* - `inst` pins the addressed `(instanceId, epoch)` incarnation up front; a stale-epoch reply is
|
|
291
|
+
* `expired` and a wrong-instance reply `internal`.
|
|
292
|
+
* - `one` cannot pin an instance up front (the queue picks the responder), so the caller MUST supply
|
|
293
|
+
* `currentEpoch(instanceId)`: after the reply lands, the answering incarnation's epoch is checked
|
|
294
|
+
* against its current registry epoch, and a superseded-but-still-connected queue member's reply is
|
|
295
|
+
* `expired`. The queue winner is NOT implicitly current — that is a check, not an assumption.
|
|
296
|
+
* `currencyReference` says what that hook returns, for the refusal's wording and marker: the
|
|
297
|
+
* documented `registry` read (default), or `bind` when a caller supplies its own resolve's epoch
|
|
298
|
+
* instead (the describe-bound default in {@link invokeCommand}), where a responder ahead of it is
|
|
299
|
+
* a successor and the caller's handle is the stale side.
|
|
300
|
+
*
|
|
301
|
+
* Application-level failure is NOT a throw: the resolved `reply` carries `ok: false` with the
|
|
302
|
+
* responder's structured error (§13.3). This boundary throws only for its own refusals: invalid args
|
|
303
|
+
* `bad-request`; an unparseable/mis-echoed/mis-attributed reply `internal` (a raw decode error never
|
|
304
|
+
* escapes); a throwing `currentEpoch` hook `internal` and a garbled (non-integer/negative) currency
|
|
305
|
+
* value `failed-precondition` (the read's own failure, never mislabeled staleness); a stale reply `expired`;
|
|
306
|
+
* NO responder `unavailable` (SPEC 13.5, the broker no-responders answer — the broker's no-responders 503 lands on a reply-to that
|
|
307
|
+
* sits on THIS caller's own rail, so a manual, fully-disposed probe distinguishes it from a slow
|
|
308
|
+
* responder without leaving a lingering request); a failed reply subscription `unavailable`; a
|
|
309
|
+
* broker publish violation `permission-denied` naming the refused subject (the connection-status
|
|
310
|
+
* watch that keeps a missing GRANT from reading as an unanswered deadline); the elapsed budget
|
|
311
|
+
* `deadline-exceeded`. Every subscription, timer, and status watch is released in the `finally`.
|
|
312
|
+
*/
|
|
313
|
+
export async function epCall(nc, space, route, op, opts) {
|
|
314
|
+
opts.signal?.throwIfAborted();
|
|
315
|
+
const deadlineMs = assertDeadline(opts.deadlineMs);
|
|
316
|
+
if (route.mode === "one" && opts.currentEpoch === undefined)
|
|
317
|
+
throw new EpEnvelopeError("bad-request", "epCall on the `one` rail requires opts.currentEpoch: the queue winner is not implicitly current, and a superseded-but-connected member's reply must be rejected (SPEC 13.2, the stale-reply rejection rule)");
|
|
318
|
+
const req = buildRequest(space, route, op, { replyExpected: true, deadlineMs });
|
|
319
|
+
const expect = route.mode === "inst" ? { instanceId: route.instanceId, epoch: route.epoch } : undefined;
|
|
320
|
+
// A no-responders reply-to that lands on THIS caller's OWN rail (within its §13.9 read grant, no
|
|
321
|
+
// inbox prefix needed): responders answer on the DERIVED rail, so this sentinel only ever carries
|
|
322
|
+
// the broker's no-responders 503, which our rail subscription observes and disposes with everything
|
|
323
|
+
// else in the finally — no ghost request/subscription/timer survives a successful call.
|
|
324
|
+
const noRespReplyTo = noRespondersReplyTo(space, op.caller, req.n);
|
|
325
|
+
const started = Date.now();
|
|
326
|
+
let sub;
|
|
327
|
+
let timer;
|
|
328
|
+
let denialWatch;
|
|
329
|
+
let onAbort;
|
|
330
|
+
const cancelled = new Promise((_, reject) => {
|
|
331
|
+
onAbort = () => reject(new EpEnvelopeError("unavailable", `${op.endpoint}.${op.command} observation cancelled; the request may have executed`, undefined, "unknown"));
|
|
332
|
+
opts.signal?.addEventListener("abort", onAbort, { once: true });
|
|
333
|
+
});
|
|
334
|
+
try {
|
|
335
|
+
// Register denial observation before publishing. Keep subscription and publication in the
|
|
336
|
+
// same promise executor: a closed/draining connection must not strand a rejected reply wait.
|
|
337
|
+
// The broker dropped the publish, so no responder received the command: `not-executed` (§13.3).
|
|
338
|
+
denialWatch = openPublishDenialWatch(nc, req.subject, () => new EpEnvelopeError("permission-denied", `the call for ${op.endpoint}.${op.command} was REFUSED BY THE BROKER, not unanswered: this caller's credential does not authorize publishing to "${req.subject}"${route.mode === "inst" ? ` (the instance rail for ${route.instanceId}: an instance-addressed call needs a credential minted with that instance, not a class-rail one)` : ""}. The responder may be perfectly healthy; the grant is what is missing (SPEC 13.2)`, undefined, "not-executed"), "call");
|
|
339
|
+
const outcome = new Promise((resolve, reject) => {
|
|
340
|
+
sub = nc.subscribe(replySubjectFor(space, op.caller, req.n), {
|
|
341
|
+
callback: (err, msg) => {
|
|
342
|
+
if (err) {
|
|
343
|
+
reject(new EpEnvelopeError("unavailable", `the caller's reply subscription failed: ${err.message}`));
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
// Broker no-responders is authoritative ONLY on the reserved sentinel reply-to: no responder
|
|
347
|
+
// holds a publish grant for the `_nr._nr._nr` subject (§13.9), so only the broker's control
|
|
348
|
+
// frame reaches it. A 503 status header on a NORMAL responder subject is just a responder
|
|
349
|
+
// frame carrying a status line — a recipient knows the nonce and could forge one to
|
|
350
|
+
// impersonate transport absence — so it takes the ordinary attributed-reply path below, never
|
|
351
|
+
// the broker-control path.
|
|
352
|
+
if (msg.subject === noRespReplyTo) {
|
|
353
|
+
if (isNoRespondersMsg(msg)) {
|
|
354
|
+
reject(new EpEnvelopeError("unavailable", `no responder for ${op.endpoint}.${op.command} (SPEC 13.5)`, [unansweredDetail(op)]));
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
reject(new EpEnvelopeError("internal", `a non-503 message reached the reserved no-responders sentinel for ${op.endpoint}.${op.command}; nothing but the broker control frame is addressable there`));
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
resolve({ subject: msg.subject, data: msg.data });
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
opts.signal?.throwIfAborted();
|
|
364
|
+
nc.publish(req.subject, req.body, { reply: noRespReplyTo });
|
|
365
|
+
});
|
|
366
|
+
const timeout = new Promise((_, reject) => { timer = setTimeout(() => reject(new EpEnvelopeError("deadline-exceeded", `no reply to ${op.endpoint}.${op.command} within the ${deadlineMs}ms budget (SPEC 13.5)`, [unansweredDetail(op)])), deadlineMs); });
|
|
367
|
+
const msg = await Promise.race([outcome, timeout, denialWatch.denied, cancelled]);
|
|
368
|
+
const attributed = parseAttributedReply(space, msg.subject, msg.data, req.requestId, op, expect);
|
|
369
|
+
// Taken BEFORE the currency check below, because a responder that fenced on the bind settled
|
|
370
|
+
// the same question better: it knows it did not run the command, where the check can only
|
|
371
|
+
// observe that the answer came from elsewhere. Returning the refusal keeps it an ordinary
|
|
372
|
+
// application-level failure (§13.5) that tells the caller a retry is safe, instead of a throw
|
|
373
|
+
// that says nothing about whether the command ran. Cross-checked against the SUBJECT first: a
|
|
374
|
+
// reply attributed to the very incarnation the caller bound cannot coherently claim it is not
|
|
375
|
+
// that incarnation (§13.3).
|
|
376
|
+
// Gated on the marker's PRESENCE, not on the outcome. Whether the caller may act on this
|
|
377
|
+
// refusal is a separate question, settled downstream by `replyRefusedBeforeEffect`; whether the
|
|
378
|
+
// reply is coherent is settled here, and a reply that omits the outcome is no less obliged to
|
|
379
|
+
// agree with its own attribution. Gating both on the same predicate let a refusal buy its way
|
|
380
|
+
// out of the checks by leaving a field off.
|
|
381
|
+
if (attributed.reply.ok === false && bindRefusalMarked(attributed.reply.error)) {
|
|
382
|
+
if (op.bind === undefined)
|
|
383
|
+
throw new EpEnvelopeError("internal", `${op.endpoint}.${op.command} replied with a bind refusal to a request that carried no bind`);
|
|
384
|
+
const r = attributed.responder;
|
|
385
|
+
if (r.instanceId === op.bind.instanceId && r.epoch === op.bind.epoch)
|
|
386
|
+
throw new EpEnvelopeError("internal", `${op.endpoint} instance ${r.instanceId} refused ${op.command} as the wrong incarnation, but the reply subject attributes it to exactly the bound one (${op.bind.instanceId} epoch ${op.bind.epoch}); the body does not get to contradict its own attribution (SPEC 13.3)`);
|
|
387
|
+
// AND THE REFUSAL MUST BE AN ANSWER TO *THIS* REQUEST, FROM *THIS* RESPONDER. THREE CHECKS ARE
|
|
388
|
+
// JOINTLY REQUIRED here — the subject check above, plus `boundTo` and `servedBy` below — and
|
|
389
|
+
// removing any one of them accepts a "did not run" the caller cannot derive. A caller acts on
|
|
390
|
+
// this marker by re-issuing a command it would otherwise never repeat, so it is checked rather
|
|
391
|
+
// than believed: a fence computes it from the request's own bind against its own identity, so
|
|
392
|
+
// both halves are DERIVABLE. A `boundTo` that is not the block this request carried was not
|
|
393
|
+
// computed from this request; a `servedBy` disagreeing with the reply subject is a body
|
|
394
|
+
// contradicting its own attribution. Both are `internal`, not a retry.
|
|
395
|
+
const refusal = (attributed.reply.error?.details ?? []).find((d) => d.kind === EP_BIND_REFUSED);
|
|
396
|
+
if (refusal === undefined)
|
|
397
|
+
throw new EpEnvelopeError("internal", `${op.endpoint}.${op.command} came back marked ${EP_BIND_REFUSED} with no such detail to derive it from (SPEC 13.3)`);
|
|
398
|
+
if (refusal.boundTo.instanceId !== op.bind.instanceId || refusal.boundTo.epoch !== op.bind.epoch)
|
|
399
|
+
throw new EpEnvelopeError("internal", `${op.endpoint} refused ${op.command} against bind ${refusal.boundTo.instanceId} epoch ${refusal.boundTo.epoch}, but this request carried ${op.bind.instanceId} epoch ${op.bind.epoch}; a refusal computed from another request proves nothing about this one (SPEC 13.3)`);
|
|
400
|
+
if (refusal.servedBy.instanceId !== r.instanceId || refusal.servedBy.epoch !== r.epoch)
|
|
401
|
+
throw new EpEnvelopeError("internal", `${op.endpoint} refused ${op.command} claiming to be served by ${refusal.servedBy.instanceId} epoch ${refusal.servedBy.epoch}, but the reply subject attributes it to ${r.instanceId} epoch ${r.epoch}; the body does not get to contradict its own attribution (SPEC 13.3)`);
|
|
402
|
+
return attributed;
|
|
403
|
+
}
|
|
404
|
+
if (route.mode === "one") {
|
|
405
|
+
// §13.2, the stale-reply rejection rule currency for the queue winner, bounded by the REMAINING budget so the whole
|
|
406
|
+
// call stays within ONE `deadlineMs` (deliberately NOT a second dedicated budget like scatter's
|
|
407
|
+
// `reconcileDeadlineMs`: a call's reply usually arrives well before T, leaving room to verify,
|
|
408
|
+
// whereas scatter's gather deterministically eats its whole deadline). The consequence is a
|
|
409
|
+
// deliberate disposition: a VALID reply that lands with no budget left to verify currency is
|
|
410
|
+
// `deadline-exceeded`, not the reply — the operation could not complete-and-verify within its
|
|
411
|
+
// budget. Recorded for the panel's §13.5 reconciliation (dedicated one-rail currency budget?).
|
|
412
|
+
const remaining = deadlineMs - (Date.now() - started);
|
|
413
|
+
if (remaining <= 0)
|
|
414
|
+
throw new EpEnvelopeError("deadline-exceeded", `no budget left to verify the \`one\` responder's currency within ${deadlineMs}ms (SPEC 13.5)`);
|
|
415
|
+
// The hook is an untrusted caller-supplied boundary (same class as scatter's reconcile): its
|
|
416
|
+
// own throw is normalized into the documented catalog, and its VALUE is runtime-fenced — a
|
|
417
|
+
// NaN/garbled epoch compares unequal to any real epoch and would masquerade as staleness
|
|
418
|
+
// (`expired`), mislabeling a valid reply; fail loud as the read's own failure instead.
|
|
419
|
+
let cur;
|
|
420
|
+
try {
|
|
421
|
+
cur = await raceBounded(() => opts.currentEpoch(attributed.responder.instanceId), remaining, `the \`one\` currency read for ${op.endpoint}.${op.command}`);
|
|
422
|
+
}
|
|
423
|
+
catch (e) {
|
|
424
|
+
if (e instanceof EpEnvelopeError)
|
|
425
|
+
throw e; // the bound's deadline-exceeded, or the hook's own structured refusal
|
|
426
|
+
throw new EpEnvelopeError("internal", `the \`one\` currency read threw (${e instanceof Error ? e.message : String(e)}); the documented error catalog holds at this boundary (SPEC 13.3)`);
|
|
427
|
+
}
|
|
428
|
+
if (!Number.isSafeInteger(cur) || cur < 0)
|
|
429
|
+
throw new EpEnvelopeError("failed-precondition", `the \`one\` currency read returned a non-integer/negative epoch ${String(cur)}; a garbled currency read is refused as the read's own failure, never reported as responder staleness (SPEC 13.2)`);
|
|
430
|
+
if (attributed.responder.epoch !== cur)
|
|
431
|
+
throw staleEpochRefusal(op, attributed.responder, cur, opts.currencyReference ?? "registry", "one");
|
|
432
|
+
}
|
|
433
|
+
return attributed;
|
|
434
|
+
}
|
|
435
|
+
finally {
|
|
436
|
+
sub?.unsubscribe();
|
|
437
|
+
if (timer !== undefined)
|
|
438
|
+
clearTimeout(timer);
|
|
439
|
+
denialWatch?.release();
|
|
440
|
+
if (onAbort)
|
|
441
|
+
opts.signal?.removeEventListener("abort", onAbort);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
// ---- cast (§13.5: at-most-once, never replied) --------------------------------------------------
|
|
445
|
+
/**
|
|
446
|
+
* Cast one command: the same request form with `replyExpected: false` — the responder never
|
|
447
|
+
* replies, even on failure (§13.5 at-most-once), so this resolves once the request is flushed to
|
|
448
|
+
* the broker. `deadlineMs` is optional and advisory for `one`/`inst` (the envelope requires it only
|
|
449
|
+
* for calls and journal submissions, §13.3), but MANDATORY for `all`: §13.2's
|
|
450
|
+
* `checkRequestSubjectAgreement` refuses an all-rail request without a deadline regardless of
|
|
451
|
+
* `replyExpected`, and a cast has no reply on which that refusal could surface — so an all-cast
|
|
452
|
+
* without a deadline would be silently dropped by every responder. Fail loud at the caller instead.
|
|
453
|
+
*
|
|
454
|
+
* A broker publish refusal is NOT a flushed cast: `nc.publish` returns normally on a violation, so
|
|
455
|
+
* the permission watch (see {@link openPublishDenialWatch}, registered before the publish and
|
|
456
|
+
* released in the `finally`) races the flush, and a refused cast settles `permission-denied`
|
|
457
|
+
* naming the refused subject as soon as the connection reports it — never a resolution the caller
|
|
458
|
+
* could read as "it was cast". Nothing is added to the healthy path: a permitted publish is
|
|
459
|
+
* unaffected and the flush round-trip stands as the settling time.
|
|
460
|
+
*/
|
|
461
|
+
export async function epCast(nc, space, route, op, opts = {}) {
|
|
462
|
+
if (route.mode === "all" && opts.deadlineMs === undefined)
|
|
463
|
+
throw new EpEnvelopeError("bad-request", "an all-rail cast (scatter) requires deadlineMs (SPEC 13.2: checkRequestSubjectAgreement refuses an all request without a deadline; a cast has no reply to carry that refusal, so it would be silently dropped)");
|
|
464
|
+
const req = buildRequest(space, route, op, {
|
|
465
|
+
replyExpected: false,
|
|
466
|
+
...(opts.deadlineMs !== undefined ? { deadlineMs: assertDeadline(opts.deadlineMs) } : {}),
|
|
467
|
+
});
|
|
468
|
+
// REGISTER THE PERMISSION WATCH BEFORE THE PUBLISH IT IS WATCHING, and race it against the
|
|
469
|
+
// flush: a refused cast that resolved with the flush would be the exact success masquerade the
|
|
470
|
+
// watch exists to eliminate, and the caller has no reply or deadline of its own to notice
|
|
471
|
+
// otherwise. The refusal is not wall-clock latency: the broker writes the permission ERROR
|
|
472
|
+
// before the PONG that answers the flush, so the violation is already on the connection when
|
|
473
|
+
// the flush resolves — but its dispatch to this race rides a longer microtask chain than the
|
|
474
|
+
// flush's own continuation, and `Promise.race` would hand the flush the win on arrival order
|
|
475
|
+
// alone. Chaining ONE EVENT-LOOP TURN (`setImmediate`, not a timer) after the flush lets that
|
|
476
|
+
// chain complete first: a refused publish rejects deterministically, and a permitted one
|
|
477
|
+
// settles on the next loop turn — the flush round-trip remains the entire cost.
|
|
478
|
+
const denialWatch = openPublishDenialWatch(nc, req.subject, () => new EpEnvelopeError("permission-denied", `the cast for ${op.endpoint}.${op.command} was REFUSED BY THE BROKER, not cast: this caller's credential does not authorize publishing to "${req.subject}". The responder may be perfectly healthy; the grant is what is missing (SPEC 13.2)`), "cast");
|
|
479
|
+
try {
|
|
480
|
+
nc.publish(req.subject, req.body);
|
|
481
|
+
await Promise.race([
|
|
482
|
+
nc.flush().then(() => new Promise((resolve) => setImmediate(resolve))),
|
|
483
|
+
denialWatch.denied,
|
|
484
|
+
]);
|
|
485
|
+
}
|
|
486
|
+
finally {
|
|
487
|
+
denialWatch.release();
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
//# sourceMappingURL=endpoint-call.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-call.js","sourceRoot":"","sources":["../src/endpoint-call.ts"],"names":[],"mappings":"AAAA;wFACwF;AACxF,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,aAAa,EAAE,oBAAoB,EAAE,kBAAkB,EAA8C,MAAM,wBAAwB,CAAC;AAChN,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,aAAa,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,eAAe,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,eAAe,EAAE,iBAAiB,EAA6O,MAAM,wBAAwB,CAAC;AA4Cjd,MAAM,KAAK,GAAG,GAAW,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,uCAAuC;AAErI,SAAS,aAAa,CAAC,CAAe;IACpC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC/C,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;QAC3C,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC;IAClF,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;AAC3C,CAAC;AAED,SAAS,UAAU,CAAC,CAAe;IACjC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAC;IACxC,OAAO;QACL,KAAK,EAAE,kBAAkB,CAAC,CAAC,CAAC,KAAK,EAAE,cAAc,CAAC;QAClD,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,YAAY,EAAE,oBAAoB,CAAC,CAAC,CAAC,YAAY,EAAE,qBAAqB,CAAC;QACzE,GAAG,CAAC,CAAC,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,KAAa,EACb,KAAc,EACd,EAAY,EACZ,IAAqD;IAErD,8FAA8F;IAC9F,qFAAqF;IACrF,gGAAgG;IAChG,+FAA+F;IAC/F,oGAAoG;IACpG,IAAI,IAAyC,CAAC;IAC9C,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,CAAC,CAA4B,CAAC;IAC5G,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,gGAAgG;QAChG,sGAAsG;QACtG,MAAM,IAAI,eAAe,CAAC,aAAa,EAAE,gCAAgC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,cAAc,CAAC,CAAC;IACpJ,CAAC;IACD,IAAI,CAAC;QACH,eAAe,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,CAAC,CAAC,YAAY,eAAe,CAAC;YAAE,MAAM,CAAC,CAAC;QAC7C,+FAA+F;QAC/F,oFAAoF;QACpF,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,kBAAkB,CAAC;QACpF,MAAM,IAAI,eAAe,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACnJ,CAAC;IACD,8FAA8F;IAC9F,2FAA2F;IAC3F,iEAAiE;IACjE,IAAI,EAAE,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC1B,IAAI,EAAE,CAAC,OAAO,KAAK,UAAU;YAC3B,MAAM,IAAI,eAAe,CAAC,aAAa,EAAE,6EAA6E,CAAC,CAAC;QAC1H,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK;YACtB,MAAM,IAAI,eAAe,CAAC,aAAa,EAAE,kGAAkG,CAAC,CAAC;QAC/I,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,EAAE,CAAC,IAAI,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU;YAClE,MAAM,IAAI,eAAe,CAAC,aAAa,EAAE,oBAAoB,EAAE,CAAC,IAAI,CAAC,UAAU,iDAAiD,KAAK,CAAC,UAAU,eAAe,CAAC,CAAC;IACrK,CAAC;IACD,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;IAClB,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE;QACtC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO;QACjD,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1D,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC;KAC5B,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IAC7F,MAAM,GAAG,GAAoB;QAC3B,CAAC,EAAE,CAAC;QACJ,EAAE,EAAE,SAAS;QACb,EAAE,EAAE;YACF,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,OAAO,EAAE,EAAE,CAAC,OAAO;YACnB,WAAW,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,aAAa;YAC5C,YAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa;SAC/C;QACD,KAAK,EAAE,WAAW,EAAE,sEAAsE;QAC1F,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,GAAG,CAAC,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpF,GAAG,CAAC,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,oBAAoB,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,iBAAiB,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7I,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvC,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE;QACvF,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,GAAG,CAAC,EAAE,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,GAAG,CAAC,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACpD,CAAC;IACF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;AACxF,CAAC;AAED,mGAAmG;AACnG,qGAAqG;AACrG,kFAAkF;AAClF,MAAM,YAAY,GAAG,aAAa,CAAC;AACnC,MAAM,UAAU,cAAc,CAAC,UAAkB,EAAE,IAAI,GAAG,YAAY;IACpE,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,IAAI,UAAU,IAAI,CAAC,IAAI,UAAU,GAAG,YAAY;QACnF,MAAM,IAAI,eAAe,CAAC,aAAa,EAAE,GAAG,IAAI,IAAI,UAAU,qDAAqD,YAAY,6EAA6E,CAAC,CAAC;IAChN,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;oEAKoE;AACpE,SAAS,iBAAiB,CAAC,GAAQ;IACjC,MAAM,CAAC,GAAG,GAAG,CAAC,OAAgE,CAAC;IAC/E,OAAO,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC;AAC7D,CAAC;AAUD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,EAAkB,EAClB,KAAa,EACb,QAAgB,EAChB,UAAkB,EAClB,MAAgB,EAChB,IAA4B;IAE5B,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,oBAAoB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC3D,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC;IAClB,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IACvI,MAAM,GAAG,GAAG;QACV,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,WAAW;QAC5E,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,EAAE;KAC1F,CAAC;IACF,8FAA8F;IAC9F,iGAAiG;IACjG,0EAA0E;IAC1E,MAAM,aAAa,GAAG,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC5D,2FAA2F;IAC3F,+FAA+F;IAC/F,+FAA+F;IAC/F,MAAM,WAAW,GAAG,sBAAsB,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,CAAC,mBAAmB,EACnG,0BAA0B,QAAQ,IAAI,GAAG,0GAA0G,OAAO,4BAA4B,GAAG,oFAAoF,CAAC,EAAE,OAAO,CAAC,CAAC;IAC3R,IAAI,GAA6B,CAAC;IAClC,IAAI,KAAgD,CAAC;IACrD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,OAAO,CAAqB,CAAC,OAAO,EAAE,EAAE;YAC1D,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,UAAU,CAAC,CAAC;YACzD,0FAA0F;YAC1F,6FAA6F;YAC7F,6FAA6F;YAC7F,0FAA0F;YAC1F,8FAA8F;YAC9F,2FAA2F;YAC3F,2FAA2F;YAC3F,wFAAwF;YACxF,0FAA0F;YAC1F,0DAA0D;YAC1D,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;YAChB,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE;gBAChC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,KAAK,IAAI,IAAI,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;aAClG,CAAC,CAAC;YACH,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;QAC/F,CAAC,CAAC,CAAC;QACH,+FAA+F;QAC/F,4FAA4F;QAC5F,6FAA6F;QAC7F,0BAA0B;QAC1B,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3D,CAAC;YAAS,CAAC;QACT,GAAG,EAAE,WAAW,EAAE,CAAC;QACnB,IAAI,KAAK,KAAK,SAAS;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC7C,WAAW,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAED;8FAC8F;AAC9F,MAAM,CAAC,KAAK,UAAU,WAAW,CAAI,IAA0B,EAAE,EAAU,EAAE,IAAY,EAAE,OAAyB;IAClH,IAAI,CAA4C,CAAC;IACjD,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC;YACxB,CAAC,KAAK,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE;YACtB,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,mBAAmB,EAAE,GAAG,IAAI,8BAA8B,EAAE,uBAAuB,EAAE,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;SAC5L,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QAAC,IAAI,CAAC,KAAK,SAAS;YAAE,YAAY,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;AACrD,CAAC;AAED;2FAC2F;AAC3F,MAAM,gBAAgB,GAAG,CAAC,EAAY,EAAsB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAC/K;6FAC6F;AAC7F,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EAAY,EAA8B,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,uBAAuB,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;AAEhK;iGACiG;AACjG,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,MAAgB,EAAE,CAAS;IACxE,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,gBAAgB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AAC3H,CAAC;AAED;;+FAE+F;AAC/F,SAAS,mBAAmB,CAAC,KAAa,EAAE,MAAgB,EAAE,CAAS;IACrE,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,sBAAsB,gBAAgB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;AACjI,CAAC;AASD;;;;;;;;;;;;;;;6CAe6C;AAC7C,SAAS,iBAAiB,CACxB,EAAY,EACZ,SAAgD,EAChD,IAAY,EACZ,SAA8B,EAC9B,IAAoB;IAEpB,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC,QAAQ,aAAa,SAAS,CAAC,UAAU,EAAE,CAAC;IAClE,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC;IACrC,MAAM,SAAS,GAAG,SAAS,KAAK,MAAM;QACpC,CAAC,CAAC,CAAC,KAAK;YACN,CAAC,CAAC,GAAG,GAAG,sBAAsB,SAAS,CAAC,KAAK,kDAAkD,IAAI,sIAAsI;YACzO,CAAC,CAAC,GAAG,GAAG,sBAAsB,SAAS,CAAC,KAAK,kDAAkD,IAAI,gFAAgF,CAAC;QACtL,CAAC,CAAC,CAAC,KAAK;YACN,CAAC,CAAC,GAAG,GAAG,sBAAsB,SAAS,CAAC,KAAK,0DAA0D,IAAI,gKAAgK;YAC3Q,CAAC,CAAC,GAAG,GAAG,sBAAsB,SAAS,CAAC,KAAK,0DAA0D,IAAI,gFAAgF,CAAC,CAAC;IACjM,MAAM,MAAM,GAA6B;QACvC,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,CAAC,UAAU;QACxG,GAAG,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,aAAa,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,KAAK,MAAM;KACpF,CAAC;IACF,OAAO,IAAI,eAAe,CAAC,SAAS,EAClC,GAAG,SAAS,sDAAsD,SAAS,CAAC,UAAU,iDAAiD,EAAE,CAAC,OAAO,0JAA0J,EAC3S,CAAC,MAAM,CAAC,CAAC,CAAC;AACd,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAa,EAAE,OAAe,EAAE,IAAgB,EAAE,SAAiB,EAAE,EAAY,EAAE,MAAgD;IACtK,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO;QACrC,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,2EAA2E,OAAO,EAAE,CAAC,CAAC;IAC9H,sFAAsF;IACtF,mGAAmG;IACnG,kGAAkG;IAClG,iGAAiG;IACjG,mGAAmG;IACnG,IAAI,MAAM,CAAC,QAAQ,KAAK,EAAE,CAAC,QAAQ;QACjC,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,mBAAmB,MAAM,CAAC,QAAQ,kCAAkC,EAAE,CAAC,QAAQ,mGAAmG,CAAC,CAAC;IAC5N,IAAI,MAAM,EAAE,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,UAAU;QAC7E,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,mBAAmB,MAAM,CAAC,UAAU,oCAAoC,MAAM,CAAC,UAAU,eAAe,CAAC,CAAC;IAClJ,IAAI,MAAM,EAAE,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK;QAC9D,MAAM,iBAAiB,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpH,gGAAgG;IAChG,iGAAiG;IACjG,4BAA4B;IAC5B,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAAC,CAAC;IAC7D,OAAO,CAAC,EAAE,CAAC;QAAC,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,oDAAoD,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,6GAA6G,CAAC,CAAC;IAAC,CAAC;IACjQ,MAAM,KAAK,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,EAAE,KAAK,SAAS;QACxB,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,aAAa,KAAK,CAAC,EAAE,mCAAmC,SAAS,wCAAwC,CAAC,CAAC;IACnJ,yFAAyF;IACzF,6FAA6F;IAC7F,IAAI,KAAK,CAAC,EAAE;QAAE,iBAAiB,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACzE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;AACjH,CAAC;AAED,oGAAoG;AAEpG;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,EAAkB,EAClB,KAAa,EACb,KAA4E,EAC5E,EAAY,EACZ,IAA4J;IAE5J,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;IAC9B,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACnD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS;QACzD,MAAM,IAAI,eAAe,CAAC,aAAa,EAAE,6MAA6M,CAAC,CAAC;IAC1P,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACxG,iGAAiG;IACjG,kGAAkG;IAClG,oGAAoG;IACpG,wFAAwF;IACxF,MAAM,aAAa,GAAG,mBAAmB,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,IAAI,GAA6B,CAAC;IAClC,IAAI,KAAgD,CAAC;IACrD,IAAI,WAAoE,CAAC;IACzE,IAAI,OAAiC,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QACjD,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,uDAAuD,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;QACtK,IAAI,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,0FAA0F;QAC1F,6FAA6F;QAC7F,gGAAgG;QAChG,WAAW,GAAG,sBAAsB,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,CAAC,mBAAmB,EACjG,gBAAgB,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,0GAA0G,GAAG,CAAC,OAAO,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,2BAA2B,KAAK,CAAC,UAAU,kGAAkG,CAAC,CAAC,CAAC,EAAE,oFAAoF,EAAE,SAAS,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;QACxc,MAAM,OAAO,GAAG,IAAI,OAAO,CAAwC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrF,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE;gBAC3D,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;oBACrB,IAAI,GAAG,EAAE,CAAC;wBAAC,MAAM,CAAC,IAAI,eAAe,CAAC,aAAa,EAAE,2CAA2C,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;wBAAC,OAAO;oBAAC,CAAC;oBAC1H,6FAA6F;oBAC7F,4FAA4F;oBAC5F,0FAA0F;oBAC1F,oFAAoF;oBACpF,8FAA8F;oBAC9F,2BAA2B;oBAC3B,IAAI,GAAG,CAAC,OAAO,KAAK,aAAa,EAAE,CAAC;wBAClC,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;4BAAC,MAAM,CAAC,IAAI,eAAe,CAAC,aAAa,EAAE,oBAAoB,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,cAAc,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;4BAAC,OAAO;wBAAC,CAAC;wBACxK,MAAM,CAAC,IAAI,eAAe,CAAC,UAAU,EAAE,qEAAqE,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,6DAA6D,CAAC,CAAC,CAAC;wBAAC,OAAO;oBAC/M,CAAC;oBACD,OAAO,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;gBACpD,CAAC;aACF,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;YAC9B,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,mBAAmB,EAAE,eAAe,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,eAAe,UAAU,uBAAuB,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjQ,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;QAClF,MAAM,UAAU,GAAG,oBAAoB,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;QACjG,6FAA6F;QAC7F,0FAA0F;QAC1F,0FAA0F;QAC1F,8FAA8F;QAC9F,8FAA8F;QAC9F,8FAA8F;QAC9F,4BAA4B;QAC5B,yFAAyF;QACzF,gGAAgG;QAChG,8FAA8F;QAC9F,8FAA8F;QAC9F,4CAA4C;QAC5C,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/E,IAAI,EAAE,CAAC,IAAI,KAAK,SAAS;gBACvB,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,gEAAgE,CAAC,CAAC;YACtI,MAAM,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC;YAC/B,IAAI,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,KAAK,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK;gBAClE,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,aAAa,CAAC,CAAC,UAAU,YAAY,EAAE,CAAC,OAAO,4FAA4F,EAAE,CAAC,IAAI,CAAC,UAAU,UAAU,EAAE,CAAC,IAAI,CAAC,KAAK,wEAAwE,CAAC,CAAC;YACpT,+FAA+F;YAC/F,6FAA6F;YAC7F,8FAA8F;YAC9F,+FAA+F;YAC/F,8FAA8F;YAC9F,4FAA4F;YAC5F,wFAAwF;YACxF,uEAAuE;YACvE,MAAM,OAAO,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,eAAe,CAAoC,CAAC;YACnI,IAAI,OAAO,KAAK,SAAS;gBACvB,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,qBAAqB,eAAe,oDAAoD,CAAC,CAAC;YAC9J,IAAI,OAAO,CAAC,OAAO,CAAC,UAAU,KAAK,EAAE,CAAC,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK;gBAC9F,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,YAAY,EAAE,CAAC,OAAO,iBAAiB,OAAO,CAAC,OAAO,CAAC,UAAU,UAAU,OAAO,CAAC,OAAO,CAAC,KAAK,8BAA8B,EAAE,CAAC,IAAI,CAAC,UAAU,UAAU,EAAE,CAAC,IAAI,CAAC,KAAK,qFAAqF,CAAC,CAAC;YACpT,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;gBACpF,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,YAAY,EAAE,CAAC,OAAO,6BAA6B,OAAO,CAAC,QAAQ,CAAC,UAAU,UAAU,OAAO,CAAC,QAAQ,CAAC,KAAK,4CAA4C,CAAC,CAAC,UAAU,UAAU,CAAC,CAAC,KAAK,uEAAuE,CAAC,CAAC;YACtT,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACzB,oHAAoH;YACpH,gGAAgG;YAChG,+FAA+F;YAC/F,4FAA4F;YAC5F,6FAA6F;YAC7F,8FAA8F;YAC9F,+FAA+F;YAC/F,MAAM,SAAS,GAAG,UAAU,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC;YACtD,IAAI,SAAS,IAAI,CAAC;gBAAE,MAAM,IAAI,eAAe,CAAC,mBAAmB,EAAE,oEAAoE,UAAU,gBAAgB,CAAC,CAAC;YACnK,6FAA6F;YAC7F,2FAA2F;YAC3F,yFAAyF;YACzF,uFAAuF;YACvF,IAAI,GAAW,CAAC;YAChB,IAAI,CAAC;gBACH,GAAG,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,YAAa,CAAC,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,iCAAiC,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAC9J,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,YAAY,eAAe;oBAAE,MAAM,CAAC,CAAC,CAAC,sEAAsE;gBACjH,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,oCAAoC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,oEAAoE,CAAC,CAAC;YAC5L,CAAC;YACD,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC;gBACvC,MAAM,IAAI,eAAe,CAAC,qBAAqB,EAAE,mEAAmE,MAAM,CAAC,GAAG,CAAC,mHAAmH,CAAC,CAAC;YACtP,IAAI,UAAU,CAAC,SAAS,CAAC,KAAK,KAAK,GAAG;gBACpC,MAAM,iBAAiB,CAAC,EAAE,EAAE,UAAU,CAAC,SAAS,EAAE,GAAG,EAAE,IAAI,CAAC,iBAAiB,IAAI,UAAU,EAAE,KAAK,CAAC,CAAC;QACxG,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,GAAG,EAAE,WAAW,EAAE,CAAC;QACnB,IAAI,KAAK,KAAK,SAAS;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC7C,WAAW,EAAE,OAAO,EAAE,CAAC;QACvB,IAAI,OAAO;YAAE,IAAI,CAAC,MAAM,EAAE,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,oGAAoG;AAEpG;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,EAAkB,EAClB,KAAa,EACb,KAAc,EACd,EAAY,EACZ,OAAgC,EAAE;IAElC,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;QACvD,MAAM,IAAI,eAAe,CAAC,aAAa,EAAE,gNAAgN,CAAC,CAAC;IAC7P,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;QACzC,aAAa,EAAE,KAAK;QACpB,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,cAAc,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1F,CAAC,CAAC;IACH,2FAA2F;IAC3F,+FAA+F;IAC/F,0FAA0F;IAC1F,2FAA2F;IAC3F,6FAA6F;IAC7F,6FAA6F;IAC7F,6FAA6F;IAC7F,8FAA8F;IAC9F,yFAAyF;IACzF,gFAAgF;IAChF,MAAM,WAAW,GAAG,sBAAsB,CAAC,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,CAAC,mBAAmB,EACvG,gBAAgB,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,OAAO,oGAAoG,GAAG,CAAC,OAAO,qFAAqF,CAAC,EAAE,MAAM,CAAC,CAAC;IAC1P,IAAI,CAAC;QACH,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,OAAO,CAAC,IAAI,CAAC;YACjB,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;YAC5E,WAAW,CAAC,MAAM;SACnB,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,WAAW,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
|