@continuonai/rcan-ts 0.1.2 → 0.3.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 +85 -0
- package/bin/rcan-validate.mjs +86 -0
- package/dist/browser.d.mts +165 -32
- package/dist/browser.mjs +299 -2
- package/dist/browser.mjs.map +1 -1
- package/dist/index.d.mts +165 -32
- package/dist/index.d.ts +165 -32
- package/dist/index.js +308 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +299 -2
- package/dist/index.mjs.map +1 -1
- package/dist/rcan-validate.js +14 -1
- package/dist/rcan.iife.js +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ Official TypeScript SDK for the **RCAN v1.2** Robot Communication and Accountabi
|
|
|
9
9
|
npm install @continuonai/rcan-ts
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
+
> **v0.2.0** — RCAN v1.2 spec compliance including §17 Distributed Registry Node Protocol
|
|
13
|
+
|
|
12
14
|
### CDN / Browser (no build step)
|
|
13
15
|
|
|
14
16
|
```html
|
|
@@ -139,6 +141,89 @@ result.warnings.forEach((w) => console.warn("⚠️", w));
|
|
|
139
141
|
| `validateURI` | Validate a Robot URI string |
|
|
140
142
|
| `validateMessage` | Validate a RCAN message object |
|
|
141
143
|
| `validateConfig` | L1/L2/L3 conformance check for a robot RCAN config |
|
|
144
|
+
| `NodeClient` | Resolve RRNs from federated registry nodes (§17) |
|
|
145
|
+
| `fetchCanonicalSchema` | Fetch the canonical JSON schema from rcan.dev |
|
|
146
|
+
| `validateConfigAgainstSchema` | Validate a config object against the live JSON schema |
|
|
147
|
+
| `validateNodeAgainstSchema` | Validate a node manifest against the node schema |
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Distributed Registry Nodes (§17)
|
|
152
|
+
|
|
153
|
+
RCAN v1.2 §17 introduces a federated registry network. `NodeClient` resolves RRNs from any node — root or delegated authoritative.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { NodeClient } from '@continuonai/rcan-ts';
|
|
157
|
+
|
|
158
|
+
const client = new NodeClient();
|
|
159
|
+
|
|
160
|
+
// Resolve an RRN across the federation
|
|
161
|
+
const result = await client.resolve('RRN-BD-000000000001');
|
|
162
|
+
console.log(`Resolved by: ${result.resolved_by}`);
|
|
163
|
+
console.log(`Robot: ${result.record.name}`);
|
|
164
|
+
|
|
165
|
+
// Discover the authoritative node for a namespace
|
|
166
|
+
const node = await client.discover('RRN-BD-000000000001');
|
|
167
|
+
console.log(`Authoritative: ${node.operator} at ${node.api_base}`);
|
|
168
|
+
|
|
169
|
+
// List all known registry nodes
|
|
170
|
+
const nodes = await client.listNodes();
|
|
171
|
+
nodes.forEach(n => console.log(`${n.operator}: ${n.namespace_prefix}`));
|
|
172
|
+
|
|
173
|
+
// Verify a node manifest
|
|
174
|
+
const manifest = await client.getNodeManifest('https://registry.example.com');
|
|
175
|
+
const isValid = client.verifyNode(manifest);
|
|
176
|
+
|
|
177
|
+
// Error handling
|
|
178
|
+
import { RCANNodeNotFoundError, RCANNodeTrustError } from '@continuonai/rcan-ts';
|
|
179
|
+
try {
|
|
180
|
+
const result = await client.resolve('RRN-UNKNOWN-000000000001');
|
|
181
|
+
} catch (e) {
|
|
182
|
+
if (e instanceof RCANNodeNotFoundError) {
|
|
183
|
+
console.log(`Not found: ${e.rrn}`);
|
|
184
|
+
} else if (e instanceof RCANNodeTrustError) {
|
|
185
|
+
console.log(`Trust failure: ${e.reason}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### RRN Format
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
Root namespace: RRN-000000000001 (12-digit recommended, 8-digit still valid)
|
|
194
|
+
Delegated: RRN-BD-000000000001 (prefix 2-8 alphanumeric chars)
|
|
195
|
+
Legacy (valid): RRN-00000001 (8-digit, backward compatible)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Schema Validation
|
|
199
|
+
|
|
200
|
+
Validate configs against the canonical JSON schema published at rcan.dev:
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
import { validateConfigAgainstSchema, validateNodeAgainstSchema } from '@continuonai/rcan-ts';
|
|
204
|
+
|
|
205
|
+
// Validate a RCAN config against the canonical schema from rcan.dev
|
|
206
|
+
const result = await validateConfigAgainstSchema(myConfig);
|
|
207
|
+
if (!result.valid) {
|
|
208
|
+
console.error('Config invalid:', result.errors);
|
|
209
|
+
} else if (result.skipped) {
|
|
210
|
+
console.warn('Schema validation skipped (rcan.dev unreachable)');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Validate a node manifest
|
|
214
|
+
const nodeResult = await validateNodeAgainstSchema(manifest);
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### CDN / Browser Usage
|
|
218
|
+
|
|
219
|
+
```html
|
|
220
|
+
<script src="https://unpkg.com/@continuonai/rcan-ts/dist/rcan.iife.js"></script>
|
|
221
|
+
<script>
|
|
222
|
+
const { validateConfig, NodeClient } = window.RCAN;
|
|
223
|
+
const client = new NodeClient();
|
|
224
|
+
client.resolve('RRN-000000000001').then(r => console.log(r));
|
|
225
|
+
</script>
|
|
226
|
+
```
|
|
142
227
|
|
|
143
228
|
---
|
|
144
229
|
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { NodeClient, validateConfig, VERSION, SPEC_VERSION } from '../dist/index.js';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import { parseArgs } from 'util';
|
|
5
|
+
|
|
6
|
+
const { values, positionals } = parseArgs({
|
|
7
|
+
args: process.argv.slice(2),
|
|
8
|
+
options: {
|
|
9
|
+
version: { type: 'boolean', short: 'v' },
|
|
10
|
+
file: { type: 'string', short: 'f' },
|
|
11
|
+
},
|
|
12
|
+
allowPositionals: true,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (values.version) {
|
|
16
|
+
console.log(`rcan-validate (ts) ${VERSION} (RCAN spec ${SPEC_VERSION})`);
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const [subcommand, target] = positionals;
|
|
21
|
+
|
|
22
|
+
if (subcommand === 'node') {
|
|
23
|
+
if (!target) {
|
|
24
|
+
console.error('Usage: rcan-validate node <url>');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const client = new NodeClient();
|
|
29
|
+
console.log(`Validating node manifest: ${target}`);
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
const manifest = await client.getNodeManifest(target);
|
|
33
|
+
const valid = client.verifyNode(manifest);
|
|
34
|
+
|
|
35
|
+
const checks = [
|
|
36
|
+
['node_type', manifest.node_type, ['root','authoritative','resolver','cache'].includes(manifest.node_type)],
|
|
37
|
+
['operator', manifest.operator, !!manifest.operator],
|
|
38
|
+
['namespace_prefix', manifest.namespace_prefix, !!manifest.namespace_prefix],
|
|
39
|
+
['public_key', manifest.public_key?.substring(0, 20) + '...', manifest.public_key?.startsWith('ed25519:')],
|
|
40
|
+
['api_base', manifest.api_base, manifest.api_base?.startsWith('https://')],
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
for (const [name, value, pass] of checks) {
|
|
44
|
+
console.log(` ${pass ? '✓' : '✗'} ${name}: ${value}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const passed = checks.filter(([,,p]) => p).length;
|
|
48
|
+
console.log(`\n${valid ? 'PASS' : 'FAIL'} (${passed}/${checks.length} checks)`);
|
|
49
|
+
process.exit(valid ? 0 : 1);
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.error(`❌ Error: ${e.message}`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (subcommand === 'config') {
|
|
57
|
+
const filePath = target || values.file;
|
|
58
|
+
if (!filePath) {
|
|
59
|
+
console.error('Usage: rcan-validate config <file>');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
65
|
+
const config = JSON.parse(raw);
|
|
66
|
+
const result = validateConfig(config);
|
|
67
|
+
if (result.ok) {
|
|
68
|
+
console.log('✓ Config valid');
|
|
69
|
+
if (result.warnings?.length) {
|
|
70
|
+
result.warnings.forEach(w => console.warn(` ⚠️ ${w}`));
|
|
71
|
+
}
|
|
72
|
+
process.exit(0);
|
|
73
|
+
} else {
|
|
74
|
+
console.error('✗ Config invalid:');
|
|
75
|
+
result.issues?.forEach(i => console.error(` ❌ ${i}`));
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.error(`❌ Error: ${e.message}`);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
console.error(`Unknown subcommand: ${subcommand}`);
|
|
85
|
+
console.error('Usage: rcan-validate node <url> | rcan-validate config <file> | rcan-validate --version');
|
|
86
|
+
process.exit(1);
|
package/dist/browser.d.mts
CHANGED
|
@@ -201,48 +201,101 @@ declare class AuditChain {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
/**
|
|
204
|
-
*
|
|
204
|
+
* rcan-ts types — TypeScript interfaces for RCAN config and message shapes.
|
|
205
205
|
*
|
|
206
|
-
*
|
|
206
|
+
* These provide parity with the rcan-py TypedDicts and enable
|
|
207
|
+
* static type checking with tsc/ts-jest/pyright.
|
|
207
208
|
*/
|
|
208
|
-
interface
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
209
|
+
interface RCANMetadata {
|
|
210
|
+
manufacturer?: string;
|
|
211
|
+
model?: string;
|
|
212
|
+
version?: string;
|
|
213
|
+
device_id?: string;
|
|
214
|
+
robot_name?: string;
|
|
215
|
+
rrn?: string;
|
|
216
|
+
rcan_uri?: string;
|
|
213
217
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
218
|
+
interface RCANAgentConfig {
|
|
219
|
+
provider?: string;
|
|
220
|
+
model?: string;
|
|
221
|
+
temperature?: number;
|
|
222
|
+
confidence_gates?: Array<{
|
|
223
|
+
threshold?: number;
|
|
224
|
+
[key: string]: unknown;
|
|
225
|
+
}>;
|
|
226
|
+
hitl_gates?: Array<Record<string, unknown>>;
|
|
227
|
+
commitment_chain?: {
|
|
228
|
+
enabled?: boolean;
|
|
229
|
+
[key: string]: unknown;
|
|
224
230
|
};
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
confidence_gates?: Array<{
|
|
229
|
-
threshold?: number;
|
|
230
|
-
}>;
|
|
231
|
-
hitl_gates?: Array<Record<string, unknown>>;
|
|
232
|
-
commitment_chain?: {
|
|
233
|
-
enabled?: boolean;
|
|
234
|
-
};
|
|
235
|
-
signing?: {
|
|
236
|
-
enabled?: boolean;
|
|
237
|
-
};
|
|
231
|
+
signing?: {
|
|
232
|
+
enabled?: boolean;
|
|
233
|
+
[key: string]: unknown;
|
|
238
234
|
};
|
|
235
|
+
}
|
|
236
|
+
interface RCANConfig {
|
|
237
|
+
rcan_version?: string;
|
|
238
|
+
metadata?: RCANMetadata;
|
|
239
|
+
agent?: RCANAgentConfig;
|
|
240
|
+
channels?: Record<string, unknown>;
|
|
239
241
|
rcan_protocol?: {
|
|
240
242
|
jwt_auth?: {
|
|
241
243
|
enabled?: boolean;
|
|
242
244
|
};
|
|
245
|
+
[key: string]: unknown;
|
|
243
246
|
};
|
|
244
247
|
[key: string]: unknown;
|
|
245
248
|
}
|
|
249
|
+
interface RCANMessageEnvelope {
|
|
250
|
+
cmd: string;
|
|
251
|
+
target: string;
|
|
252
|
+
rcan_version?: string;
|
|
253
|
+
confidence?: number;
|
|
254
|
+
timestamp_ns?: number;
|
|
255
|
+
params?: Record<string, unknown>;
|
|
256
|
+
signature?: string;
|
|
257
|
+
[key: string]: unknown;
|
|
258
|
+
}
|
|
259
|
+
interface RCANRegistryNode {
|
|
260
|
+
rcan_node_version: string;
|
|
261
|
+
node_type: "root" | "authoritative" | "resolver" | "cache";
|
|
262
|
+
operator: string;
|
|
263
|
+
namespace_prefix: string;
|
|
264
|
+
public_key: string;
|
|
265
|
+
api_base: string;
|
|
266
|
+
registry_ui?: string;
|
|
267
|
+
spec_version?: string;
|
|
268
|
+
capabilities?: string[];
|
|
269
|
+
sync_endpoint?: string;
|
|
270
|
+
last_sync?: string;
|
|
271
|
+
ttl_seconds?: number;
|
|
272
|
+
contact?: string;
|
|
273
|
+
governance?: string;
|
|
274
|
+
federation_protocol?: string;
|
|
275
|
+
}
|
|
276
|
+
interface RCANResolveResult {
|
|
277
|
+
rrn: string;
|
|
278
|
+
resolved_by: string;
|
|
279
|
+
namespace: string;
|
|
280
|
+
record: Record<string, unknown>;
|
|
281
|
+
cache_status: "HIT" | "MISS" | "STALE";
|
|
282
|
+
resolved_at: string;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* RCAN Validation — validate messages, configs, and URIs.
|
|
287
|
+
*
|
|
288
|
+
* Each function returns a ValidationResult with ok, issues, warnings, info.
|
|
289
|
+
*/
|
|
290
|
+
|
|
291
|
+
interface ValidationResult {
|
|
292
|
+
ok: boolean;
|
|
293
|
+
issues: string[];
|
|
294
|
+
warnings: string[];
|
|
295
|
+
info: string[];
|
|
296
|
+
}
|
|
297
|
+
declare function validateURI(uri: string): ValidationResult;
|
|
298
|
+
declare function validateMessage(data: unknown): ValidationResult;
|
|
246
299
|
declare function validateConfig(config: RCANConfig): ValidationResult;
|
|
247
300
|
|
|
248
301
|
/**
|
|
@@ -270,6 +323,22 @@ declare class RCANSignatureError extends RCANError {
|
|
|
270
323
|
declare class RCANRegistryError extends RCANError {
|
|
271
324
|
constructor(message: string);
|
|
272
325
|
}
|
|
326
|
+
declare class RCANNodeError extends RCANError {
|
|
327
|
+
readonly nodeUrl?: string | undefined;
|
|
328
|
+
constructor(message: string, nodeUrl?: string | undefined);
|
|
329
|
+
}
|
|
330
|
+
declare class RCANNodeNotFoundError extends RCANNodeError {
|
|
331
|
+
readonly rrn: string;
|
|
332
|
+
constructor(rrn: string, nodeUrl?: string);
|
|
333
|
+
}
|
|
334
|
+
declare class RCANNodeSyncError extends RCANNodeError {
|
|
335
|
+
readonly cause?: Error | undefined;
|
|
336
|
+
constructor(message: string, nodeUrl?: string, cause?: Error | undefined);
|
|
337
|
+
}
|
|
338
|
+
declare class RCANNodeTrustError extends RCANNodeError {
|
|
339
|
+
readonly reason: "invalid_signature" | "expired_cert" | "unknown_issuer" | "missing_pubkey";
|
|
340
|
+
constructor(reason: RCANNodeTrustError["reason"], nodeUrl?: string);
|
|
341
|
+
}
|
|
273
342
|
|
|
274
343
|
/**
|
|
275
344
|
* rcan-ts — RegistryClient
|
|
@@ -339,6 +408,68 @@ declare class RegistryClient {
|
|
|
339
408
|
}): Promise<Robot[]>;
|
|
340
409
|
}
|
|
341
410
|
|
|
411
|
+
/**
|
|
412
|
+
* rcan-ts — NodeClient
|
|
413
|
+
* Federation-aware node discovery and RRN resolution.
|
|
414
|
+
*
|
|
415
|
+
* Zero runtime dependencies — uses globalThis.fetch (Node 18+, browsers, CF Workers).
|
|
416
|
+
*
|
|
417
|
+
* @see https://rcan.dev/spec#section-federation
|
|
418
|
+
*/
|
|
419
|
+
|
|
420
|
+
declare class NodeClient {
|
|
421
|
+
private readonly rootUrl;
|
|
422
|
+
private readonly timeoutMs;
|
|
423
|
+
constructor(rootUrl?: string, timeoutMs?: number);
|
|
424
|
+
private _fetch;
|
|
425
|
+
/**
|
|
426
|
+
* Fetch /.well-known/rcan-node.json from any node URL.
|
|
427
|
+
* Throws RCANNodeTrustError if the manifest is malformed.
|
|
428
|
+
* Throws RCANNodeSyncError on network failure.
|
|
429
|
+
*/
|
|
430
|
+
getNodeManifest(nodeUrl: string): Promise<RCANRegistryNode>;
|
|
431
|
+
/**
|
|
432
|
+
* Get list of known registry nodes from root /api/v1/nodes.
|
|
433
|
+
* Optionally filter by namespace prefix (e.g. "BD").
|
|
434
|
+
*/
|
|
435
|
+
listNodes(prefix?: string): Promise<RCANRegistryNode[]>;
|
|
436
|
+
/**
|
|
437
|
+
* Find the authoritative node for an RRN.
|
|
438
|
+
* - Delegated RRN (RRN-BD-00000001): GET /api/v1/nodes?prefix=BD, return first match.
|
|
439
|
+
* - Root RRN (RRN-00000042): return root node manifest.
|
|
440
|
+
* - Unknown format: throws RCANNodeNotFoundError.
|
|
441
|
+
*/
|
|
442
|
+
discover(rrn: string): Promise<RCANRegistryNode>;
|
|
443
|
+
/**
|
|
444
|
+
* Resolve an RRN across the federation.
|
|
445
|
+
* First tries {rootUrl}/api/v1/resolve/{rrn}.
|
|
446
|
+
* On 404, discovers the authoritative node and tries {node.api_base}/robots/{rrn}.
|
|
447
|
+
*/
|
|
448
|
+
resolve(rrn: string): Promise<RCANResolveResult>;
|
|
449
|
+
/**
|
|
450
|
+
* Verify a node manifest is well-formed.
|
|
451
|
+
* Checks required fields, ed25519: public_key prefix, valid node_type, https:// api_base.
|
|
452
|
+
*/
|
|
453
|
+
verifyNode(manifest: unknown): manifest is RCANRegistryNode;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
declare function fetchCanonicalSchema(schemaName: string): Promise<object | null>;
|
|
457
|
+
/**
|
|
458
|
+
* Validate a config object against the canonical rcan-config schema from rcan.dev.
|
|
459
|
+
* Returns { valid: true } or { valid: false, errors: string[] }.
|
|
460
|
+
* Gracefully returns { valid: true, skipped: true } if schema unreachable.
|
|
461
|
+
*/
|
|
462
|
+
declare function validateConfigAgainstSchema(config: unknown): Promise<{
|
|
463
|
+
valid: boolean;
|
|
464
|
+
errors?: string[];
|
|
465
|
+
skipped?: boolean;
|
|
466
|
+
}>;
|
|
467
|
+
declare function validateNodeAgainstSchema(manifest: unknown): Promise<{
|
|
468
|
+
valid: boolean;
|
|
469
|
+
errors?: string[];
|
|
470
|
+
skipped?: boolean;
|
|
471
|
+
}>;
|
|
472
|
+
|
|
342
473
|
/**
|
|
343
474
|
* rcan-ts — Official TypeScript SDK for RCAN v1.2
|
|
344
475
|
* Robot Communication and Accountability Network
|
|
@@ -347,7 +478,9 @@ declare class RegistryClient {
|
|
|
347
478
|
* @see https://github.com/continuonai/rcan-ts
|
|
348
479
|
*/
|
|
349
480
|
|
|
350
|
-
declare const VERSION = "0.
|
|
481
|
+
declare const VERSION = "0.3.0";
|
|
482
|
+
declare const SPEC_VERSION = "1.2";
|
|
483
|
+
/** @deprecated Use SPEC_VERSION instead */
|
|
351
484
|
declare const RCAN_VERSION = "1.2";
|
|
352
485
|
|
|
353
|
-
export { type ApprovalStatus, AuditChain, AuditError, type ChainVerifyResult, CommitmentRecord, type CommitmentRecordData, type CommitmentRecordJSON, ConfidenceGate, GateError, HiTLGate, type ListResult, type PendingApproval, RCANAddressError, type RCANConfig, RCANError, RCANGateError, RCANMessage, type RCANMessageData, RCANMessageError, RCANRegistryError, RCANSignatureError, RCANValidationError, RCAN_VERSION, type RegistrationResult, RegistryClient, type Robot, type RobotRegistration, RobotURI, RobotURIError, type RobotURIOptions, type SignatureBlock, VERSION, type ValidationResult, validateConfig, validateMessage, validateURI };
|
|
486
|
+
export { type ApprovalStatus, AuditChain, AuditError, type ChainVerifyResult, CommitmentRecord, type CommitmentRecordData, type CommitmentRecordJSON, ConfidenceGate, GateError, HiTLGate, type ListResult, NodeClient, type PendingApproval, RCANAddressError, type RCANAgentConfig, type RCANConfig, RCANError, RCANGateError, RCANMessage, type RCANMessageData, type RCANMessageEnvelope, RCANMessageError, type RCANMetadata, RCANNodeError, RCANNodeNotFoundError, RCANNodeSyncError, RCANNodeTrustError, RCANRegistryError, type RCANRegistryNode, type RCANResolveResult, RCANSignatureError, RCANValidationError, RCAN_VERSION, type RegistrationResult, RegistryClient, type Robot, type RobotRegistration, RobotURI, RobotURIError, type RobotURIOptions, SPEC_VERSION, type SignatureBlock, VERSION, type ValidationResult, fetchCanonicalSchema, validateConfig, validateConfigAgainstSchema, validateMessage, validateNodeAgainstSchema, validateURI };
|