@cotal-ai/core 0.66.1 → 0.67.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/auth-provider.d.ts +16 -9
- package/dist/auth-provider.d.ts.map +1 -1
- package/dist/backup-config.d.ts +1 -1
- package/dist/backup-config.d.ts.map +1 -1
- package/dist/backup-config.js +6 -2
- package/dist/backup-config.js.map +1 -1
- package/dist/connector.d.ts +24 -0
- package/dist/connector.d.ts.map +1 -1
- package/dist/connector.js.map +1 -1
- package/dist/endpoint-action.d.ts.map +1 -1
- package/dist/endpoint-action.js +9 -10
- package/dist/endpoint-action.js.map +1 -1
- package/dist/endpoint-envelope.d.ts.map +1 -1
- package/dist/endpoint-envelope.js +1 -3
- package/dist/endpoint-envelope.js.map +1 -1
- package/dist/endpoint-grants.d.ts +1 -1
- package/dist/endpoint-grants.d.ts.map +1 -1
- package/dist/endpoint-grants.js +1 -0
- package/dist/endpoint-grants.js.map +1 -1
- package/dist/endpoint-invoke.d.ts +6 -0
- package/dist/endpoint-invoke.d.ts.map +1 -1
- package/dist/endpoint-invoke.js +6 -0
- package/dist/endpoint-invoke.js.map +1 -1
- package/dist/endpoint-reconcile.js +2 -2
- package/dist/endpoint-reconcile.js.map +1 -1
- package/dist/endpoint-serve-kv.d.ts.map +1 -1
- package/dist/endpoint-serve-kv.js +29 -44
- package/dist/endpoint-serve-kv.js.map +1 -1
- package/dist/endpoint-service.d.ts +3 -10
- package/dist/endpoint-service.d.ts.map +1 -1
- package/dist/endpoint-service.js +3 -3
- package/dist/endpoint-service.js.map +1 -1
- package/dist/endpoint.d.ts +8 -8
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +19 -20
- package/dist/endpoint.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lifecycle-saga.d.ts.map +1 -1
- package/dist/lifecycle-saga.js +24 -24
- package/dist/lifecycle-saga.js.map +1 -1
- package/dist/lifecycle-state.d.ts +44 -36
- package/dist/lifecycle-state.d.ts.map +1 -1
- package/dist/lifecycle-state.js.map +1 -1
- package/dist/provision.d.ts +14 -1
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +27 -4
- package/dist/provision.js.map +1 -1
- package/dist/remote-manager-authority.d.ts +13 -1
- package/dist/remote-manager-authority.d.ts.map +1 -1
- package/dist/remote-manager-authority.js +24 -17
- package/dist/remote-manager-authority.js.map +1 -1
- package/dist/spaces.d.ts +5 -1
- package/dist/spaces.d.ts.map +1 -1
- package/dist/spaces.js +50 -15
- package/dist/spaces.js.map +1 -1
- package/dist/subjects.d.ts +9 -0
- package/dist/subjects.d.ts.map +1 -1
- package/dist/subjects.js +14 -0
- package/dist/subjects.js.map +1 -1
- package/dist/transfer.d.ts +110 -0
- package/dist/transfer.d.ts.map +1 -0
- package/dist/transfer.js +325 -0
- package/dist/transfer.js.map +1 -0
- package/package.json +1 -1
package/dist/endpoint.js
CHANGED
|
@@ -8,7 +8,7 @@ import { credsClaims, credsFingerprint, credsRenewalDelayMs, idFromCreds } from
|
|
|
8
8
|
import { requireBrokerFloor } from "./broker-floor.js";
|
|
9
9
|
import { inspectCredHealth } from "./provision.js";
|
|
10
10
|
import { parseSecretStoreIdentity, } from "./secret-store.js";
|
|
11
|
-
import { resolveService, invokeCommand, submitAndFollowGoal } from "./endpoint-invoke.js";
|
|
11
|
+
import { BIND_SPLIT_REISSUES, resolveService, invokeCommand, submitAndFollowGoal } from "./endpoint-invoke.js";
|
|
12
12
|
import { EpEnvelopeError, respondedButUnbound, replyRefusedBeforeEffect, EP_BIND_REFUSED } from "./endpoint-envelope.js";
|
|
13
13
|
import { isRepeatSafeCommand } from "./endpoint-grants.js";
|
|
14
14
|
import { assertIdToken, assertGeneration } from "./endpoint-subjects.js";
|
|
@@ -98,15 +98,19 @@ const READ_HISTORY_DEFAULT_LIMIT = 100;
|
|
|
98
98
|
* request pull a channel's whole retained set through it. Clamped, not refused — a UI asking for
|
|
99
99
|
* more than a page should get a page, and `complete: false` already tells it more remains. */
|
|
100
100
|
const READ_HISTORY_MAX_LIMIT = 200;
|
|
101
|
-
/** The NEWEST prefix-from-the-end of `items` whose serialized
|
|
102
|
-
* preserved. Returns `[]` when not even the newest single message fits — the caller
|
|
103
|
-
* loudly there rather than serve an empty page, which would read as "no history".
|
|
101
|
+
/** The NEWEST prefix-from-the-end of `items` whose serialized `readHistory` reply fits `budget`
|
|
102
|
+
* bytes, order preserved. Returns `[]` when not even the newest single message fits — the caller
|
|
103
|
+
* must refuse loudly there rather than serve an empty page, which would read as "no history".
|
|
104
|
+
*
|
|
105
|
+
* The `ControlReply` around the items rides the same NATS message, so it is charged too: items
|
|
106
|
+
* that fit on their own can still make a reply the broker refuses.
|
|
104
107
|
*
|
|
105
108
|
* Measured in ENCODED bytes, not `string.length`: a page of multi-byte text would otherwise be
|
|
106
109
|
* undercounted and still overflow the broker. Same discipline as `assertFactFits`. */
|
|
107
110
|
export function fitHistoryPage(items, budget) {
|
|
108
111
|
const enc = new TextEncoder();
|
|
109
|
-
|
|
112
|
+
// The reply with no items, at its longer `complete` value.
|
|
113
|
+
let used = enc.encode(JSON.stringify({ ok: true, data: { items: [], complete: false } })).length;
|
|
110
114
|
let first = items.length; // index of the oldest kept item
|
|
111
115
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
112
116
|
const size = enc.encode(JSON.stringify(items[i])).length + 1; // + the `,` separator
|
|
@@ -2017,7 +2021,8 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
2017
2021
|
* and only knowing someone answered:
|
|
2018
2022
|
* - the RESPONDER fenced it on the request's `bind` (§13.2, an `ok:false` reply marked
|
|
2019
2023
|
* {@link replyRefusedBeforeEffect}): the command did not run, so the bind is dropped and the
|
|
2020
|
-
* call re-issued
|
|
2024
|
+
* call re-issued for any command, up to {@link BIND_SPLIT_REISSUES} times while each re-issue
|
|
2025
|
+
* is refused the same way. If a re-issue cannot be resolved, the refusal
|
|
2021
2026
|
* surfaces — still saying the command did not run — naming the resolve failure as why the
|
|
2022
2027
|
* repair could not be attempted.
|
|
2023
2028
|
* - this CLIENT caught it on the reply ({@link respondedButUnbound}: a different instance,
|
|
@@ -2066,7 +2071,7 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
2066
2071
|
const doInvoke = async (signal = opts.signal) => {
|
|
2067
2072
|
signal?.throwIfAborted();
|
|
2068
2073
|
try {
|
|
2069
|
-
|
|
2074
|
+
let r = await invokeResolved(await resolve(signal), signal);
|
|
2070
2075
|
// THE RESPONDER FENCED IT (§13.2 `ai.cotal.ep.bind-refused`): a class member saw the call
|
|
2071
2076
|
// was bound to a different incarnation and refused BEFORE running the command.
|
|
2072
2077
|
//
|
|
@@ -2075,9 +2080,10 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
2075
2080
|
// otherwise keep its stale bind and meet the same refusal forever.
|
|
2076
2081
|
//
|
|
2077
2082
|
// The re-issue is NOT gated on {@link isRepeatSafeCommand}: the responder states the command
|
|
2078
|
-
// did not run, so
|
|
2079
|
-
//
|
|
2080
|
-
|
|
2083
|
+
// did not run, so each re-issue is a FIRST attempt, not a second. It repeats up to the bound
|
|
2084
|
+
// the CLI uses, because the re-issue rides the same class queue and splits again at the same
|
|
2085
|
+
// rate; repairing once left a quarter of all calls in a two-manager space failing (#443).
|
|
2086
|
+
for (let reissues = 0; reissues < BIND_SPLIT_REISSUES && r.reply.ok === false && replyRefusedBeforeEffect(r.reply.error); reissues++) {
|
|
2081
2087
|
// Counted before it is repaired: a recovery that leaves no trace takes the split rate with it.
|
|
2082
2088
|
this.splitsRecovered++;
|
|
2083
2089
|
// `boundTo` is the other half of `servedBy`: who the handle THOUGHT it was talking to,
|
|
@@ -2127,7 +2133,7 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
2127
2133
|
// re-issue never went out. Prose is for the reader; this is for the machine.
|
|
2128
2134
|
"not-executed");
|
|
2129
2135
|
}
|
|
2130
|
-
|
|
2136
|
+
r = await invokeResolved(reissueTarget, signal);
|
|
2131
2137
|
}
|
|
2132
2138
|
return r;
|
|
2133
2139
|
}
|
|
@@ -4346,23 +4352,16 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
4346
4352
|
// So bound by BYTES too, keeping the NEWEST that fit — which needs no new vocabulary, because
|
|
4347
4353
|
// `complete: false` already means "older history remains behind this page". Trimming here is the
|
|
4348
4354
|
// documented truncation signal doing its job, not a silent degradation.
|
|
4349
|
-
const fitted = fitHistoryPage(wanted, this.
|
|
4355
|
+
const fitted = fitHistoryPage(wanted, this.maxPayload);
|
|
4350
4356
|
// `wanted.length > 0` is load-bearing, not defensive: an EMPTY channel also fits nothing, and
|
|
4351
4357
|
// without this guard a channel nobody has posted to was refused with "the newest message exceeds
|
|
4352
4358
|
// the payload budget" — a confident, entirely wrong explanation for a legitimately empty result.
|
|
4353
4359
|
// Genuine emptiness is `{ items: [], complete: true }`; only a message too large to ever send is
|
|
4354
4360
|
// the error.
|
|
4355
4361
|
if (wanted.length > 0 && fitted.length === 0)
|
|
4356
|
-
return { ok: false, error: `readHistory: the newest message on "${channel}" alone exceeds the broker payload budget (${this.
|
|
4362
|
+
return { ok: false, error: `readHistory: the newest message on "${channel}" alone exceeds the broker payload budget (${this.maxPayload} bytes) - refused loudly rather than served as an empty page` };
|
|
4357
4363
|
return { ok: true, data: { items: fitted, complete: reachedStart && fitted.length === wanted.length } };
|
|
4358
4364
|
}
|
|
4359
|
-
/** Bytes a control reply may occupy: the broker's `max_payload` less headroom for the `ControlReply`
|
|
4360
|
-
* envelope wrapped around the items. Read from the live server info rather than assumed, since an
|
|
4361
|
-
* operator can raise or lower it. */
|
|
4362
|
-
payloadBudget() {
|
|
4363
|
-
const max = this.nc?.info?.max_payload ?? 1_048_576;
|
|
4364
|
-
return Math.max(1, Math.floor(max * 0.9));
|
|
4365
|
-
}
|
|
4366
4365
|
/** Stop serving Plane-3 WITHOUT tearing down the connection, so a daemon that has just learned its
|
|
4367
4366
|
* lease may no longer be its own can stop acting on the shard while it finds out for certain.
|
|
4368
4367
|
*
|