capdag 0.127.280 → 0.137.303
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/capdag.js +147 -90
- package/capdag.test.js +359 -270
- package/package.json +2 -2
package/capdag.js
CHANGED
|
@@ -27,47 +27,102 @@ const ErrorCodes = {
|
|
|
27
27
|
UNTERMINATED_QUOTE: 8,
|
|
28
28
|
INVALID_ESCAPE_SEQUENCE: 9,
|
|
29
29
|
MISSING_IN_SPEC: 10,
|
|
30
|
-
MISSING_OUT_SPEC: 11
|
|
30
|
+
MISSING_OUT_SPEC: 11,
|
|
31
|
+
EMPTY_VALUE: 12,
|
|
32
|
+
INVALID_IN_SPEC: 13,
|
|
33
|
+
INVALID_OUT_SPEC: 14
|
|
31
34
|
};
|
|
32
35
|
|
|
33
36
|
// Note: All parsing is delegated to TaggedUrn from tagged-urn-js
|
|
34
37
|
// No duplicate state machine or parsing helpers needed here
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
|
-
* Cap URN implementation with
|
|
40
|
+
* Cap URN implementation with direction specs and optional tags.
|
|
38
41
|
*
|
|
39
|
-
* Direction
|
|
40
|
-
* -
|
|
41
|
-
* -
|
|
42
|
+
* Direction rules match the Rust reference:
|
|
43
|
+
* - missing `in` or `out` defaults to `media:`
|
|
44
|
+
* - `in=*` and `out=*` normalize to `media:`
|
|
45
|
+
* - empty `in=` / `out=` are rejected
|
|
42
46
|
* - tags: Other optional tags (no longer contains in/out)
|
|
43
47
|
*/
|
|
44
48
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
49
|
+
* Normalize a parsed direction tag to canonical wildcard semantics.
|
|
50
|
+
* Missing tags and `*` both become `media:`.
|
|
51
|
+
*
|
|
52
|
+
* @param {TaggedUrn} taggedUrn - Parsed tagged URN
|
|
53
|
+
* @param {string} tagName - `in` or `out`
|
|
54
|
+
* @returns {string} Normalized direction spec
|
|
48
55
|
*/
|
|
49
|
-
function
|
|
50
|
-
|
|
56
|
+
function processDirectionTag(taggedUrn, tagName) {
|
|
57
|
+
const rawValue = taggedUrn.getTag(tagName);
|
|
58
|
+
if (rawValue === undefined || rawValue === '*') {
|
|
59
|
+
return 'media:';
|
|
60
|
+
}
|
|
61
|
+
if (rawValue === '') {
|
|
62
|
+
throw new CapUrnError(
|
|
63
|
+
tagName === 'in' ? ErrorCodes.INVALID_IN_SPEC : ErrorCodes.INVALID_OUT_SPEC,
|
|
64
|
+
`Empty value for '${tagName}' tag is not allowed`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
return rawValue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Canonicalize a direction spec via MediaUrn parsing.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} spec - Media URN string
|
|
74
|
+
* @param {string} tagName - `in` or `out`
|
|
75
|
+
* @returns {string} Canonical media URN string
|
|
76
|
+
*/
|
|
77
|
+
function canonicalizeDirectionSpec(spec, tagName) {
|
|
78
|
+
if (spec === 'media:' || spec === '*') {
|
|
79
|
+
return spec;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
return MediaUrn.fromString(spec).toString();
|
|
84
|
+
} catch (error) {
|
|
85
|
+
throw new CapUrnError(
|
|
86
|
+
tagName === 'in' ? ErrorCodes.INVALID_IN_SPEC : ErrorCodes.INVALID_OUT_SPEC,
|
|
87
|
+
`Invalid media URN for ${tagName} spec '${spec}': ${error.message}`
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Validate a direction spec while preserving the caller-provided string.
|
|
94
|
+
* This matches the reference `with_in_spec` / `with_out_spec` behavior.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} spec - Media URN string
|
|
97
|
+
* @param {string} tagName - `in` or `out`
|
|
98
|
+
* @returns {string} The original spec when valid
|
|
99
|
+
*/
|
|
100
|
+
function validatePreservedDirectionSpec(spec, tagName) {
|
|
101
|
+
if (spec === 'media:' || spec === '*') {
|
|
102
|
+
return spec;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
MediaUrn.fromString(spec);
|
|
107
|
+
return spec;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
throw new CapUrnError(
|
|
110
|
+
tagName === 'in' ? ErrorCodes.INVALID_IN_SPEC : ErrorCodes.INVALID_OUT_SPEC,
|
|
111
|
+
`Invalid media URN for ${tagName} spec '${spec}': ${error.message}`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
51
114
|
}
|
|
52
115
|
|
|
53
116
|
class CapUrn {
|
|
54
117
|
/**
|
|
55
|
-
* Create a new CapUrn with
|
|
56
|
-
* @param {string} inSpec -
|
|
57
|
-
* @param {string} outSpec -
|
|
118
|
+
* Create a new CapUrn with direction specs.
|
|
119
|
+
* @param {string} inSpec - Input media URN (e.g., "media:void")
|
|
120
|
+
* @param {string} outSpec - Output media URN (e.g., "media:object")
|
|
58
121
|
* @param {Object} tags - Other tags (must NOT contain 'in' or 'out')
|
|
59
122
|
*/
|
|
60
123
|
constructor(inSpec, outSpec, tags = {}) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
throw new CapUrnError(ErrorCodes.INVALID_FORMAT, `Invalid 'in' media URN: ${inSpec}. Must start with 'media:' or be '*'`);
|
|
64
|
-
}
|
|
65
|
-
if (!isValidMediaUrnOrWildcard(outSpec)) {
|
|
66
|
-
throw new CapUrnError(ErrorCodes.INVALID_FORMAT, `Invalid 'out' media URN: ${outSpec}. Must start with 'media:' or be '*'`);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
this.inSpec = inSpec;
|
|
70
|
-
this.outSpec = outSpec;
|
|
124
|
+
this.inSpec = canonicalizeDirectionSpec(inSpec, 'in');
|
|
125
|
+
this.outSpec = canonicalizeDirectionSpec(outSpec, 'out');
|
|
71
126
|
this.tags = {};
|
|
72
127
|
// Copy tags, filtering out any 'in' or 'out' that might have slipped through
|
|
73
128
|
for (const [key, value] of Object.entries(tags)) {
|
|
@@ -116,13 +171,14 @@ class CapUrn {
|
|
|
116
171
|
* Create a Cap URN from string representation
|
|
117
172
|
* Format: cap:in="<media-urn>";out="<media-urn>";key1=value1;key2=value2;...
|
|
118
173
|
*
|
|
119
|
-
*
|
|
174
|
+
* Missing `in` / `out` default to `media:`. `in=*` / `out=*` are also
|
|
175
|
+
* normalized to `media:`.
|
|
120
176
|
*
|
|
121
177
|
* Uses TaggedUrn for parsing to ensure consistent behavior across implementations.
|
|
122
178
|
*
|
|
123
179
|
* @param {string} s - The Cap URN string
|
|
124
180
|
* @returns {CapUrn} The parsed Cap URN
|
|
125
|
-
* @throws {CapUrnError} If parsing fails or
|
|
181
|
+
* @throws {CapUrnError} If parsing fails or direction specs are invalid
|
|
126
182
|
*/
|
|
127
183
|
static fromString(s) {
|
|
128
184
|
if (!s || typeof s !== 'string') {
|
|
@@ -162,24 +218,8 @@ class CapUrn {
|
|
|
162
218
|
throw new CapUrnError(ErrorCodes.MISSING_CAP_PREFIX, `Expected 'cap:' prefix, got '${taggedUrn.getPrefix()}:'`);
|
|
163
219
|
}
|
|
164
220
|
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
const outSpec = taggedUrn.getTag('out');
|
|
168
|
-
|
|
169
|
-
if (!inSpec) {
|
|
170
|
-
throw new CapUrnError(ErrorCodes.MISSING_IN_SPEC, "Cap URN requires 'in' tag for input media URN");
|
|
171
|
-
}
|
|
172
|
-
if (!outSpec) {
|
|
173
|
-
throw new CapUrnError(ErrorCodes.MISSING_OUT_SPEC, "Cap URN requires 'out' tag for output media URN");
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
// Validate in/out are media URNs or wildcards
|
|
177
|
-
if (!isValidMediaUrnOrWildcard(inSpec)) {
|
|
178
|
-
throw new CapUrnError(ErrorCodes.INVALID_FORMAT, `Invalid 'in' media URN: ${inSpec}. Must start with 'media:' or be '*'`);
|
|
179
|
-
}
|
|
180
|
-
if (!isValidMediaUrnOrWildcard(outSpec)) {
|
|
181
|
-
throw new CapUrnError(ErrorCodes.INVALID_FORMAT, `Invalid 'out' media URN: ${outSpec}. Must start with 'media:' or be '*'`);
|
|
182
|
-
}
|
|
221
|
+
const inSpec = processDirectionTag(taggedUrn, 'in');
|
|
222
|
+
const outSpec = processDirectionTag(taggedUrn, 'out');
|
|
183
223
|
|
|
184
224
|
// Build remaining tags (excluding in/out)
|
|
185
225
|
const remainingTags = {};
|
|
@@ -193,12 +233,12 @@ class CapUrn {
|
|
|
193
233
|
}
|
|
194
234
|
|
|
195
235
|
/**
|
|
196
|
-
* Create a Cap URN from a tags object
|
|
197
|
-
*
|
|
236
|
+
* Create a Cap URN from a tags object.
|
|
237
|
+
* Unlike string parsing, this path requires explicit `in` and `out` tags.
|
|
198
238
|
*
|
|
199
239
|
* @param {Object} tags - Object containing all tags including 'in' and 'out'
|
|
200
240
|
* @returns {CapUrn} The parsed Cap URN
|
|
201
|
-
* @throws {CapUrnError} If
|
|
241
|
+
* @throws {CapUrnError} If `in` or `out` tags are missing or invalid
|
|
202
242
|
*/
|
|
203
243
|
static fromTags(tags) {
|
|
204
244
|
const inSpec = tags['in'] || tags['IN'];
|
|
@@ -211,12 +251,11 @@ class CapUrn {
|
|
|
211
251
|
throw new CapUrnError(ErrorCodes.MISSING_OUT_SPEC, "Cap URN requires 'out' tag for output media URN");
|
|
212
252
|
}
|
|
213
253
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
throw new CapUrnError(ErrorCodes.INVALID_FORMAT, `Invalid 'in' media URN: ${inSpec}. Must start with 'media:' or be '*'`);
|
|
254
|
+
if (inSpec === '') {
|
|
255
|
+
throw new CapUrnError(ErrorCodes.INVALID_IN_SPEC, "Empty value for 'in' tag is not allowed");
|
|
217
256
|
}
|
|
218
|
-
if (
|
|
219
|
-
throw new CapUrnError(ErrorCodes.
|
|
257
|
+
if (outSpec === '') {
|
|
258
|
+
throw new CapUrnError(ErrorCodes.INVALID_OUT_SPEC, "Empty value for 'out' tag is not allowed");
|
|
220
259
|
}
|
|
221
260
|
|
|
222
261
|
// Build remaining tags (excluding in/out)
|
|
@@ -289,15 +328,18 @@ class CapUrn {
|
|
|
289
328
|
}
|
|
290
329
|
|
|
291
330
|
/**
|
|
292
|
-
* Create a new cap URN with an added or updated tag
|
|
293
|
-
*
|
|
294
|
-
*
|
|
331
|
+
* Create a new cap URN with an added or updated tag.
|
|
332
|
+
* Attempts to set `in` / `out` through `withTag` are ignored; use
|
|
333
|
+
* `withInSpec` / `withOutSpec` instead.
|
|
295
334
|
*
|
|
296
335
|
* @param {string} key - The tag key
|
|
297
336
|
* @param {string} value - The tag value
|
|
298
337
|
* @returns {CapUrn} A new CapUrn instance with the tag added/updated
|
|
299
338
|
*/
|
|
300
339
|
withTag(key, value) {
|
|
340
|
+
if (value === '') {
|
|
341
|
+
throw new CapUrnError(ErrorCodes.EMPTY_VALUE, `Empty value for key '${key}' (use '*' for wildcard)`);
|
|
342
|
+
}
|
|
301
343
|
const keyLower = key.toLowerCase();
|
|
302
344
|
// Silently ignore attempts to set in/out via withTag
|
|
303
345
|
if (keyLower === 'in' || keyLower === 'out') {
|
|
@@ -315,7 +357,9 @@ class CapUrn {
|
|
|
315
357
|
* @returns {CapUrn} A new CapUrn instance with the updated inSpec
|
|
316
358
|
*/
|
|
317
359
|
withInSpec(inSpec) {
|
|
318
|
-
|
|
360
|
+
const updated = new CapUrn(this.inSpec, this.outSpec, this.tags);
|
|
361
|
+
updated.inSpec = validatePreservedDirectionSpec(inSpec, 'in');
|
|
362
|
+
return updated;
|
|
319
363
|
}
|
|
320
364
|
|
|
321
365
|
/**
|
|
@@ -325,7 +369,9 @@ class CapUrn {
|
|
|
325
369
|
* @returns {CapUrn} A new CapUrn instance with the updated outSpec
|
|
326
370
|
*/
|
|
327
371
|
withOutSpec(outSpec) {
|
|
328
|
-
|
|
372
|
+
const updated = new CapUrn(this.inSpec, this.outSpec, this.tags);
|
|
373
|
+
updated.outSpec = validatePreservedDirectionSpec(outSpec, 'out');
|
|
374
|
+
return updated;
|
|
329
375
|
}
|
|
330
376
|
|
|
331
377
|
/**
|
|
@@ -366,11 +412,9 @@ class CapUrn {
|
|
|
366
412
|
return true;
|
|
367
413
|
}
|
|
368
414
|
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
|
|
372
|
-
// "*" is also treated as wildcard. "media:" on the instance side still participates.
|
|
373
|
-
if (this.inSpec !== '*' && this.inSpec !== 'media:' && request.inSpec !== '*') {
|
|
415
|
+
// Input direction: pattern accepts instance. `media:` on the pattern side is
|
|
416
|
+
// the wildcard top and skips the check.
|
|
417
|
+
if (this.inSpec !== 'media:' && this.inSpec !== '*') {
|
|
374
418
|
const capIn = TaggedUrn.fromString(this.inSpec);
|
|
375
419
|
const requestIn = TaggedUrn.fromString(request.inSpec);
|
|
376
420
|
if (!capIn.accepts(requestIn)) {
|
|
@@ -378,10 +422,9 @@ class CapUrn {
|
|
|
378
422
|
}
|
|
379
423
|
}
|
|
380
424
|
|
|
381
|
-
//
|
|
382
|
-
//
|
|
383
|
-
|
|
384
|
-
if (this.outSpec !== '*' && this.outSpec !== 'media:' && request.outSpec !== '*') {
|
|
425
|
+
// Output direction: provider output must conform to requested output.
|
|
426
|
+
// `media:` on the pattern side is wildcard top and skips the check.
|
|
427
|
+
if (this.outSpec !== 'media:' && this.outSpec !== '*') {
|
|
385
428
|
const capOut = TaggedUrn.fromString(this.outSpec);
|
|
386
429
|
const requestOut = TaggedUrn.fromString(request.outSpec);
|
|
387
430
|
if (!capOut.conformsTo(requestOut)) {
|
|
@@ -389,33 +432,23 @@ class CapUrn {
|
|
|
389
432
|
}
|
|
390
433
|
}
|
|
391
434
|
|
|
392
|
-
// Check all
|
|
393
|
-
for (const [
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
if (capValue === undefined) {
|
|
397
|
-
// Missing tag in cap is treated as wildcard - can handle any value
|
|
398
|
-
continue;
|
|
399
|
-
}
|
|
435
|
+
// Check all tags required by the pattern. Missing tags in the instance reject.
|
|
436
|
+
for (const [patternKey, patternValue] of Object.entries(this.tags)) {
|
|
437
|
+
const requestValue = request.tags[patternKey];
|
|
400
438
|
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
continue;
|
|
439
|
+
if (requestValue === undefined) {
|
|
440
|
+
return false;
|
|
404
441
|
}
|
|
405
442
|
|
|
406
|
-
if (requestValue === '*') {
|
|
407
|
-
// Request accepts any value - cap's specific value matches
|
|
443
|
+
if (patternValue === '*' || requestValue === '*') {
|
|
408
444
|
continue;
|
|
409
445
|
}
|
|
410
446
|
|
|
411
|
-
if (
|
|
412
|
-
// Cap has specific value that doesn't match request's specific value
|
|
447
|
+
if (patternValue !== requestValue) {
|
|
413
448
|
return false;
|
|
414
449
|
}
|
|
415
450
|
}
|
|
416
451
|
|
|
417
|
-
// If cap has additional specific tags that request doesn't specify, that's fine
|
|
418
|
-
// The cap is just more specific than needed
|
|
419
452
|
return true;
|
|
420
453
|
}
|
|
421
454
|
|
|
@@ -441,12 +474,13 @@ class CapUrn {
|
|
|
441
474
|
*/
|
|
442
475
|
specificity() {
|
|
443
476
|
let count = 0;
|
|
444
|
-
// Direction specs contribute their MediaUrn tag count
|
|
445
|
-
|
|
477
|
+
// Direction specs contribute their MediaUrn tag count. `media:` is the
|
|
478
|
+
// wildcard top and contributes zero.
|
|
479
|
+
if (this.inSpec !== 'media:' && this.inSpec !== '*') {
|
|
446
480
|
const inMedia = TaggedUrn.fromString(this.inSpec);
|
|
447
481
|
count += Object.keys(inMedia.tags).length;
|
|
448
482
|
}
|
|
449
|
-
if (this.outSpec !== '*') {
|
|
483
|
+
if (this.outSpec !== 'media:' && this.outSpec !== '*') {
|
|
450
484
|
const outMedia = TaggedUrn.fromString(this.outSpec);
|
|
451
485
|
count += Object.keys(outMedia.tags).length;
|
|
452
486
|
}
|
|
@@ -686,7 +720,7 @@ class CapMatcher {
|
|
|
686
720
|
let bestSpecificity = -1;
|
|
687
721
|
|
|
688
722
|
for (const cap of caps) {
|
|
689
|
-
if (
|
|
723
|
+
if (request.accepts(cap)) {
|
|
690
724
|
const specificity = cap.specificity();
|
|
691
725
|
if (specificity > bestSpecificity) {
|
|
692
726
|
best = cap;
|
|
@@ -706,7 +740,7 @@ class CapMatcher {
|
|
|
706
740
|
* @returns {CapUrn[]} Array of matching caps sorted by specificity (most specific first)
|
|
707
741
|
*/
|
|
708
742
|
static findAllMatches(caps, request) {
|
|
709
|
-
const matches = caps.filter(cap =>
|
|
743
|
+
const matches = caps.filter(cap => request.accepts(cap));
|
|
710
744
|
|
|
711
745
|
// Sort by specificity (most specific first)
|
|
712
746
|
matches.sort((a, b) => b.specificity() - a.specificity());
|
|
@@ -900,6 +934,8 @@ const MEDIA_TEXTABLE_PAGE = 'media:textable;page';
|
|
|
900
934
|
// Collection types
|
|
901
935
|
const MEDIA_COLLECTION = 'media:collection;record';
|
|
902
936
|
const MEDIA_COLLECTION_LIST = 'media:collection;list;record';
|
|
937
|
+
// Media URN for adapter selection output - JSON record
|
|
938
|
+
const MEDIA_ADAPTER_SELECTION = 'media:adapter-selection;json;record';
|
|
903
939
|
|
|
904
940
|
// =============================================================================
|
|
905
941
|
// STANDARD CAP URN CONSTANTS
|
|
@@ -909,6 +945,10 @@ const MEDIA_COLLECTION_LIST = 'media:collection;list;record';
|
|
|
909
945
|
// Accepts any media type as input and outputs any media type
|
|
910
946
|
const CAP_IDENTITY = 'cap:in=media:;out=media:';
|
|
911
947
|
|
|
948
|
+
// Adapter-selection capability. Default implementation returns empty END (no match).
|
|
949
|
+
// Cartridges that inspect file content override this with a handler that returns {"media_urns": [...]}.
|
|
950
|
+
const CAP_ADAPTER_SELECTION = 'cap:in="media:";out="media:adapter-selection;json;record"';
|
|
951
|
+
|
|
912
952
|
// =============================================================================
|
|
913
953
|
// MEDIA URN CLASS
|
|
914
954
|
// =============================================================================
|
|
@@ -2473,6 +2513,23 @@ function validateCapArgs(cap) {
|
|
|
2473
2513
|
}
|
|
2474
2514
|
}
|
|
2475
2515
|
|
|
2516
|
+
// RULE11: Stdin source consistency with in= spec
|
|
2517
|
+
// If in= is media:void, no args may have stdin sources.
|
|
2518
|
+
// If in= is anything other than media:void, at least one arg must have a stdin source.
|
|
2519
|
+
const inMediaUrn = cap.urn.inMediaUrn();
|
|
2520
|
+
const voidUrn = MediaUrn.fromString(MEDIA_VOID);
|
|
2521
|
+
const inIsVoid = inMediaUrn.isEquivalent(voidUrn);
|
|
2522
|
+
if (inIsVoid && stdinUrns.length > 0) {
|
|
2523
|
+
throw new ValidationError('InvalidCapSchema', capUrn, {
|
|
2524
|
+
issue: `RULE11: Cap has in="${MEDIA_VOID}" but argument(s) declare stdin source`
|
|
2525
|
+
});
|
|
2526
|
+
}
|
|
2527
|
+
if (!inIsVoid && stdinUrns.length === 0 && args.length > 0) {
|
|
2528
|
+
throw new ValidationError('InvalidCapSchema', capUrn, {
|
|
2529
|
+
issue: `RULE11: Cap has non-void in= spec but no argument declares a stdin source`
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2476
2533
|
// RULE5: No two args may have same position
|
|
2477
2534
|
const positionSet = new Set();
|
|
2478
2535
|
for (const { position, mediaUrn } of positions) {
|
|
@@ -2507,9 +2564,6 @@ function validateCapArgs(cap) {
|
|
|
2507
2564
|
flagSet.add(flag);
|
|
2508
2565
|
}
|
|
2509
2566
|
|
|
2510
|
-
// RULE8: No unknown keys in source objects - this is handled in ArgSource.fromJSON()
|
|
2511
|
-
// RULE11: cli_flag used verbatim as specified - enforced by design
|
|
2512
|
-
// RULE12: media_urn is the key, no name field - enforced by CapArg structure
|
|
2513
2567
|
}
|
|
2514
2568
|
|
|
2515
2569
|
/**
|
|
@@ -5628,6 +5682,9 @@ module.exports = {
|
|
|
5628
5682
|
// Collection types
|
|
5629
5683
|
MEDIA_COLLECTION,
|
|
5630
5684
|
MEDIA_COLLECTION_LIST,
|
|
5685
|
+
MEDIA_ADAPTER_SELECTION,
|
|
5686
|
+
// Standard cap URN constants
|
|
5687
|
+
CAP_ADAPTER_SELECTION,
|
|
5631
5688
|
// Cap execution result
|
|
5632
5689
|
CapResult,
|
|
5633
5690
|
// Unified argument type
|