{"version":3,"sources":["../../src/test/index.ts","../../src/test/sandbox.ts","../../src/internal/lru-map.ts","../../src/adapters/in-memory-cache.ts","../../src/adapters/console-logger.ts","../../src/config.ts","../../src/types/errors.ts","../../src/types/schemas.ts","../../src/internal/sensitive.ts","../../src/types/index.ts","../../src/utils.ts","../../src/scoped.ts","../../src/ports.ts","../../src/adapters/in-memory-store.ts"],"sourcesContent":["export * from \"./sandbox.js\";\n","import { test } from \"vitest\";\nimport type { Act, ActOptions } from \"../act.js\";\nimport { InMemoryCache } from \"../adapters/in-memory-cache.js\";\nimport { InMemoryStore } from \"../adapters/in-memory-store.js\";\nimport type { Cache, Store } from \"../types/index.js\";\n\n/**\n * Minimal structural shape — anything with a `.build()` that returns an\n * Act. Avoids the variance pitfalls of constraining on the full\n * `ActBuilder<TSchemaReg, TEvents, TActions, TStateMap, TActor>`\n * generic when called across package boundaries.\n */\ntype AnyActBuilder<TApp> = {\n  // `ActOptions<any>` rather than `ActOptions<string>` (the default) — a\n  // builder narrowed to `ActOptions<\"default\">` would otherwise trip\n  // function-parameter contravariance against `ActOptions<string>`. The\n  // `any` only widens `onlyLanes`; the rest of the option shape\n  // (`scoped`, `correlator`, `settleDebounceMs`, etc.) still type-checks\n  // at the runtime call site below.\n  build: (options?: ActOptions<any>) => TApp;\n};\n\n/**\n * Options for {@link sandbox} / {@link fixture}.\n *\n * Defaults to `new InMemoryStore() + new InMemoryCache()` per call.\n * Override `store` / `cache` to point at PG, SQLite, or any other\n * adapter — factories run once per call so each test gets a fresh\n * instance.\n */\nexport type SandboxOptions = {\n  /** Factory for the per-test store. Defaults to `new InMemoryStore()`. */\n  readonly store?: () => Store | Promise<Store>;\n  /** Factory for the per-test cache. Defaults to `new InMemoryCache()`. */\n  readonly cache?: () => Cache | Promise<Cache>;\n  /** Pass-through ActOptions. `scoped` is filled in by the helper. */\n  readonly actOptions?: Omit<ActOptions, \"scoped\">;\n};\n\n/** Return shape of {@link sandbox}. */\nexport type Sandbox<TApp> = {\n  readonly app: TApp;\n  readonly store: Store;\n  readonly cache: Cache;\n  /** Tears down the Act, store, and cache. Idempotent. */\n  readonly dispose: () => Promise<void>;\n};\n\n/**\n * Build a scoped Act bound to a fresh `{ store, cache }` bag.\n *\n * Intended for parallel-safe test isolation. Each call constructs new\n * ports (defaults to InMemoryStore + InMemoryCache), seeds the store,\n * builds the Act with `ActOptions.scoped`, and returns `{ app, store,\n * cache, dispose }`. The caller owns the lifecycle: `dispose()` performs\n * `app.shutdown()` followed by `store.dispose()` + `cache.dispose()`.\n *\n * Prefer {@link fixture} when fixture-style ergonomics fit; reach for\n * `sandbox` when you need explicit control (e.g., wiring inside\n * `beforeAll` rather than per-test, or two scoped Acts in one test, or\n * direct access to the store/cache handles).\n *\n * @example Per-test isolated Act with explicit dispose\n * ```ts\n * import { sandbox } from \"@rotorsoft/act/test\";\n *\n * const counterBuilder = act().withState(Counter);\n *\n * it(\"increments\", async () => {\n *   const { app, dispose } = await sandbox(counterBuilder);\n *   await app.do(\"increment\", { stream: \"c-1\", actor }, { by: 1 });\n *   expect((await app.load(\"Counter\", \"c-1\")).state.count).toBe(1);\n *   await dispose();\n * });\n * ```\n *\n * @example Custom store factory (PG per-test schema)\n * ```ts\n * const { app, dispose } = await sandbox(builder, {\n *   store: () => new PostgresStore({ schema: `t_${nanoid()}` }),\n * });\n * ```\n */\nexport async function sandbox<TApp>(\n  builder: AnyActBuilder<TApp>,\n  options: SandboxOptions = {}\n): Promise<Sandbox<TApp>> {\n  const store = options.store ? await options.store() : new InMemoryStore();\n  const cache = options.cache ? await options.cache() : new InMemoryCache();\n  await store.seed();\n\n  const app = builder.build({\n    ...options.actOptions,\n    scoped: { store, cache },\n  });\n\n  let _disposed: Promise<void> | undefined;\n  const dispose = (): Promise<void> => {\n    if (!_disposed) {\n      _disposed = (async () => {\n        await (app as unknown as Act<any, any, any, any, any>).shutdown();\n        await store.dispose();\n        await cache.dispose();\n      })();\n    }\n    return _disposed;\n  };\n\n  return { app, store, cache, dispose };\n}\n\n/**\n * Vitest fixture wrapper around {@link sandbox}.\n *\n * Returns a `test` instance with an `app` fixture — each test gets a\n * fresh, isolated Act and vitest's fixture lifecycle runs the cleanup\n * automatically when the test completes.\n *\n * Works with `test.concurrent(...)` — every concurrent invocation\n * receives its own bag, so tests don't race on the singleton.\n *\n * For tests that also need direct access to the underlying `store` /\n * `cache` handles, use {@link sandbox} explicitly.\n *\n * @example Fixture-style — auto cleanup, parallel-safe\n * ```ts\n * import { fixture } from \"@rotorsoft/act/test\";\n *\n * const test = fixture(act().withState(Counter));\n *\n * test(\"increments\", async ({ app }) => {\n *   await app.do(\"increment\", { stream: \"c-1\", actor }, { by: 1 });\n *   expect((await app.load(\"Counter\", \"c-1\")).state.count).toBe(1);\n * });\n *\n * test.concurrent(\"isolated from concurrent peers\", async ({ app }) => {\n *   // Each concurrent invocation gets its own store + cache — no\n *   // singleton contention, no flake.\n * });\n * ```\n *\n * @example Custom store factory\n * ```ts\n * const test = fixture(builder, {\n *   store: () => new PostgresStore({ schema: `t_${nanoid()}` }),\n * });\n * ```\n */\nexport function fixture<TApp>(\n  builder: AnyActBuilder<TApp>,\n  defaults: SandboxOptions = {}\n) {\n  return test.extend<{ app: TApp }>({\n    app: async (\n      // biome-ignore lint/correctness/noEmptyPattern: vitest fixture API requires a destructured deps parameter\n      {},\n      use: (value: TApp) => Promise<void>\n    ) => {\n      const ctx = await sandbox(builder, defaults);\n      try {\n        await use(ctx.app);\n      } finally {\n        await ctx.dispose();\n      }\n    },\n  });\n}\n","/**\n * @module lru-map\n * @category Internal\n *\n * Tiny bounded LRU map / set built on insertion-ordered `Map`. Used to cap\n * memory in long-running orchestrators that mint large numbers of keys —\n * notably:\n *\n * - {@link InMemoryCache}: stream → state checkpoint\n * - `Act._subscribed_streams`: stream → presence (LruSet)\n *\n * Apps with millions of dynamic streams (one target per aggregate) can't\n * afford an unbounded `Set<string>` — eviction is required.\n *\n * @internal\n */\n\n/**\n * Bounded LRU map. `get()` promotes; `has()` does not. `set()` always\n * promotes and evicts the oldest entry when at capacity.\n *\n * @internal\n */\nexport class LruMap<K, V> {\n  private readonly _entries = new Map<K, V>();\n  private readonly _max_size: number;\n\n  constructor(maxSize: number) {\n    this._max_size = maxSize;\n  }\n\n  get(key: K): V | undefined {\n    const v = this._entries.get(key);\n    if (v === undefined) return undefined;\n    // promote: delete + re-insert moves to most-recent position\n    this._entries.delete(key);\n    this._entries.set(key, v);\n    return v;\n  }\n\n  has(key: K): boolean {\n    return this._entries.has(key);\n  }\n\n  set(key: K, value: V): void {\n    this._entries.delete(key);\n    if (this._entries.size >= this._max_size) {\n      // size >= maxSize ≥ 1 → at least one entry exists → next().value\n      // is the oldest key (asserted with `!`).\n      const oldest = this._entries.keys().next().value!;\n      this._entries.delete(oldest);\n    }\n    this._entries.set(key, value);\n  }\n\n  delete(key: K): boolean {\n    return this._entries.delete(key);\n  }\n\n  clear(): void {\n    this._entries.clear();\n  }\n\n  get size(): number {\n    return this._entries.size;\n  }\n}\n\n/**\n * Bounded LRU set built on top of {@link LruMap}. `has()` does not promote;\n * `add()` does (re-inserting if already present, evicting the oldest at\n * capacity).\n *\n * @internal\n */\nexport class LruSet<T> {\n  private readonly _map: LruMap<T, true>;\n\n  constructor(maxSize: number) {\n    this._map = new LruMap(maxSize);\n  }\n\n  has(value: T): boolean {\n    return this._map.has(value);\n  }\n\n  add(value: T): void {\n    this._map.set(value, true);\n  }\n\n  delete(value: T): boolean {\n    return this._map.delete(value);\n  }\n\n  clear(): void {\n    this._map.clear();\n  }\n\n  get size(): number {\n    return this._map.size;\n  }\n}\n","import { LruMap } from \"../internal/lru-map.js\";\nimport type { Cache, CacheEntry, Schema } from \"../types/index.js\";\n\n/**\n * In-memory LRU cache for stream snapshots.\n *\n * Backed by an internal `LruMap` for O(1) get/set with LRU eviction.\n * Configurable `maxSize` bounds memory usage.\n *\n * @example\n * ```typescript\n * import { cache } from \"@rotorsoft/act\";\n * import { InMemoryCache } from \"@rotorsoft/act\";\n *\n * cache(new InMemoryCache({ maxSize: 500 }));\n * ```\n */\n/* eslint-disable @typescript-eslint/require-await -- async interface for Redis-compatibility */\nexport class InMemoryCache implements Cache {\n  // CacheEntry<any> lets `get<TState>` and `set<TState>` flow without casts:\n  // any is bidirectionally compatible with the per-call TState binding, while\n  // the public Cache interface still presents a typed surface to callers.\n  private readonly _entries: LruMap<string, CacheEntry<any>>;\n\n  constructor(options?: { maxSize?: number }) {\n    this._entries = new LruMap(options?.maxSize ?? 1000);\n  }\n\n  /** @inheritDoc */\n  async get<TState extends Schema>(\n    stream: string\n  ): Promise<CacheEntry<TState> | undefined> {\n    return this._entries.get(stream);\n  }\n\n  /** @inheritDoc */\n  async set<TState extends Schema>(\n    stream: string,\n    entry: CacheEntry<TState>\n  ): Promise<void> {\n    this._entries.set(stream, entry);\n  }\n\n  /** @inheritDoc */\n  async invalidate(stream: string): Promise<void> {\n    this._entries.delete(stream);\n  }\n\n  /** @inheritDoc */\n  async clear(): Promise<void> {\n    this._entries.clear();\n  }\n\n  /** @inheritDoc */\n  async dispose(): Promise<void> {\n    this._entries.clear();\n  }\n\n  /** Current number of entries held by the LRU. */\n  get size(): number {\n    return this._entries.size;\n  }\n}\n","/**\n * @module adapters/console-logger\n *\n * High-performance console logger inspired by pino's design:\n * - Numeric level comparison for O(1) gating\n * - stdout.write() in production for raw JSON lines (no console overhead)\n * - Colorized single-line output in development\n * - No-op method replacement when level is above threshold\n * - Child logger support with merged bindings\n */\nimport type { Logger } from \"../types/index.js\";\n\nconst LEVEL_VALUES: Record<string, number> = {\n  fatal: 60,\n  error: 50,\n  warn: 40,\n  info: 30,\n  debug: 20,\n  trace: 10,\n};\n\nconst LEVEL_COLORS: Record<string, string> = {\n  fatal: \"\\x1b[41m\\x1b[37m\", // white on red bg\n  error: \"\\x1b[31m\", // red\n  warn: \"\\x1b[33m\", // yellow\n  info: \"\\x1b[32m\", // green\n  debug: \"\\x1b[36m\", // cyan\n  trace: \"\\x1b[90m\", // gray\n};\n\nconst RESET = \"\\x1b[0m\";\n\nconst noop = () => {};\n\n/**\n * Default console logger for the Act framework.\n *\n * Production mode emits newline-delimited JSON (compatible with GCP, AWS\n * CloudWatch, Datadog, and other structured log ingestion systems).\n *\n * Development mode emits colorized, human-readable output.\n */\nexport class ConsoleLogger implements Logger {\n  level: string;\n  private readonly _pretty: boolean;\n\n  readonly fatal: Logger[\"fatal\"];\n  readonly error: Logger[\"error\"];\n  readonly warn: Logger[\"warn\"];\n  readonly info: Logger[\"info\"];\n  readonly debug: Logger[\"debug\"];\n  readonly trace: Logger[\"trace\"];\n\n  constructor(\n    options: {\n      level?: string;\n      pretty?: boolean;\n      bindings?: Record<string, unknown>;\n    } = {}\n  ) {\n    const {\n      level = \"info\",\n      pretty = process.env.NODE_ENV !== \"production\",\n      bindings,\n    } = options;\n    this._pretty = pretty;\n    this.level = level;\n\n    const threshold = LEVEL_VALUES[level] ?? 30;\n    const write = pretty\n      ? this._pretty_write.bind(this, bindings)\n      : this._json_write.bind(this, bindings);\n\n    // Assign methods — noop when level is gated (like pino's level-based replacement)\n    this.fatal = write.bind(this, \"fatal\", 60); // fatal is always enabled\n    this.error = threshold <= 50 ? write.bind(this, \"error\", 50) : noop;\n    this.warn = threshold <= 40 ? write.bind(this, \"warn\", 40) : noop;\n    this.info = threshold <= 30 ? write.bind(this, \"info\", 30) : noop;\n    this.debug = threshold <= 20 ? write.bind(this, \"debug\", 20) : noop;\n    this.trace = threshold <= 10 ? write.bind(this, \"trace\", 10) : noop;\n  }\n\n  /** No-op — `console.log` has no resources to release. */\n  async dispose(): Promise<void> {}\n\n  /** @inheritDoc */\n  child(bindings: Record<string, unknown>): Logger {\n    return new ConsoleLogger({\n      level: this.level,\n      pretty: this._pretty,\n      bindings,\n    });\n  }\n\n  private _json_write(\n    bindings: Record<string, unknown> | undefined,\n    level: string,\n    _num: number,\n    obj_or_msg: unknown,\n    msg?: string\n  ): void {\n    let obj: Record<string, unknown>;\n    let message: string | undefined;\n\n    if (typeof obj_or_msg === \"string\") {\n      message = obj_or_msg;\n      obj = {};\n    } else if (obj_or_msg instanceof Error) {\n      // Error instances spread to `{}` — capture the salient fields\n      // explicitly so structured log aggregators see them.\n      message = msg ?? obj_or_msg.message;\n      obj = {\n        error: { message: obj_or_msg.message, name: obj_or_msg.name },\n        stack: obj_or_msg.stack,\n      };\n    } else if (obj_or_msg !== null && typeof obj_or_msg === \"object\") {\n      message = msg;\n      obj = { ...(obj_or_msg as Record<string, unknown>) };\n    } else {\n      message = msg;\n      obj = { value: obj_or_msg };\n    }\n\n    const entry = Object.assign({ level, time: Date.now() }, bindings, obj);\n    if (message) entry.msg = message;\n\n    let line: string;\n    try {\n      line = JSON.stringify(entry);\n    } catch {\n      // Cyclic or unserializable payload — emit a minimal line rather\n      // than crash the log call site.\n      line = JSON.stringify({\n        level,\n        time: entry.time,\n        msg: message ?? \"[unserializable]\",\n        unserializable: true,\n      });\n    }\n    process.stdout.write(line + \"\\n\");\n  }\n\n  private _pretty_write(\n    bindings: Record<string, unknown> | undefined,\n    level: string,\n    _num: number,\n    obj_or_msg: unknown,\n    msg?: string\n  ): void {\n    const color = LEVEL_COLORS[level];\n    const tag = `${color}${level.toUpperCase().padEnd(5)}${RESET}`;\n    const ts = new Date().toISOString().slice(11, 23); // HH:mm:ss.SSS\n\n    let message: string;\n    let data: string | undefined;\n\n    if (typeof obj_or_msg === \"string\") {\n      message = obj_or_msg;\n    } else if (obj_or_msg instanceof Error) {\n      // Error instances don't serialize their `message`/`stack` via\n      // JSON.stringify — `JSON.stringify(err) === \"{}\"`. Render the\n      // message inline and the stack as the data payload so operators\n      // see something useful instead of an empty object.\n      message = msg ?? obj_or_msg.message;\n      data = obj_or_msg.stack;\n    } else {\n      message = msg ?? \"\";\n      if (obj_or_msg !== undefined && obj_or_msg !== null) {\n        try {\n          data = JSON.stringify(obj_or_msg);\n        } catch {\n          data = \"[unserializable]\";\n        }\n      }\n    }\n\n    const bind_str =\n      bindings && Object.keys(bindings).length\n        ? ` ${JSON.stringify(bindings)}`\n        : \"\";\n\n    const parts = [ts, tag, message, data, bind_str].filter(Boolean);\n    process.stdout.write(parts.join(\" \") + \"\\n\");\n  }\n}\n","/**\n * @packageDocumentation\n * Configuration utilities for Act Framework environment, logging, and package metadata.\n *\n * Provides type-safe configuration loading and validation using Zod schemas.\n *\n * @module config\n */\nimport * as fs from \"node:fs\";\nimport { z } from \"zod\";\nimport { log } from \"./ports.js\";\nimport {\n  type Environment,\n  Environments,\n  type LogLevel,\n  LogLevels,\n} from \"./types/index.js\";\nimport { extend } from \"./utils.js\";\n\n/**\n * Zod schema for validating package.json metadata.\n * @internal\n */\nexport const PackageSchema = z.object({\n  name: z.string().min(1),\n  version: z.string().min(1),\n  description: z.string().min(1).optional(),\n  author: z\n    .object({ name: z.string().min(1), email: z.string().optional() })\n    .optional()\n    .or(z.string().min(1))\n    .optional(),\n  license: z.string().min(1).optional(),\n  dependencies: z.record(z.string(), z.string()).optional(),\n});\n\n/**\n * Type representing the validated package.json metadata.\n *\n * @internal\n */\nexport type Package = z.infer<typeof PackageSchema>;\n\n/**\n * Fallback package metadata when `package.json` can't be read at module\n * load — happens when the framework is consumed from a CWD that doesn't\n * have one (bundled CLIs, Lambda layers, embedded scripts) or when the\n * file exists but is malformed.\n *\n * The values are deliberately synthetic so callers spot them immediately:\n * `config().name === \"act-fallback\"` is a runtime signal that the framework\n * couldn't load the host project's package.json.\n *\n * @internal\n */\nconst FALLBACK_PACKAGE: Package = {\n  name: \"act-fallback\",\n  version: \"0.0.0-fallback\",\n  description: \"Synthetic fallback — package.json could not be loaded\",\n};\n\n/**\n * Loads and parses the local package.json file as a Package object. On\n * any read or parse failure, falls back to {@link FALLBACK_PACKAGE} and\n * stashes the error so {@link config} can surface it on first access —\n * we can't call `log()` here because the logger port memoizes on first\n * call and locking it at module load defeats user injection.\n *\n * @internal\n */\nconst get_package = (): Package => {\n  try {\n    const raw = fs.readFileSync(\"package.json\");\n    return JSON.parse(raw.toString()) as Package;\n  } catch (err) {\n    pkg_load_error = err;\n    return FALLBACK_PACKAGE;\n  }\n};\n\n/** Stashed read/parse error from {@link get_package}, surfaced by config(). */\nlet pkg_load_error: unknown;\n\n/**\n * Zod schema for the full Act Framework configuration object.\n * Includes package metadata, environment, logging, and timing options.\n * @internal\n */\nconst BaseSchema = PackageSchema.extend({\n  env: z.enum(Environments),\n  logLevel: z.enum(LogLevels),\n  logSingleLine: z.boolean(),\n  sleepMs: z.number().int().min(0).max(5000),\n});\n\n/**\n * Type representing the validated Act Framework configuration object.\n */\nexport type Config = z.infer<typeof BaseSchema>;\n\nconst { NODE_ENV, LOG_LEVEL, LOG_SINGLE_LINE, SLEEP_MS } = process.env;\n\nconst env = (NODE_ENV || \"development\") as Environment;\nconst logLevel = (LOG_LEVEL ||\n  (NODE_ENV === \"test\"\n    ? \"fatal\"\n    : NODE_ENV === \"production\"\n      ? \"info\"\n      : \"trace\")) as LogLevel;\nconst logSingleLine = (LOG_SINGLE_LINE || \"true\") === \"true\";\nconst sleepMs = parseInt(NODE_ENV === \"test\" ? \"0\" : (SLEEP_MS ?? \"100\"), 10);\n\nconst pkg = get_package();\n\n// Lazily validated on first call. Cannot run extend() at module load\n// because of a utils.ts <-> config.ts cycle (utils imports config for\n// sleep()'s default). Inputs are frozen after import, so the cached\n// result is stable for the life of the process.\nlet _validated: Config | undefined;\n\n/**\n * Gets the current Act Framework configuration.\n *\n * Configuration is loaded from package.json and environment variables, providing\n * type-safe access to application metadata and runtime settings.\n *\n * **Environment Variables:**\n * - `NODE_ENV`: \"development\" | \"test\" | \"staging\" | \"production\" (default: \"development\")\n * - `LOG_LEVEL`: \"fatal\" | \"error\" | \"warn\" | \"info\" | \"debug\" | \"trace\"\n * - `LOG_SINGLE_LINE`: \"true\" | \"false\" (default: \"true\")\n * - `SLEEP_MS`: Milliseconds for sleep utility (default: 100, 0 for tests)\n *\n * **Defaults by environment:**\n * - test: logLevel=\"error\", sleepMs=0\n * - production: logLevel=\"info\"\n * - development: logLevel=\"trace\"\n *\n * @returns The validated configuration object\n *\n * @example Basic usage\n * ```typescript\n * import { config } from \"@rotorsoft/act\";\n *\n * const cfg = config();\n * console.log(`App: ${cfg.name} v${cfg.version}`);\n * console.log(`Environment: ${cfg.env}`);\n * console.log(`Log level: ${cfg.logLevel}`);\n * ```\n *\n * @example Environment-specific behavior\n * ```typescript\n * import { config } from \"@rotorsoft/act\";\n *\n * const cfg = config();\n *\n * if (cfg.env === \"production\") {\n *   // Use PostgreSQL in production\n *   store(new PostgresStore(prodConfig));\n * } else {\n *   // Use in-memory store for dev/test\n *   store(new InMemoryStore());\n * }\n * ```\n *\n * @example Adjusting log levels\n * ```typescript\n * // Set via environment variable:\n * // LOG_LEVEL=debug npm start\n *\n * // Or check in code:\n * const cfg = config();\n * if (cfg.logLevel === \"trace\") {\n *   logger.trace(\"Detailed debugging enabled\");\n * }\n * ```\n *\n * @see {@link Config} for configuration type\n */\nexport const config = (): Config => {\n  if (!_validated) {\n    _validated = extend(\n      { ...pkg, env, logLevel, logSingleLine, sleepMs },\n      BaseSchema\n    );\n    if (pkg_load_error) {\n      // Surface the fallback once, after _validated is set so the\n      // recursive log() → config() call short-circuits. log() resolves\n      // through the port singleton — respects user injection and level.\n      const msg =\n        pkg_load_error instanceof Error\n          ? pkg_load_error.message\n          : typeof pkg_load_error === \"string\"\n            ? pkg_load_error\n            : \"unknown error\";\n      log().warn(\n        `[act] Could not read package.json (${msg}); using synthetic ` +\n          `name=\"${FALLBACK_PACKAGE.name}\" version=\"${FALLBACK_PACKAGE.version}\".`\n      );\n      pkg_load_error = undefined;\n    }\n  }\n  return _validated;\n};\n","import type {\n  Actor,\n  Message,\n  Schema,\n  Schemas,\n  Snapshot,\n  Target,\n} from \"./action.js\";\n\n/**\n * @packageDocumentation\n * @module act/types\n * @category Types\n * Application error type constants and error classes for the Act Framework.\n *\n * - `ERR_VALIDATION`: Schema validation error\n * - `ERR_INVARIANT`: Invariant validation error\n * - `ERR_CONCURRENCY`: Optimistic concurrency validation error on commits\n */\nexport const Errors = {\n  ValidationError: \"ERR_VALIDATION\",\n  InvariantError: \"ERR_INVARIANT\",\n  ConcurrencyError: \"ERR_CONCURRENCY\",\n  StreamClosedError: \"ERR_STREAM_CLOSED\",\n  NonRetryableError: \"ERR_NON_RETRYABLE\",\n  StoreError: \"ERR_STORE\",\n} as const;\n\n/**\n * Thrown when an action or event payload fails Zod schema validation.\n *\n * This error indicates that data doesn't match the expected schema defined\n * for an action or event. The `details` property contains the Zod validation\n * error with specific information about what failed.\n *\n * @example Catching validation errors\n * ```typescript\n * import { ValidationError } from \"@rotorsoft/act\";\n *\n * try {\n *   await app.do(\"createUser\", target, {\n *     email: \"invalid-email\",  // Missing @ symbol\n *     age: -5                  // Negative age\n *   });\n * } catch (error) {\n *   if (error instanceof ValidationError) {\n *     console.error(\"Validation failed for:\", error.target);\n *     console.error(\"Invalid payload:\", error.payload);\n *     console.error(\"Validation details:\", error.details);\n *     // details contains Zod error with field-level info\n *   }\n * }\n * ```\n *\n * @example Logging validation details\n * ```typescript\n * try {\n *   await app.do(\"updateProfile\", target, payload);\n * } catch (error) {\n *   if (error instanceof ValidationError) {\n *     error.details.errors.forEach((err) => {\n *       console.error(`Field ${err.path.join(\".\")}: ${err.message}`);\n *     });\n *   }\n * }\n * ```\n *\n * @see {@link https://zod.dev | Zod documentation} for validation details\n */\nexport class ValidationError extends Error {\n  /** The type of target being validated (e.g., \"action\", \"event\") */\n  public readonly target: string;\n  /** The invalid payload that failed validation */\n  public readonly payload: any;\n  /** Zod validation error details */\n  public readonly details: any;\n\n  constructor(target: string, payload: any, details: any) {\n    super(`Invalid ${target} payload`);\n    this.name = Errors.ValidationError;\n    this.target = target;\n    this.payload = payload;\n    this.details = details;\n  }\n}\n\n/**\n * Thrown when a business rule (invariant) is violated during action execution.\n *\n * Invariants are conditions that must hold true for an action to succeed.\n * They're checked after loading the current state but before emitting events.\n * This error provides complete context about what action was attempted and\n * why it was rejected.\n *\n * @template TState - State schema type\n * @template TEvents - Event schemas type\n * @template TActions - Action schemas type\n * @template TKey - Action name\n * @template TActor - Actor type extending base Actor\n *\n * @example Catching invariant violations\n * ```typescript\n * import { InvariantError } from \"@rotorsoft/act\";\n *\n * try {\n *   await app.do(\"withdraw\",\n *     { stream: \"account-123\", actor: { id: \"user1\", name: \"Alice\" } },\n *     { amount: 1000 }\n *   );\n * } catch (error) {\n *   if (error instanceof InvariantError) {\n *     console.error(\"Action:\", error.action);\n *     console.error(\"Reason:\", error.description);\n *     console.error(\"Current state:\", error.snapshot.state);\n *     console.error(\"Attempted payload:\", error.payload);\n *   }\n * }\n * ```\n *\n * @example User-friendly error messages\n * ```typescript\n * try {\n *   await app.do(\"closeTicket\", target, payload);\n * } catch (error) {\n *   if (error instanceof InvariantError) {\n *     // Present friendly message to user\n *     if (error.description === \"Ticket must be open\") {\n *       return { error: \"This ticket is already closed\" };\n *     } else if (error.description === \"Not authorized\") {\n *       return { error: \"You don't have permission to close this ticket\" };\n *     }\n *   }\n * }\n * ```\n *\n * @example Logging with context\n * ```typescript\n * try {\n *   await app.do(\"transfer\", target, { to: \"account2\", amount: 500 });\n * } catch (error) {\n *   if (error instanceof InvariantError) {\n *     logger.error({\n *       action: error.action,\n *       stream: error.target.stream,\n *       actor: error.target.actor,\n *       reason: error.description,\n *       balance: error.snapshot.state.balance,\n *       attempted: error.payload.amount\n *     }, \"Invariant violation\");\n *   }\n * }\n * ```\n *\n * @see {@link Invariant} for defining business rules\n */\nexport class InvariantError<\n  TState extends Schema,\n  TEvents extends Schemas,\n  TActions extends Schemas,\n  TKey extends keyof TActions,\n  TActor extends Actor = Actor,\n> extends Error {\n  /** The action that was attempted */\n  readonly action: TKey;\n  /** The action payload that was provided */\n  readonly payload: Readonly<TActions[TKey]>;\n  /** The target stream and actor context */\n  readonly target: Target<TActor>;\n  /** The current state snapshot when invariant was checked */\n  readonly snapshot: Snapshot<TState, TEvents>;\n  /** Human-readable description of why the invariant failed */\n  readonly description: string;\n\n  constructor(\n    action: TKey,\n    payload: Readonly<TActions[TKey]>,\n    target: Target<TActor>,\n    snapshot: Snapshot<TState, TEvents>,\n    description: string\n  ) {\n    super(`${action as string} failed invariant: ${description}`);\n    this.name = Errors.InvariantError;\n    this.action = action;\n    this.payload = payload;\n    this.target = target;\n    this.snapshot = snapshot;\n    this.description = description;\n  }\n}\n\n/**\n * Thrown when optimistic concurrency control detects a conflict.\n *\n * This error occurs when trying to commit events to a stream that has been\n * modified by another process since it was last loaded. The version number\n * doesn't match expectations, indicating a concurrent modification.\n *\n * This is a normal occurrence in distributed systems and should be handled\n * by reloading the current state and retrying the action.\n *\n * @example Handling concurrency conflicts with retry\n * ```typescript\n * import { ConcurrencyError } from \"@rotorsoft/act\";\n *\n * async function transferWithRetry(from, to, amount, maxRetries = 3) {\n *   for (let attempt = 0; attempt < maxRetries; attempt++) {\n *     try {\n *       await app.do(\"transfer\",\n *         { stream: from, actor: currentUser },\n *         { to, amount }\n *       );\n *       return { success: true };\n *     } catch (error) {\n *       if (error instanceof ConcurrencyError) {\n *         if (attempt < maxRetries - 1) {\n *           console.log(`Concurrent modification detected, retrying... (${attempt + 1}/${maxRetries})`);\n *           await sleep(100 * Math.pow(2, attempt)); // Exponential backoff\n *           continue;\n *         }\n *       }\n *       throw error;\n *     }\n *   }\n *   return { success: false, reason: \"Too many concurrent modifications\" };\n * }\n * ```\n *\n * @example Logging concurrency conflicts\n * ```typescript\n * try {\n *   await app.do(\"updateInventory\", target, payload);\n * } catch (error) {\n *   if (error instanceof ConcurrencyError) {\n *     logger.warn({\n *       stream: error.stream,\n *       expectedVersion: error.expectedVersion,\n *       actualVersion: error.lastVersion,\n *       events: error.events.map(e => e.name)\n *     }, \"Concurrent modification detected\");\n *   }\n * }\n * ```\n *\n * @example User feedback for conflicts\n * ```typescript\n * try {\n *   await app.do(\"editDocument\", target, { content: newContent });\n * } catch (error) {\n *   if (error instanceof ConcurrencyError) {\n *     return {\n *       error: \"This document was modified by another user. Please refresh and try again.\",\n *       code: \"CONCURRENT_MODIFICATION\"\n *     };\n *   }\n * }\n * ```\n *\n * @see {@link Store.commit} for version checking details\n */\nexport class ConcurrencyError extends Error {\n  /** The stream that had the concurrent modification */\n  public readonly stream: string;\n  /** The actual current version in the store */\n  public readonly lastVersion: number;\n  /** The events that were being committed */\n  public readonly events: Message<Schemas, keyof Schemas>[];\n  /** The version number that was expected */\n  public readonly expectedVersion: number;\n\n  constructor(\n    stream: string,\n    lastVersion: number,\n    events: Message<Schemas, keyof Schemas>[],\n    expectedVersion: number\n  ) {\n    // Message lists stream + event names only. Payloads remain accessible\n    // via `error.events` for callers who need them — keeping them out of\n    // the message avoids MB-scale strings on contended writes and keeps\n    // potentially-sensitive data out of log streams.\n    super(\n      `Concurrency error committing \"${events\n        .map((e) => `${stream}.${e.name}`)\n        .join(\n          \", \"\n        )}\". Expected version ${expectedVersion} but found version ${lastVersion}.`\n    );\n    this.name = Errors.ConcurrencyError;\n    this.stream = stream;\n    this.lastVersion = lastVersion;\n    this.events = events;\n    this.expectedVersion = expectedVersion;\n  }\n}\n\n/**\n * Thrown when attempting to write to a stream that has been closed\n * with a tombstone event.\n *\n * A tombstoned stream is permanently closed — no further actions can\n * be executed against it. The only way to reopen a tombstoned stream\n * is through `Act.close()` with a `restart` callback.\n *\n * @example\n * ```typescript\n * import { StreamClosedError } from \"@rotorsoft/act\";\n *\n * try {\n *   await app.do(\"updateTicket\", target, payload);\n * } catch (error) {\n *   if (error instanceof StreamClosedError) {\n *     console.error(`Stream ${error.stream} is closed`);\n *   }\n * }\n * ```\n *\n * @see {@link Act.close} for closing streams\n */\nexport class StreamClosedError extends Error {\n  /** The stream that is closed */\n  public readonly stream: string;\n\n  constructor(stream: string) {\n    super(`Stream \"${stream}\" is closed (tombstoned)`);\n    this.name = Errors.StreamClosedError;\n    this.stream = stream;\n  }\n}\n\n/**\n * Thrown by a {@link Store} adapter when an infrastructure operation fails\n * for a reason that is *not* a domain condition — a dropped connection, a\n * transaction rollback, a query timeout. It is the typed boundary between\n * \"the store is unavailable/degraded\" and the domain errors above\n * ({@link ConcurrencyError}, {@link StreamClosedError}), which describe\n * legitimate outcomes the caller should branch on.\n *\n * Adapters wrap their driver errors in `StoreError` (preserving the\n * original via `cause`) so the orchestrator can distinguish a degraded\n * backend from \"no work\" and react accordingly — see the drain circuit\n * breaker, which trips on repeated `StoreError`s and surfaces an\n * `error` lifecycle event instead of silently spinning on a down\n * database.\n *\n * @example\n * ```typescript\n * app.on(\"error\", ({ error, circuit }) => {\n *   if (error instanceof StoreError)\n *     alert(`store ${error.operation} failing; circuit=${circuit}`);\n * });\n * ```\n */\nexport class StoreError extends Error {\n  /** The store operation that failed (e.g. `\"claim\"`, `\"ack\"`, `\"commit\"`). */\n  public readonly operation: string;\n\n  constructor(operation: string, options?: { cause?: unknown }) {\n    super(`Store operation \"${operation}\" failed`, options);\n    this.name = Errors.StoreError;\n    this.operation = operation;\n  }\n}\n\n/**\n * Thrown by a reaction handler to signal that the failure is permanent\n * and the drain pipeline should block the stream immediately, without\n * consuming the rest of the `maxRetries` budget.\n *\n * The drain finalizer detects `instanceof NonRetryableError` and forces\n * `block = options.blockOnError` regardless of `lease.retry`. When\n * `blockOnError` is `false`, behavior is unchanged (drain keeps retrying\n * forever) — the class never overrides the operator's explicit \"never\n * block\" choice.\n *\n * Use this for failures the handler *knows* won't get better on retry:\n * a 4xx from a webhook, a `ZodError` on malformed input, a \"user\n * deleted\" 404 from a downstream API. Use regular `Error` (or a\n * subclass) for transient failures so the existing retry-with-backoff\n * loop applies.\n *\n * @example Wrapping a permanent downstream error\n * ```typescript\n * import { NonRetryableError } from \"@rotorsoft/act\";\n *\n * .on(\"OrderConfirmed\")\n *   .do(async (event) => {\n *     const res = await fetch(url, ...);\n *     if (res.status >= 400 && res.status < 500) {\n *       throw new NonRetryableError(\n *         `webhook ${url} responded ${res.status}`,\n *         { cause: await res.text() }\n *       );\n *     }\n *     if (!res.ok) throw new Error(`webhook ${url} responded ${res.status}`);\n *   })\n * ```\n *\n * @example Marking validation failures as non-retryable\n * ```typescript\n * .on(\"PaymentReceived\")\n *   .do(async (event) => {\n *     const parsed = Schema.safeParse(event.data);\n *     if (!parsed.success) {\n *       throw new NonRetryableError(\"payment payload failed validation\", {\n *         cause: parsed.error,\n *       });\n *     }\n *     // ... handle parsed payload\n *   })\n * ```\n */\nexport class NonRetryableError extends Error {\n  /** The original failure, if any. Mirrors the standard `Error.cause` shape. */\n  public override readonly cause?: unknown;\n\n  constructor(message: string, options?: { cause?: unknown }) {\n    super(message);\n    this.name = Errors.NonRetryableError;\n    this.cause = options?.cause;\n  }\n}\n","import { type ZodObject, type ZodRawShape, z } from \"zod\";\n// Deep-path import (vs `../internal/index.js`) is deliberate — `_registry` is\n// a side-effect-free leaf, and going through the internal barrel would pull\n// tracing.ts → config.ts in at type-schema load time and crash on TDZ when a\n// test imports a public schema before config is initialized.\nimport { _mark_sensitive, _registry } from \"../internal/sensitive.js\";\n\n/**\n * @packageDocumentation\n * @module act/types\n * @category Types\n * Zod schemas and helpers for the Act Framework.\n */\n\n/**\n * An empty Zod schema (no properties).\n */\nexport const ZodEmpty = z.record(z.string(), z.never());\n\n/**\n * Sensitive-data foundation re-exports (#855 / epic #566).\n *\n * - `REDACTED` / `SHREDDED` — sentinels placed in `event.data[field]`\n *   when the caller isn't authorized to see a sensitive field\n *   (`.discloses(predicate)` returned `false` or none was declared —\n *   recoverable) or the underlying PII was wiped (`Store.forget_pii` —\n *   irrecoverable).\n *   top-level field names marked via {@link sensitive}. A pure,\n *   read-only helper that inspects the out-of-band sensitive registry (a\n *   process-global `WeakMap`) `sensitive()` populates, otherwise\n *   unreachable from outside the package. Surfaced for adapters and\n *   tooling that must reflect input sensitivity on their own wire\n *   surface — e.g. the `@rotorsoft/act-http/openapi` emitter marks these\n *   fields `writeOnly` + `format: password` so generated clients and\n *   Swagger UI don't echo PII freely. Returns `[]` for non-object\n *   schemas or objects with no sensitive fields; top-level shape only.\n */\nexport { pii_fields, REDACTED, SHREDDED } from \"../internal/sensitive.js\";\n\n/**\n * Mark a Zod schema as sensitive. Returns the same schema instance — the\n * marker is registered out-of-band so the static type is preserved and the\n * call site reads as a pure annotation.\n *\n * Idempotent: re-wrapping an already-sensitive schema is a no-op.\n *\n * The marker is what the orchestrator inspects to split event payloads into\n * `data` + `pii` on commit, gate reads via `.discloses`, and strip handler\n * payloads. Part of the sensitive-data foundation (#855 / epic #566).\n *\n * @example\n * ```ts\n * import { z } from \"zod\";\n * import { state, sensitive } from \"@rotorsoft/act\";\n *\n * const UserRegistered = z.object({\n *   email: sensitive(z.string()),\n *   name: sensitive(z.string()),\n *   plan: z.enum([\"free\", \"pro\"]),  // not sensitive — stays in events.data\n * });\n * ```\n *\n * @param schema - The Zod schema to mark sensitive.\n * @returns The same schema instance, unmodified at the type level.\n */\nexport function sensitive<T extends z.ZodType>(schema: T): T {\n  _registry.add(schema, { sensitive: true });\n  // Also stamp the def, so the marker survives the clone Zod produces for\n  // any refinement chained AFTER this call — `sensitive(z.string()).min(1)`\n  // used to lose it silently and write plaintext into `events.data` (#1417).\n  _mark_sensitive(schema);\n  return schema;\n}\n\n/**\n * Zod schema for an actor (user, system, etc.).\n */\nexport const ActorSchema = z\n  .object({\n    id: z.string(),\n    name: z.string(),\n  })\n  .loose()\n  .readonly();\n\n/**\n * Zod schema for a target (stream and actor info).\n */\nexport const TargetSchema = z\n  .object({\n    stream: z.string(),\n    actor: ActorSchema,\n    expectedVersion: z.number().optional(),\n  })\n  .loose()\n  .readonly();\n\n/**\n * Zod schema for causation event metadata.\n */\nexport const CausationEventSchema = z.object({\n  id: z.number(),\n  name: z.string(),\n  stream: z.string(),\n});\n\n/**\n * Zod schema for event metadata (correlation and causation).\n */\nexport const EventMetaSchema = z\n  .object({\n    correlation: z.string(),\n    causation: z.object({\n      action: TargetSchema.and(z.object({ name: z.string() })).optional(),\n      event: CausationEventSchema.optional(),\n    }),\n  })\n  .readonly();\n\n/**\n * Zod schema for committed event metadata (id, stream, version, created, meta).\n */\nexport const CommittedMetaSchema = z\n  .object({\n    id: z.number(),\n    stream: z.string(),\n    version: z.number(),\n    created: z.date(),\n    meta: EventMetaSchema,\n  })\n  .readonly();\n\n/**\n * Type representing the full state schema for a domain.\n * @property events - Map of event names to Zod schemas.\n * @property actions - Map of action names to Zod schemas.\n * @property state - Zod schema for the state object.\n */\nexport type StateSchema = Readonly<{\n  events: Record<string, ZodObject<ZodRawShape> | typeof ZodEmpty>;\n  actions: Record<string, ZodObject<ZodRawShape> | typeof ZodEmpty>;\n  state: ZodObject<ZodRawShape>;\n}>;\n\n/**\n * Query options for event store queries.\n */\nexport const QuerySchema = z\n  .object({\n    stream: z.string().optional(),\n    names: z.string().array().optional(),\n    before: z.number().optional(),\n    after: z.number().optional(),\n    limit: z.number().optional(),\n    created_before: z.date().optional(),\n    created_after: z.date().optional(),\n    backward: z.boolean().optional(),\n    correlation: z.string().optional(),\n    with_snaps: z.boolean().optional(),\n    stream_exact: z.boolean().optional(),\n  })\n  .readonly();\n","/**\n * @module sensitive\n * @category Internal\n *\n * Internal mechanics for the sensitive-data foundation (#855 / epic #566).\n * The public surface (`sensitive(zodType)`) lives at `libs/act/src/sensitive.ts`\n * and re-exports `REDACTED` / `SHREDDED` from here; this module holds the\n * registry plus the helpers the orchestrator calls during commit, load, and\n * handler dispatch.\n *\n * - `_registry` — process-global `z.registry<{ sensitive: true }>()`. Public\n *   `sensitive()` adds to it; the helpers in this module read it.\n * - `pii_fields(schema)` — walk a Zod schema's top-level shape, return the\n *   keys marked via `sensitive(...)`.\n * - `pii_gate(event, fields, predicate, actor)` — produce the external\n *   view: plaintext when authorized, `[REDACTED]` when not, `[SHREDDED]`\n *   when the underlying pii column is null.\n * - `pii_strip(event, fields)` — remove sensitive keys entirely\n *   before invoking projection / reaction handlers.\n *\n * @internal\n */\n\nimport { z } from \"zod\";\nimport type { Actor, Committed, Schemas } from \"../types/index.js\";\n\n/**\n * Sentinel placed in `event.data[field]` when the caller isn't authorized to\n * see the sensitive field — either `.discloses(predicate)` returned `false`,\n * or no predicate was declared (framework default-deny). Recoverable: a\n * properly-authorized read returns the plaintext.\n *\n * Re-exported from `libs/act/src/sensitive.ts` as part of the public surface.\n */\nexport const REDACTED = \"[REDACTED]\" as const;\n\n/**\n * Sentinel placed in `event.data[field]` when the underlying PII payload has\n * been wiped via `Store.forget_pii(stream)` — the row's pii column is `NULL`\n * and the original plaintext is gone forever. Irrecoverable.\n *\n * Re-exported from `libs/act/src/sensitive.ts` as part of the public surface.\n */\nexport const SHREDDED = \"[SHREDDED]\" as const;\n\n/**\n * Process-global registry holding every Zod schema marked sensitive. Backed\n * by a `WeakMap`, so wrapper-created instances (`.optional()`, `.nullable()`,\n * `.default()`) that chain off a marked schema produce *new* schema instances\n * the registry doesn't track; the field walker handles those via unwrap.\n *\n * Exported so the public `sensitive(zodType)` wrapper can call `_registry.add`.\n * Underscore prefix marks \"framework-private, don't touch from user code.\"\n *\n * @internal\n */\nexport const _registry = z.registry<{ sensitive: true }>();\n\n/**\n * Marker key stamped onto a schema's own `def`. Zod clones a schema on every\n * refinement (`.min()`, `.email()`, `.trim()`, `.describe()`, `.refine()`,\n * `.transform()`, …) via `{...def}`, which copies own symbol keys — so a\n * marker on the def survives the whole chain, while the `_registry` WeakMap\n * (keyed on the *instance*) does not (#1417).\n *\n * The registry is still populated and still consulted: it covers schemas\n * marked before this key existed, and it is the mechanism the public\n * `sensitive()` doc-comment describes.\n *\n * @internal\n */\nexport const _SENSITIVE = Symbol.for(\"act.sensitive\");\n\n/**\n * Stamp the def-level marker. Called by the public `sensitive()` alongside\n * `_registry.add`.\n *\n * @internal\n */\nexport function _mark_sensitive(schema: z.ZodType): void {\n  const def = (\n    schema as unknown as {\n      _zod?: { def?: Record<PropertyKey, unknown> };\n    }\n  )._zod?.def;\n  if (def) def[_SENSITIVE] = true;\n}\n\n/**\n * True when the given schema was marked via `sensitive(...)`.\n *\n * Walks through Zod wrapper layers (`.optional()`, `.nullable()`,\n * `.default()`, `.readonly()`) by following `_def.innerType` until it reaches\n * a non-wrapper schema, then checks the registry. Wrappers create new schema\n * instances; the marker lives on the *inner* schema the user wrapped, so we\n * test that one.\n *\n * @internal\n */\nexport function is_pii(schema: z.ZodType): boolean {\n  let cur: z.ZodType = schema;\n  while (true) {\n    if (_registry.has(cur)) return true;\n    // Def-level marker: survives the clone a refinement produces, which the\n    // instance-keyed registry above cannot (#1417).\n    const def = (\n      cur as unknown as {\n        _zod?: { def?: Record<PropertyKey, unknown> };\n      }\n    )._zod?.def;\n    if (def?.[_SENSITIVE] === true) return true;\n    const inner = (cur as { _def?: { innerType?: z.ZodType } })._def?.innerType;\n    if (!inner || inner === cur) return false;\n    cur = inner;\n  }\n}\n\n/**\n * Derive an event's sensitive fields, as the declared schema of each.\n *\n * Walks the top-level shape of a `z.object({...})` and keeps the keys whose\n * schema (after unwrapping optional/nullable/default wrappers) was marked via\n * `sensitive(...)`. Returns an empty object for non-object schemas or events\n * with no sensitive fields — the common-case zero-cost path.\n *\n * Only the top-level shape is walked. Sensitive fields nested inside a\n * `z.object` declared inside the event payload would require recursive\n * descent; that's deferred until a real callsite needs it.\n *\n * A union event has no top-level shape, so the options are walked and merged:\n * a key sensitive in any variant must be split, because the stored payload\n * could be that variant ([#1417](https://github.com/Rotorsoft/act-root/issues/1417)).\n * The first variant to declare a key wins, which only matters to a caller that\n * wants the schema rather than the name.\n *\n * Returning the schemas rather than just the names is what lets a caller do\n * something per field — the event builder asks each one whether it holds a\n * date, so the `pii` sidecar's dates can be revived like any other.\n *\n * @internal\n */\nexport function pii_schemas(schema: z.ZodType): Record<string, z.ZodType> {\n  const shape = (schema as { shape?: Record<string, z.ZodType> }).shape;\n  if (shape && typeof shape === \"object\") {\n    const fields: Record<string, z.ZodType> = {};\n    for (const key of Object.keys(shape))\n      if (is_pii(shape[key])) fields[key] = shape[key];\n    return fields;\n  }\n  const options = (schema as { options?: unknown }).options;\n  if (Array.isArray(options)) {\n    const fields: Record<string, z.ZodType> = {};\n    for (const option of options)\n      for (const [key, field] of Object.entries(\n        pii_schemas(option as z.ZodType)\n      ))\n        fields[key] ??= field;\n    return fields;\n  }\n  return {};\n}\n\n/**\n * The names of an event's sensitive fields — {@link pii_schemas} keyed.\n *\n * @internal — consumed by the registry's `sensitive_fields(event_name)` lookup,\n * and public through `types/schemas.ts`, where act-http's OpenAPI emitter uses\n * it to mark request-body properties `writeOnly`.\n */\nexport function pii_fields(schema: z.ZodType): readonly string[] {\n  return Object.keys(pii_schemas(schema));\n}\n\n/**\n * Split an emitted event's `data` into `data` (non-sensitive) + `pii`\n * (sensitive) using the field list precomputed at build time. Used by the\n * State's `_pii_split` decorator just before `Store.commit`.\n *\n * Single forward pass over `Object.keys(validated)` — same shape as the\n * spread-and-delete-free implementation in slice 3, just hoisted out of the\n * orchestrator hot path so it's only invoked when the State actually has a\n * sensitive event.\n *\n * @internal\n */\nexport function pii_split<TName, TData extends Record<string, unknown>>(\n  emitted: { name: TName; data: TData },\n  fields: readonly string[]\n): { name: TName; data: TData; pii: Record<string, unknown> } {\n  const data = { ...emitted.data };\n  const pii: Record<string, unknown> = {};\n  for (const f of fields) {\n    if (f in data) {\n      pii[f] = data[f];\n      delete data[f];\n    }\n  }\n  return { name: emitted.name, data, pii };\n}\n\n/**\n * Build the **external view** of a committed event — the form returned by\n * `load()`, `query()`, `query_array()`, and the snapshot in `do()`'s reply.\n *\n * Only ever reached for events that declare sensitive fields — the sole caller\n * is {@link make_gate}, which the builder invokes exclusively for sensitive\n * events; non-sensitive events short-circuit to {@link IDENTITY_GATE} before\n * they get here. `fields` is therefore guaranteed non-empty (same contract as\n * {@link pii_strip}).\n *\n * - Event whose `pii` payload is null/undefined → substitute {@link SHREDDED}\n *   for each declared field. Irrecoverable, so no predicate check.\n * - Event with a `pii` payload, predicate returns `true` → merge `pii` into\n *   `data` (plaintext).\n * - Event with a `pii` payload, predicate returns `false` OR no predicate\n *   declared (framework default-deny) → substitute {@link REDACTED} for each\n *   declared field.\n *\n * @internal\n */\nexport function pii_gate<TEvents extends Schemas, TKey extends keyof TEvents>(\n  event: Committed<TEvents, TKey>,\n  fields: readonly string[],\n  predicate: ((event: any, actor: Actor) => boolean) | null,\n  actor: Actor | undefined\n): Committed<TEvents, TKey> {\n  const data = event.data as Record<string, unknown>;\n  // The external view NEVER carries the isolated `pii` sidecar — dropping it\n  // is the whole point of the gate. Keeping it (an earlier `...event` spread)\n  // leaked plaintext PII on every gated read surface (`load`, `query`,\n  // `query_array`) even while `data` was correctly redacted (#1277). Strip it\n  // once here; the plaintext lives in `data` only on the authorized path.\n  const { pii, ...rest } = event as Committed<TEvents, TKey> & {\n    pii?: Record<string, unknown> | null;\n  };\n  if (pii == null) {\n    const shredded: Record<string, unknown> = { ...data };\n    for (const f of fields) shredded[f] = SHREDDED;\n    return { ...rest, data: shredded as Committed<TEvents, TKey>[\"data\"] };\n  }\n  // Plaintext path requires both an actor AND a predicate that allows. Missing\n  // either → default-deny → REDACTED.\n  const allowed = !!actor && !!predicate && predicate(event, actor);\n  if (allowed) {\n    return {\n      ...rest,\n      data: { ...data, ...pii } as Committed<TEvents, TKey>[\"data\"],\n    };\n  }\n  const redacted: Record<string, unknown> = { ...data };\n  for (const f of fields) redacted[f] = REDACTED;\n  return { ...rest, data: redacted as Committed<TEvents, TKey>[\"data\"] };\n}\n\n/**\n * A prebuilt per-event read gate: given a committed event and the reading\n * actor, return the caller-visible form. This is the single gating primitive\n * the builder prebuilds for **every** read surface — both the actor-less\n * `query` / `query_array` (which pass no actor → default-deny) and the\n * actor-aware `load` / `do`-return view (which pass the reader). Non-sensitive\n * events use the shared {@link IDENTITY_GATE}; sensitive events use a redactor\n * built by {@link make_gate} that closes over the field list and the state's\n * disclosure predicate, so the read path never recomputes the sensitive-field\n * lookup nor allocates per event.\n *\n * The `actor` is optional so the actor-less surfaces can call `gate(event)`.\n *\n * @internal\n */\nexport type EventGate = <TEvents extends Schemas, TKey extends keyof TEvents>(\n  event: Committed<TEvents, TKey>,\n  actor?: Actor\n) => Committed<TEvents, TKey>;\n\n/**\n * Shared zero-cost gate for every event with no `sensitive(...)` fields — a\n * single frozen reference the builder hands back for non-sensitive events, so\n * the common path is one `Map` miss and an identity call, no allocation. This\n * is the \"by default, return the event\" half of the prebuilt per-event gate.\n *\n * @internal\n */\nexport const IDENTITY_GATE: EventGate = (event) => event;\n\n/**\n * Prebuild a read gate for a sensitive event, capturing its field list and the\n * disclosure predicate once at build time. The returned closure defers to\n * {@link pii_gate} with the reading actor supplied per call:\n *\n * - `predicate = null` (the actor-less `query` surfaces, or a state that never\n *   declared `.discloses`) → default-deny: declared fields come back\n *   {@link REDACTED} (or {@link SHREDDED} once the pii column is forgotten).\n * - `predicate` set + an authorized actor → plaintext merged into `data`.\n *\n * Either way the isolated `pii` sidecar is dropped. The builder stores one gate\n * per sensitive event (per state for the load path; predicate-less for the\n * query path); non-sensitive events fall back to {@link IDENTITY_GATE}.\n *\n * @internal\n */\nexport function make_gate(\n  fields: readonly string[],\n  predicate: ((event: any, actor: Actor) => boolean) | null\n): EventGate {\n  return (event, actor) => pii_gate(event, fields, predicate, actor);\n}\n\n/**\n * Build the **handler view** — sensitive keys removed entirely from `data`\n * and the `pii` field dropped from the event. Used before invoking projection\n * handlers and reaction handlers, which never see PII by framework rule.\n *\n * Different from {@link pii_gate} (which substitutes {@link REDACTED} or\n * {@link SHREDDED}) — projection tables and reaction sinks shouldn't even\n * structurally observe the keys, so a handler that mistakenly writes\n * `event.data.email` into a column would get `undefined`, not a sentinel\n * string that looks like real data. The strictness is deliberate.\n *\n * Reactions that genuinely need PII (e.g. a welcome-email reaction reading\n * `email`) opt back in by explicitly calling `app.load(stream, { actor:\n * system_actor })` inside the handler — pulling PII through the gate at the\n * call site makes the security-relevant path visible in code review.\n *\n * @internal\n */\nexport function pii_strip<\n  TEvents extends Schemas,\n  TKey extends keyof TEvents & string,\n>(\n  event: Committed<TEvents, TKey>,\n  fields: readonly string[]\n): Committed<TEvents, TKey> {\n  // Contract: `fields` is non-empty. `build_handle` / `build_handle_batch`\n  // filter on `fields.length > 0` before invocation.\n  const data = event.data as Record<string, unknown>;\n  const stripped: Record<string, unknown> = {};\n  for (const k of Object.keys(data)) {\n    if (!fields.includes(k)) stripped[k] = data[k];\n  }\n  const { pii: _drop_pii, ...rest } = event as Committed<TEvents, TKey> & {\n    pii?: unknown;\n  };\n  return {\n    ...rest,\n    data: stripped as Committed<TEvents, TKey>[\"data\"],\n  } as Committed<TEvents, TKey>;\n}\n","/**\n * @packageDocumentation\n * @module act/types\n * Barrel file for Act Framework core types.\n *\n * Re-exports all major type definitions for actions, errors, ports, reactions, registries, and schemas.\n * Also defines common environment and log level types/constants for configuration and logging.\n *\n * @remarks\n * Import from this module to access all core framework types in one place.\n */\nexport type * from \"./action.js\";\nexport type * from \"./audit.js\";\nexport * from \"./errors.js\";\nexport type * from \"./ports.js\";\nexport type * from \"./reaction.js\";\nexport type * from \"./registry.js\";\nexport * from \"./schemas.js\";\n\n/**\n * Supported runtime environments for the framework.\n * - `development`: Local development\n * - `test`: Automated testing\n * - `staging`: Pre-production\n * - `production`: Live/production\n */\nexport const Environments = [\n  \"development\",\n  \"test\",\n  \"staging\",\n  \"production\",\n] as const;\n\n/**\n * Type representing a valid environment string.\n */\nexport type Environment = (typeof Environments)[number];\n\n/**\n * Supported log levels for framework logging.\n * - `fatal`, `error`, `warn`, `info`, `debug`, `trace`\n */\nexport const LogLevels = [\n  \"fatal\",\n  \"error\",\n  \"warn\",\n  \"info\",\n  \"debug\",\n  \"trace\",\n] as const;\n\n/**\n * Type representing a valid log level string.\n */\nexport type LogLevel = (typeof LogLevels)[number];\n","import { prettifyError, ZodError, type ZodType } from \"zod\";\nimport { config } from \"./config.js\";\nimport { ValidationError } from \"./types/index.js\";\n\n/**\n * @module utils\n * @category Utilities\n *\n * Small utilities used across the framework:\n * - {@link validate} — parse a payload against a Zod schema, throwing\n *   {@link ValidationError} on failure.\n * - {@link extend} — validate a source object and merge into defaults.\n * - {@link sleep} — async delay (default duration from `config().sleepMs`).\n */\n\n/**\n * Parse `payload` against `schema`, returning the validated value or throwing\n * a {@link ValidationError} with prettified Zod details. When `schema` is\n * omitted, returns `payload` unchanged. The framework calls this for every\n * `app.do()` action, every emitted event, and every state init.\n *\n * @example\n * ```typescript\n * const UserSchema = z.object({ email: z.string().email() });\n * const user = validate(\"User\", { email: \"alice@example.com\" }, UserSchema);\n * ```\n *\n * @see {@link ValidationError}\n */\nexport const validate = <S>(\n  target: string,\n  payload: Readonly<S>,\n  schema?: ZodType<S>\n): Readonly<S> => {\n  try {\n    return schema ? schema.parse(payload) : payload;\n  } catch (error) {\n    if (error instanceof ZodError) {\n      throw new ValidationError(target, payload, prettifyError(error));\n    }\n    throw new ValidationError(target, payload, error);\n  }\n};\n\n/**\n * Validate `source` against `schema` and return a new object that merges\n * `source` over the optional `target` defaults. Used by {@link config} for\n * env-var-overrides-defaults patterns; safe to call elsewhere — it never\n * mutates `target`.\n *\n * @example\n * ```typescript\n * const schema = z.object({ host: z.string(), port: z.number() });\n * const cfg = extend({ port: 8080 }, schema, { host: \"localhost\", port: 80 });\n * // → { host: \"localhost\", port: 8080 }\n * ```\n *\n * @throws {@link ValidationError} if `source` fails the schema.\n */\nexport const extend = <\n  S extends Record<string, unknown>,\n  T extends Record<string, unknown>,\n>(\n  source: Readonly<S>,\n  schema: ZodType<S>,\n  target?: Readonly<T>\n): Readonly<S & T> => {\n  const value = validate(\"config\", source, schema);\n  return { ...target, ...value } as Readonly<S & T>;\n};\n\n/**\n * Pause for `ms` milliseconds (or `config().sleepMs` when omitted — `100ms`\n * in dev, `0ms` in tests). Used by adapters to simulate async I/O.\n *\n * @example\n * ```typescript\n * await sleep();      // default delay from config\n * await sleep(500);   // explicit 500ms\n * ```\n */\nexport async function sleep(ms?: number) {\n  return new Promise((resolve) => setTimeout(resolve, ms ?? config().sleepMs));\n}\n\n/**\n * Regex metacharacters that, when present in a reaction `source`, make it a\n * pattern rather than a literal stream name. A source containing none of\n * these is a bare stream name — the common case — and every claim/fetch\n * site matches it by string equality on the store's stream index. A source\n * containing any of them is compiled as a RegExp and matched against\n * candidate streams with the caller's own anchoring (e.g. `^(A|B)$`).\n */\nconst SOURCE_METACHARACTERS = /[\\^$.*+?()[\\]{}|\\\\]/;\n\n/**\n * True when `source` is a **literal** stream name — it carries no regex\n * metacharacter, so every adapter treats it as an exact match. This is the\n * fast, index-friendly path and covers every autoclose/dynamic-resolver\n * source (bare stream names). A `false` return means the source is a\n * **pattern** (contains `^ $ . * + ? ( ) [ ] { } | \\`) and must be compiled\n * as a RegExp before matching — the shape the calculator's static\n * `source: \"^(A|B)$\"` reaction relies on.\n *\n * The single source of truth for literal-vs-pattern classification across\n * the InMemory has-work probe, the drain fetch path, and the SQL adapters,\n * so all three agree on which sources take the exact path.\n *\n * @example\n * ```typescript\n * is_literal_source(\"Board\");    // → true  (exact lookup)\n * is_literal_source(\"^(A|B)$\");  // → false (compile as RegExp)\n * ```\n */\nexport function is_literal_source(source: string): boolean {\n  return !SOURCE_METACHARACTERS.test(source);\n}\n\n/**\n * Matches an ISO-8601 timestamp, the shape `JSON.stringify` produces for a\n * `Date`.\n *\n * @internal\n */\nconst ISO_8601 =\n  /^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\\.\\d+)?(Z|[+-][0-2][0-9]:[0-5][0-9])?$/;\n\n/**\n * Revive ISO-8601-shaped strings into `Date`s during `JSON.parse`.\n *\n * **The framework no longer uses this.** Dates are resolved from the declared\n * `z.date()` paths at build time and converted on read, so a field declared\n * `z.string()` keeps its string even when the value looks like a timestamp\n * ([#1556](https://github.com/Rotorsoft/act-root/issues/1556)). Adapters\n * return what they stored; typing is the orchestrator's job.\n *\n * Kept exported for host applications that parse Act JSON themselves and want\n * the old shape-based behaviour. New code should let the schema decide.\n *\n */\nexport const dateReviver = (_key: string, value: unknown): unknown =>\n  typeof value === \"string\" && ISO_8601.test(value) ? new Date(value) : value;\n","/**\n * @module scoped\n * @category Internal\n *\n * Ambient execution context — every `AsyncLocalStorage` the framework owns\n * lives here, and so does every operation on one. No other module calls\n * `.run()` or `.getStore()`; they ask for a runner or a reader instead, so\n * this file is the single place to look at the abstraction.\n *\n * Two contexts:\n *\n * - **ports** — the active Act's store/cache bag, so `store()` / `cache()`\n *   resolve per-Act rather than per-process (ACT-501). Installed by the\n *   orchestrator via {@link make_run_scoped}, read by the port singletons\n *   via {@link current_ports}.\n * - **reaction** — the event a handler is processing, so a dispatch made\n *   anywhere inside that handler can thread `reactingTo` whichever `IAct`\n *   reference made the call (#1541). Installed via {@link run_reacting},\n *   read at the orchestrator boundary via {@link current_reacting}.\n *\n * Keeping the mechanics here keeps ambient state out of `internal/`, whose\n * modules are stateless implementations that receive what they need.\n *\n * @internal\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type {\n  Actor,\n  Cache,\n  Committed,\n  IAct,\n  Schemas,\n  Store,\n} from \"./types/index.js\";\n\n/** Per-Act ports bag (ACT-501). Both required together — a shared cache across stores would collide on stream keys. */\nexport type Scoped = {\n  readonly store: Store;\n  readonly cache: Cache;\n};\n\n/**\n * What an Act actually installs in its frame: the ports a caller passed,\n * plus per-Act settings that runtime code has to read from the *running*\n * Act rather than from whatever closure it was built in.\n *\n * `autoclose_window` is here because the autoclose reactions are\n * synthesized once into the shared registry and handed by reference to\n * every Act built from that builder, so a window captured at synthesis is\n * the first tenant's window for everyone (#1615). The frame is per-Act, so\n * reading it here is what makes the setting per-Act too.\n *\n * Wider than {@link Scoped} on purpose: `Scoped` types what a caller\n * *passes* through `ActOptions.scoped` and is public; this is what the\n * orchestrator *installs* and is not.\n *\n * @internal\n */\nexport type ActFrame = Scoped & {\n  readonly autoclose_window?: {\n    readonly start: number;\n    readonly end: number;\n    readonly timeZone: string;\n  };\n};\n\n/**\n * AsyncLocalStorage carrying the active Act's ports.\n *\n * Exported for in-repo tooling that measures the context itself (the\n * scope-overhead bench). NOT public: `ports.ts` no longer re-exports it and\n * `index.ts` reaches this module only for the `Scoped` type, so it is not\n * importable from the package. Everything else uses the helpers below.\n */\nexport const scoped = new AsyncLocalStorage<ActFrame>();\n\n/**\n * The reaction currently running, as a box the handler can empty.\n *\n * A frame captured by work the handler started and did not await outlives the\n * handler and can never be unbound. The *frame* is unreclaimable, but the\n * *box inside it* is not: clearing `event` as the handler settles turns every\n * later read through that frame into \"no reaction\", without anyone having to\n * ask a second question (#1562).\n *\n * Not reachable from `index.ts`.\n */\ntype Reacting = { event: Committed<Schemas, string> | undefined };\n\nconst reacting = new AsyncLocalStorage<Reacting>();\n\n/**\n * Builds the runner an Act uses to enter its own port scope.\n *\n * Every Act gets a frame, including one built without `ActOptions.scoped` —\n * that one carries the singleton adapters (see `default_scope` in `ports.ts`).\n * Entering unconditionally is what makes an Act's ports its own: a runner that\n * collapsed to `fn()` for a singleton Act did not leave whatever frame it was\n * called from, so dispatching into a shared Act from inside a tenant's handler\n * resolved `store()` to that tenant and wrote the shared Act's events into the\n * tenant's log ([#1597](https://github.com/Rotorsoft/act-root/issues/1597)).\n *\n * @internal\n */\nexport function make_run_scoped(\n  bag: ActFrame\n): <T>(fn: () => Promise<T>) => Promise<T> {\n  return (fn) => scoped.run(bag, fn);\n}\n\n/**\n * The running Act's off-hours autoclose window, or `undefined` when it\n * declared none (or when read outside any Act).\n *\n * Read at resolution time rather than captured at synthesis: the autoclose\n * reactions belong to the shared registry, and only the frame knows which\n * Act is running them (#1615).\n *\n * @internal\n */\nexport function current_autoclose_window(): ActFrame[\"autoclose_window\"] {\n  return scoped.getStore()?.autoclose_window;\n}\n\n/**\n * The active Act's ports, or `undefined` outside any Act.\n *\n * Every Act runs in a frame, so this is `undefined` only for a call made\n * outside one — `store()` and `cache()` fall back to the singleton adapters\n * there, which is what a bare `store()` in application setup expects.\n *\n * @internal\n */\nexport function current_ports(): Scoped | undefined {\n  return scoped.getStore();\n}\n\n/**\n * Runs `fn` with `event` installed as the triggering-event context.\n *\n * Entered per payload rather than per lease: the context has to unwind with\n * the handler so it never reaches the drain cycle, and work a handler started\n * without awaiting has to resume into its own event's frame.\n *\n * @internal\n */\nexport function run_reacting<T>(\n  event: Committed<Schemas, string>,\n  fn: () => Promise<T>\n): Promise<T> {\n  const box: Reacting = { event };\n  return reacting.run(box, async () => {\n    try {\n      return await fn();\n    } finally {\n      // Anything still running keeps this frame; from here it reads empty.\n      box.event = undefined;\n    }\n  });\n}\n\n/**\n * The event being reacted to, or `undefined` outside a running handler —\n * including inside work that outlived one.\n *\n * @internal\n */\nexport function current_reacting(): Committed<Schemas, string> | undefined {\n  return reacting.getStore()?.event;\n}\n\n/**\n * Everything a reaction handler runs inside: the `IAct` facade it is handed\n * as its third argument, and the triggering-event context that every dispatch\n * made within it resolves — including one through a captured `app`.\n *\n * Built here rather than in the dispatcher so the dispatcher never has to\n * know how either half works; it receives this whole and calls it.\n *\n * @internal\n */\nexport type ReactionScope<\n  TEvents extends Schemas,\n  TActions extends Schemas,\n  TActor extends Actor = Actor,\n> = {\n  readonly app: IAct<TEvents, TActions, TActor>;\n  readonly run: <T>(\n    event: Committed<Schemas, string>,\n    fn: () => Promise<T>\n  ) => Promise<T>;\n};\n\n/**\n * Assembles the reaction scope from the orchestrator's bound `IAct` methods.\n *\n * @internal\n */\nexport function make_reaction_scope<\n  TEvents extends Schemas,\n  TActions extends Schemas,\n  TActor extends Actor = Actor,\n>(\n  app: IAct<TEvents, TActions, TActor>\n): ReactionScope<TEvents, TActions, TActor> {\n  return { app, run: run_reacting };\n}\n","import { ConsoleLogger } from \"./adapters/console-logger.js\";\nimport { InMemoryCache } from \"./adapters/in-memory-cache.js\";\nimport { InMemoryStore } from \"./adapters/in-memory-store.js\";\nimport { config } from \"./config.js\";\nimport { register_disposer, run_disposers } from \"./disposers.js\";\nimport { current_ports, type Scoped } from \"./scoped.js\";\nimport type {\n  Cache,\n  Disposable,\n  Disposer,\n  Logger,\n  Store,\n} from \"./types/index.js\";\n\n// `Scoped` is the type of the public `ActOptions.scoped` bag, so it stays\n// exported. The AsyncLocalStorage carrying it does not: it is a mechanism,\n// it was only ever reachable because `index.ts` star-exports this module,\n// and its own doc-comment already declared it internal.\nexport type { Scoped } from \"./scoped.js\";\n\n/**\n * Port/adapter infrastructure for the Act framework.\n *\n * All infrastructure concerns (logging, storage, caching) are managed as\n * singleton adapters injected via port functions. Each port follows the same\n * pattern: first call wins with a sensible default, optional adapter injection.\n *\n * - `log()` — structured logging (default: ConsoleLogger)\n * - `store()` — event persistence (default: InMemoryStore)\n * - `cache()` — state checkpoints (default: InMemoryCache)\n * - `dispose()` — register cleanup functions for graceful shutdown\n *\n * @module ports\n */\n\n/**\n * List of exit codes for process termination. Consumed by signal handlers\n * and {@link disposeAndExit}; not part of the user-facing surface.\n *\n * @internal\n */\nexport const ExitCodes = [\"ERROR\", \"EXIT\"] as const;\n\n/**\n * Type for allowed exit codes.\n *\n * - `\"ERROR\"` — abnormal termination (uncaught exception, unhandled rejection)\n * - `\"EXIT\"` — clean shutdown (SIGINT, SIGTERM, or manual trigger)\n *\n * @internal\n */\nexport type ExitCode = (typeof ExitCodes)[number];\n\n// ---------------------------------------------------------------------------\n// Port factory\n// ---------------------------------------------------------------------------\n\n/**\n * Factory function that creates or returns the injected adapter.\n * @internal\n */\ntype Injector<Port extends Disposable> = (adapter?: Port) => Port;\n\n/** Singleton adapter registry, keyed by injector function name. */\nconst adapters = new Map<string, Disposable>();\n\n/**\n * Creates a singleton port with optional adapter injection.\n *\n * The first call initializes the adapter (using the provided adapter or the\n * injector's default). Subsequent calls return the cached singleton. Adapters\n * are disposed in reverse registration order during {@link disposeAndExit}.\n *\n * @param injector - Named function that creates the default adapter\n * @returns Port function: call with no args to get the singleton, or pass an\n *          adapter on the first call to override the default\n *\n * @example\n * ```typescript\n * const store = port(function store(adapter?: Store) {\n *   return adapter || new InMemoryStore();\n * });\n * const s = store(); // InMemoryStore\n * ```\n */\nexport function port<Port extends Disposable>(injector: Injector<Port>) {\n  return (adapter?: Port): Port => {\n    if (!adapters.has(injector.name)) {\n      const injected = injector(adapter);\n      adapters.set(injector.name, injected);\n      // log() is now in adapters (or this IS the log port we just registered),\n      // so the recursive call resolves immediately. Routing through the logger\n      // means level gating (e.g. silenced in tests at fatal) takes effect.\n      log().info(`[act] + ${injector.name}:${injected.constructor.name}`);\n    }\n    return adapters.get(injector.name) as Port;\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Ports: log, store, cache\n// ---------------------------------------------------------------------------\n\n/**\n * Gets or injects the singleton logger.\n *\n * By default, Act uses a built-in {@link ConsoleLogger} that emits JSON lines\n * in production (compatible with GCP, AWS CloudWatch, Datadog) and colorized\n * output in development — zero external dependencies.\n *\n * For pino, inject a `PinoLogger` from `@rotorsoft/act-pino` before building\n * your application.\n *\n * @param adapter - Optional logger implementation to inject\n * @returns The singleton logger instance\n *\n * @example Default console logger\n * ```typescript\n * import { log } from \"@rotorsoft/act\";\n * const logger = log();\n * logger.info(\"Application started\");\n * ```\n *\n * @example Injecting pino\n * ```typescript\n * import { log } from \"@rotorsoft/act\";\n * import { PinoLogger } from \"@rotorsoft/act-pino\";\n * log(new PinoLogger({ level: \"debug\", pretty: true }));\n * ```\n *\n * @see {@link Logger} for the interface contract\n * @see {@link ConsoleLogger} for the default implementation\n */\nexport const log = port(function log(adapter?: Logger) {\n  const cfg = config();\n  return (\n    adapter ||\n    new ConsoleLogger({\n      level: cfg.logLevel,\n      pretty: cfg.env !== \"production\",\n    })\n  );\n});\n\n/**\n * Gets or injects the singleton event store.\n *\n * By default, Act uses an {@link InMemoryStore} suitable for development and\n * testing. For production, inject a persistent store like `PostgresStore` from\n * `@rotorsoft/act-pg` before building your application.\n *\n * **Important:** Store injection must happen before creating any Act instances.\n * Once set, the store cannot be changed without restarting the application.\n *\n * @param adapter - Optional store implementation to inject\n * @returns The singleton store instance\n *\n * @example Default in-memory store\n * ```typescript\n * import { store } from \"@rotorsoft/act\";\n * const s = store();\n * ```\n *\n * @example Injecting PostgreSQL\n * ```typescript\n * import { store } from \"@rotorsoft/act\";\n * import { PostgresStore } from \"@rotorsoft/act-pg\";\n *\n * store(new PostgresStore({\n *   host: \"localhost\",\n *   port: 5432,\n *   database: \"myapp\",\n *   user: \"postgres\",\n *   password: \"secret\",\n * }));\n * ```\n *\n * @see {@link Store} for the interface contract\n * @see {@link InMemoryStore} for the default implementation\n */\n// ALS check lives outside `port()` — its cache fires only once, so the\n// per-call branch on a scoped Act has to be in the public wrapper.\nconst _store = port(function store(adapter?: Store): Store {\n  return adapter ?? new InMemoryStore();\n});\n\nexport const store = ((adapter?: Store): Store => {\n  return current_ports()?.store ?? _store(adapter);\n}) as (adapter?: Store) => Store;\n\n/**\n * Gets or injects the singleton cache.\n *\n * By default, Act uses an {@link InMemoryCache} (LRU, maxSize 1000). For\n * distributed deployments, inject a Redis-backed cache before building your\n * application.\n *\n * @param adapter - Optional cache implementation to inject\n * @returns The singleton cache instance\n *\n * @see {@link Cache} for the interface contract\n * @see {@link InMemoryCache} for the default implementation\n */\nconst _cache = port(function cache(adapter?: Cache) {\n  return adapter ?? new InMemoryCache();\n});\n\nexport const cache = ((adapter?: Cache): Cache => {\n  return current_ports()?.cache ?? _cache(adapter);\n}) as (adapter?: Cache) => Cache;\n\n/**\n * The ports bag an Act without `ActOptions.scoped` runs in: the singleton\n * adapters, read through the same frame a scoped Act uses.\n *\n * Every Act entering a frame is what keeps its ports its own. Without one, a\n * shared Act called from inside a tenant's handler inherited that tenant's\n * frame and committed to the tenant's store (#1597).\n *\n * The properties are getters on purpose. The adapters are resolved lazily and\n * injected after `act().build()` in the normal case — `store(new PgStore())`\n * in application setup, or a test's `beforeEach` — so capturing them when the\n * bag is made would pin whatever existed at build time. They read the raw\n * resolvers rather than the public `store()`/`cache()`, which consult the\n * frame this bag *is* and would recurse.\n *\n * @internal\n */\nexport const default_scope = (): Scoped => DEFAULT_SCOPE;\n\nconst DEFAULT_SCOPE: Scoped = {\n  get store() {\n    return _store();\n  },\n  get cache() {\n    return _cache();\n  },\n};\n\n// ---------------------------------------------------------------------------\n// Disposal\n// ---------------------------------------------------------------------------\n\n/**\n * Registered cleanup functions live in `disposers.ts`, which holds\n * lifetime-bound entries weakly so registering never pins its target for the\n * process lifetime (#1441). The public surface here is unchanged.\n */\n\n/**\n * Disposes all registered adapters and disposers, then exits the process.\n *\n * Execution order:\n * 1. Custom disposers (registered via {@link dispose}) — in reverse order\n * 2. Port adapters (log, store, cache) — in reverse registration order\n * 3. Adapter registry is cleared\n * 4. Process exits (skipped in test environment)\n *\n * In production, `\"ERROR\"` exits are silently ignored to avoid crashing on\n * transient failures (e.g. an uncaught promise in a non-critical path).\n *\n * @param code - Exit code: `\"EXIT\"` for clean shutdown (exit 0),\n *               `\"ERROR\"` for abnormal termination (exit 1)\n */\nexport async function disposeAndExit(code: ExitCode = \"EXIT\"): Promise<void> {\n  if (code === \"ERROR\" && config().env === \"production\") {\n    // Surface the swallow so incident triage can see it. Without this\n    // log the framework looks unresponsive after an uncaught exception\n    // in prod — exactly when operators most need a breadcrumb.\n    log().warn(\n      \"disposeAndExit('ERROR') ignored in production — process kept alive\"\n    );\n    return;\n  }\n\n  // Run sequentially in reverse registration order so a disposer can rely on\n  // later-registered disposers (and adapters on later-registered adapters)\n  // having already finished — Promise.all would race them.\n  await run_disposers();\n  for (const adapter of [...adapters.values()].reverse()) {\n    await adapter.dispose();\n    log().info(`[act] - ${adapter.constructor.name}`);\n  }\n  adapters.clear();\n  config().env !== \"test\" && process.exit(code === \"ERROR\" ? 1 : 0);\n}\n\n/**\n * Registers a cleanup function for graceful shutdown.\n *\n * Disposers are called automatically on SIGINT, SIGTERM, uncaught exceptions,\n * and unhandled rejections. They execute in reverse registration order before\n * port adapters are disposed.\n *\n * @param disposer - Async function to call during cleanup. Omit to get a\n *                   reference to {@link disposeAndExit} without registering.\n * @returns Function to manually trigger disposal and exit\n *\n * @example\n * ```typescript\n * import { dispose } from \"@rotorsoft/act\";\n *\n * const db = connectDatabase();\n * dispose(async () => await db.close());\n *\n * // In tests\n * afterAll(async () => await dispose()());\n * ```\n *\n * @see {@link disposeAndExit} for the full shutdown sequence\n */\nexport function dispose(\n  disposer?: Disposer\n): (code?: ExitCode) => Promise<void> {\n  disposer && register_disposer(disposer);\n  return disposeAndExit;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * Event name used internally for snapshot events in the event store.\n * Snapshot events store a full state checkpoint, enabling efficient cold-start\n * recovery without replaying the entire event stream.\n */\nexport const SNAP_EVENT = \"__snapshot__\";\n\n/**\n * Event name used internally for tombstone events in the event store.\n * A tombstone marks a stream as permanently closed — no further writes\n * are permitted until the stream is explicitly restarted via `close()`.\n *\n * @see {@link Act.close} for the close-the-books API\n */\nexport const TOMBSTONE_EVENT = \"__tombstone__\";\n\n/**\n * Name of the implicit lane every reaction lands in unless its `.to({lane})`\n * declaration says otherwise (ACT-1103). Acts that don't call\n * `.withLane(...)` see only this lane, and behavior is identical to\n * pre-1103 single-controller drain.\n *\n * Persisted on `streams.lane` and threaded as the strict-typed default in\n * builder generics — `lane?: TLanes` always includes `\"default\"`.\n */\nexport const DEFAULT_LANE = \"default\";\n","/**\n * @packageDocumentation\n * @module act/adapters\n * In-memory event store adapter for the Act Framework.\n *\n * This adapter implements the Store interface and is suitable for development, testing, and demonstration purposes.\n * All data is stored in memory and lost on process exit.\n *\n * @category Adapters\n */\n\nimport { DEFAULT_LANE, SNAP_EVENT, TOMBSTONE_EVENT } from \"../ports.js\";\nimport { ConcurrencyError } from \"../types/errors.js\";\nimport type {\n  BlockedLease,\n  Committed,\n  EventMeta,\n  Lease,\n  Message,\n  Query,\n  QueryStatsOptions,\n  QueryStreams,\n  QueryStreamsResult,\n  Schema,\n  Schemas,\n  Store,\n  StreamFilter,\n  StreamPosition,\n  StreamStats,\n  SubscribeInput,\n} from \"../types/index.js\";\nimport { sleep } from \"../utils.js\";\n\n/**\n * @internal\n * Represents an in-memory stream for event processing and leasing.\n */\nclass InMemoryStream {\n  readonly stream: string;\n  readonly source: string | undefined;\n  private _at = -1;\n  private _retry = -1;\n  private _blocked = false;\n  private _error = \"\";\n  private _leased_by: string | undefined = undefined;\n  private _leased_until: Date | undefined = undefined;\n  private _priority = 0;\n  private _lane: string = DEFAULT_LANE;\n  // Persisted next-visit time (#1090). When set and still in the future, the\n  // stream is held out of `claim` entirely — so a deferred reaction is not\n  // re-claimed (and `retry` is never bumped) until its due-time passes. Unlike\n  // in-process backoff, this is durable store state shared across workers.\n  private _deferred_at: number | undefined = undefined;\n  // Work mark (#1485): highest event id observed to resolve to this target.\n  // `undefined` means UNKNOWN — the row predates the mark, so `claim` falls\n  // back to the legacy has-work probe rather than treating it as \"no work\".\n  private _correlated_at: number | undefined = undefined;\n\n  constructor(\n    stream: string,\n    source: string | undefined,\n    priority = 0,\n    lane: string = DEFAULT_LANE\n  ) {\n    this.stream = stream;\n    this.source = source;\n    this._priority = priority;\n    this._lane = lane;\n  }\n\n  get priority() {\n    return this._priority;\n  }\n\n  get lane() {\n    return this._lane;\n  }\n\n  /** Replace on every subscribe — current builder config wins on restart. */\n  set lane(value: string) {\n    this._lane = value;\n  }\n\n  /**\n   * Bump the priority via {@link subscribe}: keeps the maximum across\n   * reactions so the highest-priority registrant wins.\n   */\n  bump_priority(priority: number) {\n    if (priority > this._priority) this._priority = priority;\n  }\n\n  get correlated_at() {\n    return this._correlated_at;\n  }\n\n  /**\n   * Raise the work mark via {@link subscribe}: keeps the maximum, for every\n   * value including zero and negatives, so a mark never regresses.\n   */\n  mark(correlated_at: number) {\n    if (\n      this._correlated_at === undefined ||\n      correlated_at > this._correlated_at\n    )\n      this._correlated_at = correlated_at;\n  }\n\n  /**\n   * Set the priority outright via {@link prioritize}: operator\n   * runtime override that ignores the build-time `max()` invariant.\n   */\n  set_priority(priority: number) {\n    this._priority = priority;\n  }\n\n  get is_available() {\n    return (\n      !this._blocked &&\n      (!this._leased_until || this._leased_until <= new Date()) &&\n      // A stream deferred to a future time is not claimable until due (#1090).\n      (!this._deferred_at || this._deferred_at <= Date.now())\n    );\n  }\n\n  /**\n   * Hold this stream out of `claim` until `deferred_at` (ms since epoch).\n   * Set by a deliberate `defer` outcome — not a failure, so retry/blocked\n   * state is untouched. Cleared by ack/block/reset/unblock.\n   */\n  defer(deferred_at: number) {\n    this._deferred_at = deferred_at;\n    // A defer is not a failure: reset retry so the redelivery after the\n    // due-time is a fresh attempt, never accumulating toward maxRetries.\n    this._retry = -1;\n  }\n\n  get at() {\n    return this._at;\n  }\n\n  get retry() {\n    return this._retry;\n  }\n\n  get blocked() {\n    return this._blocked;\n  }\n\n  get error() {\n    return this._error;\n  }\n\n  get leased_by() {\n    return this._leased_by;\n  }\n\n  get leased_until() {\n    return this._leased_until;\n  }\n\n  /** Persisted next-visit time (#1090/#1221), or undefined when no active defer. */\n  get deferred_at() {\n    return this._deferred_at;\n  }\n\n  /**\n   * Attempt to lease this stream for processing.\n   * @param lease - The lease request.\n   * @param millis - Lease duration in milliseconds.\n   * @returns The granted lease or undefined if blocked.\n   */\n  lease(lease: Lease, millis: number): Lease {\n    // The holder is recorded whatever the duration, matching both SQL\n    // adapters. `millis` governs only how long the lease stands: a\n    // zero-length one expires the instant it is granted, so the stream is\n    // immediately re-claimable — but `ack` is gated on the holder, and a\n    // lease granted with no holder recorded is one whose every ack is\n    // dropped, leaving the watermark parked and every event redelivered.\n    this._leased_by = lease.by;\n    this._leased_until = new Date(Date.now() + millis);\n    this._retry = this._retry + 1;\n    return {\n      stream: this.stream,\n      source: this.source,\n      at: lease.at,\n      by: lease.by,\n      retry: this._retry,\n      lagging: lease.lagging,\n      lane: this._lane,\n    };\n  }\n\n  /**\n   * Finalize this stream's lease: ack (advance the watermark) or, when the\n   * lease carries a `due` marker, defer (persist the schedule, hold the\n   * watermark) — see {@link Store.ack}.\n   * @param lease - The lease request.\n   */\n  ack(lease: Lease) {\n    if (this._leased_by === lease.by) {\n      this._leased_by = undefined;\n      this._leased_until = undefined;\n      if (lease.due !== undefined) {\n        // Due marker: advance the watermark past the events handled this cycle\n        // (`lease.at`) AND schedule the re-visit, persisting the caller's\n        // retry — advance and defer are independent legs (#1278). Advancing\n        // means the succeeded prefix never re-runs on redelivery. An explicit\n        // defer passes `retry: -1` (a defer is not a failure); a backoff retry\n        // passes the climbing counter so it keeps accruing toward the block\n        // threshold across windows (#1262). Deferred entries are not part of\n        // ack's return value.\n        this._at = lease.at;\n        this._retry = lease.retry;\n        this._deferred_at = lease.due;\n        return undefined;\n      }\n      // A successful ack clears the retry budget and any pending defer.\n      this._retry = -1;\n      this._at = lease.at;\n      this._deferred_at = undefined;\n      return {\n        stream: this.stream,\n        source: this.source,\n        at: this._at,\n        by: lease.by,\n        retry: this._retry,\n        lagging: lease.lagging,\n        lane: this._lane,\n      };\n    }\n  }\n\n  /**\n   * Block a stream for processing after failing to process and reaching max retries with blocking enabled.\n   * @param lease - The lease request.\n   * @param error Blocked error message.\n   */\n  block(lease: Lease, error: string) {\n    // Skip already-blocked streams so a redundant block is a no-op, mirroring\n    // the SQL adapters' `WHERE ... AND blocked = false` guard (#1263). Without\n    // this, re-blocking returns the lease again and emits a spurious duplicate\n    // `blocked` lifecycle event that the durable stores suppress.\n    if (this._leased_by === lease.by && !this._blocked) {\n      this._blocked = true;\n      this._error = error;\n      // A blocked stream is poison; clear any pending defer (#1090).\n      this._deferred_at = undefined;\n      return {\n        stream: this.stream,\n        source: this.source,\n        at: this._at,\n        by: this._leased_by,\n        retry: this._retry,\n        error: this._error,\n        lagging: lease.lagging,\n        lane: this._lane,\n      };\n    }\n  }\n\n  /**\n   * Reset this stream's watermark and state for replay. The retry counter\n   * resets to -1 to match the constructor + ack() invariant (\"released\n   * stream\"); the next claim() bumps it to 0 (first attempt).\n   */\n  reset() {\n    this._at = -1;\n    this._retry = -1;\n    this._blocked = false;\n    this._error = \"\";\n    this._leased_by = undefined;\n    this._leased_until = undefined;\n    this._deferred_at = undefined;\n  }\n\n  /**\n   * Clear the blocked flag and lease bookkeeping without touching the\n   * watermark. Returns true if the stream was actually blocked (and is\n   * now flipped); false otherwise.\n   */\n  unblock(): boolean {\n    if (!this._blocked) return false;\n    this._blocked = false;\n    this._retry = -1;\n    this._error = \"\";\n    this._leased_by = undefined;\n    this._leased_until = undefined;\n    this._deferred_at = undefined;\n    return true;\n  }\n}\n\n/**\n * In-memory event store implementation.\n *\n * This is the default store used by Act when no other store is injected.\n * It stores all events in memory and is suitable for:\n * - Development and prototyping\n * - Unit and integration testing\n * - Demonstrations and examples\n *\n * **Not suitable for production** - all data is lost when the process exits.\n * Use {@link PostgresStore} for production deployments.\n *\n * The in-memory store provides:\n * - Full {@link Store} interface implementation\n * - Optimistic concurrency control\n * - Stream leasing for distributed processing simulation\n * - Snapshot support\n * - Fast performance (no I/O overhead)\n *\n * **`Store.notify` is intentionally not implemented.** The notify hook is a\n * cross-process wake-up signal — local commits already arm the drain via\n * `do()`. An in-memory store is single-process by definition, so there is\n * no remote writer to be notified of. The {@link Act} orchestrator\n * detects the absence and falls back to the existing debounce/poll path.\n *\n * @example Using in tests\n * ```typescript\n * import { store } from \"@rotorsoft/act\";\n *\n * describe(\"Counter\", () => {\n *   beforeEach(async () => {\n *     // Reset store between tests\n *     await store().seed();\n *   });\n *\n *   it(\"increments\", async () => {\n *     await app.do(\"increment\", target, { by: 5 });\n *     const snapshot = await app.load(Counter, \"counter-1\");\n *     expect(snapshot.state.count).toBe(5);\n *   });\n * });\n * ```\n *\n * @example Explicit instantiation\n * ```typescript\n * import { InMemoryStore } from \"@rotorsoft/act\";\n *\n * const testStore = new InMemoryStore();\n * await testStore.seed();\n *\n * // Use for specific test scenarios\n * await testStore.commit(\"test-stream\", events, meta);\n * ```\n *\n * @example Querying events\n * ```typescript\n * const events: any[] = [];\n * await store().query(\n *   (event) => events.push(event),\n *   { stream: \"test-stream\" }\n * );\n * console.log(`Found ${events.length} events`);\n * ```\n *\n * @see {@link Store} for the interface definition\n * @see {@link PostgresStore} for production use\n * @see {@link store} for injecting stores\n *\n * @category Adapters\n */\nexport class InMemoryStore implements Store {\n  // stored events\n  private _events: Committed<Schemas, keyof Schemas>[] = [];\n  // next event id — monotonic, never reused. Deletions (truncate, windowed\n  // prune) punch holes in the id sequence, so ids are NOT array indexes and\n  // NOT `_events.length`; they only stay sorted ascending in `_events`.\n  private _next_id = 0;\n  // stored stream positions and other metadata\n  private _streams: Map<string, InMemoryStream> = new Map();\n  /** Correlate checkpoint (#1484): how far the log has been READ. */\n  private _correlated_at = -1;\n  /**\n   * Per-correlator checkpoint and lease (#1532), keyed by correlator.\n   *\n   * Keyed rather than singular because correlators that look for different\n   * things read the log for different reasons: sharing one position lets a\n   * partial-behaviour worker inherit another's, and sharing one lease lets\n   * one starve the other. Callers that supply no correlator use\n   * `_correlated_at` instead, which is the pre-#1532 behaviour.\n   */\n  private _correlators = new Map<\n    string,\n    { at: number; by: string; until: number }\n  >();\n  // last committed version per stream — O(1) replacement for filter-on-commit\n  private _stream_versions: Map<string, number> = new Map();\n  // max non-snapshot event id per stream — drives the has-work probe in\n  // claim(): an O(1) lookup for a literal source, and the per-stream max\n  // that a pattern source scans, without touching the full event log.\n  private _max_event_id_by_stream: Map<string, number> = new Map();\n  // global max non-snapshot event id — fast pre-check for source-less streams in claim()\n  private _max_non_snap_event_id = -1;\n  // stream → (event_id → cloned sensitive payload). Two-level so `forget_pii`\n  // is O(1) — drop the inner Map for the stream and the wipe is done — mirroring\n  // the `DELETE WHERE stream = ?` scope that durable adapters get from their\n  // stream index. Entries exist only for events committed with a non-null\n  // `pii` field; absence means \"no PII\" (returned as `null` on load).\n  private _pii: Map<string, Map<number, Record<string, unknown>>> = new Map();\n\n  private _reset_indexes() {\n    this._events.length = 0;\n    this._next_id = 0;\n    this._correlated_at = -1;\n    this._stream_versions.clear();\n    this._max_event_id_by_stream.clear();\n    this._max_non_snap_event_id = -1;\n    this._pii.clear();\n  }\n\n  // First index whose event id is greater than `after`. `_events` stays\n  // sorted ascending by id (append-only commits; deletions preserve\n  // order), so id-bounded scans binary-search their start instead of\n  // assuming id === index — an invariant that truncation breaks.\n  private _first_index_after(after: number): number {\n    let lo = 0;\n    let hi = this._events.length;\n    while (lo < hi) {\n      const mid = (lo + hi) >>> 1;\n      if (this._events[mid].id > after) hi = mid;\n      else lo = mid + 1;\n    }\n    return lo;\n  }\n\n  // Attach the isolated PII payload (or null) to an event before handing it to\n  // a caller. Allocation-free for events without PII — by far the common case.\n  private _with_pii<E extends Schemas>(\n    e: Committed<E, keyof E>\n  ): Committed<E, keyof E> {\n    const pii = this._pii.get(e.stream)?.get(e.id);\n    return pii ? ({ ...e, pii } as Committed<E, keyof E>) : e;\n  }\n\n  /**\n   * Dispose of the store and clear all events.\n   * @returns Promise that resolves when disposal is complete.\n   */\n  async dispose() {\n    await sleep();\n    this._reset_indexes();\n  }\n\n  /**\n   * Seed the store with initial data (no-op for in-memory).\n   * @returns Promise that resolves when seeding is complete.\n   */\n  async seed() {\n    await sleep();\n  }\n\n  /**\n   * Drop all data from the store.\n   * @returns Promise that resolves when the store is cleared.\n   */\n  async drop() {\n    await sleep();\n    this._reset_indexes();\n    this._streams = new Map();\n  }\n\n  private in_query<E extends Schemas>(query: Query, e: Committed<E, keyof E>) {\n    if (query.stream) {\n      if (query.stream_exact) {\n        if (e.stream !== query.stream) return false;\n      } else if (!RegExp(query.stream).test(e.stream)) return false;\n    }\n    if (query.names && !query.names.includes(e.name as string)) return false;\n    if (query.correlation && e.meta?.correlation !== query.correlation)\n      return false;\n    if (e.name === SNAP_EVENT && !query.with_snaps) return false;\n    return true;\n  }\n\n  /**\n   * Query events in the store, optionally filtered by query options.\n   * @param callback - Function to call for each event.\n   * @param query - Optional query options.\n   * @returns The number of events processed.\n   */\n  async query<E extends Schemas>(\n    callback: (event: Committed<E, keyof E>) => void,\n    query?: Query\n  ) {\n    await sleep();\n    let count = 0;\n    // Snapshot resume floor: `with_snaps` requests a resume at the latest\n    // snapshot for an exact single stream, so pre-snapshot events aren't read.\n    // The orchestrator sets `with_snaps` only for an unbounded current-state\n    // load — it suppresses the flag under any `asOf` bound (RFC 1274) — so the\n    // store applies the floor whenever asked and never re-checks bounds. An\n    // explicit `after` is a separate resume point that wins. No snapshot → -1,\n    // i.e. a full scan. Forward starts at the snapshot; backward stops at it.\n    let floor_index = -1;\n    if (\n      query?.with_snaps &&\n      query.stream_exact &&\n      query.stream !== undefined &&\n      query.after === undefined\n    ) {\n      for (let j = this._events.length - 1; j >= 0; j--) {\n        const e = this._events[j];\n        if (e.stream === query.stream && e.name === SNAP_EVENT) {\n          floor_index = j;\n          break;\n        }\n      }\n    }\n    if (query?.backward) {\n      const floor_id = floor_index >= 0 ? this._events[floor_index].id : -1;\n      let i =\n        (query?.before !== undefined\n          ? this._first_index_after(query.before - 1)\n          : this._events.length) - 1;\n      while (i >= 0) {\n        const e = this._events[i--];\n        if (query && !this.in_query(query, e)) continue;\n        if (query?.created_before && e.created >= query.created_before)\n          continue;\n        if (query.after !== undefined && e.id <= query.after) break;\n        // Below the resume floor → every remaining (lower-id) event is too,\n        // so stop the DESC scan.\n        if (floor_id >= 0 && e.id < floor_id) break;\n        // `created` is not monotonic with `id` (restore preserves the\n        // source timestamps verbatim), so a failing time bound skips the\n        // event rather than terminating the scan — matching PG/SQLite,\n        // which treat `created` bounds as pure WHERE filters. Only the\n        // id-ordered `after` bound above may short-circuit.\n        if (query.created_after && e.created <= query.created_after) continue;\n        await Promise.resolve(\n          callback(this._with_pii(e as Committed<E, keyof E>))\n        );\n        count++;\n        if (query?.limit && count >= query.limit) break;\n      }\n    } else {\n      let i =\n        floor_index >= 0\n          ? floor_index\n          : this._first_index_after(query?.after ?? -1);\n      while (i < this._events.length) {\n        const e = this._events[i++];\n        if (query && !this.in_query(query, e)) continue;\n        if (query?.created_after && e.created <= query.created_after) continue;\n        if (query?.before !== undefined && e.id >= query.before) break;\n        // `created` is not monotonic with `id`, so a failing time bound\n        // skips the event rather than terminating the scan — matching\n        // PG/SQLite. Only the id-ordered `before` bound above may\n        // short-circuit.\n        if (query?.created_before && e.created >= query.created_before)\n          continue;\n        await Promise.resolve(\n          callback(this._with_pii(e as Committed<E, keyof E>))\n        );\n        count++;\n        if (query?.limit && count >= query.limit) break;\n      }\n    }\n    return count;\n  }\n\n  /**\n   * Commit one or more events to a stream.\n   * @param stream - The stream name.\n   * @param msgs - The events/messages to commit.\n   * @param meta - Event metadata.\n   * @param expectedVersion - Optional optimistic concurrency check.\n   * @returns The committed events with metadata.\n   * @throws ConcurrencyError if expectedVersion does not match.\n   */\n  async commit<E extends Schemas>(\n    stream: string,\n    msgs: Message<E, keyof E>[],\n    meta: EventMeta,\n    expectedVersion?: number\n  ) {\n    await sleep();\n    const current_version = this._stream_versions.get(stream) ?? -1;\n    if (\n      typeof expectedVersion === \"number\" &&\n      current_version !== expectedVersion\n    ) {\n      throw new ConcurrencyError(\n        stream,\n        current_version,\n        msgs as Message<Schemas, keyof Schemas>[],\n        expectedVersion\n      );\n    }\n\n    let version = current_version + 1;\n    let last_non_snap_id = -1;\n    const committed = msgs.map(({ name, data, pii }) => {\n      const c: Committed<E, keyof E> = {\n        id: this._next_id++,\n        stream,\n        version,\n        created: new Date(),\n        name,\n        data,\n        meta,\n      };\n      // The stored event is the pii-less view — `forget_pii` only has to\n      // drop the inner Map for the stream, never the event row. Mandatory\n      // clone on the pii payload defends against caller-side mutation.\n      this._events.push(c as Committed<Schemas, keyof Schemas>);\n      if (pii != null) {\n        let per_stream = this._pii.get(stream);\n        if (!per_stream) {\n          per_stream = new Map();\n          this._pii.set(stream, per_stream);\n        }\n        per_stream.set(c.id, structuredClone(pii) as Record<string, unknown>);\n      }\n      if (name !== SNAP_EVENT) last_non_snap_id = c.id;\n      version++;\n      return this._with_pii(c);\n    });\n    this._stream_versions.set(stream, version - 1);\n    if (last_non_snap_id >= 0) {\n      this._max_event_id_by_stream.set(stream, last_non_snap_id);\n      // commit always assigns a fresh id from the monotonic _next_id, so\n      // any non-snap commit strictly raises the global max.\n      this._max_non_snap_event_id = last_non_snap_id;\n    }\n    return committed;\n  }\n\n  /**\n   * Atomically discovers and leases streams for processing.\n   * Fuses poll + lease into a single operation.\n   * @param lagging - Max streams from lagging frontier.\n   * @param leading - Max streams from leading frontier.\n   * @param by - Lease holder identifier.\n   * @param millis - Lease duration in milliseconds.\n   * @returns Granted leases.\n   */\n  async claim(\n    lagging: number,\n    leading: number,\n    by: string,\n    millis: number,\n    lane?: string\n  ) {\n    await sleep();\n    // Eligibility is a pure subscription-row predicate (#1488). `claim`\n    // never looks at the event log: `correlate` records the highest event id\n    // that resolves to a target, and `at < correlated_at` is the whole\n    // question. The probe this replaced walked the event index once per\n    // eligible subscription, matching `source` literally or as a pattern —\n    // matching that now happens in correlate, when it decides what to mark.\n    //\n    // An unmarked row is not claimable, by definition (#1446): `undefined`\n    // means the row has never been correlated, not that it has no work.\n    const has_work = (s: InMemoryStream): boolean =>\n      s.correlated_at !== undefined && s.at < s.correlated_at;\n    const available = [...this._streams.values()].filter(\n      (s) =>\n        s.is_available && has_work(s) && (lane === undefined || s.lane === lane)\n    );\n    // Lagging frontier orders by priority DESC (higher first), then by\n    // watermark ASC (most-behind first). Mirrors the PG `claim()` SQL\n    // — see `libs/act-pg/PERFORMANCE.md` for the benchmark that\n    // motivated the priority dimension. A fairness reserve (ACT-1223)\n    // carves `fair` slots off the budget and fills them by pure watermark\n    // order (priority ignored) so a default-priority lagging stream can\n    // never be starved out of the frontier by sustained higher-priority\n    // load. With everyone at the same priority both slices order by `at`,\n    // so this is a behavioral no-op for existing workloads.\n    const fair = lagging >= 2 ? Math.max(1, Math.floor(lagging / 4)) : 0;\n    const by_priority = [...available].sort(\n      (a, b) => b.priority - a.priority || a.at - b.at\n    );\n    const priority_slice = by_priority.slice(0, lagging - fair);\n    const picked = new Set(priority_slice.map((s) => s.stream));\n    const fair_slice = [...available]\n      .sort((a, b) => a.at - b.at)\n      .filter((s) => !picked.has(s.stream))\n      .slice(0, fair);\n    const lag = [...priority_slice, ...fair_slice].map((s) => ({\n      stream: s.stream,\n      source: s.source,\n      at: s.at,\n      lagging: true,\n    }));\n    const lead = available\n      .sort((a, b) => b.at - a.at)\n      .slice(0, leading)\n      .map((s) => ({\n        stream: s.stream,\n        source: s.source,\n        at: s.at,\n        lagging: false,\n      }));\n    // deduplicate (a stream can appear in both frontiers)\n    const seen = new Set<string>();\n    const combined = [...lag, ...lead].filter((p) => {\n      if (seen.has(p.stream)) return false;\n      seen.add(p.stream);\n      return true;\n    });\n    // lease each atomically\n    return combined\n      .map((p) =>\n        this._streams.get(p.stream)?.lease({ ...p, by, retry: 0 }, millis)\n      )\n      .filter((l) => !!l);\n  }\n\n  /**\n   * Registers streams for event processing. When the same stream is\n   * resubscribed with a different priority, the **maximum** wins — so\n   * the highest-priority registered reaction sets the scheduling lane.\n   * Use {@link prioritize} for operator runtime overrides.\n   *\n   * @param streams - Streams to register with optional source + priority.\n   * @returns subscribed count and current max watermark.\n   */\n  async subscribe(\n    streams: SubscribeInput[],\n    correlated_at?: number,\n    correlator?: { key: string; by: string; millis: number }\n  ) {\n    await sleep();\n\n    // The correlate checkpoint is written by its own producer, in the call\n    // correlate already makes (#1484). Monotonic: a lower value is ignored.\n    //\n    // With a correlator the position and the lease are per-key (#1532); a key\n    // with no row yet inherits the shared value, so an upgrade does not\n    // re-read history.\n    let correlating: boolean | undefined;\n    /** This correlator's position, once known — always set when keyed. */\n    let keyed_at: number | undefined;\n    if (correlator) {\n      const now = Date.now();\n      const held = this._correlators.get(correlator.key);\n      // A key with no row yet inherits the shared position, so a new\n      // correlator does not re-read history.\n      const at = Math.max(held?.at ?? this._correlated_at, correlated_at ?? -1);\n      keyed_at = at;\n      if (!held || held.until < now || held.by === correlator.by) {\n        correlating = true;\n        this._correlators.set(correlator.key, {\n          at,\n          by: correlator.by,\n          // A non-positive `millis` releases outright rather than setting an\n          // expiry a hair in the future: a successor asking inside the same\n          // millisecond would otherwise still be refused.\n          until: correlator.millis > 0 ? now + correlator.millis : 0,\n        });\n      } else {\n        // Refused, which is only possible when a live holder exists — so the\n        // row is here to keep. The position still advances: this caller may\n        // already have scanned, and dropping how far it read would leave its\n        // marks ahead of its recorded position.\n        correlating = false;\n        held.at = at;\n      }\n      // The shared position tracks how far *any* correlator has read: the\n      // floor a brand-new key inherits, and what a caller reading without a\n      // correlator still sees.\n      if (correlated_at !== undefined && correlated_at > this._correlated_at)\n        this._correlated_at = correlated_at;\n    } else if (\n      correlated_at !== undefined &&\n      correlated_at > this._correlated_at\n    )\n      this._correlated_at = correlated_at;\n\n    let subscribed = 0;\n    for (const {\n      stream,\n      source,\n      priority = 0,\n      lane = DEFAULT_LANE,\n      correlated_at,\n    } of streams) {\n      const existing = this._streams.get(stream);\n      if (existing) {\n        // The lane rides the priority max (#1599): compared before the\n        // bump, so a subscribe at or above the stored priority sets the\n        // lane and one below leaves it alone. A caller that has forgotten\n        // what a stream carries — an evicted LRU record, a fresh process —\n        // then cannot re-lane it by resolving to it at a lower priority.\n        if (priority >= existing.priority) existing.lane = lane;\n        existing.bump_priority(priority);\n        if (correlated_at !== undefined) existing.mark(correlated_at);\n      } else {\n        const created = new InMemoryStream(stream, source, priority, lane);\n        if (correlated_at !== undefined) created.mark(correlated_at);\n        this._streams.set(stream, created);\n        subscribed++;\n      }\n    }\n    let watermark = -1;\n    for (const s of this._streams.values()) {\n      if (s.at > watermark) watermark = s.at;\n    }\n    return {\n      subscribed,\n      watermark,\n      correlated_at: keyed_at ?? this._correlated_at,\n      ...(correlating === undefined ? {} : { correlating }),\n    };\n  }\n\n  /**\n   * Acknowledge completion of processing for leased streams.\n   * @param leases - Leases to acknowledge, including last processed watermark and lease holder.\n   */\n  async ack(leases: Lease[]) {\n    await sleep();\n    // Acks and defer schedules land in one synchronous pass — the\n    // in-memory equivalent of the single-transaction contract on\n    // {@link Store.ack}: no await between entries, so a caller\n    // never observes a cycle's acks without its schedules. `due`-carrying\n    // entries defer (and return undefined), the rest ack.\n    return leases\n      .map((l) => this._streams.get(l.stream)?.ack(l))\n      .filter((l) => !!l);\n  }\n\n  /**\n   * Block a stream for processing after failing to process and reaching max retries with blocking enabled.\n   * @param leases - Leases to block, including lease holder and last error message.\n   * @returns Blocked leases.\n   */\n  async block(leases: BlockedLease[]) {\n    await sleep();\n    return leases\n      .map((l) => this._streams.get(l.stream)?.block(l, l.error))\n      .filter((l) => !!l);\n  }\n\n  /**\n   * Hold the matched streams out of {@link claim} until `deferred_at`\n   * (ms since epoch) — see {@link Store.defer}. Accepts an explicit list\n   * of names or a {@link StreamFilter}, mirroring {@link reset}/{@link unblock}.\n   * Persisted store state (unlike in-process backoff), so the skip is honored\n   * by every competing worker. Unknown names are silently skipped.\n   *\n   * @returns Count of streams whose `deferred_at` was set.\n   */\n  async defer(input: string[] | StreamFilter, deferred_at: number) {\n    await sleep();\n    let count = 0;\n    if (Array.isArray(input)) {\n      // De-dup the array so a repeated name counts once, matching PG's\n      // set-based `WHERE stream = ANY(...)` (#1360).\n      for (const name of new Set(input)) {\n        const s = this._streams.get(name);\n        if (s) {\n          s.defer(deferred_at);\n          count++;\n        }\n      }\n    } else {\n      const matches = this._filter_predicate(input);\n      for (const s of this._streams.values()) {\n        if (matches(s)) {\n          s.defer(deferred_at);\n          count++;\n        }\n      }\n    }\n    return count;\n  }\n\n  /**\n   * Build a predicate from a {@link StreamFilter}. Compiled regexes are\n   * cached in the closure so callers can apply it across the streams\n   * map without re-compiling per iteration.\n   */\n  private _filter_predicate(\n    filter: StreamFilter\n  ): (s: InMemoryStream) => boolean {\n    const stream_re =\n      filter.stream && !filter.stream_exact\n        ? new RegExp(filter.stream)\n        : undefined;\n    const source_re =\n      filter.source && !filter.source_exact\n        ? new RegExp(filter.source)\n        : undefined;\n    return (s) => {\n      if (filter.stream !== undefined) {\n        if (\n          filter.stream_exact\n            ? s.stream !== filter.stream\n            : !stream_re!.test(s.stream)\n        )\n          return false;\n      }\n      if (filter.source !== undefined) {\n        if (s.source === undefined) return false;\n        if (\n          filter.source_exact\n            ? s.source !== filter.source\n            : !source_re!.test(s.source)\n        )\n          return false;\n      }\n      if (filter.blocked !== undefined && s.blocked !== filter.blocked)\n        return false;\n      if (filter.lane !== undefined && s.lane !== filter.lane) return false;\n      return true;\n    };\n  }\n\n  /**\n   * Reset watermarks to -1, clearing retry, blocked, error, and lease\n   * state so the matched streams can be replayed from the beginning.\n   * Accepts either an explicit list of names or a {@link StreamFilter}.\n   *\n   * @param input - Stream names or a filter selecting the streams to reset.\n   * @returns Count of streams that were actually reset.\n   */\n  async reset(input: string[] | StreamFilter) {\n    await sleep();\n    let count = 0;\n    if (Array.isArray(input)) {\n      // De-dup the array so a repeated name counts once, matching PG's\n      // set-based `WHERE stream = ANY(...)` (#1360).\n      for (const name of new Set(input)) {\n        const s = this._streams.get(name);\n        if (s) {\n          s.reset();\n          count++;\n        }\n      }\n    } else {\n      const matches = this._filter_predicate(input);\n      for (const s of this._streams.values()) {\n        if (matches(s)) {\n          s.reset();\n          count++;\n        }\n      }\n    }\n    return count;\n  }\n\n  /**\n   * Clear the blocked flag (and retry / error / lease) on the matched\n   * streams without touching the watermark. Streams that aren't blocked\n   * at call time are silently skipped. Accepts either an explicit list\n   * of names or a {@link StreamFilter}. The filter form always restricts\n   * to blocked streams — passing `blocked: false` matches nothing.\n   * See {@link Store.unblock}.\n   *\n   * @param input - Stream names or a filter selecting the streams to unblock.\n   * @returns Count of streams that were actually flipped (were blocked).\n   */\n  /**\n   * Wipe the sensitive-data payload for every event on the stream — see\n   * {@link Store.forget_pii}. O(1) drop of the stream's inner Map; the size of\n   * that Map is the count of events that had PII. Idempotent: a second call\n   * finds no inner Map and returns `0`.\n   *\n   * @param stream - Target stream.\n   * @returns Count of events whose isolated PII payload was deleted.\n   */\n  async forget_pii(stream: string): Promise<number> {\n    await sleep();\n    const count = this._pii.get(stream)?.size ?? 0;\n    this._pii.delete(stream);\n    return count;\n  }\n\n  async unblock(input: string[] | StreamFilter) {\n    await sleep();\n    let count = 0;\n    if (Array.isArray(input)) {\n      for (const name of input) {\n        const s = this._streams.get(name);\n        if (s?.unblock()) count++;\n      }\n    } else {\n      // Filter form: always restrict to blocked streams. An explicit\n      // `blocked: false` in the filter is silently overridden — there\n      // is no use case for \"unblock unblocked streams.\"\n      const matches = this._filter_predicate({ ...input, blocked: true });\n      for (const s of this._streams.values()) {\n        if (matches(s) && s.unblock()) count++;\n      }\n    }\n    return count;\n  }\n\n  /**\n   * Bulk-update priority of streams matching `filter`. Mirrors\n   * {@link query_streams}'s filter semantics — see {@link Store.prioritize}.\n   * Unlike {@link subscribe} (which keeps `max()` of registered\n   * priorities), this sets the priority outright — operator override\n   * for the build-time scheduling policy.\n   *\n   * @returns Count of streams whose priority changed.\n   */\n  async prioritize(filter: StreamFilter, priority: number) {\n    await sleep();\n    const matches = this._filter_predicate(filter);\n    let count = 0;\n    for (const s of this._streams.values()) {\n      if (!matches(s)) continue;\n      if (s.priority !== priority) {\n        s.set_priority(priority);\n        count++;\n      }\n    }\n    return count;\n  }\n\n  /**\n   * Streams registered subscription positions to the callback, ordered by\n   * stream name. Returns the highest event id in the store and the count\n   * of positions emitted.\n   */\n  async query_streams(\n    callback: (position: StreamPosition) => void,\n    query?: QueryStreams\n  ): Promise<QueryStreamsResult> {\n    await sleep();\n    const limit = query?.limit ?? 100;\n    const after = query?.after;\n    const blocked = query?.blocked;\n    const source_matches = query?.source_matches;\n    const stream_re =\n      query?.stream && !query.stream_exact\n        ? new RegExp(query.stream)\n        : undefined;\n    const source_re =\n      query?.source && !query.source_exact\n        ? new RegExp(query.source)\n        : undefined;\n    // Reverse-match: a stream qualifies when its stored `source` pattern\n    // matches at least one of the requested names. Patterns are compiled\n    // once and cached — many subscriptions share one source pattern.\n    const reverse_cache = new Map<string, RegExp>();\n    const reverse_match = (source: string): boolean => {\n      let re = reverse_cache.get(source);\n      if (!re) {\n        re = new RegExp(source);\n        reverse_cache.set(source, re);\n      }\n      return source_matches!.some((name) => re!.test(name));\n    };\n\n    // Order by stream name so `after`/`limit` keyset-paginate\n    // deterministically. The sort MUST agree with the `after` cursor below\n    // (JS `<=`, i.e. UTF-16 code-unit order) — `localeCompare` disagrees\n    // with `<=` on mixed-case/accented names (`B`=66 < `a`=97 by code unit,\n    // but `a` < `B` by locale), which let the cursor skip streams the sort\n    // placed after it (#1375, the `query_streams` twin of #1357).\n    // The default `Array.sort()` comparator IS code-unit order, so it\n    // matches `<=` exactly — and PG/SQLite, which paginate under their\n    // binary collation. Sorting the keys (rather than comparing values)\n    // keeps that default in play.\n    const sorted = [...this._streams.keys()]\n      .sort()\n      .map((stream) => this._streams.get(stream) as InMemoryStream);\n\n    let count = 0;\n    for (const s of sorted) {\n      if (after !== undefined && s.stream <= after) continue;\n      if (query?.stream !== undefined) {\n        if (\n          query.stream_exact\n            ? s.stream !== query.stream\n            : !stream_re!.test(s.stream)\n        )\n          continue;\n      }\n      if (query?.source !== undefined) {\n        if (s.source === undefined) continue;\n        if (\n          query.source_exact\n            ? s.source !== query.source\n            : !source_re!.test(s.source)\n        )\n          continue;\n      }\n      if (source_matches !== undefined) {\n        // Absent/empty source = no source constraint = consumes from\n        // every stream, so it matches any requested name. Only a\n        // present source that matches none of them is excluded.\n        if (s.source && !reverse_match(s.source)) continue;\n      }\n      if (blocked !== undefined && s.blocked !== blocked) continue;\n      if (query?.lane !== undefined && s.lane !== query.lane) continue;\n      // Checked before emitting, not after: a bound applied afterwards\n      // lets `limit: 0` through as exactly one row, where both SQL\n      // adapters return none.\n      if (count >= limit) break;\n      callback({\n        stream: s.stream,\n        source: s.source,\n        at: s.at,\n        retry: s.retry,\n        blocked: s.blocked,\n        error: s.error,\n        priority: s.priority,\n        leased_by: s.leased_by,\n        leased_until: s.leased_until,\n        lane: s.lane,\n        deferred_at: s.deferred_at,\n        correlated_at: s.correlated_at,\n      });\n      count++;\n    }\n    return { maxEventId: this._events.at(-1)?.id ?? -1, count };\n  }\n\n  /**\n   * Per-stream aggregated stats — see {@link Store.query_stats}.\n   *\n   * Single forward scan over the in-memory event list, accumulating per\n   * stream. The \"cheap heads\" cost tier from durable adapters doesn't\n   * apply here (InMemory has no indexes); correctness is the goal, perf\n   * is a non-issue.\n   *\n   * Scope rules:\n   * - Array `input` — explicit stream names, regardless of subscription.\n   * - Filter `input` — `stream`/`stream_exact` match against event-bearing\n   *   stream names; `source`/`source_exact`/`blocked` require a\n   *   corresponding subscription in `_streams` (those are subscription\n   *   concepts, not event concepts). Empty filter `{}` matches every\n   *   event-bearing stream.\n   */\n  async query_stats<E extends Schemas>(\n    input: string[] | Pick<StreamFilter, \"stream\" | \"stream_exact\">,\n    options?: QueryStatsOptions<E>\n  ): Promise<Map<string, StreamStats<E>>> {\n    await sleep();\n    const exclude = new Set<string>(options?.exclude ?? []);\n    const want_tail = options?.tail ?? false;\n    const want_count = options?.count ?? false;\n    const want_names = options?.names ?? false;\n    const before = options?.before;\n    const after = options?.after;\n    const limit = options?.limit;\n\n    // Pre-compile per-stream scope predicate, cached as we go so each\n    // distinct stream evaluates the regex once.\n    const array_targets = Array.isArray(input) ? new Set(input) : null;\n    const filter = Array.isArray(input) ? null : input;\n    const stream_re =\n      filter?.stream && !filter.stream_exact\n        ? new RegExp(filter.stream)\n        : undefined;\n\n    const scope_cache = new Map<string, boolean>();\n    const in_scope = (stream: string): boolean => {\n      const cached = scope_cache.get(stream);\n      if (cached !== undefined) return cached;\n      let ok = true;\n      if (array_targets) {\n        ok = array_targets.has(stream);\n      } else if (filter?.stream !== undefined) {\n        ok = filter.stream_exact\n          ? stream === filter.stream\n          : // stream_re set when stream is regex\n            stream_re!.test(stream);\n      }\n      scope_cache.set(stream, ok);\n      return ok;\n    };\n\n    type Acc = {\n      head: Committed<Schemas, keyof Schemas>;\n      tail?: Committed<Schemas, keyof Schemas>;\n      count: number;\n      names?: Record<string, number>;\n    };\n    const acc = new Map<string, Acc>();\n    for (const e of this._events) {\n      if (before !== undefined && e.id >= before) continue;\n      if (!in_scope(e.stream)) continue;\n      if (exclude.has(e.name as string)) continue;\n      let a = acc.get(e.stream);\n      if (!a) {\n        a = { head: e, count: 0 };\n        if (want_tail) a.tail = e;\n        if (want_names) a.names = {};\n        acc.set(e.stream, a);\n      }\n      a.head = e;\n      a.count++;\n      if (want_names) {\n        const n = String(e.name);\n        // a.names initialized above when want_names\n        a.names![n] = (a.names![n] ?? 0) + 1;\n      }\n    }\n\n    // Order by stream name so `after`/`limit` keyset-paginate\n    // deterministically. The sort MUST agree with the `after` cursor below\n    // (JS `<=`, i.e. UTF-16 code-unit order) — `localeCompare` disagrees with\n    // `<=` on mixed-case/accented names (`B`=66 < `a`=97 by code unit, but\n    // `a` < `B` by locale), which would let the cursor skip streams the sort\n    // placed after it (#1357). The default `Array.sort()` comparator IS\n    // code-unit order, so it matches `<=` exactly — and PG/SQLite, which\n    // paginate `query_stats` under their binary collation.\n    const ordered = [...acc.keys()].sort();\n    const out = new Map<string, StreamStats<E>>();\n    for (const stream of ordered) {\n      // Before the row, not after it — `limit: 0` means none.\n      if (limit !== undefined && out.size >= limit) break;\n      if (after !== undefined && stream <= after) continue;\n      const a = acc.get(stream)!;\n      const stats: {\n        head: Committed<Schemas, keyof Schemas>;\n        tail?: Committed<Schemas, keyof Schemas>;\n        count?: number;\n        names?: Record<string, number>;\n      } = { head: a.head };\n      if (want_tail) stats.tail = a.tail;\n      if (want_count) stats.count = a.count;\n      if (want_names) stats.names = a.names;\n      out.set(stream, stats as StreamStats<E>);\n    }\n    return out;\n  }\n\n  /**\n   * Atomically truncates streams and seeds each with a snapshot or tombstone.\n   * Windowed targets (`before` set) prune the prefix below the closest safe\n   * `__snapshot__` instead — no seed, subscriptions untouched, no-op when no\n   * snapshot qualifies.\n   * @param targets - Streams to truncate with optional snapshot state and meta,\n   *   or a `before`/`max_id` boundary for a windowed prefix delete.\n   * @returns Map keyed by stream name, each entry with `deleted` count and `committed` event.\n   */\n  async truncate(\n    targets: Array<{\n      stream: string;\n      snapshot?: Schema;\n      meta?: EventMeta;\n      before?: Date;\n      max_id?: number;\n    }>\n  ) {\n    await sleep();\n    const result = new Map<\n      string,\n      {\n        deleted: number;\n        committed: Committed<Schemas, keyof Schemas>;\n        before?: Date;\n      }\n    >();\n\n    // Windowed targets: pure prefix delete behind the closest safe snapshot.\n    const windowed = targets.filter((t) => t.before !== undefined);\n    if (windowed.length) {\n      const drop = new Set<number>();\n      for (const { stream, before, max_id } of windowed) {\n        let boundary: Committed<Schemas, keyof Schemas> | undefined;\n        for (const e of this._events) {\n          if (\n            e.stream === stream &&\n            e.name === SNAP_EVENT &&\n            e.created < before! &&\n            (max_id === undefined || e.id <= max_id) &&\n            (!boundary || e.id > boundary.id)\n          )\n            boundary = e;\n        }\n        if (!boundary) continue; // no qualifying snapshot → no-op\n        let deleted = 0;\n        for (const e of this._events) {\n          if (e.stream === stream && e.id < boundary.id) {\n            drop.add(e.id);\n            this._pii.get(stream)?.delete(e.id);\n            deleted++;\n          }\n        }\n        result.set(stream, { deleted, committed: boundary, before });\n      }\n      if (drop.size) this._events = this._events.filter((e) => !drop.has(e.id));\n    }\n\n    const full = targets.filter((t) => t.before === undefined);\n    // Count per-stream deletions\n    const deleted_counts = new Map<string, number>();\n    const stream_set = new Set(full.map((t) => t.stream));\n    for (const e of this._events) {\n      if (stream_set.has(e.stream)) {\n        deleted_counts.set(e.stream, (deleted_counts.get(e.stream) ?? 0) + 1);\n      }\n    }\n    this._events = this._events.filter((e) => !stream_set.has(e.stream));\n    // Subscriptions are deliberately untouched, for restart *and* retire\n    // targets alike — see the note in truncate's contract. A tombstoned\n    // stream's subscription is inert, and reaping it is maintenance that\n    // `seed()` performs (#1527).\n    for (const stream of stream_set) {\n      this._stream_versions.delete(stream);\n      this._max_event_id_by_stream.delete(stream);\n      // The pii payloads die with the event rows, matching the durable\n      // adapters' `DELETE WHERE stream = ?` scope.\n      this._pii.delete(stream);\n    }\n    for (const { stream, snapshot, meta } of full) {\n      const event: Committed<Schemas, keyof Schemas> = {\n        id: this._next_id++,\n        stream,\n        version: 0,\n        created: new Date(),\n        name: snapshot !== undefined ? SNAP_EVENT : TOMBSTONE_EVENT,\n        data: snapshot ?? {},\n        meta: meta ?? { correlation: \"\", causation: {} },\n      };\n      this._events.push(event);\n      this._stream_versions.set(stream, 0);\n      if (event.name !== SNAP_EVENT) {\n        this._max_event_id_by_stream.set(stream, event.id);\n      }\n      result.set(stream, {\n        deleted: deleted_counts.get(stream) ?? 0,\n        committed: event,\n      });\n    }\n    // Recompute global max from the per-stream index — deletions may have\n    // dropped the previous max, while new tombstones may have raised it.\n    let max = -1;\n    for (const id of this._max_event_id_by_stream.values())\n      if (id > max) max = id;\n    this._max_non_snap_event_id = max;\n    return result;\n  }\n\n  /**\n   * Atomically wipe-and-rebuild the store under an in-process snapshot.\n   *\n   * Captures every index state up front, clears it, then hands the\n   * orchestrator a per-event insert `callback` via the driver. Any\n   * throw inside the driver restores the snapshot, leaving the store\n   * byte-for-byte unchanged from the operator's perspective.\n   *\n   * `id`s are reassigned `0..N-1` as events arrive (dense — the\n   * monotonic id counter restarts at 0 for the rebuild). `created` is\n   * preserved verbatim from the source.\n   */\n  async restore(\n    driver: (\n      callback: (event: Committed<Schemas, keyof Schemas>) => Promise<number>\n    ) => Promise<void>\n  ): Promise<void> {\n    await sleep();\n    // Snapshot every index so we can roll back on throw.\n    const prev_events = this._events;\n    const prev_next_id = this._next_id;\n    const prev_streams = this._streams;\n    const prev_stream_versions = this._stream_versions;\n    const prev_max_event_id_by_stream = this._max_event_id_by_stream;\n    const prev_max_non_snap_event_id = this._max_non_snap_event_id;\n    const prev_pii = this._pii;\n    // Swap in fresh state for the duration of the rebuild.\n    this._events = [];\n    this._next_id = 0;\n    this._streams = new Map();\n    this._stream_versions = new Map();\n    this._max_event_id_by_stream = new Map();\n    this._max_non_snap_event_id = -1;\n    this._pii = new Map();\n    try {\n      await driver(async (event) => {\n        const id = this._next_id++;\n        // Split `pii` out of the stored row into the isolated `_pii` map,\n        // mirroring `commit`. The stored event is the pii-less view so\n        // `forget_pii` — which only drops the `_pii` entry — actually\n        // erases restored PII (durable adapters restore into their\n        // isolated column for the same reason).\n        const { pii, ...rest } = event;\n        const committed: Committed<Schemas, keyof Schemas> = { ...rest, id };\n        this._events.push(committed);\n        if (pii != null) {\n          let per_stream = this._pii.get(event.stream);\n          if (!per_stream) {\n            per_stream = new Map();\n            this._pii.set(event.stream, per_stream);\n          }\n          per_stream.set(id, structuredClone(pii) as Record<string, unknown>);\n        }\n        // Last event per stream wins for the version watermark — the\n        // source is expected to be in commit order, so this is also\n        // the highest version. Out-of-order sources get last-wins,\n        // matching the legacy raw-SQL restore.\n        this._stream_versions.set(event.stream, event.version);\n        if (event.name !== SNAP_EVENT) {\n          this._max_event_id_by_stream.set(event.stream, id);\n          this._max_non_snap_event_id = id;\n        }\n        return id;\n      });\n    } catch (err) {\n      // Roll back to the captured snapshot — every index restored\n      // exactly as it was before the call started.\n      this._events = prev_events;\n      this._next_id = prev_next_id;\n      this._streams = prev_streams;\n      this._stream_versions = prev_stream_versions;\n      this._max_event_id_by_stream = prev_max_event_id_by_stream;\n      this._max_non_snap_event_id = prev_max_non_snap_event_id;\n      this._pii = prev_pii;\n      throw err;\n    }\n  }\n}\n"],"mappings":"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","names":["import_zod","import_zod","import_zod","log","correlated_at","store","cache"]}