@continuonai/rcan-ts 0.8.0 → 1.2.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/README.md +1 -0
- package/dist/browser.d.mts +482 -39
- package/dist/browser.mjs +627 -73
- package/dist/browser.mjs.map +1 -1
- package/dist/index.d.mts +482 -39
- package/dist/index.d.ts +482 -39
- package/dist/index.js +665 -74
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +627 -73
- package/dist/index.mjs.map +1 -1
- package/dist/rcan-validate.js +22 -2
- package/dist/rcan.iife.js +16 -3
- package/package.json +28 -5
package/dist/browser.mjs
CHANGED
|
@@ -99,8 +99,8 @@ var RobotURI = class _RobotURI {
|
|
|
99
99
|
};
|
|
100
100
|
|
|
101
101
|
// src/version.ts
|
|
102
|
-
var SPEC_VERSION = "
|
|
103
|
-
var SDK_VERSION = "
|
|
102
|
+
var SPEC_VERSION = "2.2.0";
|
|
103
|
+
var SDK_VERSION = "1.2.0";
|
|
104
104
|
function validateVersionCompat(incomingVersion, localVersion = SPEC_VERSION) {
|
|
105
105
|
const parseParts = (v) => {
|
|
106
106
|
const parts = v.split(".");
|
|
@@ -151,9 +151,14 @@ var MessageType = /* @__PURE__ */ ((MessageType2) => {
|
|
|
151
151
|
MessageType2[MessageType2["CONTRIBUTE_RESULT"] = 34] = "CONTRIBUTE_RESULT";
|
|
152
152
|
MessageType2[MessageType2["CONTRIBUTE_CANCEL"] = 35] = "CONTRIBUTE_CANCEL";
|
|
153
153
|
MessageType2[MessageType2["TRAINING_DATA"] = 36] = "TRAINING_DATA";
|
|
154
|
-
MessageType2[MessageType2["
|
|
155
|
-
MessageType2[MessageType2["
|
|
156
|
-
MessageType2[MessageType2["
|
|
154
|
+
MessageType2[MessageType2["COMPETITION_ENTER"] = 37] = "COMPETITION_ENTER";
|
|
155
|
+
MessageType2[MessageType2["COMPETITION_SCORE"] = 38] = "COMPETITION_SCORE";
|
|
156
|
+
MessageType2[MessageType2["SEASON_STANDING"] = 39] = "SEASON_STANDING";
|
|
157
|
+
MessageType2[MessageType2["PERSONAL_RESEARCH_RESULT"] = 40] = "PERSONAL_RESEARCH_RESULT";
|
|
158
|
+
MessageType2[MessageType2["AUTHORITY_ACCESS"] = 41] = "AUTHORITY_ACCESS";
|
|
159
|
+
MessageType2[MessageType2["AUTHORITY_RESPONSE"] = 42] = "AUTHORITY_RESPONSE";
|
|
160
|
+
MessageType2[MessageType2["FIRMWARE_ATTESTATION"] = 43] = "FIRMWARE_ATTESTATION";
|
|
161
|
+
MessageType2[MessageType2["SBOM_UPDATE"] = 44] = "SBOM_UPDATE";
|
|
157
162
|
return MessageType2;
|
|
158
163
|
})(MessageType || {});
|
|
159
164
|
var RCANMessageError = class extends Error {
|
|
@@ -190,6 +195,12 @@ var RCANMessage = class _RCANMessage {
|
|
|
190
195
|
__publicField(this, "transportEncoding");
|
|
191
196
|
/** v1.6: GAP-18 multi-modal media chunks */
|
|
192
197
|
__publicField(this, "mediaChunks");
|
|
198
|
+
/** v2.1: SHA-256 of sender's firmware manifest */
|
|
199
|
+
__publicField(this, "firmwareHash");
|
|
200
|
+
/** v2.1: URI to sender's SBOM attestation endpoint */
|
|
201
|
+
__publicField(this, "attestationRef");
|
|
202
|
+
/** v2.2: ML-DSA-65 post-quantum signature (field 16, FIPS 204). Hybrid alongside Ed25519. */
|
|
203
|
+
__publicField(this, "pqSig");
|
|
193
204
|
if (!data.cmd || data.cmd.trim() === "") {
|
|
194
205
|
throw new RCANMessageError("'cmd' is required");
|
|
195
206
|
}
|
|
@@ -217,6 +228,14 @@ var RCANMessage = class _RCANMessage {
|
|
|
217
228
|
this.loa = data.loa;
|
|
218
229
|
this.transportEncoding = data.transportEncoding;
|
|
219
230
|
this.mediaChunks = data.mediaChunks;
|
|
231
|
+
this.firmwareHash = data.firmwareHash;
|
|
232
|
+
this.attestationRef = data.attestationRef;
|
|
233
|
+
this.pqSig = data.pqSig;
|
|
234
|
+
if (this.signature !== void 0 && this.signature["sig"] === "pending") {
|
|
235
|
+
throw new RCANMessageError(
|
|
236
|
+
"signature.sig:'pending' is not valid in RCAN v2.1. Sign the message before sending."
|
|
237
|
+
);
|
|
238
|
+
}
|
|
220
239
|
if (this.confidence !== void 0) {
|
|
221
240
|
if (this.confidence < 0 || this.confidence > 1) {
|
|
222
241
|
throw new RCANMessageError(
|
|
@@ -258,6 +277,9 @@ var RCANMessage = class _RCANMessage {
|
|
|
258
277
|
if (this.loa !== void 0) obj.loa = this.loa;
|
|
259
278
|
if (this.transportEncoding !== void 0) obj.transportEncoding = this.transportEncoding;
|
|
260
279
|
if (this.mediaChunks !== void 0) obj.mediaChunks = this.mediaChunks;
|
|
280
|
+
if (this.firmwareHash !== void 0) obj.firmwareHash = this.firmwareHash;
|
|
281
|
+
if (this.attestationRef !== void 0) obj.attestationRef = this.attestationRef;
|
|
282
|
+
if (this.pqSig !== void 0) obj.pqSig = this.pqSig;
|
|
261
283
|
return obj;
|
|
262
284
|
}
|
|
263
285
|
/** Serialize to JSON string */
|
|
@@ -300,7 +322,10 @@ var RCANMessage = class _RCANMessage {
|
|
|
300
322
|
readOnly: obj.readOnly,
|
|
301
323
|
loa: obj.loa,
|
|
302
324
|
transportEncoding: obj.transportEncoding,
|
|
303
|
-
mediaChunks: obj.mediaChunks
|
|
325
|
+
mediaChunks: obj.mediaChunks,
|
|
326
|
+
firmwareHash: obj.firmwareHash,
|
|
327
|
+
attestationRef: obj.attestationRef,
|
|
328
|
+
pqSig: obj.pqSig
|
|
304
329
|
});
|
|
305
330
|
}
|
|
306
331
|
};
|
|
@@ -2060,80 +2085,133 @@ function makeFaultReport(params) {
|
|
|
2060
2085
|
}
|
|
2061
2086
|
|
|
2062
2087
|
// src/identity.ts
|
|
2063
|
-
var
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2088
|
+
var Role = /* @__PURE__ */ ((Role2) => {
|
|
2089
|
+
Role2[Role2["GUEST"] = 1] = "GUEST";
|
|
2090
|
+
Role2[Role2["OPERATOR"] = 2] = "OPERATOR";
|
|
2091
|
+
Role2[Role2["CONTRIBUTOR"] = 3] = "CONTRIBUTOR";
|
|
2092
|
+
Role2[Role2["ADMIN"] = 4] = "ADMIN";
|
|
2093
|
+
Role2[Role2["M2M_PEER"] = 5] = "M2M_PEER";
|
|
2094
|
+
Role2[Role2["CREATOR"] = 6] = "CREATOR";
|
|
2095
|
+
Role2[Role2["M2M_TRUSTED"] = 7] = "M2M_TRUSTED";
|
|
2096
|
+
return Role2;
|
|
2097
|
+
})(Role || {});
|
|
2098
|
+
var LevelOfAssurance = Role;
|
|
2099
|
+
var ROLE_JWT_LEVEL = {
|
|
2100
|
+
[1 /* GUEST */]: 1,
|
|
2101
|
+
[2 /* OPERATOR */]: 2,
|
|
2102
|
+
[3 /* CONTRIBUTOR */]: 2.5,
|
|
2103
|
+
[4 /* ADMIN */]: 3,
|
|
2104
|
+
[5 /* M2M_PEER */]: 4,
|
|
2105
|
+
[6 /* CREATOR */]: 5,
|
|
2106
|
+
[7 /* M2M_TRUSTED */]: 6
|
|
2107
|
+
};
|
|
2108
|
+
var JWT_LEVEL_TO_ROLE = new Map(
|
|
2109
|
+
Object.entries(ROLE_JWT_LEVEL).map(
|
|
2110
|
+
([role, level]) => [level, Number(role)]
|
|
2111
|
+
)
|
|
2112
|
+
);
|
|
2113
|
+
function roleFromJwtLevel(level) {
|
|
2114
|
+
return JWT_LEVEL_TO_ROLE.get(level);
|
|
2115
|
+
}
|
|
2116
|
+
var SCOPE_MIN_ROLE = {
|
|
2117
|
+
"status": 1 /* GUEST */,
|
|
2118
|
+
"discover": 1 /* GUEST */,
|
|
2119
|
+
"chat": 1 /* GUEST */,
|
|
2120
|
+
"observer": 1 /* GUEST */,
|
|
2121
|
+
"contribute": 3 /* CONTRIBUTOR */,
|
|
2122
|
+
"control": 2 /* OPERATOR */,
|
|
2123
|
+
"teleop": 2 /* OPERATOR */,
|
|
2124
|
+
"training": 4 /* ADMIN */,
|
|
2125
|
+
"training_data": 4 /* ADMIN */,
|
|
2126
|
+
"config": 4 /* ADMIN */,
|
|
2127
|
+
"authority": 4 /* ADMIN */,
|
|
2128
|
+
"admin": 6 /* CREATOR */,
|
|
2129
|
+
"safety": 6 /* CREATOR */,
|
|
2130
|
+
"estop": 6 /* CREATOR */,
|
|
2131
|
+
"fleet.trusted": 7 /* M2M_TRUSTED */
|
|
2132
|
+
};
|
|
2069
2133
|
var DEFAULT_LOA_POLICY = {
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2134
|
+
minRoleForDiscover: 1 /* GUEST */,
|
|
2135
|
+
minRoleForStatus: 1 /* GUEST */,
|
|
2136
|
+
minRoleForChat: 1 /* GUEST */,
|
|
2137
|
+
minRoleForControl: 1 /* GUEST */,
|
|
2138
|
+
minRoleForSafety: 1 /* GUEST */
|
|
2075
2139
|
};
|
|
2076
2140
|
var PRODUCTION_LOA_POLICY = {
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2141
|
+
minRoleForDiscover: 1 /* GUEST */,
|
|
2142
|
+
minRoleForStatus: 1 /* GUEST */,
|
|
2143
|
+
minRoleForChat: 1 /* GUEST */,
|
|
2144
|
+
minRoleForControl: 2 /* OPERATOR */,
|
|
2145
|
+
minRoleForSafety: 6 /* CREATOR */
|
|
2082
2146
|
};
|
|
2083
|
-
function
|
|
2147
|
+
function decodeJwtPayload(token) {
|
|
2084
2148
|
try {
|
|
2085
2149
|
const parts = token.split(".");
|
|
2086
|
-
if (parts.length < 2) return
|
|
2150
|
+
if (parts.length < 2) return null;
|
|
2087
2151
|
const payloadB64 = (parts[1] ?? "").replace(/-/g, "+").replace(/_/g, "/");
|
|
2088
2152
|
const padded = payloadB64 + "=".repeat((4 - payloadB64.length % 4) % 4);
|
|
2089
|
-
|
|
2090
|
-
if (typeof atob !== "undefined") {
|
|
2091
|
-
json = atob(padded);
|
|
2092
|
-
} else {
|
|
2093
|
-
json = Buffer.from(padded, "base64").toString("utf-8");
|
|
2094
|
-
}
|
|
2095
|
-
const claims = JSON.parse(json);
|
|
2096
|
-
const loa = claims["loa"];
|
|
2097
|
-
if (typeof loa === "number" && loa >= 1 && loa <= 3) {
|
|
2098
|
-
return loa;
|
|
2099
|
-
}
|
|
2153
|
+
return JSON.parse(atob(padded));
|
|
2100
2154
|
} catch {
|
|
2155
|
+
return null;
|
|
2101
2156
|
}
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
return policy.minLoaStatus;
|
|
2111
|
-
case "chat":
|
|
2112
|
-
return policy.minLoaChat;
|
|
2113
|
-
case "contribute":
|
|
2114
|
-
return policy.minLoaChat;
|
|
2115
|
-
// v1.7: between chat and control
|
|
2116
|
-
case "control":
|
|
2117
|
-
return policy.minLoaControl;
|
|
2118
|
-
case "safety":
|
|
2119
|
-
return policy.minLoaSafety;
|
|
2120
|
-
default:
|
|
2121
|
-
return null;
|
|
2122
|
-
}
|
|
2123
|
-
}
|
|
2124
|
-
function validateLoaForScope(loa, scope, policy = DEFAULT_LOA_POLICY) {
|
|
2125
|
-
const min = minLoaForScope(scope, policy);
|
|
2126
|
-
if (min === null) {
|
|
2127
|
-
return { valid: true, reason: "unknown scope; allowed by default" };
|
|
2128
|
-
}
|
|
2129
|
-
if (loa >= min) {
|
|
2130
|
-
return { valid: true, reason: "ok" };
|
|
2157
|
+
}
|
|
2158
|
+
function extractRoleFromJwt(token) {
|
|
2159
|
+
const payload = decodeJwtPayload(token);
|
|
2160
|
+
if (!payload) return 1 /* GUEST */;
|
|
2161
|
+
const rcanRole = payload["rcan_role"];
|
|
2162
|
+
if (rcanRole !== void 0 && rcanRole !== null) {
|
|
2163
|
+
const role = roleFromJwtLevel(Number(rcanRole));
|
|
2164
|
+
if (role !== void 0) return role;
|
|
2131
2165
|
}
|
|
2166
|
+
const loa = payload["loa"];
|
|
2167
|
+
if (loa !== void 0 && loa !== null) {
|
|
2168
|
+
const role = roleFromJwtLevel(Number(loa));
|
|
2169
|
+
if (role !== void 0) return role;
|
|
2170
|
+
}
|
|
2171
|
+
return 1 /* GUEST */;
|
|
2172
|
+
}
|
|
2173
|
+
function extractLoaFromJwt(token) {
|
|
2174
|
+
return extractRoleFromJwt(token);
|
|
2175
|
+
}
|
|
2176
|
+
function extractIdentityFromJwt(token) {
|
|
2177
|
+
const payload = decodeJwtPayload(token);
|
|
2178
|
+
if (!payload) {
|
|
2179
|
+
return { sub: "", role: 1 /* GUEST */, jwtLevel: 1, scopes: [] };
|
|
2180
|
+
}
|
|
2181
|
+
const rcanRole = payload["rcan_role"];
|
|
2182
|
+
const loa = payload["loa"];
|
|
2183
|
+
const rawLevel = rcanRole !== void 0 ? Number(rcanRole) : loa !== void 0 ? Number(loa) : 1;
|
|
2184
|
+
const role = roleFromJwtLevel(rawLevel) ?? 1 /* GUEST */;
|
|
2185
|
+
const scopes = Array.isArray(payload["rcan_scopes"]) ? payload["rcan_scopes"] : Array.isArray(payload["scopes"]) ? payload["scopes"] : [];
|
|
2132
2186
|
return {
|
|
2133
|
-
|
|
2134
|
-
|
|
2187
|
+
sub: String(payload["sub"] ?? ""),
|
|
2188
|
+
role,
|
|
2189
|
+
jwtLevel: ROLE_JWT_LEVEL[role],
|
|
2190
|
+
registryUrl: payload["registry_url"],
|
|
2191
|
+
scopes,
|
|
2192
|
+
verifiedAt: payload["verified_at"],
|
|
2193
|
+
peerRrn: payload["peer_rrn"],
|
|
2194
|
+
fleetRrns: Array.isArray(payload["fleet_rrns"]) ? payload["fleet_rrns"] : void 0
|
|
2135
2195
|
};
|
|
2136
2196
|
}
|
|
2197
|
+
function validateRoleForScope(role, scope) {
|
|
2198
|
+
const required = SCOPE_MIN_ROLE[scope.toLowerCase()];
|
|
2199
|
+
if (required === void 0) {
|
|
2200
|
+
if (role >= 2 /* OPERATOR */) return { ok: true, reason: "" };
|
|
2201
|
+
return {
|
|
2202
|
+
ok: false,
|
|
2203
|
+
reason: `Unknown scope '${scope}': applying OPERATOR minimum. Caller has ${Role[role]}.`
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
if (role >= required) return { ok: true, reason: "" };
|
|
2207
|
+
return {
|
|
2208
|
+
ok: false,
|
|
2209
|
+
reason: `Scope '${scope}' requires ${Role[required]} (JWT level ${ROLE_JWT_LEVEL[required]}), but caller has ${Role[role]} (JWT level ${ROLE_JWT_LEVEL[role]})`
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
function validateLoaForScope(role, scope) {
|
|
2213
|
+
return validateRoleForScope(role, scope);
|
|
2214
|
+
}
|
|
2137
2215
|
|
|
2138
2216
|
// src/federation.ts
|
|
2139
2217
|
var RegistryTier = /* @__PURE__ */ ((RegistryTier2) => {
|
|
@@ -2259,12 +2337,12 @@ function generateId5() {
|
|
|
2259
2337
|
}
|
|
2260
2338
|
function makeFederationSync(source, target, syncType, payload) {
|
|
2261
2339
|
return new RCANMessage({
|
|
2262
|
-
rcan: "1.
|
|
2263
|
-
rcanVersion: "1.
|
|
2340
|
+
rcan: "2.1.0",
|
|
2341
|
+
rcanVersion: "2.1.0",
|
|
2264
2342
|
cmd: "federation_sync",
|
|
2265
2343
|
target,
|
|
2266
2344
|
params: {
|
|
2267
|
-
msg_type: 23 /*
|
|
2345
|
+
msg_type: 23 /* FLEET_COMMAND */,
|
|
2268
2346
|
msg_id: generateId5(),
|
|
2269
2347
|
source_registry: source,
|
|
2270
2348
|
target_registry: target,
|
|
@@ -2291,17 +2369,17 @@ async function validateCrossRegistryCommand(msg, localRegistry, trustCache) {
|
|
|
2291
2369
|
reason: `REGISTRY_UNKNOWN: ${sourceRegistry} is not in the local trust cache`
|
|
2292
2370
|
};
|
|
2293
2371
|
}
|
|
2294
|
-
let loa = 1 /*
|
|
2372
|
+
let loa = 1 /* GUEST */;
|
|
2295
2373
|
const registryJwt = msg.params?.["registry_jwt"];
|
|
2296
2374
|
if (registryJwt) {
|
|
2297
2375
|
loa = extractLoaFromJwt(registryJwt);
|
|
2298
2376
|
} else if (typeof msg.loa === "number") {
|
|
2299
2377
|
loa = msg.loa;
|
|
2300
2378
|
}
|
|
2301
|
-
if (loa < 2 /*
|
|
2379
|
+
if (loa < 2 /* OPERATOR */) {
|
|
2302
2380
|
return {
|
|
2303
2381
|
valid: false,
|
|
2304
|
-
reason: `LOA_INSUFFICIENT: cross-registry commands require LoA>=2 (
|
|
2382
|
+
reason: `LOA_INSUFFICIENT: cross-registry commands require LoA>=2 (OPERATOR), got role=${loa}`
|
|
2305
2383
|
};
|
|
2306
2384
|
}
|
|
2307
2385
|
return { valid: true, reason: "cross-registry command accepted" };
|
|
@@ -2740,24 +2818,470 @@ function isPreemptedBy(scopeLevel) {
|
|
|
2740
2818
|
return scopeLevel >= 3;
|
|
2741
2819
|
}
|
|
2742
2820
|
|
|
2821
|
+
// src/competition.ts
|
|
2822
|
+
var COMPETITION_SCOPE_LEVEL = 2;
|
|
2823
|
+
var _idCounter2 = 0;
|
|
2824
|
+
function _generateRunId() {
|
|
2825
|
+
return `run-${Date.now()}-${++_idCounter2}`;
|
|
2826
|
+
}
|
|
2827
|
+
function makeCompetitionEnter(params = {}) {
|
|
2828
|
+
return {
|
|
2829
|
+
type: 37 /* COMPETITION_ENTER */,
|
|
2830
|
+
competition_id: params.competition_id ?? "",
|
|
2831
|
+
competition_format: params.competition_format ?? "sprint",
|
|
2832
|
+
hardware_tier: params.hardware_tier ?? "",
|
|
2833
|
+
model_id: params.model_id ?? "",
|
|
2834
|
+
robot_rrn: params.robot_rrn ?? "",
|
|
2835
|
+
entered_at: params.entered_at ?? Date.now() / 1e3
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
function makeCompetitionScore(params = {}) {
|
|
2839
|
+
const score = params.score ?? 0;
|
|
2840
|
+
if (score < 0 || score > 1) {
|
|
2841
|
+
throw new Error(`score must be in [0.0, 1.0], got ${score}`);
|
|
2842
|
+
}
|
|
2843
|
+
return {
|
|
2844
|
+
type: 38 /* COMPETITION_SCORE */,
|
|
2845
|
+
competition_id: params.competition_id ?? "",
|
|
2846
|
+
candidate_id: params.candidate_id ?? "",
|
|
2847
|
+
score,
|
|
2848
|
+
hardware_tier: params.hardware_tier ?? "",
|
|
2849
|
+
verified: params.verified ?? false,
|
|
2850
|
+
submitted_at: params.submitted_at ?? Date.now() / 1e3
|
|
2851
|
+
};
|
|
2852
|
+
}
|
|
2853
|
+
function makeSeasonStanding(params = {}) {
|
|
2854
|
+
return {
|
|
2855
|
+
type: 39 /* SEASON_STANDING */,
|
|
2856
|
+
season_id: params.season_id ?? "",
|
|
2857
|
+
class_id: params.class_id ?? "",
|
|
2858
|
+
standings: params.standings ?? [],
|
|
2859
|
+
days_remaining: params.days_remaining ?? 0,
|
|
2860
|
+
broadcast_at: params.broadcast_at ?? Date.now() / 1e3
|
|
2861
|
+
};
|
|
2862
|
+
}
|
|
2863
|
+
function makePersonalResearchResult(params = {}) {
|
|
2864
|
+
const score = params.score ?? 0;
|
|
2865
|
+
if (score < 0 || score > 1) {
|
|
2866
|
+
throw new Error(`score must be in [0.0, 1.0], got ${score}`);
|
|
2867
|
+
}
|
|
2868
|
+
return {
|
|
2869
|
+
type: 40 /* PERSONAL_RESEARCH_RESULT */,
|
|
2870
|
+
run_id: params.run_id ?? _generateRunId(),
|
|
2871
|
+
run_type: params.run_type ?? "personal",
|
|
2872
|
+
candidate_id: params.candidate_id ?? "",
|
|
2873
|
+
score,
|
|
2874
|
+
hardware_tier: params.hardware_tier ?? "",
|
|
2875
|
+
model_id: params.model_id ?? "",
|
|
2876
|
+
owner_uid: params.owner_uid ?? "",
|
|
2877
|
+
metrics: params.metrics ?? {
|
|
2878
|
+
success_rate: 0,
|
|
2879
|
+
p66_rate: 0,
|
|
2880
|
+
token_efficiency: 0,
|
|
2881
|
+
latency_score: 0
|
|
2882
|
+
},
|
|
2883
|
+
submitted_to_community: params.submitted_to_community ?? false,
|
|
2884
|
+
created_at: params.created_at ?? Date.now() / 1e3
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
function validateCompetitionScope(scopeLevel) {
|
|
2888
|
+
return scopeLevel >= COMPETITION_SCOPE_LEVEL;
|
|
2889
|
+
}
|
|
2890
|
+
|
|
2891
|
+
// src/firmware.ts
|
|
2892
|
+
var FIRMWARE_MANIFEST_PATH = "/.well-known/rcan-firmware-manifest.json";
|
|
2893
|
+
function manifestToWire(m) {
|
|
2894
|
+
const wire = {
|
|
2895
|
+
rrn: m.rrn,
|
|
2896
|
+
firmware_version: m.firmwareVersion,
|
|
2897
|
+
build_hash: m.buildHash,
|
|
2898
|
+
components: m.components,
|
|
2899
|
+
signed_at: m.signedAt
|
|
2900
|
+
};
|
|
2901
|
+
if (m.signature) wire.signature = m.signature;
|
|
2902
|
+
return wire;
|
|
2903
|
+
}
|
|
2904
|
+
function manifestFromWire(w) {
|
|
2905
|
+
return {
|
|
2906
|
+
rrn: w.rrn,
|
|
2907
|
+
firmwareVersion: w.firmware_version,
|
|
2908
|
+
buildHash: w.build_hash,
|
|
2909
|
+
components: w.components ?? [],
|
|
2910
|
+
signedAt: w.signed_at ?? "",
|
|
2911
|
+
signature: w.signature
|
|
2912
|
+
};
|
|
2913
|
+
}
|
|
2914
|
+
function canonicalManifestJson(m) {
|
|
2915
|
+
const obj = {
|
|
2916
|
+
build_hash: m.buildHash,
|
|
2917
|
+
components: m.components.map((c) => ({
|
|
2918
|
+
hash: c.hash,
|
|
2919
|
+
name: c.name,
|
|
2920
|
+
version: c.version
|
|
2921
|
+
})),
|
|
2922
|
+
firmware_version: m.firmwareVersion,
|
|
2923
|
+
rrn: m.rrn,
|
|
2924
|
+
signed_at: m.signedAt
|
|
2925
|
+
};
|
|
2926
|
+
return JSON.stringify(obj);
|
|
2927
|
+
}
|
|
2928
|
+
var FirmwareIntegrityError = class extends Error {
|
|
2929
|
+
constructor(message) {
|
|
2930
|
+
super(message);
|
|
2931
|
+
this.name = "FirmwareIntegrityError";
|
|
2932
|
+
}
|
|
2933
|
+
};
|
|
2934
|
+
function validateManifest(m) {
|
|
2935
|
+
const errors = [];
|
|
2936
|
+
if (!m.rrn) errors.push("rrn is required");
|
|
2937
|
+
if (!m.firmwareVersion) errors.push("firmwareVersion is required");
|
|
2938
|
+
if (!m.buildHash) errors.push("buildHash is required");
|
|
2939
|
+
if (!m.buildHash.startsWith("sha256:")) errors.push("buildHash must start with 'sha256:'");
|
|
2940
|
+
if (!m.signedAt) errors.push("signedAt is required");
|
|
2941
|
+
if (!m.signature) errors.push("signature is required (manifest must be signed)");
|
|
2942
|
+
for (const [i, c] of m.components.entries()) {
|
|
2943
|
+
if (!c.name) errors.push(`components[${i}].name is required`);
|
|
2944
|
+
if (!c.version) errors.push(`components[${i}].version is required`);
|
|
2945
|
+
if (!c.hash.startsWith("sha256:")) errors.push(`components[${i}].hash must start with 'sha256:'`);
|
|
2946
|
+
}
|
|
2947
|
+
return errors;
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
// src/authority.ts
|
|
2951
|
+
function authorityAccessToWire(p) {
|
|
2952
|
+
return {
|
|
2953
|
+
request_id: p.requestId,
|
|
2954
|
+
authority_id: p.authorityId,
|
|
2955
|
+
requested_data: p.requestedData,
|
|
2956
|
+
justification: p.justification,
|
|
2957
|
+
expires_at: p.expiresAt
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2960
|
+
function authorityAccessFromWire(w) {
|
|
2961
|
+
return {
|
|
2962
|
+
requestId: w.request_id,
|
|
2963
|
+
authorityId: w.authority_id,
|
|
2964
|
+
requestedData: w.requested_data ?? [],
|
|
2965
|
+
justification: w.justification ?? "",
|
|
2966
|
+
expiresAt: w.expires_at ?? 0
|
|
2967
|
+
};
|
|
2968
|
+
}
|
|
2969
|
+
function validateAuthorityAccess(p) {
|
|
2970
|
+
const errors = [];
|
|
2971
|
+
if (!p.requestId) errors.push("requestId is required");
|
|
2972
|
+
if (!p.authorityId) errors.push("authorityId is required");
|
|
2973
|
+
if (!p.requestedData || p.requestedData.length === 0)
|
|
2974
|
+
errors.push("requestedData must include at least one category");
|
|
2975
|
+
if (!p.justification) errors.push("justification is required");
|
|
2976
|
+
if (!p.expiresAt || p.expiresAt <= 0) errors.push("expiresAt must be a positive Unix timestamp");
|
|
2977
|
+
if (p.expiresAt < Date.now() / 1e3) errors.push("expiresAt is in the past \u2014 request has expired");
|
|
2978
|
+
return errors;
|
|
2979
|
+
}
|
|
2980
|
+
function isAuthorityRequestValid(p) {
|
|
2981
|
+
return Date.now() / 1e3 < p.expiresAt && validateAuthorityAccess(p).length === 0;
|
|
2982
|
+
}
|
|
2983
|
+
var AUTHORITY_ERROR_CODES = {
|
|
2984
|
+
NOT_RECOGNIZED: "AUTHORITY_NOT_RECOGNIZED",
|
|
2985
|
+
REQUEST_EXPIRED: "AUTHORITY_REQUEST_EXPIRED",
|
|
2986
|
+
INVALID_TOKEN: "AUTHORITY_INVALID_TOKEN",
|
|
2987
|
+
RATE_LIMITED: "AUTHORITY_RATE_LIMITED"
|
|
2988
|
+
};
|
|
2989
|
+
|
|
2990
|
+
// src/m2m.ts
|
|
2991
|
+
var RRF_REVOCATION_URL = "https://api.rrf.rcan.dev/v2/revocations";
|
|
2992
|
+
var M2M_TRUSTED_ISSUER = "rrf.rcan.dev";
|
|
2993
|
+
var RRF_REVOCATION_CACHE_TTL_MS = 55e3;
|
|
2994
|
+
var M2MAuthError = class extends Error {
|
|
2995
|
+
constructor(message) {
|
|
2996
|
+
super(message);
|
|
2997
|
+
this.name = "M2MAuthError";
|
|
2998
|
+
}
|
|
2999
|
+
};
|
|
3000
|
+
function decodeJwtPayload2(token) {
|
|
3001
|
+
const parts = token.split(".");
|
|
3002
|
+
if (parts.length < 2) throw new M2MAuthError("Invalid JWT structure");
|
|
3003
|
+
const b64 = (parts[1] ?? "").replace(/-/g, "+").replace(/_/g, "/");
|
|
3004
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
3005
|
+
try {
|
|
3006
|
+
return JSON.parse(atob(padded));
|
|
3007
|
+
} catch (e) {
|
|
3008
|
+
throw new M2MAuthError(`JWT payload decode failed: ${String(e)}`);
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
function parseM2mPeerToken(token) {
|
|
3012
|
+
const payload = decodeJwtPayload2(token);
|
|
3013
|
+
const exp = Number(payload["exp"] ?? 0);
|
|
3014
|
+
if (exp > 0 && Date.now() / 1e3 > exp) {
|
|
3015
|
+
throw new M2MAuthError(`M2M_PEER token expired (sub=${String(payload["sub"])})`);
|
|
3016
|
+
}
|
|
3017
|
+
const peerRrn = String(payload["peer_rrn"] ?? "");
|
|
3018
|
+
if (!peerRrn) throw new M2MAuthError("M2M_PEER token missing peer_rrn claim");
|
|
3019
|
+
return {
|
|
3020
|
+
sub: String(payload["sub"] ?? ""),
|
|
3021
|
+
peerRrn,
|
|
3022
|
+
scopes: Array.isArray(payload["rcan_scopes"]) ? payload["rcan_scopes"] : Array.isArray(payload["scopes"]) ? payload["scopes"] : [],
|
|
3023
|
+
exp,
|
|
3024
|
+
iss: String(payload["iss"] ?? "")
|
|
3025
|
+
};
|
|
3026
|
+
}
|
|
3027
|
+
function parseM2mTrustedToken(token) {
|
|
3028
|
+
const payload = decodeJwtPayload2(token);
|
|
3029
|
+
const iss = String(payload["iss"] ?? "");
|
|
3030
|
+
if (iss !== M2M_TRUSTED_ISSUER) {
|
|
3031
|
+
throw new M2MAuthError(
|
|
3032
|
+
`M2M_TRUSTED issuer must be '${M2M_TRUSTED_ISSUER}', got '${iss}'`
|
|
3033
|
+
);
|
|
3034
|
+
}
|
|
3035
|
+
const scopes = Array.isArray(payload["rcan_scopes"]) ? payload["rcan_scopes"] : Array.isArray(payload["scopes"]) ? payload["scopes"] : [];
|
|
3036
|
+
if (!scopes.includes("fleet.trusted")) {
|
|
3037
|
+
throw new M2MAuthError("M2M_TRUSTED token missing required 'fleet.trusted' scope");
|
|
3038
|
+
}
|
|
3039
|
+
const exp = Number(payload["exp"] ?? 0);
|
|
3040
|
+
if (exp > 0 && Date.now() / 1e3 > exp) {
|
|
3041
|
+
throw new M2MAuthError(`M2M_TRUSTED token expired (sub=${String(payload["sub"])})`);
|
|
3042
|
+
}
|
|
3043
|
+
const rrfSig = String(payload["rrf_sig"] ?? "");
|
|
3044
|
+
if (!rrfSig) throw new M2MAuthError("M2M_TRUSTED token missing rrf_sig claim");
|
|
3045
|
+
const fleetRrns = Array.isArray(payload["fleet_rrns"]) ? payload["fleet_rrns"] : [];
|
|
3046
|
+
return {
|
|
3047
|
+
sub: String(payload["sub"] ?? ""),
|
|
3048
|
+
fleetRrns,
|
|
3049
|
+
scopes,
|
|
3050
|
+
exp,
|
|
3051
|
+
iss,
|
|
3052
|
+
rrfSig
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
3055
|
+
function verifyM2mTrustedTokenClaims(token, targetRrn) {
|
|
3056
|
+
const claims = parseM2mTrustedToken(token);
|
|
3057
|
+
if (!claims.fleetRrns.includes(targetRrn)) {
|
|
3058
|
+
throw new M2MAuthError(
|
|
3059
|
+
`M2M_TRUSTED token does not authorize commanding '${targetRrn}'. Authorized fleet: [${claims.fleetRrns.join(", ")}]`
|
|
3060
|
+
);
|
|
3061
|
+
}
|
|
3062
|
+
return claims;
|
|
3063
|
+
}
|
|
3064
|
+
var _revocationCache = null;
|
|
3065
|
+
async function fetchRRFRevocations(url = RRF_REVOCATION_URL) {
|
|
3066
|
+
const now = Date.now();
|
|
3067
|
+
if (_revocationCache && now - _revocationCache.fetchedAt < RRF_REVOCATION_CACHE_TTL_MS) {
|
|
3068
|
+
return _revocationCache;
|
|
3069
|
+
}
|
|
3070
|
+
try {
|
|
3071
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout?.(5e3) });
|
|
3072
|
+
const data = await resp.json();
|
|
3073
|
+
_revocationCache = {
|
|
3074
|
+
revokedOrchestrators: new Set(data.revoked_orchestrators ?? []),
|
|
3075
|
+
revokedJtis: new Set(data.revoked_jtis ?? []),
|
|
3076
|
+
fetchedAt: now
|
|
3077
|
+
};
|
|
3078
|
+
} catch {
|
|
3079
|
+
if (_revocationCache) return _revocationCache;
|
|
3080
|
+
_revocationCache = { revokedOrchestrators: /* @__PURE__ */ new Set(), revokedJtis: /* @__PURE__ */ new Set(), fetchedAt: now };
|
|
3081
|
+
}
|
|
3082
|
+
return _revocationCache;
|
|
3083
|
+
}
|
|
3084
|
+
async function isM2mTrustedRevoked(claims, jti) {
|
|
3085
|
+
const cache = await fetchRRFRevocations();
|
|
3086
|
+
if (cache.revokedOrchestrators.has(claims.sub)) return true;
|
|
3087
|
+
if (jti && cache.revokedJtis.has(jti)) return true;
|
|
3088
|
+
return false;
|
|
3089
|
+
}
|
|
3090
|
+
async function verifyM2mTrustedToken(token, targetRrn, options) {
|
|
3091
|
+
const claims = verifyM2mTrustedTokenClaims(token, targetRrn);
|
|
3092
|
+
if (!options?.skipRevocationCheck) {
|
|
3093
|
+
const revoked = await isM2mTrustedRevoked(claims);
|
|
3094
|
+
if (revoked) {
|
|
3095
|
+
throw new M2MAuthError(
|
|
3096
|
+
`M2M_TRUSTED orchestrator '${claims.sub}' is on the RRF revocation list`
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
return claims;
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
// src/pqSigning.ts
|
|
3104
|
+
function toBase64url(bytes) {
|
|
3105
|
+
let binary = "";
|
|
3106
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
3107
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
3108
|
+
}
|
|
3109
|
+
function fromBase64url(b64) {
|
|
3110
|
+
const padded = b64.replace(/-/g, "+").replace(/_/g, "/");
|
|
3111
|
+
const binary = atob(padded);
|
|
3112
|
+
const bytes = new Uint8Array(binary.length);
|
|
3113
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
3114
|
+
return bytes;
|
|
3115
|
+
}
|
|
3116
|
+
async function sha256hex(data) {
|
|
3117
|
+
const g = typeof globalThis !== "undefined" ? globalThis : {};
|
|
3118
|
+
const webcrypto = g.crypto;
|
|
3119
|
+
const subtle = webcrypto?.subtle;
|
|
3120
|
+
if (subtle) {
|
|
3121
|
+
const buf = await subtle.digest("SHA-256", data);
|
|
3122
|
+
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
|
|
3123
|
+
}
|
|
3124
|
+
const nodeCrypto = await import("crypto").catch(() => null);
|
|
3125
|
+
if (nodeCrypto) {
|
|
3126
|
+
return nodeCrypto.createHash("sha256").update(data).digest("hex").slice(0, 8);
|
|
3127
|
+
}
|
|
3128
|
+
throw new Error("No SHA-256 implementation available");
|
|
3129
|
+
}
|
|
3130
|
+
var _mlDsaModule;
|
|
3131
|
+
async function requireNoblePostQuantum() {
|
|
3132
|
+
if (_mlDsaModule) return _mlDsaModule;
|
|
3133
|
+
if (typeof __require !== "undefined") {
|
|
3134
|
+
try {
|
|
3135
|
+
_mlDsaModule = __require("@noble/post-quantum/ml-dsa.js");
|
|
3136
|
+
return _mlDsaModule;
|
|
3137
|
+
} catch {
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
try {
|
|
3141
|
+
_mlDsaModule = await import("@noble/post-quantum/ml-dsa.js");
|
|
3142
|
+
return _mlDsaModule;
|
|
3143
|
+
} catch {
|
|
3144
|
+
throw new Error(
|
|
3145
|
+
"ML-DSA signing requires @noble/post-quantum. Install with: npm install @noble/post-quantum"
|
|
3146
|
+
);
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
var MLDSAKeyPair = class _MLDSAKeyPair {
|
|
3150
|
+
constructor(data) {
|
|
3151
|
+
__publicField(this, "keyId");
|
|
3152
|
+
__publicField(this, "publicKey");
|
|
3153
|
+
__publicField(this, "secretKey");
|
|
3154
|
+
this.keyId = data.keyId;
|
|
3155
|
+
this.publicKey = data.publicKey;
|
|
3156
|
+
this.secretKey = data.secretKey;
|
|
3157
|
+
}
|
|
3158
|
+
/** Generate a new ML-DSA-65 key pair. */
|
|
3159
|
+
static async generate() {
|
|
3160
|
+
const { ml_dsa65 } = await requireNoblePostQuantum();
|
|
3161
|
+
const kp = ml_dsa65.keygen();
|
|
3162
|
+
const keyId = await sha256hex(kp.publicKey);
|
|
3163
|
+
return new _MLDSAKeyPair({
|
|
3164
|
+
publicKey: kp.publicKey,
|
|
3165
|
+
secretKey: kp.secretKey,
|
|
3166
|
+
keyId
|
|
3167
|
+
});
|
|
3168
|
+
}
|
|
3169
|
+
/** Build a verify-only key pair from raw public key bytes. */
|
|
3170
|
+
static async fromPublicKey(publicKey) {
|
|
3171
|
+
const keyId = await sha256hex(publicKey);
|
|
3172
|
+
return new _MLDSAKeyPair({ publicKey, keyId });
|
|
3173
|
+
}
|
|
3174
|
+
/** Build a full key pair from saved bytes (public + secret). */
|
|
3175
|
+
static async fromKeyMaterial(publicKey, secretKey) {
|
|
3176
|
+
const keyId = await sha256hex(publicKey);
|
|
3177
|
+
return new _MLDSAKeyPair({ publicKey, secretKey, keyId });
|
|
3178
|
+
}
|
|
3179
|
+
get hasPrivateKey() {
|
|
3180
|
+
return this.secretKey !== void 0;
|
|
3181
|
+
}
|
|
3182
|
+
/** Sign raw bytes; returns ML-DSA-65 signature (3309 bytes). */
|
|
3183
|
+
async signBytes(data) {
|
|
3184
|
+
if (!this.secretKey) {
|
|
3185
|
+
throw new Error("Cannot sign: MLDSAKeyPair has no private key (verify-only)");
|
|
3186
|
+
}
|
|
3187
|
+
const { ml_dsa65 } = await requireNoblePostQuantum();
|
|
3188
|
+
return ml_dsa65.sign(data, this.secretKey);
|
|
3189
|
+
}
|
|
3190
|
+
/**
|
|
3191
|
+
* Verify an ML-DSA-65 signature.
|
|
3192
|
+
* @returns true if valid
|
|
3193
|
+
* @throws {Error} on invalid signature
|
|
3194
|
+
*/
|
|
3195
|
+
async verifyBytes(data, signature) {
|
|
3196
|
+
const { ml_dsa65 } = await requireNoblePostQuantum();
|
|
3197
|
+
const ok = ml_dsa65.verify(signature, data, this.publicKey);
|
|
3198
|
+
if (!ok) throw new Error("ML-DSA signature verification failed");
|
|
3199
|
+
}
|
|
3200
|
+
toString() {
|
|
3201
|
+
const mode = this.hasPrivateKey ? "private+public" : "public-only";
|
|
3202
|
+
return `MLDSAKeyPair(keyId=${this.keyId}, alg=ML-DSA-65, ${mode})`;
|
|
3203
|
+
}
|
|
3204
|
+
};
|
|
3205
|
+
function canonicalMessageBytes(msg) {
|
|
3206
|
+
const m = msg;
|
|
3207
|
+
const payload = {
|
|
3208
|
+
rcan: msg.rcan,
|
|
3209
|
+
msg_id: m["msgId"] ?? m["msg_id"] ?? "",
|
|
3210
|
+
timestamp: msg.timestamp,
|
|
3211
|
+
cmd: msg.cmd,
|
|
3212
|
+
target: msg.target,
|
|
3213
|
+
params: msg.params
|
|
3214
|
+
};
|
|
3215
|
+
const sorted = JSON.stringify(
|
|
3216
|
+
Object.fromEntries(Object.entries(payload).sort()),
|
|
3217
|
+
null,
|
|
3218
|
+
void 0
|
|
3219
|
+
);
|
|
3220
|
+
return new TextEncoder().encode(sorted);
|
|
3221
|
+
}
|
|
3222
|
+
async function addPQSignature(msg, keypair) {
|
|
3223
|
+
const payload = canonicalMessageBytes(msg);
|
|
3224
|
+
const rawSig = await keypair.signBytes(payload);
|
|
3225
|
+
const block = {
|
|
3226
|
+
alg: "ml-dsa-65",
|
|
3227
|
+
kid: keypair.keyId,
|
|
3228
|
+
sig: toBase64url(rawSig)
|
|
3229
|
+
};
|
|
3230
|
+
msg["pqSig"] = block;
|
|
3231
|
+
return msg;
|
|
3232
|
+
}
|
|
3233
|
+
async function verifyPQSignature(msg, trustedKeys, requirePQ = false) {
|
|
3234
|
+
const pqSig = msg["pqSig"];
|
|
3235
|
+
if (!pqSig) {
|
|
3236
|
+
if (requirePQ) {
|
|
3237
|
+
throw new Error("ML-DSA signature (pqSig) required but missing from message");
|
|
3238
|
+
}
|
|
3239
|
+
return;
|
|
3240
|
+
}
|
|
3241
|
+
if (pqSig.alg !== "ml-dsa-65") {
|
|
3242
|
+
throw new Error(`Unsupported PQ signature algorithm: ${pqSig.alg}`);
|
|
3243
|
+
}
|
|
3244
|
+
const matched = trustedKeys.find((k) => k.keyId === pqSig.kid);
|
|
3245
|
+
if (!matched) {
|
|
3246
|
+
throw new Error(
|
|
3247
|
+
`No trusted ML-DSA key with kid=${pqSig.kid}. Known kids: [${trustedKeys.map((k) => k.keyId).join(", ")}]`
|
|
3248
|
+
);
|
|
3249
|
+
}
|
|
3250
|
+
let rawSig;
|
|
3251
|
+
try {
|
|
3252
|
+
rawSig = fromBase64url(pqSig.sig);
|
|
3253
|
+
} catch (e) {
|
|
3254
|
+
throw new Error(`Invalid base64url ML-DSA signature: ${e}`);
|
|
3255
|
+
}
|
|
3256
|
+
const payload = canonicalMessageBytes(msg);
|
|
3257
|
+
await matched.verifyBytes(payload, rawSig);
|
|
3258
|
+
}
|
|
3259
|
+
|
|
2743
3260
|
// src/index.ts
|
|
2744
3261
|
var VERSION = "0.6.0";
|
|
2745
3262
|
var RCAN_VERSION = "1.6";
|
|
2746
3263
|
export {
|
|
3264
|
+
AUTHORITY_ERROR_CODES,
|
|
2747
3265
|
AuditChain,
|
|
2748
3266
|
AuditError,
|
|
3267
|
+
COMPETITION_SCOPE_LEVEL,
|
|
2749
3268
|
CONTRIBUTE_SCOPE_LEVEL,
|
|
2750
3269
|
ClockDriftError,
|
|
2751
3270
|
CommitmentRecord,
|
|
2752
3271
|
ConfidenceGate,
|
|
2753
3272
|
DEFAULT_LOA_POLICY,
|
|
2754
3273
|
DataCategory,
|
|
3274
|
+
FIRMWARE_MANIFEST_PATH,
|
|
2755
3275
|
FaultCode,
|
|
2756
3276
|
FederationSyncType,
|
|
3277
|
+
FirmwareIntegrityError,
|
|
2757
3278
|
GateError,
|
|
2758
3279
|
HiTLGate,
|
|
2759
3280
|
KeyStore,
|
|
2760
3281
|
LevelOfAssurance,
|
|
3282
|
+
M2MAuthError,
|
|
3283
|
+
M2M_TRUSTED_ISSUER,
|
|
3284
|
+
MLDSAKeyPair,
|
|
2761
3285
|
MediaEncoding,
|
|
2762
3286
|
MessageType,
|
|
2763
3287
|
NodeClient,
|
|
@@ -2783,13 +3307,18 @@ export {
|
|
|
2783
3307
|
RCANValidationError,
|
|
2784
3308
|
RCANVersionIncompatibleError,
|
|
2785
3309
|
RCAN_VERSION,
|
|
3310
|
+
ROLE_JWT_LEVEL,
|
|
3311
|
+
RRF_REVOCATION_CACHE_TTL_MS,
|
|
3312
|
+
RRF_REVOCATION_URL,
|
|
2786
3313
|
RegistryClient,
|
|
2787
3314
|
RegistryTier,
|
|
2788
3315
|
ReplayCache,
|
|
2789
3316
|
RevocationCache,
|
|
2790
3317
|
RobotURI,
|
|
2791
3318
|
RobotURIError,
|
|
3319
|
+
Role,
|
|
2792
3320
|
SAFETY_MESSAGE_TYPE,
|
|
3321
|
+
SCOPE_MIN_ROLE,
|
|
2793
3322
|
SDK_VERSION,
|
|
2794
3323
|
SPEC_VERSION,
|
|
2795
3324
|
TransportEncoding,
|
|
@@ -2799,7 +3328,11 @@ export {
|
|
|
2799
3328
|
addDelegationHop,
|
|
2800
3329
|
addMediaInline,
|
|
2801
3330
|
addMediaRef,
|
|
3331
|
+
addPQSignature,
|
|
2802
3332
|
assertClockSynced,
|
|
3333
|
+
authorityAccessFromWire,
|
|
3334
|
+
authorityAccessToWire,
|
|
3335
|
+
canonicalManifestJson,
|
|
2803
3336
|
checkClockSync,
|
|
2804
3337
|
checkRevocation,
|
|
2805
3338
|
decodeBleFrames,
|
|
@@ -2808,11 +3341,18 @@ export {
|
|
|
2808
3341
|
encodeBleFrames,
|
|
2809
3342
|
encodeCompact,
|
|
2810
3343
|
encodeMinimal,
|
|
3344
|
+
extractIdentityFromJwt,
|
|
2811
3345
|
extractLoaFromJwt,
|
|
3346
|
+
extractRoleFromJwt,
|
|
2812
3347
|
fetchCanonicalSchema,
|
|
3348
|
+
fetchRRFRevocations,
|
|
3349
|
+
isAuthorityRequestValid,
|
|
3350
|
+
isM2mTrustedRevoked,
|
|
2813
3351
|
isPreemptedBy,
|
|
2814
3352
|
isSafetyMessage,
|
|
2815
3353
|
makeCloudRelayMessage,
|
|
3354
|
+
makeCompetitionEnter,
|
|
3355
|
+
makeCompetitionScore,
|
|
2816
3356
|
makeConfigUpdate,
|
|
2817
3357
|
makeConsentDeny,
|
|
2818
3358
|
makeConsentGrant,
|
|
@@ -2825,8 +3365,10 @@ export {
|
|
|
2825
3365
|
makeFaultReport,
|
|
2826
3366
|
makeFederationSync,
|
|
2827
3367
|
makeKeyRotationMessage,
|
|
3368
|
+
makePersonalResearchResult,
|
|
2828
3369
|
makeResumeMessage,
|
|
2829
3370
|
makeRevocationBroadcast,
|
|
3371
|
+
makeSeasonStanding,
|
|
2830
3372
|
makeStopMessage,
|
|
2831
3373
|
makeStreamChunk,
|
|
2832
3374
|
makeTrainingConsentDeny,
|
|
@@ -2834,7 +3376,14 @@ export {
|
|
|
2834
3376
|
makeTrainingConsentRequest,
|
|
2835
3377
|
makeTrainingDataMessage,
|
|
2836
3378
|
makeTransparencyMessage,
|
|
3379
|
+
manifestFromWire,
|
|
3380
|
+
manifestToWire,
|
|
3381
|
+
parseM2mPeerToken,
|
|
3382
|
+
parseM2mTrustedToken,
|
|
3383
|
+
roleFromJwtLevel,
|
|
2837
3384
|
selectTransport,
|
|
3385
|
+
validateAuthorityAccess,
|
|
3386
|
+
validateCompetitionScope,
|
|
2838
3387
|
validateConfig,
|
|
2839
3388
|
validateConfigAgainstSchema,
|
|
2840
3389
|
validateConfigUpdate,
|
|
@@ -2843,13 +3392,18 @@ export {
|
|
|
2843
3392
|
validateCrossRegistryCommand,
|
|
2844
3393
|
validateDelegationChain,
|
|
2845
3394
|
validateLoaForScope,
|
|
3395
|
+
validateManifest,
|
|
2846
3396
|
validateMediaChunks,
|
|
2847
3397
|
validateMessage,
|
|
2848
3398
|
validateNodeAgainstSchema,
|
|
2849
3399
|
validateReplay,
|
|
3400
|
+
validateRoleForScope,
|
|
2850
3401
|
validateSafetyMessage,
|
|
2851
3402
|
validateTrainingDataMessage,
|
|
2852
3403
|
validateURI,
|
|
2853
|
-
validateVersionCompat
|
|
3404
|
+
validateVersionCompat,
|
|
3405
|
+
verifyM2mTrustedToken,
|
|
3406
|
+
verifyM2mTrustedTokenClaims,
|
|
3407
|
+
verifyPQSignature
|
|
2854
3408
|
};
|
|
2855
3409
|
//# sourceMappingURL=browser.mjs.map
|