capdag 0.88.20458

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.
Files changed (5) hide show
  1. package/README.md +131 -0
  2. package/RULES.md +111 -0
  3. package/capdag.js +4322 -0
  4. package/capdag.test.js +2874 -0
  5. package/package.json +36 -0
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # Cap URN - JavaScript Implementation
2
+
3
+ JavaScript implementation of Cap URN (Capability Uniform Resource Names), built on [Tagged URN](https://github.com/machinefabric/tagged-urn-js).
4
+
5
+ ## Features
6
+
7
+ - **Required Direction Specifiers** - `in`/`out` tags for input/output media types
8
+ - **Media URN Validation** - Validates direction spec values are valid Media URNs
9
+ - **Special Pattern Values** - `*` (must-have-any), `?` (unspecified), `!` (must-not-have)
10
+ - **Graded Specificity** - Exact values score higher than wildcards
11
+ - **Cross-Language Compatible** - Identical behavior to Rust, Go, and Objective-C implementations
12
+ - **Production Ready** - No fallbacks, fails hard on invalid input
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install capdag
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ```javascript
23
+ const { CapUrn, CapUrnBuilder, CapMatcher } = require('capdag');
24
+
25
+ // Create from string (with required direction specifiers)
26
+ const cap = CapUrn.fromString('cap:in="media:binary";op=extract;out="media:object"');
27
+ console.log(cap.toString());
28
+
29
+ // Use builder pattern
30
+ const built = new CapUrnBuilder()
31
+ .inSpec('media:void')
32
+ .outSpec('media:object')
33
+ .tag('op', 'generate')
34
+ .tag('target', 'thumbnail')
35
+ .build();
36
+
37
+ // Matching
38
+ const request = CapUrn.fromString('cap:in="media:binary";op=extract;out="media:object"');
39
+ console.log(cap.accepts(request)); // true
40
+
41
+ // Find best match by specificity
42
+ const caps = [
43
+ CapUrn.fromString('cap:in=*;op=extract;out=*'),
44
+ CapUrn.fromString('cap:in="media:binary";op=extract;out="media:object"'),
45
+ CapUrn.fromString('cap:ext=pdf;in="media:binary";op=extract;out="media:object"')
46
+ ];
47
+ const best = CapMatcher.findBestMatch(caps, request);
48
+ console.log(best.toString()); // Most specific match
49
+ ```
50
+
51
+ ## API Reference
52
+
53
+ ### CapUrn Class
54
+
55
+ #### Static Methods
56
+ - `CapUrn.fromString(s)` - Parse Cap URN from string
57
+ - Throws `CapUrnError` on invalid format or missing direction specifiers
58
+
59
+ #### Instance Methods
60
+ - `toString()` - Get canonical string representation
61
+ - `getTag(key)` - Get tag value (case-insensitive)
62
+ - `getInSpec()` - Get input media type
63
+ - `getOutSpec()` - Get output media type
64
+ - `hasTag(key, value)` - Check if tag exists with value
65
+ - `withTag(key, value)` - Add/update tag (returns new instance)
66
+ - `withoutTag(key)` - Remove tag (returns new instance)
67
+ - `accepts(request)` - Check if this cap (as pattern) accepts a request
68
+ - `specificity()` - Get specificity score for matching
69
+ - `isMoreSpecificThan(other)` - Compare specificity
70
+ - `equals(other)` - Check equality
71
+
72
+ ### CapUrnBuilder Class
73
+
74
+ Fluent builder for constructing Cap URNs:
75
+
76
+ ```javascript
77
+ const cap = new CapUrnBuilder()
78
+ .inSpec('media:binary')
79
+ .outSpec('media:object')
80
+ .tag('op', 'extract')
81
+ .tag('target', 'metadata')
82
+ .build();
83
+ ```
84
+
85
+ ### CapMatcher Class
86
+
87
+ Utility for matching sets of caps:
88
+
89
+ - `CapMatcher.findBestMatch(caps, request)` - Find most specific match
90
+ - `CapMatcher.findAllMatches(caps, request)` - Find all matches (sorted by specificity)
91
+
92
+ ### Error Handling
93
+
94
+ ```javascript
95
+ const { CapUrnError, ErrorCodes } = require('capdag');
96
+
97
+ try {
98
+ const cap = CapUrn.fromString('cap:op=extract'); // Missing in/out
99
+ } catch (error) {
100
+ if (error instanceof CapUrnError) {
101
+ console.log(`Error code: ${error.code}`); // MISSING_IN_SPEC
102
+ }
103
+ }
104
+ ```
105
+
106
+ Cap-specific error codes:
107
+ - `ErrorCodes.MISSING_IN_SPEC` - Missing required `in` tag
108
+ - `ErrorCodes.MISSING_OUT_SPEC` - Missing required `out` tag
109
+ - `ErrorCodes.INVALID_MEDIA_URN` - Invalid Media URN in direction spec
110
+
111
+ For base Tagged URN error codes, see [Tagged URN documentation](https://github.com/machinefabric/tagged-urn-js).
112
+
113
+ ## Documentation
114
+
115
+ - [RULES.md](./RULES.md) - Cap-specific rules
116
+ - [Tagged URN RULES.md](https://github.com/machinefabric/tagged-urn-js/blob/main/RULES.md) - Base format rules (case, quoting, wildcards, etc.)
117
+
118
+ ## Testing
119
+
120
+ ```bash
121
+ npm test
122
+ ```
123
+
124
+ ## Cross-Language Compatibility
125
+
126
+ This JavaScript implementation produces identical results to:
127
+ - [Rust reference implementation](https://github.com/machinefabric/capdag)
128
+ - [Go implementation](https://github.com/machinefabric/capdag-go)
129
+ - [Objective-C implementation](https://github.com/machinefabric/capdag-objc)
130
+
131
+ All implementations pass the same test cases and follow identical rules.
package/RULES.md ADDED
@@ -0,0 +1,111 @@
1
+ # Cap URN Rules (JavaScript)
2
+
3
+ ## Overview
4
+
5
+ Cap URNs extend Tagged URNs with capability-specific requirements. For base Tagged URN format rules (case handling, tag ordering, special values, quoting, value-less tags, etc.), see [Tagged URN RULES.md](https://github.com/machinefabric/tagged-urn-js/blob/main/RULES.md).
6
+
7
+ This document covers only cap-specific rules.
8
+
9
+ ## Cap-Specific Rules
10
+
11
+ ### 1. Required Direction Specifiers
12
+
13
+ Cap URNs **must** include `in` and `out` tags that specify input/output media types:
14
+
15
+ ```javascript
16
+ // Valid cap URN with direction specifiers
17
+ const cap = CapUrn.fromString('cap:in="media:binary";op=extract;out="media:object"');
18
+
19
+ // Invalid - missing direction specifiers
20
+ CapUrn.fromString('cap:op=extract'); // throws ErrorCodes.MISSING_IN_SPEC
21
+ ```
22
+
23
+ ### 2. Media URN Validation
24
+
25
+ Direction specifier values must be valid Media URNs or special pattern values:
26
+
27
+ ```javascript
28
+ // Valid: Media URN value
29
+ 'cap:in="media:binary";op=extract;out="media:object"'
30
+
31
+ // Valid: Must-have-any (any media type)
32
+ 'cap:in=*;op=extract;out=*'
33
+
34
+ // Invalid: Not a Media URN or special value
35
+ 'cap:in=binary;op=extract;out=object' // throws ErrorCodes.INVALID_MEDIA_URN
36
+ ```
37
+
38
+ ### 3. Matching Semantics
39
+
40
+ Cap matching uses Tagged URN matching semantics:
41
+
42
+ | Pattern Value | Meaning | Instance Missing | Instance=v | Instance=x≠v |
43
+ |---------------|---------|------------------|------------|--------------|
44
+ | (missing) | No constraint | OK | OK | OK |
45
+ | `K=?` | No constraint (explicit) | OK | OK | OK |
46
+ | `K=!` | Must-not-have | OK | NO | NO |
47
+ | `K=*` | Must-have, any value | NO | OK | OK |
48
+ | `K=v` | Must-have, exact value | NO | OK | NO |
49
+
50
+ ### 4. Graded Specificity
51
+
52
+ Specificity uses graded scoring:
53
+
54
+ | Value Type | Score |
55
+ |------------|-------|
56
+ | Exact value (K=v) | 3 |
57
+ | Must-have-any (K=*) | 2 |
58
+ | Must-not-have (K=!) | 1 |
59
+ | Unspecified (K=?) or missing | 0 |
60
+
61
+ Examples:
62
+ - `cap:in="media:binary";op=extract;out="media:object"` → 3+3+3 = 9
63
+ - `cap:in=*;op=extract;out=*` → 2+3+2 = 7
64
+
65
+ ## Cap-Specific Error Codes
66
+
67
+ | Code | Name | Description |
68
+ |------|------|-------------|
69
+ | 10 | MISSING_IN_SPEC | Cap URN missing required `in` tag |
70
+ | 11 | MISSING_OUT_SPEC | Cap URN missing required `out` tag |
71
+ | 12 | INVALID_MEDIA_URN | Direction spec value is not a valid Media URN |
72
+
73
+ ## Validation Rules
74
+
75
+ ### XV5: No Redefinition of Registry Media Specs
76
+
77
+ Inline media specs in a capability's `media_specs` table must not redefine media specs that already exist in the global registry or built-in specs.
78
+
79
+ ```javascript
80
+ const { validateNoMediaSpecRedefinitionSync, MEDIA_STRING } = require('capdag');
81
+
82
+ // This will fail - MEDIA_STRING is a built-in spec
83
+ const mediaSpecs = {
84
+ [MEDIA_STRING]: { media_type: 'text/plain', title: 'My String' }
85
+ };
86
+ const result = validateNoMediaSpecRedefinitionSync(mediaSpecs);
87
+ // result: { valid: false, error: 'XV5: ...', redefines: ['media:textable'] }
88
+
89
+ // This is allowed - custom spec that doesn't exist
90
+ const customSpecs = {
91
+ 'media:my-custom-type': { media_type: 'application/json', title: 'My Type' }
92
+ };
93
+ const customResult = validateNoMediaSpecRedefinitionSync(customSpecs);
94
+ // result: { valid: true }
95
+ ```
96
+
97
+ For server-side validation with registry access, use the async version:
98
+ ```javascript
99
+ const { validateNoMediaSpecRedefinition } = require('capdag');
100
+
101
+ const result = await validateNoMediaSpecRedefinition(mediaSpecs, {
102
+ registryLookup: async (urn) => await mediaStore.get(urn) !== null
103
+ });
104
+ ```
105
+
106
+ ## Cross-Language Compatibility
107
+
108
+ This JavaScript implementation follows the same rules as:
109
+ - [Rust reference implementation](https://github.com/machinefabric/capdag)
110
+ - [Go implementation](https://github.com/machinefabric/capdag-go)
111
+ - [Objective-C implementation](https://github.com/machinefabric/capdag-objc)