@cotal-ai/core 0.70.0 → 0.71.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 +16 -2
- package/dist/agent-file.js.map +1 -1
- package/dist/auth-provider.d.ts +9 -1
- package/dist/auth-provider.d.ts.map +1 -1
- package/dist/auth-provider.js +10 -0
- package/dist/auth-provider.js.map +1 -1
- package/dist/channels.js +1 -1
- package/dist/channels.js.map +1 -1
- package/dist/connector-setup.d.ts +9 -5
- package/dist/connector-setup.d.ts.map +1 -1
- package/dist/connector.d.ts +2 -1
- package/dist/connector.d.ts.map +1 -1
- package/dist/connector.js.map +1 -1
- package/dist/endpoint-action.d.ts +3 -0
- package/dist/endpoint-action.d.ts.map +1 -1
- package/dist/endpoint-action.js +8 -6
- package/dist/endpoint-action.js.map +1 -1
- package/dist/endpoint-records.d.ts +2 -1
- package/dist/endpoint-records.d.ts.map +1 -1
- package/dist/endpoint-records.js +1 -1
- package/dist/endpoint-records.js.map +1 -1
- package/dist/endpoint.d.ts +3 -1
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +18 -25
- 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/kv-scan.d.ts.map +1 -1
- package/dist/kv-scan.js +1 -6
- package/dist/kv-scan.js.map +1 -1
- package/dist/provision.js +1 -1
- package/dist/provision.js.map +1 -1
- package/dist/run-driver-grants.d.ts.map +1 -1
- package/dist/run-driver-grants.js +5 -1
- package/dist/run-driver-grants.js.map +1 -1
- package/dist/secret-fs.d.ts +4 -3
- package/dist/secret-fs.d.ts.map +1 -1
- package/dist/secret-fs.js +10 -11
- package/dist/secret-fs.js.map +1 -1
- package/dist/startup-confirm.d.ts +20 -0
- package/dist/startup-confirm.d.ts.map +1 -0
- package/dist/startup-confirm.js +49 -0
- package/dist/startup-confirm.js.map +1 -0
- package/dist/streams.d.ts +2 -2
- package/dist/streams.js +2 -2
- package/dist/subjects.d.ts +6 -7
- package/dist/subjects.d.ts.map +1 -1
- package/dist/subjects.js +20 -10
- package/dist/subjects.js.map +1 -1
- package/package.json +5 -1
package/dist/endpoint.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from "node:events";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { createConnection } from "node:net";
|
|
4
|
-
import { connect, credsAuthenticator, headers, tokenAuthenticator, nanos, AuthorizationError, PermissionViolationError, UserAuthenticationExpiredError, NoRespondersError, RequestError, } from "@nats-io/transport-node";
|
|
4
|
+
import { connect, credsAuthenticator, headers, tokenAuthenticator, nanos, AuthorizationError, PermissionViolationError, UserAuthenticationExpiredError, NoRespondersError, RequestError, TimeoutError, ClosedConnectionError, } from "@nats-io/transport-node";
|
|
5
5
|
import { wsconnect } from "@nats-io/nats-core";
|
|
6
6
|
import { parseLivenessAnswer, responderFromLease, responderFromProbe, isLivenessPlane, LIVENESS_PLANES, } from "./liveness.js";
|
|
7
7
|
import { credsClaims, credsFingerprint, credsRenewalDelayMs, idFromCreds } from "./identity.js";
|
|
@@ -26,7 +26,7 @@ import { openMembersRegistry, commitMember, tombstoneMember, activateMember, rea
|
|
|
26
26
|
import { openAclRegistry, readAcl, readAclForAlias, aclRetired, AmbiguousAclAlias, commitAcl as writeAclRecord, reissueAcl as writeAclReissue } from "./acls.js";
|
|
27
27
|
import { openDeliveryRegistry } from "./lease.js";
|
|
28
28
|
import { openChannelRegistry, effectiveReplay, effectiveReplayWindowMs, effectiveDeliveryClass, readChannelConfig, readChannelDefaults, } from "./channels.js";
|
|
29
|
-
import { anycastSubject, CHANNEL_DEFAULTS_KEY, chatStream, chatHistDurable, chatSubject, controlServiceSubject, livenessSubject, livenessServeFilter, CONTROL_DELIVERY, CONTROL_DELIVERY_ADMIN, dmStream, dmDurable, dlvStream, dlvDurable, dlvSubject, dinboxSubject, inboxStream, parseDinboxPrincipal, FANOUT_DURABLE, INBOX_READER_DURABLE, leaseKey, managerBucket, MANAGER_LEASE_KEY, MANAGER_RENEWAL_LEASE_KEY, managerLeaseKey, chatWildcard, assertValidChannel, channelInAllow, isConcreteChannel, normalizeMentions, parseSubject, isPrincipalOwnerToken, assertInboxConnId, presenceBucket, membershipBucket, MEMBERSHIP_FEED_KEY, principalKey, parsePrincipalKey, assertLifecycleToken, mintLifecycleUid, lifecycleNameKey, DEV_OWNER, spacePrefix, spaceWildcard, subjectMatches, taskStream, taskDurable, token, unicastSubject, unicastRecvFilter, } from "./subjects.js";
|
|
29
|
+
import { anycastSubject, assertValidRole, CHANNEL_DEFAULTS_KEY, chatStream, chatHistDurable, chatSubject, controlServiceSubject, livenessSubject, livenessServeFilter, CONTROL_DELIVERY, CONTROL_DELIVERY_ADMIN, dmStream, dmDurable, dlvStream, dlvDurable, dlvSubject, dinboxSubject, inboxStream, parseDinboxPrincipal, FANOUT_DURABLE, INBOX_READER_DURABLE, leaseKey, managerBucket, MANAGER_LEASE_KEY, MANAGER_RENEWAL_LEASE_KEY, managerLeaseKey, chatWildcard, assertValidChannel, channelInAllow, isConcreteChannel, normalizeMentions, parseSubject, isPrincipalOwnerToken, assertInboxConnId, presenceBucket, membershipBucket, MEMBERSHIP_FEED_KEY, principalKey, parsePrincipalKey, assertLifecycleToken, mintLifecycleUid, lifecycleNameKey, DEV_OWNER, spacePrefix, spaceWildcard, subjectMatches, taskStream, taskDurable, token, unicastSubject, unicastRecvFilter, } from "./subjects.js";
|
|
30
30
|
export const DEFAULT_SERVER = "nats://127.0.0.1:4222";
|
|
31
31
|
const PLANE3_FRAME_HEADER = "Cotal-Delivery-Frame";
|
|
32
32
|
/** Space joined when none is given on the CLI (the `cotal-<space>` cmux tab, etc.). */
|
|
@@ -403,8 +403,11 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
403
403
|
this.space = opts.space;
|
|
404
404
|
// A display name is the client-side handle a peer is addressed by; reject the reserved `/`
|
|
405
405
|
// (the future owner/name separator) and surrounding whitespace at the one identity choke
|
|
406
|
-
// point every join/spawn path flows through.
|
|
406
|
+
// point every join/spawn path flows through. A role is an address too, refused here before
|
|
407
|
+
// presence can advertise it.
|
|
407
408
|
assertValidName(opts.card.name);
|
|
409
|
+
if (opts.card.role !== undefined)
|
|
410
|
+
assertValidRole(opts.card.role);
|
|
408
411
|
// Auth mode is EITHER static creds (dev/no-login) OR a user bearer (login → callout) — never both.
|
|
409
412
|
if (opts.bearer) {
|
|
410
413
|
if (opts.creds || opts.token || opts.user || opts.pass)
|
|
@@ -1842,6 +1845,8 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
1842
1845
|
async anycastAttributed(service, text, opts) {
|
|
1843
1846
|
if (!this.js)
|
|
1844
1847
|
throw new Error(this.notLiveMsg());
|
|
1848
|
+
// The subject builder admits `*` for allow rules; a publish needs one concrete role.
|
|
1849
|
+
assertValidRole(service);
|
|
1845
1850
|
const msg = {
|
|
1846
1851
|
id: randomUUID(),
|
|
1847
1852
|
ts: Date.now(),
|
|
@@ -2785,8 +2790,8 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
2785
2790
|
watch.consumerName = undefined;
|
|
2786
2791
|
}
|
|
2787
2792
|
else {
|
|
2788
|
-
const closedEpoch = err
|
|
2789
|
-
const timeout =
|
|
2793
|
+
const closedEpoch = err instanceof ClosedConnectionError;
|
|
2794
|
+
const timeout = err instanceof TimeoutError;
|
|
2790
2795
|
const dyingEpochTimeout = timeout && (this.reconnecting || !this.nc || this.nc.isClosed());
|
|
2791
2796
|
// Cleanup of an ordered consumer: a delete timeout means the broker did not answer in time,
|
|
2792
2797
|
// not that the endpoint is unusable. The broker reaps an idle/ephemeral consumer anyway.
|
|
@@ -4727,9 +4732,7 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
4727
4732
|
probeFailureOutcome(e) {
|
|
4728
4733
|
if (e instanceof AuthorizationError || e instanceof PermissionViolationError)
|
|
4729
4734
|
return "refused";
|
|
4730
|
-
|
|
4731
|
-
const msg = e?.message ?? "";
|
|
4732
|
-
if (name === "TimeoutError" || /timeout/i.test(msg))
|
|
4735
|
+
if (e instanceof TimeoutError)
|
|
4733
4736
|
return "timeout";
|
|
4734
4737
|
// Anything else is a transport or client failure: it says something about our link, not about
|
|
4735
4738
|
// the plane, so it is graded like a refusal rather than guessed at.
|
|
@@ -5472,7 +5475,9 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
5472
5475
|
await this.pump(taskStream(this.space), taskDurable(this.card.role));
|
|
5473
5476
|
}
|
|
5474
5477
|
}
|
|
5475
|
-
/** Drive one consumer: decode
|
|
5478
|
+
/** Drive one consumer: decode and hand each message to listeners with ack control. Our own sends are
|
|
5479
|
+
* delivered too: on the DM inbox and the role queue they were addressed to us, so none is an echo,
|
|
5480
|
+
* and acking one unseen on the work queue would delete the only copy of the request. */
|
|
5476
5481
|
async pump(stream, durable) {
|
|
5477
5482
|
if (!this.js)
|
|
5478
5483
|
throw new Error("endpoint not started");
|
|
@@ -5506,10 +5511,6 @@ export class CotalEndpoint extends EventEmitter {
|
|
|
5506
5511
|
`does not match subject sender ${parsed?.sender ?? "(unparseable)"}`));
|
|
5507
5512
|
continue;
|
|
5508
5513
|
}
|
|
5509
|
-
if (msg.from.id === this.card.id) {
|
|
5510
|
-
m.ack(); // our own echo — advance past it
|
|
5511
|
-
continue;
|
|
5512
|
-
}
|
|
5513
5514
|
// No-replay + dedup (chat only): drop a message at/below this channel's join watermark
|
|
5514
5515
|
// — pre-join history the New tail still carries for a *lagging* joiner (cursor behind the
|
|
5515
5516
|
// frontier), and the overlap a replay backfill already delivered. Must ack, or JetStream
|
|
@@ -7065,14 +7066,6 @@ export async function isReachable(servers = DEFAULT_SERVER, opts = {}) {
|
|
|
7065
7066
|
return e instanceof AuthorizationError || e instanceof UserAuthenticationExpiredError;
|
|
7066
7067
|
}
|
|
7067
7068
|
}
|
|
7068
|
-
/** True when `err` is a dial/consumer-op timeout rather than a real refusal — the one shared test
|
|
7069
|
-
* for "the operation ran out of its own budget", used both by {@link classifyProbeFailure} (#851:
|
|
7070
|
-
* a probe timeout must never collapse into `unreachable`, which a TLS-required target then
|
|
7071
|
-
* misreads as a trust failure) and by {@link Endpoint#disarmMembershipWatch}'s consumer-delete
|
|
7072
|
-
* cleanup, which predates it. */
|
|
7073
|
-
function isTimeoutError(err) {
|
|
7074
|
-
return err instanceof Error && (err.name === "TimeoutError" || /timeout/i.test(err.message));
|
|
7075
|
-
}
|
|
7076
7069
|
/** Like {@link isReachable}, but distinguishes "up but won't take these creds" from "nothing there".
|
|
7077
7070
|
* `spawn` needs the difference: auth-required → name the trust dir + next step; unreachable → the
|
|
7078
7071
|
* mesh is down (prune the stale entry, tell the user to `cotal up`). Pass `creds` to confirm a
|
|
@@ -7138,10 +7131,10 @@ function classifyProbeFailure(e, opts) {
|
|
|
7138
7131
|
// The broker answered but rejected these creds (so it IS up) — auth-required, not stale-auth.
|
|
7139
7132
|
if (e instanceof AuthorizationError)
|
|
7140
7133
|
return { ok: false, reason: "auth-required" };
|
|
7141
|
-
// A dial that ran out of its own budget is neither a refusal nor a dead broker — it is latency
|
|
7142
|
-
// `
|
|
7143
|
-
//
|
|
7144
|
-
if (e
|
|
7134
|
+
// A dial that ran out of its own budget is neither a refusal nor a dead broker — it is latency,
|
|
7135
|
+
// and grading it `unreachable` made a TLS-required target read as a trust failure (#851). Only
|
|
7136
|
+
// nats-core's TimeoutError means that: a peer's `-ERR` that mentions a timeout answered at once.
|
|
7137
|
+
if (e instanceof TimeoutError)
|
|
7145
7138
|
return { ok: false, reason: "timeout" };
|
|
7146
7139
|
return { ok: false, reason: "unreachable" };
|
|
7147
7140
|
}
|