capdag 1.306.150 → 1.361.331

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/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright © MachineFabric and contributors.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md CHANGED
@@ -15,12 +15,17 @@ features.
15
15
  npm install capdag
16
16
  ```
17
17
 
18
- Node.js 14 or newer is required by the package manifest.
18
+ The package is an ES module and needs Node.js 20 or newer. Dispatch,
19
+ acceptance, equivalence and specificity are decided by code generated from the
20
+ proved model ([formal foundations](https://capdag.com/docs/02-formal-foundations/)),
21
+ which runs as WebAssembly: it is instantiated when the package is first
22
+ imported, so importing it waits for that (top-level `await`), and a CommonJS
23
+ `require` cannot load it.
19
24
 
20
25
  ## Parse and build Cap URNs
21
26
 
22
27
  ```javascript
23
- const { CapUrn, CapUrnBuilder } = require("capdag");
28
+ import { CapUrn, CapUrnBuilder } from "capdag";
24
29
 
25
30
  const parsed = CapUrn.fromString(
26
31
  'cap:disbind;in="media:ext=pdf";out="media:enc=utf-8;page"'
@@ -42,13 +47,24 @@ equivalence, conformance, dispatch, and ranking instead of string surgery.
42
47
  - `capdag.js` provides URNs, definitions, dispatch, and matching.
43
48
  - `machine-parser.js` is generated from `machine.pegjs`.
44
49
  - `planner.js` provides planning and Machine Notation structures.
45
- - `cap-fab-renderer.js` and the browser build support graph presentation.
50
+ - `cap-fab-renderer.js` (`capdag/cap-fab-renderer`) renders graphs; the page
51
+ provides cytoscape and cytoscape-elk.
52
+ - `formal/` is the generated model code, with its WebAssembly program.
46
53
  - [`RULES.md`](RULES.md) records package-specific construction rules.
47
54
 
48
55
  The normative semantics and terminology live in the
49
- [CapDAG specification](https://github.com/machinefabric/capdag/blob/main/docs/01-overview.md). Source comments and
56
+ [CapDAG specification](https://capdag.com/docs/01-overview/). Source comments and
50
57
  exports are the JavaScript API reference.
51
58
 
59
+ ## Use it in a browser
60
+
61
+ `node build-browser.js <dir>` lays out capdag, tagged-urn and lungo-ts as ES
62
+ modules a page loads without a bundler, each beside its WebAssembly program.
63
+ A page imports `<dir>/capdag/capdag.js`, or — for page scripts that are not
64
+ modules — imports `<dir>/capdag/browser.js` from a module script, which puts
65
+ every public name on the global object once the models are instantiated. A page
66
+ with a content security policy allows `script-src 'wasm-unsafe-eval'`.
67
+
52
68
  ## Build and verify changes
53
69
 
54
70
  ```bash
package/RULES.md CHANGED
@@ -106,6 +106,6 @@ const result = await validateNoMediaDefRedefinition(mediaDefs, {
106
106
  ## Cross-Language Compatibility
107
107
 
108
108
  This JavaScript implementation follows the same rules as:
109
- - [Rust reference implementation](https://github.com/machinefabric/capdag)
109
+ - [Rust reference implementation](https://github.com/machinefabric/capdag-rs)
110
110
  - [Go implementation](https://github.com/machinefabric/capdag-go)
111
111
  - [Objective-C implementation](https://github.com/machinefabric/capdag-objc)
package/build-browser.js CHANGED
@@ -1,205 +1,108 @@
1
1
  #!/usr/bin/env node
2
- // Build browser-compatible bundles of tagged-urn, capdag, and
3
- // cap-fab-renderer from the local sources + resolved tagged-urn
4
- // dependency. Outputs three self-contained IIFE-wrapped JS files to
5
- // `dist/` that each expose their exported classes as window globals.
2
+ // Lay out capdag, tagged-urn and lungo-ts for a browser: the ES modules as
3
+ // they are, each beside the WebAssembly program it instantiates, with the
4
+ // package names they import by rewritten to the paths they are laid out at —
5
+ // so a page loads them without a bundler or an import map.
6
6
  //
7
- // The browser build exists because capdag-js source files are CJS:
8
- // they use `require()` and `module.exports`, which a plain <script tag>
9
- // cannot load. For browser consumers (capdag-dot-com, macfloom
10
- // WKWebViews) we strip those CJS hooks and wrap the result in an IIFE
11
- // that assigns to window.*.
7
+ // <outDir>/lungo-ts/ the WebAssembly host every generated program runs on
8
+ // <outDir>/tagged-urn/ tagged-urn.js and its model (formal/)
9
+ // <outDir>/capdag/ capdag.js, cap-fab-renderer.js and their model (formal/)
10
+ // <outDir>/capdag/browser.js
12
11
  //
13
- // Load order at the consumer:
14
- // 1. tagged-urn.js — defines window.TaggedUrn, etc.
15
- // 2. capdag.js — reads window.TaggedUrn, defines CapUrn,
16
- // MediaUrn, Cap, CapFab, createCap, …
17
- // 3. cap-fab-renderer.js — reads window.cytoscape + capdag globals
18
- // at call time, defines CapFabRenderer.
12
+ // browser.js puts the public names of tagged-urn, capdag and the renderer on
13
+ // the page's global object, for page scripts that are not modules
14
+ // (capdag-dot-com, macfloom's web views). The programs are instantiated when
15
+ // the modules are first imported, so a page imports browser.js from a module
16
+ // script of its own and uses the globals after that import.
19
17
  //
20
18
  // Running: `node build-browser.js [outDir]`. Default outDir is ./dist.
21
19
 
22
- 'use strict';
20
+ import fs from 'node:fs';
21
+ import path from 'node:path';
22
+ import { fileURLToPath } from 'node:url';
23
23
 
24
- const fs = require('fs');
25
- const path = require('path');
24
+ const here = path.dirname(fileURLToPath(import.meta.url));
25
+ const outDir = process.argv[2] ? path.resolve(process.argv[2]) : path.join(here, 'dist');
26
26
 
27
- const here = __dirname;
28
- const outDir = process.argv[2]
29
- ? path.resolve(process.argv[2])
30
- : path.join(here, 'dist');
31
- fs.mkdirSync(outDir, { recursive: true });
32
-
33
- function stripCJS(src) {
34
- // Strip the CJS `Import TaggedUrn` comment and the trailing
35
- // `module.exports = {...}` block, then rewrite any single-line
36
- // `const { ... } = require('tagged-urn')` destructure into a
37
- // destructure from `window`. The destructure may include any subset
38
- // of names (TaggedUrn, valuesMatch, scoreTagValue, …) so long as it
39
- // is one line; renames like `valuesMatch: taggedUrnValuesMatch` are
40
- // preserved verbatim.
41
- return src
42
- .replace(/^\/\/.*Import TaggedUrn.*\n/m, '')
43
- .replace(
44
- /^const\s*(\{[^}]*\})\s*=\s*require\s*\(\s*['"]tagged-urn['"]\s*\)\s*;?\s*$/gm,
45
- 'const $1 = window;'
46
- )
47
- .replace(/^module\.exports\s*=\s*\{[\s\S]*?\};?\s*$/m, '');
48
- }
49
-
50
- function buildTaggedUrn() {
51
- // tagged-urn is a sibling npm dependency. Resolve its main file.
52
- const srcPath = require.resolve('tagged-urn');
53
- const src = fs.readFileSync(srcPath, 'utf8');
54
- const processed = src.replace(/^module\.exports\s*=\s*\{[\s\S]*?\};?\s*$/m, '');
55
- const wrapped = `// tagged-urn — browser build
56
- // Generated from the tagged-urn npm package by capdag-js/build-browser.js.
57
- // Do not edit directly.
58
-
59
- (function() {
60
- 'use strict';
61
-
62
- ${processed}
63
-
64
- window.TaggedUrn = TaggedUrn;
65
- window.TaggedUrnBuilder = TaggedUrnBuilder;
66
- window.UrnMatcher = UrnMatcher;
67
- window.TaggedUrnError = TaggedUrnError;
68
- window.TaggedUrnErrorCodes = ErrorCodes;
69
- window.valuesMatch = valuesMatch;
70
- window.scoreTagValue = scoreTagValue;
71
-
72
- })();
73
- `;
74
- fs.writeFileSync(path.join(outDir, 'tagged-urn.js'), wrapped);
75
- console.log(` wrote ${path.join(outDir, 'tagged-urn.js')}`);
27
+ /** The directory of a package this one imports, as Node resolves it from here. */
28
+ function packageDir(name, entry) {
29
+ const dir = path.dirname(fileURLToPath(import.meta.resolve(name)));
30
+ if (!fs.existsSync(path.join(dir, entry))) {
31
+ throw new Error(`${name} resolved to ${dir}, which has no ${entry}`);
32
+ }
33
+ return dir;
76
34
  }
77
35
 
78
- function buildCapdag() {
79
- const srcPath = path.join(here, 'capdag.js');
80
- const src = fs.readFileSync(srcPath, 'utf8');
81
-
82
- const parserPath = path.join(here, 'machine-parser.js');
83
- if (!fs.existsSync(parserPath)) {
84
- throw new Error(`machine-parser.js not found at ${parserPath} — run 'npm run build:parser' first`);
36
+ /**
37
+ * Copy `files` from `from` to `to`, replacing in each the import specifiers
38
+ * `rewrites` names for it. Every rewrite must apply: a source that no longer
39
+ * imports what this expects would otherwise ship still naming a package the
40
+ * browser cannot resolve.
41
+ */
42
+ function lay(from, to, files, rewrites = {}) {
43
+ for (const file of files) {
44
+ const source = path.join(from, file);
45
+ const target = path.join(to, file);
46
+ fs.mkdirSync(path.dirname(target), { recursive: true });
47
+ const replacing = rewrites[file];
48
+ if (!replacing) {
49
+ fs.copyFileSync(source, target);
50
+ continue;
51
+ }
52
+ let text = fs.readFileSync(source, 'utf8');
53
+ for (const [specifier, replacement] of Object.entries(replacing)) {
54
+ const forms = [`from '${specifier}'`, `from "${specifier}"`];
55
+ const found = forms.filter((form) => text.includes(form));
56
+ if (found.length === 0) {
57
+ throw new Error(`${source} does not import '${specifier}', which the browser layout rewrites`);
58
+ }
59
+ for (const form of found) {
60
+ text = text.split(form).join(`from '${replacement}'`);
61
+ }
62
+ }
63
+ fs.writeFileSync(target, text);
85
64
  }
86
- const parserSrc = fs.readFileSync(parserPath, 'utf8');
87
-
88
- let processed = stripCJS(src);
89
- // Replace the `const machineParser = require('./machine-parser.js')`
90
- // line with a local variable the inlined parser assigns below.
91
- processed = processed.replace(
92
- /^const\s+machineParser\s*=\s*require\s*\(\s*['"]\.\/machine-parser\.js['"]\s*\)\s*;?\s*$/m,
93
- '// machineParser is inlined above'
94
- );
95
-
96
- const inlinedParser = `
97
- // Inlined Peggy-generated machine parser.
98
- var machineParser = (function() {
99
- var module = { exports: {} };
100
- var exports = module.exports;
101
- ${parserSrc}
102
- return module.exports;
103
- })();
104
- `;
105
-
106
- const wrapped = `// capdag — browser build
107
- // Generated from capdag-js/capdag.js by capdag-js/build-browser.js.
108
- // Do not edit directly. Requires tagged-urn.js loaded first.
109
-
110
- (function() {
111
- 'use strict';
112
-
113
- if (!window.TaggedUrn) {
114
- throw new Error('TaggedUrn global is not defined. Load tagged-urn.js before capdag.js.');
65
+ console.log(` laid out ${to}`);
115
66
  }
116
67
 
117
- ${inlinedParser}
118
-
119
- ${processed}
120
-
121
- // Expose every public class and function as a window global.
122
- window.CapUrn = CapUrn;
123
- window.CapUrnBuilder = CapUrnBuilder;
124
- window.CapMatcher = CapMatcher;
125
- window.CapUrnError = CapUrnError;
126
- window.CapUrnErrorCodes = ErrorCodes;
127
- window.MediaUrn = MediaUrn;
128
- window.MediaUrnError = MediaUrnError;
129
- window.MediaUrnErrorCodes = MediaUrnErrorCodes;
130
- window.Cap = Cap;
131
- window.CapArg = CapArg;
132
- window.ArgSource = ArgSource;
133
- window.RegisteredBy = RegisteredBy;
134
- window.createCap = createCap;
135
- window.createCapWithDescription = createCapWithDescription;
136
- window.createCapWithMetadata = createCapWithMetadata;
137
- window.createCapWithDescriptionAndMetadata = createCapWithDescriptionAndMetadata;
138
- window.ValidationError = ValidationError;
139
- window.InputValidator = InputValidator;
140
- window.OutputValidator = OutputValidator;
141
- window.CapValidator = CapValidator;
142
- window.validateCapArgs = validateCapArgs;
143
- window.RESERVED_CLI_FLAGS = RESERVED_CLI_FLAGS;
144
- window.MediaDef = MediaDef;
145
- window.MediaDefError = MediaDefError;
146
- window.MediaDefErrorCodes = MediaDefErrorCodes;
147
- window.isBinaryCapUrn = isBinaryCapUrn;
148
- window.isJSONCapUrn = isJSONCapUrn;
149
- window.isStructuredCapUrn = isStructuredCapUrn;
150
- window.resolveMediaUrn = resolveMediaUrn;
151
- window.buildExtensionIndex = buildExtensionIndex;
152
- window.mediaUrnsForExtension = mediaUrnsForExtension;
153
- window.getExtensionMappings = getExtensionMappings;
154
- window.CapFabEdge = CapFabEdge;
155
- window.CapFabStats = CapFabStats;
156
- window.CapFab = CapFab;
157
- window.StdinSource = StdinSource;
158
- window.StdinSourceKind = StdinSourceKind;
159
- window.CapArgumentValue = CapArgumentValue;
160
- window.MachineSyntaxError = MachineSyntaxError;
161
- window.MachineSyntaxErrorCodes = MachineSyntaxErrorCodes;
162
- window.MachineEdge = MachineEdge;
163
- window.Machine = Machine;
164
- window.MachineBuilder = MachineBuilder;
165
- window.parseMachine = parseMachine;
166
-
167
- })();
168
- `;
169
-
170
- fs.writeFileSync(path.join(outDir, 'capdag.js'), wrapped);
171
- console.log(` wrote ${path.join(outDir, 'capdag.js')}`);
68
+ const taggedUrnDir = packageDir('tagged-urn', 'tagged-urn.js');
69
+ const lungoTsDir = packageDir('lungo-ts', 'index.js');
70
+ const parser = path.join(here, 'machine-parser.js');
71
+ if (!fs.existsSync(parser)) {
72
+ throw new Error(`machine-parser.js not found at ${parser} — run 'npm run build:parser' first`);
172
73
  }
173
74
 
174
- function buildCapFabRenderer() {
175
- const srcPath = path.join(here, 'cap-fab-renderer.js');
176
- const src = fs.readFileSync(srcPath, 'utf8');
177
- // The file's CJS exports block is at the bottom, guarded by
178
- // `typeof module !== 'undefined'`. Strip everything from that guard
179
- // to the end of the file.
180
- const stripped = src.replace(
181
- /if\s*\(\s*typeof\s+module\s*!==\s*'undefined'[\s\S]*$/,
182
- ''
183
- );
184
- const wrapped = `// cap-fab-renderer — browser build
185
- // Generated from capdag-js/cap-fab-renderer.js by capdag-js/build-browser.js.
186
- // Do not edit directly. Requires cytoscape, cytoscape-elk, tagged-urn.js,
187
- // and capdag.js to be loaded first.
188
-
189
- (function() {
190
- 'use strict';
75
+ for (const dir of ['lungo-ts', 'tagged-urn', 'capdag']) {
76
+ fs.rmSync(path.join(outDir, dir), { recursive: true, force: true });
77
+ }
191
78
 
192
- ${stripped}
79
+ const model = { 'formal/index.js': { 'lungo-ts': '../../lungo-ts/index.js' } };
193
80
 
194
- window.CapFabRenderer = CapFabRenderer;
81
+ lay(lungoTsDir, path.join(outDir, 'lungo-ts'), ['index.js', 'wasi.js']);
82
+ lay(taggedUrnDir, path.join(outDir, 'tagged-urn'),
83
+ ['tagged-urn.js', 'formal/index.js', 'formal/program.wasm'], model);
84
+ lay(here, path.join(outDir, 'capdag'),
85
+ ['capdag.js', 'planner.js', 'machine-parser.js', 'cap-fab-renderer.js', 'formal/index.js', 'formal/program.wasm'],
86
+ { ...model, 'capdag.js': { 'tagged-urn': '../tagged-urn/tagged-urn.js' } });
195
87
 
196
- })();
197
- `;
198
- fs.writeFileSync(path.join(outDir, 'cap-fab-renderer.js'), wrapped);
199
- console.log(` wrote ${path.join(outDir, 'cap-fab-renderer.js')}`);
200
- }
201
-
202
- buildTaggedUrn();
203
- buildCapdag();
204
- buildCapFabRenderer();
205
- console.log(`browser bundles written to ${outDir}`);
88
+ fs.writeFileSync(path.join(outDir, 'capdag', 'browser.js'), `// Generated by capdag-js/build-browser.js. Do not edit.
89
+ //
90
+ // The public names of tagged-urn, capdag and the renderer, on the page's
91
+ // global object. Import this from a module script; the names are there once
92
+ // the import has completed.
93
+
94
+ import * as taggedUrn from '../tagged-urn/tagged-urn.js';
95
+ import * as capdag from './capdag.js';
96
+ import { CapFabRenderer } from './cap-fab-renderer.js';
97
+
98
+ // Both packages export an ErrorCodes; each is published under its own name.
99
+ const { ErrorCodes: TaggedUrnErrorCodes, ...taggedUrnNames } = taggedUrn;
100
+ const { ErrorCodes: CapUrnErrorCodes, ...capdagNames } = capdag;
101
+
102
+ Object.assign(globalThis, taggedUrnNames, capdagNames, {
103
+ TaggedUrnErrorCodes,
104
+ CapUrnErrorCodes,
105
+ CapFabRenderer,
106
+ });
107
+ `);
108
+ console.log(`browser modules written to ${outDir}`);
@@ -41,27 +41,19 @@
41
41
  // uses a different name for the same concept, the fix is at the producer,
42
42
  // not here.
43
43
 
44
- 'use strict';
44
+ import { CapUrn, CapFab, MediaUrn, createCap } from './capdag.js';
45
45
 
46
46
  // =============================================================================
47
- // Host dependencies — resolved at call time. When this file runs inside
48
- // Node (for tests) the globals are on `global`.
47
+ // Host dependencies — the page's: cytoscape and cytoscape-elk, loaded as
48
+ // scripts, resolved from the global object when a graph is drawn.
49
49
  // =============================================================================
50
50
 
51
51
  function requireHostDependency(name) {
52
- const g = (typeof window !== 'undefined') ? window
53
- : (typeof global !== 'undefined') ? global
54
- : null;
55
- if (g === null) {
56
- throw new Error(
57
- `CapFabRenderer: no global object (window/global) — cannot resolve '${name}'`
58
- );
59
- }
60
- const value = g[name];
52
+ const value = globalThis[name];
61
53
  if (value === undefined) {
62
54
  throw new Error(
63
55
  `CapFabRenderer: required host dependency '${name}' is not loaded. ` +
64
- `Load cytoscape, cytoscape-elk, tagged-urn.js, and capdag.js before this script.`
56
+ `Load cytoscape and cytoscape-elk before drawing a graph.`
65
57
  );
66
58
  }
67
59
  return value;
@@ -104,7 +96,6 @@ function cardinalityFromCap(cap) {
104
96
  // =============================================================================
105
97
 
106
98
  function canonicalMediaUrn(mediaUrnString) {
107
- const MediaUrn = requireHostDependency('MediaUrn');
108
99
  return MediaUrn.fromString(mediaUrnString).toString();
109
100
  }
110
101
 
@@ -118,7 +109,6 @@ function mediaNodeLabel() {
118
109
  }
119
110
 
120
111
  function requireExplicitDisplayName(canonicalUrn, displayEntries, context) {
121
- const MediaUrn = requireHostDependency('MediaUrn');
122
112
  const candidate = MediaUrn.fromString(canonicalUrn);
123
113
  for (const entry of displayEntries) {
124
114
  if (candidate.isEquivalent(entry.media)) return entry.display;
@@ -1159,9 +1149,6 @@ function annotateCrowdedBrowseEdges(edges) {
1159
1149
  function buildBrowseGraphData(capabilities) {
1160
1150
  validateBrowseData(capabilities);
1161
1151
 
1162
- const CapUrn = requireHostDependency('CapUrn');
1163
- const createCap = requireHostDependency('createCap');
1164
- const CapFab = requireHostDependency('CapFab');
1165
1152
 
1166
1153
  const nodesMap = new Map();
1167
1154
  const edges = [];
@@ -1328,7 +1315,6 @@ function buildStrandGraphData(data) {
1328
1315
  // Look up a display name for a media URN via the host-supplied map.
1329
1316
  // Uses `MediaUrn.isEquivalent` so tag-order variation doesn't defeat
1330
1317
  // the lookup — URNs are compared semantically, never as raw strings.
1331
- const MediaUrn = requireHostDependency('MediaUrn');
1332
1318
  const displayEntries = [];
1333
1319
  for (const [urn, display] of Object.entries(mediaDisplayNames)) {
1334
1320
  if (typeof display !== 'string' || display.length === 0) continue;
@@ -1652,7 +1638,6 @@ function buildStrandGraphData(data) {
1652
1638
  // cap edge lands on that merged endpoint. Removes the visible
1653
1639
  // duplicate node.
1654
1640
  function collapseStrandShapeTransitions(built) {
1655
- const MediaUrn = requireHostDependency('MediaUrn');
1656
1641
 
1657
1642
  // Index for lookups.
1658
1643
  const nodeById = new Map();
@@ -1817,7 +1802,6 @@ function strandCytoscapeElements(built, options) {
1817
1802
  // matches the supplied URN string. Uses CapUrn.isEquivalent — never
1818
1803
  // string equality.
1819
1804
  function findCapStepIndexByUrn(steps, targetUrnString) {
1820
- const CapUrn = requireHostDependency('CapUrn');
1821
1805
  const target = CapUrn.fromString(targetUrnString);
1822
1806
  for (let i = 0; i < steps.length; i++) {
1823
1807
  const variant = Object.keys(steps[i].step_type)[0];
@@ -2171,7 +2155,6 @@ function buildRunGraphData(data) {
2171
2155
  // Look up a display name for a media URN via the host-supplied
2172
2156
  // `media_display_names` map. Uses `MediaUrn.isEquivalent` for
2173
2157
  // semantic URN equality.
2174
- const MediaUrn = requireHostDependency('MediaUrn');
2175
2158
  const mediaDisplayNames = data.media_display_names || {};
2176
2159
  const displayEntries = [];
2177
2160
  for (const [urn, display] of Object.entries(mediaDisplayNames)) {
@@ -3649,7 +3632,6 @@ class CapFabRenderer {
3649
3632
  return;
3650
3633
  }
3651
3634
 
3652
- const CapUrn = requireHostDependency('CapUrn');
3653
3635
  const target = CapUrn.fromString(this._capUrnString(cap));
3654
3636
 
3655
3637
  for (const [edgeId, edgeCap] of this.capabilitiesByEdgeId) {
@@ -3691,7 +3673,6 @@ class CapFabRenderer {
3691
3673
  getEdgeDataByCapUrn(capUrnString) {
3692
3674
  if (this.mode !== 'browse') return null;
3693
3675
  if (!this.cy || typeof capUrnString !== 'string' || capUrnString.length === 0) return null;
3694
- const CapUrn = requireHostDependency('CapUrn');
3695
3676
  const target = CapUrn.fromString(capUrnString);
3696
3677
  for (const [edgeId, edgeCap] of this.capabilitiesByEdgeId) {
3697
3678
  const candidate = CapUrn.fromString(edgeCap.urn);
@@ -3708,7 +3689,6 @@ class CapFabRenderer {
3708
3689
  throw new Error(`CapFabRenderer: selectEdgeByCapUrn is only valid in browse mode (current: ${this.mode})`);
3709
3690
  }
3710
3691
  if (!this.cy || typeof capUrnString !== 'string' || capUrnString.length === 0) return;
3711
- const CapUrn = requireHostDependency('CapUrn');
3712
3692
  const target = CapUrn.fromString(capUrnString);
3713
3693
  for (const [edgeId, edgeCap] of this.capabilitiesByEdgeId) {
3714
3694
  const candidate = CapUrn.fromString(edgeCap.urn);
@@ -4067,30 +4047,26 @@ class CapFabRenderer {
4067
4047
  }
4068
4048
 
4069
4049
  // =============================================================================
4070
- // Module exports — CJS for Node tests. Browser-side the build-browser.js
4071
- // concatenation wraps these declarations in an IIFE and assigns
4072
- // `window.CapFabRenderer`.
4050
+ // Module exports
4073
4051
  // =============================================================================
4074
4052
 
4075
- if (typeof module !== 'undefined' && module.exports) {
4076
- module.exports = {
4077
- CapFabRenderer,
4078
- cardinalityLabel,
4079
- cardinalityFromCap,
4080
- canonicalMediaUrn,
4081
- mediaNodeLabel,
4082
- buildBrowseGraphData,
4083
- buildStrandGraphData,
4084
- collapseStrandShapeTransitions,
4085
- buildRunGraphData,
4086
- buildEditorGraphData,
4087
- buildResolvedMachineGraphData,
4088
- classifyStrandCapSteps,
4089
- validateStrandPayload,
4090
- validateRunPayload,
4091
- validateEditorGraphPayload,
4092
- validateResolvedMachinePayload,
4093
- validateStrandStep,
4094
- validateBodyOutcome,
4095
- };
4096
- }
4053
+ export {
4054
+ CapFabRenderer,
4055
+ cardinalityLabel,
4056
+ cardinalityFromCap,
4057
+ canonicalMediaUrn,
4058
+ mediaNodeLabel,
4059
+ buildBrowseGraphData,
4060
+ buildStrandGraphData,
4061
+ collapseStrandShapeTransitions,
4062
+ buildRunGraphData,
4063
+ buildEditorGraphData,
4064
+ buildResolvedMachineGraphData,
4065
+ classifyStrandCapSteps,
4066
+ validateStrandPayload,
4067
+ validateRunPayload,
4068
+ validateEditorGraphPayload,
4069
+ validateResolvedMachinePayload,
4070
+ validateStrandStep,
4071
+ validateBodyOutcome,
4072
+ };