@continuonai/rcan-ts 0.6.0 → 1.1.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/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,24 +17,39 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
21
31
  var index_exports = {};
22
32
  __export(index_exports, {
33
+ AUTHORITY_ERROR_CODES: () => AUTHORITY_ERROR_CODES,
23
34
  AuditChain: () => AuditChain,
24
35
  AuditError: () => AuditError,
36
+ COMPETITION_SCOPE_LEVEL: () => COMPETITION_SCOPE_LEVEL,
37
+ CONTRIBUTE_SCOPE_LEVEL: () => CONTRIBUTE_SCOPE_LEVEL,
25
38
  ClockDriftError: () => ClockDriftError,
26
39
  CommitmentRecord: () => CommitmentRecord,
27
40
  ConfidenceGate: () => ConfidenceGate,
28
41
  DEFAULT_LOA_POLICY: () => DEFAULT_LOA_POLICY,
29
42
  DataCategory: () => DataCategory,
43
+ FIRMWARE_MANIFEST_PATH: () => FIRMWARE_MANIFEST_PATH,
30
44
  FaultCode: () => FaultCode,
31
45
  FederationSyncType: () => FederationSyncType,
46
+ FirmwareIntegrityError: () => FirmwareIntegrityError,
32
47
  GateError: () => GateError,
33
48
  HiTLGate: () => HiTLGate,
34
49
  KeyStore: () => KeyStore,
35
50
  LevelOfAssurance: () => LevelOfAssurance,
51
+ M2MAuthError: () => M2MAuthError,
52
+ M2M_TRUSTED_ISSUER: () => M2M_TRUSTED_ISSUER,
36
53
  MediaEncoding: () => MediaEncoding,
37
54
  MessageType: () => MessageType,
38
55
  NodeClient: () => NodeClient,
@@ -58,13 +75,18 @@ __export(index_exports, {
58
75
  RCANValidationError: () => RCANValidationError,
59
76
  RCANVersionIncompatibleError: () => RCANVersionIncompatibleError,
60
77
  RCAN_VERSION: () => RCAN_VERSION,
78
+ ROLE_JWT_LEVEL: () => ROLE_JWT_LEVEL,
79
+ RRF_REVOCATION_CACHE_TTL_MS: () => RRF_REVOCATION_CACHE_TTL_MS,
80
+ RRF_REVOCATION_URL: () => RRF_REVOCATION_URL,
61
81
  RegistryClient: () => RegistryClient,
62
82
  RegistryTier: () => RegistryTier,
63
83
  ReplayCache: () => ReplayCache,
64
84
  RevocationCache: () => RevocationCache,
65
85
  RobotURI: () => RobotURI,
66
86
  RobotURIError: () => RobotURIError,
87
+ Role: () => Role,
67
88
  SAFETY_MESSAGE_TYPE: () => SAFETY_MESSAGE_TYPE,
89
+ SCOPE_MIN_ROLE: () => SCOPE_MIN_ROLE,
68
90
  SDK_VERSION: () => SDK_VERSION,
69
91
  SPEC_VERSION: () => SPEC_VERSION,
70
92
  TransportEncoding: () => TransportEncoding,
@@ -75,6 +97,9 @@ __export(index_exports, {
75
97
  addMediaInline: () => addMediaInline,
76
98
  addMediaRef: () => addMediaRef,
77
99
  assertClockSynced: () => assertClockSynced,
100
+ authorityAccessFromWire: () => authorityAccessFromWire,
101
+ authorityAccessToWire: () => authorityAccessToWire,
102
+ canonicalManifestJson: () => canonicalManifestJson,
78
103
  checkClockSync: () => checkClockSync,
79
104
  checkRevocation: () => checkRevocation,
80
105
  decodeBleFrames: () => decodeBleFrames,
@@ -83,21 +108,34 @@ __export(index_exports, {
83
108
  encodeBleFrames: () => encodeBleFrames,
84
109
  encodeCompact: () => encodeCompact,
85
110
  encodeMinimal: () => encodeMinimal,
111
+ extractIdentityFromJwt: () => extractIdentityFromJwt,
86
112
  extractLoaFromJwt: () => extractLoaFromJwt,
113
+ extractRoleFromJwt: () => extractRoleFromJwt,
87
114
  fetchCanonicalSchema: () => fetchCanonicalSchema,
115
+ fetchRRFRevocations: () => fetchRRFRevocations,
116
+ isAuthorityRequestValid: () => isAuthorityRequestValid,
117
+ isM2mTrustedRevoked: () => isM2mTrustedRevoked,
118
+ isPreemptedBy: () => isPreemptedBy,
88
119
  isSafetyMessage: () => isSafetyMessage,
89
120
  makeCloudRelayMessage: () => makeCloudRelayMessage,
121
+ makeCompetitionEnter: () => makeCompetitionEnter,
122
+ makeCompetitionScore: () => makeCompetitionScore,
90
123
  makeConfigUpdate: () => makeConfigUpdate,
91
124
  makeConsentDeny: () => makeConsentDeny,
92
125
  makeConsentGrant: () => makeConsentGrant,
93
126
  makeConsentRequest: () => makeConsentRequest,
127
+ makeContributeCancel: () => makeContributeCancel,
128
+ makeContributeRequest: () => makeContributeRequest,
129
+ makeContributeResult: () => makeContributeResult,
94
130
  makeEstopMessage: () => makeEstopMessage,
95
131
  makeEstopWithQoS: () => makeEstopWithQoS,
96
132
  makeFaultReport: () => makeFaultReport,
97
133
  makeFederationSync: () => makeFederationSync,
98
134
  makeKeyRotationMessage: () => makeKeyRotationMessage,
135
+ makePersonalResearchResult: () => makePersonalResearchResult,
99
136
  makeResumeMessage: () => makeResumeMessage,
100
137
  makeRevocationBroadcast: () => makeRevocationBroadcast,
138
+ makeSeasonStanding: () => makeSeasonStanding,
101
139
  makeStopMessage: () => makeStopMessage,
102
140
  makeStreamChunk: () => makeStreamChunk,
103
141
  makeTrainingConsentDeny: () => makeTrainingConsentDeny,
@@ -105,22 +143,34 @@ __export(index_exports, {
105
143
  makeTrainingConsentRequest: () => makeTrainingConsentRequest,
106
144
  makeTrainingDataMessage: () => makeTrainingDataMessage,
107
145
  makeTransparencyMessage: () => makeTransparencyMessage,
146
+ manifestFromWire: () => manifestFromWire,
147
+ manifestToWire: () => manifestToWire,
148
+ parseM2mPeerToken: () => parseM2mPeerToken,
149
+ parseM2mTrustedToken: () => parseM2mTrustedToken,
150
+ roleFromJwtLevel: () => roleFromJwtLevel,
108
151
  selectTransport: () => selectTransport,
152
+ validateAuthorityAccess: () => validateAuthorityAccess,
153
+ validateCompetitionScope: () => validateCompetitionScope,
109
154
  validateConfig: () => validateConfig,
110
155
  validateConfigAgainstSchema: () => validateConfigAgainstSchema,
111
156
  validateConfigUpdate: () => validateConfigUpdate,
112
157
  validateConsentMessage: () => validateConsentMessage,
158
+ validateContributeScope: () => validateContributeScope,
113
159
  validateCrossRegistryCommand: () => validateCrossRegistryCommand,
114
160
  validateDelegationChain: () => validateDelegationChain,
115
161
  validateLoaForScope: () => validateLoaForScope,
162
+ validateManifest: () => validateManifest,
116
163
  validateMediaChunks: () => validateMediaChunks,
117
164
  validateMessage: () => validateMessage,
118
165
  validateNodeAgainstSchema: () => validateNodeAgainstSchema,
119
166
  validateReplay: () => validateReplay,
167
+ validateRoleForScope: () => validateRoleForScope,
120
168
  validateSafetyMessage: () => validateSafetyMessage,
121
169
  validateTrainingDataMessage: () => validateTrainingDataMessage,
122
170
  validateURI: () => validateURI,
123
- validateVersionCompat: () => validateVersionCompat
171
+ validateVersionCompat: () => validateVersionCompat,
172
+ verifyM2mTrustedToken: () => verifyM2mTrustedToken,
173
+ verifyM2mTrustedTokenClaims: () => verifyM2mTrustedTokenClaims
124
174
  });
125
175
  module.exports = __toCommonJS(index_exports);
126
176
 
@@ -215,8 +265,8 @@ var RobotURI = class _RobotURI {
215
265
  };
216
266
 
217
267
  // src/version.ts
218
- var SPEC_VERSION = "1.6";
219
- var SDK_VERSION = "0.6.0";
268
+ var SPEC_VERSION = "2.1.0";
269
+ var SDK_VERSION = "1.1.0";
220
270
  function validateVersionCompat(incomingVersion, localVersion = SPEC_VERSION) {
221
271
  const parseParts = (v) => {
222
272
  const parts = v.split(".");
@@ -237,18 +287,18 @@ var MessageType = /* @__PURE__ */ ((MessageType2) => {
237
287
  MessageType2[MessageType2["HEARTBEAT"] = 4] = "HEARTBEAT";
238
288
  MessageType2[MessageType2["CONFIG"] = 5] = "CONFIG";
239
289
  MessageType2[MessageType2["SAFETY"] = 6] = "SAFETY";
240
- MessageType2[MessageType2["SENSOR_DATA"] = 7] = "SENSOR_DATA";
241
- MessageType2[MessageType2["AUDIT"] = 8] = "AUDIT";
290
+ MessageType2[MessageType2["AUTH"] = 7] = "AUTH";
291
+ MessageType2[MessageType2["ERROR"] = 8] = "ERROR";
242
292
  MessageType2[MessageType2["DISCOVER"] = 9] = "DISCOVER";
243
- MessageType2[MessageType2["TRAINING_DATA"] = 10] = "TRAINING_DATA";
244
- MessageType2[MessageType2["TRANSPARENCY"] = 11] = "TRANSPARENCY";
245
- MessageType2[MessageType2["FEDERATION_SYNC"] = 12] = "FEDERATION_SYNC";
246
- MessageType2[MessageType2["ALERT"] = 13] = "ALERT";
247
- MessageType2[MessageType2["TELEOP"] = 14] = "TELEOP";
248
- MessageType2[MessageType2["CHAT"] = 15] = "CHAT";
249
- MessageType2[MessageType2["ERROR"] = 16] = "ERROR";
293
+ MessageType2[MessageType2["PENDING_AUTH"] = 10] = "PENDING_AUTH";
294
+ MessageType2[MessageType2["INVOKE"] = 11] = "INVOKE";
295
+ MessageType2[MessageType2["INVOKE_RESULT"] = 12] = "INVOKE_RESULT";
296
+ MessageType2[MessageType2["INVOKE_CANCEL"] = 13] = "INVOKE_CANCEL";
297
+ MessageType2[MessageType2["REGISTRY_REGISTER"] = 14] = "REGISTRY_REGISTER";
298
+ MessageType2[MessageType2["REGISTRY_RESOLVE"] = 15] = "REGISTRY_RESOLVE";
299
+ MessageType2[MessageType2["TRANSPARENCY"] = 16] = "TRANSPARENCY";
250
300
  MessageType2[MessageType2["COMMAND_ACK"] = 17] = "COMMAND_ACK";
251
- MessageType2[MessageType2["COMMAND_COMMIT"] = 18] = "COMMAND_COMMIT";
301
+ MessageType2[MessageType2["COMMAND_NACK"] = 18] = "COMMAND_NACK";
252
302
  MessageType2[MessageType2["ROBOT_REVOCATION"] = 19] = "ROBOT_REVOCATION";
253
303
  MessageType2[MessageType2["CONSENT_REQUEST"] = 20] = "CONSENT_REQUEST";
254
304
  MessageType2[MessageType2["CONSENT_GRANT"] = 21] = "CONSENT_GRANT";
@@ -257,7 +307,24 @@ var MessageType = /* @__PURE__ */ ((MessageType2) => {
257
307
  MessageType2[MessageType2["SUBSCRIBE"] = 24] = "SUBSCRIBE";
258
308
  MessageType2[MessageType2["UNSUBSCRIBE"] = 25] = "UNSUBSCRIBE";
259
309
  MessageType2[MessageType2["FAULT_REPORT"] = 26] = "FAULT_REPORT";
260
- MessageType2[MessageType2["COMMAND_NACK"] = 27] = "COMMAND_NACK";
310
+ MessageType2[MessageType2["KEY_ROTATION"] = 27] = "KEY_ROTATION";
311
+ MessageType2[MessageType2["COMMAND_COMMIT"] = 28] = "COMMAND_COMMIT";
312
+ MessageType2[MessageType2["SENSOR_DATA"] = 29] = "SENSOR_DATA";
313
+ MessageType2[MessageType2["TRAINING_CONSENT_REQUEST"] = 30] = "TRAINING_CONSENT_REQUEST";
314
+ MessageType2[MessageType2["TRAINING_CONSENT_GRANT"] = 31] = "TRAINING_CONSENT_GRANT";
315
+ MessageType2[MessageType2["TRAINING_CONSENT_DENY"] = 32] = "TRAINING_CONSENT_DENY";
316
+ MessageType2[MessageType2["CONTRIBUTE_REQUEST"] = 33] = "CONTRIBUTE_REQUEST";
317
+ MessageType2[MessageType2["CONTRIBUTE_RESULT"] = 34] = "CONTRIBUTE_RESULT";
318
+ MessageType2[MessageType2["CONTRIBUTE_CANCEL"] = 35] = "CONTRIBUTE_CANCEL";
319
+ MessageType2[MessageType2["TRAINING_DATA"] = 36] = "TRAINING_DATA";
320
+ MessageType2[MessageType2["COMPETITION_ENTER"] = 37] = "COMPETITION_ENTER";
321
+ MessageType2[MessageType2["COMPETITION_SCORE"] = 38] = "COMPETITION_SCORE";
322
+ MessageType2[MessageType2["SEASON_STANDING"] = 39] = "SEASON_STANDING";
323
+ MessageType2[MessageType2["PERSONAL_RESEARCH_RESULT"] = 40] = "PERSONAL_RESEARCH_RESULT";
324
+ MessageType2[MessageType2["AUTHORITY_ACCESS"] = 41] = "AUTHORITY_ACCESS";
325
+ MessageType2[MessageType2["AUTHORITY_RESPONSE"] = 42] = "AUTHORITY_RESPONSE";
326
+ MessageType2[MessageType2["FIRMWARE_ATTESTATION"] = 43] = "FIRMWARE_ATTESTATION";
327
+ MessageType2[MessageType2["SBOM_UPDATE"] = 44] = "SBOM_UPDATE";
261
328
  return MessageType2;
262
329
  })(MessageType || {});
263
330
  var RCANMessageError = class extends Error {
@@ -293,6 +360,10 @@ var RCANMessage = class _RCANMessage {
293
360
  transportEncoding;
294
361
  /** v1.6: GAP-18 multi-modal media chunks */
295
362
  mediaChunks;
363
+ /** v2.1: SHA-256 of sender's firmware manifest */
364
+ firmwareHash;
365
+ /** v2.1: URI to sender's SBOM attestation endpoint */
366
+ attestationRef;
296
367
  constructor(data) {
297
368
  if (!data.cmd || data.cmd.trim() === "") {
298
369
  throw new RCANMessageError("'cmd' is required");
@@ -321,6 +392,13 @@ var RCANMessage = class _RCANMessage {
321
392
  this.loa = data.loa;
322
393
  this.transportEncoding = data.transportEncoding;
323
394
  this.mediaChunks = data.mediaChunks;
395
+ this.firmwareHash = data.firmwareHash;
396
+ this.attestationRef = data.attestationRef;
397
+ if (this.signature !== void 0 && this.signature["sig"] === "pending") {
398
+ throw new RCANMessageError(
399
+ "signature.sig:'pending' is not valid in RCAN v2.1. Sign the message before sending."
400
+ );
401
+ }
324
402
  if (this.confidence !== void 0) {
325
403
  if (this.confidence < 0 || this.confidence > 1) {
326
404
  throw new RCANMessageError(
@@ -362,6 +440,8 @@ var RCANMessage = class _RCANMessage {
362
440
  if (this.loa !== void 0) obj.loa = this.loa;
363
441
  if (this.transportEncoding !== void 0) obj.transportEncoding = this.transportEncoding;
364
442
  if (this.mediaChunks !== void 0) obj.mediaChunks = this.mediaChunks;
443
+ if (this.firmwareHash !== void 0) obj.firmwareHash = this.firmwareHash;
444
+ if (this.attestationRef !== void 0) obj.attestationRef = this.attestationRef;
365
445
  return obj;
366
446
  }
367
447
  /** Serialize to JSON string */
@@ -404,7 +484,9 @@ var RCANMessage = class _RCANMessage {
404
484
  readOnly: obj.readOnly,
405
485
  loa: obj.loa,
406
486
  transportEncoding: obj.transportEncoding,
407
- mediaChunks: obj.mediaChunks
487
+ mediaChunks: obj.mediaChunks,
488
+ firmwareHash: obj.firmwareHash,
489
+ attestationRef: obj.attestationRef
408
490
  });
409
491
  }
410
492
  };
@@ -1377,6 +1459,7 @@ async function fetchCanonicalSchema(schemaName) {
1377
1459
  try {
1378
1460
  const controller = new AbortController();
1379
1461
  const timer = setTimeout(() => controller.abort(), 5e3);
1462
+ timer.unref?.();
1380
1463
  const res = await fetch(`${SCHEMA_BASE}/${schemaName}`, { signal: controller.signal });
1381
1464
  clearTimeout(timer);
1382
1465
  if (!res.ok) return null;
@@ -2017,7 +2100,7 @@ function makeTrainingConsentDeny(params) {
2017
2100
  return makeConsentDeny(params);
2018
2101
  }
2019
2102
  function validateTrainingDataMessage(msg) {
2020
- if (msg.params.message_type !== 10 /* TRAINING_DATA */) {
2103
+ if (msg.params.message_type !== 36 /* TRAINING_DATA */) {
2021
2104
  return { valid: false, reason: "not a TRAINING_DATA message" };
2022
2105
  }
2023
2106
  const token = msg.params.consent_token;
@@ -2157,77 +2240,133 @@ function makeFaultReport(params) {
2157
2240
  }
2158
2241
 
2159
2242
  // src/identity.ts
2160
- var LevelOfAssurance = /* @__PURE__ */ ((LevelOfAssurance2) => {
2161
- LevelOfAssurance2[LevelOfAssurance2["ANONYMOUS"] = 1] = "ANONYMOUS";
2162
- LevelOfAssurance2[LevelOfAssurance2["EMAIL_VERIFIED"] = 2] = "EMAIL_VERIFIED";
2163
- LevelOfAssurance2[LevelOfAssurance2["HARDWARE_TOKEN"] = 3] = "HARDWARE_TOKEN";
2164
- return LevelOfAssurance2;
2165
- })(LevelOfAssurance || {});
2243
+ var Role = /* @__PURE__ */ ((Role2) => {
2244
+ Role2[Role2["GUEST"] = 1] = "GUEST";
2245
+ Role2[Role2["OPERATOR"] = 2] = "OPERATOR";
2246
+ Role2[Role2["CONTRIBUTOR"] = 3] = "CONTRIBUTOR";
2247
+ Role2[Role2["ADMIN"] = 4] = "ADMIN";
2248
+ Role2[Role2["M2M_PEER"] = 5] = "M2M_PEER";
2249
+ Role2[Role2["CREATOR"] = 6] = "CREATOR";
2250
+ Role2[Role2["M2M_TRUSTED"] = 7] = "M2M_TRUSTED";
2251
+ return Role2;
2252
+ })(Role || {});
2253
+ var LevelOfAssurance = Role;
2254
+ var ROLE_JWT_LEVEL = {
2255
+ [1 /* GUEST */]: 1,
2256
+ [2 /* OPERATOR */]: 2,
2257
+ [3 /* CONTRIBUTOR */]: 2.5,
2258
+ [4 /* ADMIN */]: 3,
2259
+ [5 /* M2M_PEER */]: 4,
2260
+ [6 /* CREATOR */]: 5,
2261
+ [7 /* M2M_TRUSTED */]: 6
2262
+ };
2263
+ var JWT_LEVEL_TO_ROLE = new Map(
2264
+ Object.entries(ROLE_JWT_LEVEL).map(
2265
+ ([role, level]) => [level, Number(role)]
2266
+ )
2267
+ );
2268
+ function roleFromJwtLevel(level) {
2269
+ return JWT_LEVEL_TO_ROLE.get(level);
2270
+ }
2271
+ var SCOPE_MIN_ROLE = {
2272
+ "status": 1 /* GUEST */,
2273
+ "discover": 1 /* GUEST */,
2274
+ "chat": 1 /* GUEST */,
2275
+ "observer": 1 /* GUEST */,
2276
+ "contribute": 3 /* CONTRIBUTOR */,
2277
+ "control": 2 /* OPERATOR */,
2278
+ "teleop": 2 /* OPERATOR */,
2279
+ "training": 4 /* ADMIN */,
2280
+ "training_data": 4 /* ADMIN */,
2281
+ "config": 4 /* ADMIN */,
2282
+ "authority": 4 /* ADMIN */,
2283
+ "admin": 6 /* CREATOR */,
2284
+ "safety": 6 /* CREATOR */,
2285
+ "estop": 6 /* CREATOR */,
2286
+ "fleet.trusted": 7 /* M2M_TRUSTED */
2287
+ };
2166
2288
  var DEFAULT_LOA_POLICY = {
2167
- minLoaDiscover: 1 /* ANONYMOUS */,
2168
- minLoaStatus: 1 /* ANONYMOUS */,
2169
- minLoaChat: 1 /* ANONYMOUS */,
2170
- minLoaControl: 1 /* ANONYMOUS */,
2171
- minLoaSafety: 1 /* ANONYMOUS */
2289
+ minRoleForDiscover: 1 /* GUEST */,
2290
+ minRoleForStatus: 1 /* GUEST */,
2291
+ minRoleForChat: 1 /* GUEST */,
2292
+ minRoleForControl: 1 /* GUEST */,
2293
+ minRoleForSafety: 1 /* GUEST */
2172
2294
  };
2173
2295
  var PRODUCTION_LOA_POLICY = {
2174
- minLoaDiscover: 1 /* ANONYMOUS */,
2175
- minLoaStatus: 1 /* ANONYMOUS */,
2176
- minLoaChat: 1 /* ANONYMOUS */,
2177
- minLoaControl: 2 /* EMAIL_VERIFIED */,
2178
- minLoaSafety: 3 /* HARDWARE_TOKEN */
2296
+ minRoleForDiscover: 1 /* GUEST */,
2297
+ minRoleForStatus: 1 /* GUEST */,
2298
+ minRoleForChat: 1 /* GUEST */,
2299
+ minRoleForControl: 2 /* OPERATOR */,
2300
+ minRoleForSafety: 6 /* CREATOR */
2179
2301
  };
2180
- function extractLoaFromJwt(token) {
2302
+ function decodeJwtPayload(token) {
2181
2303
  try {
2182
2304
  const parts = token.split(".");
2183
- if (parts.length < 2) return 1 /* ANONYMOUS */;
2305
+ if (parts.length < 2) return null;
2184
2306
  const payloadB64 = (parts[1] ?? "").replace(/-/g, "+").replace(/_/g, "/");
2185
2307
  const padded = payloadB64 + "=".repeat((4 - payloadB64.length % 4) % 4);
2186
- let json;
2187
- if (typeof atob !== "undefined") {
2188
- json = atob(padded);
2189
- } else {
2190
- json = Buffer.from(padded, "base64").toString("utf-8");
2191
- }
2192
- const claims = JSON.parse(json);
2193
- const loa = claims["loa"];
2194
- if (typeof loa === "number" && loa >= 1 && loa <= 3) {
2195
- return loa;
2196
- }
2308
+ return JSON.parse(atob(padded));
2197
2309
  } catch {
2310
+ return null;
2198
2311
  }
2199
- return 1 /* ANONYMOUS */;
2200
- }
2201
- function minLoaForScope(scope, policy) {
2202
- const s = scope.toLowerCase();
2203
- switch (s) {
2204
- case "discover":
2205
- return policy.minLoaDiscover;
2206
- case "status":
2207
- return policy.minLoaStatus;
2208
- case "chat":
2209
- return policy.minLoaChat;
2210
- case "control":
2211
- return policy.minLoaControl;
2212
- case "safety":
2213
- return policy.minLoaSafety;
2214
- default:
2215
- return null;
2216
- }
2217
- }
2218
- function validateLoaForScope(loa, scope, policy = DEFAULT_LOA_POLICY) {
2219
- const min = minLoaForScope(scope, policy);
2220
- if (min === null) {
2221
- return { valid: true, reason: "unknown scope; allowed by default" };
2222
- }
2223
- if (loa >= min) {
2224
- return { valid: true, reason: "ok" };
2312
+ }
2313
+ function extractRoleFromJwt(token) {
2314
+ const payload = decodeJwtPayload(token);
2315
+ if (!payload) return 1 /* GUEST */;
2316
+ const rcanRole = payload["rcan_role"];
2317
+ if (rcanRole !== void 0 && rcanRole !== null) {
2318
+ const role = roleFromJwtLevel(Number(rcanRole));
2319
+ if (role !== void 0) return role;
2320
+ }
2321
+ const loa = payload["loa"];
2322
+ if (loa !== void 0 && loa !== null) {
2323
+ const role = roleFromJwtLevel(Number(loa));
2324
+ if (role !== void 0) return role;
2325
+ }
2326
+ return 1 /* GUEST */;
2327
+ }
2328
+ function extractLoaFromJwt(token) {
2329
+ return extractRoleFromJwt(token);
2330
+ }
2331
+ function extractIdentityFromJwt(token) {
2332
+ const payload = decodeJwtPayload(token);
2333
+ if (!payload) {
2334
+ return { sub: "", role: 1 /* GUEST */, jwtLevel: 1, scopes: [] };
2335
+ }
2336
+ const rcanRole = payload["rcan_role"];
2337
+ const loa = payload["loa"];
2338
+ const rawLevel = rcanRole !== void 0 ? Number(rcanRole) : loa !== void 0 ? Number(loa) : 1;
2339
+ const role = roleFromJwtLevel(rawLevel) ?? 1 /* GUEST */;
2340
+ const scopes = Array.isArray(payload["rcan_scopes"]) ? payload["rcan_scopes"] : Array.isArray(payload["scopes"]) ? payload["scopes"] : [];
2341
+ return {
2342
+ sub: String(payload["sub"] ?? ""),
2343
+ role,
2344
+ jwtLevel: ROLE_JWT_LEVEL[role],
2345
+ registryUrl: payload["registry_url"],
2346
+ scopes,
2347
+ verifiedAt: payload["verified_at"],
2348
+ peerRrn: payload["peer_rrn"],
2349
+ fleetRrns: Array.isArray(payload["fleet_rrns"]) ? payload["fleet_rrns"] : void 0
2350
+ };
2351
+ }
2352
+ function validateRoleForScope(role, scope) {
2353
+ const required = SCOPE_MIN_ROLE[scope.toLowerCase()];
2354
+ if (required === void 0) {
2355
+ if (role >= 2 /* OPERATOR */) return { ok: true, reason: "" };
2356
+ return {
2357
+ ok: false,
2358
+ reason: `Unknown scope '${scope}': applying OPERATOR minimum. Caller has ${Role[role]}.`
2359
+ };
2225
2360
  }
2361
+ if (role >= required) return { ok: true, reason: "" };
2226
2362
  return {
2227
- valid: false,
2228
- reason: `LOA_INSUFFICIENT: scope=${scope} requires LoA>=${min}, caller has LoA=${loa}`
2363
+ ok: false,
2364
+ reason: `Scope '${scope}' requires ${Role[required]} (JWT level ${ROLE_JWT_LEVEL[required]}), but caller has ${Role[role]} (JWT level ${ROLE_JWT_LEVEL[role]})`
2229
2365
  };
2230
2366
  }
2367
+ function validateLoaForScope(role, scope) {
2368
+ return validateRoleForScope(role, scope);
2369
+ }
2231
2370
 
2232
2371
  // src/federation.ts
2233
2372
  var RegistryTier = /* @__PURE__ */ ((RegistryTier2) => {
@@ -2351,12 +2490,12 @@ function generateId5() {
2351
2490
  }
2352
2491
  function makeFederationSync(source, target, syncType, payload) {
2353
2492
  return new RCANMessage({
2354
- rcan: "1.6",
2355
- rcanVersion: "1.6",
2493
+ rcan: "2.1.0",
2494
+ rcanVersion: "2.1.0",
2356
2495
  cmd: "federation_sync",
2357
2496
  target,
2358
2497
  params: {
2359
- msg_type: 12 /* FEDERATION_SYNC */,
2498
+ msg_type: 23 /* FLEET_COMMAND */,
2360
2499
  msg_id: generateId5(),
2361
2500
  source_registry: source,
2362
2501
  target_registry: target,
@@ -2383,17 +2522,17 @@ async function validateCrossRegistryCommand(msg, localRegistry, trustCache) {
2383
2522
  reason: `REGISTRY_UNKNOWN: ${sourceRegistry} is not in the local trust cache`
2384
2523
  };
2385
2524
  }
2386
- let loa = 1 /* ANONYMOUS */;
2525
+ let loa = 1 /* GUEST */;
2387
2526
  const registryJwt = msg.params?.["registry_jwt"];
2388
2527
  if (registryJwt) {
2389
2528
  loa = extractLoaFromJwt(registryJwt);
2390
2529
  } else if (typeof msg.loa === "number") {
2391
2530
  loa = msg.loa;
2392
2531
  }
2393
- if (loa < 2 /* EMAIL_VERIFIED */) {
2532
+ if (loa < 2 /* OPERATOR */) {
2394
2533
  return {
2395
2534
  valid: false,
2396
- reason: `LOA_INSUFFICIENT: cross-registry commands require LoA>=2 (EMAIL_VERIFIED), got LoA=${loa}`
2535
+ reason: `LOA_INSUFFICIENT: cross-registry commands require LoA>=2 (OPERATOR), got role=${loa}`
2397
2536
  };
2398
2537
  }
2399
2538
  return { valid: true, reason: "cross-registry command accepted" };
@@ -2482,7 +2621,8 @@ async function sha256Bytes(input) {
2482
2621
  const encoded = new TextEncoder().encode(input);
2483
2622
  const ab = new ArrayBuffer(encoded.byteLength);
2484
2623
  new Uint8Array(ab).set(encoded);
2485
- const hashBuffer = await crypto.subtle.digest("SHA-256", ab);
2624
+ const subtle = globalThis.crypto?.subtle ?? (await import("crypto")).webcrypto.subtle;
2625
+ const hashBuffer = await subtle.digest("SHA-256", ab);
2486
2626
  return new Uint8Array(hashBuffer);
2487
2627
  }
2488
2628
  async function encodeMinimal(message) {
@@ -2633,9 +2773,10 @@ function generateId6() {
2633
2773
  return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
2634
2774
  }
2635
2775
  async function computeSha256Hex(data) {
2776
+ const subtle = globalThis.crypto?.subtle ?? (await import("crypto")).webcrypto.subtle;
2636
2777
  const ab = new ArrayBuffer(data.byteLength);
2637
2778
  new Uint8Array(ab).set(data);
2638
- const hashBuffer = await crypto.subtle.digest("SHA-256", ab);
2779
+ const hashBuffer = await subtle.digest("SHA-256", ab);
2639
2780
  const hashArray = new Uint8Array(hashBuffer);
2640
2781
  return Array.from(hashArray).map((b) => b.toString(16).padStart(2, "0")).join("");
2641
2782
  }
@@ -2728,7 +2869,7 @@ async function makeTrainingDataMessage(media) {
2728
2869
  cmd: "training_data",
2729
2870
  target: "rcan://training/data",
2730
2871
  params: {
2731
- msg_type: 10 /* TRAINING_DATA */,
2872
+ msg_type: 36 /* TRAINING_DATA */,
2732
2873
  msg_id: generateId6()
2733
2874
  },
2734
2875
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -2761,7 +2902,7 @@ async function makeStreamChunk(streamId, data, mimeType, chunkIndex, isFinal) {
2761
2902
  cmd: "stream_chunk",
2762
2903
  target: "rcan://streaming/chunk",
2763
2904
  params: {
2764
- msg_type: 7 /* SENSOR_DATA */,
2905
+ msg_type: 29 /* SENSOR_DATA */,
2765
2906
  msg_id: generateId6(),
2766
2907
  stream_chunk: streamChunkMeta
2767
2908
  },
@@ -2771,24 +2912,372 @@ async function makeStreamChunk(streamId, data, mimeType, chunkIndex, isFinal) {
2771
2912
  return msg;
2772
2913
  }
2773
2914
 
2915
+ // src/contribute.ts
2916
+ var CONTRIBUTE_SCOPE_LEVEL = 2.5;
2917
+ var _idCounter = 0;
2918
+ function _generateId() {
2919
+ return `cr-${Date.now()}-${++_idCounter}`;
2920
+ }
2921
+ function makeContributeRequest(params = {}) {
2922
+ return {
2923
+ type: 33 /* CONTRIBUTE_REQUEST */,
2924
+ request_id: params.request_id ?? _generateId(),
2925
+ project_id: params.project_id ?? "",
2926
+ project_name: params.project_name ?? "",
2927
+ work_unit_id: params.work_unit_id ?? "",
2928
+ resource_type: params.resource_type ?? "cpu",
2929
+ estimated_duration_s: params.estimated_duration_s ?? 0,
2930
+ priority: params.priority ?? 0,
2931
+ payload: params.payload ?? {},
2932
+ timestamp: params.timestamp ?? Date.now() / 1e3
2933
+ };
2934
+ }
2935
+ function makeContributeResult(params = {}) {
2936
+ const result = {
2937
+ type: 34 /* CONTRIBUTE_RESULT */,
2938
+ request_id: params.request_id ?? "",
2939
+ work_unit_id: params.work_unit_id ?? "",
2940
+ status: params.status ?? "completed",
2941
+ resource_type: params.resource_type ?? "cpu",
2942
+ duration_s: params.duration_s ?? 0,
2943
+ compute_units: params.compute_units ?? 0,
2944
+ result_payload: params.result_payload ?? {},
2945
+ timestamp: params.timestamp ?? Date.now() / 1e3
2946
+ };
2947
+ if (params.error_message !== void 0) {
2948
+ result.error_message = params.error_message;
2949
+ }
2950
+ return result;
2951
+ }
2952
+ function makeContributeCancel(params = {}) {
2953
+ return {
2954
+ type: 35 /* CONTRIBUTE_CANCEL */,
2955
+ request_id: params.request_id ?? "",
2956
+ work_unit_id: params.work_unit_id ?? "",
2957
+ reason: params.reason ?? "",
2958
+ timestamp: params.timestamp ?? Date.now() / 1e3
2959
+ };
2960
+ }
2961
+ function validateContributeScope(scopeLevel, action = "request") {
2962
+ if (action === "request" || action === "result") {
2963
+ return scopeLevel >= CONTRIBUTE_SCOPE_LEVEL;
2964
+ }
2965
+ if (action === "cancel") {
2966
+ return scopeLevel >= 2;
2967
+ }
2968
+ return false;
2969
+ }
2970
+ function isPreemptedBy(scopeLevel) {
2971
+ return scopeLevel >= 3;
2972
+ }
2973
+
2974
+ // src/competition.ts
2975
+ var COMPETITION_SCOPE_LEVEL = 2;
2976
+ var _idCounter2 = 0;
2977
+ function _generateRunId() {
2978
+ return `run-${Date.now()}-${++_idCounter2}`;
2979
+ }
2980
+ function makeCompetitionEnter(params = {}) {
2981
+ return {
2982
+ type: 37 /* COMPETITION_ENTER */,
2983
+ competition_id: params.competition_id ?? "",
2984
+ competition_format: params.competition_format ?? "sprint",
2985
+ hardware_tier: params.hardware_tier ?? "",
2986
+ model_id: params.model_id ?? "",
2987
+ robot_rrn: params.robot_rrn ?? "",
2988
+ entered_at: params.entered_at ?? Date.now() / 1e3
2989
+ };
2990
+ }
2991
+ function makeCompetitionScore(params = {}) {
2992
+ const score = params.score ?? 0;
2993
+ if (score < 0 || score > 1) {
2994
+ throw new Error(`score must be in [0.0, 1.0], got ${score}`);
2995
+ }
2996
+ return {
2997
+ type: 38 /* COMPETITION_SCORE */,
2998
+ competition_id: params.competition_id ?? "",
2999
+ candidate_id: params.candidate_id ?? "",
3000
+ score,
3001
+ hardware_tier: params.hardware_tier ?? "",
3002
+ verified: params.verified ?? false,
3003
+ submitted_at: params.submitted_at ?? Date.now() / 1e3
3004
+ };
3005
+ }
3006
+ function makeSeasonStanding(params = {}) {
3007
+ return {
3008
+ type: 39 /* SEASON_STANDING */,
3009
+ season_id: params.season_id ?? "",
3010
+ class_id: params.class_id ?? "",
3011
+ standings: params.standings ?? [],
3012
+ days_remaining: params.days_remaining ?? 0,
3013
+ broadcast_at: params.broadcast_at ?? Date.now() / 1e3
3014
+ };
3015
+ }
3016
+ function makePersonalResearchResult(params = {}) {
3017
+ const score = params.score ?? 0;
3018
+ if (score < 0 || score > 1) {
3019
+ throw new Error(`score must be in [0.0, 1.0], got ${score}`);
3020
+ }
3021
+ return {
3022
+ type: 40 /* PERSONAL_RESEARCH_RESULT */,
3023
+ run_id: params.run_id ?? _generateRunId(),
3024
+ run_type: params.run_type ?? "personal",
3025
+ candidate_id: params.candidate_id ?? "",
3026
+ score,
3027
+ hardware_tier: params.hardware_tier ?? "",
3028
+ model_id: params.model_id ?? "",
3029
+ owner_uid: params.owner_uid ?? "",
3030
+ metrics: params.metrics ?? {
3031
+ success_rate: 0,
3032
+ p66_rate: 0,
3033
+ token_efficiency: 0,
3034
+ latency_score: 0
3035
+ },
3036
+ submitted_to_community: params.submitted_to_community ?? false,
3037
+ created_at: params.created_at ?? Date.now() / 1e3
3038
+ };
3039
+ }
3040
+ function validateCompetitionScope(scopeLevel) {
3041
+ return scopeLevel >= COMPETITION_SCOPE_LEVEL;
3042
+ }
3043
+
3044
+ // src/firmware.ts
3045
+ var FIRMWARE_MANIFEST_PATH = "/.well-known/rcan-firmware-manifest.json";
3046
+ function manifestToWire(m) {
3047
+ const wire = {
3048
+ rrn: m.rrn,
3049
+ firmware_version: m.firmwareVersion,
3050
+ build_hash: m.buildHash,
3051
+ components: m.components,
3052
+ signed_at: m.signedAt
3053
+ };
3054
+ if (m.signature) wire.signature = m.signature;
3055
+ return wire;
3056
+ }
3057
+ function manifestFromWire(w) {
3058
+ return {
3059
+ rrn: w.rrn,
3060
+ firmwareVersion: w.firmware_version,
3061
+ buildHash: w.build_hash,
3062
+ components: w.components ?? [],
3063
+ signedAt: w.signed_at ?? "",
3064
+ signature: w.signature
3065
+ };
3066
+ }
3067
+ function canonicalManifestJson(m) {
3068
+ const obj = {
3069
+ build_hash: m.buildHash,
3070
+ components: m.components.map((c) => ({
3071
+ hash: c.hash,
3072
+ name: c.name,
3073
+ version: c.version
3074
+ })),
3075
+ firmware_version: m.firmwareVersion,
3076
+ rrn: m.rrn,
3077
+ signed_at: m.signedAt
3078
+ };
3079
+ return JSON.stringify(obj);
3080
+ }
3081
+ var FirmwareIntegrityError = class extends Error {
3082
+ constructor(message) {
3083
+ super(message);
3084
+ this.name = "FirmwareIntegrityError";
3085
+ }
3086
+ };
3087
+ function validateManifest(m) {
3088
+ const errors = [];
3089
+ if (!m.rrn) errors.push("rrn is required");
3090
+ if (!m.firmwareVersion) errors.push("firmwareVersion is required");
3091
+ if (!m.buildHash) errors.push("buildHash is required");
3092
+ if (!m.buildHash.startsWith("sha256:")) errors.push("buildHash must start with 'sha256:'");
3093
+ if (!m.signedAt) errors.push("signedAt is required");
3094
+ if (!m.signature) errors.push("signature is required (manifest must be signed)");
3095
+ for (const [i, c] of m.components.entries()) {
3096
+ if (!c.name) errors.push(`components[${i}].name is required`);
3097
+ if (!c.version) errors.push(`components[${i}].version is required`);
3098
+ if (!c.hash.startsWith("sha256:")) errors.push(`components[${i}].hash must start with 'sha256:'`);
3099
+ }
3100
+ return errors;
3101
+ }
3102
+
3103
+ // src/authority.ts
3104
+ function authorityAccessToWire(p) {
3105
+ return {
3106
+ request_id: p.requestId,
3107
+ authority_id: p.authorityId,
3108
+ requested_data: p.requestedData,
3109
+ justification: p.justification,
3110
+ expires_at: p.expiresAt
3111
+ };
3112
+ }
3113
+ function authorityAccessFromWire(w) {
3114
+ return {
3115
+ requestId: w.request_id,
3116
+ authorityId: w.authority_id,
3117
+ requestedData: w.requested_data ?? [],
3118
+ justification: w.justification ?? "",
3119
+ expiresAt: w.expires_at ?? 0
3120
+ };
3121
+ }
3122
+ function validateAuthorityAccess(p) {
3123
+ const errors = [];
3124
+ if (!p.requestId) errors.push("requestId is required");
3125
+ if (!p.authorityId) errors.push("authorityId is required");
3126
+ if (!p.requestedData || p.requestedData.length === 0)
3127
+ errors.push("requestedData must include at least one category");
3128
+ if (!p.justification) errors.push("justification is required");
3129
+ if (!p.expiresAt || p.expiresAt <= 0) errors.push("expiresAt must be a positive Unix timestamp");
3130
+ if (p.expiresAt < Date.now() / 1e3) errors.push("expiresAt is in the past \u2014 request has expired");
3131
+ return errors;
3132
+ }
3133
+ function isAuthorityRequestValid(p) {
3134
+ return Date.now() / 1e3 < p.expiresAt && validateAuthorityAccess(p).length === 0;
3135
+ }
3136
+ var AUTHORITY_ERROR_CODES = {
3137
+ NOT_RECOGNIZED: "AUTHORITY_NOT_RECOGNIZED",
3138
+ REQUEST_EXPIRED: "AUTHORITY_REQUEST_EXPIRED",
3139
+ INVALID_TOKEN: "AUTHORITY_INVALID_TOKEN",
3140
+ RATE_LIMITED: "AUTHORITY_RATE_LIMITED"
3141
+ };
3142
+
3143
+ // src/m2m.ts
3144
+ var RRF_REVOCATION_URL = "https://api.rrf.rcan.dev/v2/revocations";
3145
+ var M2M_TRUSTED_ISSUER = "rrf.rcan.dev";
3146
+ var RRF_REVOCATION_CACHE_TTL_MS = 55e3;
3147
+ var M2MAuthError = class extends Error {
3148
+ constructor(message) {
3149
+ super(message);
3150
+ this.name = "M2MAuthError";
3151
+ }
3152
+ };
3153
+ function decodeJwtPayload2(token) {
3154
+ const parts = token.split(".");
3155
+ if (parts.length < 2) throw new M2MAuthError("Invalid JWT structure");
3156
+ const b64 = (parts[1] ?? "").replace(/-/g, "+").replace(/_/g, "/");
3157
+ const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
3158
+ try {
3159
+ return JSON.parse(atob(padded));
3160
+ } catch (e) {
3161
+ throw new M2MAuthError(`JWT payload decode failed: ${String(e)}`);
3162
+ }
3163
+ }
3164
+ function parseM2mPeerToken(token) {
3165
+ const payload = decodeJwtPayload2(token);
3166
+ const exp = Number(payload["exp"] ?? 0);
3167
+ if (exp > 0 && Date.now() / 1e3 > exp) {
3168
+ throw new M2MAuthError(`M2M_PEER token expired (sub=${String(payload["sub"])})`);
3169
+ }
3170
+ const peerRrn = String(payload["peer_rrn"] ?? "");
3171
+ if (!peerRrn) throw new M2MAuthError("M2M_PEER token missing peer_rrn claim");
3172
+ return {
3173
+ sub: String(payload["sub"] ?? ""),
3174
+ peerRrn,
3175
+ scopes: Array.isArray(payload["rcan_scopes"]) ? payload["rcan_scopes"] : Array.isArray(payload["scopes"]) ? payload["scopes"] : [],
3176
+ exp,
3177
+ iss: String(payload["iss"] ?? "")
3178
+ };
3179
+ }
3180
+ function parseM2mTrustedToken(token) {
3181
+ const payload = decodeJwtPayload2(token);
3182
+ const iss = String(payload["iss"] ?? "");
3183
+ if (iss !== M2M_TRUSTED_ISSUER) {
3184
+ throw new M2MAuthError(
3185
+ `M2M_TRUSTED issuer must be '${M2M_TRUSTED_ISSUER}', got '${iss}'`
3186
+ );
3187
+ }
3188
+ const scopes = Array.isArray(payload["rcan_scopes"]) ? payload["rcan_scopes"] : Array.isArray(payload["scopes"]) ? payload["scopes"] : [];
3189
+ if (!scopes.includes("fleet.trusted")) {
3190
+ throw new M2MAuthError("M2M_TRUSTED token missing required 'fleet.trusted' scope");
3191
+ }
3192
+ const exp = Number(payload["exp"] ?? 0);
3193
+ if (exp > 0 && Date.now() / 1e3 > exp) {
3194
+ throw new M2MAuthError(`M2M_TRUSTED token expired (sub=${String(payload["sub"])})`);
3195
+ }
3196
+ const rrfSig = String(payload["rrf_sig"] ?? "");
3197
+ if (!rrfSig) throw new M2MAuthError("M2M_TRUSTED token missing rrf_sig claim");
3198
+ const fleetRrns = Array.isArray(payload["fleet_rrns"]) ? payload["fleet_rrns"] : [];
3199
+ return {
3200
+ sub: String(payload["sub"] ?? ""),
3201
+ fleetRrns,
3202
+ scopes,
3203
+ exp,
3204
+ iss,
3205
+ rrfSig
3206
+ };
3207
+ }
3208
+ function verifyM2mTrustedTokenClaims(token, targetRrn) {
3209
+ const claims = parseM2mTrustedToken(token);
3210
+ if (!claims.fleetRrns.includes(targetRrn)) {
3211
+ throw new M2MAuthError(
3212
+ `M2M_TRUSTED token does not authorize commanding '${targetRrn}'. Authorized fleet: [${claims.fleetRrns.join(", ")}]`
3213
+ );
3214
+ }
3215
+ return claims;
3216
+ }
3217
+ var _revocationCache = null;
3218
+ async function fetchRRFRevocations(url = RRF_REVOCATION_URL) {
3219
+ const now = Date.now();
3220
+ if (_revocationCache && now - _revocationCache.fetchedAt < RRF_REVOCATION_CACHE_TTL_MS) {
3221
+ return _revocationCache;
3222
+ }
3223
+ try {
3224
+ const resp = await fetch(url, { signal: AbortSignal.timeout?.(5e3) });
3225
+ const data = await resp.json();
3226
+ _revocationCache = {
3227
+ revokedOrchestrators: new Set(data.revoked_orchestrators ?? []),
3228
+ revokedJtis: new Set(data.revoked_jtis ?? []),
3229
+ fetchedAt: now
3230
+ };
3231
+ } catch {
3232
+ if (_revocationCache) return _revocationCache;
3233
+ _revocationCache = { revokedOrchestrators: /* @__PURE__ */ new Set(), revokedJtis: /* @__PURE__ */ new Set(), fetchedAt: now };
3234
+ }
3235
+ return _revocationCache;
3236
+ }
3237
+ async function isM2mTrustedRevoked(claims, jti) {
3238
+ const cache = await fetchRRFRevocations();
3239
+ if (cache.revokedOrchestrators.has(claims.sub)) return true;
3240
+ if (jti && cache.revokedJtis.has(jti)) return true;
3241
+ return false;
3242
+ }
3243
+ async function verifyM2mTrustedToken(token, targetRrn, options) {
3244
+ const claims = verifyM2mTrustedTokenClaims(token, targetRrn);
3245
+ if (!options?.skipRevocationCheck) {
3246
+ const revoked = await isM2mTrustedRevoked(claims);
3247
+ if (revoked) {
3248
+ throw new M2MAuthError(
3249
+ `M2M_TRUSTED orchestrator '${claims.sub}' is on the RRF revocation list`
3250
+ );
3251
+ }
3252
+ }
3253
+ return claims;
3254
+ }
3255
+
2774
3256
  // src/index.ts
2775
3257
  var VERSION = "0.6.0";
2776
3258
  var RCAN_VERSION = "1.6";
2777
3259
  // Annotate the CommonJS export names for ESM import in node:
2778
3260
  0 && (module.exports = {
3261
+ AUTHORITY_ERROR_CODES,
2779
3262
  AuditChain,
2780
3263
  AuditError,
3264
+ COMPETITION_SCOPE_LEVEL,
3265
+ CONTRIBUTE_SCOPE_LEVEL,
2781
3266
  ClockDriftError,
2782
3267
  CommitmentRecord,
2783
3268
  ConfidenceGate,
2784
3269
  DEFAULT_LOA_POLICY,
2785
3270
  DataCategory,
3271
+ FIRMWARE_MANIFEST_PATH,
2786
3272
  FaultCode,
2787
3273
  FederationSyncType,
3274
+ FirmwareIntegrityError,
2788
3275
  GateError,
2789
3276
  HiTLGate,
2790
3277
  KeyStore,
2791
3278
  LevelOfAssurance,
3279
+ M2MAuthError,
3280
+ M2M_TRUSTED_ISSUER,
2792
3281
  MediaEncoding,
2793
3282
  MessageType,
2794
3283
  NodeClient,
@@ -2814,13 +3303,18 @@ var RCAN_VERSION = "1.6";
2814
3303
  RCANValidationError,
2815
3304
  RCANVersionIncompatibleError,
2816
3305
  RCAN_VERSION,
3306
+ ROLE_JWT_LEVEL,
3307
+ RRF_REVOCATION_CACHE_TTL_MS,
3308
+ RRF_REVOCATION_URL,
2817
3309
  RegistryClient,
2818
3310
  RegistryTier,
2819
3311
  ReplayCache,
2820
3312
  RevocationCache,
2821
3313
  RobotURI,
2822
3314
  RobotURIError,
3315
+ Role,
2823
3316
  SAFETY_MESSAGE_TYPE,
3317
+ SCOPE_MIN_ROLE,
2824
3318
  SDK_VERSION,
2825
3319
  SPEC_VERSION,
2826
3320
  TransportEncoding,
@@ -2831,6 +3325,9 @@ var RCAN_VERSION = "1.6";
2831
3325
  addMediaInline,
2832
3326
  addMediaRef,
2833
3327
  assertClockSynced,
3328
+ authorityAccessFromWire,
3329
+ authorityAccessToWire,
3330
+ canonicalManifestJson,
2834
3331
  checkClockSync,
2835
3332
  checkRevocation,
2836
3333
  decodeBleFrames,
@@ -2839,21 +3336,34 @@ var RCAN_VERSION = "1.6";
2839
3336
  encodeBleFrames,
2840
3337
  encodeCompact,
2841
3338
  encodeMinimal,
3339
+ extractIdentityFromJwt,
2842
3340
  extractLoaFromJwt,
3341
+ extractRoleFromJwt,
2843
3342
  fetchCanonicalSchema,
3343
+ fetchRRFRevocations,
3344
+ isAuthorityRequestValid,
3345
+ isM2mTrustedRevoked,
3346
+ isPreemptedBy,
2844
3347
  isSafetyMessage,
2845
3348
  makeCloudRelayMessage,
3349
+ makeCompetitionEnter,
3350
+ makeCompetitionScore,
2846
3351
  makeConfigUpdate,
2847
3352
  makeConsentDeny,
2848
3353
  makeConsentGrant,
2849
3354
  makeConsentRequest,
3355
+ makeContributeCancel,
3356
+ makeContributeRequest,
3357
+ makeContributeResult,
2850
3358
  makeEstopMessage,
2851
3359
  makeEstopWithQoS,
2852
3360
  makeFaultReport,
2853
3361
  makeFederationSync,
2854
3362
  makeKeyRotationMessage,
3363
+ makePersonalResearchResult,
2855
3364
  makeResumeMessage,
2856
3365
  makeRevocationBroadcast,
3366
+ makeSeasonStanding,
2857
3367
  makeStopMessage,
2858
3368
  makeStreamChunk,
2859
3369
  makeTrainingConsentDeny,
@@ -2861,21 +3371,33 @@ var RCAN_VERSION = "1.6";
2861
3371
  makeTrainingConsentRequest,
2862
3372
  makeTrainingDataMessage,
2863
3373
  makeTransparencyMessage,
3374
+ manifestFromWire,
3375
+ manifestToWire,
3376
+ parseM2mPeerToken,
3377
+ parseM2mTrustedToken,
3378
+ roleFromJwtLevel,
2864
3379
  selectTransport,
3380
+ validateAuthorityAccess,
3381
+ validateCompetitionScope,
2865
3382
  validateConfig,
2866
3383
  validateConfigAgainstSchema,
2867
3384
  validateConfigUpdate,
2868
3385
  validateConsentMessage,
3386
+ validateContributeScope,
2869
3387
  validateCrossRegistryCommand,
2870
3388
  validateDelegationChain,
2871
3389
  validateLoaForScope,
3390
+ validateManifest,
2872
3391
  validateMediaChunks,
2873
3392
  validateMessage,
2874
3393
  validateNodeAgainstSchema,
2875
3394
  validateReplay,
3395
+ validateRoleForScope,
2876
3396
  validateSafetyMessage,
2877
3397
  validateTrainingDataMessage,
2878
3398
  validateURI,
2879
- validateVersionCompat
3399
+ validateVersionCompat,
3400
+ verifyM2mTrustedToken,
3401
+ verifyM2mTrustedTokenClaims
2880
3402
  });
2881
3403
  //# sourceMappingURL=index.js.map