@jucie.io/state 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- # @jucie-state/core
1
+ # @jucie.io/state
2
2
 
3
3
  A powerful state management system for JavaScript applications featuring path-based access, history management, and serialization capabilities.
4
4
 
package/dist/State.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @jucie-state/state - State management module
2
+ * @jucie.io/state - State management module
3
3
  */
4
4
 
5
5
  export interface StateValue {
package/dist/main.js.map CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../core/src/lib/TOKENS.js", "../core/src/lib/pathEncoder.js", "../core/src/lib/marker.js", "../core/src/lib/tree/traverse.js", "../core/src/lib/tree/mutate.js", "../core/src/utils/isPrimitive.js", "../core/src/utils/clone.js", "../core/src/lib/gsru.js", "../core/src/admin/buffer.js", "../core/src/admin/binary.js", "../core/src/admin/pack.js", "../core/src/admin/unpack.js", "../core/src/lib/tree/seek.js", "../core/src/lib/change.js", "../core/src/State.js", "../core/src/Plugin.js", "../core/src/lib/global.js"],
3
+ "sources": ["../src/lib/TOKENS.js", "../src/lib/pathEncoder.js", "../src/lib/marker.js", "../src/lib/tree/traverse.js", "../src/lib/tree/mutate.js", "../src/utils/isPrimitive.js", "../src/utils/clone.js", "../src/lib/gsru.js", "../src/admin/buffer.js", "../src/admin/binary.js", "../src/admin/pack.js", "../src/admin/unpack.js", "../src/lib/tree/seek.js", "../src/lib/change.js", "../src/State.js", "../src/Plugin.js", "../src/lib/global.js"],
4
4
  "sourcesContent": ["export const GLOBAL_TAG = '*';\nexport const STATE_CONTEXT = Symbol('STATE_CONTEXT');\nexport const MATCHER = Symbol('MATCHER');\nexport const CREATED = 'CREATED';\nexport const DELETED = 'DELETED';\nexport const UPDATED = 'UPDATED';\n\n// Marker type bitflags\nexport const MARKER_GLOBAL = 1; // 0b001\nexport const MARKER_SINGLE = 2; // 0b010\nexport const MARKER_MANY = 4; // 0b100\nexport const MARKER_EPHEMERAL = 8; // 0b1000\n\n// Comparison result constants\nexport const MATCH_EXACT = 0; // Markers are identical\nexport const MATCH_PARENT = 1; // controlMarker is child of comparedMarker (parent changed)\nexport const MATCH_CHILD = 2; // comparedMarker is child of controlMarker (child changed)\nexport const MATCH_NONE = -1; // No relationship", "import { GLOBAL_TAG } from './TOKENS.js';\n\n// Fast helpers\nfunction escapeStr(str) {\n // Order matters: escape ~ first, then .\n let out = \"\";\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"~\") out += \"~~\";\n else if (ch === \".\") out += \"~d\";\n else out += ch;\n }\n // Represent empty strings as ~e to avoid trailing-dot filenames\n return out.length === 0 ? \"~e\" : out;\n}\n\nfunction unescapeStr(str) {\n let out = \"\";\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"~\") {\n const next = str[++i];\n if (next === \"~\") out += \"~\";\n else if (next === \"d\") out += \".\";\n else if (next === \"e\") out += \"\"; // empty string marker\n else {\n // Unknown escape: treat as literal (robustness)\n out += \"~\" + (next ?? \"\");\n }\n } else {\n out += ch;\n }\n }\n return out;\n}\n\nexport function encodePath(segments) {\n // segments: array of strings or integers\n // Produces: filename/URL-safe string like \"sfoo.n0.sbaz\"\n const parts = new Array(segments.length);\n for (let i = 0; i < segments.length; i++) {\n const v = segments[i];\n if (typeof v === \"number\" && Number.isInteger(v)) {\n // 'n' tag\n parts[i] = \"n\" + String(v); // decimal; includes \"-\" if negative\n } else if (typeof v === \"string\") {\n // 's' tag\n parts[i] = \"s\" + escapeStr(v);\n } else {\n // If you need more types, add here (e.g., booleans 'b', floats 'f').\n throw new TypeError(`Unsupported segment type at index ${i}: ${v}`);\n }\n }\n // Use '.' as separator (safe in URLs and filenames; we avoid trailing '.')\n return parts.join(\".\");\n}\n\nexport function decodeAddress(address) {\n if (address === GLOBAL_TAG) return GLOBAL_TAG;\n if (address.length === 0) return [];\n const raw = address.split(\".\");\n const out = new Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n const token = raw[i];\n if (token.length === 0) {\n // Disallow empty tokens (would imply trailing or double dots)\n throw new Error(\"Invalid address: empty token\");\n }\n const tag = token[0];\n const body = token.slice(1);\n if (tag === \"n\") {\n // Fast parse (no regex)\n if (body.length === 0 || !/^[-]?\\d+$/.test(body)) {\n throw new Error(`Invalid numeric token: \"${token}\"`);\n }\n const num = Number(body);\n // Ensure it was an integer\n if (!Number.isInteger(num)) {\n throw new Error(`Non-integer numeric token: \"${token}\"`);\n }\n out[i] = num;\n } else if (tag === \"s\") {\n out[i] = unescapeStr(body);\n } else {\n throw new Error(`Unknown type tag \"${tag}\" in token \"${token}\"`);\n }\n }\n return out;\n}\n", "import { encodePath } from './pathEncoder.js';\nimport { GLOBAL_TAG } from './TOKENS.js';\nimport {\n MARKER_GLOBAL,\n MARKER_SINGLE,\n MARKER_MANY,\n MARKER_EPHEMERAL,\n MATCH_EXACT,\n MATCH_PARENT,\n MATCH_CHILD,\n MATCH_NONE \n} from './TOKENS.js';\n\n// Marker type bitflags\n\n// Helper functions to check marker type\nexport function isGlobalMarker(marker) {\n return (marker.type & MARKER_GLOBAL) === MARKER_GLOBAL;\n}\n\nexport function isPathMarker(marker) {\n return (marker.type & MARKER_SINGLE) === MARKER_SINGLE;\n}\n\nexport function isMarkers(marker) {\n return (marker.type & MARKER_MANY) === MARKER_MANY;\n}\n\nexport function isEphemeralMarker(marker) {\n return (marker.type & MARKER_EPHEMERAL) === MARKER_EPHEMERAL;\n}\n\nexport function isGlobalPath(path) {\n return !path || path.length === 0 || path === GLOBAL_TAG || path[0] === GLOBAL_TAG;\n}\n\nexport function normalizePaths(args = []) { \n const len = args.length;\n if (len === 0) return [0, [] ];\n if (len === 1 && args[0] === GLOBAL_TAG) return [0, [] ];\n \n if (Array.isArray(args[0])) {\n return len === 1 \n ? [1, [args[0]] ]\n : [len, args ];\n }\n \n return [1, [[...args]] ];\n}\n\nfunction pathHasEphemeral(path) {\n if (!Array.isArray(path)) {\n return false;\n }\n\n for (let i = 0; i < path.length; i++) {\n const segment = path[i];\n if (typeof segment === 'string' && segment.charCodeAt(0) === 46) { // '.'\n return true;\n }\n }\n\n return false;\n}\n\n// Marker factory\nexport function createMarker(paths = []) {\n if (isGlobalPath(paths)) {\n return {\n address: GLOBAL_TAG,\n isMarker: true,\n length: 0,\n path: [],\n children: null,\n type: MARKER_GLOBAL\n };\n }\n \n const [length, normalizedPaths] = normalizePaths(paths);\n const type = length === 1 ? MARKER_SINGLE : MARKER_MANY;\n const path = length === 1 ? normalizedPaths[0] : normalizedPaths;\n const children = length > 1 ? normalizedPaths.map(path => createMarker(path)) : null;\n const isEphemeral = type === MARKER_SINGLE\n ? pathHasEphemeral(path)\n : children.some(child => isEphemeralMarker(child));\n\n let markerType = type;\n if (isEphemeral) {\n markerType |= MARKER_EPHEMERAL;\n }\n\n return {\n address: type === MARKER_SINGLE ? encodePath(path) : null,\n isMarker: true,\n length,\n path,\n children,\n type: markerType\n };\n}\n\nexport function createChildMarker(parentMarker, childPaths) {\n if (childPaths.length === 0) {\n return parentMarker;\n }\n // Normalize the child paths\n const [childLength, normalizedChildPaths] = normalizePaths(childPaths);\n \n // Handle global marker - just return marker with child paths\n if (isGlobalMarker(parentMarker)) {\n return createMarker(normalizedChildPaths, parentMarker.state);\n }\n \n // Handle single path marker\n if (isPathMarker(parentMarker)) {\n if (childLength === 0) {\n // No child paths, return parent as-is\n return parentMarker;\n }\n \n if (childLength === 1) {\n // Single child path - append to parent path\n const newPath = [...parentMarker.path, ...normalizedChildPaths[0]];\n return createMarker(newPath, parentMarker.state);\n } else {\n // Multiple child paths - create many markers\n const newPaths = normalizedChildPaths.map(childPath => \n [...parentMarker.path, ...childPath]\n );\n return createMarker(newPaths, parentMarker.state);\n }\n }\n \n // Handle many markers - recursively create child markers for each\n if (isMarkers(parentMarker)) {\n const newMarkers = new Array(parentMarker.length);\n let i = 0;\n while (i < parentMarker.length) {\n newMarkers[i] = createChildMarker(parentMarker.children[i], childPaths);\n i++;\n }\n \n // Collect all paths from the new markers\n const allPaths = [];\n i = 0;\n while (i < newMarkers.length) {\n const marker = newMarkers[i];\n if (isPathMarker(marker)) {\n allPaths.push(marker.path);\n } else if (isMarkers(marker)) {\n let j = 0;\n while (j < marker.length) {\n allPaths.push(marker.children[j].path);\n j++;\n }\n }\n i++;\n }\n \n return createMarker(allPaths, parentMarker.state);\n }\n \n // Fallback - shouldn't reach here\n return parentMarker;\n}\n\nexport function dispatch(marker, { global, path, ephemeral, error }) {\n try {\n if (!marker.isMarker) return undefined;\n if (isGlobalMarker(marker)) return global ? global(marker) : undefined;\n if (isEphemeralMarker(marker)) return ephemeral ? ephemeral(marker) : path ? path(marker) : undefined;\n if (isPathMarker(marker)) return path ? path(marker) : undefined;\n if (isMarkers(marker)) {\n const results = new Array(marker.length);\n let i = 0;\n while (i < marker.length) {\n const nestedMarker = marker.children[i];\n results[i] = dispatch(nestedMarker, { global, path, ephemeral, error });\n i++;\n }\n return results;\n }\n \n return undefined;\n } catch (err) {\n return error ? error(err.message) : undefined;\n }\n}\n\nexport function compareMarkers(controlMarker, comparedMarker) {\n // Both are global markers or exact address match\n if (isGlobalMarker(controlMarker) && isGlobalMarker(comparedMarker)) {\n return MATCH_EXACT;\n }\n\n // If comparedMarker is global, it's always a parent\n if (isGlobalMarker(comparedMarker)) {\n return MATCH_PARENT;\n }\n \n // Need addresses to compare\n if (!controlMarker.address || !comparedMarker.address) {\n return MATCH_NONE;\n }\n \n // Exact match\n if (controlMarker.address === comparedMarker.address) {\n return MATCH_EXACT;\n }\n \n // controlMarker is more nested (child) - parent changed\n if (controlMarker.address.startsWith(comparedMarker.address + '.')) {\n return MATCH_PARENT;\n }\n \n // comparedMarker is more nested (child) - child changed\n if (comparedMarker.address.startsWith(controlMarker.address + '.')) {\n return MATCH_CHILD;\n }\n \n return MATCH_NONE;\n}\n\nexport const Marker = {\n compare: compareMarkers,\n create: createMarker,\n createChild: createChildMarker,\n dispatch: dispatch,\n isGlobal: isGlobalMarker,\n isSingle: isPathMarker,\n isMarkers: isMarkers,\n isEphemeral: isEphemeralMarker\n};", "const traversalFunctions = [\n null, // index 0 (unused)\n null, // index 1 (single property access doesn't need optimization)\n (obj, path) => obj?.[path[0]]?.[path[1]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]]?.[path[4]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]]?.[path[4]]?.[path[5]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]]?.[path[4]]?.[path[5]]?.[path[6]],\n (obj, path) => obj?.[path[0]]?.[path[1]]?.[path[2]]?.[path[3]]?.[path[4]]?.[path[5]]?.[path[6]]?.[path[7]]\n]\n\nfunction createTraversalFunction(length) {\n const accessors = Array.from({ length }, (_, i) => `?.[path[${i}]]`);\n const expr = \"obj\" + accessors.join(\"\");\n const fn = new Function(\"obj\", \"path\", `return ${expr}`);\n traversalFunctions[length] = fn;\n return fn;\n}\n\nexport function traverse(state, path) {\n const len = path.length;\n if (len === 0) return state;\n if (len === 1) return state[path[0]];\n \n // Use existing function if available\n if (len < traversalFunctions.length && traversalFunctions[len]) {\n return traversalFunctions[len](state, path);\n }\n \n // Create and cache new function if needed\n if (!traversalFunctions[len]) {\n return createTraversalFunction(len)(state, path);\n }\n \n return traversalFunctions[len](state, path);\n}\n\n", "import { traverse } from './traverse.js';\n\n// Helper function to create appropriate container type\nfunction createNodeType (a) {\n return typeof a === 'number' ? [] : {};\n}\n\n\nconst graftFunctions = [\n null, // index 0\n null, // index 1\n (state, path, value) => {\n const [a, b] = path;\n state[a] = a in state ? state[a] : createNodeType(b);\n state[a][b] = value;\n return value;\n },\n (state, path, value) => {\n const [a, b, c] = path;\n state[a] = a in state ? state[a] : createNodeType(b);\n state[a][b] = b in state[a] ? state[a][b] : createNodeType(c);\n state[a][b][c] = value;\n return value;\n },\n (state, path, value) => {\n const [a, b, c, d] = path;\n state[a] = a in state ? state[a] : createNodeType(b);\n state[a][b] = b in state[a] ? state[a][b] : createNodeType(c);\n state[a][b][c] = c in state[a][b] ? state[a][b][c] : createNodeType(d);\n state[a][b][c][d] = value;\n return value;\n },\n (state, path, value) => {\n const [a, b, c, d, e] = path;\n state[a] = a in state ? state[a] : createNodeType(b);\n state[a][b] = b in state[a] ? state[a][b] : createNodeType(c);\n state[a][b][c] = c in state[a][b] ? state[a][b][c] : createNodeType(d);\n state[a][b][c][d] = d in state[a][b][c] ? state[a][b][c][d] : createNodeType(e);\n state[a][b][c][d][e] = value;\n return value;\n },\n (state, path, value) => {\n const [a, b, c, d, e, f] = path;\n state[a] = a in state ? state[a] : createNodeType(b);\n state[a][b] = b in state[a] ? state[a][b] : createNodeType(c);\n state[a][b][c] = c in state[a][b] ? state[a][b][c] : createNodeType(d);\n state[a][b][c][d] = d in state[a][b][c] ? state[a][b][c][d] : createNodeType(e);\n state[a][b][c][d][e] = e in state[a][b][c][d] ? state[a][b][c][d][e] : createNodeType(f);\n state[a][b][c][d][e][f] = value;\n return value;\n },\n (state, path, value) => {\n const [a, b, c, d, e, f, g] = path;\n state[a] = a in state ? state[a] : createNodeType(b);\n state[a][b] = b in state[a] ? state[a][b] : createNodeType(c);\n state[a][b][c] = c in state[a][b] ? state[a][b][c] : createNodeType(d);\n state[a][b][c][d] = d in state[a][b][c] ? state[a][b][c][d] : createNodeType(e);\n state[a][b][c][d][e] = e in state[a][b][c][d] ? state[a][b][c][d][e] : createNodeType(f);\n state[a][b][c][d][e][f] = f in state[a][b][c][d][e] ? state[a][b][c][d][e][f] : createNodeType(g);\n state[a][b][c][d][e][f][g] = value;\n return value;\n },\n (state, path, value) => {\n const [a, b, c, d, e, f, g, h] = path;\n state[a] = a in state ? state[a] : createNodeType(b);\n state[a][b] = b in state[a] ? state[a][b] : createNodeType(c);\n state[a][b][c] = c in state[a][b] ? state[a][b][c] : createNodeType(d);\n state[a][b][c][d] = d in state[a][b][c] ? state[a][b][c][d] : createNodeType(e);\n state[a][b][c][d][e] = e in state[a][b][c][d] ? state[a][b][c][d][e] : createNodeType(f);\n state[a][b][c][d][e][f] = f in state[a][b][c][d][e] ? state[a][b][c][d][e][f] : createNodeType(g);\n state[a][b][c][d][e][f][g] = g in state[a][b][c][d][e][f] ? state[a][b][c][d][e][f][g] : createNodeType(h);\n state[a][b][c][d][e][f][g][h] = value;\n return value;\n }\n];\n\nfunction createGraftFunction(depth) {\n // Instead of alphabet, use numbered variables\n const names = Array.from({ length: depth }, (_, i) => `v${i}`);\n const args = names.join(', ');\n let body = `const [${args}] = path;\\n`;\n\n let pathSoFar = 'state';\n for (let i = 0; i < depth - 1; i++) {\n const current = names[i];\n const next = names[i + 1];\n body += `${pathSoFar}[${current}] = (${pathSoFar}[${current}] !== undefined && typeof ${pathSoFar}[${current}] === 'object') ? ${pathSoFar}[${current}] : createNodeType(${next});\\n`;\n pathSoFar += `[${current}]`;\n }\n\n body += `${pathSoFar}[${names[depth - 1]}] = value;\\nreturn state;`;\n\n const fn = new Function('state', 'path', 'value', 'createNodeType', body);\n graftFunctions[depth] = (state, path, value) => fn(state, path, value, createNodeType);\n return graftFunctions[depth];\n}\n\nexport function graft(state, path, value) {\n const len = path.length;\n\n if (len === 0) {\n return Object.assign(state, value);\n }\n\n if (len === 1) {\n return state[path[0]] = value;\n }\n \n // Use or create cached function\n if (!graftFunctions[len]) {\n return createGraftFunction(len)(state, path, value);\n }\n \n return graftFunctions[len](state, path, value);\n}\n\nexport function detach(state, path) {\n const len = path.length;\n \n if (len === 0) {\n return undefined;\n }\n\n if (len === 1) {\n const value = state[path[0]];\n if (Array.isArray(state)) {\n state.splice(path[0], 1);\n } else {\n delete state[path[0]];\n }\n return value;\n }\n\n const parentPath = path.slice(0, -1);\n const last = path[len - 1];\n const parent = traverse(state, parentPath);\n \n if (!parent) return undefined;\n \n const value = parent[last];\n if (Array.isArray(parent)) {\n parent.splice(last, 1);\n } else {\n delete parent[last];\n }\n return value;\n}\n\n// tree/mutate.js\nexport function replace(oldState, newState) {\n // Get all existing keys\n const oldKeys = Object.keys(oldState);\n let i = 0;\n \n // Clear existing properties\n while (i < oldKeys.length) {\n delete oldState[oldKeys[i]];\n i++;\n }\n\n // Get all new keys\n const newKeys = Object.keys(newState);\n i = 0;\n\n // Deep merge new properties\n while (i < newKeys.length) {\n const key = newKeys[i];\n const value = newState[key];\n \n if (value && typeof value === 'object' && !Array.isArray(value)) {\n oldState[key] = oldState[key] || {};\n replace(oldState[key], value);\n } else {\n oldState[key] = value;\n }\n \n i++;\n }\n\n return oldState;\n}\n\nexport function clear(state) {\n const keys = Object.keys(state);\n for (const key of keys) {\n delete state[key];\n }\n return state;\n}\n\nexport function fuse(oldState, newState) {\n return Object.assign(oldState, newState);\n}", "export function isPrimitive(value) {\n // Fast type check for primitives\n const type = typeof value;\n return value === null || \n value === undefined || \n type === 'string' || \n type === 'number' || \n type === 'boolean' || \n type === 'bigint' || \n type === 'symbol' || \n type === 'function';\n}", "export const clone = (value) => {\n if (structuredClone) {\n return structuredClone(value);\n } else {\n return JSON.parse(JSON.stringify(value));\n }\n}\n", "import { isGlobalPath, dispatch } from './marker.js';\nimport { traverse } from './tree/traverse.js';\nimport { graft, detach, replace } from './tree/mutate.js';\nimport { isPrimitive } from '../utils/isPrimitive.js';\nimport { clone } from '../utils/clone.js';\n\nfunction spread(value) {\n if (Array.isArray(value)) {\n return [...value];\n }\n if (typeof value === 'object' && value !== null) {\n return {...value};\n }\n return value;\n}\n\nexport function get(state, marker, cb) {\n let shouldCallCallback = false;\n try {\n return dispatch(marker, {\n global: () => {\n shouldCallCallback = true;\n return state;\n },\n path: ({path}) => {\n shouldCallCallback = true;\n return traverse(state, path);\n }\n });\n } catch (error) {\n console.error(error);\n return undefined;\n } finally {\n if (shouldCallCallback && cb) {\n cb(marker);\n }\n }\n}\n\nexport function set(state, marker, value, method, cb) {\n let from;\n let shouldCallCallback = false;\n \n try {\n return dispatch(marker, {\n global: () => {\n from = {...state};\n state = replace(state, value);\n shouldCallCallback = true;\n return value;\n },\n path: ({path}) => {\n from = spread(traverse(state, path));\n graft(state, path, value);\n shouldCallCallback = true;\n return value;\n }\n });\n } catch (error) {\n console.error(error);\n return undefined;\n } finally {\n if (shouldCallCallback && cb) {\n cb(marker, method, value, from);\n }\n }\n}\n\nexport function remove(state, marker, method, cb) {\n let from;\n let shouldCallCallback = false;\n try {\n return dispatch(marker, {\n global: () => {\n from = state;\n state = replace(state, {});\n shouldCallCallback = true;\n return from;\n },\n path: ({path}) => { \n from = detach(state, path);\n shouldCallCallback = true;\n return from;\n }\n });\n } catch (error) {\n console.error(error);\n return undefined;\n } finally {\n if (cb) {\n cb(marker, method, undefined, from);\n }\n }\n}\n\nexport function update(state, marker, fn, method, cb) {\n let from, to;\n let shouldCallCallback = false;\n try {\n return dispatch(marker, {\n global: () => {\n from = state;\n to = fn(state);\n state = replace(state, to);\n shouldCallCallback = true;\n return to;\n },\n path: ({ path }) => {\n from = isGlobalPath(path) ? state : traverse(state, path);\n const clonePrev = isPrimitive(from) ? from : clone(from);\n to = fn(clonePrev);\n graft(state, path, to);\n shouldCallCallback = true;\n return to;\n }\n });\n } catch (error) {\n console.error(error);\n return undefined;\n } finally {\n if (shouldCallCallback && cb) {\n cb(marker, method, to, from);\n }\n }\n}", "export function isBrowser() {\n return typeof window !== \"undefined\" && typeof window.crypto !== \"undefined\" && !!window.crypto.subtle;\n}\n\nexport function getSubtle() {\n if (typeof crypto !== \"undefined\" && crypto.subtle) return crypto.subtle;\n // Node.js\n const { webcrypto } = require(\"node:crypto\");\n return webcrypto.subtle;\n}\n\n// base64url encode/decode for both envs\nexport function base64urlEncode(bytes) {\n if (typeof Buffer !== \"undefined\" && Buffer.from) {\n // Node\n return Buffer.from(bytes).toString(\"base64\")\n .replace(/=/g, \"\")\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\");\n } else {\n // Browser\n // Convert bytes -> binary string -> base64 -> base64url\n let bin = \"\";\n for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);\n const b64 = btoa(bin);\n return b64.replace(/=/g, \"\").replace(/\\+/g, \"-\").replace(/\\//g, \"_\");\n }\n}\n\nexport function base64urlDecode(str) {\n // restore padding\n const pad = str.length % 4 === 2 ? \"==\"\n : str.length % 4 === 3 ? \"=\"\n : str.length % 4 === 0 ? \"\"\n : \"=\".repeat(4 - (str.length % 4));\n const b64 = str.replace(/-/g, \"+\").replace(/_/g, \"/\") + pad;\n\n if (typeof Buffer !== \"undefined\" && Buffer.from) {\n const buf = Buffer.from(b64, \"base64\");\n return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);\n } else {\n // Browser\n const bin = atob(b64);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);\n return out;\n }\n}\n\n// Canonical JSON (stable ordering) to avoid hash drift due to key order\nexport function stableStringify(value) {\n if (value === null || typeof value !== \"object\") {\n return JSON.stringify(value);\n }\n if (Array.isArray(value)) {\n const items = value.map(v => stableStringify(v)).join(\",\");\n return `[${items}]`;\n }\n const keys = Object.keys(value).sort();\n const props = keys.map(k => `${JSON.stringify(k)}:${stableStringify(value[k])}`).join(\",\");\n return `{${props}}`;\n}\n\n// Optional replacer to omit ephemeral keys\nexport function defaultReplacer(key, value) {\n // drop keys starting with '.' or exactly 'ephemeral'\n if (key && key[0] === \".\") return undefined;\n return value;\n}\n\nexport function applyReplacerDeep(input, replacer = defaultReplacer, parentKey = \"\") {\n if (input === null || typeof input !== \"object\") return input;\n\n if (Array.isArray(input)) {\n return input.map(v => applyReplacerDeep(v, replacer));\n }\n\n const out = {};\n for (const k of Object.keys(input)) {\n const v = replacer(k, input[k]);\n if (typeof v !== \"undefined\") {\n out[k] = applyReplacerDeep(v, replacer, k);\n }\n }\n return out;\n}\n\n// Convert path IDs with null chars to arrays for JSON serialization\nexport function pathIdsToArrays(input) {\n if (input === null || typeof input !== \"object\") return input;\n\n if (Array.isArray(input)) {\n return input.map(v => {\n // Check if array element is a string with null character (path ID)\n if (typeof v === 'string' && v.includes('\\0')) {\n const pathArray = v.split('\\0').map(segment => {\n const [type, value] = segment.split(':');\n return type === 'n' ? parseInt(value) : value;\n });\n return `__pathArray:${JSON.stringify(pathArray)}`;\n }\n return pathIdsToArrays(v);\n });\n }\n\n const out = {};\n for (const k of Object.keys(input)) {\n const v = input[k];\n // Check if key contains null character (path ID)\n if (typeof k === 'string' && k.includes('\\0')) {\n // Convert path ID to array format\n const pathArray = k.split('\\0').map(segment => {\n const [type, value] = segment.split(':');\n return type === 'n' ? parseInt(value) : value;\n });\n out[`__pathArray:${JSON.stringify(pathArray)}`] = pathIdsToArrays(v);\n } else {\n out[k] = pathIdsToArrays(v);\n }\n }\n return out;\n}\n\n// Convert arrays back to path IDs with null chars after JSON parsing\nexport function arraysToPathIds(input) {\n if (input === null || typeof input !== \"object\") return input;\n\n if (Array.isArray(input)) {\n return input.map(v => {\n // Check if array element is a path array\n if (typeof v === 'string' && v.startsWith('__pathArray:')) {\n const pathArray = JSON.parse(v.substring(12)); // Remove '__pathArray:' prefix\n // Convert array back to path ID with null chars\n const pathId = pathArray.map(segment => {\n const type = typeof segment === 'number' ? 'n' : 's';\n return `${type}:${segment}`;\n }).join('\\0');\n return pathId;\n }\n return arraysToPathIds(v);\n });\n }\n\n const out = {};\n for (const k of Object.keys(input)) {\n const v = input[k];\n // Check if key is a path array\n if (typeof k === 'string' && k.startsWith('__pathArray:')) {\n const pathArray = JSON.parse(k.substring(12)); // Remove '__pathArray:' prefix\n // Convert array back to path ID with null chars\n const pathId = pathArray.map(segment => {\n const type = typeof segment === 'number' ? 'n' : 's';\n return `${type}:${segment}`;\n }).join('\\0');\n out[pathId] = arraysToPathIds(v);\n } else {\n out[k] = arraysToPathIds(v);\n }\n }\n return out;\n}\n\nexport async function sha256(bytes) {\n const subtle = getSubtle();\n const digest = await subtle.digest(\"SHA-256\", bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength));\n return new Uint8Array(digest);\n}\n\nexport function constantTimeEqual(a, b) {\n if (a.length !== b.length) return false;\n let acc = 0;\n for (let i = 0; i < a.length; i++) acc |= (a[i] ^ b[i]);\n return acc === 0;\n}", "import { encode, decode } from 'cbor-x';\n\n// Magic header for binary capsules\nexport const MAGIC = new Uint8Array([0x4A, 0x53, 0x43, 0x32]); // \"JSC2\" (Object Capsule v2)\nexport const VERSION = 2;\n\n// Base64url encoding/decoding utilities\nexport function base64urlEncode(buffer) {\n // Process in chunks to avoid call stack overflow for large buffers\n const chunkSize = 8192; // Process 8KB at a time\n let binaryString = '';\n \n for (let i = 0; i < buffer.length; i += chunkSize) {\n const chunk = buffer.slice(i, i + chunkSize);\n binaryString += String.fromCharCode(...chunk);\n }\n \n return btoa(binaryString)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n}\n\nexport function base64urlDecode(str) {\n const base64 = str\n .replace(/-/g, '+')\n .replace(/_/g, '/');\n \n // Add padding if needed\n const padded = base64 + '='.repeat((4 - base64.length % 4) % 4);\n const binaryString = atob(padded);\n \n // Convert to Uint8Array efficiently for large strings\n const result = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n result[i] = binaryString.charCodeAt(i);\n }\n return result;\n}\n\n// Simple checksum calculation\nexport function calculateChecksum(buffer) {\n let checksum = 0;\n for (let i = 0; i < buffer.length; i++) {\n checksum = ((checksum << 5) - checksum + buffer[i]) >>> 0; // Ensure positive 32-bit\n }\n return checksum;\n}\n\n// Binary encoding utilities for capsule header\nexport function writeUint32(value, buffer, offset = 0) {\n const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 4);\n view.setUint32(0, value, true); // little-endian\n return offset + 4;\n}\n\nexport function readUint32(buffer, offset = 0) {\n const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 4);\n return view.getUint32(0, true); // little-endian\n}\n\nexport function writeUint16(value, buffer, offset = 0) {\n const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 2);\n view.setUint16(0, value, true); // little-endian\n return offset + 2;\n}\n\nexport function readUint16(buffer, offset = 0) {\n const view = new DataView(buffer.buffer, buffer.byteOffset + offset, 2);\n return view.getUint16(0, true); // little-endian\n}\n\nexport function writeUint8(value, buffer, offset = 0) {\n buffer[offset] = value;\n return offset + 1;\n}\n\nexport function readUint8(buffer, offset = 0) {\n return buffer[offset];\n}\n\n// Object encoding using cbor-x\nexport function encodeObject(obj) {\n return encode(obj);\n}\n\nexport function decodeObject(buffer) {\n const obj = decode(buffer);\n return [obj, buffer.length];\n}", "import { defaultReplacer, applyReplacerDeep } from './buffer.js';\nimport { \n MAGIC, VERSION, \n writeUint32, writeUint16, writeUint8,\n encodeObject,\n calculateChecksum, base64urlEncode\n} from './binary.js';\n\n// ---------- Binary Capsule Format ----------\n// [ 0..3 ] Magic \"JSC2\" (Jucie State Capsule v2)\n// [ 4..5 ] u16 version (big-endian) = 2\n// [ 6 ] u8 flags (reserved for future use)\n// [ 7..10 ] u32 checksum (simple checksum)\n// [11..14 ] u32 payloadLength (big-endian)\n// [15.. ] payload bytes (binary encoded data)\n\n// ---------- Public API ----------\n\n/**\n * Export any data object as a resilient binary capsule string (base64url).\n * Reciprocal with importState.\n * @param {Object} data - The data object to export\n * @param {Object} options - Export options\n */\nexport async function pack(data, { replacer = defaultReplacer } = {}) {\n // 1) Clean ephemeral/transient fields\n const clean = applyReplacerDeep(data, replacer);\n\n // 2) Encode data to binary\n const dataBuffer = encodeObject(clean);\n\n // 3) Create payload: [dataLength:4][data:varies]\n const payloadLength = 4 + dataBuffer.length;\n const payload = new Uint8Array(payloadLength);\n \n let offset = 0;\n offset = writeUint32(dataBuffer.length, payload, offset);\n payload.set(dataBuffer, offset);\n\n // 4) Calculate checksum\n const checksum = calculateChecksum(payload);\n\n // 5) Build capsule\n const headerLen = 4 + 2 + 1 + 4 + 4; // 15 bytes\n const capsule = new Uint8Array(headerLen + payload.length);\n\n // Magic\n capsule.set(MAGIC, 0);\n\n // Version u16 LE\n writeUint16(VERSION, capsule, 4);\n\n // Flags u8\n writeUint8(0, capsule, 6);\n\n // Checksum u32 LE\n writeUint32(checksum, capsule, 7);\n\n // Payload length u32 LE\n writeUint32(payload.length, capsule, 11);\n\n // Payload\n capsule.set(payload, 15);\n\n // 6) Base64url encode (single portable string)\n return base64urlEncode(capsule);\n}", "import { \n MAGIC, VERSION, \n decodeObject,\n calculateChecksum, base64urlDecode,\n readUint16, readUint8, readUint32\n} from './binary.js';\n\n// ---------- Binary Capsule Format ----------\n// [ 0..3 ] Magic \"JSC2\" (Jucie State Capsule v2)\n// [ 4..5 ] u16 version (big-endian) = 2\n// [ 6 ] u8 flags (reserved for future use)\n// [ 7..10 ] u32 checksum (simple checksum)\n// [11..14 ] u32 payloadLength (big-endian)\n// [15.. ] payload bytes (binary encoded data)\n\n// ---------- Public API ----------\n\n/**\n * Import a binary capsule string created by exportState.\n * Returns decoded data object with metadata.\n * @param {String} capsuleString - Base64url encoded capsule\n * @param {Function} [cb] - Optional callback(data)\n */\nexport async function unpack(capsuleString, cb) {\n // 1) Decode\n const capsule = base64urlDecode(capsuleString);\n\n // 2) Sanity checks\n if (capsule.length < 15) {\n throw new Error(\"Invalid capsule: too short\");\n }\n\n // Magic\n for (let i = 0; i < 4; i++) {\n if (capsule[i] !== MAGIC[i]) throw new Error(\"Invalid capsule: bad magic\");\n }\n\n // Version\n const version = readUint16(capsule, 4);\n if (version !== VERSION) {\n throw new Error(`Unsupported capsule version: ${version}`);\n }\n\n // Flags (reserved)\n const flags = readUint8(capsule, 6);\n\n // Checksum\n const storedChecksum = readUint32(capsule, 7);\n\n // Payload length\n const payloadLength = readUint32(capsule, 11);\n if (payloadLength < 0) throw new Error(\"Invalid capsule: negative payload length\");\n if (capsule.length !== 15 + payloadLength) throw new Error(\"Invalid capsule: length mismatch\");\n\n const payload = capsule.slice(15);\n\n // 3) Verify checksum\n const actualChecksum = calculateChecksum(payload);\n if (storedChecksum !== actualChecksum) {\n throw new Error(\"Integrity check failed: checksum mismatch\");\n }\n\n // 4) Decode payload\n let offset = 0;\n \n // Decode data\n const dataLength = readUint32(payload, offset);\n offset += 4;\n \n if (offset + dataLength > payload.length) {\n throw new Error(`Data length ${dataLength} exceeds payload bounds at offset ${offset}`);\n }\n \n const [data] = decodeObject(payload.slice(offset, offset + dataLength));\n\n // 5) Call callback if provided\n if (cb) cb(data);\n\n return {\n data, // Add 'data' key for generic usage\n meta: {\n version,\n flags,\n bytes: capsule.length,\n checksum: actualChecksum.toString(16),\n },\n };\n}", "// Internal matcher logic\nfunction match(value, matcher, testValue) {\n switch (matcher) {\n case 'is':\n case '===':\n case '==': return value === testValue;\n case 'not':\n case '!==':\n case '!=': return value !== testValue;\n case 'includes': return Array.isArray(value) && value.includes(testValue);\n case 'has': return typeof value === 'object' && value !== null && Object.values(value).includes(testValue);\n case 'in': return typeof value === 'object' && value !== null && testValue in value;\n case 'gt':\n case '>': return value > testValue;\n case 'lt':\n case '<': return value < testValue;\n case 'gte':\n case '>=': return value >= testValue;\n case 'lte':\n case '<=': return value <= testValue;\n default: throw new Error(`Unknown matcher: ${matcher}`);\n }\n}\n\nexport function seek(obj, targetKey, matcher, testValue, currentPath = [], findAll = false) {\n const results = [];\n\n if (obj === null || typeof obj !== 'object') return results;\n\n for (const [key, value] of Object.entries(obj)) {\n // \u2705 Check the key directly\n if (key === targetKey && match(value, matcher, testValue)) {\n results.push([...currentPath, key]);\n if (!findAll) return results;\n }\n\n // \u2705 Recurse if object/array\n if (typeof value === 'object' && value !== null) {\n if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n const item = value[i];\n if (item && typeof item === 'object') {\n const nested = seek(item, targetKey, matcher, testValue, [...currentPath, key, i], findAll);\n results.push(...nested);\n if (!findAll && results.length > 0) return results;\n }\n }\n } else {\n const nested = seek(value, targetKey, matcher, testValue, [...currentPath, key], findAll);\n results.push(...nested);\n if (!findAll && results.length > 0) return results;\n }\n }\n }\n\n return results;\n}\n\n// Helper functions for common search patterns\nexport function findFirstNode(obj, key, matcher = 'is', value) {\n return seek(obj, key, matcher, value, [], false)?.[0];\n}\n\nexport function findAllNodes(obj, key, matcher = 'is', value) {\n return seek(obj, key, matcher, value, [], true);\n}", "import { GLOBAL_TAG, CREATED, DELETED, UPDATED } from './TOKENS.js';\nimport { dispatch } from './marker.js';\n\nexport const OPERATION_INVERSES = {\n [CREATED]: DELETED,\n [DELETED]: CREATED,\n [UPDATED]: UPDATED,\n}\n\n/**\n * Determines the operation type based on from/to values\n * \n * @private\n * @param {*} from - Previous value\n * @param {*} to - New value\n * @returns {'created'|'deleted'|'updated'} Operation type\n */\nfunction determineOperation(to, from) {\n if (from === undefined) return CREATED;\n if (to === undefined) return DELETED;\n return UPDATED;\n}\n\n/**\n * Creates a change object with the given parameters\n * \n * @param {string} method - Method that triggered the change\n * @param {*} from - Previous value\n * @param {*} to - New value\n * @returns {Object} Change object\n * @example\n * createChange('set', undefined, 'new value') \n * // => { method: 'set', operation: 'created', from: undefined, to: 'new value' }\n */\nexport function createChange(marker, method, to, from) {\n return dispatch(marker, {\n global: () => ({\n path: GLOBAL_TAG,\n method,\n operation: determineOperation(to, from),\n from,\n to\n }),\n path: (marker) => ({\n path: marker.path,\n method,\n operation: determineOperation(to, from),\n from,\n to\n }),\n });\n}\n\n/**\n * Inverts a change object for undo operations\n * \n * @param {Object} change - Change object to invert\n * @param {string} change.method - Original method\n * @param {string} change.operation - Original operation\n * @param {*} change.from - Original from value\n * @param {*} change.to - Original to value\n * @returns {Object} Inverted change object\n * @example\n * invertChange({ method: 'set', operation: 'created', from: undefined, to: 'value' })\n * // => { method: 'set', operation: 'deleted', from: 'value', to: undefined }\n */\nexport function invertChange(change) {\n const {address, path, method, from, to, operation } = change;\n return {\n address,\n path,\n method,\n to: from,\n from: to,\n operation: invertOperation(operation),\n }\n}\n\nexport function invertOperation(operation) {\n return OPERATION_INVERSES[operation];\n}\n\n/**\n * Checks if a change needs to be inverted based on the method\n * \n * @param {string} method - Method to check\n * @returns {boolean} True if the change should be inverted\n * @example\n * shouldInvertChange('undo') // => true\n * shouldInvertChange('set') // => false\n */\nexport function shouldInvertChange(method) {\n return ['undo', 'redo', 'stepBackward', 'stepForward'].includes(method);\n}", "import { get, set, remove, update } from './lib/gsru.js';\nimport { createMarker, createChildMarker, dispatch } from './lib/marker.js';\nimport { pack } from './admin/pack.js';\nimport { unpack } from './admin/unpack.js';\nimport { clear } from './lib/tree/mutate.js';\nimport { findFirstNode, findAllNodes } from './lib/tree/seek.js';\nimport { CREATED, DELETED, UPDATED } from './lib/TOKENS.js';\nimport { createChange } from './lib/change.js';\n\nexport class State {\n #state;\n #marker;\n #batchDepth = 0;\n #changeHandler;\n #accessHandler;\n #plugins = new Map();\n\n static create (state = {}) {\n const instance = new State(state);\n\n return instance;\n }\n\n constructor(state, marker = null, changeHandler = null, accessHandler = null) {\n this.#state = state;\n this.#changeHandler = changeHandler || this.#createChangeHandler();\n this.#accessHandler = accessHandler || this.#createAccessHandler();\n this.#marker = marker || createMarker();\n this.#batchDepth = 0;\n }\n\n install(...plugins) {\n const initializeFunctions = new Map();\n\n for (const plugin of plugins) {\n if (this.#plugins.has(plugin.name)) {\n console.warn(`Plugin \"${plugin.name}\" already installed`);\n continue;\n }\n\n if (!plugin.install) {\n console.warn(`Plugin \"${plugin.name}\" does not have an install function`);\n continue;\n }\n\n const pluginInstance = plugin.install(this);\n this.#plugins.set(plugin.name, pluginInstance);\n\n if (pluginInstance.initialize) {\n initializeFunctions.set(plugin.name, () => pluginInstance.initialize(this, pluginInstance.options));\n }\n\n if (pluginInstance.actions) {\n const actions = pluginInstance.actions(this, pluginInstance.options);\n Object.defineProperty(this, plugin.name, {\n value: actions,\n writable: false,\n enumerable: true,\n configurable: false\n });\n }\n }\n\n initializeFunctions.forEach(initialize => initialize());\n return this;\n }\n\n get batching() {\n return this.#batchDepth > 0;\n }\n\n // Core State Accessors\n get(...args) {\n return get(this.#state, createChildMarker(this.#marker, args), this.#accessHandler);\n }\n\n has(...args) {\n const marker = createChildMarker(this.#marker, args);\n return dispatch(marker, {\n global: () => undefined,\n path: (marker) => get(this.#state, marker, this.#accessHandler) !== undefined,\n });\n }\n\n keys(...args) {\n const marker = createChildMarker(this.#marker, args);\n return dispatch(marker, {\n global: () => Object.keys(this.#state),\n path: (marker) => Object.keys(get(this.#state, marker, this.#accessHandler) || {}),\n });\n }\n\n typeof(...args) {\n const marker = createChildMarker(this.#marker, args);\n const value = dispatch(marker, {\n global: () => undefined,\n path: ({ path }) => typeof get(this.#state, path, this.#accessHandler),\n });\n return value;\n }\n\n // Queries\n findWhere(key, matcher = 'is', value) {\n const state = get(this.#state, this.#marker, this.#accessHandler);\n return findFirstNode(state, key, matcher, value);\n }\n\n findAllWhere(key, matcher = 'is', value) {\n const state = get(this.#state, this.#marker, this.#accessHandler);\n return findAllNodes(state, key, matcher, value);\n }\n\n // Mutations\n set(...args) {\n const value = args.pop(); \n const marker = createChildMarker(this.#marker, args);\n // No sync tombstone check - let async processing handle conflicts\n return set(this.#state, marker, value, 'set', this.#changeHandler);\n }\n\n update(...args) {\n const fn = args.pop();\n const marker = createChildMarker(this.#marker, args);\n \n // No sync tombstone check - let async processing handle conflicts \n return update(this.#state, marker, fn, 'update', this.#changeHandler);\n }\n\n apply(changeEntries) {\n for (const changeEntry of changeEntries) {\n const { path, operation, to } = changeEntry;\n\n const marker = createChildMarker(this.#marker, path);\n switch (operation) {\n case CREATED:\n case UPDATED:\n set(this.#state, marker, to, 'apply', this.#changeHandler);\n break;\n case DELETED:\n remove(this.#state, marker, 'apply', this.#changeHandler);\n break;\n }\n }\n }\n\n load(value) {\n set(this.#state, this.#marker, value, 'load', this.#changeHandler);\n return this;\n }\n\n remove(...args) {\n const marker = createChildMarker(this.#marker, args);\n return remove(this.#state, marker, 'remove', this.#changeHandler);\n }\n\n // Lifecycle / Admin\n async export(...args) {\n try {\n const marker = createChildMarker(this.#marker, args);\n const promises = dispatch(marker, {\n global: async () => await pack(this.#state),\n path: async (path) => await pack(get(this.#state, path, this.#accessHandler)),\n });\n if (!Array.isArray(promises)) {\n return await promises;\n }\n return await Promise.all(promises);\n } catch (err) {\n console.trace(`Failed to export state: ${err.message}`);\n throw err\n }\n }\n\n async import(exportedData) {\n try {\n const { data } = await unpack(exportedData);\n this.load(data);\n return this;\n } catch (err) {\n console.trace(`Failed to import state: ${err.message}`);\n throw err\n }\n }\n\n reset() {\n clear(this.#state);\n for (const plugin of this.#plugins.values()) {\n if (plugin.reset) {\n plugin.reset();\n }\n }\n this.#changeHandler = this.#createChangeHandler();\n this.#marker = createMarker([], this);\n this.#batchDepth = 0;\n }\n\n\n // Reactivity Utilities\n ref(...path) {\n const marker = createChildMarker(this.#marker, path);\n return new State(this.#state, marker, this.#changeHandler, this.#accessHandler);\n }\n\n batch(fn) {\n this.#batchDepth++;\n this.#notifyPlugins('onBatchStart', this.batching);\n if (fn) {\n fn(this);\n return this.endBatch();\n }\n return () => this.endBatch();\n }\n\n endBatch() {\n this.#batchDepth--;\n if (this.#batchDepth === 0) {\n this.#notifyPlugins('onBatchEnd');\n }\n return this;\n }\n\n // Private change handler\n #createChangeHandler() {\n return (marker, method, to = undefined, from = undefined) => {\n this.#notifyPlugins('onStateChange', marker, createChange(marker, method, to, from), this.batching);\n }\n }\n\n #createAccessHandler() {\n return (marker) => this.#notifyPlugins('onStateAccess', marker);\n }\n\n #notifyPlugins(event, ...args) {\n for (const plugin of this.#plugins.values()) {\n if (typeof plugin[event] === 'function') {\n plugin[event](...args);\n }\n }\n }\n}\n\nexport const createState = (...args) => State.create(...args);\nexport const isState = (target) => target instanceof State;", "export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "import { STATE_CONTEXT } from './TOKENS.js';\n\n/**\n * Registers the state globally, but only if no state has already been set.\n * @param {object} state \n */\n\nexport function provideState(state) {\n if (!globalThis[STATE_CONTEXT]) {\n globalThis[STATE_CONTEXT] = state;\n }\n}\n\nexport function hasState() {\n return globalThis[STATE_CONTEXT] !== undefined;\n}\n\n/**\n * Forcefully override the state in the global context.\n * Useful for testing or resetting.\n */\nexport function forceState(state) {\n globalThis[STATE_CONTEXT] = state;\n}\n\n/**\n * Retrieves the globally registered state.\n */\nexport function getState() {\n return globalThis[STATE_CONTEXT] || null;\n}\n\n/**\n * Retrieves the globally registered state.\n */\nexport function useState() {\n return getState();\n}\n\nexport function clearState() {\n globalThis[STATE_CONTEXT] = undefined;\n}"],
5
5
  "mappings": "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",
6
6
  "names": ["GLOBAL_TAG", "STATE_CONTEXT", "MATCHER", "CREATED", "DELETED", "UPDATED", "MARKER_GLOBAL", "MARKER_SINGLE", "MARKER_MANY", "MARKER_EPHEMERAL", "escapeStr", "str", "out", "i", "ch", "encodePath", "segments", "parts", "i", "v", "escapeStr", "isGlobalMarker", "marker", "MARKER_GLOBAL", "isPathMarker", "MARKER_SINGLE", "isMarkers", "MARKER_MANY", "isEphemeralMarker", "MARKER_EPHEMERAL", "isGlobalPath", "path", "GLOBAL_TAG", "normalizePaths", "args", "len", "pathHasEphemeral", "i", "segment", "createMarker", "paths", "length", "normalizedPaths", "type", "children", "isEphemeral", "child", "markerType", "encodePath", "createChildMarker", "parentMarker", "childPaths", "childLength", "normalizedChildPaths", "newPath", "newPaths", "childPath", "newMarkers", "allPaths", "j", "dispatch", "global", "ephemeral", "error", "results", "nestedMarker", "err", "traversalFunctions", "obj", "path", "createTraversalFunction", "length", "expr", "_", "fn", "traverse", "state", "len", "createNodeType", "a", "graftFunctions", "state", "path", "value", "b", "c", "d", "e", "f", "g", "h", "createGraftFunction", "depth", "names", "_", "i", "body", "pathSoFar", "current", "next", "fn", "graft", "len", "detach", "parentPath", "last", "parent", "traverse", "replace", "oldState", "newState", "oldKeys", "newKeys", "key", "clear", "keys", "isPrimitive", "value", "type", "clone", "value", "spread", "value", "get", "state", "marker", "cb", "shouldCallCallback", "dispatch", "path", "traverse", "error", "set", "method", "from", "replace", "graft", "remove", "detach", "update", "fn", "to", "isGlobalPath", "clonePrev", "isPrimitive", "clone", "defaultReplacer", "key", "value", "applyReplacerDeep", "input", "replacer", "parentKey", "v", "out", "k", "encode", "decode", "MAGIC", "VERSION", "base64urlEncode", "buffer", "binaryString", "i", "chunk", "base64urlDecode", "str", "base64", "padded", "result", "calculateChecksum", "checksum", "writeUint32", "value", "offset", "readUint32", "writeUint16", "readUint16", "writeUint8", "readUint8", "encodeObject", "obj", "decodeObject", "pack", "data", "replacer", "defaultReplacer", "clean", "applyReplacerDeep", "dataBuffer", "encodeObject", "payloadLength", "payload", "offset", "writeUint32", "checksum", "calculateChecksum", "headerLen", "capsule", "MAGIC", "writeUint16", "VERSION", "writeUint8", "base64urlEncode", "unpack", "capsuleString", "cb", "capsule", "base64urlDecode", "i", "MAGIC", "version", "readUint16", "VERSION", "flags", "readUint8", "storedChecksum", "readUint32", "payloadLength", "payload", "actualChecksum", "calculateChecksum", "offset", "dataLength", "data", "decodeObject", "match", "value", "matcher", "testValue", "seek", "obj", "targetKey", "currentPath", "findAll", "results", "key", "i", "item", "nested", "findFirstNode", "findAllNodes", "OPERATION_INVERSES", "CREATED", "DELETED", "UPDATED", "determineOperation", "to", "from", "createChange", "marker", "method", "dispatch", "GLOBAL_TAG", "State", "_State", "#state", "#marker", "#batchDepth", "#changeHandler", "#accessHandler", "#plugins", "state", "marker", "changeHandler", "accessHandler", "#createChangeHandler", "#createAccessHandler", "createMarker", "plugins", "initializeFunctions", "plugin", "pluginInstance", "actions", "initialize", "args", "get", "createChildMarker", "dispatch", "path", "key", "matcher", "value", "findFirstNode", "findAllNodes", "set", "fn", "update", "changeEntries", "changeEntry", "operation", "to", "CREATED", "UPDATED", "DELETED", "remove", "promises", "pack", "err", "exportedData", "data", "unpack", "clear", "#notifyPlugins", "method", "from", "createChange", "event", "createState", "isState", "target", "Plugin", "options", "state", "pluginInstance", "provideState", "state", "STATE_CONTEXT", "hasState", "forceState", "getState", "useState", "clearState"]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../core/src/lib/TOKENS.js", "../../core/src/lib/change.js", "../../core/src/utils/defer.js", "../../core/src/Plugin.js", "../../plugins/history/src/HistoryManager.js"],
4
- "sourcesContent": ["export const GLOBAL_TAG = '*';\nexport const STATE_CONTEXT = Symbol('STATE_CONTEXT');\nexport const MATCHER = Symbol('MATCHER');\nexport const CREATED = 'CREATED';\nexport const DELETED = 'DELETED';\nexport const UPDATED = 'UPDATED';\n\n// Marker type bitflags\nexport const MARKER_GLOBAL = 1; // 0b001\nexport const MARKER_SINGLE = 2; // 0b010\nexport const MARKER_MANY = 4; // 0b100\nexport const MARKER_EPHEMERAL = 8; // 0b1000\n\n// Comparison result constants\nexport const MATCH_EXACT = 0; // Markers are identical\nexport const MATCH_PARENT = 1; // controlMarker is child of comparedMarker (parent changed)\nexport const MATCH_CHILD = 2; // comparedMarker is child of controlMarker (child changed)\nexport const MATCH_NONE = -1; // No relationship", "import { GLOBAL_TAG, CREATED, DELETED, UPDATED } from './TOKENS.js';\nimport { dispatch } from './marker.js';\n\nexport const OPERATION_INVERSES = {\n [CREATED]: DELETED,\n [DELETED]: CREATED,\n [UPDATED]: UPDATED,\n}\n\n/**\n * Determines the operation type based on from/to values\n * \n * @private\n * @param {*} from - Previous value\n * @param {*} to - New value\n * @returns {'created'|'deleted'|'updated'} Operation type\n */\nfunction determineOperation(to, from) {\n if (from === undefined) return CREATED;\n if (to === undefined) return DELETED;\n return UPDATED;\n}\n\n/**\n * Creates a change object with the given parameters\n * \n * @param {string} method - Method that triggered the change\n * @param {*} from - Previous value\n * @param {*} to - New value\n * @returns {Object} Change object\n * @example\n * createChange('set', undefined, 'new value') \n * // => { method: 'set', operation: 'created', from: undefined, to: 'new value' }\n */\nexport function createChange(marker, method, to, from) {\n return dispatch(marker, {\n global: () => ({\n path: GLOBAL_TAG,\n method,\n operation: determineOperation(to, from),\n from,\n to\n }),\n path: (marker) => ({\n path: marker.path,\n method,\n operation: determineOperation(to, from),\n from,\n to\n }),\n });\n}\n\n/**\n * Inverts a change object for undo operations\n * \n * @param {Object} change - Change object to invert\n * @param {string} change.method - Original method\n * @param {string} change.operation - Original operation\n * @param {*} change.from - Original from value\n * @param {*} change.to - Original to value\n * @returns {Object} Inverted change object\n * @example\n * invertChange({ method: 'set', operation: 'created', from: undefined, to: 'value' })\n * // => { method: 'set', operation: 'deleted', from: 'value', to: undefined }\n */\nexport function invertChange(change) {\n const {address, path, method, from, to, operation } = change;\n return {\n address,\n path,\n method,\n to: from,\n from: to,\n operation: invertOperation(operation),\n }\n}\n\nexport function invertOperation(operation) {\n return OPERATION_INVERSES[operation];\n}\n\n/**\n * Checks if a change needs to be inverted based on the method\n * \n * @param {string} method - Method to check\n * @returns {boolean} True if the change should be inverted\n * @example\n * shouldInvertChange('undo') // => true\n * shouldInvertChange('set') // => false\n */\nexport function shouldInvertChange(method) {\n return ['undo', 'redo', 'stepBackward', 'stepForward'].includes(method);\n}", "export function defer(arg1, arg2) {\n let callback = null;\n let delay = 0;\n\n if (typeof arg1 === 'function') {\n callback = arg1;\n if (typeof arg2 === 'number') {\n delay = arg2;\n }\n } else if (typeof arg1 === 'number') {\n delay = arg1;\n }\n \n return (...args) => new Promise((resolve, reject) => {\n setTimeout(() => {\n try {\n const result = callback ? callback(...args) : undefined;\n resolve(result);\n } catch (error) {\n reject(error);\n }\n }, delay);\n });\n}\n", "export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "import { invertChange } from \"@jucie-state/core/lib/change.js\";\nimport { defer } from \"@jucie-state/core/utils/defer.js\";\nimport { Plugin } from \"@jucie-state/core/Plugin\";\n\nclass Marker {\n constructor(description = '') {\n this.isMarker = true;\n this.description = description;\n }\n}\n\nexport class HistoryManager extends Plugin {\n static name = 'history';\n static options = {\n maxSize: 100\n };\n\n #changes = [];\n #started = false;\n #commitListeners = new Set();\n #cursor = 0;\n #batchDepth = 0;\n #pendingChanges = new Map();\n #isRecording = true;\n #commitScheduled = false;\n onUndoRedo = null;\n\n initialize(state) {\n this.onUndoRedo = (changes) => state.apply(changes);\n }\n\n #start() {\n // Reset history and set baseline at current state\n this.#changes = [new Marker('History Start')];\n this.#cursor = 0;\n this.#started = true;\n this.#pendingChanges.clear();\n this.#batchDepth = 0;\n this.#commitScheduled = false;\n }\n\n actions (state) {\n return {\n undo: (cb) => this.undo(cb),\n redo: (cb) => this.redo(cb),\n canUndo: () => this.canUndo(),\n canRedo: () => this.canRedo(),\n batch: () => this.batch(),\n commit: () => this.commit(),\n onCommit: (callback) => this.onCommit(callback),\n addMarker: (description) => this.addMarker(description),\n size: () => this.size(),\n start: () => this.#start()\n }\n }\n\n #deferredCommit = defer(() => {\n this.#commitPendingChanges();\n this.#commitScheduled = false;\n });\n\n onStateChange(marker, change, batching) {\n // Ignore all changes if history hasn't been started yet\n if (!this.#started) return;\n if (!this.#isRecording || change.method === 'apply') return;\n \n const existingChange = this.#pendingChanges.get(marker.address);\n const recordedChange = existingChange \n ? { ...change, from: existingChange.from } // Need to preserve original 'from'\n : change; // Can use original object directly\n this.#pendingChanges.set(marker.address, recordedChange);\n\n if (!batching && this.#batchDepth === 0) {\n this.#scheduleCommit();\n }\n }\n\n addMarker(description = '') {\n this.#commitPendingChanges(description);\n this.#cursor = this.#changes.length - 1;\n }\n\n undo = defer((cb) => {\n if (!this.onUndoRedo) {\n throw new Error('Undo/redo handler is required for undo operation');\n }\n\n this.#commitPendingChanges();\n\n // We should always have at least the initial marker\n if (this.#cursor <= 0) return false;\n this.#isRecording = false;\n \n // We should be at a marker\n if (!(this.#changes[this.#cursor] instanceof Marker)) {\n console.warn('Expected to be at a marker for undo operation');\n return false;\n }\n \n const changesToUndo = new Set();\n let tempCursor = this.#cursor - 1; // Don't modify the actual cursor yet\n \n // Collect changes until we hit the next marker\n while (tempCursor > 0) { // Changed from >= 0 to > 0 to preserve initial marker\n const changeEntry = this.#changes[tempCursor];\n \n if (changeEntry instanceof Marker) {\n break;\n }\n \n changesToUndo.add(invertChange(changeEntry));\n tempCursor--;\n }\n \n // Only update cursor after successfully collecting changes\n this.#cursor = tempCursor;\n \n // Apply the changes (already in correct order)\n this.onUndoRedo(Array.from(changesToUndo));\n \n if (cb && typeof cb === 'function') {\n cb();\n }\n\n this.#isRecording = true;\n return true;\n });\n\n redo = defer((cb) => {\n if (!this.onUndoRedo) {\n throw new Error('Undo/redo handler is required for redo operation');\n }\n\n if (this.#cursor >= this.#changes.length - 1) return false;\n this.#isRecording = false;\n \n // We should be at a marker\n if (!(this.#changes[this.#cursor] instanceof Marker)) {\n console.warn('Expected to be at a marker for redo operation');\n return false;\n }\n \n const changesToRedo = new Set();\n this.#cursor++; // Move past current marker\n \n // Collect changes until we hit the next marker\n while (this.#cursor < this.#changes.length) {\n const change = this.#changes[this.#cursor];\n \n if (change instanceof Marker) {\n break;\n }\n \n changesToRedo.add(change);\n this.#cursor++;\n }\n\n // Apply the changes in original order\n this.onUndoRedo(changesToRedo);\n \n if (cb && typeof cb === 'function') {\n cb();\n }\n\n this.#isRecording = true;\n return true;\n });\n\n canUndo() {\n return this.#cursor > 0;\n }\n\n canRedo() {\n return this.#cursor < this.#changes.length - 1;\n }\n\n size() {\n return this.#changes.length;\n }\n\n\n batch() {\n this.#batchDepth++;\n\n return () => {\n this.#batchDepth--;\n };\n }\n\n commit() {\n this.#batchDepth = this.#batchDepth - 1 < 0 ? 0 : this.#batchDepth - 1;\n\n if (this.#batchDepth === 0) {\n this.#commitPendingChanges();\n }\n \n return this;\n }\n\n pause() {\n this.#isRecording = false;\n }\n\n resume() {\n this.#isRecording = true;\n }\n\n onCommit(callback) {\n this.#commitListeners.add(callback);\n\n return () => {\n this.#commitListeners.delete(callback);\n };\n }\n\n reset() {\n this.#changes = [new Marker('History Start')];\n this.#commitListeners = new Set();\n this.#cursor = 0;\n this.#batchDepth = 0;\n this.#pendingChanges = new Map();\n this.#isRecording = true;\n this.#commitScheduled = false;\n this.#started = false;\n this.onUndoRedo = null;\n }\n\n #scheduleCommit() {\n if (!this.#commitScheduled) {\n this.#commitScheduled = true;\n this.#deferredCommit();\n }\n }\n\n #commitPendingChanges(description = '') {\n if (this.#pendingChanges.size === 0) return;\n\n // Truncate future changes if we're not at the end\n if (this.#cursor < this.#changes.length - 1) {\n this.#changes.splice(this.#cursor + 1);\n }\n\n // Add all pending changes individually\n const changes = Array.from(this.#pendingChanges.values());\n this.#changes.push(...changes);\n\n // Notify listeners\n this.#commitListeners.forEach(listener => listener(changes));\n \n // Add a marker automatically after the changes, but only if the last item isn't already a marker\n const lastItem = this.#changes[this.#changes.length - 1];\n \n if (!(lastItem instanceof Marker)) {\n this.#changes.push(new Marker(description || Date.now().toString()));\n }\n\n // Ensure the changes do not exceed maxSize\n while (this.#changes.length > this.options.maxSize) {\n this.#changes.shift(); // Remove the oldest change\n }\n\n // Clear pending changes\n this.#pendingChanges.clear();\n\n // Update current index\n this.#cursor = this.#changes.length - 1;\n }\n}\n"],
3
+ "sources": ["../../src/lib/TOKENS.js", "../../src/lib/change.js", "../../src/utils/defer.js", "../../src/Plugin.js", "../../plugins/history/src/HistoryManager.js"],
4
+ "sourcesContent": ["export const GLOBAL_TAG = '*';\nexport const STATE_CONTEXT = Symbol('STATE_CONTEXT');\nexport const MATCHER = Symbol('MATCHER');\nexport const CREATED = 'CREATED';\nexport const DELETED = 'DELETED';\nexport const UPDATED = 'UPDATED';\n\n// Marker type bitflags\nexport const MARKER_GLOBAL = 1; // 0b001\nexport const MARKER_SINGLE = 2; // 0b010\nexport const MARKER_MANY = 4; // 0b100\nexport const MARKER_EPHEMERAL = 8; // 0b1000\n\n// Comparison result constants\nexport const MATCH_EXACT = 0; // Markers are identical\nexport const MATCH_PARENT = 1; // controlMarker is child of comparedMarker (parent changed)\nexport const MATCH_CHILD = 2; // comparedMarker is child of controlMarker (child changed)\nexport const MATCH_NONE = -1; // No relationship", "import { GLOBAL_TAG, CREATED, DELETED, UPDATED } from './TOKENS.js';\nimport { dispatch } from './marker.js';\n\nexport const OPERATION_INVERSES = {\n [CREATED]: DELETED,\n [DELETED]: CREATED,\n [UPDATED]: UPDATED,\n}\n\n/**\n * Determines the operation type based on from/to values\n * \n * @private\n * @param {*} from - Previous value\n * @param {*} to - New value\n * @returns {'created'|'deleted'|'updated'} Operation type\n */\nfunction determineOperation(to, from) {\n if (from === undefined) return CREATED;\n if (to === undefined) return DELETED;\n return UPDATED;\n}\n\n/**\n * Creates a change object with the given parameters\n * \n * @param {string} method - Method that triggered the change\n * @param {*} from - Previous value\n * @param {*} to - New value\n * @returns {Object} Change object\n * @example\n * createChange('set', undefined, 'new value') \n * // => { method: 'set', operation: 'created', from: undefined, to: 'new value' }\n */\nexport function createChange(marker, method, to, from) {\n return dispatch(marker, {\n global: () => ({\n path: GLOBAL_TAG,\n method,\n operation: determineOperation(to, from),\n from,\n to\n }),\n path: (marker) => ({\n path: marker.path,\n method,\n operation: determineOperation(to, from),\n from,\n to\n }),\n });\n}\n\n/**\n * Inverts a change object for undo operations\n * \n * @param {Object} change - Change object to invert\n * @param {string} change.method - Original method\n * @param {string} change.operation - Original operation\n * @param {*} change.from - Original from value\n * @param {*} change.to - Original to value\n * @returns {Object} Inverted change object\n * @example\n * invertChange({ method: 'set', operation: 'created', from: undefined, to: 'value' })\n * // => { method: 'set', operation: 'deleted', from: 'value', to: undefined }\n */\nexport function invertChange(change) {\n const {address, path, method, from, to, operation } = change;\n return {\n address,\n path,\n method,\n to: from,\n from: to,\n operation: invertOperation(operation),\n }\n}\n\nexport function invertOperation(operation) {\n return OPERATION_INVERSES[operation];\n}\n\n/**\n * Checks if a change needs to be inverted based on the method\n * \n * @param {string} method - Method to check\n * @returns {boolean} True if the change should be inverted\n * @example\n * shouldInvertChange('undo') // => true\n * shouldInvertChange('set') // => false\n */\nexport function shouldInvertChange(method) {\n return ['undo', 'redo', 'stepBackward', 'stepForward'].includes(method);\n}", "export function defer(arg1, arg2) {\n let callback = null;\n let delay = 0;\n\n if (typeof arg1 === 'function') {\n callback = arg1;\n if (typeof arg2 === 'number') {\n delay = arg2;\n }\n } else if (typeof arg1 === 'number') {\n delay = arg1;\n }\n \n return (...args) => new Promise((resolve, reject) => {\n setTimeout(() => {\n try {\n const result = callback ? callback(...args) : undefined;\n resolve(result);\n } catch (error) {\n reject(error);\n }\n }, delay);\n });\n}\n", "export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "import { invertChange } from \"../../../src/lib/change.js\";\nimport { defer } from \"../../../src/utils/defer.js\";\nimport { Plugin } from \"../../../src/Plugin.js\";\n\nclass Marker {\n constructor(description = '') {\n this.isMarker = true;\n this.description = description;\n }\n}\n\nexport class HistoryManager extends Plugin {\n static name = 'history';\n static options = {\n maxSize: 100\n };\n\n #changes = [];\n #started = false;\n #commitListeners = new Set();\n #cursor = 0;\n #batchDepth = 0;\n #pendingChanges = new Map();\n #isRecording = true;\n #commitScheduled = false;\n onUndoRedo = null;\n\n initialize(state) {\n this.onUndoRedo = (changes) => state.apply(changes);\n }\n\n #start() {\n // Reset history and set baseline at current state\n this.#changes = [new Marker('History Start')];\n this.#cursor = 0;\n this.#started = true;\n this.#pendingChanges.clear();\n this.#batchDepth = 0;\n this.#commitScheduled = false;\n }\n\n actions (state) {\n return {\n undo: (cb) => this.undo(cb),\n redo: (cb) => this.redo(cb),\n canUndo: () => this.canUndo(),\n canRedo: () => this.canRedo(),\n batch: () => this.batch(),\n commit: () => this.commit(),\n onCommit: (callback) => this.onCommit(callback),\n addMarker: (description) => this.addMarker(description),\n size: () => this.size(),\n start: () => this.#start()\n }\n }\n\n #deferredCommit = defer(() => {\n this.#commitPendingChanges();\n this.#commitScheduled = false;\n });\n\n onStateChange(marker, change, batching) {\n // Ignore all changes if history hasn't been started yet\n if (!this.#started) return;\n if (!this.#isRecording || change.method === 'apply') return;\n \n const existingChange = this.#pendingChanges.get(marker.address);\n const recordedChange = existingChange \n ? { ...change, from: existingChange.from } // Need to preserve original 'from'\n : change; // Can use original object directly\n this.#pendingChanges.set(marker.address, recordedChange);\n\n if (!batching && this.#batchDepth === 0) {\n this.#scheduleCommit();\n }\n }\n\n addMarker(description = '') {\n this.#commitPendingChanges(description);\n this.#cursor = this.#changes.length - 1;\n }\n\n undo = defer((cb) => {\n if (!this.onUndoRedo) {\n throw new Error('Undo/redo handler is required for undo operation');\n }\n\n this.#commitPendingChanges();\n\n // We should always have at least the initial marker\n if (this.#cursor <= 0) return false;\n this.#isRecording = false;\n \n // We should be at a marker\n if (!(this.#changes[this.#cursor] instanceof Marker)) {\n console.warn('Expected to be at a marker for undo operation');\n return false;\n }\n \n const changesToUndo = new Set();\n let tempCursor = this.#cursor - 1; // Don't modify the actual cursor yet\n \n // Collect changes until we hit the next marker\n while (tempCursor > 0) { // Changed from >= 0 to > 0 to preserve initial marker\n const changeEntry = this.#changes[tempCursor];\n \n if (changeEntry instanceof Marker) {\n break;\n }\n \n changesToUndo.add(invertChange(changeEntry));\n tempCursor--;\n }\n \n // Only update cursor after successfully collecting changes\n this.#cursor = tempCursor;\n \n // Apply the changes (already in correct order)\n this.onUndoRedo(Array.from(changesToUndo));\n \n if (cb && typeof cb === 'function') {\n cb();\n }\n\n this.#isRecording = true;\n return true;\n });\n\n redo = defer((cb) => {\n if (!this.onUndoRedo) {\n throw new Error('Undo/redo handler is required for redo operation');\n }\n\n if (this.#cursor >= this.#changes.length - 1) return false;\n this.#isRecording = false;\n \n // We should be at a marker\n if (!(this.#changes[this.#cursor] instanceof Marker)) {\n console.warn('Expected to be at a marker for redo operation');\n return false;\n }\n \n const changesToRedo = new Set();\n this.#cursor++; // Move past current marker\n \n // Collect changes until we hit the next marker\n while (this.#cursor < this.#changes.length) {\n const change = this.#changes[this.#cursor];\n \n if (change instanceof Marker) {\n break;\n }\n \n changesToRedo.add(change);\n this.#cursor++;\n }\n\n // Apply the changes in original order\n this.onUndoRedo(changesToRedo);\n \n if (cb && typeof cb === 'function') {\n cb();\n }\n\n this.#isRecording = true;\n return true;\n });\n\n canUndo() {\n return this.#cursor > 0;\n }\n\n canRedo() {\n return this.#cursor < this.#changes.length - 1;\n }\n\n size() {\n return this.#changes.length;\n }\n\n\n batch() {\n this.#batchDepth++;\n\n return () => {\n this.#batchDepth--;\n };\n }\n\n commit() {\n this.#batchDepth = this.#batchDepth - 1 < 0 ? 0 : this.#batchDepth - 1;\n\n if (this.#batchDepth === 0) {\n this.#commitPendingChanges();\n }\n \n return this;\n }\n\n pause() {\n this.#isRecording = false;\n }\n\n resume() {\n this.#isRecording = true;\n }\n\n onCommit(callback) {\n this.#commitListeners.add(callback);\n\n return () => {\n this.#commitListeners.delete(callback);\n };\n }\n\n reset() {\n this.#changes = [new Marker('History Start')];\n this.#commitListeners = new Set();\n this.#cursor = 0;\n this.#batchDepth = 0;\n this.#pendingChanges = new Map();\n this.#isRecording = true;\n this.#commitScheduled = false;\n this.#started = false;\n this.onUndoRedo = null;\n }\n\n #scheduleCommit() {\n if (!this.#commitScheduled) {\n this.#commitScheduled = true;\n this.#deferredCommit();\n }\n }\n\n #commitPendingChanges(description = '') {\n if (this.#pendingChanges.size === 0) return;\n\n // Truncate future changes if we're not at the end\n if (this.#cursor < this.#changes.length - 1) {\n this.#changes.splice(this.#cursor + 1);\n }\n\n // Add all pending changes individually\n const changes = Array.from(this.#pendingChanges.values());\n this.#changes.push(...changes);\n\n // Notify listeners\n this.#commitListeners.forEach(listener => listener(changes));\n \n // Add a marker automatically after the changes, but only if the last item isn't already a marker\n const lastItem = this.#changes[this.#changes.length - 1];\n \n if (!(lastItem instanceof Marker)) {\n this.#changes.push(new Marker(description || Date.now().toString()));\n }\n\n // Ensure the changes do not exceed maxSize\n while (this.#changes.length > this.options.maxSize) {\n this.#changes.shift(); // Remove the oldest change\n }\n\n // Clear pending changes\n this.#pendingChanges.clear();\n\n // Update current index\n this.#cursor = this.#changes.length - 1;\n }\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": ["STATE_CONTEXT", "MATCHER", "CREATED", "DELETED", "UPDATED", "OPERATION_INVERSES", "CREATED", "DELETED", "UPDATED", "invertChange", "change", "address", "path", "method", "from", "to", "operation", "invertOperation", "OPERATION_INVERSES", "defer", "arg1", "arg2", "callback", "delay", "args", "resolve", "reject", "result", "error", "Plugin", "options", "state", "pluginInstance", "Marker", "description", "HistoryManager", "Plugin", "#changes", "#started", "#commitListeners", "#cursor", "#batchDepth", "#pendingChanges", "#isRecording", "#commitScheduled", "state", "changes", "#start", "cb", "callback", "#deferredCommit", "defer", "#commitPendingChanges", "marker", "change", "batching", "existingChange", "recordedChange", "#scheduleCommit", "changesToUndo", "tempCursor", "changeEntry", "invertChange", "changesToRedo", "listener"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../core/src/Plugin.js", "../../core/src/lib/TOKENS.js", "../../core/src/lib/pathEncoder.js", "../../core/src/lib/marker.js", "../../plugins/matcher/src/Matcher.js"],
4
- "sourcesContent": ["export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "export const GLOBAL_TAG = '*';\nexport const STATE_CONTEXT = Symbol('STATE_CONTEXT');\nexport const MATCHER = Symbol('MATCHER');\nexport const CREATED = 'CREATED';\nexport const DELETED = 'DELETED';\nexport const UPDATED = 'UPDATED';\n\n// Marker type bitflags\nexport const MARKER_GLOBAL = 1; // 0b001\nexport const MARKER_SINGLE = 2; // 0b010\nexport const MARKER_MANY = 4; // 0b100\nexport const MARKER_EPHEMERAL = 8; // 0b1000\n\n// Comparison result constants\nexport const MATCH_EXACT = 0; // Markers are identical\nexport const MATCH_PARENT = 1; // controlMarker is child of comparedMarker (parent changed)\nexport const MATCH_CHILD = 2; // comparedMarker is child of controlMarker (child changed)\nexport const MATCH_NONE = -1; // No relationship", "import { GLOBAL_TAG } from './TOKENS.js';\n\n// Fast helpers\nfunction escapeStr(str) {\n // Order matters: escape ~ first, then .\n let out = \"\";\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"~\") out += \"~~\";\n else if (ch === \".\") out += \"~d\";\n else out += ch;\n }\n // Represent empty strings as ~e to avoid trailing-dot filenames\n return out.length === 0 ? \"~e\" : out;\n}\n\nfunction unescapeStr(str) {\n let out = \"\";\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"~\") {\n const next = str[++i];\n if (next === \"~\") out += \"~\";\n else if (next === \"d\") out += \".\";\n else if (next === \"e\") out += \"\"; // empty string marker\n else {\n // Unknown escape: treat as literal (robustness)\n out += \"~\" + (next ?? \"\");\n }\n } else {\n out += ch;\n }\n }\n return out;\n}\n\nexport function encodePath(segments) {\n // segments: array of strings or integers\n // Produces: filename/URL-safe string like \"sfoo.n0.sbaz\"\n const parts = new Array(segments.length);\n for (let i = 0; i < segments.length; i++) {\n const v = segments[i];\n if (typeof v === \"number\" && Number.isInteger(v)) {\n // 'n' tag\n parts[i] = \"n\" + String(v); // decimal; includes \"-\" if negative\n } else if (typeof v === \"string\") {\n // 's' tag\n parts[i] = \"s\" + escapeStr(v);\n } else {\n // If you need more types, add here (e.g., booleans 'b', floats 'f').\n throw new TypeError(`Unsupported segment type at index ${i}: ${v}`);\n }\n }\n // Use '.' as separator (safe in URLs and filenames; we avoid trailing '.')\n return parts.join(\".\");\n}\n\nexport function decodeAddress(address) {\n if (address === GLOBAL_TAG) return GLOBAL_TAG;\n if (address.length === 0) return [];\n const raw = address.split(\".\");\n const out = new Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n const token = raw[i];\n if (token.length === 0) {\n // Disallow empty tokens (would imply trailing or double dots)\n throw new Error(\"Invalid address: empty token\");\n }\n const tag = token[0];\n const body = token.slice(1);\n if (tag === \"n\") {\n // Fast parse (no regex)\n if (body.length === 0 || !/^[-]?\\d+$/.test(body)) {\n throw new Error(`Invalid numeric token: \"${token}\"`);\n }\n const num = Number(body);\n // Ensure it was an integer\n if (!Number.isInteger(num)) {\n throw new Error(`Non-integer numeric token: \"${token}\"`);\n }\n out[i] = num;\n } else if (tag === \"s\") {\n out[i] = unescapeStr(body);\n } else {\n throw new Error(`Unknown type tag \"${tag}\" in token \"${token}\"`);\n }\n }\n return out;\n}\n", "import { encodePath } from './pathEncoder.js';\nimport { GLOBAL_TAG } from './TOKENS.js';\nimport {\n MARKER_GLOBAL,\n MARKER_SINGLE,\n MARKER_MANY,\n MARKER_EPHEMERAL,\n MATCH_EXACT,\n MATCH_PARENT,\n MATCH_CHILD,\n MATCH_NONE \n} from './TOKENS.js';\n\n// Marker type bitflags\n\n// Helper functions to check marker type\nexport function isGlobalMarker(marker) {\n return (marker.type & MARKER_GLOBAL) === MARKER_GLOBAL;\n}\n\nexport function isPathMarker(marker) {\n return (marker.type & MARKER_SINGLE) === MARKER_SINGLE;\n}\n\nexport function isMarkers(marker) {\n return (marker.type & MARKER_MANY) === MARKER_MANY;\n}\n\nexport function isEphemeralMarker(marker) {\n return (marker.type & MARKER_EPHEMERAL) === MARKER_EPHEMERAL;\n}\n\nexport function isGlobalPath(path) {\n return !path || path.length === 0 || path === GLOBAL_TAG || path[0] === GLOBAL_TAG;\n}\n\nexport function normalizePaths(args = []) { \n const len = args.length;\n if (len === 0) return [0, [] ];\n if (len === 1 && args[0] === GLOBAL_TAG) return [0, [] ];\n \n if (Array.isArray(args[0])) {\n return len === 1 \n ? [1, [args[0]] ]\n : [len, args ];\n }\n \n return [1, [[...args]] ];\n}\n\nfunction pathHasEphemeral(path) {\n if (!Array.isArray(path)) {\n return false;\n }\n\n for (let i = 0; i < path.length; i++) {\n const segment = path[i];\n if (typeof segment === 'string' && segment.charCodeAt(0) === 46) { // '.'\n return true;\n }\n }\n\n return false;\n}\n\n// Marker factory\nexport function createMarker(paths = []) {\n if (isGlobalPath(paths)) {\n return {\n address: GLOBAL_TAG,\n isMarker: true,\n length: 0,\n path: [],\n children: null,\n type: MARKER_GLOBAL\n };\n }\n \n const [length, normalizedPaths] = normalizePaths(paths);\n const type = length === 1 ? MARKER_SINGLE : MARKER_MANY;\n const path = length === 1 ? normalizedPaths[0] : normalizedPaths;\n const children = length > 1 ? normalizedPaths.map(path => createMarker(path)) : null;\n const isEphemeral = type === MARKER_SINGLE\n ? pathHasEphemeral(path)\n : children.some(child => isEphemeralMarker(child));\n\n let markerType = type;\n if (isEphemeral) {\n markerType |= MARKER_EPHEMERAL;\n }\n\n return {\n address: type === MARKER_SINGLE ? encodePath(path) : null,\n isMarker: true,\n length,\n path,\n children,\n type: markerType\n };\n}\n\nexport function createChildMarker(parentMarker, childPaths) {\n if (childPaths.length === 0) {\n return parentMarker;\n }\n // Normalize the child paths\n const [childLength, normalizedChildPaths] = normalizePaths(childPaths);\n \n // Handle global marker - just return marker with child paths\n if (isGlobalMarker(parentMarker)) {\n return createMarker(normalizedChildPaths, parentMarker.state);\n }\n \n // Handle single path marker\n if (isPathMarker(parentMarker)) {\n if (childLength === 0) {\n // No child paths, return parent as-is\n return parentMarker;\n }\n \n if (childLength === 1) {\n // Single child path - append to parent path\n const newPath = [...parentMarker.path, ...normalizedChildPaths[0]];\n return createMarker(newPath, parentMarker.state);\n } else {\n // Multiple child paths - create many markers\n const newPaths = normalizedChildPaths.map(childPath => \n [...parentMarker.path, ...childPath]\n );\n return createMarker(newPaths, parentMarker.state);\n }\n }\n \n // Handle many markers - recursively create child markers for each\n if (isMarkers(parentMarker)) {\n const newMarkers = new Array(parentMarker.length);\n let i = 0;\n while (i < parentMarker.length) {\n newMarkers[i] = createChildMarker(parentMarker.children[i], childPaths);\n i++;\n }\n \n // Collect all paths from the new markers\n const allPaths = [];\n i = 0;\n while (i < newMarkers.length) {\n const marker = newMarkers[i];\n if (isPathMarker(marker)) {\n allPaths.push(marker.path);\n } else if (isMarkers(marker)) {\n let j = 0;\n while (j < marker.length) {\n allPaths.push(marker.children[j].path);\n j++;\n }\n }\n i++;\n }\n \n return createMarker(allPaths, parentMarker.state);\n }\n \n // Fallback - shouldn't reach here\n return parentMarker;\n}\n\nexport function dispatch(marker, { global, path, ephemeral, error }) {\n try {\n if (!marker.isMarker) return undefined;\n if (isGlobalMarker(marker)) return global ? global(marker) : undefined;\n if (isEphemeralMarker(marker)) return ephemeral ? ephemeral(marker) : path ? path(marker) : undefined;\n if (isPathMarker(marker)) return path ? path(marker) : undefined;\n if (isMarkers(marker)) {\n const results = new Array(marker.length);\n let i = 0;\n while (i < marker.length) {\n const nestedMarker = marker.children[i];\n results[i] = dispatch(nestedMarker, { global, path, ephemeral, error });\n i++;\n }\n return results;\n }\n \n return undefined;\n } catch (err) {\n return error ? error(err.message) : undefined;\n }\n}\n\nexport function compareMarkers(controlMarker, comparedMarker) {\n // Both are global markers or exact address match\n if (isGlobalMarker(controlMarker) && isGlobalMarker(comparedMarker)) {\n return MATCH_EXACT;\n }\n\n // If comparedMarker is global, it's always a parent\n if (isGlobalMarker(comparedMarker)) {\n return MATCH_PARENT;\n }\n \n // Need addresses to compare\n if (!controlMarker.address || !comparedMarker.address) {\n return MATCH_NONE;\n }\n \n // Exact match\n if (controlMarker.address === comparedMarker.address) {\n return MATCH_EXACT;\n }\n \n // controlMarker is more nested (child) - parent changed\n if (controlMarker.address.startsWith(comparedMarker.address + '.')) {\n return MATCH_PARENT;\n }\n \n // comparedMarker is more nested (child) - child changed\n if (comparedMarker.address.startsWith(controlMarker.address + '.')) {\n return MATCH_CHILD;\n }\n \n return MATCH_NONE;\n}\n\nexport const Marker = {\n compare: compareMarkers,\n create: createMarker,\n createChild: createChildMarker,\n dispatch: dispatch,\n isGlobal: isGlobalMarker,\n isSingle: isPathMarker,\n isMarkers: isMarkers,\n isEphemeral: isEphemeralMarker\n};", "import { Plugin } from '@jucie-state/core/Plugin';\nimport { compareMarkers, createMarker, dispatch } from '@jucie-state/core/lib/marker.js';\nimport { MATCHER } from '@jucie-state/core/lib/TOKENS.js';\n\nimport { MATCH_CHILD, MATCH_PARENT, MATCH_EXACT, MATCH_NONE } from '@jucie-state/core/lib/TOKENS.js';\n\nexport class Matcher extends Plugin {\n static name = 'matcher';\n static options = {\n matchers: [],\n };\n \n #matchers = new Set();\n \n initialize(state, config) {\n if (config.matchers && config.matchers.length > 0) {\n for (const matcher of config.matchers) {\n if (typeof matcher === 'function' && matcher._isMatcher === MATCHER) {\n this.#assignMatcherState(matcher);\n this.#addMatcher(matcher);\n } else {\n if (!matcher.path || !matcher.handler) {\n throw new Error('Matcher path and handler are required');\n }\n this.#addMatcher(createMatcher(matcher.path, matcher.handler));\n }\n }\n }\n }\n\n actions () {\n return {\n createMatcher: (path, handler) => {\n const matcher = createMatcher(path, handler);\n this.#assignMatcherState(matcher);\n this.#addMatcher(matcher);\n return () => this.#removeMatcher(matcher);\n },\n addMatcher: (matcher) => this.#addMatcher(matcher),\n removeMatcher: (matcher) => this.#removeMatcher(matcher),\n }\n }\n\n #assignMatcherState(matcher) {\n Object.defineProperty(matcher, '_state', {\n value: this.state,\n writable: false,\n configurable: false\n });\n }\n\n #addMatcher(matcher) {\n this.#assignMatcherState(matcher);\n this.#matchers.add(matcher);\n return () => this.#removeMatcher(matcher);\n }\n\n #removeMatcher(matcher) {\n this.#matchers.delete(matcher);\n }\n\n onStateChange(marker, change) {\n this.#matchers.forEach(matcher => matcher(marker, change));\n }\n}\n\nexport function createMatcher(matchPath, fn) {\n if (!Array.isArray(matchPath)) {\n throw new Error('matchPath must be an array');\n }\n\n if (matchPath.length === 0) {\n throw new Error('matchPath must be a non-empty array');\n }\n\n if (fn === undefined || typeof fn !== 'function') {\n throw new Error('Matcher function is required');\n }\n\n const changeQueue = new Map();\n let isFlushing = false;\n\n const matchMarker = createMarker(matchPath);\n const matcher = (marker) => {\n if (compareMarkers(matchMarker, marker) >= 0) {\n queueChange(marker);\n };\n }\n\n function flushChanges() {\n if (isFlushing) return;\n isFlushing = true;\n setTimeout(() => {\n const markers = Array.from(changeQueue.values());\n let changes = {};\n let hasChanges = false;\n for (const marker of markers) {\n dispatch(marker, {\n global: () => {\n changes = matcher._state.get(matchPath);\n hasChanges = true;\n },\n path: () => {\n const comp = compareMarkers(matchMarker, marker);\n \n switch (comp) {\n case MATCH_PARENT:\n case MATCH_EXACT:\n changes = matcher._state.get(matchPath);\n hasChanges = true;\n break;\n case MATCH_CHILD:\n const childPath = marker.path.slice(0, matchPath.length + 1);\n const key = childPath[childPath.length - 1];\n changes = typeof changes === 'object' && changes !== null ? changes : {};\n changes[key] = matcher._state.get(childPath);\n hasChanges = true;\n break;\n }\n },\n });\n }\n\n if (hasChanges) {\n fn(changes);\n }\n changeQueue.clear();\n isFlushing = false;\n }, 0);\n }\n\n function queueChange(marker) {\n if (changeQueue.has(marker.address)) {\n changeQueue.delete(marker.address);\n }\n changeQueue.set(marker.address, marker);\n flushChanges();\n }\n\n Object.defineProperty(matcher, '_isMatcher', {\n value: MATCHER,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n\n return matcher;\n}"],
3
+ "sources": ["../../src/Plugin.js", "../../src/lib/TOKENS.js", "../../src/lib/pathEncoder.js", "../../src/lib/marker.js", "../../plugins/matcher/src/Matcher.js"],
4
+ "sourcesContent": ["export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "export const GLOBAL_TAG = '*';\nexport const STATE_CONTEXT = Symbol('STATE_CONTEXT');\nexport const MATCHER = Symbol('MATCHER');\nexport const CREATED = 'CREATED';\nexport const DELETED = 'DELETED';\nexport const UPDATED = 'UPDATED';\n\n// Marker type bitflags\nexport const MARKER_GLOBAL = 1; // 0b001\nexport const MARKER_SINGLE = 2; // 0b010\nexport const MARKER_MANY = 4; // 0b100\nexport const MARKER_EPHEMERAL = 8; // 0b1000\n\n// Comparison result constants\nexport const MATCH_EXACT = 0; // Markers are identical\nexport const MATCH_PARENT = 1; // controlMarker is child of comparedMarker (parent changed)\nexport const MATCH_CHILD = 2; // comparedMarker is child of controlMarker (child changed)\nexport const MATCH_NONE = -1; // No relationship", "import { GLOBAL_TAG } from './TOKENS.js';\n\n// Fast helpers\nfunction escapeStr(str) {\n // Order matters: escape ~ first, then .\n let out = \"\";\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"~\") out += \"~~\";\n else if (ch === \".\") out += \"~d\";\n else out += ch;\n }\n // Represent empty strings as ~e to avoid trailing-dot filenames\n return out.length === 0 ? \"~e\" : out;\n}\n\nfunction unescapeStr(str) {\n let out = \"\";\n for (let i = 0; i < str.length; i++) {\n const ch = str[i];\n if (ch === \"~\") {\n const next = str[++i];\n if (next === \"~\") out += \"~\";\n else if (next === \"d\") out += \".\";\n else if (next === \"e\") out += \"\"; // empty string marker\n else {\n // Unknown escape: treat as literal (robustness)\n out += \"~\" + (next ?? \"\");\n }\n } else {\n out += ch;\n }\n }\n return out;\n}\n\nexport function encodePath(segments) {\n // segments: array of strings or integers\n // Produces: filename/URL-safe string like \"sfoo.n0.sbaz\"\n const parts = new Array(segments.length);\n for (let i = 0; i < segments.length; i++) {\n const v = segments[i];\n if (typeof v === \"number\" && Number.isInteger(v)) {\n // 'n' tag\n parts[i] = \"n\" + String(v); // decimal; includes \"-\" if negative\n } else if (typeof v === \"string\") {\n // 's' tag\n parts[i] = \"s\" + escapeStr(v);\n } else {\n // If you need more types, add here (e.g., booleans 'b', floats 'f').\n throw new TypeError(`Unsupported segment type at index ${i}: ${v}`);\n }\n }\n // Use '.' as separator (safe in URLs and filenames; we avoid trailing '.')\n return parts.join(\".\");\n}\n\nexport function decodeAddress(address) {\n if (address === GLOBAL_TAG) return GLOBAL_TAG;\n if (address.length === 0) return [];\n const raw = address.split(\".\");\n const out = new Array(raw.length);\n for (let i = 0; i < raw.length; i++) {\n const token = raw[i];\n if (token.length === 0) {\n // Disallow empty tokens (would imply trailing or double dots)\n throw new Error(\"Invalid address: empty token\");\n }\n const tag = token[0];\n const body = token.slice(1);\n if (tag === \"n\") {\n // Fast parse (no regex)\n if (body.length === 0 || !/^[-]?\\d+$/.test(body)) {\n throw new Error(`Invalid numeric token: \"${token}\"`);\n }\n const num = Number(body);\n // Ensure it was an integer\n if (!Number.isInteger(num)) {\n throw new Error(`Non-integer numeric token: \"${token}\"`);\n }\n out[i] = num;\n } else if (tag === \"s\") {\n out[i] = unescapeStr(body);\n } else {\n throw new Error(`Unknown type tag \"${tag}\" in token \"${token}\"`);\n }\n }\n return out;\n}\n", "import { encodePath } from './pathEncoder.js';\nimport { GLOBAL_TAG } from './TOKENS.js';\nimport {\n MARKER_GLOBAL,\n MARKER_SINGLE,\n MARKER_MANY,\n MARKER_EPHEMERAL,\n MATCH_EXACT,\n MATCH_PARENT,\n MATCH_CHILD,\n MATCH_NONE \n} from './TOKENS.js';\n\n// Marker type bitflags\n\n// Helper functions to check marker type\nexport function isGlobalMarker(marker) {\n return (marker.type & MARKER_GLOBAL) === MARKER_GLOBAL;\n}\n\nexport function isPathMarker(marker) {\n return (marker.type & MARKER_SINGLE) === MARKER_SINGLE;\n}\n\nexport function isMarkers(marker) {\n return (marker.type & MARKER_MANY) === MARKER_MANY;\n}\n\nexport function isEphemeralMarker(marker) {\n return (marker.type & MARKER_EPHEMERAL) === MARKER_EPHEMERAL;\n}\n\nexport function isGlobalPath(path) {\n return !path || path.length === 0 || path === GLOBAL_TAG || path[0] === GLOBAL_TAG;\n}\n\nexport function normalizePaths(args = []) { \n const len = args.length;\n if (len === 0) return [0, [] ];\n if (len === 1 && args[0] === GLOBAL_TAG) return [0, [] ];\n \n if (Array.isArray(args[0])) {\n return len === 1 \n ? [1, [args[0]] ]\n : [len, args ];\n }\n \n return [1, [[...args]] ];\n}\n\nfunction pathHasEphemeral(path) {\n if (!Array.isArray(path)) {\n return false;\n }\n\n for (let i = 0; i < path.length; i++) {\n const segment = path[i];\n if (typeof segment === 'string' && segment.charCodeAt(0) === 46) { // '.'\n return true;\n }\n }\n\n return false;\n}\n\n// Marker factory\nexport function createMarker(paths = []) {\n if (isGlobalPath(paths)) {\n return {\n address: GLOBAL_TAG,\n isMarker: true,\n length: 0,\n path: [],\n children: null,\n type: MARKER_GLOBAL\n };\n }\n \n const [length, normalizedPaths] = normalizePaths(paths);\n const type = length === 1 ? MARKER_SINGLE : MARKER_MANY;\n const path = length === 1 ? normalizedPaths[0] : normalizedPaths;\n const children = length > 1 ? normalizedPaths.map(path => createMarker(path)) : null;\n const isEphemeral = type === MARKER_SINGLE\n ? pathHasEphemeral(path)\n : children.some(child => isEphemeralMarker(child));\n\n let markerType = type;\n if (isEphemeral) {\n markerType |= MARKER_EPHEMERAL;\n }\n\n return {\n address: type === MARKER_SINGLE ? encodePath(path) : null,\n isMarker: true,\n length,\n path,\n children,\n type: markerType\n };\n}\n\nexport function createChildMarker(parentMarker, childPaths) {\n if (childPaths.length === 0) {\n return parentMarker;\n }\n // Normalize the child paths\n const [childLength, normalizedChildPaths] = normalizePaths(childPaths);\n \n // Handle global marker - just return marker with child paths\n if (isGlobalMarker(parentMarker)) {\n return createMarker(normalizedChildPaths, parentMarker.state);\n }\n \n // Handle single path marker\n if (isPathMarker(parentMarker)) {\n if (childLength === 0) {\n // No child paths, return parent as-is\n return parentMarker;\n }\n \n if (childLength === 1) {\n // Single child path - append to parent path\n const newPath = [...parentMarker.path, ...normalizedChildPaths[0]];\n return createMarker(newPath, parentMarker.state);\n } else {\n // Multiple child paths - create many markers\n const newPaths = normalizedChildPaths.map(childPath => \n [...parentMarker.path, ...childPath]\n );\n return createMarker(newPaths, parentMarker.state);\n }\n }\n \n // Handle many markers - recursively create child markers for each\n if (isMarkers(parentMarker)) {\n const newMarkers = new Array(parentMarker.length);\n let i = 0;\n while (i < parentMarker.length) {\n newMarkers[i] = createChildMarker(parentMarker.children[i], childPaths);\n i++;\n }\n \n // Collect all paths from the new markers\n const allPaths = [];\n i = 0;\n while (i < newMarkers.length) {\n const marker = newMarkers[i];\n if (isPathMarker(marker)) {\n allPaths.push(marker.path);\n } else if (isMarkers(marker)) {\n let j = 0;\n while (j < marker.length) {\n allPaths.push(marker.children[j].path);\n j++;\n }\n }\n i++;\n }\n \n return createMarker(allPaths, parentMarker.state);\n }\n \n // Fallback - shouldn't reach here\n return parentMarker;\n}\n\nexport function dispatch(marker, { global, path, ephemeral, error }) {\n try {\n if (!marker.isMarker) return undefined;\n if (isGlobalMarker(marker)) return global ? global(marker) : undefined;\n if (isEphemeralMarker(marker)) return ephemeral ? ephemeral(marker) : path ? path(marker) : undefined;\n if (isPathMarker(marker)) return path ? path(marker) : undefined;\n if (isMarkers(marker)) {\n const results = new Array(marker.length);\n let i = 0;\n while (i < marker.length) {\n const nestedMarker = marker.children[i];\n results[i] = dispatch(nestedMarker, { global, path, ephemeral, error });\n i++;\n }\n return results;\n }\n \n return undefined;\n } catch (err) {\n return error ? error(err.message) : undefined;\n }\n}\n\nexport function compareMarkers(controlMarker, comparedMarker) {\n // Both are global markers or exact address match\n if (isGlobalMarker(controlMarker) && isGlobalMarker(comparedMarker)) {\n return MATCH_EXACT;\n }\n\n // If comparedMarker is global, it's always a parent\n if (isGlobalMarker(comparedMarker)) {\n return MATCH_PARENT;\n }\n \n // Need addresses to compare\n if (!controlMarker.address || !comparedMarker.address) {\n return MATCH_NONE;\n }\n \n // Exact match\n if (controlMarker.address === comparedMarker.address) {\n return MATCH_EXACT;\n }\n \n // controlMarker is more nested (child) - parent changed\n if (controlMarker.address.startsWith(comparedMarker.address + '.')) {\n return MATCH_PARENT;\n }\n \n // comparedMarker is more nested (child) - child changed\n if (comparedMarker.address.startsWith(controlMarker.address + '.')) {\n return MATCH_CHILD;\n }\n \n return MATCH_NONE;\n}\n\nexport const Marker = {\n compare: compareMarkers,\n create: createMarker,\n createChild: createChildMarker,\n dispatch: dispatch,\n isGlobal: isGlobalMarker,\n isSingle: isPathMarker,\n isMarkers: isMarkers,\n isEphemeral: isEphemeralMarker\n};", "import { Plugin } from '@jucie.io/state/Plugin';\nimport { compareMarkers, createMarker, dispatch } from '@jucie.io/state/lib/marker.js';\nimport { MATCHER } from '@jucie.io/state/lib/TOKENS.js';\n\nimport { MATCH_CHILD, MATCH_PARENT, MATCH_EXACT, MATCH_NONE } from '@jucie.io/state/lib/TOKENS.js';\n\nexport class Matcher extends Plugin {\n static name = 'matcher';\n static options = {\n matchers: [],\n };\n \n #matchers = new Set();\n \n initialize(state, config) {\n if (config.matchers && config.matchers.length > 0) {\n for (const matcher of config.matchers) {\n if (typeof matcher === 'function' && matcher._isMatcher === MATCHER) {\n this.#assignMatcherState(matcher);\n this.#addMatcher(matcher);\n } else {\n if (!matcher.path || !matcher.handler) {\n throw new Error('Matcher path and handler are required');\n }\n this.#addMatcher(createMatcher(matcher.path, matcher.handler));\n }\n }\n }\n }\n\n actions () {\n return {\n createMatcher: (path, handler) => {\n const matcher = createMatcher(path, handler);\n this.#assignMatcherState(matcher);\n this.#addMatcher(matcher);\n return () => this.#removeMatcher(matcher);\n },\n addMatcher: (matcher) => this.#addMatcher(matcher),\n removeMatcher: (matcher) => this.#removeMatcher(matcher),\n }\n }\n\n #assignMatcherState(matcher) {\n Object.defineProperty(matcher, '_state', {\n value: this.state,\n writable: false,\n configurable: false\n });\n }\n\n #addMatcher(matcher) {\n this.#assignMatcherState(matcher);\n this.#matchers.add(matcher);\n return () => this.#removeMatcher(matcher);\n }\n\n #removeMatcher(matcher) {\n this.#matchers.delete(matcher);\n }\n\n onStateChange(marker, change) {\n this.#matchers.forEach(matcher => matcher(marker, change));\n }\n}\n\nexport function createMatcher(matchPath, fn) {\n if (!Array.isArray(matchPath)) {\n throw new Error('matchPath must be an array');\n }\n\n if (matchPath.length === 0) {\n throw new Error('matchPath must be a non-empty array');\n }\n\n if (fn === undefined || typeof fn !== 'function') {\n throw new Error('Matcher function is required');\n }\n\n const changeQueue = new Map();\n let isFlushing = false;\n\n const matchMarker = createMarker(matchPath);\n const matcher = (marker) => {\n if (compareMarkers(matchMarker, marker) >= 0) {\n queueChange(marker);\n };\n }\n\n function flushChanges() {\n if (isFlushing) return;\n isFlushing = true;\n setTimeout(() => {\n const markers = Array.from(changeQueue.values());\n let changes = {};\n let hasChanges = false;\n for (const marker of markers) {\n dispatch(marker, {\n global: () => {\n changes = matcher._state.get(matchPath);\n hasChanges = true;\n },\n path: () => {\n const comp = compareMarkers(matchMarker, marker);\n \n switch (comp) {\n case MATCH_PARENT:\n case MATCH_EXACT:\n changes = matcher._state.get(matchPath);\n hasChanges = true;\n break;\n case MATCH_CHILD:\n const childPath = marker.path.slice(0, matchPath.length + 1);\n const key = childPath[childPath.length - 1];\n changes = typeof changes === 'object' && changes !== null ? changes : {};\n changes[key] = matcher._state.get(childPath);\n hasChanges = true;\n break;\n }\n },\n });\n }\n\n if (hasChanges) {\n fn(changes);\n }\n changeQueue.clear();\n isFlushing = false;\n }, 0);\n }\n\n function queueChange(marker) {\n if (changeQueue.has(marker.address)) {\n changeQueue.delete(marker.address);\n }\n changeQueue.set(marker.address, marker);\n flushChanges();\n }\n\n Object.defineProperty(matcher, '_isMatcher', {\n value: MATCHER,\n writable: false,\n enumerable: false,\n configurable: true\n });\n\n\n return matcher;\n}"],
5
5
  "mappings": "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",
6
6
  "names": ["Plugin", "options", "state", "pluginInstance", "GLOBAL_TAG", "STATE_CONTEXT", "MATCHER", "MARKER_GLOBAL", "MARKER_SINGLE", "MARKER_MANY", "MARKER_EPHEMERAL", "MATCH_EXACT", "MATCH_PARENT", "MATCH_CHILD", "MATCH_NONE", "escapeStr", "str", "out", "i", "ch", "encodePath", "segments", "parts", "i", "v", "escapeStr", "isGlobalMarker", "marker", "MARKER_GLOBAL", "isPathMarker", "MARKER_SINGLE", "isMarkers", "MARKER_MANY", "isEphemeralMarker", "MARKER_EPHEMERAL", "isGlobalPath", "path", "GLOBAL_TAG", "normalizePaths", "args", "len", "pathHasEphemeral", "i", "segment", "createMarker", "paths", "length", "normalizedPaths", "type", "children", "isEphemeral", "child", "markerType", "encodePath", "dispatch", "marker", "global", "path", "ephemeral", "error", "isGlobalMarker", "isEphemeralMarker", "isPathMarker", "isMarkers", "results", "i", "nestedMarker", "err", "compareMarkers", "controlMarker", "comparedMarker", "MATCH_EXACT", "MATCH_PARENT", "MATCH_NONE", "MATCH_CHILD", "Matcher", "Plugin", "#matchers", "state", "config", "matcher", "MATCHER", "#assignMatcherState", "#addMatcher", "createMatcher", "path", "handler", "#removeMatcher", "marker", "change", "matchPath", "fn", "changeQueue", "isFlushing", "matchMarker", "createMarker", "compareMarkers", "queueChange", "flushChanges", "markers", "changes", "hasChanges", "dispatch", "MATCH_PARENT", "MATCH_EXACT", "MATCH_CHILD", "childPath", "key"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../core/src/Plugin.js", "../../plugins/on-change/src/OnChange.js"],
4
- "sourcesContent": ["export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "import { Plugin } from '@jucie-state/core/Plugin';\n\nexport class OnChange extends Plugin {\n static name = 'onChange';\n\n #listeners = new Set();\n #changeQueue = new Map();\n #flushing = false;\n #hasListeners = false;\n #debounceMs = 0;\n\n constructor(options = {}) {\n super(options);\n this.#debounceMs = options.debounce ?? 0;\n }\n\n actions() {\n return {\n addListener: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#addListener(callback);\n },\n subscribe: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#addListener(callback);\n },\n unsubscribe: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#removeListener(callback);\n },\n removeListener: (callback) => {\n return this.#removeListener(callback);\n },\n clear: () => this.#clear()\n }\n }\n\n onStateChange(marker, change) {\n if (!this.#hasListeners || change.method === 'apply') {\n return;\n }\n\n this.#queueChange(marker, change);\n }\n\n #queueChange(marker, change) {\n if (this.#changeQueue.has(marker.address)) {\n this.#changeQueue.delete(marker.address);\n }\n this.#changeQueue.set(marker.address, change);\n this.#flush();\n }\n\n #flush() {\n if (this.#flushing) {\n return;\n }\n this.#flushing = true;\n try {\n setTimeout(() => {\n const changes = Array.from(this.#changeQueue.values());\n this.#changeQueue.clear();\n for (const callback of this.#listeners) {\n try {\n callback(changes);\n } catch (error) {\n console.error('Error in onChange listener:', error);\n }\n }\n this.#flushing = false;\n }, this.#debounceMs);\n } catch (error) {\n console.error(error);\n }\n }\n\n #addListener(callback) {\n this.#listeners.add(callback);\n this.#hasListeners = true;\n return () => this.#removeListener(callback);\n }\n\n #removeListener(callback) {\n if (typeof callback !== 'function') {\n return;\n }\n this.#listeners.delete(callback);\n if (this.#listeners.size === 0) {\n this.#hasListeners = false;\n }\n }\n\n #clear() {\n this.#listeners.clear();\n this.#changeQueue.clear();\n this.#hasListeners = false;\n }\n}"],
3
+ "sources": ["../../src/Plugin.js", "../../plugins/on-change/src/OnChange.js"],
4
+ "sourcesContent": ["export class Plugin {\n\n static name = null;\n static options = {};\n\n static configure(options) {\n options = {...this.options, ...options};\n return {\n install: (state) => this.install(state, options),\n name: this.name,\n options\n }\n }\n\n static install(state, options) {\n options = {...this.options, ...options};\n const pluginInstance = new this(state, options);\n\n Object.defineProperty(pluginInstance, 'state', {\n value: state,\n writable: false,\n configurable: false\n });\n \n Object.defineProperty(pluginInstance, 'options', {\n value: options,\n writable: false,\n configurable: false\n });\n\n \n return pluginInstance;\n }\n}\n\nexport default Plugin;", "import { Plugin } from '@jucie.io/state/Plugin';\n\nexport class OnChange extends Plugin {\n static name = 'onChange';\n\n #listeners = new Set();\n #changeQueue = new Map();\n #flushing = false;\n #hasListeners = false;\n #debounceMs = 0;\n\n constructor(options = {}) {\n super(options);\n this.#debounceMs = options.debounce ?? 0;\n }\n\n actions() {\n return {\n addListener: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#addListener(callback);\n },\n subscribe: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#addListener(callback);\n },\n unsubscribe: (callback) => {\n if (typeof callback !== 'function') {\n return;\n }\n return this.#removeListener(callback);\n },\n removeListener: (callback) => {\n return this.#removeListener(callback);\n },\n clear: () => this.#clear()\n }\n }\n\n onStateChange(marker, change) {\n if (!this.#hasListeners || change.method === 'apply') {\n return;\n }\n\n this.#queueChange(marker, change);\n }\n\n #queueChange(marker, change) {\n if (this.#changeQueue.has(marker.address)) {\n this.#changeQueue.delete(marker.address);\n }\n this.#changeQueue.set(marker.address, change);\n this.#flush();\n }\n\n #flush() {\n if (this.#flushing) {\n return;\n }\n this.#flushing = true;\n try {\n setTimeout(() => {\n const changes = Array.from(this.#changeQueue.values());\n this.#changeQueue.clear();\n for (const callback of this.#listeners) {\n try {\n callback(changes);\n } catch (error) {\n console.error('Error in onChange listener:', error);\n }\n }\n this.#flushing = false;\n }, this.#debounceMs);\n } catch (error) {\n console.error(error);\n }\n }\n\n #addListener(callback) {\n this.#listeners.add(callback);\n this.#hasListeners = true;\n return () => this.#removeListener(callback);\n }\n\n #removeListener(callback) {\n if (typeof callback !== 'function') {\n return;\n }\n this.#listeners.delete(callback);\n if (this.#listeners.size === 0) {\n this.#hasListeners = false;\n }\n }\n\n #clear() {\n this.#listeners.clear();\n this.#changeQueue.clear();\n this.#hasListeners = false;\n }\n}"],
5
5
  "mappings": "AAAO,IAAMA,EAAN,KAAa,CAElB,OAAO,KAAO,KACd,OAAO,QAAU,CAAC,EAElB,OAAO,UAAUC,EAAS,CACxB,OAAAA,EAAU,CAAC,GAAG,KAAK,QAAS,GAAGA,CAAO,EAC/B,CACL,QAAUC,GAAU,KAAK,QAAQA,EAAOD,CAAO,EAC/C,KAAM,KAAK,KACX,QAAAA,CACF,CACF,CAEA,OAAO,QAAQC,EAAOD,EAAS,CAC7BA,EAAU,CAAC,GAAG,KAAK,QAAS,GAAGA,CAAO,EACtC,IAAME,EAAiB,IAAI,KAAKD,EAAOD,CAAO,EAE9C,cAAO,eAAeE,EAAgB,QAAS,CAC7C,MAAOD,EACP,SAAU,GACV,aAAc,EAChB,CAAC,EAED,OAAO,eAAeC,EAAgB,UAAW,CAC/C,MAAOF,EACP,SAAU,GACV,aAAc,EAChB,CAAC,EAGME,CACT,CACF,EC/BO,IAAMC,EAAN,cAAuBC,CAAO,CACnC,OAAO,KAAO,WAEdC,GAAa,IAAI,IACjBC,GAAe,IAAI,IACnBC,GAAY,GACZC,GAAgB,GAChBC,GAAc,EAEd,YAAYC,EAAU,CAAC,EAAG,CACxB,MAAMA,CAAO,EACb,KAAKD,GAAcC,EAAQ,UAAY,CACzC,CAEA,SAAU,CACR,MAAO,CACL,YAAcC,GAAa,CACzB,GAAI,OAAOA,GAAa,WAGxB,OAAO,KAAKC,GAAaD,CAAQ,CACnC,EACA,UAAYA,GAAa,CACvB,GAAI,OAAOA,GAAa,WAGxB,OAAO,KAAKC,GAAaD,CAAQ,CACnC,EACA,YAAcA,GAAa,CACzB,GAAI,OAAOA,GAAa,WAGxB,OAAO,KAAKE,GAAgBF,CAAQ,CACtC,EACA,eAAiBA,GACR,KAAKE,GAAgBF,CAAQ,EAEtC,MAAO,IAAM,KAAKG,GAAO,CAC3B,CACF,CAEA,cAAcC,EAAQC,EAAQ,CACxB,CAAC,KAAKR,IAAiBQ,EAAO,SAAW,SAI7C,KAAKC,GAAaF,EAAQC,CAAM,CAClC,CAEAC,GAAaF,EAAQC,EAAQ,CACvB,KAAKV,GAAa,IAAIS,EAAO,OAAO,GACtC,KAAKT,GAAa,OAAOS,EAAO,OAAO,EAEzC,KAAKT,GAAa,IAAIS,EAAO,QAASC,CAAM,EAC5C,KAAKE,GAAO,CACd,CAEAA,IAAS,CACP,GAAI,MAAKX,GAGT,MAAKA,GAAY,GACjB,GAAI,CACF,WAAW,IAAM,CACf,IAAMY,EAAU,MAAM,KAAK,KAAKb,GAAa,OAAO,CAAC,EACrD,KAAKA,GAAa,MAAM,EACxB,QAAWK,KAAY,KAAKN,GAC1B,GAAI,CACFM,EAASQ,CAAO,CAClB,OAASC,EAAO,CACd,QAAQ,MAAM,8BAA+BA,CAAK,CACpD,CAEF,KAAKb,GAAY,EACnB,EAAG,KAAKE,EAAW,CACrB,OAASW,EAAO,CACd,QAAQ,MAAMA,CAAK,CACrB,EACF,CAEAR,GAAaD,EAAU,CACrB,YAAKN,GAAW,IAAIM,CAAQ,EAC5B,KAAKH,GAAgB,GACd,IAAM,KAAKK,GAAgBF,CAAQ,CAC5C,CAEAE,GAAgBF,EAAU,CACpB,OAAOA,GAAa,aAGxB,KAAKN,GAAW,OAAOM,CAAQ,EAC3B,KAAKN,GAAW,OAAS,IAC3B,KAAKG,GAAgB,IAEzB,CAEAM,IAAS,CACP,KAAKT,GAAW,MAAM,EACtB,KAAKC,GAAa,MAAM,EACxB,KAAKE,GAAgB,EACvB,CACF",
6
6
  "names": ["Plugin", "options", "state", "pluginInstance", "OnChange", "Plugin", "#listeners", "#changeQueue", "#flushing", "#hasListeners", "#debounceMs", "options", "callback", "#addListener", "#removeListener", "#clear", "marker", "change", "#queueChange", "#flush", "changes", "error"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jucie.io/state",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Modular state management system with path-based access, history, and reactive plugins",
5
5
  "type": "module",
6
6
  "main": "./dist/main.js",
@@ -33,20 +33,17 @@
33
33
  },
34
34
  "files": [
35
35
  "dist/",
36
- "core/README.md",
36
+ "README.md",
37
37
  "plugins/history/README.md",
38
38
  "plugins/matcher/README.md",
39
- "plugins/on-change/README.md",
40
- "README.md",
41
- "LICENSE"
39
+ "plugins/on-change/README.md"
42
40
  ],
43
41
  "scripts": {
44
- "build": "node scripts/build-monolith.js",
42
+ "build": "node ../scripts/build-state.js",
45
43
  "test": "vitest",
46
44
  "bench": "NODE_OPTIONS='--max-old-space-size=4096' vitest bench 2>&1 | grep -v 'faster than' | grep -v 'BENCH Summary' | grep -v '^ [a-z]'",
47
45
  "bench:raw": "NODE_OPTIONS='--max-old-space-size=4096' vitest bench",
48
- "clean": "rm -rf dist",
49
- "prepublishOnly": "npm run build"
46
+ "clean": "rm -rf dist"
50
47
  },
51
48
  "repository": {
52
49
  "type": "git",
@@ -73,9 +70,5 @@
73
70
  "dependencies": {
74
71
  "cbor-x": "^1.6.0"
75
72
  },
76
- "devDependencies": {
77
- "esbuild": "^0.24.2",
78
- "nodemon": "^3.1.10",
79
- "vitest": "^1.6.1"
80
- }
73
+ "devDependencies": {}
81
74
  }
@@ -10,7 +10,7 @@ Path-based state watching plugin for @jucio.io/state that allows you to watch sp
10
10
  - 📦 **Automatic Batching**: Changes are automatically batched and debounced
11
11
  - 🔄 **Smart Consolidation**: Multiple changes to the same path are consolidated
12
12
  - 🎬 **Declarative Setup**: Define matchers during state initialization
13
- - 🔌 **Plugin Architecture**: Seamlessly integrates with @jucie-state/core
13
+ - 🔌 **Plugin Architecture**: Seamlessly integrates with @jucie.io/state
14
14
 
15
15
  ## Installation
16
16
 
package/LICENSE DELETED
@@ -1,61 +0,0 @@
1
- MIT License with Commons Clause
2
-
3
- Copyright (c) 2025 Jucio
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
22
-
23
- ---
24
-
25
- "Commons Clause" License Condition v1.0
26
-
27
- The Software is provided to you by the Licensor under the License, as defined
28
- below, subject to the following condition.
29
-
30
- Without limiting other conditions in the License, the grant of rights under the
31
- License will not include, and the License does not grant to you, the right to
32
- Sell the Software.
33
-
34
- For purposes of the foregoing, "Sell" means practicing any or all of the rights
35
- granted to you under the License to provide to third parties, for a fee or other
36
- consideration (including without limitation fees for hosting or consulting/
37
- support services related to the Software), a product or service whose value
38
- derives, entirely or substantially, from the functionality of the Software.
39
-
40
- Any license notice or attribution required by the License must also include
41
- this Commons Clause License Condition notice.
42
-
43
- Software: @jucie-state/state
44
- License: MIT License
45
- Licensor: Jucio
46
-
47
- ---
48
-
49
- ADDITIONAL TERMS
50
-
51
- This software is provided "as-is" without any warranty, support, or guarantee.
52
- The author(s) are not obligated to:
53
- - Provide support or answer questions
54
- - Accept or implement feature requests
55
- - Review or merge pull requests
56
- - Fix bugs or security issues
57
- - Maintain or update the software
58
-
59
- You may submit issues and pull requests, but there is no expectation that they
60
- will be addressed. Use this software at your own risk.
61
-