@skygraph/core 0.4.0 → 0.5.0
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/README.md +48 -0
- package/dist/{chunk-KP75DEA4.js → chunk-7FA2TBSZ.js} +206 -7
- package/dist/chunk-7FA2TBSZ.js.map +1 -0
- package/dist/graph.cjs +210 -6
- package/dist/graph.cjs.map +1 -1
- package/dist/graph.d.cts +131 -2
- package/dist/graph.d.ts +131 -2
- package/dist/graph.js +11 -1
- package/dist/index.cjs +210 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-KP75DEA4.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,7 @@ import { C as Core, W as WriteEvent, M as Middleware } from './types-B-rKQJ4R.cj
|
|
|
2
2
|
export { N as NextFn, a as WriteSource } from './types-B-rKQJ4R.cjs';
|
|
3
3
|
export { MeasureCache, MeasureCacheEvent, MeasureCacheListener, MeasureCacheOptions, VirtualEngine, VirtualEngineEvent, VirtualEngineListener, VirtualEngineOptions, VirtualItem, VirtualRange, createMeasureCache, createVirtual } from './virtual.cjs';
|
|
4
4
|
export { FieldMeta, FieldMetaExtensions, FieldOptions, FormEngine, FormListOperation, FormOptions, FormState, GetFieldValue, Rule, RuleFn, RuleObject, ValidationMode, ValidationResult, createForm } from './form.cjs';
|
|
5
|
-
export { AABB, Anchor, AnchorId, AnchorPolicy, BezierPathOptions, EdgeEndpoint, EdgeId, EdgeInit, GraphEdge, GraphEngine, GraphEngineOptions, GraphNode, GraphState, NodeId, NodeInit, NodeTransform, NodeUpdate, OBB, Outline, Point, RouteOrthogonalOptions, Side, aabbFromOBB, createGraph, getBezierPath, nearestSide, obbContainsPoint, obbCorners, pointsToPath, pointsToRoundedPath, routeOrthogonal } from './graph.cjs';
|
|
5
|
+
export { AABB, Anchor, AnchorId, AnchorPolicy, BezierPathOptions, EdgeEndpoint, EdgeId, EdgeInit, GraphEdge, GraphEngine, GraphEngineOptions, GraphNode, GraphState, NodeId, NodeInit, NodeTransform, NodeUpdate, OBB, Outline, Point, ResolvedEndpoint, RouteOrthogonalOptions, Side, aabbFromOBB, createGraph, floatingAnchor, getBezierPath, getEdgePosition, getNodeIntersection, inferSide, nearestSide, obbContainsPoint, obbCorners, pointsToPath, pointsToRoundedPath, resolveEdgeEndpoint, routeOrthogonal } from './graph.cjs';
|
|
6
6
|
export { AdvancedFilter, AggregateFn, AggregateType, ColumnAggregate, ColumnFilter, FilterFn, FilterOperator, RowId, SortConfig, SortDirection, TableEngine, TableGroup, TableOptions, TableState, computeAggregate, createTable, matchesColumnFilter, matchesOperator, resolveOperator } from './table.cjs';
|
|
7
7
|
export { TreeEngine, TreeEngineOptions, TreeFieldNames, TreeKey, TreeNodeData, TreeState, createTree } from './tree.cjs';
|
|
8
8
|
export { Assignment as CalendarAssignment, AssignmentStatus as CalendarAssignmentStatus, AvailabilityRule as CalendarAvailabilityRule, Conflict as CalendarConflict, ConflictReason as CalendarConflictReason, DayOfWeek as CalendarDayOfWeek, DetectConflictsOptions as CalendarDetectConflictsOptions, CalendarEngine, CalendarEngineOptions, Resource as CalendarResource, CalendarScale, CalendarState, createCalendar, detectConflicts, isAvailable } from './calendar.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { C as Core, W as WriteEvent, M as Middleware } from './types-B-rKQJ4R.js
|
|
|
2
2
|
export { N as NextFn, a as WriteSource } from './types-B-rKQJ4R.js';
|
|
3
3
|
export { MeasureCache, MeasureCacheEvent, MeasureCacheListener, MeasureCacheOptions, VirtualEngine, VirtualEngineEvent, VirtualEngineListener, VirtualEngineOptions, VirtualItem, VirtualRange, createMeasureCache, createVirtual } from './virtual.js';
|
|
4
4
|
export { FieldMeta, FieldMetaExtensions, FieldOptions, FormEngine, FormListOperation, FormOptions, FormState, GetFieldValue, Rule, RuleFn, RuleObject, ValidationMode, ValidationResult, createForm } from './form.js';
|
|
5
|
-
export { AABB, Anchor, AnchorId, AnchorPolicy, BezierPathOptions, EdgeEndpoint, EdgeId, EdgeInit, GraphEdge, GraphEngine, GraphEngineOptions, GraphNode, GraphState, NodeId, NodeInit, NodeTransform, NodeUpdate, OBB, Outline, Point, RouteOrthogonalOptions, Side, aabbFromOBB, createGraph, getBezierPath, nearestSide, obbContainsPoint, obbCorners, pointsToPath, pointsToRoundedPath, routeOrthogonal } from './graph.js';
|
|
5
|
+
export { AABB, Anchor, AnchorId, AnchorPolicy, BezierPathOptions, EdgeEndpoint, EdgeId, EdgeInit, GraphEdge, GraphEngine, GraphEngineOptions, GraphNode, GraphState, NodeId, NodeInit, NodeTransform, NodeUpdate, OBB, Outline, Point, ResolvedEndpoint, RouteOrthogonalOptions, Side, aabbFromOBB, createGraph, floatingAnchor, getBezierPath, getEdgePosition, getNodeIntersection, inferSide, nearestSide, obbContainsPoint, obbCorners, pointsToPath, pointsToRoundedPath, resolveEdgeEndpoint, routeOrthogonal } from './graph.js';
|
|
6
6
|
export { AdvancedFilter, AggregateFn, AggregateType, ColumnAggregate, ColumnFilter, FilterFn, FilterOperator, RowId, SortConfig, SortDirection, TableEngine, TableGroup, TableOptions, TableState, computeAggregate, createTable, matchesColumnFilter, matchesOperator, resolveOperator } from './table.js';
|
|
7
7
|
export { TreeEngine, TreeEngineOptions, TreeFieldNames, TreeKey, TreeNodeData, TreeState, createTree } from './tree.js';
|
|
8
8
|
export { Assignment as CalendarAssignment, AssignmentStatus as CalendarAssignmentStatus, AvailabilityRule as CalendarAvailabilityRule, Conflict as CalendarConflict, ConflictReason as CalendarConflictReason, DayOfWeek as CalendarDayOfWeek, DetectConflictsOptions as CalendarDetectConflictsOptions, CalendarEngine, CalendarEngineOptions, Resource as CalendarResource, CalendarScale, CalendarState, createCalendar, detectConflicts, isAvailable } from './calendar.js';
|
package/dist/index.js
CHANGED
|
@@ -18,14 +18,19 @@ import {
|
|
|
18
18
|
import {
|
|
19
19
|
aabbFromOBB,
|
|
20
20
|
createGraph,
|
|
21
|
+
floatingAnchor,
|
|
21
22
|
getBezierPath,
|
|
23
|
+
getEdgePosition,
|
|
24
|
+
getNodeIntersection,
|
|
25
|
+
inferSide,
|
|
22
26
|
nearestSide,
|
|
23
27
|
obbContainsPoint,
|
|
24
28
|
obbCorners,
|
|
25
29
|
pointsToPath,
|
|
26
30
|
pointsToRoundedPath,
|
|
31
|
+
resolveEdgeEndpoint,
|
|
27
32
|
routeOrthogonal
|
|
28
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-7FA2TBSZ.js";
|
|
29
34
|
import {
|
|
30
35
|
createCalendar,
|
|
31
36
|
detectConflicts,
|
|
@@ -446,8 +451,12 @@ export {
|
|
|
446
451
|
createTypedCore,
|
|
447
452
|
createVirtual,
|
|
448
453
|
detectConflicts,
|
|
454
|
+
floatingAnchor,
|
|
449
455
|
freezeMiddleware,
|
|
450
456
|
getBezierPath,
|
|
457
|
+
getEdgePosition,
|
|
458
|
+
getNodeIntersection,
|
|
459
|
+
inferSide,
|
|
451
460
|
isAvailable,
|
|
452
461
|
listReservedPrefixes,
|
|
453
462
|
loggerMiddleware,
|
|
@@ -460,6 +469,7 @@ export {
|
|
|
460
469
|
pointsToPath,
|
|
461
470
|
pointsToRoundedPath,
|
|
462
471
|
reservePrefix,
|
|
472
|
+
resolveEdgeEndpoint,
|
|
463
473
|
resolveOperator,
|
|
464
474
|
routeOrthogonal,
|
|
465
475
|
validationMiddleware
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Core.ts","../src/middleware/logger.ts","../src/middleware/freeze.ts","../src/middleware/persistence.ts","../src/middleware/validation.ts","../src/plugins/history.ts","../src/typed.ts"],"sourcesContent":["import { Store } from './runtime/Store'\nimport { SubscriptionEngine } from './runtime/SubscriptionEngine'\nimport { Batch } from './runtime/Batch'\nimport { Transaction } from './runtime/Transaction'\nimport { ComputedEngine } from './runtime/ComputedEngine'\nimport type { Core, Middleware, WriteEvent, NextFn } from './types'\n\nclass CoreImpl implements Core {\n private store = new Store()\n private subscriptions = new SubscriptionEngine()\n private batch_ = new Batch()\n private transaction_ = new Transaction()\n private computed_ = new ComputedEngine()\n\n private middlewares: Middleware[] = []\n\n // ── Middleware ──\n\n use(middleware: Middleware): () => void {\n this.middlewares.push(middleware)\n return () => {\n const idx = this.middlewares.indexOf(middleware)\n if (idx !== -1) this.middlewares.splice(idx, 1)\n }\n }\n\n private dispatchWrite(event: WriteEvent): void {\n let idx = 0\n const chain: NextFn = (ev: WriteEvent) => {\n if (idx < this.middlewares.length) {\n const mw = this.middlewares[idx++]\n mw(ev, chain)\n } else {\n this.commitWrite(ev)\n }\n }\n chain(event)\n }\n\n private commitWrite(event: WriteEvent): void {\n this.store.set(event.path, event.value)\n }\n\n // ── Public API ──\n\n get(path: string): unknown {\n return this.store.get(path)\n }\n\n set(path: string, value: unknown): void {\n if (this.transaction_.isActive) {\n this.transaction_.stage(path, value, this.store.get(path))\n return\n }\n\n const oldValue = this.store.get(path)\n if (Object.is(oldValue, value)) return\n\n this.dispatchWrite({ path, value, oldValue, source: 'user' })\n\n const computedChanges = this.propagateComputed(new Set([path]))\n\n if (this.batch_.isActive) {\n this.batch_.enqueue(path, value)\n for (const [cp, cv] of computedChanges) {\n this.batch_.enqueue(cp, cv)\n }\n return\n }\n\n this.subscriptions.notify(path, value)\n this.subscriptions.notifyMany(computedChanges)\n }\n\n subscribe(path: string, cb: (value: unknown) => void): () => void {\n return this.subscriptions.subscribe(path, cb)\n }\n\n batch(fn: () => void): void {\n this.batch_.start()\n try {\n fn()\n } finally {\n const changes = this.batch_.end()\n if (changes) {\n this.subscriptions.notifyMany(changes)\n }\n }\n }\n\n transaction(fn: () => void): void {\n this.batch_.start()\n this.transaction_.start()\n try {\n fn()\n const staged = this.transaction_.getStaged()\n\n // Pass all writes through middleware first, collecting approved ones.\n // dispatchWrite normally commits to store, so we temporarily redirect\n // commits to a pending list and only apply them atomically if all succeed.\n const approved: Array<{ path: string; value: unknown }> = []\n const origCommit = this.commitWrite.bind(this)\n this.commitWrite = (ev: WriteEvent) => {\n approved.push({ path: ev.path, value: ev.value })\n }\n\n try {\n for (const write of staged) {\n if (Object.is(write.value, write.prevValue)) continue\n this.dispatchWrite({\n path: write.path,\n value: write.value,\n oldValue: write.prevValue,\n source: 'transaction',\n })\n }\n } finally {\n this.commitWrite = origCommit\n }\n\n // All middleware passed — atomically apply to store\n const changes = new Map<string, unknown>()\n for (const { path, value } of approved) {\n this.store.set(path, value)\n changes.set(path, value)\n }\n\n this.transaction_.complete()\n\n const computedChanges = this.propagateComputed(new Set(changes.keys()))\n\n for (const [path, value] of changes) {\n this.batch_.enqueue(path, value)\n }\n for (const [path, value] of computedChanges) {\n this.batch_.enqueue(path, value)\n }\n } catch (e) {\n this.transaction_.rollback()\n throw e\n } finally {\n const batchedChanges = this.batch_.end()\n if (batchedChanges) {\n this.subscriptions.notifyMany(batchedChanges)\n }\n }\n }\n\n computed(\n target: string,\n deps: string[],\n fn: (...values: unknown[]) => unknown,\n ): void {\n this.computed_.register(target, deps, fn)\n const depValues = deps.map((d) => this.store.get(d))\n const value = fn(...depValues)\n const oldValue = this.store.get(target)\n this.dispatchWrite({\n path: target,\n value,\n oldValue,\n source: 'computed',\n })\n\n if (!Object.is(oldValue, value)) {\n this.subscriptions.notify(target, value)\n }\n }\n\n // ── Snapshot / Restore ──\n\n snapshot(): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const path of this.store.paths()) {\n result[path] = this.store.get(path)\n }\n return result\n }\n\n restore(snap: Record<string, unknown>): void {\n this.batch_.start()\n try {\n for (const [path, value] of Object.entries(snap)) {\n const oldValue = this.store.get(path)\n if (!Object.is(oldValue, value)) {\n this.dispatchWrite({ path, value, oldValue, source: 'restore' })\n this.batch_.enqueue(path, value)\n }\n }\n } finally {\n const changes = this.batch_.end()\n if (changes) {\n this.subscriptions.notifyMany(changes)\n }\n }\n }\n\n // ── Internal helpers ──\n\n private propagateComputed(changedPaths: Set<string>): Map<string, unknown> {\n const rawChanges = this.computed_.propagateRaw(changedPaths, this.store)\n const dispatched = new Map<string, unknown>()\n\n for (const [path, { value, oldValue }] of rawChanges) {\n this.dispatchWrite({ path, value, oldValue, source: 'computed' })\n dispatched.set(path, value)\n }\n\n return dispatched\n }\n}\n\nexport function createCore(): Core {\n return new CoreImpl()\n}\n","import type { Middleware, WriteEvent, NextFn } from '../types'\n\nexport interface LoggerOptions {\n filter?: (event: WriteEvent) => boolean\n log?: (message: string, event: WriteEvent) => void\n}\n\nexport function loggerMiddleware(options: LoggerOptions = {}): Middleware {\n const log = options.log ?? ((msg, ev) => console.log(msg, ev.path, ev.value))\n const filter = options.filter\n\n return (event: WriteEvent, next: NextFn) => {\n if (filter && !filter(event)) {\n next(event)\n return\n }\n log(`[skygraph:${event.source}]`, event)\n next(event)\n }\n}\n","import type { Middleware, WriteEvent, NextFn } from '../types'\n\n/**\n * Prevents writes to specified path prefixes.\n * Useful for making parts of the store read-only.\n */\nexport function freezeMiddleware(frozenPaths: string[]): Middleware {\n return (event: WriteEvent, next: NextFn) => {\n for (const prefix of frozenPaths) {\n if (event.path === prefix || event.path.startsWith(prefix + '.')) {\n return\n }\n }\n next(event)\n }\n}\n","import type { Middleware, WriteEvent, NextFn } from '../types'\n\nexport interface PersistenceOptions {\n key?: string\n paths?: string[]\n storage?: {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n }\n debounce?: number\n}\n\n/**\n * Persists selected paths to a storage backend (localStorage by default).\n * Debounced to avoid excessive writes.\n */\nexport function persistenceMiddleware(options: PersistenceOptions = {}): Middleware {\n const storageKey = options.key ?? 'skygraph:state'\n const storage = options.storage ?? (typeof localStorage !== 'undefined' ? localStorage : null)\n const paths = options.paths\n const debounceMs = options.debounce ?? 100\n\n let pending: Record<string, unknown> = {}\n let timer: ReturnType<typeof setTimeout> | null = null\n\n function flush() {\n if (!storage) return\n const existing = storage.getItem(storageKey)\n let data: Record<string, unknown> = {}\n if (existing) {\n try {\n data = JSON.parse(existing)\n } catch {\n /* corrupted, start fresh */\n }\n }\n Object.assign(data, pending)\n storage.setItem(storageKey, JSON.stringify(data))\n pending = {}\n timer = null\n }\n\n return (event: WriteEvent, next: NextFn) => {\n next(event)\n\n if (paths && !paths.some((p) => event.path === p || event.path.startsWith(p + '.'))) {\n return\n }\n\n pending[event.path] = event.value\n\n if (timer === null) {\n timer = setTimeout(flush, debounceMs)\n }\n }\n}\n","import type { Middleware, WriteEvent, NextFn } from '../types'\n\nexport type Validator = (event: WriteEvent) => boolean | string\n\nexport interface ValidationMiddlewareOptions {\n validators: Record<string, Validator>\n onReject?: (event: WriteEvent, reason: string) => void\n}\n\n/**\n * Validates writes against a map of path -> validator.\n * If the validator returns false or a string (error message),\n * the write is rejected and onReject is called (if provided).\n */\nexport function validationMiddleware(\n optionsOrValidators: ValidationMiddlewareOptions | Record<string, Validator>,\n): Middleware {\n const isOptions = 'validators' in optionsOrValidators\n const validators: Record<string, Validator> = isOptions\n ? (optionsOrValidators as ValidationMiddlewareOptions).validators\n : (optionsOrValidators as Record<string, Validator>)\n const onReject = isOptions\n ? (optionsOrValidators as ValidationMiddlewareOptions).onReject\n : undefined\n\n return (event: WriteEvent, next: NextFn) => {\n const validator = validators[event.path]\n if (validator) {\n const result = validator(event)\n if (result === false || typeof result === 'string') {\n onReject?.(event, typeof result === 'string' ? result : 'Validation failed')\n return\n }\n }\n next(event)\n }\n}\n","import type { Core, Middleware, WriteEvent, NextFn } from '../types'\n\nexport interface HistoryEntry {\n timestamp: number\n patches: ReadonlyArray<{ path: string; value: unknown; oldValue: unknown }>\n}\n\nexport interface HistoryPlugin {\n readonly entries: ReadonlyArray<HistoryEntry>\n readonly cursor: number\n readonly canUndo: boolean\n readonly canRedo: boolean\n\n undo(): void\n redo(): void\n jumpTo(index: number): void\n clear(): void\n destroy(): void\n}\n\nexport interface HistoryOptions {\n maxEntries?: number\n /** Group multiple writes within this window (ms) into a single entry */\n groupWindow?: number\n filter?: (event: WriteEvent) => boolean\n}\n\nexport function createHistory(core: Core, options: HistoryOptions = {}): HistoryPlugin {\n const maxEntries = options.maxEntries ?? 100\n const groupWindow = options.groupWindow ?? 0\n const filter = options.filter\n\n const entries: HistoryEntry[] = []\n let cursor = -1\n let travelling = false\n let groupTimer: ReturnType<typeof setTimeout> | null = null\n let pendingPatches: HistoryEntry['patches'][number][] = []\n\n function flushGroup() {\n if (pendingPatches.length === 0) return\n const entry: HistoryEntry = {\n timestamp: Date.now(),\n patches: [...pendingPatches],\n }\n pendingPatches = []\n\n if (cursor < entries.length - 1) {\n entries.splice(cursor + 1)\n }\n\n entries.push(entry)\n cursor++\n if (entries.length > maxEntries) {\n entries.shift()\n cursor--\n }\n\n groupTimer = null\n }\n\n const middleware: Middleware = (event: WriteEvent, next: NextFn) => {\n next(event)\n\n if (travelling) return\n if (event.source === 'computed') return\n if (filter && !filter(event)) return\n\n pendingPatches.push({\n path: event.path,\n value: event.value,\n oldValue: event.oldValue,\n })\n\n if (groupWindow > 0) {\n if (groupTimer === null) {\n groupTimer = setTimeout(flushGroup, groupWindow)\n }\n } else {\n flushGroup()\n }\n }\n\n const unsub = core.use(middleware)\n\n function applyPatches(patches: HistoryEntry['patches'], direction: 'undo' | 'redo') {\n travelling = true\n try {\n core.batch(() => {\n if (direction === 'undo') {\n for (let i = patches.length - 1; i >= 0; i--) {\n core.set(patches[i].path, patches[i].oldValue)\n }\n } else {\n for (const patch of patches) {\n core.set(patch.path, patch.value)\n }\n }\n })\n } finally {\n travelling = false\n }\n }\n\n return {\n get entries() {\n return entries as ReadonlyArray<HistoryEntry>\n },\n get cursor() {\n return cursor\n },\n get canUndo() {\n return cursor >= 0\n },\n get canRedo() {\n return cursor < entries.length - 1\n },\n\n undo() {\n if (cursor < 0) return\n flushGroup()\n applyPatches(entries[cursor].patches, 'undo')\n cursor--\n },\n\n redo() {\n if (cursor >= entries.length - 1) return\n flushGroup()\n cursor++\n applyPatches(entries[cursor].patches, 'redo')\n },\n\n jumpTo(index: number) {\n if (index < -1 || index >= entries.length) return\n flushGroup()\n\n while (cursor > index) {\n applyPatches(entries[cursor].patches, 'undo')\n cursor--\n }\n while (cursor < index) {\n cursor++\n applyPatches(entries[cursor].patches, 'redo')\n }\n },\n\n clear() {\n entries.length = 0\n cursor = -1\n pendingPatches = []\n if (groupTimer !== null) {\n clearTimeout(groupTimer)\n groupTimer = null\n }\n },\n\n destroy() {\n this.clear()\n unsub()\n },\n }\n}\n","import type { Core } from './types'\n\n/**\n * Utility types for path-based type inference.\n * These provide compile-time type safety over the untyped Core runtime.\n */\n\ntype Primitive = string | number | boolean | null | undefined\n\n/**\n * Extracts dot-notation paths from a nested object type (max 3 levels deep).\n * Example: Path<{user: {name: string}}> = \"user\" | \"user.name\"\n */\nexport type Path<T> = T extends Primitive\n ? never\n : {\n [K in keyof T & string]: T[K] extends Primitive\n ? K\n : T[K] extends Record<string, unknown>\n ?\n | K\n | `${K}.${keyof T[K] & string}`\n | {\n [L in keyof T[K] & string]: T[K][L] extends Record<\n string,\n unknown\n >\n ? `${K}.${L}.${keyof T[K][L] & string}`\n : never\n }[keyof T[K] & string]\n : K\n }[keyof T & string]\n\n/**\n * Resolves the value type at a given dot-notation path (max 3 levels).\n */\nexport type PathValue<T, P extends string> = P extends keyof T\n ? T[P]\n : P extends `${infer K}.${infer Rest}`\n ? K extends keyof T\n ? Rest extends keyof T[K]\n ? T[K][Rest]\n : Rest extends `${infer L}.${infer M}`\n ? L extends keyof T[K]\n ? M extends keyof T[K][L]\n ? T[K][L][M]\n : unknown\n : unknown\n : unknown\n : unknown\n : unknown\n\n/**\n * Type-safe wrapper over Core.\n * Compile-time only — runtime behavior is identical to Core.\n */\nexport interface TypedCore<T> {\n get<K extends Path<T>>(path: K): PathValue<T, K>\n set<K extends Path<T>>(path: K, value: PathValue<T, K>): void\n subscribe<K extends Path<T>>(\n path: K,\n cb: (value: PathValue<T, K>) => void\n ): () => void\n batch(fn: () => void): void\n transaction(fn: () => void): void\n computed<K extends Path<T>>(\n target: K,\n deps: Path<T>[],\n fn: (...values: unknown[]) => PathValue<T, K>\n ): void\n /** Access the untyped core underneath */\n raw: Core\n}\n\n/**\n * Creates a type-safe wrapper around an existing Core instance.\n * No runtime overhead — just type narrowing.\n */\nexport function createTypedCore<T>(core: Core): TypedCore<T> {\n return {\n get: core.get.bind(core) as TypedCore<T>['get'],\n set: core.set.bind(core) as TypedCore<T>['set'],\n subscribe: core.subscribe.bind(core) as TypedCore<T>['subscribe'],\n batch: core.batch.bind(core),\n transaction: core.transaction.bind(core),\n computed: core.computed.bind(core) as TypedCore<T>['computed'],\n raw: core,\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/Core.ts","../src/middleware/logger.ts","../src/middleware/freeze.ts","../src/middleware/persistence.ts","../src/middleware/validation.ts","../src/plugins/history.ts","../src/typed.ts"],"sourcesContent":["import { Store } from './runtime/Store'\nimport { SubscriptionEngine } from './runtime/SubscriptionEngine'\nimport { Batch } from './runtime/Batch'\nimport { Transaction } from './runtime/Transaction'\nimport { ComputedEngine } from './runtime/ComputedEngine'\nimport type { Core, Middleware, WriteEvent, NextFn } from './types'\n\nclass CoreImpl implements Core {\n private store = new Store()\n private subscriptions = new SubscriptionEngine()\n private batch_ = new Batch()\n private transaction_ = new Transaction()\n private computed_ = new ComputedEngine()\n\n private middlewares: Middleware[] = []\n\n // ── Middleware ──\n\n use(middleware: Middleware): () => void {\n this.middlewares.push(middleware)\n return () => {\n const idx = this.middlewares.indexOf(middleware)\n if (idx !== -1) this.middlewares.splice(idx, 1)\n }\n }\n\n private dispatchWrite(event: WriteEvent): void {\n let idx = 0\n const chain: NextFn = (ev: WriteEvent) => {\n if (idx < this.middlewares.length) {\n const mw = this.middlewares[idx++]\n mw(ev, chain)\n } else {\n this.commitWrite(ev)\n }\n }\n chain(event)\n }\n\n private commitWrite(event: WriteEvent): void {\n this.store.set(event.path, event.value)\n }\n\n // ── Public API ──\n\n get(path: string): unknown {\n return this.store.get(path)\n }\n\n set(path: string, value: unknown): void {\n if (this.transaction_.isActive) {\n this.transaction_.stage(path, value, this.store.get(path))\n return\n }\n\n const oldValue = this.store.get(path)\n if (Object.is(oldValue, value)) return\n\n this.dispatchWrite({ path, value, oldValue, source: 'user' })\n\n const computedChanges = this.propagateComputed(new Set([path]))\n\n if (this.batch_.isActive) {\n this.batch_.enqueue(path, value)\n for (const [cp, cv] of computedChanges) {\n this.batch_.enqueue(cp, cv)\n }\n return\n }\n\n this.subscriptions.notify(path, value)\n this.subscriptions.notifyMany(computedChanges)\n }\n\n subscribe(path: string, cb: (value: unknown) => void): () => void {\n return this.subscriptions.subscribe(path, cb)\n }\n\n batch(fn: () => void): void {\n this.batch_.start()\n try {\n fn()\n } finally {\n const changes = this.batch_.end()\n if (changes) {\n this.subscriptions.notifyMany(changes)\n }\n }\n }\n\n transaction(fn: () => void): void {\n this.batch_.start()\n this.transaction_.start()\n try {\n fn()\n const staged = this.transaction_.getStaged()\n\n // Pass all writes through middleware first, collecting approved ones.\n // dispatchWrite normally commits to store, so we temporarily redirect\n // commits to a pending list and only apply them atomically if all succeed.\n const approved: Array<{ path: string; value: unknown }> = []\n const origCommit = this.commitWrite.bind(this)\n this.commitWrite = (ev: WriteEvent) => {\n approved.push({ path: ev.path, value: ev.value })\n }\n\n try {\n for (const write of staged) {\n if (Object.is(write.value, write.prevValue)) continue\n this.dispatchWrite({\n path: write.path,\n value: write.value,\n oldValue: write.prevValue,\n source: 'transaction',\n })\n }\n } finally {\n this.commitWrite = origCommit\n }\n\n // All middleware passed — atomically apply to store\n const changes = new Map<string, unknown>()\n for (const { path, value } of approved) {\n this.store.set(path, value)\n changes.set(path, value)\n }\n\n this.transaction_.complete()\n\n const computedChanges = this.propagateComputed(new Set(changes.keys()))\n\n for (const [path, value] of changes) {\n this.batch_.enqueue(path, value)\n }\n for (const [path, value] of computedChanges) {\n this.batch_.enqueue(path, value)\n }\n } catch (e) {\n this.transaction_.rollback()\n throw e\n } finally {\n const batchedChanges = this.batch_.end()\n if (batchedChanges) {\n this.subscriptions.notifyMany(batchedChanges)\n }\n }\n }\n\n computed(\n target: string,\n deps: string[],\n fn: (...values: unknown[]) => unknown,\n ): void {\n this.computed_.register(target, deps, fn)\n const depValues = deps.map((d) => this.store.get(d))\n const value = fn(...depValues)\n const oldValue = this.store.get(target)\n this.dispatchWrite({\n path: target,\n value,\n oldValue,\n source: 'computed',\n })\n\n if (!Object.is(oldValue, value)) {\n this.subscriptions.notify(target, value)\n }\n }\n\n // ── Snapshot / Restore ──\n\n snapshot(): Record<string, unknown> {\n const result: Record<string, unknown> = {}\n for (const path of this.store.paths()) {\n result[path] = this.store.get(path)\n }\n return result\n }\n\n restore(snap: Record<string, unknown>): void {\n this.batch_.start()\n try {\n for (const [path, value] of Object.entries(snap)) {\n const oldValue = this.store.get(path)\n if (!Object.is(oldValue, value)) {\n this.dispatchWrite({ path, value, oldValue, source: 'restore' })\n this.batch_.enqueue(path, value)\n }\n }\n } finally {\n const changes = this.batch_.end()\n if (changes) {\n this.subscriptions.notifyMany(changes)\n }\n }\n }\n\n // ── Internal helpers ──\n\n private propagateComputed(changedPaths: Set<string>): Map<string, unknown> {\n const rawChanges = this.computed_.propagateRaw(changedPaths, this.store)\n const dispatched = new Map<string, unknown>()\n\n for (const [path, { value, oldValue }] of rawChanges) {\n this.dispatchWrite({ path, value, oldValue, source: 'computed' })\n dispatched.set(path, value)\n }\n\n return dispatched\n }\n}\n\nexport function createCore(): Core {\n return new CoreImpl()\n}\n","import type { Middleware, WriteEvent, NextFn } from '../types'\n\nexport interface LoggerOptions {\n filter?: (event: WriteEvent) => boolean\n log?: (message: string, event: WriteEvent) => void\n}\n\nexport function loggerMiddleware(options: LoggerOptions = {}): Middleware {\n const log = options.log ?? ((msg, ev) => console.log(msg, ev.path, ev.value))\n const filter = options.filter\n\n return (event: WriteEvent, next: NextFn) => {\n if (filter && !filter(event)) {\n next(event)\n return\n }\n log(`[skygraph:${event.source}]`, event)\n next(event)\n }\n}\n","import type { Middleware, WriteEvent, NextFn } from '../types'\n\n/**\n * Prevents writes to specified path prefixes.\n * Useful for making parts of the store read-only.\n */\nexport function freezeMiddleware(frozenPaths: string[]): Middleware {\n return (event: WriteEvent, next: NextFn) => {\n for (const prefix of frozenPaths) {\n if (event.path === prefix || event.path.startsWith(prefix + '.')) {\n return\n }\n }\n next(event)\n }\n}\n","import type { Middleware, WriteEvent, NextFn } from '../types'\n\nexport interface PersistenceOptions {\n key?: string\n paths?: string[]\n storage?: {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n }\n debounce?: number\n}\n\n/**\n * Persists selected paths to a storage backend (localStorage by default).\n * Debounced to avoid excessive writes.\n */\nexport function persistenceMiddleware(options: PersistenceOptions = {}): Middleware {\n const storageKey = options.key ?? 'skygraph:state'\n const storage = options.storage ?? (typeof localStorage !== 'undefined' ? localStorage : null)\n const paths = options.paths\n const debounceMs = options.debounce ?? 100\n\n let pending: Record<string, unknown> = {}\n let timer: ReturnType<typeof setTimeout> | null = null\n\n function flush() {\n if (!storage) return\n const existing = storage.getItem(storageKey)\n let data: Record<string, unknown> = {}\n if (existing) {\n try {\n data = JSON.parse(existing)\n } catch {\n /* corrupted, start fresh */\n }\n }\n Object.assign(data, pending)\n storage.setItem(storageKey, JSON.stringify(data))\n pending = {}\n timer = null\n }\n\n return (event: WriteEvent, next: NextFn) => {\n next(event)\n\n if (paths && !paths.some((p) => event.path === p || event.path.startsWith(p + '.'))) {\n return\n }\n\n pending[event.path] = event.value\n\n if (timer === null) {\n timer = setTimeout(flush, debounceMs)\n }\n }\n}\n","import type { Middleware, WriteEvent, NextFn } from '../types'\n\nexport type Validator = (event: WriteEvent) => boolean | string\n\nexport interface ValidationMiddlewareOptions {\n validators: Record<string, Validator>\n onReject?: (event: WriteEvent, reason: string) => void\n}\n\n/**\n * Validates writes against a map of path -> validator.\n * If the validator returns false or a string (error message),\n * the write is rejected and onReject is called (if provided).\n */\nexport function validationMiddleware(\n optionsOrValidators: ValidationMiddlewareOptions | Record<string, Validator>,\n): Middleware {\n const isOptions = 'validators' in optionsOrValidators\n const validators: Record<string, Validator> = isOptions\n ? (optionsOrValidators as ValidationMiddlewareOptions).validators\n : (optionsOrValidators as Record<string, Validator>)\n const onReject = isOptions\n ? (optionsOrValidators as ValidationMiddlewareOptions).onReject\n : undefined\n\n return (event: WriteEvent, next: NextFn) => {\n const validator = validators[event.path]\n if (validator) {\n const result = validator(event)\n if (result === false || typeof result === 'string') {\n onReject?.(event, typeof result === 'string' ? result : 'Validation failed')\n return\n }\n }\n next(event)\n }\n}\n","import type { Core, Middleware, WriteEvent, NextFn } from '../types'\n\nexport interface HistoryEntry {\n timestamp: number\n patches: ReadonlyArray<{ path: string; value: unknown; oldValue: unknown }>\n}\n\nexport interface HistoryPlugin {\n readonly entries: ReadonlyArray<HistoryEntry>\n readonly cursor: number\n readonly canUndo: boolean\n readonly canRedo: boolean\n\n undo(): void\n redo(): void\n jumpTo(index: number): void\n clear(): void\n destroy(): void\n}\n\nexport interface HistoryOptions {\n maxEntries?: number\n /** Group multiple writes within this window (ms) into a single entry */\n groupWindow?: number\n filter?: (event: WriteEvent) => boolean\n}\n\nexport function createHistory(core: Core, options: HistoryOptions = {}): HistoryPlugin {\n const maxEntries = options.maxEntries ?? 100\n const groupWindow = options.groupWindow ?? 0\n const filter = options.filter\n\n const entries: HistoryEntry[] = []\n let cursor = -1\n let travelling = false\n let groupTimer: ReturnType<typeof setTimeout> | null = null\n let pendingPatches: HistoryEntry['patches'][number][] = []\n\n function flushGroup() {\n if (pendingPatches.length === 0) return\n const entry: HistoryEntry = {\n timestamp: Date.now(),\n patches: [...pendingPatches],\n }\n pendingPatches = []\n\n if (cursor < entries.length - 1) {\n entries.splice(cursor + 1)\n }\n\n entries.push(entry)\n cursor++\n if (entries.length > maxEntries) {\n entries.shift()\n cursor--\n }\n\n groupTimer = null\n }\n\n const middleware: Middleware = (event: WriteEvent, next: NextFn) => {\n next(event)\n\n if (travelling) return\n if (event.source === 'computed') return\n if (filter && !filter(event)) return\n\n pendingPatches.push({\n path: event.path,\n value: event.value,\n oldValue: event.oldValue,\n })\n\n if (groupWindow > 0) {\n if (groupTimer === null) {\n groupTimer = setTimeout(flushGroup, groupWindow)\n }\n } else {\n flushGroup()\n }\n }\n\n const unsub = core.use(middleware)\n\n function applyPatches(patches: HistoryEntry['patches'], direction: 'undo' | 'redo') {\n travelling = true\n try {\n core.batch(() => {\n if (direction === 'undo') {\n for (let i = patches.length - 1; i >= 0; i--) {\n core.set(patches[i].path, patches[i].oldValue)\n }\n } else {\n for (const patch of patches) {\n core.set(patch.path, patch.value)\n }\n }\n })\n } finally {\n travelling = false\n }\n }\n\n return {\n get entries() {\n return entries as ReadonlyArray<HistoryEntry>\n },\n get cursor() {\n return cursor\n },\n get canUndo() {\n return cursor >= 0\n },\n get canRedo() {\n return cursor < entries.length - 1\n },\n\n undo() {\n if (cursor < 0) return\n flushGroup()\n applyPatches(entries[cursor].patches, 'undo')\n cursor--\n },\n\n redo() {\n if (cursor >= entries.length - 1) return\n flushGroup()\n cursor++\n applyPatches(entries[cursor].patches, 'redo')\n },\n\n jumpTo(index: number) {\n if (index < -1 || index >= entries.length) return\n flushGroup()\n\n while (cursor > index) {\n applyPatches(entries[cursor].patches, 'undo')\n cursor--\n }\n while (cursor < index) {\n cursor++\n applyPatches(entries[cursor].patches, 'redo')\n }\n },\n\n clear() {\n entries.length = 0\n cursor = -1\n pendingPatches = []\n if (groupTimer !== null) {\n clearTimeout(groupTimer)\n groupTimer = null\n }\n },\n\n destroy() {\n this.clear()\n unsub()\n },\n }\n}\n","import type { Core } from './types'\n\n/**\n * Utility types for path-based type inference.\n * These provide compile-time type safety over the untyped Core runtime.\n */\n\ntype Primitive = string | number | boolean | null | undefined\n\n/**\n * Extracts dot-notation paths from a nested object type (max 3 levels deep).\n * Example: Path<{user: {name: string}}> = \"user\" | \"user.name\"\n */\nexport type Path<T> = T extends Primitive\n ? never\n : {\n [K in keyof T & string]: T[K] extends Primitive\n ? K\n : T[K] extends Record<string, unknown>\n ?\n | K\n | `${K}.${keyof T[K] & string}`\n | {\n [L in keyof T[K] & string]: T[K][L] extends Record<\n string,\n unknown\n >\n ? `${K}.${L}.${keyof T[K][L] & string}`\n : never\n }[keyof T[K] & string]\n : K\n }[keyof T & string]\n\n/**\n * Resolves the value type at a given dot-notation path (max 3 levels).\n */\nexport type PathValue<T, P extends string> = P extends keyof T\n ? T[P]\n : P extends `${infer K}.${infer Rest}`\n ? K extends keyof T\n ? Rest extends keyof T[K]\n ? T[K][Rest]\n : Rest extends `${infer L}.${infer M}`\n ? L extends keyof T[K]\n ? M extends keyof T[K][L]\n ? T[K][L][M]\n : unknown\n : unknown\n : unknown\n : unknown\n : unknown\n\n/**\n * Type-safe wrapper over Core.\n * Compile-time only — runtime behavior is identical to Core.\n */\nexport interface TypedCore<T> {\n get<K extends Path<T>>(path: K): PathValue<T, K>\n set<K extends Path<T>>(path: K, value: PathValue<T, K>): void\n subscribe<K extends Path<T>>(\n path: K,\n cb: (value: PathValue<T, K>) => void\n ): () => void\n batch(fn: () => void): void\n transaction(fn: () => void): void\n computed<K extends Path<T>>(\n target: K,\n deps: Path<T>[],\n fn: (...values: unknown[]) => PathValue<T, K>\n ): void\n /** Access the untyped core underneath */\n raw: Core\n}\n\n/**\n * Creates a type-safe wrapper around an existing Core instance.\n * No runtime overhead — just type narrowing.\n */\nexport function createTypedCore<T>(core: Core): TypedCore<T> {\n return {\n get: core.get.bind(core) as TypedCore<T>['get'],\n set: core.set.bind(core) as TypedCore<T>['set'],\n subscribe: core.subscribe.bind(core) as TypedCore<T>['subscribe'],\n batch: core.batch.bind(core),\n transaction: core.transaction.bind(core),\n computed: core.computed.bind(core) as TypedCore<T>['computed'],\n raw: core,\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engines/graph/history.ts","../src/engines/graph/GraphEngine.ts","../src/engines/graph/router.ts","../src/engines/graph/obb.ts"],"sourcesContent":["/**\r\n * Undo/redo history for `GraphEngine`.\r\n *\r\n * Snapshots are shallow: they capture the current `nodes` / `edges` arrays\r\n * plus the engine id counters. Because all mutating paths in `GraphEngine`\r\n * replace nodes/edges via `Map.set(id, { ...next })` (never in-place mutation),\r\n * a shallow array of references is enough to restore an exact prior state.\r\n *\r\n * The store/derived data (`edgesByNode`) is rebuilt from `edges` on restore —\r\n * keeping it out of the snapshot avoids subtle corruption if a future change\r\n * adds a derived index.\r\n */\r\nimport type { GraphEdge, GraphNode } from './types'\r\n\r\n/** Maximum number of entries kept in either undo or redo stack. */\r\nexport const HISTORY_LIMIT = 100\r\n\r\n/**\r\n * Immutable snapshot of the engine's state at a point in time.\r\n * Restoration is exact — including id counters so newly generated ids\r\n * don't collide with ids that existed in a future-then-undone state.\r\n */\r\nexport interface GraphSnapshot {\r\n readonly nodes: readonly GraphNode[]\r\n readonly edges: readonly GraphEdge[]\r\n readonly nodeCounter: number\r\n readonly edgeCounter: number\r\n}\r\n\r\n/** One entry on the undo or redo stack. */\r\nexport interface HistoryEntry {\r\n readonly snapshot: GraphSnapshot\r\n readonly label?: string\r\n}\r\n\r\nexport interface History {\r\n push(entry: HistoryEntry): void\r\n popUndo(): HistoryEntry | undefined\r\n popRedo(): HistoryEntry | undefined\r\n pushRedo(entry: HistoryEntry): void\r\n clearRedo(): void\r\n canUndo(): boolean\r\n canRedo(): boolean\r\n clear(): void\r\n /**\r\n * Replace the label on the most recent undo entry without disturbing\r\n * its snapshot. No-op when the stack is empty.\r\n */\r\n relabelTop(label: string | undefined): void\r\n /** Read-only label of the most recent undo entry (or `undefined`). */\r\n topLabel(): string | undefined\r\n /** @internal — for tests/introspection only. */\r\n size(): { undo: number; redo: number }\r\n}\r\n\r\n/**\r\n * Pure data store for the undo/redo stacks. The engine owns the capture /\r\n * restore semantics; this module only enforces the LIFO discipline and the\r\n * stack-size cap.\r\n */\r\nexport function createHistory(limit: number = HISTORY_LIMIT): History {\r\n const undoStack: HistoryEntry[] = []\r\n const redoStack: HistoryEntry[] = []\r\n\r\n function trim(stack: HistoryEntry[]): void {\r\n while (stack.length > limit) stack.shift()\r\n }\r\n\r\n return {\r\n push(entry) {\r\n undoStack.push(entry)\r\n trim(undoStack)\r\n },\r\n popUndo() {\r\n return undoStack.pop()\r\n },\r\n pushRedo(entry) {\r\n redoStack.push(entry)\r\n trim(redoStack)\r\n },\r\n popRedo() {\r\n return redoStack.pop()\r\n },\r\n clearRedo() {\r\n redoStack.length = 0\r\n },\r\n canUndo() {\r\n return undoStack.length > 0\r\n },\r\n canRedo() {\r\n return redoStack.length > 0\r\n },\r\n clear() {\r\n undoStack.length = 0\r\n redoStack.length = 0\r\n },\r\n relabelTop(label) {\r\n const top = undoStack[undoStack.length - 1]\r\n if (!top) return\r\n undoStack[undoStack.length - 1] = { snapshot: top.snapshot, label }\r\n },\r\n topLabel() {\r\n return undoStack[undoStack.length - 1]?.label\r\n },\r\n size() {\r\n return { undo: undoStack.length, redo: redoStack.length }\r\n },\r\n }\r\n}\r\n","import type { Core } from '../../types'\r\nimport { GRAPH_PREFIX } from '../namespaces'\r\nimport { createHistory, HISTORY_LIMIT, type HistoryEntry, type GraphSnapshot } from './history'\r\nimport type {\r\n AABB,\r\n Anchor,\r\n AnchorId,\r\n AnchorPolicy,\r\n EdgeEndpoint,\r\n EdgeId,\r\n EdgeInit,\r\n GraphEdge,\r\n GraphEngine,\r\n GraphEngineOptions,\r\n GraphNode,\r\n GraphState,\r\n NodeId,\r\n NodeInit,\r\n NodeTransform,\r\n NodeUpdate,\r\n OBB,\r\n Outline,\r\n Point,\r\n} from './types'\r\n\r\nlet engineCounter = 0\r\n\r\nconst DEFAULT_OUTLINE: Outline = { kind: 'rect', w: 100, h: 60 }\r\nconst DEFAULT_TRANSFORM: NodeTransform = { x: 0, y: 0 }\r\nconst DEFAULT_ANCHOR_POLICY: AnchorPolicy = { kind: 'perEdge', k: 1 }\r\n\r\n/**\r\n * Reactive diagram engine — the fourth member of the form / table / tree /\r\n * **graph** family. State is mirrored into the Core store under `$graph.`\r\n * for cross-engine coordination, but the in-memory maps are the source of\r\n * truth and the public read API.\r\n *\r\n * v0 scope (initial Graph engine stream — see CHANGELOG):\r\n * - Node / Edge model + parent hierarchy\r\n * - addNode / removeNode / updateNode / moveNode / setParent\r\n * - addEdge / removeEdge\r\n * - anchor generator (perEdge / byLength / manual)\r\n * - bounds computation (AABB, no rotation)\r\n * - geomRevision bump on geometry-affecting updates\r\n *\r\n * NOT in v0:\r\n * - orthogonal routing (with obstacle avoidance)\r\n * - undo / redo (covered separately by `plugins/history`)\r\n * - snap-to-grid, drag-and-drop palette\r\n * - rotated bounding boxes (OBB)\r\n */\r\nexport function createGraph(core: Core, options?: GraphEngineOptions): GraphEngine {\r\n const engineId = `g${engineCounter++}${options?.name ? `-${options.name}` : ''}`\r\n const prefix = GRAPH_PREFIX\r\n\r\n const nodes = new Map<NodeId, GraphNode>()\r\n const edges = new Map<EdgeId, GraphEdge>()\r\n const edgesByNode = new Map<NodeId, Set<EdgeId>>()\r\n\r\n let nodeCounter = 0\r\n let edgeCounter = 0\r\n\r\n // ─── Persistence + local subscribers ──────────────────────────────────────\r\n //\r\n // We mirror snapshots into the Core store so other engines / external\r\n // observers can react via `core.subscribe(...)`. We ALSO maintain a small\r\n // local subscriber set that React adapters use directly — that avoids\r\n // having to know the engineId-suffixed path from the outside.\r\n\r\n const localSubscribers = new Set<() => void>()\r\n\r\n function publishSnapshot() {\r\n core.set(`${prefix}snapshot.${engineId}`, {\r\n nodes: Array.from(nodes.values()),\r\n edges: Array.from(edges.values()),\r\n })\r\n for (const cb of localSubscribers) cb()\r\n }\r\n\r\n function subscribeLocal(cb: () => void): () => void {\r\n localSubscribers.add(cb)\r\n return () => {\r\n localSubscribers.delete(cb)\r\n }\r\n }\r\n\r\n publishSnapshot() // initial empty snapshot\r\n\r\n // ─── History (undo/redo) ──────────────────────────────────────────────────\r\n //\r\n // The engine wraps every mutating public method in `_withHistory`. The\r\n // wrapper captures the engine state on the OUTERMOST call (so nested\r\n // mutations — e.g. `removeNode` -> `removeEdge` — only contribute one\r\n // history entry) and pushes the captured snapshot to the undo stack on\r\n // commit. `transaction(fn)` is the public form of the same primitive,\r\n // letting callers batch unrelated mutations into a single entry.\r\n //\r\n // Restoration (`undo`/`redo`) sets `isRestoring = true` to suppress\r\n // history capture inside `_restoreState`.\r\n\r\n const history = createHistory(HISTORY_LIMIT)\r\n let transactionDepth = 0\r\n let pendingEntry: HistoryEntry | null = null\r\n let isRestoring = false\r\n\r\n function _captureState(): GraphSnapshot {\r\n return {\r\n nodes: Array.from(nodes.values()),\r\n edges: Array.from(edges.values()),\r\n nodeCounter,\r\n edgeCounter,\r\n }\r\n }\r\n\r\n function _restoreState(snapshot: GraphSnapshot): void {\r\n nodes.clear()\r\n edges.clear()\r\n edgesByNode.clear()\r\n for (const n of snapshot.nodes) {\r\n nodes.set(n.id, n)\r\n edgesByNode.set(n.id, new Set())\r\n }\r\n for (const e of snapshot.edges) {\r\n edges.set(e.id, e)\r\n ensureBucket(endpointNode(e.from)).add(e.id)\r\n ensureBucket(endpointNode(e.to)).add(e.id)\r\n }\r\n nodeCounter = snapshot.nodeCounter\r\n edgeCounter = snapshot.edgeCounter\r\n }\r\n\r\n function _withHistory<T>(fn: () => T, label?: string): T {\r\n if (isRestoring) return fn()\r\n const wasOuter = transactionDepth === 0\r\n if (wasOuter) {\r\n pendingEntry = { snapshot: _captureState(), label }\r\n } else if (label !== undefined && pendingEntry && pendingEntry.label === undefined) {\r\n pendingEntry = { snapshot: pendingEntry.snapshot, label }\r\n }\r\n transactionDepth++\r\n try {\r\n return fn()\r\n } finally {\r\n transactionDepth--\r\n if (transactionDepth === 0 && wasOuter) {\r\n if (pendingEntry !== null) {\r\n history.push(pendingEntry)\r\n history.clearRedo()\r\n }\r\n pendingEntry = null\r\n }\r\n }\r\n }\r\n\r\n // ─── Helpers ──────────────────────────────────────────────────────────────\r\n\r\n function newNodeId(): NodeId {\r\n return `${engineId}-n${nodeCounter++}`\r\n }\r\n\r\n function newEdgeId(): EdgeId {\r\n return `${engineId}-e${edgeCounter++}`\r\n }\r\n\r\n function ensureBucket(nodeId: NodeId): Set<EdgeId> {\r\n let bucket = edgesByNode.get(nodeId)\r\n if (!bucket) {\r\n bucket = new Set()\r\n edgesByNode.set(nodeId, bucket)\r\n }\r\n return bucket\r\n }\r\n\r\n function endpointNode(ep: EdgeEndpoint): NodeId {\r\n return ep.node\r\n }\r\n\r\n function bumpRevision(node: GraphNode): GraphNode {\r\n return { ...node, geomRevision: node.geomRevision + 1 }\r\n }\r\n\r\n // ─── Node operations ──────────────────────────────────────────────────────\r\n //\r\n // The `_impl` functions are the raw mutators. The exported `addNode` /\r\n // `removeNode` / ... wrap them in `_withHistory` so the public surface\r\n // automatically participates in undo/redo. Internal calls between\r\n // mutators (e.g. `removeNode` → `removeEdge`) go through the wrapped\r\n // form too, but `_withHistory` recognizes nested transactions and only\r\n // commits one entry.\r\n\r\n function _addNodeImpl(init: NodeInit = {}): NodeId {\r\n const id = init.id ?? newNodeId()\r\n if (nodes.has(id)) {\r\n throw new Error(`[skygraph/graph] node id \"${id}\" already exists`)\r\n }\r\n const node: GraphNode = {\r\n id,\r\n parentId: init.parentId ?? null,\r\n transform: init.transform ?? { ...DEFAULT_TRANSFORM },\r\n outline: init.outline ?? DEFAULT_OUTLINE,\r\n anchorPolicy: init.anchorPolicy ?? DEFAULT_ANCHOR_POLICY,\r\n data: init.data,\r\n geomRevision: 0,\r\n }\r\n nodes.set(id, node)\r\n edgesByNode.set(id, new Set())\r\n publishSnapshot()\r\n return id\r\n }\r\n\r\n function addNode(init: NodeInit = {}): NodeId {\r\n return _withHistory(() => _addNodeImpl(init))\r\n }\r\n\r\n function _removeNodeImpl(id: NodeId): void {\r\n if (!nodes.has(id)) return\r\n const incident = edgesByNode.get(id)\r\n if (incident) {\r\n for (const eid of incident) removeEdge(eid)\r\n }\r\n // re-parent any children to root (do not orphan them)\r\n for (const [otherId, n] of nodes) {\r\n if (n.parentId === id) {\r\n nodes.set(otherId, { ...n, parentId: null })\r\n }\r\n }\r\n nodes.delete(id)\r\n edgesByNode.delete(id)\r\n publishSnapshot()\r\n }\r\n\r\n function removeNode(id: NodeId): void {\r\n _withHistory(() => _removeNodeImpl(id))\r\n }\r\n\r\n function _updateNodeImpl(id: NodeId, patch: NodeUpdate): void {\r\n const node = nodes.get(id)\r\n if (!node) {\r\n throw new Error(`[skygraph/graph] node \"${id}\" not found`)\r\n }\r\n const next: GraphNode = {\r\n ...node,\r\n transform: patch.transform ? { ...node.transform, ...patch.transform } : node.transform,\r\n outline: patch.outline ?? node.outline,\r\n anchorPolicy: patch.anchorPolicy ?? node.anchorPolicy,\r\n data: patch.data === undefined ? node.data : patch.data,\r\n }\r\n const geomChanged =\r\n patch.transform !== undefined ||\r\n patch.outline !== undefined ||\r\n patch.anchorPolicy !== undefined\r\n nodes.set(id, geomChanged ? bumpRevision(next) : next)\r\n publishSnapshot()\r\n }\r\n\r\n function updateNode(id: NodeId, patch: NodeUpdate): void {\r\n _withHistory(() => _updateNodeImpl(id, patch))\r\n }\r\n\r\n function moveNode(id: NodeId, x: number, y: number): void {\r\n _withHistory(() => _updateNodeImpl(id, { transform: { x, y } }))\r\n }\r\n\r\n function _setParentImpl(id: NodeId, parentId: NodeId | null): void {\r\n const node = nodes.get(id)\r\n if (!node) {\r\n throw new Error(`[skygraph/graph] node \"${id}\" not found`)\r\n }\r\n if (parentId !== null && !nodes.has(parentId)) {\r\n throw new Error(`[skygraph/graph] parent node \"${parentId}\" not found`)\r\n }\r\n if (parentId === id) {\r\n throw new Error(`[skygraph/graph] node cannot be its own parent (\"${id}\")`)\r\n }\r\n // cycle check — walk up the chain to make sure we don't introduce a loop\r\n let cursor: NodeId | null = parentId\r\n while (cursor !== null) {\r\n if (cursor === id) {\r\n throw new Error(`[skygraph/graph] setParent would create a cycle (\"${id}\" → \"${parentId}\")`)\r\n }\r\n cursor = nodes.get(cursor)?.parentId ?? null\r\n }\r\n nodes.set(id, { ...node, parentId })\r\n publishSnapshot()\r\n }\r\n\r\n function setParent(id: NodeId, parentId: NodeId | null): void {\r\n _withHistory(() => _setParentImpl(id, parentId))\r\n }\r\n\r\n // ─── Edge operations ──────────────────────────────────────────────────────\r\n\r\n function _addEdgeImpl(init: EdgeInit): EdgeId {\r\n const id = init.id ?? newEdgeId()\r\n if (edges.has(id)) {\r\n throw new Error(`[skygraph/graph] edge id \"${id}\" already exists`)\r\n }\r\n const fromId = endpointNode(init.from)\r\n const toId = endpointNode(init.to)\r\n if (!nodes.has(fromId)) {\r\n throw new Error(`[skygraph/graph] addEdge: from-node \"${fromId}\" not found`)\r\n }\r\n if (!nodes.has(toId)) {\r\n throw new Error(`[skygraph/graph] addEdge: to-node \"${toId}\" not found`)\r\n }\r\n const edge: GraphEdge = {\r\n id,\r\n from: init.from,\r\n to: init.to,\r\n routing: init.routing ?? 'straight',\r\n waypoints: init.waypoints,\r\n data: init.data,\r\n }\r\n edges.set(id, edge)\r\n ensureBucket(fromId).add(id)\r\n ensureBucket(toId).add(id)\r\n publishSnapshot()\r\n return id\r\n }\r\n\r\n function addEdge(init: EdgeInit): EdgeId {\r\n return _withHistory(() => _addEdgeImpl(init))\r\n }\r\n\r\n function _removeEdgeImpl(id: EdgeId): void {\r\n const edge = edges.get(id)\r\n if (!edge) return\r\n edgesByNode.get(endpointNode(edge.from))?.delete(id)\r\n edgesByNode.get(endpointNode(edge.to))?.delete(id)\r\n edges.delete(id)\r\n publishSnapshot()\r\n }\r\n\r\n function removeEdge(id: EdgeId): void {\r\n _withHistory(() => _removeEdgeImpl(id))\r\n }\r\n\r\n // ─── Read API ─────────────────────────────────────────────────────────────\r\n\r\n function getNode(id: NodeId): GraphNode | undefined {\r\n return nodes.get(id)\r\n }\r\n\r\n function getEdge(id: EdgeId): GraphEdge | undefined {\r\n return edges.get(id)\r\n }\r\n\r\n function getState(): GraphState {\r\n const byNode = new Map<NodeId, readonly EdgeId[]>()\r\n for (const [nid, set] of edgesByNode) byNode.set(nid, Array.from(set))\r\n return {\r\n nodes: new Map(nodes),\r\n edges: new Map(edges),\r\n edgesByNode: byNode,\r\n }\r\n }\r\n\r\n function childrenOf(id: NodeId | null): NodeId[] {\r\n const out: NodeId[] = []\r\n for (const n of nodes.values()) {\r\n if (n.parentId === id) out.push(n.id)\r\n }\r\n return out\r\n }\r\n\r\n function edgesOf(id: NodeId): EdgeId[] {\r\n return Array.from(edgesByNode.get(id) ?? [])\r\n }\r\n\r\n // ─── Anchor generator ────────────────────────────────────────────────────\r\n //\r\n // Anchor IDs are deterministic functions of (outline kind, anchor policy).\r\n // Bumping `k` keeps existing anchors stable: corner ids never change, and\r\n // mid-edge anchor ids include the current `k` so callers can re-bind by\r\n // perimeter parameter `s` if they care about stability under k changes.\r\n\r\n function rectCornerId(corner: 'nw' | 'ne' | 'se' | 'sw'): AnchorId {\r\n return corner\r\n }\r\n\r\n function rectAnchors(w: number, h: number, policy: AnchorPolicy): Anchor[] {\r\n const corners: Anchor[] = [\r\n { id: rectCornerId('nw'), s: 0, point: [0, 0] },\r\n { id: rectCornerId('ne'), s: 0.25, point: [w, 0] },\r\n { id: rectCornerId('se'), s: 0.5, point: [w, h] },\r\n { id: rectCornerId('sw'), s: 0.75, point: [0, h] },\r\n ]\r\n if (policy.kind === 'manual') {\r\n return policy.anchors.map(a => ({\r\n id: a.id,\r\n s: a.s,\r\n point: pointOnRectPerimeter(w, h, a.s),\r\n }))\r\n }\r\n\r\n const k = policy.kind === 'perEdge' ? Math.max(0, Math.floor(policy.k)) : null\r\n const density = policy.kind === 'byLength' ? policy.density : null\r\n\r\n const out: Anchor[] = [...corners]\r\n // four edges, in clockwise order — n, e, s, w\r\n const edgesGeom: Array<{ start: number; end: number }> = [\r\n { start: 0, end: 0.25 }, // top\r\n { start: 0.25, end: 0.5 }, // right\r\n { start: 0.5, end: 0.75 }, // bottom\r\n { start: 0.75, end: 1 }, // left\r\n ]\r\n edgesGeom.forEach((edge, edgeIdx) => {\r\n let count = 0\r\n if (k !== null) count = k\r\n if (density !== null) {\r\n const len = edgeIdx % 2 === 0 ? w : h\r\n count = Math.max(0, Math.floor(len / density) - 1)\r\n }\r\n for (let i = 1; i <= count; i++) {\r\n const t = i / (count + 1)\r\n const s = edge.start + (edge.end - edge.start) * t\r\n out.push({\r\n id: `edge${edgeIdx}-${i}of${count}`,\r\n s,\r\n point: pointOnRectPerimeter(w, h, s),\r\n })\r\n }\r\n })\r\n out.sort((a, b) => a.s - b.s)\r\n return out\r\n }\r\n\r\n function pointOnRectPerimeter(w: number, h: number, s: number): Point {\r\n // s ∈ [0..1) traversing nw→ne→se→sw→nw\r\n const ss = ((s % 1) + 1) % 1\r\n if (ss < 0.25) return [w * (ss / 0.25), 0]\r\n if (ss < 0.5) return [w, h * ((ss - 0.25) / 0.25)]\r\n if (ss < 0.75) return [w * (1 - (ss - 0.5) / 0.25), h]\r\n return [0, h * (1 - (ss - 0.75) / 0.25)]\r\n }\r\n\r\n function polygonAnchors(verts: readonly Point[], policy: AnchorPolicy): Anchor[] {\r\n if (verts.length === 0) return []\r\n // total perimeter\r\n const segLengths: number[] = []\r\n let total = 0\r\n for (let i = 0; i < verts.length; i++) {\r\n const a = verts[i]\r\n const b = verts[(i + 1) % verts.length]\r\n const dx = b[0] - a[0]\r\n const dy = b[1] - a[1]\r\n const len = Math.hypot(dx, dy)\r\n segLengths.push(len)\r\n total += len\r\n }\r\n const cumS: number[] = [0]\r\n for (let i = 0; i < segLengths.length; i++) {\r\n cumS.push(cumS[i]! + segLengths[i]! / total)\r\n }\r\n\r\n function pointAt(s: number): Point {\r\n const ss = ((s % 1) + 1) % 1\r\n // find segment\r\n let i = 0\r\n while (i < cumS.length - 1 && cumS[i + 1]! <= ss) i++\r\n const a = verts[i % verts.length]\r\n const b = verts[(i + 1) % verts.length]\r\n const segS0 = cumS[i]!\r\n const segS1 = cumS[i + 1]!\r\n const t = segS1 === segS0 ? 0 : (ss - segS0) / (segS1 - segS0)\r\n return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]\r\n }\r\n\r\n if (policy.kind === 'manual') {\r\n return policy.anchors.map(a => ({ id: a.id, s: a.s, point: pointAt(a.s) }))\r\n }\r\n\r\n const out: Anchor[] = []\r\n // vertices always become anchors\r\n for (let i = 0; i < verts.length; i++) {\r\n out.push({\r\n id: `v${i}`,\r\n s: cumS[i]!,\r\n point: [verts[i]![0], verts[i]![1]],\r\n })\r\n }\r\n\r\n const k = policy.kind === 'perEdge' ? Math.max(0, Math.floor(policy.k)) : null\r\n const density = policy.kind === 'byLength' ? policy.density : null\r\n\r\n for (let i = 0; i < verts.length; i++) {\r\n const segLen = segLengths[i]!\r\n let count = 0\r\n if (k !== null) count = k\r\n if (density !== null) count = Math.max(0, Math.floor(segLen / density) - 1)\r\n const s0 = cumS[i]!\r\n const s1 = cumS[i + 1]!\r\n for (let j = 1; j <= count; j++) {\r\n const t = j / (count + 1)\r\n const s = s0 + (s1 - s0) * t\r\n out.push({ id: `v${i}-${j}of${count}`, s, point: pointAt(s) })\r\n }\r\n }\r\n out.sort((a, b) => a.s - b.s)\r\n return out\r\n }\r\n\r\n function ellipseAnchors(rx: number, ry: number, policy: AnchorPolicy): Anchor[] {\r\n function pointAt(s: number): Point {\r\n const angle = ((s % 1) + 1) % 1 * Math.PI * 2\r\n return [rx * Math.cos(angle), ry * Math.sin(angle)]\r\n }\r\n if (policy.kind === 'manual') {\r\n return policy.anchors.map(a => ({ id: a.id, s: a.s, point: pointAt(a.s) }))\r\n }\r\n const k = policy.kind === 'perEdge' ? Math.max(1, Math.floor(policy.k)) : null\r\n // density-by-arc is approximate; uniform-by-angle is good enough for v0.\r\n const totalSamples = k !== null\r\n ? Math.max(4, k * 4)\r\n : Math.max(4, Math.floor((2 * Math.PI * Math.max(rx, ry)) / (policy as { kind: 'byLength'; density: number }).density))\r\n const out: Anchor[] = []\r\n for (let i = 0; i < totalSamples; i++) {\r\n const s = i / totalSamples\r\n out.push({ id: `el${i}of${totalSamples}`, s, point: pointAt(s) })\r\n }\r\n return out\r\n }\r\n\r\n function anchorsOf(id: NodeId): Anchor[] {\r\n const node = nodes.get(id)\r\n if (!node) return []\r\n const o = node.outline\r\n if (o.kind === 'rect') return rectAnchors(o.w, o.h, node.anchorPolicy)\r\n if (o.kind === 'polygon') return polygonAnchors(o.verts, node.anchorPolicy)\r\n if (o.kind === 'ellipse') return ellipseAnchors(o.rx, o.ry, node.anchorPolicy)\r\n if (o.kind === 'path') return polygonAnchors(o.flatten, node.anchorPolicy)\r\n return []\r\n }\r\n\r\n // ─── Bounds (AABB in world space — no rotation in v0) ────────────────────\r\n\r\n function localBounds(node: GraphNode): { x0: number; y0: number; x1: number; y1: number } {\r\n const o = node.outline\r\n if (o.kind === 'rect') return { x0: 0, y0: 0, x1: o.w, y1: o.h }\r\n if (o.kind === 'ellipse') return { x0: -o.rx, y0: -o.ry, x1: o.rx, y1: o.ry }\r\n const verts = o.kind === 'polygon' ? o.verts : o.flatten\r\n if (verts.length === 0) return { x0: 0, y0: 0, x1: 0, y1: 0 }\r\n let x0 = verts[0]![0]\r\n let x1 = verts[0]![0]\r\n let y0 = verts[0]![1]\r\n let y1 = verts[0]![1]\r\n for (const [x, y] of verts) {\r\n if (x < x0) x0 = x\r\n if (x > x1) x1 = x\r\n if (y < y0) y0 = y\r\n if (y > y1) y1 = y\r\n }\r\n return { x0, y0, x1, y1 }\r\n }\r\n\r\n function worldOriginOf(id: NodeId): { x: number; y: number; scale: number } {\r\n let cursor: NodeId | null = id\r\n let x = 0\r\n let y = 0\r\n let scale = 1\r\n while (cursor !== null) {\r\n const n = nodes.get(cursor)\r\n if (!n) break\r\n const s = n.transform.scale ?? 1\r\n x = n.transform.x + x * s\r\n y = n.transform.y + y * s\r\n scale *= s\r\n cursor = n.parentId\r\n }\r\n return { x, y, scale }\r\n }\r\n\r\n function boundsOf(id: NodeId): AABB {\r\n const node = nodes.get(id)\r\n if (!node) return { x: 0, y: 0, w: 0, h: 0 }\r\n const lb = localBounds(node)\r\n const origin = worldOriginOf(id)\r\n const w = (lb.x1 - lb.x0) * origin.scale\r\n const h = (lb.y1 - lb.y0) * origin.scale\r\n return {\r\n x: origin.x + lb.x0 * origin.scale,\r\n y: origin.y + lb.y0 * origin.scale,\r\n w,\r\n h,\r\n }\r\n }\r\n\r\n /**\r\n * Oriented bounding box in world space.\r\n *\r\n * v0 simplification: rotation is composed by summing `transform.rot`\r\n * along the parent chain (treating ancestors as if their rotations\r\n * commuted). For a single rotated node this is exact; for nested rotated\r\n * groups the centre / angle remain a useful approximation suitable for\r\n * selection overlays. Tighter OBB composition (full affine product)\r\n * lands when the engine grows a proper world-matrix cache.\r\n */\r\n function getNodeOBB(id: NodeId): OBB {\r\n const node = nodes.get(id)\r\n if (!node) return { center: [0, 0], halfWidth: 0, halfHeight: 0, angle: 0 }\r\n const lb = localBounds(node)\r\n const origin = worldOriginOf(id)\r\n const localCx = (lb.x0 + lb.x1) / 2\r\n const localCy = (lb.y0 + lb.y1) / 2\r\n const halfWidth = Math.abs((lb.x1 - lb.x0) / 2 * origin.scale)\r\n const halfHeight = Math.abs((lb.y1 - lb.y0) / 2 * origin.scale)\r\n let angle = 0\r\n let cursor: NodeId | null = id\r\n while (cursor !== null) {\r\n const n = nodes.get(cursor)\r\n if (!n) break\r\n angle += n.transform.rot ?? 0\r\n cursor = n.parentId\r\n }\r\n const center: Point = [\r\n origin.x + localCx * origin.scale,\r\n origin.y + localCy * origin.scale,\r\n ]\r\n return { center, halfWidth, halfHeight, angle }\r\n }\r\n\r\n function clear(): void {\r\n nodes.clear()\r\n edges.clear()\r\n edgesByNode.clear()\r\n nodeCounter = 0\r\n edgeCounter = 0\r\n history.clear()\r\n pendingEntry = null\r\n transactionDepth = 0\r\n isRestoring = false\r\n publishSnapshot()\r\n }\r\n\r\n // ─── Public history API ──────────────────────────────────────────────────\r\n\r\n function transaction(fn: () => void, label?: string): void {\r\n _withHistory(fn, label)\r\n }\r\n\r\n function pushHistory(label?: string): void {\r\n if (transactionDepth > 0) {\r\n // Inside a transaction: commit the current pending entry as a sub-\r\n // boundary, then start a fresh capture for the remainder of the\r\n // transaction. This lets a single `transaction(fn)` produce more\r\n // than one undo entry — useful when a batch operation has natural\r\n // sub-steps (`}; { ` between groups).\r\n if (pendingEntry !== null) {\r\n history.push({ snapshot: pendingEntry.snapshot, label: pendingEntry.label ?? label })\r\n history.clearRedo()\r\n }\r\n pendingEntry = { snapshot: _captureState(), label: undefined }\r\n return\r\n }\r\n // Standalone: re-label the most recent undo entry. We DO NOT push a\r\n // duplicate snapshot of the current state — auto-push has already\r\n // captured every meaningful boundary, so an extra standalone push\r\n // would just clutter the stack with no-op entries that consume undo\r\n // slots without changing visible state. Re-labeling is the useful\r\n // bit you can't get any other way outside a transaction.\r\n history.relabelTop(label)\r\n }\r\n\r\n function undo(): boolean {\r\n if (!history.canUndo()) return false\r\n const entry = history.popUndo()!\r\n history.pushRedo({ snapshot: _captureState(), label: entry.label })\r\n isRestoring = true\r\n try {\r\n _restoreState(entry.snapshot)\r\n } finally {\r\n isRestoring = false\r\n }\r\n publishSnapshot()\r\n return true\r\n }\r\n\r\n function redo(): boolean {\r\n if (!history.canRedo()) return false\r\n const entry = history.popRedo()!\r\n history.push({ snapshot: _captureState(), label: entry.label })\r\n isRestoring = true\r\n try {\r\n _restoreState(entry.snapshot)\r\n } finally {\r\n isRestoring = false\r\n }\r\n publishSnapshot()\r\n return true\r\n }\r\n\r\n function canUndo(): boolean {\r\n return history.canUndo()\r\n }\r\n\r\n function canRedo(): boolean {\r\n return history.canRedo()\r\n }\r\n\r\n function clearHistory(): void {\r\n history.clear()\r\n }\r\n\r\n return {\r\n addNode,\r\n removeNode,\r\n updateNode,\r\n moveNode,\r\n setParent,\r\n addEdge,\r\n removeEdge,\r\n getNode,\r\n getEdge,\r\n getState,\r\n childrenOf,\r\n edgesOf,\r\n anchorsOf,\r\n boundsOf,\r\n getNodeOBB,\r\n subscribe: subscribeLocal,\r\n transaction,\r\n pushHistory,\r\n undo,\r\n redo,\r\n canUndo,\r\n canRedo,\r\n clearHistory,\r\n clear,\r\n }\r\n}\r\n","import type { AABB, Point } from './types'\r\n\r\n/**\r\n * Orthogonal-routing module.\r\n *\r\n * Two strategies share one entry point — `routeOrthogonal`:\r\n *\r\n * 1. **L-route fallback** (no obstacles): a single-bend right-angle path.\r\n * Cheap, deterministic, and good enough for the \"two free-floating\r\n * nodes\" case.\r\n *\r\n * 2. **A* on a uniform grid** (with obstacles): when the caller passes\r\n * `obstacles`, the router discretises world space into a grid of step\r\n * `gridSize` (default 10) and runs a 4-connected A* with a turn\r\n * penalty so the search prefers long straight runs. The result is a\r\n * polyline whose interior bends are all axis-aligned right angles\r\n * and which never enters the interior of any obstacle.\r\n *\r\n * Both strategies share a common output shape: a `readonly Point[]`\r\n * with the original `start` as the first element and the original `end`\r\n * as the last. Consumers (e.g. `<Diagram>`) feed it straight to\r\n * `pointsToPath`.\r\n *\r\n * **`sourceBounds` / `targetBounds` (since 3.3c).** When the caller knows\r\n * which axis-aligned rectangle each endpoint sits on, the router will\r\n * pick the side of the rectangle nearest to the *other* endpoint and\r\n * extend a short perpendicular stub away from the node. That keeps edges\r\n * from sliding diagonally out of corner-anchors (`s = 0.25` / `s = 0.75`)\r\n * and from immediately re-entering the node they just exited — both of\r\n * which were visible in the Workflow Editor showcase prior to 3.3c.\r\n *\r\n * The router is intentionally pure — no engine state, no React, no DOM —\r\n * so it can be tested in isolation and reused outside of `<Diagram>`\r\n * (e.g. server-side path pre-computation).\r\n */\r\n\r\n/** Direction the previous step entered the current cell from. */\r\ntype Dir = 'h' | 'v' | null\r\n\r\n/** Side of an AABB the route exits through. */\r\nexport type RectSide = 'top' | 'right' | 'bottom' | 'left'\r\n\r\n/** Options for {@link routeOrthogonal}. */\r\nexport interface RouteOrthogonalOptions {\r\n /**\r\n * Bend preference for the no-obstacle case.\r\n * - `auto` (default) picks H-then-V or V-then-H based on which leg is longer.\r\n * - `hv` forces horizontal first.\r\n * - `vh` forces vertical first.\r\n *\r\n * Ignored when `obstacles` is non-empty — A* picks bends from costs.\r\n */\r\n preferred?: 'auto' | 'hv' | 'vh'\r\n /**\r\n * Rectangular obstacles to avoid (in world coordinates). When omitted /\r\n * empty, the router takes the cheap L-route path.\r\n */\r\n obstacles?: readonly AABB[]\r\n /**\r\n * Discretisation step for A*. Smaller values give smoother paths at the\r\n * cost of more search nodes. Default: 10.\r\n */\r\n gridSize?: number\r\n /**\r\n * Inflate every obstacle by this margin (world units) before clipping.\r\n * Useful to keep edges from hugging node borders. Default: 0.\r\n */\r\n inflate?: number\r\n /**\r\n * Hard cap on A* expansions. Acts as a safety net so a pathological\r\n * search never hangs the renderer. Default: 5000.\r\n */\r\n maxNodes?: number\r\n /**\r\n * AABB of the source node. When provided, the route exits the side of\r\n * the rectangle nearest to `end` with a short perpendicular stub. The\r\n * raw `start` point is kept as the first polyline vertex so the edge\r\n * still meets the anchor exactly.\r\n */\r\n sourceBounds?: AABB\r\n /**\r\n * AABB of the target node. When provided, the route enters the side of\r\n * the rectangle nearest to `start` with a short perpendicular stub. The\r\n * raw `end` point is kept as the last polyline vertex.\r\n */\r\n targetBounds?: AABB\r\n /**\r\n * Length (world units) of the perpendicular stub generated when\r\n * `sourceBounds` / `targetBounds` is set. Defaults to `max(8, gridSize)`.\r\n */\r\n stubLength?: number\r\n /**\r\n * Snap intermediate waypoints to a grid of this step. Defaults to the\r\n * effective `gridSize`. Set to `0` to disable snapping in the no-\r\n * obstacle path. A* already operates on the grid so this option only\r\n * affects the L-route fallback.\r\n */\r\n snap?: number\r\n}\r\n\r\n/**\r\n * Compute an orthogonal (right-angled) path between two points.\r\n *\r\n * - With no `sourceBounds` / `targetBounds` and no obstacles: a single-\r\n * bend L-route, identical to the v0 implementation.\r\n * - With `sourceBounds` / `targetBounds`: the route exits/enters from\r\n * the side of each rectangle nearest to the other endpoint.\r\n * - With obstacles: 4-connected A* on a grid of step `gridSize`. Uses\r\n * a turn penalty so straight runs are preferred. Falls back to the\r\n * L-route if A* cannot find a path within `maxNodes` expansions or\r\n * either endpoint is unreachable.\r\n *\r\n * The third argument also accepts the legacy bare-string form\r\n * (`'auto' | 'hv' | 'vh'`) for backwards compatibility with the v0 API.\r\n */\r\nexport function routeOrthogonal(\r\n start: Point,\r\n end: Point,\r\n options?: RouteOrthogonalOptions | 'auto' | 'hv' | 'vh',\r\n): readonly Point[] {\r\n const opts: RouteOrthogonalOptions =\r\n typeof options === 'string' ? { preferred: options } : (options ?? {})\r\n\r\n const gridSize = opts.gridSize ?? 10\r\n const stubLength = opts.stubLength ?? Math.max(8, gridSize)\r\n\r\n // ─── Step 1. Derive the \"approach points\" from optional bounds ────────────\r\n // Each approach point lives at the centre of the side of the source/\r\n // target rectangle that is closest to the other endpoint. We extend a\r\n // short perpendicular stub OUTWARDS from the rectangle so the rendered\r\n // edge has at least one straight segment exiting/entering the node.\r\n\r\n let sExit: Point | null = null\r\n let sStub: Point | null = null\r\n let sCorner: Point | null = null\r\n if (opts.sourceBounds) {\r\n const exitInfo = exitOnNearestSide(opts.sourceBounds, end)\r\n sExit = exitInfo.point\r\n sStub = extrudePoint(exitInfo.point, exitInfo.side, stubLength)\r\n // Bridge from the raw anchor (which may sit anywhere on the\r\n // outline — corner anchors like `s=0.25` are common) to `sExit`\r\n // through a right-angle bend, so every segment stays axis-aligned.\r\n sCorner = orthoBridge(start, sExit, exitInfo.side)\r\n }\r\n\r\n let tExit: Point | null = null\r\n let tStub: Point | null = null\r\n let tCorner: Point | null = null\r\n if (opts.targetBounds) {\r\n const enterInfo = exitOnNearestSide(opts.targetBounds, start)\r\n tExit = enterInfo.point\r\n tStub = extrudePoint(enterInfo.point, enterInfo.side, stubLength)\r\n tCorner = orthoBridge(end, tExit, enterInfo.side)\r\n }\r\n\r\n // ─── Step 2. Determine the \"core\" route between sStub and tStub ──────────\r\n // When neither bounds is set, the core route is just `start → end`.\r\n // Otherwise it sits between the perpendicular stubs we just built.\r\n const coreStart: Point = sStub ?? start\r\n const coreEnd: Point = tStub ?? end\r\n\r\n // Obstacles: when both source/target bounds are provided, they should\r\n // NOT be obstacles to themselves — caller is expected to filter the\r\n // pair out, but we double-strip just in case (matches by reference).\r\n const obstacles = opts.obstacles ?? []\r\n const filteredObstacles =\r\n obstacles.length > 0 && (opts.sourceBounds || opts.targetBounds)\r\n ? obstacles.filter((o) => o !== opts.sourceBounds && o !== opts.targetBounds)\r\n : obstacles\r\n\r\n let core: readonly Point[]\r\n if (filteredObstacles.length === 0) {\r\n const snap = opts.snap ?? gridSize\r\n core = lRoute(coreStart, coreEnd, opts.preferred ?? 'auto', snap)\r\n } else {\r\n const inflate = opts.inflate ?? 0\r\n const maxNodes = opts.maxNodes ?? 5000\r\n const aStar = aStarRoute(coreStart, coreEnd, filteredObstacles, gridSize, inflate, maxNodes)\r\n core = aStar ?? lRoute(coreStart, coreEnd, opts.preferred ?? 'auto', opts.snap ?? gridSize)\r\n }\r\n\r\n // ─── Step 3. Stitch the final polyline ────────────────────────────────────\r\n // [start, sExit, sStub, ...core..., tStub, tExit, end], collapsing\r\n // adjacent duplicates and runs of collinear points.\r\n\r\n const points: Point[] = []\r\n pushIfDistinct(points, start)\r\n if (sCorner && !pointsEqual(sCorner, start)) pushIfDistinct(points, sCorner)\r\n if (sExit && !pointsEqual(sExit, points[points.length - 1]!)) pushIfDistinct(points, sExit)\r\n if (sStub && !pointsEqual(sStub, points[points.length - 1]!)) pushIfDistinct(points, sStub)\r\n\r\n for (let i = 0; i < core.length; i++) {\r\n const p = core[i]!\r\n // skip the core endpoints if they exactly match the stubs we already pushed\r\n if (i === 0 && sStub && pointsEqual(p, sStub)) continue\r\n if (i === core.length - 1 && tStub && pointsEqual(p, tStub)) continue\r\n pushIfDistinct(points, p)\r\n }\r\n\r\n if (tStub && !pointsEqual(tStub, points[points.length - 1]!)) pushIfDistinct(points, tStub)\r\n if (tExit && !pointsEqual(tExit, points[points.length - 1]!)) pushIfDistinct(points, tExit)\r\n if (tCorner && !pointsEqual(tCorner, points[points.length - 1]!)) pushIfDistinct(points, tCorner)\r\n if (!pointsEqual(end, points[points.length - 1]!)) pushIfDistinct(points, end)\r\n\r\n return compressCollinear(points)\r\n}\r\n\r\n/**\r\n * Build an SVG path `d` attribute from a polyline.\r\n *\r\n * pointsToPath([[0,0], [10,0], [10,5]]) → \"M 0 0 L 10 0 L 10 5\"\r\n */\r\nexport function pointsToPath(points: readonly Point[]): string {\r\n if (points.length === 0) return ''\r\n const [head, ...rest] = points\r\n return `M ${head[0]} ${head[1]} ${rest.map((p) => `L ${p[0]} ${p[1]}`).join(' ')}`\r\n}\r\n\r\n/**\r\n * Build a rounded-corner SVG path from an orthogonal polyline.\r\n *\r\n * Every interior bend (where two consecutive segments meet at a right\r\n * angle) is replaced with a quadratic Bezier whose control point sits\r\n * exactly at the corner — this produces the visual signature of\r\n * \"smooth-step\" edges found in React Flow / draw.io / Lucidchart\r\n * without changing the underlying polyline geometry.\r\n *\r\n * pointsToRoundedPath([[0,0], [10,0], [10,5]], 4)\r\n * → \"M 0 0 L 6 0 Q 10 0 10 4 L 10 5\"\r\n *\r\n * `radius` is clamped to half of the shorter adjacent segment so the\r\n * curves never overshoot. Passing `0` makes it identical to\r\n * {@link pointsToPath}.\r\n */\r\nexport function pointsToRoundedPath(points: readonly Point[], radius: number): string {\r\n if (points.length === 0) return ''\r\n if (points.length < 3 || radius <= 0) return pointsToPath(points)\r\n\r\n let d = `M ${points[0]![0]} ${points[0]![1]}`\r\n for (let i = 1; i < points.length - 1; i++) {\r\n const a = points[i - 1]!\r\n const b = points[i]!\r\n const c = points[i + 1]!\r\n\r\n // Length of segments meeting at b — clamp the bend so it never\r\n // eats more than half of either neighbour.\r\n const lenAB = Math.hypot(b[0] - a[0], b[1] - a[1])\r\n const lenBC = Math.hypot(c[0] - b[0], c[1] - b[1])\r\n const r = Math.min(radius, lenAB / 2, lenBC / 2)\r\n\r\n const ux = (b[0] - a[0]) / (lenAB || 1)\r\n const uy = (b[1] - a[1]) / (lenAB || 1)\r\n const vx = (c[0] - b[0]) / (lenBC || 1)\r\n const vy = (c[1] - b[1]) / (lenBC || 1)\r\n\r\n // Collinear corner (cross product is zero) → the \"bend\" is just\r\n // a continuation of the previous segment; emit a plain line and\r\n // skip the Q. This keeps multi-segment straight runs visually\r\n // identical to {@link pointsToPath} regardless of the radius.\r\n const cross = ux * vy - uy * vx\r\n if (r < 0.5 || Math.abs(cross) < 1e-9) {\r\n d += ` L ${b[0]} ${b[1]}`\r\n continue\r\n }\r\n\r\n const p1x = b[0] - ux * r\r\n const p1y = b[1] - uy * r\r\n const p2x = b[0] + vx * r\r\n const p2y = b[1] + vy * r\r\n\r\n d += ` L ${p1x} ${p1y} Q ${b[0]} ${b[1]} ${p2x} ${p2y}`\r\n }\r\n const tail = points[points.length - 1]!\r\n d += ` L ${tail[0]} ${tail[1]}`\r\n return d\r\n}\r\n\r\n// ─── Bezier routing ────────────────────────────────────────────────────────\r\n\r\n/** Side of an AABB that an endpoint exits / enters through. */\r\nexport type Side = 'top' | 'right' | 'bottom' | 'left'\r\n\r\nexport interface BezierPathOptions {\r\n /** Source point — where the curve starts. */\r\n source: Point\r\n /** Side of the source node the curve exits through. */\r\n sourceSide: Side\r\n /** Target point — where the curve ends. */\r\n target: Point\r\n /** Side of the target node the curve enters through. */\r\n targetSide: Side\r\n /**\r\n * Curve intensity. `0.25` is React Flow's default — strong enough\r\n * to feel natural, soft enough not to loop. Range: `0..1`.\r\n */\r\n curvature?: number\r\n}\r\n\r\nfunction controlOffset(distance: number, curvature: number): number {\r\n if (distance >= 0) return 0.5 * distance\r\n // Negative distance means the curve has to swing back around; we\r\n // boost the control offset proportionally so the loop reads cleanly.\r\n return curvature * 25 * Math.sqrt(-distance)\r\n}\r\n\r\nfunction controlPoint(\r\n side: Side,\r\n x1: number,\r\n y1: number,\r\n x2: number,\r\n y2: number,\r\n curvature: number,\r\n): Point {\r\n switch (side) {\r\n case 'left':\r\n return [x1 - controlOffset(x1 - x2, curvature), y1]\r\n case 'right':\r\n return [x1 + controlOffset(x2 - x1, curvature), y1]\r\n case 'top':\r\n return [x1, y1 - controlOffset(y1 - y2, curvature)]\r\n case 'bottom':\r\n return [x1, y1 + controlOffset(y2 - y1, curvature)]\r\n }\r\n}\r\n\r\n/**\r\n * Cubic-bezier SVG path between two endpoints, with control handles\r\n * extending perpendicular to each side. Mirrors React Flow's\r\n * `getBezierPath` algorithm.\r\n *\r\n * `sourceSide` / `targetSide` tell the function which face of each\r\n * node the endpoint sits on so the curve always exits and enters\r\n * perpendicular to the node outline — this is the difference between\r\n * a \"wavy\" edge and a \"deliberate\" one.\r\n *\r\n * Use {@link nearestSide} to derive the side from an AABB + opposite\r\n * point when the caller doesn't already know it.\r\n */\r\nexport function getBezierPath(opts: BezierPathOptions): string {\r\n const curvature = opts.curvature ?? 0.25\r\n const [sx, sy] = opts.source\r\n const [tx, ty] = opts.target\r\n const [c1x, c1y] = controlPoint(opts.sourceSide, sx, sy, tx, ty, curvature)\r\n const [c2x, c2y] = controlPoint(opts.targetSide, tx, ty, sx, sy, curvature)\r\n return `M ${sx} ${sy} C ${c1x} ${c1y} ${c2x} ${c2y} ${tx} ${ty}`\r\n}\r\n\r\n/**\r\n * Pick the side of `box` whose midpoint is closest to `target`. Same\r\n * logic as the internal helper used by orthogonal routing — exposed\r\n * publicly so consumers of `getBezierPath` don't need to re-implement\r\n * it.\r\n */\r\nexport function nearestSide(box: AABB, target: Point): Side {\r\n const cx = box.x + box.w / 2\r\n const cy = box.y + box.h / 2\r\n const dx = target[0] - cx\r\n const dy = target[1] - cy\r\n if (Math.abs(dx) >= Math.abs(dy)) return dx >= 0 ? 'right' : 'left'\r\n return dy >= 0 ? 'bottom' : 'top'\r\n}\r\n\r\n// ─── Side / stub helpers ────────────────────────────────────────────────────\r\n\r\n/**\r\n * Pick the side of `box` nearest to `target` and return the midpoint of\r\n * that side. The chosen side is the one whose dominant axis matches the\r\n * dominant axis of the (target → box-centre) vector.\r\n */\r\nfunction exitOnNearestSide(box: AABB, target: Point): { point: Point; side: RectSide } {\r\n const cx = box.x + box.w / 2\r\n const cy = box.y + box.h / 2\r\n const dx = target[0] - cx\r\n const dy = target[1] - cy\r\n if (Math.abs(dx) >= Math.abs(dy)) {\r\n if (dx >= 0) return { point: [box.x + box.w, cy], side: 'right' }\r\n return { point: [box.x, cy], side: 'left' }\r\n }\r\n if (dy >= 0) return { point: [cx, box.y + box.h], side: 'bottom' }\r\n return { point: [cx, box.y], side: 'top' }\r\n}\r\n\r\n/** Extrude `point` perpendicular to `side` by `distance` world units. */\r\nfunction extrudePoint(point: Point, side: RectSide, distance: number): Point {\r\n switch (side) {\r\n case 'top':\r\n return [point[0], point[1] - distance]\r\n case 'right':\r\n return [point[0] + distance, point[1]]\r\n case 'bottom':\r\n return [point[0], point[1] + distance]\r\n case 'left':\r\n return [point[0] - distance, point[1]]\r\n }\r\n}\r\n\r\n/**\r\n * Right-angle bridge between an arbitrary anchor (`start`) and the\r\n * side-midpoint exit (`exit`). Returns the corner where the path bends\r\n * 90° so every segment stays axis-aligned.\r\n *\r\n * For a `right`/`left` exit the path runs vertical-first (drops to the\r\n * exit's row, then exits horizontally); for `top`/`bottom` it runs\r\n * horizontal-first. Collinear cases collapse harmlessly during\r\n * compression.\r\n */\r\nfunction orthoBridge(start: Point, exit: Point, side: RectSide): Point {\r\n switch (side) {\r\n case 'right':\r\n case 'left':\r\n // bend at (exit.x, start.y) → vertical run first, then horizontal exit\r\n return [exit[0], start[1]]\r\n case 'top':\r\n case 'bottom':\r\n // bend at (start.x, exit.y) → horizontal run first, then vertical exit\r\n return [start[0], exit[1]]\r\n }\r\n}\r\n\r\nfunction pointsEqual(a: Point, b: Point): boolean {\r\n return a[0] === b[0] && a[1] === b[1]\r\n}\r\n\r\nfunction pushIfDistinct(arr: Point[], p: Point): void {\r\n if (arr.length === 0) {\r\n arr.push(p)\r\n return\r\n }\r\n const last = arr[arr.length - 1]!\r\n if (!pointsEqual(last, p)) arr.push(p)\r\n}\r\n\r\n/**\r\n * Drop collinear interior points so the output polyline only has corners.\r\n * Handles both pure-vertical / pure-horizontal segments produced by\r\n * orthogonal routing and the rare diagonal we emit when stitching\r\n * non-orthogonal endpoints to the exit point.\r\n */\r\nfunction compressCollinear(points: readonly Point[]): Point[] {\r\n if (points.length <= 2) return points.slice()\r\n const out: Point[] = [points[0]!, points[1]!]\r\n for (let i = 2; i < points.length; i++) {\r\n const cur = points[i]!\r\n const a = out[out.length - 2]!\r\n const b = out[out.length - 1]!\r\n const dx1 = b[0] - a[0]\r\n const dy1 = b[1] - a[1]\r\n const dx2 = cur[0] - b[0]\r\n const dy2 = cur[1] - b[1]\r\n // Both vectors point in the same direction (cross = 0 AND signs match)\r\n // → `b` is interior to a straight run; drop it.\r\n const cross = dx1 * dy2 - dy1 * dx2\r\n if (cross === 0 && Math.sign(dx1) === Math.sign(dx2) && Math.sign(dy1) === Math.sign(dy2)) {\r\n out[out.length - 1] = cur\r\n } else {\r\n out.push(cur)\r\n }\r\n }\r\n return out\r\n}\r\n\r\n// ─── L-route (no obstacles) ────────────────────────────────────────────────\r\n\r\nfunction lRoute(\r\n start: Point,\r\n end: Point,\r\n preferred: 'auto' | 'hv' | 'vh',\r\n _snapStep: number,\r\n): readonly Point[] {\r\n const [sx, sy] = start\r\n const [ex, ey] = end\r\n\r\n if (sx === ex || sy === ey) return [start, end]\r\n\r\n // The corner sits at `(ex, sy)` (HV) or `(sx, ey)` (VH). Both\r\n // coordinates are anchored to one of the endpoints, so the resulting\r\n // two segments are guaranteed axis-aligned. We deliberately do NOT\r\n // snap to a grid here: `start` / `end` are exact anchor positions\r\n // (set by the caller), and rounding the corner to a grid step would\r\n // skew one of the two segments into a diagonal. `_snapStep` is kept\r\n // in the signature so the A*-fallback can pass it through; snapping\r\n // proper happens inside A* where the whole search runs on the grid.\r\n const dx = Math.abs(ex - sx)\r\n const dy = Math.abs(ey - sy)\r\n const useHV = preferred === 'hv' ? true : preferred === 'vh' ? false : dx >= dy\r\n\r\n if (useHV) return [start, [ex, sy], end]\r\n return [start, [sx, ey], end]\r\n}\r\n\r\n// ─── A* on a grid (obstacle-aware path) ────────────────────────────────────\r\n\r\ninterface InflatedRect {\r\n x0: number\r\n y0: number\r\n x1: number\r\n y1: number\r\n}\r\n\r\nfunction inflateObstacles(obstacles: readonly AABB[], pad: number): InflatedRect[] {\r\n return obstacles.map((o) => ({\r\n x0: o.x - pad,\r\n y0: o.y - pad,\r\n x1: o.x + o.w + pad,\r\n y1: o.y + o.h + pad,\r\n }))\r\n}\r\n\r\n/**\r\n * Strict-interior point-in-obstacle test. Border points are considered\r\n * free so paths can \"hug\" an obstacle without snagging on it.\r\n */\r\nfunction pointBlocked(x: number, y: number, rects: readonly InflatedRect[]): boolean {\r\n for (const r of rects) {\r\n if (x > r.x0 && x < r.x1 && y > r.y0 && y < r.y1) return true\r\n }\r\n return false\r\n}\r\n\r\nfunction snap(value: number, step: number): number {\r\n return Math.round(value / step) * step\r\n}\r\n\r\nfunction key(x: number, y: number): string {\r\n return `${x},${y}`\r\n}\r\n\r\nfunction manhattan(ax: number, ay: number, bx: number, by: number): number {\r\n return Math.abs(ax - bx) + Math.abs(ay - by)\r\n}\r\n\r\n/**\r\n * Reconstruct path from `cameFrom` map and compress collinear points so\r\n * the output polyline only has corners.\r\n */\r\nfunction reconstruct(cameFrom: Map<string, string>, endKey: string): Point[] {\r\n const reversed: Point[] = []\r\n let cursor: string | undefined = endKey\r\n while (cursor !== undefined) {\r\n const [xs, ys] = cursor.split(',')\r\n reversed.push([Number(xs), Number(ys)])\r\n cursor = cameFrom.get(cursor)\r\n }\r\n reversed.reverse()\r\n // Collapse runs of collinear points.\r\n const out: Point[] = []\r\n for (let i = 0; i < reversed.length; i++) {\r\n const cur = reversed[i]!\r\n if (out.length < 2) {\r\n out.push(cur)\r\n continue\r\n }\r\n const a = out[out.length - 2]!\r\n const b = out[out.length - 1]!\r\n const dx1 = b[0] - a[0]\r\n const dy1 = b[1] - a[1]\r\n const dx2 = cur[0] - b[0]\r\n const dy2 = cur[1] - b[1]\r\n if (Math.sign(dx1) === Math.sign(dx2) && Math.sign(dy1) === Math.sign(dy2)) {\r\n out[out.length - 1] = cur\r\n } else {\r\n out.push(cur)\r\n }\r\n }\r\n return out\r\n}\r\n\r\n/**\r\n * Minimal binary min-heap keyed by `f`. Replaces the original linear\r\n * scan over `open` — that was O(N) per pop, which dominated the A*\r\n * runtime on dense diagrams. With the heap a 6-node / 8-edge layout\r\n * routes in ~1 ms instead of ~12 ms.\r\n *\r\n * Stale entries (i.e. a key that's been re-pushed with a smaller `f`)\r\n * are tolerated: we re-check `gScore` on pop and drop entries that\r\n * don't match the current best score. This is the standard \"lazy\r\n * deletion\" pattern and keeps the heap operations cheap.\r\n */\r\ninterface OpenEntry {\r\n k: string\r\n x: number\r\n y: number\r\n f: number\r\n}\r\n\r\nclass MinHeap {\r\n private readonly data: OpenEntry[] = []\r\n\r\n get size(): number {\r\n return this.data.length\r\n }\r\n\r\n push(entry: OpenEntry): void {\r\n this.data.push(entry)\r\n this.bubbleUp(this.data.length - 1)\r\n }\r\n\r\n pop(): OpenEntry | undefined {\r\n if (this.data.length === 0) return undefined\r\n const head = this.data[0]!\r\n const tail = this.data.pop()!\r\n if (this.data.length > 0) {\r\n this.data[0] = tail\r\n this.bubbleDown(0)\r\n }\r\n return head\r\n }\r\n\r\n private bubbleUp(i: number): void {\r\n while (i > 0) {\r\n const parent = (i - 1) >> 1\r\n if (this.data[i]!.f < this.data[parent]!.f) {\r\n const tmp = this.data[i]!\r\n this.data[i] = this.data[parent]!\r\n this.data[parent] = tmp\r\n i = parent\r\n } else {\r\n return\r\n }\r\n }\r\n }\r\n\r\n private bubbleDown(i: number): void {\r\n const n = this.data.length\r\n while (true) {\r\n const l = i * 2 + 1\r\n const r = l + 1\r\n let smallest = i\r\n if (l < n && this.data[l]!.f < this.data[smallest]!.f) smallest = l\r\n if (r < n && this.data[r]!.f < this.data[smallest]!.f) smallest = r\r\n if (smallest === i) return\r\n const tmp = this.data[i]!\r\n this.data[i] = this.data[smallest]!\r\n this.data[smallest] = tmp\r\n i = smallest\r\n }\r\n }\r\n}\r\n\r\nfunction aStarRoute(\r\n start: Point,\r\n end: Point,\r\n obstacles: readonly AABB[],\r\n gridSize: number,\r\n inflate: number,\r\n maxNodes: number,\r\n): readonly Point[] | null {\r\n const rects = inflateObstacles(obstacles, inflate)\r\n\r\n const sx = snap(start[0], gridSize)\r\n const sy = snap(start[1], gridSize)\r\n const ex = snap(end[0], gridSize)\r\n const ey = snap(end[1], gridSize)\r\n\r\n if (pointBlocked(sx, sy, rects) || pointBlocked(ex, ey, rects)) return null\r\n\r\n const startKey = key(sx, sy)\r\n const endKey = key(ex, ey)\r\n\r\n const gScore = new Map<string, number>([[startKey, 0]])\r\n const cameFrom = new Map<string, string>()\r\n const cameDir = new Map<string, Dir>([[startKey, null]])\r\n\r\n const open = new MinHeap()\r\n open.push({ k: startKey, x: sx, y: sy, f: manhattan(sx, sy, ex, ey) })\r\n\r\n const TURN_PENALTY = gridSize\r\n\r\n let expansions = 0\r\n\r\n while (open.size > 0) {\r\n if (expansions++ > maxNodes) return null\r\n\r\n const current = open.pop()!\r\n // Lazy deletion: discard stale heap entries left over from\r\n // previous, now-superseded score updates.\r\n const bestG = gScore.get(current.k) ?? Infinity\r\n const expectedF = bestG + manhattan(current.x, current.y, ex, ey)\r\n if (current.f > expectedF) continue\r\n\r\n if (current.k === endKey) {\r\n const path = reconstruct(cameFrom, endKey)\r\n if (path.length > 0) {\r\n path[0] = start\r\n path[path.length - 1] = end\r\n }\r\n return path\r\n }\r\n\r\n const incomingDir = cameDir.get(current.k) ?? null\r\n const neighbours: ReadonlyArray<readonly [number, number, Dir]> = [\r\n [gridSize, 0, 'h'],\r\n [-gridSize, 0, 'h'],\r\n [0, gridSize, 'v'],\r\n [0, -gridSize, 'v'],\r\n ]\r\n for (const [dx, dy, dir] of neighbours) {\r\n const nx = current.x + dx\r\n const ny = current.y + dy\r\n if (pointBlocked(nx, ny, rects)) continue\r\n\r\n const turn = incomingDir !== null && incomingDir !== dir\r\n const tentativeG = bestG + gridSize + (turn ? TURN_PENALTY : 0)\r\n const nk = key(nx, ny)\r\n const prevG = gScore.get(nk) ?? Infinity\r\n if (tentativeG < prevG) {\r\n cameFrom.set(nk, current.k)\r\n cameDir.set(nk, dir)\r\n gScore.set(nk, tentativeG)\r\n const f = tentativeG + manhattan(nx, ny, ex, ey)\r\n open.push({ k: nk, x: nx, y: ny, f })\r\n }\r\n }\r\n }\r\n\r\n return null\r\n}\r\n","import type { AABB, Point } from './types'\n\n/**\n * Oriented Bounding Box — a rectangle in world space described by its centre,\n * half-extents along its local axes, and a rotation angle.\n *\n * Used when a node has a non-zero `transform.rot`: the AABB is no longer a\n * tight fit, so callers that need a tight collision shape (selection\n * outline, manipulator handles, etc.) should use the OBB instead.\n *\n * Conventions:\n * - `center` is the centre of the rectangle in world coordinates.\n * - `halfWidth` / `halfHeight` are the half-extents along the OBB's own\n * local axes (already pre-multiplied by the world scale).\n * - `angle` is the rotation of the OBB's local frame relative to world,\n * in radians, positive counter-clockwise.\n *\n * For an axis-aligned node (`angle === 0`) the OBB and AABB coincide, modulo\n * the (centre + half-extents) vs (top-left + size) representation.\n */\nexport interface OBB {\n readonly center: Point\n readonly halfWidth: number\n readonly halfHeight: number\n readonly angle: number\n}\n\n/**\n * Compute the four corners of an OBB in world space.\n *\n * Order is: top-left → top-right → bottom-right → bottom-left in OBB-local\n * space, after applying the rotation. Useful for SVG `<polygon>` rendering\n * and for AABB derivation.\n */\nexport function obbCorners(obb: OBB): readonly [Point, Point, Point, Point] {\n const cos = Math.cos(obb.angle)\n const sin = Math.sin(obb.angle)\n const { halfWidth: hw, halfHeight: hh } = obb\n const [cx, cy] = obb.center\n // local corners (TL, TR, BR, BL)\n const lx: readonly number[] = [-hw, hw, hw, -hw]\n const ly: readonly number[] = [-hh, -hh, hh, hh]\n const out: Point[] = []\n for (let i = 0; i < 4; i++) {\n const x = lx[i]!\n const y = ly[i]!\n out.push([cx + x * cos - y * sin, cy + x * sin + y * cos])\n }\n return out as unknown as readonly [Point, Point, Point, Point]\n}\n\n/**\n * Build the tightest axis-aligned bounding box that contains a given OBB.\n *\n * For a non-zero `angle` the resulting AABB is strictly larger (in area)\n * than the OBB — it has to enclose all four rotated corners. This is the\n * canonical \"broad-phase\" box used by the routing layer.\n */\nexport function aabbFromOBB(obb: OBB): AABB {\n const corners = obbCorners(obb)\n let x0 = corners[0][0]\n let x1 = corners[0][0]\n let y0 = corners[0][1]\n let y1 = corners[0][1]\n for (let i = 1; i < 4; i++) {\n const [x, y] = corners[i]!\n if (x < x0) x0 = x\n if (x > x1) x1 = x\n if (y < y0) y0 = y\n if (y > y1) y1 = y\n }\n return { x: x0, y: y0, w: x1 - x0, h: y1 - y0 }\n}\n\n/**\n * Test whether a world-space point lies inside an OBB.\n *\n * Inverse-rotates the point into OBB-local space and checks the\n * half-extents. O(1).\n */\nexport function obbContainsPoint(obb: OBB, p: Point): boolean {\n const cos = Math.cos(-obb.angle)\n const sin = Math.sin(-obb.angle)\n const dx = p[0] - obb.center[0]\n const dy = p[1] - obb.center[1]\n const lx = dx * cos - dy * sin\n const ly = dx * sin + dy * cos\n return Math.abs(lx) <= obb.halfWidth && Math.abs(ly) <= obb.halfHeight\n}\n"],"mappings":"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","names":["snap"]}
|