libpetri 1.8.1 → 1.8.3

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.
@@ -20,7 +20,7 @@ var EDGE_STYLES = {
20
20
  reset: { color: "#fd7e14", style: "bold", arrowhead: "normal", penwidth: 2 }
21
21
  };
22
22
  var FONT = { family: "Helvetica,Arial,sans-serif", nodeSize: 12, edgeSize: 10 };
23
- var GRAPH = { nodesep: 0.5, ranksep: 0.75, forcelabels: true, overlap: false, outputorder: "edgesfirst", splines: "curved" };
23
+ var GRAPH = { nodesep: 0.5, ranksep: 0.75, forcelabels: true, overlap: false, outputorder: "edgesfirst" };
24
24
  function nodeStyle(category) {
25
25
  return NODE_STYLES[category];
26
26
  }
@@ -158,8 +158,7 @@ function mapToGraph(net, config = DEFAULT_DOT_CONFIG) {
158
158
  forcelabels: String(GRAPH.forcelabels),
159
159
  overlap: String(GRAPH.overlap),
160
160
  fontname: FONT.family,
161
- outputorder: GRAPH.outputorder,
162
- splines: GRAPH.splines
161
+ outputorder: GRAPH.outputorder
163
162
  },
164
163
  nodeDefaults: {
165
164
  fontname: FONT.family,
@@ -413,4 +412,4 @@ export {
413
412
  renderDot,
414
413
  dotExport
415
414
  };
416
- //# sourceMappingURL=chunk-JNHADILD.js.map
415
+ //# sourceMappingURL=chunk-2HWR2675.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/export/styles.ts","../src/export/petri-net-mapper.ts","../src/export/dot-renderer.ts","../src/export/dot-exporter.ts"],"sourcesContent":["// GENERATED from spec/petri-net-styles.json — do not edit manually.\n// Regenerate with: scripts/generate-styles.sh\n\n/**\n * Style loader for Petri net visualization.\n *\n * Reads the shared style definition from `spec/petri-net-styles.json` and\n * exposes typed accessors for node and edge visual properties.\n *\n * @module export/styles\n */\n\nimport type { NodeShape, EdgeLineStyle, ArrowHead } from './graph.js';\n\n// ======================== Style Types ========================\n\nexport interface NodeVisual {\n readonly shape: NodeShape;\n readonly fill: string;\n readonly stroke: string;\n readonly penwidth: number;\n readonly style?: string;\n readonly height?: number;\n readonly width?: number;\n}\n\nexport interface EdgeVisual {\n readonly color: string;\n readonly style: EdgeLineStyle;\n readonly arrowhead: ArrowHead;\n readonly penwidth?: number;\n}\n\nexport interface FontStyle {\n readonly family: string;\n readonly nodeSize: number;\n readonly edgeSize: number;\n}\n\nexport interface GraphStyle {\n readonly nodesep: number;\n readonly ranksep: number;\n readonly forcelabels: boolean;\n readonly overlap: boolean;\n readonly outputorder: string;\n}\n\n// ======================== Inline Style Data ========================\n\n// Inlined from spec/petri-net-styles.json to avoid runtime JSON import issues.\n// Keep in sync with the spec file.\n\nconst NODE_STYLES: Record<NodeCategory, NodeVisual> = {\n place: { shape: 'circle', fill: '#FFFFFF', stroke: '#333333', penwidth: 1.5, width: 0.35 },\n start: { shape: 'circle', fill: '#d4edda', stroke: '#28a745', penwidth: 2.0, width: 0.35 },\n end: { shape: 'doublecircle', fill: '#cce5ff', stroke: '#004085', penwidth: 2.0, width: 0.35 },\n environment: { shape: 'circle', fill: '#f8d7da', stroke: '#721c24', penwidth: 2.0, style: 'dashed', width: 0.35 },\n transition: { shape: 'box', fill: '#fff3cd', stroke: '#856404', penwidth: 1.0, height: 0.4, width: 0.8 },\n};\n\nconst EDGE_STYLES: Record<EdgeCategory, EdgeVisual> = {\n input: { color: '#333333', style: 'solid', arrowhead: 'normal' },\n output: { color: '#333333', style: 'solid', arrowhead: 'normal' },\n inhibitor: { color: '#dc3545', style: 'solid', arrowhead: 'odot' },\n read: { color: '#6c757d', style: 'dashed', arrowhead: 'normal' },\n reset: { color: '#fd7e14', style: 'bold', arrowhead: 'normal', penwidth: 2.0 },\n};\n\nexport const FONT: FontStyle = { family: 'Helvetica,Arial,sans-serif', nodeSize: 12, edgeSize: 10 };\n\nexport const GRAPH: GraphStyle = { nodesep: 0.5, ranksep: 0.75, forcelabels: true, overlap: false, outputorder: 'edgesfirst' };\n\n// ======================== Public API ========================\n\nexport type NodeCategory = 'place' | 'start' | 'end' | 'environment' | 'transition';\nexport type EdgeCategory = 'input' | 'output' | 'inhibitor' | 'read' | 'reset';\n\n/** Returns the visual style for the given node category. */\nexport function nodeStyle(category: NodeCategory): NodeVisual {\n return NODE_STYLES[category];\n}\n\n/** Returns the visual style for the given edge/arc type. */\nexport function edgeStyle(arcType: EdgeCategory): EdgeVisual {\n return EDGE_STYLES[arcType];\n}\n","/**\n * Maps a PetriNet definition to a format-agnostic Graph.\n *\n * This is where all the Petri net semantics live. The mapper understands\n * places, transitions, arcs, timing, and priority. It produces a Graph\n * that can be rendered to DOT (or any other format) without Petri net knowledge.\n *\n * @module export/petri-net-mapper\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { Transition } from '../core/transition.js';\nimport type { Out } from '../core/out.js';\nimport { earliest, latest, hasDeadline } from '../core/timing.js';\nimport type { Graph, GraphNode, GraphEdge, RankDir } from './graph.js';\nimport { nodeStyle, edgeStyle, FONT, GRAPH } from './styles.js';\nimport type { NodeCategory } from './styles.js';\n\n// ======================== Configuration ========================\n\nexport interface DotConfig {\n readonly direction: RankDir;\n readonly showTypes: boolean;\n readonly showIntervals: boolean;\n readonly showPriority: boolean;\n readonly environmentPlaces?: ReadonlySet<string>;\n}\n\nexport const DEFAULT_DOT_CONFIG: DotConfig = {\n direction: 'TB',\n showTypes: true,\n showIntervals: true,\n showPriority: true,\n};\n\n// ======================== Public API ========================\n\n/** Sanitizes a name for use as a graph node ID. */\nexport function sanitize(name: string): string {\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\n}\n\n/** Maps a PetriNet to a format-agnostic Graph. */\nexport function mapToGraph(net: PetriNet, config: DotConfig = DEFAULT_DOT_CONFIG): Graph {\n const places = analyzePlaces(net);\n const envNames = config.environmentPlaces ?? new Set<string>();\n\n const nodes: GraphNode[] = [];\n const edges: GraphEdge[] = [];\n\n // Place nodes\n for (const [name, info] of places) {\n const category = placeCategory(info, envNames.has(name));\n const style = nodeStyle(category);\n nodes.push({\n id: 'p_' + sanitize(name),\n label: '',\n shape: style.shape,\n fill: style.fill,\n stroke: style.stroke,\n penwidth: style.penwidth,\n semanticId: name,\n style: style.style,\n width: style.width,\n attrs: { xlabel: name, fixedsize: 'true' },\n });\n }\n\n // Transition nodes\n for (const t of net.transitions) {\n const style = nodeStyle('transition');\n nodes.push({\n id: 't_' + sanitize(t.name),\n label: transitionLabel(t, config),\n shape: style.shape,\n fill: style.fill,\n stroke: style.stroke,\n penwidth: style.penwidth,\n semanticId: t.name,\n height: style.height,\n width: style.width,\n });\n }\n\n // Edges\n for (const t of net.transitions) {\n const tid = 't_' + sanitize(t.name);\n\n // Input arcs from inputSpecs\n for (const spec of t.inputSpecs) {\n const pid = 'p_' + sanitize(spec.place.name);\n const inputStyle = edgeStyle('input');\n let label: string | undefined;\n switch (spec.type) {\n case 'exactly':\n label = `\\u00d7${spec.count}`;\n break;\n case 'all':\n label = '*';\n break;\n case 'at-least':\n label = `\\u2265${spec.minimum}`;\n break;\n }\n edges.push({\n from: pid,\n to: tid,\n label,\n color: inputStyle.color,\n style: inputStyle.style,\n arrowhead: inputStyle.arrowhead,\n arcType: 'input',\n });\n }\n\n // Output arcs from outputSpec\n if (t.outputSpec !== null) {\n edges.push(...outputEdges(tid, t.outputSpec, null));\n }\n\n // Inhibitor arcs\n for (const inh of t.inhibitors) {\n const pid = 'p_' + sanitize(inh.place.name);\n const inhStyle = edgeStyle('inhibitor');\n edges.push({\n from: pid,\n to: tid,\n color: inhStyle.color,\n style: inhStyle.style,\n arrowhead: inhStyle.arrowhead,\n arcType: 'inhibitor',\n });\n }\n\n // Read arcs\n for (const r of t.reads) {\n const pid = 'p_' + sanitize(r.place.name);\n const readStyle = edgeStyle('read');\n edges.push({\n from: pid,\n to: tid,\n label: 'read',\n color: readStyle.color,\n style: readStyle.style,\n arrowhead: readStyle.arrowhead,\n arcType: 'read',\n });\n }\n\n // Reset arcs (only those without matching output)\n const outputPlaceNames = t.outputSpec !== null\n ? new Set([...t.outputPlaces()].map(p => p.name))\n : new Set<string>();\n for (const rst of t.resets) {\n if (!outputPlaceNames.has(rst.place.name)) {\n const pid = 'p_' + sanitize(rst.place.name);\n const resetStyle = edgeStyle('reset');\n edges.push({\n from: tid,\n to: pid,\n label: 'reset',\n color: resetStyle.color,\n style: resetStyle.style,\n arrowhead: resetStyle.arrowhead,\n penwidth: resetStyle.penwidth,\n arcType: 'reset',\n });\n }\n }\n }\n\n return {\n id: sanitize(net.name),\n rankdir: config.direction,\n nodes,\n edges,\n subgraphs: [],\n graphAttrs: {\n nodesep: String(GRAPH.nodesep),\n ranksep: String(GRAPH.ranksep),\n forcelabels: String(GRAPH.forcelabels),\n overlap: String(GRAPH.overlap),\n fontname: FONT.family,\n outputorder: GRAPH.outputorder,\n },\n nodeDefaults: {\n fontname: FONT.family,\n fontsize: String(FONT.nodeSize),\n },\n edgeDefaults: {\n fontname: FONT.family,\n fontsize: String(FONT.edgeSize),\n },\n };\n}\n\n// ======================== Place Analysis ========================\n\ninterface PlaceInfo {\n hasIncoming: boolean;\n hasOutgoing: boolean;\n}\n\nfunction analyzePlaces(net: PetriNet): Map<string, PlaceInfo> {\n const map = new Map<string, PlaceInfo>();\n\n function ensure(name: string): PlaceInfo {\n let info = map.get(name);\n if (!info) {\n info = { hasIncoming: false, hasOutgoing: false };\n map.set(name, info);\n }\n return info;\n }\n\n for (const t of net.transitions) {\n for (const spec of t.inputSpecs) {\n ensure(spec.place.name).hasOutgoing = true;\n }\n if (t.outputSpec !== null) {\n for (const p of t.outputPlaces()) {\n ensure(p.name).hasIncoming = true;\n }\n }\n for (const inh of t.inhibitors) {\n ensure(inh.place.name);\n }\n for (const r of t.reads) {\n ensure(r.place.name).hasOutgoing = true;\n }\n for (const rst of t.resets) {\n ensure(rst.place.name);\n }\n }\n\n return map;\n}\n\nfunction placeCategory(info: PlaceInfo, isEnvironment: boolean): NodeCategory {\n if (isEnvironment) return 'environment';\n if (!info.hasIncoming) return 'start';\n if (!info.hasOutgoing) return 'end';\n return 'place';\n}\n\n// ======================== Helpers ========================\n\nfunction transitionLabel(t: Transition, config: DotConfig): string {\n const parts = [t.name];\n\n if (config.showIntervals) {\n const e = earliest(t.timing);\n const l = latest(t.timing);\n const max = hasDeadline(t.timing) ? String(l) : '\\u221e';\n parts.push(`[${e}, ${max}]ms`);\n }\n\n if (config.showPriority && t.priority !== 0) {\n parts.push(`prio=${t.priority}`);\n }\n\n return parts.join(' ');\n}\n\nfunction outputEdges(transitionId: string, out: Out, branchLabel: string | null): GraphEdge[] {\n const outStyle = edgeStyle('output');\n\n switch (out.type) {\n case 'place': {\n const pid = 'p_' + sanitize(out.place.name);\n return [{\n from: transitionId,\n to: pid,\n label: branchLabel ?? undefined,\n color: outStyle.color,\n style: outStyle.style,\n arrowhead: outStyle.arrowhead,\n arcType: 'output',\n }];\n }\n\n case 'forward-input': {\n const pid = 'p_' + sanitize(out.to.name);\n const label = (branchLabel ? branchLabel + ' ' : '') + '\\u27f5' + out.from.name;\n return [{\n from: transitionId,\n to: pid,\n label,\n color: outStyle.color,\n style: 'dashed' as const,\n arrowhead: outStyle.arrowhead,\n arcType: 'output',\n }];\n }\n\n case 'and':\n return out.children.flatMap(c => outputEdges(transitionId, c, branchLabel));\n\n case 'xor': {\n const edges: GraphEdge[] = [];\n for (const child of out.children) {\n const label = inferBranchLabel(child);\n edges.push(...outputEdges(transitionId, child, label));\n }\n return edges;\n }\n\n case 'timeout':\n return outputEdges(transitionId, out.child, `\\u23f1${out.afterMs}ms`);\n }\n}\n\nfunction inferBranchLabel(out: Out): string | null {\n switch (out.type) {\n case 'place': return out.place.name;\n case 'timeout': return `\\u23f1${out.afterMs}ms`;\n case 'forward-input': return out.to.name;\n case 'and':\n case 'xor':\n return null;\n }\n}\n","/**\n * Renders a Graph to DOT (Graphviz) string.\n *\n * Pure function with zero Petri net knowledge. Operates solely on the\n * format-agnostic Graph model.\n *\n * @module export/dot-renderer\n */\n\nimport type { Graph, GraphNode, GraphEdge, Subgraph } from './graph.js';\n\n// ======================== Public API ========================\n\n/** Renders a Graph to a DOT string suitable for Graphviz. */\nexport function renderDot(graph: Graph): string {\n const lines: string[] = [];\n\n lines.push(`digraph ${quoteId(graph.id)} {`);\n\n // Graph attributes\n lines.push(` rankdir=${graph.rankdir};`);\n for (const [key, value] of Object.entries(graph.graphAttrs)) {\n lines.push(` ${key}=${quoteAttr(value)};`);\n }\n\n // Node defaults\n if (Object.keys(graph.nodeDefaults).length > 0) {\n lines.push(` node [${formatAttrs(graph.nodeDefaults)}];`);\n }\n\n // Edge defaults\n if (Object.keys(graph.edgeDefaults).length > 0) {\n lines.push(` edge [${formatAttrs(graph.edgeDefaults)}];`);\n }\n\n lines.push('');\n\n // Subgraphs\n for (const sg of graph.subgraphs) {\n lines.push(...renderSubgraph(sg, ' '));\n lines.push('');\n }\n\n // Nodes\n for (const node of graph.nodes) {\n lines.push(` ${renderNode(node)}`);\n }\n\n if (graph.nodes.length > 0) {\n lines.push('');\n }\n\n // Edges\n for (const edge of graph.edges) {\n lines.push(` ${renderEdge(edge)}`);\n }\n\n lines.push('}');\n\n return lines.join('\\n');\n}\n\n// ======================== Internal Rendering ========================\n\nfunction renderNode(node: GraphNode): string {\n const attrs: Record<string, string> = {\n label: node.label,\n shape: node.shape,\n style: node.style ? `\"filled,${node.style}\"` : 'filled',\n fillcolor: node.fill,\n color: node.stroke,\n penwidth: String(node.penwidth),\n };\n\n if (node.height !== undefined) {\n attrs['height'] = String(node.height);\n }\n if (node.width !== undefined) {\n attrs['width'] = String(node.width);\n }\n\n // Merge extra attrs\n if (node.attrs) {\n for (const [key, value] of Object.entries(node.attrs)) {\n attrs[key] = value;\n }\n }\n\n return `${quoteId(node.id)} [${formatNodeAttrs(attrs)}];`;\n}\n\nfunction renderEdge(edge: GraphEdge): string {\n const attrs: Record<string, string> = {\n color: edge.color,\n style: edge.style,\n arrowhead: edge.arrowhead,\n };\n\n if (edge.label !== undefined) {\n attrs['label'] = edge.label;\n }\n if (edge.penwidth !== undefined) {\n attrs['penwidth'] = String(edge.penwidth);\n }\n\n // Merge extra attrs\n if (edge.attrs) {\n for (const [key, value] of Object.entries(edge.attrs)) {\n attrs[key] = value;\n }\n }\n\n return `${quoteId(edge.from)} -> ${quoteId(edge.to)} [${formatNodeAttrs(attrs)}];`;\n}\n\nfunction renderSubgraph(sg: Subgraph, indent: string): string[] {\n const lines: string[] = [];\n lines.push(`${indent}subgraph ${quoteId('cluster_' + sg.id)} {`);\n\n if (sg.label !== undefined) {\n lines.push(`${indent} label=${quoteAttr(sg.label)};`);\n }\n\n if (sg.attrs) {\n for (const [key, value] of Object.entries(sg.attrs)) {\n lines.push(`${indent} ${key}=${quoteAttr(value)};`);\n }\n }\n\n for (const node of sg.nodes) {\n lines.push(`${indent} ${renderNode(node)}`);\n }\n\n lines.push(`${indent}}`);\n return lines;\n}\n\n// ======================== DOT Quoting ========================\n\n/** Quotes a DOT identifier. Always quotes to be safe with special chars. */\nfunction quoteId(id: string): string {\n // DOT keywords that must be quoted\n if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(id) && !isDotKeyword(id)) {\n return id;\n }\n return `\"${escapeDot(id)}\"`;\n}\n\n/** Quotes a DOT attribute value. */\nfunction quoteAttr(value: string): string {\n // Numbers don't need quoting\n if (/^-?\\d+(\\.\\d+)?$/.test(value)) {\n return value;\n }\n return `\"${escapeDot(value)}\"`;\n}\n\n/** Escapes special characters for DOT strings. */\nfunction escapeDot(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Formats node/edge attributes where certain values (like style with commas)\n * need special handling.\n */\nfunction formatNodeAttrs(attrs: Record<string, string>): string {\n return Object.entries(attrs)\n .map(([key, value]) => {\n // Style values that are already pre-quoted (contain the quote char)\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return `${key}=${value}`;\n }\n return `${key}=${quoteAttr(value)}`;\n })\n .join(', ');\n}\n\n/** Formats simple key=value attributes. */\nfunction formatAttrs(attrs: Readonly<Record<string, string>>): string {\n return Object.entries(attrs)\n .map(([key, value]) => `${key}=${quoteAttr(value)}`)\n .join(', ');\n}\n\n/** DOT language keywords that must be quoted when used as identifiers. */\nfunction isDotKeyword(id: string): boolean {\n const lower = id.toLowerCase();\n return lower === 'graph' || lower === 'digraph' || lower === 'subgraph'\n || lower === 'node' || lower === 'edge' || lower === 'strict';\n}\n","/**\n * Convenience function for exporting a PetriNet to DOT format.\n *\n * @module export/dot-exporter\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { DotConfig } from './petri-net-mapper.js';\nimport { mapToGraph } from './petri-net-mapper.js';\nimport { renderDot } from './dot-renderer.js';\n\n/**\n * Exports a PetriNet to DOT (Graphviz) format.\n *\n * @param net the Petri net to export\n * @param config optional export configuration\n * @returns DOT string suitable for rendering with Graphviz\n */\nexport function dotExport(net: PetriNet, config?: DotConfig): string {\n return renderDot(mapToGraph(net, config));\n}\n"],"mappings":";;;;;;;AAoDA,IAAM,cAAgD;AAAA,EACpD,OAAc,EAAE,OAAO,UAAW,MAAM,WAAW,QAAQ,WAAW,UAAU,KAAK,OAAO,KAAK;AAAA,EACjG,OAAc,EAAE,OAAO,UAAW,MAAM,WAAW,QAAQ,WAAW,UAAU,GAAK,OAAO,KAAK;AAAA,EACjG,KAAc,EAAE,OAAO,gBAAiB,MAAM,WAAW,QAAQ,WAAW,UAAU,GAAK,OAAO,KAAK;AAAA,EACvG,aAAc,EAAE,OAAO,UAAW,MAAM,WAAW,QAAQ,WAAW,UAAU,GAAK,OAAO,UAAU,OAAO,KAAK;AAAA,EAClH,YAAc,EAAE,OAAO,OAAQ,MAAM,WAAW,QAAQ,WAAW,UAAU,GAAK,QAAQ,KAAK,OAAO,IAAI;AAC5G;AAEA,IAAM,cAAgD;AAAA,EACpD,OAAW,EAAE,OAAO,WAAW,OAAO,SAAU,WAAW,SAAS;AAAA,EACpE,QAAW,EAAE,OAAO,WAAW,OAAO,SAAU,WAAW,SAAS;AAAA,EACpE,WAAW,EAAE,OAAO,WAAW,OAAO,SAAU,WAAW,OAAO;AAAA,EAClE,MAAW,EAAE,OAAO,WAAW,OAAO,UAAW,WAAW,SAAS;AAAA,EACrE,OAAW,EAAE,OAAO,WAAW,OAAO,QAAS,WAAW,UAAW,UAAU,EAAI;AACrF;AAEO,IAAM,OAAkB,EAAE,QAAQ,8BAA8B,UAAU,IAAI,UAAU,GAAG;AAE3F,IAAM,QAAoB,EAAE,SAAS,KAAK,SAAS,MAAM,aAAa,MAAM,SAAS,OAAO,aAAa,aAAa;AAQtH,SAAS,UAAU,UAAoC;AAC5D,SAAO,YAAY,QAAQ;AAC7B;AAGO,SAAS,UAAU,SAAmC;AAC3D,SAAO,YAAY,OAAO;AAC5B;;;ACzDO,IAAM,qBAAgC;AAAA,EAC3C,WAAW;AAAA,EACX,WAAW;AAAA,EACX,eAAe;AAAA,EACf,cAAc;AAChB;AAKO,SAAS,SAAS,MAAsB;AAC7C,SAAO,KAAK,QAAQ,kBAAkB,GAAG;AAC3C;AAGO,SAAS,WAAW,KAAe,SAAoB,oBAA2B;AACvF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,WAAW,OAAO,qBAAqB,oBAAI,IAAY;AAE7D,QAAM,QAAqB,CAAC;AAC5B,QAAM,QAAqB,CAAC;AAG5B,aAAW,CAAC,MAAM,IAAI,KAAK,QAAQ;AACjC,UAAM,WAAW,cAAc,MAAM,SAAS,IAAI,IAAI,CAAC;AACvD,UAAM,QAAQ,UAAU,QAAQ;AAChC,UAAM,KAAK;AAAA,MACT,IAAI,OAAO,SAAS,IAAI;AAAA,MACxB,OAAO;AAAA,MACP,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,UAAU,MAAM;AAAA,MAChB,YAAY;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,OAAO,MAAM;AAAA,MACb,OAAO,EAAE,QAAQ,MAAM,WAAW,OAAO;AAAA,IAC3C,CAAC;AAAA,EACH;AAGA,aAAW,KAAK,IAAI,aAAa;AAC/B,UAAM,QAAQ,UAAU,YAAY;AACpC,UAAM,KAAK;AAAA,MACT,IAAI,OAAO,SAAS,EAAE,IAAI;AAAA,MAC1B,OAAO,gBAAgB,GAAG,MAAM;AAAA,MAChC,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,QAAQ,MAAM;AAAA,MACd,UAAU,MAAM;AAAA,MAChB,YAAY,EAAE;AAAA,MACd,QAAQ,MAAM;AAAA,MACd,OAAO,MAAM;AAAA,IACf,CAAC;AAAA,EACH;AAGA,aAAW,KAAK,IAAI,aAAa;AAC/B,UAAM,MAAM,OAAO,SAAS,EAAE,IAAI;AAGlC,eAAW,QAAQ,EAAE,YAAY;AAC/B,YAAM,MAAM,OAAO,SAAS,KAAK,MAAM,IAAI;AAC3C,YAAM,aAAa,UAAU,OAAO;AACpC,UAAI;AACJ,cAAQ,KAAK,MAAM;AAAA,QACjB,KAAK;AACH,kBAAQ,OAAS,KAAK,KAAK;AAC3B;AAAA,QACF,KAAK;AACH,kBAAQ;AACR;AAAA,QACF,KAAK;AACH,kBAAQ,SAAS,KAAK,OAAO;AAC7B;AAAA,MACJ;AACA,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,IAAI;AAAA,QACJ;AAAA,QACA,OAAO,WAAW;AAAA,QAClB,OAAO,WAAW;AAAA,QAClB,WAAW,WAAW;AAAA,QACtB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAGA,QAAI,EAAE,eAAe,MAAM;AACzB,YAAM,KAAK,GAAG,YAAY,KAAK,EAAE,YAAY,IAAI,CAAC;AAAA,IACpD;AAGA,eAAW,OAAO,EAAE,YAAY;AAC9B,YAAM,MAAM,OAAO,SAAS,IAAI,MAAM,IAAI;AAC1C,YAAM,WAAW,UAAU,WAAW;AACtC,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,WAAW,SAAS;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAGA,eAAW,KAAK,EAAE,OAAO;AACvB,YAAM,MAAM,OAAO,SAAS,EAAE,MAAM,IAAI;AACxC,YAAM,YAAY,UAAU,MAAM;AAClC,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,OAAO;AAAA,QACP,OAAO,UAAU;AAAA,QACjB,OAAO,UAAU;AAAA,QACjB,WAAW,UAAU;AAAA,QACrB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAGA,UAAM,mBAAmB,EAAE,eAAe,OACtC,IAAI,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,EAAE,IAAI,OAAK,EAAE,IAAI,CAAC,IAC9C,oBAAI,IAAY;AACpB,eAAW,OAAO,EAAE,QAAQ;AAC1B,UAAI,CAAC,iBAAiB,IAAI,IAAI,MAAM,IAAI,GAAG;AACzC,cAAM,MAAM,OAAO,SAAS,IAAI,MAAM,IAAI;AAC1C,cAAM,aAAa,UAAU,OAAO;AACpC,cAAM,KAAK;AAAA,UACT,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,OAAO,WAAW;AAAA,UAClB,OAAO,WAAW;AAAA,UAClB,WAAW,WAAW;AAAA,UACtB,UAAU,WAAW;AAAA,UACrB,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,SAAS,IAAI,IAAI;AAAA,IACrB,SAAS,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,IACA,WAAW,CAAC;AAAA,IACZ,YAAY;AAAA,MACV,SAAS,OAAO,MAAM,OAAO;AAAA,MAC7B,SAAS,OAAO,MAAM,OAAO;AAAA,MAC7B,aAAa,OAAO,MAAM,WAAW;AAAA,MACrC,SAAS,OAAO,MAAM,OAAO;AAAA,MAC7B,UAAU,KAAK;AAAA,MACf,aAAa,MAAM;AAAA,IACrB;AAAA,IACA,cAAc;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,UAAU,OAAO,KAAK,QAAQ;AAAA,IAChC;AAAA,IACA,cAAc;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,UAAU,OAAO,KAAK,QAAQ;AAAA,IAChC;AAAA,EACF;AACF;AASA,SAAS,cAAc,KAAuC;AAC5D,QAAM,MAAM,oBAAI,IAAuB;AAEvC,WAAS,OAAO,MAAyB;AACvC,QAAI,OAAO,IAAI,IAAI,IAAI;AACvB,QAAI,CAAC,MAAM;AACT,aAAO,EAAE,aAAa,OAAO,aAAa,MAAM;AAChD,UAAI,IAAI,MAAM,IAAI;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAEA,aAAW,KAAK,IAAI,aAAa;AAC/B,eAAW,QAAQ,EAAE,YAAY;AAC/B,aAAO,KAAK,MAAM,IAAI,EAAE,cAAc;AAAA,IACxC;AACA,QAAI,EAAE,eAAe,MAAM;AACzB,iBAAW,KAAK,EAAE,aAAa,GAAG;AAChC,eAAO,EAAE,IAAI,EAAE,cAAc;AAAA,MAC/B;AAAA,IACF;AACA,eAAW,OAAO,EAAE,YAAY;AAC9B,aAAO,IAAI,MAAM,IAAI;AAAA,IACvB;AACA,eAAW,KAAK,EAAE,OAAO;AACvB,aAAO,EAAE,MAAM,IAAI,EAAE,cAAc;AAAA,IACrC;AACA,eAAW,OAAO,EAAE,QAAQ;AAC1B,aAAO,IAAI,MAAM,IAAI;AAAA,IACvB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,MAAiB,eAAsC;AAC5E,MAAI,cAAe,QAAO;AAC1B,MAAI,CAAC,KAAK,YAAa,QAAO;AAC9B,MAAI,CAAC,KAAK,YAAa,QAAO;AAC9B,SAAO;AACT;AAIA,SAAS,gBAAgB,GAAe,QAA2B;AACjE,QAAM,QAAQ,CAAC,EAAE,IAAI;AAErB,MAAI,OAAO,eAAe;AACxB,UAAM,IAAI,SAAS,EAAE,MAAM;AAC3B,UAAM,IAAI,OAAO,EAAE,MAAM;AACzB,UAAM,MAAM,YAAY,EAAE,MAAM,IAAI,OAAO,CAAC,IAAI;AAChD,UAAM,KAAK,IAAI,CAAC,KAAK,GAAG,KAAK;AAAA,EAC/B;AAEA,MAAI,OAAO,gBAAgB,EAAE,aAAa,GAAG;AAC3C,UAAM,KAAK,QAAQ,EAAE,QAAQ,EAAE;AAAA,EACjC;AAEA,SAAO,MAAM,KAAK,GAAG;AACvB;AAEA,SAAS,YAAY,cAAsB,KAAU,aAAyC;AAC5F,QAAM,WAAW,UAAU,QAAQ;AAEnC,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK,SAAS;AACZ,YAAM,MAAM,OAAO,SAAS,IAAI,MAAM,IAAI;AAC1C,aAAO,CAAC;AAAA,QACN,MAAM;AAAA,QACN,IAAI;AAAA,QACJ,OAAO,eAAe;AAAA,QACtB,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS;AAAA,QAChB,WAAW,SAAS;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,IAEA,KAAK,iBAAiB;AACpB,YAAM,MAAM,OAAO,SAAS,IAAI,GAAG,IAAI;AACvC,YAAM,SAAS,cAAc,cAAc,MAAM,MAAM,WAAW,IAAI,KAAK;AAC3E,aAAO,CAAC;AAAA,QACN,MAAM;AAAA,QACN,IAAI;AAAA,QACJ;AAAA,QACA,OAAO,SAAS;AAAA,QAChB,OAAO;AAAA,QACP,WAAW,SAAS;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,IAEA,KAAK;AACH,aAAO,IAAI,SAAS,QAAQ,OAAK,YAAY,cAAc,GAAG,WAAW,CAAC;AAAA,IAE5E,KAAK,OAAO;AACV,YAAM,QAAqB,CAAC;AAC5B,iBAAW,SAAS,IAAI,UAAU;AAChC,cAAM,QAAQ,iBAAiB,KAAK;AACpC,cAAM,KAAK,GAAG,YAAY,cAAc,OAAO,KAAK,CAAC;AAAA,MACvD;AACA,aAAO;AAAA,IACT;AAAA,IAEA,KAAK;AACH,aAAO,YAAY,cAAc,IAAI,OAAO,SAAS,IAAI,OAAO,IAAI;AAAA,EACxE;AACF;AAEA,SAAS,iBAAiB,KAAyB;AACjD,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK;AAAS,aAAO,IAAI,MAAM;AAAA,IAC/B,KAAK;AAAW,aAAO,SAAS,IAAI,OAAO;AAAA,IAC3C,KAAK;AAAiB,aAAO,IAAI,GAAG;AAAA,IACpC,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,EACX;AACF;;;ACnTO,SAAS,UAAU,OAAsB;AAC9C,QAAM,QAAkB,CAAC;AAEzB,QAAM,KAAK,WAAW,QAAQ,MAAM,EAAE,CAAC,IAAI;AAG3C,QAAM,KAAK,eAAe,MAAM,OAAO,GAAG;AAC1C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,UAAU,GAAG;AAC3D,UAAM,KAAK,OAAO,GAAG,IAAI,UAAU,KAAK,CAAC,GAAG;AAAA,EAC9C;AAGA,MAAI,OAAO,KAAK,MAAM,YAAY,EAAE,SAAS,GAAG;AAC9C,UAAM,KAAK,aAAa,YAAY,MAAM,YAAY,CAAC,IAAI;AAAA,EAC7D;AAGA,MAAI,OAAO,KAAK,MAAM,YAAY,EAAE,SAAS,GAAG;AAC9C,UAAM,KAAK,aAAa,YAAY,MAAM,YAAY,CAAC,IAAI;AAAA,EAC7D;AAEA,QAAM,KAAK,EAAE;AAGb,aAAW,MAAM,MAAM,WAAW;AAChC,UAAM,KAAK,GAAG,eAAe,IAAI,MAAM,CAAC;AACxC,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,aAAW,QAAQ,MAAM,OAAO;AAC9B,UAAM,KAAK,OAAO,WAAW,IAAI,CAAC,EAAE;AAAA,EACtC;AAEA,MAAI,MAAM,MAAM,SAAS,GAAG;AAC1B,UAAM,KAAK,EAAE;AAAA,EACf;AAGA,aAAW,QAAQ,MAAM,OAAO;AAC9B,UAAM,KAAK,OAAO,WAAW,IAAI,CAAC,EAAE;AAAA,EACtC;AAEA,QAAM,KAAK,GAAG;AAEd,SAAO,MAAM,KAAK,IAAI;AACxB;AAIA,SAAS,WAAW,MAAyB;AAC3C,QAAM,QAAgC;AAAA,IACpC,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK,QAAQ,WAAW,KAAK,KAAK,MAAM;AAAA,IAC/C,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,IACZ,UAAU,OAAO,KAAK,QAAQ;AAAA,EAChC;AAEA,MAAI,KAAK,WAAW,QAAW;AAC7B,UAAM,QAAQ,IAAI,OAAO,KAAK,MAAM;AAAA,EACtC;AACA,MAAI,KAAK,UAAU,QAAW;AAC5B,UAAM,OAAO,IAAI,OAAO,KAAK,KAAK;AAAA,EACpC;AAGA,MAAI,KAAK,OAAO;AACd,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACrD,YAAM,GAAG,IAAI;AAAA,IACf;AAAA,EACF;AAEA,SAAO,GAAG,QAAQ,KAAK,EAAE,CAAC,KAAK,gBAAgB,KAAK,CAAC;AACvD;AAEA,SAAS,WAAW,MAAyB;AAC3C,QAAM,QAAgC;AAAA,IACpC,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK;AAAA,IACZ,WAAW,KAAK;AAAA,EAClB;AAEA,MAAI,KAAK,UAAU,QAAW;AAC5B,UAAM,OAAO,IAAI,KAAK;AAAA,EACxB;AACA,MAAI,KAAK,aAAa,QAAW;AAC/B,UAAM,UAAU,IAAI,OAAO,KAAK,QAAQ;AAAA,EAC1C;AAGA,MAAI,KAAK,OAAO;AACd,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,KAAK,GAAG;AACrD,YAAM,GAAG,IAAI;AAAA,IACf;AAAA,EACF;AAEA,SAAO,GAAG,QAAQ,KAAK,IAAI,CAAC,OAAO,QAAQ,KAAK,EAAE,CAAC,KAAK,gBAAgB,KAAK,CAAC;AAChF;AAEA,SAAS,eAAe,IAAc,QAA0B;AAC9D,QAAM,QAAkB,CAAC;AACzB,QAAM,KAAK,GAAG,MAAM,YAAY,QAAQ,aAAa,GAAG,EAAE,CAAC,IAAI;AAE/D,MAAI,GAAG,UAAU,QAAW;AAC1B,UAAM,KAAK,GAAG,MAAM,aAAa,UAAU,GAAG,KAAK,CAAC,GAAG;AAAA,EACzD;AAEA,MAAI,GAAG,OAAO;AACZ,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,KAAK,GAAG;AACnD,YAAM,KAAK,GAAG,MAAM,OAAO,GAAG,IAAI,UAAU,KAAK,CAAC,GAAG;AAAA,IACvD;AAAA,EACF;AAEA,aAAW,QAAQ,GAAG,OAAO;AAC3B,UAAM,KAAK,GAAG,MAAM,OAAO,WAAW,IAAI,CAAC,EAAE;AAAA,EAC/C;AAEA,QAAM,KAAK,GAAG,MAAM,GAAG;AACvB,SAAO;AACT;AAKA,SAAS,QAAQ,IAAoB;AAEnC,MAAI,2BAA2B,KAAK,EAAE,KAAK,CAAC,aAAa,EAAE,GAAG;AAC5D,WAAO;AAAA,EACT;AACA,SAAO,IAAI,UAAU,EAAE,CAAC;AAC1B;AAGA,SAAS,UAAU,OAAuB;AAExC,MAAI,kBAAkB,KAAK,KAAK,GAAG;AACjC,WAAO;AAAA,EACT;AACA,SAAO,IAAI,UAAU,KAAK,CAAC;AAC7B;AAGA,SAAS,UAAU,GAAmB;AACpC,SAAO,EAAE,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK;AACrD;AAMA,SAAS,gBAAgB,OAAuC;AAC9D,SAAO,OAAO,QAAQ,KAAK,EACxB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;AAErB,QAAI,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAAG;AAChD,aAAO,GAAG,GAAG,IAAI,KAAK;AAAA,IACxB;AACA,WAAO,GAAG,GAAG,IAAI,UAAU,KAAK,CAAC;AAAA,EACnC,CAAC,EACA,KAAK,IAAI;AACd;AAGA,SAAS,YAAY,OAAiD;AACpE,SAAO,OAAO,QAAQ,KAAK,EACxB,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,GAAG,IAAI,UAAU,KAAK,CAAC,EAAE,EAClD,KAAK,IAAI;AACd;AAGA,SAAS,aAAa,IAAqB;AACzC,QAAM,QAAQ,GAAG,YAAY;AAC7B,SAAO,UAAU,WAAW,UAAU,aAAa,UAAU,cACxD,UAAU,UAAU,UAAU,UAAU,UAAU;AACzD;;;AC5KO,SAAS,UAAU,KAAe,QAA4B;AACnE,SAAO,UAAU,WAAW,KAAK,MAAM,CAAC;AAC1C;","names":[]}
@@ -724,8 +724,12 @@ declare class SessionArchiveWriter {
724
724
  writeV3(session: DebugSession): Buffer;
725
725
  /**
726
726
  * Shared framing logic: length-prefixed header JSON, then length-prefixed
727
- * event JSON, then gzip. Both v1 and v2 archives use the identical event
728
- * wire format, so the body loop is version-agnostic.
727
+ * event JSON, then gzip. All header versions share the identical event wire
728
+ * format, so the body loop is version-agnostic.
729
+ *
730
+ * Takes the events snapshot directly so the body iterates the same array the
731
+ * caller used to populate {@link SessionArchive.eventCount} — preserving the
732
+ * `header.eventCount === events.length` invariant.
729
733
  */
730
734
  private writeFramed;
731
735
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  dotExport,
3
3
  sanitize
4
- } from "../chunk-JNHADILD.js";
4
+ } from "../chunk-2HWR2675.js";
5
5
  import "../chunk-FN773SSE.js";
6
6
 
7
7
  // src/debug/debug-command.ts
@@ -1583,16 +1583,17 @@ var SessionArchiveWriter = class {
1583
1583
  * testing or when producing archives for consumers pinned to libpetri ≤ 1.6.1.
1584
1584
  */
1585
1585
  writeV1(session) {
1586
+ const events = Object.freeze([...session.eventStore.events()]);
1586
1587
  const header = {
1587
1588
  version: 1,
1588
1589
  sessionId: session.sessionId,
1589
1590
  netName: session.netName,
1590
1591
  dotDiagram: session.dotDiagram,
1591
1592
  startTime: new Date(session.startTime).toISOString(),
1592
- eventCount: session.eventStore.eventCount(),
1593
+ eventCount: events.length,
1593
1594
  structure: buildNetStructure(session)
1594
1595
  };
1595
- return this.writeFramed(header, session);
1596
+ return this.writeFramed(header, events);
1596
1597
  }
1597
1598
  /**
1598
1599
  * Writes a session in the v2 format — richer header with `endTime`, `tags`,
@@ -1604,7 +1605,8 @@ var SessionArchiveWriter = class {
1604
1605
  * passes walk the same sequence from the start.
1605
1606
  */
1606
1607
  writeV2(session) {
1607
- const metadata = computeMetadata(session.eventStore);
1608
+ const events = Object.freeze([...session.eventStore.events()]);
1609
+ const metadata = computeMetadata(events);
1608
1610
  const header = {
1609
1611
  version: 2,
1610
1612
  sessionId: session.sessionId,
@@ -1612,7 +1614,7 @@ var SessionArchiveWriter = class {
1612
1614
  dotDiagram: session.dotDiagram,
1613
1615
  startTime: new Date(session.startTime).toISOString(),
1614
1616
  endTime: session.endTime !== void 0 ? new Date(session.endTime).toISOString() : void 0,
1615
- eventCount: session.eventStore.eventCount(),
1617
+ eventCount: events.length,
1616
1618
  // Snapshot of tags at archive-write time — record the state that was
1617
1619
  // current when the session was archived, not whatever happens on the
1618
1620
  // live session afterwards.
@@ -1620,7 +1622,7 @@ var SessionArchiveWriter = class {
1620
1622
  metadata,
1621
1623
  structure: buildNetStructure(session)
1622
1624
  };
1623
- return this.writeFramed(header, session);
1625
+ return this.writeFramed(header, events);
1624
1626
  }
1625
1627
  /**
1626
1628
  * Writes a session in the v3 format — same header shape as v2, with version=3
@@ -1628,7 +1630,8 @@ var SessionArchiveWriter = class {
1628
1630
  * legacy `value` string (see {@link tokenInfo}).
1629
1631
  */
1630
1632
  writeV3(session) {
1631
- const metadata = computeMetadata(session.eventStore);
1633
+ const events = Object.freeze([...session.eventStore.events()]);
1634
+ const metadata = computeMetadata(events);
1632
1635
  const header = {
1633
1636
  version: 3,
1634
1637
  sessionId: session.sessionId,
@@ -1636,25 +1639,29 @@ var SessionArchiveWriter = class {
1636
1639
  dotDiagram: session.dotDiagram,
1637
1640
  startTime: new Date(session.startTime).toISOString(),
1638
1641
  endTime: session.endTime !== void 0 ? new Date(session.endTime).toISOString() : void 0,
1639
- eventCount: session.eventStore.eventCount(),
1642
+ eventCount: events.length,
1640
1643
  tags: { ...session.tags },
1641
1644
  metadata,
1642
1645
  structure: buildNetStructure(session)
1643
1646
  };
1644
- return this.writeFramed(header, session);
1647
+ return this.writeFramed(header, events);
1645
1648
  }
1646
1649
  /**
1647
1650
  * Shared framing logic: length-prefixed header JSON, then length-prefixed
1648
- * event JSON, then gzip. Both v1 and v2 archives use the identical event
1649
- * wire format, so the body loop is version-agnostic.
1651
+ * event JSON, then gzip. All header versions share the identical event wire
1652
+ * format, so the body loop is version-agnostic.
1653
+ *
1654
+ * Takes the events snapshot directly so the body iterates the same array the
1655
+ * caller used to populate {@link SessionArchive.eventCount} — preserving the
1656
+ * `header.eventCount === events.length` invariant.
1650
1657
  */
1651
- writeFramed(header, session) {
1658
+ writeFramed(header, events) {
1652
1659
  const parts = [];
1653
1660
  const metaBytes = Buffer.from(JSON.stringify(header), "utf-8");
1654
1661
  const metaLen = Buffer.alloc(4);
1655
1662
  metaLen.writeUInt32BE(metaBytes.length);
1656
1663
  parts.push(metaLen, metaBytes);
1657
- for (const event of session.eventStore) {
1664
+ for (const event of events) {
1658
1665
  const eventInfo = toEventInfo(event);
1659
1666
  const eventBytes = Buffer.from(JSON.stringify(eventInfo), "utf-8");
1660
1667
  const eventLen = Buffer.alloc(4);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/debug/debug-command.ts","../../src/debug/archive/session-archive-reader.ts","../../src/debug/debug-event-store.ts","../../src/debug/archive/session-archive.ts","../../src/debug/place-analysis.ts","../../src/debug/debug-session-registry.ts","../../src/debug/marking-cache.ts","../../src/debug/net-event-converter.ts","../../src/debug/debug-protocol-handler.ts","../../src/debug/debug-aware-event-store.ts","../../src/debug/archive/file-session-archive-storage.ts","../../src/debug/archive/session-archive-writer.ts","../../src/debug/archive/session-metadata.ts","../../src/debug/index.ts"],"sourcesContent":["/**\n * Commands sent from debug UI client to server via WebSocket.\n * TypeScript port of Java's DebugCommand sealed interface.\n */\n\nexport type SubscriptionMode = 'live' | 'replay';\n\nexport type BreakpointType =\n | 'TRANSITION_ENABLED'\n | 'TRANSITION_START'\n | 'TRANSITION_COMPLETE'\n | 'TRANSITION_FAIL'\n | 'TOKEN_ADDED'\n | 'TOKEN_REMOVED';\n\nexport interface BreakpointConfig {\n readonly id: string;\n readonly type: BreakpointType;\n readonly target: string | null;\n readonly enabled: boolean;\n}\n\nexport interface EventFilter {\n readonly eventTypes: readonly string[] | null;\n readonly transitionNames: readonly string[] | null;\n readonly placeNames: readonly string[] | null;\n readonly excludeEventTypes?: readonly string[] | null;\n readonly excludeTransitionNames?: readonly string[] | null;\n readonly excludePlaceNames?: readonly string[] | null;\n}\n\nexport type DebugCommand =\n | { readonly type: 'subscribe'; readonly sessionId: string; readonly mode: SubscriptionMode; readonly fromIndex?: number }\n | { readonly type: 'unsubscribe'; readonly sessionId: string }\n | {\n readonly type: 'listSessions';\n readonly limit?: number;\n readonly activeOnly?: boolean;\n /** Optional tag filter (AND semantics). Empty or missing matches all. (libpetri 1.6.0+) */\n readonly tagFilter?: Readonly<Record<string, string>>;\n }\n | { readonly type: 'seek'; readonly sessionId: string; readonly timestamp: string }\n | { readonly type: 'playbackSpeed'; readonly sessionId: string; readonly speed: number }\n | { readonly type: 'filter'; readonly sessionId: string; readonly filter: EventFilter }\n | { readonly type: 'pause'; readonly sessionId: string }\n | { readonly type: 'resume'; readonly sessionId: string }\n | { readonly type: 'stepForward'; readonly sessionId: string }\n | { readonly type: 'stepBackward'; readonly sessionId: string }\n | { readonly type: 'setBreakpoint'; readonly sessionId: string; readonly breakpoint: BreakpointConfig }\n | { readonly type: 'clearBreakpoint'; readonly sessionId: string; readonly breakpointId: string }\n | { readonly type: 'listBreakpoints'; readonly sessionId: string }\n | { readonly type: 'listArchives'; readonly limit?: number; readonly prefix?: string }\n | { readonly type: 'importArchive'; readonly sessionId: string }\n | { readonly type: 'uploadArchive'; readonly fileName: string; readonly data: string };\n\nexport function eventFilterAll(): EventFilter {\n return { eventTypes: null, transitionNames: null, placeNames: null, excludeEventTypes: null, excludeTransitionNames: null, excludePlaceNames: null };\n}\n","/**\n * Reads session archives from length-prefixed binary format.\n *\n * Handles both v1 (libpetri 1.5.x–1.6.x) and v2 (libpetri 1.7.0+) archives via\n * a lenient \"version probe\": parse the header JSON once, switch on the\n * `version` field, narrow to the correct concrete type, and normalize missing\n * optional fields to their defaults. Events inside the body use the same wire\n * format across versions, so the event read path is shared.\n */\n\nimport { gunzipSync } from 'node:zlib';\nimport { DebugEventStore } from '../debug-event-store.js';\nimport type { NetEventInfo } from '../debug-response.js';\nimport type { NetEvent } from '../../event/net-event.js';\nimport type { Token } from '../../core/token.js';\nimport type {\n SessionArchive,\n SessionArchiveV1,\n SessionArchiveV2,\n SessionArchiveV3,\n} from './session-archive.js';\nimport {\n CURRENT_VERSION,\n MIN_SUPPORTED_VERSION,\n emptyMetadata,\n} from './session-archive.js';\n\nexport interface ImportedSession {\n readonly metadata: SessionArchive;\n readonly eventStore: DebugEventStore;\n}\n\nconst MAX_EVENT_SIZE = 10 * 1024 * 1024; // 10 MB\n\nexport class SessionArchiveReader {\n /** Reads only the metadata header from an archive. */\n readMetadata(compressed: Buffer): SessionArchive {\n const data = gunzipSync(compressed);\n const metaLen = data.readUInt32BE(0);\n const metaJson = data.subarray(4, 4 + metaLen).toString('utf-8');\n return parseHeader(metaJson);\n }\n\n /** Reads the full archive: metadata + all events into a DebugEventStore. */\n readFull(compressed: Buffer): ImportedSession {\n const data = gunzipSync(compressed);\n let offset = 0;\n\n // Read metadata\n const metaLen = data.readUInt32BE(offset);\n offset += 4;\n const metaJson = data.subarray(offset, offset + metaLen).toString('utf-8');\n offset += metaLen;\n const metadata = parseHeader(metaJson);\n\n // Read events — same wire format across versions.\n const eventStore = new DebugEventStore(metadata.sessionId, Number.MAX_SAFE_INTEGER);\n while (offset < data.length) {\n if (offset + 4 > data.length) break;\n const eventLen = data.readUInt32BE(offset);\n offset += 4;\n if (eventLen <= 0 || eventLen > MAX_EVENT_SIZE) {\n throw new Error(`Invalid event size: ${eventLen}`);\n }\n if (offset + eventLen > data.length) break;\n const eventJson = data.subarray(offset, offset + eventLen).toString('utf-8');\n offset += eventLen;\n\n const eventInfo: NetEventInfo = JSON.parse(eventJson);\n const netEvent = eventInfoToNetEvent(eventInfo);\n eventStore.append(netEvent);\n }\n\n return { metadata, eventStore };\n }\n}\n\n/**\n * Peeks the archive `version` field via a single JSON parse, then narrows the\n * result into the correct {@link SessionArchive} variant. v2-only optional\n * fields (`tags`, `metadata`) are normalized to their empty defaults so\n * callers never need to guard against `undefined` on a declared-v2 archive.\n */\nfunction parseHeader(metaJson: string): SessionArchive {\n const raw = JSON.parse(metaJson) as { version: number } & Record<string, unknown>;\n switch (raw.version) {\n case 1:\n return raw as unknown as SessionArchiveV1;\n case 2: {\n const v2 = raw as unknown as SessionArchiveV2;\n // Normalize: v2 defines tags + metadata as REQUIRED in the type, but a\n // hand-written or partially-built header could omit them — fall back\n // to empty defaults rather than emit `undefined` into typed code.\n return {\n ...v2,\n tags: v2.tags ?? {},\n metadata: v2.metadata ?? emptyMetadata(),\n };\n }\n case 3: {\n const v3 = raw as unknown as SessionArchiveV3;\n return {\n ...v3,\n tags: v3.tags ?? {},\n metadata: v3.metadata ?? emptyMetadata(),\n };\n }\n default:\n throw new Error(\n `Unsupported archive version: ${raw.version} ` +\n `(reader supports ${MIN_SUPPORTED_VERSION}..${CURRENT_VERSION})`,\n );\n }\n}\n\n/** Converts a serialized NetEventInfo back to a NetEvent. */\nfunction eventInfoToNetEvent(info: NetEventInfo): NetEvent {\n const timestamp = new Date(info.timestamp).getTime();\n const d = info.details;\n\n switch (info.type) {\n case 'ExecutionStarted':\n return { type: 'execution-started', timestamp, netName: d['netName'] as string, executionId: d['executionId'] as string };\n case 'ExecutionCompleted':\n return { type: 'execution-completed', timestamp, netName: d['netName'] as string, executionId: d['executionId'] as string, totalDurationMs: d['totalDurationMs'] as number };\n case 'TransitionEnabled':\n return { type: 'transition-enabled', timestamp, transitionName: info.transitionName! };\n case 'TransitionClockRestarted':\n return { type: 'transition-clock-restarted', timestamp, transitionName: info.transitionName! };\n case 'TransitionStarted': {\n const tokens = (d['consumedTokens'] as readonly WireTokenInfo[])\n .map(t => infoToToken(t));\n return { type: 'transition-started', timestamp, transitionName: info.transitionName!, consumedTokens: tokens };\n }\n case 'TransitionCompleted': {\n const tokens = (d['producedTokens'] as readonly WireTokenInfo[])\n .map(t => infoToToken(t));\n return { type: 'transition-completed', timestamp, transitionName: info.transitionName!, producedTokens: tokens, durationMs: d['durationMs'] as number };\n }\n case 'TransitionFailed':\n return { type: 'transition-failed', timestamp, transitionName: info.transitionName!, errorMessage: d['errorMessage'] as string, exceptionType: d['exceptionType'] as string };\n case 'TransitionTimedOut':\n return { type: 'transition-timed-out', timestamp, transitionName: info.transitionName!, deadlineMs: d['deadlineMs'] as number, actualDurationMs: d['actualDurationMs'] as number };\n case 'ActionTimedOut':\n return { type: 'action-timed-out', timestamp, transitionName: info.transitionName!, timeoutMs: d['timeoutMs'] as number };\n case 'TokenAdded': {\n const t = d['token'] as WireTokenInfo;\n return { type: 'token-added', timestamp, placeName: info.placeName!, token: infoToToken(t) };\n }\n case 'TokenRemoved': {\n const t = d['token'] as WireTokenInfo;\n return { type: 'token-removed', timestamp, placeName: info.placeName!, token: infoToToken(t) };\n }\n case 'MarkingSnapshot': {\n const markingData = d['marking'] as Record<string, readonly WireTokenInfo[]>;\n const marking = new Map<string, Token<unknown>[]>();\n for (const [place, tokens] of Object.entries(markingData)) {\n marking.set(place, tokens.map(t => infoToToken(t)));\n }\n return { type: 'marking-snapshot', timestamp, marking };\n }\n case 'LogMessage':\n return {\n type: 'log-message',\n timestamp,\n transitionName: info.transitionName!,\n logger: d['loggerName'] as string,\n level: d['level'] as string,\n message: d['message'] as string,\n error: (d['throwable'] as string | undefined) ?? null,\n errorMessage: (d['throwableMessage'] as string | undefined) ?? null,\n };\n default:\n // Fallback: create a minimal event for unknown types\n return { type: 'transition-enabled', timestamp, transitionName: info.transitionName ?? 'unknown' };\n }\n}\n\n/**\n * Wire shape of a serialized token body. Matches {@link TokenInfo} minus the\n * `id` field (archives never emit token identity). `structured` is optional\n * and preserved verbatim on replay per EVT-025 AC5.\n */\ninterface WireTokenInfo {\n readonly type: string;\n readonly value: string | null;\n readonly structured?: unknown;\n readonly timestamp: string | null;\n}\n\nfunction infoToToken(t: WireTokenInfo): Token<unknown> {\n const createdAt = t.timestamp ? new Date(t.timestamp).getTime() : Date.now();\n // Preserve `structured` only when the writer emitted it — keep live-token\n // shape (no `structured` field) identical for tokens that lacked it.\n return t.structured === undefined\n ? { value: t.value, createdAt }\n : { value: t.value, createdAt, structured: t.structured };\n}\n","/**\n * EventStore with live tailing and historical replay.\n * TypeScript port of Java's DebugEventStore.\n *\n * Node.js simplifications: single-threaded, no locks needed,\n * synchronous Set<Function> for subscribers, microtask broadcast.\n */\n\nimport type { EventStore } from '../event/event-store.js';\nimport type { NetEvent } from '../event/net-event.js';\n\n/** Handle for managing a live event subscription. */\nexport interface Subscription {\n cancel(): void;\n isActive(): boolean;\n}\n\n/** Default maximum events to retain before evicting oldest. */\nexport const DEFAULT_MAX_EVENTS = 10_000;\n\nexport class DebugEventStore implements EventStore {\n private readonly _events: NetEvent[] = [];\n private readonly _subscribers = new Set<(event: NetEvent) => void>();\n private readonly _sessionId: string;\n private readonly _maxEvents: number;\n private _eventCount = 0;\n private _evictedCount = 0;\n\n constructor(sessionId: string, maxEvents = DEFAULT_MAX_EVENTS) {\n if (maxEvents <= 0) throw new Error(`maxEvents must be positive, got: ${maxEvents}`);\n this._sessionId = sessionId;\n this._maxEvents = maxEvents;\n }\n\n get sessionId(): string { return this._sessionId; }\n get maxEvents(): number { return this._maxEvents; }\n\n /** Total events appended (including evicted). */\n eventCount(): number { return this._eventCount; }\n\n /** Number of events evicted from the store. */\n evictedCount(): number { return this._evictedCount; }\n\n // ======================== EventStore Implementation ========================\n\n append(event: NetEvent): void {\n this._events.push(event);\n this._eventCount++;\n\n // Evict oldest when capacity exceeded\n while (this._events.length > this._maxEvents) {\n this._events.shift();\n this._evictedCount++;\n }\n\n // Broadcast to subscribers (microtask for async-like behavior)\n if (this._subscribers.size > 0) {\n // Use queueMicrotask instead of synchronous call to avoid blocking\n const subscribers = [...this._subscribers];\n queueMicrotask(() => {\n for (const sub of subscribers) {\n try {\n sub(event);\n } catch (e) {\n console.warn('Subscriber threw exception during event broadcast', e);\n }\n }\n });\n }\n }\n\n events(): readonly NetEvent[] {\n return this._events;\n }\n\n isEnabled(): boolean {\n return true;\n }\n\n size(): number {\n return this._events.length;\n }\n\n isEmpty(): boolean {\n return this._events.length === 0;\n }\n\n // ======================== Live Tailing ========================\n\n /** Subscribe to receive events as they occur. */\n subscribe(listener: (event: NetEvent) => void): Subscription {\n this._subscribers.add(listener);\n return {\n cancel: () => { this._subscribers.delete(listener); },\n isActive: () => this._subscribers.has(listener),\n };\n }\n\n /** Number of active subscribers. */\n subscriberCount(): number {\n return this._subscribers.size;\n }\n\n // ======================== Historical Replay ========================\n\n /** Returns events starting from a specific index. */\n eventsFrom(fromIndex: number): readonly NetEvent[] {\n const adjustedSkip = Math.max(0, fromIndex - this._evictedCount);\n if (adjustedSkip <= 0) return this._events;\n return this._events.slice(adjustedSkip);\n }\n\n /** Returns all events since the specified timestamp. */\n eventsSince(from: number): readonly NetEvent[] {\n return this._events.filter(e => e.timestamp >= from);\n }\n\n /** Returns events within a time range. */\n eventsBetween(from: number, to: number): readonly NetEvent[] {\n return this._events.filter(e => e.timestamp >= from && e.timestamp < to);\n }\n\n /**\n * Returns an iterator over all retained events.\n * Useful for archive writers that need zero-copy traversal.\n */\n [Symbol.iterator](): Iterator<NetEvent> {\n return this._events[Symbol.iterator]();\n }\n\n // ======================== Lifecycle ========================\n\n /** Close the store (no-op in JS, but matches Java interface). */\n close(): void {\n this._subscribers.clear();\n }\n}\n","/**\n * Metadata header for a session archive file.\n *\n * Discriminated union across format versions so callers can pattern-match on\n * `archive.version` to access v2-only fields with type narrowing:\n *\n * ```ts\n * const archive = reader.readMetadata(bytes);\n * if (archive.version === 2) {\n * console.log(archive.tags, archive.endTime, archive.metadata.hasErrors);\n * }\n * ```\n *\n * ## Version contract\n *\n * - **v1** (libpetri 1.5.x–1.6.x): original format. Header carries `sessionId`,\n * `netName`, `dotDiagram`, `startTime`, `eventCount`, and net `structure`.\n * - **v2** (libpetri 1.7.x): adds `endTime`, user-defined `tags`, and pre-computed\n * {@link SessionMetadata}. Events inside v2 archives use the legacy `toString`-based\n * token format — types are erased on disk.\n * - **v3** (libpetri 1.8.0+): same header shape as v2. Differs in the event body —\n * token values are serialized with a `structured` JSON payload in addition to the\n * legacy `value` string, so consumers that understand the original shape can\n * surface typed fields without parsing the `toString` form.\n *\n * The {@link SessionArchiveReader} peeks the `version` field via a lenient JSON\n * parse and dispatches to the correct concrete type. All three versions coexist\n * in the same storage bucket.\n */\nimport type { NetStructure } from '../debug-response.js';\n\n/** Common fields shared by v1 and v2 archive headers. */\ninterface SessionArchiveBase {\n readonly sessionId: string;\n readonly netName: string;\n readonly dotDiagram: string;\n /** ISO-8601 instant the session started. */\n readonly startTime: string;\n readonly eventCount: number;\n readonly structure: NetStructure;\n}\n\n/** Legacy v1 archive header (libpetri 1.5.x–1.6.x). */\nexport interface SessionArchiveV1 extends SessionArchiveBase {\n readonly version: 1;\n}\n\n/**\n * v2 archive header (libpetri 1.7.0+). Adds end time, tags, and pre-computed\n * metadata so listing tools and samplers can filter/aggregate without scanning\n * the event body.\n */\nexport interface SessionArchiveV2 extends SessionArchiveBase {\n readonly version: 2;\n /** ISO-8601 instant the session ended. Undefined for sessions archived while still active. */\n readonly endTime?: string;\n /** User-defined session tags (e.g., `{channel: \"voice\"}`). Always present; may be empty. */\n readonly tags: Readonly<Record<string, string>>;\n /** Pre-computed aggregate stats. Always present; `emptyMetadata()` for no-event sessions. */\n readonly metadata: SessionMetadata;\n}\n\n/**\n * v3 archive header (libpetri 1.8.0+). Structurally identical to `SessionArchiveV2`;\n * the version bump signals that the event body carries `structured` token payloads\n * alongside the legacy `value` string.\n */\nexport interface SessionArchiveV3 extends SessionArchiveBase {\n readonly version: 3;\n readonly endTime?: string;\n readonly tags: Readonly<Record<string, string>>;\n readonly metadata: SessionMetadata;\n}\n\n/**\n * Discriminated union of all supported archive header versions.\n *\n * Type-narrowing example:\n * ```ts\n * if (archive.version >= 2) {\n * // TS knows archive has tags / endTime / metadata here.\n * }\n * ```\n */\nexport type SessionArchive = SessionArchiveV1 | SessionArchiveV2 | SessionArchiveV3;\n\n/** Version written by default by {@link SessionArchiveWriter.write} (latest supported). */\nexport const CURRENT_VERSION = 3;\n\n/** Lowest version {@link SessionArchiveReader} can decode. */\nexport const MIN_SUPPORTED_VERSION = 1;\n\n/**\n * Pre-computed aggregate statistics attached to a v2 session archive header.\n *\n * Computed once during archive write by a single-pass scan of the event store.\n * Readers can answer `hasErrors`, histogram, and first/last timestamp queries\n * without iterating the event stream — enabling cheap triage, sampling, and\n * listing of many archives.\n *\n * For v1 archives (no pre-computed metadata), callers can recompute on-demand\n * via {@link computeMetadata}.\n */\nexport interface SessionMetadata {\n /**\n * Count of events per `NetEvent` subtype name (PascalCase, matching the\n * wire format used by `NetEventInfo.type` — e.g. `TransitionStarted -> 412`).\n * Keys are stored in alphabetical order for deterministic JSON output.\n */\n readonly eventTypeHistogram: Readonly<Record<string, number>>;\n /** ISO-8601 timestamp of the oldest event, or undefined if the session had no events. */\n readonly firstEventTime?: string;\n /** ISO-8601 timestamp of the newest event, or undefined if the session had no events. */\n readonly lastEventTime?: string;\n /**\n * True if the session contains at least one error-signal event\n * (`TransitionFailed`, `TransitionTimedOut`, `ActionTimedOut`, or\n * a `LogMessage` at level `ERROR`).\n */\n readonly hasErrors: boolean;\n}\n\n/** Returns a {@link SessionMetadata} with no data. Used as a default for empty sessions. */\nexport function emptyMetadata(): SessionMetadata {\n return { eventTypeHistogram: {}, hasErrors: false };\n}\n","/**\n * Analyze places for start/end/environment classification.\n * TypeScript port of Java's PlaceAnalysis.\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { Place } from '../core/place.js';\n\nexport interface PlaceAnalysisInfo {\n readonly tokenType: string;\n readonly hasIncoming: boolean;\n readonly hasOutgoing: boolean;\n}\n\nexport class PlaceAnalysis {\n private readonly _data: ReadonlyMap<string, PlaceAnalysisInfo>;\n\n constructor(data: ReadonlyMap<string, PlaceAnalysisInfo>) {\n this._data = data;\n }\n\n get data(): ReadonlyMap<string, PlaceAnalysisInfo> {\n return this._data;\n }\n\n isStart(placeName: string): boolean {\n const info = this._data.get(placeName);\n return info != null && !info.hasIncoming;\n }\n\n isEnd(placeName: string): boolean {\n const info = this._data.get(placeName);\n return info != null && !info.hasOutgoing;\n }\n\n /** Build place analysis from a PetriNet. */\n static from(net: PetriNet): PlaceAnalysis {\n const data = new Map<string, { tokenType: string; hasIncoming: boolean; hasOutgoing: boolean }>();\n\n function ensure(place: Place<unknown>): { tokenType: string; hasIncoming: boolean; hasOutgoing: boolean } {\n let info = data.get(place.name);\n if (!info) {\n info = { tokenType: 'unknown', hasIncoming: false, hasOutgoing: false };\n data.set(place.name, info);\n }\n return info;\n }\n\n for (const transition of net.transitions) {\n // Input arcs: place → transition (place has outgoing)\n for (const input of transition.inputSpecs) {\n const info = ensure((input as { place: Place<unknown> }).place);\n info.hasOutgoing = true;\n }\n\n // Output arcs: transition → place (place has incoming)\n if (transition.outputSpec) {\n const outputPlaces = collectOutputPlaces(transition.outputSpec);\n for (const place of outputPlaces) {\n const info = ensure(place);\n info.hasIncoming = true;\n }\n }\n\n // Inhibitor arcs: just ensure place exists\n for (const inh of transition.inhibitors) {\n ensure((inh as { place: Place<unknown> }).place);\n }\n\n // Read arcs: place has outgoing (read = test without consuming)\n for (const read of transition.reads) {\n const info = ensure((read as { place: Place<unknown> }).place);\n info.hasOutgoing = true;\n }\n\n // Reset arcs: just ensure place exists\n for (const reset of transition.resets) {\n ensure((reset as { place: Place<unknown> }).place);\n }\n }\n\n return new PlaceAnalysis(data as ReadonlyMap<string, PlaceAnalysisInfo>);\n }\n}\n\n/** Recursively collect all output places from an Out spec. */\nfunction collectOutputPlaces(out: unknown): Place<unknown>[] {\n const spec = out as { type: string; place?: Place<unknown>; children?: unknown[]; child?: unknown; from?: Place<unknown>; to?: Place<unknown> };\n switch (spec.type) {\n case 'place':\n return spec.place ? [spec.place] : [];\n case 'and':\n case 'xor':\n return (spec.children ?? []).flatMap(c => collectOutputPlaces(c));\n case 'timeout':\n return spec.child ? collectOutputPlaces(spec.child) : [];\n case 'forward-input':\n return spec.to ? [spec.to] : [];\n default:\n return [];\n }\n}\n","/**\n * Registry for managing Petri net debug sessions.\n * TypeScript port of Java's DebugSessionRegistry.\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { Transition } from '../core/transition.js';\nimport { dotExport } from '../export/dot-exporter.js';\nimport { sanitize } from '../export/petri-net-mapper.js';\nimport type { NetStructure, PlaceInfo, TransitionInfo } from './debug-response.js';\nimport { PlaceAnalysis } from './place-analysis.js';\nimport { DebugEventStore } from './debug-event-store.js';\nimport type { SessionCompletionListener } from './session-completion-listener.js';\n\nexport interface DebugSession {\n readonly sessionId: string;\n readonly netName: string;\n readonly dotDiagram: string;\n readonly places: PlaceAnalysis | null;\n readonly transitions: ReadonlySet<Transition>;\n readonly eventStore: DebugEventStore;\n readonly startTime: number;\n readonly active: boolean;\n readonly importedStructure: NetStructure | null;\n /** Stamped on first `complete()`. Undefined while the session is active. (libpetri 1.6.0+) */\n readonly endTime?: number;\n /**\n * Per-session tag storage, mutated in place by the registry. The reference is\n * readonly but the underlying object is not — prefer\n * {@link DebugSessionRegistry.tag}/{@link DebugSessionRegistry.tagsFor}\n * over direct access.\n */\n readonly tags: Record<string, string>;\n}\n\n/** Builds the net structure from a session's stored place and transition info. */\nexport function buildNetStructure(session: DebugSession): NetStructure {\n if (session.importedStructure) {\n return session.importedStructure;\n }\n\n const places = session.places;\n if (!places) {\n return { places: [], transitions: [] };\n }\n\n const placeInfos: PlaceInfo[] = [];\n for (const [name, info] of places.data) {\n placeInfos.push({\n name,\n graphId: `p_${sanitize(name)}`,\n tokenType: info.tokenType,\n isStart: !info.hasIncoming,\n isEnd: !info.hasOutgoing,\n isEnvironment: false,\n });\n }\n\n const transitionInfos: TransitionInfo[] = [];\n for (const t of session.transitions) {\n transitionInfos.push({\n name: t.name,\n graphId: `t_${sanitize(t.name)}`,\n });\n }\n\n return { places: placeInfos, transitions: transitionInfos };\n}\n\nexport type EventStoreFactory = (sessionId: string) => DebugEventStore;\n\nexport class DebugSessionRegistry {\n private readonly _sessions = new Map<string, DebugSession>();\n private readonly _maxSessions: number;\n private readonly _eventStoreFactory: EventStoreFactory;\n private readonly _completionListeners: readonly SessionCompletionListener[];\n\n constructor(\n maxSessions = 50,\n eventStoreFactory?: EventStoreFactory,\n completionListeners?: SessionCompletionListener[],\n ) {\n this._maxSessions = maxSessions;\n this._eventStoreFactory = eventStoreFactory ?? ((id: string) => new DebugEventStore(id));\n this._completionListeners = completionListeners ? [...completionListeners] : [];\n }\n\n /**\n * Registers a new debug session for the given Petri net.\n * Generates DOT diagram and extracts net structure.\n *\n * @param sessionId unique session id\n * @param net the Petri net being executed\n * @param tags optional user-defined tags (libpetri 1.6.0+) — e.g. `{channel: 'voice'}`\n */\n register(sessionId: string, net: PetriNet, tags?: Readonly<Record<string, string>>): DebugSession {\n const dotDiagram = dotExport(net);\n const places = PlaceAnalysis.from(net);\n const eventStore = this._eventStoreFactory(sessionId);\n\n const session: DebugSession = {\n sessionId,\n netName: net.name,\n dotDiagram,\n places,\n transitions: net.transitions,\n eventStore,\n startTime: Date.now(),\n active: true,\n importedStructure: null,\n tags: tags ? { ...tags } : {},\n };\n\n this.evictIfNecessary();\n this._sessions.set(sessionId, session);\n return session;\n }\n\n /**\n * Marks a session as completed (no longer active) and notifies completion listeners.\n *\n * <p>Stamps `endTime = Date.now()` on the first completion. Idempotent: subsequent\n * calls preserve the existing endTime. (libpetri 1.6.0+)\n */\n complete(sessionId: string): void {\n const session = this._sessions.get(sessionId);\n if (session) {\n const endTime = session.endTime ?? Date.now();\n // Spread preserves the same `tags` object reference, so any concurrent\n // tag() call via the old session still writes to the right storage.\n const completed: DebugSession = { ...session, active: false, endTime };\n this._sessions.set(sessionId, completed);\n this.notifyCompletionListeners(completed);\n }\n }\n\n /** Removes a session from the registry. Tags die with the session. */\n remove(sessionId: string): DebugSession | undefined {\n const removed = this._sessions.get(sessionId);\n if (removed) {\n this._sessions.delete(sessionId);\n removed.eventStore.close();\n }\n return removed;\n }\n\n /** Returns a session by ID. */\n getSession(sessionId: string): DebugSession | undefined {\n return this._sessions.get(sessionId);\n }\n\n /**\n * Sets or overwrites a single tag on a session. (libpetri 1.6.0+)\n *\n * Tags accumulate until the session is removed. Setting a key that already\n * exists replaces its value.\n *\n * If `sessionId` is not a currently-registered session the call is a no-op.\n * A tag write that races with {@link remove} is harmless — the write lands on\n * the now-orphaned session object and is garbage collected along with it.\n */\n tag(sessionId: string, key: string, value: string): void {\n const session = this._sessions.get(sessionId);\n if (!session) return;\n session.tags[key] = value;\n }\n\n /**\n * Returns a snapshot of the tags attached to a session. Returns an empty\n * object if the session has no tags or does not exist. (libpetri 1.6.0+)\n */\n tagsFor(sessionId: string): Readonly<Record<string, string>> {\n const session = this._sessions.get(sessionId);\n return session ? { ...session.tags } : {};\n }\n\n /** Lists sessions, ordered by start time (most recent first). */\n listSessions(limit: number, tagFilter?: Readonly<Record<string, string>>): readonly DebugSession[] {\n return [...this._sessions.values()]\n .filter(s => this.matchesTagFilter(s, tagFilter))\n .sort((a, b) => b.startTime - a.startTime)\n .slice(0, limit);\n }\n\n /** Lists only active sessions. */\n listActiveSessions(\n limit: number,\n tagFilter?: Readonly<Record<string, string>>,\n ): readonly DebugSession[] {\n return [...this._sessions.values()]\n .filter(s => s.active)\n .filter(s => this.matchesTagFilter(s, tagFilter))\n .sort((a, b) => b.startTime - a.startTime)\n .slice(0, limit);\n }\n\n /** Total number of sessions. */\n get size(): number {\n return this._sessions.size;\n }\n\n /**\n * Registers an imported (archived) session as an inactive, read-only session.\n *\n * @param endTime when the original session ended (libpetri 1.6.0+)\n * @param tags user-defined tags attached to the imported session (libpetri 1.6.0+)\n */\n registerImported(\n sessionId: string,\n netName: string,\n dotDiagram: string,\n structure: NetStructure,\n eventStore: DebugEventStore,\n startTime: number,\n endTime?: number,\n tags?: Readonly<Record<string, string>>,\n ): DebugSession {\n this.evictIfNecessary();\n\n const session: DebugSession = {\n sessionId,\n netName,\n dotDiagram,\n places: null,\n transitions: new Set(),\n eventStore,\n startTime,\n active: false,\n importedStructure: structure,\n endTime,\n tags: tags ? { ...tags } : {},\n };\n\n this._sessions.set(sessionId, session);\n return session;\n }\n\n /** AND-match: all filter entries must exactly match the session's tags. */\n private matchesTagFilter(\n session: DebugSession,\n filter: Readonly<Record<string, string>> | undefined,\n ): boolean {\n if (!filter) return true;\n const keys = Object.keys(filter);\n if (keys.length === 0) return true;\n const tags = session.tags;\n for (const key of keys) {\n if (tags[key] !== filter[key]) return false;\n }\n return true;\n }\n\n /** Notifies all completion listeners. Exceptions are caught and logged. */\n private notifyCompletionListeners(session: DebugSession): void {\n for (const listener of this._completionListeners) {\n try {\n listener(session);\n } catch (e) {\n console.warn(`Session completion listener failed for ${session.sessionId}`, e);\n }\n }\n }\n\n /** Evicts oldest inactive sessions if at capacity. */\n private evictIfNecessary(): void {\n if (this._sessions.size < this._maxSessions) return;\n\n const candidates = [...this._sessions.values()]\n .sort((a, b) => {\n // Inactive first, then oldest\n if (a.active !== b.active) return a.active ? 1 : -1;\n return a.startTime - b.startTime;\n });\n\n for (const candidate of candidates) {\n if (this._sessions.size < this._maxSessions) break;\n const evicted = this._sessions.get(candidate.sessionId);\n if (evicted) {\n this._sessions.delete(candidate.sessionId);\n evicted.eventStore.close();\n }\n }\n }\n}\n","/**\n * Caches computed state snapshots at periodic intervals for efficient seek/step.\n * TypeScript port of Java's MarkingCache.\n */\n\nimport type { NetEvent } from '../event/net-event.js';\nimport type { TokenInfo } from './debug-response.js';\nimport { computeState, applyEvents, toImmutableState, type ComputedState } from './debug-protocol-handler.js';\n\n/** Number of events between cached snapshots. */\nexport const SNAPSHOT_INTERVAL = 256;\n\nexport class MarkingCache {\n private readonly _snapshots: ComputedState[] = [];\n\n /**\n * Computes the state at the given event index, using cached snapshots\n * to minimize the number of events that need to be replayed.\n *\n * @param events the full event list for the session\n * @param targetIndex event index to compute state at (exclusive upper bound)\n */\n computeAt(events: readonly NetEvent[], targetIndex: number): ComputedState {\n if (targetIndex <= 0) {\n return computeState([]);\n }\n\n this.ensureCachedUpTo(events, targetIndex);\n\n if (this._snapshots.length === 0) {\n return computeState(events.slice(0, targetIndex));\n }\n\n // Find highest snapshot <= targetIndex\n const snapshotSlot = Math.min(Math.floor(targetIndex / SNAPSHOT_INTERVAL), this._snapshots.length) - 1;\n\n if (snapshotSlot < 0) {\n return computeState(events.slice(0, targetIndex));\n }\n\n const snapshotEventIndex = (snapshotSlot + 1) * SNAPSHOT_INTERVAL;\n\n if (snapshotEventIndex === targetIndex) {\n return this._snapshots[snapshotSlot]!;\n }\n\n return replayDelta(this._snapshots[snapshotSlot]!, events.slice(snapshotEventIndex, targetIndex));\n }\n\n /** Invalidates the cache. */\n invalidate(): void {\n this._snapshots.length = 0;\n }\n\n /** Extends the snapshot cache to cover at least up to the given event index. */\n private ensureCachedUpTo(events: readonly NetEvent[], targetIndex: number): void {\n const neededSnapshots = Math.floor(targetIndex / SNAPSHOT_INTERVAL);\n\n while (this._snapshots.length < neededSnapshots) {\n const nextSnapshotIndex = (this._snapshots.length + 1) * SNAPSHOT_INTERVAL;\n if (nextSnapshotIndex > events.length) break;\n\n if (this._snapshots.length === 0) {\n this._snapshots.push(computeState(events.slice(0, nextSnapshotIndex)));\n } else {\n const prevSnapshotIndex = this._snapshots.length * SNAPSHOT_INTERVAL;\n const delta = events.slice(prevSnapshotIndex, nextSnapshotIndex);\n this._snapshots.push(replayDelta(this._snapshots[this._snapshots.length - 1]!, delta));\n }\n }\n }\n}\n\n/** Replays delta events on top of a base snapshot to produce a new state. */\nfunction replayDelta(base: ComputedState, delta: readonly NetEvent[]): ComputedState {\n const marking = new Map<string, TokenInfo[]>();\n for (const [key, value] of base.marking) {\n marking.set(key, [...value]);\n }\n const enabled = new Set(base.enabledTransitions);\n const inFlight = new Set(base.inFlightTransitions);\n applyEvents(marking, enabled, inFlight, delta);\n return toImmutableState(marking, enabled, inFlight);\n}\n","/**\n * Converts CTPN NetEvent instances to serializable DebugResponse types.\n * TypeScript port of Java's NetEventConverter.\n */\n\nimport type { Token } from '../core/token.js';\nimport type { NetEvent } from '../event/net-event.js';\nimport type { NetEventInfo, TokenInfo } from './debug-response.js';\n\n/** Converts a NetEvent to a serializable NetEventInfo. */\nexport function toEventInfo(event: NetEvent, compact = false): NetEventInfo {\n switch (event.type) {\n case 'execution-started':\n return {\n type: 'ExecutionStarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: { netName: event.netName, executionId: event.executionId },\n };\n\n case 'execution-completed':\n return {\n type: 'ExecutionCompleted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: {\n netName: event.netName,\n executionId: event.executionId,\n totalDurationMs: event.totalDurationMs,\n },\n };\n\n case 'transition-enabled':\n return {\n type: 'TransitionEnabled',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {},\n };\n\n case 'transition-clock-restarted':\n return {\n type: 'TransitionClockRestarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {},\n };\n\n case 'transition-started':\n return {\n type: 'TransitionStarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n consumedTokens: event.consumedTokens.map(t => compact ? compactTokenInfo(t) : tokenInfo(t)),\n },\n };\n\n case 'transition-completed':\n return {\n type: 'TransitionCompleted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n producedTokens: event.producedTokens.map(t => compact ? compactTokenInfo(t) : tokenInfo(t)),\n durationMs: event.durationMs,\n },\n };\n\n case 'transition-failed':\n return {\n type: 'TransitionFailed',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n errorMessage: event.errorMessage,\n exceptionType: event.exceptionType,\n },\n };\n\n case 'transition-timed-out':\n return {\n type: 'TransitionTimedOut',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n deadlineMs: event.deadlineMs,\n actualDurationMs: event.actualDurationMs,\n },\n };\n\n case 'action-timed-out':\n return {\n type: 'ActionTimedOut',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: { timeoutMs: event.timeoutMs },\n };\n\n case 'token-added':\n return {\n type: 'TokenAdded',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: event.placeName,\n details: {\n token: compact ? compactTokenInfo(event.token) : tokenInfo(event.token),\n },\n };\n\n case 'token-removed':\n return {\n type: 'TokenRemoved',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: event.placeName,\n details: {\n token: compact ? compactTokenInfo(event.token) : tokenInfo(event.token),\n },\n };\n\n case 'marking-snapshot':\n return {\n type: 'MarkingSnapshot',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: {\n marking: convertMarking(event.marking, compact),\n },\n };\n\n case 'log-message': {\n const details: Record<string, unknown> = {\n loggerName: event.logger,\n level: event.level,\n message: event.message,\n };\n if (event.error != null) details['throwable'] = event.error;\n if (event.errorMessage != null) details['throwableMessage'] = event.errorMessage;\n return {\n type: 'LogMessage',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details,\n };\n }\n }\n}\n\n/**\n * Converts a Token to a serializable {@link TokenInfo}.\n *\n * @remarks\n * The emitted `type` is `value.constructor.name` for objects and `typeof value`\n * for primitives — a *simple name*, not a fully-qualified type identifier.\n * TypeScript has no portable FQN, so cross-language replay from TypeScript\n * archives into a Java reader loses the original type identity (Java's\n * `Class.forName` will fail on simple names) and falls through to the\n * `Token<JsonNode>` graceful-degradation path. The `structured` payload\n * survives intact across languages.\n *\n * The v3 archive body format described in [EVT-025](../../../spec/08-events-observability.md)\n * always emits `structured` alongside `value` so the bundled debug UI keeps\n * rendering while LLM-facing consumers get typed fields. See {@link structuredValue}\n * for the projection rules.\n */\nexport function tokenInfo(token: Token<unknown>): TokenInfo {\n const value = token.value;\n const type = value != null ? typeof value === 'object' ? value.constructor.name : typeof value : 'null';\n const fullValue = value != null ? String(value) : 'null';\n const info: TokenInfo = {\n id: null,\n type,\n value: fullValue,\n timestamp: new Date(token.createdAt).toISOString(),\n };\n const structured = structuredValue(value);\n return structured === undefined ? info : { ...info, structured };\n}\n\n/**\n * Projects a token value into a JSON-friendly representation for the `structured`\n * TokenInfo field. Returns `undefined` when no useful projection exists (null values,\n * opaque objects Jackson-on-the-Java-side would drop); callers omit the field in that\n * case so wire size stays neutral for unstructurable tokens.\n *\n * @remarks\n * Implementation notes:\n * - Primitives and plain objects / arrays pass through untouched (already JSON-safe).\n * - Maps / Sets are projected to a plain shape — debug tooling doesn't need the\n * prototype identity and JSON consumers can't use it anyway.\n * - Classes with a `toJSON()` method are respected via structured clone (uses the\n * same path as `JSON.stringify`).\n *\n * Security: uses `JSON.parse(JSON.stringify(...))` which is safe against code\n * execution and prototype pollution. A hostile token value with a custom\n * `toJSON()` override could still return misleading data — archives are a\n * trust boundary (see [EVT-025](../../../spec/08-events-observability.md)).\n */\nfunction structuredValue(value: unknown): unknown | undefined {\n if (value == null) return undefined;\n const t = typeof value;\n if (t === 'string' || t === 'number' || t === 'boolean') return value;\n if (t === 'bigint') return String(value); // bigint → string for JSON-safety\n if (t === 'symbol' || t === 'function') return undefined;\n // Plain arrays / plain objects / objects with toJSON — JSON.parse(JSON.stringify(...))\n // is the cheapest way to drop non-serializable fields and flatten to wire-ready shape.\n try {\n const cloned = JSON.parse(JSON.stringify(value));\n // Skip empty objects — they're opaque beans with no useful structure, just inflating responses.\n if (cloned && typeof cloned === 'object' && !Array.isArray(cloned) && Object.keys(cloned).length === 0) {\n return undefined;\n }\n return cloned;\n } catch {\n return undefined;\n }\n}\n\n/** Converts a Token to compact TokenInfo (type only, no value). */\nexport function compactTokenInfo(token: Token<unknown>): TokenInfo {\n const value = token.value;\n const type = value != null ? typeof value === 'object' ? value.constructor.name : typeof value : 'null';\n return {\n id: null,\n type,\n value: null,\n timestamp: new Date(token.createdAt).toISOString(),\n };\n}\n\n/** Converts a marking map to serializable form. */\nexport function convertMarking(\n marking: ReadonlyMap<string, readonly Token<unknown>[]>,\n compact = false,\n): Record<string, readonly TokenInfo[]> {\n const result: Record<string, readonly TokenInfo[]> = {};\n const mapper = compact ? compactTokenInfo : tokenInfo;\n for (const [name, tokens] of marking) {\n result[name] = tokens.map(mapper);\n }\n return result;\n}\n","/**\n * Framework-agnostic handler for the Petri net debug protocol.\n * TypeScript port of Java's DebugProtocolHandler.\n *\n * Manages debug subscriptions, event filtering, breakpoints, and replay\n * for connected clients. Decoupled from any specific WebSocket framework\n * via the ResponseSink type.\n */\n\nimport type { NetEvent } from '../event/net-event.js';\nimport type { DebugCommand, EventFilter, BreakpointConfig } from './debug-command.js';\nimport type { DebugResponse, TokenInfo, NetEventInfo, ArchiveSummary, SessionSummary } from './debug-response.js';\nimport type { SessionArchiveStorage } from './archive/session-archive-storage.js';\nimport { SessionArchiveReader } from './archive/session-archive-reader.js';\nimport type { DebugSession } from './debug-session-registry.js';\nimport { type DebugSessionRegistry, buildNetStructure } from './debug-session-registry.js';\nimport type { Subscription } from './debug-event-store.js';\nimport { MarkingCache } from './marking-cache.js';\nimport { toEventInfo, tokenInfo, convertMarking } from './net-event-converter.js';\n\n/** Callback for sending responses to a connected client. */\nexport type ResponseSink = (response: DebugResponse) => void;\n\n/** Computed state from replaying events. */\nexport interface ComputedState {\n readonly marking: ReadonlyMap<string, readonly TokenInfo[]>;\n readonly enabledTransitions: readonly string[];\n readonly inFlightTransitions: readonly string[];\n}\n\n/** Maximum events per batch when sending historical events. */\nconst BATCH_SIZE = 500;\n\nexport class DebugProtocolHandler {\n private readonly _sessionRegistry: DebugSessionRegistry;\n private readonly _archiveStorage: SessionArchiveStorage | null;\n private readonly _clients = new Map<string, ClientState>();\n\n constructor(sessionRegistry: DebugSessionRegistry, archiveStorage?: SessionArchiveStorage | null) {\n this._sessionRegistry = sessionRegistry;\n this._archiveStorage = archiveStorage ?? null;\n }\n\n /** Registers a new client connection. */\n clientConnected(clientId: string, sink: ResponseSink): void {\n this._clients.set(clientId, new ClientState(sink));\n }\n\n /** Cleans up when a client disconnects. */\n clientDisconnected(clientId: string): void {\n const state = this._clients.get(clientId);\n this._clients.delete(clientId);\n if (state) state.subscriptions.cancelAll();\n }\n\n /** Handles a command from a connected client. */\n handleCommand(clientId: string, command: DebugCommand): void {\n const clientState = this._clients.get(clientId);\n if (!clientState) return;\n\n try {\n switch (command.type) {\n case 'listSessions': this.handleListSessions(clientState, command); break;\n case 'subscribe': this.handleSubscribe(clientState, command); break;\n case 'unsubscribe': this.handleUnsubscribe(clientState, command); break;\n case 'seek': this.handleSeek(clientState, command); break;\n case 'playbackSpeed': this.handlePlaybackSpeed(clientState, command); break;\n case 'filter': this.handleSetFilter(clientState, command); break;\n case 'pause': this.handlePause(clientState, command); break;\n case 'resume': this.handleResume(clientState, command); break;\n case 'stepForward': this.handleStepForward(clientState, command); break;\n case 'stepBackward': this.handleStepBackward(clientState, command); break;\n case 'setBreakpoint': this.handleSetBreakpoint(clientState, command); break;\n case 'clearBreakpoint': this.handleClearBreakpoint(clientState, command); break;\n case 'listBreakpoints': this.handleListBreakpoints(clientState, command); break;\n case 'listArchives': this.handleListArchives(clientState, command); break;\n case 'importArchive': this.handleImportArchive(clientState, command); break;\n case 'uploadArchive': this.handleUploadArchive(clientState, command); break;\n }\n } catch (e) {\n this.sendError(clientState, 'COMMAND_ERROR', e instanceof Error ? e.message : String(e), null);\n }\n }\n\n // ======================== Command Handlers ========================\n\n private handleListSessions(client: ClientState, cmd: Extract<DebugCommand, { type: 'listSessions' }>): void {\n const limit = cmd.limit ?? 50;\n const sessions = cmd.activeOnly\n ? this._sessionRegistry.listActiveSessions(limit, cmd.tagFilter)\n : this._sessionRegistry.listSessions(limit, cmd.tagFilter);\n\n const summaries = sessions.map(s => this.toProtocolSummary(s));\n\n this.send(client, { type: 'sessionList', sessions: summaries });\n }\n\n private toProtocolSummary(s: DebugSession): SessionSummary {\n const tags = this._sessionRegistry.tagsFor(s.sessionId);\n return {\n sessionId: s.sessionId,\n netName: s.netName,\n startTime: new Date(s.startTime).toISOString(),\n active: s.active,\n eventCount: s.eventStore.eventCount(),\n tags: Object.keys(tags).length > 0 ? tags : undefined,\n endTime: s.endTime !== undefined ? new Date(s.endTime).toISOString() : undefined,\n durationMs: s.endTime !== undefined ? s.endTime - s.startTime : undefined,\n };\n }\n\n private handleSubscribe(client: ClientState, cmd: Extract<DebugCommand, { type: 'subscribe' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n const eventStore = debugSession.eventStore;\n client.subscriptions.cancel(cmd.sessionId);\n\n const events = eventStore.events();\n const computed = computeState(events);\n const structure = buildNetStructure(debugSession);\n\n this.send(client, {\n type: 'subscribed',\n sessionId: cmd.sessionId,\n netName: debugSession.netName,\n dotDiagram: debugSession.dotDiagram,\n structure,\n currentMarking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n eventCount: eventStore.eventCount(),\n mode: cmd.mode,\n });\n\n const fromIndex = cmd.fromIndex ?? 0;\n if (cmd.mode === 'live') {\n this.subscribeLive(client, cmd.sessionId, debugSession, fromIndex);\n } else {\n this.subscribeReplay(client, cmd.sessionId, debugSession, fromIndex);\n }\n }\n\n private subscribeLive(client: ClientState, sessionId: string, debugSession: DebugSession, fromIndex: number): void {\n const eventStore = debugSession.eventStore;\n let eventIndex = fromIndex;\n\n const historicalEvents = eventStore.eventsFrom(fromIndex);\n if (historicalEvents.length > 0) {\n const filtered = historicalEvents\n .filter(e => client.subscriptions.matchesFilter(sessionId, e))\n .map(e => toEventInfo(e));\n this.sendInBatches(client, sessionId, fromIndex, filtered);\n eventIndex = fromIndex + historicalEvents.length;\n }\n\n const subscription = eventStore.subscribe(event => {\n if (!client.subscriptions.isPaused(sessionId) && client.subscriptions.matchesFilter(sessionId, event)) {\n const eventInfo = toEventInfo(event);\n const idx = eventIndex++;\n\n const hitBreakpoint = client.subscriptions.checkBreakpoints(sessionId, event);\n if (hitBreakpoint) {\n client.subscriptions.setPaused(sessionId, true);\n this.send(client, {\n type: 'breakpointHit',\n sessionId,\n breakpointId: hitBreakpoint.id,\n event: eventInfo,\n eventIndex: idx,\n });\n }\n\n this.send(client, { type: 'event', sessionId, index: idx, event: eventInfo });\n }\n });\n\n client.subscriptions.addSubscription(sessionId, subscription, eventIndex);\n }\n\n private subscribeReplay(client: ClientState, sessionId: string, debugSession: DebugSession, fromIndex: number): void {\n const eventStore = debugSession.eventStore;\n\n const events = eventStore.eventsFrom(fromIndex);\n const converted = events.map(e => toEventInfo(e));\n this.sendInBatches(client, sessionId, fromIndex, converted);\n\n const eventIndex = fromIndex + events.length;\n client.subscriptions.addSubscription(sessionId, null, eventIndex);\n client.subscriptions.setPaused(sessionId, true);\n }\n\n private handleUnsubscribe(client: ClientState, cmd: Extract<DebugCommand, { type: 'unsubscribe' }>): void {\n client.subscriptions.cancel(cmd.sessionId);\n this.send(client, { type: 'unsubscribed', sessionId: cmd.sessionId });\n }\n\n private handleSeek(client: ClientState, cmd: Extract<DebugCommand, { type: 'seek' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', 'Session not found', cmd.sessionId);\n return;\n }\n\n const events = debugSession.eventStore.events();\n const targetTs = new Date(cmd.timestamp).getTime();\n\n let targetIndex = 0;\n for (let i = 0; i < events.length; i++) {\n if (events[i]!.timestamp >= targetTs) {\n targetIndex = i;\n break;\n }\n targetIndex = i + 1;\n }\n\n client.subscriptions.setEventIndex(cmd.sessionId, targetIndex);\n const computed = client.subscriptions.computeStateAt(cmd.sessionId, events, targetIndex);\n\n this.send(client, {\n type: 'markingSnapshot',\n sessionId: cmd.sessionId,\n marking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n });\n }\n\n private handlePlaybackSpeed(client: ClientState, cmd: Extract<DebugCommand, { type: 'playbackSpeed' }>): void {\n client.subscriptions.setSpeed(cmd.sessionId, cmd.speed);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: client.subscriptions.isPaused(cmd.sessionId),\n speed: cmd.speed,\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleSetFilter(client: ClientState, cmd: Extract<DebugCommand, { type: 'filter' }>): void {\n client.subscriptions.setFilter(cmd.sessionId, cmd.filter);\n this.send(client, { type: 'filterApplied', sessionId: cmd.sessionId, filter: cmd.filter });\n }\n\n private handlePause(client: ClientState, cmd: Extract<DebugCommand, { type: 'pause' }>): void {\n client.subscriptions.setPaused(cmd.sessionId, true);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: true,\n speed: client.subscriptions.getSpeed(cmd.sessionId),\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleResume(client: ClientState, cmd: Extract<DebugCommand, { type: 'resume' }>): void {\n client.subscriptions.setPaused(cmd.sessionId, false);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: false,\n speed: client.subscriptions.getSpeed(cmd.sessionId),\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleStepForward(client: ClientState, cmd: Extract<DebugCommand, { type: 'stepForward' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n const events = debugSession.eventStore.events();\n const currentIndex = client.subscriptions.getEventIndex(cmd.sessionId);\n\n if (currentIndex < events.length) {\n const event = events[currentIndex]!;\n this.send(client, {\n type: 'event',\n sessionId: cmd.sessionId,\n index: currentIndex,\n event: toEventInfo(event),\n });\n client.subscriptions.setEventIndex(cmd.sessionId, currentIndex + 1);\n }\n }\n\n private handleStepBackward(client: ClientState, cmd: Extract<DebugCommand, { type: 'stepBackward' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n let currentIndex = client.subscriptions.getEventIndex(cmd.sessionId);\n if (currentIndex > 0) {\n currentIndex--;\n client.subscriptions.setEventIndex(cmd.sessionId, currentIndex);\n\n const events = debugSession.eventStore.events();\n const computed = client.subscriptions.computeStateAt(cmd.sessionId, events, currentIndex);\n\n this.send(client, {\n type: 'markingSnapshot',\n sessionId: cmd.sessionId,\n marking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n });\n }\n }\n\n private handleSetBreakpoint(client: ClientState, cmd: Extract<DebugCommand, { type: 'setBreakpoint' }>): void {\n client.subscriptions.addBreakpoint(cmd.sessionId, cmd.breakpoint);\n this.send(client, { type: 'breakpointSet', sessionId: cmd.sessionId, breakpoint: cmd.breakpoint });\n }\n\n private handleClearBreakpoint(client: ClientState, cmd: Extract<DebugCommand, { type: 'clearBreakpoint' }>): void {\n client.subscriptions.removeBreakpoint(cmd.sessionId, cmd.breakpointId);\n this.send(client, { type: 'breakpointCleared', sessionId: cmd.sessionId, breakpointId: cmd.breakpointId });\n }\n\n private handleListBreakpoints(client: ClientState, cmd: Extract<DebugCommand, { type: 'listBreakpoints' }>): void {\n const breakpoints = client.subscriptions.getBreakpoints(cmd.sessionId);\n this.send(client, { type: 'breakpointList', sessionId: cmd.sessionId, breakpoints });\n }\n\n // ======================== Archive Handlers ========================\n\n private async handleListArchives(client: ClientState, cmd: Extract<DebugCommand, { type: 'listArchives' }>): Promise<void> {\n if (!this._archiveStorage || !this._archiveStorage.isAvailable()) {\n this.send(client, { type: 'archiveList', archives: [], storageAvailable: false });\n return;\n }\n try {\n const limit = cmd.limit ?? 50;\n const archived = await this._archiveStorage.list(limit, cmd.prefix);\n const summaries: ArchiveSummary[] = archived.map(a => ({\n sessionId: a.sessionId,\n key: a.key,\n sizeBytes: a.sizeBytes,\n lastModified: new Date(a.lastModified).toISOString(),\n }));\n this.send(client, { type: 'archiveList', archives: summaries, storageAvailable: true });\n } catch (e) {\n this.sendError(client, 'ARCHIVE_LIST_ERROR', e instanceof Error ? e.message : String(e), null);\n }\n }\n\n private async handleImportArchive(client: ClientState, cmd: Extract<DebugCommand, { type: 'importArchive' }>): Promise<void> {\n if (!this._archiveStorage || !this._archiveStorage.isAvailable()) {\n this.sendError(client, 'NO_ARCHIVE_STORAGE', 'Archive storage is not configured', null);\n return;\n }\n try {\n const data = await this._archiveStorage.retrieve(cmd.sessionId);\n const reader = new SessionArchiveReader();\n const imported = reader.readFull(data);\n const meta = imported.metadata;\n this._sessionRegistry.registerImported(\n meta.sessionId, meta.netName, meta.dotDiagram,\n meta.structure, imported.eventStore,\n new Date(meta.startTime).getTime(),\n );\n this.send(client, {\n type: 'archiveImported',\n sessionId: meta.sessionId,\n netName: meta.netName,\n eventCount: meta.eventCount,\n });\n this.broadcastSessionList();\n } catch (e) {\n this.sendError(client, 'ARCHIVE_IMPORT_ERROR', e instanceof Error ? e.message : String(e), cmd.sessionId);\n }\n }\n\n private async handleUploadArchive(client: ClientState, cmd: Extract<DebugCommand, { type: 'uploadArchive' }>): Promise<void> {\n try {\n const decoded = Buffer.from(cmd.data, 'base64');\n const reader = new SessionArchiveReader();\n const imported = reader.readFull(decoded);\n const meta = imported.metadata;\n this._sessionRegistry.registerImported(\n meta.sessionId, meta.netName, meta.dotDiagram,\n meta.structure, imported.eventStore,\n new Date(meta.startTime).getTime(),\n );\n this.send(client, {\n type: 'archiveImported',\n sessionId: meta.sessionId,\n netName: meta.netName,\n eventCount: meta.eventCount,\n });\n this.broadcastSessionList();\n } catch (e) {\n this.sendError(client, 'ARCHIVE_UPLOAD_ERROR', e instanceof Error ? e.message : String(e), null);\n }\n }\n\n private broadcastSessionList(): void {\n const sessions = this._sessionRegistry.listSessions(50);\n const summaries = sessions.map(s => this.toProtocolSummary(s));\n const response: DebugResponse = { type: 'sessionList', sessions: summaries };\n for (const clientState of this._clients.values()) {\n try { this.send(clientState, response); } catch { /* best-effort broadcast */ }\n }\n }\n\n // ======================== Helper Methods ========================\n\n private send(client: ClientState, response: DebugResponse): void {\n client.sink(response);\n }\n\n private sendError(client: ClientState, code: string, message: string, sessionId: string | null): void {\n this.send(client, { type: 'error', code, message, sessionId });\n }\n\n private sendInBatches(client: ClientState, sessionId: string, startIndex: number, events: readonly NetEventInfo[]): void {\n if (events.length === 0) {\n this.send(client, { type: 'eventBatch', sessionId, startIndex, events: [], hasMore: false });\n return;\n }\n for (let i = 0; i < events.length; i += BATCH_SIZE) {\n const end = Math.min(i + BATCH_SIZE, events.length);\n const chunk = events.slice(i, end);\n const hasMore = end < events.length;\n this.send(client, { type: 'eventBatch', sessionId, startIndex: startIndex + i, events: chunk, hasMore });\n }\n }\n}\n\n// ======================== State Computation (exported for MarkingCache) ========================\n\n/** Computes marking, enabled transitions, and in-flight transitions from events. */\nexport function computeState(events: readonly NetEvent[]): ComputedState {\n const marking = new Map<string, TokenInfo[]>();\n const enabled = new Set<string>();\n const inFlight = new Set<string>();\n applyEvents(marking, enabled, inFlight, events);\n return toImmutableState(marking, enabled, inFlight);\n}\n\n/** Applies events to mutable accumulator collections. */\nexport function applyEvents(\n marking: Map<string, TokenInfo[]>,\n enabled: Set<string>,\n inFlight: Set<string>,\n events: readonly NetEvent[],\n): void {\n for (const event of events) {\n switch (event.type) {\n case 'token-added': {\n let tokens = marking.get(event.placeName);\n if (!tokens) {\n tokens = [];\n marking.set(event.placeName, tokens);\n }\n tokens.push(tokenInfo(event.token));\n break;\n }\n case 'token-removed': {\n const tokens = marking.get(event.placeName);\n if (tokens && tokens.length > 0) tokens.shift();\n break;\n }\n case 'marking-snapshot': {\n marking.clear();\n const converted = convertMarking(event.marking);\n for (const [key, value] of Object.entries(converted)) {\n marking.set(key, [...value]);\n }\n break;\n }\n case 'transition-enabled':\n enabled.add(event.transitionName);\n break;\n case 'transition-started':\n enabled.delete(event.transitionName);\n inFlight.add(event.transitionName);\n break;\n case 'transition-completed':\n inFlight.delete(event.transitionName);\n break;\n case 'transition-failed':\n inFlight.delete(event.transitionName);\n break;\n case 'transition-timed-out':\n inFlight.delete(event.transitionName);\n break;\n case 'action-timed-out':\n inFlight.delete(event.transitionName);\n break;\n default:\n break;\n }\n }\n}\n\n/** Converts mutable accumulator collections into an immutable ComputedState. */\nexport function toImmutableState(\n marking: Map<string, TokenInfo[]>,\n enabled: Set<string>,\n inFlight: Set<string>,\n): ComputedState {\n const resultMarking = new Map<string, readonly TokenInfo[]>();\n for (const [key, value] of marking) {\n resultMarking.set(key, [...value]);\n }\n return {\n marking: resultMarking,\n enabledTransitions: [...enabled],\n inFlightTransitions: [...inFlight],\n };\n}\n\n/** Convert Map to Record for JSON serialization. */\nfunction mapToRecord(map: ReadonlyMap<string, readonly TokenInfo[]>): Record<string, readonly TokenInfo[]> {\n const result: Record<string, readonly TokenInfo[]> = {};\n for (const [key, value] of map) {\n result[key] = value;\n }\n return result;\n}\n\n// ======================== Client State ========================\n\nclass ClientState {\n readonly sink: ResponseSink;\n readonly subscriptions = new SubscriptionState();\n\n constructor(sink: ResponseSink) {\n this.sink = sink;\n }\n}\n\n// ======================== Subscription State ========================\n\ninterface SessionSubscription {\n subscription: Subscription | null;\n eventIndex: number;\n markingCache: MarkingCache;\n breakpoints: Map<string, BreakpointConfig>;\n paused: boolean;\n speed: number;\n filter: EventFilter | null;\n}\n\nclass SubscriptionState {\n private readonly _sessionSubs = new Map<string, SessionSubscription>();\n\n addSubscription(sessionId: string, subscription: Subscription | null, eventIndex: number): void {\n this._sessionSubs.set(sessionId, {\n subscription,\n eventIndex,\n markingCache: new MarkingCache(),\n breakpoints: new Map(),\n paused: false,\n speed: 1.0,\n filter: null,\n });\n }\n\n cancel(sessionId: string): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub?.subscription) sub.subscription.cancel();\n this._sessionSubs.delete(sessionId);\n }\n\n cancelAll(): void {\n for (const sub of this._sessionSubs.values()) {\n if (sub.subscription) sub.subscription.cancel();\n }\n this._sessionSubs.clear();\n }\n\n isPaused(sessionId: string): boolean {\n return this._sessionSubs.get(sessionId)?.paused ?? false;\n }\n\n setPaused(sessionId: string, paused: boolean): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.paused = paused;\n }\n\n getSpeed(sessionId: string): number {\n return this._sessionSubs.get(sessionId)?.speed ?? 1.0;\n }\n\n setSpeed(sessionId: string, speed: number): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.speed = speed;\n }\n\n getEventIndex(sessionId: string): number {\n return this._sessionSubs.get(sessionId)?.eventIndex ?? 0;\n }\n\n setEventIndex(sessionId: string, index: number): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.eventIndex = index;\n }\n\n computeStateAt(sessionId: string, events: readonly NetEvent[], targetIndex: number): ComputedState {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) return sub.markingCache.computeAt(events, targetIndex);\n return computeState(events.slice(0, targetIndex));\n }\n\n setFilter(sessionId: string, filter: EventFilter): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.filter = filter;\n }\n\n matchesFilter(sessionId: string, event: NetEvent): boolean {\n const sub = this._sessionSubs.get(sessionId);\n if (!sub?.filter) return true;\n\n const filter = sub.filter;\n\n // Event type: include then exclude\n const eventType = eventTypeToName(event);\n if (filter.eventTypes && filter.eventTypes.length > 0) {\n if (!filter.eventTypes.includes(eventType)) return false;\n }\n if (filter.excludeEventTypes && filter.excludeEventTypes.length > 0) {\n if (filter.excludeEventTypes.includes(eventType)) return false;\n }\n\n // Transition name: extract once, include then exclude\n const needTransition = (filter.transitionNames && filter.transitionNames.length > 0)\n || (filter.excludeTransitionNames && filter.excludeTransitionNames.length > 0);\n if (needTransition) {\n const tn = extractTransitionName(event);\n if (filter.transitionNames && filter.transitionNames.length > 0) {\n if (!tn || !filter.transitionNames.includes(tn)) return false;\n }\n if (filter.excludeTransitionNames && filter.excludeTransitionNames.length > 0) {\n if (tn && filter.excludeTransitionNames.includes(tn)) return false;\n }\n }\n\n // Place name: extract once, include then exclude\n const needPlace = (filter.placeNames && filter.placeNames.length > 0)\n || (filter.excludePlaceNames && filter.excludePlaceNames.length > 0);\n if (needPlace) {\n const pn = extractPlaceName(event);\n if (filter.placeNames && filter.placeNames.length > 0) {\n if (!pn || !filter.placeNames.includes(pn)) return false;\n }\n if (filter.excludePlaceNames && filter.excludePlaceNames.length > 0) {\n if (pn && filter.excludePlaceNames.includes(pn)) return false;\n }\n }\n\n return true;\n }\n\n addBreakpoint(sessionId: string, breakpoint: BreakpointConfig): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.breakpoints.set(breakpoint.id, breakpoint);\n }\n\n removeBreakpoint(sessionId: string, breakpointId: string): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.breakpoints.delete(breakpointId);\n }\n\n getBreakpoints(sessionId: string): readonly BreakpointConfig[] {\n const sub = this._sessionSubs.get(sessionId);\n return sub ? [...sub.breakpoints.values()] : [];\n }\n\n checkBreakpoints(sessionId: string, event: NetEvent): BreakpointConfig | null {\n const sub = this._sessionSubs.get(sessionId);\n if (!sub || sub.breakpoints.size === 0) return null;\n\n for (const bp of sub.breakpoints.values()) {\n if (!bp.enabled) continue;\n if (matchesBreakpoint(bp, event)) return bp;\n }\n return null;\n }\n}\n\nfunction eventTypeToName(event: NetEvent): string {\n const map: Record<string, string> = {\n 'execution-started': 'ExecutionStarted',\n 'execution-completed': 'ExecutionCompleted',\n 'transition-enabled': 'TransitionEnabled',\n 'transition-clock-restarted': 'TransitionClockRestarted',\n 'transition-started': 'TransitionStarted',\n 'transition-completed': 'TransitionCompleted',\n 'transition-failed': 'TransitionFailed',\n 'transition-timed-out': 'TransitionTimedOut',\n 'action-timed-out': 'ActionTimedOut',\n 'token-added': 'TokenAdded',\n 'token-removed': 'TokenRemoved',\n 'marking-snapshot': 'MarkingSnapshot',\n 'log-message': 'LogMessage',\n };\n return map[event.type] ?? event.type;\n}\n\nfunction extractTransitionName(event: NetEvent): string | null {\n switch (event.type) {\n case 'transition-enabled':\n case 'transition-clock-restarted':\n case 'transition-started':\n case 'transition-completed':\n case 'transition-failed':\n case 'transition-timed-out':\n case 'action-timed-out':\n case 'log-message':\n return event.transitionName;\n default:\n return null;\n }\n}\n\nfunction extractPlaceName(event: NetEvent): string | null {\n switch (event.type) {\n case 'token-added':\n case 'token-removed':\n return event.placeName;\n default:\n return null;\n }\n}\n\nfunction matchesBreakpoint(bp: BreakpointConfig, event: NetEvent): boolean {\n switch (bp.type) {\n case 'TRANSITION_ENABLED':\n return event.type === 'transition-enabled' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_START':\n return event.type === 'transition-started' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_COMPLETE':\n return event.type === 'transition-completed' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_FAIL':\n return event.type === 'transition-failed' && (bp.target === null || bp.target === event.transitionName);\n case 'TOKEN_ADDED':\n return event.type === 'token-added' && (bp.target === null || bp.target === event.placeName);\n case 'TOKEN_REMOVED':\n return event.type === 'token-removed' && (bp.target === null || bp.target === event.placeName);\n default:\n return false;\n }\n}\n","/**\n * EventStore that delegates to both a primary store and a debug store.\n * TypeScript port of Java's DebugAwareEventStore.\n */\n\nimport type { EventStore } from '../event/event-store.js';\nimport type { NetEvent } from '../event/net-event.js';\nimport type { DebugEventStore } from './debug-event-store.js';\n\nexport class DebugAwareEventStore implements EventStore {\n private readonly _primary: EventStore;\n private readonly _debugStore: DebugEventStore;\n\n constructor(primary: EventStore, debugStore: DebugEventStore) {\n this._primary = primary;\n this._debugStore = debugStore;\n }\n\n append(event: NetEvent): void {\n this._primary.append(event);\n try {\n this._debugStore.append(event);\n } catch {\n // Debug failures must not break production\n }\n }\n\n events(): readonly NetEvent[] {\n return this._primary.events();\n }\n\n isEnabled(): boolean {\n return true;\n }\n\n size(): number {\n return this._primary.size();\n }\n\n isEmpty(): boolean {\n return this._primary.isEmpty();\n }\n\n /** Returns the underlying debug store for subscription management. */\n get debugStore(): DebugEventStore {\n return this._debugStore;\n }\n}\n","/**\n * File-system backed storage for session archives.\n * Uses Node.js fs/promises — no external dependencies.\n */\n\nimport { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';\nimport { join, normalize, resolve } from 'node:path';\nimport type { ArchivedSessionSummary, SessionArchiveStorage, OutputStreamConsumer } from './session-archive-storage.js';\nimport { Writable } from 'node:stream';\n\nconst EXTENSION = '.archive.gz';\n\nexport class FileSessionArchiveStorage implements SessionArchiveStorage {\n private readonly _directory: string;\n\n constructor(directory: string) {\n this._directory = resolve(directory);\n }\n\n async storeStreaming(sessionId: string, writer: OutputStreamConsumer): Promise<void> {\n const target = this.archivePath(sessionId);\n const dir = join(target, '..');\n await mkdir(dir, { recursive: true });\n\n const chunks: Buffer[] = [];\n const writable = new Writable({\n write(chunk: Buffer, _encoding, callback) {\n chunks.push(chunk);\n callback();\n },\n });\n\n await writer(writable);\n await writeFile(target, Buffer.concat(chunks));\n }\n\n async list(limit: number, prefix?: string): Promise<readonly ArchivedSessionSummary[]> {\n try {\n await stat(this._directory);\n } catch {\n return [];\n }\n\n const results: ArchivedSessionSummary[] = [];\n let prefixDirs: string[];\n try {\n prefixDirs = await readdir(this._directory);\n } catch {\n return [];\n }\n\n for (const prefixDir of prefixDirs) {\n const prefixPath = join(this._directory, prefixDir);\n try {\n const s = await stat(prefixPath);\n if (!s.isDirectory()) continue;\n } catch {\n continue;\n }\n\n // Skip subdirectories that can't contain matches\n if (prefix && prefixDir.length === 1 && prefixDir[0] !== prefix[0]) continue;\n\n let files: string[];\n try {\n files = await readdir(prefixPath);\n } catch {\n continue;\n }\n\n for (const file of files) {\n if (!file.endsWith(EXTENSION)) continue;\n const sessionId = file.slice(0, -EXTENSION.length);\n if (prefix && !sessionId.startsWith(prefix)) continue;\n\n const filePath = join(prefixPath, file);\n try {\n const fileStat = await stat(filePath);\n const relativePath = join(prefixDir, file);\n results.push({\n sessionId,\n key: relativePath,\n sizeBytes: fileStat.size,\n lastModified: fileStat.mtimeMs,\n });\n } catch {\n // skip unreadable files\n }\n }\n }\n\n results.sort((a, b) => b.lastModified - a.lastModified);\n return results.slice(0, limit);\n }\n\n async retrieve(sessionId: string): Promise<Buffer> {\n const path = this.archivePath(sessionId);\n try {\n return await readFile(path);\n } catch {\n throw new Error(`Archive not found for session: ${sessionId}`);\n }\n }\n\n isAvailable(): boolean {\n return true;\n }\n\n private archivePath(sessionId: string): string {\n if (!sessionId || !sessionId.trim()) {\n throw new Error(`Invalid session ID: ${sessionId}`);\n }\n const prefix = sessionId[0]!;\n const resolved = normalize(join(this._directory, prefix, sessionId + EXTENSION));\n if (!resolved.startsWith(this._directory)) {\n throw new Error(`Session ID escapes archive directory: ${sessionId}`);\n }\n return resolved;\n }\n}\n","/**\n * Writes a debug session to a length-prefixed binary archive format.\n *\n * Format (inside gzip):\n * `[4 bytes: metadata JSON length][N bytes: metadata JSON]`\n * `[4 bytes: event JSON length][N bytes: event JSON]`\n * ...\n * (EOF terminates the stream)\n *\n * ## Format selection\n *\n * `write()` defaults to {@link CURRENT_VERSION} (v3 as of libpetri 1.8.0).\n * Callers that need to emit legacy archives — compatibility tests or readers\n * pinned to older libpetri versions — can call `writeV1()` or `writeV2()`.\n *\n * Note: all writers now emit the v3 token body format (structured alongside\n * value-string) regardless of header version. A 1.8.0+ writer cannot produce\n * byte-for-byte 1.7.x event bodies.\n *\n * Cross-language note: the `type` field in each serialized `TokenInfo` is\n * `value.constructor.name` — a simple name, not an FQN. Replaying a TypeScript\n * archive through the Java reader therefore cannot reconstruct the original\n * typed token (Java needs an FQN to `Class.forName`); Java falls through to\n * `Token<JsonNode>` preserving the `structured` JSON payload. See\n * {@link tokenInfo} for the full asymmetry and the [EVT-025](../../../../spec/08-events-observability.md)\n * spec entry for the full wire-format contract.\n */\n\nimport { gzipSync } from 'node:zlib';\nimport type { DebugSession } from '../debug-session-registry.js';\nimport { buildNetStructure } from '../debug-session-registry.js';\nimport { toEventInfo } from '../net-event-converter.js';\nimport type {\n SessionArchive,\n SessionArchiveV1,\n SessionArchiveV2,\n SessionArchiveV3,\n} from './session-archive.js';\nimport { computeMetadata } from './session-metadata.js';\n\nexport class SessionArchiveWriter {\n /**\n * Writes a complete session archive in the current format (v3 as of 1.8.0)\n * and returns the compressed bytes.\n */\n write(session: DebugSession): Buffer {\n return this.writeV3(session);\n }\n\n /**\n * Writes a session in the legacy v1 format. Use only for compatibility\n * testing or when producing archives for consumers pinned to libpetri ≤ 1.6.1.\n */\n writeV1(session: DebugSession): Buffer {\n const header: SessionArchiveV1 = {\n version: 1,\n sessionId: session.sessionId,\n netName: session.netName,\n dotDiagram: session.dotDiagram,\n startTime: new Date(session.startTime).toISOString(),\n eventCount: session.eventStore.eventCount(),\n structure: buildNetStructure(session),\n };\n return this.writeFramed(header, session);\n }\n\n /**\n * Writes a session in the v2 format — richer header with `endTime`, `tags`,\n * and pre-computed {@link SessionMetadata}.\n *\n * Two passes over the event store: one to compute metadata, one to serialize\n * events. `DebugEventStore` stores events in a plain readonly array and its\n * `[Symbol.iterator]()` returns a fresh array iterator each call, so both\n * passes walk the same sequence from the start.\n */\n writeV2(session: DebugSession): Buffer {\n const metadata = computeMetadata(session.eventStore);\n\n const header: SessionArchiveV2 = {\n version: 2,\n sessionId: session.sessionId,\n netName: session.netName,\n dotDiagram: session.dotDiagram,\n startTime: new Date(session.startTime).toISOString(),\n endTime:\n session.endTime !== undefined\n ? new Date(session.endTime).toISOString()\n : undefined,\n eventCount: session.eventStore.eventCount(),\n // Snapshot of tags at archive-write time — record the state that was\n // current when the session was archived, not whatever happens on the\n // live session afterwards.\n tags: { ...session.tags },\n metadata,\n structure: buildNetStructure(session),\n };\n return this.writeFramed(header, session);\n }\n\n /**\n * Writes a session in the v3 format — same header shape as v2, with version=3\n * signalling that token payloads carry a `structured` field alongside the\n * legacy `value` string (see {@link tokenInfo}).\n */\n writeV3(session: DebugSession): Buffer {\n const metadata = computeMetadata(session.eventStore);\n\n const header: SessionArchiveV3 = {\n version: 3,\n sessionId: session.sessionId,\n netName: session.netName,\n dotDiagram: session.dotDiagram,\n startTime: new Date(session.startTime).toISOString(),\n endTime:\n session.endTime !== undefined\n ? new Date(session.endTime).toISOString()\n : undefined,\n eventCount: session.eventStore.eventCount(),\n tags: { ...session.tags },\n metadata,\n structure: buildNetStructure(session),\n };\n return this.writeFramed(header, session);\n }\n\n /**\n * Shared framing logic: length-prefixed header JSON, then length-prefixed\n * event JSON, then gzip. Both v1 and v2 archives use the identical event\n * wire format, so the body loop is version-agnostic.\n */\n private writeFramed(header: SessionArchive, session: DebugSession): Buffer {\n const parts: Buffer[] = [];\n\n // Header\n const metaBytes = Buffer.from(JSON.stringify(header), 'utf-8');\n const metaLen = Buffer.alloc(4);\n metaLen.writeUInt32BE(metaBytes.length);\n parts.push(metaLen, metaBytes);\n\n // Events — same serialization for both versions\n for (const event of session.eventStore) {\n const eventInfo = toEventInfo(event);\n const eventBytes = Buffer.from(JSON.stringify(eventInfo), 'utf-8');\n const eventLen = Buffer.alloc(4);\n eventLen.writeUInt32BE(eventBytes.length);\n parts.push(eventLen, eventBytes);\n }\n\n return gzipSync(Buffer.concat(parts));\n }\n}\n","/**\n * Shared metadata computation for session archives.\n *\n * Mirrors the Java `SessionMetadata.computeFrom` helper: single-pass scan of\n * an event iterable producing the histogram / first-last timestamps /\n * hasErrors triple. Reused by the v2 archive writer (at archive time) and by\n * read-path fallbacks that need aggregate stats for a v1 archive.\n */\n\nimport type { NetEvent } from '../../event/net-event.js';\nimport { toEventInfo } from '../net-event-converter.js';\nimport type { SessionMetadata } from './session-archive.js';\n\n/**\n * Walks the given event sequence once and produces a {@link SessionMetadata}\n * summary. Allocates one intermediate object for the histogram plus the\n * returned immutable-ish record.\n *\n * Histogram keys match the wire format emitted by {@link toEventInfo}\n * (PascalCase like `TransitionStarted`, `LogMessage`) so they are identical\n * to what the Java and Rust implementations produce.\n *\n * Keys are emitted in alphabetical order for deterministic JSON output\n * (prompt-cache friendly).\n */\nexport function computeMetadata(events: Iterable<NetEvent>): SessionMetadata {\n const raw: Record<string, number> = {};\n let first: number | undefined;\n let last: number | undefined;\n let hasErrors = false;\n\n for (const event of events) {\n // Reuse toEventInfo's PascalCase mapping so histogram keys match the\n // wire format the LLM already sees. Cheap — one small object per event,\n // garbage collected immediately.\n const typeName = toEventInfo(event).type;\n raw[typeName] = (raw[typeName] ?? 0) + 1;\n if (first === undefined) first = event.timestamp;\n last = event.timestamp;\n if (isErrorEvent(event)) hasErrors = true;\n }\n\n // Sort keys alphabetically for a deterministic JSON key order.\n const histogram: Record<string, number> = {};\n for (const key of Object.keys(raw).sort()) {\n histogram[key] = raw[key]!;\n }\n\n return {\n eventTypeHistogram: histogram,\n firstEventTime: first !== undefined ? new Date(first).toISOString() : undefined,\n lastEventTime: last !== undefined ? new Date(last).toISOString() : undefined,\n hasErrors,\n };\n}\n\n/**\n * Superset of `isFailureEvent` from `net-event.ts` that additionally treats\n * `LogMessage` at level `ERROR` (case-insensitive) as an error signal.\n *\n * Kept private to this module — `isFailureEvent` has a narrower meaning\n * (transition lifecycle failures only) and other callers rely on that.\n */\nfunction isErrorEvent(event: NetEvent): boolean {\n switch (event.type) {\n case 'transition-failed':\n case 'transition-timed-out':\n case 'action-timed-out':\n return true;\n case 'log-message':\n return event.level.toUpperCase() === 'ERROR';\n default:\n return false;\n }\n}\n","/**\n * Debug infrastructure for Petri net execution visualization.\n *\n * Provides a framework-agnostic debug protocol handler, event store with\n * live tailing, session registry, and marking cache for efficient replay.\n *\n * @module debug\n */\n\n// Protocol types\nexport type { DebugCommand, SubscriptionMode, BreakpointType, BreakpointConfig, EventFilter } from './debug-command.js';\nexport { eventFilterAll } from './debug-command.js';\nexport type {\n DebugResponse, SessionSummary, TokenInfo, NetEventInfo,\n PlaceInfo, TransitionInfo, NetStructure, ArchiveSummary,\n} from './debug-response.js';\n\n// Core infrastructure\nexport { DebugProtocolHandler } from './debug-protocol-handler.js';\nexport type { ResponseSink, ComputedState } from './debug-protocol-handler.js';\nexport { DebugEventStore, DEFAULT_MAX_EVENTS } from './debug-event-store.js';\nexport type { Subscription } from './debug-event-store.js';\nexport { DebugSessionRegistry, buildNetStructure } from './debug-session-registry.js';\nexport type { DebugSession, EventStoreFactory } from './debug-session-registry.js';\nexport type { SessionCompletionListener } from './session-completion-listener.js';\nexport { MarkingCache, SNAPSHOT_INTERVAL } from './marking-cache.js';\n\n// Converters and analysis\nexport { toEventInfo, tokenInfo, compactTokenInfo, convertMarking } from './net-event-converter.js';\nexport { DebugAwareEventStore } from './debug-aware-event-store.js';\nexport { PlaceAnalysis } from './place-analysis.js';\nexport type { PlaceAnalysisInfo } from './place-analysis.js';\n\n// Archive\nexport type { SessionArchive } from './archive/session-archive.js';\nexport { CURRENT_VERSION } from './archive/session-archive.js';\nexport type { SessionArchiveStorage, ArchivedSessionSummary, OutputStreamConsumer } from './archive/session-archive-storage.js';\nexport { FileSessionArchiveStorage } from './archive/file-session-archive-storage.js';\nexport { SessionArchiveWriter } from './archive/session-archive-writer.js';\nexport { SessionArchiveReader } from './archive/session-archive-reader.js';\nexport type { ImportedSession } from './archive/session-archive-reader.js';\n\n/**\n * Returns the path to the bundled debug UI assets directory.\n * Requires Node.js — resolves relative to this module's location.\n */\nexport async function debugUiAssetPath(): Promise<string> {\n // eslint-disable-next-line @typescript-eslint/no-implied-eval\n const dynamicImport = Function('m', 'return import(m)') as (m: string) => Promise<Record<string, unknown>>;\n const nodeUrl = await dynamicImport('node:url') as { fileURLToPath(url: string | URL): string };\n const nodePath = await dynamicImport('node:path') as { dirname(p: string): string; join(...paths: string[]): string };\n const thisDir = nodePath.dirname(nodeUrl.fileURLToPath(import.meta.url));\n return nodePath.join(thisDir, '..', 'debug-ui');\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/debug/debug-command.ts","../../src/debug/archive/session-archive-reader.ts","../../src/debug/debug-event-store.ts","../../src/debug/archive/session-archive.ts","../../src/debug/place-analysis.ts","../../src/debug/debug-session-registry.ts","../../src/debug/marking-cache.ts","../../src/debug/net-event-converter.ts","../../src/debug/debug-protocol-handler.ts","../../src/debug/debug-aware-event-store.ts","../../src/debug/archive/file-session-archive-storage.ts","../../src/debug/archive/session-archive-writer.ts","../../src/debug/archive/session-metadata.ts","../../src/debug/index.ts"],"sourcesContent":["/**\n * Commands sent from debug UI client to server via WebSocket.\n * TypeScript port of Java's DebugCommand sealed interface.\n */\n\nexport type SubscriptionMode = 'live' | 'replay';\n\nexport type BreakpointType =\n | 'TRANSITION_ENABLED'\n | 'TRANSITION_START'\n | 'TRANSITION_COMPLETE'\n | 'TRANSITION_FAIL'\n | 'TOKEN_ADDED'\n | 'TOKEN_REMOVED';\n\nexport interface BreakpointConfig {\n readonly id: string;\n readonly type: BreakpointType;\n readonly target: string | null;\n readonly enabled: boolean;\n}\n\nexport interface EventFilter {\n readonly eventTypes: readonly string[] | null;\n readonly transitionNames: readonly string[] | null;\n readonly placeNames: readonly string[] | null;\n readonly excludeEventTypes?: readonly string[] | null;\n readonly excludeTransitionNames?: readonly string[] | null;\n readonly excludePlaceNames?: readonly string[] | null;\n}\n\nexport type DebugCommand =\n | { readonly type: 'subscribe'; readonly sessionId: string; readonly mode: SubscriptionMode; readonly fromIndex?: number }\n | { readonly type: 'unsubscribe'; readonly sessionId: string }\n | {\n readonly type: 'listSessions';\n readonly limit?: number;\n readonly activeOnly?: boolean;\n /** Optional tag filter (AND semantics). Empty or missing matches all. (libpetri 1.6.0+) */\n readonly tagFilter?: Readonly<Record<string, string>>;\n }\n | { readonly type: 'seek'; readonly sessionId: string; readonly timestamp: string }\n | { readonly type: 'playbackSpeed'; readonly sessionId: string; readonly speed: number }\n | { readonly type: 'filter'; readonly sessionId: string; readonly filter: EventFilter }\n | { readonly type: 'pause'; readonly sessionId: string }\n | { readonly type: 'resume'; readonly sessionId: string }\n | { readonly type: 'stepForward'; readonly sessionId: string }\n | { readonly type: 'stepBackward'; readonly sessionId: string }\n | { readonly type: 'setBreakpoint'; readonly sessionId: string; readonly breakpoint: BreakpointConfig }\n | { readonly type: 'clearBreakpoint'; readonly sessionId: string; readonly breakpointId: string }\n | { readonly type: 'listBreakpoints'; readonly sessionId: string }\n | { readonly type: 'listArchives'; readonly limit?: number; readonly prefix?: string }\n | { readonly type: 'importArchive'; readonly sessionId: string }\n | { readonly type: 'uploadArchive'; readonly fileName: string; readonly data: string };\n\nexport function eventFilterAll(): EventFilter {\n return { eventTypes: null, transitionNames: null, placeNames: null, excludeEventTypes: null, excludeTransitionNames: null, excludePlaceNames: null };\n}\n","/**\n * Reads session archives from length-prefixed binary format.\n *\n * Handles both v1 (libpetri 1.5.x–1.6.x) and v2 (libpetri 1.7.0+) archives via\n * a lenient \"version probe\": parse the header JSON once, switch on the\n * `version` field, narrow to the correct concrete type, and normalize missing\n * optional fields to their defaults. Events inside the body use the same wire\n * format across versions, so the event read path is shared.\n */\n\nimport { gunzipSync } from 'node:zlib';\nimport { DebugEventStore } from '../debug-event-store.js';\nimport type { NetEventInfo } from '../debug-response.js';\nimport type { NetEvent } from '../../event/net-event.js';\nimport type { Token } from '../../core/token.js';\nimport type {\n SessionArchive,\n SessionArchiveV1,\n SessionArchiveV2,\n SessionArchiveV3,\n} from './session-archive.js';\nimport {\n CURRENT_VERSION,\n MIN_SUPPORTED_VERSION,\n emptyMetadata,\n} from './session-archive.js';\n\nexport interface ImportedSession {\n readonly metadata: SessionArchive;\n readonly eventStore: DebugEventStore;\n}\n\nconst MAX_EVENT_SIZE = 10 * 1024 * 1024; // 10 MB\n\nexport class SessionArchiveReader {\n /** Reads only the metadata header from an archive. */\n readMetadata(compressed: Buffer): SessionArchive {\n const data = gunzipSync(compressed);\n const metaLen = data.readUInt32BE(0);\n const metaJson = data.subarray(4, 4 + metaLen).toString('utf-8');\n return parseHeader(metaJson);\n }\n\n /** Reads the full archive: metadata + all events into a DebugEventStore. */\n readFull(compressed: Buffer): ImportedSession {\n const data = gunzipSync(compressed);\n let offset = 0;\n\n // Read metadata\n const metaLen = data.readUInt32BE(offset);\n offset += 4;\n const metaJson = data.subarray(offset, offset + metaLen).toString('utf-8');\n offset += metaLen;\n const metadata = parseHeader(metaJson);\n\n // Read events — same wire format across versions.\n const eventStore = new DebugEventStore(metadata.sessionId, Number.MAX_SAFE_INTEGER);\n while (offset < data.length) {\n if (offset + 4 > data.length) break;\n const eventLen = data.readUInt32BE(offset);\n offset += 4;\n if (eventLen <= 0 || eventLen > MAX_EVENT_SIZE) {\n throw new Error(`Invalid event size: ${eventLen}`);\n }\n if (offset + eventLen > data.length) break;\n const eventJson = data.subarray(offset, offset + eventLen).toString('utf-8');\n offset += eventLen;\n\n const eventInfo: NetEventInfo = JSON.parse(eventJson);\n const netEvent = eventInfoToNetEvent(eventInfo);\n eventStore.append(netEvent);\n }\n\n return { metadata, eventStore };\n }\n}\n\n/**\n * Peeks the archive `version` field via a single JSON parse, then narrows the\n * result into the correct {@link SessionArchive} variant. v2-only optional\n * fields (`tags`, `metadata`) are normalized to their empty defaults so\n * callers never need to guard against `undefined` on a declared-v2 archive.\n */\nfunction parseHeader(metaJson: string): SessionArchive {\n const raw = JSON.parse(metaJson) as { version: number } & Record<string, unknown>;\n switch (raw.version) {\n case 1:\n return raw as unknown as SessionArchiveV1;\n case 2: {\n const v2 = raw as unknown as SessionArchiveV2;\n // Normalize: v2 defines tags + metadata as REQUIRED in the type, but a\n // hand-written or partially-built header could omit them — fall back\n // to empty defaults rather than emit `undefined` into typed code.\n return {\n ...v2,\n tags: v2.tags ?? {},\n metadata: v2.metadata ?? emptyMetadata(),\n };\n }\n case 3: {\n const v3 = raw as unknown as SessionArchiveV3;\n return {\n ...v3,\n tags: v3.tags ?? {},\n metadata: v3.metadata ?? emptyMetadata(),\n };\n }\n default:\n throw new Error(\n `Unsupported archive version: ${raw.version} ` +\n `(reader supports ${MIN_SUPPORTED_VERSION}..${CURRENT_VERSION})`,\n );\n }\n}\n\n/** Converts a serialized NetEventInfo back to a NetEvent. */\nfunction eventInfoToNetEvent(info: NetEventInfo): NetEvent {\n const timestamp = new Date(info.timestamp).getTime();\n const d = info.details;\n\n switch (info.type) {\n case 'ExecutionStarted':\n return { type: 'execution-started', timestamp, netName: d['netName'] as string, executionId: d['executionId'] as string };\n case 'ExecutionCompleted':\n return { type: 'execution-completed', timestamp, netName: d['netName'] as string, executionId: d['executionId'] as string, totalDurationMs: d['totalDurationMs'] as number };\n case 'TransitionEnabled':\n return { type: 'transition-enabled', timestamp, transitionName: info.transitionName! };\n case 'TransitionClockRestarted':\n return { type: 'transition-clock-restarted', timestamp, transitionName: info.transitionName! };\n case 'TransitionStarted': {\n const tokens = (d['consumedTokens'] as readonly WireTokenInfo[])\n .map(t => infoToToken(t));\n return { type: 'transition-started', timestamp, transitionName: info.transitionName!, consumedTokens: tokens };\n }\n case 'TransitionCompleted': {\n const tokens = (d['producedTokens'] as readonly WireTokenInfo[])\n .map(t => infoToToken(t));\n return { type: 'transition-completed', timestamp, transitionName: info.transitionName!, producedTokens: tokens, durationMs: d['durationMs'] as number };\n }\n case 'TransitionFailed':\n return { type: 'transition-failed', timestamp, transitionName: info.transitionName!, errorMessage: d['errorMessage'] as string, exceptionType: d['exceptionType'] as string };\n case 'TransitionTimedOut':\n return { type: 'transition-timed-out', timestamp, transitionName: info.transitionName!, deadlineMs: d['deadlineMs'] as number, actualDurationMs: d['actualDurationMs'] as number };\n case 'ActionTimedOut':\n return { type: 'action-timed-out', timestamp, transitionName: info.transitionName!, timeoutMs: d['timeoutMs'] as number };\n case 'TokenAdded': {\n const t = d['token'] as WireTokenInfo;\n return { type: 'token-added', timestamp, placeName: info.placeName!, token: infoToToken(t) };\n }\n case 'TokenRemoved': {\n const t = d['token'] as WireTokenInfo;\n return { type: 'token-removed', timestamp, placeName: info.placeName!, token: infoToToken(t) };\n }\n case 'MarkingSnapshot': {\n const markingData = d['marking'] as Record<string, readonly WireTokenInfo[]>;\n const marking = new Map<string, Token<unknown>[]>();\n for (const [place, tokens] of Object.entries(markingData)) {\n marking.set(place, tokens.map(t => infoToToken(t)));\n }\n return { type: 'marking-snapshot', timestamp, marking };\n }\n case 'LogMessage':\n return {\n type: 'log-message',\n timestamp,\n transitionName: info.transitionName!,\n logger: d['loggerName'] as string,\n level: d['level'] as string,\n message: d['message'] as string,\n error: (d['throwable'] as string | undefined) ?? null,\n errorMessage: (d['throwableMessage'] as string | undefined) ?? null,\n };\n default:\n // Fallback: create a minimal event for unknown types\n return { type: 'transition-enabled', timestamp, transitionName: info.transitionName ?? 'unknown' };\n }\n}\n\n/**\n * Wire shape of a serialized token body. Matches {@link TokenInfo} minus the\n * `id` field (archives never emit token identity). `structured` is optional\n * and preserved verbatim on replay per EVT-025 AC5.\n */\ninterface WireTokenInfo {\n readonly type: string;\n readonly value: string | null;\n readonly structured?: unknown;\n readonly timestamp: string | null;\n}\n\nfunction infoToToken(t: WireTokenInfo): Token<unknown> {\n const createdAt = t.timestamp ? new Date(t.timestamp).getTime() : Date.now();\n // Preserve `structured` only when the writer emitted it — keep live-token\n // shape (no `structured` field) identical for tokens that lacked it.\n return t.structured === undefined\n ? { value: t.value, createdAt }\n : { value: t.value, createdAt, structured: t.structured };\n}\n","/**\n * EventStore with live tailing and historical replay.\n * TypeScript port of Java's DebugEventStore.\n *\n * Node.js simplifications: single-threaded, no locks needed,\n * synchronous Set<Function> for subscribers, microtask broadcast.\n */\n\nimport type { EventStore } from '../event/event-store.js';\nimport type { NetEvent } from '../event/net-event.js';\n\n/** Handle for managing a live event subscription. */\nexport interface Subscription {\n cancel(): void;\n isActive(): boolean;\n}\n\n/** Default maximum events to retain before evicting oldest. */\nexport const DEFAULT_MAX_EVENTS = 10_000;\n\nexport class DebugEventStore implements EventStore {\n private readonly _events: NetEvent[] = [];\n private readonly _subscribers = new Set<(event: NetEvent) => void>();\n private readonly _sessionId: string;\n private readonly _maxEvents: number;\n private _eventCount = 0;\n private _evictedCount = 0;\n\n constructor(sessionId: string, maxEvents = DEFAULT_MAX_EVENTS) {\n if (maxEvents <= 0) throw new Error(`maxEvents must be positive, got: ${maxEvents}`);\n this._sessionId = sessionId;\n this._maxEvents = maxEvents;\n }\n\n get sessionId(): string { return this._sessionId; }\n get maxEvents(): number { return this._maxEvents; }\n\n /** Total events appended (including evicted). */\n eventCount(): number { return this._eventCount; }\n\n /** Number of events evicted from the store. */\n evictedCount(): number { return this._evictedCount; }\n\n // ======================== EventStore Implementation ========================\n\n append(event: NetEvent): void {\n this._events.push(event);\n this._eventCount++;\n\n // Evict oldest when capacity exceeded\n while (this._events.length > this._maxEvents) {\n this._events.shift();\n this._evictedCount++;\n }\n\n // Broadcast to subscribers (microtask for async-like behavior)\n if (this._subscribers.size > 0) {\n // Use queueMicrotask instead of synchronous call to avoid blocking\n const subscribers = [...this._subscribers];\n queueMicrotask(() => {\n for (const sub of subscribers) {\n try {\n sub(event);\n } catch (e) {\n console.warn('Subscriber threw exception during event broadcast', e);\n }\n }\n });\n }\n }\n\n events(): readonly NetEvent[] {\n return this._events;\n }\n\n isEnabled(): boolean {\n return true;\n }\n\n size(): number {\n return this._events.length;\n }\n\n isEmpty(): boolean {\n return this._events.length === 0;\n }\n\n // ======================== Live Tailing ========================\n\n /** Subscribe to receive events as they occur. */\n subscribe(listener: (event: NetEvent) => void): Subscription {\n this._subscribers.add(listener);\n return {\n cancel: () => { this._subscribers.delete(listener); },\n isActive: () => this._subscribers.has(listener),\n };\n }\n\n /** Number of active subscribers. */\n subscriberCount(): number {\n return this._subscribers.size;\n }\n\n // ======================== Historical Replay ========================\n\n /** Returns events starting from a specific index. */\n eventsFrom(fromIndex: number): readonly NetEvent[] {\n const adjustedSkip = Math.max(0, fromIndex - this._evictedCount);\n if (adjustedSkip <= 0) return this._events;\n return this._events.slice(adjustedSkip);\n }\n\n /** Returns all events since the specified timestamp. */\n eventsSince(from: number): readonly NetEvent[] {\n return this._events.filter(e => e.timestamp >= from);\n }\n\n /** Returns events within a time range. */\n eventsBetween(from: number, to: number): readonly NetEvent[] {\n return this._events.filter(e => e.timestamp >= from && e.timestamp < to);\n }\n\n /**\n * Returns an iterator over all retained events.\n * Useful for archive writers that need zero-copy traversal.\n */\n [Symbol.iterator](): Iterator<NetEvent> {\n return this._events[Symbol.iterator]();\n }\n\n // ======================== Lifecycle ========================\n\n /** Close the store (no-op in JS, but matches Java interface). */\n close(): void {\n this._subscribers.clear();\n }\n}\n","/**\n * Metadata header for a session archive file.\n *\n * Discriminated union across format versions so callers can pattern-match on\n * `archive.version` to access v2-only fields with type narrowing:\n *\n * ```ts\n * const archive = reader.readMetadata(bytes);\n * if (archive.version === 2) {\n * console.log(archive.tags, archive.endTime, archive.metadata.hasErrors);\n * }\n * ```\n *\n * ## Version contract\n *\n * - **v1** (libpetri 1.5.x–1.6.x): original format. Header carries `sessionId`,\n * `netName`, `dotDiagram`, `startTime`, `eventCount`, and net `structure`.\n * - **v2** (libpetri 1.7.x): adds `endTime`, user-defined `tags`, and pre-computed\n * {@link SessionMetadata}. Events inside v2 archives use the legacy `toString`-based\n * token format — types are erased on disk.\n * - **v3** (libpetri 1.8.0+): same header shape as v2. Differs in the event body —\n * token values are serialized with a `structured` JSON payload in addition to the\n * legacy `value` string, so consumers that understand the original shape can\n * surface typed fields without parsing the `toString` form.\n *\n * The {@link SessionArchiveReader} peeks the `version` field via a lenient JSON\n * parse and dispatches to the correct concrete type. All three versions coexist\n * in the same storage bucket.\n */\nimport type { NetStructure } from '../debug-response.js';\n\n/** Common fields shared by v1 and v2 archive headers. */\ninterface SessionArchiveBase {\n readonly sessionId: string;\n readonly netName: string;\n readonly dotDiagram: string;\n /** ISO-8601 instant the session started. */\n readonly startTime: string;\n readonly eventCount: number;\n readonly structure: NetStructure;\n}\n\n/** Legacy v1 archive header (libpetri 1.5.x–1.6.x). */\nexport interface SessionArchiveV1 extends SessionArchiveBase {\n readonly version: 1;\n}\n\n/**\n * v2 archive header (libpetri 1.7.0+). Adds end time, tags, and pre-computed\n * metadata so listing tools and samplers can filter/aggregate without scanning\n * the event body.\n */\nexport interface SessionArchiveV2 extends SessionArchiveBase {\n readonly version: 2;\n /** ISO-8601 instant the session ended. Undefined for sessions archived while still active. */\n readonly endTime?: string;\n /** User-defined session tags (e.g., `{channel: \"voice\"}`). Always present; may be empty. */\n readonly tags: Readonly<Record<string, string>>;\n /** Pre-computed aggregate stats. Always present; `emptyMetadata()` for no-event sessions. */\n readonly metadata: SessionMetadata;\n}\n\n/**\n * v3 archive header (libpetri 1.8.0+). Structurally identical to `SessionArchiveV2`;\n * the version bump signals that the event body carries `structured` token payloads\n * alongside the legacy `value` string.\n */\nexport interface SessionArchiveV3 extends SessionArchiveBase {\n readonly version: 3;\n readonly endTime?: string;\n readonly tags: Readonly<Record<string, string>>;\n readonly metadata: SessionMetadata;\n}\n\n/**\n * Discriminated union of all supported archive header versions.\n *\n * Type-narrowing example:\n * ```ts\n * if (archive.version >= 2) {\n * // TS knows archive has tags / endTime / metadata here.\n * }\n * ```\n */\nexport type SessionArchive = SessionArchiveV1 | SessionArchiveV2 | SessionArchiveV3;\n\n/** Version written by default by {@link SessionArchiveWriter.write} (latest supported). */\nexport const CURRENT_VERSION = 3;\n\n/** Lowest version {@link SessionArchiveReader} can decode. */\nexport const MIN_SUPPORTED_VERSION = 1;\n\n/**\n * Pre-computed aggregate statistics attached to a v2 session archive header.\n *\n * Computed once during archive write by a single-pass scan of the event store.\n * Readers can answer `hasErrors`, histogram, and first/last timestamp queries\n * without iterating the event stream — enabling cheap triage, sampling, and\n * listing of many archives.\n *\n * For v1 archives (no pre-computed metadata), callers can recompute on-demand\n * via {@link computeMetadata}.\n */\nexport interface SessionMetadata {\n /**\n * Count of events per `NetEvent` subtype name (PascalCase, matching the\n * wire format used by `NetEventInfo.type` — e.g. `TransitionStarted -> 412`).\n * Keys are stored in alphabetical order for deterministic JSON output.\n */\n readonly eventTypeHistogram: Readonly<Record<string, number>>;\n /** ISO-8601 timestamp of the oldest event, or undefined if the session had no events. */\n readonly firstEventTime?: string;\n /** ISO-8601 timestamp of the newest event, or undefined if the session had no events. */\n readonly lastEventTime?: string;\n /**\n * True if the session contains at least one error-signal event\n * (`TransitionFailed`, `TransitionTimedOut`, `ActionTimedOut`, or\n * a `LogMessage` at level `ERROR`).\n */\n readonly hasErrors: boolean;\n}\n\n/** Returns a {@link SessionMetadata} with no data. Used as a default for empty sessions. */\nexport function emptyMetadata(): SessionMetadata {\n return { eventTypeHistogram: {}, hasErrors: false };\n}\n","/**\n * Analyze places for start/end/environment classification.\n * TypeScript port of Java's PlaceAnalysis.\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { Place } from '../core/place.js';\n\nexport interface PlaceAnalysisInfo {\n readonly tokenType: string;\n readonly hasIncoming: boolean;\n readonly hasOutgoing: boolean;\n}\n\nexport class PlaceAnalysis {\n private readonly _data: ReadonlyMap<string, PlaceAnalysisInfo>;\n\n constructor(data: ReadonlyMap<string, PlaceAnalysisInfo>) {\n this._data = data;\n }\n\n get data(): ReadonlyMap<string, PlaceAnalysisInfo> {\n return this._data;\n }\n\n isStart(placeName: string): boolean {\n const info = this._data.get(placeName);\n return info != null && !info.hasIncoming;\n }\n\n isEnd(placeName: string): boolean {\n const info = this._data.get(placeName);\n return info != null && !info.hasOutgoing;\n }\n\n /** Build place analysis from a PetriNet. */\n static from(net: PetriNet): PlaceAnalysis {\n const data = new Map<string, { tokenType: string; hasIncoming: boolean; hasOutgoing: boolean }>();\n\n function ensure(place: Place<unknown>): { tokenType: string; hasIncoming: boolean; hasOutgoing: boolean } {\n let info = data.get(place.name);\n if (!info) {\n info = { tokenType: 'unknown', hasIncoming: false, hasOutgoing: false };\n data.set(place.name, info);\n }\n return info;\n }\n\n for (const transition of net.transitions) {\n // Input arcs: place → transition (place has outgoing)\n for (const input of transition.inputSpecs) {\n const info = ensure((input as { place: Place<unknown> }).place);\n info.hasOutgoing = true;\n }\n\n // Output arcs: transition → place (place has incoming)\n if (transition.outputSpec) {\n const outputPlaces = collectOutputPlaces(transition.outputSpec);\n for (const place of outputPlaces) {\n const info = ensure(place);\n info.hasIncoming = true;\n }\n }\n\n // Inhibitor arcs: just ensure place exists\n for (const inh of transition.inhibitors) {\n ensure((inh as { place: Place<unknown> }).place);\n }\n\n // Read arcs: place has outgoing (read = test without consuming)\n for (const read of transition.reads) {\n const info = ensure((read as { place: Place<unknown> }).place);\n info.hasOutgoing = true;\n }\n\n // Reset arcs: just ensure place exists\n for (const reset of transition.resets) {\n ensure((reset as { place: Place<unknown> }).place);\n }\n }\n\n return new PlaceAnalysis(data as ReadonlyMap<string, PlaceAnalysisInfo>);\n }\n}\n\n/** Recursively collect all output places from an Out spec. */\nfunction collectOutputPlaces(out: unknown): Place<unknown>[] {\n const spec = out as { type: string; place?: Place<unknown>; children?: unknown[]; child?: unknown; from?: Place<unknown>; to?: Place<unknown> };\n switch (spec.type) {\n case 'place':\n return spec.place ? [spec.place] : [];\n case 'and':\n case 'xor':\n return (spec.children ?? []).flatMap(c => collectOutputPlaces(c));\n case 'timeout':\n return spec.child ? collectOutputPlaces(spec.child) : [];\n case 'forward-input':\n return spec.to ? [spec.to] : [];\n default:\n return [];\n }\n}\n","/**\n * Registry for managing Petri net debug sessions.\n * TypeScript port of Java's DebugSessionRegistry.\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { Transition } from '../core/transition.js';\nimport { dotExport } from '../export/dot-exporter.js';\nimport { sanitize } from '../export/petri-net-mapper.js';\nimport type { NetStructure, PlaceInfo, TransitionInfo } from './debug-response.js';\nimport { PlaceAnalysis } from './place-analysis.js';\nimport { DebugEventStore } from './debug-event-store.js';\nimport type { SessionCompletionListener } from './session-completion-listener.js';\n\nexport interface DebugSession {\n readonly sessionId: string;\n readonly netName: string;\n readonly dotDiagram: string;\n readonly places: PlaceAnalysis | null;\n readonly transitions: ReadonlySet<Transition>;\n readonly eventStore: DebugEventStore;\n readonly startTime: number;\n readonly active: boolean;\n readonly importedStructure: NetStructure | null;\n /** Stamped on first `complete()`. Undefined while the session is active. (libpetri 1.6.0+) */\n readonly endTime?: number;\n /**\n * Per-session tag storage, mutated in place by the registry. The reference is\n * readonly but the underlying object is not — prefer\n * {@link DebugSessionRegistry.tag}/{@link DebugSessionRegistry.tagsFor}\n * over direct access.\n */\n readonly tags: Record<string, string>;\n}\n\n/** Builds the net structure from a session's stored place and transition info. */\nexport function buildNetStructure(session: DebugSession): NetStructure {\n if (session.importedStructure) {\n return session.importedStructure;\n }\n\n const places = session.places;\n if (!places) {\n return { places: [], transitions: [] };\n }\n\n const placeInfos: PlaceInfo[] = [];\n for (const [name, info] of places.data) {\n placeInfos.push({\n name,\n graphId: `p_${sanitize(name)}`,\n tokenType: info.tokenType,\n isStart: !info.hasIncoming,\n isEnd: !info.hasOutgoing,\n isEnvironment: false,\n });\n }\n\n const transitionInfos: TransitionInfo[] = [];\n for (const t of session.transitions) {\n transitionInfos.push({\n name: t.name,\n graphId: `t_${sanitize(t.name)}`,\n });\n }\n\n return { places: placeInfos, transitions: transitionInfos };\n}\n\nexport type EventStoreFactory = (sessionId: string) => DebugEventStore;\n\nexport class DebugSessionRegistry {\n private readonly _sessions = new Map<string, DebugSession>();\n private readonly _maxSessions: number;\n private readonly _eventStoreFactory: EventStoreFactory;\n private readonly _completionListeners: readonly SessionCompletionListener[];\n\n constructor(\n maxSessions = 50,\n eventStoreFactory?: EventStoreFactory,\n completionListeners?: SessionCompletionListener[],\n ) {\n this._maxSessions = maxSessions;\n this._eventStoreFactory = eventStoreFactory ?? ((id: string) => new DebugEventStore(id));\n this._completionListeners = completionListeners ? [...completionListeners] : [];\n }\n\n /**\n * Registers a new debug session for the given Petri net.\n * Generates DOT diagram and extracts net structure.\n *\n * @param sessionId unique session id\n * @param net the Petri net being executed\n * @param tags optional user-defined tags (libpetri 1.6.0+) — e.g. `{channel: 'voice'}`\n */\n register(sessionId: string, net: PetriNet, tags?: Readonly<Record<string, string>>): DebugSession {\n const dotDiagram = dotExport(net);\n const places = PlaceAnalysis.from(net);\n const eventStore = this._eventStoreFactory(sessionId);\n\n const session: DebugSession = {\n sessionId,\n netName: net.name,\n dotDiagram,\n places,\n transitions: net.transitions,\n eventStore,\n startTime: Date.now(),\n active: true,\n importedStructure: null,\n tags: tags ? { ...tags } : {},\n };\n\n this.evictIfNecessary();\n this._sessions.set(sessionId, session);\n return session;\n }\n\n /**\n * Marks a session as completed (no longer active) and notifies completion listeners.\n *\n * <p>Stamps `endTime = Date.now()` on the first completion. Idempotent: subsequent\n * calls preserve the existing endTime. (libpetri 1.6.0+)\n */\n complete(sessionId: string): void {\n const session = this._sessions.get(sessionId);\n if (session) {\n const endTime = session.endTime ?? Date.now();\n // Spread preserves the same `tags` object reference, so any concurrent\n // tag() call via the old session still writes to the right storage.\n const completed: DebugSession = { ...session, active: false, endTime };\n this._sessions.set(sessionId, completed);\n this.notifyCompletionListeners(completed);\n }\n }\n\n /** Removes a session from the registry. Tags die with the session. */\n remove(sessionId: string): DebugSession | undefined {\n const removed = this._sessions.get(sessionId);\n if (removed) {\n this._sessions.delete(sessionId);\n removed.eventStore.close();\n }\n return removed;\n }\n\n /** Returns a session by ID. */\n getSession(sessionId: string): DebugSession | undefined {\n return this._sessions.get(sessionId);\n }\n\n /**\n * Sets or overwrites a single tag on a session. (libpetri 1.6.0+)\n *\n * Tags accumulate until the session is removed. Setting a key that already\n * exists replaces its value.\n *\n * If `sessionId` is not a currently-registered session the call is a no-op.\n * A tag write that races with {@link remove} is harmless — the write lands on\n * the now-orphaned session object and is garbage collected along with it.\n */\n tag(sessionId: string, key: string, value: string): void {\n const session = this._sessions.get(sessionId);\n if (!session) return;\n session.tags[key] = value;\n }\n\n /**\n * Returns a snapshot of the tags attached to a session. Returns an empty\n * object if the session has no tags or does not exist. (libpetri 1.6.0+)\n */\n tagsFor(sessionId: string): Readonly<Record<string, string>> {\n const session = this._sessions.get(sessionId);\n return session ? { ...session.tags } : {};\n }\n\n /** Lists sessions, ordered by start time (most recent first). */\n listSessions(limit: number, tagFilter?: Readonly<Record<string, string>>): readonly DebugSession[] {\n return [...this._sessions.values()]\n .filter(s => this.matchesTagFilter(s, tagFilter))\n .sort((a, b) => b.startTime - a.startTime)\n .slice(0, limit);\n }\n\n /** Lists only active sessions. */\n listActiveSessions(\n limit: number,\n tagFilter?: Readonly<Record<string, string>>,\n ): readonly DebugSession[] {\n return [...this._sessions.values()]\n .filter(s => s.active)\n .filter(s => this.matchesTagFilter(s, tagFilter))\n .sort((a, b) => b.startTime - a.startTime)\n .slice(0, limit);\n }\n\n /** Total number of sessions. */\n get size(): number {\n return this._sessions.size;\n }\n\n /**\n * Registers an imported (archived) session as an inactive, read-only session.\n *\n * @param endTime when the original session ended (libpetri 1.6.0+)\n * @param tags user-defined tags attached to the imported session (libpetri 1.6.0+)\n */\n registerImported(\n sessionId: string,\n netName: string,\n dotDiagram: string,\n structure: NetStructure,\n eventStore: DebugEventStore,\n startTime: number,\n endTime?: number,\n tags?: Readonly<Record<string, string>>,\n ): DebugSession {\n this.evictIfNecessary();\n\n const session: DebugSession = {\n sessionId,\n netName,\n dotDiagram,\n places: null,\n transitions: new Set(),\n eventStore,\n startTime,\n active: false,\n importedStructure: structure,\n endTime,\n tags: tags ? { ...tags } : {},\n };\n\n this._sessions.set(sessionId, session);\n return session;\n }\n\n /** AND-match: all filter entries must exactly match the session's tags. */\n private matchesTagFilter(\n session: DebugSession,\n filter: Readonly<Record<string, string>> | undefined,\n ): boolean {\n if (!filter) return true;\n const keys = Object.keys(filter);\n if (keys.length === 0) return true;\n const tags = session.tags;\n for (const key of keys) {\n if (tags[key] !== filter[key]) return false;\n }\n return true;\n }\n\n /** Notifies all completion listeners. Exceptions are caught and logged. */\n private notifyCompletionListeners(session: DebugSession): void {\n for (const listener of this._completionListeners) {\n try {\n listener(session);\n } catch (e) {\n console.warn(`Session completion listener failed for ${session.sessionId}`, e);\n }\n }\n }\n\n /** Evicts oldest inactive sessions if at capacity. */\n private evictIfNecessary(): void {\n if (this._sessions.size < this._maxSessions) return;\n\n const candidates = [...this._sessions.values()]\n .sort((a, b) => {\n // Inactive first, then oldest\n if (a.active !== b.active) return a.active ? 1 : -1;\n return a.startTime - b.startTime;\n });\n\n for (const candidate of candidates) {\n if (this._sessions.size < this._maxSessions) break;\n const evicted = this._sessions.get(candidate.sessionId);\n if (evicted) {\n this._sessions.delete(candidate.sessionId);\n evicted.eventStore.close();\n }\n }\n }\n}\n","/**\n * Caches computed state snapshots at periodic intervals for efficient seek/step.\n * TypeScript port of Java's MarkingCache.\n */\n\nimport type { NetEvent } from '../event/net-event.js';\nimport type { TokenInfo } from './debug-response.js';\nimport { computeState, applyEvents, toImmutableState, type ComputedState } from './debug-protocol-handler.js';\n\n/** Number of events between cached snapshots. */\nexport const SNAPSHOT_INTERVAL = 256;\n\nexport class MarkingCache {\n private readonly _snapshots: ComputedState[] = [];\n\n /**\n * Computes the state at the given event index, using cached snapshots\n * to minimize the number of events that need to be replayed.\n *\n * @param events the full event list for the session\n * @param targetIndex event index to compute state at (exclusive upper bound)\n */\n computeAt(events: readonly NetEvent[], targetIndex: number): ComputedState {\n if (targetIndex <= 0) {\n return computeState([]);\n }\n\n this.ensureCachedUpTo(events, targetIndex);\n\n if (this._snapshots.length === 0) {\n return computeState(events.slice(0, targetIndex));\n }\n\n // Find highest snapshot <= targetIndex\n const snapshotSlot = Math.min(Math.floor(targetIndex / SNAPSHOT_INTERVAL), this._snapshots.length) - 1;\n\n if (snapshotSlot < 0) {\n return computeState(events.slice(0, targetIndex));\n }\n\n const snapshotEventIndex = (snapshotSlot + 1) * SNAPSHOT_INTERVAL;\n\n if (snapshotEventIndex === targetIndex) {\n return this._snapshots[snapshotSlot]!;\n }\n\n return replayDelta(this._snapshots[snapshotSlot]!, events.slice(snapshotEventIndex, targetIndex));\n }\n\n /** Invalidates the cache. */\n invalidate(): void {\n this._snapshots.length = 0;\n }\n\n /** Extends the snapshot cache to cover at least up to the given event index. */\n private ensureCachedUpTo(events: readonly NetEvent[], targetIndex: number): void {\n const neededSnapshots = Math.floor(targetIndex / SNAPSHOT_INTERVAL);\n\n while (this._snapshots.length < neededSnapshots) {\n const nextSnapshotIndex = (this._snapshots.length + 1) * SNAPSHOT_INTERVAL;\n if (nextSnapshotIndex > events.length) break;\n\n if (this._snapshots.length === 0) {\n this._snapshots.push(computeState(events.slice(0, nextSnapshotIndex)));\n } else {\n const prevSnapshotIndex = this._snapshots.length * SNAPSHOT_INTERVAL;\n const delta = events.slice(prevSnapshotIndex, nextSnapshotIndex);\n this._snapshots.push(replayDelta(this._snapshots[this._snapshots.length - 1]!, delta));\n }\n }\n }\n}\n\n/** Replays delta events on top of a base snapshot to produce a new state. */\nfunction replayDelta(base: ComputedState, delta: readonly NetEvent[]): ComputedState {\n const marking = new Map<string, TokenInfo[]>();\n for (const [key, value] of base.marking) {\n marking.set(key, [...value]);\n }\n const enabled = new Set(base.enabledTransitions);\n const inFlight = new Set(base.inFlightTransitions);\n applyEvents(marking, enabled, inFlight, delta);\n return toImmutableState(marking, enabled, inFlight);\n}\n","/**\n * Converts CTPN NetEvent instances to serializable DebugResponse types.\n * TypeScript port of Java's NetEventConverter.\n */\n\nimport type { Token } from '../core/token.js';\nimport type { NetEvent } from '../event/net-event.js';\nimport type { NetEventInfo, TokenInfo } from './debug-response.js';\n\n/** Converts a NetEvent to a serializable NetEventInfo. */\nexport function toEventInfo(event: NetEvent, compact = false): NetEventInfo {\n switch (event.type) {\n case 'execution-started':\n return {\n type: 'ExecutionStarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: { netName: event.netName, executionId: event.executionId },\n };\n\n case 'execution-completed':\n return {\n type: 'ExecutionCompleted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: {\n netName: event.netName,\n executionId: event.executionId,\n totalDurationMs: event.totalDurationMs,\n },\n };\n\n case 'transition-enabled':\n return {\n type: 'TransitionEnabled',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {},\n };\n\n case 'transition-clock-restarted':\n return {\n type: 'TransitionClockRestarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {},\n };\n\n case 'transition-started':\n return {\n type: 'TransitionStarted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n consumedTokens: event.consumedTokens.map(t => compact ? compactTokenInfo(t) : tokenInfo(t)),\n },\n };\n\n case 'transition-completed':\n return {\n type: 'TransitionCompleted',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n producedTokens: event.producedTokens.map(t => compact ? compactTokenInfo(t) : tokenInfo(t)),\n durationMs: event.durationMs,\n },\n };\n\n case 'transition-failed':\n return {\n type: 'TransitionFailed',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n errorMessage: event.errorMessage,\n exceptionType: event.exceptionType,\n },\n };\n\n case 'transition-timed-out':\n return {\n type: 'TransitionTimedOut',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: {\n deadlineMs: event.deadlineMs,\n actualDurationMs: event.actualDurationMs,\n },\n };\n\n case 'action-timed-out':\n return {\n type: 'ActionTimedOut',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details: { timeoutMs: event.timeoutMs },\n };\n\n case 'token-added':\n return {\n type: 'TokenAdded',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: event.placeName,\n details: {\n token: compact ? compactTokenInfo(event.token) : tokenInfo(event.token),\n },\n };\n\n case 'token-removed':\n return {\n type: 'TokenRemoved',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: event.placeName,\n details: {\n token: compact ? compactTokenInfo(event.token) : tokenInfo(event.token),\n },\n };\n\n case 'marking-snapshot':\n return {\n type: 'MarkingSnapshot',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: null,\n placeName: null,\n details: {\n marking: convertMarking(event.marking, compact),\n },\n };\n\n case 'log-message': {\n const details: Record<string, unknown> = {\n loggerName: event.logger,\n level: event.level,\n message: event.message,\n };\n if (event.error != null) details['throwable'] = event.error;\n if (event.errorMessage != null) details['throwableMessage'] = event.errorMessage;\n return {\n type: 'LogMessage',\n timestamp: new Date(event.timestamp).toISOString(),\n transitionName: event.transitionName,\n placeName: null,\n details,\n };\n }\n }\n}\n\n/**\n * Converts a Token to a serializable {@link TokenInfo}.\n *\n * @remarks\n * The emitted `type` is `value.constructor.name` for objects and `typeof value`\n * for primitives — a *simple name*, not a fully-qualified type identifier.\n * TypeScript has no portable FQN, so cross-language replay from TypeScript\n * archives into a Java reader loses the original type identity (Java's\n * `Class.forName` will fail on simple names) and falls through to the\n * `Token<JsonNode>` graceful-degradation path. The `structured` payload\n * survives intact across languages.\n *\n * The v3 archive body format described in [EVT-025](../../../spec/08-events-observability.md)\n * always emits `structured` alongside `value` so the bundled debug UI keeps\n * rendering while LLM-facing consumers get typed fields. See {@link structuredValue}\n * for the projection rules.\n */\nexport function tokenInfo(token: Token<unknown>): TokenInfo {\n const value = token.value;\n const type = value != null ? typeof value === 'object' ? value.constructor.name : typeof value : 'null';\n const fullValue = value != null ? String(value) : 'null';\n const info: TokenInfo = {\n id: null,\n type,\n value: fullValue,\n timestamp: new Date(token.createdAt).toISOString(),\n };\n const structured = structuredValue(value);\n return structured === undefined ? info : { ...info, structured };\n}\n\n/**\n * Projects a token value into a JSON-friendly representation for the `structured`\n * TokenInfo field. Returns `undefined` when no useful projection exists (null values,\n * opaque objects Jackson-on-the-Java-side would drop); callers omit the field in that\n * case so wire size stays neutral for unstructurable tokens.\n *\n * @remarks\n * Implementation notes:\n * - Primitives and plain objects / arrays pass through untouched (already JSON-safe).\n * - Maps / Sets are projected to a plain shape — debug tooling doesn't need the\n * prototype identity and JSON consumers can't use it anyway.\n * - Classes with a `toJSON()` method are respected via structured clone (uses the\n * same path as `JSON.stringify`).\n *\n * Security: uses `JSON.parse(JSON.stringify(...))` which is safe against code\n * execution and prototype pollution. A hostile token value with a custom\n * `toJSON()` override could still return misleading data — archives are a\n * trust boundary (see [EVT-025](../../../spec/08-events-observability.md)).\n */\nfunction structuredValue(value: unknown): unknown | undefined {\n if (value == null) return undefined;\n const t = typeof value;\n if (t === 'string' || t === 'number' || t === 'boolean') return value;\n if (t === 'bigint') return String(value); // bigint → string for JSON-safety\n if (t === 'symbol' || t === 'function') return undefined;\n // Plain arrays / plain objects / objects with toJSON — JSON.parse(JSON.stringify(...))\n // is the cheapest way to drop non-serializable fields and flatten to wire-ready shape.\n try {\n const cloned = JSON.parse(JSON.stringify(value));\n // Skip empty objects — they're opaque beans with no useful structure, just inflating responses.\n if (cloned && typeof cloned === 'object' && !Array.isArray(cloned) && Object.keys(cloned).length === 0) {\n return undefined;\n }\n return cloned;\n } catch {\n return undefined;\n }\n}\n\n/** Converts a Token to compact TokenInfo (type only, no value). */\nexport function compactTokenInfo(token: Token<unknown>): TokenInfo {\n const value = token.value;\n const type = value != null ? typeof value === 'object' ? value.constructor.name : typeof value : 'null';\n return {\n id: null,\n type,\n value: null,\n timestamp: new Date(token.createdAt).toISOString(),\n };\n}\n\n/** Converts a marking map to serializable form. */\nexport function convertMarking(\n marking: ReadonlyMap<string, readonly Token<unknown>[]>,\n compact = false,\n): Record<string, readonly TokenInfo[]> {\n const result: Record<string, readonly TokenInfo[]> = {};\n const mapper = compact ? compactTokenInfo : tokenInfo;\n for (const [name, tokens] of marking) {\n result[name] = tokens.map(mapper);\n }\n return result;\n}\n","/**\n * Framework-agnostic handler for the Petri net debug protocol.\n * TypeScript port of Java's DebugProtocolHandler.\n *\n * Manages debug subscriptions, event filtering, breakpoints, and replay\n * for connected clients. Decoupled from any specific WebSocket framework\n * via the ResponseSink type.\n */\n\nimport type { NetEvent } from '../event/net-event.js';\nimport type { DebugCommand, EventFilter, BreakpointConfig } from './debug-command.js';\nimport type { DebugResponse, TokenInfo, NetEventInfo, ArchiveSummary, SessionSummary } from './debug-response.js';\nimport type { SessionArchiveStorage } from './archive/session-archive-storage.js';\nimport { SessionArchiveReader } from './archive/session-archive-reader.js';\nimport type { DebugSession } from './debug-session-registry.js';\nimport { type DebugSessionRegistry, buildNetStructure } from './debug-session-registry.js';\nimport type { Subscription } from './debug-event-store.js';\nimport { MarkingCache } from './marking-cache.js';\nimport { toEventInfo, tokenInfo, convertMarking } from './net-event-converter.js';\n\n/** Callback for sending responses to a connected client. */\nexport type ResponseSink = (response: DebugResponse) => void;\n\n/** Computed state from replaying events. */\nexport interface ComputedState {\n readonly marking: ReadonlyMap<string, readonly TokenInfo[]>;\n readonly enabledTransitions: readonly string[];\n readonly inFlightTransitions: readonly string[];\n}\n\n/** Maximum events per batch when sending historical events. */\nconst BATCH_SIZE = 500;\n\nexport class DebugProtocolHandler {\n private readonly _sessionRegistry: DebugSessionRegistry;\n private readonly _archiveStorage: SessionArchiveStorage | null;\n private readonly _clients = new Map<string, ClientState>();\n\n constructor(sessionRegistry: DebugSessionRegistry, archiveStorage?: SessionArchiveStorage | null) {\n this._sessionRegistry = sessionRegistry;\n this._archiveStorage = archiveStorage ?? null;\n }\n\n /** Registers a new client connection. */\n clientConnected(clientId: string, sink: ResponseSink): void {\n this._clients.set(clientId, new ClientState(sink));\n }\n\n /** Cleans up when a client disconnects. */\n clientDisconnected(clientId: string): void {\n const state = this._clients.get(clientId);\n this._clients.delete(clientId);\n if (state) state.subscriptions.cancelAll();\n }\n\n /** Handles a command from a connected client. */\n handleCommand(clientId: string, command: DebugCommand): void {\n const clientState = this._clients.get(clientId);\n if (!clientState) return;\n\n try {\n switch (command.type) {\n case 'listSessions': this.handleListSessions(clientState, command); break;\n case 'subscribe': this.handleSubscribe(clientState, command); break;\n case 'unsubscribe': this.handleUnsubscribe(clientState, command); break;\n case 'seek': this.handleSeek(clientState, command); break;\n case 'playbackSpeed': this.handlePlaybackSpeed(clientState, command); break;\n case 'filter': this.handleSetFilter(clientState, command); break;\n case 'pause': this.handlePause(clientState, command); break;\n case 'resume': this.handleResume(clientState, command); break;\n case 'stepForward': this.handleStepForward(clientState, command); break;\n case 'stepBackward': this.handleStepBackward(clientState, command); break;\n case 'setBreakpoint': this.handleSetBreakpoint(clientState, command); break;\n case 'clearBreakpoint': this.handleClearBreakpoint(clientState, command); break;\n case 'listBreakpoints': this.handleListBreakpoints(clientState, command); break;\n case 'listArchives': this.handleListArchives(clientState, command); break;\n case 'importArchive': this.handleImportArchive(clientState, command); break;\n case 'uploadArchive': this.handleUploadArchive(clientState, command); break;\n }\n } catch (e) {\n this.sendError(clientState, 'COMMAND_ERROR', e instanceof Error ? e.message : String(e), null);\n }\n }\n\n // ======================== Command Handlers ========================\n\n private handleListSessions(client: ClientState, cmd: Extract<DebugCommand, { type: 'listSessions' }>): void {\n const limit = cmd.limit ?? 50;\n const sessions = cmd.activeOnly\n ? this._sessionRegistry.listActiveSessions(limit, cmd.tagFilter)\n : this._sessionRegistry.listSessions(limit, cmd.tagFilter);\n\n const summaries = sessions.map(s => this.toProtocolSummary(s));\n\n this.send(client, { type: 'sessionList', sessions: summaries });\n }\n\n private toProtocolSummary(s: DebugSession): SessionSummary {\n const tags = this._sessionRegistry.tagsFor(s.sessionId);\n return {\n sessionId: s.sessionId,\n netName: s.netName,\n startTime: new Date(s.startTime).toISOString(),\n active: s.active,\n eventCount: s.eventStore.eventCount(),\n tags: Object.keys(tags).length > 0 ? tags : undefined,\n endTime: s.endTime !== undefined ? new Date(s.endTime).toISOString() : undefined,\n durationMs: s.endTime !== undefined ? s.endTime - s.startTime : undefined,\n };\n }\n\n private handleSubscribe(client: ClientState, cmd: Extract<DebugCommand, { type: 'subscribe' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n const eventStore = debugSession.eventStore;\n client.subscriptions.cancel(cmd.sessionId);\n\n const events = eventStore.events();\n const computed = computeState(events);\n const structure = buildNetStructure(debugSession);\n\n this.send(client, {\n type: 'subscribed',\n sessionId: cmd.sessionId,\n netName: debugSession.netName,\n dotDiagram: debugSession.dotDiagram,\n structure,\n currentMarking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n eventCount: eventStore.eventCount(),\n mode: cmd.mode,\n });\n\n const fromIndex = cmd.fromIndex ?? 0;\n if (cmd.mode === 'live') {\n this.subscribeLive(client, cmd.sessionId, debugSession, fromIndex);\n } else {\n this.subscribeReplay(client, cmd.sessionId, debugSession, fromIndex);\n }\n }\n\n private subscribeLive(client: ClientState, sessionId: string, debugSession: DebugSession, fromIndex: number): void {\n const eventStore = debugSession.eventStore;\n let eventIndex = fromIndex;\n\n const historicalEvents = eventStore.eventsFrom(fromIndex);\n if (historicalEvents.length > 0) {\n const filtered = historicalEvents\n .filter(e => client.subscriptions.matchesFilter(sessionId, e))\n .map(e => toEventInfo(e));\n this.sendInBatches(client, sessionId, fromIndex, filtered);\n eventIndex = fromIndex + historicalEvents.length;\n }\n\n const subscription = eventStore.subscribe(event => {\n if (!client.subscriptions.isPaused(sessionId) && client.subscriptions.matchesFilter(sessionId, event)) {\n const eventInfo = toEventInfo(event);\n const idx = eventIndex++;\n\n const hitBreakpoint = client.subscriptions.checkBreakpoints(sessionId, event);\n if (hitBreakpoint) {\n client.subscriptions.setPaused(sessionId, true);\n this.send(client, {\n type: 'breakpointHit',\n sessionId,\n breakpointId: hitBreakpoint.id,\n event: eventInfo,\n eventIndex: idx,\n });\n }\n\n this.send(client, { type: 'event', sessionId, index: idx, event: eventInfo });\n }\n });\n\n client.subscriptions.addSubscription(sessionId, subscription, eventIndex);\n }\n\n private subscribeReplay(client: ClientState, sessionId: string, debugSession: DebugSession, fromIndex: number): void {\n const eventStore = debugSession.eventStore;\n\n const events = eventStore.eventsFrom(fromIndex);\n const converted = events.map(e => toEventInfo(e));\n this.sendInBatches(client, sessionId, fromIndex, converted);\n\n const eventIndex = fromIndex + events.length;\n client.subscriptions.addSubscription(sessionId, null, eventIndex);\n client.subscriptions.setPaused(sessionId, true);\n }\n\n private handleUnsubscribe(client: ClientState, cmd: Extract<DebugCommand, { type: 'unsubscribe' }>): void {\n client.subscriptions.cancel(cmd.sessionId);\n this.send(client, { type: 'unsubscribed', sessionId: cmd.sessionId });\n }\n\n private handleSeek(client: ClientState, cmd: Extract<DebugCommand, { type: 'seek' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', 'Session not found', cmd.sessionId);\n return;\n }\n\n const events = debugSession.eventStore.events();\n const targetTs = new Date(cmd.timestamp).getTime();\n\n let targetIndex = 0;\n for (let i = 0; i < events.length; i++) {\n if (events[i]!.timestamp >= targetTs) {\n targetIndex = i;\n break;\n }\n targetIndex = i + 1;\n }\n\n client.subscriptions.setEventIndex(cmd.sessionId, targetIndex);\n const computed = client.subscriptions.computeStateAt(cmd.sessionId, events, targetIndex);\n\n this.send(client, {\n type: 'markingSnapshot',\n sessionId: cmd.sessionId,\n marking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n });\n }\n\n private handlePlaybackSpeed(client: ClientState, cmd: Extract<DebugCommand, { type: 'playbackSpeed' }>): void {\n client.subscriptions.setSpeed(cmd.sessionId, cmd.speed);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: client.subscriptions.isPaused(cmd.sessionId),\n speed: cmd.speed,\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleSetFilter(client: ClientState, cmd: Extract<DebugCommand, { type: 'filter' }>): void {\n client.subscriptions.setFilter(cmd.sessionId, cmd.filter);\n this.send(client, { type: 'filterApplied', sessionId: cmd.sessionId, filter: cmd.filter });\n }\n\n private handlePause(client: ClientState, cmd: Extract<DebugCommand, { type: 'pause' }>): void {\n client.subscriptions.setPaused(cmd.sessionId, true);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: true,\n speed: client.subscriptions.getSpeed(cmd.sessionId),\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleResume(client: ClientState, cmd: Extract<DebugCommand, { type: 'resume' }>): void {\n client.subscriptions.setPaused(cmd.sessionId, false);\n this.send(client, {\n type: 'playbackStateChanged',\n sessionId: cmd.sessionId,\n paused: false,\n speed: client.subscriptions.getSpeed(cmd.sessionId),\n currentIndex: client.subscriptions.getEventIndex(cmd.sessionId),\n });\n }\n\n private handleStepForward(client: ClientState, cmd: Extract<DebugCommand, { type: 'stepForward' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n const events = debugSession.eventStore.events();\n const currentIndex = client.subscriptions.getEventIndex(cmd.sessionId);\n\n if (currentIndex < events.length) {\n const event = events[currentIndex]!;\n this.send(client, {\n type: 'event',\n sessionId: cmd.sessionId,\n index: currentIndex,\n event: toEventInfo(event),\n });\n client.subscriptions.setEventIndex(cmd.sessionId, currentIndex + 1);\n }\n }\n\n private handleStepBackward(client: ClientState, cmd: Extract<DebugCommand, { type: 'stepBackward' }>): void {\n const debugSession = this._sessionRegistry.getSession(cmd.sessionId);\n if (!debugSession) {\n this.sendError(client, 'SESSION_NOT_FOUND', `Session not found: ${cmd.sessionId}`, cmd.sessionId);\n return;\n }\n\n let currentIndex = client.subscriptions.getEventIndex(cmd.sessionId);\n if (currentIndex > 0) {\n currentIndex--;\n client.subscriptions.setEventIndex(cmd.sessionId, currentIndex);\n\n const events = debugSession.eventStore.events();\n const computed = client.subscriptions.computeStateAt(cmd.sessionId, events, currentIndex);\n\n this.send(client, {\n type: 'markingSnapshot',\n sessionId: cmd.sessionId,\n marking: mapToRecord(computed.marking),\n enabledTransitions: computed.enabledTransitions,\n inFlightTransitions: computed.inFlightTransitions,\n });\n }\n }\n\n private handleSetBreakpoint(client: ClientState, cmd: Extract<DebugCommand, { type: 'setBreakpoint' }>): void {\n client.subscriptions.addBreakpoint(cmd.sessionId, cmd.breakpoint);\n this.send(client, { type: 'breakpointSet', sessionId: cmd.sessionId, breakpoint: cmd.breakpoint });\n }\n\n private handleClearBreakpoint(client: ClientState, cmd: Extract<DebugCommand, { type: 'clearBreakpoint' }>): void {\n client.subscriptions.removeBreakpoint(cmd.sessionId, cmd.breakpointId);\n this.send(client, { type: 'breakpointCleared', sessionId: cmd.sessionId, breakpointId: cmd.breakpointId });\n }\n\n private handleListBreakpoints(client: ClientState, cmd: Extract<DebugCommand, { type: 'listBreakpoints' }>): void {\n const breakpoints = client.subscriptions.getBreakpoints(cmd.sessionId);\n this.send(client, { type: 'breakpointList', sessionId: cmd.sessionId, breakpoints });\n }\n\n // ======================== Archive Handlers ========================\n\n private async handleListArchives(client: ClientState, cmd: Extract<DebugCommand, { type: 'listArchives' }>): Promise<void> {\n if (!this._archiveStorage || !this._archiveStorage.isAvailable()) {\n this.send(client, { type: 'archiveList', archives: [], storageAvailable: false });\n return;\n }\n try {\n const limit = cmd.limit ?? 50;\n const archived = await this._archiveStorage.list(limit, cmd.prefix);\n const summaries: ArchiveSummary[] = archived.map(a => ({\n sessionId: a.sessionId,\n key: a.key,\n sizeBytes: a.sizeBytes,\n lastModified: new Date(a.lastModified).toISOString(),\n }));\n this.send(client, { type: 'archiveList', archives: summaries, storageAvailable: true });\n } catch (e) {\n this.sendError(client, 'ARCHIVE_LIST_ERROR', e instanceof Error ? e.message : String(e), null);\n }\n }\n\n private async handleImportArchive(client: ClientState, cmd: Extract<DebugCommand, { type: 'importArchive' }>): Promise<void> {\n if (!this._archiveStorage || !this._archiveStorage.isAvailable()) {\n this.sendError(client, 'NO_ARCHIVE_STORAGE', 'Archive storage is not configured', null);\n return;\n }\n try {\n const data = await this._archiveStorage.retrieve(cmd.sessionId);\n const reader = new SessionArchiveReader();\n const imported = reader.readFull(data);\n const meta = imported.metadata;\n this._sessionRegistry.registerImported(\n meta.sessionId, meta.netName, meta.dotDiagram,\n meta.structure, imported.eventStore,\n new Date(meta.startTime).getTime(),\n );\n this.send(client, {\n type: 'archiveImported',\n sessionId: meta.sessionId,\n netName: meta.netName,\n eventCount: meta.eventCount,\n });\n this.broadcastSessionList();\n } catch (e) {\n this.sendError(client, 'ARCHIVE_IMPORT_ERROR', e instanceof Error ? e.message : String(e), cmd.sessionId);\n }\n }\n\n private async handleUploadArchive(client: ClientState, cmd: Extract<DebugCommand, { type: 'uploadArchive' }>): Promise<void> {\n try {\n const decoded = Buffer.from(cmd.data, 'base64');\n const reader = new SessionArchiveReader();\n const imported = reader.readFull(decoded);\n const meta = imported.metadata;\n this._sessionRegistry.registerImported(\n meta.sessionId, meta.netName, meta.dotDiagram,\n meta.structure, imported.eventStore,\n new Date(meta.startTime).getTime(),\n );\n this.send(client, {\n type: 'archiveImported',\n sessionId: meta.sessionId,\n netName: meta.netName,\n eventCount: meta.eventCount,\n });\n this.broadcastSessionList();\n } catch (e) {\n this.sendError(client, 'ARCHIVE_UPLOAD_ERROR', e instanceof Error ? e.message : String(e), null);\n }\n }\n\n private broadcastSessionList(): void {\n const sessions = this._sessionRegistry.listSessions(50);\n const summaries = sessions.map(s => this.toProtocolSummary(s));\n const response: DebugResponse = { type: 'sessionList', sessions: summaries };\n for (const clientState of this._clients.values()) {\n try { this.send(clientState, response); } catch { /* best-effort broadcast */ }\n }\n }\n\n // ======================== Helper Methods ========================\n\n private send(client: ClientState, response: DebugResponse): void {\n client.sink(response);\n }\n\n private sendError(client: ClientState, code: string, message: string, sessionId: string | null): void {\n this.send(client, { type: 'error', code, message, sessionId });\n }\n\n private sendInBatches(client: ClientState, sessionId: string, startIndex: number, events: readonly NetEventInfo[]): void {\n if (events.length === 0) {\n this.send(client, { type: 'eventBatch', sessionId, startIndex, events: [], hasMore: false });\n return;\n }\n for (let i = 0; i < events.length; i += BATCH_SIZE) {\n const end = Math.min(i + BATCH_SIZE, events.length);\n const chunk = events.slice(i, end);\n const hasMore = end < events.length;\n this.send(client, { type: 'eventBatch', sessionId, startIndex: startIndex + i, events: chunk, hasMore });\n }\n }\n}\n\n// ======================== State Computation (exported for MarkingCache) ========================\n\n/** Computes marking, enabled transitions, and in-flight transitions from events. */\nexport function computeState(events: readonly NetEvent[]): ComputedState {\n const marking = new Map<string, TokenInfo[]>();\n const enabled = new Set<string>();\n const inFlight = new Set<string>();\n applyEvents(marking, enabled, inFlight, events);\n return toImmutableState(marking, enabled, inFlight);\n}\n\n/** Applies events to mutable accumulator collections. */\nexport function applyEvents(\n marking: Map<string, TokenInfo[]>,\n enabled: Set<string>,\n inFlight: Set<string>,\n events: readonly NetEvent[],\n): void {\n for (const event of events) {\n switch (event.type) {\n case 'token-added': {\n let tokens = marking.get(event.placeName);\n if (!tokens) {\n tokens = [];\n marking.set(event.placeName, tokens);\n }\n tokens.push(tokenInfo(event.token));\n break;\n }\n case 'token-removed': {\n const tokens = marking.get(event.placeName);\n if (tokens && tokens.length > 0) tokens.shift();\n break;\n }\n case 'marking-snapshot': {\n marking.clear();\n const converted = convertMarking(event.marking);\n for (const [key, value] of Object.entries(converted)) {\n marking.set(key, [...value]);\n }\n break;\n }\n case 'transition-enabled':\n enabled.add(event.transitionName);\n break;\n case 'transition-started':\n enabled.delete(event.transitionName);\n inFlight.add(event.transitionName);\n break;\n case 'transition-completed':\n inFlight.delete(event.transitionName);\n break;\n case 'transition-failed':\n inFlight.delete(event.transitionName);\n break;\n case 'transition-timed-out':\n inFlight.delete(event.transitionName);\n break;\n case 'action-timed-out':\n inFlight.delete(event.transitionName);\n break;\n default:\n break;\n }\n }\n}\n\n/** Converts mutable accumulator collections into an immutable ComputedState. */\nexport function toImmutableState(\n marking: Map<string, TokenInfo[]>,\n enabled: Set<string>,\n inFlight: Set<string>,\n): ComputedState {\n const resultMarking = new Map<string, readonly TokenInfo[]>();\n for (const [key, value] of marking) {\n resultMarking.set(key, [...value]);\n }\n return {\n marking: resultMarking,\n enabledTransitions: [...enabled],\n inFlightTransitions: [...inFlight],\n };\n}\n\n/** Convert Map to Record for JSON serialization. */\nfunction mapToRecord(map: ReadonlyMap<string, readonly TokenInfo[]>): Record<string, readonly TokenInfo[]> {\n const result: Record<string, readonly TokenInfo[]> = {};\n for (const [key, value] of map) {\n result[key] = value;\n }\n return result;\n}\n\n// ======================== Client State ========================\n\nclass ClientState {\n readonly sink: ResponseSink;\n readonly subscriptions = new SubscriptionState();\n\n constructor(sink: ResponseSink) {\n this.sink = sink;\n }\n}\n\n// ======================== Subscription State ========================\n\ninterface SessionSubscription {\n subscription: Subscription | null;\n eventIndex: number;\n markingCache: MarkingCache;\n breakpoints: Map<string, BreakpointConfig>;\n paused: boolean;\n speed: number;\n filter: EventFilter | null;\n}\n\nclass SubscriptionState {\n private readonly _sessionSubs = new Map<string, SessionSubscription>();\n\n addSubscription(sessionId: string, subscription: Subscription | null, eventIndex: number): void {\n this._sessionSubs.set(sessionId, {\n subscription,\n eventIndex,\n markingCache: new MarkingCache(),\n breakpoints: new Map(),\n paused: false,\n speed: 1.0,\n filter: null,\n });\n }\n\n cancel(sessionId: string): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub?.subscription) sub.subscription.cancel();\n this._sessionSubs.delete(sessionId);\n }\n\n cancelAll(): void {\n for (const sub of this._sessionSubs.values()) {\n if (sub.subscription) sub.subscription.cancel();\n }\n this._sessionSubs.clear();\n }\n\n isPaused(sessionId: string): boolean {\n return this._sessionSubs.get(sessionId)?.paused ?? false;\n }\n\n setPaused(sessionId: string, paused: boolean): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.paused = paused;\n }\n\n getSpeed(sessionId: string): number {\n return this._sessionSubs.get(sessionId)?.speed ?? 1.0;\n }\n\n setSpeed(sessionId: string, speed: number): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.speed = speed;\n }\n\n getEventIndex(sessionId: string): number {\n return this._sessionSubs.get(sessionId)?.eventIndex ?? 0;\n }\n\n setEventIndex(sessionId: string, index: number): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.eventIndex = index;\n }\n\n computeStateAt(sessionId: string, events: readonly NetEvent[], targetIndex: number): ComputedState {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) return sub.markingCache.computeAt(events, targetIndex);\n return computeState(events.slice(0, targetIndex));\n }\n\n setFilter(sessionId: string, filter: EventFilter): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.filter = filter;\n }\n\n matchesFilter(sessionId: string, event: NetEvent): boolean {\n const sub = this._sessionSubs.get(sessionId);\n if (!sub?.filter) return true;\n\n const filter = sub.filter;\n\n // Event type: include then exclude\n const eventType = eventTypeToName(event);\n if (filter.eventTypes && filter.eventTypes.length > 0) {\n if (!filter.eventTypes.includes(eventType)) return false;\n }\n if (filter.excludeEventTypes && filter.excludeEventTypes.length > 0) {\n if (filter.excludeEventTypes.includes(eventType)) return false;\n }\n\n // Transition name: extract once, include then exclude\n const needTransition = (filter.transitionNames && filter.transitionNames.length > 0)\n || (filter.excludeTransitionNames && filter.excludeTransitionNames.length > 0);\n if (needTransition) {\n const tn = extractTransitionName(event);\n if (filter.transitionNames && filter.transitionNames.length > 0) {\n if (!tn || !filter.transitionNames.includes(tn)) return false;\n }\n if (filter.excludeTransitionNames && filter.excludeTransitionNames.length > 0) {\n if (tn && filter.excludeTransitionNames.includes(tn)) return false;\n }\n }\n\n // Place name: extract once, include then exclude\n const needPlace = (filter.placeNames && filter.placeNames.length > 0)\n || (filter.excludePlaceNames && filter.excludePlaceNames.length > 0);\n if (needPlace) {\n const pn = extractPlaceName(event);\n if (filter.placeNames && filter.placeNames.length > 0) {\n if (!pn || !filter.placeNames.includes(pn)) return false;\n }\n if (filter.excludePlaceNames && filter.excludePlaceNames.length > 0) {\n if (pn && filter.excludePlaceNames.includes(pn)) return false;\n }\n }\n\n return true;\n }\n\n addBreakpoint(sessionId: string, breakpoint: BreakpointConfig): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.breakpoints.set(breakpoint.id, breakpoint);\n }\n\n removeBreakpoint(sessionId: string, breakpointId: string): void {\n const sub = this._sessionSubs.get(sessionId);\n if (sub) sub.breakpoints.delete(breakpointId);\n }\n\n getBreakpoints(sessionId: string): readonly BreakpointConfig[] {\n const sub = this._sessionSubs.get(sessionId);\n return sub ? [...sub.breakpoints.values()] : [];\n }\n\n checkBreakpoints(sessionId: string, event: NetEvent): BreakpointConfig | null {\n const sub = this._sessionSubs.get(sessionId);\n if (!sub || sub.breakpoints.size === 0) return null;\n\n for (const bp of sub.breakpoints.values()) {\n if (!bp.enabled) continue;\n if (matchesBreakpoint(bp, event)) return bp;\n }\n return null;\n }\n}\n\nfunction eventTypeToName(event: NetEvent): string {\n const map: Record<string, string> = {\n 'execution-started': 'ExecutionStarted',\n 'execution-completed': 'ExecutionCompleted',\n 'transition-enabled': 'TransitionEnabled',\n 'transition-clock-restarted': 'TransitionClockRestarted',\n 'transition-started': 'TransitionStarted',\n 'transition-completed': 'TransitionCompleted',\n 'transition-failed': 'TransitionFailed',\n 'transition-timed-out': 'TransitionTimedOut',\n 'action-timed-out': 'ActionTimedOut',\n 'token-added': 'TokenAdded',\n 'token-removed': 'TokenRemoved',\n 'marking-snapshot': 'MarkingSnapshot',\n 'log-message': 'LogMessage',\n };\n return map[event.type] ?? event.type;\n}\n\nfunction extractTransitionName(event: NetEvent): string | null {\n switch (event.type) {\n case 'transition-enabled':\n case 'transition-clock-restarted':\n case 'transition-started':\n case 'transition-completed':\n case 'transition-failed':\n case 'transition-timed-out':\n case 'action-timed-out':\n case 'log-message':\n return event.transitionName;\n default:\n return null;\n }\n}\n\nfunction extractPlaceName(event: NetEvent): string | null {\n switch (event.type) {\n case 'token-added':\n case 'token-removed':\n return event.placeName;\n default:\n return null;\n }\n}\n\nfunction matchesBreakpoint(bp: BreakpointConfig, event: NetEvent): boolean {\n switch (bp.type) {\n case 'TRANSITION_ENABLED':\n return event.type === 'transition-enabled' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_START':\n return event.type === 'transition-started' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_COMPLETE':\n return event.type === 'transition-completed' && (bp.target === null || bp.target === event.transitionName);\n case 'TRANSITION_FAIL':\n return event.type === 'transition-failed' && (bp.target === null || bp.target === event.transitionName);\n case 'TOKEN_ADDED':\n return event.type === 'token-added' && (bp.target === null || bp.target === event.placeName);\n case 'TOKEN_REMOVED':\n return event.type === 'token-removed' && (bp.target === null || bp.target === event.placeName);\n default:\n return false;\n }\n}\n","/**\n * EventStore that delegates to both a primary store and a debug store.\n * TypeScript port of Java's DebugAwareEventStore.\n */\n\nimport type { EventStore } from '../event/event-store.js';\nimport type { NetEvent } from '../event/net-event.js';\nimport type { DebugEventStore } from './debug-event-store.js';\n\nexport class DebugAwareEventStore implements EventStore {\n private readonly _primary: EventStore;\n private readonly _debugStore: DebugEventStore;\n\n constructor(primary: EventStore, debugStore: DebugEventStore) {\n this._primary = primary;\n this._debugStore = debugStore;\n }\n\n append(event: NetEvent): void {\n this._primary.append(event);\n try {\n this._debugStore.append(event);\n } catch {\n // Debug failures must not break production\n }\n }\n\n events(): readonly NetEvent[] {\n return this._primary.events();\n }\n\n isEnabled(): boolean {\n return true;\n }\n\n size(): number {\n return this._primary.size();\n }\n\n isEmpty(): boolean {\n return this._primary.isEmpty();\n }\n\n /** Returns the underlying debug store for subscription management. */\n get debugStore(): DebugEventStore {\n return this._debugStore;\n }\n}\n","/**\n * File-system backed storage for session archives.\n * Uses Node.js fs/promises — no external dependencies.\n */\n\nimport { mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';\nimport { join, normalize, resolve } from 'node:path';\nimport type { ArchivedSessionSummary, SessionArchiveStorage, OutputStreamConsumer } from './session-archive-storage.js';\nimport { Writable } from 'node:stream';\n\nconst EXTENSION = '.archive.gz';\n\nexport class FileSessionArchiveStorage implements SessionArchiveStorage {\n private readonly _directory: string;\n\n constructor(directory: string) {\n this._directory = resolve(directory);\n }\n\n async storeStreaming(sessionId: string, writer: OutputStreamConsumer): Promise<void> {\n const target = this.archivePath(sessionId);\n const dir = join(target, '..');\n await mkdir(dir, { recursive: true });\n\n const chunks: Buffer[] = [];\n const writable = new Writable({\n write(chunk: Buffer, _encoding, callback) {\n chunks.push(chunk);\n callback();\n },\n });\n\n await writer(writable);\n await writeFile(target, Buffer.concat(chunks));\n }\n\n async list(limit: number, prefix?: string): Promise<readonly ArchivedSessionSummary[]> {\n try {\n await stat(this._directory);\n } catch {\n return [];\n }\n\n const results: ArchivedSessionSummary[] = [];\n let prefixDirs: string[];\n try {\n prefixDirs = await readdir(this._directory);\n } catch {\n return [];\n }\n\n for (const prefixDir of prefixDirs) {\n const prefixPath = join(this._directory, prefixDir);\n try {\n const s = await stat(prefixPath);\n if (!s.isDirectory()) continue;\n } catch {\n continue;\n }\n\n // Skip subdirectories that can't contain matches\n if (prefix && prefixDir.length === 1 && prefixDir[0] !== prefix[0]) continue;\n\n let files: string[];\n try {\n files = await readdir(prefixPath);\n } catch {\n continue;\n }\n\n for (const file of files) {\n if (!file.endsWith(EXTENSION)) continue;\n const sessionId = file.slice(0, -EXTENSION.length);\n if (prefix && !sessionId.startsWith(prefix)) continue;\n\n const filePath = join(prefixPath, file);\n try {\n const fileStat = await stat(filePath);\n const relativePath = join(prefixDir, file);\n results.push({\n sessionId,\n key: relativePath,\n sizeBytes: fileStat.size,\n lastModified: fileStat.mtimeMs,\n });\n } catch {\n // skip unreadable files\n }\n }\n }\n\n results.sort((a, b) => b.lastModified - a.lastModified);\n return results.slice(0, limit);\n }\n\n async retrieve(sessionId: string): Promise<Buffer> {\n const path = this.archivePath(sessionId);\n try {\n return await readFile(path);\n } catch {\n throw new Error(`Archive not found for session: ${sessionId}`);\n }\n }\n\n isAvailable(): boolean {\n return true;\n }\n\n private archivePath(sessionId: string): string {\n if (!sessionId || !sessionId.trim()) {\n throw new Error(`Invalid session ID: ${sessionId}`);\n }\n const prefix = sessionId[0]!;\n const resolved = normalize(join(this._directory, prefix, sessionId + EXTENSION));\n if (!resolved.startsWith(this._directory)) {\n throw new Error(`Session ID escapes archive directory: ${sessionId}`);\n }\n return resolved;\n }\n}\n","/**\n * Writes a debug session to a length-prefixed binary archive format.\n *\n * Format (inside gzip):\n * `[4 bytes: metadata JSON length][N bytes: metadata JSON]`\n * `[4 bytes: event JSON length][N bytes: event JSON]`\n * ...\n * (EOF terminates the stream)\n *\n * ## Format selection\n *\n * `write()` defaults to {@link CURRENT_VERSION} (v3 as of libpetri 1.8.0).\n * Callers that need to emit legacy archives — compatibility tests or readers\n * pinned to older libpetri versions — can call `writeV1()` or `writeV2()`.\n *\n * Note: all writers now emit the v3 token body format (structured alongside\n * value-string) regardless of header version. A 1.8.0+ writer cannot produce\n * byte-for-byte 1.7.x event bodies.\n *\n * Cross-language note: the `type` field in each serialized `TokenInfo` is\n * `value.constructor.name` — a simple name, not an FQN. Replaying a TypeScript\n * archive through the Java reader therefore cannot reconstruct the original\n * typed token (Java needs an FQN to `Class.forName`); Java falls through to\n * `Token<JsonNode>` preserving the `structured` JSON payload. See\n * {@link tokenInfo} for the full asymmetry and the [EVT-025](../../../../spec/08-events-observability.md)\n * spec entry for the full wire-format contract.\n */\n\nimport { gzipSync } from 'node:zlib';\nimport type { DebugSession } from '../debug-session-registry.js';\nimport { buildNetStructure } from '../debug-session-registry.js';\nimport type { NetEvent } from '../../event/net-event.js';\nimport { toEventInfo } from '../net-event-converter.js';\nimport type {\n SessionArchive,\n SessionArchiveV1,\n SessionArchiveV2,\n SessionArchiveV3,\n} from './session-archive.js';\nimport { computeMetadata } from './session-metadata.js';\n\nexport class SessionArchiveWriter {\n /**\n * Writes a complete session archive in the current format (v3 as of 1.8.0)\n * and returns the compressed bytes.\n */\n write(session: DebugSession): Buffer {\n return this.writeV3(session);\n }\n\n /**\n * Writes a session in the legacy v1 format. Use only for compatibility\n * testing or when producing archives for consumers pinned to libpetri ≤ 1.6.1.\n */\n writeV1(session: DebugSession): Buffer {\n // Single snapshot — both header eventCount and body iterate the same frozen array.\n // DebugEventStore.events() returns the live readonly array, so we spread once and\n // freeze to make accidental mutation a runtime error.\n const events: readonly NetEvent[] = Object.freeze([...session.eventStore.events()]);\n const header: SessionArchiveV1 = {\n version: 1,\n sessionId: session.sessionId,\n netName: session.netName,\n dotDiagram: session.dotDiagram,\n startTime: new Date(session.startTime).toISOString(),\n eventCount: events.length,\n structure: buildNetStructure(session),\n };\n return this.writeFramed(header, events);\n }\n\n /**\n * Writes a session in the v2 format — richer header with `endTime`, `tags`,\n * and pre-computed {@link SessionMetadata}.\n *\n * Two passes over the event store: one to compute metadata, one to serialize\n * events. `DebugEventStore` stores events in a plain readonly array and its\n * `[Symbol.iterator]()` returns a fresh array iterator each call, so both\n * passes walk the same sequence from the start.\n */\n writeV2(session: DebugSession): Buffer {\n // Single snapshot drives metadata, header eventCount, and body. See writeV1.\n const events: readonly NetEvent[] = Object.freeze([...session.eventStore.events()]);\n const metadata = computeMetadata(events);\n\n const header: SessionArchiveV2 = {\n version: 2,\n sessionId: session.sessionId,\n netName: session.netName,\n dotDiagram: session.dotDiagram,\n startTime: new Date(session.startTime).toISOString(),\n endTime:\n session.endTime !== undefined\n ? new Date(session.endTime).toISOString()\n : undefined,\n eventCount: events.length,\n // Snapshot of tags at archive-write time — record the state that was\n // current when the session was archived, not whatever happens on the\n // live session afterwards.\n tags: { ...session.tags },\n metadata,\n structure: buildNetStructure(session),\n };\n return this.writeFramed(header, events);\n }\n\n /**\n * Writes a session in the v3 format — same header shape as v2, with version=3\n * signalling that token payloads carry a `structured` field alongside the\n * legacy `value` string (see {@link tokenInfo}).\n */\n writeV3(session: DebugSession): Buffer {\n // Single snapshot drives metadata, header eventCount, and body. See writeV1.\n const events: readonly NetEvent[] = Object.freeze([...session.eventStore.events()]);\n const metadata = computeMetadata(events);\n\n const header: SessionArchiveV3 = {\n version: 3,\n sessionId: session.sessionId,\n netName: session.netName,\n dotDiagram: session.dotDiagram,\n startTime: new Date(session.startTime).toISOString(),\n endTime:\n session.endTime !== undefined\n ? new Date(session.endTime).toISOString()\n : undefined,\n eventCount: events.length,\n tags: { ...session.tags },\n metadata,\n structure: buildNetStructure(session),\n };\n return this.writeFramed(header, events);\n }\n\n /**\n * Shared framing logic: length-prefixed header JSON, then length-prefixed\n * event JSON, then gzip. All header versions share the identical event wire\n * format, so the body loop is version-agnostic.\n *\n * Takes the events snapshot directly so the body iterates the same array the\n * caller used to populate {@link SessionArchive.eventCount} — preserving the\n * `header.eventCount === events.length` invariant.\n */\n private writeFramed(header: SessionArchive, events: readonly NetEvent[]): Buffer {\n const parts: Buffer[] = [];\n\n // Header\n const metaBytes = Buffer.from(JSON.stringify(header), 'utf-8');\n const metaLen = Buffer.alloc(4);\n metaLen.writeUInt32BE(metaBytes.length);\n parts.push(metaLen, metaBytes);\n\n // Events — same serialization across all header versions\n for (const event of events) {\n const eventInfo = toEventInfo(event);\n const eventBytes = Buffer.from(JSON.stringify(eventInfo), 'utf-8');\n const eventLen = Buffer.alloc(4);\n eventLen.writeUInt32BE(eventBytes.length);\n parts.push(eventLen, eventBytes);\n }\n\n return gzipSync(Buffer.concat(parts));\n }\n}\n","/**\n * Shared metadata computation for session archives.\n *\n * Mirrors the Java `SessionMetadata.computeFrom` helper: single-pass scan of\n * an event iterable producing the histogram / first-last timestamps /\n * hasErrors triple. Reused by the v2 archive writer (at archive time) and by\n * read-path fallbacks that need aggregate stats for a v1 archive.\n */\n\nimport type { NetEvent } from '../../event/net-event.js';\nimport { toEventInfo } from '../net-event-converter.js';\nimport type { SessionMetadata } from './session-archive.js';\n\n/**\n * Walks the given event sequence once and produces a {@link SessionMetadata}\n * summary. Allocates one intermediate object for the histogram plus the\n * returned immutable-ish record.\n *\n * Histogram keys match the wire format emitted by {@link toEventInfo}\n * (PascalCase like `TransitionStarted`, `LogMessage`) so they are identical\n * to what the Java and Rust implementations produce.\n *\n * Keys are emitted in alphabetical order for deterministic JSON output\n * (prompt-cache friendly).\n */\nexport function computeMetadata(events: Iterable<NetEvent>): SessionMetadata {\n const raw: Record<string, number> = {};\n let first: number | undefined;\n let last: number | undefined;\n let hasErrors = false;\n\n for (const event of events) {\n // Reuse toEventInfo's PascalCase mapping so histogram keys match the\n // wire format the LLM already sees. Cheap — one small object per event,\n // garbage collected immediately.\n const typeName = toEventInfo(event).type;\n raw[typeName] = (raw[typeName] ?? 0) + 1;\n if (first === undefined) first = event.timestamp;\n last = event.timestamp;\n if (isErrorEvent(event)) hasErrors = true;\n }\n\n // Sort keys alphabetically for a deterministic JSON key order.\n const histogram: Record<string, number> = {};\n for (const key of Object.keys(raw).sort()) {\n histogram[key] = raw[key]!;\n }\n\n return {\n eventTypeHistogram: histogram,\n firstEventTime: first !== undefined ? new Date(first).toISOString() : undefined,\n lastEventTime: last !== undefined ? new Date(last).toISOString() : undefined,\n hasErrors,\n };\n}\n\n/**\n * Superset of `isFailureEvent` from `net-event.ts` that additionally treats\n * `LogMessage` at level `ERROR` (case-insensitive) as an error signal.\n *\n * Kept private to this module — `isFailureEvent` has a narrower meaning\n * (transition lifecycle failures only) and other callers rely on that.\n */\nfunction isErrorEvent(event: NetEvent): boolean {\n switch (event.type) {\n case 'transition-failed':\n case 'transition-timed-out':\n case 'action-timed-out':\n return true;\n case 'log-message':\n return event.level.toUpperCase() === 'ERROR';\n default:\n return false;\n }\n}\n","/**\n * Debug infrastructure for Petri net execution visualization.\n *\n * Provides a framework-agnostic debug protocol handler, event store with\n * live tailing, session registry, and marking cache for efficient replay.\n *\n * @module debug\n */\n\n// Protocol types\nexport type { DebugCommand, SubscriptionMode, BreakpointType, BreakpointConfig, EventFilter } from './debug-command.js';\nexport { eventFilterAll } from './debug-command.js';\nexport type {\n DebugResponse, SessionSummary, TokenInfo, NetEventInfo,\n PlaceInfo, TransitionInfo, NetStructure, ArchiveSummary,\n} from './debug-response.js';\n\n// Core infrastructure\nexport { DebugProtocolHandler } from './debug-protocol-handler.js';\nexport type { ResponseSink, ComputedState } from './debug-protocol-handler.js';\nexport { DebugEventStore, DEFAULT_MAX_EVENTS } from './debug-event-store.js';\nexport type { Subscription } from './debug-event-store.js';\nexport { DebugSessionRegistry, buildNetStructure } from './debug-session-registry.js';\nexport type { DebugSession, EventStoreFactory } from './debug-session-registry.js';\nexport type { SessionCompletionListener } from './session-completion-listener.js';\nexport { MarkingCache, SNAPSHOT_INTERVAL } from './marking-cache.js';\n\n// Converters and analysis\nexport { toEventInfo, tokenInfo, compactTokenInfo, convertMarking } from './net-event-converter.js';\nexport { DebugAwareEventStore } from './debug-aware-event-store.js';\nexport { PlaceAnalysis } from './place-analysis.js';\nexport type { PlaceAnalysisInfo } from './place-analysis.js';\n\n// Archive\nexport type { SessionArchive } from './archive/session-archive.js';\nexport { CURRENT_VERSION } from './archive/session-archive.js';\nexport type { SessionArchiveStorage, ArchivedSessionSummary, OutputStreamConsumer } from './archive/session-archive-storage.js';\nexport { FileSessionArchiveStorage } from './archive/file-session-archive-storage.js';\nexport { SessionArchiveWriter } from './archive/session-archive-writer.js';\nexport { SessionArchiveReader } from './archive/session-archive-reader.js';\nexport type { ImportedSession } from './archive/session-archive-reader.js';\n\n/**\n * Returns the path to the bundled debug UI assets directory.\n * Requires Node.js — resolves relative to this module's location.\n */\nexport async function debugUiAssetPath(): Promise<string> {\n // eslint-disable-next-line @typescript-eslint/no-implied-eval\n const dynamicImport = Function('m', 'return import(m)') as (m: string) => Promise<Record<string, unknown>>;\n const nodeUrl = await dynamicImport('node:url') as { fileURLToPath(url: string | URL): string };\n const nodePath = await dynamicImport('node:path') as { dirname(p: string): string; join(...paths: string[]): string };\n const thisDir = nodePath.dirname(nodeUrl.fileURLToPath(import.meta.url));\n return nodePath.join(thisDir, '..', 'debug-ui');\n}\n"],"mappings":"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","names":[]}
@@ -108,7 +108,7 @@ ${svgContent}
108
108
 
109
109
  // src/doclet/petri-net-plugin.ts
110
110
  async function getDotExport() {
111
- const mod = await import("../dot-exporter-MBIV5R67.js");
111
+ const mod = await import("../dot-exporter-DTLQPW5H.js");
112
112
  return mod.dotExport;
113
113
  }
114
114
  var TAG_NAME = "@petrinet";
@@ -0,0 +1,8 @@
1
+ import {
2
+ dotExport
3
+ } from "./chunk-2HWR2675.js";
4
+ import "./chunk-FN773SSE.js";
5
+ export {
6
+ dotExport
7
+ };
8
+ //# sourceMappingURL=dot-exporter-DTLQPW5H.js.map
@@ -93,7 +93,6 @@ interface GraphStyle {
93
93
  readonly forcelabels: boolean;
94
94
  readonly overlap: boolean;
95
95
  readonly outputorder: string;
96
- readonly splines: string;
97
96
  }
98
97
  declare const FONT: FontStyle;
99
98
  declare const GRAPH: GraphStyle;
@@ -8,7 +8,7 @@ import {
8
8
  nodeStyle,
9
9
  renderDot,
10
10
  sanitize
11
- } from "../chunk-JNHADILD.js";
11
+ } from "../chunk-2HWR2675.js";
12
12
  import "../chunk-FN773SSE.js";
13
13
  export {
14
14
  DEFAULT_DOT_CONFIG,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libpetri",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "Coloured Time Petri Net engine — TypeScript port",
5
5
  "homepage": "https://libpetri.org",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/export/styles.ts","../src/export/petri-net-mapper.ts","../src/export/dot-renderer.ts","../src/export/dot-exporter.ts"],"sourcesContent":["// GENERATED from spec/petri-net-styles.json — do not edit manually.\n// Regenerate with: scripts/generate-styles.sh\n\n/**\n * Style loader for Petri net visualization.\n *\n * Reads the shared style definition from `spec/petri-net-styles.json` and\n * exposes typed accessors for node and edge visual properties.\n *\n * @module export/styles\n */\n\nimport type { NodeShape, EdgeLineStyle, ArrowHead } from './graph.js';\n\n// ======================== Style Types ========================\n\nexport interface NodeVisual {\n readonly shape: NodeShape;\n readonly fill: string;\n readonly stroke: string;\n readonly penwidth: number;\n readonly style?: string;\n readonly height?: number;\n readonly width?: number;\n}\n\nexport interface EdgeVisual {\n readonly color: string;\n readonly style: EdgeLineStyle;\n readonly arrowhead: ArrowHead;\n readonly penwidth?: number;\n}\n\nexport interface FontStyle {\n readonly family: string;\n readonly nodeSize: number;\n readonly edgeSize: number;\n}\n\nexport interface GraphStyle {\n readonly nodesep: number;\n readonly ranksep: number;\n readonly forcelabels: boolean;\n readonly overlap: boolean;\n readonly outputorder: string;\n readonly splines: string;\n}\n\n// ======================== Inline Style Data ========================\n\n// Inlined from spec/petri-net-styles.json to avoid runtime JSON import issues.\n// Keep in sync with the spec file.\n\nconst NODE_STYLES: Record<NodeCategory, NodeVisual> = {\n place: { shape: 'circle', fill: '#FFFFFF', stroke: '#333333', penwidth: 1.5, width: 0.35 },\n start: { shape: 'circle', fill: '#d4edda', stroke: '#28a745', penwidth: 2.0, width: 0.35 },\n end: { shape: 'doublecircle', fill: '#cce5ff', stroke: '#004085', penwidth: 2.0, width: 0.35 },\n environment: { shape: 'circle', fill: '#f8d7da', stroke: '#721c24', penwidth: 2.0, style: 'dashed', width: 0.35 },\n transition: { shape: 'box', fill: '#fff3cd', stroke: '#856404', penwidth: 1.0, height: 0.4, width: 0.8 },\n};\n\nconst EDGE_STYLES: Record<EdgeCategory, EdgeVisual> = {\n input: { color: '#333333', style: 'solid', arrowhead: 'normal' },\n output: { color: '#333333', style: 'solid', arrowhead: 'normal' },\n inhibitor: { color: '#dc3545', style: 'solid', arrowhead: 'odot' },\n read: { color: '#6c757d', style: 'dashed', arrowhead: 'normal' },\n reset: { color: '#fd7e14', style: 'bold', arrowhead: 'normal', penwidth: 2.0 },\n};\n\nexport const FONT: FontStyle = { family: 'Helvetica,Arial,sans-serif', nodeSize: 12, edgeSize: 10 };\n\nexport const GRAPH: GraphStyle = { nodesep: 0.5, ranksep: 0.75, forcelabels: true, overlap: false, outputorder: 'edgesfirst', splines: 'curved' };\n\n// ======================== Public API ========================\n\nexport type NodeCategory = 'place' | 'start' | 'end' | 'environment' | 'transition';\nexport type EdgeCategory = 'input' | 'output' | 'inhibitor' | 'read' | 'reset';\n\n/** Returns the visual style for the given node category. */\nexport function nodeStyle(category: NodeCategory): NodeVisual {\n return NODE_STYLES[category];\n}\n\n/** Returns the visual style for the given edge/arc type. */\nexport function edgeStyle(arcType: EdgeCategory): EdgeVisual {\n return EDGE_STYLES[arcType];\n}\n","/**\n * Maps a PetriNet definition to a format-agnostic Graph.\n *\n * This is where all the Petri net semantics live. The mapper understands\n * places, transitions, arcs, timing, and priority. It produces a Graph\n * that can be rendered to DOT (or any other format) without Petri net knowledge.\n *\n * @module export/petri-net-mapper\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { Transition } from '../core/transition.js';\nimport type { Out } from '../core/out.js';\nimport { earliest, latest, hasDeadline } from '../core/timing.js';\nimport type { Graph, GraphNode, GraphEdge, RankDir } from './graph.js';\nimport { nodeStyle, edgeStyle, FONT, GRAPH } from './styles.js';\nimport type { NodeCategory } from './styles.js';\n\n// ======================== Configuration ========================\n\nexport interface DotConfig {\n readonly direction: RankDir;\n readonly showTypes: boolean;\n readonly showIntervals: boolean;\n readonly showPriority: boolean;\n readonly environmentPlaces?: ReadonlySet<string>;\n}\n\nexport const DEFAULT_DOT_CONFIG: DotConfig = {\n direction: 'TB',\n showTypes: true,\n showIntervals: true,\n showPriority: true,\n};\n\n// ======================== Public API ========================\n\n/** Sanitizes a name for use as a graph node ID. */\nexport function sanitize(name: string): string {\n return name.replace(/[^a-zA-Z0-9_]/g, '_');\n}\n\n/** Maps a PetriNet to a format-agnostic Graph. */\nexport function mapToGraph(net: PetriNet, config: DotConfig = DEFAULT_DOT_CONFIG): Graph {\n const places = analyzePlaces(net);\n const envNames = config.environmentPlaces ?? new Set<string>();\n\n const nodes: GraphNode[] = [];\n const edges: GraphEdge[] = [];\n\n // Place nodes\n for (const [name, info] of places) {\n const category = placeCategory(info, envNames.has(name));\n const style = nodeStyle(category);\n nodes.push({\n id: 'p_' + sanitize(name),\n label: '',\n shape: style.shape,\n fill: style.fill,\n stroke: style.stroke,\n penwidth: style.penwidth,\n semanticId: name,\n style: style.style,\n width: style.width,\n attrs: { xlabel: name, fixedsize: 'true' },\n });\n }\n\n // Transition nodes\n for (const t of net.transitions) {\n const style = nodeStyle('transition');\n nodes.push({\n id: 't_' + sanitize(t.name),\n label: transitionLabel(t, config),\n shape: style.shape,\n fill: style.fill,\n stroke: style.stroke,\n penwidth: style.penwidth,\n semanticId: t.name,\n height: style.height,\n width: style.width,\n });\n }\n\n // Edges\n for (const t of net.transitions) {\n const tid = 't_' + sanitize(t.name);\n\n // Input arcs from inputSpecs\n for (const spec of t.inputSpecs) {\n const pid = 'p_' + sanitize(spec.place.name);\n const inputStyle = edgeStyle('input');\n let label: string | undefined;\n switch (spec.type) {\n case 'exactly':\n label = `\\u00d7${spec.count}`;\n break;\n case 'all':\n label = '*';\n break;\n case 'at-least':\n label = `\\u2265${spec.minimum}`;\n break;\n }\n edges.push({\n from: pid,\n to: tid,\n label,\n color: inputStyle.color,\n style: inputStyle.style,\n arrowhead: inputStyle.arrowhead,\n arcType: 'input',\n });\n }\n\n // Output arcs from outputSpec\n if (t.outputSpec !== null) {\n edges.push(...outputEdges(tid, t.outputSpec, null));\n }\n\n // Inhibitor arcs\n for (const inh of t.inhibitors) {\n const pid = 'p_' + sanitize(inh.place.name);\n const inhStyle = edgeStyle('inhibitor');\n edges.push({\n from: pid,\n to: tid,\n color: inhStyle.color,\n style: inhStyle.style,\n arrowhead: inhStyle.arrowhead,\n arcType: 'inhibitor',\n });\n }\n\n // Read arcs\n for (const r of t.reads) {\n const pid = 'p_' + sanitize(r.place.name);\n const readStyle = edgeStyle('read');\n edges.push({\n from: pid,\n to: tid,\n label: 'read',\n color: readStyle.color,\n style: readStyle.style,\n arrowhead: readStyle.arrowhead,\n arcType: 'read',\n });\n }\n\n // Reset arcs (only those without matching output)\n const outputPlaceNames = t.outputSpec !== null\n ? new Set([...t.outputPlaces()].map(p => p.name))\n : new Set<string>();\n for (const rst of t.resets) {\n if (!outputPlaceNames.has(rst.place.name)) {\n const pid = 'p_' + sanitize(rst.place.name);\n const resetStyle = edgeStyle('reset');\n edges.push({\n from: tid,\n to: pid,\n label: 'reset',\n color: resetStyle.color,\n style: resetStyle.style,\n arrowhead: resetStyle.arrowhead,\n penwidth: resetStyle.penwidth,\n arcType: 'reset',\n });\n }\n }\n }\n\n return {\n id: sanitize(net.name),\n rankdir: config.direction,\n nodes,\n edges,\n subgraphs: [],\n graphAttrs: {\n nodesep: String(GRAPH.nodesep),\n ranksep: String(GRAPH.ranksep),\n forcelabels: String(GRAPH.forcelabels),\n overlap: String(GRAPH.overlap),\n fontname: FONT.family,\n outputorder: GRAPH.outputorder,\n splines: GRAPH.splines,\n },\n nodeDefaults: {\n fontname: FONT.family,\n fontsize: String(FONT.nodeSize),\n },\n edgeDefaults: {\n fontname: FONT.family,\n fontsize: String(FONT.edgeSize),\n },\n };\n}\n\n// ======================== Place Analysis ========================\n\ninterface PlaceInfo {\n hasIncoming: boolean;\n hasOutgoing: boolean;\n}\n\nfunction analyzePlaces(net: PetriNet): Map<string, PlaceInfo> {\n const map = new Map<string, PlaceInfo>();\n\n function ensure(name: string): PlaceInfo {\n let info = map.get(name);\n if (!info) {\n info = { hasIncoming: false, hasOutgoing: false };\n map.set(name, info);\n }\n return info;\n }\n\n for (const t of net.transitions) {\n for (const spec of t.inputSpecs) {\n ensure(spec.place.name).hasOutgoing = true;\n }\n if (t.outputSpec !== null) {\n for (const p of t.outputPlaces()) {\n ensure(p.name).hasIncoming = true;\n }\n }\n for (const inh of t.inhibitors) {\n ensure(inh.place.name);\n }\n for (const r of t.reads) {\n ensure(r.place.name).hasOutgoing = true;\n }\n for (const rst of t.resets) {\n ensure(rst.place.name);\n }\n }\n\n return map;\n}\n\nfunction placeCategory(info: PlaceInfo, isEnvironment: boolean): NodeCategory {\n if (isEnvironment) return 'environment';\n if (!info.hasIncoming) return 'start';\n if (!info.hasOutgoing) return 'end';\n return 'place';\n}\n\n// ======================== Helpers ========================\n\nfunction transitionLabel(t: Transition, config: DotConfig): string {\n const parts = [t.name];\n\n if (config.showIntervals) {\n const e = earliest(t.timing);\n const l = latest(t.timing);\n const max = hasDeadline(t.timing) ? String(l) : '\\u221e';\n parts.push(`[${e}, ${max}]ms`);\n }\n\n if (config.showPriority && t.priority !== 0) {\n parts.push(`prio=${t.priority}`);\n }\n\n return parts.join(' ');\n}\n\nfunction outputEdges(transitionId: string, out: Out, branchLabel: string | null): GraphEdge[] {\n const outStyle = edgeStyle('output');\n\n switch (out.type) {\n case 'place': {\n const pid = 'p_' + sanitize(out.place.name);\n return [{\n from: transitionId,\n to: pid,\n label: branchLabel ?? undefined,\n color: outStyle.color,\n style: outStyle.style,\n arrowhead: outStyle.arrowhead,\n arcType: 'output',\n }];\n }\n\n case 'forward-input': {\n const pid = 'p_' + sanitize(out.to.name);\n const label = (branchLabel ? branchLabel + ' ' : '') + '\\u27f5' + out.from.name;\n return [{\n from: transitionId,\n to: pid,\n label,\n color: outStyle.color,\n style: 'dashed' as const,\n arrowhead: outStyle.arrowhead,\n arcType: 'output',\n }];\n }\n\n case 'and':\n return out.children.flatMap(c => outputEdges(transitionId, c, branchLabel));\n\n case 'xor': {\n const edges: GraphEdge[] = [];\n for (const child of out.children) {\n const label = inferBranchLabel(child);\n edges.push(...outputEdges(transitionId, child, label));\n }\n return edges;\n }\n\n case 'timeout':\n return outputEdges(transitionId, out.child, `\\u23f1${out.afterMs}ms`);\n }\n}\n\nfunction inferBranchLabel(out: Out): string | null {\n switch (out.type) {\n case 'place': return out.place.name;\n case 'timeout': return `\\u23f1${out.afterMs}ms`;\n case 'forward-input': return out.to.name;\n case 'and':\n case 'xor':\n return null;\n }\n}\n","/**\n * Renders a Graph to DOT (Graphviz) string.\n *\n * Pure function with zero Petri net knowledge. Operates solely on the\n * format-agnostic Graph model.\n *\n * @module export/dot-renderer\n */\n\nimport type { Graph, GraphNode, GraphEdge, Subgraph } from './graph.js';\n\n// ======================== Public API ========================\n\n/** Renders a Graph to a DOT string suitable for Graphviz. */\nexport function renderDot(graph: Graph): string {\n const lines: string[] = [];\n\n lines.push(`digraph ${quoteId(graph.id)} {`);\n\n // Graph attributes\n lines.push(` rankdir=${graph.rankdir};`);\n for (const [key, value] of Object.entries(graph.graphAttrs)) {\n lines.push(` ${key}=${quoteAttr(value)};`);\n }\n\n // Node defaults\n if (Object.keys(graph.nodeDefaults).length > 0) {\n lines.push(` node [${formatAttrs(graph.nodeDefaults)}];`);\n }\n\n // Edge defaults\n if (Object.keys(graph.edgeDefaults).length > 0) {\n lines.push(` edge [${formatAttrs(graph.edgeDefaults)}];`);\n }\n\n lines.push('');\n\n // Subgraphs\n for (const sg of graph.subgraphs) {\n lines.push(...renderSubgraph(sg, ' '));\n lines.push('');\n }\n\n // Nodes\n for (const node of graph.nodes) {\n lines.push(` ${renderNode(node)}`);\n }\n\n if (graph.nodes.length > 0) {\n lines.push('');\n }\n\n // Edges\n for (const edge of graph.edges) {\n lines.push(` ${renderEdge(edge)}`);\n }\n\n lines.push('}');\n\n return lines.join('\\n');\n}\n\n// ======================== Internal Rendering ========================\n\nfunction renderNode(node: GraphNode): string {\n const attrs: Record<string, string> = {\n label: node.label,\n shape: node.shape,\n style: node.style ? `\"filled,${node.style}\"` : 'filled',\n fillcolor: node.fill,\n color: node.stroke,\n penwidth: String(node.penwidth),\n };\n\n if (node.height !== undefined) {\n attrs['height'] = String(node.height);\n }\n if (node.width !== undefined) {\n attrs['width'] = String(node.width);\n }\n\n // Merge extra attrs\n if (node.attrs) {\n for (const [key, value] of Object.entries(node.attrs)) {\n attrs[key] = value;\n }\n }\n\n return `${quoteId(node.id)} [${formatNodeAttrs(attrs)}];`;\n}\n\nfunction renderEdge(edge: GraphEdge): string {\n const attrs: Record<string, string> = {\n color: edge.color,\n style: edge.style,\n arrowhead: edge.arrowhead,\n };\n\n if (edge.label !== undefined) {\n attrs['label'] = edge.label;\n }\n if (edge.penwidth !== undefined) {\n attrs['penwidth'] = String(edge.penwidth);\n }\n\n // Merge extra attrs\n if (edge.attrs) {\n for (const [key, value] of Object.entries(edge.attrs)) {\n attrs[key] = value;\n }\n }\n\n return `${quoteId(edge.from)} -> ${quoteId(edge.to)} [${formatNodeAttrs(attrs)}];`;\n}\n\nfunction renderSubgraph(sg: Subgraph, indent: string): string[] {\n const lines: string[] = [];\n lines.push(`${indent}subgraph ${quoteId('cluster_' + sg.id)} {`);\n\n if (sg.label !== undefined) {\n lines.push(`${indent} label=${quoteAttr(sg.label)};`);\n }\n\n if (sg.attrs) {\n for (const [key, value] of Object.entries(sg.attrs)) {\n lines.push(`${indent} ${key}=${quoteAttr(value)};`);\n }\n }\n\n for (const node of sg.nodes) {\n lines.push(`${indent} ${renderNode(node)}`);\n }\n\n lines.push(`${indent}}`);\n return lines;\n}\n\n// ======================== DOT Quoting ========================\n\n/** Quotes a DOT identifier. Always quotes to be safe with special chars. */\nfunction quoteId(id: string): string {\n // DOT keywords that must be quoted\n if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(id) && !isDotKeyword(id)) {\n return id;\n }\n return `\"${escapeDot(id)}\"`;\n}\n\n/** Quotes a DOT attribute value. */\nfunction quoteAttr(value: string): string {\n // Numbers don't need quoting\n if (/^-?\\d+(\\.\\d+)?$/.test(value)) {\n return value;\n }\n return `\"${escapeDot(value)}\"`;\n}\n\n/** Escapes special characters for DOT strings. */\nfunction escapeDot(s: string): string {\n return s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Formats node/edge attributes where certain values (like style with commas)\n * need special handling.\n */\nfunction formatNodeAttrs(attrs: Record<string, string>): string {\n return Object.entries(attrs)\n .map(([key, value]) => {\n // Style values that are already pre-quoted (contain the quote char)\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return `${key}=${value}`;\n }\n return `${key}=${quoteAttr(value)}`;\n })\n .join(', ');\n}\n\n/** Formats simple key=value attributes. */\nfunction formatAttrs(attrs: Readonly<Record<string, string>>): string {\n return Object.entries(attrs)\n .map(([key, value]) => `${key}=${quoteAttr(value)}`)\n .join(', ');\n}\n\n/** DOT language keywords that must be quoted when used as identifiers. */\nfunction isDotKeyword(id: string): boolean {\n const lower = id.toLowerCase();\n return lower === 'graph' || lower === 'digraph' || lower === 'subgraph'\n || lower === 'node' || lower === 'edge' || lower === 'strict';\n}\n","/**\n * Convenience function for exporting a PetriNet to DOT format.\n *\n * @module export/dot-exporter\n */\n\nimport type { PetriNet } from '../core/petri-net.js';\nimport type { DotConfig } from './petri-net-mapper.js';\nimport { mapToGraph } from './petri-net-mapper.js';\nimport { renderDot } from './dot-renderer.js';\n\n/**\n * Exports a PetriNet to DOT (Graphviz) format.\n *\n * @param net the Petri net to export\n * @param config optional export configuration\n * @returns DOT string suitable for rendering with Graphviz\n */\nexport function dotExport(net: PetriNet, config?: DotConfig): string {\n return renderDot(mapToGraph(net, config));\n}\n"],"mappings":"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","names":[]}
@@ -1,8 +0,0 @@
1
- import {
2
- dotExport
3
- } from "./chunk-JNHADILD.js";
4
- import "./chunk-FN773SSE.js";
5
- export {
6
- dotExport
7
- };
8
- //# sourceMappingURL=dot-exporter-MBIV5R67.js.map