capdag 0.178.444 → 0.181.455
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 +363 -94
- package/capdag.test.js +364 -116
- package/package.json +2 -2
package/capdag.js
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
// Follows the exact same rules as Rust, Go, and Objective-C implementations
|
|
3
3
|
|
|
4
4
|
// Import TaggedUrn from the tagged-urn package
|
|
5
|
-
const {
|
|
5
|
+
const {
|
|
6
|
+
TaggedUrn,
|
|
7
|
+
valuesMatch: taggedUrnValuesMatch,
|
|
8
|
+
scoreTagValue
|
|
9
|
+
} = require('tagged-urn');
|
|
6
10
|
|
|
7
11
|
/**
|
|
8
12
|
* Error types for Cap URN operations
|
|
@@ -30,7 +34,10 @@ const ErrorCodes = {
|
|
|
30
34
|
MISSING_OUT_SPEC: 11,
|
|
31
35
|
EMPTY_VALUE: 12,
|
|
32
36
|
INVALID_IN_SPEC: 13,
|
|
33
|
-
INVALID_OUT_SPEC: 14
|
|
37
|
+
INVALID_OUT_SPEC: 14,
|
|
38
|
+
INVALID_EFFECT: 15,
|
|
39
|
+
INVALID_EFFECT_APPLICATION: 16,
|
|
40
|
+
ILLEGAL_DECLARATION: 17
|
|
34
41
|
};
|
|
35
42
|
|
|
36
43
|
// Note: All parsing is delegated to TaggedUrn from tagged-urn-js
|
|
@@ -114,8 +121,8 @@ function validatePreservedDirectionSpec(spec, tagName) {
|
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
/**
|
|
117
|
-
* Functional category of a cap, derived from all
|
|
118
|
-
* `out`, and the remaining tags). The classification is **logical** —
|
|
124
|
+
* Functional category of a cap, derived from all four structural axes
|
|
125
|
+
* (`in`, `out`, `effect`, and the remaining tags). The classification is **logical** —
|
|
119
126
|
* the dispatch protocol does not branch on CapKind. Exposed so tools,
|
|
120
127
|
* UIs, planners, and tests can reason about a cap's role without
|
|
121
128
|
* re-deriving the rules.
|
|
@@ -124,15 +131,13 @@ function validatePreservedDirectionSpec(spec, tagName) {
|
|
|
124
131
|
* is the **top type** (universal wildcard). With those anchors the
|
|
125
132
|
* five kinds fall out:
|
|
126
133
|
*
|
|
127
|
-
* IDENTITY in=media:, out=media:, no other tags → A → A
|
|
134
|
+
* IDENTITY in=media:, out=media:, effect=none, no other tags → A → A
|
|
128
135
|
* SOURCE in=media:void, out!=void → () → B
|
|
129
136
|
* SINK in!=void, out=media:void → A → ()
|
|
130
137
|
* EFFECT in=media:void, out=media:void → () → ()
|
|
131
138
|
* TRANSFORM anything else
|
|
132
139
|
*
|
|
133
|
-
*
|
|
134
|
-
* tag specifies something on the third axis and demotes the morphism
|
|
135
|
-
* to a TRANSFORM whose in/out happen to be the wildcards.
|
|
140
|
+
* `cap:effect=none` is the categorical identity morphism.
|
|
136
141
|
*
|
|
137
142
|
* String values are snake_case to match other capdag enum
|
|
138
143
|
* serializations on the wire.
|
|
@@ -145,6 +150,50 @@ const CapKind = Object.freeze({
|
|
|
145
150
|
TRANSFORM: 'transform',
|
|
146
151
|
});
|
|
147
152
|
|
|
153
|
+
const CapEffect = Object.freeze({
|
|
154
|
+
DECLARED: 'declared',
|
|
155
|
+
NONE: 'none',
|
|
156
|
+
PATCH: 'patch',
|
|
157
|
+
ANY: '?',
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
function normalizeEffectValue(rawValue) {
|
|
161
|
+
if (rawValue === undefined || rawValue === null) return CapEffect.DECLARED;
|
|
162
|
+
if (rawValue === '?' || rawValue === '*') return CapEffect.ANY;
|
|
163
|
+
if (rawValue === CapEffect.DECLARED) return CapEffect.DECLARED;
|
|
164
|
+
if (rawValue === CapEffect.NONE) return CapEffect.NONE;
|
|
165
|
+
if (rawValue === CapEffect.PATCH) return CapEffect.PATCH;
|
|
166
|
+
if (rawValue === '') {
|
|
167
|
+
throw new CapUrnError(ErrorCodes.INVALID_EFFECT, "Empty value for 'effect' tag is not allowed");
|
|
168
|
+
}
|
|
169
|
+
throw new CapUrnError(
|
|
170
|
+
ErrorCodes.INVALID_EFFECT,
|
|
171
|
+
`Unsupported effect '${rawValue}'. Supported values are declared, none, patch, or explicit unconstrained ?effect/effect=*`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function validateNonStructuralTags(tags) {
|
|
176
|
+
try {
|
|
177
|
+
new TaggedUrn('cap', tags, true);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
const msg = error && error.message ? error.message : String(error);
|
|
180
|
+
const msgLower = msg.toLowerCase();
|
|
181
|
+
if (msgLower.includes('duplicate')) {
|
|
182
|
+
throw new CapUrnError(ErrorCodes.DUPLICATE_KEY, msg);
|
|
183
|
+
}
|
|
184
|
+
if (msgLower.includes('numeric') || msgLower.includes('purely numeric')) {
|
|
185
|
+
throw new CapUrnError(ErrorCodes.NUMERIC_KEY, msg);
|
|
186
|
+
}
|
|
187
|
+
if (msgLower.includes('invalid character')) {
|
|
188
|
+
throw new CapUrnError(ErrorCodes.INVALID_CHARACTER, msg);
|
|
189
|
+
}
|
|
190
|
+
if (msgLower.includes('escape')) {
|
|
191
|
+
throw new CapUrnError(ErrorCodes.INVALID_ESCAPE_SEQUENCE, msg);
|
|
192
|
+
}
|
|
193
|
+
throw new CapUrnError(ErrorCodes.INVALID_TAG_FORMAT, msg);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
148
197
|
class CapUrn {
|
|
149
198
|
// Per-axis weights for cap-URN specificity. Two orders of
|
|
150
199
|
// magnitude separate each axis to keep them in distinct digit
|
|
@@ -157,19 +206,23 @@ class CapUrn {
|
|
|
157
206
|
* Create a new CapUrn with direction specs.
|
|
158
207
|
* @param {string} inSpec - Input media URN (e.g., "media:void")
|
|
159
208
|
* @param {string} outSpec - Output media URN (e.g., "media:object")
|
|
160
|
-
* @param {
|
|
209
|
+
* @param {string} effect - Runtime media identity effect
|
|
210
|
+
* @param {Object} tags - Other tags (must NOT contain 'in', 'out', or 'effect')
|
|
161
211
|
*/
|
|
162
|
-
constructor(inSpec, outSpec, tags = {}) {
|
|
212
|
+
constructor(inSpec, outSpec, effect = CapEffect.DECLARED, tags = {}) {
|
|
163
213
|
this.inSpec = canonicalizeDirectionSpec(inSpec, 'in');
|
|
164
214
|
this.outSpec = canonicalizeDirectionSpec(outSpec, 'out');
|
|
215
|
+
this.effectValue = normalizeEffectValue(effect);
|
|
165
216
|
this.tags = {};
|
|
166
|
-
// Copy tags, filtering out any
|
|
217
|
+
// Copy tags, filtering out any structural coordinates that might have slipped through
|
|
167
218
|
for (const [key, value] of Object.entries(tags)) {
|
|
168
219
|
const keyLower = key.toLowerCase();
|
|
169
|
-
if (keyLower !== 'in' && keyLower !== 'out') {
|
|
220
|
+
if (keyLower !== 'in' && keyLower !== 'out' && keyLower !== 'effect') {
|
|
170
221
|
this.tags[keyLower] = value;
|
|
171
222
|
}
|
|
172
223
|
}
|
|
224
|
+
validateNonStructuralTags(this.tags);
|
|
225
|
+
this._validateAdmissible();
|
|
173
226
|
}
|
|
174
227
|
|
|
175
228
|
/**
|
|
@@ -188,6 +241,14 @@ class CapUrn {
|
|
|
188
241
|
return this.outSpec;
|
|
189
242
|
}
|
|
190
243
|
|
|
244
|
+
/**
|
|
245
|
+
* Get the canonical effect coordinate.
|
|
246
|
+
* @returns {string}
|
|
247
|
+
*/
|
|
248
|
+
getEffect() {
|
|
249
|
+
return this.effectValue;
|
|
250
|
+
}
|
|
251
|
+
|
|
191
252
|
/**
|
|
192
253
|
* Parse the in= spec into a MediaUrn.
|
|
193
254
|
* @returns {MediaUrn} The input media URN
|
|
@@ -207,15 +268,11 @@ class CapUrn {
|
|
|
207
268
|
}
|
|
208
269
|
|
|
209
270
|
/**
|
|
210
|
-
* Functional category of this cap, derived from all
|
|
211
|
-
* `in
|
|
212
|
-
* the tags (the operation/metadata axis — `this.tags` does NOT
|
|
213
|
-
* include in/out, those live in this.inSpec/this.outSpec).
|
|
271
|
+
* Functional category of this cap, derived from all four axes:
|
|
272
|
+
* `in`, `out`, `effect`, and the remaining y-axis tags.
|
|
214
273
|
*
|
|
215
|
-
* Identity requires
|
|
216
|
-
*
|
|
217
|
-
* there are no other tags. Source/Sink/Effect are decided by void
|
|
218
|
-
* on either directional axis. Anything else is Transform.
|
|
274
|
+
* Identity requires top/top, no other tags, and explicit
|
|
275
|
+
* `effect=none`.
|
|
219
276
|
*
|
|
220
277
|
* @returns {string} A {@link CapKind} value (snake_case string).
|
|
221
278
|
* @throws {MediaUrnError} If either side is not a valid media URN
|
|
@@ -232,7 +289,9 @@ class CapUrn {
|
|
|
232
289
|
const outTop = outMedia.isTop();
|
|
233
290
|
const noExtraTags = Object.keys(this.tags).length === 0;
|
|
234
291
|
|
|
235
|
-
if (inTop && outTop && noExtraTags)
|
|
292
|
+
if (inTop && outTop && noExtraTags) {
|
|
293
|
+
if (this.effectValue === CapEffect.NONE) return CapKind.IDENTITY;
|
|
294
|
+
}
|
|
236
295
|
if (inVoid && outVoid) return CapKind.EFFECT;
|
|
237
296
|
if (inVoid) return CapKind.SOURCE;
|
|
238
297
|
if (outVoid) return CapKind.SINK;
|
|
@@ -293,20 +352,23 @@ class CapUrn {
|
|
|
293
352
|
const inSpec = processDirectionTag(taggedUrn, 'in');
|
|
294
353
|
const outSpec = processDirectionTag(taggedUrn, 'out');
|
|
295
354
|
|
|
296
|
-
|
|
355
|
+
const effect = normalizeEffectValue(taggedUrn.getTag('effect'));
|
|
356
|
+
|
|
357
|
+
// Build remaining tags (excluding in/out/effect)
|
|
297
358
|
const remainingTags = {};
|
|
298
359
|
for (const [key, value] of Object.entries(taggedUrn.tags)) {
|
|
299
|
-
if (key !== 'in' && key !== 'out') {
|
|
360
|
+
if (key !== 'in' && key !== 'out' && key !== 'effect') {
|
|
300
361
|
remainingTags[key] = value;
|
|
301
362
|
}
|
|
302
363
|
}
|
|
303
364
|
|
|
304
|
-
return new CapUrn(inSpec, outSpec, remainingTags);
|
|
365
|
+
return new CapUrn(inSpec, outSpec, effect, remainingTags);
|
|
305
366
|
}
|
|
306
367
|
|
|
307
368
|
/**
|
|
308
369
|
* Create a Cap URN from a tags object.
|
|
309
|
-
*
|
|
370
|
+
* Missing structural coordinates default exactly as they do in string
|
|
371
|
+
* parsing (`in=media:`, `out=media:`, `effect=declared`).
|
|
310
372
|
*
|
|
311
373
|
* @param {Object} tags - Object containing all tags including 'in' and 'out'
|
|
312
374
|
* @returns {CapUrn} The parsed Cap URN
|
|
@@ -330,16 +392,18 @@ class CapUrn {
|
|
|
330
392
|
throw new CapUrnError(ErrorCodes.INVALID_OUT_SPEC, "Empty value for 'out' tag is not allowed");
|
|
331
393
|
}
|
|
332
394
|
|
|
333
|
-
|
|
395
|
+
const effect = normalizeEffectValue(tags['effect'] || tags['EFFECT']);
|
|
396
|
+
|
|
397
|
+
// Build remaining tags (excluding in/out/effect)
|
|
334
398
|
const remainingTags = {};
|
|
335
399
|
for (const [key, value] of Object.entries(tags)) {
|
|
336
400
|
const keyLower = key.toLowerCase();
|
|
337
|
-
if (keyLower !== 'in' && keyLower !== 'out') {
|
|
401
|
+
if (keyLower !== 'in' && keyLower !== 'out' && keyLower !== 'effect') {
|
|
338
402
|
remainingTags[keyLower] = value;
|
|
339
403
|
}
|
|
340
404
|
}
|
|
341
405
|
|
|
342
|
-
return new CapUrn(inSpec, outSpec, remainingTags);
|
|
406
|
+
return new CapUrn(inSpec, outSpec, effect, remainingTags);
|
|
343
407
|
}
|
|
344
408
|
|
|
345
409
|
/**
|
|
@@ -352,11 +416,8 @@ class CapUrn {
|
|
|
352
416
|
*/
|
|
353
417
|
toString() {
|
|
354
418
|
// `in` and `out` segments are emitted only when they refine beyond
|
|
355
|
-
// the trivial wildcard `media:`.
|
|
356
|
-
// `
|
|
357
|
-
// `cap:` — the bare identity URN. The canonicalizer collapses both
|
|
358
|
-
// written forms (`cap:` and `cap:in=media:;out=media:`) to one
|
|
359
|
-
// representative so byte-equality matches semantic identity.
|
|
419
|
+
// the trivial wildcard `media:`. Missing `effect` means the default
|
|
420
|
+
// `declared`; `effect=none` is preserved.
|
|
360
421
|
const allTags = { ...this.tags };
|
|
361
422
|
if (this.inSpec !== 'media:') {
|
|
362
423
|
allTags['in'] = this.inSpec;
|
|
@@ -364,6 +425,9 @@ class CapUrn {
|
|
|
364
425
|
if (this.outSpec !== 'media:') {
|
|
365
426
|
allTags['out'] = this.outSpec;
|
|
366
427
|
}
|
|
428
|
+
if (this.effectValue !== CapEffect.DECLARED) {
|
|
429
|
+
allTags['effect'] = this.effectValue;
|
|
430
|
+
}
|
|
367
431
|
|
|
368
432
|
const taggedUrn = new TaggedUrn('cap', allTags, true);
|
|
369
433
|
return taggedUrn.toString();
|
|
@@ -372,7 +436,8 @@ class CapUrn {
|
|
|
372
436
|
/**
|
|
373
437
|
* Get the value of a specific tag
|
|
374
438
|
* Key is normalized to lowercase for lookup
|
|
375
|
-
* Returns inSpec for "in" key, outSpec for "out" key
|
|
439
|
+
* Returns inSpec for "in" key, outSpec for "out" key, and the effect
|
|
440
|
+
* coordinate for "effect".
|
|
376
441
|
*
|
|
377
442
|
* @param {string} key - The tag key
|
|
378
443
|
* @returns {string|undefined} The tag value or undefined if not found
|
|
@@ -385,13 +450,16 @@ class CapUrn {
|
|
|
385
450
|
if (keyLower === 'out') {
|
|
386
451
|
return this.outSpec;
|
|
387
452
|
}
|
|
453
|
+
if (keyLower === 'effect') {
|
|
454
|
+
return this.effectValue;
|
|
455
|
+
}
|
|
388
456
|
return this.tags[keyLower];
|
|
389
457
|
}
|
|
390
458
|
|
|
391
459
|
/**
|
|
392
460
|
* Check if this cap has a specific tag with a specific value
|
|
393
461
|
* Key is normalized to lowercase; value comparison is case-sensitive
|
|
394
|
-
* Checks inSpec for "in" key, outSpec for "out" key
|
|
462
|
+
* Checks inSpec for "in" key, outSpec for "out" key, and effect for "effect"
|
|
395
463
|
*
|
|
396
464
|
* @param {string} key - The tag key
|
|
397
465
|
* @param {string} value - The tag value to check
|
|
@@ -405,6 +473,9 @@ class CapUrn {
|
|
|
405
473
|
if (keyLower === 'out') {
|
|
406
474
|
return this.outSpec === value;
|
|
407
475
|
}
|
|
476
|
+
if (keyLower === 'effect') {
|
|
477
|
+
return this.effectValue === value;
|
|
478
|
+
}
|
|
408
479
|
const tagValue = this.tags[keyLower];
|
|
409
480
|
return tagValue !== undefined && tagValue === value;
|
|
410
481
|
}
|
|
@@ -422,7 +493,7 @@ class CapUrn {
|
|
|
422
493
|
*/
|
|
423
494
|
hasMarkerTag(tagName) {
|
|
424
495
|
const keyLower = tagName.toLowerCase();
|
|
425
|
-
if (keyLower === 'in' || keyLower === 'out') {
|
|
496
|
+
if (keyLower === 'in' || keyLower === 'out' || keyLower === 'effect') {
|
|
426
497
|
return false;
|
|
427
498
|
}
|
|
428
499
|
return this.tags[keyLower] === '*';
|
|
@@ -430,8 +501,8 @@ class CapUrn {
|
|
|
430
501
|
|
|
431
502
|
/**
|
|
432
503
|
* Create a new cap URN with an added or updated tag.
|
|
433
|
-
*
|
|
434
|
-
*
|
|
504
|
+
* Reserved structural coordinates must be changed through dedicated
|
|
505
|
+
* accessors.
|
|
435
506
|
*
|
|
436
507
|
* @param {string} key - The tag key
|
|
437
508
|
* @param {string} value - The tag value
|
|
@@ -442,13 +513,15 @@ class CapUrn {
|
|
|
442
513
|
throw new CapUrnError(ErrorCodes.EMPTY_VALUE, `Empty value for key '${key}' (use '*' for wildcard)`);
|
|
443
514
|
}
|
|
444
515
|
const keyLower = key.toLowerCase();
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
516
|
+
if (keyLower === 'in' || keyLower === 'out' || keyLower === 'effect') {
|
|
517
|
+
throw new CapUrnError(
|
|
518
|
+
ErrorCodes.INVALID_TAG_FORMAT,
|
|
519
|
+
`Reserved structural key '${keyLower}' must be changed via withInSpec(), withOutSpec(), or withEffect()`
|
|
520
|
+
);
|
|
448
521
|
}
|
|
449
522
|
const newTags = { ...this.tags };
|
|
450
523
|
newTags[keyLower] = value;
|
|
451
|
-
return new CapUrn(this.inSpec, this.outSpec, newTags);
|
|
524
|
+
return new CapUrn(this.inSpec, this.outSpec, this.effectValue, newTags);
|
|
452
525
|
}
|
|
453
526
|
|
|
454
527
|
/**
|
|
@@ -458,9 +531,12 @@ class CapUrn {
|
|
|
458
531
|
* @returns {CapUrn} A new CapUrn instance with the updated inSpec
|
|
459
532
|
*/
|
|
460
533
|
withInSpec(inSpec) {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
534
|
+
return new CapUrn(
|
|
535
|
+
validatePreservedDirectionSpec(inSpec, 'in'),
|
|
536
|
+
this.outSpec,
|
|
537
|
+
this.effectValue,
|
|
538
|
+
this.tags
|
|
539
|
+
);
|
|
464
540
|
}
|
|
465
541
|
|
|
466
542
|
/**
|
|
@@ -470,28 +546,43 @@ class CapUrn {
|
|
|
470
546
|
* @returns {CapUrn} A new CapUrn instance with the updated outSpec
|
|
471
547
|
*/
|
|
472
548
|
withOutSpec(outSpec) {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
549
|
+
return new CapUrn(
|
|
550
|
+
this.inSpec,
|
|
551
|
+
validatePreservedDirectionSpec(outSpec, 'out'),
|
|
552
|
+
this.effectValue,
|
|
553
|
+
this.tags
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Create a new cap URN with a different effect coordinate.
|
|
559
|
+
*
|
|
560
|
+
* @param {string} effect
|
|
561
|
+
* @returns {CapUrn}
|
|
562
|
+
*/
|
|
563
|
+
withEffect(effect) {
|
|
564
|
+
return new CapUrn(this.inSpec, this.outSpec, normalizeEffectValue(effect), this.tags);
|
|
476
565
|
}
|
|
477
566
|
|
|
478
567
|
/**
|
|
479
568
|
* Create a new cap URN with a tag removed
|
|
480
569
|
* Key is normalized to lowercase for case-insensitive removal
|
|
481
|
-
*
|
|
570
|
+
* Reserved structural coordinates must be changed through dedicated accessors.
|
|
482
571
|
*
|
|
483
572
|
* @param {string} key - The tag key to remove
|
|
484
573
|
* @returns {CapUrn} A new CapUrn instance with the tag removed
|
|
485
574
|
*/
|
|
486
575
|
withoutTag(key) {
|
|
487
576
|
const keyLower = key.toLowerCase();
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
577
|
+
if (keyLower === 'in' || keyLower === 'out' || keyLower === 'effect') {
|
|
578
|
+
throw new CapUrnError(
|
|
579
|
+
ErrorCodes.INVALID_TAG_FORMAT,
|
|
580
|
+
`Reserved structural key '${keyLower}' cannot be removed via withoutTag()`
|
|
581
|
+
);
|
|
491
582
|
}
|
|
492
583
|
const newTags = { ...this.tags };
|
|
493
584
|
delete newTags[keyLower];
|
|
494
|
-
return new CapUrn(this.inSpec, this.outSpec, newTags);
|
|
585
|
+
return new CapUrn(this.inSpec, this.outSpec, this.effectValue, newTags);
|
|
495
586
|
}
|
|
496
587
|
|
|
497
588
|
/**
|
|
@@ -516,8 +607,8 @@ class CapUrn {
|
|
|
516
607
|
// Input direction: pattern accepts instance. `media:` on the pattern side is
|
|
517
608
|
// the wildcard top and skips the check.
|
|
518
609
|
if (this.inSpec !== 'media:' && this.inSpec !== '*') {
|
|
519
|
-
const capIn =
|
|
520
|
-
const requestIn =
|
|
610
|
+
const capIn = MediaUrn.fromString(this.inSpec);
|
|
611
|
+
const requestIn = MediaUrn.fromString(request.inSpec);
|
|
521
612
|
if (!capIn.accepts(requestIn)) {
|
|
522
613
|
return false;
|
|
523
614
|
}
|
|
@@ -526,13 +617,17 @@ class CapUrn {
|
|
|
526
617
|
// Output direction: provider output must conform to requested output.
|
|
527
618
|
// `media:` on the pattern side is wildcard top and skips the check.
|
|
528
619
|
if (this.outSpec !== 'media:' && this.outSpec !== '*') {
|
|
529
|
-
const capOut =
|
|
530
|
-
const requestOut =
|
|
620
|
+
const capOut = MediaUrn.fromString(this.outSpec);
|
|
621
|
+
const requestOut = MediaUrn.fromString(request.outSpec);
|
|
531
622
|
if (!capOut.conformsTo(requestOut)) {
|
|
532
623
|
return false;
|
|
533
624
|
}
|
|
534
625
|
}
|
|
535
626
|
|
|
627
|
+
if (this.effectValue !== CapEffect.ANY && this.effectValue !== request.effectValue) {
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
|
|
536
631
|
// Y-axis: every tag's per-key match runs through the six-form
|
|
537
632
|
// truth table (taggedUrnValuesMatch). Walk the union of all keys
|
|
538
633
|
// appearing on either side so missing-on-pattern and
|
|
@@ -593,8 +688,8 @@ class CapUrn {
|
|
|
593
688
|
* @returns {number} The specificity score
|
|
594
689
|
*/
|
|
595
690
|
specificity() {
|
|
596
|
-
const inUrn =
|
|
597
|
-
const outUrn =
|
|
691
|
+
const inUrn = MediaUrn.fromString(this.inSpec);
|
|
692
|
+
const outUrn = MediaUrn.fromString(this.outSpec);
|
|
598
693
|
|
|
599
694
|
let yScore = 0;
|
|
600
695
|
for (const value of Object.values(this.tags)) {
|
|
@@ -629,10 +724,13 @@ class CapUrn {
|
|
|
629
724
|
withWildcardTag(key) {
|
|
630
725
|
const keyLower = key.toLowerCase();
|
|
631
726
|
if (keyLower === 'in') {
|
|
632
|
-
return this.withInSpec('
|
|
727
|
+
return this.withInSpec('media:');
|
|
633
728
|
}
|
|
634
729
|
if (keyLower === 'out') {
|
|
635
|
-
return this.withOutSpec('
|
|
730
|
+
return this.withOutSpec('media:');
|
|
731
|
+
}
|
|
732
|
+
if (keyLower === 'effect') {
|
|
733
|
+
return this.withEffect(CapEffect.ANY);
|
|
636
734
|
}
|
|
637
735
|
if (this.tags.hasOwnProperty(keyLower)) {
|
|
638
736
|
return this.withTag(key, '*');
|
|
@@ -642,7 +740,7 @@ class CapUrn {
|
|
|
642
740
|
|
|
643
741
|
/**
|
|
644
742
|
* Create a new cap with only specified tags
|
|
645
|
-
* Always preserves inSpec
|
|
743
|
+
* Always preserves inSpec, outSpec, and effect.
|
|
646
744
|
*
|
|
647
745
|
* @param {string[]} keys - Array of tag keys to include
|
|
648
746
|
* @returns {CapUrn} A new CapUrn instance with only the specified tags (plus in/out)
|
|
@@ -651,29 +749,28 @@ class CapUrn {
|
|
|
651
749
|
const newTags = {};
|
|
652
750
|
for (const key of keys) {
|
|
653
751
|
const normalizedKey = key.toLowerCase();
|
|
654
|
-
|
|
655
|
-
if (normalizedKey !== 'in' && normalizedKey !== 'out') {
|
|
752
|
+
if (normalizedKey !== 'in' && normalizedKey !== 'out' && normalizedKey !== 'effect') {
|
|
656
753
|
if (this.tags.hasOwnProperty(normalizedKey)) {
|
|
657
754
|
newTags[normalizedKey] = this.tags[normalizedKey];
|
|
658
755
|
}
|
|
659
756
|
}
|
|
660
757
|
}
|
|
661
|
-
return new CapUrn(this.inSpec, this.outSpec, newTags);
|
|
758
|
+
return new CapUrn(this.inSpec, this.outSpec, this.effectValue, newTags);
|
|
662
759
|
}
|
|
663
760
|
|
|
664
761
|
/**
|
|
665
762
|
* Merge with another cap (other takes precedence for conflicts)
|
|
666
|
-
*
|
|
763
|
+
* Structural coordinates are taken from other.
|
|
667
764
|
*
|
|
668
765
|
* @param {CapUrn} other - The cap to merge with
|
|
669
766
|
* @returns {CapUrn} A new CapUrn instance with merged tags
|
|
670
767
|
*/
|
|
671
768
|
merge(other) {
|
|
672
769
|
if (!other) {
|
|
673
|
-
return new CapUrn(this.inSpec, this.outSpec, this.tags);
|
|
770
|
+
return new CapUrn(this.inSpec, this.outSpec, this.effectValue, this.tags);
|
|
674
771
|
}
|
|
675
772
|
const newTags = { ...this.tags, ...other.tags };
|
|
676
|
-
return new CapUrn(other.inSpec, other.outSpec, newTags);
|
|
773
|
+
return new CapUrn(other.inSpec, other.outSpec, other.effectValue, newTags);
|
|
677
774
|
}
|
|
678
775
|
|
|
679
776
|
/**
|
|
@@ -710,7 +807,7 @@ class CapUrn {
|
|
|
710
807
|
}
|
|
711
808
|
|
|
712
809
|
// Compare direction specs
|
|
713
|
-
if (this.inSpec !== other.inSpec || this.outSpec !== other.outSpec) {
|
|
810
|
+
if (this.inSpec !== other.inSpec || this.outSpec !== other.outSpec || this.effectValue !== other.effectValue) {
|
|
714
811
|
return false;
|
|
715
812
|
}
|
|
716
813
|
|
|
@@ -751,6 +848,139 @@ class CapUrn {
|
|
|
751
848
|
}
|
|
752
849
|
return hash.toString(16);
|
|
753
850
|
}
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Check if this provider can dispatch the given request.
|
|
854
|
+
*
|
|
855
|
+
* @param {CapUrn} request
|
|
856
|
+
* @returns {boolean}
|
|
857
|
+
*/
|
|
858
|
+
isDispatchable(request) {
|
|
859
|
+
return this._inputDispatchable(request)
|
|
860
|
+
&& this._outputDispatchable(request)
|
|
861
|
+
&& this._effectDispatchable(request)
|
|
862
|
+
&& this._capTagsDispatchable(request);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
_inputDispatchable(request) {
|
|
866
|
+
if (request.inSpec === 'media:') return true;
|
|
867
|
+
if (this.inSpec === 'media:') return true;
|
|
868
|
+
return MediaUrn.fromString(request.inSpec).conformsTo(MediaUrn.fromString(this.inSpec));
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
_outputDispatchable(request) {
|
|
872
|
+
if (request.outSpec === 'media:') return true;
|
|
873
|
+
if (this.outSpec === 'media:') return false;
|
|
874
|
+
return MediaUrn.fromString(this.outSpec).conformsTo(MediaUrn.fromString(request.outSpec));
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
_effectDispatchable(request) {
|
|
878
|
+
return request.effectValue === CapEffect.ANY || this.effectValue === request.effectValue;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
_capTagsDispatchable(request) {
|
|
882
|
+
const allKeys = new Set([
|
|
883
|
+
...Object.keys(this.tags),
|
|
884
|
+
...Object.keys(request.tags),
|
|
885
|
+
]);
|
|
886
|
+
for (const key of allKeys) {
|
|
887
|
+
const patt = Object.prototype.hasOwnProperty.call(request.tags, key)
|
|
888
|
+
? request.tags[key]
|
|
889
|
+
: undefined;
|
|
890
|
+
const inst = Object.prototype.hasOwnProperty.call(this.tags, key)
|
|
891
|
+
? this.tags[key]
|
|
892
|
+
: undefined;
|
|
893
|
+
if (!taggedUrnValuesMatch(inst, patt)) {
|
|
894
|
+
return false;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
return true;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Infer the runtime output media for a concrete runtime input.
|
|
902
|
+
*
|
|
903
|
+
* @param {MediaUrn} runtimeInput
|
|
904
|
+
* @returns {MediaUrn}
|
|
905
|
+
*/
|
|
906
|
+
inferRuntimeOutputMedia(runtimeInput) {
|
|
907
|
+
const declaredIn = this.inMediaUrn();
|
|
908
|
+
const declaredOut = this.outMediaUrn();
|
|
909
|
+
|
|
910
|
+
if (!runtimeInput.conformsTo(declaredIn)) {
|
|
911
|
+
throw new CapUrnError(
|
|
912
|
+
ErrorCodes.INVALID_EFFECT_APPLICATION,
|
|
913
|
+
`Runtime input '${runtimeInput}' does not conform to declared input '${declaredIn}'`
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
let runtimeOut;
|
|
918
|
+
switch (this.effectValue) {
|
|
919
|
+
case CapEffect.DECLARED:
|
|
920
|
+
runtimeOut = declaredOut;
|
|
921
|
+
break;
|
|
922
|
+
case CapEffect.NONE:
|
|
923
|
+
runtimeOut = runtimeInput;
|
|
924
|
+
break;
|
|
925
|
+
case CapEffect.PATCH: {
|
|
926
|
+
const delta = declaredOut.deltaFrom(declaredIn);
|
|
927
|
+
runtimeOut = runtimeInput.applyDelta(delta);
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
case CapEffect.ANY:
|
|
931
|
+
throw new CapUrnError(
|
|
932
|
+
ErrorCodes.INVALID_EFFECT_APPLICATION,
|
|
933
|
+
'Cannot infer runtime output for an unconstrained effect request'
|
|
934
|
+
);
|
|
935
|
+
default:
|
|
936
|
+
throw new CapUrnError(
|
|
937
|
+
ErrorCodes.INVALID_EFFECT_APPLICATION,
|
|
938
|
+
`Unexpected effect '${this.effectValue}' during runtime output inference`
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (!runtimeOut.conformsTo(declaredOut)) {
|
|
943
|
+
throw new CapUrnError(
|
|
944
|
+
ErrorCodes.INVALID_EFFECT_APPLICATION,
|
|
945
|
+
`Inferred runtime output '${runtimeOut}' does not conform to declared output '${declaredOut}'`
|
|
946
|
+
);
|
|
947
|
+
}
|
|
948
|
+
return runtimeOut;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
_validateAdmissible() {
|
|
952
|
+
const inMedia = this.inMediaUrn();
|
|
953
|
+
const outMedia = this.outMediaUrn();
|
|
954
|
+
const noExtraTags = Object.keys(this.tags).length === 0;
|
|
955
|
+
|
|
956
|
+
if (inMedia.isTop() && outMedia.isTop() && noExtraTags && this.effectValue === CapEffect.DECLARED) {
|
|
957
|
+
throw new CapUrnError(
|
|
958
|
+
ErrorCodes.ILLEGAL_DECLARATION,
|
|
959
|
+
'illegal bare top cap; use cap:effect=none for identity, or declare a non-vacuous input/output/effect/tag'
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
if (this.effectValue === CapEffect.NONE) {
|
|
964
|
+
if (!inMedia.conformsTo(outMedia)) {
|
|
965
|
+
throw new CapUrnError(
|
|
966
|
+
ErrorCodes.ILLEGAL_DECLARATION,
|
|
967
|
+
`effect=none requires declared input '${inMedia}' to conform to declared output '${outMedia}'`
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
if (this.effectValue === CapEffect.PATCH) {
|
|
974
|
+
const delta = outMedia.deltaFrom(inMedia);
|
|
975
|
+
const witness = inMedia.applyDelta(delta);
|
|
976
|
+
if (!witness.conformsTo(outMedia)) {
|
|
977
|
+
throw new CapUrnError(
|
|
978
|
+
ErrorCodes.ILLEGAL_DECLARATION,
|
|
979
|
+
`effect=patch witness '${witness}' does not conform to declared output '${outMedia}'`
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
754
984
|
}
|
|
755
985
|
|
|
756
986
|
/**
|
|
@@ -760,6 +990,7 @@ class CapUrnBuilder {
|
|
|
760
990
|
constructor() {
|
|
761
991
|
this._inSpec = null;
|
|
762
992
|
this._outSpec = null;
|
|
993
|
+
this._effect = CapEffect.DECLARED;
|
|
763
994
|
this._tags = {};
|
|
764
995
|
}
|
|
765
996
|
|
|
@@ -785,10 +1016,15 @@ class CapUrnBuilder {
|
|
|
785
1016
|
return this;
|
|
786
1017
|
}
|
|
787
1018
|
|
|
1019
|
+
effect(effect) {
|
|
1020
|
+
this._effect = normalizeEffectValue(effect);
|
|
1021
|
+
return this;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
788
1024
|
/**
|
|
789
1025
|
* Add or update a tag
|
|
790
1026
|
* Key is normalized to lowercase; value is preserved as-is
|
|
791
|
-
*
|
|
1027
|
+
* Structural coordinates are reserved; use dedicated methods instead.
|
|
792
1028
|
*
|
|
793
1029
|
* @param {string} key - The tag key
|
|
794
1030
|
* @param {string} value - The tag value
|
|
@@ -796,10 +1032,13 @@ class CapUrnBuilder {
|
|
|
796
1032
|
*/
|
|
797
1033
|
tag(key, value) {
|
|
798
1034
|
const keyLower = key.toLowerCase();
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
1035
|
+
if (keyLower === 'in' || keyLower === 'out' || keyLower === 'effect') {
|
|
1036
|
+
throw new CapUrnError(
|
|
1037
|
+
ErrorCodes.INVALID_TAG_FORMAT,
|
|
1038
|
+
`Reserved structural key '${keyLower}' must be set via inSpec(), outSpec(), or effect()`
|
|
1039
|
+
);
|
|
802
1040
|
}
|
|
1041
|
+
this._tags[keyLower] = value;
|
|
803
1042
|
return this;
|
|
804
1043
|
}
|
|
805
1044
|
|
|
@@ -813,9 +1052,13 @@ class CapUrnBuilder {
|
|
|
813
1052
|
*/
|
|
814
1053
|
marker(key) {
|
|
815
1054
|
const keyLower = key.toLowerCase();
|
|
816
|
-
if (keyLower
|
|
817
|
-
|
|
1055
|
+
if (keyLower === 'in' || keyLower === 'out' || keyLower === 'effect') {
|
|
1056
|
+
throw new CapUrnError(
|
|
1057
|
+
ErrorCodes.INVALID_TAG_FORMAT,
|
|
1058
|
+
`Reserved structural key '${keyLower}' cannot be used as a marker`
|
|
1059
|
+
);
|
|
818
1060
|
}
|
|
1061
|
+
this._tags[keyLower] = '*';
|
|
819
1062
|
return this;
|
|
820
1063
|
}
|
|
821
1064
|
|
|
@@ -832,7 +1075,7 @@ class CapUrnBuilder {
|
|
|
832
1075
|
if (!this._outSpec) {
|
|
833
1076
|
throw new CapUrnError(ErrorCodes.MISSING_OUT_SPEC, "Cap URN requires 'out' spec - call outSpec() before build()");
|
|
834
1077
|
}
|
|
835
|
-
return new CapUrn(this._inSpec, this._outSpec, this._tags);
|
|
1078
|
+
return new CapUrn(this._inSpec, this._outSpec, this._effect, this._tags);
|
|
836
1079
|
}
|
|
837
1080
|
}
|
|
838
1081
|
|
|
@@ -1128,9 +1371,9 @@ const MEDIA_MEDIA_SPEC_DEFINITION = 'media:media-spec-definition;json;record;tex
|
|
|
1128
1371
|
// STANDARD CAP URN CONSTANTS
|
|
1129
1372
|
// =============================================================================
|
|
1130
1373
|
|
|
1131
|
-
// Standard
|
|
1132
|
-
// Accepts any media type as input and
|
|
1133
|
-
const CAP_IDENTITY = 'cap:
|
|
1374
|
+
// Standard identity capability URN.
|
|
1375
|
+
// Accepts any media type as input and preserves the runtime media identity.
|
|
1376
|
+
const CAP_IDENTITY = 'cap:effect=none';
|
|
1134
1377
|
|
|
1135
1378
|
// Adapter-selection capability. Default implementation returns empty END (no match).
|
|
1136
1379
|
// Cartridges that inspect file content override this with a handler that returns {"media_urns": [...]}.
|
|
@@ -1390,6 +1633,20 @@ class MediaUrn {
|
|
|
1390
1633
|
*/
|
|
1391
1634
|
isComparable(other) { return this._urn.isComparable(other._urn); }
|
|
1392
1635
|
|
|
1636
|
+
/**
|
|
1637
|
+
* Compute the coordinate-space delta from `base` to this media URN.
|
|
1638
|
+
* @param {MediaUrn} base
|
|
1639
|
+
* @returns {TaggedUrnCoordinateDelta}
|
|
1640
|
+
*/
|
|
1641
|
+
deltaFrom(base) { return this._urn.deltaFrom(base._urn); }
|
|
1642
|
+
|
|
1643
|
+
/**
|
|
1644
|
+
* Apply a coordinate-space delta to this media URN.
|
|
1645
|
+
* @param {TaggedUrnCoordinateDelta} delta
|
|
1646
|
+
* @returns {MediaUrn}
|
|
1647
|
+
*/
|
|
1648
|
+
applyDelta(delta) { return new MediaUrn(this._urn.applyDelta(delta)); }
|
|
1649
|
+
|
|
1393
1650
|
/**
|
|
1394
1651
|
* @param {MediaUrn} other
|
|
1395
1652
|
* @returns {boolean}
|
|
@@ -2118,9 +2375,9 @@ class CapArg {
|
|
|
2118
2375
|
this.required = required;
|
|
2119
2376
|
this.is_sequence = options.is_sequence || false;
|
|
2120
2377
|
this.sources = sources; // Array of ArgSource
|
|
2121
|
-
this.arg_description = options.arg_description
|
|
2378
|
+
this.arg_description = options.arg_description !== undefined ? options.arg_description : null;
|
|
2122
2379
|
this.default_value = options.default_value !== undefined ? options.default_value : null;
|
|
2123
|
-
this.metadata = options.metadata
|
|
2380
|
+
this.metadata = options.metadata !== undefined ? options.metadata : null;
|
|
2124
2381
|
}
|
|
2125
2382
|
|
|
2126
2383
|
/**
|
|
@@ -2154,11 +2411,15 @@ class CapArg {
|
|
|
2154
2411
|
sources: this.sources.map(s => s.toJSON())
|
|
2155
2412
|
};
|
|
2156
2413
|
if (this.is_sequence) result.is_sequence = true;
|
|
2157
|
-
if (this.arg_description
|
|
2414
|
+
if (this.arg_description !== null && this.arg_description !== undefined) {
|
|
2415
|
+
result.arg_description = this.arg_description;
|
|
2416
|
+
}
|
|
2158
2417
|
if (this.default_value !== null && this.default_value !== undefined) {
|
|
2159
2418
|
result.default_value = this.default_value;
|
|
2160
2419
|
}
|
|
2161
|
-
if (this.metadata
|
|
2420
|
+
if (this.metadata !== null && this.metadata !== undefined) {
|
|
2421
|
+
result.metadata = this.metadata;
|
|
2422
|
+
}
|
|
2162
2423
|
return result;
|
|
2163
2424
|
}
|
|
2164
2425
|
|
|
@@ -2618,10 +2879,10 @@ class CapManifest {
|
|
|
2618
2879
|
* @param {CapGroup[]} capGroups - Cap groups (all caps must be in a group)
|
|
2619
2880
|
*/
|
|
2620
2881
|
constructor(name, version, channel, registryUrl, description, capGroups = []) {
|
|
2621
|
-
if (
|
|
2882
|
+
if (typeof name !== 'string') {
|
|
2622
2883
|
throw new Error('CapManifest name is required and must be a string');
|
|
2623
2884
|
}
|
|
2624
|
-
if (
|
|
2885
|
+
if (typeof version !== 'string') {
|
|
2625
2886
|
throw new Error('CapManifest version is required and must be a string');
|
|
2626
2887
|
}
|
|
2627
2888
|
if (channel !== 'release' && channel !== 'nightly') {
|
|
@@ -2630,7 +2891,7 @@ class CapManifest {
|
|
|
2630
2891
|
if (registryUrl !== null && registryUrl !== undefined && typeof registryUrl !== 'string') {
|
|
2631
2892
|
throw new Error("CapManifest registry_url must be null (dev build) or a string");
|
|
2632
2893
|
}
|
|
2633
|
-
if (
|
|
2894
|
+
if (typeof description !== 'string') {
|
|
2634
2895
|
throw new Error('CapManifest description is required and must be a string');
|
|
2635
2896
|
}
|
|
2636
2897
|
|
|
@@ -2664,10 +2925,10 @@ class CapManifest {
|
|
|
2664
2925
|
* @throws {Error} If required fields are missing or invalid
|
|
2665
2926
|
*/
|
|
2666
2927
|
static fromJSON(json) {
|
|
2667
|
-
if (!json
|
|
2668
|
-
if (!json
|
|
2669
|
-
if (!json
|
|
2670
|
-
if (!json
|
|
2928
|
+
if (!Object.prototype.hasOwnProperty.call(json, 'name')) throw new Error('CapManifest missing required field: name');
|
|
2929
|
+
if (!Object.prototype.hasOwnProperty.call(json, 'version')) throw new Error('CapManifest missing required field: version');
|
|
2930
|
+
if (!Object.prototype.hasOwnProperty.call(json, 'channel')) throw new Error('CapManifest missing required field: channel');
|
|
2931
|
+
if (!Object.prototype.hasOwnProperty.call(json, 'description')) throw new Error('CapManifest missing required field: description');
|
|
2671
2932
|
if (!Array.isArray(json.cap_groups)) throw new Error('CapManifest missing required field: cap_groups');
|
|
2672
2933
|
|
|
2673
2934
|
// registry_url must be present as a key (may be null for dev builds)
|
|
@@ -2700,10 +2961,16 @@ class CapManifest {
|
|
|
2700
2961
|
capGroups
|
|
2701
2962
|
);
|
|
2702
2963
|
|
|
2703
|
-
if (
|
|
2964
|
+
if (Object.prototype.hasOwnProperty.call(json, 'author')) {
|
|
2965
|
+
if (typeof json.author !== 'string') {
|
|
2966
|
+
throw new Error('CapManifest author must be a string when present');
|
|
2967
|
+
}
|
|
2704
2968
|
manifest.author = json.author;
|
|
2705
2969
|
}
|
|
2706
|
-
if (
|
|
2970
|
+
if (Object.prototype.hasOwnProperty.call(json, 'page_url')) {
|
|
2971
|
+
if (typeof json.page_url !== 'string') {
|
|
2972
|
+
throw new Error('CapManifest page_url must be a string when present');
|
|
2973
|
+
}
|
|
2707
2974
|
manifest.page_url = json.page_url;
|
|
2708
2975
|
}
|
|
2709
2976
|
|
|
@@ -2723,8 +2990,8 @@ class CapManifest {
|
|
|
2723
2990
|
description: this.description,
|
|
2724
2991
|
cap_groups: this.cap_groups.map(g => g.toJSON())
|
|
2725
2992
|
};
|
|
2726
|
-
if (this.author) result.author = this.author;
|
|
2727
|
-
if (this.page_url) result.page_url = this.page_url;
|
|
2993
|
+
if (this.author !== null && this.author !== undefined) result.author = this.author;
|
|
2994
|
+
if (this.page_url !== null && this.page_url !== undefined) result.page_url = this.page_url;
|
|
2728
2995
|
return result;
|
|
2729
2996
|
}
|
|
2730
2997
|
}
|
|
@@ -6086,6 +6353,7 @@ class FabricRegistryClient {
|
|
|
6086
6353
|
module.exports = {
|
|
6087
6354
|
CapUrn,
|
|
6088
6355
|
CapKind,
|
|
6356
|
+
CapEffect,
|
|
6089
6357
|
CapUrnBuilder,
|
|
6090
6358
|
CapMatcher,
|
|
6091
6359
|
CapUrnError,
|
|
@@ -6220,6 +6488,7 @@ module.exports = {
|
|
|
6220
6488
|
MEDIA_CAP_DEFINITION,
|
|
6221
6489
|
MEDIA_MEDIA_SPEC_DEFINITION,
|
|
6222
6490
|
// Standard cap URN constants
|
|
6491
|
+
CAP_IDENTITY,
|
|
6223
6492
|
CAP_ADAPTER_SELECTION,
|
|
6224
6493
|
CAP_LOOKUP_CAP_FABRIC,
|
|
6225
6494
|
CAP_LOOKUP_MEDIA_SPEC_FABRIC,
|