@fortemi/graph 2026.7.1 → 2026.7.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.
package/dist/index.d.ts CHANGED
@@ -335,6 +335,6 @@ declare class GraphController {
335
335
  saveCurrentCommunity(input: CommunityCreateInput): Promise<CommunitySourceDescriptor>;
336
336
  }
337
337
 
338
- declare const VERSION = "2026.7.1";
338
+ declare const VERSION = "2026.7.3";
339
339
 
340
340
  export { COMMUNITY_COLORS, type CommunityGraph, type ExpandOptions, type FitOptions, GRAPH_SNAPSHOT_VERSION, type GraphBounds, type GraphCommunity, GraphController, type GraphControllerDb, type GraphControllerListener, type GraphControllerOptions, type GraphControllerState, type GraphControllerStatus, type GraphEdge, type GraphFilter, type GraphLayoutAlgorithm, type GraphLayoutState, type GraphNode, type GraphSnapshot, type GraphSourceMode, type GraphSourceRef, type GraphTransitionState, type LayoutOptions, type NodeRadiusOptions, type NodeRadiusResolver, type PositionedCommunity, type PositionedGraph, type PositionedGraphNode, type SerializeSnapshotOptions, UNASSIGNED_COMMUNITY_COLOR, VERSION, type ViewportTransform, buildAdjacency, colorForCommunity, computeDegrees, computeGraphBounds, deserializeGraphSnapshot, expandNeighborhood, filterCommunityGraph, fitGraphToViewport, layoutCommunityGraph, neighborhoodSubgraph, neighborsOf, nodeRadius, serializeGraphSnapshot, stringifyGraphSnapshot, subgraphForNodes };
package/dist/index.js CHANGED
@@ -609,7 +609,7 @@ var GraphController = class _GraphController {
609
609
  };
610
610
 
611
611
  // src/index.ts
612
- var VERSION = "2026.7.1";
612
+ var VERSION = "2026.7.3";
613
613
 
614
614
  export { COMMUNITY_COLORS, GRAPH_SNAPSHOT_VERSION, GraphController, UNASSIGNED_COMMUNITY_COLOR, VERSION, buildAdjacency, colorForCommunity, computeDegrees, computeGraphBounds, deserializeGraphSnapshot, expandNeighborhood, filterCommunityGraph, fitGraphToViewport, layoutCommunityGraph, neighborhoodSubgraph, neighborsOf, nodeRadius, serializeGraphSnapshot, stringifyGraphSnapshot, subgraphForNodes };
615
615
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/degree.ts","../src/color.ts","../src/filter.ts","../src/rng.ts","../src/layout.ts","../src/bounds.ts","../src/neighborhood.ts","../src/serialize.ts","../src/controller.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { CommunityGraph } from './types.js'\n\n/** Count the (undirected) degree of every node, including isolated nodes (0). */\nexport function computeDegrees(graph: CommunityGraph): Map<string, number> {\n const degree = new Map<string, number>()\n for (const node of graph.nodes) degree.set(node.id, 0)\n for (const edge of graph.edges) {\n degree.set(edge.source, (degree.get(edge.source) ?? 0) + 1)\n degree.set(edge.target, (degree.get(edge.target) ?? 0) + 1)\n }\n return degree\n}\n\nexport interface NodeRadiusOptions {\n /** Radius of a degree-0 node. */\n base?: number\n /** Pixels added per unit of degree. */\n perDegree?: number\n /** Hard floor on the radius. */\n min?: number\n /** Hard ceiling on the radius. */\n max?: number\n}\n\n/**\n * Map a node degree to a render radius. Defaults match the values historically\n * used by the React `GraphView`: `clamp(5 + degree * 1.5, 5, 16)`.\n */\nexport function nodeRadius(degree: number, options: NodeRadiusOptions = {}): number {\n const base = options.base ?? 5\n const perDegree = options.perDegree ?? 1.5\n const min = options.min ?? 5\n const max = options.max ?? 16\n return Math.max(min, Math.min(max, base + degree * perDegree))\n}\n","/** Default qualitative palette for community coloring (8 hues). */\nexport const COMMUNITY_COLORS = [\n '#2f6fbb',\n '#d97706',\n '#218838',\n '#7c3aed',\n '#c2410c',\n '#0f766e',\n '#be185d',\n '#4b5563',\n] as const\n\n/** Color used for nodes that are not assigned to any community. */\nexport const UNASSIGNED_COMMUNITY_COLOR = '#64748b'\n\n/**\n * Deterministically assign a color to a community id by hashing the id into the\n * palette. The same id always maps to the same color across runs and hosts.\n * Pass a custom `palette` to theme the output. Matches the historical\n * `GraphView` color assignment.\n */\nexport function colorForCommunity(\n communityId: string | undefined,\n palette: readonly string[] = COMMUNITY_COLORS,\n unassignedColor: string = UNASSIGNED_COMMUNITY_COLOR,\n): string {\n if (!communityId) return unassignedColor\n if (palette.length === 0) return unassignedColor\n let hash = 0\n for (const char of communityId) hash = (hash * 31 + char.charCodeAt(0)) | 0\n return palette[Math.abs(hash) % palette.length]\n}\n","import type { CommunityGraph, GraphNode } from './types.js'\n\nexport interface GraphFilter {\n /** Keep only nodes belonging to these communities (by community id). */\n communityIds?: string[]\n /** Keep only edges whose `kind` is in this set. */\n edgeKinds?: string[]\n /** Explicit allow-list of node ids. Useful for privacy / visibility filtering. */\n nodeIds?: string[]\n /**\n * Arbitrary per-node predicate evaluated against the (allow-listed) nodes.\n * Returning `false` removes the node and any edge touching it. Hosts whose\n * nodes carry extra metadata (privacy class, type, etc.) can filter on it here.\n */\n nodePredicate?: (node: GraphNode) => boolean\n}\n\n/**\n * Produce a new {@link CommunityGraph} containing only the nodes, edges, and\n * community memberships permitted by `filter`. Pure — the input is not mutated.\n *\n * Filtering precedence:\n * 1. `communityIds` (if non-empty) restricts the candidate node set to members\n * of those communities; otherwise `nodeIds` (if given) is the candidate set,\n * else all nodes.\n * 2. `nodePredicate` further narrows the candidate set.\n * 3. Edges survive only when both endpoints survive and `edgeKinds` permits.\n * 4. Empty communities are dropped.\n */\nexport function filterCommunityGraph(\n graph: CommunityGraph | null | undefined,\n filter?: GraphFilter,\n): CommunityGraph {\n if (!graph) return { nodes: [], edges: [], communities: [] }\n\n const nodeIds = new Set(filter?.nodeIds ?? graph.nodes.map((node) => node.id))\n if (filter?.communityIds?.length) {\n const allowedCommunities = new Set(filter.communityIds)\n nodeIds.clear()\n for (const community of graph.communities) {\n if (allowedCommunities.has(community.id)) {\n for (const nodeId of community.nodes) nodeIds.add(nodeId)\n }\n }\n }\n\n const predicate = filter?.nodePredicate\n if (predicate) {\n for (const node of graph.nodes) {\n if (nodeIds.has(node.id) && !predicate(node)) nodeIds.delete(node.id)\n }\n }\n\n const edgeKinds = filter?.edgeKinds ? new Set(filter.edgeKinds) : null\n const nodes = graph.nodes.filter((node) => nodeIds.has(node.id))\n const edges = graph.edges.filter((edge) => (\n nodeIds.has(edge.source)\n && nodeIds.has(edge.target)\n && (!edgeKinds || edgeKinds.has(edge.kind ?? ''))\n ))\n const communities = graph.communities\n .map((community) => ({ ...community, nodes: community.nodes.filter((nodeId) => nodeIds.has(nodeId)) }))\n .filter((community) => community.nodes.length > 0)\n return { nodes, edges, communities }\n}\n","// Tiny deterministic PRNG (mulberry32). Used by the force layout to seed\n// initial jitter so that identical (seed, graph, options) always yields\n// identical coordinates — no Math.random, no time, no platform variance.\n\n/**\n * Create a deterministic pseudo-random generator from a 32-bit integer seed.\n * Returns a function producing floats in [0, 1). Identical seeds yield\n * identical sequences across platforms.\n */\nexport function mulberry32(seed: number): () => number {\n // Coerce to a non-zero unsigned 32-bit integer so seed 0 still advances.\n let a = (seed >>> 0) || 0x9e3779b9\n return function next(): number {\n a |= 0\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n","import { computeDegrees, nodeRadius as defaultNodeRadius, type NodeRadiusOptions } from './degree.js'\nimport { mulberry32 } from './rng.js'\nimport type {\n CommunityGraph,\n GraphLayoutAlgorithm,\n GraphNode,\n PositionedCommunity,\n PositionedGraph,\n PositionedGraphNode,\n} from './types.js'\n\n/**\n * How to derive each node's render radius. Either a fixed pixel value, a set of\n * {@link NodeRadiusOptions} fed to the default degree→radius mapping, or a full\n * resolver `(degree, node) => number`.\n */\nexport type NodeRadiusResolver =\n | number\n | NodeRadiusOptions\n | ((degree: number, node: GraphNode) => number)\n\nexport interface LayoutOptions {\n /** Layout algorithm. `force` runs deterministic settlement; the others are closed-form. */\n algorithm?: GraphLayoutAlgorithm\n width?: number\n height?: number\n /** Seed for the deterministic PRNG used by `force` initial jitter. Identical seed ⇒ identical output. */\n seed?: number\n /** Number of settlement iterations for the `force` algorithm. */\n ticks?: number\n /** Per-node render radius (default: degree-derived, clamped 5..16). */\n nodeRadius?: NodeRadiusResolver\n /** Target edge length in px for the spring force (`force` only). */\n linkDistance?: number\n /** Spring stiffness 0..1 (`force` only). */\n linkStrength?: number\n /** Repulsion magnitude; negative pushes nodes apart (`force` only). */\n chargeStrength?: number\n /** Extra spacing beyond `r_i + r_j` when resolving collisions (`force` only). */\n collisionPadding?: number\n /** Pull toward the node's community centroid, 0..1 (`force` only). */\n communityStrength?: number\n /** Keep every node center at least this many px from each canvas edge. */\n boundsPadding?: number\n}\n\nconst DEFAULTS = {\n width: 760,\n height: 460,\n seed: 1,\n ticks: 300,\n linkDistance: 60,\n linkStrength: 0.08,\n chargeStrength: -240,\n collisionPadding: 2,\n communityStrength: 0.05,\n boundsPadding: 24,\n} as const\n\n/** Mild global pull toward the canvas center so disconnected nodes don't drift. */\nconst GRAVITY = 0.02\n\nfunction resolveRadius(\n resolver: NodeRadiusResolver | undefined,\n degree: number,\n node: GraphNode,\n): number {\n if (resolver === undefined) return defaultNodeRadius(degree)\n if (typeof resolver === 'number') return resolver\n if (typeof resolver === 'function') return resolver(degree, node)\n return defaultNodeRadius(degree, resolver)\n}\n\n/** Clamp `value` into `[lo, hi]`, collapsing to the midpoint if the range inverts. */\nfunction clampToRange(value: number, lo: number, hi: number): number {\n if (lo > hi) return (lo + hi) / 2\n return Math.max(lo, Math.min(hi, value))\n}\n\n/**\n * Deterministically position the nodes of a {@link CommunityGraph} in 2D space.\n *\n * For the default `force` algorithm this runs a fixed-iteration, seeded force\n * settlement (spring link attraction, charge repulsion, collision spacing,\n * community cohesion, centering, and bounds clamping). It is fully synchronous\n * and headless — no animation frames — so the same `(graph, options)` always\n * yields identical coordinates, safe for snapshot rendering and SSR. The\n * `radial`, `community`, and `manual` algorithms remain closed-form.\n *\n * Every node is annotated with its render radius `r`, degree, and resolved\n * community; the result also carries community centroids over the final layout.\n */\nexport function layoutCommunityGraph(\n graph: CommunityGraph,\n options: LayoutOptions = {},\n): PositionedGraph {\n const algorithm = options.algorithm ?? 'force'\n const width = options.width ?? DEFAULTS.width\n const height = options.height ?? DEFAULTS.height\n const boundsPadding = options.boundsPadding ?? DEFAULTS.boundsPadding\n\n const degree = computeDegrees(graph)\n\n const communityByNode = new Map<string, string>()\n for (const community of graph.communities) {\n for (const nodeId of community.nodes) {\n if (!communityByNode.has(nodeId)) communityByNode.set(nodeId, community.id)\n }\n }\n\n const centerX = width / 2\n const centerY = height / 2\n const radius = Math.max(40, Math.min(width, height) * 0.38)\n const n = graph.nodes.length\n\n // Per-node render radius (stable, used by force spacing and by consumers).\n const r = graph.nodes.map((node) =>\n resolveRadius(options.nodeRadius, degree.get(node.id) ?? 0, node),\n )\n\n // Index from node id → array position (edges reference nodes by id).\n const indexOf = new Map<string, number>()\n graph.nodes.forEach((node, i) => indexOf.set(node.id, i))\n\n // Community ring anchors — used both as closed-form positions and as the\n // initial seed for force settlement, keeping clusters legible.\n const communityIndexById = new Map<string, number>()\n graph.communities.forEach((community, i) => communityIndexById.set(community.id, i))\n\n const x = new Float64Array(n)\n const y = new Float64Array(n)\n\n // --- Initial / closed-form positions ---------------------------------------\n graph.nodes.forEach((node, index) => {\n const angle = (Math.PI * 2 * index) / Math.max(1, n)\n const communityId = communityByNode.get(node.id)\n const communityIndex = communityId !== undefined ? communityIndexById.get(communityId) ?? -1 : -1\n const communityAngle =\n (Math.PI * 2 * Math.max(0, communityIndex)) / Math.max(1, graph.communities.length)\n const useCommunityOrbit = algorithm === 'community' || algorithm === 'force'\n const communityRadius = algorithm === 'community' ? radius * 0.55 : radius\n const localRadius =\n algorithm === 'force'\n ? radius * (0.7 + ((degree.get(node.id) ?? 0) % 4) * 0.08)\n : radius\n\n if (useCommunityOrbit && communityIndex >= 0) {\n x[index] = centerX + Math.cos(communityAngle) * communityRadius + Math.cos(angle) * 46\n y[index] = centerY + Math.sin(communityAngle) * communityRadius + Math.sin(angle) * 46\n } else {\n x[index] = centerX + Math.cos(angle) * localRadius\n y[index] =\n centerY + Math.sin(angle) * (algorithm === 'radial' ? radius : localRadius * 0.72)\n }\n })\n\n // --- Force settlement (force algorithm only) -------------------------------\n if (algorithm === 'force' && n > 1) {\n const ticks = Math.max(0, Math.floor(options.ticks ?? DEFAULTS.ticks))\n const seed = options.seed ?? DEFAULTS.seed\n const linkDistance = options.linkDistance ?? DEFAULTS.linkDistance\n const linkStrength = options.linkStrength ?? DEFAULTS.linkStrength\n const chargeStrength = options.chargeStrength ?? DEFAULTS.chargeStrength\n const collisionPadding = options.collisionPadding ?? DEFAULTS.collisionPadding\n const communityStrength = options.communityStrength ?? DEFAULTS.communityStrength\n\n const rng = mulberry32(seed)\n // Deterministic jitter so no two seeded nodes coincide (avoids div-by-zero).\n for (let i = 0; i < n; i++) {\n x[i] += (rng() - 0.5) * 8\n y[i] += (rng() - 0.5) * 8\n }\n\n // Pre-resolve edge endpoints to array indices once.\n const links: Array<{ a: number; b: number; weight: number }> = []\n for (const edge of graph.edges) {\n const a = indexOf.get(edge.source)\n const b = indexOf.get(edge.target)\n if (a === undefined || b === undefined || a === b) continue\n links.push({ a, b, weight: edge.weight > 0 ? edge.weight : 1 })\n }\n\n // Community membership as array indices, for centroid cohesion.\n const communityOf = graph.nodes.map((node) => communityByNode.get(node.id))\n const communityIds = graph.communities.map((c) => c.id)\n\n const dispX = new Float64Array(n)\n const dispY = new Float64Array(n)\n const chargeCutoff = linkDistance * 6\n const cooling = ticks > 0 ? Math.pow(0.001, 1 / ticks) : 1\n let alpha = 1\n\n for (let t = 0; t < ticks; t++) {\n dispX.fill(0)\n dispY.fill(0)\n\n // Spring link attraction toward linkDistance.\n for (const link of links) {\n let dx = x[link.b] - x[link.a]\n let dy = y[link.b] - y[link.a]\n const dist = Math.max(0.01, Math.hypot(dx, dy))\n const force = ((dist - linkDistance) / dist) * linkStrength * link.weight\n dx *= force\n dy *= force\n dispX[link.a] += dx\n dispY[link.a] += dy\n dispX[link.b] -= dx\n dispY[link.b] -= dy\n }\n\n // Pairwise charge repulsion (with a distance cutoff for dense graphs).\n for (let i = 0; i < n; i++) {\n for (let j = i + 1; j < n; j++) {\n const dx = x[i] - x[j]\n const dy = y[i] - y[j]\n const dist = Math.max(0.01, Math.hypot(dx, dy))\n if (dist > chargeCutoff) continue\n // chargeStrength is negative ⇒ repulsion magnitude is positive.\n const mag = -chargeStrength / dist\n const ux = (dx / dist) * mag\n const uy = (dy / dist) * mag\n dispX[i] += ux\n dispY[i] += uy\n dispX[j] -= ux\n dispY[j] -= uy\n }\n }\n\n // Community cohesion (toward centroid) + global centering gravity.\n if (communityStrength > 0 && communityIds.length > 0) {\n const cx = new Float64Array(communityIds.length)\n const cy = new Float64Array(communityIds.length)\n const cn = new Int32Array(communityIds.length)\n const idxById = new Map<string, number>()\n communityIds.forEach((id, i) => idxById.set(id, i))\n for (let i = 0; i < n; i++) {\n const cid = communityOf[i]\n if (cid === undefined) continue\n const ci = idxById.get(cid)\n if (ci === undefined) continue\n cx[ci] += x[i]\n cy[ci] += y[i]\n cn[ci] += 1\n }\n for (let i = 0; i < n; i++) {\n const cid = communityOf[i]\n if (cid === undefined) continue\n const ci = idxById.get(cid)\n if (ci === undefined || cn[ci] === 0) continue\n dispX[i] += (cx[ci] / cn[ci] - x[i]) * communityStrength\n dispY[i] += (cy[ci] / cn[ci] - y[i]) * communityStrength\n }\n }\n for (let i = 0; i < n; i++) {\n dispX[i] += (centerX - x[i]) * GRAVITY\n dispY[i] += (centerY - y[i]) * GRAVITY\n }\n\n // Apply soft forces, cooled by alpha.\n for (let i = 0; i < n; i++) {\n x[i] += dispX[i] * alpha\n y[i] += dispY[i] * alpha\n }\n\n // Hard collision resolution (full strength) so nodes don't overlap.\n for (let i = 0; i < n; i++) {\n for (let j = i + 1; j < n; j++) {\n const dx = x[i] - x[j]\n const dy = y[i] - y[j]\n const dist = Math.max(0.01, Math.hypot(dx, dy))\n const minDist = r[i] + r[j] + collisionPadding\n if (dist >= minDist) continue\n const push = (minDist - dist) / 2\n const ux = (dx / dist) * push\n const uy = (dy / dist) * push\n x[i] += ux\n y[i] += uy\n x[j] -= ux\n y[j] -= uy\n }\n }\n\n // Clamp inside the padded canvas every tick.\n for (let i = 0; i < n; i++) {\n x[i] = clampToRange(x[i], boundsPadding + r[i], width - boundsPadding - r[i])\n y[i] = clampToRange(y[i], boundsPadding + r[i], height - boundsPadding - r[i])\n }\n\n alpha *= cooling\n }\n } else {\n // Closed-form algorithms: still honor the bounds clamp.\n for (let i = 0; i < n; i++) {\n x[i] = clampToRange(x[i], boundsPadding + r[i], width - boundsPadding - r[i])\n y[i] = clampToRange(y[i], boundsPadding + r[i], height - boundsPadding - r[i])\n }\n }\n\n // --- Build the result ------------------------------------------------------\n const nodes = graph.nodes.map((node, index): PositionedGraphNode => ({\n ...node,\n x: x[index],\n y: y[index],\n r: r[index],\n degree: degree.get(node.id) ?? 0,\n communityId: communityByNode.get(node.id),\n }))\n\n const nodeIndex = new Map(nodes.map((node) => [node.id, node]))\n\n const communities: PositionedCommunity[] = graph.communities.map((community) => {\n let sx = 0\n let sy = 0\n let size = 0\n for (const nodeId of community.nodes) {\n const positioned = nodeIndex.get(nodeId)\n if (!positioned) continue\n sx += positioned.x\n sy += positioned.y\n size += 1\n }\n return size > 0\n ? { id: community.id, x: sx / size, y: sy / size, size }\n : { id: community.id, x: centerX, y: centerY, size: 0 }\n })\n\n return { nodes, edges: graph.edges, nodeIndex, communities }\n}\n","import type { GraphBounds, PositionedGraphNode, ViewportTransform } from './types.js'\n\nconst EMPTY_BOUNDS: GraphBounds = {\n minX: 0,\n minY: 0,\n maxX: 0,\n maxY: 0,\n width: 0,\n height: 0,\n centerX: 0,\n centerY: 0,\n}\n\n/**\n * Compute the axis-aligned bounding box around a set of positioned nodes.\n * Returns an all-zero box for an empty input.\n */\nexport function computeGraphBounds(\n nodes: ReadonlyArray<Pick<PositionedGraphNode, 'x' | 'y'>>,\n): GraphBounds {\n if (nodes.length === 0) return { ...EMPTY_BOUNDS }\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const node of nodes) {\n if (node.x < minX) minX = node.x\n if (node.y < minY) minY = node.y\n if (node.x > maxX) maxX = node.x\n if (node.y > maxY) maxY = node.y\n }\n return {\n minX,\n minY,\n maxX,\n maxY,\n width: maxX - minX,\n height: maxY - minY,\n centerX: (minX + maxX) / 2,\n centerY: (minY + maxY) / 2,\n }\n}\n\nexport interface FitOptions {\n /** Uniform padding (in viewport units) to leave around the graph. */\n padding?: number\n /** Clamp the computed scale to this minimum. */\n minScale?: number\n /** Clamp the computed scale to this maximum. */\n maxScale?: number\n}\n\n/**\n * Compute a {@link ViewportTransform} (uniform scale + translation) that fits\n * `bounds` centered within a `viewport` of the given width/height. Apply the\n * result as `translate(offsetX, offsetY) scale(scale)` in SVG/canvas space.\n */\nexport function fitGraphToViewport(\n bounds: GraphBounds,\n viewport: { width: number; height: number },\n options: FitOptions = {},\n): ViewportTransform {\n const padding = options.padding ?? 0\n const minScale = options.minScale ?? 0\n const maxScale = options.maxScale ?? Infinity\n\n const availableWidth = Math.max(0, viewport.width - padding * 2)\n const availableHeight = Math.max(0, viewport.height - padding * 2)\n\n let scale = 1\n if (bounds.width > 0 || bounds.height > 0) {\n const scaleX = bounds.width > 0 ? availableWidth / bounds.width : Infinity\n const scaleY = bounds.height > 0 ? availableHeight / bounds.height : Infinity\n scale = Math.min(scaleX, scaleY)\n }\n if (!Number.isFinite(scale) || scale <= 0) scale = 1\n scale = Math.max(minScale, Math.min(maxScale, scale))\n\n const offsetX = viewport.width / 2 - bounds.centerX * scale\n const offsetY = viewport.height / 2 - bounds.centerY * scale\n return { scale, offsetX, offsetY }\n}\n","import { filterCommunityGraph } from './filter.js'\nimport type { CommunityGraph } from './types.js'\n\n/** Build an undirected adjacency map from a graph's edges. */\nexport function buildAdjacency(graph: CommunityGraph): Map<string, Set<string>> {\n const adjacency = new Map<string, Set<string>>()\n const ensure = (id: string) => {\n let set = adjacency.get(id)\n if (!set) {\n set = new Set<string>()\n adjacency.set(id, set)\n }\n return set\n }\n for (const node of graph.nodes) ensure(node.id)\n for (const edge of graph.edges) {\n ensure(edge.source).add(edge.target)\n ensure(edge.target).add(edge.source)\n }\n return adjacency\n}\n\n/** Return the set of node ids directly adjacent to `nodeId` (excludes itself). */\nexport function neighborsOf(graph: CommunityGraph, nodeId: string): Set<string> {\n return new Set(buildAdjacency(graph).get(nodeId) ?? [])\n}\n\nexport interface ExpandOptions {\n /** How many edge-hops to traverse from the seeds. Default 1. */\n depth?: number\n /** Include the seed ids in the result. Default true. */\n includeSeeds?: boolean\n}\n\n/**\n * Breadth-first expansion of one or more seed nodes out to `depth` hops.\n * Returns the set of reached node ids (seeds included by default).\n */\nexport function expandNeighborhood(\n graph: CommunityGraph,\n seeds: Iterable<string>,\n options: ExpandOptions = {},\n): Set<string> {\n const depth = options.depth ?? 1\n const includeSeeds = options.includeSeeds ?? true\n const adjacency = buildAdjacency(graph)\n\n const seen = new Set<string>()\n let frontier = new Set<string>()\n for (const seed of seeds) {\n if (adjacency.has(seed) || depth === 0) {\n seen.add(seed)\n frontier.add(seed)\n }\n }\n\n for (let hop = 0; hop < depth; hop++) {\n const next = new Set<string>()\n for (const id of frontier) {\n for (const neighbor of adjacency.get(id) ?? []) {\n if (!seen.has(neighbor)) {\n seen.add(neighbor)\n next.add(neighbor)\n }\n }\n }\n if (next.size === 0) break\n frontier = next\n }\n\n if (!includeSeeds) {\n for (const seed of seeds) seen.delete(seed)\n }\n return seen\n}\n\n/**\n * Extract the induced subgraph over `nodeIds` — a {@link CommunityGraph}\n * containing only those nodes, the edges between them, and the trimmed\n * community memberships. Thin wrapper over {@link filterCommunityGraph}.\n */\nexport function subgraphForNodes(graph: CommunityGraph, nodeIds: Iterable<string>): CommunityGraph {\n return filterCommunityGraph(graph, { nodeIds: Array.from(nodeIds) })\n}\n\n/**\n * Convenience: the induced subgraph of a seed node plus its `depth`-hop\n * neighborhood. Useful for \"expand selection\" interactions.\n */\nexport function neighborhoodSubgraph(\n graph: CommunityGraph,\n seeds: Iterable<string>,\n options: ExpandOptions = {},\n): CommunityGraph {\n return subgraphForNodes(graph, expandNeighborhood(graph, seeds, options))\n}\n","import type { CommunityGraph, GraphLayoutAlgorithm } from './types.js'\n\n/** Current on-disk version for {@link GraphSnapshot}. */\nexport const GRAPH_SNAPSHOT_VERSION = 1\n\n/**\n * A self-contained, serializable representation of a community graph plus the\n * layout intent used to render it. Designed to be written to a static JSON file\n * and consumed by a JS-only host (e.g. a documentation site) without recomputing\n * the graph.\n */\nexport interface GraphSnapshot {\n version: number\n graph: CommunityGraph\n layout?: {\n algorithm: GraphLayoutAlgorithm\n width: number\n height: number\n }\n generatedAt?: string\n}\n\nexport interface SerializeSnapshotOptions {\n layout?: GraphSnapshot['layout']\n /** ISO timestamp to stamp into the snapshot. Omit for reproducible output. */\n generatedAt?: string\n}\n\nfunction sortedGraph(graph: CommunityGraph): CommunityGraph {\n return {\n nodes: [...graph.nodes].sort((a, b) => a.id.localeCompare(b.id)),\n edges: [...graph.edges].sort((a, b) => (\n a.source.localeCompare(b.source)\n || a.target.localeCompare(b.target)\n || (a.kind ?? '').localeCompare(b.kind ?? '')\n )),\n communities: [...graph.communities]\n .map((community) => ({ ...community, nodes: [...community.nodes].sort() }))\n .sort((a, b) => a.id.localeCompare(b.id)),\n }\n}\n\n/**\n * Build a deterministic {@link GraphSnapshot} from a graph. Nodes, edges, and\n * community members are sorted so that equal graphs serialize identically\n * (stable diffs, content-addressable caching).\n */\nexport function serializeGraphSnapshot(\n graph: CommunityGraph,\n options: SerializeSnapshotOptions = {},\n): GraphSnapshot {\n const snapshot: GraphSnapshot = {\n version: GRAPH_SNAPSHOT_VERSION,\n graph: sortedGraph(graph),\n }\n if (options.layout) snapshot.layout = options.layout\n if (options.generatedAt) snapshot.generatedAt = options.generatedAt\n return snapshot\n}\n\n/** Stable JSON string for a graph snapshot. */\nexport function stringifyGraphSnapshot(\n graph: CommunityGraph,\n options: SerializeSnapshotOptions = {},\n): string {\n return JSON.stringify(serializeGraphSnapshot(graph, options))\n}\n\n/**\n * Validate and unwrap a {@link GraphSnapshot} (or its JSON string) back into a\n * {@link CommunityGraph}. Throws on shape/version mismatch.\n */\nexport function deserializeGraphSnapshot(input: GraphSnapshot | string): CommunityGraph {\n const snapshot: unknown = typeof input === 'string' ? JSON.parse(input) : input\n if (!snapshot || typeof snapshot !== 'object') {\n throw new Error('invalid graph snapshot: not an object')\n }\n const candidate = snapshot as Partial<GraphSnapshot>\n if (candidate.version !== GRAPH_SNAPSHOT_VERSION) {\n throw new Error(`unsupported graph snapshot version: ${String(candidate.version)}`)\n }\n const graph = candidate.graph\n if (\n !graph\n || !Array.isArray(graph.nodes)\n || !Array.isArray(graph.edges)\n || !Array.isArray(graph.communities)\n ) {\n throw new Error('invalid graph snapshot: missing graph nodes/edges/communities')\n }\n return graph\n}\n","// Framework-agnostic graph-source controller.\n//\n// Owns the graph \"source mode\" state machine (citations | topics | precomputed\n// | dynamic-search | user-authored), transition tracking, and the mode→fetch\n// dispatch. The capability previously lived inside the React `useGraphController`\n// hook; it now lives here so JS-only hosts can drive the same logic without\n// React. The React hook is a thin `useSyncExternalStore` adapter over this class.\n//\n// This module depends on @fortemi/core for the repositories and shared types.\n// @fortemi/core never depends on @fortemi/graph — the dependency direction is\n// the linear chain: pglite ← @fortemi/core ← @fortemi/graph ← @fortemi/react.\n\nimport {\n CommunitiesRepository,\n GraphRepository,\n type CommunityCreateInput,\n type CommunityFilterDefinition,\n type CommunityGraph,\n type CommunitySourceDescriptor,\n type DatabaseClient,\n type EmbeddingSetSelector,\n type QueryExecutor,\n type SimilarityGraphResult,\n} from '@fortemi/core'\nimport type { GraphLayoutAlgorithm } from './types.js'\n\n/** A database handle accepted by the underlying repositories. */\nexport type GraphControllerDb = QueryExecutor & DatabaseClient\n\nexport type GraphSourceMode =\n | 'citations'\n | 'topics'\n | 'precomputed'\n | 'dynamic-search'\n | 'user-authored'\n\nexport interface GraphLayoutState {\n algorithm: GraphLayoutAlgorithm\n pinSelectedNodes?: boolean\n preserveViewport?: boolean\n communitySpacing?: number\n}\n\nexport interface GraphTransitionState {\n fromMode?: GraphSourceMode\n toMode: GraphSourceMode\n reason: 'mode-change' | 'embedding-set-change' | 'community-source-change' | 'filter-change' | 'recompute'\n startedAt: string\n}\n\nexport interface GraphControllerStatus {\n loading: boolean\n error: Error | null\n freshness: 'fresh' | 'stale' | 'unknown' | null\n cache: SimilarityGraphResult['cache'] | null\n}\n\nexport type GraphSourceRef = SimilarityGraphResult['graphSource'] | { id: string; name: string }\n\n/** The full, framework-agnostic controller state surfaced to subscribers. */\nexport interface GraphControllerState {\n mode: GraphSourceMode\n graph: CommunityGraph | null\n graphSource?: GraphSourceRef\n communitySource?: CommunitySourceDescriptor\n embeddingSetSelector?: EmbeddingSetSelector\n filters?: CommunityFilterDefinition\n layout: GraphLayoutState\n status: GraphControllerStatus\n transition?: GraphTransitionState\n}\n\nexport interface GraphControllerOptions {\n initialMode?: GraphSourceMode\n initialEmbeddingSetSelector?: EmbeddingSetSelector\n initialCommunitySourceId?: string\n initialFilters?: CommunityFilterDefinition\n layout?: Partial<GraphLayoutState>\n}\n\nconst DEFAULT_LAYOUT: GraphLayoutState = {\n algorithm: 'force',\n preserveViewport: true,\n communitySpacing: 1,\n}\n\nexport type GraphControllerListener = (state: GraphControllerState) => void\n\n/**\n * Drives graph-source selection and loading independent of any UI framework.\n *\n * Construct with pre-built repositories (handy for tests) or via\n * {@link GraphController.fromDb}. Subscribe with {@link subscribe} and read the\n * current state with {@link getState}; call {@link start} once to trigger the\n * initial load. Setters update state and schedule a refresh, mirroring the\n * effect-driven behavior of the original React hook.\n */\nexport class GraphController {\n private readonly graphRepo: GraphRepository\n private readonly communityRepo: CommunitiesRepository\n private readonly listeners = new Set<GraphControllerListener>()\n private communitySourceId: string | null\n private state: GraphControllerState\n\n /** Build a controller from a database handle (production path). */\n static fromDb(db: GraphControllerDb, options: GraphControllerOptions = {}): GraphController {\n return new GraphController(new GraphRepository(db), new CommunitiesRepository(db), options)\n }\n\n constructor(\n graphRepo: GraphRepository,\n communityRepo: CommunitiesRepository,\n options: GraphControllerOptions = {},\n ) {\n this.graphRepo = graphRepo\n this.communityRepo = communityRepo\n this.communitySourceId = options.initialCommunitySourceId ?? null\n this.state = {\n mode: options.initialMode ?? 'citations',\n graph: null,\n graphSource: undefined,\n communitySource: undefined,\n embeddingSetSelector: options.initialEmbeddingSetSelector,\n filters: options.initialFilters,\n layout: { ...DEFAULT_LAYOUT, ...options.layout },\n status: { loading: false, error: null, freshness: null, cache: null },\n transition: undefined,\n }\n }\n\n getState(): GraphControllerState {\n return this.state\n }\n\n subscribe(listener: GraphControllerListener): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n /** Run the initial load. Call once after construction (the hook calls this on mount). */\n async start(): Promise<void> {\n await this.refresh()\n }\n\n private setState(patch: Partial<GraphControllerState>): void {\n this.state = { ...this.state, ...patch }\n for (const listener of this.listeners) listener(this.state)\n }\n\n private beginTransition(\n toMode: GraphSourceMode,\n reason: GraphTransitionState['reason'],\n fromMode: GraphSourceMode = this.state.mode,\n ): void {\n this.setState({ transition: { fromMode, toMode, reason, startedAt: new Date().toISOString() } })\n }\n\n async refresh(): Promise<void> {\n try {\n this.setState({ status: { ...this.state.status, loading: true, error: null } })\n const sources = await this.communityRepo.listCommunitySources()\n const activeCommunity = this.communitySourceId\n ? sources.find((source) => source.id === this.communitySourceId)\n : undefined\n this.setState({ communitySource: activeCommunity })\n\n const mode = this.state.mode\n\n if (mode === 'citations') {\n const nextGraph = await this.graphRepo.buildLinkGraph()\n this.setState({\n graph: nextGraph,\n graphSource: { id: 'citations', name: 'Citation graph' },\n status: { loading: false, error: null, freshness: 'fresh', cache: null },\n })\n return\n }\n\n if (mode === 'topics') {\n const selector = this.state.embeddingSetSelector\n if (!selector) throw new Error('topics mode requires an embedding-set selector')\n const result = await this.graphRepo.buildOrLoadSimilarityGraph({ selector })\n this.setState({\n graph: result.graph,\n graphSource: result.graphSource,\n status: { loading: false, error: null, freshness: result.freshness, cache: result.cache },\n })\n return\n }\n\n if (mode === 'precomputed') {\n if (!activeCommunity?.graphSourceId) {\n throw new Error('precomputed mode requires a community source with graphSourceId')\n }\n const assignments = await this.communityRepo.getCommunityAssignments(activeCommunity.id)\n const nextGraph = await this.graphRepo.loadGraphArtifact(\n activeCommunity.graphSourceId,\n assignments.map((assignment) => assignment.noteId),\n )\n this.setState({\n graph: nextGraph,\n graphSource: { id: activeCommunity.graphSourceId, name: activeCommunity.name },\n status: { loading: false, error: null, freshness: activeCommunity.freshness ?? 'unknown', cache: null },\n })\n return\n }\n\n if (mode === 'dynamic-search') {\n const assignments = await this.communityRepo.previewDynamicCommunity(this.state.filters ?? {})\n this.setState({\n graph: {\n nodes: assignments.map((assignment) => ({ id: assignment.noteId })),\n edges: [],\n communities: [{ id: 'dynamic-preview', nodes: assignments.map((assignment) => assignment.noteId) }],\n },\n graphSource: { id: 'dynamic-preview', name: 'Dynamic preview' },\n status: { loading: false, error: null, freshness: 'unknown', cache: null },\n })\n return\n }\n\n if (mode === 'user-authored') {\n if (!activeCommunity) throw new Error('user-authored mode requires an active community source')\n const assignments = await this.communityRepo.getCommunityAssignments(activeCommunity.id)\n this.setState({\n graph: {\n nodes: assignments.map((assignment) => ({ id: assignment.noteId })),\n edges: [],\n communities: [{ id: activeCommunity.id, nodes: assignments.map((assignment) => assignment.noteId) }],\n },\n graphSource: { id: activeCommunity.graphSourceId ?? activeCommunity.id, name: activeCommunity.name },\n status: { loading: false, error: null, freshness: activeCommunity.freshness ?? 'unknown', cache: null },\n })\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err))\n this.setState({ status: { ...this.state.status, loading: false, error: e } })\n throw e\n }\n }\n\n setMode(nextMode: GraphSourceMode): void {\n this.beginTransition(nextMode, 'mode-change')\n this.setState({ mode: nextMode })\n void this.refresh()\n }\n\n setEmbeddingSetSelector(selector: EmbeddingSetSelector): void {\n this.beginTransition('topics', 'embedding-set-change')\n this.setState({ embeddingSetSelector: selector, mode: 'topics' })\n void this.refresh()\n }\n\n setCommunitySource(sourceId: string | null): void {\n this.communitySourceId = sourceId\n this.beginTransition(this.state.mode, 'community-source-change')\n void this.refresh()\n }\n\n /** Apply dynamic-search filters and switch into that mode (state only). */\n private applyFilters(nextFilters: CommunityFilterDefinition): void {\n this.beginTransition('dynamic-search', 'filter-change')\n this.setState({ filters: nextFilters, mode: 'dynamic-search' })\n }\n\n setFilters(nextFilters: CommunityFilterDefinition): void {\n this.applyFilters(nextFilters)\n void this.refresh()\n }\n\n async recompute(): Promise<void> {\n this.beginTransition(this.state.mode, 'recompute')\n if (this.state.mode === 'topics' && this.state.embeddingSetSelector) {\n const result = await this.graphRepo.buildOrLoadSimilarityGraph({\n selector: this.state.embeddingSetSelector,\n source: 'live-only',\n })\n this.setState({\n graph: result.graph,\n graphSource: result.graphSource,\n status: { loading: false, error: null, freshness: result.freshness, cache: result.cache },\n })\n return\n }\n await this.refresh()\n }\n\n async previewDynamicCommunity(nextFilters: CommunityFilterDefinition): Promise<void> {\n this.applyFilters(nextFilters)\n await this.refresh()\n }\n\n async saveCurrentCommunity(input: CommunityCreateInput): Promise<CommunitySourceDescriptor> {\n const source = await this.communityRepo.saveCommunity(input)\n this.communitySourceId = source.id\n this.setState({ communitySource: source })\n return source\n }\n}\n","// @fortemi/graph — framework-agnostic graph presentation/projection helpers\n// plus the graph-source controller.\n//\n// Depends on @fortemi/core (the base data layer) and is consumed by\n// @fortemi/react and JS-only hosts. Dependency direction is the linear chain:\n// pglite ← @fortemi/core ← @fortemi/graph ← @fortemi/react. @fortemi/core never\n// imports @fortemi/graph.\n//\n// Pure projection helpers (layout, filtering, coloring, sizing, bounds,\n// neighborhood, snapshot) give React and JS-only hosts the shared logic to\n// render their own SVG/canvas views. `GraphController` adds the framework-\n// agnostic graph-source state machine (mode selection + load dispatch) on top\n// of @fortemi/core's repositories.\n//\n// Community *detection* intentionally lives in @fortemi/core (the base layer);\n// this package only renders/projects graphs it is given and orchestrates which\n// source to load.\n\nexport const VERSION = '2026.7.1'\n\nexport type {\n GraphNode,\n GraphEdge,\n GraphCommunity,\n CommunityGraph,\n GraphLayoutAlgorithm,\n PositionedGraphNode,\n PositionedCommunity,\n PositionedGraph,\n GraphBounds,\n ViewportTransform,\n} from './types.js'\n\nexport { computeDegrees, nodeRadius } from './degree.js'\nexport type { NodeRadiusOptions } from './degree.js'\n\nexport { COMMUNITY_COLORS, UNASSIGNED_COMMUNITY_COLOR, colorForCommunity } from './color.js'\n\nexport { filterCommunityGraph } from './filter.js'\nexport type { GraphFilter } from './filter.js'\n\nexport { layoutCommunityGraph } from './layout.js'\nexport type { LayoutOptions, NodeRadiusResolver } from './layout.js'\n\nexport { computeGraphBounds, fitGraphToViewport } from './bounds.js'\nexport type { FitOptions } from './bounds.js'\n\nexport {\n buildAdjacency,\n neighborsOf,\n expandNeighborhood,\n subgraphForNodes,\n neighborhoodSubgraph,\n} from './neighborhood.js'\nexport type { ExpandOptions } from './neighborhood.js'\n\nexport {\n GRAPH_SNAPSHOT_VERSION,\n serializeGraphSnapshot,\n stringifyGraphSnapshot,\n deserializeGraphSnapshot,\n} from './serialize.js'\nexport type { GraphSnapshot, SerializeSnapshotOptions } from './serialize.js'\n\nexport { GraphController } from './controller.js'\nexport type {\n GraphControllerDb,\n GraphSourceMode,\n GraphLayoutState,\n GraphTransitionState,\n GraphControllerStatus,\n GraphSourceRef,\n GraphControllerState,\n GraphControllerOptions,\n GraphControllerListener,\n} from './controller.js'\n"]}
1
+ {"version":3,"sources":["../src/degree.ts","../src/color.ts","../src/filter.ts","../src/rng.ts","../src/layout.ts","../src/bounds.ts","../src/neighborhood.ts","../src/serialize.ts","../src/controller.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { CommunityGraph } from './types.js'\n\n/** Count the (undirected) degree of every node, including isolated nodes (0). */\nexport function computeDegrees(graph: CommunityGraph): Map<string, number> {\n const degree = new Map<string, number>()\n for (const node of graph.nodes) degree.set(node.id, 0)\n for (const edge of graph.edges) {\n degree.set(edge.source, (degree.get(edge.source) ?? 0) + 1)\n degree.set(edge.target, (degree.get(edge.target) ?? 0) + 1)\n }\n return degree\n}\n\nexport interface NodeRadiusOptions {\n /** Radius of a degree-0 node. */\n base?: number\n /** Pixels added per unit of degree. */\n perDegree?: number\n /** Hard floor on the radius. */\n min?: number\n /** Hard ceiling on the radius. */\n max?: number\n}\n\n/**\n * Map a node degree to a render radius. Defaults match the values historically\n * used by the React `GraphView`: `clamp(5 + degree * 1.5, 5, 16)`.\n */\nexport function nodeRadius(degree: number, options: NodeRadiusOptions = {}): number {\n const base = options.base ?? 5\n const perDegree = options.perDegree ?? 1.5\n const min = options.min ?? 5\n const max = options.max ?? 16\n return Math.max(min, Math.min(max, base + degree * perDegree))\n}\n","/** Default qualitative palette for community coloring (8 hues). */\nexport const COMMUNITY_COLORS = [\n '#2f6fbb',\n '#d97706',\n '#218838',\n '#7c3aed',\n '#c2410c',\n '#0f766e',\n '#be185d',\n '#4b5563',\n] as const\n\n/** Color used for nodes that are not assigned to any community. */\nexport const UNASSIGNED_COMMUNITY_COLOR = '#64748b'\n\n/**\n * Deterministically assign a color to a community id by hashing the id into the\n * palette. The same id always maps to the same color across runs and hosts.\n * Pass a custom `palette` to theme the output. Matches the historical\n * `GraphView` color assignment.\n */\nexport function colorForCommunity(\n communityId: string | undefined,\n palette: readonly string[] = COMMUNITY_COLORS,\n unassignedColor: string = UNASSIGNED_COMMUNITY_COLOR,\n): string {\n if (!communityId) return unassignedColor\n if (palette.length === 0) return unassignedColor\n let hash = 0\n for (const char of communityId) hash = (hash * 31 + char.charCodeAt(0)) | 0\n return palette[Math.abs(hash) % palette.length]\n}\n","import type { CommunityGraph, GraphNode } from './types.js'\n\nexport interface GraphFilter {\n /** Keep only nodes belonging to these communities (by community id). */\n communityIds?: string[]\n /** Keep only edges whose `kind` is in this set. */\n edgeKinds?: string[]\n /** Explicit allow-list of node ids. Useful for privacy / visibility filtering. */\n nodeIds?: string[]\n /**\n * Arbitrary per-node predicate evaluated against the (allow-listed) nodes.\n * Returning `false` removes the node and any edge touching it. Hosts whose\n * nodes carry extra metadata (privacy class, type, etc.) can filter on it here.\n */\n nodePredicate?: (node: GraphNode) => boolean\n}\n\n/**\n * Produce a new {@link CommunityGraph} containing only the nodes, edges, and\n * community memberships permitted by `filter`. Pure — the input is not mutated.\n *\n * Filtering precedence:\n * 1. `communityIds` (if non-empty) restricts the candidate node set to members\n * of those communities; otherwise `nodeIds` (if given) is the candidate set,\n * else all nodes.\n * 2. `nodePredicate` further narrows the candidate set.\n * 3. Edges survive only when both endpoints survive and `edgeKinds` permits.\n * 4. Empty communities are dropped.\n */\nexport function filterCommunityGraph(\n graph: CommunityGraph | null | undefined,\n filter?: GraphFilter,\n): CommunityGraph {\n if (!graph) return { nodes: [], edges: [], communities: [] }\n\n const nodeIds = new Set(filter?.nodeIds ?? graph.nodes.map((node) => node.id))\n if (filter?.communityIds?.length) {\n const allowedCommunities = new Set(filter.communityIds)\n nodeIds.clear()\n for (const community of graph.communities) {\n if (allowedCommunities.has(community.id)) {\n for (const nodeId of community.nodes) nodeIds.add(nodeId)\n }\n }\n }\n\n const predicate = filter?.nodePredicate\n if (predicate) {\n for (const node of graph.nodes) {\n if (nodeIds.has(node.id) && !predicate(node)) nodeIds.delete(node.id)\n }\n }\n\n const edgeKinds = filter?.edgeKinds ? new Set(filter.edgeKinds) : null\n const nodes = graph.nodes.filter((node) => nodeIds.has(node.id))\n const edges = graph.edges.filter((edge) => (\n nodeIds.has(edge.source)\n && nodeIds.has(edge.target)\n && (!edgeKinds || edgeKinds.has(edge.kind ?? ''))\n ))\n const communities = graph.communities\n .map((community) => ({ ...community, nodes: community.nodes.filter((nodeId) => nodeIds.has(nodeId)) }))\n .filter((community) => community.nodes.length > 0)\n return { nodes, edges, communities }\n}\n","// Tiny deterministic PRNG (mulberry32). Used by the force layout to seed\n// initial jitter so that identical (seed, graph, options) always yields\n// identical coordinates — no Math.random, no time, no platform variance.\n\n/**\n * Create a deterministic pseudo-random generator from a 32-bit integer seed.\n * Returns a function producing floats in [0, 1). Identical seeds yield\n * identical sequences across platforms.\n */\nexport function mulberry32(seed: number): () => number {\n // Coerce to a non-zero unsigned 32-bit integer so seed 0 still advances.\n let a = (seed >>> 0) || 0x9e3779b9\n return function next(): number {\n a |= 0\n a = (a + 0x6d2b79f5) | 0\n let t = Math.imul(a ^ (a >>> 15), 1 | a)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n","import { computeDegrees, nodeRadius as defaultNodeRadius, type NodeRadiusOptions } from './degree.js'\nimport { mulberry32 } from './rng.js'\nimport type {\n CommunityGraph,\n GraphLayoutAlgorithm,\n GraphNode,\n PositionedCommunity,\n PositionedGraph,\n PositionedGraphNode,\n} from './types.js'\n\n/**\n * How to derive each node's render radius. Either a fixed pixel value, a set of\n * {@link NodeRadiusOptions} fed to the default degree→radius mapping, or a full\n * resolver `(degree, node) => number`.\n */\nexport type NodeRadiusResolver =\n | number\n | NodeRadiusOptions\n | ((degree: number, node: GraphNode) => number)\n\nexport interface LayoutOptions {\n /** Layout algorithm. `force` runs deterministic settlement; the others are closed-form. */\n algorithm?: GraphLayoutAlgorithm\n width?: number\n height?: number\n /** Seed for the deterministic PRNG used by `force` initial jitter. Identical seed ⇒ identical output. */\n seed?: number\n /** Number of settlement iterations for the `force` algorithm. */\n ticks?: number\n /** Per-node render radius (default: degree-derived, clamped 5..16). */\n nodeRadius?: NodeRadiusResolver\n /** Target edge length in px for the spring force (`force` only). */\n linkDistance?: number\n /** Spring stiffness 0..1 (`force` only). */\n linkStrength?: number\n /** Repulsion magnitude; negative pushes nodes apart (`force` only). */\n chargeStrength?: number\n /** Extra spacing beyond `r_i + r_j` when resolving collisions (`force` only). */\n collisionPadding?: number\n /** Pull toward the node's community centroid, 0..1 (`force` only). */\n communityStrength?: number\n /** Keep every node center at least this many px from each canvas edge. */\n boundsPadding?: number\n}\n\nconst DEFAULTS = {\n width: 760,\n height: 460,\n seed: 1,\n ticks: 300,\n linkDistance: 60,\n linkStrength: 0.08,\n chargeStrength: -240,\n collisionPadding: 2,\n communityStrength: 0.05,\n boundsPadding: 24,\n} as const\n\n/** Mild global pull toward the canvas center so disconnected nodes don't drift. */\nconst GRAVITY = 0.02\n\nfunction resolveRadius(\n resolver: NodeRadiusResolver | undefined,\n degree: number,\n node: GraphNode,\n): number {\n if (resolver === undefined) return defaultNodeRadius(degree)\n if (typeof resolver === 'number') return resolver\n if (typeof resolver === 'function') return resolver(degree, node)\n return defaultNodeRadius(degree, resolver)\n}\n\n/** Clamp `value` into `[lo, hi]`, collapsing to the midpoint if the range inverts. */\nfunction clampToRange(value: number, lo: number, hi: number): number {\n if (lo > hi) return (lo + hi) / 2\n return Math.max(lo, Math.min(hi, value))\n}\n\n/**\n * Deterministically position the nodes of a {@link CommunityGraph} in 2D space.\n *\n * For the default `force` algorithm this runs a fixed-iteration, seeded force\n * settlement (spring link attraction, charge repulsion, collision spacing,\n * community cohesion, centering, and bounds clamping). It is fully synchronous\n * and headless — no animation frames — so the same `(graph, options)` always\n * yields identical coordinates, safe for snapshot rendering and SSR. The\n * `radial`, `community`, and `manual` algorithms remain closed-form.\n *\n * Every node is annotated with its render radius `r`, degree, and resolved\n * community; the result also carries community centroids over the final layout.\n */\nexport function layoutCommunityGraph(\n graph: CommunityGraph,\n options: LayoutOptions = {},\n): PositionedGraph {\n const algorithm = options.algorithm ?? 'force'\n const width = options.width ?? DEFAULTS.width\n const height = options.height ?? DEFAULTS.height\n const boundsPadding = options.boundsPadding ?? DEFAULTS.boundsPadding\n\n const degree = computeDegrees(graph)\n\n const communityByNode = new Map<string, string>()\n for (const community of graph.communities) {\n for (const nodeId of community.nodes) {\n if (!communityByNode.has(nodeId)) communityByNode.set(nodeId, community.id)\n }\n }\n\n const centerX = width / 2\n const centerY = height / 2\n const radius = Math.max(40, Math.min(width, height) * 0.38)\n const n = graph.nodes.length\n\n // Per-node render radius (stable, used by force spacing and by consumers).\n const r = graph.nodes.map((node) =>\n resolveRadius(options.nodeRadius, degree.get(node.id) ?? 0, node),\n )\n\n // Index from node id → array position (edges reference nodes by id).\n const indexOf = new Map<string, number>()\n graph.nodes.forEach((node, i) => indexOf.set(node.id, i))\n\n // Community ring anchors — used both as closed-form positions and as the\n // initial seed for force settlement, keeping clusters legible.\n const communityIndexById = new Map<string, number>()\n graph.communities.forEach((community, i) => communityIndexById.set(community.id, i))\n\n const x = new Float64Array(n)\n const y = new Float64Array(n)\n\n // --- Initial / closed-form positions ---------------------------------------\n graph.nodes.forEach((node, index) => {\n const angle = (Math.PI * 2 * index) / Math.max(1, n)\n const communityId = communityByNode.get(node.id)\n const communityIndex = communityId !== undefined ? communityIndexById.get(communityId) ?? -1 : -1\n const communityAngle =\n (Math.PI * 2 * Math.max(0, communityIndex)) / Math.max(1, graph.communities.length)\n const useCommunityOrbit = algorithm === 'community' || algorithm === 'force'\n const communityRadius = algorithm === 'community' ? radius * 0.55 : radius\n const localRadius =\n algorithm === 'force'\n ? radius * (0.7 + ((degree.get(node.id) ?? 0) % 4) * 0.08)\n : radius\n\n if (useCommunityOrbit && communityIndex >= 0) {\n x[index] = centerX + Math.cos(communityAngle) * communityRadius + Math.cos(angle) * 46\n y[index] = centerY + Math.sin(communityAngle) * communityRadius + Math.sin(angle) * 46\n } else {\n x[index] = centerX + Math.cos(angle) * localRadius\n y[index] =\n centerY + Math.sin(angle) * (algorithm === 'radial' ? radius : localRadius * 0.72)\n }\n })\n\n // --- Force settlement (force algorithm only) -------------------------------\n if (algorithm === 'force' && n > 1) {\n const ticks = Math.max(0, Math.floor(options.ticks ?? DEFAULTS.ticks))\n const seed = options.seed ?? DEFAULTS.seed\n const linkDistance = options.linkDistance ?? DEFAULTS.linkDistance\n const linkStrength = options.linkStrength ?? DEFAULTS.linkStrength\n const chargeStrength = options.chargeStrength ?? DEFAULTS.chargeStrength\n const collisionPadding = options.collisionPadding ?? DEFAULTS.collisionPadding\n const communityStrength = options.communityStrength ?? DEFAULTS.communityStrength\n\n const rng = mulberry32(seed)\n // Deterministic jitter so no two seeded nodes coincide (avoids div-by-zero).\n for (let i = 0; i < n; i++) {\n x[i] += (rng() - 0.5) * 8\n y[i] += (rng() - 0.5) * 8\n }\n\n // Pre-resolve edge endpoints to array indices once.\n const links: Array<{ a: number; b: number; weight: number }> = []\n for (const edge of graph.edges) {\n const a = indexOf.get(edge.source)\n const b = indexOf.get(edge.target)\n if (a === undefined || b === undefined || a === b) continue\n links.push({ a, b, weight: edge.weight > 0 ? edge.weight : 1 })\n }\n\n // Community membership as array indices, for centroid cohesion.\n const communityOf = graph.nodes.map((node) => communityByNode.get(node.id))\n const communityIds = graph.communities.map((c) => c.id)\n\n const dispX = new Float64Array(n)\n const dispY = new Float64Array(n)\n const chargeCutoff = linkDistance * 6\n const cooling = ticks > 0 ? Math.pow(0.001, 1 / ticks) : 1\n let alpha = 1\n\n for (let t = 0; t < ticks; t++) {\n dispX.fill(0)\n dispY.fill(0)\n\n // Spring link attraction toward linkDistance.\n for (const link of links) {\n let dx = x[link.b] - x[link.a]\n let dy = y[link.b] - y[link.a]\n const dist = Math.max(0.01, Math.hypot(dx, dy))\n const force = ((dist - linkDistance) / dist) * linkStrength * link.weight\n dx *= force\n dy *= force\n dispX[link.a] += dx\n dispY[link.a] += dy\n dispX[link.b] -= dx\n dispY[link.b] -= dy\n }\n\n // Pairwise charge repulsion (with a distance cutoff for dense graphs).\n for (let i = 0; i < n; i++) {\n for (let j = i + 1; j < n; j++) {\n const dx = x[i] - x[j]\n const dy = y[i] - y[j]\n const dist = Math.max(0.01, Math.hypot(dx, dy))\n if (dist > chargeCutoff) continue\n // chargeStrength is negative ⇒ repulsion magnitude is positive.\n const mag = -chargeStrength / dist\n const ux = (dx / dist) * mag\n const uy = (dy / dist) * mag\n dispX[i] += ux\n dispY[i] += uy\n dispX[j] -= ux\n dispY[j] -= uy\n }\n }\n\n // Community cohesion (toward centroid) + global centering gravity.\n if (communityStrength > 0 && communityIds.length > 0) {\n const cx = new Float64Array(communityIds.length)\n const cy = new Float64Array(communityIds.length)\n const cn = new Int32Array(communityIds.length)\n const idxById = new Map<string, number>()\n communityIds.forEach((id, i) => idxById.set(id, i))\n for (let i = 0; i < n; i++) {\n const cid = communityOf[i]\n if (cid === undefined) continue\n const ci = idxById.get(cid)\n if (ci === undefined) continue\n cx[ci] += x[i]\n cy[ci] += y[i]\n cn[ci] += 1\n }\n for (let i = 0; i < n; i++) {\n const cid = communityOf[i]\n if (cid === undefined) continue\n const ci = idxById.get(cid)\n if (ci === undefined || cn[ci] === 0) continue\n dispX[i] += (cx[ci] / cn[ci] - x[i]) * communityStrength\n dispY[i] += (cy[ci] / cn[ci] - y[i]) * communityStrength\n }\n }\n for (let i = 0; i < n; i++) {\n dispX[i] += (centerX - x[i]) * GRAVITY\n dispY[i] += (centerY - y[i]) * GRAVITY\n }\n\n // Apply soft forces, cooled by alpha.\n for (let i = 0; i < n; i++) {\n x[i] += dispX[i] * alpha\n y[i] += dispY[i] * alpha\n }\n\n // Hard collision resolution (full strength) so nodes don't overlap.\n for (let i = 0; i < n; i++) {\n for (let j = i + 1; j < n; j++) {\n const dx = x[i] - x[j]\n const dy = y[i] - y[j]\n const dist = Math.max(0.01, Math.hypot(dx, dy))\n const minDist = r[i] + r[j] + collisionPadding\n if (dist >= minDist) continue\n const push = (minDist - dist) / 2\n const ux = (dx / dist) * push\n const uy = (dy / dist) * push\n x[i] += ux\n y[i] += uy\n x[j] -= ux\n y[j] -= uy\n }\n }\n\n // Clamp inside the padded canvas every tick.\n for (let i = 0; i < n; i++) {\n x[i] = clampToRange(x[i], boundsPadding + r[i], width - boundsPadding - r[i])\n y[i] = clampToRange(y[i], boundsPadding + r[i], height - boundsPadding - r[i])\n }\n\n alpha *= cooling\n }\n } else {\n // Closed-form algorithms: still honor the bounds clamp.\n for (let i = 0; i < n; i++) {\n x[i] = clampToRange(x[i], boundsPadding + r[i], width - boundsPadding - r[i])\n y[i] = clampToRange(y[i], boundsPadding + r[i], height - boundsPadding - r[i])\n }\n }\n\n // --- Build the result ------------------------------------------------------\n const nodes = graph.nodes.map((node, index): PositionedGraphNode => ({\n ...node,\n x: x[index],\n y: y[index],\n r: r[index],\n degree: degree.get(node.id) ?? 0,\n communityId: communityByNode.get(node.id),\n }))\n\n const nodeIndex = new Map(nodes.map((node) => [node.id, node]))\n\n const communities: PositionedCommunity[] = graph.communities.map((community) => {\n let sx = 0\n let sy = 0\n let size = 0\n for (const nodeId of community.nodes) {\n const positioned = nodeIndex.get(nodeId)\n if (!positioned) continue\n sx += positioned.x\n sy += positioned.y\n size += 1\n }\n return size > 0\n ? { id: community.id, x: sx / size, y: sy / size, size }\n : { id: community.id, x: centerX, y: centerY, size: 0 }\n })\n\n return { nodes, edges: graph.edges, nodeIndex, communities }\n}\n","import type { GraphBounds, PositionedGraphNode, ViewportTransform } from './types.js'\n\nconst EMPTY_BOUNDS: GraphBounds = {\n minX: 0,\n minY: 0,\n maxX: 0,\n maxY: 0,\n width: 0,\n height: 0,\n centerX: 0,\n centerY: 0,\n}\n\n/**\n * Compute the axis-aligned bounding box around a set of positioned nodes.\n * Returns an all-zero box for an empty input.\n */\nexport function computeGraphBounds(\n nodes: ReadonlyArray<Pick<PositionedGraphNode, 'x' | 'y'>>,\n): GraphBounds {\n if (nodes.length === 0) return { ...EMPTY_BOUNDS }\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n for (const node of nodes) {\n if (node.x < minX) minX = node.x\n if (node.y < minY) minY = node.y\n if (node.x > maxX) maxX = node.x\n if (node.y > maxY) maxY = node.y\n }\n return {\n minX,\n minY,\n maxX,\n maxY,\n width: maxX - minX,\n height: maxY - minY,\n centerX: (minX + maxX) / 2,\n centerY: (minY + maxY) / 2,\n }\n}\n\nexport interface FitOptions {\n /** Uniform padding (in viewport units) to leave around the graph. */\n padding?: number\n /** Clamp the computed scale to this minimum. */\n minScale?: number\n /** Clamp the computed scale to this maximum. */\n maxScale?: number\n}\n\n/**\n * Compute a {@link ViewportTransform} (uniform scale + translation) that fits\n * `bounds` centered within a `viewport` of the given width/height. Apply the\n * result as `translate(offsetX, offsetY) scale(scale)` in SVG/canvas space.\n */\nexport function fitGraphToViewport(\n bounds: GraphBounds,\n viewport: { width: number; height: number },\n options: FitOptions = {},\n): ViewportTransform {\n const padding = options.padding ?? 0\n const minScale = options.minScale ?? 0\n const maxScale = options.maxScale ?? Infinity\n\n const availableWidth = Math.max(0, viewport.width - padding * 2)\n const availableHeight = Math.max(0, viewport.height - padding * 2)\n\n let scale = 1\n if (bounds.width > 0 || bounds.height > 0) {\n const scaleX = bounds.width > 0 ? availableWidth / bounds.width : Infinity\n const scaleY = bounds.height > 0 ? availableHeight / bounds.height : Infinity\n scale = Math.min(scaleX, scaleY)\n }\n if (!Number.isFinite(scale) || scale <= 0) scale = 1\n scale = Math.max(minScale, Math.min(maxScale, scale))\n\n const offsetX = viewport.width / 2 - bounds.centerX * scale\n const offsetY = viewport.height / 2 - bounds.centerY * scale\n return { scale, offsetX, offsetY }\n}\n","import { filterCommunityGraph } from './filter.js'\nimport type { CommunityGraph } from './types.js'\n\n/** Build an undirected adjacency map from a graph's edges. */\nexport function buildAdjacency(graph: CommunityGraph): Map<string, Set<string>> {\n const adjacency = new Map<string, Set<string>>()\n const ensure = (id: string) => {\n let set = adjacency.get(id)\n if (!set) {\n set = new Set<string>()\n adjacency.set(id, set)\n }\n return set\n }\n for (const node of graph.nodes) ensure(node.id)\n for (const edge of graph.edges) {\n ensure(edge.source).add(edge.target)\n ensure(edge.target).add(edge.source)\n }\n return adjacency\n}\n\n/** Return the set of node ids directly adjacent to `nodeId` (excludes itself). */\nexport function neighborsOf(graph: CommunityGraph, nodeId: string): Set<string> {\n return new Set(buildAdjacency(graph).get(nodeId) ?? [])\n}\n\nexport interface ExpandOptions {\n /** How many edge-hops to traverse from the seeds. Default 1. */\n depth?: number\n /** Include the seed ids in the result. Default true. */\n includeSeeds?: boolean\n}\n\n/**\n * Breadth-first expansion of one or more seed nodes out to `depth` hops.\n * Returns the set of reached node ids (seeds included by default).\n */\nexport function expandNeighborhood(\n graph: CommunityGraph,\n seeds: Iterable<string>,\n options: ExpandOptions = {},\n): Set<string> {\n const depth = options.depth ?? 1\n const includeSeeds = options.includeSeeds ?? true\n const adjacency = buildAdjacency(graph)\n\n const seen = new Set<string>()\n let frontier = new Set<string>()\n for (const seed of seeds) {\n if (adjacency.has(seed) || depth === 0) {\n seen.add(seed)\n frontier.add(seed)\n }\n }\n\n for (let hop = 0; hop < depth; hop++) {\n const next = new Set<string>()\n for (const id of frontier) {\n for (const neighbor of adjacency.get(id) ?? []) {\n if (!seen.has(neighbor)) {\n seen.add(neighbor)\n next.add(neighbor)\n }\n }\n }\n if (next.size === 0) break\n frontier = next\n }\n\n if (!includeSeeds) {\n for (const seed of seeds) seen.delete(seed)\n }\n return seen\n}\n\n/**\n * Extract the induced subgraph over `nodeIds` — a {@link CommunityGraph}\n * containing only those nodes, the edges between them, and the trimmed\n * community memberships. Thin wrapper over {@link filterCommunityGraph}.\n */\nexport function subgraphForNodes(graph: CommunityGraph, nodeIds: Iterable<string>): CommunityGraph {\n return filterCommunityGraph(graph, { nodeIds: Array.from(nodeIds) })\n}\n\n/**\n * Convenience: the induced subgraph of a seed node plus its `depth`-hop\n * neighborhood. Useful for \"expand selection\" interactions.\n */\nexport function neighborhoodSubgraph(\n graph: CommunityGraph,\n seeds: Iterable<string>,\n options: ExpandOptions = {},\n): CommunityGraph {\n return subgraphForNodes(graph, expandNeighborhood(graph, seeds, options))\n}\n","import type { CommunityGraph, GraphLayoutAlgorithm } from './types.js'\n\n/** Current on-disk version for {@link GraphSnapshot}. */\nexport const GRAPH_SNAPSHOT_VERSION = 1\n\n/**\n * A self-contained, serializable representation of a community graph plus the\n * layout intent used to render it. Designed to be written to a static JSON file\n * and consumed by a JS-only host (e.g. a documentation site) without recomputing\n * the graph.\n */\nexport interface GraphSnapshot {\n version: number\n graph: CommunityGraph\n layout?: {\n algorithm: GraphLayoutAlgorithm\n width: number\n height: number\n }\n generatedAt?: string\n}\n\nexport interface SerializeSnapshotOptions {\n layout?: GraphSnapshot['layout']\n /** ISO timestamp to stamp into the snapshot. Omit for reproducible output. */\n generatedAt?: string\n}\n\nfunction sortedGraph(graph: CommunityGraph): CommunityGraph {\n return {\n nodes: [...graph.nodes].sort((a, b) => a.id.localeCompare(b.id)),\n edges: [...graph.edges].sort((a, b) => (\n a.source.localeCompare(b.source)\n || a.target.localeCompare(b.target)\n || (a.kind ?? '').localeCompare(b.kind ?? '')\n )),\n communities: [...graph.communities]\n .map((community) => ({ ...community, nodes: [...community.nodes].sort() }))\n .sort((a, b) => a.id.localeCompare(b.id)),\n }\n}\n\n/**\n * Build a deterministic {@link GraphSnapshot} from a graph. Nodes, edges, and\n * community members are sorted so that equal graphs serialize identically\n * (stable diffs, content-addressable caching).\n */\nexport function serializeGraphSnapshot(\n graph: CommunityGraph,\n options: SerializeSnapshotOptions = {},\n): GraphSnapshot {\n const snapshot: GraphSnapshot = {\n version: GRAPH_SNAPSHOT_VERSION,\n graph: sortedGraph(graph),\n }\n if (options.layout) snapshot.layout = options.layout\n if (options.generatedAt) snapshot.generatedAt = options.generatedAt\n return snapshot\n}\n\n/** Stable JSON string for a graph snapshot. */\nexport function stringifyGraphSnapshot(\n graph: CommunityGraph,\n options: SerializeSnapshotOptions = {},\n): string {\n return JSON.stringify(serializeGraphSnapshot(graph, options))\n}\n\n/**\n * Validate and unwrap a {@link GraphSnapshot} (or its JSON string) back into a\n * {@link CommunityGraph}. Throws on shape/version mismatch.\n */\nexport function deserializeGraphSnapshot(input: GraphSnapshot | string): CommunityGraph {\n const snapshot: unknown = typeof input === 'string' ? JSON.parse(input) : input\n if (!snapshot || typeof snapshot !== 'object') {\n throw new Error('invalid graph snapshot: not an object')\n }\n const candidate = snapshot as Partial<GraphSnapshot>\n if (candidate.version !== GRAPH_SNAPSHOT_VERSION) {\n throw new Error(`unsupported graph snapshot version: ${String(candidate.version)}`)\n }\n const graph = candidate.graph\n if (\n !graph\n || !Array.isArray(graph.nodes)\n || !Array.isArray(graph.edges)\n || !Array.isArray(graph.communities)\n ) {\n throw new Error('invalid graph snapshot: missing graph nodes/edges/communities')\n }\n return graph\n}\n","// Framework-agnostic graph-source controller.\n//\n// Owns the graph \"source mode\" state machine (citations | topics | precomputed\n// | dynamic-search | user-authored), transition tracking, and the mode→fetch\n// dispatch. The capability previously lived inside the React `useGraphController`\n// hook; it now lives here so JS-only hosts can drive the same logic without\n// React. The React hook is a thin `useSyncExternalStore` adapter over this class.\n//\n// This module depends on @fortemi/core for the repositories and shared types.\n// @fortemi/core never depends on @fortemi/graph — the dependency direction is\n// the linear chain: pglite ← @fortemi/core ← @fortemi/graph ← @fortemi/react.\n\nimport {\n CommunitiesRepository,\n GraphRepository,\n type CommunityCreateInput,\n type CommunityFilterDefinition,\n type CommunityGraph,\n type CommunitySourceDescriptor,\n type DatabaseClient,\n type EmbeddingSetSelector,\n type QueryExecutor,\n type SimilarityGraphResult,\n} from '@fortemi/core'\nimport type { GraphLayoutAlgorithm } from './types.js'\n\n/** A database handle accepted by the underlying repositories. */\nexport type GraphControllerDb = QueryExecutor & DatabaseClient\n\nexport type GraphSourceMode =\n | 'citations'\n | 'topics'\n | 'precomputed'\n | 'dynamic-search'\n | 'user-authored'\n\nexport interface GraphLayoutState {\n algorithm: GraphLayoutAlgorithm\n pinSelectedNodes?: boolean\n preserveViewport?: boolean\n communitySpacing?: number\n}\n\nexport interface GraphTransitionState {\n fromMode?: GraphSourceMode\n toMode: GraphSourceMode\n reason: 'mode-change' | 'embedding-set-change' | 'community-source-change' | 'filter-change' | 'recompute'\n startedAt: string\n}\n\nexport interface GraphControllerStatus {\n loading: boolean\n error: Error | null\n freshness: 'fresh' | 'stale' | 'unknown' | null\n cache: SimilarityGraphResult['cache'] | null\n}\n\nexport type GraphSourceRef = SimilarityGraphResult['graphSource'] | { id: string; name: string }\n\n/** The full, framework-agnostic controller state surfaced to subscribers. */\nexport interface GraphControllerState {\n mode: GraphSourceMode\n graph: CommunityGraph | null\n graphSource?: GraphSourceRef\n communitySource?: CommunitySourceDescriptor\n embeddingSetSelector?: EmbeddingSetSelector\n filters?: CommunityFilterDefinition\n layout: GraphLayoutState\n status: GraphControllerStatus\n transition?: GraphTransitionState\n}\n\nexport interface GraphControllerOptions {\n initialMode?: GraphSourceMode\n initialEmbeddingSetSelector?: EmbeddingSetSelector\n initialCommunitySourceId?: string\n initialFilters?: CommunityFilterDefinition\n layout?: Partial<GraphLayoutState>\n}\n\nconst DEFAULT_LAYOUT: GraphLayoutState = {\n algorithm: 'force',\n preserveViewport: true,\n communitySpacing: 1,\n}\n\nexport type GraphControllerListener = (state: GraphControllerState) => void\n\n/**\n * Drives graph-source selection and loading independent of any UI framework.\n *\n * Construct with pre-built repositories (handy for tests) or via\n * {@link GraphController.fromDb}. Subscribe with {@link subscribe} and read the\n * current state with {@link getState}; call {@link start} once to trigger the\n * initial load. Setters update state and schedule a refresh, mirroring the\n * effect-driven behavior of the original React hook.\n */\nexport class GraphController {\n private readonly graphRepo: GraphRepository\n private readonly communityRepo: CommunitiesRepository\n private readonly listeners = new Set<GraphControllerListener>()\n private communitySourceId: string | null\n private state: GraphControllerState\n\n /** Build a controller from a database handle (production path). */\n static fromDb(db: GraphControllerDb, options: GraphControllerOptions = {}): GraphController {\n return new GraphController(new GraphRepository(db), new CommunitiesRepository(db), options)\n }\n\n constructor(\n graphRepo: GraphRepository,\n communityRepo: CommunitiesRepository,\n options: GraphControllerOptions = {},\n ) {\n this.graphRepo = graphRepo\n this.communityRepo = communityRepo\n this.communitySourceId = options.initialCommunitySourceId ?? null\n this.state = {\n mode: options.initialMode ?? 'citations',\n graph: null,\n graphSource: undefined,\n communitySource: undefined,\n embeddingSetSelector: options.initialEmbeddingSetSelector,\n filters: options.initialFilters,\n layout: { ...DEFAULT_LAYOUT, ...options.layout },\n status: { loading: false, error: null, freshness: null, cache: null },\n transition: undefined,\n }\n }\n\n getState(): GraphControllerState {\n return this.state\n }\n\n subscribe(listener: GraphControllerListener): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n /** Run the initial load. Call once after construction (the hook calls this on mount). */\n async start(): Promise<void> {\n await this.refresh()\n }\n\n private setState(patch: Partial<GraphControllerState>): void {\n this.state = { ...this.state, ...patch }\n for (const listener of this.listeners) listener(this.state)\n }\n\n private beginTransition(\n toMode: GraphSourceMode,\n reason: GraphTransitionState['reason'],\n fromMode: GraphSourceMode = this.state.mode,\n ): void {\n this.setState({ transition: { fromMode, toMode, reason, startedAt: new Date().toISOString() } })\n }\n\n async refresh(): Promise<void> {\n try {\n this.setState({ status: { ...this.state.status, loading: true, error: null } })\n const sources = await this.communityRepo.listCommunitySources()\n const activeCommunity = this.communitySourceId\n ? sources.find((source) => source.id === this.communitySourceId)\n : undefined\n this.setState({ communitySource: activeCommunity })\n\n const mode = this.state.mode\n\n if (mode === 'citations') {\n const nextGraph = await this.graphRepo.buildLinkGraph()\n this.setState({\n graph: nextGraph,\n graphSource: { id: 'citations', name: 'Citation graph' },\n status: { loading: false, error: null, freshness: 'fresh', cache: null },\n })\n return\n }\n\n if (mode === 'topics') {\n const selector = this.state.embeddingSetSelector\n if (!selector) throw new Error('topics mode requires an embedding-set selector')\n const result = await this.graphRepo.buildOrLoadSimilarityGraph({ selector })\n this.setState({\n graph: result.graph,\n graphSource: result.graphSource,\n status: { loading: false, error: null, freshness: result.freshness, cache: result.cache },\n })\n return\n }\n\n if (mode === 'precomputed') {\n if (!activeCommunity?.graphSourceId) {\n throw new Error('precomputed mode requires a community source with graphSourceId')\n }\n const assignments = await this.communityRepo.getCommunityAssignments(activeCommunity.id)\n const nextGraph = await this.graphRepo.loadGraphArtifact(\n activeCommunity.graphSourceId,\n assignments.map((assignment) => assignment.noteId),\n )\n this.setState({\n graph: nextGraph,\n graphSource: { id: activeCommunity.graphSourceId, name: activeCommunity.name },\n status: { loading: false, error: null, freshness: activeCommunity.freshness ?? 'unknown', cache: null },\n })\n return\n }\n\n if (mode === 'dynamic-search') {\n const assignments = await this.communityRepo.previewDynamicCommunity(this.state.filters ?? {})\n this.setState({\n graph: {\n nodes: assignments.map((assignment) => ({ id: assignment.noteId })),\n edges: [],\n communities: [{ id: 'dynamic-preview', nodes: assignments.map((assignment) => assignment.noteId) }],\n },\n graphSource: { id: 'dynamic-preview', name: 'Dynamic preview' },\n status: { loading: false, error: null, freshness: 'unknown', cache: null },\n })\n return\n }\n\n if (mode === 'user-authored') {\n if (!activeCommunity) throw new Error('user-authored mode requires an active community source')\n const assignments = await this.communityRepo.getCommunityAssignments(activeCommunity.id)\n this.setState({\n graph: {\n nodes: assignments.map((assignment) => ({ id: assignment.noteId })),\n edges: [],\n communities: [{ id: activeCommunity.id, nodes: assignments.map((assignment) => assignment.noteId) }],\n },\n graphSource: { id: activeCommunity.graphSourceId ?? activeCommunity.id, name: activeCommunity.name },\n status: { loading: false, error: null, freshness: activeCommunity.freshness ?? 'unknown', cache: null },\n })\n }\n } catch (err) {\n const e = err instanceof Error ? err : new Error(String(err))\n this.setState({ status: { ...this.state.status, loading: false, error: e } })\n throw e\n }\n }\n\n setMode(nextMode: GraphSourceMode): void {\n this.beginTransition(nextMode, 'mode-change')\n this.setState({ mode: nextMode })\n void this.refresh()\n }\n\n setEmbeddingSetSelector(selector: EmbeddingSetSelector): void {\n this.beginTransition('topics', 'embedding-set-change')\n this.setState({ embeddingSetSelector: selector, mode: 'topics' })\n void this.refresh()\n }\n\n setCommunitySource(sourceId: string | null): void {\n this.communitySourceId = sourceId\n this.beginTransition(this.state.mode, 'community-source-change')\n void this.refresh()\n }\n\n /** Apply dynamic-search filters and switch into that mode (state only). */\n private applyFilters(nextFilters: CommunityFilterDefinition): void {\n this.beginTransition('dynamic-search', 'filter-change')\n this.setState({ filters: nextFilters, mode: 'dynamic-search' })\n }\n\n setFilters(nextFilters: CommunityFilterDefinition): void {\n this.applyFilters(nextFilters)\n void this.refresh()\n }\n\n async recompute(): Promise<void> {\n this.beginTransition(this.state.mode, 'recompute')\n if (this.state.mode === 'topics' && this.state.embeddingSetSelector) {\n const result = await this.graphRepo.buildOrLoadSimilarityGraph({\n selector: this.state.embeddingSetSelector,\n source: 'live-only',\n })\n this.setState({\n graph: result.graph,\n graphSource: result.graphSource,\n status: { loading: false, error: null, freshness: result.freshness, cache: result.cache },\n })\n return\n }\n await this.refresh()\n }\n\n async previewDynamicCommunity(nextFilters: CommunityFilterDefinition): Promise<void> {\n this.applyFilters(nextFilters)\n await this.refresh()\n }\n\n async saveCurrentCommunity(input: CommunityCreateInput): Promise<CommunitySourceDescriptor> {\n const source = await this.communityRepo.saveCommunity(input)\n this.communitySourceId = source.id\n this.setState({ communitySource: source })\n return source\n }\n}\n","// @fortemi/graph — framework-agnostic graph presentation/projection helpers\n// plus the graph-source controller.\n//\n// Depends on @fortemi/core (the base data layer) and is consumed by\n// @fortemi/react and JS-only hosts. Dependency direction is the linear chain:\n// pglite ← @fortemi/core ← @fortemi/graph ← @fortemi/react. @fortemi/core never\n// imports @fortemi/graph.\n//\n// Pure projection helpers (layout, filtering, coloring, sizing, bounds,\n// neighborhood, snapshot) give React and JS-only hosts the shared logic to\n// render their own SVG/canvas views. `GraphController` adds the framework-\n// agnostic graph-source state machine (mode selection + load dispatch) on top\n// of @fortemi/core's repositories.\n//\n// Community *detection* intentionally lives in @fortemi/core (the base layer);\n// this package only renders/projects graphs it is given and orchestrates which\n// source to load.\n\nexport const VERSION = '2026.7.3'\n\nexport type {\n GraphNode,\n GraphEdge,\n GraphCommunity,\n CommunityGraph,\n GraphLayoutAlgorithm,\n PositionedGraphNode,\n PositionedCommunity,\n PositionedGraph,\n GraphBounds,\n ViewportTransform,\n} from './types.js'\n\nexport { computeDegrees, nodeRadius } from './degree.js'\nexport type { NodeRadiusOptions } from './degree.js'\n\nexport { COMMUNITY_COLORS, UNASSIGNED_COMMUNITY_COLOR, colorForCommunity } from './color.js'\n\nexport { filterCommunityGraph } from './filter.js'\nexport type { GraphFilter } from './filter.js'\n\nexport { layoutCommunityGraph } from './layout.js'\nexport type { LayoutOptions, NodeRadiusResolver } from './layout.js'\n\nexport { computeGraphBounds, fitGraphToViewport } from './bounds.js'\nexport type { FitOptions } from './bounds.js'\n\nexport {\n buildAdjacency,\n neighborsOf,\n expandNeighborhood,\n subgraphForNodes,\n neighborhoodSubgraph,\n} from './neighborhood.js'\nexport type { ExpandOptions } from './neighborhood.js'\n\nexport {\n GRAPH_SNAPSHOT_VERSION,\n serializeGraphSnapshot,\n stringifyGraphSnapshot,\n deserializeGraphSnapshot,\n} from './serialize.js'\nexport type { GraphSnapshot, SerializeSnapshotOptions } from './serialize.js'\n\nexport { GraphController } from './controller.js'\nexport type {\n GraphControllerDb,\n GraphSourceMode,\n GraphLayoutState,\n GraphTransitionState,\n GraphControllerStatus,\n GraphSourceRef,\n GraphControllerState,\n GraphControllerOptions,\n GraphControllerListener,\n} from './controller.js'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fortemi/graph",
3
- "version": "2026.7.1",
3
+ "version": "2026.7.3",
4
4
  "description": "Framework-agnostic graph tooling for fortemi: pure TypeScript helpers for community-graph layout, filtering, color assignment, degree sizing, bounds/fit, neighborhood expansion, and static snapshot serialization, plus a framework-agnostic GraphController for graph-source selection. No React. Depends on @fortemi/core; consumed by @fortemi/react and JS-only hosts.",
5
5
  "keywords": [
6
6
  "fortemi",
@@ -43,7 +43,7 @@
43
43
  "LICENSE"
44
44
  ],
45
45
  "dependencies": {
46
- "@fortemi/core": "2026.7.1"
46
+ "@fortemi/core": "2026.7.3"
47
47
  },
48
48
  "devDependencies": {
49
49
  "tsup": "^8.3.5",