@schoolai/shipyard 0.1.0-nightly.20260217

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/derive-placeholder.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/diff-overlay.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/functional-helpers.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/loro.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-doc.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/json-patch.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/utils/type-guards.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/overlay.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/base.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/utils.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/counter-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/counter-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/conversion.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/list-ref-base.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/list-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/list-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/movable-list-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/movable-list-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/proxy-handlers.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/record-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/record-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/struct-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/struct-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/text-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/text-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/tree-node-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/tree-node-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/tree-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/tree-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/doc-ref-internals.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/typed-refs/doc-ref.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/validation.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/path-builder.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/path-compiler.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/path-evaluator.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/placeholder-proxy.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/replay-diff.ts","../../../node_modules/.pnpm/@loro-extended+change@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/change/src/shape.ts","../../../node_modules/.pnpm/@logtape+logtape@1.3.7/node_modules/@logtape/logtape/src/level.ts","../../../node_modules/.pnpm/@logtape+logtape@1.3.7/node_modules/@logtape/logtape/src/logger.ts","../../../node_modules/.pnpm/@logtape+logtape@1.3.7/node_modules/@logtape/logtape/src/context.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/index.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/adapter/adapter.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/channel-directory.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/generate-uuid.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/adapter/bridge-adapter.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/adapter/delayed-network-adapter.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/channel.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/channel-json.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/handle.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/equal.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/with-timeout.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/middleware/rate-limiter.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/middleware.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/permissions.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/repo.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/adapter/adapter-manager.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-executor.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-apply-ephemeral.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-batch.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/timerless-ephemeral-store.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-broadcast-ephemeral-batch.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-broadcast-ephemeral-namespace.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-dispatch.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-emit-ephemeral-change.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-import-doc-data.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/get-established-channels-for-doc.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-remove-ephemeral-peer.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-send-establishment-message.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-send-message.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-send-sync-request.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-send-sync-response.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-stop-channel.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/handle-subscribe-doc.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/command-handlers/index.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/ephemeral-store-manager.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/heartbeat-manager.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/middleware-processor.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/outbound-batcher.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/state-helpers.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/work-queue.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer-program.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/peer-state-helpers.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/permission-context.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/utils.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/connection/handle-establish-request.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/connection/handle-establish-response.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/discovery/handle-directory-request.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/types.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/discovery/handle-directory-response.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/discovery/handle-new-doc.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/ephemeral/handle-ephemeral.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/handle-delete-request.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/handle-sync-request.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/get-storage-channel-ids.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/utils.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/handle-sync-response.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/handle-sync-update.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/channel-dispatcher.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/connection/handle-channel-added.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/connection/handle-channel-removed.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/connection/handle-establish-channel.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/handle-doc-delete.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/handle-doc-ensure.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/propagate-to-peers.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/handle-doc-imported.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/sync/handle-local-doc-change.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/synchronizer/synchronizer-dispatcher.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/make-immutable-update.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/generate-peer-id.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/utils/validate-peer-id.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/storage/storage-adapter.ts","../../../node_modules/.pnpm/@loro-extended+repo@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/repo/src/storage/in-memory-storage-adapter.ts","../../../node_modules/.pnpm/emittery@1.2.0/node_modules/emittery/maps.js","../../../node_modules/.pnpm/emittery@1.2.0/node_modules/emittery/index.js","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/interface.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/constant.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/internal.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/proto.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/draft.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/copy.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/mark.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/deepFreeze.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/forEach.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/finalize.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/patch.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/unsafe.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/map.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/set.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/draft.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/draftify.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/current.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/makeCreator.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/create.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/apply.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/original.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/rawReturn.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/marker.ts","../../../node_modules/.pnpm/mutative@1.3.0/node_modules/mutative/src/utils/cast.ts","../../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.js","../../../node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/url-alphabet/index.js","../../../packages/loro-schema/dist/index.js","../src/file-storage-adapter.ts","../src/logger.ts","../src/lifecycle.ts","../src/serve.ts","../../../node_modules/.pnpm/@loro-extended+adapter-webrtc@5.4.2_loro-crdt@1.10.5/node_modules/@loro-extended/adapter-webrtc/src/adapter.ts","../src/branch-watcher.ts","../src/capabilities.ts","../src/peer-manager.ts","../src/pty-manager.ts","../src/session-manager.ts","../src/streaming-input-controller.ts","../src/signaling-setup.ts","../src/signaling.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { resolve } from 'node:path';\nimport { parseArgs } from 'node:util';\nimport { change, type createTypedDoc } from '@loro-extended/change';\nimport { Repo } from '@loro-extended/repo';\nimport {\n buildDocumentId,\n DEFAULT_EPOCH,\n EpochDocumentSchema,\n generateTaskId,\n TaskDocumentSchema,\n} from '@shipyard/loro-schema';\nimport { type Env, validateEnv } from './env.js';\nimport { FileStorageAdapter } from './file-storage-adapter.js';\nimport { LifecycleManager } from './lifecycle.js';\nimport { createChildLogger, logger } from './logger.js';\nimport { serve } from './serve.js';\nimport { SessionManager, type SessionResult } from './session-manager.js';\nimport { createSignalingHandle, type SignalingHandle } from './signaling-setup.js';\n\ninterface CliArgs {\n prompt?: string;\n resume?: string;\n taskId?: string;\n cwd?: string;\n dataDir?: string;\n model?: string;\n serve?: boolean;\n}\n\nfunction parseCliArgs(): CliArgs {\n const { values } = parseArgs({\n options: {\n prompt: { type: 'string', short: 'p' },\n 'task-id': { type: 'string', short: 't' },\n resume: { type: 'string', short: 'r' },\n 'data-dir': { type: 'string', short: 'd' },\n cwd: { type: 'string' },\n model: { type: 'string', short: 'm' },\n serve: { type: 'boolean', short: 's' },\n help: { type: 'boolean', short: 'h' },\n },\n strict: true,\n });\n\n if (values.help) {\n logger.info(\n [\n 'shipyard-daemon - Claude Agent SDK + Loro CRDT sync',\n '',\n 'Usage:',\n ' shipyard login Authenticate with Shipyard',\n ' shipyard login --check Check current auth status',\n ' shipyard logout Clear stored credentials',\n '',\n ' shipyard-daemon --prompt \"Fix the bug in auth.ts\" [options]',\n ' shipyard-daemon --resume <session-id> --task-id <id> [--prompt \"Continue\"]',\n ' shipyard-daemon --serve',\n '',\n 'Options:',\n ' -p, --prompt <text> Prompt for the agent',\n ' -t, --task-id <id> Task ID (auto-generated if not provided)',\n ' -r, --resume <id> Resume session by session ID',\n ' -d, --data-dir <path> Data directory (default: ~/.shipyard/data)',\n ' --cwd <path> Working directory for agent',\n ' -m, --model <name> Model to use',\n ' -s, --serve Run in serve mode (signaling + spawn-agent)',\n ' -h, --help Show this help',\n '',\n 'Environment:',\n ' ANTHROPIC_API_KEY API key for Claude (required for task mode)',\n ' SHIPYARD_DEV Set to 1 for dev mode (uses ~/.shipyard-dev/)',\n ' SHIPYARD_DATA_DIR Data directory (overridden by --data-dir)',\n ' LOG_LEVEL Log level: debug, info, warn, error (default: info)',\n ' SHIPYARD_SIGNALING_URL Signaling server WebSocket URL (optional)',\n ' SHIPYARD_USER_TOKEN JWT for signaling auth (optional)',\n ' SHIPYARD_USER_ID User ID for signaling path (optional, from login)',\n ' SHIPYARD_MACHINE_ID Machine identifier (default: os.hostname())',\n ' SHIPYARD_MACHINE_NAME Human-readable machine name (default: os.hostname())',\n ].join('\\n')\n );\n process.exit(0);\n }\n\n return {\n prompt: values.prompt,\n resume: values.resume,\n taskId: values['task-id'],\n cwd: values.cwd,\n dataDir: values['data-dir'],\n model: values.model,\n serve: values.serve,\n };\n}\n\nasync function setupSignaling(\n env: Env,\n log: ReturnType<typeof createChildLogger>\n): Promise<SignalingHandle | null> {\n const handle = await createSignalingHandle(env, log);\n if (handle) {\n handle.connection.connect();\n }\n return handle;\n}\n\nasync function setupRepo(dataDir: string) {\n await mkdir(dataDir, { recursive: true, mode: 0o700 });\n const storage = new FileStorageAdapter(dataDir);\n const repo = new Repo({\n identity: { name: 'shipyard-daemon' },\n adapters: [storage],\n });\n return repo;\n}\n\nasync function loadEpoch(repo: Repo): Promise<number> {\n const epochHandle = repo.get('epoch', EpochDocumentSchema);\n\n try {\n await epochHandle.waitForSync({ kind: 'storage', timeout: 5_000 });\n } catch {\n logger.debug('No existing epoch data in storage');\n }\n\n if (epochHandle.loroDoc.opCount() === 0) {\n change(epochHandle.doc, (draft) => {\n draft.schema.version = DEFAULT_EPOCH;\n });\n logger.debug({ epoch: DEFAULT_EPOCH }, 'Initialized epoch document');\n return DEFAULT_EPOCH;\n }\n\n return epochHandle.doc.toJSON().schema.version;\n}\n\nasync function loadTaskDoc(repo: Repo, taskDocId: string, taskId: string, prompt?: string) {\n const taskHandle = repo.get(taskDocId, TaskDocumentSchema);\n\n try {\n await taskHandle.waitForSync({ kind: 'storage', timeout: 5_000 });\n } catch {\n logger.debug({ taskDocId }, 'No existing task data in storage (new task)');\n }\n\n if (taskHandle.loroDoc.opCount() === 0) {\n initializeTaskDoc(taskHandle.doc, taskId, prompt);\n logger.debug({ taskDocId }, 'Initialized new task document');\n }\n\n return taskHandle;\n}\n\nfunction initializeTaskDoc(\n doc: ReturnType<typeof createTypedDoc<typeof TaskDocumentSchema>>,\n taskId: string,\n prompt?: string\n): void {\n const now = Date.now();\n change(doc, (draft) => {\n draft.meta.id = taskId;\n draft.meta.title = prompt?.slice(0, 80) ?? 'Untitled task';\n draft.meta.status = 'submitted';\n draft.meta.createdAt = now;\n draft.meta.updatedAt = now;\n });\n}\n\nfunction handleResult(\n log: ReturnType<typeof createChildLogger>,\n result: SessionResult,\n startTime: number\n): void {\n const wallTimeMs = Date.now() - startTime;\n log.info(\n {\n sessionId: result.sessionId,\n agentSessionId: result.agentSessionId,\n status: result.status,\n totalCostUsd: result.totalCostUsd,\n durationMs: result.durationMs,\n wallTimeMs,\n },\n 'Session complete'\n );\n\n if (result.resultText) {\n log.info({ resultText: result.resultText }, 'Agent result');\n }\n}\n\nasync function handleSubcommand(): Promise<boolean> {\n const subcommand = process.argv[2];\n\n if (subcommand === 'login') {\n const { loginCommand } = await import('./commands/login.js');\n const hasCheck = process.argv.includes('--check');\n await loginCommand({ check: hasCheck });\n return true;\n }\n\n if (subcommand === 'logout') {\n const { logoutCommand } = await import('./commands/logout.js');\n await logoutCommand();\n return true;\n }\n\n return false;\n}\n\nasync function loadAuthFromConfig(env: Env): Promise<void> {\n if (env.SHIPYARD_USER_TOKEN) return;\n\n const { loadAuthToken } = await import('./auth.js');\n const auth = await loadAuthToken();\n\n if (auth.status === 'ok') {\n env.SHIPYARD_USER_TOKEN = auth.token;\n env.SHIPYARD_USER_ID = auth.userId;\n if (auth.signalingUrl) {\n env.SHIPYARD_SIGNALING_URL = auth.signalingUrl;\n }\n return;\n }\n\n if (auth.status === 'expired') {\n logger.warn('Auth token expired. Run `shipyard login` to re-authenticate.');\n return;\n }\n\n logger.warn('No auth token found. Run `shipyard login` to authenticate.');\n}\n\nfunction validateTaskArgs(args: CliArgs, env: Env): void {\n if (!args.prompt && !args.resume) {\n logger.error('Either --prompt, --resume, or --serve is required. Use --help for usage.');\n process.exit(1);\n }\n\n if (!env.ANTHROPIC_API_KEY) {\n logger.error('ANTHROPIC_API_KEY is required when running tasks. Use --help for usage.');\n process.exit(1);\n }\n}\n\nfunction createCleanup(\n signalingHandle: SignalingHandle | null,\n lifecycle: LifecycleManager,\n repo: Repo\n): () => void {\n let cleanedUp = false;\n return () => {\n if (cleanedUp) return;\n cleanedUp = true;\n signalingHandle?.signaling.unregister();\n signalingHandle?.signaling.destroy();\n signalingHandle?.connection.disconnect();\n lifecycle.destroy();\n repo.reset();\n };\n}\n\nfunction formatError(error: unknown): { err: string; stack: string | undefined } {\n const err = error instanceof Error ? error.message : String(error);\n const stack = error instanceof Error ? error.stack : undefined;\n return { err, stack };\n}\n\nasync function main(): Promise<void> {\n if (await handleSubcommand()) return;\n\n const env = validateEnv();\n const args = parseCliArgs();\n\n await loadAuthFromConfig(env);\n\n if (args.serve) {\n return serve(env);\n }\n\n validateTaskArgs(args, env);\n\n const dataDir = resolve(args.dataDir ?? env.SHIPYARD_DATA_DIR.replace('~', homedir()));\n const taskId = args.taskId ?? generateTaskId();\n const log = createChildLogger({ taskId });\n\n log.info({ dataDir, prompt: args.prompt, resume: args.resume }, 'Starting daemon');\n\n const repo = await setupRepo(dataDir);\n const lifecycle = new LifecycleManager();\n const signalingHandle = await setupSignaling(env, log);\n const cleanup = createCleanup(signalingHandle, lifecycle, repo);\n\n lifecycle.onShutdown(async () => {\n log.info('Cleaning up...');\n cleanup();\n });\n\n const epoch = await loadEpoch(repo);\n const taskDocId = buildDocumentId('task', taskId, epoch);\n log.info({ taskDocId, epoch }, 'Using task document');\n\n const taskHandle = await loadTaskDoc(repo, taskDocId, taskId, args.prompt);\n const manager = new SessionManager(taskHandle.doc);\n const abortController = lifecycle.createAbortController();\n const startTime = Date.now();\n\n try {\n const result = args.resume\n ? await manager.resumeSession(args.resume, args.prompt ?? 'Continue.', { abortController })\n : await manager.createSession({\n prompt: args.prompt ?? '',\n cwd: args.cwd ?? process.cwd(),\n model: args.model,\n abortController,\n });\n\n handleResult(log, result, startTime);\n } catch (error: unknown) {\n const { err, stack } = formatError(error);\n log.error({ err, stack }, 'Session failed');\n cleanup();\n process.exit(1);\n }\n\n cleanup();\n}\n\nmain().catch((error: unknown) => {\n const errMsg = error instanceof Error ? error.message : String(error);\n const errStack = error instanceof Error ? error.stack : undefined;\n logger.error({ err: errMsg, stack: errStack }, 'Fatal error');\n process.exit(1);\n});\n","import type { ContainerOrValueShape, DocShape, ValueShape } from \"./shape.js\"\nimport type { InferPlaceholderType } from \"./types.js\"\n\n/**\n * Derives the placeholder state from a schema by composing placeholder values.\n *\n * For leaf nodes (text, counter, values): uses _placeholder directly\n * For containers (map, list, record): recurses into nested shapes\n */\nexport function derivePlaceholder<T extends DocShape>(\n schema: T,\n): InferPlaceholderType<T> {\n const result: Record<string, unknown> = {}\n\n for (const [key, shape] of Object.entries(schema.shapes)) {\n result[key] = deriveShapePlaceholder(shape)\n }\n\n return result as InferPlaceholderType<T>\n}\n\n/**\n * Derives placeholder for a single shape.\n *\n * Leaf nodes: return _placeholder directly\n * Containers: recurse into nested shapes (ignore _placeholder on containers)\n */\nexport function deriveShapePlaceholder(shape: ContainerOrValueShape): unknown {\n switch (shape._type) {\n // Any container - no placeholder (undefined)\n case \"any\":\n return undefined\n\n // Leaf containers - use _placeholder directly\n case \"text\":\n return shape._placeholder\n case \"counter\":\n return shape._placeholder\n\n // Dynamic containers - always empty (no per-entry merging)\n case \"list\":\n case \"movableList\":\n case \"tree\":\n return []\n case \"record\":\n return {}\n\n // Structured container - recurse into nested shapes\n case \"struct\": {\n const result: Record<string, unknown> = {}\n for (const [key, nestedShape] of Object.entries(shape.shapes)) {\n result[key] = deriveShapePlaceholder(nestedShape)\n }\n return result\n }\n\n case \"value\":\n return deriveValueShapePlaceholder(shape)\n\n default:\n return undefined\n }\n}\n\nfunction deriveValueShapePlaceholder(shape: ValueShape): unknown {\n switch (shape.valueType) {\n // Any value - no placeholder (undefined)\n case \"any\":\n return undefined\n\n // Leaf values - use _placeholder directly\n case \"string\":\n return shape._placeholder\n case \"number\":\n return shape._placeholder\n case \"boolean\":\n return shape._placeholder\n case \"null\":\n return null\n case \"undefined\":\n return undefined\n case \"uint8array\":\n return shape._placeholder\n\n // Structured value - recurse into nested shapes (like struct)\n case \"struct\": {\n const result: Record<string, unknown> = {}\n for (const [key, nestedShape] of Object.entries(shape.shape)) {\n result[key] = deriveValueShapePlaceholder(nestedShape)\n }\n return result\n }\n\n // Dynamic values - always empty\n case \"array\":\n return []\n case \"record\":\n return {}\n\n // Unions - use _placeholder if explicitly set, otherwise derive from first variant\n case \"union\": {\n // Check if _placeholder was explicitly set (not the default empty object)\n // We need to check if it's a primitive value OR a non-empty object\n const placeholder = shape._placeholder\n if (placeholder !== undefined) {\n // If it's a primitive (null, string, number, boolean), use it\n if (placeholder === null || typeof placeholder !== \"object\") {\n return placeholder\n }\n // If it's an object with keys, use it\n if (Object.keys(placeholder as object).length > 0) {\n return placeholder\n }\n }\n // Otherwise derive from first variant\n return deriveValueShapePlaceholder(shape.shapes[0])\n }\n\n case \"discriminatedUnion\": {\n // Check if _placeholder was explicitly set (not the default empty object)\n const placeholder = shape._placeholder\n if (placeholder !== undefined) {\n // If it's a primitive (null, string, number, boolean), use it\n if (placeholder === null || typeof placeholder !== \"object\") {\n return placeholder\n }\n // If it's an object with keys, use it\n if (Object.keys(placeholder as object).length > 0) {\n return placeholder\n }\n }\n // Otherwise derive from first variant\n const firstKey = Object.keys(shape.variants)[0]\n return deriveValueShapePlaceholder(shape.variants[firstKey])\n }\n\n default:\n return undefined\n }\n}\n","import type { ContainerID, Diff, LoroDoc, LoroEventBatch } from \"loro-crdt\"\n\nexport type DiffOverlay = ReadonlyMap<ContainerID, Diff>\n\nexport function createDiffOverlay(\n doc: LoroDoc,\n batch: LoroEventBatch,\n): DiffOverlay {\n return new Map(doc.diff(batch.to, batch.from, false))\n}\n","import {\n type LoroCounter,\n LoroDoc,\n type LoroEventBatch,\n type LoroList,\n type LoroMap,\n type LoroMovableList,\n type LoroText,\n type LoroTree,\n} from \"loro-crdt\"\nimport { createDiffOverlay } from \"./diff-overlay.js\"\nimport { loro } from \"./loro.js\"\nimport type {\n ContainerOrValueShape,\n ContainerShape,\n CounterContainerShape,\n DocShape,\n ListContainerShape,\n MovableListContainerShape,\n RecordContainerShape,\n ShapeToContainer,\n StructContainerShape,\n TextContainerShape,\n TreeRefInterface,\n} from \"./shape.js\"\nimport { createTypedDoc, type Frontiers, type TypedDoc } from \"./typed-doc.js\"\nimport { INTERNAL_SYMBOL, type TypedRef } from \"./typed-refs/base.js\"\nimport type { StructRef } from \"./typed-refs/struct-ref.js\"\nimport type { TreeRef } from \"./typed-refs/tree-ref.js\"\nimport { createContainerTypedRef } from \"./typed-refs/utils.js\"\nimport type { Mutable } from \"./types.js\"\n\n/**\n * The primary method of mutating typed documents and refs.\n * Batches multiple mutations into a single transaction.\n * All changes commit together at the end.\n *\n * Use this for:\n * - Find-and-mutate operations (required due to JS limitations)\n * - Performance (fewer commits)\n * - Atomic undo (all changes = one undo step)\n *\n * Returns the doc/ref for chaining.\n *\n * @param target - The TypedDoc or TypedRef to mutate\n * @param fn - Function that performs mutations on the draft\n * @returns The same target for chaining\n *\n * @example\n * ```typescript\n * import { change } from \"@loro-extended/change\"\n *\n * // Document-level change (chainable)\n * change(doc, draft => {\n * draft.count.increment(10)\n * draft.title.update(\"Hello\")\n * })\n * .count.increment(5) // Optional: continue mutating\n * .toJSON() // Optional: get snapshot\n *\n * // Ref-level change - enables encapsulation\n * function addItems(list: ListRef<...>) {\n * change(list, draft => {\n * draft.push({ name: \"item1\" })\n * draft.push({ name: \"item2\" })\n * })\n * }\n *\n * // TreeRef example - pass around refs without exposing the doc\n * function addStates(states: TreeRef<StateShape>) {\n * change(states, draft => {\n * draft.createNode({ name: \"idle\" })\n * draft.createNode({ name: \"running\" })\n * })\n * }\n * ```\n */\n// Overload for TypedDoc\nexport function change<Shape extends DocShape>(\n doc: TypedDoc<Shape>,\n fn: (draft: Mutable<Shape>) => void,\n): TypedDoc<Shape>\n\n// Overload for TreeRef (special case - not a TypedRef<ContainerShape>)\nexport function change<DataShape extends StructContainerShape>(\n ref: TreeRef<DataShape>,\n fn: (draft: TreeRef<DataShape>) => void,\n): TreeRef<DataShape>\n\n// Overload for TreeRefInterface (the mutable type from TreeContainerShape)\nexport function change<DataShape extends StructContainerShape>(\n ref: TreeRefInterface<DataShape>,\n fn: (draft: TreeRefInterface<DataShape>) => void,\n): TreeRefInterface<DataShape>\n\n// Overload for StructRef (special case - uses Proxy, not a class extending TypedRef)\n// This must come before the generic TypedRef overload to match StructRef properly\nexport function change<\n NestedShapes extends Record<string, ContainerOrValueShape>,\n>(\n ref: StructRef<NestedShapes>,\n fn: (draft: StructRef<NestedShapes>) => void,\n): StructRef<NestedShapes>\n\n// Overload for TypedRef (all container refs) - preserves concrete ref type\nexport function change<T extends TypedRef<ContainerShape>>(\n ref: T,\n fn: (draft: T) => void,\n): T\n\n// Implementation\nexport function change(\n target:\n | TypedDoc<any>\n | TypedRef<any>\n | TreeRef<any>\n | TreeRefInterface<any>\n | StructRef<any>,\n fn: (draft: any) => void,\n):\n | TypedDoc<any>\n | TypedRef<any>\n | TreeRef<any>\n | TreeRefInterface<any>\n | StructRef<any> {\n // Check if it's a TypedDoc (has .change method)\n if (\"change\" in target && typeof (target as any).change === \"function\") {\n return (target as TypedDoc<any>).change(fn)\n }\n\n // It's a TypedRef or TreeRef - use ref-level change logic\n return changeRef(target as TypedRef<any> | TreeRef<any>, fn)\n}\n\n/**\n * Internal implementation for ref-level change.\n * Creates a draft ref with batchedMutation=true, executes the function,\n * absorbs changes, and commits.\n */\nfunction changeRef<T extends TypedRef<any> | TreeRef<any>>(\n ref: T,\n fn: (draft: T) => void,\n): T {\n // Get internals via INTERNAL_SYMBOL\n const internals = (ref as any)[INTERNAL_SYMBOL]\n if (!internals) {\n throw new Error(\n \"change() requires a TypedRef with internal methods. \" +\n \"Make sure you're passing a valid typed ref.\",\n )\n }\n\n // Get the params needed to create a draft\n const params = internals.getTypedRefParams()\n\n // Create draft params with batchedMutation enabled and autoCommit disabled\n const draftParams = {\n ...params,\n autoCommit: false,\n batchedMutation: true,\n }\n\n // Create the draft ref using the same factory that created the original\n const draft = createContainerTypedRef(draftParams) as T\n\n // Execute the user's function with the draft\n fn(draft)\n\n // Absorb any cached plain values back into the Loro containers\n const draftInternals = (draft as any)[INTERNAL_SYMBOL]\n draftInternals.absorbPlainValues()\n\n // Commit the changes\n // Note: Loro's commit() is idempotent, so nested calls are safe\n internals.getDoc().commit()\n\n // Return the original ref for chaining\n return ref\n}\n\n/**\n * Access the underlying LoroDoc for advanced operations.\n * Works on both TypedDoc and any typed ref (TextRef, CounterRef, ListRef, etc.).\n *\n * @param docOrRef - The TypedDoc or typed ref to unwrap\n * @returns The underlying LoroDoc instance (or undefined for refs created outside a doc context)\n *\n * @example\n * ```typescript\n * import { getLoroDoc } from \"@loro-extended/change\"\n *\n * // From TypedDoc\n * const loroDoc = getLoroDoc(doc)\n * const version = loroDoc.version()\n * loroDoc.subscribe(() => console.log(\"changed\"))\n *\n * // From any ref (TextRef, CounterRef, ListRef, etc.)\n * const titleRef = doc.title\n * const loroDoc = getLoroDoc(titleRef)\n * loroDoc?.subscribe(() => console.log(\"changed\"))\n * ```\n */\nexport function getLoroDoc<Shape extends DocShape>(\n doc: TypedDoc<Shape>,\n): LoroDoc\nexport function getLoroDoc<Shape extends ContainerShape>(\n ref: TypedRef<Shape>,\n): LoroDoc\nexport function getLoroDoc<DataShape extends StructContainerShape>(\n ref: TreeRef<DataShape>,\n): LoroDoc\nexport function getLoroDoc<DataShape extends StructContainerShape>(\n ref: TreeRefInterface<DataShape>,\n): LoroDoc\nexport function getLoroDoc(\n docOrRef:\n | TypedDoc<any>\n | TypedRef<any>\n | TreeRef<any>\n | TreeRefInterface<any>,\n): LoroDoc {\n // Use loro() to access the underlying LoroDoc\n return loro(docOrRef as any).doc\n}\n\n/**\n * Access the underlying Loro container from a typed ref.\n * Returns the correctly-typed container based on the ref type.\n *\n * @param ref - The typed ref to unwrap\n * @returns The underlying Loro container (LoroText, LoroCounter, LoroList, etc.)\n *\n * @example\n * ```typescript\n * import { getLoroContainer } from \"@loro-extended/change\"\n *\n * const titleRef = doc.title\n * const loroText = getLoroContainer(titleRef) // LoroText\n *\n * const countRef = doc.count\n * const loroCounter = getLoroContainer(countRef) // LoroCounter\n *\n * const itemsRef = doc.items\n * const loroList = getLoroContainer(itemsRef) // LoroList\n *\n * // Subscribe to container-level changes\n * loroText.subscribe((event) => console.log(\"Text changed:\", event))\n * ```\n */\nexport function getLoroContainer(ref: TypedRef<TextContainerShape>): LoroText\nexport function getLoroContainer(\n ref: TypedRef<CounterContainerShape>,\n): LoroCounter\nexport function getLoroContainer(ref: TypedRef<ListContainerShape>): LoroList\nexport function getLoroContainer(\n ref: TypedRef<MovableListContainerShape>,\n): LoroMovableList\nexport function getLoroContainer(ref: TypedRef<RecordContainerShape>): LoroMap\nexport function getLoroContainer(ref: TypedRef<StructContainerShape>): LoroMap\nexport function getLoroContainer<\n NestedShapes extends Record<string, ContainerOrValueShape>,\n>(ref: StructRef<NestedShapes>): LoroMap\nexport function getLoroContainer<DataShape extends StructContainerShape>(\n ref: TreeRef<DataShape>,\n): LoroTree\nexport function getLoroContainer<DataShape extends StructContainerShape>(\n ref: TreeRefInterface<DataShape>,\n): LoroTree\nexport function getLoroContainer<Shape extends ContainerShape>(\n ref: TypedRef<Shape>,\n): ShapeToContainer<Shape>\nexport function getLoroContainer(\n ref: TypedRef<any> | TreeRef<any> | TreeRefInterface<any> | StructRef<any>,\n): unknown {\n // Use loro() to access the underlying container\n return loro(ref as any).container\n}\n\n/**\n * Creates a new TypedDoc as a fork of the current document.\n * The forked doc contains all history up to the current version.\n * The forked doc has a different PeerID from the original by default.\n *\n * For raw LoroDoc access, use: `loro(doc).doc.fork()`\n *\n * @param doc - The TypedDoc to fork\n * @param options - Optional settings\n * @param options.preservePeerId - If true, copies the original doc's peer ID to the fork\n * @returns A new TypedDoc with the same schema at the current version\n *\n * @example\n * ```typescript\n * import { fork, loro } from \"@loro-extended/change\"\n *\n * const doc = createTypedDoc(schema);\n * doc.title.update(\"Hello\");\n *\n * // Fork the document\n * const forkedDoc = fork(doc);\n * forkedDoc.title.update(\"World\");\n *\n * console.log(doc.title.toString()); // \"Hello\"\n * console.log(forkedDoc.title.toString()); // \"World\"\n *\n * // Fork with same peer ID (for World/Worldview pattern)\n * const worldview = fork(world, { preservePeerId: true });\n * ```\n */\nexport function fork<Shape extends DocShape>(\n doc: TypedDoc<Shape>,\n options?: { preservePeerId?: boolean },\n): TypedDoc<Shape> {\n const loroDoc = loro(doc).doc\n const forkedLoroDoc = loroDoc.fork()\n const shape = loro(doc).docShape as Shape\n\n // Optionally preserve the peer ID (useful for World/Worldview pattern)\n if (options?.preservePeerId) {\n forkedLoroDoc.setPeerId(loroDoc.peerId)\n }\n\n return createTypedDoc(shape, { doc: forkedLoroDoc })\n}\n\n/**\n * Creates a new TypedDoc at a specified version (frontiers).\n * The forked doc will only contain history before the specified frontiers.\n * The forked doc has a different PeerID from the original.\n *\n * For raw LoroDoc access, use: `loro(doc).doc.forkAt(frontiers)`\n *\n * @param doc - The TypedDoc to fork\n * @param frontiers - The version to fork at (obtained from `loro(doc).doc.frontiers()`)\n * @returns A new TypedDoc with the same schema at the specified version\n *\n * @example\n * ```typescript\n * import { forkAt, loro } from \"@loro-extended/change\"\n *\n * const doc = createTypedDoc(schema);\n * doc.title.update(\"Hello\");\n * const frontiers = loro(doc).doc.frontiers();\n * doc.title.update(\"World\");\n *\n * // Fork at the earlier version\n * const forkedDoc = forkAt(doc, frontiers);\n * console.log(forkedDoc.title.toString()); // \"Hello\"\n * console.log(doc.title.toString()); // \"World\"\n * ```\n */\nexport function forkAt<Shape extends DocShape>(\n doc: TypedDoc<Shape>,\n frontiers: Frontiers,\n): TypedDoc<Shape> {\n const loroDoc = loro(doc).doc\n const forkedLoroDoc = loroDoc.forkAt(frontiers)\n const shape = loro(doc).docShape as Shape\n return createTypedDoc(shape, { doc: forkedLoroDoc })\n}\n\n/**\n * Creates a new TypedDoc at a specified version using a shallow snapshot.\n * Unlike `forkAt`, this creates a \"garbage-collected\" snapshot that only\n * contains the current state and history since the specified frontiers.\n *\n * This is more memory-efficient than `forkAt` for documents with long history,\n * especially useful for the fork-and-merge pattern in LEA where we only need:\n * 1. Read current state\n * 2. Apply changes\n * 3. Export delta and merge back\n *\n * The shallow fork has a different PeerID from the original by default.\n * Use `preservePeerId: true` to copy the original's peer ID (useful for\n * fork-and-merge patterns where you want consistent frontier progression).\n *\n * @param doc - The TypedDoc to fork\n * @param frontiers - The version to fork at (obtained from `loro(doc).doc.frontiers()`)\n * @param options - Optional settings\n * @param options.preservePeerId - If true, copies the original doc's peer ID to the fork\n * @returns A new TypedDoc with the same schema at the specified version (shallow)\n *\n * @example\n * ```typescript\n * import { shallowForkAt, loro } from \"@loro-extended/change\"\n *\n * const doc = createTypedDoc(schema);\n * doc.title.update(\"Hello\");\n * const frontiers = loro(doc).doc.frontiers();\n *\n * // Create a shallow fork (memory-efficient)\n * const shallowDoc = shallowForkAt(doc, frontiers, { preservePeerId: true });\n *\n * // Modify the shallow doc\n * shallowDoc.title.update(\"World\");\n *\n * // Merge changes back\n * const update = loro(shallowDoc).doc.export({\n * mode: \"update\",\n * from: loro(doc).doc.version()\n * });\n * loro(doc).doc.import(update);\n * ```\n */\nexport function shallowForkAt<Shape extends DocShape>(\n doc: TypedDoc<Shape>,\n frontiers: Frontiers,\n options?: { preservePeerId?: boolean },\n): TypedDoc<Shape> {\n const loroDoc = loro(doc).doc\n const shape = loro(doc).docShape as Shape\n\n // Export a shallow snapshot at the specified frontiers\n const shallowBytes = loroDoc.export({\n mode: \"shallow-snapshot\",\n frontiers,\n })\n\n // Create a new LoroDoc from the shallow snapshot\n const shallowLoroDoc = LoroDoc.fromSnapshot(shallowBytes)\n\n // Optionally preserve the peer ID for consistent frontier progression\n if (options?.preservePeerId) {\n shallowLoroDoc.setPeerId(loroDoc.peerId)\n }\n\n return createTypedDoc(shape, { doc: shallowLoroDoc })\n}\n\nexport type Transition<Shape extends DocShape> = {\n before: TypedDoc<Shape>\n after: TypedDoc<Shape>\n}\n\n/**\n * Build a `{ before, after }` transition from a TypedDoc and a Loro event batch.\n * Uses a reverse diff overlay to compute the \"before\" view without checkout.\n * Throws on checkout events to avoid time-travel transitions.\n */\nexport function getTransition<Shape extends DocShape>(\n doc: TypedDoc<Shape>,\n event: LoroEventBatch,\n): Transition<Shape> {\n if (event.by === \"checkout\") {\n throw new Error(\"getTransition does not support checkout events\")\n }\n\n const loroDoc = getLoroDoc(doc)\n const shape = loro(doc).docShape as Shape\n const overlay = createDiffOverlay(loroDoc, event)\n\n return {\n before: createTypedDoc(shape, { doc: loroDoc, overlay }),\n after: createTypedDoc(shape, { doc: loroDoc }),\n }\n}\n","/**\n * The `loro()` function - single escape hatch for CRDT internals.\n *\n * Design Principle:\n * > If it takes a plain JavaScript value, keep it on the ref.\n * > If it takes a Loro container or exposes CRDT internals, move to `loro()`.\n *\n * @example\n * ```typescript\n * import { loro } from \"@loro-extended/change\"\n *\n * // Access underlying LoroDoc\n * loro(ref).doc\n *\n * // Access underlying Loro container (correctly typed)\n * loro(ref).container // LoroList, LoroMap, LoroText, etc.\n *\n * // Subscribe to changes\n * loro(ref).subscribe(callback)\n *\n * // Container operations\n * loro(list).pushContainer(loroMap)\n * loro(struct).setContainer('key', loroMap)\n * ```\n */\n\nimport type {\n Container,\n LoroCounter,\n LoroDoc,\n LoroEventBatch,\n LoroList,\n LoroMap,\n LoroMovableList,\n LoroText,\n LoroTree,\n LoroTreeNode,\n Subscription,\n} from \"loro-crdt\"\nimport type { JsonPatch } from \"./json-patch.js\"\nimport type {\n ContainerOrValueShape,\n ContainerShape,\n DocShape,\n StructContainerShape,\n TreeRefInterface,\n} from \"./shape.js\"\nimport type { TypedDoc } from \"./typed-doc.js\"\nimport type { TypedRef } from \"./typed-refs/base.js\"\nimport type { CounterRef } from \"./typed-refs/counter-ref.js\"\nimport type { ListRef } from \"./typed-refs/list-ref.js\"\nimport type { MovableListRef } from \"./typed-refs/movable-list-ref.js\"\nimport type { RecordRef } from \"./typed-refs/record-ref.js\"\nimport type { StructRef } from \"./typed-refs/struct-ref.js\"\nimport type { TextRef } from \"./typed-refs/text-ref.js\"\nimport type { TreeNodeRef } from \"./typed-refs/tree-node-ref.js\"\nimport type { TreeRef } from \"./typed-refs/tree-ref.js\"\n\n// ============================================================================\n// Symbol for loro() access\n// ============================================================================\n\n/**\n * Well-known Symbol for loro() access.\n * This is exported so advanced users can access it directly if needed.\n */\nexport const LORO_SYMBOL = Symbol.for(\"loro-extended:loro\")\n\n// ============================================================================\n// Interface definitions for loro() return types\n// ============================================================================\n\n/**\n * Base interface for all loro() return types.\n * Provides access to the underlying LoroDoc, container, and subscription.\n */\nexport interface LoroRefBase {\n /** The underlying LoroDoc */\n readonly doc: LoroDoc\n\n /** The underlying Loro container */\n readonly container: unknown\n\n /**\n * Subscribe to container-level changes.\n * @param callback - Function called when the container changes\n * @returns Subscription that can be used to unsubscribe\n */\n subscribe(callback: (event: LoroEventBatch) => void): Subscription\n}\n\n/**\n * loro() return type for ListRef and MovableListRef.\n * Provides container operations that take Loro containers.\n */\nexport interface LoroListRef extends LoroRefBase {\n /** The underlying LoroList or LoroMovableList */\n readonly container: LoroList | LoroMovableList\n\n /**\n * Push a Loro container to the end of the list.\n * Use this when you need to add a pre-existing container.\n */\n pushContainer(container: Container): Container\n\n /**\n * Insert a Loro container at the specified index.\n * Use this when you need to insert a pre-existing container.\n */\n insertContainer(index: number, container: Container): Container\n}\n\n/**\n * loro() return type for StructRef and RecordRef.\n * Provides container operations that take Loro containers.\n */\nexport interface LoroMapRef extends LoroRefBase {\n /** The underlying LoroMap */\n readonly container: LoroMap\n\n /**\n * Set a Loro container at the specified key.\n * Use this when you need to set a pre-existing container.\n */\n setContainer(key: string, container: Container): Container\n}\n\n/**\n * loro() return type for TextRef.\n */\nexport interface LoroTextRef extends LoroRefBase {\n /** The underlying LoroText */\n readonly container: LoroText\n}\n\n/**\n * loro() return type for CounterRef.\n */\nexport interface LoroCounterRef extends LoroRefBase {\n /** The underlying LoroCounter */\n readonly container: LoroCounter\n}\n\n/**\n * loro() return type for TreeRef.\n */\nexport interface LoroTreeRef extends LoroRefBase {\n /** The underlying LoroTree */\n readonly container: LoroTree\n}\n\n/**\n * loro() return type for TreeNodeRef.\n */\nexport interface LoroTreeNodeRef extends LoroRefBase {\n /** The underlying LoroTreeNode */\n readonly container: LoroTreeNode\n}\n\n/**\n * loro() return type for TypedDoc.\n * Provides access to doc-level operations.\n */\nexport interface LoroTypedDocRef extends LoroRefBase {\n /** The underlying LoroDoc (same as doc for TypedDoc) */\n readonly container: LoroDoc\n\n /**\n * Apply JSON Patch operations to the document.\n * @param patch - Array of JSON Patch operations (RFC 6902)\n * @param pathPrefix - Optional path prefix for scoped operations\n */\n applyPatch(patch: JsonPatch, pathPrefix?: (string | number)[]): void\n\n /** Access the document schema shape */\n readonly docShape: DocShape\n\n /** Get raw CRDT value without placeholder overlay */\n readonly rawValue: unknown\n}\n\n// ============================================================================\n// loro() function overloads\n// ============================================================================\n\n/**\n * Access CRDT internals for a ListRef.\n */\nexport function loro<NestedShape extends ContainerShape>(\n ref: ListRef<NestedShape>,\n): LoroListRef\n\n/**\n * Access CRDT internals for a MovableListRef.\n */\nexport function loro<NestedShape extends ContainerShape>(\n ref: MovableListRef<NestedShape>,\n): LoroListRef\n\n/**\n * Access CRDT internals for a StructRef.\n */\nexport function loro<\n NestedShapes extends Record<string, ContainerOrValueShape>,\n>(ref: StructRef<NestedShapes>): LoroMapRef\n\n/**\n * Access CRDT internals for a RecordRef.\n */\nexport function loro<NestedShape extends ContainerShape>(\n ref: RecordRef<NestedShape>,\n): LoroMapRef\n\n/**\n * Access CRDT internals for a TextRef.\n */\nexport function loro(ref: TextRef): LoroTextRef\n\n/**\n * Access CRDT internals for a CounterRef.\n */\nexport function loro(ref: CounterRef): LoroCounterRef\n\n/**\n * Access CRDT internals for a TreeRef.\n */\nexport function loro<DataShape extends StructContainerShape>(\n ref: TreeRef<DataShape> | TreeRefInterface<DataShape>,\n): LoroTreeRef\n\n/**\n * Access CRDT internals for a TreeNodeRef.\n */\nexport function loro<DataShape extends StructContainerShape>(\n ref: TreeNodeRef<DataShape>,\n): LoroTreeNodeRef\n\n/**\n * Access CRDT internals for a TypedDoc.\n */\nexport function loro<Shape extends DocShape>(\n doc: TypedDoc<Shape>,\n): LoroTypedDocRef\n\n/**\n * Access CRDT internals for any TypedRef.\n */\nexport function loro<Shape extends ContainerShape>(\n ref: TypedRef<Shape>,\n): LoroRefBase\n\n/**\n * The `loro()` function - single escape hatch for CRDT internals.\n *\n * Use this to access:\n * - The underlying LoroDoc\n * - The underlying Loro container (correctly typed)\n * - Container-level subscriptions\n * - Container operations that take Loro containers (pushContainer, setContainer, etc.)\n *\n * @param refOrDoc - A TypedRef or TypedDoc\n * @returns An object with CRDT internals and operations\n *\n * @example\n * ```typescript\n * import { loro } from \"@loro-extended/change\"\n *\n * // Access underlying LoroDoc\n * loro(doc.settings).doc\n *\n * // Access underlying Loro container\n * loro(doc.items).container // LoroList\n *\n * // Subscribe to changes\n * loro(doc.settings).subscribe(event => { ... })\n *\n * // Container operations\n * loro(doc.items).pushContainer(loroMap)\n * ```\n */\nexport function loro(\n refOrDoc:\n | TypedRef<any>\n | TypedDoc<any>\n | TreeRef<any>\n | TreeRefInterface<any>\n | TreeNodeRef<any>\n | StructRef<any>,\n): LoroRefBase {\n // Access the loro namespace via the well-known symbol\n const loroNamespace = (refOrDoc as any)[LORO_SYMBOL]\n if (!loroNamespace) {\n throw new Error(\n \"Invalid argument: expected TypedRef, TreeRef, or TypedDoc with loro() support\",\n )\n }\n return loroNamespace\n}\n","/** biome-ignore-all lint/suspicious/noExplicitAny: fix later */\n\nimport {\n LoroDoc,\n type LoroEventBatch,\n type PeerID,\n type Subscription,\n} from \"loro-crdt\"\nimport { derivePlaceholder } from \"./derive-placeholder.js\"\nimport {\n type JsonPatch,\n JsonPatchApplicator,\n type JsonPatchOperation,\n normalizePath,\n} from \"./json-patch.js\"\nimport { LORO_SYMBOL, type LoroTypedDocRef } from \"./loro.js\"\nimport { overlayPlaceholder } from \"./overlay.js\"\nimport type { DocShape } from \"./shape.js\"\nimport { type DiffOverlay, INTERNAL_SYMBOL } from \"./typed-refs/base.js\"\nimport { DocRef } from \"./typed-refs/doc-ref.js\"\nimport type { Infer, InferPlaceholderType, Mutable } from \"./types.js\"\nimport { validatePlaceholder } from \"./validation.js\"\n\n/**\n * Internal TypedDoc implementation (not directly exposed to users).\n * Users interact with the proxied version that provides direct schema access.\n */\nclass TypedDocInternal<Shape extends DocShape> {\n private shape: Shape\n private placeholder: InferPlaceholderType<Shape>\n private doc: LoroDoc\n private overlay?: DiffOverlay\n private valueRef: DocRef<Shape> | null = null\n // Reference to the proxy for returning from change()\n proxy: TypedDoc<Shape> | null = null\n\n constructor(\n shape: Shape,\n doc: LoroDoc = new LoroDoc(),\n overlay?: DiffOverlay,\n ) {\n this.shape = shape\n this.placeholder = derivePlaceholder(shape)\n this.doc = doc\n this.overlay = overlay\n\n validatePlaceholder(this.placeholder, this.shape)\n }\n\n get value(): Mutable<Shape> {\n if (!this.valueRef) {\n this.valueRef = new DocRef({\n shape: this.shape,\n placeholder: this.placeholder as any,\n doc: this.doc,\n autoCommit: true,\n overlay: this.overlay,\n })\n }\n return this.valueRef as unknown as Mutable<Shape>\n }\n\n toJSON(): Infer<Shape> {\n const crdtValue = this.doc.toJSON()\n return overlayPlaceholder(\n this.shape,\n crdtValue,\n this.placeholder as any,\n ) as Infer<Shape>\n }\n\n change(fn: (draft: Mutable<Shape>) => void): void {\n const draft = new DocRef({\n shape: this.shape,\n placeholder: this.placeholder as any,\n doc: this.doc,\n autoCommit: false,\n batchedMutation: true, // Enable value shape caching for find-and-mutate patterns\n overlay: this.overlay,\n })\n fn(draft as unknown as Mutable<Shape>)\n draft[INTERNAL_SYMBOL].absorbPlainValues()\n this.doc.commit()\n\n // Invalidate cached value ref since doc changed\n this.valueRef = null\n }\n\n applyPatch(patch: JsonPatch, pathPrefix?: (string | number)[]): void {\n this.change(draft => {\n const applicator = new JsonPatchApplicator(draft)\n\n const prefixedPatch = pathPrefix\n ? patch.map((op: JsonPatchOperation) => ({\n ...op,\n path: [...pathPrefix, ...normalizePath(op.path)],\n }))\n : patch\n\n applicator.applyPatch(prefixedPatch)\n })\n }\n\n get loroDoc(): LoroDoc {\n return this.doc\n }\n\n get docShape(): Shape {\n return this.shape\n }\n\n get rawValue(): any {\n return this.doc.toJSON()\n }\n}\n\n/**\n * The proxied TypedDoc type that provides direct schema access.\n * Schema properties are accessed directly on the doc object.\n *\n * @example\n * ```typescript\n * const doc = createTypedDoc(schema);\n *\n * // Direct schema access\n * doc.count.increment(5);\n * doc.title.insert(0, \"Hello\");\n *\n * // Serialize to JSON (works on doc and all refs)\n * const snapshot = doc.toJSON();\n * const users = doc.users.toJSON();\n *\n * // Batched mutations via change()\n * doc.change(draft => {\n * draft.count.increment(10);\n * draft.title.update(\"World\");\n * });\n *\n * // Access CRDT internals via loro()\n * import { loro } from \"@loro-extended/change\";\n * loro(doc).doc; // LoroDoc\n * loro(doc).subscribe(callback);\n * ```\n */\n/**\n * Frontiers represent a specific version in the document's history.\n * Each frontier is an operation ID consisting of a peer ID and counter.\n */\nexport type Frontiers = { peer: PeerID; counter: number }[]\n\nexport type CreateTypedDocOptions = {\n doc?: LoroDoc\n overlay?: DiffOverlay\n}\n\nexport type TypedDoc<Shape extends DocShape> = Mutable<Shape> & {\n /**\n * The primary method of mutating typed documents.\n * Batches multiple mutations into a single transaction.\n * All changes commit together at the end.\n *\n * Use this for:\n * - Find-and-mutate operations (required due to JS limitations)\n * - Performance (fewer commits)\n * - Atomic undo (all changes = one undo step)\n *\n * Returns the doc for chaining.\n *\n * @example\n * ```typescript\n * doc.change(draft => {\n * draft.count.increment(10);\n * draft.title.update(\"World\");\n * });\n * ```\n */\n change(fn: (draft: Mutable<Shape>) => void): TypedDoc<Shape>\n\n /**\n * Returns the full plain JavaScript object representation of the document.\n * This is an O(N) operation that serializes the entire document.\n *\n * @example\n * ```typescript\n * const snapshot = doc.toJSON();\n * console.log(snapshot.count); // number\n * ```\n */\n toJSON(): Infer<Shape>\n\n /**\n * Creates a new TypedDoc at a specified version (frontiers).\n * The forked doc will only contain history before the specified frontiers.\n * The forked doc has a different PeerID from the original.\n *\n * For raw LoroDoc access, use: `loro(doc).doc.forkAt(frontiers)`\n *\n * @param frontiers - The version to fork at (obtained from `loro(doc).doc.frontiers()`)\n * @returns A new TypedDoc with the same schema at the specified version\n *\n * @example\n * ```typescript\n * import { loro } from \"@loro-extended/change\";\n *\n * const doc = createTypedDoc(schema);\n * doc.title.update(\"Hello\");\n * const frontiers = loro(doc).doc.frontiers();\n * doc.title.update(\"World\");\n *\n * // Fork at the earlier version\n * const forkedDoc = doc.forkAt(frontiers);\n * console.log(forkedDoc.title.toString()); // \"Hello\"\n * console.log(doc.title.toString()); // \"World\"\n * ```\n */\n forkAt(frontiers: Frontiers): TypedDoc<Shape>\n}\n\n/**\n * Creates a new TypedDoc with the given schema.\n * Returns a proxied document where schema properties are accessed directly.\n *\n * @param shape - The document schema (with optional .placeholder() values)\n * @param options - Optional existing LoroDoc or diff overlay\n * @returns A proxied TypedDoc with direct schema access\n *\n * @example\n * ```typescript\n * const schema = Shape.doc({\n * title: Shape.text(),\n * count: Shape.counter(),\n * });\n *\n * const doc = createTypedDoc(schema);\n *\n * // Direct mutations (auto-commit)\n * doc.count.increment(5);\n * doc.title.insert(0, \"Hello\");\n *\n * // Batched mutations via change()\n * doc.change(draft => {\n * draft.count.increment(10);\n * draft.title.update(\"World\");\n * });\n *\n * // Get plain JSON\n * const snapshot = doc.toJSON();\n *\n * // Access CRDT internals via loro()\n * import { loro } from \"@loro-extended/change\";\n * loro(doc).doc; // LoroDoc\n * loro(doc).subscribe(callback);\n * ```\n */\nexport function createTypedDoc<Shape extends DocShape>(\n shape: Shape,\n options: CreateTypedDocOptions = {},\n): TypedDoc<Shape> {\n const internal = new TypedDocInternal(\n shape,\n options.doc || new LoroDoc(),\n options.overlay,\n )\n\n // Create the loro() namespace for this doc\n const loroNamespace: LoroTypedDocRef = {\n get doc(): LoroDoc {\n return internal.loroDoc\n },\n get container(): LoroDoc {\n return internal.loroDoc\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n return internal.loroDoc.subscribe(callback)\n },\n applyPatch(patch: JsonPatch, pathPrefix?: (string | number)[]): void {\n internal.applyPatch(patch, pathPrefix)\n },\n get docShape(): DocShape {\n return internal.docShape\n },\n get rawValue(): unknown {\n return internal.rawValue\n },\n }\n\n // Create the change() function that returns the proxy for chaining\n const changeFunction = (\n fn: (draft: Mutable<Shape>) => void,\n ): TypedDoc<Shape> => {\n internal.change(fn)\n return proxy\n }\n\n // Create the forkAt() function that returns a new TypedDoc at the specified version\n const forkAtFunction = (frontiers: Frontiers): TypedDoc<Shape> => {\n const forkedLoroDoc = internal.loroDoc.forkAt(frontiers)\n return createTypedDoc(internal.docShape, { doc: forkedLoroDoc })\n }\n\n // Create a proxy that delegates schema properties to the DocRef\n // and provides change() and forkAt() methods\n const proxy = new Proxy(internal.value as object, {\n get(target, prop, receiver) {\n // loro() access via well-known symbol\n if (prop === LORO_SYMBOL) {\n return loroNamespace\n }\n\n // change() method directly on doc\n if (prop === \"change\") {\n return changeFunction\n }\n\n // forkAt() method directly on doc\n if (prop === \"forkAt\") {\n return forkAtFunction\n }\n\n // toJSON() should always read fresh from the CRDT\n if (prop === \"toJSON\") {\n return () => internal.toJSON()\n }\n\n // Delegate to the DocRef (which is the target)\n return Reflect.get(target, prop, receiver)\n },\n\n set(target, prop, value, receiver) {\n // Don't allow setting change, forkAt, or LORO_SYMBOL\n if (prop === LORO_SYMBOL || prop === \"change\" || prop === \"forkAt\") {\n return false\n }\n\n // Delegate to the DocRef\n return Reflect.set(target, prop, value, receiver)\n },\n\n // Support 'in' operator\n has(target, prop) {\n if (prop === LORO_SYMBOL || prop === \"change\" || prop === \"forkAt\")\n return true\n return Reflect.has(target, prop)\n },\n\n // Support Object.keys() - filter out Symbol properties to allow proxies to be used\n // in place of plain objects. This prevents React's \"Object keys must be strings\" error.\n ownKeys(target) {\n return Reflect.ownKeys(target).filter(key => typeof key === \"string\")\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (prop === \"change\") {\n return {\n configurable: true,\n enumerable: false,\n value: changeFunction,\n }\n }\n if (prop === \"forkAt\") {\n return {\n configurable: true,\n enumerable: false,\n value: forkAtFunction,\n }\n }\n if (prop === LORO_SYMBOL) {\n return {\n configurable: true,\n enumerable: false,\n value: loroNamespace,\n }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n }) as TypedDoc<Shape>\n\n // Store reference to proxy for returning from change()\n internal.proxy = proxy\n\n return proxy\n}\n","/** biome-ignore-all lint/suspicious/noExplicitAny: JSON Patch values can be any type */\n\nimport type { DocShape } from \"./shape.js\"\nimport type { Draft } from \"./types.js\"\n\n// =============================================================================\n// JSON PATCH TYPES - Discriminated Union for Type Safety\n// =============================================================================\n\nexport type JsonPatchAddOperation = {\n op: \"add\"\n path: string | (string | number)[]\n value: any\n}\n\nexport type JsonPatchRemoveOperation = {\n op: \"remove\"\n path: string | (string | number)[]\n}\n\nexport type JsonPatchReplaceOperation = {\n op: \"replace\"\n path: string | (string | number)[]\n value: any\n}\n\nexport type JsonPatchMoveOperation = {\n op: \"move\"\n path: string | (string | number)[]\n from: string | (string | number)[]\n}\n\nexport type JsonPatchCopyOperation = {\n op: \"copy\"\n path: string | (string | number)[]\n from: string | (string | number)[]\n}\n\nexport type JsonPatchTestOperation = {\n op: \"test\"\n path: string | (string | number)[]\n value: any\n}\n\nexport type JsonPatchOperation =\n | JsonPatchAddOperation\n | JsonPatchRemoveOperation\n | JsonPatchReplaceOperation\n | JsonPatchMoveOperation\n | JsonPatchCopyOperation\n | JsonPatchTestOperation\n\nexport type JsonPatch = JsonPatchOperation[]\n\n// =============================================================================\n// PATH NAVIGATION UTILITIES\n// =============================================================================\n\n/**\n * Normalize JSON Pointer string to path array\n * Handles RFC 6901 escaping: ~1 -> /, ~0 -> ~\n */\nexport function normalizePath(\n path: string | (string | number)[],\n): (string | number)[] {\n if (Array.isArray(path)) {\n return path\n }\n\n // Handle JSON Pointer format (RFC 6901)\n if (path.startsWith(\"/\")) {\n return path\n .slice(1) // Remove leading slash\n .split(\"/\")\n .map(segment => {\n // Handle JSON Pointer escaping\n const unescaped = segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\")\n // Try to parse as number for array indices\n const asNumber = Number(unescaped)\n return Number.isInteger(asNumber) && asNumber >= 0\n ? asNumber\n : unescaped\n })\n }\n\n // Handle simple dot notation or single segment\n return path.split(\".\").map(segment => {\n const asNumber = Number(segment)\n return Number.isInteger(asNumber) && asNumber >= 0 ? asNumber : segment\n })\n}\n\n/**\n * Navigate to a target path using natural DraftNode property access\n * This follows the existing patterns from the test suite\n */\nfunction navigateToPath<T extends DocShape>(\n draft: Draft<T>,\n path: (string | number)[],\n): { parent: any; key: string | number } {\n if (path.length === 0) {\n throw new Error(\"Cannot navigate to empty path\")\n }\n\n let current = draft as any\n\n // Navigate to parent of target\n for (let i = 0; i < path.length - 1; i++) {\n const segment = path[i]\n\n if (typeof segment === \"string\") {\n // Use natural property access - this leverages existing DraftNode lazy creation\n current = current[segment]\n if (current === undefined) {\n throw new Error(`Cannot navigate to path segment: ${segment}`)\n }\n } else if (typeof segment === \"number\") {\n // List/array access using get() method (following existing patterns)\n if (current.get && typeof current.get === \"function\") {\n current = current.get(segment)\n if (current === undefined) {\n throw new Error(`List index ${segment} does not exist`)\n }\n } else {\n throw new Error(`Cannot use numeric index ${segment} on non-list`)\n }\n } else {\n throw new Error(`Invalid path segment type: ${typeof segment}`)\n }\n }\n\n const targetKey = path[path.length - 1]\n return { parent: current, key: targetKey }\n}\n\n/**\n * Get value at path using natural DraftNode access patterns\n */\nfunction getValueAtPath<T extends DocShape>(\n draft: Draft<T>,\n path: (string | number)[],\n): any {\n if (path.length === 0) {\n return draft\n }\n\n const { parent, key } = navigateToPath(draft, path)\n\n if (typeof key === \"string\") {\n // Use natural property access or get() method\n if (parent.get && typeof parent.get === \"function\") {\n return parent.get(key)\n }\n return parent[key]\n } else if (typeof key === \"number\") {\n // List access using get() method\n if (parent.get && typeof parent.get === \"function\") {\n return parent.get(key)\n }\n throw new Error(`Cannot use numeric index ${key} on non-list`)\n }\n\n throw new Error(`Invalid key type: ${typeof key}`)\n}\n\n// =============================================================================\n// OPERATION HANDLERS - Following existing DraftNode patterns\n// =============================================================================\n\n/**\n * Handle 'add' operation using existing DraftNode methods\n */\nfunction handleAdd<T extends DocShape>(\n draft: Draft<T>,\n operation: JsonPatchAddOperation,\n): void {\n const path = normalizePath(operation.path)\n const { parent, key } = navigateToPath(draft, path)\n\n if (typeof key === \"string\") {\n // Map-like operations - use natural assignment or set() method\n if (parent.set && typeof parent.set === \"function\") {\n parent.set(key, operation.value)\n } else {\n // Natural property assignment (follows existing test patterns)\n parent[key] = operation.value\n }\n } else if (typeof key === \"number\") {\n // List operations - use insert() method (follows existing patterns)\n if (parent.insert && typeof parent.insert === \"function\") {\n parent.insert(key, operation.value)\n } else {\n throw new Error(`Cannot insert at numeric index ${key} on non-list`)\n }\n } else {\n throw new Error(`Invalid key type: ${typeof key}`)\n }\n}\n\n/**\n * Handle 'remove' operation using existing DraftNode methods\n */\nfunction handleRemove<T extends DocShape>(\n draft: Draft<T>,\n operation: JsonPatchRemoveOperation,\n): void {\n const path = normalizePath(operation.path)\n const { parent, key } = navigateToPath(draft, path)\n\n if (typeof key === \"string\") {\n // Map-like operations - use delete() method (follows existing patterns)\n if (parent.delete && typeof parent.delete === \"function\") {\n parent.delete(key)\n } else {\n delete parent[key]\n }\n } else if (typeof key === \"number\") {\n // List operations - use delete() method with count (follows existing patterns)\n if (parent.delete && typeof parent.delete === \"function\") {\n parent.delete(key, 1)\n } else {\n throw new Error(`Cannot remove at numeric index ${key} on non-list`)\n }\n } else {\n throw new Error(`Invalid key type: ${typeof key}`)\n }\n}\n\n/**\n * Handle 'replace' operation using existing DraftNode methods\n */\nfunction handleReplace<T extends DocShape>(\n draft: Draft<T>,\n operation: JsonPatchReplaceOperation,\n): void {\n const path = normalizePath(operation.path)\n const { parent, key } = navigateToPath(draft, path)\n\n if (typeof key === \"string\") {\n // Map-like operations - use set() method or natural assignment\n if (parent.set && typeof parent.set === \"function\") {\n parent.set(key, operation.value)\n } else {\n parent[key] = operation.value\n }\n } else if (typeof key === \"number\") {\n // List operations - delete then insert (follows existing patterns)\n if (\n parent.delete &&\n parent.insert &&\n typeof parent.delete === \"function\" &&\n typeof parent.insert === \"function\"\n ) {\n parent.delete(key, 1)\n parent.insert(key, operation.value)\n } else {\n throw new Error(`Cannot replace at numeric index ${key} on non-list`)\n }\n } else {\n throw new Error(`Invalid key type: ${typeof key}`)\n }\n}\n\n/**\n * Handle 'move' operation using existing DraftNode methods\n */\nfunction handleMove<T extends DocShape>(\n draft: Draft<T>,\n operation: JsonPatchMoveOperation,\n): void {\n const fromPath = normalizePath(operation.from)\n const toPath = normalizePath(operation.path)\n\n // For list moves within the same parent, we need special handling\n if (\n fromPath.length === toPath.length &&\n fromPath.slice(0, -1).every((segment, i) => segment === toPath[i])\n ) {\n // Same parent container - use list move operation if available\n const fromIndex = fromPath[fromPath.length - 1]\n const toIndex = toPath[toPath.length - 1]\n\n if (typeof fromIndex === \"number\" && typeof toIndex === \"number\") {\n const { parent } = navigateToPath(draft, fromPath.slice(0, -1))\n\n // Check if the parent has a move method (like LoroMovableList)\n if (parent.move && typeof parent.move === \"function\") {\n parent.move(fromIndex, toIndex)\n return\n }\n\n // Otherwise, get value, remove, then add at target index\n const value = getValueAtPath(draft, fromPath)\n handleRemove(draft, { op: \"remove\", path: operation.from })\n\n // For JSON Patch move semantics, the target index refers to the position\n // in the final array, not the intermediate array after removal.\n // No index adjustment needed - use the original target index.\n handleAdd(draft, { op: \"add\", path: operation.path, value })\n return\n }\n }\n\n // Different parents or non-numeric indices - standard move\n const value = getValueAtPath(draft, fromPath)\n handleRemove(draft, { op: \"remove\", path: operation.from })\n handleAdd(draft, { op: \"add\", path: operation.path, value })\n}\n\n/**\n * Handle 'copy' operation using existing DraftNode methods\n */\nfunction handleCopy<T extends DocShape>(\n draft: Draft<T>,\n operation: JsonPatchCopyOperation,\n): void {\n const fromPath = normalizePath(operation.from)\n\n // Get the value to copy\n const value = getValueAtPath(draft, fromPath)\n\n // Add to destination (no removal)\n handleAdd(draft, { op: \"add\", path: operation.path, value })\n}\n\n/**\n * Handle 'test' operation using existing DraftNode value access\n */\nfunction handleTest<T extends DocShape>(\n draft: Draft<T>,\n operation: JsonPatchTestOperation,\n): boolean {\n const path = normalizePath(operation.path)\n const actualValue = getValueAtPath(draft, path)\n\n // Deep equality check for test operation\n return JSON.stringify(actualValue) === JSON.stringify(operation.value)\n}\n\n// =============================================================================\n// MAIN APPLICATOR - Simple orchestration following existing patterns\n// =============================================================================\n\n/**\n * Main JSON Patch applicator - follows existing change() patterns\n */\nexport class JsonPatchApplicator<T extends DocShape> {\n constructor(private rootDraft: Draft<T>) {}\n\n /**\n * Apply a single JSON Patch operation\n */\n applyOperation(operation: JsonPatchOperation): void {\n switch (operation.op) {\n case \"add\":\n handleAdd(this.rootDraft, operation)\n break\n case \"remove\":\n handleRemove(this.rootDraft, operation)\n break\n case \"replace\":\n handleReplace(this.rootDraft, operation)\n break\n case \"move\":\n handleMove(this.rootDraft, operation)\n break\n case \"copy\":\n handleCopy(this.rootDraft, operation)\n break\n case \"test\":\n if (!handleTest(this.rootDraft, operation)) {\n throw new Error(`JSON Patch test failed at path: ${operation.path}`)\n }\n break\n default:\n // TypeScript will catch this at compile time with proper discriminated union\n throw new Error(\n `Unsupported JSON Patch operation: ${(operation as any).op}`,\n )\n }\n }\n\n /**\n * Apply multiple JSON Patch operations in sequence\n */\n applyPatch(patch: JsonPatch): void {\n for (const operation of patch) {\n this.applyOperation(operation)\n }\n }\n}\n","import type {\n Container,\n LoroCounter,\n LoroList,\n LoroMap,\n LoroMovableList,\n LoroText,\n LoroTree,\n LoroTreeNode,\n Value,\n} from \"loro-crdt\"\nimport type {\n ContainerOrValueShape,\n ContainerShape,\n CounterContainerShape,\n ListContainerShape,\n MovableListContainerShape,\n RecordContainerShape,\n StructContainerShape,\n TextContainerShape,\n TreeContainerShape,\n ValueShape,\n} from \"../shape.js\"\n\nexport { isContainer, isContainerId } from \"loro-crdt\"\n\n/**\n * Type guard to check if a container is a LoroCounter\n */\nexport function isLoroCounter(container: Container): container is LoroCounter {\n return container.kind() === \"Counter\"\n}\n\n/**\n * Type guard to check if a container is a LoroList\n */\nexport function isLoroList(container: Container): container is LoroList {\n return container.kind() === \"List\"\n}\n\n/**\n * Type guard to check if a container is a LoroMap\n */\nexport function isLoroMap(container: Container): container is LoroMap {\n return container.kind() === \"Map\"\n}\n\n/**\n * Type guard to check if a container is a LoroMovableList\n */\nexport function isLoroMovableList(\n container: Container,\n): container is LoroMovableList {\n return container.kind() === \"MovableList\"\n}\n\n/**\n * Type guard to check if a container is a LoroText\n */\nexport function isLoroText(container: Container): container is LoroText {\n return container.kind() === \"Text\"\n}\n\n/**\n * Type guard to check if a container is a LoroTree\n */\nexport function isLoroTree(container: Container): container is LoroTree {\n return container.kind() === \"Tree\"\n}\n\n/**\n * Type guard to check if an object is a LoroTreeNode\n * Note: LoroTreeNode is not a Container, so we check for its specific properties\n */\nexport function isLoroTreeNode(obj: any): obj is LoroTreeNode {\n return (\n obj &&\n typeof obj === \"object\" &&\n typeof obj.id === \"string\" &&\n typeof obj.data === \"object\" &&\n typeof obj.parent === \"function\" &&\n typeof obj.children === \"function\" &&\n typeof obj.createNode === \"function\"\n )\n}\n\n/**\n * Type guard to ensure cached container matches expected type using kind() method\n */\nexport function assertContainerType<T extends Container>(\n cached: Container,\n expected: T,\n context: string = \"container operation\",\n): asserts cached is T {\n if (cached.kind() !== expected.kind()) {\n throw new Error(\n `Type safety violation in ${context}: ` +\n `cached container kind '${cached.kind()}' does not match ` +\n `expected kind '${expected.kind()}'`,\n )\n }\n\n // Additional safety check: ensure IDs match\n if (cached.id !== expected.id) {\n throw new Error(\n `Container ID mismatch in ${context}: ` +\n `cached ID '${cached.id}' does not match expected ID '${expected.id}'`,\n )\n }\n}\n\n/**\n * Type guard to check if a schema is for TextDraftNode\n */\nexport function isTextShape(\n schema: ContainerOrValueShape,\n): schema is TextContainerShape {\n return schema && typeof schema === \"object\" && schema._type === \"text\"\n}\n\n/**\n * Type guard to check if a schema is for CounterDraftNode\n */\nexport function isCounterShape(\n schema: ContainerOrValueShape,\n): schema is CounterContainerShape {\n return schema && typeof schema === \"object\" && schema._type === \"counter\"\n}\n\n/**\n * Type guard to check if a schema is for ListDraftNode\n */\nexport function isListShape(\n schema: ContainerOrValueShape,\n): schema is ListContainerShape {\n return schema && typeof schema === \"object\" && schema._type === \"list\"\n}\n\n/**\n * Type guard to check if a schema is for MovableListDraftNode\n */\nexport function isMovableListShape(\n schema: ContainerOrValueShape,\n): schema is MovableListContainerShape {\n return schema && typeof schema === \"object\" && schema._type === \"movableList\"\n}\n\n/**\n * Type guard to check if a schema is for StructDraftNode\n */\nexport function isStructShape(\n schema: ContainerOrValueShape,\n): schema is StructContainerShape {\n return schema && typeof schema === \"object\" && schema._type === \"struct\"\n}\n\n/**\n * @deprecated Use isStructShape instead. isMapShape is an alias for backward compatibility.\n */\nexport const isMapShape = isStructShape\n\n/**\n * Type guard to check if a schema is for RecordDraftNode\n */\nexport function isRecordShape(\n schema: ContainerOrValueShape,\n): schema is RecordContainerShape {\n return schema && typeof schema === \"object\" && schema._type === \"record\"\n}\n\n/**\n * Type guard to check if a schema is for TreeDraftNode\n */\nexport function isTreeShape(\n schema: ContainerOrValueShape,\n): schema is TreeContainerShape {\n return schema && typeof schema === \"object\" && schema._type === \"tree\"\n}\n\nexport function isContainerShape(\n schema: ContainerOrValueShape,\n): schema is ContainerShape {\n return schema._type && schema._type !== \"value\"\n}\n\n/**\n * Type guard to check if a schema is any of the Value shapes\n */\nexport function isValueShape(\n schema: ContainerOrValueShape,\n): schema is ValueShape {\n return (\n schema._type === \"value\" &&\n [\n \"string\",\n \"number\",\n \"boolean\",\n \"null\",\n \"undefined\",\n \"uint8array\",\n \"struct\",\n \"record\",\n \"array\",\n \"union\",\n \"discriminatedUnion\",\n \"any\",\n ].includes(schema.valueType)\n )\n}\n\nexport function isObjectValue(value: Value): value is { [key: string]: Value } {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n !(value instanceof Uint8Array)\n )\n}\n","import type { TreeID, Value } from \"loro-crdt\"\nimport { deriveShapePlaceholder } from \"./derive-placeholder.js\"\nimport type {\n ContainerShape,\n DiscriminatedUnionValueShape,\n DocShape,\n StructContainerShape,\n TreeContainerShape,\n TreeNodeJSON,\n ValueShape,\n} from \"./shape.js\"\nimport { isObjectValue } from \"./utils/type-guards.js\"\n\n/**\n * Overlays CRDT state with placeholder defaults\n */\nexport function overlayPlaceholder<Shape extends DocShape>(\n shape: Shape,\n crdtValue: { [key: string]: Value },\n placeholderValue: { [key: string]: Value },\n): { [key: string]: Value } {\n if (typeof crdtValue !== \"object\") {\n throw new Error(\"crdt object is required\")\n }\n\n if (typeof placeholderValue !== \"object\") {\n throw new Error(\"placeholder object is required\")\n }\n\n const result = { ...placeholderValue }\n\n for (const [key, propShape] of Object.entries(shape.shapes)) {\n const propCrdtValue = crdtValue[key]\n\n const propPlaceholderValue =\n placeholderValue[key as keyof typeof placeholderValue]\n\n result[key as keyof typeof result] = mergeValue(\n propShape,\n propCrdtValue,\n propPlaceholderValue,\n )\n }\n\n return result\n}\n\n/**\n * Merges individual CRDT values with placeholder defaults\n */\nexport function mergeValue<Shape extends ContainerShape | ValueShape>(\n shape: Shape,\n crdtValue: Value,\n placeholderValue: Value,\n): Value {\n // For \"any\" shapes, just return the CRDT value as-is (no placeholder merging)\n if (shape._type === \"any\") {\n return crdtValue\n }\n\n // For \"any\" value shapes, just return the CRDT value as-is\n if (shape._type === \"value\" && (shape as any).valueType === \"any\") {\n return crdtValue\n }\n\n if (crdtValue === undefined && placeholderValue === undefined) {\n throw new Error(\"either crdt or placeholder value must be defined\")\n }\n\n switch (shape._type) {\n case \"text\":\n return crdtValue !== undefined ? crdtValue : (placeholderValue ?? \"\")\n case \"counter\":\n return crdtValue !== undefined ? crdtValue : (placeholderValue ?? 0)\n case \"list\":\n case \"movableList\": {\n if (crdtValue === undefined) {\n return placeholderValue ?? []\n }\n\n const crdtArray = crdtValue as Value[]\n const itemShape = shape.shape\n const itemPlaceholder = deriveShapePlaceholder(itemShape)\n\n return crdtArray.map(item =>\n mergeValue(itemShape, item, itemPlaceholder as Value),\n )\n }\n case \"struct\": {\n if (!isObjectValue(crdtValue) && crdtValue !== undefined) {\n throw new Error(\"struct crdt must be object\")\n }\n\n const crdtStructValue = crdtValue ?? {}\n\n if (!isObjectValue(placeholderValue) && placeholderValue !== undefined) {\n throw new Error(\"struct placeholder must be object\")\n }\n\n const placeholderStructValue = placeholderValue ?? {}\n\n const result = { ...placeholderStructValue }\n for (const [key, nestedShape] of Object.entries(shape.shapes)) {\n const nestedCrdtValue = crdtStructValue[key]\n const nestedPlaceholderValue = placeholderStructValue[key]\n\n result[key as keyof typeof result] = mergeValue(\n nestedShape,\n nestedCrdtValue,\n nestedPlaceholderValue,\n )\n }\n\n return result\n }\n case \"tree\": {\n if (crdtValue === undefined) {\n return placeholderValue ?? []\n }\n // Transform Loro's native tree format to our typed format\n const treeShape = shape as TreeContainerShape\n return transformTreeNodes(crdtValue as any[], treeShape.shape) as any\n }\n case \"record\": {\n if (!isObjectValue(crdtValue) && crdtValue !== undefined) {\n throw new Error(\"record crdt must be object\")\n }\n\n const crdtRecordValue = (crdtValue as Record<string, Value>) ?? {}\n const result: Record<string, Value> = {}\n\n // For records, we iterate over the keys present in the CRDT value\n // and apply the nested shape's placeholder logic to each value\n for (const key of Object.keys(crdtRecordValue)) {\n const nestedCrdtValue = crdtRecordValue[key]\n // For records, the placeholder is always {}, so we need to derive\n // the placeholder for the nested shape on the fly\n const nestedPlaceholderValue = deriveShapePlaceholder(shape.shape)\n\n result[key] = mergeValue(\n shape.shape,\n nestedCrdtValue,\n nestedPlaceholderValue as Value,\n )\n }\n\n return result\n }\n default:\n if (shape._type === \"value\" && shape.valueType === \"struct\") {\n const crdtObj = (crdtValue as any) ?? {}\n const placeholderObj = (placeholderValue as any) ?? {}\n const result = { ...placeholderObj }\n\n if (typeof crdtObj !== \"object\" || crdtObj === null) {\n return crdtValue !== undefined ? crdtValue : placeholderValue\n }\n\n for (const [key, propShape] of Object.entries(shape.shape)) {\n const propCrdt = crdtObj[key]\n const propPlaceholder = placeholderObj[key]\n result[key] = mergeValue(propShape, propCrdt, propPlaceholder)\n }\n return result\n }\n\n // Handle discriminated unions\n if (shape._type === \"value\" && shape.valueType === \"discriminatedUnion\") {\n return mergeDiscriminatedUnion(\n shape as DiscriminatedUnionValueShape,\n crdtValue,\n placeholderValue,\n )\n }\n\n return crdtValue !== undefined ? crdtValue : placeholderValue\n }\n}\n\n/**\n * Merges a discriminated union value by determining the variant from the discriminant key.\n * Uses the placeholderValue's discriminant to determine the default variant when the discriminant is missing.\n */\nfunction mergeDiscriminatedUnion(\n shape: DiscriminatedUnionValueShape,\n crdtValue: Value,\n placeholderValue: Value,\n): Value {\n const crdtObj = (crdtValue as Record<string, Value>) ?? {}\n const placeholderObj = (placeholderValue as Record<string, Value>) ?? {}\n\n // Get the discriminant value from CRDT, falling back to placeholder\n const discriminantValue =\n crdtObj[shape.discriminantKey] ?? placeholderObj[shape.discriminantKey]\n\n if (typeof discriminantValue !== \"string\") {\n // If no valid discriminant, return the placeholder\n return placeholderValue\n }\n\n // Find the variant shape for this discriminant value\n const variantShape = shape.variants[discriminantValue]\n\n if (!variantShape) {\n // Unknown variant - return CRDT value or placeholder\n return crdtValue !== undefined ? crdtValue : placeholderValue\n }\n\n // Merge using the variant's object shape\n // If the placeholder's discriminant doesn't match the current discriminant,\n // we shouldn't use the placeholder for merging as it belongs to a different variant.\n const placeholderDiscriminant = placeholderObj[shape.discriminantKey]\n const effectivePlaceholderValue =\n placeholderDiscriminant === discriminantValue ? placeholderValue : undefined\n\n return mergeValue(variantShape, crdtValue, effectivePlaceholderValue as Value)\n}\n\n/**\n * Loro's native tree node format from toJSON()\n */\ninterface LoroTreeNodeJSON {\n id: string\n parent: string | null\n index: number\n fractional_index: string\n meta: Record<string, Value>\n children: LoroTreeNodeJSON[]\n}\n\n/**\n * Transforms Loro's native tree format to our typed TreeNodeJSON format.\n * - Renames `meta` to `data`\n * - Renames `fractional_index` to `fractionalIndex`\n * - Applies placeholder merging to node data\n */\nfunction transformTreeNodes<DataShape extends StructContainerShape>(\n nodes: LoroTreeNodeJSON[],\n dataShape: DataShape,\n): TreeNodeJSON<DataShape>[] {\n const dataPlaceholder = deriveShapePlaceholder(dataShape) as Value\n\n return nodes.map(node => transformTreeNode(node, dataShape, dataPlaceholder))\n}\n\n/**\n * Transforms a single tree node and its children recursively.\n */\nfunction transformTreeNode<DataShape extends StructContainerShape>(\n node: LoroTreeNodeJSON,\n dataShape: DataShape,\n dataPlaceholder: Value,\n): TreeNodeJSON<DataShape> {\n // Merge the node's meta (data) with the placeholder\n const mergedData = mergeValue(dataShape, node.meta, dataPlaceholder)\n\n return {\n id: node.id as TreeID,\n parent: node.parent as TreeID | null,\n index: node.index,\n fractionalIndex: node.fractional_index,\n data: mergedData as DataShape[\"_plain\"],\n children: node.children.map(child =>\n transformTreeNode(child, dataShape, dataPlaceholder),\n ),\n }\n}\n","import type {\n ContainerID,\n Diff,\n LoroDoc,\n LoroEventBatch,\n Subscription,\n} from \"loro-crdt\"\nimport { LORO_SYMBOL, type LoroRefBase } from \"../loro.js\"\nimport type { ContainerShape, DocShape, ShapeToContainer } from \"../shape.js\"\nimport type { Infer } from \"../types.js\"\n\n/**\n * Symbol for internal methods that should not be enumerable or accessible to users.\n * Used to hide implementation details like absorbPlainValues(), getTypedRefParams(), etc.\n *\n * This achieves Success Criteria #7 from loro-api-refactor.md:\n * \"Internal methods hidden - Via Symbol, not enumerable\"\n */\nexport const INTERNAL_SYMBOL = Symbol.for(\"loro-extended:internal\")\n\n// ============================================================================\n// Minimal Interface for absorbPlainValues contract\n// ============================================================================\n\n/**\n * Minimal interface for refs that only need absorbPlainValues.\n * Used by TreeNodeRef which doesn't extend TypedRef.\n */\nexport interface RefInternalsBase {\n /** Absorb mutated plain values back into Loro containers */\n absorbPlainValues(): void\n /** Force materialization of the container and its nested containers */\n materialize(): void\n}\n\n// ============================================================================\n// TypedRefParams and TypedRef Base Class\n// ============================================================================\n\nexport type DiffOverlay = ReadonlyMap<ContainerID, Diff>\n\nexport type TypedRefParams<Shape extends DocShape | ContainerShape> = {\n shape: Shape\n placeholder?: Infer<Shape>\n getContainer: () => ShapeToContainer<Shape>\n autoCommit?: boolean // Auto-commit after mutations\n batchedMutation?: boolean // True when inside change() block - enables value shape caching for find-and-mutate patterns\n getDoc: () => LoroDoc // Needed for auto-commit\n overlay?: DiffOverlay // Optional reverse diff overlay for \"before\" reads\n}\n\n// ============================================================================\n// BaseRefInternals - Abstract base class for all internal implementations\n// ============================================================================\n\n/**\n * Abstract base class for all ref internal implementations.\n * Contains shared logic that was previously in TypedRef.createBaseInternals().\n *\n * Subclasses implement specific behavior for each ref type.\n */\nexport abstract class BaseRefInternals<Shape extends DocShape | ContainerShape>\n implements RefInternalsBase\n{\n protected cachedContainer: ShapeToContainer<Shape> | undefined\n protected loroNamespace: LoroRefBase | undefined\n private _suppressAutoCommit = false\n\n constructor(protected readonly params: TypedRefParams<Shape>) {}\n\n /** Get the underlying Loro container (cached) */\n getContainer(): ShapeToContainer<Shape> {\n if (!this.cachedContainer) {\n this.cachedContainer = this.params.getContainer()\n }\n return this.cachedContainer\n }\n\n /** Commit changes if autoCommit is enabled and not suppressed */\n commitIfAuto(): void {\n if (this.params.autoCommit && !this._suppressAutoCommit) {\n this.params.getDoc().commit()\n }\n }\n\n /**\n * Temporarily suppress auto-commit during batch operations.\n * Used by assignPlainValueToTypedRef() to batch multiple property assignments.\n */\n setSuppressAutoCommit(suppress: boolean): void {\n this._suppressAutoCommit = suppress\n }\n\n /** Check if auto-commit is currently suppressed */\n isSuppressAutoCommit(): boolean {\n return this._suppressAutoCommit\n }\n\n /** Get the shape for this ref */\n getShape(): Shape {\n return this.params.shape\n }\n\n /** Get the placeholder value */\n getPlaceholder(): Infer<Shape> | undefined {\n return this.params.placeholder\n }\n\n /** Check if autoCommit is enabled */\n getAutoCommit(): boolean {\n return !!this.params.autoCommit\n }\n\n /** Check if in batched mutation mode */\n getBatchedMutation(): boolean {\n return !!this.params.batchedMutation\n }\n\n /** Get the LoroDoc */\n getDoc(): LoroDoc {\n return this.params.getDoc()\n }\n\n /** Get the diff overlay map (if provided) */\n getOverlay(): DiffOverlay | undefined {\n return this.params.overlay\n }\n\n /**\n * Get the TypedRefParams needed to recreate this ref.\n * Used by change() to create draft refs with modified params.\n *\n * Returns a new params object with the same shape, placeholder, getContainer, and getDoc,\n * but allows overriding autoCommit and batchedMutation for draft creation.\n */\n getTypedRefParams(): TypedRefParams<Shape> {\n return {\n shape: this.params.shape,\n placeholder: this.params.placeholder,\n getContainer: this.params.getContainer,\n autoCommit: this.params.autoCommit,\n batchedMutation: this.params.batchedMutation,\n getDoc: this.params.getDoc,\n overlay: this.params.overlay,\n }\n }\n\n /** Get the loro namespace (cached) */\n getLoroNamespace(): LoroRefBase {\n if (!this.loroNamespace) {\n this.loroNamespace = this.createLoroNamespace()\n }\n return this.loroNamespace\n }\n\n /** Absorb mutated plain values back into Loro containers - subclasses override */\n abstract absorbPlainValues(): void\n\n /** Force materialization of the container and its nested containers */\n materialize(): void {\n this.getContainer()\n }\n\n /** Create the loro() namespace object - subclasses override for specific types */\n protected createLoroNamespace(): LoroRefBase {\n const self = this\n return {\n get doc(): LoroDoc {\n return self.params.getDoc()\n },\n get container(): unknown {\n return self.getContainer()\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n return (self.getContainer() as any).subscribe(callback)\n },\n }\n }\n}\n\n/**\n * Base class for all typed refs.\n *\n * All internal methods are accessed via [INTERNAL_SYMBOL] to prevent\n * namespace collisions with user data properties.\n *\n * Uses the Facade + Implementation pattern:\n * - TypedRef is the thin public facade\n * - BaseRefInternals subclasses contain all implementation logic\n */\nexport abstract class TypedRef<Shape extends DocShape | ContainerShape> {\n /**\n * Internal implementation accessed via Symbol.\n * Subclasses must set this to their specific internals class instance.\n */\n abstract [INTERNAL_SYMBOL]: BaseRefInternals<Shape>\n\n /**\n * Serializes the ref to a plain JSON-compatible value.\n * Returns the plain type inferred from the shape.\n */\n abstract toJSON(): Infer<Shape>\n\n /**\n * Access the loro() namespace via the well-known symbol.\n * This is used by the loro() function to access CRDT internals.\n */\n get [LORO_SYMBOL](): LoroRefBase {\n return this[INTERNAL_SYMBOL].getLoroNamespace()\n }\n}\n","import {\n LoroCounter,\n LoroList,\n LoroMap,\n LoroMovableList,\n LoroText,\n LoroTree,\n type Value,\n} from \"loro-crdt\"\nimport type {\n ContainerShape,\n CounterContainerShape,\n ListContainerShape,\n MovableListContainerShape,\n RecordContainerShape,\n StructContainerShape,\n TextContainerShape,\n TreeContainerShape,\n} from \"../shape.js\"\nimport { INTERNAL_SYMBOL, type TypedRef, type TypedRefParams } from \"./base.js\"\nimport { CounterRef } from \"./counter-ref.js\"\nimport { ListRef } from \"./list-ref.js\"\nimport { MovableListRef } from \"./movable-list-ref.js\"\nimport {\n listProxyHandler,\n movableListProxyHandler,\n recordProxyHandler,\n} from \"./proxy-handlers.js\"\nimport { RecordRef } from \"./record-ref.js\"\nimport { createStructRef } from \"./struct-ref.js\"\nimport { TextRef } from \"./text-ref.js\"\nimport { TreeRef } from \"./tree-ref.js\"\n\n/**\n * Mapping from container shape types to their Loro constructor classes.\n * Used when creating new containers via getOrCreateContainer().\n *\n * Note: \"any\" is not included because AnyContainerShape is an escape hatch\n * that doesn't create typed refs - it returns raw Loro containers.\n */\nexport const containerConstructor = {\n counter: LoroCounter,\n list: LoroList,\n movableList: LoroMovableList,\n record: LoroMap, // Records use LoroMap as their underlying container\n struct: LoroMap, // Structs use LoroMap as their underlying container\n text: LoroText,\n tree: LoroTree,\n} as const\n\n/**\n * Type guard to check if a container shape type has a constructor.\n * Returns false for \"any\" which is an escape hatch.\n */\nexport function hasContainerConstructor(\n type: string,\n): type is keyof typeof containerConstructor {\n return type in containerConstructor\n}\n\n/**\n * Unwraps a TypedRef to its primitive value for readonly access.\n * Counter refs return their numeric value, Text refs return their string.\n * Other container types are returned as-is.\n */\nexport function unwrapReadonlyPrimitive(\n ref: TypedRef<any>,\n shape: ContainerShape,\n): any {\n if (shape._type === \"counter\") {\n return (ref as any).value\n }\n if (shape._type === \"text\") {\n return (ref as any).toString()\n }\n return ref\n}\n\n/**\n * Type guard to check if a value has internal methods via INTERNAL_SYMBOL.\n */\nfunction hasInternalSymbol(\n value: unknown,\n): value is { [INTERNAL_SYMBOL]: { absorbPlainValues(): void } } {\n return value !== null && typeof value === \"object\" && INTERNAL_SYMBOL in value\n}\n\n/**\n * Absorbs cached plain values back into a LoroMap container.\n * For TypedRef entries (or any object with INTERNAL_SYMBOL), recursively calls absorbPlainValues().\n * For plain Value entries, sets them directly on the container.\n */\nexport function absorbCachedPlainValues(\n cache: Map<string, TypedRef<ContainerShape> | Value>,\n getContainer: () => LoroMap,\n): void {\n let container: LoroMap | undefined\n\n for (const [key, ref] of cache.entries()) {\n if (hasInternalSymbol(ref)) {\n // Contains a TypedRef or TreeRef, not a plain Value: keep recursing\n ref[INTERNAL_SYMBOL].absorbPlainValues()\n } else {\n // Plain value!\n if (!container) container = getContainer()\n container.set(key, ref)\n }\n }\n}\n\n/**\n * Serializes a TypedRef to JSON by iterating over its keys.\n * For nested TypedRefs with toJSON(), calls their toJSON method.\n * For plain values, includes them directly.\n */\nexport function serializeRefToJSON(\n ref: Record<string, any>,\n keys: Iterable<string>,\n): Record<string, any> {\n const result: Record<string, any> = {}\n for (const key of keys) {\n const value = ref[key]\n if (value && typeof value === \"object\" && \"toJSON\" in value) {\n result[key] = value.toJSON()\n } else {\n result[key] = value\n }\n }\n return result\n}\n\n// Generic catch-all overload\nexport function createContainerTypedRef<T extends ContainerShape>(\n params: TypedRefParams<T>,\n): TypedRef<T>\n\n// Implementation\nexport function createContainerTypedRef(\n params: TypedRefParams<ContainerShape>,\n): TypedRef<ContainerShape> | TreeRef<StructContainerShape> {\n switch (params.shape._type) {\n case \"counter\":\n return new CounterRef(params as TypedRefParams<CounterContainerShape>)\n case \"list\":\n return new Proxy(\n new ListRef(params as TypedRefParams<ListContainerShape>),\n listProxyHandler,\n )\n case \"struct\":\n return createStructRef(\n params as TypedRefParams<StructContainerShape>,\n ) as unknown as TypedRef<ContainerShape>\n case \"movableList\":\n return new Proxy(\n new MovableListRef(params as TypedRefParams<MovableListContainerShape>),\n movableListProxyHandler,\n )\n case \"record\":\n return new Proxy(\n new RecordRef(params as TypedRefParams<RecordContainerShape>),\n recordProxyHandler,\n )\n case \"text\":\n return new TextRef(params as TypedRefParams<TextContainerShape>)\n case \"tree\": {\n const treeShape = params.shape as TreeContainerShape\n return new TreeRef({\n shape: treeShape,\n placeholder: params.placeholder as never[],\n getContainer: params.getContainer as () => LoroTree,\n autoCommit: params.autoCommit,\n getDoc: params.getDoc,\n })\n }\n default:\n throw new Error(\n `Unknown container type: ${(params.shape as ContainerShape)._type}`,\n )\n }\n}\n\n/**\n * Assigns a plain JavaScript value to a TypedRef.\n *\n * For struct/record types, this batches all property assignments and only\n * commits once at the end to avoid multiple subscription notifications.\n *\n * @param ref - The TypedRef to assign to\n * @param value - The plain value to assign\n * @param skipCommit - If true, skip the final commit (caller will handle it)\n * @returns true if assignment was successful, false otherwise\n */\nexport function assignPlainValueToTypedRef(\n ref: TypedRef<any>,\n value: any,\n skipCommit = false,\n): boolean {\n // Access internals via INTERNAL_SYMBOL\n const internals = ref[INTERNAL_SYMBOL]\n\n // Force materialization of the container\n if (internals) {\n internals.materialize()\n }\n\n const shape = internals?.getShape?.() ?? (ref as any).shape\n const shapeType = shape?._type\n\n if (shapeType === \"struct\" || shapeType === \"record\") {\n // Suppress auto-commit during batch assignment to avoid multiple notifications\n const wasSuppressed = internals?.isSuppressAutoCommit?.() ?? false\n if (internals && !wasSuppressed) {\n internals.setSuppressAutoCommit(true)\n }\n\n try {\n for (const k in value) {\n ;(ref as any)[k] = value[k]\n }\n } finally {\n // Restore auto-commit state\n if (internals && !wasSuppressed) {\n internals.setSuppressAutoCommit(false)\n }\n }\n\n // Commit once after all properties are assigned (unless skipCommit is true)\n if (!skipCommit && internals?.getAutoCommit?.()) {\n internals.getDoc().commit()\n }\n\n return true\n }\n\n if (shapeType === \"list\" || shapeType === \"movableList\") {\n if (Array.isArray(value)) {\n const listRef = ref as any\n\n // Suppress auto-commit during batch operations\n const wasSuppressed = internals?.isSuppressAutoCommit?.() ?? false\n if (internals && !wasSuppressed) {\n internals.setSuppressAutoCommit(true)\n }\n\n try {\n if (listRef.length > 0) {\n listRef.delete(0, listRef.length)\n }\n for (const item of value) {\n listRef.push(item)\n }\n } finally {\n if (internals && !wasSuppressed) {\n internals.setSuppressAutoCommit(false)\n }\n }\n\n // Commit once after all items are added (unless skipCommit is true)\n if (!skipCommit && internals?.getAutoCommit?.()) {\n internals.getDoc().commit()\n }\n\n return true\n }\n }\n\n if (shapeType === \"text\") {\n if (typeof value === \"string\") {\n ;(ref as any).update(value)\n return true\n }\n return false\n }\n\n if (shapeType === \"counter\") {\n if (typeof value === \"number\") {\n const currentValue = (ref as any).value\n const diff = value - currentValue\n if (diff > 0) {\n ;(ref as any).increment(diff)\n } else if (diff < 0) {\n ;(ref as any).decrement(-diff)\n }\n return true\n }\n return false\n }\n\n return false\n}\n","import type {\n CounterDiff,\n LoroCounter,\n LoroDoc,\n LoroEventBatch,\n Subscription,\n} from \"loro-crdt\"\nimport type { LoroCounterRef } from \"../loro.js\"\nimport type { CounterContainerShape } from \"../shape.js\"\nimport { BaseRefInternals } from \"./base.js\"\n\n/**\n * Internal implementation for CounterRef.\n * Contains all logic, state, and implementation details.\n */\nexport class CounterRefInternals extends BaseRefInternals<CounterContainerShape> {\n private materialized = false\n\n /** Increment the counter value */\n increment(value: number = 1): void {\n this.materialized = true\n ;(this.getContainer() as LoroCounter).increment(value)\n this.commitIfAuto()\n }\n\n /** Decrement the counter value */\n decrement(value: number = 1): void {\n this.materialized = true\n ;(this.getContainer() as LoroCounter).decrement(value)\n this.commitIfAuto()\n }\n\n /** Get the current counter value */\n getValue(): number {\n const container = this.getContainer() as LoroCounter\n const containerValue = container.value\n const overlay = this.getOverlay()\n if (overlay) {\n const diff = overlay.get((container as any).id)\n if (diff && diff.type === \"counter\") {\n const counterDiff = diff as CounterDiff\n return containerValue + counterDiff.increment\n }\n }\n if (containerValue !== 0 || this.materialized) {\n return containerValue\n }\n // Return placeholder if available and container is at default state\n const placeholder = this.getPlaceholder()\n if (placeholder !== undefined) {\n return placeholder as number\n }\n return containerValue\n }\n\n /** No plain values in counter */\n absorbPlainValues(): void {\n // no plain values contained within\n }\n\n /** Create the loro namespace for counter */\n protected override createLoroNamespace(): LoroCounterRef {\n const self = this\n return {\n get doc(): LoroDoc {\n return self.getDoc()\n },\n get container(): LoroCounter {\n return self.getContainer() as LoroCounter\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n return (self.getContainer() as LoroCounter).subscribe(callback)\n },\n }\n }\n}\n","import type { CounterContainerShape } from \"../shape.js\"\nimport { INTERNAL_SYMBOL, TypedRef, type TypedRefParams } from \"./base.js\"\nimport { CounterRefInternals } from \"./counter-ref-internals.js\"\n\n/**\n * Counter typed ref - thin facade that delegates to CounterRefInternals.\n */\nexport class CounterRef extends TypedRef<CounterContainerShape> {\n [INTERNAL_SYMBOL]: CounterRefInternals\n\n constructor(params: TypedRefParams<CounterContainerShape>) {\n super()\n this[INTERNAL_SYMBOL] = new CounterRefInternals(params)\n }\n\n /** Increment the counter by the given value (default 1) */\n increment(value?: number): void {\n this[INTERNAL_SYMBOL].increment(value)\n }\n\n /** Decrement the counter by the given value (default 1) */\n decrement(value?: number): void {\n this[INTERNAL_SYMBOL].decrement(value)\n }\n\n /** Get the current counter value */\n get value(): number {\n return this[INTERNAL_SYMBOL].getValue()\n }\n\n valueOf(): number {\n return this.value\n }\n\n toJSON(): number {\n return this.value\n }\n\n [Symbol.toPrimitive](hint: string): number | string {\n if (hint === \"string\") {\n return String(this.value)\n }\n return this.value\n }\n}\n","import {\n type Container,\n LoroCounter,\n LoroList,\n LoroMap,\n LoroMovableList,\n LoroText,\n type Value,\n} from \"loro-crdt\"\nimport type {\n ArrayValueShape,\n ContainerOrValueShape,\n ListContainerShape,\n MovableListContainerShape,\n RecordContainerShape,\n RecordValueShape,\n StructContainerShape,\n StructValueShape,\n} from \"./shape.js\"\nimport {\n isContainer,\n isContainerShape,\n isObjectValue,\n isValueShape,\n} from \"./utils/type-guards.js\"\n\n/**\n * Converts string input to LoroText container\n */\nfunction convertTextInput(value: string): LoroText {\n const text = new LoroText()\n\n text.insert(0, value)\n\n return text\n}\n\n/**\n * Converts number input to LoroCounter container\n */\nfunction convertCounterInput(value: number): LoroCounter {\n const counter = new LoroCounter()\n counter.increment(value)\n return counter\n}\n\n/**\n * Converts array input to LoroList container\n */\nfunction convertListInput(\n value: Value[],\n shape: ListContainerShape | ArrayValueShape,\n // parentPath: string[],\n): LoroList | Value[] {\n if (!isContainerShape(shape)) {\n return value\n }\n\n const list = new LoroList()\n\n for (const item of value) {\n const convertedItem = convertInputToRef(item, shape.shape)\n if (isContainer(convertedItem)) {\n list.pushContainer(convertedItem)\n } else {\n list.push(convertedItem)\n }\n }\n\n return list\n}\n\n/**\n * Converts array input to LoroMovableList container\n */\nfunction convertMovableListInput(\n value: Value[],\n shape: MovableListContainerShape | ArrayValueShape,\n // parentPath: string[],\n): LoroMovableList | Value[] {\n if (!isContainerShape(shape)) {\n return value\n }\n\n const list = new LoroMovableList()\n\n for (const item of value) {\n const convertedItem = convertInputToRef(item, shape.shape)\n if (isContainer(convertedItem)) {\n list.pushContainer(convertedItem)\n } else {\n list.push(convertedItem)\n }\n }\n\n return list\n}\n\n/**\n * Converts object input to LoroMap container (Struct)\n */\nfunction convertStructInput(\n value: { [key: string]: Value },\n shape: StructContainerShape | StructValueShape,\n): LoroMap | { [key: string]: Value } {\n if (!isContainerShape(shape)) {\n return value\n }\n\n const map = new LoroMap()\n\n // Iterate over schema keys to ensure all nested containers are materialized\n for (const k of Object.keys(shape.shapes)) {\n const nestedSchema = shape.shapes[k]\n const v = value[k]\n\n if (v !== undefined) {\n const convertedValue = convertInputToRef(v, nestedSchema)\n if (isContainer(convertedValue)) {\n map.setContainer(k, convertedValue)\n } else {\n map.set(k, convertedValue)\n }\n } else if (isContainerShape(nestedSchema)) {\n // If value is missing but it's a container shape, create an empty container\n // This ensures deterministic container IDs across peers\n let emptyValue: any\n if (nestedSchema._type === \"struct\" || nestedSchema._type === \"record\") {\n emptyValue = {}\n } else if (\n nestedSchema._type === \"list\" ||\n nestedSchema._type === \"movableList\"\n ) {\n emptyValue = []\n } else if (nestedSchema._type === \"text\") {\n emptyValue = \"\"\n } else if (nestedSchema._type === \"counter\") {\n emptyValue = 0\n }\n\n if (emptyValue !== undefined) {\n const convertedValue = convertInputToRef(emptyValue, nestedSchema)\n if (isContainer(convertedValue)) {\n map.setContainer(k, convertedValue)\n }\n }\n }\n }\n\n // Also handle keys present in value but not in schema (if any, though for structs this shouldn't happen ideally)\n // But for backward compatibility or loose typing, we might want to preserve them?\n // The original code did:\n // if (nestedSchema) { ... } else { map.set(k, value) }\n // So it allowed extra keys.\n for (const [k, v] of Object.entries(value)) {\n if (!shape.shapes[k]) {\n map.set(k, v)\n }\n }\n\n return map\n}\n\n/**\n * Converts object input to LoroMap container (Record)\n */\nfunction convertRecordInput(\n value: { [key: string]: Value },\n shape: RecordContainerShape | RecordValueShape,\n): LoroMap | { [key: string]: Value } {\n if (!isContainerShape(shape)) {\n return value\n }\n\n const map = new LoroMap()\n for (const [k, v] of Object.entries(value)) {\n const convertedValue = convertInputToRef(v, shape.shape)\n if (isContainer(convertedValue)) {\n map.setContainer(k, convertedValue)\n } else {\n map.set(k, convertedValue)\n }\n }\n\n return map\n}\n\n/**\n * Main conversion function that transforms input values to appropriate CRDT containers\n * based on schema definitions\n */\nexport function convertInputToRef<Shape extends ContainerOrValueShape>(\n value: Value,\n shape: Shape,\n): Container | Value {\n switch (shape._type) {\n case \"text\": {\n if (typeof value !== \"string\") {\n throw new Error(\"string expected\")\n }\n\n return convertTextInput(value)\n }\n case \"counter\": {\n if (typeof value !== \"number\") {\n throw new Error(\"number expected\")\n }\n\n return convertCounterInput(value)\n }\n case \"list\": {\n if (!Array.isArray(value)) {\n throw new Error(\"array expected\")\n }\n\n return convertListInput(value, shape)\n }\n case \"movableList\": {\n if (!Array.isArray(value)) {\n throw new Error(\"array expected\")\n }\n\n return convertMovableListInput(value, shape)\n }\n case \"struct\": {\n if (!isObjectValue(value)) {\n throw new Error(\"object expected\")\n }\n\n return convertStructInput(value, shape)\n }\n case \"record\": {\n if (!isObjectValue(value)) {\n throw new Error(\"object expected\")\n }\n\n return convertRecordInput(value, shape)\n }\n case \"value\": {\n if (!isValueShape(shape)) {\n throw new Error(\"value expected\")\n }\n\n return value\n }\n\n case \"tree\":\n throw new Error(\"tree type unimplemented\")\n\n default:\n throw new Error(`unexpected type: ${(shape as Shape)._type}`)\n }\n}\n","import type {\n Container,\n Delta,\n ListDiff,\n LoroDoc,\n LoroEventBatch,\n LoroList,\n LoroMovableList,\n Subscription,\n} from \"loro-crdt\"\nimport { convertInputToRef } from \"../conversion.js\"\nimport { deriveShapePlaceholder } from \"../derive-placeholder.js\"\nimport type { LoroListRef } from \"../loro.js\"\nimport { mergeValue } from \"../overlay.js\"\nimport type { ContainerOrValueShape, ContainerShape } from \"../shape.js\"\nimport {\n isContainer,\n isContainerShape,\n isValueShape,\n} from \"../utils/type-guards.js\"\nimport {\n BaseRefInternals,\n INTERNAL_SYMBOL,\n TypedRef,\n type TypedRefParams,\n} from \"./base.js\"\nimport { createContainerTypedRef } from \"./utils.js\"\n\n// ============================================================================\n// ListRefBaseInternals - Internal implementation class\n// ============================================================================\n\n/**\n * Internal implementation for ListRefBase.\n * Contains all logic, state, and implementation details for list operations.\n */\nexport class ListRefBaseInternals<\n NestedShape extends ContainerOrValueShape,\n Item = NestedShape[\"_plain\"],\n MutableItem = NestedShape[\"_mutable\"],\n> extends BaseRefInternals<any> {\n private itemCache = new Map<number, any>()\n private overlayListCache?: Item[]\n\n getOverlayList(): Item[] | undefined {\n const overlay = this.getOverlay()\n if (!overlay) {\n return undefined\n }\n\n const shape = this.getShape()\n if (!isValueShape(shape.shape)) {\n return undefined\n }\n\n if (!this.overlayListCache) {\n const container = this.getContainer() as LoroList | LoroMovableList\n const diff = overlay.get(container.id)\n if (!diff || diff.type !== \"list\") {\n return undefined\n }\n\n const afterValues: Item[] = []\n for (let i = 0; i < container.length; i++) {\n afterValues.push(container.get(i) as Item)\n }\n\n this.overlayListCache = applyListDelta(\n afterValues,\n (diff as ListDiff).diff as Delta<Item[]>[],\n )\n }\n\n return this.overlayListCache\n }\n\n /** Get typed ref params for creating child refs at an index */\n getChildTypedRefParams(\n index: number,\n shape: ContainerShape,\n ): TypedRefParams<ContainerShape> {\n return {\n shape,\n placeholder: undefined, // List items don't have placeholder\n getContainer: () => {\n const container = this.getContainer() as LoroList | LoroMovableList\n const containerItem = container.get(index)\n if (!containerItem || !isContainer(containerItem)) {\n throw new Error(`No container found at index ${index}`)\n }\n return containerItem\n },\n autoCommit: this.getAutoCommit(),\n batchedMutation: this.getBatchedMutation(),\n getDoc: () => this.getDoc(),\n overlay: this.getOverlay(),\n }\n }\n\n /** Get item for predicate functions (returns plain value) */\n getPredicateItem(index: number): Item | undefined {\n const shape = this.getShape()\n const container = this.getContainer() as LoroList | LoroMovableList\n const overlayList = this.getOverlayList()\n\n // CRITICAL FIX: For predicates to work correctly with mutations,\n // we need to check if there's a cached (mutated) version first\n const cachedItem = this.itemCache.get(index)\n if (cachedItem && isValueShape(shape.shape)) {\n // For value shapes, if we have a cached item, use it so predicates see mutations\n return cachedItem as Item\n }\n\n if (overlayList && isValueShape(shape.shape)) {\n return overlayList[index]\n }\n\n const containerItem = container.get(index)\n if (containerItem === undefined) {\n return undefined as Item\n }\n\n if (isValueShape(shape.shape)) {\n // For value shapes, return the plain value directly\n return containerItem as Item\n } else {\n // For container shapes, we need to return the plain object representation\n // This allows predicates to access nested properties like article.metadata.author\n if (isContainer(containerItem)) {\n // Convert container to plain object for predicate logic\n // Handle different container types that may not have toJSON method\n if (\n typeof containerItem === \"object\" &&\n containerItem !== null &&\n \"toJSON\" in containerItem\n ) {\n return (containerItem as any).toJSON() as Item\n } else if (\n typeof containerItem === \"object\" &&\n containerItem !== null &&\n \"getShallowValue\" in containerItem\n ) {\n // For containers like LoroCounter that don't have toJSON but have getShallowValue\n return (containerItem as any).getShallowValue() as Item\n } else {\n // Fallback for other container types\n return containerItem as Item\n }\n }\n return containerItem as Item\n }\n }\n\n /** Get mutable item for return values (returns ref or cached value) */\n getMutableItem(index: number): MutableItem | undefined {\n const shape = this.getShape()\n const container = this.getContainer() as LoroList | LoroMovableList\n const overlayList = this.getOverlayList()\n\n // Get the raw container item\n const containerItem = overlayList\n ? (overlayList[index] as Item | undefined)\n : (container.get(index) as Item | undefined)\n if (containerItem === undefined) {\n return undefined as MutableItem\n }\n\n if (isValueShape(shape.shape)) {\n // When NOT in batchedMutation mode (direct access outside of change()), ALWAYS read fresh\n // from container (NEVER cache). This ensures we always get the latest value\n // from the CRDT, even when modified by a different ref instance (e.g., drafts from change())\n //\n // When in batchedMutation mode (inside change()), we cache value shapes so that\n // mutations to found/filtered items persist back to the CRDT via absorbPlainValues()\n if (!this.getBatchedMutation()) {\n return containerItem as MutableItem\n }\n\n // In batched mode (within change()), we need to cache value shapes\n // so that mutations to found/filtered items persist back to the CRDT\n // via absorbPlainValues() at the end of change()\n let cachedItem = this.itemCache.get(index)\n if (cachedItem) {\n return cachedItem\n }\n\n // For value shapes, we need to ensure mutations persist\n // The key insight: we must return the SAME object for the same index\n // so that mutations to filtered/found items persist back to the cache\n if (typeof containerItem === \"object\" && containerItem !== null) {\n // Create a deep copy for objects so mutations can be tracked\n // IMPORTANT: Only create the copy once, then always return the same cached object\n cachedItem = JSON.parse(JSON.stringify(containerItem))\n } else {\n // For primitives, just use the value directly\n cachedItem = containerItem\n }\n this.itemCache.set(index, cachedItem)\n return cachedItem as MutableItem\n }\n\n // Container shapes: only cache in batchedMutation mode (inside change())\n // Outside of change(), always create fresh refs to avoid stale cache issues\n // after move operations (where indices shift but cached refs have hardcoded indices)\n if (!this.getBatchedMutation()) {\n return createContainerTypedRef(\n this.getChildTypedRefParams(index, shape.shape as ContainerShape),\n ) as MutableItem\n }\n\n // In batched mode, cache for consistent behavior within a single change() call\n let cachedItem = this.itemCache.get(index)\n if (!cachedItem) {\n cachedItem = createContainerTypedRef(\n this.getChildTypedRefParams(index, shape.shape as ContainerShape),\n )\n this.itemCache.set(index, cachedItem)\n }\n\n return cachedItem as MutableItem\n }\n\n /** Insert with automatic conversion */\n insertWithConversion(index: number, item: unknown): void {\n const shape = this.getShape()\n const container = this.getContainer() as LoroList | LoroMovableList\n const convertedItem = convertInputToRef(item as any, shape.shape)\n if (isContainer(convertedItem)) {\n container.insertContainer(index, convertedItem)\n } else {\n container.insert(index, convertedItem)\n }\n }\n\n /** Push with automatic conversion */\n pushWithConversion(item: unknown): void {\n const shape = this.getShape()\n const container = this.getContainer() as LoroList | LoroMovableList\n const convertedItem = convertInputToRef(item as any, shape.shape)\n if (isContainer(convertedItem)) {\n container.pushContainer(convertedItem)\n } else {\n container.push(convertedItem)\n }\n }\n\n /** Absorb value at specific index (for value shapes) - subclasses override */\n absorbValueAtIndex(_index: number, _value: unknown): void {\n throw new Error(\"absorbValueAtIndex must be implemented by subclass\")\n }\n\n /** Update cache indices after a delete operation */\n updateCacheForDelete(deleteIndex: number, deleteLen: number): void {\n const newCache = new Map<number, any>()\n\n for (const [cachedIndex, cachedItem] of this.itemCache.entries()) {\n if (cachedIndex < deleteIndex) {\n // Items before the deletion point keep their indices\n newCache.set(cachedIndex, cachedItem)\n } else if (cachedIndex >= deleteIndex + deleteLen) {\n // Items after the deletion range shift down by deleteLen\n newCache.set(cachedIndex - deleteLen, cachedItem)\n }\n // Items within the deletion range are removed from cache\n }\n\n this.itemCache = newCache\n }\n\n /** Update cache indices after an insert operation */\n updateCacheForInsert(insertIndex: number): void {\n const newCache = new Map<number, any>()\n\n for (const [cachedIndex, cachedItem] of this.itemCache.entries()) {\n if (cachedIndex < insertIndex) {\n // Items before the insertion point keep their indices\n newCache.set(cachedIndex, cachedItem)\n } else {\n // Items at or after the insertion point shift up by 1\n newCache.set(cachedIndex + 1, cachedItem)\n }\n }\n\n this.itemCache = newCache\n }\n\n /** Absorb mutated plain values back into Loro containers */\n absorbPlainValues(): void {\n // Critical function: absorb mutated plain values back into Loro containers\n // This is called at the end of change() to persist mutations made to plain objects\n const shape = this.getShape()\n for (const [index, cachedItem] of this.itemCache.entries()) {\n if (cachedItem) {\n if (isValueShape(shape.shape)) {\n // For value shapes, delegate to subclass-specific absorption logic\n this.absorbValueAtIndex(index, cachedItem)\n } else {\n // For container shapes, the item should be a typed ref that handles its own absorption\n if (\n cachedItem &&\n typeof cachedItem === \"object\" &&\n INTERNAL_SYMBOL in cachedItem\n ) {\n ;(cachedItem as any)[INTERNAL_SYMBOL].absorbPlainValues()\n }\n }\n }\n }\n\n // Clear the cache after absorbing values\n this.itemCache.clear()\n }\n\n /** Create the loro namespace for list */\n protected override createLoroNamespace(): LoroListRef {\n const self = this\n return {\n get doc(): LoroDoc {\n return self.getDoc()\n },\n get container(): LoroList | LoroMovableList {\n return self.getContainer() as LoroList | LoroMovableList\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n return (self.getContainer() as LoroList | LoroMovableList).subscribe(\n callback,\n )\n },\n pushContainer(container: Container): Container {\n const result = (\n self.getContainer() as LoroList | LoroMovableList\n ).pushContainer(container)\n self.commitIfAuto()\n return result\n },\n insertContainer(index: number, container: Container): Container {\n const result = (\n self.getContainer() as LoroList | LoroMovableList\n ).insertContainer(index, container)\n self.commitIfAuto()\n return result\n },\n }\n }\n}\n\n// ============================================================================\n// ListRefBase - Public facade class\n// ============================================================================\n\n/**\n * Shared logic for list operations - thin facade that delegates to ListRefBaseInternals.\n */\nexport abstract class ListRefBase<\n NestedShape extends ContainerOrValueShape,\n Item = NestedShape[\"_plain\"],\n MutableItem = NestedShape[\"_mutable\"],\n> extends TypedRef<any> {\n [INTERNAL_SYMBOL]: ListRefBaseInternals<NestedShape, Item, MutableItem>\n\n constructor(params: TypedRefParams<any>) {\n super()\n this[INTERNAL_SYMBOL] = this.createInternals(params)\n }\n\n /** Subclasses override to create their specific internals */\n protected abstract createInternals(\n params: TypedRefParams<any>,\n ): ListRefBaseInternals<NestedShape, Item, MutableItem>\n\n // Array-like methods for better developer experience\n // DUAL INTERFACE: Predicates get Item (plain data), return values are MutableItem (mutable)\n\n find(\n predicate: (item: Item, index: number) => boolean,\n ): MutableItem | undefined {\n for (let i = 0; i < this.length; i++) {\n const predicateItem = this[INTERNAL_SYMBOL].getPredicateItem(i)\n if (predicate(predicateItem as Item, i)) {\n return this[INTERNAL_SYMBOL].getMutableItem(i) as MutableItem // Return mutable item\n }\n }\n return undefined\n }\n\n findIndex(predicate: (item: Item, index: number) => boolean): number {\n for (let i = 0; i < this.length; i++) {\n const predicateItem = this[INTERNAL_SYMBOL].getPredicateItem(i)\n if (predicate(predicateItem as Item, i)) {\n return i\n }\n }\n return -1\n }\n\n map<ReturnType>(\n callback: (item: Item, index: number) => ReturnType,\n ): ReturnType[] {\n const result: ReturnType[] = []\n for (let i = 0; i < this.length; i++) {\n const predicateItem = this[INTERNAL_SYMBOL].getPredicateItem(i)\n result.push(callback(predicateItem as Item, i))\n }\n return result\n }\n\n filter(predicate: (item: Item, index: number) => boolean): MutableItem[] {\n const result: MutableItem[] = []\n for (let i = 0; i < this.length; i++) {\n const predicateItem = this[INTERNAL_SYMBOL].getPredicateItem(i)\n if (predicate(predicateItem as Item, i)) {\n result.push(this[INTERNAL_SYMBOL].getMutableItem(i) as MutableItem) // Return mutable items\n }\n }\n return result\n }\n\n forEach(callback: (item: Item, index: number) => void): void {\n for (let i = 0; i < this.length; i++) {\n const predicateItem = this[INTERNAL_SYMBOL].getPredicateItem(i)\n callback(predicateItem as Item, i)\n }\n }\n\n some(predicate: (item: Item, index: number) => boolean): boolean {\n for (let i = 0; i < this.length; i++) {\n const predicateItem = this[INTERNAL_SYMBOL].getPredicateItem(i)\n if (predicate(predicateItem as Item, i)) {\n return true\n }\n }\n return false\n }\n\n every(predicate: (item: Item, index: number) => boolean): boolean {\n for (let i = 0; i < this.length; i++) {\n const predicateItem = this[INTERNAL_SYMBOL].getPredicateItem(i)\n if (!predicate(predicateItem as Item, i)) {\n return false\n }\n }\n return true\n }\n\n slice(start?: number, end?: number): MutableItem[] {\n const len = this.length\n\n // Normalize start index (following JavaScript Array.prototype.slice semantics)\n const startIndex =\n start === undefined\n ? 0\n : start < 0\n ? Math.max(len + start, 0)\n : Math.min(start, len)\n\n // Normalize end index\n const endIndex =\n end === undefined\n ? len\n : end < 0\n ? Math.max(len + end, 0)\n : Math.min(end, len)\n\n const result: MutableItem[] = []\n for (let i = startIndex; i < endIndex; i++) {\n result.push(this[INTERNAL_SYMBOL].getMutableItem(i) as MutableItem)\n }\n return result\n }\n\n insert(index: number, item: Item): void {\n // Update cache indices before performing the insert operation\n this[INTERNAL_SYMBOL].updateCacheForInsert(index)\n this[INTERNAL_SYMBOL].insertWithConversion(index, item)\n this[INTERNAL_SYMBOL].commitIfAuto()\n }\n\n delete(index: number, len: number): void {\n // Update cache indices before performing the delete operation\n this[INTERNAL_SYMBOL].updateCacheForDelete(index, len)\n const container = this[INTERNAL_SYMBOL].getContainer() as\n | LoroList\n | LoroMovableList\n container.delete(index, len)\n this[INTERNAL_SYMBOL].commitIfAuto()\n }\n\n push(item: Item): void {\n this[INTERNAL_SYMBOL].pushWithConversion(item)\n this[INTERNAL_SYMBOL].commitIfAuto()\n }\n\n pushContainer(container: Container): Container {\n const loroContainer = this[INTERNAL_SYMBOL].getContainer() as\n | LoroList\n | LoroMovableList\n const result = loroContainer.pushContainer(container)\n this[INTERNAL_SYMBOL].commitIfAuto()\n return result\n }\n\n insertContainer(index: number, container: Container): Container {\n const loroContainer = this[INTERNAL_SYMBOL].getContainer() as\n | LoroList\n | LoroMovableList\n const result = loroContainer.insertContainer(index, container)\n this[INTERNAL_SYMBOL].commitIfAuto()\n return result\n }\n\n get(index: number): MutableItem | undefined {\n return this[INTERNAL_SYMBOL].getMutableItem(index) as\n | MutableItem\n | undefined\n }\n\n toArray(): Item[] {\n const overlayList = this[INTERNAL_SYMBOL].getOverlayList()\n if (overlayList) {\n return [...overlayList]\n }\n const result: Item[] = []\n for (let i = 0; i < this.length; i++) {\n result.push(this[INTERNAL_SYMBOL].getPredicateItem(i) as Item)\n }\n return result\n }\n\n toJSON(): Item[] {\n const shape = this[INTERNAL_SYMBOL].getShape()\n const overlayList = this[INTERNAL_SYMBOL].getOverlayList()\n const container = this[INTERNAL_SYMBOL].getContainer() as\n | LoroList\n | LoroMovableList\n const nativeJson = overlayList ?? (container.toJSON() as any[])\n\n // If the nested shape is a container shape (map, record, etc.) or an object value shape,\n // we need to overlay placeholders for each item\n if (\n isContainerShape(shape.shape) ||\n (isValueShape(shape.shape) && shape.shape.valueType === \"struct\")\n ) {\n const itemPlaceholder = deriveShapePlaceholder(shape.shape)\n return nativeJson.map(item =>\n mergeValue(shape.shape, item, itemPlaceholder as any),\n ) as Item[]\n }\n\n // For primitive value shapes, no overlay needed\n return nativeJson ?? []\n }\n\n [Symbol.iterator](): IterableIterator<MutableItem> {\n let index = 0\n return {\n next: (): IteratorResult<MutableItem> => {\n if (index < this.length) {\n return {\n value: this[INTERNAL_SYMBOL].getMutableItem(index++) as MutableItem,\n done: false,\n }\n }\n return { value: undefined, done: true }\n },\n [Symbol.iterator]() {\n return this\n },\n }\n }\n\n get length(): number {\n const overlayList = this[INTERNAL_SYMBOL].getOverlayList()\n if (overlayList) {\n return overlayList.length\n }\n const container = this[INTERNAL_SYMBOL].getContainer() as\n | LoroList\n | LoroMovableList\n return container.length\n }\n}\n\nfunction applyListDelta<T>(input: T[], delta: Delta<T[]>[]): T[] {\n const result: T[] = []\n let index = 0\n\n for (const op of delta) {\n if (op.retain !== undefined) {\n result.push(...input.slice(index, index + op.retain))\n index += op.retain\n } else if (op.delete !== undefined) {\n index += op.delete\n } else if (op.insert !== undefined) {\n result.push(...op.insert)\n }\n }\n\n if (index < input.length) {\n result.push(...input.slice(index))\n }\n\n return result\n}\n","import type { LoroList } from \"loro-crdt\"\nimport type { ContainerOrValueShape } from \"../shape.js\"\nimport { ListRefBaseInternals } from \"./list-ref-base.js\"\n\n/**\n * Internal implementation for ListRef.\n * Extends ListRefBaseInternals with LoroList-specific absorption logic.\n */\nexport class ListRefInternals<\n NestedShape extends ContainerOrValueShape,\n Item = NestedShape[\"_plain\"],\n MutableItem = NestedShape[\"_mutable\"],\n> extends ListRefBaseInternals<NestedShape, Item, MutableItem> {\n /** Absorb value at specific index for LoroList */\n override absorbValueAtIndex(index: number, value: unknown): void {\n // LoroList doesn't have set method, need to delete and insert\n const container = this.getContainer() as LoroList\n container.delete(index, 1)\n container.insert(index, value)\n }\n}\n","import type { ContainerOrValueShape } from \"../shape.js\"\nimport type { InferMutableType } from \"../types.js\"\nimport type { TypedRefParams } from \"./base.js\"\nimport { ListRefBase } from \"./list-ref-base.js\"\nimport { ListRefInternals } from \"./list-ref-internals.js\"\n\n/**\n * List typed ref - thin facade that delegates to ListRefInternals.\n */\nexport class ListRef<\n NestedShape extends ContainerOrValueShape,\n> extends ListRefBase<NestedShape> {\n // Returns the mutable type which has toJSON() and other ref methods.\n // For assignment, the proxy handler accepts plain values and converts them.\n // TypeScript may require type assertions for plain value assignments.\n [index: number]: InferMutableType<NestedShape> | undefined\n\n protected override createInternals(\n params: TypedRefParams<any>,\n ): ListRefInternals<NestedShape> {\n return new ListRefInternals(params)\n }\n}\n","import type { LoroMovableList } from \"loro-crdt\"\nimport type { ContainerOrValueShape } from \"../shape.js\"\nimport { ListRefBaseInternals } from \"./list-ref-base.js\"\n\n// ============================================================================\n// MovableListRefInternals - Internal implementation class\n// ============================================================================\n\n/**\n * Internal implementation for MovableListRef.\n * Extends ListRefBaseInternals with LoroMovableList-specific methods.\n */\nexport class MovableListRefInternals<\n NestedShape extends ContainerOrValueShape,\n Item = NestedShape[\"_plain\"],\n MutableItem = NestedShape[\"_mutable\"],\n> extends ListRefBaseInternals<NestedShape, Item, MutableItem> {\n /** Absorb value at specific index for LoroMovableList */\n override absorbValueAtIndex(index: number, value: unknown): void {\n // LoroMovableList has set method\n const container = this.getContainer() as LoroMovableList\n container.set(index, value)\n }\n\n /** Move an item from one index to another */\n move(from: number, to: number): void {\n const container = this.getContainer() as LoroMovableList\n container.move(from, to)\n this.commitIfAuto()\n }\n\n /** Set an item at a specific index */\n set(index: number, item: unknown): void {\n const container = this.getContainer() as LoroMovableList\n container.set(index, item)\n this.commitIfAuto()\n }\n}\n","import type { Container } from \"loro-crdt\"\nimport type { ContainerOrValueShape } from \"../shape.js\"\nimport type { InferMutableType } from \"../types.js\"\nimport { INTERNAL_SYMBOL, type TypedRefParams } from \"./base.js\"\nimport { ListRefBase } from \"./list-ref-base.js\"\nimport { MovableListRefInternals } from \"./movable-list-ref-internals.js\"\n\n/**\n * Movable list typed ref - thin facade that delegates to MovableListRefInternals.\n */\nexport class MovableListRef<\n NestedShape extends ContainerOrValueShape,\n Item = NestedShape[\"_plain\"],\n> extends ListRefBase<NestedShape> {\n declare [INTERNAL_SYMBOL]: MovableListRefInternals<NestedShape>;\n [index: number]: InferMutableType<NestedShape> | undefined\n\n protected override createInternals(\n params: TypedRefParams<any>,\n ): MovableListRefInternals<NestedShape> {\n return new MovableListRefInternals(params)\n }\n\n move(from: number, to: number): void {\n this[INTERNAL_SYMBOL].move(from, to)\n }\n\n set(index: number, item: Exclude<Item, Container>) {\n this[INTERNAL_SYMBOL].set(index, item)\n }\n}\n","import { INTERNAL_SYMBOL } from \"./base.js\"\nimport type { ListRef } from \"./list-ref.js\"\nimport type { MovableListRef } from \"./movable-list-ref.js\"\nimport type { RecordRef } from \"./record-ref.js\"\nimport type { RecordRefInternals } from \"./record-ref-internals.js\"\n\nexport const recordProxyHandler: ProxyHandler<RecordRef<any>> = {\n get: (target, prop) => {\n if (typeof prop === \"string\" && !(prop in target)) {\n // Use getRef for reading - returns undefined for non-existent keys\n return (target[INTERNAL_SYMBOL] as RecordRefInternals<any>).getRef(prop)\n }\n return Reflect.get(target, prop)\n },\n\n set: (target, prop, value) => {\n if (typeof prop === \"string\" && !(prop in target)) {\n target.set(prop, value)\n return true\n }\n return Reflect.set(target, prop, value)\n },\n\n deleteProperty: (target, prop) => {\n if (typeof prop === \"string\" && !(prop in target)) {\n target.delete(prop)\n return true\n }\n return Reflect.deleteProperty(target, prop)\n },\n\n // Support `in` operator for checking key existence\n has: (target, prop) => {\n if (typeof prop === \"string\") {\n // Check if it's a method/property on the class first\n if (prop in target) {\n return true\n }\n // Otherwise check the underlying container\n return target.has(prop)\n }\n return Reflect.has(target, prop)\n },\n\n ownKeys: target => {\n return target.keys()\n },\n\n getOwnPropertyDescriptor: (target, prop) => {\n if (typeof prop === \"string\" && target.has(prop)) {\n return {\n configurable: true,\n enumerable: true,\n value: target.get(prop),\n }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n}\n\nexport const listProxyHandler: ProxyHandler<ListRef<any>> = {\n get: (target, prop) => {\n if (typeof prop === \"string\") {\n const index = Number(prop)\n if (!Number.isNaN(index)) {\n return target.get(index)\n }\n }\n return Reflect.get(target, prop)\n },\n\n set: (target, prop, value) => {\n if (typeof prop === \"string\") {\n const index = Number(prop)\n if (!Number.isNaN(index)) {\n // For lists, assignment to index implies replacement\n target.delete(index, 1)\n target.insert(index, value)\n return true\n }\n }\n return Reflect.set(target, prop, value)\n },\n}\n\nexport const movableListProxyHandler: ProxyHandler<MovableListRef<any>> = {\n get: (target, prop) => {\n if (typeof prop === \"string\") {\n const index = Number(prop)\n if (!Number.isNaN(index)) {\n return target.get(index)\n }\n }\n return Reflect.get(target, prop)\n },\n\n set: (target, prop, value) => {\n if (typeof prop === \"string\") {\n const index = Number(prop)\n if (!Number.isNaN(index)) {\n // MovableList supports set directly\n target.set(index, value)\n return true\n }\n }\n return Reflect.set(target, prop, value)\n },\n}\n","import type {\n Container,\n LoroDoc,\n LoroEventBatch,\n LoroMap,\n MapDiff,\n Subscription,\n Value,\n} from \"loro-crdt\"\nimport { deriveShapePlaceholder } from \"../derive-placeholder.js\"\nimport type { LoroMapRef } from \"../loro.js\"\nimport type {\n ContainerOrValueShape,\n ContainerShape,\n RecordContainerShape,\n} from \"../shape.js\"\nimport { isContainerShape, isValueShape } from \"../utils/type-guards.js\"\nimport { BaseRefInternals, type TypedRef, type TypedRefParams } from \"./base.js\"\nimport {\n absorbCachedPlainValues,\n assignPlainValueToTypedRef,\n containerConstructor,\n createContainerTypedRef,\n hasContainerConstructor,\n} from \"./utils.js\"\n\n/**\n * Internal implementation for RecordRef.\n * Contains all logic, state, and implementation details.\n */\nexport class RecordRefInternals<\n NestedShape extends ContainerOrValueShape,\n> extends BaseRefInternals<any> {\n private refCache = new Map<string, TypedRef<ContainerShape> | Value>()\n\n /** Get typed ref params for creating child refs at a key */\n getChildTypedRefParams(\n key: string,\n shape: ContainerShape,\n ): TypedRefParams<ContainerShape> {\n // First try to get placeholder from the Record's placeholder (if it has an entry for this key)\n let placeholder = (this.getPlaceholder() as any)?.[key]\n\n // If no placeholder exists for this key, derive one from the schema's shape\n // This is critical for Records where the placeholder is always {} but nested\n // containers need valid placeholders to fall back to for missing values\n if (placeholder === undefined) {\n placeholder = deriveShapePlaceholder(shape)\n }\n\n // AnyContainerShape is an escape hatch - it doesn't have a constructor\n if (!hasContainerConstructor(shape._type)) {\n throw new Error(\n `Cannot create typed ref for shape type \"${shape._type}\". ` +\n `Use Shape.any() only at the document root level.`,\n )\n }\n\n const LoroContainer = containerConstructor[shape._type]\n const container = this.getContainer() as LoroMap\n\n return {\n shape,\n placeholder,\n getContainer: () =>\n container.getOrCreateContainer(key, new (LoroContainer as any)()),\n autoCommit: this.getAutoCommit(),\n batchedMutation: this.getBatchedMutation(),\n getDoc: () => this.getDoc(),\n }\n }\n\n /** Get a ref for a key without creating (returns undefined for non-existent container keys) */\n getRef(key: string): unknown {\n const recordShape = this.getShape() as RecordContainerShape<NestedShape>\n const shape = recordShape.shape\n const container = this.getContainer() as LoroMap\n\n // For container shapes, check if the key exists first\n // This allows optional chaining (?.) to work correctly for non-existent keys\n if (isContainerShape(shape)) {\n const existing = container.get(key)\n if (existing === undefined) {\n return undefined\n }\n }\n\n return this.getOrCreateRef(key)\n }\n\n /** Get or create a ref for a key (always creates for container shapes) */\n getOrCreateRef(key: string): unknown {\n const recordShape = this.getShape() as RecordContainerShape<NestedShape>\n const shape = recordShape.shape\n const container = this.getContainer() as LoroMap\n\n if (isValueShape(shape)) {\n const overlay = this.getOverlay()\n if (overlay) {\n const containerId = (container as any).id\n const diff = overlay.get(containerId)\n if (diff && diff.type === \"map\") {\n const mapDiff = diff as MapDiff\n if (key in mapDiff.updated) {\n return mapDiff.updated[key] as Value\n }\n }\n }\n // When NOT in batchedMutation mode (direct access outside of change()), ALWAYS read fresh\n // from container (NEVER cache). This ensures we always get the latest value\n // from the CRDT, even when modified by a different ref instance (e.g., drafts from change())\n //\n // When in batchedMutation mode (inside change()), we cache value shapes so that\n // mutations to nested objects persist back to the CRDT via absorbPlainValues()\n if (!this.getBatchedMutation()) {\n const containerValue = container.get(key)\n if (containerValue !== undefined) {\n return containerValue\n }\n // Fall back to placeholder if the container doesn't have the value\n const placeholder = (this.getPlaceholder() as any)?.[key]\n if (placeholder !== undefined) {\n return placeholder\n }\n // Fall back to the default value from the shape\n return (shape as any)._plain\n }\n\n // In batched mode (within change()), we cache value shapes so that\n // mutations to nested objects persist back to the CRDT via absorbPlainValues()\n let ref = this.refCache.get(key)\n if (!ref) {\n const containerValue = container.get(key)\n if (containerValue !== undefined) {\n // For objects, create a deep copy so mutations can be tracked\n if (typeof containerValue === \"object\" && containerValue !== null) {\n ref = JSON.parse(JSON.stringify(containerValue))\n } else {\n ref = containerValue as Value\n }\n } else {\n // Fall back to placeholder if the container doesn't have the value\n const placeholder = (this.getPlaceholder() as any)?.[key]\n if (placeholder !== undefined) {\n ref = placeholder as Value\n } else {\n // Fall back to the default value from the shape\n ref = (shape as any)._plain\n }\n }\n this.refCache.set(key, ref)\n }\n return ref\n }\n\n // For container shapes, we can safely cache the ref since it's a handle\n // to the underlying Loro container, not a value copy.\n let ref = this.refCache.get(key)\n if (!ref) {\n ref = createContainerTypedRef(\n this.getChildTypedRefParams(key, shape as ContainerShape),\n )\n this.refCache.set(key, ref)\n }\n\n return ref as any\n }\n\n /** Set a value at a key */\n set(key: string, value: any): void {\n const recordShape = this.getShape() as RecordContainerShape<NestedShape>\n const shape = recordShape.shape\n const container = this.getContainer() as LoroMap\n\n if (isValueShape(shape)) {\n container.set(key, value)\n this.refCache.set(key, value)\n this.commitIfAuto()\n } else {\n // For container shapes, try to assign the plain value\n // Use getOrCreateRef to ensure the container is created\n // assignPlainValueToTypedRef handles batching and commits internally\n const ref = this.getOrCreateRef(key)\n if (assignPlainValueToTypedRef(ref as TypedRef<any>, value)) {\n // Don't call commitIfAuto here - assignPlainValueToTypedRef handles it\n return\n }\n throw new Error(\n \"Cannot set container directly, modify the typed ref instead\",\n )\n }\n }\n\n /** Delete a key */\n delete(key: string): void {\n const container = this.getContainer() as LoroMap\n container.delete(key)\n this.refCache.delete(key)\n this.commitIfAuto()\n }\n\n /**\n * Replace entire contents with new values.\n * Keys not in `values` are removed.\n */\n replace(values: Record<string, any>): void {\n const container = this.getContainer() as LoroMap\n const currentKeys = new Set(container.keys())\n const newKeys = new Set(Object.keys(values))\n\n // Suppress auto-commit during batch operations\n const wasSuppressed = this.isSuppressAutoCommit()\n if (!wasSuppressed) {\n this.setSuppressAutoCommit(true)\n }\n\n try {\n // Delete keys that are not in the new values\n for (const key of currentKeys) {\n if (!newKeys.has(key)) {\n container.delete(key)\n this.refCache.delete(key)\n }\n }\n\n // Set new/updated values\n for (const key of newKeys) {\n this.set(key, values[key])\n }\n } finally {\n // Restore auto-commit state\n if (!wasSuppressed) {\n this.setSuppressAutoCommit(false)\n }\n }\n\n // Commit once after all operations\n this.commitIfAuto()\n }\n\n /**\n * Merge values into record.\n * Existing keys not in `values` are kept.\n */\n merge(values: Record<string, any>): void {\n // Suppress auto-commit during batch operations\n const wasSuppressed = this.isSuppressAutoCommit()\n if (!wasSuppressed) {\n this.setSuppressAutoCommit(true)\n }\n\n try {\n // Set new/updated values (no deletions)\n for (const key of Object.keys(values)) {\n this.set(key, values[key])\n }\n } finally {\n // Restore auto-commit state\n if (!wasSuppressed) {\n this.setSuppressAutoCommit(false)\n }\n }\n\n // Commit once after all operations\n this.commitIfAuto()\n }\n\n /**\n * Remove all entries from the record.\n */\n clear(): void {\n const container = this.getContainer() as LoroMap\n const keys = container.keys()\n\n if (keys.length === 0) {\n return // No-op on empty record\n }\n\n // Suppress auto-commit during batch operations\n const wasSuppressed = this.isSuppressAutoCommit()\n if (!wasSuppressed) {\n this.setSuppressAutoCommit(true)\n }\n\n try {\n // Delete all keys\n for (const key of keys) {\n container.delete(key)\n this.refCache.delete(key)\n }\n } finally {\n // Restore auto-commit state\n if (!wasSuppressed) {\n this.setSuppressAutoCommit(false)\n }\n }\n\n // Commit once after all operations\n this.commitIfAuto()\n }\n\n /** Absorb mutated plain values back into Loro containers */\n absorbPlainValues(): void {\n absorbCachedPlainValues(this.refCache, () => this.getContainer() as LoroMap)\n }\n\n /** Create the loro namespace for record */\n protected override createLoroNamespace(): LoroMapRef {\n const self = this\n return {\n get doc(): LoroDoc {\n return self.getDoc()\n },\n get container(): LoroMap {\n return self.getContainer() as LoroMap\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n return (self.getContainer() as LoroMap).subscribe(callback)\n },\n setContainer(key: string, container: Container): Container {\n const result = (self.getContainer() as LoroMap).setContainer(\n key,\n container,\n )\n self.commitIfAuto()\n return result\n },\n }\n }\n}\n","import type { Container, LoroMap } from \"loro-crdt\"\nimport type { ContainerOrValueShape } from \"../shape.js\"\nimport type { Infer, InferMutableType } from \"../types.js\"\nimport { INTERNAL_SYMBOL, TypedRef, type TypedRefParams } from \"./base.js\"\nimport { RecordRefInternals } from \"./record-ref-internals.js\"\nimport { serializeRefToJSON } from \"./utils.js\"\n\n/**\n * Record typed ref - thin facade that delegates to RecordRefInternals.\n */\nexport class RecordRef<\n NestedShape extends ContainerOrValueShape,\n> extends TypedRef<any> {\n [key: string]: InferMutableType<NestedShape> | undefined | any\n\n [INTERNAL_SYMBOL]: RecordRefInternals<NestedShape>\n\n constructor(params: TypedRefParams<any>) {\n super()\n this[INTERNAL_SYMBOL] = new RecordRefInternals(params)\n }\n\n /** Set a value at a key */\n set(key: string, value: any): void {\n this[INTERNAL_SYMBOL].set(key, value)\n }\n\n /** Delete a key */\n delete(key: string): void {\n this[INTERNAL_SYMBOL].delete(key)\n }\n\n get(key: string): InferMutableType<NestedShape> | undefined {\n // In batched mutation mode (inside change()), use getOrCreateRef to create containers\n // This allows patterns like: draft.scores.get(\"alice\")!.increment(10)\n if (this[INTERNAL_SYMBOL].getBatchedMutation()) {\n return this[INTERNAL_SYMBOL].getOrCreateRef(key) as\n | InferMutableType<NestedShape>\n | undefined\n }\n // In readonly mode, use getRef which returns undefined for non-existent keys\n return this[INTERNAL_SYMBOL].getRef(key) as\n | InferMutableType<NestedShape>\n | undefined\n }\n\n setContainer<C extends Container>(key: string, container: C): C {\n const loroContainer = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n const result = loroContainer.setContainer(key, container)\n this[INTERNAL_SYMBOL].commitIfAuto()\n return result\n }\n\n has(key: string): boolean {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n return container.get(key) !== undefined\n }\n\n keys(): string[] {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n return container.keys()\n }\n\n /**\n * Returns an array of all values in the record.\n * For container-valued records, returns properly typed refs.\n */\n values(): InferMutableType<NestedShape>[] {\n // We know keys() only returns keys that exist, so get() will not return undefined\n return this.keys().map(\n key => this.get(key) as InferMutableType<NestedShape>,\n )\n }\n\n /**\n * Returns an array of [key, value] pairs.\n * For container-valued records, values are properly typed refs.\n */\n entries(): [string, InferMutableType<NestedShape>][] {\n // We know keys() only returns keys that exist, so get() will not return undefined\n return this.keys().map(key => [\n key,\n this.get(key) as InferMutableType<NestedShape>,\n ])\n }\n\n get size(): number {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n return container.size\n }\n\n /**\n * Replace entire contents with new values.\n * Keys not in `values` are removed.\n *\n * @example\n * ```typescript\n * doc.change(draft => {\n * draft.players.replace({\n * alice: { score: 100 },\n * bob: { score: 50 }\n * })\n * })\n * ```\n */\n replace(values: Record<string, Infer<NestedShape>>): void {\n this[INTERNAL_SYMBOL].replace(values)\n }\n\n /**\n * Merge values into record.\n * Existing keys not in `values` are kept.\n *\n * @example\n * ```typescript\n * doc.change(draft => {\n * // Adds charlie, updates alice, keeps bob unchanged\n * draft.players.merge({\n * alice: { score: 150 },\n * charlie: { score: 25 }\n * })\n * })\n * ```\n */\n merge(values: Record<string, Infer<NestedShape>>): void {\n this[INTERNAL_SYMBOL].merge(values)\n }\n\n /**\n * Remove all entries from the record.\n *\n * @example\n * ```typescript\n * doc.change(draft => {\n * draft.players.clear()\n * })\n * ```\n */\n clear(): void {\n this[INTERNAL_SYMBOL].clear()\n }\n\n toJSON(): Record<string, Infer<NestedShape>> {\n return serializeRefToJSON(this, this.keys()) as Record<\n string,\n Infer<NestedShape>\n >\n }\n}\n","import type {\n Container,\n LoroDoc,\n LoroEventBatch,\n LoroMap,\n MapDiff,\n Subscription,\n Value,\n} from \"loro-crdt\"\nimport type { LoroMapRef } from \"../loro.js\"\nimport type {\n ContainerOrValueShape,\n ContainerShape,\n StructContainerShape,\n ValueShape,\n} from \"../shape.js\"\nimport { isValueShape } from \"../utils/type-guards.js\"\nimport {\n BaseRefInternals,\n INTERNAL_SYMBOL,\n type TypedRef,\n type TypedRefParams,\n} from \"./base.js\"\nimport {\n absorbCachedPlainValues,\n assignPlainValueToTypedRef,\n containerConstructor,\n createContainerTypedRef,\n hasContainerConstructor,\n} from \"./utils.js\"\n\n/**\n * Internal implementation for StructRef.\n * Contains all logic, state, and implementation details.\n */\nexport class StructRefInternals<\n NestedShapes extends Record<string, ContainerOrValueShape>,\n> extends BaseRefInternals<any> {\n private propertyCache = new Map<string, TypedRef<ContainerShape> | Value>()\n\n /** Get typed ref params for creating child refs at a key */\n getChildTypedRefParams(\n key: string,\n shape: ContainerShape,\n ): TypedRefParams<ContainerShape> {\n const placeholder = (this.getPlaceholder() as any)?.[key]\n\n // AnyContainerShape is an escape hatch - it doesn't have a constructor\n if (!hasContainerConstructor(shape._type)) {\n throw new Error(\n `Cannot create typed ref for shape type \"${shape._type}\". ` +\n `Use Shape.any() only at the document root level.`,\n )\n }\n\n const LoroContainer = containerConstructor[shape._type]\n const container = this.getContainer() as LoroMap\n\n return {\n shape,\n placeholder,\n getContainer: () =>\n container.getOrCreateContainer(key, new (LoroContainer as any)()),\n autoCommit: this.getAutoCommit(),\n batchedMutation: this.getBatchedMutation(),\n getDoc: () => this.getDoc(),\n }\n }\n\n /** Get or create a ref for a key */\n getOrCreateRef<Shape extends ContainerShape | ValueShape>(\n key: string,\n shape?: Shape,\n ): unknown {\n const structShape = this.getShape() as StructContainerShape<NestedShapes>\n const actualShape = shape || structShape.shapes[key]\n const container = this.getContainer() as LoroMap\n\n if (isValueShape(actualShape)) {\n const overlay = this.getOverlay()\n if (overlay) {\n const containerId = (container as any).id\n const diff = overlay.get(containerId)\n if (diff && diff.type === \"map\") {\n const mapDiff = diff as MapDiff\n if (key in mapDiff.updated) {\n return mapDiff.updated[key] as Value\n }\n }\n }\n // When NOT in batchedMutation mode (direct access outside of change()), ALWAYS read fresh\n // from container (NEVER cache). This ensures we always get the latest value\n // from the CRDT, even when modified by a different ref instance (e.g., drafts from change())\n //\n // When in batchedMutation mode (inside change()), we cache value shapes so that\n // mutations to nested objects persist back to the CRDT via absorbPlainValues()\n if (!this.getBatchedMutation()) {\n const containerValue = container.get(key)\n if (containerValue !== undefined) {\n return containerValue\n }\n // Only fall back to placeholder if the container doesn't have the value\n const placeholder = (this.getPlaceholder() as any)?.[key]\n if (placeholder === undefined) {\n throw new Error(\"placeholder required\")\n }\n return placeholder\n }\n\n // In batched mode (within change()), we cache value shapes so that\n // mutations to nested objects persist back to the CRDT via absorbPlainValues()\n let ref = this.propertyCache.get(key)\n if (!ref) {\n const containerValue = container.get(key)\n if (containerValue !== undefined) {\n // For objects, create a deep copy so mutations can be tracked\n if (typeof containerValue === \"object\" && containerValue !== null) {\n ref = JSON.parse(JSON.stringify(containerValue))\n } else {\n ref = containerValue as Value\n }\n } else {\n // Only fall back to placeholder if the container doesn't have the value\n const placeholder = (this.getPlaceholder() as any)?.[key]\n if (placeholder === undefined) {\n throw new Error(\"placeholder required\")\n }\n ref = placeholder as Value\n }\n this.propertyCache.set(key, ref)\n }\n return ref\n }\n\n // Container shapes: safe to cache (handles)\n let ref = this.propertyCache.get(key)\n if (!ref) {\n ref = createContainerTypedRef(\n this.getChildTypedRefParams(key, actualShape as ContainerShape),\n )\n this.propertyCache.set(key, ref)\n }\n\n return ref as Shape extends ContainerShape ? TypedRef<Shape> : Value\n }\n\n /** Set a property value */\n setPropertyValue(key: string, value: unknown): void {\n const structShape = this.getShape() as StructContainerShape<NestedShapes>\n const shape = structShape.shapes[key]\n const container = this.getContainer() as LoroMap\n\n if (!shape) {\n throw new Error(`Unknown property: ${key}`)\n }\n\n if (isValueShape(shape)) {\n container.set(key, value)\n this.propertyCache.set(key, value as Value)\n this.commitIfAuto()\n } else {\n // For container shapes, try to assign the plain value\n // assignPlainValueToTypedRef handles batching and commits internally\n const ref = this.getOrCreateRef(key, shape)\n if (assignPlainValueToTypedRef(ref as TypedRef<any>, value)) {\n // Don't call commitIfAuto here - assignPlainValueToTypedRef handles it\n return\n }\n throw new Error(\n \"Cannot set container directly, modify the typed ref instead\",\n )\n }\n }\n\n /** Delete a property */\n deleteProperty(key: string): void {\n const container = this.getContainer() as LoroMap\n container.delete(key)\n this.propertyCache.delete(key)\n this.commitIfAuto()\n }\n\n /** Absorb mutated plain values back into Loro containers */\n absorbPlainValues(): void {\n absorbCachedPlainValues(\n this.propertyCache,\n () => this.getContainer() as LoroMap,\n )\n }\n\n /** Force materialization of the container and its nested containers */\n override materialize(): void {\n // Ensure this container exists\n this.getContainer()\n\n // Recursively materialize nested containers\n const structShape = this.getShape() as StructContainerShape<NestedShapes>\n for (const key in structShape.shapes) {\n const shape = structShape.shapes[key]\n if (!isValueShape(shape)) {\n // Get the ref (which creates it if needed)\n const ref = this.getOrCreateRef(key, shape) as TypedRef<any>\n // Force materialization\n ref[INTERNAL_SYMBOL].materialize()\n }\n }\n }\n\n /** Create the loro namespace for struct */\n protected override createLoroNamespace(): LoroMapRef {\n const self = this\n return {\n get doc(): LoroDoc {\n return self.getDoc()\n },\n get container(): LoroMap {\n return self.getContainer() as LoroMap\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n return (self.getContainer() as LoroMap).subscribe(callback)\n },\n setContainer(key: string, container: Container): Container {\n const result = (self.getContainer() as LoroMap).setContainer(\n key,\n container,\n )\n self.commitIfAuto()\n return result\n },\n }\n }\n}\n","import type { Container, LoroMap, Value } from \"loro-crdt\"\nimport { LORO_SYMBOL, type LoroMapRef } from \"../loro.js\"\nimport type { ContainerOrValueShape, StructContainerShape } from \"../shape.js\"\nimport type { Infer } from \"../types.js\"\nimport {\n INTERNAL_SYMBOL,\n type RefInternalsBase,\n TypedRef,\n type TypedRefParams,\n} from \"./base.js\"\nimport { StructRefInternals } from \"./struct-ref-internals.js\"\nimport { serializeRefToJSON } from \"./utils.js\"\n\n/**\n * Internal implementation class for struct containers.\n * The actual StructRef is a Proxy wrapping this class.\n */\nclass StructRefImpl<\n NestedShapes extends Record<string, ContainerOrValueShape>,\n> extends TypedRef<any> {\n [INTERNAL_SYMBOL]: StructRefInternals<NestedShapes>\n\n constructor(params: TypedRefParams<any>) {\n super()\n this[INTERNAL_SYMBOL] = new StructRefInternals(params)\n }\n\n get structShape(): StructContainerShape<NestedShapes> {\n return this[\n INTERNAL_SYMBOL\n ].getShape() as StructContainerShape<NestedShapes>\n }\n\n toJSON(): Infer<StructContainerShape<NestedShapes>> {\n return serializeRefToJSON(\n this as any,\n Object.keys(this.structShape.shapes),\n ) as Infer<StructContainerShape<NestedShapes>>\n }\n\n // Deprecated methods - kept for backward compatibility\n // @deprecated Use property access instead: obj.key\n get(key: string): any {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n return container.get(key)\n }\n\n // @deprecated Use property assignment instead: obj.key = value\n set(key: string, value: Value): void {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n container.set(key, value)\n this[INTERNAL_SYMBOL].commitIfAuto()\n }\n\n // @deprecated Use loro(struct).setContainer() instead\n setContainer<C extends Container>(key: string, container: C): C {\n const loroContainer = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n const result = loroContainer.setContainer(key, container)\n this[INTERNAL_SYMBOL].commitIfAuto()\n return result\n }\n\n // @deprecated Use delete obj.key instead\n delete(key: string): void {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n container.delete(key)\n this[INTERNAL_SYMBOL].commitIfAuto()\n }\n\n // @deprecated Use 'key' in obj instead\n has(key: string): boolean {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n return container.get(key) !== undefined\n }\n\n // @deprecated Use Object.keys(obj) instead\n keys(): string[] {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n return container.keys()\n }\n\n // @deprecated Use Object.values(obj) instead\n values(): any[] {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n return container.values()\n }\n\n // @deprecated Not standard for objects\n get size(): number {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroMap\n return container.size\n }\n}\n\n/**\n * Creates a StructRef wrapped in a Proxy for JavaScript-native object behavior.\n * Supports:\n * - Property access: obj.key\n * - Property assignment: obj.key = value\n * - Object.keys(obj)\n * - 'key' in obj\n * - delete obj.key\n * - toJSON()\n * - loro(obj) for CRDT access\n */\nexport function createStructRef<\n NestedShapes extends Record<string, ContainerOrValueShape>,\n>(\n params: TypedRefParams<StructContainerShape<NestedShapes>>,\n): StructRef<NestedShapes> {\n const impl = new StructRefImpl<NestedShapes>(params)\n\n const proxy = new Proxy(impl, {\n get(target, prop, receiver) {\n // Handle Symbol access (loro(), internal, etc.)\n if (prop === LORO_SYMBOL) {\n return target[INTERNAL_SYMBOL].getLoroNamespace()\n }\n\n // Handle INTERNAL_SYMBOL for internal methods\n if (prop === INTERNAL_SYMBOL) {\n return target[INTERNAL_SYMBOL]\n }\n\n // Handle toJSON - use serializeRefToJSON with the proxy (receiver) so property access goes through the proxy\n if (prop === \"toJSON\") {\n return () =>\n serializeRefToJSON(receiver, Object.keys(target.structShape.shapes))\n }\n\n // Handle shape access (internal - needed for assignPlainValueToTypedRef)\n if (prop === \"shape\") {\n return target.structShape\n }\n\n // Schema property access\n if (typeof prop === \"string\" && prop in target.structShape.shapes) {\n const shape = target.structShape.shapes[prop]\n return target[INTERNAL_SYMBOL].getOrCreateRef(prop, shape)\n }\n\n return undefined\n },\n\n set(target, prop, value) {\n if (typeof prop === \"string\" && prop in target.structShape.shapes) {\n target[INTERNAL_SYMBOL].setPropertyValue(prop, value)\n return true\n }\n return false\n },\n\n has(target, prop) {\n if (\n prop === LORO_SYMBOL ||\n prop === INTERNAL_SYMBOL ||\n prop === \"toJSON\" ||\n prop === \"shape\"\n ) {\n return true\n }\n if (typeof prop === \"string\") {\n return prop in target.structShape.shapes\n }\n return false\n },\n\n deleteProperty(target, prop) {\n if (typeof prop === \"string\" && prop in target.structShape.shapes) {\n target[INTERNAL_SYMBOL].deleteProperty(prop)\n return true\n }\n return false\n },\n\n ownKeys(target) {\n // Return only schema keys, not internal methods\n return Object.keys(target.structShape.shapes)\n },\n\n getOwnPropertyDescriptor(target, prop) {\n if (typeof prop === \"string\" && prop in target.structShape.shapes) {\n const shape = target.structShape.shapes[prop]\n return {\n configurable: true,\n enumerable: true,\n value: target[INTERNAL_SYMBOL].getOrCreateRef(prop, shape),\n }\n }\n return undefined\n },\n }) as unknown as StructRef<NestedShapes>\n\n return proxy\n}\n\n/**\n * Typed ref for struct containers (objects with fixed keys).\n * Uses LoroMap as the underlying container.\n *\n * Supports JavaScript-native object behavior:\n * - Property access: obj.key\n * - Property assignment: obj.key = value\n * - Object.keys(obj)\n * - 'key' in obj\n * - delete obj.key\n *\n * @example\n * ```typescript\n * const schema = Shape.doc({\n * settings: Shape.struct({\n * darkMode: Shape.plain.boolean().placeholder(false),\n * fontSize: Shape.plain.number().placeholder(14),\n * }),\n * });\n *\n * const doc = createTypedDoc(schema);\n *\n * // Property access\n * doc.settings.darkMode = true;\n * console.log(doc.settings.darkMode); // true\n *\n * // Object.keys()\n * console.log(Object.keys(doc.settings)); // ['darkMode', 'fontSize']\n *\n * // 'key' in obj\n * console.log('darkMode' in doc.settings); // true\n *\n * // delete obj.key\n * delete doc.settings.darkMode;\n *\n * // CRDT access via loro()\n * import { loro } from \"@loro-extended/change\";\n * loro(doc.settings).setContainer('nested', loroMap);\n * loro(doc.settings).subscribe(callback);\n * ```\n */\nexport type StructRef<\n NestedShapes extends Record<string, ContainerOrValueShape>,\n> = {\n [K in keyof NestedShapes]: NestedShapes[K][\"_mutable\"]\n} & {\n /**\n * Serializes the struct to a plain JSON-compatible object.\n */\n toJSON(): Infer<StructContainerShape<NestedShapes>>\n\n /**\n * Internal methods accessed via INTERNAL_SYMBOL.\n * @internal\n */\n [INTERNAL_SYMBOL]: RefInternalsBase\n\n /**\n * Access CRDT internals via the well-known symbol.\n * Used by the loro() function.\n */\n [LORO_SYMBOL]: LoroMapRef\n}\n\n// Re-export for backward compatibility\n// The old class-based StructRef is now replaced by the proxy-based version\nexport { StructRefImpl as StructRefClass }\n","import type {\n Delta,\n LoroDoc,\n LoroEventBatch,\n LoroText,\n Subscription,\n TextDiff,\n} from \"loro-crdt\"\nimport type { LoroTextRef } from \"../loro.js\"\nimport type { TextContainerShape } from \"../shape.js\"\nimport { BaseRefInternals } from \"./base.js\"\n\n/**\n * Internal implementation for TextRef.\n * Contains all logic, state, and implementation details.\n */\nexport class TextRefInternals extends BaseRefInternals<TextContainerShape> {\n private materialized = false\n\n /** Insert text at the given index */\n insert(index: number, content: string): void {\n this.materialized = true\n ;(this.getContainer() as LoroText).insert(index, content)\n this.commitIfAuto()\n }\n\n /** Delete text at the given index */\n delete(index: number, len: number): void {\n this.materialized = true\n ;(this.getContainer() as LoroText).delete(index, len)\n this.commitIfAuto()\n }\n\n /** Update the entire text content */\n update(text: string): void {\n this.materialized = true\n ;(this.getContainer() as LoroText).update(text)\n this.commitIfAuto()\n }\n\n /** Mark a range of text with a key-value pair */\n mark(range: { start: number; end: number }, key: string, value: any): void {\n this.materialized = true\n ;(this.getContainer() as LoroText).mark(range, key, value)\n this.commitIfAuto()\n }\n\n /** Remove a mark from a range of text */\n unmark(range: { start: number; end: number }, key: string): void {\n this.materialized = true\n ;(this.getContainer() as LoroText).unmark(range, key)\n this.commitIfAuto()\n }\n\n /** Apply a delta to the text */\n applyDelta(delta: any[]): void {\n this.materialized = true\n ;(this.getContainer() as LoroText).applyDelta(delta)\n this.commitIfAuto()\n }\n\n /** Get the text as a string */\n getStringValue(): string {\n const container = this.getContainer() as LoroText\n const overlay = this.getOverlay()\n if (overlay) {\n const diff = overlay.get(container.id)\n if (diff && diff.type === \"text\") {\n const containerValue = container.toString()\n return applyTextDelta(containerValue, (diff as TextDiff).diff)\n }\n }\n const containerValue = container.toString()\n if (containerValue !== \"\" || this.materialized) {\n return containerValue\n }\n // Return placeholder if available and container is at default state\n const placeholder = this.getPlaceholder()\n if (placeholder !== undefined) {\n return placeholder as string\n }\n return containerValue\n }\n\n /** Get the text as a delta */\n toDelta(): any[] {\n const container = this.getContainer() as LoroText\n const overlay = this.getOverlay()\n if (overlay) {\n const diff = overlay.get(container.id)\n if (diff && diff.type === \"text\") {\n const base = container.toDelta() as Delta<string>[]\n return applyDeltaToDelta(base, (diff as TextDiff).diff)\n }\n }\n return container.toDelta()\n }\n\n /** Get the length of the text */\n getLength(): number {\n const container = this.getContainer() as LoroText\n const overlay = this.getOverlay()\n if (overlay) {\n const diff = overlay.get(container.id)\n if (diff && diff.type === \"text\") {\n return applyTextDelta(container.toString(), (diff as TextDiff).diff)\n .length\n }\n }\n return container.length\n }\n\n /** No plain values in text */\n absorbPlainValues(): void {\n // no plain values contained within\n }\n\n /** Create the loro namespace for text */\n protected override createLoroNamespace(): LoroTextRef {\n const self = this\n return {\n get doc(): LoroDoc {\n return self.getDoc()\n },\n get container(): LoroText {\n return self.getContainer() as LoroText\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n return (self.getContainer() as LoroText).subscribe(callback)\n },\n }\n }\n}\n\nfunction applyTextDelta(text: string, delta: Delta<string>[]): string {\n let result = \"\"\n let index = 0\n\n for (const op of delta) {\n if (op.retain !== undefined) {\n result += text.slice(index, index + op.retain)\n index += op.retain\n } else if (op.delete !== undefined) {\n index += op.delete\n } else if (op.insert !== undefined) {\n result += op.insert\n }\n }\n\n if (index < text.length) {\n result += text.slice(index)\n }\n\n return result\n}\n\nfunction applyDeltaToDelta(\n base: Delta<string>[],\n diff: Delta<string>[],\n): Delta<string>[] {\n const baseText = base\n .map(op => (op.insert !== undefined ? op.insert : \"\"))\n .join(\"\")\n const nextText = applyTextDelta(baseText, diff)\n return nextText ? [{ insert: nextText }] : []\n}\n","import type { TextContainerShape } from \"../shape.js\"\nimport { INTERNAL_SYMBOL, TypedRef, type TypedRefParams } from \"./base.js\"\nimport { TextRefInternals } from \"./text-ref-internals.js\"\n\n/**\n * Text typed ref - thin facade that delegates to TextRefInternals.\n */\nexport class TextRef extends TypedRef<TextContainerShape> {\n [INTERNAL_SYMBOL]: TextRefInternals\n\n constructor(params: TypedRefParams<TextContainerShape>) {\n super()\n this[INTERNAL_SYMBOL] = new TextRefInternals(params)\n }\n\n /** Insert text at the given index */\n insert(index: number, content: string): void {\n this[INTERNAL_SYMBOL].insert(index, content)\n }\n\n /** Delete text at the given index */\n delete(index: number, len: number): void {\n this[INTERNAL_SYMBOL].delete(index, len)\n }\n\n /** Update the entire text content */\n update(text: string): void {\n this[INTERNAL_SYMBOL].update(text)\n }\n\n /** Mark a range of text with a key-value pair */\n mark(range: { start: number; end: number }, key: string, value: any): void {\n this[INTERNAL_SYMBOL].mark(range, key, value)\n }\n\n /** Remove a mark from a range of text */\n unmark(range: { start: number; end: number }, key: string): void {\n this[INTERNAL_SYMBOL].unmark(range, key)\n }\n\n /** Apply a delta to the text */\n applyDelta(delta: any[]): void {\n this[INTERNAL_SYMBOL].applyDelta(delta)\n }\n\n /** Get the text as a string */\n toString(): string {\n return this[INTERNAL_SYMBOL].getStringValue()\n }\n\n valueOf(): string {\n return this.toString()\n }\n\n toJSON(): string {\n return this.toString()\n }\n\n [Symbol.toPrimitive](_hint: string): string {\n return this.toString()\n }\n\n /** Get the text as a delta */\n toDelta(): any[] {\n return this[INTERNAL_SYMBOL].toDelta()\n }\n\n /** Get the length of the text */\n get length(): number {\n return this[INTERNAL_SYMBOL].getLength()\n }\n}\n","import type {\n LoroDoc,\n LoroEventBatch,\n LoroTreeNode,\n Subscription,\n} from \"loro-crdt\"\nimport { deriveShapePlaceholder } from \"../derive-placeholder.js\"\nimport type { LoroTreeNodeRef } from \"../loro.js\"\nimport type { StructContainerShape } from \"../shape.js\"\nimport type { Infer } from \"../types.js\"\nimport {\n INTERNAL_SYMBOL,\n type RefInternalsBase,\n type TypedRefParams,\n} from \"./base.js\"\nimport { createStructRef, type StructRef } from \"./struct-ref.js\"\nimport type { TreeNodeRef, TreeNodeRefParams } from \"./tree-node-ref.js\"\n\n// Forward declaration to avoid circular import\n// TreeRef will be passed in via constructor params\nexport interface TreeRefLike<DataShape extends StructContainerShape> {\n getOrCreateNodeRef(node: LoroTreeNode): TreeNodeRef<DataShape>\n}\n\n/**\n * Internal implementation for TreeNodeRef.\n * Contains all logic, state, and implementation details.\n */\nexport class TreeNodeRefInternals<DataShape extends StructContainerShape>\n implements RefInternalsBase\n{\n private dataRef: StructRef<DataShape[\"shapes\"]> | undefined\n private loroNamespace: LoroTreeNodeRef | undefined\n\n constructor(private readonly params: TreeNodeRefParams<DataShape>) {}\n\n /** Get the underlying LoroTreeNode */\n getNode(): LoroTreeNode {\n return this.params.node\n }\n\n /** Get the data shape for this node */\n getDataShape(): DataShape {\n return this.params.dataShape\n }\n\n /** Get the parent TreeRef */\n getTreeRef(): TreeRefLike<DataShape> {\n return this.params.treeRef\n }\n\n /** Check if autoCommit is enabled */\n getAutoCommit(): boolean {\n return this.params.autoCommit ?? false\n }\n\n /** Check if in batched mutation mode */\n getBatchedMutation(): boolean {\n return this.params.batchedMutation ?? false\n }\n\n /** Get the LoroDoc */\n getDoc(): LoroDoc {\n return this.params.getDoc()\n }\n\n /** Commit changes if autoCommit is enabled */\n commitIfAuto(): void {\n if (this.params.autoCommit) {\n this.params.getDoc().commit()\n }\n }\n\n /** Get or create the data StructRef */\n getOrCreateDataRef(): StructRef<DataShape[\"shapes\"]> {\n if (!this.dataRef) {\n const node = this.getNode()\n const dataShape = this.getDataShape()\n\n // Get the node's data container (LoroMap)\n const dataContainer = (node as any).data\n\n if (!dataContainer) {\n throw new Error(`Node ${node.id} has no data container`)\n }\n\n // Create placeholder from the data shape\n const placeholder = deriveShapePlaceholder(dataShape) as Infer<DataShape>\n\n const refParams: TypedRefParams<\n StructContainerShape<DataShape[\"shapes\"]>\n > = {\n shape: {\n _type: \"struct\" as const,\n shapes: dataShape.shapes,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as any,\n },\n placeholder: placeholder as any,\n getContainer: () => dataContainer,\n autoCommit: this.getAutoCommit(),\n batchedMutation: this.getBatchedMutation(),\n getDoc: this.params.getDoc,\n }\n\n this.dataRef = createStructRef(refParams)\n }\n return this.dataRef\n }\n\n /** Absorb mutated plain values back into Loro containers */\n absorbPlainValues(): void {\n if (this.dataRef) {\n this.dataRef[INTERNAL_SYMBOL].absorbPlainValues()\n }\n }\n\n /** Force materialization of the container and its nested containers */\n materialize(): void {\n // Ensure data ref is created and materialized\n const dataRef = this.getOrCreateDataRef()\n dataRef[INTERNAL_SYMBOL].materialize()\n }\n\n /** Get the loro namespace (cached) */\n getLoroNamespace(): LoroTreeNodeRef {\n if (!this.loroNamespace) {\n this.loroNamespace = this.createLoroNamespace()\n }\n return this.loroNamespace\n }\n\n /** Create the loro namespace for tree node */\n protected createLoroNamespace(): LoroTreeNodeRef {\n const self = this\n return {\n get doc(): LoroDoc {\n return self.getDoc()\n },\n get container(): LoroTreeNode {\n return self.getNode()\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n // LoroTreeNode doesn't have subscribe, but we can subscribe to the tree\n // However, LoroRefBase expects subscribe.\n // For now, we can throw or return a dummy subscription if LoroTreeNode doesn't support it.\n // But wait, LoroTreeNode is just a handle.\n // Let's check if LoroTreeNode has subscribe.\n // If not, we might need to subscribe to the tree and filter?\n // Or maybe we just cast it if it exists at runtime.\n return (self.getNode() as any).subscribe?.(callback) || (() => {})\n },\n }\n }\n}\n","import type { LoroDoc, LoroTreeNode, TreeID } from \"loro-crdt\"\nimport { LORO_SYMBOL, type LoroTreeNodeRef } from \"../loro.js\"\nimport type { StructContainerShape } from \"../shape.js\"\nimport type { Infer } from \"../types.js\"\nimport { INTERNAL_SYMBOL } from \"./base.js\"\nimport type { StructRef } from \"./struct-ref.js\"\nimport {\n TreeNodeRefInternals,\n type TreeRefLike,\n} from \"./tree-node-ref-internals.js\"\n\nexport interface TreeNodeRefParams<DataShape extends StructContainerShape> {\n node: LoroTreeNode\n dataShape: DataShape\n treeRef: TreeRefLike<DataShape>\n autoCommit?: boolean\n batchedMutation?: boolean\n getDoc: () => LoroDoc\n}\n\n/**\n * Typed ref for a single tree node - thin facade that delegates to TreeNodeRefInternals.\n * Provides type-safe access to node metadata via the `.data` property.\n *\n * **Note:** TreeNodeRef is not a subclass of TypedRef, but it implements\n * `[INTERNAL_SYMBOL]: RefInternalsBase` for consistency with other refs.\n * This allows internal code to call `absorbPlainValues()` uniformly\n * across all ref types during the `change()` commit phase.\n *\n * @example\n * ```typescript\n * const node = tree.createNode({ name: \"idle\", facts: {} })\n * node.data.name = \"active\" // Typed access\n * const child = node.createNode({ name: \"running\", facts: {} })\n * ```\n */\nexport class TreeNodeRef<DataShape extends StructContainerShape> {\n [INTERNAL_SYMBOL]: TreeNodeRefInternals<DataShape>\n\n constructor(params: TreeNodeRefParams<DataShape>) {\n this[INTERNAL_SYMBOL] = new TreeNodeRefInternals(params)\n }\n\n /**\n * Access the loro() namespace via the well-known symbol.\n */\n get [LORO_SYMBOL](): LoroTreeNodeRef {\n return this[INTERNAL_SYMBOL].getLoroNamespace()\n }\n\n /**\n * The unique TreeID of this node.\n */\n get id(): TreeID {\n return this[INTERNAL_SYMBOL].getNode().id\n }\n\n /**\n * Typed access to the node's metadata.\n * This is a StructRef wrapping the node's LoroMap data container.\n */\n get data(): StructRef<DataShape[\"shapes\"]> & {\n [K in keyof DataShape[\"shapes\"]]: DataShape[\"shapes\"][K][\"_mutable\"]\n } {\n return this[INTERNAL_SYMBOL].getOrCreateDataRef() as StructRef<\n DataShape[\"shapes\"]\n > & {\n [K in keyof DataShape[\"shapes\"]]: DataShape[\"shapes\"][K][\"_mutable\"]\n }\n }\n\n /**\n * Create a child node under this node.\n *\n * @param initialData - Optional partial data to initialize the child with\n * @param index - Optional position among siblings\n * @returns The created child TreeNodeRef\n */\n createNode(\n initialData?: Partial<Infer<DataShape>>,\n index?: number,\n ): TreeNodeRef<DataShape> {\n const node = this[INTERNAL_SYMBOL].getNode()\n const treeRef = this[INTERNAL_SYMBOL].getTreeRef()\n\n // Create child node - Loro's createNode on a tree node creates a child\n const loroNode = (node as any).createNode(index)\n const nodeRef = treeRef.getOrCreateNodeRef(loroNode)\n\n // Initialize data if provided\n if (initialData) {\n for (const [key, value] of Object.entries(initialData)) {\n ;(nodeRef.data as any)[key] = value\n }\n }\n\n this[INTERNAL_SYMBOL].commitIfAuto()\n return nodeRef\n }\n\n /**\n * Get the parent node, if any.\n */\n parent(): TreeNodeRef<DataShape> | undefined {\n const node = this[INTERNAL_SYMBOL].getNode()\n const treeRef = this[INTERNAL_SYMBOL].getTreeRef()\n\n const parentNode = (node as any).parent?.()\n if (!parentNode) return undefined\n return treeRef.getOrCreateNodeRef(parentNode)\n }\n\n /**\n * Get all child nodes in order.\n */\n children(): TreeNodeRef<DataShape>[] {\n const node = this[INTERNAL_SYMBOL].getNode()\n const treeRef = this[INTERNAL_SYMBOL].getTreeRef()\n\n const childNodes = (node as any).children?.() || []\n return childNodes.map((n: LoroTreeNode) => treeRef.getOrCreateNodeRef(n))\n }\n\n /**\n * Move this node to a new parent.\n *\n * @param newParent - The new parent node (undefined for root)\n * @param index - Optional position among siblings\n */\n move(newParent?: TreeNodeRef<DataShape>, index?: number): void {\n const node = this[INTERNAL_SYMBOL].getNode()\n\n // node.move takes a LoroTreeNode or undefined, not an ID\n const parentNode = newParent\n ? newParent[INTERNAL_SYMBOL].getNode()\n : undefined\n ;(node as any).move?.(parentNode, index)\n this[INTERNAL_SYMBOL].commitIfAuto()\n }\n\n /**\n * Move this node to be after the given sibling.\n */\n moveAfter(sibling: TreeNodeRef<DataShape>): void {\n const node = this[INTERNAL_SYMBOL].getNode()\n const siblingNode = sibling[INTERNAL_SYMBOL].getNode()\n\n node.moveAfter(siblingNode)\n this[INTERNAL_SYMBOL].commitIfAuto()\n }\n\n /**\n * Move this node to be before the given sibling.\n */\n moveBefore(sibling: TreeNodeRef<DataShape>): void {\n const node = this[INTERNAL_SYMBOL].getNode()\n const siblingNode = sibling[INTERNAL_SYMBOL].getNode()\n\n node.moveBefore(siblingNode)\n this[INTERNAL_SYMBOL].commitIfAuto()\n }\n\n /**\n * Get the index of this node among its siblings.\n */\n index(): number | undefined {\n const node = this[INTERNAL_SYMBOL].getNode()\n return node.index()\n }\n\n /**\n * Get the fractional index string for ordering.\n */\n fractionalIndex(): string | undefined {\n const node = this[INTERNAL_SYMBOL].getNode()\n return node.fractionalIndex()\n }\n\n /**\n * Check if this node has been deleted.\n */\n isDeleted(): boolean {\n const node = this[INTERNAL_SYMBOL].getNode()\n return node.isDeleted()\n }\n\n /**\n * Serialize this node and its descendants to JSON.\n */\n toJSON(): {\n id: TreeID\n parent: TreeID | null\n index: number\n fractionalIndex: string\n data: Infer<DataShape>\n children: any[]\n } {\n const children = this.children()\n return {\n id: this.id,\n parent: this.parent()?.id ?? null,\n index: this.index() ?? 0,\n fractionalIndex: this.fractionalIndex() ?? \"\",\n data: this.data.toJSON() as Infer<DataShape>,\n children: children.map(child => child.toJSON()),\n }\n }\n}\n","import type {\n LoroDoc,\n LoroEventBatch,\n LoroTree,\n LoroTreeNode,\n Subscription,\n TreeID,\n} from \"loro-crdt\"\nimport type { LoroTreeRef } from \"../loro.js\"\nimport type { StructContainerShape, TreeContainerShape } from \"../shape.js\"\nimport { BaseRefInternals, INTERNAL_SYMBOL } from \"./base.js\"\nimport { TreeNodeRef } from \"./tree-node-ref.js\"\nimport type { TreeRef } from \"./tree-ref.js\"\n\n/**\n * Internal implementation for TreeRef.\n * Contains all logic, state, and implementation details.\n */\nexport class TreeRefInternals<\n DataShape extends StructContainerShape,\n> extends BaseRefInternals<TreeContainerShape<DataShape>> {\n private nodeCache = new Map<TreeID, TreeNodeRef<DataShape>>()\n private treeRef: TreeRef<DataShape> | null = null\n\n /** Set the parent TreeRef (needed for creating node refs) */\n setTreeRef(treeRef: TreeRef<DataShape>): void {\n this.treeRef = treeRef\n }\n\n /** Get the data shape for tree nodes */\n getDataShape(): DataShape {\n const shape = this.getShape() as TreeContainerShape<DataShape>\n return shape.shape\n }\n\n /** Get or create a node ref for a LoroTreeNode */\n getOrCreateNodeRef(node: LoroTreeNode): TreeNodeRef<DataShape> {\n const id = node.id\n\n if (!this.treeRef) {\n throw new Error(\"treeRef required\")\n }\n\n let nodeRef = this.nodeCache.get(id)\n if (!nodeRef) {\n nodeRef = new TreeNodeRef({\n node,\n dataShape: this.getDataShape(),\n treeRef: this.treeRef,\n autoCommit: this.getAutoCommit(),\n batchedMutation: this.getBatchedMutation(),\n getDoc: () => this.getDoc(),\n })\n this.nodeCache.set(id, nodeRef)\n }\n\n return nodeRef\n }\n\n /** Get a node by its ID */\n getNodeByID(id: TreeID): TreeNodeRef<DataShape> | undefined {\n // Check cache first\n const cached = this.nodeCache.get(id)\n if (cached) return cached\n\n const container = this.getContainer() as LoroTree\n\n // Check if node exists in tree\n if (!container.has(id)) return undefined\n\n // Find the node in the tree's nodes\n const nodes = container.nodes()\n const node = nodes.find(n => n.id === id)\n if (!node) return undefined\n\n return this.getOrCreateNodeRef(node)\n }\n\n /** Delete a node from the tree */\n delete(target: TreeID | TreeNodeRef<DataShape>): void {\n const id = typeof target === \"string\" ? target : target.id\n const container = this.getContainer() as LoroTree\n container.delete(id)\n // Remove from cache\n this.nodeCache.delete(id)\n this.commitIfAuto()\n }\n\n /** Absorb mutated plain values back into Loro containers */\n absorbPlainValues(): void {\n for (const nodeRef of this.nodeCache.values()) {\n nodeRef[INTERNAL_SYMBOL].absorbPlainValues()\n }\n }\n\n /** Create the loro namespace for tree */\n protected override createLoroNamespace(): LoroTreeRef {\n const self = this\n return {\n get doc(): LoroDoc {\n return self.getDoc()\n },\n get container(): LoroTree {\n return self.getContainer() as LoroTree\n },\n subscribe(callback: (event: LoroEventBatch) => void): Subscription {\n return (self.getContainer() as LoroTree).subscribe(callback)\n },\n }\n }\n}\n","import type { LoroTree, LoroTreeNode, TreeID } from \"loro-crdt\"\nimport type {\n StructContainerShape,\n TreeContainerShape,\n TreeNodeJSON,\n} from \"../shape.js\"\nimport type { Infer } from \"../types.js\"\nimport { INTERNAL_SYMBOL, TypedRef, type TypedRefParams } from \"./base.js\"\nimport type { TreeNodeRef } from \"./tree-node-ref.js\"\nimport { TreeRefInternals } from \"./tree-ref-internals.js\"\n\n/**\n * Typed ref for tree (forest) containers - thin facade that delegates to TreeRefInternals.\n * Wraps LoroTree with type-safe access to node metadata.\n *\n * @example\n * ```typescript\n * const StateNodeDataShape = Shape.struct({\n * name: Shape.text(),\n * facts: Shape.record(Shape.plain.any()),\n * })\n *\n * doc.change(draft => {\n * const root = draft.states.createNode({ name: \"idle\", facts: {} })\n * const child = root.createNode({ name: \"running\", facts: {} })\n * child.data.name = \"active\"\n * })\n * ```\n */\nexport class TreeRef<DataShape extends StructContainerShape> extends TypedRef<\n TreeContainerShape<DataShape>\n> {\n [INTERNAL_SYMBOL]: TreeRefInternals<DataShape>\n\n constructor(params: TypedRefParams<TreeContainerShape<DataShape>>) {\n super()\n this[INTERNAL_SYMBOL] = new TreeRefInternals(params)\n this[INTERNAL_SYMBOL].setTreeRef(this)\n }\n\n /**\n * Get the data shape for tree nodes.\n */\n private get dataShape(): DataShape {\n return this[INTERNAL_SYMBOL].getDataShape()\n }\n\n /**\n * Get or create a node ref for a LoroTreeNode.\n */\n getOrCreateNodeRef(node: LoroTreeNode): TreeNodeRef<DataShape> {\n return this[INTERNAL_SYMBOL].getOrCreateNodeRef(node)\n }\n\n /**\n * Get a node by its ID.\n */\n getNodeByID(id: TreeID): TreeNodeRef<DataShape> | undefined {\n return this[INTERNAL_SYMBOL].getNodeByID(id)\n }\n\n /**\n * Delete a node from the tree.\n */\n delete(target: TreeID | TreeNodeRef<DataShape>): void {\n this[INTERNAL_SYMBOL].delete(target)\n }\n\n /**\n * Serialize the tree to a nested JSON structure.\n * Each node includes its data and children recursively.\n */\n toJSON(): Infer<TreeContainerShape<DataShape>> {\n // Use Loro's native toJSON which returns nested structure\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroTree\n const nativeJson = container.toJSON() as any[]\n return this.transformNativeJson(nativeJson) as Infer<\n TreeContainerShape<DataShape>\n >\n }\n\n /**\n * Create a new root node with optional initial data.\n *\n * @param initialData - Optional partial data to initialize the node with\n * @returns The created TreeNodeRef\n */\n createNode(initialData?: Partial<Infer<DataShape>>): TreeNodeRef<DataShape> {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroTree\n const loroNode = container.createNode()\n const nodeRef = this.getOrCreateNodeRef(loroNode)\n\n // Initialize data if provided\n if (initialData) {\n for (const [key, value] of Object.entries(initialData)) {\n ;(nodeRef.data as any)[key] = value\n }\n }\n\n this[INTERNAL_SYMBOL].commitIfAuto()\n return nodeRef\n }\n\n /**\n * Get all root nodes (nodes without parents).\n * Returns nodes in their fractional index order.\n */\n roots(): TreeNodeRef<DataShape>[] {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroTree\n return container.roots().map(node => this.getOrCreateNodeRef(node))\n }\n\n /**\n * Get all nodes in the tree (unordered).\n * By default, excludes deleted nodes (tombstones).\n *\n * @param options.includeDeleted - If true, includes deleted nodes. Default: false.\n * @returns Array of TreeNodeRef for matching nodes\n */\n nodes(options?: { includeDeleted?: boolean }): TreeNodeRef<DataShape>[] {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroTree\n const allNodes = container.nodes()\n const filtered = options?.includeDeleted\n ? allNodes\n : allNodes.filter(node => !node.isDeleted())\n return filtered.map(node => this.getOrCreateNodeRef(node))\n }\n\n /**\n * Check if a node with the given ID exists in the tree.\n */\n has(id: TreeID): boolean {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroTree\n return container.has(id)\n }\n\n /**\n * Enable fractional index generation for ordering.\n *\n * @param jitter - Optional jitter value to avoid conflicts (0 = no jitter)\n */\n enableFractionalIndex(jitter = 0): void {\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroTree\n container.enableFractionalIndex(jitter)\n }\n\n /**\n * Transform Loro's native JSON format to our typed format.\n */\n private transformNativeJson(nodes: any[]): TreeNodeJSON<DataShape>[] {\n return nodes.map(node => ({\n id: node.id as TreeID,\n parent: node.parent as TreeID | null,\n index: node.index as number,\n fractionalIndex: node.fractional_index as string,\n data: node.meta as Infer<DataShape>,\n children: this.transformNativeJson(node.children || []),\n }))\n }\n\n /**\n * Get a flat array representation of all nodes.\n * Flattens the nested tree structure into a single array.\n */\n toArray(): Array<{\n id: TreeID\n parent: TreeID | null\n index: number\n fractionalIndex: string\n data: Infer<DataShape>\n }> {\n const result: Array<{\n id: TreeID\n parent: TreeID | null\n index: number\n fractionalIndex: string\n data: Infer<DataShape>\n }> = []\n\n // Flatten the nested structure\n const flattenNodes = (nodes: any[]) => {\n for (const node of nodes) {\n result.push({\n id: node.id as TreeID,\n parent: node.parent as TreeID | null,\n index: node.index as number,\n fractionalIndex: node.fractional_index as string,\n data: node.meta as Infer<DataShape>,\n })\n if (node.children && node.children.length > 0) {\n flattenNodes(node.children)\n }\n }\n }\n\n const container = this[INTERNAL_SYMBOL].getContainer() as LoroTree\n const nativeJson = container.toJSON() as any[]\n flattenNodes(nativeJson)\n return result\n }\n}\n","import type { LoroDoc } from \"loro-crdt\"\nimport type { Infer } from \"../index.js\"\nimport type { ContainerShape, DocShape } from \"../shape.js\"\nimport {\n BaseRefInternals,\n INTERNAL_SYMBOL,\n type TypedRef,\n type TypedRefParams,\n} from \"./base.js\"\nimport { createContainerTypedRef } from \"./utils.js\"\n\nconst containerGetter = {\n counter: \"getCounter\",\n list: \"getList\",\n movableList: \"getMovableList\",\n record: \"getMap\",\n struct: \"getMap\", // Structs use LoroMap as their underlying container\n text: \"getText\",\n tree: \"getTree\",\n} as const satisfies Record<string, keyof LoroDoc>\n\ntype ContainerGetterKey = keyof typeof containerGetter\n\n/**\n * Internal implementation for DocRef.\n * Contains all logic, state, and implementation details.\n */\nexport class DocRefInternals<\n Shape extends DocShape,\n> extends BaseRefInternals<Shape> {\n private propertyCache = new Map<string, TypedRef<ContainerShape>>()\n private doc: LoroDoc\n private requiredPlaceholder: Infer<Shape>\n\n constructor(\n params: Omit<TypedRefParams<Shape>, \"getContainer\" | \"getDoc\"> & {\n doc: LoroDoc\n autoCommit?: boolean\n batchedMutation?: boolean\n },\n ) {\n super({\n ...params,\n getContainer: () => {\n throw new Error(\"can't get container on DocRef\")\n },\n getDoc: () => params.doc,\n } as TypedRefParams<Shape>)\n\n this.doc = params.doc\n this.requiredPlaceholder = params.placeholder as Infer<Shape>\n }\n\n /** Get typed ref params for creating child refs at a key */\n getChildTypedRefParams(\n key: string,\n shape: ContainerShape,\n ): TypedRefParams<ContainerShape> {\n // Handle \"any\" shape type - it's an escape hatch that doesn't have a specific getter\n if (shape._type === \"any\") {\n throw new Error(\n `Cannot get typed ref params for \"any\" shape type. ` +\n `The \"any\" shape is an escape hatch for untyped containers and should be accessed directly via loroDoc.`,\n )\n }\n\n const getterName = containerGetter[shape._type as ContainerGetterKey]\n const getter = this.doc[getterName].bind(this.doc)\n\n return {\n shape,\n placeholder: this.requiredPlaceholder[key],\n getContainer: () => getter(key),\n autoCommit: this.getAutoCommit(),\n batchedMutation: this.getBatchedMutation(),\n getDoc: () => this.doc,\n overlay: this.getOverlay(),\n }\n }\n\n /** Get or create a typed ref for a key */\n getOrCreateTypedRef(\n key: string,\n shape: ContainerShape,\n ): TypedRef<ContainerShape> | number | string {\n let ref = this.propertyCache.get(key)\n\n if (!ref) {\n ref = createContainerTypedRef(this.getChildTypedRefParams(key, shape))\n this.propertyCache.set(key, ref)\n }\n\n return ref\n }\n\n /** Absorb mutated plain values back into Loro containers */\n absorbPlainValues(): void {\n // By iterating over the propertyCache, we achieve a small optimization\n // by only absorbing values that have been 'touched' in some way\n for (const [, ref] of this.propertyCache.entries()) {\n ref[INTERNAL_SYMBOL].absorbPlainValues()\n }\n }\n}\n","import type { LoroDoc } from \"loro-crdt\"\nimport type { Infer } from \"../index.js\"\nimport type { DocShape } from \"../shape.js\"\nimport { INTERNAL_SYMBOL, TypedRef, type TypedRefParams } from \"./base.js\"\nimport { DocRefInternals } from \"./doc-ref-internals.js\"\nimport { serializeRefToJSON } from \"./utils.js\"\n\n/**\n * Doc Ref class - thin facade that delegates to DocRefInternals.\n * The actual object passed to the change `mutation` function.\n */\nexport class DocRef<Shape extends DocShape> extends TypedRef<Shape> {\n [INTERNAL_SYMBOL]: DocRefInternals<Shape>\n\n constructor(\n params: Omit<TypedRefParams<Shape>, \"getContainer\" | \"getDoc\"> & {\n doc: LoroDoc\n autoCommit?: boolean\n batchedMutation?: boolean\n },\n ) {\n super()\n if (!params.placeholder) throw new Error(\"placeholder required\")\n this[INTERNAL_SYMBOL] = new DocRefInternals(params)\n this.createLazyProperties()\n }\n\n private createLazyProperties(): void {\n const shape = this[INTERNAL_SYMBOL].getShape() as DocShape\n for (const key in shape.shapes) {\n const containerShape = shape.shapes[key]\n Object.defineProperty(this, key, {\n get: () =>\n this[INTERNAL_SYMBOL].getOrCreateTypedRef(key, containerShape),\n enumerable: true,\n })\n }\n }\n\n toJSON(): Infer<Shape> {\n const shape = this[INTERNAL_SYMBOL].getShape() as DocShape\n return serializeRefToJSON(\n this as any,\n Object.keys(shape.shapes),\n ) as Infer<Shape>\n }\n}\n","import type {\n ArrayValueShape,\n ContainerOrValueShape,\n DiscriminatedUnionValueShape,\n DocShape,\n ListContainerShape,\n MovableListContainerShape,\n RecordContainerShape,\n RecordValueShape,\n StringValueShape,\n StructContainerShape,\n StructValueShape,\n UnionValueShape,\n ValueShape,\n} from \"./shape.js\"\nimport type { Infer } from \"./types.js\"\n\n/**\n * Validates a value against a ContainerShape or ValueShape schema\n */\nexport function validateValue(\n value: unknown,\n schema: ContainerOrValueShape,\n path: string = \"\",\n): unknown {\n if (!schema || typeof schema !== \"object\" || !(\"_type\" in schema)) {\n throw new Error(`Invalid schema at path ${path}: missing _type`)\n }\n\n const currentPath = path || \"root\"\n\n // Handle AnyContainerShape - no validation, accept anything\n if (schema._type === \"any\") {\n return value\n }\n\n // Handle ContainerShape types\n if (schema._type === \"text\") {\n if (typeof value !== \"string\") {\n throw new Error(\n `Expected string at path ${currentPath}, got ${typeof value}`,\n )\n }\n return value\n }\n\n if (schema._type === \"counter\") {\n if (typeof value !== \"number\") {\n throw new Error(\n `Expected number at path ${currentPath}, got ${typeof value}`,\n )\n }\n return value\n }\n\n if (schema._type === \"list\" || schema._type === \"movableList\") {\n if (!Array.isArray(value)) {\n throw new Error(\n `Expected array at path ${currentPath}, got ${typeof value}`,\n )\n }\n const listSchema = schema as ListContainerShape | MovableListContainerShape\n return value.map((item, index) =>\n validateValue(item, listSchema.shape, `${currentPath}[${index}]`),\n )\n }\n\n if (schema._type === \"struct\") {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(\n `Expected object at path ${currentPath}, got ${typeof value}`,\n )\n }\n const structSchema = schema as StructContainerShape\n const result: Record<string, unknown> = {}\n\n // Validate each property in the struct shape\n for (const [key, nestedSchema] of Object.entries(structSchema.shapes)) {\n const nestedPath = `${currentPath}.${key}`\n const nestedValue = (value as Record<string, unknown>)[key]\n result[key] = validateValue(nestedValue, nestedSchema, nestedPath)\n }\n return result\n }\n\n if (schema._type === \"record\") {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(\n `Expected object at path ${currentPath}, got ${typeof value}`,\n )\n }\n const recordSchema = schema as RecordContainerShape\n const result: Record<string, unknown> = {}\n\n // Validate each property in the record\n for (const [key, nestedValue] of Object.entries(value)) {\n const nestedPath = `${currentPath}.${key}`\n result[key] = validateValue(nestedValue, recordSchema.shape, nestedPath)\n }\n return result\n }\n\n if (schema._type === \"tree\") {\n if (!Array.isArray(value)) {\n throw new Error(\n `Expected array for tree at path ${currentPath}, got ${typeof value}`,\n )\n }\n // Trees can contain any structure, so we just validate it's an array\n return value\n }\n\n // Handle ValueShape types\n if (schema._type === \"value\") {\n const valueSchema = schema as ValueShape\n\n switch (valueSchema.valueType) {\n // AnyValueShape - no validation, accept anything\n case \"any\":\n return value\n\n case \"string\": {\n if (typeof value !== \"string\") {\n throw new Error(\n `Expected string at path ${currentPath}, got ${typeof value}`,\n )\n }\n const stringSchema = valueSchema as StringValueShape\n if (stringSchema.options && !stringSchema.options.includes(value)) {\n throw new Error(\n `Expected one of [${stringSchema.options.join(\", \")}] at path ${currentPath}, got \"${value}\"`,\n )\n }\n return value\n }\n\n case \"number\":\n if (typeof value !== \"number\") {\n throw new Error(\n `Expected number at path ${currentPath}, got ${typeof value}`,\n )\n }\n return value\n\n case \"boolean\":\n if (typeof value !== \"boolean\") {\n throw new Error(\n `Expected boolean at path ${currentPath}, got ${typeof value}`,\n )\n }\n return value\n\n case \"null\":\n if (value !== null) {\n throw new Error(\n `Expected null at path ${currentPath}, got ${typeof value}`,\n )\n }\n return value\n\n case \"undefined\":\n if (value !== undefined) {\n throw new Error(\n `Expected undefined at path ${currentPath}, got ${typeof value}`,\n )\n }\n return value\n\n case \"uint8array\":\n if (!(value instanceof Uint8Array)) {\n throw new Error(\n `Expected Uint8Array at path ${currentPath}, got ${typeof value}`,\n )\n }\n return value\n\n case \"struct\": {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(\n `Expected object at path ${currentPath}, got ${typeof value}`,\n )\n }\n const structSchema = valueSchema as StructValueShape\n const result: Record<string, unknown> = {}\n\n // Validate each property in the struct shape\n for (const [key, nestedSchema] of Object.entries(structSchema.shape)) {\n const nestedPath = `${currentPath}.${key}`\n const nestedValue = (value as Record<string, unknown>)[key]\n result[key] = validateValue(nestedValue, nestedSchema, nestedPath)\n }\n return result\n }\n\n case \"record\": {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(\n `Expected object at path ${currentPath}, got ${typeof value}`,\n )\n }\n const recordSchema = valueSchema as RecordValueShape\n const result: Record<string, unknown> = {}\n\n // Validate each property in the record\n for (const [key, nestedValue] of Object.entries(value)) {\n const nestedPath = `${currentPath}.${key}`\n result[key] = validateValue(\n nestedValue,\n recordSchema.shape,\n nestedPath,\n )\n }\n return result\n }\n\n case \"array\": {\n if (!Array.isArray(value)) {\n throw new Error(\n `Expected array at path ${currentPath}, got ${typeof value}`,\n )\n }\n const arraySchema = valueSchema as ArrayValueShape\n return value.map((item, index) =>\n validateValue(item, arraySchema.shape, `${currentPath}[${index}]`),\n )\n }\n\n case \"union\": {\n const unionSchema = valueSchema as UnionValueShape\n let lastError: Error | null = null\n\n // Try to validate against each shape in the union\n for (const shape of unionSchema.shapes) {\n try {\n return validateValue(value, shape, currentPath)\n } catch (error) {\n lastError = error as Error\n }\n }\n\n throw new Error(\n `Value at path ${currentPath} does not match any union type: ${lastError?.message}`,\n )\n }\n\n case \"discriminatedUnion\": {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(\n `Expected object at path ${currentPath}, got ${typeof value}`,\n )\n }\n\n const unionSchema = valueSchema as DiscriminatedUnionValueShape\n const discriminantKey = unionSchema.discriminantKey\n const discriminantValue = (value as Record<string, unknown>)[\n discriminantKey\n ]\n\n if (typeof discriminantValue !== \"string\") {\n throw new Error(\n `Expected string for discriminant key \"${discriminantKey}\" at path ${currentPath}, got ${typeof discriminantValue}`,\n )\n }\n\n const variantSchema = unionSchema.variants[discriminantValue]\n\n if (!variantSchema) {\n throw new Error(\n `Invalid discriminant value \"${discriminantValue}\" at path ${currentPath}. Expected one of: ${Object.keys(\n unionSchema.variants,\n ).join(\", \")}`,\n )\n }\n\n return validateValue(value, variantSchema, currentPath)\n }\n\n default:\n throw new Error(`Unknown value type: ${(valueSchema as any).valueType}`)\n }\n }\n\n throw new Error(`Unknown schema type: ${(schema as any)._type}`)\n}\n\n/**\n * Validates placeholder against schema structure without using Zod\n * Combines the functionality of createPlaceholderValidator and createValueValidator\n */\nexport function validatePlaceholder<T extends DocShape>(\n placeholder: unknown,\n schema: T,\n): Infer<T> {\n if (\n !placeholder ||\n typeof placeholder !== \"object\" ||\n Array.isArray(placeholder)\n ) {\n throw new Error(\"Placeholder must be an object\")\n }\n\n const result: Record<string, unknown> = {}\n\n // Validate each property in the document schema\n for (const [key, schemaValue] of Object.entries(schema.shapes)) {\n const value = (placeholder as Record<string, unknown>)[key]\n result[key] = validateValue(value, schemaValue, key)\n }\n\n return result as Infer<T>\n}\n","// ============================================================================\n// Path Builder Factory\n// ============================================================================\n//\n// Runtime implementation of the path builder that creates PathSelector objects\n// with proper segments for JSONPath compilation.\n\nimport type { PathBuilder, PathSegment, PathSelector } from \"./path-selector.js\"\nimport type { ContainerOrValueShape, DocShape } from \"./shape.js\"\n\nfunction createPathSelector<T>(segments: PathSegment[]): PathSelector<T> {\n return {\n __resultType: undefined as unknown as T,\n __segments: segments,\n }\n}\n\nfunction createPathNode(\n shape: ContainerOrValueShape,\n segments: PathSegment[],\n): unknown {\n const selector = createPathSelector(segments)\n\n // Terminal shapes (text, counter, value)\n if (shape._type === \"text\" || shape._type === \"counter\") {\n return selector\n }\n if (shape._type === \"value\") {\n return selector\n }\n\n // List/MovableList\n if (shape._type === \"list\" || shape._type === \"movableList\") {\n return Object.assign(selector, {\n get $each() {\n return createPathNode(shape.shape, [...segments, { type: \"each\" }])\n },\n $at(index: number) {\n return createPathNode(shape.shape, [\n ...segments,\n { type: \"index\", index },\n ])\n },\n get $first() {\n return createPathNode(shape.shape, [\n ...segments,\n { type: \"index\", index: 0 },\n ])\n },\n get $last() {\n return createPathNode(shape.shape, [\n ...segments,\n { type: \"index\", index: -1 },\n ])\n },\n })\n }\n\n // Struct (fixed keys)\n if (shape._type === \"struct\") {\n const props: Record<string, unknown> = {}\n for (const key in shape.shapes) {\n Object.defineProperty(props, key, {\n get() {\n return createPathNode(shape.shapes[key], [\n ...segments,\n { type: \"property\", key },\n ])\n },\n enumerable: true,\n })\n }\n return Object.assign(selector, props)\n }\n\n // Record (dynamic keys)\n if (shape._type === \"record\") {\n return Object.assign(selector, {\n get $each() {\n return createPathNode(shape.shape, [...segments, { type: \"each\" }])\n },\n $key(key: string) {\n return createPathNode(shape.shape, [...segments, { type: \"key\", key }])\n },\n })\n }\n\n return selector\n}\n\n/**\n * Creates a path builder for a given document shape.\n *\n * The path builder provides a type-safe DSL for selecting paths within\n * a document. The resulting PathSelector can be compiled to a JSONPath\n * string for use with subscribeJsonpath.\n *\n * @example\n * ```typescript\n * const docShape = Shape.doc({\n * books: Shape.list(Shape.struct({\n * title: Shape.text(),\n * price: Shape.plain.number(),\n * })),\n * })\n *\n * const builder = createPathBuilder(docShape)\n * const selector = builder.books.$each.title\n * // selector.__segments = [\n * // { type: \"property\", key: \"books\" },\n * // { type: \"each\" },\n * // { type: \"property\", key: \"title\" }\n * // ]\n * ```\n */\nexport function createPathBuilder<D extends DocShape>(\n docShape: D,\n): PathBuilder<D> {\n const builder: Record<string, unknown> = {}\n\n for (const key in docShape.shapes) {\n Object.defineProperty(builder, key, {\n get() {\n return createPathNode(docShape.shapes[key], [{ type: \"property\", key }])\n },\n enumerable: true,\n })\n }\n\n return builder as PathBuilder<D>\n}\n","// ============================================================================\n// JSONPath Compiler\n// ============================================================================\n//\n// Compiles PathSelector segments to JSONPath strings for use with\n// subscribeJsonpath.\n\nimport type { PathSegment } from \"./path-selector.js\"\n\n/**\n * Compiles path segments to a JSONPath string.\n *\n * @example\n * ```typescript\n * const segments = [\n * { type: \"property\", key: \"books\" },\n * { type: \"each\" },\n * { type: \"property\", key: \"title\" }\n * ]\n * compileToJsonPath(segments) // => '$.books[*].title'\n * ```\n */\nexport function compileToJsonPath(segments: PathSegment[]): string {\n let path = \"$\"\n\n for (const segment of segments) {\n switch (segment.type) {\n case \"property\":\n // Use dot notation for simple identifiers, bracket notation for safety\n if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(segment.key)) {\n path += `.${segment.key}`\n } else {\n path += `[\"${escapeJsonPathKey(segment.key)}\"]`\n }\n break\n case \"each\":\n path += \"[*]\"\n break\n case \"index\":\n path += `[${segment.index}]`\n break\n case \"key\":\n path += `[\"${escapeJsonPathKey(segment.key)}\"]`\n break\n }\n }\n\n return path\n}\n\n/**\n * Escapes special characters in a JSONPath key.\n */\nfunction escapeJsonPathKey(key: string): string {\n return key.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')\n}\n\n/**\n * Check if the path contains any wildcard segments.\n * Paths with wildcards need deep equality checking for change detection.\n */\nexport function hasWildcard(segments: PathSegment[]): boolean {\n return segments.some(s => s.type === \"each\")\n}\n","// ============================================================================\n// Path Evaluator\n// ============================================================================\n//\n// Evaluates a path selector against a TypedDoc to get the current value.\n// This is used for:\n// 1. Establishing the initial previousValue baseline\n// 2. Getting the current value when subscribeJsonpath fires\n// 3. Deep equality comparison to filter false positives\n\nimport type { PathSegment, PathSelector } from \"./path-selector.js\"\nimport type { DocShape } from \"./shape.js\"\nimport type { TypedDoc } from \"./typed-doc.js\"\n\n/**\n * Evaluate a path selector against a TypedDoc to get the current value.\n * Returns the value(s) at the path, properly typed.\n *\n * @example\n * ```typescript\n * const selector = builder.books.$each.title\n * const titles = evaluatePath(doc, selector)\n * // titles: string[]\n * ```\n */\nexport function evaluatePath<D extends DocShape, T>(\n doc: TypedDoc<D>,\n selector: PathSelector<T>,\n): T {\n const json = doc.toJSON()\n return evaluatePathOnValue(json, selector.__segments) as T\n}\n\n/**\n * Evaluate path segments against a plain JavaScript value.\n * This is the core recursive evaluation logic.\n */\nexport function evaluatePathOnValue(\n value: unknown,\n segments: PathSegment[],\n): unknown {\n if (segments.length === 0) {\n return value\n }\n\n const [segment, ...rest] = segments\n\n switch (segment.type) {\n case \"property\":\n case \"key\":\n if (value == null) return undefined\n if (typeof value !== \"object\") return undefined\n return evaluatePathOnValue(\n (value as Record<string, unknown>)[segment.key],\n rest,\n )\n\n case \"index\": {\n if (!Array.isArray(value)) return undefined\n // Handle negative indices: -1 = last, -2 = second-to-last, etc.\n const index =\n segment.index < 0 ? value.length + segment.index : segment.index\n if (index < 0 || index >= value.length) return undefined\n return evaluatePathOnValue(value[index], rest)\n }\n\n case \"each\":\n if (Array.isArray(value)) {\n return value.map(item => evaluatePathOnValue(item, rest))\n }\n if (typeof value === \"object\" && value !== null) {\n return Object.values(value).map(item => evaluatePathOnValue(item, rest))\n }\n return []\n }\n}\n","/**\n * Creates a proxy around a placeholder value (plain object/array) that mimics\n * the behavior of TypedRef, specifically adding a .toJSON() method.\n *\n * This ensures consistent UX where users can call .toJSON() on document state\n * regardless of whether it's loading (placeholder) or loaded (live ref).\n */\nexport function createPlaceholderProxy<T extends object>(target: T): T {\n // Cache for wrapped properties to ensure referential stability\n const cache = new Map<string | symbol, any>()\n\n return new Proxy(target, {\n get(target, prop, receiver) {\n // Intercept .toJSON()\n if (prop === \"toJSON\") {\n return () => target\n }\n\n // Check cache first\n if (cache.has(prop)) {\n return cache.get(prop)\n }\n\n // Get value from target\n const value = Reflect.get(target, prop, receiver)\n\n // Recursively wrap objects/arrays\n if (value && typeof value === \"object\") {\n const wrapped = createPlaceholderProxy(value)\n cache.set(prop, wrapped)\n return wrapped\n }\n\n return value\n },\n })\n}\n","import type {\n Container,\n ContainerID,\n CounterDiff,\n Diff,\n ListDiff,\n LoroCounter,\n LoroDoc,\n LoroList,\n LoroMap,\n LoroMovableList,\n LoroText,\n LoroTree,\n MapDiff,\n TextDiff,\n TreeDiff,\n TreeDiffItem,\n Value,\n} from \"loro-crdt\"\n\n/**\n * Replay a diff as local operations on a document.\n *\n * Unlike doc.import() which creates import events, this creates LOCAL events\n * that are captured by subscribeLocalUpdates() and UndoManager.\n *\n * @param doc - The target document to apply changes to\n * @param diff - The diff from doc.diff(from, to, false)\n */\nexport function replayDiff(doc: LoroDoc, diff: [ContainerID, Diff][]): void {\n // Map from source container IDs to target containers\n // This is needed because when we create new containers, they get different IDs\n const containerMap = new Map<ContainerID, Container>()\n\n for (const [containerId, containerDiff] of diff) {\n // First, try to get the container from our map (for newly created containers)\n let container = containerMap.get(containerId)\n\n // If not in map, try to get it from the doc (for existing containers)\n if (!container) {\n container = doc.getContainerById(containerId)\n }\n\n if (!container) {\n // Container doesn't exist yet - this can happen for newly created containers\n // that haven't been mapped yet. Skip for now, it will be created when\n // processing the parent container's diff.\n continue\n }\n\n switch (containerDiff.type) {\n case \"text\":\n replayTextDiff(container as LoroText, containerDiff)\n break\n case \"list\":\n replayListDiff(\n container as LoroList | LoroMovableList,\n containerDiff,\n containerMap,\n )\n break\n case \"map\":\n replayMapDiff(container as LoroMap, containerDiff, containerMap)\n break\n case \"tree\":\n replayTreeDiff(container as LoroTree, containerDiff)\n break\n case \"counter\":\n replayCounterDiff(container as LoroCounter, containerDiff)\n break\n }\n }\n}\n\n/**\n * Replay text diff operations\n */\nfunction replayTextDiff(text: LoroText, diff: TextDiff): void {\n // LoroText has applyDelta which handles the delta format directly\n text.applyDelta(diff.diff)\n}\n\n/**\n * Replay list diff operations\n */\nfunction replayListDiff(\n list: LoroList | LoroMovableList,\n diff: ListDiff,\n containerMap: Map<ContainerID, Container>,\n): void {\n let index = 0\n\n for (const delta of diff.diff) {\n if (delta.retain !== undefined) {\n // Retain: skip over existing elements\n index += delta.retain\n } else if (delta.delete !== undefined) {\n // Delete: remove elements at current position\n list.delete(index, delta.delete)\n // Don't advance index - next operation is at same position\n } else if (delta.insert !== undefined) {\n // Insert: add elements at current position\n const values = delta.insert\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n if (isContainer(value)) {\n // For containers, we need to insert a new container of the same type\n // The container's contents will be handled by its own diff entry\n const newContainer = createContainerOfSameType(value)\n const insertedContainer = (list as LoroList).insertContainer(\n index + i,\n newContainer,\n )\n // Map the source container ID to the newly created container\n containerMap.set(value.id, insertedContainer)\n } else {\n ;(list as LoroList).insert(\n index + i,\n value as Exclude<Value, Container>,\n )\n }\n }\n index += values.length\n }\n }\n}\n\n/**\n * Replay map diff operations\n */\nfunction replayMapDiff(\n map: LoroMap,\n diff: MapDiff,\n containerMap: Map<ContainerID, Container>,\n): void {\n for (const [key, value] of Object.entries(diff.updated)) {\n if (value === undefined) {\n // Delete the key\n map.delete(key)\n } else if (isContainer(value)) {\n // Set a container - create a new one of the same type\n const newContainer = createContainerOfSameType(value)\n const insertedContainer = map.setContainer(key, newContainer)\n // Map the source container ID to the newly created container\n containerMap.set(value.id, insertedContainer)\n } else {\n // Set a primitive value\n map.set(key, value as Exclude<Value, Container>)\n }\n }\n}\n\n/**\n * Replay tree diff operations\n */\nfunction replayTreeDiff(tree: LoroTree, diff: TreeDiff): void {\n for (const item of diff.diff) {\n replayTreeDiffItem(tree, item)\n }\n}\n\n/**\n * Replay a single tree diff item\n */\nfunction replayTreeDiffItem(tree: LoroTree, item: TreeDiffItem): void {\n switch (item.action) {\n case \"create\":\n // Create a new node under the specified parent\n // Note: The node ID is determined by the CRDT, we can't specify it\n // This means we're creating a NEW node, not recreating the exact same one\n tree.createNode(item.parent, item.index)\n break\n case \"delete\":\n // Delete the node\n tree.delete(item.target)\n break\n case \"move\":\n // Move the node to a new parent/position\n tree.move(item.target, item.parent, item.index)\n break\n }\n}\n\n/**\n * Replay counter diff operations\n */\nfunction replayCounterDiff(counter: LoroCounter, diff: CounterDiff): void {\n if (diff.increment > 0) {\n counter.increment(diff.increment)\n } else if (diff.increment < 0) {\n counter.decrement(-diff.increment)\n }\n // If increment is 0, no operation needed\n}\n\n/**\n * Check if a value is a Container\n */\nfunction isContainer(value: Value | Container): value is Container {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"kind\" in value &&\n typeof (value as Container).kind === \"function\"\n )\n}\n\n/**\n * Create a new detached container of the same type as the given container\n */\nfunction createContainerOfSameType(container: Container): Container {\n const kind = container.kind()\n switch (kind) {\n case \"List\":\n return new (container.constructor as new () => LoroList)()\n case \"Map\":\n return new (container.constructor as new () => LoroMap)()\n case \"Text\":\n return new (container.constructor as new () => LoroText)()\n case \"Tree\":\n return new (container.constructor as new () => LoroTree)()\n case \"Counter\":\n return new (container.constructor as new () => LoroCounter)()\n case \"MovableList\":\n return new (container.constructor as new () => LoroMovableList)()\n default:\n throw new Error(`Unknown container kind: ${kind}`)\n }\n}\n","// biome-ignore-all lint/suspicious/noExplicitAny: required\n\nimport type {\n LoroCounter,\n LoroList,\n LoroMap,\n LoroMovableList,\n LoroText,\n LoroTree,\n TreeID,\n Value,\n} from \"loro-crdt\"\n\nimport { LORO_SYMBOL, type LoroTreeRef } from \"./loro.js\"\nimport type { CounterRef } from \"./typed-refs/counter-ref.js\"\nimport type { ListRef } from \"./typed-refs/list-ref.js\"\nimport type { MovableListRef } from \"./typed-refs/movable-list-ref.js\"\nimport type { RecordRef } from \"./typed-refs/record-ref.js\"\nimport type { StructRef } from \"./typed-refs/struct-ref.js\"\nimport type { TextRef } from \"./typed-refs/text-ref.js\"\nimport type { TreeNodeRef } from \"./typed-refs/tree-node-ref.js\"\n\nexport interface Shape<Plain, Mutable, Placeholder = Plain> {\n readonly _type: string\n readonly _plain: Plain\n readonly _mutable: Mutable\n readonly _placeholder: Placeholder\n}\n\n// Type for shapes that support placeholder customization\nexport type WithPlaceholder<S extends Shape<any, any, any>> = S & {\n placeholder(value: S[\"_placeholder\"]): S\n}\n\n/**\n * Type for value shapes that support the .nullable() method.\n * Returns a union of null and the original shape with null as the default placeholder.\n */\nexport type WithNullable<S extends ValueShape> = {\n nullable(): WithPlaceholder<UnionValueShape<[NullValueShape, S]>>\n}\n\nexport interface DocShape<\n NestedShapes extends Record<string, ContainerShape> = Record<\n string,\n ContainerShape\n >,\n> extends Shape<\n { [K in keyof NestedShapes]: NestedShapes[K][\"_plain\"] },\n { [K in keyof NestedShapes]: NestedShapes[K][\"_mutable\"] },\n { [K in keyof NestedShapes]: NestedShapes[K][\"_placeholder\"] }\n > {\n readonly _type: \"doc\"\n // A doc's root containers each separately has its own shape, hence 'shapes'\n readonly shapes: NestedShapes\n}\n\nexport interface TextContainerShape extends Shape<string, TextRef, string> {\n readonly _type: \"text\"\n}\nexport interface CounterContainerShape\n extends Shape<number, CounterRef, number> {\n readonly _type: \"counter\"\n}\n/**\n * JSON representation of a tree node with typed data.\n * Used for serialization (toJSON) of tree structures.\n */\nexport type TreeNodeJSON<DataShape extends StructContainerShape> = {\n id: TreeID\n parent: TreeID | null\n index: number\n fractionalIndex: string\n data: DataShape[\"_plain\"]\n children: TreeNodeJSON<DataShape>[]\n}\n\n/**\n * Interface describing the TreeRef API for use in shape definitions.\n * This avoids circular type references that would occur with the TreeRef class.\n * @internal\n */\nexport interface TreeRefInterface<DataShape extends StructContainerShape> {\n /** Get or create a node ref for a LoroTreeNode */\n getOrCreateNodeRef(node: unknown): TreeNodeRef<DataShape>\n /** Get a node by its ID */\n getNodeByID(id: TreeID): TreeNodeRef<DataShape> | undefined\n /** Delete a node from the tree */\n delete(target: TreeID | TreeNodeRef<DataShape>): void\n /** Serialize the tree to a nested JSON structure */\n toJSON(): TreeNodeJSON<DataShape>[]\n /** Create a new root node with optional initial data */\n createNode(initialData?: Partial<DataShape[\"_plain\"]>): TreeNodeRef<DataShape>\n /** Get all root nodes (nodes without parents) */\n roots(): TreeNodeRef<DataShape>[]\n /** Get all nodes in the tree (unordered). By default excludes deleted nodes. */\n nodes(options?: { includeDeleted?: boolean }): TreeNodeRef<DataShape>[]\n /** Check if a node with the given ID exists in the tree */\n has(id: TreeID): boolean\n /** Enable fractional index generation for ordering */\n enableFractionalIndex(jitter?: number): void\n /** Get a flat array representation of all nodes */\n toArray(): Array<{\n id: TreeID\n parent: TreeID | null\n index: number\n fractionalIndex: string\n data: DataShape[\"_plain\"]\n }>\n\n /**\n * Access CRDT internals via the well-known symbol.\n */\n readonly [LORO_SYMBOL]: LoroTreeRef\n}\n\n/**\n * Container shape for tree (forest) structures.\n * Each node in the tree has typed metadata stored in a LoroMap.\n *\n * @example\n * ```typescript\n * const StateNodeDataShape = Shape.struct({\n * name: Shape.text(),\n * facts: Shape.record(Shape.plain.any()),\n * })\n *\n * const Schema = Shape.doc({\n * states: Shape.tree(StateNodeDataShape),\n * })\n * ```\n */\nexport interface TreeContainerShape<\n DataShape extends StructContainerShape = StructContainerShape,\n> extends Shape<\n TreeNodeJSON<DataShape>[],\n TreeRefInterface<DataShape>,\n never[]\n > {\n readonly _type: \"tree\"\n /**\n * The shape of each node's data (metadata).\n * This is a StructContainerShape that defines the typed properties on node.data.\n */\n readonly shape: DataShape\n}\n\n// Container schemas using interfaces for recursive references\n// NOTE: List and Record use never[] and Record<string, never> for Placeholder\n// to enforce that only empty values ([] and {}) are valid in placeholder state.\n// This prevents users from expecting per-entry merging behavior.\nexport interface ListContainerShape<\n NestedShape extends ContainerOrValueShape = ContainerOrValueShape,\n> extends Shape<NestedShape[\"_plain\"][], ListRef<NestedShape>, never[]> {\n readonly _type: \"list\"\n // A list contains many elements, all of the same 'shape'\n readonly shape: NestedShape\n}\n\nexport interface MovableListContainerShape<\n NestedShape extends ContainerOrValueShape = ContainerOrValueShape,\n> extends Shape<NestedShape[\"_plain\"][], MovableListRef<NestedShape>, never[]> {\n readonly _type: \"movableList\"\n // A list contains many elements, all of the same 'shape'\n readonly shape: NestedShape\n}\n\n/**\n * @deprecated Use StructContainerShape instead. MapContainerShape is an alias for backward compatibility.\n */\nexport type MapContainerShape<\n NestedShapes extends Record<string, ContainerOrValueShape> = Record<\n string,\n ContainerOrValueShape\n >,\n> = StructContainerShape<NestedShapes>\n\n/**\n * Container shape for objects with fixed keys (structs).\n * This is the preferred way to define fixed-key objects.\n * Uses LoroMap as the underlying container.\n */\nexport interface StructContainerShape<\n NestedShapes extends Record<string, ContainerOrValueShape> = Record<\n string,\n ContainerOrValueShape\n >,\n> extends Shape<\n { [K in keyof NestedShapes]: NestedShapes[K][\"_plain\"] },\n StructRef<NestedShapes>,\n { [K in keyof NestedShapes]: NestedShapes[K][\"_placeholder\"] }\n > {\n readonly _type: \"struct\"\n // Each struct property has its own shape, hence 'shapes'\n readonly shapes: NestedShapes\n}\n\nexport interface RecordContainerShape<\n NestedShape extends ContainerOrValueShape = ContainerOrValueShape,\n> extends Shape<\n Record<string, NestedShape[\"_plain\"]>,\n RecordRef<NestedShape>,\n Record<string, never>\n > {\n readonly _type: \"record\"\n readonly shape: NestedShape\n}\n\n/**\n * Container escape hatch - represents \"any LoroContainer\".\n * Use this when integrating with external libraries that manage their own document structure.\n *\n * @example\n * ```typescript\n * // loro-prosemirror manages its own structure\n * const ProseMirrorDocShape = Shape.doc({\n * doc: Shape.any(), // opt out of typing for this container\n * })\n * ```\n */\nexport interface AnyContainerShape extends Shape<unknown, unknown, undefined> {\n readonly _type: \"any\"\n}\n\n/**\n * Union of all container shape types.\n *\n * Each container shape has a `_mutable` type parameter that maps to the\n * corresponding TypedRef class (e.g., TextContainerShape → TextRef).\n * This enables deriving ref types from shapes:\n *\n * ```typescript\n * // Get the ref type for any container shape\n * type RefType = ContainerShape[\"_mutable\"]\n *\n * // Exclude AnyContainerShape to get only typed refs\n * type AnyTypedRef = Exclude<ContainerShape, AnyContainerShape>[\"_mutable\"]\n * ```\n *\n * This creates intentional parallel hierarchies:\n * - ContainerShape → defines what data looks like (schema)\n * - TypedRef (via _mutable) → defines how you interact with data\n * - loro() overloads → CRDT escape hatch (IDE DX)\n * - change() overloads → mutation boundaries (IDE DX)\n */\nexport type ContainerShape =\n | AnyContainerShape\n | CounterContainerShape\n | ListContainerShape\n | MovableListContainerShape\n | RecordContainerShape\n | StructContainerShape\n | TextContainerShape\n | TreeContainerShape\n\nexport type ContainerType = ContainerShape[\"_type\"]\n\n// LoroValue shape types - a shape for each of Loro's Value types\nexport interface StringValueShape<T extends string = string>\n extends Shape<T, T, T> {\n readonly _type: \"value\"\n readonly valueType: \"string\"\n readonly options?: T[]\n}\nexport interface NumberValueShape extends Shape<number, number, number> {\n readonly _type: \"value\"\n readonly valueType: \"number\"\n}\nexport interface BooleanValueShape extends Shape<boolean, boolean, boolean> {\n readonly _type: \"value\"\n readonly valueType: \"boolean\"\n}\nexport interface NullValueShape extends Shape<null, null, null> {\n readonly _type: \"value\"\n readonly valueType: \"null\"\n}\nexport interface UndefinedValueShape\n extends Shape<undefined, undefined, undefined> {\n readonly _type: \"value\"\n readonly valueType: \"undefined\"\n}\nexport interface Uint8ArrayValueShape\n extends Shape<Uint8Array, Uint8Array, Uint8Array> {\n readonly _type: \"value\"\n readonly valueType: \"uint8array\"\n}\n\n/**\n * @deprecated Use StructValueShape instead. ObjectValueShape is an alias for backward compatibility.\n */\nexport type ObjectValueShape<\n T extends Record<string, ValueShape> = Record<string, ValueShape>,\n> = StructValueShape<T>\n\n/**\n * Value shape for objects with fixed keys (structs).\n * This is the preferred way to define fixed-key plain value objects.\n * Identical structure to ObjectValueShape but with valueType: \"struct\".\n */\nexport interface StructValueShape<\n T extends Record<string, ValueShape> = Record<string, ValueShape>,\n> extends Shape<\n { [K in keyof T]: T[K][\"_plain\"] },\n { [K in keyof T]: T[K][\"_mutable\"] },\n { [K in keyof T]: T[K][\"_placeholder\"] }\n > {\n readonly _type: \"value\"\n readonly valueType: \"struct\"\n readonly shape: T\n}\n\n// NOTE: RecordValueShape and ArrayValueShape use Record<string, never> and never[]\n// for Placeholder to enforce that only empty values ({} and []) are valid.\nexport interface RecordValueShape<T extends ValueShape = ValueShape>\n extends Shape<\n Record<string, T[\"_plain\"]>,\n Record<string, T[\"_mutable\"]>,\n Record<string, never>\n > {\n readonly _type: \"value\"\n readonly valueType: \"record\"\n readonly shape: T\n}\n\nexport interface ArrayValueShape<T extends ValueShape = ValueShape>\n extends Shape<T[\"_plain\"][], T[\"_mutable\"][], never[]> {\n readonly _type: \"value\"\n readonly valueType: \"array\"\n readonly shape: T\n}\n\nexport interface UnionValueShape<T extends ValueShape[] = ValueShape[]>\n extends Shape<\n T[number][\"_plain\"],\n T[number][\"_mutable\"],\n T[number][\"_placeholder\"]\n > {\n readonly _type: \"value\"\n readonly valueType: \"union\"\n readonly shapes: T\n}\n\n/**\n * A discriminated union shape that uses a discriminant key to determine which variant to use.\n * This enables type-safe handling of tagged unions like:\n *\n * ```typescript\n * type GamePresence =\n * | { type: \"client\"; name: string; input: { force: number; angle: number } }\n * | { type: \"server\"; cars: Record<string, CarState>; tick: number }\n * ```\n *\n * @typeParam K - The discriminant key (e.g., \"type\")\n * @typeParam T - A record mapping discriminant values to their object shapes\n */\nexport interface DiscriminatedUnionValueShape<\n K extends string = string,\n T extends Record<string, StructValueShape> = Record<string, StructValueShape>,\n Plain = T[keyof T][\"_plain\"],\n Mutable = T[keyof T][\"_mutable\"],\n Placeholder = T[keyof T][\"_placeholder\"],\n> extends Shape<Plain, Mutable, Placeholder> {\n readonly _type: \"value\"\n readonly valueType: \"discriminatedUnion\"\n readonly discriminantKey: K\n readonly variants: T\n}\n\n/**\n * Value escape hatch - represents \"any Loro Value\".\n * Use this when you need to accept any valid Loro value type.\n *\n * @example\n * ```typescript\n * const FlexiblePresenceShape = Shape.plain.struct({\n * cursor: Shape.plain.any(), // accept any value type\n * })\n * ```\n */\nexport interface AnyValueShape extends Shape<Value, Value, undefined> {\n readonly _type: \"value\"\n readonly valueType: \"any\"\n}\n\n// Union of all ValueShapes - these can only contain other ValueShapes, not ContainerShapes\nexport type ValueShape =\n | AnyValueShape\n | ArrayValueShape\n | BooleanValueShape\n | DiscriminatedUnionValueShape\n | NullValueShape\n | NumberValueShape\n | RecordValueShape\n | StringValueShape\n | StructValueShape\n | Uint8ArrayValueShape\n | UndefinedValueShape\n | UnionValueShape\n\nexport type ContainerOrValueShape = ContainerShape | ValueShape\n\n/**\n * Creates a nullable version of a value shape.\n * @internal\n */\nfunction makeNullable<S extends ValueShape>(\n shape: S,\n): WithPlaceholder<UnionValueShape<[NullValueShape, S]>> {\n const nullShape: NullValueShape = {\n _type: \"value\" as const,\n valueType: \"null\" as const,\n _plain: null,\n _mutable: null,\n _placeholder: null,\n }\n\n const base: UnionValueShape<[NullValueShape, S]> = {\n _type: \"value\" as const,\n valueType: \"union\" as const,\n shapes: [nullShape, shape] as [NullValueShape, S],\n _plain: null as any,\n _mutable: null as any,\n _placeholder: null as any, // Default placeholder is null\n }\n\n return Object.assign(base, {\n placeholder(\n value: S[\"_placeholder\"] | null,\n ): UnionValueShape<[NullValueShape, S]> {\n return { ...base, _placeholder: value } as UnionValueShape<\n [NullValueShape, S]\n >\n },\n })\n}\n\n/**\n * The LoroShape factory object\n *\n * If a container has a `shape` type variable, it refers to the shape it contains--\n * so for example, a `LoroShape.list(LoroShape.text())` would return a value of type\n * `ListContainerShape<TextContainerShape>`.\n */\nexport const Shape = {\n doc: <T extends Record<string, ContainerShape>>(shape: T): DocShape<T> => ({\n _type: \"doc\" as const,\n shapes: shape,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as any,\n }),\n\n /**\n * Creates an \"any\" container shape - an escape hatch for untyped containers.\n * Use this when integrating with external libraries that manage their own document structure.\n *\n * @example\n * ```typescript\n * // loro-prosemirror manages its own structure\n * const ProseMirrorDocShape = Shape.doc({\n * doc: Shape.any(), // opt out of typing for this container\n * })\n *\n * const handle = repo.get(docId, ProseMirrorDocShape, CursorPresenceShape)\n * // handle.doc.doc is typed as `unknown` - you're on your own\n * ```\n */\n any: (): AnyContainerShape => ({\n _type: \"any\" as const,\n _plain: undefined as unknown,\n _mutable: undefined as unknown,\n _placeholder: undefined,\n }),\n\n // CRDTs are represented by Loro Containers--they converge on state using Loro's\n // various CRDT algorithms\n counter: (): WithPlaceholder<CounterContainerShape> => {\n const base: CounterContainerShape = {\n _type: \"counter\" as const,\n _plain: 0,\n _mutable: {} as CounterRef,\n _placeholder: 0,\n }\n return Object.assign(base, {\n placeholder(value: number): CounterContainerShape {\n return { ...base, _placeholder: value }\n },\n })\n },\n\n list: <T extends ContainerOrValueShape>(shape: T): ListContainerShape<T> => ({\n _type: \"list\" as const,\n shape,\n _plain: [] as any,\n _mutable: {} as any,\n _placeholder: [] as never[],\n }),\n\n /**\n * Creates a struct container shape for objects with fixed keys.\n * This is the preferred way to define fixed-key objects.\n *\n * @example\n * ```typescript\n * const UserSchema = Shape.doc({\n * user: Shape.struct({\n * name: Shape.text(),\n * age: Shape.counter(),\n * }),\n * })\n * ```\n */\n struct: <T extends Record<string, ContainerOrValueShape>>(\n shape: T,\n ): StructContainerShape<T> => ({\n _type: \"struct\" as const,\n shapes: shape,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as any,\n }),\n\n /**\n * @deprecated Use `Shape.struct` instead. `Shape.struct` will be removed in a future version.\n */\n map: <T extends Record<string, ContainerOrValueShape>>(\n shape: T,\n ): StructContainerShape<T> => ({\n _type: \"struct\" as const,\n shapes: shape,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as any,\n }),\n\n record: <T extends ContainerOrValueShape>(\n shape: T,\n ): RecordContainerShape<T> => ({\n _type: \"record\" as const,\n shape,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as Record<string, never>,\n }),\n\n movableList: <T extends ContainerOrValueShape>(\n shape: T,\n ): MovableListContainerShape<T> => ({\n _type: \"movableList\" as const,\n shape,\n _plain: [] as any,\n _mutable: {} as any,\n _placeholder: [] as never[],\n }),\n\n text: (): WithPlaceholder<TextContainerShape> => {\n const base: TextContainerShape = {\n _type: \"text\" as const,\n _plain: \"\",\n _mutable: {} as TextRef,\n _placeholder: \"\",\n }\n return Object.assign(base, {\n placeholder(value: string): TextContainerShape {\n return { ...base, _placeholder: value }\n },\n })\n },\n\n /**\n * Creates a tree container shape for hierarchical data structures.\n * Each node in the tree has typed metadata defined by the data shape.\n *\n * @example\n * ```typescript\n * const StateNodeDataShape = Shape.struct({\n * name: Shape.text(),\n * facts: Shape.record(Shape.plain.any()),\n * })\n *\n * const Schema = Shape.doc({\n * states: Shape.tree(StateNodeDataShape),\n * })\n *\n * doc.change(draft => {\n * const root = draft.states.createNode({ name: \"idle\", facts: {} })\n * const child = root.createNode({ name: \"running\", facts: {} })\n * child.data.name = \"active\"\n * })\n * ```\n */\n tree: <T extends StructContainerShape>(shape: T): TreeContainerShape<T> => ({\n _type: \"tree\" as const,\n shape,\n _plain: [] as any,\n _mutable: {} as any,\n _placeholder: [] as never[],\n }),\n\n // Values are represented as plain JS objects, with the limitation that they MUST be\n // representable as a Loro \"Value\"--basically JSON. The behavior of a Value is basically\n // \"Last Write Wins\", meaning there is no subtle convergent behavior here, just taking\n // the most recent value based on the current available information.\n plain: {\n string: <T extends string = string>(\n ...options: T[]\n ): WithPlaceholder<StringValueShape<T>> &\n WithNullable<StringValueShape<T>> => {\n const base: StringValueShape<T> = {\n _type: \"value\" as const,\n valueType: \"string\" as const,\n _plain: (options[0] ?? \"\") as T,\n _mutable: (options[0] ?? \"\") as T,\n _placeholder: (options[0] ?? \"\") as T,\n options: options.length > 0 ? options : undefined,\n }\n return Object.assign(base, {\n placeholder(value: T): StringValueShape<T> {\n return { ...base, _placeholder: value }\n },\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, StringValueShape<T>]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n number: (): WithPlaceholder<NumberValueShape> &\n WithNullable<NumberValueShape> => {\n const base: NumberValueShape = {\n _type: \"value\" as const,\n valueType: \"number\" as const,\n _plain: 0,\n _mutable: 0,\n _placeholder: 0,\n }\n return Object.assign(base, {\n placeholder(value: number): NumberValueShape {\n return { ...base, _placeholder: value }\n },\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, NumberValueShape]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n boolean: (): WithPlaceholder<BooleanValueShape> &\n WithNullable<BooleanValueShape> => {\n const base: BooleanValueShape = {\n _type: \"value\" as const,\n valueType: \"boolean\" as const,\n _plain: false,\n _mutable: false,\n _placeholder: false,\n }\n return Object.assign(base, {\n placeholder(value: boolean): BooleanValueShape {\n return { ...base, _placeholder: value }\n },\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, BooleanValueShape]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n null: (): NullValueShape => ({\n _type: \"value\" as const,\n valueType: \"null\" as const,\n _plain: null,\n _mutable: null,\n _placeholder: null,\n }),\n\n undefined: (): UndefinedValueShape => ({\n _type: \"value\" as const,\n valueType: \"undefined\" as const,\n _plain: undefined,\n _mutable: undefined,\n _placeholder: undefined,\n }),\n\n uint8Array: (): Uint8ArrayValueShape &\n WithNullable<Uint8ArrayValueShape> => {\n const base: Uint8ArrayValueShape = {\n _type: \"value\" as const,\n valueType: \"uint8array\" as const,\n _plain: new Uint8Array(),\n _mutable: new Uint8Array(),\n _placeholder: new Uint8Array(),\n }\n return Object.assign(base, {\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, Uint8ArrayValueShape]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n /**\n * Alias for `uint8Array()` - creates a shape for binary data.\n * Use this for better discoverability when working with binary data like cursor positions.\n *\n * @example\n * ```typescript\n * const CursorPresenceShape = Shape.plain.struct({\n * anchor: Shape.plain.bytes().nullable(),\n * focus: Shape.plain.bytes().nullable(),\n * })\n * ```\n */\n bytes: (): Uint8ArrayValueShape & WithNullable<Uint8ArrayValueShape> => {\n const base: Uint8ArrayValueShape = {\n _type: \"value\" as const,\n valueType: \"uint8array\" as const,\n _plain: new Uint8Array(),\n _mutable: new Uint8Array(),\n _placeholder: new Uint8Array(),\n }\n return Object.assign(base, {\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, Uint8ArrayValueShape]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n /**\n * Creates an \"any\" value shape - an escape hatch for untyped values.\n * Use this when you need to accept any valid Loro value type.\n *\n * @example\n * ```typescript\n * const FlexiblePresenceShape = Shape.plain.struct({\n * metadata: Shape.plain.any(), // accept any value type\n * })\n * ```\n */\n any: (): AnyValueShape => ({\n _type: \"value\" as const,\n valueType: \"any\" as const,\n _plain: undefined as unknown as Value,\n _mutable: undefined as unknown as Value,\n _placeholder: undefined,\n }),\n\n /**\n * Creates a struct value shape for plain objects with fixed keys.\n * This is the preferred way to define fixed-key plain value objects.\n *\n * @example\n * ```typescript\n * const PointSchema = Shape.plain.struct({\n * x: Shape.plain.number(),\n * y: Shape.plain.number(),\n * })\n * ```\n */\n struct: <T extends Record<string, ValueShape>>(\n shape: T,\n ): StructValueShape<T> & WithNullable<StructValueShape<T>> => {\n const base: StructValueShape<T> = {\n _type: \"value\" as const,\n valueType: \"struct\" as const,\n shape,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as any,\n }\n return Object.assign(base, {\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, StructValueShape<T>]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n /**\n * @deprecated Use `Shape.plain.struct` instead. `Shape.plain.struct` will be removed in a future version.\n */\n object: <T extends Record<string, ValueShape>>(\n shape: T,\n ): StructValueShape<T> & WithNullable<StructValueShape<T>> => {\n const base: StructValueShape<T> = {\n _type: \"value\" as const,\n valueType: \"struct\" as const,\n shape,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as any,\n }\n return Object.assign(base, {\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, StructValueShape<T>]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n record: <T extends ValueShape>(\n shape: T,\n ): RecordValueShape<T> & WithNullable<RecordValueShape<T>> => {\n const base: RecordValueShape<T> = {\n _type: \"value\" as const,\n valueType: \"record\" as const,\n shape,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as Record<string, never>,\n }\n return Object.assign(base, {\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, RecordValueShape<T>]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n array: <T extends ValueShape>(\n shape: T,\n ): ArrayValueShape<T> & WithNullable<ArrayValueShape<T>> => {\n const base: ArrayValueShape<T> = {\n _type: \"value\" as const,\n valueType: \"array\" as const,\n shape,\n _plain: [] as any,\n _mutable: [] as any,\n _placeholder: [] as never[],\n }\n return Object.assign(base, {\n nullable(): WithPlaceholder<\n UnionValueShape<[NullValueShape, ArrayValueShape<T>]>\n > {\n return makeNullable(base)\n },\n })\n },\n\n // Special value type that helps make things like `string | null` representable\n // TODO(duane): should this be a more general type for containers too?\n union: <T extends ValueShape[]>(\n shapes: T,\n ): WithPlaceholder<UnionValueShape<T>> => {\n const base: UnionValueShape<T> = {\n _type: \"value\" as const,\n valueType: \"union\" as const,\n shapes,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as any,\n }\n return Object.assign(base, {\n placeholder(value: T[number][\"_placeholder\"]): UnionValueShape<T> {\n return { ...base, _placeholder: value }\n },\n })\n },\n\n /**\n * Creates a discriminated union shape for type-safe tagged unions.\n *\n * @example\n * ```typescript\n * const ClientPresenceShape = Shape.plain.struct({\n * type: Shape.plain.string(\"client\"),\n * name: Shape.plain.string(),\n * input: Shape.plain.struct({ force: Shape.plain.number(), angle: Shape.plain.number() }),\n * })\n *\n * const ServerPresenceShape = Shape.plain.struct({\n * type: Shape.plain.string(\"server\"),\n * cars: Shape.plain.record(Shape.plain.struct({ x: Shape.plain.number(), y: Shape.plain.number() })),\n * tick: Shape.plain.number(),\n * })\n *\n * const GamePresenceSchema = Shape.plain.discriminatedUnion(\"type\", {\n * client: ClientPresenceShape,\n * server: ServerPresenceShape,\n * })\n * ```\n *\n * @param discriminantKey - The key used to discriminate between variants (e.g., \"type\")\n * @param variants - A record mapping discriminant values to their object shapes\n */\n discriminatedUnion: <\n K extends string,\n T extends Record<string, StructValueShape>,\n >(\n discriminantKey: K,\n variants: T,\n ): WithPlaceholder<DiscriminatedUnionValueShape<K, T>> => {\n const base: DiscriminatedUnionValueShape<K, T> = {\n _type: \"value\" as const,\n valueType: \"discriminatedUnion\" as const,\n discriminantKey,\n variants,\n _plain: {} as any,\n _mutable: {} as any,\n _placeholder: {} as any,\n }\n return Object.assign(base, {\n placeholder(\n value: T[keyof T][\"_placeholder\"],\n ): DiscriminatedUnionValueShape<K, T> {\n return { ...base, _placeholder: value }\n },\n })\n },\n },\n}\n\n// Add this type mapping near the top of your file, after the imports\nexport type ShapeToContainer<T extends DocShape | ContainerShape> =\n T extends TextContainerShape\n ? LoroText\n : T extends CounterContainerShape\n ? LoroCounter\n : T extends ListContainerShape\n ? LoroList\n : T extends MovableListContainerShape\n ? LoroMovableList\n : T extends StructContainerShape | RecordContainerShape\n ? LoroMap\n : T extends TreeContainerShape\n ? LoroTree\n : never // not a container\n","const logLevels = [\n \"trace\",\n \"debug\",\n \"info\",\n \"warning\",\n \"error\",\n \"fatal\",\n] as const;\n\n/**\n * The severity level of a {@link LogRecord}.\n */\nexport type LogLevel = typeof logLevels[number];\n\n/**\n * Lists all available log levels with the order of their severity.\n * The `\"trace\"` level goes first, and the `\"fatal\"` level goes last.\n * @returns A new copy of the array of log levels.\n * @since 1.0.0\n */\nexport function getLogLevels(): readonly LogLevel[] {\n return [...logLevels];\n}\n\n/**\n * Parses a log level from a string.\n *\n * @param level The log level as a string. This is case-insensitive.\n * @returns The log level.\n * @throws {TypeError} If the log level is invalid.\n */\nexport function parseLogLevel(level: string): LogLevel {\n level = level.toLowerCase();\n switch (level) {\n case \"trace\":\n case \"debug\":\n case \"info\":\n case \"warning\":\n case \"error\":\n case \"fatal\":\n return level;\n default:\n throw new TypeError(`Invalid log level: ${level}.`);\n }\n}\n\n/**\n * Checks if a string is a valid log level. This function can be used as\n * as a type guard to narrow the type of a string to a {@link LogLevel}.\n *\n * @param level The log level as a string. This is case-sensitive.\n * @returns `true` if the string is a valid log level.\n */\nexport function isLogLevel(level: string): level is LogLevel {\n switch (level) {\n case \"trace\":\n case \"debug\":\n case \"info\":\n case \"warning\":\n case \"error\":\n case \"fatal\":\n return true;\n default:\n return false;\n }\n}\n\n/**\n * Compares two log levels.\n * @param a The first log level.\n * @param b The second log level.\n * @returns A negative number if `a` is less than `b`, a positive number if `a`\n * is greater than `b`, or zero if they are equal.\n * @since 0.8.0\n */\nexport function compareLogLevel(a: LogLevel, b: LogLevel): number {\n const aIndex = logLevels.indexOf(a);\n if (aIndex < 0) {\n throw new TypeError(`Invalid log level: ${JSON.stringify(a)}.`);\n }\n const bIndex = logLevels.indexOf(b);\n if (bIndex < 0) {\n throw new TypeError(`Invalid log level: ${JSON.stringify(b)}.`);\n }\n return aIndex - bIndex;\n}\n","import {\n type ContextLocalStorage,\n getCategoryPrefix,\n getImplicitContext,\n} from \"./context.ts\";\nimport type { Filter } from \"./filter.ts\";\nimport { compareLogLevel, type LogLevel } from \"./level.ts\";\nimport type { LogRecord } from \"./record.ts\";\nimport type { Sink } from \"./sink.ts\";\n\n/**\n * A logger interface. It provides methods to log messages at different\n * severity levels.\n *\n * ```typescript\n * const logger = getLogger(\"category\");\n * logger.trace `A trace message with ${value}`\n * logger.debug `A debug message with ${value}.`;\n * logger.info `An info message with ${value}.`;\n * logger.warn `A warning message with ${value}.`;\n * logger.error `An error message with ${value}.`;\n * logger.fatal `A fatal error message with ${value}.`;\n * ```\n */\nexport interface Logger {\n /**\n * The category of the logger. It is an array of strings.\n */\n readonly category: readonly string[];\n\n /**\n * The logger with the supercategory of the current logger. If the current\n * logger is the root logger, this is `null`.\n */\n readonly parent: Logger | null;\n\n /**\n * Get a child logger with the given subcategory.\n *\n * ```typescript\n * const logger = getLogger(\"category\");\n * const subLogger = logger.getChild(\"sub-category\");\n * ```\n *\n * The above code is equivalent to:\n *\n * ```typescript\n * const logger = getLogger(\"category\");\n * const subLogger = getLogger([\"category\", \"sub-category\"]);\n * ```\n *\n * @param subcategory The subcategory.\n * @returns The child logger.\n */\n getChild(\n subcategory: string | readonly [string] | readonly [string, ...string[]],\n ): Logger;\n\n /**\n * Get a logger with contextual properties. This is useful for\n * log multiple messages with the shared set of properties.\n *\n * ```typescript\n * const logger = getLogger(\"category\");\n * const ctx = logger.with({ foo: 123, bar: \"abc\" });\n * ctx.info(\"A message with {foo} and {bar}.\");\n * ctx.warn(\"Another message with {foo}, {bar}, and {baz}.\", { baz: true });\n * ```\n *\n * The above code is equivalent to:\n *\n * ```typescript\n * const logger = getLogger(\"category\");\n * logger.info(\"A message with {foo} and {bar}.\", { foo: 123, bar: \"abc\" });\n * logger.warn(\n * \"Another message with {foo}, {bar}, and {baz}.\",\n * { foo: 123, bar: \"abc\", baz: true },\n * );\n * ```\n *\n * @param properties\n * @returns\n * @since 0.5.0\n */\n with(properties: Record<string, unknown>): Logger;\n\n /**\n * Log a trace message. Use this as a template string prefix.\n *\n * ```typescript\n * logger.trace `A trace message with ${value}.`;\n * ```\n *\n * @param message The message template strings array.\n * @param values The message template values.\n * @since 0.12.0\n */\n trace(message: TemplateStringsArray, ...values: readonly unknown[]): void;\n\n /**\n * Log a trace message with properties.\n *\n * ```typescript\n * logger.trace('A trace message with {value}.', { value });\n * ```\n *\n * If the properties are expensive to compute, you can pass a callback that\n * returns the properties:\n *\n * ```typescript\n * logger.trace(\n * 'A trace message with {value}.',\n * () => ({ value: expensiveComputation() })\n * );\n * ```\n *\n * @param message The message template. Placeholders to be replaced with\n * `values` are indicated by keys in curly braces (e.g.,\n * `{value}`).\n * @param properties The values to replace placeholders with. For lazy\n * evaluation, this can be a callback that returns the\n * properties.\n * @since 0.12.0\n */\n trace(\n message: string,\n properties?: Record<string, unknown> | (() => Record<string, unknown>),\n ): void;\n\n /**\n * Log a trace values with no message. This is useful when you\n * want to log properties without a message, e.g., when you want to log\n * the context of a request or an operation.\n *\n * ```typescript\n * logger.trace({ method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * Note that this is a shorthand for:\n *\n * ```typescript\n * logger.trace('{*}', { method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * If the properties are expensive to compute, you cannot use this shorthand\n * and should use the following syntax instead:\n *\n * ```typescript\n * logger.trace('{*}', () => ({\n * method: expensiveMethod(),\n * url: expensiveUrl(),\n * }));\n * ```\n *\n * @param properties The values to log. Note that this does not take\n * a callback.\n * @since 0.12.0\n */\n trace(properties: Record<string, unknown>): void;\n\n /**\n * Lazily log a trace message. Use this when the message values are expensive\n * to compute and should only be computed if the message is actually logged.\n *\n * ```typescript\n * logger.trace(l => l`A trace message with ${expensiveValue()}.`);\n * ```\n *\n * @param callback A callback that returns the message template prefix.\n * @throws {TypeError} If no log record was made inside the callback.\n * @since 0.12.0\n */\n trace(callback: LogCallback): void;\n\n /**\n * Log a debug message. Use this as a template string prefix.\n *\n * ```typescript\n * logger.debug `A debug message with ${value}.`;\n * ```\n *\n * @param message The message template strings array.\n * @param values The message template values.\n */\n debug(message: TemplateStringsArray, ...values: readonly unknown[]): void;\n\n /**\n * Log a debug message with properties.\n *\n * ```typescript\n * logger.debug('A debug message with {value}.', { value });\n * ```\n *\n * If the properties are expensive to compute, you can pass a callback that\n * returns the properties:\n *\n * ```typescript\n * logger.debug(\n * 'A debug message with {value}.',\n * () => ({ value: expensiveComputation() })\n * );\n * ```\n *\n * @param message The message template. Placeholders to be replaced with\n * `values` are indicated by keys in curly braces (e.g.,\n * `{value}`).\n * @param properties The values to replace placeholders with. For lazy\n * evaluation, this can be a callback that returns the\n * properties.\n */\n debug(\n message: string,\n properties?: Record<string, unknown> | (() => Record<string, unknown>),\n ): void;\n\n /**\n * Log a debug values with no message. This is useful when you\n * want to log properties without a message, e.g., when you want to log\n * the context of a request or an operation.\n *\n * ```typescript\n * logger.debug({ method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * Note that this is a shorthand for:\n *\n * ```typescript\n * logger.debug('{*}', { method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * If the properties are expensive to compute, you cannot use this shorthand\n * and should use the following syntax instead:\n *\n * ```typescript\n * logger.debug('{*}', () => ({\n * method: expensiveMethod(),\n * url: expensiveUrl(),\n * }));\n * ```\n *\n * @param properties The values to log. Note that this does not take\n * a callback.\n * @since 0.11.0\n */\n debug(properties: Record<string, unknown>): void;\n\n /**\n * Lazily log a debug message. Use this when the message values are expensive\n * to compute and should only be computed if the message is actually logged.\n *\n * ```typescript\n * logger.debug(l => l`A debug message with ${expensiveValue()}.`);\n * ```\n *\n * @param callback A callback that returns the message template prefix.\n * @throws {TypeError} If no log record was made inside the callback.\n */\n debug(callback: LogCallback): void;\n\n /**\n * Log an informational message. Use this as a template string prefix.\n *\n * ```typescript\n * logger.info `An info message with ${value}.`;\n * ```\n *\n * @param message The message template strings array.\n * @param values The message template values.\n */\n info(message: TemplateStringsArray, ...values: readonly unknown[]): void;\n\n /**\n * Log an informational message with properties.\n *\n * ```typescript\n * logger.info('An info message with {value}.', { value });\n * ```\n *\n * If the properties are expensive to compute, you can pass a callback that\n * returns the properties:\n *\n * ```typescript\n * logger.info(\n * 'An info message with {value}.',\n * () => ({ value: expensiveComputation() })\n * );\n * ```\n *\n * @param message The message template. Placeholders to be replaced with\n * `values` are indicated by keys in curly braces (e.g.,\n * `{value}`).\n * @param properties The values to replace placeholders with. For lazy\n * evaluation, this can be a callback that returns the\n * properties.\n */\n info(\n message: string,\n properties?: Record<string, unknown> | (() => Record<string, unknown>),\n ): void;\n\n /**\n * Log an informational values with no message. This is useful when you\n * want to log properties without a message, e.g., when you want to log\n * the context of a request or an operation.\n *\n * ```typescript\n * logger.info({ method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * Note that this is a shorthand for:\n *\n * ```typescript\n * logger.info('{*}', { method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * If the properties are expensive to compute, you cannot use this shorthand\n * and should use the following syntax instead:\n *\n * ```typescript\n * logger.info('{*}', () => ({\n * method: expensiveMethod(),\n * url: expensiveUrl(),\n * }));\n * ```\n *\n * @param properties The values to log. Note that this does not take\n * a callback.\n * @since 0.11.0\n */\n info(properties: Record<string, unknown>): void;\n\n /**\n * Lazily log an informational message. Use this when the message values are\n * expensive to compute and should only be computed if the message is actually\n * logged.\n *\n * ```typescript\n * logger.info(l => l`An info message with ${expensiveValue()}.`);\n * ```\n *\n * @param callback A callback that returns the message template prefix.\n * @throws {TypeError} If no log record was made inside the callback.\n */\n info(callback: LogCallback): void;\n\n /**\n * Log a warning message. Use this as a template string prefix.\n *\n * ```typescript\n * logger.warn `A warning message with ${value}.`;\n * ```\n *\n * @param message The message template strings array.\n * @param values The message template values.\n */\n warn(message: TemplateStringsArray, ...values: readonly unknown[]): void;\n\n /**\n * Log a warning message with properties.\n *\n * ```typescript\n * logger.warn('A warning message with {value}.', { value });\n * ```\n *\n * If the properties are expensive to compute, you can pass a callback that\n * returns the properties:\n *\n * ```typescript\n * logger.warn(\n * 'A warning message with {value}.',\n * () => ({ value: expensiveComputation() })\n * );\n * ```\n *\n * @param message The message template. Placeholders to be replaced with\n * `values` are indicated by keys in curly braces (e.g.,\n * `{value}`).\n * @param properties The values to replace placeholders with. For lazy\n * evaluation, this can be a callback that returns the\n * properties.\n */\n warn(\n message: string,\n properties?: Record<string, unknown> | (() => Record<string, unknown>),\n ): void;\n\n /**\n * Log a warning values with no message. This is useful when you\n * want to log properties without a message, e.g., when you want to log\n * the context of a request or an operation.\n *\n * ```typescript\n * logger.warn({ method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * Note that this is a shorthand for:\n *\n * ```typescript\n * logger.warn('{*}', { method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * If the properties are expensive to compute, you cannot use this shorthand\n * and should use the following syntax instead:\n *\n * ```typescript\n * logger.warn('{*}', () => ({\n * method: expensiveMethod(),\n * url: expensiveUrl(),\n * }));\n * ```\n *\n * @param properties The values to log. Note that this does not take\n * a callback.\n * @since 0.11.0\n */\n warn(properties: Record<string, unknown>): void;\n\n /**\n * Lazily log a warning message. Use this when the message values are\n * expensive to compute and should only be computed if the message is actually\n * logged.\n *\n * ```typescript\n * logger.warn(l => l`A warning message with ${expensiveValue()}.`);\n * ```\n *\n * @param callback A callback that returns the message template prefix.\n * @throws {TypeError} If no log record was made inside the callback.\n */\n warn(callback: LogCallback): void;\n\n /**\n * Log a warning message. Use this as a template string prefix.\n *\n * ```typescript\n * logger.warning `A warning message with ${value}.`;\n * ```\n *\n * @param message The message template strings array.\n * @param values The message template values.\n * @since 0.12.0\n */\n warning(message: TemplateStringsArray, ...values: readonly unknown[]): void;\n\n /**\n * Log a warning message with properties.\n *\n * ```typescript\n * logger.warning('A warning message with {value}.', { value });\n * ```\n *\n * If the properties are expensive to compute, you can pass a callback that\n * returns the properties:\n *\n * ```typescript\n * logger.warning(\n * 'A warning message with {value}.',\n * () => ({ value: expensiveComputation() })\n * );\n * ```\n *\n * @param message The message template. Placeholders to be replaced with\n * `values` are indicated by keys in curly braces (e.g.,\n * `{value}`).\n * @param properties The values to replace placeholders with. For lazy\n * evaluation, this can be a callback that returns the\n * properties.\n * @since 0.12.0\n */\n warning(\n message: string,\n properties?: Record<string, unknown> | (() => Record<string, unknown>),\n ): void;\n\n /**\n * Log a warning values with no message. This is useful when you\n * want to log properties without a message, e.g., when you want to log\n * the context of a request or an operation.\n *\n * ```typescript\n * logger.warning({ method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * Note that this is a shorthand for:\n *\n * ```typescript\n * logger.warning('{*}', { method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * If the properties are expensive to compute, you cannot use this shorthand\n * and should use the following syntax instead:\n *\n * ```typescript\n * logger.warning('{*}', () => ({\n * method: expensiveMethod(),\n * url: expensiveUrl(),\n * }));\n * ```\n *\n * @param properties The values to log. Note that this does not take\n * a callback.\n * @since 0.12.0\n */\n warning(properties: Record<string, unknown>): void;\n\n /**\n * Lazily log a warning message. Use this when the message values are\n * expensive to compute and should only be computed if the message is actually\n * logged.\n *\n * ```typescript\n * logger.warning(l => l`A warning message with ${expensiveValue()}.`);\n * ```\n *\n * @param callback A callback that returns the message template prefix.\n * @throws {TypeError} If no log record was made inside the callback.\n * @since 0.12.0\n */\n warning(callback: LogCallback): void;\n\n /**\n * Log an error message. Use this as a template string prefix.\n *\n * ```typescript\n * logger.error `An error message with ${value}.`;\n * ```\n *\n * @param message The message template strings array.\n * @param values The message template values.\n */\n error(message: TemplateStringsArray, ...values: readonly unknown[]): void;\n\n /**\n * Log an error message with properties.\n *\n * ```typescript\n * logger.warn('An error message with {value}.', { value });\n * ```\n *\n * If the properties are expensive to compute, you can pass a callback that\n * returns the properties:\n *\n * ```typescript\n * logger.error(\n * 'An error message with {value}.',\n * () => ({ value: expensiveComputation() })\n * );\n * ```\n *\n * @param message The message template. Placeholders to be replaced with\n * `values` are indicated by keys in curly braces (e.g.,\n * `{value}`).\n * @param properties The values to replace placeholders with. For lazy\n * evaluation, this can be a callback that returns the\n * properties.\n */\n error(\n message: string,\n properties?: Record<string, unknown> | (() => Record<string, unknown>),\n ): void;\n\n /**\n * Log an error values with no message. This is useful when you\n * want to log properties without a message, e.g., when you want to log\n * the context of a request or an operation.\n *\n * ```typescript\n * logger.error({ method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * Note that this is a shorthand for:\n *\n * ```typescript\n * logger.error('{*}', { method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * If the properties are expensive to compute, you cannot use this shorthand\n * and should use the following syntax instead:\n *\n * ```typescript\n * logger.error('{*}', () => ({\n * method: expensiveMethod(),\n * url: expensiveUrl(),\n * }));\n * ```\n *\n * @param properties The values to log. Note that this does not take\n * a callback.\n * @since 0.11.0\n */\n error(properties: Record<string, unknown>): void;\n\n /**\n * Lazily log an error message. Use this when the message values are\n * expensive to compute and should only be computed if the message is actually\n * logged.\n *\n * ```typescript\n * logger.error(l => l`An error message with ${expensiveValue()}.`);\n * ```\n *\n * @param callback A callback that returns the message template prefix.\n * @throws {TypeError} If no log record was made inside the callback.\n */\n error(callback: LogCallback): void;\n\n /**\n * Log a fatal error message. Use this as a template string prefix.\n *\n * ```typescript\n * logger.fatal `A fatal error message with ${value}.`;\n * ```\n *\n * @param message The message template strings array.\n * @param values The message template values.\n */\n fatal(message: TemplateStringsArray, ...values: readonly unknown[]): void;\n\n /**\n * Log a fatal error message with properties.\n *\n * ```typescript\n * logger.warn('A fatal error message with {value}.', { value });\n * ```\n *\n * If the properties are expensive to compute, you can pass a callback that\n * returns the properties:\n *\n * ```typescript\n * logger.fatal(\n * 'A fatal error message with {value}.',\n * () => ({ value: expensiveComputation() })\n * );\n * ```\n *\n * @param message The message template. Placeholders to be replaced with\n * `values` are indicated by keys in curly braces (e.g.,\n * `{value}`).\n * @param properties The values to replace placeholders with. For lazy\n * evaluation, this can be a callback that returns the\n * properties.\n */\n fatal(\n message: string,\n properties?: Record<string, unknown> | (() => Record<string, unknown>),\n ): void;\n\n /**\n * Log a fatal error values with no message. This is useful when you\n * want to log properties without a message, e.g., when you want to log\n * the context of a request or an operation.\n *\n * ```typescript\n * logger.fatal({ method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * Note that this is a shorthand for:\n *\n * ```typescript\n * logger.fatal('{*}', { method: 'GET', url: '/api/v1/resource' });\n * ```\n *\n * If the properties are expensive to compute, you cannot use this shorthand\n * and should use the following syntax instead:\n *\n * ```typescript\n * logger.fatal('{*}', () => ({\n * method: expensiveMethod(),\n * url: expensiveUrl(),\n * }));\n * ```\n *\n * @param properties The values to log. Note that this does not take\n * a callback.\n * @since 0.11.0\n */\n fatal(properties: Record<string, unknown>): void;\n\n /**\n * Lazily log a fatal error message. Use this when the message values are\n * expensive to compute and should only be computed if the message is actually\n * logged.\n *\n * ```typescript\n * logger.fatal(l => l`A fatal error message with ${expensiveValue()}.`);\n * ```\n *\n * @param callback A callback that returns the message template prefix.\n * @throws {TypeError} If no log record was made inside the callback.\n */\n fatal(callback: LogCallback): void;\n\n /**\n * Emits a log record with custom fields while using this logger's\n * category.\n *\n * This is a low-level API for integration scenarios where you need full\n * control over the log record, particularly for preserving timestamps\n * from external systems.\n *\n * ```typescript\n * const logger = getLogger([\"my-app\", \"integration\"]);\n *\n * // Emit a log with a custom timestamp\n * logger.emit({\n * timestamp: kafkaLog.originalTimestamp,\n * level: \"info\",\n * message: [kafkaLog.message],\n * rawMessage: kafkaLog.message,\n * properties: {\n * source: \"kafka\",\n * partition: kafkaLog.partition,\n * offset: kafkaLog.offset,\n * },\n * });\n * ```\n *\n * @param record Log record without category field (category comes from\n * the logger instance)\n * @since 1.1.0\n */\n emit(record: Omit<LogRecord, \"category\">): void;\n}\n\n/**\n * A logging callback function. It is used to defer the computation of a\n * message template until it is actually logged.\n * @param prefix The message template prefix.\n * @returns The rendered message array.\n */\nexport type LogCallback = (prefix: LogTemplatePrefix) => unknown[];\n\n/**\n * A logging template prefix function. It is used to log a message in\n * a {@link LogCallback} function.\n * @param message The message template strings array.\n * @param values The message template values.\n * @returns The rendered message array.\n */\nexport type LogTemplatePrefix = (\n message: TemplateStringsArray,\n ...values: unknown[]\n) => unknown[];\n\n/**\n * A function type for logging methods in the {@link Logger} interface.\n * @since 1.0.0\n */\nexport interface LogMethod {\n /**\n * Log a message with the given level using a template string.\n * @param message The message template strings array.\n * @param values The message template values.\n */\n (\n message: TemplateStringsArray,\n ...values: readonly unknown[]\n ): void;\n\n /**\n * Log a message with the given level with properties.\n * @param message The message template. Placeholders to be replaced with\n * `values` are indicated by keys in curly braces (e.g.,\n * `{value}`).\n * @param properties The values to replace placeholders with. For lazy\n * evaluation, this can be a callback that returns the\n * properties.\n */\n (\n message: string,\n properties?: Record<string, unknown> | (() => Record<string, unknown>),\n ): void;\n\n /**\n * Log a message with the given level with no message.\n * @param properties The values to log. Note that this does not take\n * a callback.\n */\n (properties: Record<string, unknown>): void;\n\n /**\n * Lazily log a message with the given level.\n * @param callback A callback that returns the message template prefix.\n * @throws {TypeError} If no log record was made inside the callback.\n */\n (callback: LogCallback): void;\n}\n\n/**\n * Get a logger with the given category.\n *\n * ```typescript\n * const logger = getLogger([\"my-app\"]);\n * ```\n *\n * @param category The category of the logger. It can be a string or an array\n * of strings. If it is a string, it is equivalent to an array\n * with a single element.\n * @returns The logger.\n */\nexport function getLogger(category: string | readonly string[] = []): Logger {\n return LoggerImpl.getLogger(category);\n}\n\n/**\n * The symbol for the global root logger.\n */\nconst globalRootLoggerSymbol = Symbol.for(\"logtape.rootLogger\");\n\n/**\n * The global root logger registry.\n */\ninterface GlobalRootLoggerRegistry {\n [globalRootLoggerSymbol]?: LoggerImpl;\n}\n\n/**\n * A logger implementation. Do not use this directly; use {@link getLogger}\n * instead. This class is exported for testing purposes.\n */\nexport class LoggerImpl implements Logger {\n readonly parent: LoggerImpl | null;\n readonly children: Record<string, LoggerImpl | WeakRef<LoggerImpl>>;\n readonly category: readonly string[];\n readonly sinks: Sink[];\n parentSinks: \"inherit\" | \"override\" = \"inherit\";\n readonly filters: Filter[];\n lowestLevel: LogLevel | null = \"trace\";\n contextLocalStorage?: ContextLocalStorage<Record<string, unknown>>;\n\n static getLogger(category: string | readonly string[] = []): LoggerImpl {\n let rootLogger: LoggerImpl | null = globalRootLoggerSymbol in globalThis\n ? ((globalThis as GlobalRootLoggerRegistry)[globalRootLoggerSymbol] ??\n null)\n : null;\n if (rootLogger == null) {\n rootLogger = new LoggerImpl(null, []);\n (globalThis as GlobalRootLoggerRegistry)[globalRootLoggerSymbol] =\n rootLogger;\n }\n if (typeof category === \"string\") return rootLogger.getChild(category);\n if (category.length === 0) return rootLogger;\n return rootLogger.getChild(category as readonly [string, ...string[]]);\n }\n\n private constructor(parent: LoggerImpl | null, category: readonly string[]) {\n this.parent = parent;\n this.children = {};\n this.category = category;\n this.sinks = [];\n this.filters = [];\n }\n\n getChild(\n subcategory:\n | string\n | readonly [string]\n | readonly [string, ...(readonly string[])],\n ): LoggerImpl {\n const name = typeof subcategory === \"string\" ? subcategory : subcategory[0];\n const childRef = this.children[name];\n let child: LoggerImpl | undefined = childRef instanceof LoggerImpl\n ? childRef\n : childRef?.deref();\n if (child == null) {\n child = new LoggerImpl(this, [...this.category, name]);\n this.children[name] = \"WeakRef\" in globalThis\n ? new WeakRef(child)\n : child;\n }\n if (typeof subcategory === \"string\" || subcategory.length === 1) {\n return child;\n }\n return child.getChild(\n subcategory.slice(1) as [string, ...(readonly string[])],\n );\n }\n\n /**\n * Reset the logger. This removes all sinks and filters from the logger.\n */\n reset(): void {\n while (this.sinks.length > 0) this.sinks.shift();\n this.parentSinks = \"inherit\";\n while (this.filters.length > 0) this.filters.shift();\n this.lowestLevel = \"trace\";\n }\n\n /**\n * Reset the logger and all its descendants. This removes all sinks and\n * filters from the logger and all its descendants.\n */\n resetDescendants(): void {\n for (const child of Object.values(this.children)) {\n const logger = child instanceof LoggerImpl ? child : child.deref();\n if (logger != null) logger.resetDescendants();\n }\n this.reset();\n }\n\n with(properties: Record<string, unknown>): Logger {\n return new LoggerCtx(this, { ...properties });\n }\n\n filter(record: LogRecord): boolean {\n for (const filter of this.filters) {\n if (!filter(record)) return false;\n }\n if (this.filters.length < 1) return this.parent?.filter(record) ?? true;\n return true;\n }\n\n *getSinks(level: LogLevel): Iterable<Sink> {\n if (\n this.lowestLevel === null || compareLogLevel(level, this.lowestLevel) < 0\n ) {\n return;\n }\n if (this.parent != null && this.parentSinks === \"inherit\") {\n for (const sink of this.parent.getSinks(level)) yield sink;\n }\n for (const sink of this.sinks) yield sink;\n }\n\n emit(record: Omit<LogRecord, \"category\">): void;\n emit(record: LogRecord, bypassSinks?: Set<Sink>): void;\n emit(\n record: Omit<LogRecord, \"category\"> | LogRecord,\n bypassSinks?: Set<Sink>,\n ): void {\n const categoryPrefix = getCategoryPrefix();\n const baseCategory = \"category\" in record\n ? (record as LogRecord).category\n : this.category;\n const fullCategory = categoryPrefix.length > 0\n ? [...categoryPrefix, ...baseCategory]\n : baseCategory;\n\n // Create the full record by copying property descriptors from the original\n // record, which preserves getters without invoking them (unlike spread).\n const descriptors = Object.getOwnPropertyDescriptors(record) as\n & PropertyDescriptorMap\n & { category?: PropertyDescriptor };\n descriptors.category = {\n value: fullCategory,\n enumerable: true,\n configurable: true,\n };\n const fullRecord = Object.defineProperties({}, descriptors) as LogRecord;\n\n if (\n this.lowestLevel === null ||\n compareLogLevel(fullRecord.level, this.lowestLevel) < 0 ||\n !this.filter(fullRecord)\n ) {\n return;\n }\n for (const sink of this.getSinks(fullRecord.level)) {\n if (bypassSinks?.has(sink)) continue;\n try {\n sink(fullRecord);\n } catch (error) {\n const bypassSinks2 = new Set(bypassSinks);\n bypassSinks2.add(sink);\n metaLogger.log(\n \"fatal\",\n \"Failed to emit a log record to sink {sink}: {error}\",\n { sink, error, record: fullRecord },\n bypassSinks2,\n );\n }\n }\n }\n\n log(\n level: LogLevel,\n rawMessage: string,\n properties: Record<string, unknown> | (() => Record<string, unknown>),\n bypassSinks?: Set<Sink>,\n ): void {\n const implicitContext = getImplicitContext();\n let cachedProps: Record<string, unknown> | undefined = undefined;\n const record: LogRecord = typeof properties === \"function\"\n ? {\n category: this.category,\n level,\n timestamp: Date.now(),\n get message() {\n return parseMessageTemplate(rawMessage, this.properties);\n },\n rawMessage,\n get properties() {\n if (cachedProps == null) {\n cachedProps = {\n ...implicitContext,\n ...properties(),\n };\n }\n return cachedProps;\n },\n }\n : {\n category: this.category,\n level,\n timestamp: Date.now(),\n message: parseMessageTemplate(rawMessage, {\n ...implicitContext,\n ...properties,\n }),\n rawMessage,\n properties: { ...implicitContext, ...properties },\n };\n this.emit(record, bypassSinks);\n }\n\n logLazily(\n level: LogLevel,\n callback: LogCallback,\n properties: Record<string, unknown> = {},\n ): void {\n const implicitContext = getImplicitContext();\n let rawMessage: TemplateStringsArray | undefined = undefined;\n let msg: unknown[] | undefined = undefined;\n function realizeMessage(): [unknown[], TemplateStringsArray] {\n if (msg == null || rawMessage == null) {\n msg = callback((tpl, ...values) => {\n rawMessage = tpl;\n return renderMessage(tpl, values);\n });\n if (rawMessage == null) throw new TypeError(\"No log record was made.\");\n }\n return [msg, rawMessage];\n }\n this.emit({\n category: this.category,\n level,\n get message() {\n return realizeMessage()[0];\n },\n get rawMessage() {\n return realizeMessage()[1];\n },\n timestamp: Date.now(),\n properties: { ...implicitContext, ...properties },\n });\n }\n\n logTemplate(\n level: LogLevel,\n messageTemplate: TemplateStringsArray,\n values: unknown[],\n properties: Record<string, unknown> = {},\n ): void {\n const implicitContext = getImplicitContext();\n this.emit({\n category: this.category,\n level,\n message: renderMessage(messageTemplate, values),\n rawMessage: messageTemplate,\n timestamp: Date.now(),\n properties: { ...implicitContext, ...properties },\n });\n }\n\n trace(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"trace\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"trace\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"trace\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"trace\", message as TemplateStringsArray, values);\n }\n }\n\n debug(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"debug\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"debug\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"debug\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"debug\", message as TemplateStringsArray, values);\n }\n }\n\n info(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"info\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"info\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"info\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"info\", message as TemplateStringsArray, values);\n }\n }\n\n warn(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\n \"warning\",\n message,\n (values[0] ?? {}) as Record<string, unknown>,\n );\n } else if (typeof message === \"function\") {\n this.logLazily(\"warning\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"warning\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"warning\", message as TemplateStringsArray, values);\n }\n }\n\n warning(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n this.warn(message, ...values);\n }\n\n error(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"error\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"error\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"error\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"error\", message as TemplateStringsArray, values);\n }\n }\n\n fatal(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"fatal\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"fatal\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"fatal\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"fatal\", message as TemplateStringsArray, values);\n }\n }\n}\n\n/**\n * A logger implementation with contextual properties. Do not use this\n * directly; use {@link Logger.with} instead. This class is exported\n * for testing purposes.\n */\nexport class LoggerCtx implements Logger {\n logger: LoggerImpl;\n properties: Record<string, unknown>;\n\n constructor(logger: LoggerImpl, properties: Record<string, unknown>) {\n this.logger = logger;\n this.properties = properties;\n }\n\n get category(): readonly string[] {\n return this.logger.category;\n }\n\n get parent(): Logger | null {\n return this.logger.parent;\n }\n\n getChild(\n subcategory: string | readonly [string] | readonly [string, ...string[]],\n ): Logger {\n return this.logger.getChild(subcategory).with(this.properties);\n }\n\n with(properties: Record<string, unknown>): Logger {\n return new LoggerCtx(this.logger, { ...this.properties, ...properties });\n }\n\n log(\n level: LogLevel,\n message: string,\n properties: Record<string, unknown> | (() => Record<string, unknown>),\n bypassSinks?: Set<Sink>,\n ): void {\n this.logger.log(\n level,\n message,\n typeof properties === \"function\"\n ? () => ({\n ...this.properties,\n ...properties(),\n })\n : { ...this.properties, ...properties },\n bypassSinks,\n );\n }\n\n logLazily(level: LogLevel, callback: LogCallback): void {\n this.logger.logLazily(level, callback, this.properties);\n }\n\n logTemplate(\n level: LogLevel,\n messageTemplate: TemplateStringsArray,\n values: unknown[],\n ): void {\n this.logger.logTemplate(level, messageTemplate, values, this.properties);\n }\n\n emit(record: Omit<LogRecord, \"category\">): void {\n const recordWithContext = {\n ...record,\n properties: { ...this.properties, ...record.properties },\n };\n this.logger.emit(recordWithContext);\n }\n\n trace(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"trace\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"trace\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"trace\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"trace\", message as TemplateStringsArray, values);\n }\n }\n\n debug(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"debug\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"debug\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"debug\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"debug\", message as TemplateStringsArray, values);\n }\n }\n\n info(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"info\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"info\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"info\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"info\", message as TemplateStringsArray, values);\n }\n }\n\n warn(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\n \"warning\",\n message,\n (values[0] ?? {}) as Record<string, unknown>,\n );\n } else if (typeof message === \"function\") {\n this.logLazily(\"warning\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"warning\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"warning\", message as TemplateStringsArray, values);\n }\n }\n\n warning(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n this.warn(message, ...values);\n }\n\n error(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"error\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"error\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"error\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"error\", message as TemplateStringsArray, values);\n }\n }\n\n fatal(\n message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>,\n ...values: unknown[]\n ): void {\n if (typeof message === \"string\") {\n this.log(\"fatal\", message, (values[0] ?? {}) as Record<string, unknown>);\n } else if (typeof message === \"function\") {\n this.logLazily(\"fatal\", message);\n } else if (!Array.isArray(message)) {\n this.log(\"fatal\", \"{*}\", message as Record<string, unknown>);\n } else {\n this.logTemplate(\"fatal\", message as TemplateStringsArray, values);\n }\n }\n}\n\n/**\n * The meta logger. It is a logger with the category `[\"logtape\", \"meta\"]`.\n */\nconst metaLogger = LoggerImpl.getLogger([\"logtape\", \"meta\"]);\n\n/**\n * Check if a property access key contains nested access patterns.\n * @param key The property key to check.\n * @returns True if the key contains nested access patterns.\n */\nfunction isNestedAccess(key: string): boolean {\n return key.includes(\".\") || key.includes(\"[\") || key.includes(\"?.\");\n}\n\n/**\n * Safely access an own property from an object, blocking prototype pollution.\n *\n * @param obj The object to access the property from.\n * @param key The property key to access.\n * @returns The property value or undefined if not accessible.\n */\nfunction getOwnProperty(obj: unknown, key: string): unknown {\n // Block dangerous prototype keys\n if (key === \"__proto__\" || key === \"prototype\" || key === \"constructor\") {\n return undefined;\n }\n\n if ((typeof obj === \"object\" || typeof obj === \"function\") && obj !== null) {\n return Object.prototype.hasOwnProperty.call(obj, key)\n ? (obj as Record<string, unknown>)[key]\n : undefined;\n }\n\n return undefined;\n}\n\n/**\n * Result of parsing a single segment from a property path.\n */\ninterface ParseSegmentResult {\n segment: string | number;\n nextIndex: number;\n}\n\n/**\n * Parse the next segment from a property path string.\n *\n * @param path The full property path string.\n * @param fromIndex The index to start parsing from.\n * @returns The parsed segment and next index, or null if parsing fails.\n */\nfunction parseNextSegment(\n path: string,\n fromIndex: number,\n): ParseSegmentResult | null {\n const len = path.length;\n let i = fromIndex;\n\n if (i >= len) return null;\n\n let segment: string | number;\n\n if (path[i] === \"[\") {\n // Bracket notation: [0] or [\"prop\"]\n i++;\n if (i >= len) return null;\n\n if (path[i] === '\"' || path[i] === \"'\") {\n // Quoted property name: [\"prop-name\"]\n const quote = path[i];\n i++;\n // Build segment with proper escape handling\n let segmentStr = \"\";\n while (i < len && path[i] !== quote) {\n if (path[i] === \"\\\\\") {\n i++; // Skip backslash\n if (i < len) {\n // Handle escape sequences according to JavaScript spec\n const escapeChar = path[i];\n switch (escapeChar) {\n case \"n\":\n segmentStr += \"\\n\";\n break;\n case \"t\":\n segmentStr += \"\\t\";\n break;\n case \"r\":\n segmentStr += \"\\r\";\n break;\n case \"b\":\n segmentStr += \"\\b\";\n break;\n case \"f\":\n segmentStr += \"\\f\";\n break;\n case \"v\":\n segmentStr += \"\\v\";\n break;\n case \"0\":\n segmentStr += \"\\0\";\n break;\n case \"\\\\\":\n segmentStr += \"\\\\\";\n break;\n case '\"':\n segmentStr += '\"';\n break;\n case \"'\":\n segmentStr += \"'\";\n break;\n case \"u\":\n // Unicode escape: \\uXXXX\n if (i + 4 < len) {\n const hex = path.slice(i + 1, i + 5);\n const codePoint = Number.parseInt(hex, 16);\n if (!Number.isNaN(codePoint)) {\n segmentStr += String.fromCharCode(codePoint);\n i += 4; // Skip the 4 hex digits\n } else {\n // Invalid unicode escape, keep as-is\n segmentStr += escapeChar;\n }\n } else {\n // Not enough characters for unicode escape\n segmentStr += escapeChar;\n }\n break;\n default:\n // For any other character after \\, just add it as-is\n segmentStr += escapeChar;\n }\n i++;\n }\n } else {\n segmentStr += path[i];\n i++;\n }\n }\n if (i >= len) return null;\n segment = segmentStr;\n i++; // Skip closing quote\n } else {\n // Array index: [0]\n const startIndex = i;\n while (\n i < len && path[i] !== \"]\" && path[i] !== \"'\" && path[i] !== '\"'\n ) {\n i++;\n }\n if (i >= len) return null;\n const indexStr = path.slice(startIndex, i);\n // Empty bracket is invalid\n if (indexStr.length === 0) return null;\n const indexNum = Number(indexStr);\n segment = Number.isNaN(indexNum) ? indexStr : indexNum;\n }\n\n // Skip closing bracket\n while (i < len && path[i] !== \"]\") i++;\n if (i < len) i++;\n } else {\n // Dot notation: prop\n const startIndex = i;\n while (\n i < len && path[i] !== \".\" && path[i] !== \"[\" && path[i] !== \"?\" &&\n path[i] !== \"]\"\n ) {\n i++;\n }\n segment = path.slice(startIndex, i);\n // Empty segment is invalid (e.g., leading dot, double dot, trailing dot)\n if (segment.length === 0) return null;\n }\n\n // Skip dot separator\n if (i < len && path[i] === \".\") i++;\n\n return { segment, nextIndex: i };\n}\n\n/**\n * Access a property or index on an object or array.\n *\n * @param obj The object or array to access.\n * @param segment The property key or array index.\n * @returns The accessed value or undefined if not accessible.\n */\nfunction accessProperty(obj: unknown, segment: string | number): unknown {\n if (typeof segment === \"string\") {\n return getOwnProperty(obj, segment);\n }\n\n // Numeric index for arrays\n if (Array.isArray(obj) && segment >= 0 && segment < obj.length) {\n return obj[segment];\n }\n\n return undefined;\n}\n\n/**\n * Resolve a nested property path from an object.\n *\n * There are two types of property access patterns:\n * 1. Array/index access: [0] or [\"prop\"]\n * 2. Property access: prop or prop?.next\n *\n * @param obj The object to traverse.\n * @param path The property path (e.g., \"user.name\", \"users[0].email\", \"user['full-name']\").\n * @returns The resolved value or undefined if path doesn't exist.\n */\nfunction resolvePropertyPath(obj: unknown, path: string): unknown {\n if (obj == null) return undefined;\n\n // Check for invalid paths\n if (path.length === 0 || path.endsWith(\".\")) return undefined;\n\n let current: unknown = obj;\n let i = 0;\n const len = path.length;\n\n while (i < len) {\n // Handle optional chaining\n const isOptional = path.slice(i, i + 2) === \"?.\";\n if (isOptional) {\n i += 2;\n if (current == null) return undefined;\n } else if (current == null) {\n return undefined;\n }\n\n // Parse the next segment\n const result = parseNextSegment(path, i);\n if (result === null) return undefined;\n\n const { segment, nextIndex } = result;\n i = nextIndex;\n\n // Access the property/index\n current = accessProperty(current, segment);\n if (current === undefined) {\n return undefined;\n }\n }\n\n return current;\n}\n\n/**\n * Parse a message template into a message template array and a values array.\n *\n * Placeholders to be replaced with `values` are indicated by keys in curly braces\n * (e.g., `{value}`). The system supports both simple property access and nested\n * property access patterns:\n *\n * **Simple property access:**\n * ```ts\n * parseMessageTemplate(\"Hello, {user}!\", { user: \"foo\" })\n * // Returns: [\"Hello, \", \"foo\", \"!\"]\n * ```\n *\n * **Nested property access (dot notation):**\n * ```ts\n * parseMessageTemplate(\"Hello, {user.name}!\", {\n * user: { name: \"foo\", email: \"foo@example.com\" }\n * })\n * // Returns: [\"Hello, \", \"foo\", \"!\"]\n * ```\n *\n * **Array indexing:**\n * ```ts\n * parseMessageTemplate(\"First: {users[0]}\", {\n * users: [\"foo\", \"bar\", \"baz\"]\n * })\n * // Returns: [\"First: \", \"foo\", \"\"]\n * ```\n *\n * **Bracket notation for special property names:**\n * ```ts\n * parseMessageTemplate(\"Name: {user[\\\"full-name\\\"]}\", {\n * user: { \"full-name\": \"foo bar\" }\n * })\n * // Returns: [\"Name: \", \"foo bar\", \"\"]\n * ```\n *\n * **Optional chaining for safe navigation:**\n * ```ts\n * parseMessageTemplate(\"Email: {user?.profile?.email}\", {\n * user: { name: \"foo\" }\n * })\n * // Returns: [\"Email: \", undefined, \"\"]\n * ```\n *\n * **Wildcard patterns:**\n * - `{*}` - Replaced with the entire properties object\n * - `{ key-with-whitespace }` - Whitespace is trimmed when looking up keys\n *\n * **Escaping:**\n * - `{{` and `}}` are escaped literal braces\n *\n * **Error handling:**\n * - Non-existent paths return `undefined`\n * - Malformed expressions resolve to `undefined` without throwing errors\n * - Out of bounds array access returns `undefined`\n *\n * @param template The message template string containing placeholders.\n * @param properties The values to replace placeholders with.\n * @returns The message template array with values interleaved between text segments.\n */\nexport function parseMessageTemplate(\n template: string,\n properties: Record<string, unknown>,\n): readonly unknown[] {\n const length = template.length;\n if (length === 0) return [\"\"];\n\n // Fast path: no placeholders\n if (!template.includes(\"{\")) return [template];\n\n const message: unknown[] = [];\n let startIndex = 0;\n\n for (let i = 0; i < length; i++) {\n const char = template[i];\n\n if (char === \"{\") {\n const nextChar = i + 1 < length ? template[i + 1] : \"\";\n\n if (nextChar === \"{\") {\n // Escaped { character - skip and continue\n i++; // Skip the next {\n continue;\n }\n\n // Find the closing }\n const closeIndex = template.indexOf(\"}\", i + 1);\n if (closeIndex === -1) {\n // No closing } found, treat as literal text\n continue;\n }\n\n // Add text before placeholder\n const beforeText = template.slice(startIndex, i);\n message.push(beforeText.replace(/{{/g, \"{\").replace(/}}/g, \"}\"));\n\n // Extract and process placeholder key\n const key = template.slice(i + 1, closeIndex);\n\n // Resolve property value\n let prop: unknown;\n\n // Check for wildcard patterns\n const trimmedKey = key.trim();\n if (trimmedKey === \"*\") {\n // This is a wildcard pattern\n prop = key in properties\n ? properties[key]\n : \"*\" in properties\n ? properties[\"*\"]\n : properties;\n } else {\n // Regular property lookup with possible whitespace handling\n if (key !== trimmedKey) {\n // Key has leading/trailing whitespace\n prop = key in properties ? properties[key] : properties[trimmedKey];\n } else {\n // Key has no leading/trailing whitespace\n prop = properties[key];\n }\n\n // If property not found directly and this looks like nested access, try nested resolution\n if (prop === undefined && isNestedAccess(trimmedKey)) {\n prop = resolvePropertyPath(properties, trimmedKey);\n }\n }\n\n message.push(prop);\n i = closeIndex; // Move to the }\n startIndex = i + 1;\n } else if (char === \"}\" && i + 1 < length && template[i + 1] === \"}\") {\n // Escaped } character - skip\n i++; // Skip the next }\n }\n }\n\n // Add remaining text\n const remainingText = template.slice(startIndex);\n message.push(remainingText.replace(/{{/g, \"{\").replace(/}}/g, \"}\"));\n\n return message;\n}\n\n/**\n * Render a message template with values.\n * @param template The message template.\n * @param values The message template values.\n * @returns The message template values interleaved between the substitution\n * values.\n */\nexport function renderMessage(\n template: TemplateStringsArray,\n values: readonly unknown[],\n): unknown[] {\n const args = [];\n for (let i = 0; i < template.length; i++) {\n args.push(template[i]);\n if (i < values.length) args.push(values[i]);\n }\n return args;\n}\n","import { LoggerImpl } from \"./logger.ts\";\n\n/**\n * Internal symbol for storing category prefix in context.\n */\nconst categoryPrefixSymbol: unique symbol = Symbol.for(\n \"logtape.categoryPrefix\",\n) as typeof categoryPrefixSymbol;\n\n/**\n * A generic interface for a context-local storage. It resembles\n * the {@link AsyncLocalStorage} API from Node.js.\n * @template T The type of the context-local store.\n * @since 0.7.0\n */\nexport interface ContextLocalStorage<T> {\n /**\n * Runs a callback with the given store as the context-local store.\n * @param store The store to use as the context-local store.\n * @param callback The callback to run.\n * @returns The return value of the callback.\n */\n run<R>(store: T, callback: () => R): R;\n\n /**\n * Returns the current context-local store.\n * @returns The current context-local store, or `undefined` if there is no\n * store.\n */\n getStore(): T | undefined;\n}\n\n/**\n * Runs a callback with the given implicit context. Every single log record\n * in the callback will have the given context.\n *\n * If no `contextLocalStorage` is configured, this function does nothing and\n * just returns the return value of the callback. It also logs a warning to\n * the `[\"logtape\", \"meta\"]` logger in this case.\n * @param context The context to inject.\n * @param callback The callback to run.\n * @returns The return value of the callback.\n * @since 0.7.0\n */\nexport function withContext<T>(\n context: Record<string, unknown>,\n callback: () => T,\n): T {\n const rootLogger = LoggerImpl.getLogger();\n if (rootLogger.contextLocalStorage == null) {\n LoggerImpl.getLogger([\"logtape\", \"meta\"]).warn(\n \"Context-local storage is not configured. \" +\n \"Specify contextLocalStorage option in the configure() function.\",\n );\n return callback();\n }\n const parentContext = rootLogger.contextLocalStorage.getStore() ?? {};\n return rootLogger.contextLocalStorage.run(\n { ...parentContext, ...context },\n callback,\n );\n}\n\n/**\n * Gets the current category prefix from context local storage.\n * @returns The current category prefix, or an empty array if not set.\n * @since 1.3.0\n */\nexport function getCategoryPrefix(): readonly string[] {\n const rootLogger = LoggerImpl.getLogger();\n const store = rootLogger.contextLocalStorage?.getStore();\n if (store == null) return [];\n const prefix = store[categoryPrefixSymbol as unknown as string];\n return Array.isArray(prefix) ? prefix : [];\n}\n\n/**\n * Gets the current implicit context from context local storage, excluding\n * internal symbol keys (like category prefix).\n * @returns The current implicit context without internal symbol keys.\n * @since 1.3.0\n */\nexport function getImplicitContext(): Record<string, unknown> {\n const rootLogger = LoggerImpl.getLogger();\n const store = rootLogger.contextLocalStorage?.getStore();\n if (store == null) return {};\n // Filter out symbol keys (like categoryPrefixSymbol)\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(store)) {\n result[key] = store[key];\n }\n return result;\n}\n\n/**\n * Runs a callback with the given category prefix prepended to all log\n * categories within the callback context.\n *\n * This is useful for SDKs or libraries that want to add their own category\n * as a prefix to logs from their internal dependencies.\n *\n * If no `contextLocalStorage` is configured, this function does nothing and\n * just returns the return value of the callback. It also logs a warning to\n * the `[\"logtape\", \"meta\"]` logger in this case.\n *\n * @example Basic usage\n * ```typescript\n * import { getLogger, withCategoryPrefix } from \"@logtape/logtape\";\n *\n * export function sdkFunction() {\n * return withCategoryPrefix([\"my-sdk\"], () => {\n * // Any logs from internal libraries within this context\n * // will have [\"my-sdk\"] prepended to their category\n * return internalLibraryFunction();\n * });\n * }\n * ```\n *\n * @param prefix The category prefix to prepend. Can be a string or an array\n * of strings.\n * @param callback The callback to run.\n * @returns The return value of the callback.\n * @since 1.3.0\n */\nexport function withCategoryPrefix<T>(\n prefix: string | readonly string[],\n callback: () => T,\n): T {\n const rootLogger = LoggerImpl.getLogger();\n if (rootLogger.contextLocalStorage == null) {\n LoggerImpl.getLogger([\"logtape\", \"meta\"]).warn(\n \"Context-local storage is not configured. \" +\n \"Specify contextLocalStorage option in the configure() function.\",\n );\n return callback();\n }\n const parentContext = rootLogger.contextLocalStorage.getStore() ?? {};\n const parentPrefix = getCategoryPrefix();\n const newPrefix = typeof prefix === \"string\" ? [prefix] : [...prefix];\n return rootLogger.contextLocalStorage.run(\n {\n ...parentContext,\n [categoryPrefixSymbol as unknown as string]: [\n ...parentPrefix,\n ...newPrefix,\n ],\n },\n callback,\n );\n}\n","export * from \"@loro-extended/change\"\nexport * from \"./adapter/adapter.js\"\nexport * from \"./adapter/bridge-adapter.js\"\nexport * from \"./adapter/delayed-network-adapter.js\"\nexport * from \"./adapter/interceptor.js\"\nexport * from \"./adapter/types.js\"\nexport * from \"./channel.js\"\nexport * from \"./channel-json.js\"\nexport * from \"./handle.js\"\nexport * from \"./middleware/rate-limiter.js\"\nexport * from \"./middleware.js\"\nexport * from \"./permissions.js\"\nexport * from \"./repo.js\"\nexport * from \"./storage/in-memory-storage-adapter.js\"\nexport * from \"./storage/storage-adapter.js\"\nexport * from \"./types.js\"\nexport * from \"./utils/generate-peer-id.js\"\nexport * from \"./utils/generate-uuid.js\"\nexport * from \"./utils/validate-peer-id.js\"\n","import { getLogger, type Logger } from \"@logtape/logtape\"\nimport type {\n AddressedEnvelope,\n Channel,\n ChannelId,\n ChannelKind,\n ChannelMsg,\n ConnectedChannel,\n GeneratedChannel,\n} from \"../channel.js\"\nimport { ChannelDirectory } from \"../channel-directory.js\"\nimport type { AdapterType, PeerIdentityDetails } from \"../types.js\"\nimport { generateUUID } from \"../utils/generate-uuid.js\"\nimport type { SendInterceptor, SendInterceptorContext } from \"./interceptor.js\"\nimport type { HandleSendFn } from \"./types.js\"\n\nexport type AnyAdapter = Adapter<any>\n\ntype AdapterParams = {\n adapterType: AdapterType\n /**\n * Unique identifier for this adapter instance.\n * If not provided, auto-generated as `{adapterType}-{uuid}`.\n * Used for idempotent add/remove operations.\n */\n adapterId?: string\n}\n\n/**\n * Context provided to adapters during initialization.\n * Contains identity, logger, and callbacks for channel lifecycle events.\n */\nexport type AdapterContext = {\n identity: PeerIdentityDetails\n logger: Logger\n /**\n * Called when a message is received on a channel.\n * Note: channelId is passed instead of channel object because the channel\n * object may be stale (due to immutable state updates in the synchronizer).\n * The synchronizer should look up the current channel from its model.\n */\n onChannelReceive: (channelId: ChannelId, message: ChannelMsg) => void\n onChannelAdded: (channel: ConnectedChannel) => void\n onChannelRemoved: (channel: Channel) => void\n onChannelEstablish: (channel: ConnectedChannel) => void\n}\n\n/**\n * @deprecated Use AdapterContext instead\n */\nexport type AdapterHooks = AdapterContext\n\n// Callbacks only (without identity and logger) for lifecycle state\ntype AdapterCallbacks = Omit<AdapterContext, \"identity\" | \"logger\">\n\ntype AdapterLifecycleCreatedState = { state: \"created\" } // Constructor finished, not initialized\n\n// biome-ignore format: left-align\ntype AdapterLifecycleInitializedState =\n & { state: \"initialized\" }\n & AdapterCallbacks\n\n// biome-ignore format: left-align\ntype AdapterLifecycleStartedState =\n & { state: \"started\" }\n & AdapterCallbacks\n\ntype AdapterLifecycleStoppedState = { state: \"stopped\" }\n\ntype AdapterLifecycleState =\n | AdapterLifecycleCreatedState\n | AdapterLifecycleInitializedState\n | AdapterLifecycleStartedState\n | AdapterLifecycleStoppedState\n\nexport abstract class Adapter<G> {\n /**\n * The kind of channels this adapter creates.\n * Default is \"network\". StorageAdapter overrides this to \"storage\".\n *\n * This is a first-class property of the adapter, not just the channels,\n * allowing code to check adapter capabilities before channels are created.\n */\n readonly kind: ChannelKind = \"network\"\n\n readonly adapterType: AdapterType\n /**\n * Unique identifier for this adapter instance.\n * Used for idempotent add/remove operations.\n */\n readonly adapterId: string\n // Logger is set during _initialize() with the Synchronizer's logger\n // Before initialization, uses a placeholder logger\n logger: Logger\n readonly channels: ChannelDirectory<G>\n\n // Used for debugging; set by AdapterManager\n onSend: HandleSendFn | undefined\n\n // Identity provided during initialization\n protected identity?: PeerIdentityDetails\n\n #lifecycle: AdapterLifecycleState = { state: \"created\" }\n #sendInterceptors: SendInterceptor[] = []\n\n constructor({ adapterType, adapterId }: AdapterParams) {\n this.adapterType = adapterType\n this.adapterId = adapterId ?? `${adapterType}-${generateUUID()}`\n // Use a placeholder logger until _initialize() provides the real one\n // This logger won't output anything unless LogTape is configured at the root level\n this.logger = getLogger().getChild(\"adapter\").with({ adapterType })\n this.channels = new ChannelDirectory(this._generate.bind(this))\n }\n\n // ============================================================================\n // PROTECTED API - For Subclasses\n // ============================================================================\n\n /**\n * Create a channel. Only callable during \"started\" state.\n * The channel must be ready to send/receive immediately.\n */\n protected addChannel(context: G): ConnectedChannel {\n const lifecycle = this.#lifecycle\n\n if (lifecycle.state !== \"started\") {\n throw new Error(\n `can't add channel in '${lifecycle.state}' state (must be 'started')`,\n )\n }\n\n const channel = this.channels.create(context, message =>\n lifecycle.onChannelReceive(channel.channelId, message),\n )\n\n lifecycle.onChannelAdded(channel)\n\n return channel\n }\n\n /**\n * Remove a channel. Only callable during \"started\" state.\n */\n protected removeChannel(channelId: ChannelId): Channel | undefined {\n const lifecycle = this.#lifecycle\n\n if (lifecycle.state !== \"started\") {\n throw new Error(\n `can't remove channel in '${lifecycle.state}' state (must be 'started')`,\n )\n }\n\n const channel = this.channels.remove(channelId)\n\n if (channel) {\n lifecycle.onChannelRemoved(channel)\n }\n\n return channel\n }\n\n /**\n * Establish a channel by triggering the establishment handshake.\n * This should be called after addChannel() to initiate communication.\n * Only callable during \"started\" state.\n */\n protected establishChannel(channelId: ChannelId): void {\n const lifecycle = this.#lifecycle\n\n if (lifecycle.state !== \"started\") {\n throw new Error(\n `can't establish channel in '${lifecycle.state}' state (must be 'started')`,\n )\n }\n\n const channel = this.channels.get(channelId)\n if (!channel) {\n throw new Error(`can't establish channel ${channelId}: channel not found`)\n }\n\n // Only establish if channel is still in connected state\n if (channel.type === \"connected\") {\n lifecycle.onChannelEstablish(channel)\n }\n }\n\n /**\n * Generate a GeneratedChannel for the given context.\n * The returned channel must be ready to use immediately.\n *\n * Note: Subclasses should return only `send` and `stop` functions.\n * The `kind` and `adapterType` will be overwritten by the adapter's\n * properties in _generate(), so specifying them is optional.\n */\n protected abstract generate(context: G): GeneratedChannel\n\n /**\n * Internal method that ensures channel metadata comes from the adapter.\n * This is what ChannelDirectory calls to create channels.\n */\n private _generate(context: G): GeneratedChannel {\n const generated = this.generate(context)\n // Override kind and adapterType with adapter's values\n // This ensures consistency even if subclass specifies different values\n return {\n ...generated,\n kind: this.kind,\n adapterType: this.adapterType,\n }\n }\n\n /**\n * Start the adapter. Create initial channels here.\n * For dynamic adapters (servers), set up listeners that will\n * call addChannel() when new connections arrive.\n */\n abstract onStart(): Promise<void>\n\n /**\n * Stop the adapter. Clean up resources and remove channels.\n */\n abstract onStop(): Promise<void>\n\n // ============================================================================\n // INTERNAL API - For Synchronizer\n // ============================================================================\n\n _initialize(context: AdapterContext): void {\n // If already initialized/started, auto-stop to allow re-initialization (handles HMR)\n if (\n this.#lifecycle.state === \"initialized\" ||\n this.#lifecycle.state === \"started\"\n ) {\n this.logger.warn(\n \"Adapter {adapterType} re-initializing (auto-stopping from {state} state)\",\n { adapterType: this.adapterType, state: this.#lifecycle.state },\n )\n this.channels.reset()\n this.#lifecycle = { state: \"stopped\" }\n }\n\n if (\n this.#lifecycle.state !== \"created\" &&\n this.#lifecycle.state !== \"stopped\"\n ) {\n throw new Error(`Adapter ${this.adapterType} already initialized`)\n }\n // Store identity for subclasses to access\n this.identity = context.identity\n // Set the real logger from the Synchronizer\n this.logger = context.logger\n .getChild(\"adapter\")\n .with({ adapterType: this.adapterType })\n // Store callbacks in lifecycle state (without identity and logger)\n this.#lifecycle = {\n state: \"initialized\",\n onChannelReceive: context.onChannelReceive,\n onChannelAdded: context.onChannelAdded,\n onChannelRemoved: context.onChannelRemoved,\n onChannelEstablish: context.onChannelEstablish,\n }\n }\n\n async _start(): Promise<void> {\n if (this.#lifecycle.state !== \"initialized\") {\n throw new Error(\n `Cannot start adapter ${this.adapterType} in state ${this.#lifecycle.state}`,\n )\n }\n // Transition to started state BEFORE calling onStart so that\n // subclasses can call addChannel() during their onStart() implementation\n this.#lifecycle = { ...this.#lifecycle, state: \"started\" }\n await this.onStart()\n }\n\n async _stop(): Promise<void> {\n if (this.#lifecycle.state !== \"started\") {\n this.logger.warn(\n \"Stopping adapter {adapterType} in unexpected state: {state.state}\",\n {\n adapterType: this.adapterType,\n state: this.#lifecycle,\n },\n )\n }\n await this.onStop()\n this.channels.reset()\n this.#lifecycle = { state: \"stopped\" }\n }\n\n /**\n * Given an envelope with zero or more toChannelIds, attempts to send the\n * message (in the envelope) through this adapter's channels. Note that this\n * does NOT guarantee delivery, only sending will be attempted through any\n * matching channels.\n *\n * @param envelope an AddressedEnvelope with message inside\n * @returns the number of channels to which the message was sent (optimistic count when interceptors are present)\n */\n _send(envelope: AddressedEnvelope): number {\n // If no interceptors, use fast path\n if (this.#sendInterceptors.length === 0) {\n return this.#doSend(envelope)\n }\n\n // Run through interceptor chain\n const context: SendInterceptorContext = {\n envelope,\n adapterType: this.adapterType,\n adapterId: this.adapterId,\n }\n\n const runChain = (index: number) => {\n if (index >= this.#sendInterceptors.length) {\n // End of chain - actually send\n this.#doSend(envelope)\n return\n }\n this.#sendInterceptors[index](context, () => runChain(index + 1))\n }\n\n runChain(0)\n\n // Return optimistic count (actual send may be delayed/dropped)\n return envelope.toChannelIds.length\n }\n\n /**\n * Internal method that performs the actual send operation.\n */\n #doSend(envelope: AddressedEnvelope): number {\n let sentCount = 0\n\n for (const toChannelId of envelope.toChannelIds) {\n const channel = this.channels.get(toChannelId)\n if (channel) {\n this.onSend?.(this.adapterType, toChannelId, envelope.message)\n channel.send(envelope.message)\n sentCount++\n }\n }\n\n return sentCount\n }\n\n // ============================================================================\n // PUBLIC API - Send Interceptors\n // ============================================================================\n\n /**\n * Add a send interceptor to the chain.\n * Interceptors are called in order of addition.\n *\n * @param interceptor - The interceptor function\n * @returns A function to remove the interceptor\n *\n * @example Delay all messages by 3 seconds\n * ```typescript\n * const unsubscribe = adapter.addSendInterceptor((ctx, next) => {\n * setTimeout(next, 3000)\n * })\n * ```\n *\n * @example Drop 10% of messages (simulate packet loss)\n * ```typescript\n * adapter.addSendInterceptor((ctx, next) => {\n * if (Math.random() > 0.1) next()\n * })\n * ```\n *\n * @example Log all messages\n * ```typescript\n * adapter.addSendInterceptor((ctx, next) => {\n * console.log('Sending:', ctx.envelope.message.type)\n * next()\n * })\n * ```\n */\n addSendInterceptor(interceptor: SendInterceptor): () => void {\n this.#sendInterceptors.push(interceptor)\n return () => {\n const idx = this.#sendInterceptors.indexOf(interceptor)\n if (idx >= 0) this.#sendInterceptors.splice(idx, 1)\n }\n }\n\n /**\n * Clear all send interceptors.\n */\n clearSendInterceptors(): void {\n this.#sendInterceptors = []\n }\n}\n","import type {\n Channel,\n ChannelId,\n ConnectedChannel,\n GenerateFn,\n ReceiveFn,\n} from \"./channel.js\"\n\nlet channelIssuanceId = 1\n\nexport type ChannelDirectoryHooks = {\n onChannelAdded: (channel: Channel) => void\n onChannelRemoved: (channel: Channel) => void\n}\n\nexport class ChannelDirectory<G> {\n private readonly channels: Map<ChannelId, Channel> = new Map()\n\n private onChannelAdded?: (channel: Channel) => void\n private onChannelRemoved?: (channel: Channel) => void\n\n constructor(readonly generate: GenerateFn<G>) {}\n\n *[Symbol.iterator](): IterableIterator<Channel> {\n yield* this.channels.values()\n }\n\n has(channelId: ChannelId): boolean {\n return this.channels.has(channelId)\n }\n\n get(channelId: ChannelId): Channel | undefined {\n return this.channels.get(channelId)\n }\n\n get size(): number {\n return this.channels.size\n }\n\n setHooks(hooks: ChannelDirectoryHooks) {\n this.onChannelAdded = hooks.onChannelAdded\n this.onChannelRemoved = hooks.onChannelRemoved\n }\n\n /**\n * Using an adapter's `generate` function, create a GeneratedChannel and then fill in\n * details needed to convert it to a ConnectedChannel.\n *\n * @param context The context specific to the Adapter type\n * @param onReceive A callback to be used to forward messages to the synchronizer\n * @returns a ConnectedChannel capable of sending EstablishmentMsgs\n */\n create(context: G, onReceive: ReceiveFn): ConnectedChannel {\n const channelId = channelIssuanceId++\n\n const generatedChannel = this.generate(context)\n\n const channel: Channel = {\n // NOTE:\n // The 'send' function becomes type-narrowed here so that only messages related\n // to establishing the peer identity can be sent through the 'connected' channel.\n // Runtime-wise, however, the `send` function is identical, which is why we can\n // pass it through with a spread.\n ...generatedChannel,\n type: \"connected\",\n channelId,\n onReceive,\n }\n\n this.channels.set(channelId, channel)\n\n this.onChannelAdded?.(channel)\n\n return channel\n }\n\n remove(channelId: ChannelId): Channel | undefined {\n const channel = this.channels.get(channelId)\n\n if (!channel) {\n return\n }\n\n this.channels.delete(channelId)\n\n this.onChannelRemoved?.(channel)\n\n return channel\n }\n\n reset() {\n for (const channelId of this.channels.keys()) {\n this.remove(channelId)\n }\n }\n}\n","/**\n * Generate a UUID v4 string.\n *\n * Uses `crypto.randomUUID()` when available (secure contexts: HTTPS or localhost).\n * Falls back to a `crypto.getRandomValues()` based implementation for non-secure\n * contexts (e.g., HTTP on LAN IP addresses).\n *\n * @returns A UUID v4 string (e.g., \"550e8400-e29b-41d4-a716-446655440000\")\n */\nexport function generateUUID(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID()\n }\n // Fallback using crypto.getRandomValues (available in all browser contexts)\n return \"10000000-1000-4000-8000-100000000000\".replace(/[018]/g, c =>\n (\n +c ^\n (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (+c / 4)))\n ).toString(16),\n )\n}\n","import { getLogger, type Logger } from \"@logtape/logtape\"\nimport type { ChannelMsg, GeneratedChannel } from \"../channel.js\"\nimport type { AdapterType, ChannelId } from \"../types.js\"\nimport { Adapter } from \"./adapter.js\"\n\ntype BridgeParams = {\n logger?: Logger\n}\n\n/**\n * A simple message router that connects multiple BridgeAdapters within the same process.\n * This enables direct message passing between adapters for testing purposes.\n */\nexport class Bridge {\n readonly adapters = new Map<AdapterType, BridgeAdapter>()\n readonly logger: Logger\n\n constructor({ logger }: BridgeParams = {}) {\n this.logger = logger ?? getLogger([\"@loro-extended\", \"repo\"])\n }\n\n /**\n * Register an adapter with this bridge\n */\n addAdapter(adapter: BridgeAdapter): void {\n if (!adapter.adapterType)\n throw new Error(\"can't add adapter without adapter id\")\n\n this.adapters.set(adapter.adapterType, adapter)\n }\n\n /**\n * Remove an adapter from this bridge\n */\n removeAdapter(adapterType: AdapterType): void {\n this.adapters.delete(adapterType)\n }\n\n /**\n * Route a message from one adapter to another\n */\n routeMessage(\n fromAdapterType: AdapterType,\n toAdapterType: AdapterType,\n message: ChannelMsg,\n ): void {\n this.logger.trace(\"routeMessage: {messageType} from {from} to {to}\", {\n from: fromAdapterType,\n to: toAdapterType,\n messageType: message.type,\n })\n const toAdapter = this.adapters.get(toAdapterType)\n if (toAdapter) {\n toAdapter.deliverMessage(fromAdapterType, message)\n } else {\n this.logger.warn(\n \"routeMessage: target adapter {toAdapterType} not found\",\n { toAdapterType },\n )\n }\n }\n\n /**\n * Get all adapter IDs currently in the bridge\n */\n get adapterTypes(): Set<AdapterType> {\n return new Set(this.adapters.keys())\n }\n}\n\ntype BridgeAdapterContext = {\n targetAdapterType: AdapterType\n}\n\ntype BridgeAdapterParams = {\n adapterType: AdapterType\n /**\n * Unique identifier for this adapter instance.\n * If not provided, defaults to adapterType for backwards compatibility.\n */\n adapterId?: string\n bridge: Bridge\n logger?: Logger\n}\n\n/**\n * An in-memory adapter for testing that connects multiple peers within the same process.\n *\n * BridgeAdapter simulates real network adapter behavior by delivering messages\n * asynchronously via `queueMicrotask()`. This ensures tests exercise the same\n * async codepaths as production adapters (WebSocket, SSE, etc.).\n *\n * **Important**: Tests using BridgeAdapter should use `waitForSync()` or\n * `waitUntilReady()` to await synchronization, just like they would with\n * real network adapters.\n *\n * @example\n * ```typescript\n * const bridge = new Bridge()\n * const repoA = new Repo({\n * adapters: [new BridgeAdapter({ adapterType: \"peer-a\", bridge })],\n * })\n * const repoB = new Repo({\n * adapters: [new BridgeAdapter({ adapterType: \"peer-b\", bridge })],\n * })\n *\n * const handleA = repoA.get(\"doc\", DocSchema)\n * handleA.change(draft => { draft.text.insert(0, \"hello\") })\n *\n * const handleB = repoB.get(\"doc\", DocSchema)\n * await handleB.waitForSync() // Wait for async message delivery\n * expect(handleB.doc.toJSON().text).toBe(\"hello\")\n * ```\n */\nexport class BridgeAdapter extends Adapter<BridgeAdapterContext> {\n readonly bridge: Bridge\n readonly logger: Logger\n\n // Track which remote adapter each channel connects to\n private channelToAdapter = new Map<ChannelId, AdapterType>()\n private adapterToChannel = new Map<AdapterType, ChannelId>()\n\n constructor({ adapterType, adapterId, bridge, logger }: BridgeAdapterParams) {\n // Default adapterId to adapterType for backwards compatibility\n super({ adapterType, adapterId: adapterId ?? adapterType })\n this.bridge = bridge\n this.logger = (logger ?? getLogger([\"@loro-extended\", \"repo\"])).with({\n adapterType,\n })\n\n this.logger.trace(`new BridgeAdapter`)\n }\n\n generate(context: BridgeAdapterContext): GeneratedChannel {\n this.logger.debug(\"generate channel to {targetAdapterType}\", {\n targetAdapterType: context.targetAdapterType,\n })\n\n return {\n adapterType: this.adapterType,\n kind: \"network\",\n send: msg => {\n this.logger.debug(\"channel.send: {messageType} from {from} to {to}\", {\n from: this.adapterType,\n to: context.targetAdapterType,\n messageType: msg.type,\n })\n // Route message through bridge to target adapter\n this.bridge.routeMessage(\n this.adapterType,\n context.targetAdapterType,\n msg,\n )\n },\n stop: () => {\n // Cleanup handled by removeChannel\n },\n }\n }\n\n /**\n * Start participating in the in-process network.\n * Uses two-phase initialization:\n * 1. Create all channels (no messages sent)\n * 2. Establish channels (only the \"newer\" adapter initiates to avoid double-establishment)\n */\n async onStart(): Promise<void> {\n this.logger.trace(`onStart - registering with bridge`)\n\n // Step 1: Register with bridge\n this.bridge.addAdapter(this)\n\n // Phase 1: Create all channels (no establishment yet)\n // Tell existing adapters to create channels to us\n for (const [adapterType, adapter] of this.bridge.adapters) {\n if (adapterType !== this.adapterType) {\n this.logger.trace(\"telling {adapterType} to create channel to us\", {\n adapterType,\n })\n adapter.createChannelTo(this.adapterType)\n }\n }\n\n // Create our channels to existing adapters\n for (const adapterType of this.bridge.adapters.keys()) {\n if (adapterType !== this.adapterType) {\n this.logger.trace(\"creating our channel to {adapterType}\", {\n adapterType,\n })\n this.createChannelTo(adapterType)\n }\n }\n\n // Phase 2: Establish channels\n // Only WE initiate establishment (to existing adapters)\n // This avoids double-establishment since we're the \"new\" adapter joining\n for (const channelId of this.adapterToChannel.values()) {\n this.logger.trace(\"establishing our channel {channelId}\", { channelId })\n this.establishChannel(channelId)\n }\n\n this.logger.trace(`onStart complete`)\n }\n\n /**\n * Stop participating in the in-process network.\n * Cleans up all channels and removes from bridge.\n */\n async onStop(): Promise<void> {\n this.logger.trace(`stop`)\n\n // Tell other adapters to remove their channels to us\n for (const [adapterType, adapter] of this.bridge.adapters) {\n if (adapterType !== this.adapterType) {\n adapter.removeChannelTo(this.adapterType)\n }\n }\n\n // Remove ourselves from bridge\n this.bridge.removeAdapter(this.adapterType)\n\n // Remove all our channels\n for (const channelId of this.channelToAdapter.keys()) {\n this.removeChannel(channelId)\n }\n this.channelToAdapter.clear()\n this.adapterToChannel.clear()\n }\n\n /**\n * Create a channel to a target adapter (Phase 1).\n * Does NOT trigger establishment - that happens in Phase 2.\n * Called by our own onStart() or by other adapters when they start.\n */\n createChannelTo(targetAdapterType: AdapterType): void {\n if (this.adapterToChannel.has(targetAdapterType)) {\n this.logger.trace(\"channel already exists to {targetAdapterType}\", {\n targetAdapterType,\n })\n return\n }\n\n const channel = this.addChannel({ targetAdapterType: targetAdapterType })\n this.channelToAdapter.set(channel.channelId, targetAdapterType)\n this.adapterToChannel.set(targetAdapterType, channel.channelId)\n\n this.logger.trace(\n \"channel {channelId} created (not yet established) to {targetAdapterType}\",\n {\n targetAdapterType,\n channelId: channel.channelId,\n },\n )\n }\n\n /**\n * Establish a channel to a target adapter (Phase 2).\n * Triggers the establishment handshake.\n * Called by our own onStart() or by other adapters when they start.\n */\n establishChannelTo(targetAdapterType: AdapterType): void {\n const channelId = this.adapterToChannel.get(targetAdapterType)\n if (!channelId) {\n this.logger.warn(\"no channel found to establish to {targetAdapterType}\", {\n targetAdapterType,\n })\n return\n }\n\n this.logger.trace(\"establishing channel {channelId}\", { channelId })\n this.establishChannel(channelId)\n }\n\n /**\n * Remove a channel to a target adapter.\n * Called by other adapters when they stop.\n */\n removeChannelTo(targetAdapterType: AdapterType): void {\n const channelId = this.adapterToChannel.get(targetAdapterType)\n if (channelId) {\n this.logger.trace(\"removing channel to adapter {targetAdapterType}\", {\n targetAdapterType,\n })\n this.removeChannel(channelId)\n this.channelToAdapter.delete(channelId)\n this.adapterToChannel.delete(targetAdapterType)\n }\n }\n\n /**\n * Deliver a message from another adapter to the appropriate channel.\n * Called by Bridge.routeMessage().\n *\n * Delivers messages asynchronously via queueMicrotask() to simulate real\n * network adapter behavior. This ensures tests using BridgeAdapter exercise\n * the same async codepaths as production adapters (WebSocket, SSE, etc.).\n *\n * Tests should use `waitForSync()` or `waitUntilReady()` to await sync completion.\n */\n deliverMessage(fromAdapterType: AdapterType, message: ChannelMsg): void {\n const channelId = this.adapterToChannel.get(fromAdapterType)\n if (channelId) {\n const channel = this.channels.get(channelId)\n if (channel) {\n this.logger.trace(\n \"queueing message {messageType} to channel {channelId} from {from}\",\n {\n from: fromAdapterType,\n messageType: message.type,\n channelId,\n },\n )\n // Defer delivery to next microtask - simulates async network behavior\n queueMicrotask(() => {\n this.logger.trace(\n \"delivering message {messageType} to channel {channelId} from {from}\",\n {\n from: fromAdapterType,\n messageType: message.type,\n channelId,\n },\n )\n channel.onReceive(message)\n })\n } else {\n this.logger.warn(\n \"channel {channelId} not found for message delivery from {fromAdapterType}\",\n {\n fromAdapterType,\n channelId,\n },\n )\n }\n } else {\n this.logger.warn(\"no channel found for adapter {fromAdapterType}\", {\n fromAdapterType,\n availableChannels: Array.from(this.adapterToChannel.keys()),\n })\n }\n }\n}\n","/**\n * A test adapter that simulates network latency between channel establishment\n * and sync-response delivery. Useful for testing timing-sensitive scenarios.\n *\n * @example\n * ```typescript\n * const adapter = new DelayedNetworkAdapter({ syncResponseDelay: 100 })\n * const repo = new Repo({\n * identity: { name: \"client\", type: \"user\" },\n * adapters: [adapter],\n * })\n *\n * const handle = repo.get(\"test-doc\", DocSchema)\n *\n * // Later, simulate server response\n * await adapter.deliverSyncResponse(\"test-doc\", serverSnapshot)\n * // Or simulate server doesn't have the document\n * await adapter.deliverUnavailable(\"test-doc\")\n * ```\n */\n\nimport { LoroDoc, type PeerID } from \"loro-crdt\"\nimport type { ChannelMsg, GeneratedChannel } from \"../channel.js\"\nimport { Adapter } from \"./adapter.js\"\n\nexport type DelayedNetworkAdapterOptions = {\n /**\n * Delay in milliseconds before delivering sync responses.\n */\n syncResponseDelay: number\n\n /**\n * The peer ID to use for the simulated server.\n * @default \"server\"\n */\n serverPeerId?: PeerID\n\n /**\n * The name to use for the simulated server.\n * @default \"server\"\n */\n serverName?: string\n}\n\nexport class DelayedNetworkAdapter extends Adapter<void> {\n private channel?: ReturnType<typeof this.addChannel>\n private syncResponseDelay: number\n private serverPeerId: PeerID\n private serverName: string\n\n /**\n * Callback invoked when a sync-request is received.\n * Useful for tests that need to know when to deliver responses.\n */\n public onSyncRequestReceived?: (docId: string) => void\n\n constructor(options: DelayedNetworkAdapterOptions) {\n super({ adapterType: \"delayed-network\" })\n this.syncResponseDelay = options.syncResponseDelay\n this.serverPeerId = options.serverPeerId ?? (\"server\" as PeerID)\n this.serverName = options.serverName ?? \"server\"\n }\n\n protected generate(): GeneratedChannel {\n return {\n kind: \"network\",\n adapterType: this.adapterType,\n send: (msg: ChannelMsg) => {\n // Intercept sync-request to notify test\n if (msg.type === \"channel/sync-request\") {\n this.onSyncRequestReceived?.(msg.docId)\n }\n },\n stop: () => {\n // No-op\n },\n }\n }\n\n async onStart(): Promise<void> {\n // Create and establish channel immediately (simulating WebSocket connect)\n this.channel = this.addChannel()\n this.establishChannel(this.channel.channelId)\n\n // Simulate server responding to establish-request\n this.channel.onReceive({\n type: \"channel/establish-response\",\n identity: {\n peerId: this.serverPeerId,\n name: this.serverName,\n type: \"service\",\n },\n })\n }\n\n async onStop(): Promise<void> {\n if (this.channel) {\n this.removeChannel(this.channel.channelId)\n }\n }\n\n /**\n * Simulate the server sending a sync-response with document data.\n *\n * @param docId - The document ID\n * @param data - The document snapshot data (from loroDoc.export({ mode: \"snapshot\" }))\n */\n async deliverSyncResponse(docId: string, data: Uint8Array): Promise<void> {\n if (!this.channel) {\n throw new Error(\"Channel not established\")\n }\n\n // Wait for the configured delay\n await new Promise(resolve => setTimeout(resolve, this.syncResponseDelay))\n\n // Import the data into a temporary doc to get the version\n const tempDoc = new LoroDoc()\n tempDoc.import(data)\n\n // Deliver the sync-response\n this.channel.onReceive({\n type: \"channel/sync-response\",\n docId,\n transmission: {\n type: \"snapshot\",\n data,\n version: tempDoc.version(),\n },\n })\n }\n\n /**\n * Simulate the server responding that it doesn't have the document.\n *\n * @param docId - The document ID\n */\n async deliverUnavailable(docId: string): Promise<void> {\n if (!this.channel) {\n throw new Error(\"Channel not established\")\n }\n\n await new Promise(resolve => setTimeout(resolve, this.syncResponseDelay))\n\n this.channel.onReceive({\n type: \"channel/sync-response\",\n docId,\n transmission: {\n type: \"unavailable\",\n },\n })\n }\n}\n","import type { VersionVector } from \"loro-crdt\"\nimport type {\n AdapterType,\n ChannelId,\n DocId,\n PeerID,\n PeerIdentityDetails,\n} from \"./types.js\"\n\nexport type { ChannelId } from \"./types.js\"\n\nexport type SyncTransmission =\n | {\n // An empty transmission, caused by a sync request--but the peer realized there is no new data to send in the sync response\n type: \"up-to-date\"\n version: VersionVector\n }\n | {\n // If needed, a complete snapshot can be sent--e.g. on first sync\n type: \"snapshot\"\n data: Uint8Array\n version: VersionVector\n }\n | {\n // Once peers are in sync, sending updates is sufficient\n type: \"update\"\n data: Uint8Array\n version: VersionVector\n }\n | {\n // A request to sync can be made to a peer, but that peer may decide not to respond (e.g. due to rules), or have nothing to respond with\n // (e.g. docId is not in storage)\n type: \"unavailable\"\n }\n\n/**\n * BARE network message types\n *\n * These contain individual message type data, but no senderId nor targetIds.\n */\n\nexport type ChannelMsgEstablishRequest = {\n type: \"channel/establish-request\"\n identity: PeerIdentityDetails\n}\n\nexport type ChannelMsgEstablishResponse = {\n type: \"channel/establish-response\"\n identity: PeerIdentityDetails\n}\n\n/**\n * Per-peer ephemeral store data; always associated with a docId (room).\n * Used in all ephemeral-related messages (sync-request, sync-response, channel/ephemeral).\n */\nexport type EphemeralStoreData = {\n peerId: PeerID\n data: Uint8Array\n /**\n * Namespace for the store (e.g., 'presence', 'cursors', 'mouse').\n * Required for the unified ephemeral store model.\n */\n namespace: string\n}\n\n/**\n * Request to sync a single document with a peer.\n *\n * When multiple documents need to be synced, wrap multiple sync-request\n * messages in a channel/batch message.\n */\nexport type ChannelMsgSyncRequest = {\n type: \"channel/sync-request\"\n docId: DocId\n requesterDocVersion: VersionVector\n /** Requester's ephemeral state for this doc (my presence data) */\n ephemeral?: EphemeralStoreData[]\n /**\n * Whether the receiver should send a reciprocal sync-request back.\n * - initiating sync-request should set bidirectional to `true`\n * - reciprocal sync-request should set bidirectional to `false`\n *\n * Set to false to prevent infinite loops when sending reciprocal requests.\n */\n bidirectional: boolean\n}\n\nexport type ChannelMsgSyncResponse = {\n type: \"channel/sync-response\"\n docId: DocId\n transmission: SyncTransmission\n /** Responder's ephemeral snapshot (all known peers' presence data) */\n ephemeral?: EphemeralStoreData[]\n}\n\nexport type ChannelMsgUpdate = {\n type: \"channel/update\"\n docId: DocId\n transmission: SyncTransmission\n}\n\nexport type ChannelMsgDirectoryRequest = {\n type: \"channel/directory-request\"\n docIds?: DocId[]\n}\n\nexport type ChannelMsgDirectoryResponse = {\n type: \"channel/directory-response\"\n docIds: DocId[]\n}\n\n/**\n * Announce new documents to peers.\n *\n * This is an unsolicited message sent when a new document is created locally.\n * Peers can then decide whether to request the document data via sync-request.\n *\n * Note: This is different from directory-response, which is a response to\n * directory-request (for glob-based document discovery).\n */\nexport type ChannelMsgNewDoc = {\n type: \"channel/new-doc\"\n docIds: DocId[]\n}\n\nexport type ChannelMsgDeleteRequest = {\n type: \"channel/delete-request\"\n docId: DocId\n}\n\nexport type ChannelMsgDeleteResponse = {\n type: \"channel/delete-response\"\n docId: DocId\n status: \"deleted\" | \"ignored\"\n}\n\nexport type ChannelMsgEphemeral = {\n type: \"channel/ephemeral\"\n docId: DocId\n hopsRemaining: number\n /** Per-peer store data. Each entry is one peer's presence data for the document. */\n stores: EphemeralStoreData[]\n}\n\n/**\n * Batch multiple established messages into a single network transmission.\n *\n * This is a transport optimization that allows sending multiple messages\n * to the same peer in a single network payload. The receiver will dispatch\n * each inner message individually.\n *\n * Use cases:\n * - Batching multiple sync-requests after connection establishment\n * - Batching ephemeral messages for heartbeat (one batch per peer)\n * - Any scenario where multiple messages go to the same peer\n *\n * Note: Nested batches are not allowed (messages cannot contain ChannelMsgBatch).\n */\nexport type ChannelMsgBatch = {\n type: \"channel/batch\"\n messages: BatchableMsg[]\n}\n\n/**\n * Messages that can be included in a batch.\n * Excludes ChannelMsgBatch to prevent nested batches.\n */\nexport type BatchableMsg =\n | ChannelMsgSyncRequest\n | ChannelMsgSyncResponse\n | ChannelMsgUpdate\n | ChannelMsgDirectoryRequest\n | ChannelMsgDirectoryResponse\n | ChannelMsgNewDoc\n | ChannelMsgDeleteRequest\n | ChannelMsgDeleteResponse\n | ChannelMsgEphemeral\n\nexport type AddressedEstablishmentEnvelope = {\n toChannelIds: ChannelId[]\n message: EstablishmentMsg\n}\n/**\n * A channel message wrapped in target channelIds to send the message to\n *\n * These augment bare network messages with targetIds, giving the message addressable recipients.\n */\n\nexport type AddressedEstablishedEnvelope = {\n toChannelIds: ChannelId[]\n message: EstablishedMsg\n}\n\nexport type AddressedEnvelope = {\n toChannelIds: ChannelId[]\n message: ChannelMsg\n}\n\nexport type ReturnEnvelope = {\n fromChannelId: ChannelId\n message: ChannelMsg\n}\n\n/**\n * BARE, ADDRESSED, and REGULAR network message union types\n *\n * These are probably what you're looking for--a way to annotate the type of message.\n */\n\n/**\n * Message type unions based on valid channel states\n */\n\n/** Messages valid during the establishment phase (ConnectedChannel) */\nexport type EstablishmentMsg =\n | ChannelMsgEstablishRequest\n | ChannelMsgEstablishResponse\n\n/** Messages valid after establishment is complete (Channel with peerId) */\nexport type EstablishedMsg =\n | ChannelMsgSyncRequest\n | ChannelMsgSyncResponse\n | ChannelMsgUpdate\n | ChannelMsgDirectoryRequest\n | ChannelMsgDirectoryResponse\n | ChannelMsgNewDoc\n | ChannelMsgDeleteRequest\n | ChannelMsgDeleteResponse\n | ChannelMsgEphemeral\n | ChannelMsgBatch\n\n/** All channel messages */\nexport type ChannelMsg = EstablishmentMsg | EstablishedMsg\n\n/**\n * Type predicate to check if a message is an establishment message.\n */\nexport function isEstablishmentMsg(msg: ChannelMsg): msg is EstablishmentMsg {\n return (\n msg.type === \"channel/establish-request\" ||\n msg.type === \"channel/establish-response\"\n )\n}\n\n/**\n * Type predicate to check if a message requires an established channel.\n */\nexport function isEstablishedMsg(msg: ChannelMsg): msg is EstablishedMsg {\n return !isEstablishmentMsg(msg)\n}\n\n/**\n * A `GeneratedChannel` is created by an adapter's generate() method.\n * It has metadata and actions but no connection to the synchronizer yet.\n *\n * biome-ignore format: left-align\n */\nexport type GeneratedChannel =\n & ChannelMeta\n & ChannelActions\n\n/**\n * A `ConnectedChannel` is registered with the synchronizer and can send/receive messages.\n * It has a channelId and an onReceive handler.\n *\n * biome-ignore format: left-align\n */\nexport type ConnectedChannel =\n & GeneratedChannel\n & ChannelIdentity\n & {\n type: 'connected',\n\n /**\n * Receive handler for incoming messages.\n * Set by the Synchronizer when the channel is added.\n */\n onReceive: (msg: ChannelMsg) => void\n\n /**\n * Type-safe send for establishment phase messages.\n * Only establishment messages can be sent before the channel is established.\n */\n send: (msg: EstablishmentMsg) => void\n }\n\n/**\n * A `Channel` is a ConnectedChannel that has completed the establish handshake\n * and knows which peer it's connected to.\n *\n * Examples of different kinds of channels:\n * - storage: we need to send a request to a database to get a document out of storage\n * - network: we need to send a request for a sync from a peer\n *\n * biome-ignore format: left-align\n */\nexport type EstablishedChannel =\n & GeneratedChannel\n & ChannelIdentity\n & {\n type: 'established'\n\n peerId: PeerID\n\n /**\n * Receive handler for incoming messages.\n * Set by the Synchronizer when the channel is added.\n */\n onReceive: (msg: ChannelMsg) => void\n\n /**\n * Type-safe send for established channel messages.\n * Only sync/directory/delete messages can be sent after establishment.\n */\n send: (msg: EstablishedMsg) => void\n }\n\nexport type Channel = ConnectedChannel | EstablishedChannel\n\n/**\n * Type guard to check if a Channel has been established with a peer.\n */\nexport function isEstablished(channel: Channel): channel is EstablishedChannel {\n return channel.type === \"established\"\n}\n\nexport type ChannelMeta = {\n kind: ChannelKind\n adapterType: AdapterType\n}\n\nexport type ChannelIdentity = {\n channelId: ChannelId\n}\n\nexport type ChannelActions = {\n /**\n * Generic send method for channel messages.\n *\n * ⚠️ WARNING: This method does not enforce type safety at compile time.\n * Prefer using `sendEstablishment()` or `sendEstablished()` for type-safe sends.\n *\n * This method is kept for internal use where the caller is responsible for\n * ensuring messages are sent to channels in the correct state.\n */\n send: (msg: ChannelMsg) => void\n stop: () => void\n}\n\n/**\n * The minimal return type for adapter's generateActions() method.\n * Adapters only need to provide send/stop - the adapter base class\n * adds kind and adapterType automatically.\n */\nexport type GeneratedChannelActions = ChannelActions\n\nexport type ChannelKind = \"storage\" | \"network\" | \"other\"\n\nexport type ReceiveFn = (msg: ChannelMsg) => void\n\n/**\n * @deprecated Channels are now ready-on-creation, no lifecycle callbacks needed\n * A set of callbacks for the channel to report its lifecycle events\n * to the Synchronizer. This allows the Synchronizer to manage connection state.\n */\nexport interface ChannelLifecycle {\n /** The channel is now connected and ready to send messages. */\n onReady: () => void\n /** An error occurred in the channel. */\n onError: (error: Error) => void\n /** The channel has disconnected. */\n onDisconnect: () => void\n}\n\nexport type GenerateFn<G> = (context: G) => GeneratedChannel\n","// packages/repo/src/channel-serialization.ts\n\nimport { VersionVector } from \"loro-crdt\"\nimport type { BatchableMsg, ChannelMsg, SyncTransmission } from \"./channel.js\"\nimport type { PeerID } from \"./types.js\"\n\n/**\n * JSON-serializable version of VersionVector\n */\nexport type VersionVectorJSON = Record<PeerID, number>\n\n/**\n * JSON-serializable version of Uint8Array (base64 encoded)\n */\nexport type BinaryDataJSON = string\n\n/**\n * JSON-serializable version of SyncTransmission\n */\nexport type SyncTransmissionJSON =\n | {\n type: \"up-to-date\"\n version: VersionVectorJSON\n }\n | {\n type: \"snapshot\"\n data: BinaryDataJSON\n version: VersionVectorJSON\n }\n | {\n type: \"update\"\n data: BinaryDataJSON\n version: VersionVectorJSON\n }\n | {\n type: \"unavailable\"\n }\n\n/**\n * JSON-serializable version of EphemeralPeerData\n */\nexport type EphemeralPeerDataJSON = {\n peerId: PeerID\n data: BinaryDataJSON\n namespace: string\n}\n\n/**\n * JSON-serializable version of EphemeralStoreData\n */\nexport type EphemeralStoreDataJSON = {\n peerId: PeerID\n data: BinaryDataJSON\n namespace: string\n}\n\n/**\n * JSON-serializable versions of all channel messages\n */\nexport type ChannelMsgJSON =\n | {\n type: \"channel/establish-request\"\n identity: {\n peerId: PeerID\n name: string\n }\n }\n | {\n type: \"channel/establish-response\"\n identity: {\n peerId: PeerID\n name: string\n }\n }\n | {\n type: \"channel/sync-request\"\n docId: string\n requesterDocVersion: VersionVectorJSON\n ephemeral?: EphemeralPeerDataJSON[]\n bidirectional: boolean\n }\n | {\n type: \"channel/sync-response\"\n docId: string\n transmission: SyncTransmissionJSON\n ephemeral?: EphemeralPeerDataJSON[]\n }\n | {\n type: \"channel/update\"\n docId: string\n transmission: SyncTransmissionJSON\n }\n | {\n type: \"channel/directory-request\"\n docIds?: string[]\n }\n | {\n type: \"channel/directory-response\"\n docIds: string[]\n }\n | {\n type: \"channel/new-doc\"\n docIds: string[]\n }\n | {\n type: \"channel/delete-request\"\n docId: string\n }\n | {\n type: \"channel/delete-response\"\n docId: string\n status: \"deleted\" | \"ignored\"\n }\n | {\n type: \"channel/ephemeral\"\n docId: string\n hopsRemaining: number\n stores: EphemeralStoreDataJSON[]\n }\n | {\n type: \"channel/batch\"\n messages: BatchableMsgJSON[]\n }\n\n/**\n * JSON-serializable version of BatchableMsg (all established messages except batch itself)\n */\nexport type BatchableMsgJSON = Exclude<\n ChannelMsgJSON,\n { type: \"channel/batch\" }\n>\n\n/**\n * Utility functions for serialization\n */\n\nexport function versionVectorToJSON(vv: VersionVector): VersionVectorJSON {\n const map = vv.toJSON()\n const obj: VersionVectorJSON = {}\n for (const [peer, counter] of map.entries()) {\n obj[peer] = counter\n }\n return obj\n}\n\nexport function versionVectorFromJSON(json: VersionVectorJSON): VersionVector {\n const map = new Map<PeerID, number>(\n Object.entries(json) as [`${number}`, number][],\n )\n return VersionVector.parseJSON(map)\n}\n\nexport function uint8ArrayToJSON(data: Uint8Array): BinaryDataJSON {\n // Convert to base64 for JSON serialization\n // Use chunked processing to avoid stack overflow with large arrays\n\n // For small arrays, use the simple approach\n if (data.length < 8192) {\n return btoa(String.fromCharCode(...data))\n }\n\n // For large arrays, process in chunks to avoid stack overflow\n const CHUNK_SIZE = 8192\n let binary = \"\"\n\n for (let i = 0; i < data.length; i += CHUNK_SIZE) {\n const chunk = data.subarray(i, Math.min(i + CHUNK_SIZE, data.length))\n binary += String.fromCharCode.apply(null, chunk as unknown as number[])\n }\n\n return btoa(binary)\n}\n\nexport function uint8ArrayFromJSON(json: BinaryDataJSON): Uint8Array {\n // Convert from base64\n const binary = atob(json)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return bytes\n}\n\n/**\n * Serialize a channel message to JSON-compatible format\n */\nexport function serializeChannelMsg(msg: ChannelMsg): ChannelMsgJSON {\n switch (msg.type) {\n case \"channel/establish-request\":\n case \"channel/establish-response\":\n case \"channel/directory-request\":\n case \"channel/directory-response\":\n case \"channel/new-doc\":\n case \"channel/delete-request\":\n case \"channel/delete-response\":\n // These messages don't contain VersionVector or Uint8Array\n return msg as ChannelMsgJSON\n\n case \"channel/sync-request\": {\n const result: ChannelMsgJSON = {\n type: msg.type,\n docId: msg.docId,\n requesterDocVersion: versionVectorToJSON(msg.requesterDocVersion),\n bidirectional: msg.bidirectional,\n }\n if (msg.ephemeral && msg.ephemeral.length > 0) {\n result.ephemeral = msg.ephemeral.map(ep => ({\n peerId: ep.peerId,\n data: uint8ArrayToJSON(ep.data),\n namespace: ep.namespace,\n }))\n }\n return result\n }\n\n case \"channel/sync-response\": {\n const result: ChannelMsgJSON = {\n type: msg.type,\n docId: msg.docId,\n transmission: serializeSyncTransmission(msg.transmission),\n }\n if (msg.ephemeral && msg.ephemeral.length > 0) {\n result.ephemeral = msg.ephemeral.map(ep => ({\n peerId: ep.peerId,\n data: uint8ArrayToJSON(ep.data),\n namespace: ep.namespace,\n }))\n }\n return result\n }\n\n case \"channel/update\":\n return {\n ...msg,\n transmission: serializeSyncTransmission(msg.transmission),\n }\n\n case \"channel/ephemeral\":\n return {\n ...msg,\n stores: msg.stores.map(s => ({\n peerId: s.peerId,\n data: uint8ArrayToJSON(s.data),\n namespace: s.namespace,\n })),\n }\n\n case \"channel/batch\":\n return {\n type: \"channel/batch\",\n messages: msg.messages.map(\n m => serializeChannelMsg(m) as BatchableMsgJSON,\n ),\n }\n }\n}\n\nfunction serializeSyncTransmission(\n transmission: SyncTransmission,\n): SyncTransmissionJSON {\n switch (transmission.type) {\n case \"up-to-date\":\n return {\n type: \"up-to-date\",\n version: versionVectorToJSON(transmission.version),\n }\n case \"snapshot\":\n return {\n type: \"snapshot\",\n data: uint8ArrayToJSON(transmission.data),\n version: versionVectorToJSON(transmission.version),\n }\n case \"update\":\n return {\n type: \"update\",\n data: uint8ArrayToJSON(transmission.data),\n version: versionVectorToJSON(transmission.version),\n }\n case \"unavailable\":\n return { type: \"unavailable\" }\n }\n}\n\n/**\n * Deserialize a JSON-compatible message back to channel message\n */\nexport function deserializeChannelMsg(json: ChannelMsgJSON): ChannelMsg {\n switch (json.type) {\n case \"channel/establish-request\":\n case \"channel/establish-response\":\n case \"channel/directory-request\":\n case \"channel/directory-response\":\n case \"channel/new-doc\":\n case \"channel/delete-request\":\n case \"channel/delete-response\":\n return json as ChannelMsg\n\n case \"channel/sync-request\": {\n const result: ChannelMsg = {\n type: json.type,\n docId: json.docId,\n requesterDocVersion: versionVectorFromJSON(json.requesterDocVersion),\n bidirectional: json.bidirectional,\n }\n if (json.ephemeral && json.ephemeral.length > 0) {\n result.ephemeral = json.ephemeral.map(ep => ({\n peerId: ep.peerId,\n data: uint8ArrayFromJSON(ep.data),\n namespace: ep.namespace,\n }))\n }\n return result\n }\n\n case \"channel/sync-response\": {\n const result: ChannelMsg = {\n type: json.type,\n docId: json.docId,\n transmission: deserializeSyncTransmission(json.transmission),\n }\n if (json.ephemeral && json.ephemeral.length > 0) {\n result.ephemeral = json.ephemeral.map(ep => ({\n peerId: ep.peerId,\n data: uint8ArrayFromJSON(ep.data),\n namespace: ep.namespace,\n }))\n }\n return result\n }\n\n case \"channel/update\":\n return {\n ...json,\n transmission: deserializeSyncTransmission(json.transmission),\n }\n\n case \"channel/ephemeral\":\n return {\n ...json,\n stores: json.stores.map(s => ({\n peerId: s.peerId,\n data: uint8ArrayFromJSON(s.data),\n namespace: s.namespace,\n })),\n }\n\n case \"channel/batch\":\n return {\n type: \"channel/batch\",\n messages: json.messages.map(\n m => deserializeChannelMsg(m) as BatchableMsg,\n ),\n }\n }\n}\n\nfunction deserializeSyncTransmission(\n json: SyncTransmissionJSON,\n): SyncTransmission {\n switch (json.type) {\n case \"up-to-date\":\n return {\n type: \"up-to-date\",\n version: versionVectorFromJSON(json.version),\n }\n case \"snapshot\":\n return {\n type: \"snapshot\",\n data: uint8ArrayFromJSON(json.data),\n version: versionVectorFromJSON(json.version),\n }\n case \"update\":\n return {\n type: \"update\",\n data: uint8ArrayFromJSON(json.data),\n version: versionVectorFromJSON(json.version),\n }\n case \"unavailable\":\n return { type: \"unavailable\" }\n }\n}\n","import { getLogger, type Logger } from \"@logtape/logtape\"\nimport type {\n DocShape,\n Infer,\n Mutable,\n ValueShape,\n} from \"@loro-extended/change\"\nimport {\n compileToJsonPath,\n createPathBuilder,\n createTypedDoc,\n evaluatePath,\n hasWildcard,\n loro,\n type PathBuilder,\n type PathSelector,\n type TypedDoc,\n} from \"@loro-extended/change\"\nimport type { EphemeralStore, Listener, LoroDoc, Value } from \"loro-crdt\"\nimport type { Synchronizer } from \"./synchronizer.js\"\nimport type { DocId, ReadyState } from \"./types.js\"\nimport { equal } from \"./utils/equal.js\"\nimport { withTimeout } from \"./utils/with-timeout.js\"\n\n/**\n * Custom predicate for determining readiness.\n */\nexport type ReadinessCheck = (readyStates: ReadyState[]) => boolean\n\n/**\n * Options for waitForSync().\n */\nexport type WaitForSyncOptions = {\n /**\n * The kind of channel to wait for.\n * @default \"network\"\n */\n kind?: \"network\" | \"storage\"\n\n /**\n * Timeout in milliseconds. Set to 0 to disable timeout.\n * @default 30000\n */\n timeout?: number\n\n /**\n * Optional AbortSignal for cancellation.\n * If aborted, the promise rejects with an AbortError.\n */\n signal?: AbortSignal\n}\n\n/**\n * Error thrown when waitForSync() times out.\n */\nexport class SyncTimeoutError extends Error {\n constructor(\n public readonly kind: \"network\" | \"storage\",\n public readonly timeoutMs: number,\n public readonly docId: string,\n public readonly lastSeenStates?: ReadyState[],\n ) {\n super(\n `waitForSync({ kind: '${kind}' }) timed out after ${timeoutMs}ms for document '${docId}'. ` +\n `No ${kind} peer completed sync within the timeout period.`,\n )\n this.name = \"SyncTimeoutError\"\n }\n}\n\n/**\n * Error thrown when waitForSync() is called but no adapters of the requested kind exist.\n */\nexport class NoAdaptersError extends Error {\n constructor(\n public readonly kind: \"network\" | \"storage\",\n public readonly docId: string,\n ) {\n super(\n `waitForSync({ kind: '${kind}' }) called for document '${docId}' but no ${kind} adapters are configured. ` +\n `Add a ${kind} adapter to the Repo before calling waitForSync().`,\n )\n this.name = \"NoAdaptersError\"\n }\n}\n\n/**\n * Shape for ephemeral store declarations.\n * Each key becomes a TypedEphemeral property on the handle.\n */\nexport type EphemeralDeclarations = Record<string, ValueShape>\n\n/**\n * TypedEphemeral provides type-safe access to an ephemeral store.\n * All ephemeral stores are shared key-value stores where keys can be anything\n * (often peerIds, but not required).\n */\nexport interface TypedEphemeral<T> {\n // ═══════════════════════════════════════════════════════════════\n // Core API - Shared key-value store\n // ═══════════════════════════════════════════════════════════════\n\n /** Set a value for any key */\n set(key: string, value: T): void\n\n /** Get a value by key */\n get(key: string): T | undefined\n\n /** Get all key-value pairs */\n getAll(): Map<string, T>\n\n /** Delete a key */\n delete(key: string): void\n\n // ═══════════════════════════════════════════════════════════════\n // Convenience API - For the common per-peer pattern\n // ═══════════════════════════════════════════════════════════════\n\n /** Get my value: equivalent to get(myPeerId) */\n readonly self: T | undefined\n\n /** Set my value: equivalent to set(myPeerId, value) */\n setSelf(value: T): void\n\n /** Get all peers except me */\n readonly peers: Map<string, T>\n\n // ═══════════════════════════════════════════════════════════════\n // Subscription\n // ═══════════════════════════════════════════════════════════════\n\n /** Subscribe to changes */\n subscribe(\n cb: (event: {\n key: string\n value: T | undefined\n source: \"local\" | \"remote\" | \"initial\"\n }) => void,\n ): () => void\n\n // ═══════════════════════════════════════════════════════════════\n // Escape Hatch\n // ═══════════════════════════════════════════════════════════════\n\n /** Access the underlying loro-crdt EphemeralStore */\n readonly raw: EphemeralStore\n}\n\n/**\n * Creates a TypedEphemeral wrapper around an EphemeralStore.\n *\n * Note: Broadcasting is handled automatically by the Synchronizer's subscription\n * to the store. When store.set() is called, the subscription fires with\n * by='local' and triggers the broadcast.\n */\nexport function createTypedEphemeral<T>(\n store: EphemeralStore,\n myPeerId: string,\n _shape: ValueShape, // For future validation\n): TypedEphemeral<T> {\n return {\n set(key: string, value: T): void {\n store.set(key, value as Value)\n },\n\n get(key: string): T | undefined {\n return store.get(key) as T | undefined\n },\n\n getAll(): Map<string, T> {\n const states = store.getAllStates()\n const result = new Map<string, T>()\n for (const [key, value] of Object.entries(states)) {\n result.set(key, value as T)\n }\n return result\n },\n\n delete(key: string): void {\n store.delete(key)\n },\n\n get self(): T | undefined {\n return store.get(myPeerId) as T | undefined\n },\n\n setSelf(value: T): void {\n store.set(myPeerId, value as Value)\n },\n\n get peers(): Map<string, T> {\n const states = store.getAllStates()\n const result = new Map<string, T>()\n for (const [key, value] of Object.entries(states)) {\n if (key !== myPeerId) {\n result.set(key, value as T)\n }\n }\n return result\n },\n\n subscribe(\n cb: (event: {\n key: string\n value: T | undefined\n source: \"local\" | \"remote\" | \"initial\"\n }) => void,\n ): () => void {\n // Track previous state to detect actual changes\n let previousStates: Record<string, unknown> = {}\n\n // Call immediately with current state for each key\n const initialStates = store.getAllStates()\n for (const [key, value] of Object.entries(initialStates)) {\n cb({ key, value: value as T, source: \"initial\" })\n }\n previousStates = { ...initialStates }\n\n // Subscribe to future changes\n return store.subscribe(event => {\n const source = event.by === \"local\" ? \"local\" : \"remote\"\n const currentStates = store.getAllStates()\n\n // Find keys that were added or changed\n for (const [key, value] of Object.entries(currentStates)) {\n const prevValue = previousStates[key]\n if (!equal(value, prevValue)) {\n cb({ key, value: value as T, source })\n }\n }\n\n // Find keys that were deleted\n for (const key of Object.keys(previousStates)) {\n if (!(key in currentStates)) {\n cb({ key, value: undefined, source })\n }\n }\n\n // Update previous state\n previousStates = { ...currentStates }\n })\n },\n\n get raw(): EphemeralStore {\n return store\n },\n }\n}\n\n/**\n * Parameters for creating a Handle.\n */\ntype HandleParams<D extends DocShape, E extends EphemeralDeclarations> = {\n docId: DocId\n docShape: D\n ephemeralShapes?: E\n synchronizer: Synchronizer\n logger?: Logger\n}\n\n/**\n * A unified handle to a Loro document with typed ephemeral stores.\n *\n * This class provides:\n * - Type-safe document access via `.doc` (always a TypedDoc)\n * - Type-safe ephemeral store access via declared store names\n * - External store integration via `addEphemeral()` / `getEphemeral()`\n * - Sync infrastructure (readyStates, waitUntilReady, etc.)\n *\n * The Handle delegates ephemeral store management to the Synchronizer,\n * which is the single source of truth for all stores.\n *\n * @typeParam D - The document shape (use Shape.any() for untyped)\n * @typeParam E - The ephemeral store declarations\n */\nexport class Handle<\n D extends DocShape,\n E extends EphemeralDeclarations = Record<string, never>,\n> {\n /**\n * The document ID.\n */\n public readonly docId: DocId\n\n /**\n * The peer ID of the local peer.\n */\n public readonly peerId: string\n\n /**\n * The Synchronizer for network operations.\n * This is the single source of truth for ephemeral stores.\n */\n private readonly synchronizer: Synchronizer\n\n /**\n * Logger instance.\n */\n private readonly logger: Logger\n\n /**\n * The document shape.\n */\n private readonly _docShape: D\n\n /**\n * The typed document.\n */\n private readonly _doc: TypedDoc<D>\n\n /**\n * Ephemeral shapes for declared stores.\n * Used to create TypedEphemeral wrappers on-demand.\n */\n private readonly _ephemeralShapes: E | undefined\n\n /**\n * Cache for TypedEphemeral wrappers.\n * Created on-demand and cached for performance.\n */\n private readonly _typedEphemeralCache: Map<string, TypedEphemeral<unknown>> =\n new Map()\n\n constructor({\n docId,\n docShape,\n ephemeralShapes,\n synchronizer,\n logger,\n }: HandleParams<D, E>) {\n this.docId = docId\n this.synchronizer = synchronizer\n this.peerId = synchronizer.identity.peerId\n this._docShape = docShape\n this._ephemeralShapes = ephemeralShapes\n\n this.logger = (logger ?? getLogger([\"@loro-extended\", \"repo\"])).with({\n docId,\n })\n\n // Ensure document state exists\n const docState = synchronizer.getOrCreateDocumentState(docId)\n\n // Create TypedDoc wrapper around the LoroDoc\n this._doc = createTypedDoc(docShape, { doc: docState.doc })\n\n // Pre-create stores in Synchronizer for declared ephemeral shapes\n // This ensures the stores exist and are subscribed for network sync\n if (ephemeralShapes) {\n for (const name of Object.keys(ephemeralShapes)) {\n synchronizer.getOrCreateNamespacedStore(docId, name)\n }\n }\n\n this.logger.trace(\"new Handle\")\n }\n\n /**\n * Get or create a TypedEphemeral wrapper for a store.\n * The wrapper is cached for performance.\n */\n private _getOrCreateTypedEphemeral<T>(\n name: string,\n shape: ValueShape,\n ): TypedEphemeral<T> {\n let typed = this._typedEphemeralCache.get(name)\n if (!typed) {\n const store = this.synchronizer.getOrCreateNamespacedStore(\n this.docId,\n name,\n )\n typed = createTypedEphemeral(store, this.peerId, shape)\n this._typedEphemeralCache.set(name, typed)\n }\n return typed as TypedEphemeral<T>\n }\n\n // ═══════════════════════════════════════════════════════════════\n // Document Access\n // ═══════════════════════════════════════════════════════════════\n\n /**\n * The strongly-typed document.\n * Always returns a TypedDoc - use Shape.any() for untyped access.\n * Access raw LoroDoc via getLoroDoc() for untyped operations.\n */\n get doc(): TypedDoc<D> {\n return this._doc\n }\n\n /**\n * Get the underlying LoroDoc for direct, untyped access.\n * Use this when you need to perform operations not supported by the typed API,\n * or when working with Shape.any() documents.\n *\n * @returns The raw LoroDoc instance\n *\n * @example\n * ```typescript\n * const handle = repo.get('my-doc', Shape.any())\n * handle.loroDoc.getMap('root').set('key', 'value')\n * ```\n */\n get loroDoc(): LoroDoc {\n return loro(this._doc).doc\n }\n\n /**\n * Convenience method: change a set of mutations in a single commit.\n */\n change(fn: (draft: Mutable<D>) => void): TypedDoc<D> {\n return this._doc.change(fn)\n }\n\n // ═══════════════════════════════════════════════════════════════\n // Document Subscriptions\n // ═══════════════════════════════════════════════════════════════\n\n /**\n * Subscribe to all changes on the document.\n *\n * The listener receives a `LoroEventBatch` from loro-crdt containing:\n * - `by`: The origin of the change (\"local\", \"import\", or \"checkout\")\n * - `origin`: Optional string identifying the change source\n * - `currentTarget`: The container ID of the event receiver (undefined for root doc)\n * - `events`: Array of `LoroEvent` objects with container diffs\n * - `from`: The frontiers before the change\n * - `to`: The frontiers after the change\n *\n * @param listener - Callback invoked on each document change\n * @returns Unsubscribe function\n */\n subscribe(listener: Listener): () => void\n\n /**\n * Subscribe to changes at a specific path using the type-safe DSL.\n *\n * The callback receives:\n * - `value`: The current value at the path (properly typed)\n * - `prev`: The previous value (undefined on first call)\n *\n * This uses two-stage filtering:\n * 1. WASM-side: subscribeJsonpath for efficient path matching\n * 2. JS-side: Deep equality check to filter false positives\n *\n * @param selector - Path selector function using the DSL\n * @param listener - Callback receiving the typed value and previous value\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * handle.subscribe(\n * p => p.books.$each.title,\n * (titles, prev) => {\n * console.log(\"Titles changed from\", prev, \"to\", titles)\n * }\n * )\n * ```\n */\n subscribe<T>(\n selector: (path: PathBuilder<D>) => PathSelector<T>,\n listener: (value: T, prev: T | undefined) => void,\n ): () => void\n\n /**\n * Subscribe to changes that may affect a JSONPath query (escape hatch).\n *\n * Use this for complex queries not expressible in the DSL (filters, etc.).\n * Note: No type safety - callback receives unknown[].\n *\n * @param jsonpath - JSONPath expression (e.g., \"$.users[*].name\")\n * @param listener - Callback receiving the query result\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * // Subscribe to changes affecting books with price > 10\n * const unsubscribe = handle.subscribe(\n * \"$.books[?@.price>10].title\",\n * (titles) => {\n * console.log(\"Expensive book titles:\", titles);\n * }\n * );\n * ```\n */\n subscribe(jsonpath: string, listener: (value: unknown[]) => void): () => void\n\n // Implementation of subscribe overloads\n subscribe(\n listenerOrSelectorOrJsonpath:\n | Listener\n | ((path: PathBuilder<D>) => PathSelector<unknown>)\n | string,\n pathListener?:\n | ((value: unknown, prev: unknown | undefined) => void)\n | ((value: unknown[]) => void),\n ): () => void {\n // Case 1: Regular subscription (all changes)\n // A regular Listener takes 1 argument and has no second argument\n // A path selector function also takes 1 argument but MUST have a second argument (the listener)\n if (typeof listenerOrSelectorOrJsonpath === \"function\" && !pathListener) {\n return loro(this._doc).doc.subscribe(\n listenerOrSelectorOrJsonpath as Listener,\n )\n }\n\n // Case 2: Raw JSONPath string (escape hatch)\n if (typeof listenerOrSelectorOrJsonpath === \"string\") {\n const jsonpath = listenerOrSelectorOrJsonpath\n const loroDoc = loro(this._doc).doc\n\n if (!pathListener) {\n throw new Error(\"JSONPath subscription requires a listener callback\")\n }\n\n const wrappedCallback = () => {\n const value = loroDoc.JSONPath(jsonpath)\n ;(pathListener as (value: unknown[]) => void)(value)\n }\n\n return loroDoc.subscribeJsonpath(jsonpath, wrappedCallback)\n }\n\n // Case 3: Type-safe path selector DSL\n const selectorFn = listenerOrSelectorOrJsonpath as (\n path: PathBuilder<D>,\n ) => PathSelector<unknown>\n const listener = pathListener as (\n value: unknown,\n prev: unknown | undefined,\n ) => void\n\n if (!listener) {\n throw new Error(\"Path selector subscription requires a listener callback\")\n }\n\n const pathBuilder = createPathBuilder(this._docShape)\n const selector = selectorFn(pathBuilder)\n const jsonpath = compileToJsonPath(selector.__segments)\n const needsDeepEqual = hasWildcard(selector.__segments)\n\n // Establish initial previousValue baseline synchronously\n // This is critical for detecting if the first signaled event is a genuine change\n let previousValue: unknown = evaluatePath(this._doc, selector)\n\n const wrappedCallback = () => {\n const newValue = evaluatePath(this._doc, selector)\n\n // For paths with wildcards, we need deep equality to filter false positives\n // For exact paths, subscribeJsonpath is already precise\n if (needsDeepEqual && equal(newValue, previousValue)) {\n return // False positive, skip callback\n }\n\n const prev = previousValue\n previousValue = newValue\n listener(newValue, prev)\n }\n\n return loro(this._doc).doc.subscribeJsonpath(jsonpath, wrappedCallback)\n }\n\n /**\n * Execute a JSONPath query against the document.\n *\n * This is a general-purpose method for querying the document with full\n * JSONPath expressiveness. Use this for ad-hoc queries or within callbacks.\n *\n * @example\n * ```typescript\n * const expensiveBooks = handle.jsonPath(\"$.books[?@.price>10]\")\n * const allTitles = handle.jsonPath(\"$..title\")\n * ```\n */\n jsonPath(path: string): unknown[] {\n return loro(this._doc).doc.JSONPath(path)\n }\n\n // ═══════════════════════════════════════════════════════════════\n // Ephemeral Store Access\n // ═══════════════════════════════════════════════════════════════\n\n /**\n * Get a typed ephemeral store by name.\n * Only works for stores declared in ephemeralShapes.\n */\n getTypedEphemeral<K extends keyof E>(name: K): TypedEphemeral<Infer<E[K]>> {\n if (!this._ephemeralShapes || !(name in this._ephemeralShapes)) {\n throw new Error(`Ephemeral store \"${String(name)}\" not found`)\n }\n const shape = this._ephemeralShapes[name as string]\n return this._getOrCreateTypedEphemeral(name as string, shape)\n }\n\n /**\n * Add an external ephemeral store for network sync.\n * Use this for libraries that bring their own EphemeralStore (like loro-prosemirror).\n *\n * @param name - The store name (namespace)\n * @param store - The EphemeralStore to register\n */\n addEphemeral(name: string, store: EphemeralStore): void {\n // Check if store already exists in Synchronizer\n const existing = this.synchronizer.getNamespacedStore(this.docId, name)\n if (existing) {\n throw new Error(`Ephemeral store \"${name}\" already exists`)\n }\n\n // Register with synchronizer for network sync\n this.synchronizer.registerExternalStore(this.docId, name, store)\n\n this.logger.debug(\"Added external ephemeral store: {name}\", { name })\n }\n\n /**\n * Get a raw ephemeral store by name.\n * Delegates to Synchronizer which is the single source of truth.\n *\n * @param name - The store name\n * @returns The EphemeralStore or undefined if not found\n */\n getEphemeral(name: string): EphemeralStore | undefined {\n return this.synchronizer.getNamespacedStore(this.docId, name)\n }\n\n // ═══════════════════════════════════════════════════════════════\n // Sync Infrastructure\n // ═══════════════════════════════════════════════════════════════\n\n /**\n * Get the current ready states for this document.\n */\n get readyStates(): ReadyState[] {\n return this.synchronizer.readyStates.get(this.docId) ?? []\n }\n\n /**\n * Subscribe to ready state changes.\n * @param cb Callback that receives the new ready states\n * @returns Unsubscribe function\n */\n onReadyStateChange(cb: (readyStates: ReadyState[]) => void): () => void {\n return this.synchronizer.emitter.on(\"ready-state-changed\", event => {\n if (event.docId === this.docId) {\n cb(event.readyStates)\n }\n })\n }\n\n /**\n * Wait until the document meets custom readiness criteria.\n * @param predicate Function that determines if the document is ready\n */\n async waitUntilReady(predicate: ReadinessCheck): Promise<Handle<D, E>> {\n await this.synchronizer.waitUntilReady(this.docId, predicate)\n return this\n }\n\n /**\n * Wait for sync to complete with a peer of the specified kind.\n *\n * Resolves when we've completed the sync handshake with a peer:\n * - Received document data (peer state = \"loaded\")\n * - Peer confirmed it doesn't have the document (peer state = \"absent\")\n *\n * This enables the common \"initializeIfEmpty\" pattern:\n * ```typescript\n * await handle.waitForSync()\n * if (handle.loroDoc.opCount() === 0) {\n * // Server doesn't have it, safe to initialize\n * initializeDocument(handle)\n * }\n * ```\n *\n * @param options - Configuration options\n * @param options.kind - The kind of channel to wait for (\"network\" or \"storage\"). Default: \"network\"\n * @param options.timeout - Timeout in milliseconds. Set to 0 to disable. Default: 30000\n * @param options.signal - Optional AbortSignal for cancellation\n * @throws {NoAdaptersError} If no adapters of the requested kind are configured\n * @throws {SyncTimeoutError} If the timeout is reached before sync completes\n * @throws {DOMException} If the signal is aborted (name: \"AbortError\")\n */\n async waitForSync(options?: WaitForSyncOptions): Promise<Handle<D, E>> {\n const kind = options?.kind ?? \"network\"\n const timeout = options?.timeout ?? 30_000\n const signal = options?.signal\n\n // Check if any adapters of the requested kind are configured\n // This uses the adapter's `kind` property, not channels, to avoid\n // race conditions during startup when channels may not exist yet.\n const hasAdapterOfKind = this.synchronizer.adapters.adapters.some(\n adapter => adapter.kind === kind,\n )\n\n if (!hasAdapterOfKind) {\n throw new NoAdaptersError(kind, this.docId)\n }\n\n // Create the predicate that checks for sync completion\n const predicate = this.createSyncPredicate(kind)\n\n // Wait for sync with timeout and abort support\n const syncPromise = this.synchronizer.waitUntilReady(this.docId, predicate)\n\n await withTimeout(syncPromise, {\n timeoutMs: timeout,\n signal,\n createTimeoutError: () =>\n new SyncTimeoutError(\n kind,\n timeout,\n this.docId,\n this.synchronizer.readyStates.get(this.docId),\n ),\n })\n\n return this\n }\n\n /**\n * Creates a predicate for checking sync completion with a peer of the specified kind.\n */\n private createSyncPredicate(\n kind: \"network\" | \"storage\",\n ): (readyStates: ReadyState[]) => boolean {\n return (readyStates: ReadyState[]): boolean =>\n readyStates.some(s => {\n // Must be a remote peer (not ourselves)\n if (s.identity.peerId === this.peerId) {\n return false\n }\n\n // Must have a channel of the requested kind\n const hasChannelOfRequestedKind = s.channels.some(c => c.kind === kind)\n if (!hasChannelOfRequestedKind) {\n return false\n }\n\n // Accept both \"loaded\" (has data) and \"absent\" (confirmed no data)\n // \"aware\" means we know they exist but haven't completed sync yet\n return s.status === \"synced\" || s.status === \"absent\"\n })\n }\n}\n\n/**\n * Type helper to extract ephemeral store types from a Handle.\n * This allows accessing declared ephemeral stores as properties.\n */\nexport type HandleWithEphemerals<\n D extends DocShape,\n E extends EphemeralDeclarations,\n> = Handle<D, E> & {\n [K in keyof E]: TypedEphemeral<Infer<E[K]>>\n}\n\n/**\n * Creates a Handle with ephemeral stores accessible as properties.\n */\nexport function createHandle<\n D extends DocShape,\n E extends EphemeralDeclarations = Record<string, never>,\n>(params: HandleParams<D, E>): HandleWithEphemerals<D, E> {\n const handle = new Handle(params)\n\n // Create a proxy that exposes ephemeral stores as properties\n return new Proxy(handle, {\n get(target, prop, receiver) {\n // Check if it's an ephemeral store name\n if (\n typeof prop === \"string\" &&\n params.ephemeralShapes &&\n prop in params.ephemeralShapes\n ) {\n return target.getTypedEphemeral(prop as keyof E)\n }\n\n // Otherwise delegate to the handle\n return Reflect.get(target, prop, receiver)\n },\n\n has(target, prop) {\n if (\n typeof prop === \"string\" &&\n params.ephemeralShapes &&\n prop in params.ephemeralShapes\n ) {\n return true\n }\n return Reflect.has(target, prop)\n },\n\n // Support Object.keys() - filter out Symbol properties and include ephemeral stores\n // This prevents React's \"Object keys must be strings\" error and ensures\n // ephemeral stores appear in enumeration.\n ownKeys(target) {\n // Get string keys from the Handle class, filtering out Symbols\n const handleKeys = Reflect.ownKeys(target).filter(\n key => typeof key === \"string\",\n )\n\n // Add ephemeral store names if declared\n if (params.ephemeralShapes) {\n const ephemeralKeys = Object.keys(params.ephemeralShapes)\n return [...new Set([...handleKeys, ...ephemeralKeys])]\n }\n\n return handleKeys\n },\n\n getOwnPropertyDescriptor(target, prop) {\n // For ephemeral stores, return a descriptor that makes them enumerable\n if (\n typeof prop === \"string\" &&\n params.ephemeralShapes &&\n prop in params.ephemeralShapes\n ) {\n return {\n configurable: true,\n enumerable: true,\n value: target.getTypedEphemeral(prop as keyof E),\n }\n }\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n }) as HandleWithEphemerals<D, E>\n}\n","// biome-ignore-all lint/suspicious/noExplicitAny: provided by https://www.npmjs.com/package/fast-deep-equal\n// biome-ignore-all lint/suspicious/noImplicitAnyLet: provided by https://www.npmjs.com/package/fast-deep-equal\n// biome-ignore-all lint/suspicious/noDoubleEquals: original code does this\n\nimport { VersionVector } from \"loro-crdt\"\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function equal(a: any, b: any): boolean {\n if (a === b) return true\n\n if (a && b && typeof a == \"object\" && typeof b == \"object\") {\n if (a.constructor !== b.constructor) return false\n\n // Handle VersionVector from loro-crdt (WASM-backed objects)\n // These need special handling because their toString() returns \"[object Object]\"\n // and they don't have standard valueOf() behavior\n if (a instanceof VersionVector && b instanceof VersionVector) {\n // Use toJSON() which returns a Map, then compare the Maps\n return equal(a.toJSON(), b.toJSON())\n }\n\n let length: number, i: any, keys: string[]\n\n if (Array.isArray(a)) {\n length = a.length\n\n if (length != b.length) return false\n\n for (i = length; i-- !== 0; ) if (!equal(a[i], b[i])) return false\n\n return true\n }\n\n if (a instanceof Map && b instanceof Map) {\n if (a.size !== b.size) return false\n\n for (i of a.entries()) if (!b.has(i[0])) return false\n\n for (i of a.entries()) if (!equal(i[1], b.get(i[0]))) return false\n\n return true\n }\n\n if (a instanceof Set && b instanceof Set) {\n if (a.size !== b.size) return false\n\n for (i of a.entries()) if (!b.has(i[0])) return false\n\n return true\n }\n\n if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {\n length = a.byteLength\n\n if (length != b.byteLength) return false\n\n for (i = length; i-- !== 0; )\n if ((a as any)[i] !== (b as any)[i]) return false\n\n return true\n }\n\n if (a.constructor === RegExp)\n return a.source === b.source && a.flags === b.flags\n\n if (a.valueOf !== Object.prototype.valueOf)\n return a.valueOf() === b.valueOf()\n\n if (a.toString !== Object.prototype.toString)\n return a.toString() === b.toString()\n\n keys = Object.keys(a)\n\n length = keys.length\n\n if (length !== Object.keys(b).length) return false\n\n for (i = length; i-- !== 0; )\n // biome-ignore lint/suspicious/noPrototypeBuiltins: original code does this\n if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false\n\n for (i = length; i-- !== 0; ) {\n const key = keys[i]\n\n if (!equal(a[key], b[key])) return false\n }\n\n return true\n }\n\n // biome-ignore lint/suspicious/noSelfCompare: true if both NaN, false otherwise\n return a !== a && b !== b\n}\n","/**\n * Wraps a promise with a timeout that properly cleans up to avoid unhandled rejections.\n *\n * Unlike `Promise.race([promise, timeoutPromise])`, this implementation:\n * - Properly clears the timeout when the promise resolves/rejects\n * - Avoids unhandled rejection warnings from the timeout promise\n * - Supports AbortSignal for cancellation\n *\n * @param promise - The promise to wrap\n * @param options - Timeout options\n * @returns The result of the promise, or throws TimeoutError/AbortError\n *\n * @example\n * ```typescript\n * const result = await withTimeout(\n * fetchData(),\n * {\n * timeoutMs: 5000,\n * createTimeoutError: () => new Error(\"Fetch timed out\"),\n * }\n * )\n * ```\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n options: {\n /**\n * Timeout in milliseconds. Set to 0 to disable timeout.\n */\n timeoutMs: number\n\n /**\n * Factory function to create the timeout error.\n * Called only when timeout actually occurs.\n */\n createTimeoutError: () => Error\n\n /**\n * Optional AbortSignal for cancellation.\n * If aborted, the promise rejects with an AbortError.\n */\n signal?: AbortSignal\n },\n): Promise<T> {\n const { timeoutMs, createTimeoutError, signal } = options\n\n // If already aborted, reject immediately\n if (signal?.aborted) {\n throw new DOMException(\"Operation was aborted\", \"AbortError\")\n }\n\n // If timeout is 0, just wait for the promise (with abort support)\n if (timeoutMs === 0) {\n if (!signal) {\n return promise\n }\n\n // Wait for promise or abort\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n reject(new DOMException(\"Operation was aborted\", \"AbortError\"))\n }\n\n signal.addEventListener(\"abort\", onAbort, { once: true })\n\n promise\n .then(result => {\n signal.removeEventListener(\"abort\", onAbort)\n resolve(result)\n })\n .catch(err => {\n signal.removeEventListener(\"abort\", onAbort)\n reject(err)\n })\n })\n }\n\n // Race between promise, timeout, and abort\n return new Promise<T>((resolve, reject) => {\n let settled = false\n\n const cleanup = () => {\n settled = true\n clearTimeout(timeoutId)\n if (signal) {\n signal.removeEventListener(\"abort\", onAbort)\n }\n }\n\n const timeoutId = setTimeout(() => {\n if (!settled) {\n cleanup()\n reject(createTimeoutError())\n }\n }, timeoutMs)\n\n const onAbort = () => {\n if (!settled) {\n cleanup()\n reject(new DOMException(\"Operation was aborted\", \"AbortError\"))\n }\n }\n\n if (signal) {\n signal.addEventListener(\"abort\", onAbort, { once: true })\n }\n\n promise\n .then(result => {\n if (!settled) {\n cleanup()\n resolve(result)\n }\n })\n .catch(err => {\n if (!settled) {\n cleanup()\n reject(err)\n }\n })\n })\n}\n","/**\n * Rate Limiter Middleware\n *\n * Provides configurable rate limiting for incoming messages.\n * Uses a sliding window algorithm for smooth rate limiting.\n *\n * ## Features\n *\n * - **Per-peer rate limiting** - Each peer has their own rate limit\n * - **Sliding window** - Smooth rate limiting without burst issues\n * - **Configurable limits** - Set max requests per time window\n * - **Burst allowance** - Optional burst capacity for legitimate spikes\n * - **Auto-cleanup** - Removes stale peer data to prevent memory leaks\n *\n * ## Usage\n *\n * ```typescript\n * import { createRateLimiter } from '@loro-extended/repo'\n *\n * const repo = new Repo({\n * middleware: [\n * createRateLimiter({\n * maxRequests: 100, // Max 100 requests\n * windowMs: 60000, // Per minute\n * burstAllowance: 10, // Allow 10 extra in bursts\n * })\n * ]\n * })\n * ```\n *\n * @module\n */\n\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareResult,\n} from \"../middleware.js\"\n\n/**\n * Configuration options for the rate limiter.\n */\nexport type RateLimiterOptions = {\n /**\n * Maximum number of requests allowed per window.\n * @default 100\n */\n maxRequests?: number\n\n /**\n * Time window in milliseconds.\n * @default 60000 (1 minute)\n */\n windowMs?: number\n\n /**\n * Additional burst capacity above maxRequests.\n * Allows short bursts of traffic without rejection.\n * @default 0\n */\n burstAllowance?: number\n\n /**\n * How often to clean up stale peer data (in milliseconds).\n * Set to 0 to disable auto-cleanup.\n * @default 300000 (5 minutes)\n */\n cleanupIntervalMs?: number\n\n /**\n * Custom key function to determine rate limit grouping.\n * By default, rate limits are per-peer.\n * @default (ctx) => ctx.peer.peerId\n */\n keyFn?: (ctx: MiddlewareContext) => string\n\n /**\n * Custom handler for rate-limited requests.\n * Called when a request is rejected due to rate limiting.\n */\n onRateLimited?: (ctx: MiddlewareContext, info: RateLimitInfo) => void\n}\n\n/**\n * Information about the current rate limit state.\n */\nexport type RateLimitInfo = {\n /** Current request count in the window */\n current: number\n /** Maximum allowed requests */\n limit: number\n /** Milliseconds until the window resets */\n resetMs: number\n /** Whether this request was allowed */\n allowed: boolean\n}\n\n/**\n * Internal state for tracking request counts.\n */\ntype PeerRateState = {\n /** Timestamps of requests in the current window */\n timestamps: number[]\n /** Last activity time (for cleanup) */\n lastActivity: number\n}\n\n/**\n * Extended middleware interface with internal state access for testing.\n */\nexport interface RateLimiterMiddleware extends Middleware {\n /** Internal state map (for testing) */\n getState(): Map<string, PeerRateState>\n /** Cleanup function to stop intervals and clear state */\n cleanup(): void\n}\n\n/**\n * Creates a rate limiter middleware with the specified options.\n *\n * @param options - Configuration options\n * @returns A middleware that enforces rate limits\n *\n * @example\n * ```typescript\n * // Basic usage: 100 requests per minute\n * const rateLimiter = createRateLimiter({\n * maxRequests: 100,\n * windowMs: 60000,\n * })\n *\n * // With burst allowance\n * const rateLimiter = createRateLimiter({\n * maxRequests: 100,\n * windowMs: 60000,\n * burstAllowance: 20, // Allow up to 120 in bursts\n * })\n *\n * // Custom key function (rate limit by document instead of peer)\n * const rateLimiter = createRateLimiter({\n * maxRequests: 50,\n * windowMs: 60000,\n * keyFn: (ctx) => ctx.document?.id ?? 'unknown',\n * })\n * ```\n */\nexport function createRateLimiter(\n options: RateLimiterOptions = {},\n): RateLimiterMiddleware {\n const {\n maxRequests = 100,\n windowMs = 60000,\n burstAllowance = 0,\n cleanupIntervalMs = 300000,\n keyFn = (ctx: MiddlewareContext) => ctx.peer?.peerId ?? \"unknown\",\n onRateLimited,\n } = options\n\n // State: Map of key -> rate state\n const state = new Map<string, PeerRateState>()\n\n // Effective limit including burst\n const effectiveLimit = maxRequests + burstAllowance\n\n // Cleanup interval handle\n let cleanupInterval: ReturnType<typeof setInterval> | undefined\n\n // Start cleanup if enabled\n if (cleanupIntervalMs > 0) {\n cleanupInterval = setInterval(() => {\n const now = Date.now()\n const staleThreshold = now - windowMs * 2 // Remove if inactive for 2 windows\n\n for (const [key, peerState] of state) {\n if (peerState.lastActivity < staleThreshold) {\n state.delete(key)\n }\n }\n }, cleanupIntervalMs)\n\n // Don't prevent process exit\n if (cleanupInterval.unref) {\n cleanupInterval.unref()\n }\n }\n\n /**\n * Check if a request should be allowed and update state.\n */\n function checkRateLimit(key: string): RateLimitInfo {\n const now = Date.now()\n const windowStart = now - windowMs\n\n // Get or create state for this key\n let peerState = state.get(key)\n if (!peerState) {\n peerState = { timestamps: [], lastActivity: now }\n state.set(key, peerState)\n }\n\n // Remove timestamps outside the window\n peerState.timestamps = peerState.timestamps.filter(ts => ts > windowStart)\n peerState.lastActivity = now\n\n // Check if under limit\n const current = peerState.timestamps.length\n const allowed = current < effectiveLimit\n\n if (allowed) {\n // Record this request\n peerState.timestamps.push(now)\n }\n\n // Calculate reset time (when oldest request falls out of window)\n const oldestTimestamp = peerState.timestamps[0] ?? now\n const resetMs = Math.max(0, oldestTimestamp + windowMs - now)\n\n return {\n current: current + (allowed ? 1 : 0),\n limit: effectiveLimit,\n resetMs,\n allowed,\n }\n }\n\n function cleanup(): void {\n if (cleanupInterval) {\n clearInterval(cleanupInterval)\n cleanupInterval = undefined\n }\n state.clear()\n }\n\n return {\n name: \"rate-limiter\",\n requires: [\"peer\"],\n\n check(ctx: MiddlewareContext): MiddlewareResult {\n // Skip if no peer context (shouldn't happen with requires: ['peer'])\n if (!ctx.peer) {\n return { allow: true }\n }\n\n const key = keyFn(ctx)\n const info = checkRateLimit(key)\n\n if (!info.allowed) {\n // Call custom handler if provided\n onRateLimited?.(ctx, info)\n\n return {\n allow: false,\n reason: `Rate limit exceeded: ${info.current}/${info.limit} requests (resets in ${Math.ceil(info.resetMs / 1000)}s)`,\n }\n }\n\n return { allow: true }\n },\n\n // Expose for testing and manual cleanup\n getState: () => state,\n cleanup,\n }\n}\n\n/**\n * Extended middleware interface for message type rate limiter.\n */\nexport interface MessageTypeRateLimiterMiddleware extends Middleware {\n /** Cleanup function to stop intervals and clear state */\n cleanup(): void\n}\n\n/**\n * Creates a rate limiter that limits by message type.\n * Useful for limiting specific operations (e.g., sync-requests).\n *\n * @param messageTypes - Array of message types to rate limit\n * @param options - Rate limiter options\n * @returns A middleware that only rate limits specified message types\n *\n * @example\n * ```typescript\n * // Limit sync-requests to 10 per minute\n * const syncLimiter = createMessageTypeRateLimiter(\n * ['channel/sync-request'],\n * { maxRequests: 10, windowMs: 60000 }\n * )\n * ```\n */\nexport function createMessageTypeRateLimiter(\n messageTypes: string[],\n options: RateLimiterOptions = {},\n): MessageTypeRateLimiterMiddleware {\n const baseLimiter = createRateLimiter(options)\n const messageTypeSet = new Set(messageTypes)\n\n return {\n name: `rate-limiter:${messageTypes.join(\",\")}`,\n requires: [\"peer\"],\n\n async check(ctx: MiddlewareContext): Promise<MiddlewareResult> {\n // Only rate limit specified message types\n if (!messageTypeSet.has(ctx.message.type)) {\n return { allow: true }\n }\n\n // Await the result in case baseLimiter.check returns a Promise\n return await baseLimiter.check(ctx)\n },\n\n // Expose cleanup from base limiter\n cleanup: () => baseLimiter.cleanup(),\n }\n}\n","import type { Logger } from \"@logtape/logtape\"\nimport type { ChannelMsg } from \"./channel.js\"\nimport type { DocContext, PeerContext } from \"./permissions.js\"\n\n/**\n * Context available to middleware.\n *\n * The available fields depend on when the middleware runs:\n * - `peer` is always available\n * - `document` is available for document-specific messages\n * - `transmission` is available for sync-response and update messages\n */\nexport type MiddlewareContext = {\n /** The incoming message */\n message: ChannelMsg\n\n /** Information about the peer sending the message */\n peer: PeerContext\n\n /** Document context (if message is document-specific) */\n document?: DocContext\n\n /** Transmission metadata (if message contains document data) */\n transmission?: {\n type: \"snapshot\" | \"update\"\n sizeBytes: number\n }\n}\n\n/**\n * Result of a middleware check.\n */\nexport type MiddlewareResult =\n | { allow: true }\n | { allow: false; reason?: string }\n\n/**\n * Middleware for advanced access control and cross-cutting concerns.\n *\n * Middleware runs BEFORE the synchronizer processes messages, at the async boundary.\n * Use middleware for:\n * - Rate limiting\n * - Size limits\n * - External auth service integration\n * - Audit logging\n * - Message transformation\n *\n * For simple permission checks, use `permissions` instead.\n *\n * @example\n * ```typescript\n * // Sync middleware: rate limiting\n * const rateLimiter: Middleware = {\n * name: 'rate-limiter',\n * requires: ['peer'],\n * check: (ctx) => {\n * const count = getRequestCount(ctx.peer.peerId)\n * return count < 100 ? { allow: true } : { allow: false, reason: 'rate-limited' }\n * }\n * }\n *\n * // Async middleware: external auth\n * const externalAuth: Middleware = {\n * name: 'external-auth',\n * requires: ['peer'],\n * check: async (ctx) => {\n * const allowed = await authService.canAccess(ctx.peer.peerId)\n * return allowed ? { allow: true } : { allow: false, reason: 'unauthorized' }\n * }\n * }\n * ```\n */\nexport interface Middleware {\n /** Name for logging and debugging */\n name: string\n\n /**\n * Declare what context fields this middleware needs.\n *\n * The system uses this to determine when to run the middleware:\n * - `['peer']` or `['document']` → runs pre-receive (before payload processed)\n * - `['transmission']` → runs post-receive (after payload available)\n *\n * If not specified, middleware runs for all messages.\n */\n requires?: (\"peer\" | \"document\" | \"transmission\")[]\n\n /**\n * Check whether the message should be allowed.\n *\n * Can be sync or async - the system handles both.\n *\n * @param ctx - Context about the message and peer\n * @returns Whether to allow the message, optionally with a reason for rejection\n */\n check(ctx: MiddlewareContext): MiddlewareResult | Promise<MiddlewareResult>\n}\n\n/**\n * Run all middleware checks for a message.\n *\n * Middleware runs in registration order and short-circuits on first rejection.\n *\n * @param middleware - Array of middleware to run\n * @param ctx - Context for the middleware\n * @param logger - Logger for debugging\n * @returns The result of the middleware chain\n */\nexport async function runMiddleware(\n middleware: Middleware[],\n ctx: MiddlewareContext,\n logger: Logger,\n): Promise<MiddlewareResult> {\n for (const mw of middleware) {\n // Check if middleware should run based on its requirements\n if (mw.requires && mw.requires.length > 0) {\n const hasRequiredContext = mw.requires.every(req => {\n switch (req) {\n case \"peer\":\n return ctx.peer !== undefined\n case \"document\":\n return ctx.document !== undefined\n case \"transmission\":\n return ctx.transmission !== undefined\n default:\n return false\n }\n })\n\n if (!hasRequiredContext) {\n // Skip this middleware - required context not available\n continue\n }\n }\n\n try {\n const result = await mw.check(ctx)\n\n if (!result.allow) {\n logger.debug(\"Message dropped by middleware {name}: {reason}\", {\n name: mw.name,\n reason: result.reason ?? \"no reason provided\",\n })\n return result\n }\n } catch (error) {\n logger.error(\"Middleware {name} threw an error: {error}\", {\n name: mw.name,\n error,\n })\n // Fail closed: if middleware throws, reject the message\n return { allow: false, reason: `middleware error: ${mw.name}` }\n }\n }\n\n return { allow: true }\n}\n","import type { LoroDoc } from \"loro-crdt\"\nimport type { ChannelKind } from \"./channel.js\"\nimport type { ChannelId, DocId, PeerID } from \"./types.js\"\n\n/**\n * Context about the document being accessed.\n */\nexport type DocContext = {\n id: DocId\n doc: LoroDoc\n}\n\n/**\n * Context about the peer making the request.\n * Flat structure for ergonomic access (e.g., `peer.channelKind` not `peer.channel.kind`).\n */\nexport type PeerContext = {\n peerId: PeerID\n peerName?: string\n peerType: \"user\" | \"bot\" | \"service\"\n channelId: ChannelId\n channelKind: ChannelKind // \"storage\" | \"network\" | \"other\"\n}\n\n/**\n * Permissions control access to documents.\n *\n * Permissions are simple, synchronous predicates that determine what peers can do.\n * They run inside the synchronizer's TEA state machine.\n *\n * For advanced use cases (rate limiting, external auth, audit logging),\n * use middleware instead.\n *\n * @example\n * ```typescript\n * const repo = new Repo({\n * permissions: {\n * visibility: (doc, peer) => doc.id.startsWith('public/'),\n * mutability: (doc, peer) => peer.peerType !== 'bot',\n * deletion: (doc, peer) => peer.peerType === 'service',\n * }\n * })\n * ```\n */\nexport interface Permissions {\n /**\n * Who can discover this document exists?\n *\n * Called when:\n * - Responding to directory-request\n * - Propagating new documents to peers\n * - Sending sync-request to channels\n *\n * BYPASS: Skipped if peer is already subscribed to the document.\n * Rationale: Once a peer knows about a doc, you can't \"un-reveal\" it.\n *\n * @default () => true (reveal all docs)\n */\n visibility(doc: DocContext, peer: PeerContext): boolean\n\n /**\n * Who can modify this document?\n *\n * Called when:\n * - Receiving sync-response with document data\n * - Receiving channel/update messages\n *\n * NO BYPASS: Always checked, even for subscribed peers.\n * Rationale: Write permissions can change over time.\n *\n * @default () => true (allow all updates)\n */\n mutability(doc: DocContext, peer: PeerContext): boolean\n\n /**\n * Who can create new documents?\n *\n * Called when:\n * - Peer sends sync-request for a document that doesn't exist locally\n *\n * NO BYPASS: Always checked.\n * Rationale: Creation is a one-time event, no subscription context.\n *\n * Note: Receives only docId (not DocContext) since the document doesn't exist yet.\n *\n * @default () => true (allow all creation)\n */\n creation(docId: DocId, peer: PeerContext): boolean\n\n /**\n * Who can delete documents?\n *\n * Called when:\n * - Receiving channel/delete-request\n * - Local deletion request\n *\n * NO BYPASS: Always checked.\n * Rationale: Deletion is destructive and must always be authorized.\n *\n * @default () => false (deny all deletion - safe default)\n */\n deletion(doc: DocContext, peer: PeerContext): boolean\n}\n\n/**\n * Default permissions: permissive for discovery and modification,\n * restrictive for deletion.\n */\nconst defaultPermissions: Permissions = {\n visibility: () => true,\n mutability: () => true,\n creation: () => true,\n deletion: () => false, // Safe default: deny deletion\n}\n\n/**\n * Create a Permissions object with defaults for any unspecified permissions.\n *\n * @param permissions - Partial permissions to override defaults\n * @returns Complete Permissions object\n *\n * @example\n * ```typescript\n * // Only override what you need\n * const permissions = createPermissions({\n * visibility: (doc, peer) => doc.id.startsWith('public/'),\n * })\n * ```\n */\nexport function createPermissions(\n permissions: Partial<Permissions> = {},\n): Permissions {\n return {\n visibility: permissions.visibility ?? defaultPermissions.visibility,\n mutability: permissions.mutability ?? defaultPermissions.mutability,\n creation: permissions.creation ?? defaultPermissions.creation,\n deletion: permissions.deletion ?? defaultPermissions.deletion,\n }\n}\n","import { getLogger, type Logger } from \"@logtape/logtape\"\nimport type { DocShape } from \"@loro-extended/change\"\nimport type { AnyAdapter } from \"./adapter/adapter.js\"\nimport {\n createHandle,\n type EphemeralDeclarations,\n type HandleWithEphemerals,\n} from \"./handle.js\"\nimport type { Middleware } from \"./middleware.js\"\nimport { createPermissions, type Permissions } from \"./permissions.js\"\nimport { type HandleUpdateFn, Synchronizer } from \"./synchronizer.js\"\nimport type { DocId, PeerIdentityDetails } from \"./types.js\"\nimport { generatePeerId } from \"./utils/generate-peer-id.js\"\nimport { validatePeerId } from \"./utils/validate-peer-id.js\"\n\nexport interface RepoParams {\n identity?: Partial<PeerIdentityDetails>\n adapters?: AnyAdapter[]\n /**\n * Permissions control access to documents.\n *\n * Permissions are simple, synchronous predicates that determine what peers can do.\n * For advanced use cases (rate limiting, external auth, audit logging),\n * use middleware instead.\n *\n * @example\n * ```typescript\n * const repo = new Repo({\n * permissions: {\n * visibility: (doc, peer) => doc.id.startsWith('public/'),\n * mutability: (doc, peer) => peer.peerType !== 'bot',\n * deletion: (doc, peer) => peer.peerType === 'service',\n * }\n * })\n * ```\n */\n permissions?: Partial<Permissions>\n /**\n * Middleware for advanced access control and cross-cutting concerns.\n *\n * Middleware runs BEFORE the synchronizer processes messages, at the async boundary.\n * Use middleware for:\n * - Rate limiting\n * - Size limits\n * - External auth service integration\n * - Audit logging\n *\n * For simple permission checks, use `permissions` instead.\n *\n * @example\n * ```typescript\n * const repo = new Repo({\n * middleware: [\n * {\n * name: 'rate-limiter',\n * requires: ['peer'],\n * check: (ctx) => {\n * const count = getRequestCount(ctx.peer.peerId)\n * return count < 100 ? { allow: true } : { allow: false, reason: 'rate-limited' }\n * }\n * }\n * ]\n * })\n * ```\n */\n middleware?: Middleware[]\n onUpdate?: HandleUpdateFn\n}\n\n/**\n * The Repo class is the central orchestrator for the Loro state synchronization system.\n * It manages the lifecycle of documents, coordinates subsystems, and provides the main\n * public API for document operations.\n *\n * With the simplified DocHandle architecture, Repo becomes a simpler orchestrator\n * that wires together the various subsystems without complex state management.\n *\n * Adapters are used to indicate how to retrieve doc state (updates, sync, etc.) from\n * storage or network systems.\n */\nexport class Repo {\n readonly logger: Logger\n readonly identity: PeerIdentityDetails\n\n // Subsystems\n readonly #synchronizer: Synchronizer\n\n constructor({\n identity = {},\n adapters = [],\n permissions,\n middleware,\n onUpdate,\n }: RepoParams = {}) {\n // Validate peerId if provided, otherwise generate one\n const peerId = identity.peerId ?? generatePeerId()\n validatePeerId(peerId)\n\n // Build complete identity with defaults\n this.identity = {\n peerId,\n name: identity.name, // undefined is fine - peerId is the unique identifier\n type: identity.type ?? \"user\",\n }\n\n const logger = getLogger([\"@loro-extended\", \"repo\"]).with({\n identity: this.identity,\n })\n this.logger = logger\n\n logger.debug(\"new Repo: {identity}\", { identity: this.identity })\n\n // Instantiate synchronizer\n const synchronizer = new Synchronizer({\n identity: this.identity,\n adapters,\n permissions: createPermissions(permissions),\n middleware: middleware ?? [],\n logger,\n onUpdate,\n })\n\n this.#synchronizer = synchronizer\n }\n\n //\n // PUBLIC API - Unified Handle API\n //\n\n /**\n * Gets (or creates) a unified handle with typed document and ephemeral stores.\n *\n * This is the primary API for accessing documents. It supports:\n * - Typed documents (use Shape.any() for untyped)\n * - Multiple typed ephemeral stores\n * - External store integration via handle.addEphemeral()\n *\n * @param docId The document ID\n * @param docShape The shape of the document (use Shape.any() for untyped)\n * @param ephemeralShapes Optional ephemeral store declarations\n * @returns A Handle with typed document and ephemeral store access\n *\n * @example\n * ```typescript\n * // Typed document with typed ephemeral stores\n * const handle = repo.get('my-doc', DocSchema, {\n * presence: PresenceSchema,\n * cursors: CursorSchema\n * })\n * handle.change(draft => { draft.title = 'Hello' })\n * handle.presence.setSelf({ status: 'online' })\n *\n * // Untyped document with typed ephemeral stores\n * const handle = repo.get('my-doc', Shape.any(), {\n * cursors: CursorSchema\n * })\n * handle.loroDoc.getMap('root').set('key', 'value')\n * handle.cursors.setSelf({ position: 42 })\n * ```\n */\n get<\n D extends DocShape,\n E extends EphemeralDeclarations = Record<string, never>,\n >(\n docId: DocId,\n docShape: D,\n ephemeralShapes?: E,\n ): HandleWithEphemerals<D, E> {\n return createHandle({\n docId,\n docShape,\n ephemeralShapes,\n synchronizer: this.#synchronizer,\n logger: this.logger,\n })\n }\n\n /**\n * Check if a document exists in the repo.\n * @param docId The document ID\n * @returns true if the document exists\n */\n has(docId: DocId): boolean {\n return this.#synchronizer.getDocumentState(docId) !== undefined\n }\n\n /**\n * Deletes a document from the repo.\n * @param docId The ID of the document to delete\n */\n async delete(docId: DocId): Promise<void> {\n await this.#synchronizer.removeDocument(docId)\n }\n\n /**\n * Disconnects all network adapters and cleans up resources.\n * This should be called when the Repo is no longer needed.\n */\n reset(): void {\n // Clear synchronizer model\n this.#synchronizer.reset()\n }\n\n //\n // PUBLIC API - Adapter Management\n //\n\n /**\n * Add an adapter at runtime.\n * Idempotent: adding an adapter with the same adapterId is a no-op.\n */\n async addAdapter(adapter: AnyAdapter): Promise<void> {\n await this.#synchronizer.addAdapter(adapter)\n }\n\n /**\n * Remove an adapter at runtime.\n * Idempotent: removing a non-existent adapter is a no-op.\n */\n async removeAdapter(adapterId: string): Promise<void> {\n await this.#synchronizer.removeAdapter(adapterId)\n }\n\n /**\n * Check if an adapter exists by ID.\n */\n hasAdapter(adapterId: string): boolean {\n return this.#synchronizer.hasAdapter(adapterId)\n }\n\n /**\n * Get an adapter by ID.\n */\n getAdapter(adapterId: string): AnyAdapter | undefined {\n return this.#synchronizer.getAdapter(adapterId)\n }\n\n /**\n * Get all current adapters.\n */\n get adapters(): AnyAdapter[] {\n return this.#synchronizer.adapters.adapters\n }\n\n // For debugging/testing purposes\n get synchronizer() {\n return this.#synchronizer\n }\n}\n","import { getLogger, type Logger } from \"@logtape/logtape\"\nimport Emittery from \"emittery\"\nimport type { EphemeralStore, Value, VersionVector } from \"loro-crdt\"\nimport { create, type Patch } from \"mutative\"\nimport type { AnyAdapter } from \"./adapter/adapter.js\"\nimport { AdapterManager } from \"./adapter/adapter-manager.js\"\nimport type {\n BatchableMsg,\n Channel,\n ChannelMsg,\n ChannelMsgSyncRequest,\n ChannelMsgSyncResponse,\n ConnectedChannel,\n SyncTransmission,\n} from \"./channel.js\"\nimport { isEstablished as isEstablishedFn } from \"./channel.js\"\nimport type { Middleware } from \"./middleware.js\"\nimport { createPermissions, type Permissions } from \"./permissions.js\"\nimport {\n type CommandContext,\n CommandExecutor,\n type SynchronizerEvents,\n} from \"./synchronizer/command-executor.js\"\nimport { commandHandlers } from \"./synchronizer/command-handlers/index.js\"\nimport { EphemeralStoreManager } from \"./synchronizer/ephemeral-store-manager.js\"\nimport { HeartbeatManager } from \"./synchronizer/heartbeat-manager.js\"\nimport { MiddlewareProcessor } from \"./synchronizer/middleware-processor.js\"\nimport { OutboundBatcher } from \"./synchronizer/outbound-batcher.js\"\nimport { getReadyStates } from \"./synchronizer/state-helpers.js\"\nimport { WorkQueue } from \"./synchronizer/work-queue.js\"\nimport {\n type Command,\n createSynchronizerUpdate,\n init as programInit,\n type SynchronizerMessage,\n type SynchronizerModel,\n} from \"./synchronizer-program.js\"\nimport type {\n ChannelId,\n DocId,\n DocState,\n PeerID,\n PeerIdentityDetails,\n PeerState,\n ReadyState,\n} from \"./types.js\"\nimport { equal } from \"./utils/equal.js\"\n\nexport type HandleUpdateFn = (patches: Patch[]) => void\n\n// Initiate a synchronizer/heartbeat every N milliseconds; used primarily for ephemeral stores\nconst HEARTBEAT_INTERVAL = 10000\n\n// SynchronizerEvents is imported from command-executor.ts to avoid circular dependency\n\ntype SynchronizerParams = {\n identity: PeerIdentityDetails\n adapters?: AnyAdapter[]\n permissions?: Permissions\n middleware?: Middleware[]\n onUpdate?: HandleUpdateFn\n logger?: Logger\n}\n\ntype SynchronizerUpdate = (\n msg: SynchronizerMessage,\n model: SynchronizerModel,\n) => [SynchronizerModel, Command?]\n\nexport type ObjectValue = { [key: string]: Value }\n\nexport class Synchronizer {\n readonly identity: PeerIdentityDetails\n readonly adapters: AdapterManager\n readonly logger: Logger\n\n readonly updateFn: SynchronizerUpdate\n\n // Extracted modules\n readonly #workQueue: WorkQueue\n readonly #outboundBatcher: OutboundBatcher\n readonly #ephemeralManager: EphemeralStoreManager\n readonly #heartbeatManager: HeartbeatManager\n readonly #middlewareProcessor: MiddlewareProcessor\n readonly #commandExecutor: CommandExecutor\n\n /**\n * Per-doc namespaced ephemeral stores (unified model).\n * Internal getter used by command execution.\n */\n get docNamespacedStores(): Map<DocId, Map<string, EphemeralStore>> {\n return this.#ephemeralManager.stores\n }\n\n readonly emitter = new Emittery<SynchronizerEvents>()\n\n readonly readyStates = new Map<DocId, ReadyState[]>()\n\n model: SynchronizerModel\n\n constructor({\n identity,\n adapters = [],\n permissions,\n middleware = [],\n onUpdate,\n logger: preferredLogger,\n }: SynchronizerParams) {\n const logger = preferredLogger ?? getLogger()\n this.logger = logger.getChild(\"synchronizer\")\n\n this.identity = identity\n\n this.logger.debug(\"new Synchronizer: {identity}\", {\n identity: this.identity,\n })\n\n this.updateFn = createSynchronizerUpdate({\n permissions: createPermissions(permissions),\n onUpdate,\n logger,\n })\n\n // Initialize model BEFORE creating AdapterManager, since adapters may\n // trigger channelAdded which needs the model\n const [initialModel, initialCommand] = programInit(this.identity)\n this.model = initialModel\n\n // Initialize extracted modules\n this.#outboundBatcher = new OutboundBatcher()\n\n this.#workQueue = new WorkQueue(() => {\n // Called at quiescence - flush outbound messages and emit ready state changes\n this.#outboundBatcher.flush(envelope => this.adapters.send(envelope))\n this.#emitReadyStateChanges()\n })\n\n this.#ephemeralManager = new EphemeralStoreManager(\n this.identity,\n (docId, namespace) => {\n // Route through dispatch for TEA compliance\n this.#dispatch({\n type: \"synchronizer/ephemeral-local-change\",\n docId,\n namespace,\n })\n },\n this.logger,\n )\n\n this.#heartbeatManager = new HeartbeatManager(HEARTBEAT_INTERVAL, () => {\n this.#dispatch({ type: \"synchronizer/heartbeat\" })\n })\n\n // Initialize middleware processor with a getter function for model access\n this.#middlewareProcessor = new MiddlewareProcessor(\n middleware,\n () => this.model,\n this.logger,\n )\n\n // Initialize command executor with handler registry\n this.#commandExecutor = new CommandExecutor(commandHandlers, () =>\n this.#buildCommandContext(),\n )\n\n // Create adapter context for dynamic adapter initialization\n const adapterContext = {\n identity: this.identity,\n logger: this.logger,\n onChannelAdded: this.channelAdded.bind(this),\n onChannelRemoved: this.channelRemoved.bind(this),\n onChannelReceive: this.channelReceive.bind(this),\n onChannelEstablish: this.channelEstablish.bind(this),\n }\n\n // Create AdapterManager (initializes adapters but doesn't start them yet)\n this.adapters = new AdapterManager({\n adapters,\n context: adapterContext,\n onReset: (adapter: AnyAdapter) => {\n for (const channel of adapter.channels) {\n this.channelRemoved(channel)\n }\n },\n logger,\n })\n\n // Execute initial command AFTER adapters is assigned (commands may access this.adapters)\n if (initialCommand) {\n this.#executeCommand(initialCommand)\n }\n\n // Start all adapters now that everything is initialized\n this.adapters.startAll()\n\n this.#heartbeatManager.start()\n }\n\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n // PUBLIC API - Heartbeat Management\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n startHeartbeat() {\n this.#heartbeatManager.start()\n }\n\n stopHeartbeat() {\n this.#heartbeatManager.stop()\n }\n\n /**\n * Get the number of middleware configured (for debugging).\n */\n get middlewareCount(): number {\n return this.#middlewareProcessor.count\n }\n\n /**\n * Handle incoming channel messages.\n *\n * Uses a unified work queue to prevent recursion when adapters deliver messages\n * synchronously (e.g., BridgeAdapter, StorageAdapter). Messages are queued\n * and processed iteratively rather than recursively.\n *\n * If middleware is configured, it runs BEFORE the synchronizer processes the message.\n * Middleware can reject messages (e.g., rate limiting, auth).\n *\n * @param channelId - The channel ID (we look up the current channel from the model\n * to ensure we have the latest state, since the model uses immutable updates)\n * @param message - The message received on the channel\n */\n channelReceive(channelId: ChannelId, message: ChannelMsg): void {\n this.#workQueue.enqueue(() =>\n this.#channelReceiveInternal(channelId, message),\n )\n }\n\n /**\n * Internal message processing after queue management.\n * This contains the actual message handling logic.\n */\n #channelReceiveInternal(channelId: ChannelId, message: ChannelMsg): void {\n this.logger.trace(\"onReceive: {messageType} from {channelId}\", {\n channelId,\n messageType: message.type,\n })\n\n // Handle channel/batch messages by running middleware on each message individually\n // This ensures size-limiting middleware can reject individual messages in a batch\n if (message.type === \"channel/batch\") {\n this.#handleBatchMessage(channelId, message.messages)\n return\n }\n\n // Run middleware if configured\n if (this.#middlewareProcessor.hasMiddleware) {\n this.#runMiddlewareAndDispatch(channelId, message)\n return\n }\n\n // No middleware - dispatch immediately\n this.#dispatch({\n type: \"synchronizer/channel-receive-message\",\n envelope: {\n fromChannelId: channelId,\n message,\n },\n })\n }\n\n /**\n * Handle a batch message by running middleware on each message individually.\n * Messages that pass middleware are collected and dispatched together.\n */\n #handleBatchMessage(channelId: ChannelId, messages: BatchableMsg[]): void {\n if (!this.#middlewareProcessor.hasMiddleware) {\n // No middleware - dispatch the batch directly\n this.#dispatch({\n type: \"synchronizer/channel-receive-message\",\n envelope: {\n fromChannelId: channelId,\n message: { type: \"channel/batch\", messages },\n },\n })\n return\n }\n\n // Process batch through middleware\n void this.#middlewareProcessor\n .processBatch(channelId, messages)\n .then(result => {\n if (result.type === \"rejected\") {\n // All messages rejected\n return\n }\n\n if (result.type === \"no-middleware\") {\n // No middleware - dispatch the batch directly\n this.#dispatch({\n type: \"synchronizer/channel-receive-message\",\n envelope: {\n fromChannelId: channelId,\n message: { type: \"channel/batch\", messages },\n },\n })\n return\n }\n\n if (result.type === \"allowed\") {\n // Single message - dispatch directly\n this.#dispatch({\n type: \"synchronizer/channel-receive-message\",\n envelope: {\n fromChannelId: channelId,\n message: result.message,\n },\n })\n return\n }\n\n if (result.type === \"allowed-batch\") {\n // Multiple messages - dispatch as batch\n this.#dispatch({\n type: \"synchronizer/channel-receive-message\",\n envelope: {\n fromChannelId: channelId,\n message: { type: \"channel/batch\", messages: result.messages },\n },\n })\n }\n })\n }\n\n /**\n * Run middleware on a single message and dispatch if allowed.\n */\n #runMiddlewareAndDispatch(channelId: ChannelId, message: ChannelMsg): void {\n void this.#middlewareProcessor\n .processMessage(channelId, message)\n .then(result => {\n if (result.type === \"allowed\" || result.type === \"no-middleware\") {\n this.#dispatch({\n type: \"synchronizer/channel-receive-message\",\n envelope: {\n fromChannelId: channelId,\n message,\n },\n })\n }\n // If result.type === \"rejected\", message is dropped (middleware rejected it)\n })\n }\n\n // Helper functions for adapter callbacks\n channelAdded(channel: ConnectedChannel) {\n this.logger.debug(\"channelAdded: {channelId}\", {\n channelId: channel.channelId,\n })\n this.#dispatch({ type: \"synchronizer/channel-added\", channel })\n }\n\n channelEstablish(channel: ConnectedChannel) {\n this.logger.debug(\"channelEstablish: {channelId}\", {\n channelId: channel.channelId,\n })\n this.#dispatch({\n type: \"synchronizer/establish-channel\",\n channelId: channel.channelId,\n })\n }\n\n channelRemoved(channel: Channel) {\n this.logger.debug(\"channelRemoved: {channelId}\", {\n channelId: channel.channelId,\n })\n this.#dispatch({ type: \"synchronizer/channel-removed\", channel })\n }\n\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n // PUBLIC API - Namespaced Ephemeral Store Management (New Unified Model)\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n /**\n * Get or create a namespaced ephemeral store for a document.\n * This is used for the new unified ephemeral store model.\n *\n * @param docId The document ID\n * @param namespace The store namespace (e.g., 'presence', 'cursors', 'mouse')\n * @returns The ephemeral store for this namespace\n */\n getOrCreateNamespacedStore(docId: DocId, namespace: string): EphemeralStore {\n return this.#ephemeralManager.getOrCreate(docId, namespace)\n }\n\n /**\n * Register an external ephemeral store for network sync.\n * Use this for libraries that bring their own EphemeralStore (like loro-prosemirror).\n *\n * @param docId The document ID\n * @param namespace The store namespace\n * @param store The external EphemeralStore to register\n */\n registerExternalStore(\n docId: DocId,\n namespace: string,\n store: EphemeralStore,\n ): void {\n this.#ephemeralManager.registerExternal(docId, namespace, store)\n }\n\n /**\n * Get a namespaced store by name.\n *\n * @param docId The document ID\n * @param namespace The store namespace\n * @returns The EphemeralStore or undefined if not found\n */\n getNamespacedStore(\n docId: DocId,\n namespace: string,\n ): EphemeralStore | undefined {\n return this.#ephemeralManager.get(docId, namespace)\n }\n\n /**\n * Broadcast a namespaced store to all peers.\n * This is called explicitly by the Handle when local changes are made.\n *\n * Routes through dispatch for TEA compliance and message aggregation.\n *\n * @param docId The document ID\n * @param namespace The store namespace\n */\n broadcastNamespacedStore(docId: DocId, namespace: string): void {\n const store = this.getNamespacedStore(docId, namespace)\n if (!store) {\n this.logger.warn(\n \"Cannot broadcast: namespaced store {namespace} not found for doc {docId}\",\n { namespace, docId },\n )\n return\n }\n\n // Route through dispatch for TEA compliance\n this.#dispatch({\n type: \"synchronizer/ephemeral-local-change\",\n docId,\n namespace,\n })\n }\n\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n // PUBLIC API - Adapter Management\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n /**\n * Add an adapter at runtime.\n * Idempotent: adding an adapter with the same adapterId is a no-op.\n */\n async addAdapter(adapter: AnyAdapter): Promise<void> {\n await this.adapters.addAdapter(adapter)\n }\n\n /**\n * Remove an adapter at runtime.\n * Idempotent: removing a non-existent adapter is a no-op.\n */\n async removeAdapter(adapterId: string): Promise<void> {\n await this.adapters.removeAdapter(adapterId)\n }\n\n /**\n * Check if an adapter exists by ID.\n */\n hasAdapter(adapterId: string): boolean {\n return this.adapters.hasAdapter(adapterId)\n }\n\n /**\n * Get an adapter by ID.\n */\n getAdapter(adapterId: string): AnyAdapter | undefined {\n return this.adapters.getAdapter(adapterId)\n }\n\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n // PUBLIC API - Document Management\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n getOrCreateDocumentState(docId: DocId): DocState {\n let docState = this.model.documents.get(docId)\n\n if (!docState) {\n this.#dispatch({ type: \"synchronizer/doc-ensure\", docId })\n docState = this.model.documents.get(docId)\n }\n\n if (!docState) {\n throw new Error(`unable to find or create doc: ${docId}`)\n }\n\n return docState\n }\n\n getDocumentState(docId: DocId): DocState | undefined {\n const state = this.model.documents.get(docId)\n return state\n }\n\n /**\n * Get docIds that a channel's peer has subscribed to\n */\n public getChannelDocIds(channelId: ChannelId): DocId[] {\n const channel = this.model.channels.get(channelId)\n if (!channel || !isEstablishedFn(channel)) {\n return []\n }\n\n const peerState = this.model.peers.get(channel.peerId)\n if (!peerState) {\n return []\n }\n\n return Array.from(peerState.subscriptions)\n }\n\n /**\n * Get all peers\n */\n public getPeers(): PeerState[] {\n return Array.from(this.model.peers.values())\n }\n\n /**\n * Get the current ready states for a document\n */\n public getReadyStates(docId: DocId): ReadyState[] {\n return getReadyStates(this.model, docId)\n }\n\n /**\n * Wait until a docId is \"ready\", with \"ready\" meaning any number of flexible things:\n * e.g.\n * - the document has been loaded from a storage channel\n * - the document has been loaded from the server\n * - with regard to the document, all channels (peers) have responded\n *\n * All of this flexibility is achieved by allowing you to pass a \"predicate\" function\n * that returns true or false depending on your needs.\n *\n * @param docId The document ID under test for the predicate\n * @param predicate A condition to wait for--the predicate is passed a ReadyState[] array\n */\n async waitUntilReady(\n docId: DocId,\n predicate: (readyStates: ReadyState[]) => boolean,\n ) {\n this.logger.debug(\"wait-until-ready is WAITING for {docId}\", { docId })\n\n const docState = this.model.documents.get(docId)\n\n if (!docState) {\n this.logger.warn(`wait-until-ready unable to get doc-state`)\n return\n }\n\n const readyStates = getReadyStates(this.model, docId)\n\n if (predicate(readyStates)) {\n this.logger.debug(\"wait-until-ready is READY (immediate) for {docId}\", {\n docId,\n })\n return\n }\n\n // Wait for ready-state-changed events using async iteration\n for await (const event of this.emitter.events(\"ready-state-changed\")) {\n // The event contains the readyStates array directly\n if (event.docId === docId && predicate(event.readyStates)) {\n // Condition met, we're done waiting\n break\n }\n }\n\n this.logger.debug(\"wait-until-ready is READY for {docId}\", { docId })\n }\n\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- =-=-=-=-=-=-=-=\n // INTERNAL RUNTIME\n // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n /**\n * Dispatch a message to the synchronizer program.\n *\n * If we're already inside the work queue processing loop, execute inline.\n * Otherwise, enqueue the work and process until quiescent.\n *\n * This unified approach handles both:\n * 1. Preventing recursion from synchronous adapters\n * 2. Batching outbound messages until quiescence\n */\n #dispatch(message: SynchronizerMessage) {\n if (this.#workQueue.isProcessing) {\n // Already inside work queue - execute inline\n this.#dispatchInternal(message)\n } else {\n // Not processing - enqueue and process\n this.#workQueue.enqueue(() => this.#dispatchInternal(message))\n }\n }\n\n /**\n * Internal dispatch implementation.\n * Runs the update function and executes any resulting command.\n */\n #dispatchInternal(message: SynchronizerMessage) {\n if (!this.model) {\n throw new Error(\"synchronizer model required\")\n }\n\n const [newModel, command] = this.updateFn(message, this.model)\n\n // We update the Synchronizer instance's model here, allowing us access to data\n // \"inside\" the TEA program. This is useful because we want the DocHandle class\n // to be able to wrap the Synchronizer as a public API.\n this.model = newModel\n\n if (command) {\n this.#executeCommand(command)\n }\n // Note: No flush here - flushing happens at quiescence in #processUntilQuiescent\n }\n\n /**\n * Check for ready-state changes and emit events.\n * Only called at the outermost dispatch level.\n */\n #emitReadyStateChanges() {\n // After all changes, compare ready-states before and after; emit ready-state-changed\n // We need to check both:\n // 1. Documents that exist in the model (may have changed)\n // 2. Documents that were cached but no longer exist (deleted)\n const docIdsToCheck = new Set([\n ...this.model.documents.keys(),\n ...this.readyStates.keys(),\n ])\n\n for (const docId of docIdsToCheck) {\n const oldReadyStates = this.readyStates.get(docId) ?? []\n\n const newReadyStates = getReadyStates(this.model, docId)\n\n if (!equal(oldReadyStates, newReadyStates)) {\n // console.dir({ docId, oldReadyStates, newReadyStates }, { depth: null })\n\n // If document was deleted, remove from cache; otherwise update cache\n if (!this.model.documents.has(docId)) {\n this.readyStates.delete(docId)\n } else {\n this.readyStates.set(docId, newReadyStates)\n }\n\n this.emitter.emit(\"ready-state-changed\", {\n docId,\n readyStates: newReadyStates,\n })\n }\n }\n }\n\n /**\n * Execute a command using the command handler registry.\n * Delegates to the CommandExecutor which looks up the appropriate handler.\n */\n #executeCommand(command: Command) {\n this.#commandExecutor.execute(command)\n }\n\n /**\n * Build the command context for command handlers.\n * This provides all dependencies handlers need to execute.\n */\n #buildCommandContext(): CommandContext {\n return {\n // Model access (read-only snapshot)\n model: this.model,\n\n // Services\n adapters: this.adapters,\n ephemeralManager: this.#ephemeralManager,\n outboundBatcher: this.#outboundBatcher,\n emitter: this.emitter,\n\n // Identity\n identity: this.identity,\n\n // Utilities\n logger: this.logger,\n dispatch: msg => this.#dispatch(msg),\n executeCommand: cmd => this.#executeCommand(cmd),\n\n // Helper functions\n validateChannelForSend: channelId =>\n this.#validateChannelForSend(channelId),\n queueSend: (channelId, message) => this.#queueSend(channelId, message),\n getNamespacedStore: (docId, namespace) =>\n this.getNamespacedStore(docId, namespace),\n getOrCreateNamespacedStore: (docId, namespace) =>\n this.getOrCreateNamespacedStore(docId, namespace),\n encodeAllPeerStores: docId => this.#encodeAllPeerStores(docId),\n buildSyncResponseMessage: (\n docId,\n requesterDocVersion,\n toChannelId,\n includeEphemeral,\n ) =>\n this.#buildSyncResponseMessage(\n docId,\n requesterDocVersion,\n toChannelId,\n includeEphemeral,\n ),\n buildSyncRequestMessage: (doc, bidirectional, includeEphemeral) =>\n this.#buildSyncRequestMessage(doc, bidirectional, includeEphemeral),\n\n // Access to docNamespacedStores\n docNamespacedStores: this.docNamespacedStores,\n }\n }\n\n #validateChannelForSend(channelId: ChannelId): boolean {\n const channel = this.model.channels.get(channelId)\n\n if (!channel) {\n this.logger.warn(\"Cannot send: channel {channelId} not found\", {\n channelId,\n })\n return false\n }\n\n if (!isEstablishedFn(channel)) {\n this.logger.warn(\"Cannot send: channel {channelId} not established\", {\n channelId,\n })\n return false\n }\n\n return true\n }\n\n /**\n * Queue a message to be sent to a channel.\n * Messages are aggregated by channel and flushed at quiescence.\n */\n #queueSend(channelId: ChannelId, message: BatchableMsg): void {\n this.#outboundBatcher.queue(channelId, message)\n }\n\n /**\n * Encode all namespaced stores for a document.\n * Returns an array of { docId, peerId, data, namespace } for each store with data.\n */\n #encodeAllPeerStores(\n docId: DocId,\n ): { docId: DocId; peerId: PeerID; data: Uint8Array; namespace: string }[] {\n const encoded = this.#ephemeralManager.encodeAll(docId)\n return encoded.map(e => ({\n docId,\n peerId: e.peerId,\n data: e.data,\n namespace: e.namespace,\n }))\n }\n\n /**\n * Build a sync-response message for a document.\n * Returns undefined if the message cannot be built (doc not found, channel not found).\n */\n #buildSyncResponseMessage(\n docId: DocId,\n requesterDocVersion: VersionVector,\n toChannelId: ChannelId,\n includeEphemeral?: boolean,\n ): ChannelMsgSyncResponse | undefined {\n const docState = this.model.documents.get(docId)\n if (!docState) {\n this.logger.warn(\"can't get doc-state, doc {docId} not found\", { docId })\n return undefined\n }\n\n // No need to check channel state - just verify channel exists\n const channel = this.model.channels.get(toChannelId)\n if (!channel) {\n this.logger.warn(\n \"can't send sync-response, channel {toChannelId} doesn't exist\",\n {\n toChannelId,\n },\n )\n return undefined\n }\n\n // Check if requester has empty version (new client)\n // An empty version vector means the requester has no state\n const ourVersion = docState.doc.version()\n const comparison = ourVersion.compare(requesterDocVersion)\n\n // If comparison is 1, we're ahead (send update)\n // If comparison is 0, we're equal (up-to-date)\n // If comparison is undefined, versions are concurrent (send update - Loro handles this!)\n // If requester version length is 0, they have nothing (send snapshot)\n const isEmpty = requesterDocVersion.length() === 0\n\n this.logger.info(\n \"#buildSyncResponseMessage version check for {docId} on {channelId}\",\n {\n channelId: toChannelId,\n docId,\n requesterDocVersionLength: requesterDocVersion.length(),\n ourVersionLength: ourVersion.length(),\n comparison,\n isEmpty,\n requesterVersionType: typeof requesterDocVersion,\n requesterVersionConstructor: requesterDocVersion.constructor.name,\n },\n )\n\n let transmission: SyncTransmission\n\n // If comparison is 0 (equal) or -1 (they are ahead), we have nothing new to send\n if ((comparison === 0 || comparison === -1) && !isEmpty) {\n this.logger.debug(\n \"building sync-response (up-to-date) for {docId} to {channelId}\",\n {\n channelId: toChannelId,\n docId,\n comparison,\n },\n )\n\n transmission = {\n type: \"up-to-date\",\n version: ourVersion,\n }\n } else {\n // Export the document data to send as sync response\n // If requester has empty version, send full snapshot\n // Otherwise send update delta from their version\n const data = docState.doc.export({\n mode: isEmpty ? \"snapshot\" : \"update\",\n from: isEmpty ? undefined : requesterDocVersion,\n })\n\n this.logger.debug(\n \"building sync-response ({transmissionType}) for {docId} to {channelId}\",\n {\n channelId: toChannelId,\n docId,\n isEmpty,\n transmissionType: isEmpty ? \"snapshot\" : \"update\",\n },\n )\n\n transmission = isEmpty\n ? {\n type: \"snapshot\" as const,\n data,\n version: ourVersion,\n }\n : {\n type: \"update\" as const,\n data,\n version: ourVersion,\n }\n }\n\n // Build the sync-response message\n const syncResponseMessage: ChannelMsgSyncResponse = {\n type: \"channel/sync-response\" as const,\n docId,\n transmission,\n }\n\n // Include ephemeral snapshot if requested\n if (includeEphemeral) {\n // Encode all namespaced stores (touch is handled inside #encodeAllPeerStores)\n const stores = this.#encodeAllPeerStores(docId)\n if (stores.length > 0) {\n syncResponseMessage.ephemeral = stores.map(s => ({\n peerId: s.peerId,\n data: s.data,\n namespace: s.namespace,\n }))\n this.logger.debug(\n \"including ephemeral data in sync-response for {docId} to {channelId}\",\n {\n docId,\n channelId: toChannelId,\n storeCount: stores.length,\n },\n )\n }\n }\n\n return syncResponseMessage\n }\n\n /**\n * Build a single sync-request message for a document.\n */\n #buildSyncRequestMessage(\n doc: { docId: DocId; requesterDocVersion: VersionVector },\n bidirectional: boolean,\n includeEphemeral?: boolean,\n ): ChannelMsgSyncRequest {\n const result: ChannelMsgSyncRequest = {\n type: \"channel/sync-request\",\n docId: doc.docId,\n requesterDocVersion: doc.requesterDocVersion,\n bidirectional,\n }\n\n // Include ephemeral data if requested\n // For sync-request, we encode all our namespaced stores\n if (includeEphemeral) {\n const stores = this.#encodeAllPeerStores(doc.docId)\n\n if (stores.length > 0) {\n result.ephemeral = stores.map(s => ({\n peerId: this.identity.peerId,\n data: s.data,\n namespace: s.namespace,\n }))\n this.logger.debug(\n \"building sync-request with ephemeral data for {docId}\",\n {\n docId: doc.docId,\n storeCount: stores.length,\n },\n )\n }\n }\n\n return result\n }\n\n /**\n * Remove a document from the synchronizer and send delete messages to all channels.\n *\n * The dispatch handles both:\n * 1. Removing the document from the model\n * 2. Sending delete-request messages to all subscribed peers (via deferred send)\n */\n public async removeDocument(docId: DocId): Promise<void> {\n const docState = this.model.documents.get(docId)\n\n if (!docState) {\n this.logger.debug(\"removeDocument: document {docId} not found\", { docId })\n return\n }\n\n // Dispatch handles both model update and sending delete-request\n this.#dispatch({ type: \"synchronizer/doc-delete\", docId })\n }\n\n public async reset() {\n // TODO(duane): Should we stop/start the heartbeat? It doesn't seem to add value to do so. Maybe we should have a stop/start function on Synchronizer?\n\n const [initialModel] = programInit(this.model.identity)\n\n // Reset all adapters via AdapterManager\n this.adapters.reset()\n\n this.model = initialModel\n }\n\n /**\n * Get the current model state (for debugging purposes).\n * Returns a deep copy to prevent accidental mutations.\n */\n public getModelSnapshot(): SynchronizerModel {\n return create(this.model)[0]\n }\n}\n","import { getLogger, type Logger } from \"@logtape/logtape\"\nimport type {\n AddressedEstablishedEnvelope,\n AddressedEstablishmentEnvelope,\n} from \"../channel.js\"\nimport type { AdapterContext, AnyAdapter } from \"./adapter.js\"\nimport type { HandleSendFn } from \"./types.js\"\n\ntype AdapterManagerParams = {\n adapters?: AnyAdapter[]\n context: AdapterContext\n onReset: (adapter: AnyAdapter) => void\n onSend?: HandleSendFn\n logger?: Logger\n}\n\n/**\n * The AdapterManager is responsible for managing adapters and sending\n * AddressedEnvelopes to their addressees via the adapters.\n *\n * Supports dynamic add/remove of adapters at runtime.\n */\nexport class AdapterManager {\n readonly #adapters = new Map<string, AnyAdapter>()\n readonly #context: AdapterContext\n readonly #onReset: (adapter: AnyAdapter) => void\n readonly #onSend?: HandleSendFn\n readonly logger: Logger\n\n constructor({\n adapters = [],\n context,\n onReset,\n onSend,\n logger,\n }: AdapterManagerParams) {\n this.#context = context\n this.#onReset = onReset\n this.#onSend = onSend\n this.logger = logger ?? getLogger([\"@loro-extended\", \"repo\"])\n\n // Initialize provided adapters synchronously (existing behavior)\n for (const adapter of adapters) {\n this.#initializeAdapter(adapter)\n }\n\n // Note: Adapters are NOT started here. Call startAll() after construction\n // to start all adapters. This allows the Synchronizer to finish initialization\n // before adapters start triggering callbacks.\n }\n\n /**\n * Start all adapters that were provided in the constructor.\n * This should be called after the Synchronizer is fully initialized.\n */\n startAll(): void {\n for (const adapter of this.#adapters.values()) {\n void adapter._start()\n }\n }\n\n #initializeAdapter(adapter: AnyAdapter): void {\n if (this.#onSend) {\n adapter.onSend = this.#onSend\n }\n adapter._initialize(this.#context)\n this.#adapters.set(adapter.adapterId, adapter)\n }\n\n /**\n * Get all adapters as an array.\n */\n get adapters(): AnyAdapter[] {\n return Array.from(this.#adapters.values())\n }\n\n /**\n * Check if an adapter exists by ID.\n */\n hasAdapter(adapterId: string): boolean {\n return this.#adapters.has(adapterId)\n }\n\n /**\n * Get an adapter by ID.\n */\n getAdapter(adapterId: string): AnyAdapter | undefined {\n return this.#adapters.get(adapterId)\n }\n\n /**\n * Add an adapter at runtime.\n * Idempotent: adding an adapter with the same adapterId is a no-op.\n */\n async addAdapter(adapter: AnyAdapter): Promise<void> {\n if (this.#adapters.has(adapter.adapterId)) {\n this.logger.debug(\"Adapter {adapterId} already exists, skipping add\", {\n adapterId: adapter.adapterId,\n })\n return\n }\n\n // Initialize and start the adapter\n this.#initializeAdapter(adapter)\n await adapter._start()\n\n this.logger.info(\"Added adapter {adapterId} of type {adapterType}\", {\n adapterId: adapter.adapterId,\n adapterType: adapter.adapterType,\n })\n }\n\n /**\n * Remove an adapter at runtime.\n * Idempotent: removing a non-existent adapter is a no-op.\n *\n * The sync protocol will naturally recover any \"lost\" state on the next\n * heartbeat or user-initiated sync.\n */\n async removeAdapter(adapterId: string): Promise<void> {\n const adapter = this.#adapters.get(adapterId)\n if (!adapter) {\n this.logger.debug(\"Adapter {adapterId} not found, skipping remove\", {\n adapterId,\n })\n return\n }\n\n // Clean up channels via callback\n this.#onReset(adapter)\n\n // Stop the adapter\n await adapter._stop()\n\n // Remove from our map\n this.#adapters.delete(adapterId)\n\n this.logger.info(\"Removed adapter {adapterId}\", { adapterId })\n }\n\n /**\n * Send an establishment message (establish-request or establish-response).\n * These messages can be sent to channels that are not yet established.\n */\n sendEstablishmentMessage(envelope: AddressedEstablishmentEnvelope): number {\n let sentCount = 0\n\n for (const adapter of this.#adapters.values()) {\n sentCount += adapter._send(envelope)\n }\n\n return sentCount\n }\n\n /**\n * Send an established message (sync, directory, delete).\n * These messages can only be sent to channels that have been established.\n */\n send(envelope: AddressedEstablishedEnvelope): number {\n let sentCount = 0\n\n for (const adapter of this.#adapters.values()) {\n sentCount += adapter._send(envelope)\n }\n\n return sentCount\n }\n\n /**\n * Reset all adapters and clear the manager.\n */\n reset() {\n for (const adapter of this.#adapters.values()) {\n // Let the adapter clean up its part\n adapter._stop()\n\n // Clean up our per-adapter part\n this.#onReset(adapter)\n }\n\n this.#adapters.clear()\n }\n}\n","import type { Logger } from \"@logtape/logtape\"\nimport type Emittery from \"emittery\"\nimport type { EphemeralStore, VersionVector } from \"loro-crdt\"\nimport type { AdapterManager } from \"../adapter/adapter-manager.js\"\nimport type { BatchableMsg } from \"../channel.js\"\nimport type {\n Command,\n SynchronizerMessage,\n SynchronizerModel,\n} from \"../synchronizer-program.js\"\nimport type {\n ChannelId,\n DocId,\n PeerID,\n PeerIdentityDetails,\n ReadyState,\n} from \"../types.js\"\nimport type { EphemeralStoreManager } from \"./ephemeral-store-manager.js\"\nimport type { OutboundBatcher } from \"./outbound-batcher.js\"\n\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n// TYPES\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n/**\n * Events that the Synchronizer can emit.\n * This type is used by command handlers to emit events.\n */\nexport type SynchronizerEvents = {\n \"ready-state-changed\": {\n docId: string\n readyStates: ReadyState[]\n }\n \"ephemeral-change\": {\n docId: string\n source: \"local\" | \"remote\"\n keys?: string[]\n peerId?: string\n }\n}\n\n/**\n * Context provided to command handlers.\n *\n * This contains all the dependencies a command handler might need to execute.\n * The context is created fresh for each command execution to ensure handlers\n * always have access to the latest state.\n */\nexport type CommandContext = {\n // Model access (read-only snapshot)\n readonly model: SynchronizerModel\n\n // Services\n readonly adapters: AdapterManager\n readonly ephemeralManager: EphemeralStoreManager\n readonly outboundBatcher: OutboundBatcher\n readonly emitter: Emittery<SynchronizerEvents>\n\n // Identity\n readonly identity: PeerIdentityDetails\n\n // Utilities\n readonly logger: Logger\n readonly dispatch: (msg: SynchronizerMessage) => void\n readonly executeCommand: (cmd: Command) => void // For recursive commands\n\n // Helper functions extracted from Synchronizer\n readonly validateChannelForSend: (channelId: ChannelId) => boolean\n readonly queueSend: (channelId: ChannelId, message: BatchableMsg) => void\n readonly getNamespacedStore: (\n docId: DocId,\n namespace: string,\n ) => EphemeralStore | undefined\n readonly getOrCreateNamespacedStore: (\n docId: DocId,\n namespace: string,\n ) => EphemeralStore\n readonly encodeAllPeerStores: (\n docId: DocId,\n ) => { docId: DocId; peerId: PeerID; data: Uint8Array; namespace: string }[]\n readonly buildSyncResponseMessage: (\n docId: DocId,\n requesterDocVersion: VersionVector,\n toChannelId: ChannelId,\n includeEphemeral?: boolean,\n ) => import(\"../channel.js\").ChannelMsgSyncResponse | undefined\n readonly buildSyncRequestMessage: (\n doc: { docId: DocId; requesterDocVersion: VersionVector },\n bidirectional: boolean,\n includeEphemeral?: boolean,\n ) => import(\"../channel.js\").ChannelMsgSyncRequest\n\n // Access to docNamespacedStores for cmd/broadcast-ephemeral-batch and cmd/remove-ephemeral-peer\n readonly docNamespacedStores: Map<DocId, Map<string, EphemeralStore>>\n}\n\n/**\n * A command handler function.\n *\n * Handlers are pure functions that take a command and context,\n * and perform side effects through the context's services.\n *\n * @template T - The specific command type this handler processes\n */\nexport type CommandHandler<T extends Command = Command> = (\n command: T,\n ctx: CommandContext,\n) => void\n\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n// COMMAND EXECUTOR\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n/**\n * CommandExecutor - Executes commands using a registry of handlers.\n *\n * This class decouples command execution from the Synchronizer class,\n * allowing handlers to be tested in isolation and new commands to be\n * added without modifying the Synchronizer.\n *\n * @example\n * ```typescript\n * const executor = new CommandExecutor(\n * commandHandlers,\n * () => synchronizer.buildCommandContext(),\n * )\n *\n * executor.execute({ type: \"cmd/stop-channel\", channel })\n * ```\n */\nexport class CommandExecutor {\n readonly #handlers: Map<Command[\"type\"], CommandHandler>\n readonly #contextProvider: () => CommandContext\n\n constructor(\n handlers: Map<Command[\"type\"], CommandHandler>,\n contextProvider: () => CommandContext,\n ) {\n this.#handlers = handlers\n this.#contextProvider = contextProvider\n }\n\n /**\n * Execute a command by looking up its handler and invoking it.\n *\n * @param command - The command to execute\n * @throws Error if no handler is registered for the command type\n */\n execute(command: Command): void {\n const handler = this.#handlers.get(command.type)\n if (!handler) {\n throw new Error(`Unknown command type: ${command.type}`)\n }\n handler(command, this.#contextProvider())\n }\n\n /**\n * Check if a handler is registered for a command type.\n */\n hasHandler(type: Command[\"type\"]): boolean {\n return this.#handlers.has(type)\n }\n\n /**\n * Get the number of registered handlers.\n */\n get handlerCount(): number {\n return this.#handlers.size\n }\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype ApplyEphemeralCommand = Extract<Command, { type: \"cmd/apply-ephemeral\" }>\n\n/**\n * Handle the cmd/apply-ephemeral command.\n *\n * Applies ephemeral data from remote peers to the appropriate namespaced stores.\n * Emits ephemeral-change events for each store that receives data.\n */\nexport function handleApplyEphemeral(\n command: ApplyEphemeralCommand,\n ctx: CommandContext,\n): void {\n const { docId, stores } = command\n\n // All ephemeral messages must have a namespace\n for (const storeData of stores) {\n const { peerId, data, namespace } = storeData\n\n if (!namespace) {\n ctx.logger.warn(\n \"cmd/apply-ephemeral: received message without namespace from {peerId} in {docId}, ignoring\",\n { peerId, docId },\n )\n continue\n }\n\n if (data.length === 0) {\n // Empty data - could indicate deletion, but for namespaced stores\n // we don't delete the whole store, just let the data expire\n ctx.logger.debug(\n \"cmd/apply-ephemeral: received empty data for namespace {namespace} from {peerId} in {docId}\",\n { namespace, peerId, docId },\n )\n } else {\n // Get or create the namespaced store and apply the data\n const store = ctx.getOrCreateNamespacedStore(docId, namespace)\n store.apply(data)\n\n ctx.logger.trace(\n \"cmd/apply-ephemeral: applied {dataLength} bytes to namespace {namespace} from {peerId} in {docId}\",\n { namespace, peerId, docId, dataLength: data.length },\n )\n }\n\n void ctx.emitter.emit(\"ephemeral-change\", {\n docId,\n source: \"remote\",\n peerId,\n })\n }\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype BatchCommand = Extract<Command, { type: \"cmd/batch\" }>\n\n/**\n * Handle the cmd/batch command.\n *\n * A utility command that executes a batch of commands sequentially.\n */\nexport function handleBatch(command: BatchCommand, ctx: CommandContext): void {\n for (const cmd of command.commands) {\n ctx.executeCommand(cmd)\n }\n}\n","import { EphemeralStore, type Value } from \"loro-crdt\"\n\n/**\n * An EphemeralStore that never expires its data.\n *\n * Used for \"my\" presence data, which should persist as long as the repo exists.\n * From my perspective, I am always here - my presence should never time out.\n *\n * ## Implementation Details\n *\n * The loro-crdt `EphemeralStore` has a timer that expires data after a timeout.\n * The timer is started by `set()` and `apply()` methods via `startTimerIfNotEmpty()`.\n *\n * This class bypasses the timer by:\n * 1. Using a large timeout (max 32-bit signed int ~24.8 days) so applied data\n * isn't immediately expired when received\n * 2. Overriding `set()` and `apply()` to call the inner wasm methods directly,\n * bypassing the `startTimerIfNotEmpty()` call\n *\n * ## Why not use `null` timeout?\n *\n * The loro-crdt EphemeralStore constructor accepts `null` as a timeout value,\n * but stores created with `null` timeout cannot receive data via `apply()` -\n * applied data is treated as immediately expired. Using a large timeout avoids\n * this issue.\n *\n * @example\n * ```typescript\n * const myStore = new TimerlessEphemeralStore()\n * myStore.set('cursor', { x: 10, y: 20 })\n * myStore.set('name', 'Alice')\n * // These values will never expire\n * ```\n */\nexport class TimerlessEphemeralStore<\n T extends Record<string, Value> = Record<string, Value>,\n> extends EphemeralStore<T> {\n constructor() {\n // Use max 32-bit signed int (~24.8 days) so applied data isn't immediately expired\n // The timer itself won't run because we override set/apply to bypass it\n super(2147483647)\n }\n\n /**\n * Set a value without triggering the expiration timer.\n */\n override set<K extends keyof T>(key: K, value: T[K]): void {\n // Call inner.set directly without triggering the timer\n // The parent class's set() calls startTimerIfNotEmpty() which we want to skip\n this.inner.set(key as string, value)\n }\n\n /**\n * Apply encoded data without triggering the expiration timer.\n */\n override apply(bytes: Uint8Array): void {\n // Call inner.apply directly without triggering the timer\n // The parent class's apply() calls startTimerIfNotEmpty() which we want to skip\n this.inner.apply(bytes)\n }\n\n /**\n * Touch all values to update their timestamps to the current time.\n *\n * This is essential for heartbeat functionality. The EphemeralStore encodes\n * data with the original timestamps from when values were set. When a receiving\n * store applies this data, it uses these timestamps to determine expiration.\n *\n * Without touching, heartbeat data would have stale timestamps and be\n * immediately expired on the receiving end.\n *\n * @example\n * ```typescript\n * // Before sending heartbeat\n * myStore.touch()\n * const data = myStore.encodeAll()\n * sendToServer(data)\n * ```\n */\n touch(): void {\n const states = this.getAllStates()\n for (const [key, value] of Object.entries(states)) {\n this.inner.set(key, value)\n }\n }\n\n /**\n * Encode all data with fresh timestamps for transmission.\n *\n * This is a convenience method that combines touch() and encodeAll().\n * Use this for heartbeat messages to ensure timestamps are current.\n *\n * @returns Encoded data with current timestamps\n */\n encodeAllFresh(): Uint8Array {\n this.touch()\n return this.encodeAll()\n }\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport { TimerlessEphemeralStore } from \"../../utils/timerless-ephemeral-store.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype BroadcastEphemeralBatchCommand = Extract<\n Command,\n { type: \"cmd/broadcast-ephemeral-batch\" }\n>\n\n/**\n * Handle the cmd/broadcast-ephemeral-batch command.\n *\n * Macro command: expands into multiple cmd/broadcast-ephemeral-namespace commands.\n * Each sub-command queues messages via queueSend(); the deferred send layer\n * aggregates them into a single channel/batch message at flush time.\n */\nexport function handleBroadcastEphemeralBatch(\n command: BroadcastEphemeralBatchCommand,\n ctx: CommandContext,\n): void {\n const subCommands: Command[] = []\n\n for (const docId of command.docIds) {\n const namespaceStores = ctx.docNamespacedStores.get(docId)\n\n if (!namespaceStores || namespaceStores.size === 0) {\n continue\n }\n\n // Touch all stores before encoding (for heartbeat timestamp refresh)\n for (const store of namespaceStores.values()) {\n if (store instanceof TimerlessEphemeralStore) {\n store.touch()\n }\n }\n\n // Create a command for each namespace\n for (const namespace of namespaceStores.keys()) {\n subCommands.push({\n type: \"cmd/broadcast-ephemeral-namespace\",\n docId,\n namespace,\n hopsRemaining: command.hopsRemaining,\n toChannelIds: [command.toChannelId],\n })\n }\n }\n\n if (subCommands.length === 0) {\n ctx.logger.debug(\n \"cmd/broadcast-ephemeral-batch: skipping (no stores to broadcast)\",\n )\n return\n }\n\n // Execute all sub-commands; each queues messages via queueSend()\n // The deferred send layer aggregates them at flush time\n for (const cmd of subCommands) {\n ctx.executeCommand(cmd)\n }\n\n ctx.logger.trace(\n \"cmd/broadcast-ephemeral-batch: expanded into {cmdCount} namespace broadcasts for channel {channelId}\",\n {\n cmdCount: subCommands.length,\n channelId: command.toChannelId,\n },\n )\n}\n","import type { ChannelMsgEphemeral } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype BroadcastEphemeralNamespaceCommand = Extract<\n Command,\n { type: \"cmd/broadcast-ephemeral-namespace\" }\n>\n\n/**\n * Handle the cmd/broadcast-ephemeral-namespace command.\n *\n * Broadcasts a single namespace's ephemeral data for a document to specified channels.\n */\nexport function handleBroadcastEphemeralNamespace(\n command: BroadcastEphemeralNamespaceCommand,\n ctx: CommandContext,\n): void {\n const { docId, namespace, hopsRemaining, toChannelIds } = command\n const store = ctx.getNamespacedStore(docId, namespace)\n\n if (!store) {\n ctx.logger.debug(\n \"cmd/broadcast-ephemeral-namespace: skipping for {docId}/{namespace} (store not found)\",\n () => ({ docId, namespace }),\n )\n return\n }\n\n const data = store.encodeAll()\n if (data.length === 0) {\n ctx.logger.debug(\n \"cmd/broadcast-ephemeral-namespace: skipping for {docId}/{namespace} (no data)\",\n () => ({ docId, namespace }),\n )\n return\n }\n\n if (toChannelIds.length === 0) {\n ctx.logger.debug(\n \"cmd/broadcast-ephemeral-namespace: skipping for {docId}/{namespace} (no channels)\",\n () => ({ docId, namespace }),\n )\n return\n }\n\n // Build the ephemeral message\n const message: ChannelMsgEphemeral = {\n type: \"channel/ephemeral\",\n docId,\n hopsRemaining,\n stores: [\n {\n peerId: ctx.identity.peerId,\n data,\n namespace,\n },\n ],\n }\n\n // Queue for each channel (deferred send will aggregate)\n for (const channelId of toChannelIds) {\n ctx.queueSend(channelId, message)\n }\n\n ctx.logger.trace(\n \"cmd/broadcast-ephemeral-namespace: queued {namespace} for {docId} to {channelCount} channels\",\n { namespace, docId, channelCount: toChannelIds.length },\n )\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype DispatchCommand = Extract<Command, { type: \"cmd/dispatch\" }>\n\n/**\n * Handle the cmd/dispatch command.\n *\n * A utility command that sends a dispatch back into the program message loop.\n */\nexport function handleDispatch(\n command: DispatchCommand,\n ctx: CommandContext,\n): void {\n ctx.dispatch(command.dispatch)\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype EmitEphemeralChangeCommand = Extract<\n Command,\n { type: \"cmd/emit-ephemeral-change\" }\n>\n\n/**\n * Handle the cmd/emit-ephemeral-change command.\n *\n * Emits an ephemeral-change event for local changes.\n */\nexport function handleEmitEphemeralChange(\n command: EmitEphemeralChangeCommand,\n ctx: CommandContext,\n): void {\n ctx.emitter.emit(\"ephemeral-change\", {\n docId: command.docId,\n source: \"local\",\n })\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype ImportDocDataCommand = Extract<Command, { type: \"cmd/import-doc-data\" }>\n\n/**\n * Handle the cmd/import-doc-data command.\n *\n * Imports document data from a remote peer and dispatches a follow-up\n * message to update peer awareness and trigger multi-hop propagation.\n */\nexport function handleImportDocData(\n command: ImportDocDataCommand,\n ctx: CommandContext,\n): void {\n const { docId, data, fromPeerId } = command\n\n const docState = ctx.model.documents.get(docId)\n if (!docState) {\n ctx.logger.warn(\"can't import doc data, doc {docId} not found\", {\n docId,\n })\n return\n }\n\n // Import the document data\n // Note: doc.subscribe() only fires for \"local\" events, so import won't trigger it\n docState.doc.import(data)\n\n // After import, dispatch a message to:\n // 1. Update peer awareness to our CURRENT version (prevents echo)\n // 2. Trigger doc-change for multi-hop propagation to OTHER peers\n //\n // We pass fromPeerId so the doc-change handler knows to skip this peer\n // (they just sent us this data, so they already have it)\n ctx.dispatch({\n type: \"synchronizer/doc-imported\",\n docId,\n fromPeerId,\n })\n}\n","import { type Channel, isEstablished } from \"../channel.js\"\nimport type { ChannelId, DocId, PeerID, PeerState } from \"../types.js\"\n\nexport function getEstablishedChannelsForDoc(\n channels: Map<ChannelId, Channel>,\n peers: Map<PeerID, PeerState>,\n docId: DocId,\n) {\n // Get all established channels for this document\n const channelIds: ChannelId[] = []\n\n for (const [channelId, channel] of channels) {\n if (isEstablished(channel)) {\n const peerState = peers.get(channel.peerId)\n if (peerState?.subscriptions.has(docId)) {\n channelIds.push(channelId)\n }\n }\n }\n\n return channelIds\n}\n","import type { ChannelMsgEphemeral } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { getEstablishedChannelsForDoc } from \"../../utils/get-established-channels-for-doc.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype RemoveEphemeralPeerCommand = Extract<\n Command,\n { type: \"cmd/remove-ephemeral-peer\" }\n>\n\n/**\n * Handle the cmd/remove-ephemeral-peer command.\n *\n * Removes a peer's data from all documents' namespaced stores and broadcasts\n * the deletion to other peers.\n */\nexport function handleRemoveEphemeralPeer(\n command: RemoveEphemeralPeerCommand,\n ctx: CommandContext,\n): void {\n const { peerId } = command\n\n // Remove the peer's data from all documents' namespaced stores\n for (const [docId, namespaceStores] of ctx.docNamespacedStores) {\n let peerDataRemoved = false\n const storesToBroadcast: { namespace: string }[] = []\n\n // Check ALL namespaces for this peer's data\n for (const [namespace, store] of namespaceStores) {\n const allStates = store.getAllStates()\n if (allStates[peerId] !== undefined) {\n // Delete the peer's key from this store\n store.delete(peerId)\n peerDataRemoved = true\n storesToBroadcast.push({ namespace })\n }\n }\n\n if (peerDataRemoved) {\n // Broadcast deletion to other peers using the utility function\n const channelIds = getEstablishedChannelsForDoc(\n ctx.model.channels,\n ctx.model.peers,\n docId,\n )\n\n if (channelIds.length > 0 && storesToBroadcast.length > 0) {\n // Build the ephemeral deletion message\n const ephemeralMessage: ChannelMsgEphemeral = {\n type: \"channel/ephemeral\",\n docId,\n hopsRemaining: 0,\n stores: storesToBroadcast.map(s => ({\n peerId,\n data: new Uint8Array(0), // Empty data signals deletion\n namespace: s.namespace,\n })),\n }\n\n // Queue for each channel (deferred send will aggregate)\n for (const channelId of channelIds) {\n ctx.queueSend(channelId, ephemeralMessage)\n }\n }\n\n // Emit change event so UI updates immediately\n // This is \"remote\" because we're removing a remote peer's data\n ctx.emitter.emit(\"ephemeral-change\", {\n docId,\n source: \"remote\",\n peerId,\n })\n }\n }\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype SendEstablishmentMessageCommand = Extract<\n Command,\n { type: \"cmd/send-establishment-message\" }\n>\n\n/**\n * Handle the cmd/send-establishment-message command.\n *\n * Sends establishment messages (establish-request or establish-response)\n * to channels that are not yet established.\n */\nexport function handleSendEstablishmentMessage(\n command: SendEstablishmentMessageCommand,\n ctx: CommandContext,\n): void {\n ctx.logger.debug(\"executing cmd/send-establishment-message: {messageType}\", {\n messageType: command.envelope.message.type,\n toChannelIds: command.envelope.toChannelIds,\n totalAdapters: ctx.adapters.adapters.length,\n adapterChannelCounts: ctx.adapters.adapters.map(a => ({\n adapterType: a.adapterType,\n channelCount: a.channels.size,\n })),\n })\n\n const sentCount = ctx.adapters.sendEstablishmentMessage(command.envelope)\n\n ctx.logger.debug(\n \"cmd/send-establishment-message result: sent {sentCount}/{expectedCount}\",\n {\n sentCount,\n expectedCount: command.envelope.toChannelIds.length,\n },\n )\n\n if (sentCount < command.envelope.toChannelIds.length) {\n ctx.logger.warn(\n \"cmd/send-establishment-message could not deliver {messageType} to all {expectedCount} channels\",\n {\n messageType: command.envelope.message.type,\n expectedCount: command.envelope.toChannelIds.length,\n channelIds: command.envelope.toChannelIds,\n },\n )\n }\n}\n","import type { BatchableMsg } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype SendMessageCommand = Extract<Command, { type: \"cmd/send-message\" }>\n\n/**\n * Handle the cmd/send-message command.\n *\n * Queues messages for deferred send (aggregated at end of dispatch).\n * Validates channels before sending and flattens nested batches.\n */\nexport function handleSendMessage(\n command: SendMessageCommand,\n ctx: CommandContext,\n): void {\n for (const channelId of command.envelope.toChannelIds) {\n if (!ctx.validateChannelForSend(channelId)) continue\n\n // Flatten nested batches\n if (command.envelope.message.type === \"channel/batch\") {\n for (const msg of command.envelope.message.messages) {\n ctx.queueSend(channelId, msg)\n }\n } else {\n ctx.queueSend(channelId, command.envelope.message as BatchableMsg)\n }\n }\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype SendSyncRequestCommand = Extract<\n Command,\n { type: \"cmd/send-sync-request\" }\n>\n\n/**\n * Handle the cmd/send-sync-request command.\n *\n * Builds and queues sync-request messages for multiple documents.\n * The deferred send layer will aggregate them into a batch at flush time.\n */\nexport function handleSendSyncRequest(\n command: SendSyncRequestCommand,\n ctx: CommandContext,\n): void {\n const { toChannelId, docs, bidirectional, includeEphemeral } = command\n\n // Validate channel exists\n const channel = ctx.model.channels.get(toChannelId)\n if (!channel) {\n ctx.logger.warn(\n \"can't send sync-request, channel {toChannelId} doesn't exist\",\n { toChannelId },\n )\n return\n }\n\n // Queue each sync-request message individually\n // The deferred send layer will aggregate them into a batch at flush time\n for (const doc of docs) {\n const message = ctx.buildSyncRequestMessage(\n doc,\n bidirectional,\n includeEphemeral,\n )\n ctx.queueSend(toChannelId, message)\n }\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype SendSyncResponseCommand = Extract<\n Command,\n { type: \"cmd/send-sync-response\" }\n>\n\n/**\n * Handle the cmd/send-sync-response command.\n *\n * Builds and queues a sync-response message for a document.\n * Optionally includes ephemeral data in the response.\n */\nexport function handleSendSyncResponse(\n command: SendSyncResponseCommand,\n ctx: CommandContext,\n): void {\n const { docId, requesterDocVersion, toChannelId, includeEphemeral } = command\n\n const message = ctx.buildSyncResponseMessage(\n docId,\n requesterDocVersion,\n toChannelId,\n includeEphemeral,\n )\n\n if (message) {\n ctx.queueSend(toChannelId, message)\n }\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype StopChannelCommand = Extract<Command, { type: \"cmd/stop-channel\" }>\n\n/**\n * Handle the cmd/stop-channel command.\n *\n * De-initializes a channel by calling its stop() method.\n */\nexport function handleStopChannel(\n command: StopChannelCommand,\n _ctx: CommandContext,\n): void {\n command.channel.stop()\n}\n","import type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandContext } from \"../command-executor.js\"\n\ntype SubscribeDocCommand = Extract<Command, { type: \"cmd/subscribe-doc\" }>\n\n/**\n * Handle the cmd/subscribe-doc command.\n *\n * Subscribes to local changes on a document, routing them through\n * the dispatch system for proper TEA compliance.\n *\n * NOTE: Remote (imported) changes are handled explicitly in handle-sync-response.\n */\nexport function handleSubscribeDoc(\n command: SubscribeDocCommand,\n ctx: CommandContext,\n): void {\n const { docId } = command\n\n const docState = ctx.model.documents.get(docId)\n if (!docState) {\n ctx.logger.warn(\"can't get doc-state, doc {docId} not found\", { docId })\n return\n }\n\n /**\n * Subscribe to local changes, to be handled by local-doc-change.\n *\n * NOTE: Remote (imported) changes are handled explicitly in handle-sync-response.\n */\n docState.doc.subscribeLocalUpdates(() => {\n ctx.dispatch({\n type: \"synchronizer/local-doc-change\",\n docId,\n })\n })\n // For \"import\" events, we don't dispatch local-doc-change here.\n // The import is triggered by cmd/import-doc-data, which is followed by\n // a cmd/dispatch for doc-change with proper peer awareness already set.\n}\n","/**\n * Command Handler Registry\n *\n * This module exports a Map of command types to their handlers.\n * The registry is used by CommandExecutor to dispatch commands.\n *\n * To add a new command:\n * 1. Create a handler file: handle-<command-name>.ts\n * 2. Import the handler here\n * 3. Add it to the commandHandlers Map\n */\n\nimport type { Command } from \"../../synchronizer-program.js\"\nimport type { CommandHandler } from \"../command-executor.js\"\n\n// Import individual handlers\nimport { handleApplyEphemeral } from \"./handle-apply-ephemeral.js\"\nimport { handleBatch } from \"./handle-batch.js\"\nimport { handleBroadcastEphemeralBatch } from \"./handle-broadcast-ephemeral-batch.js\"\nimport { handleBroadcastEphemeralNamespace } from \"./handle-broadcast-ephemeral-namespace.js\"\nimport { handleDispatch } from \"./handle-dispatch.js\"\nimport { handleEmitEphemeralChange } from \"./handle-emit-ephemeral-change.js\"\nimport { handleImportDocData } from \"./handle-import-doc-data.js\"\nimport { handleRemoveEphemeralPeer } from \"./handle-remove-ephemeral-peer.js\"\nimport { handleSendEstablishmentMessage } from \"./handle-send-establishment-message.js\"\nimport { handleSendMessage } from \"./handle-send-message.js\"\nimport { handleSendSyncRequest } from \"./handle-send-sync-request.js\"\nimport { handleSendSyncResponse } from \"./handle-send-sync-response.js\"\nimport { handleStopChannel } from \"./handle-stop-channel.js\"\nimport { handleSubscribeDoc } from \"./handle-subscribe-doc.js\"\n\n/**\n * Registry of command handlers.\n *\n * Each entry maps a command type to its handler function.\n * The CommandExecutor uses this registry to dispatch commands.\n */\nexport const commandHandlers: Map<Command[\"type\"], CommandHandler> = new Map([\n [\"cmd/stop-channel\", handleStopChannel as CommandHandler],\n [\n \"cmd/send-establishment-message\",\n handleSendEstablishmentMessage as CommandHandler,\n ],\n [\"cmd/send-message\", handleSendMessage as CommandHandler],\n [\"cmd/send-sync-response\", handleSendSyncResponse as CommandHandler],\n [\"cmd/send-sync-request\", handleSendSyncRequest as CommandHandler],\n [\"cmd/subscribe-doc\", handleSubscribeDoc as CommandHandler],\n [\"cmd/import-doc-data\", handleImportDocData as CommandHandler],\n [\"cmd/emit-ephemeral-change\", handleEmitEphemeralChange as CommandHandler],\n [\"cmd/apply-ephemeral\", handleApplyEphemeral as CommandHandler],\n [\n \"cmd/broadcast-ephemeral-batch\",\n handleBroadcastEphemeralBatch as CommandHandler,\n ],\n [\n \"cmd/broadcast-ephemeral-namespace\",\n handleBroadcastEphemeralNamespace as CommandHandler,\n ],\n [\"cmd/remove-ephemeral-peer\", handleRemoveEphemeralPeer as CommandHandler],\n [\"cmd/dispatch\", handleDispatch as CommandHandler],\n [\"cmd/batch\", handleBatch as CommandHandler],\n])\n\n// Re-export types for convenience\nexport type { CommandContext, CommandHandler } from \"../command-executor.js\"\nexport { CommandExecutor } from \"../command-executor.js\"\n","import type { Logger } from \"@logtape/logtape\"\nimport type { EphemeralStore } from \"loro-crdt\"\nimport type { EphemeralStoreData } from \"../channel.js\"\nimport type { DocId, PeerID, PeerIdentityDetails } from \"../types.js\"\nimport { TimerlessEphemeralStore } from \"../utils/timerless-ephemeral-store.js\"\n\n/**\n * EphemeralStoreManager - Manages namespaced ephemeral stores for documents\n *\n * Each document can have multiple named ephemeral stores (e.g., 'presence', 'cursors').\n * This supports both internal stores (created via getOrCreate) and external stores\n * (registered via registerExternal, e.g., from loro-prosemirror).\n *\n * @example\n * ```typescript\n * const manager = new EphemeralStoreManager(\n * identity,\n * (docId, namespace) => dispatch({ type: 'ephemeral-local-change', docId, namespace }),\n * logger\n * )\n *\n * // Get or create a store\n * const presenceStore = manager.getOrCreate('doc-1', 'presence')\n * presenceStore.set('cursor', { x: 10, y: 20 })\n *\n * // Register an external store\n * manager.registerExternal('doc-1', 'prosemirror', externalStore)\n *\n * // Encode all stores for transmission\n * const encoded = manager.encodeAll('doc-1')\n * ```\n */\nexport class EphemeralStoreManager {\n /**\n * Per-doc namespaced ephemeral stores.\n * Structure: Map<DocId, Map<Namespace, EphemeralStore>>\n */\n readonly stores = new Map<DocId, Map<string, EphemeralStore>>()\n\n /**\n * External store subscriptions for cleanup.\n * Maps store to its unsubscribe function.\n */\n readonly #subscriptions = new Map<EphemeralStore, () => void>()\n\n readonly #identity: PeerIdentityDetails\n readonly #onLocalChange: (docId: DocId, namespace: string) => void\n readonly #logger: Logger\n\n /**\n * Create a new EphemeralStoreManager.\n *\n * @param identity - Our peer identity (for peerId in encoded data)\n * @param onLocalChange - Callback when a local change is made to any store\n * @param logger - Logger for debugging\n */\n constructor(\n identity: PeerIdentityDetails,\n onLocalChange: (docId: DocId, namespace: string) => void,\n logger: Logger,\n ) {\n this.#identity = identity\n this.#onLocalChange = onLocalChange\n this.#logger = logger\n }\n\n /**\n * Get or create a namespaced ephemeral store for a document.\n *\n * @param docId - The document ID\n * @param namespace - The store namespace (e.g., 'presence', 'cursors')\n * @returns The ephemeral store for this namespace\n */\n getOrCreate(docId: DocId, namespace: string): EphemeralStore {\n let namespaceStores = this.stores.get(docId)\n if (!namespaceStores) {\n namespaceStores = new Map()\n this.stores.set(docId, namespaceStores)\n }\n\n let store = namespaceStores.get(namespace)\n if (!store) {\n // Create a new TimerlessEphemeralStore for internal stores\n store = new TimerlessEphemeralStore()\n namespaceStores.set(namespace, store)\n\n // Subscribe to changes and broadcast\n this.#subscribeToStore(docId, namespace, store)\n\n this.#logger.debug(\n \"Created namespaced store {namespace} for doc {docId}\",\n { namespace, docId },\n )\n }\n\n return store\n }\n\n /**\n * Register an external ephemeral store for network sync.\n * Use this for libraries that bring their own EphemeralStore (like loro-prosemirror).\n *\n * @param docId - The document ID\n * @param namespace - The store namespace\n * @param store - The external EphemeralStore to register\n * @throws Error if a store with this namespace already exists\n */\n registerExternal(\n docId: DocId,\n namespace: string,\n store: EphemeralStore,\n ): void {\n let namespaceStores = this.stores.get(docId)\n if (!namespaceStores) {\n namespaceStores = new Map()\n this.stores.set(docId, namespaceStores)\n }\n\n if (namespaceStores.has(namespace)) {\n throw new Error(\n `Ephemeral store \"${namespace}\" already exists for doc \"${docId}\"`,\n )\n }\n\n namespaceStores.set(namespace, store)\n\n // Subscribe to changes and broadcast\n this.#subscribeToStore(docId, namespace, store)\n\n this.#logger.debug(\n \"Registered external store {namespace} for doc {docId}\",\n {\n namespace,\n docId,\n },\n )\n }\n\n /**\n * Get a namespaced store by name.\n *\n * @param docId - The document ID\n * @param namespace - The store namespace\n * @returns The EphemeralStore or undefined if not found\n */\n get(docId: DocId, namespace: string): EphemeralStore | undefined {\n return this.stores.get(docId)?.get(namespace)\n }\n\n /**\n * Encode all namespaced stores for a document.\n * Returns an array of store data for each store with data.\n *\n * @param docId - The document ID\n * @returns Array of encoded store data\n */\n encodeAll(docId: DocId): EphemeralStoreData[] {\n const result: EphemeralStoreData[] = []\n\n const namespaceStores = this.stores.get(docId)\n if (namespaceStores) {\n for (const [namespace, store] of namespaceStores) {\n // Touch the store to update timestamps before encoding\n if (store instanceof TimerlessEphemeralStore) {\n store.touch()\n }\n const data = store.encodeAll()\n if (data.length > 0) {\n result.push({\n peerId: this.#identity.peerId,\n data,\n namespace,\n })\n }\n }\n }\n\n return result\n }\n\n /**\n * Apply ephemeral data from a remote peer.\n *\n * @param docId - The document ID\n * @param storeData - The store data to apply\n */\n applyRemote(docId: DocId, storeData: EphemeralStoreData): void {\n const { peerId, data, namespace } = storeData\n\n if (!namespace) {\n this.#logger.warn(\n \"applyRemote: received message without namespace from {peerId} in {docId}, ignoring\",\n { peerId, docId },\n )\n return\n }\n\n if (data.length === 0) {\n // Empty data - could indicate deletion, but for namespaced stores\n // we don't delete the whole store, just let the data expire\n this.#logger.debug(\n \"applyRemote: received empty data for namespace {namespace} from {peerId} in {docId}\",\n { namespace, peerId, docId },\n )\n return\n }\n\n // Get or create the namespaced store and apply the data\n const store = this.getOrCreate(docId, namespace)\n store.apply(data)\n\n this.#logger.trace(\n \"applyRemote: applied {dataLength} bytes to namespace {namespace} from {peerId} in {docId}\",\n { namespace, peerId, docId, dataLength: data.length },\n )\n }\n\n /**\n * Remove a peer's data from all documents' namespaced stores.\n *\n * @param peerId - The peer ID to remove\n * @returns Array of { docId, namespace } for stores that had data removed\n */\n removePeer(peerId: PeerID): { docId: DocId; namespace: string }[] {\n const removed: { docId: DocId; namespace: string }[] = []\n\n for (const [docId, namespaceStores] of this.stores) {\n for (const [namespace, store] of namespaceStores) {\n const allStates = store.getAllStates()\n if (allStates[peerId] !== undefined) {\n store.delete(peerId)\n removed.push({ docId, namespace })\n }\n }\n }\n\n return removed\n }\n\n /**\n * Get all namespaces for a document.\n *\n * @param docId - The document ID\n * @returns Array of namespace names\n */\n getNamespaces(docId: DocId): string[] {\n const namespaceStores = this.stores.get(docId)\n return namespaceStores ? Array.from(namespaceStores.keys()) : []\n }\n\n /**\n * Touch all stores for a document to refresh timestamps.\n * Used before encoding for heartbeat.\n *\n * @param docId - The document ID\n */\n touchAll(docId: DocId): void {\n const namespaceStores = this.stores.get(docId)\n if (namespaceStores) {\n for (const store of namespaceStores.values()) {\n if (store instanceof TimerlessEphemeralStore) {\n store.touch()\n }\n }\n }\n }\n\n /**\n * Unsubscribe from all stores and clean up.\n */\n unsubscribeAll(): void {\n for (const unsub of this.#subscriptions.values()) {\n unsub()\n }\n this.#subscriptions.clear()\n }\n\n /**\n * Subscribe to a namespaced store and set up broadcasting.\n *\n * Uses the EphemeralStore.subscribe() callback's `by` field to filter:\n * - `by: 'local'` → broadcast (change was made via `set()`)\n * - `by: 'import'` → don't broadcast (change came from network via `apply()`)\n */\n #subscribeToStore(\n docId: DocId,\n namespace: string,\n store: EphemeralStore,\n ): void {\n const unsub = store.subscribe(event => {\n // Only broadcast local changes (not imported data from network)\n if (event.by === \"local\") {\n this.#onLocalChange(docId, namespace)\n }\n })\n\n // Store the unsubscribe function for cleanup\n this.#subscriptions.set(store, unsub)\n }\n}\n","/**\n * HeartbeatManager - Manages periodic heartbeat for ephemeral store synchronization\n *\n * The heartbeat ensures ephemeral data (presence, cursors, etc.) is periodically\n * broadcast to all peers, keeping the data fresh and preventing expiration.\n *\n * @example\n * ```typescript\n * const heartbeat = new HeartbeatManager(10000, () => {\n * // Broadcast ephemeral state to all peers\n * broadcastEphemeralToAllPeers()\n * })\n *\n * heartbeat.start()\n * // ... later\n * heartbeat.stop()\n * ```\n */\nexport class HeartbeatManager {\n #interval: ReturnType<typeof setInterval> | undefined\n readonly #intervalMs: number\n readonly #onHeartbeat: () => void\n\n /**\n * Create a new HeartbeatManager.\n *\n * @param intervalMs - Interval between heartbeats in milliseconds\n * @param onHeartbeat - Callback invoked on each heartbeat\n */\n constructor(intervalMs: number, onHeartbeat: () => void) {\n this.#intervalMs = intervalMs\n this.#onHeartbeat = onHeartbeat\n }\n\n /**\n * Start the heartbeat timer.\n * If already running, this is a no-op.\n */\n start(): void {\n if (this.#interval !== undefined) {\n return\n }\n this.#interval = setInterval(() => {\n this.#onHeartbeat()\n }, this.#intervalMs)\n }\n\n /**\n * Stop the heartbeat timer.\n * If not running, this is a no-op.\n */\n stop(): void {\n if (this.#interval !== undefined) {\n clearInterval(this.#interval)\n this.#interval = undefined\n }\n }\n\n /**\n * Check if the heartbeat is currently running.\n */\n get isRunning(): boolean {\n return this.#interval !== undefined\n }\n\n /**\n * Get the configured interval in milliseconds.\n */\n get intervalMs(): number {\n return this.#intervalMs\n }\n}\n","import type { Logger } from \"@logtape/logtape\"\nimport type { PeerID } from \"loro-crdt\"\nimport type { BatchableMsg, Channel, ChannelMsg } from \"../channel.js\"\nimport { isEstablished } from \"../channel.js\"\nimport type { Middleware, MiddlewareContext } from \"../middleware.js\"\nimport { runMiddleware } from \"../middleware.js\"\nimport type { DocContext, PeerContext } from \"../permissions.js\"\nimport type { ChannelId, DocId, DocState, PeerState } from \"../types.js\"\n\n/**\n * Read-only accessor for model data needed by middleware.\n * This provides a clean interface without exposing the full model.\n */\nexport type ModelAccessor = {\n readonly channels: ReadonlyMap<ChannelId, Channel>\n readonly peers: ReadonlyMap<PeerID, PeerState>\n readonly documents: ReadonlyMap<DocId, DocState>\n}\n\n/**\n * Result of processing a message through middleware.\n */\nexport type ProcessResult =\n | { type: \"allowed\"; message: ChannelMsg }\n | { type: \"allowed-batch\"; messages: BatchableMsg[] }\n | { type: \"rejected\" }\n | { type: \"no-middleware\" }\n\n/**\n * MiddlewareProcessor - Handles middleware execution for incoming messages\n *\n * Encapsulates the logic for:\n * - Building peer context from channels\n * - Extracting document and transmission context from messages\n * - Running middleware on single messages and batches\n *\n * @example\n * ```typescript\n * const processor = new MiddlewareProcessor(middleware, contextProvider, logger)\n *\n * // Process a single message\n * const result = await processor.processMessage(channelId, message)\n * if (result.type === 'allowed') {\n * dispatch(result.message)\n * }\n *\n * // Process a batch\n * const batchResult = await processor.processBatch(channelId, messages)\n * ```\n */\nexport class MiddlewareProcessor {\n readonly #middleware: Middleware[]\n readonly #getModel: () => ModelAccessor\n readonly #logger: Logger\n\n constructor(\n middleware: Middleware[],\n getModel: () => ModelAccessor,\n logger: Logger,\n ) {\n this.#middleware = middleware\n this.#getModel = getModel\n this.#logger = logger\n }\n\n /**\n * Check if middleware is configured.\n */\n get hasMiddleware(): boolean {\n return this.#middleware.length > 0\n }\n\n /**\n * Get the number of middleware configured.\n */\n get count(): number {\n return this.#middleware.length\n }\n\n /**\n * Process a single message through middleware.\n *\n * @param channelId - The channel the message came from\n * @param message - The message to process\n * @returns Processing result\n */\n async processMessage(\n channelId: ChannelId,\n message: ChannelMsg,\n ): Promise<ProcessResult> {\n if (!this.hasMiddleware) {\n return { type: \"no-middleware\" }\n }\n\n const model = this.#getModel()\n const channel = model.channels.get(channelId)\n if (!channel) {\n return { type: \"no-middleware\" }\n }\n\n const peerContext = this.#buildPeerContextFromChannel(model, channel)\n if (!peerContext) {\n return { type: \"no-middleware\" }\n }\n\n const middlewareCtx = this.#buildMiddlewareContext(\n model,\n message,\n peerContext,\n )\n const result = await runMiddleware(\n this.#middleware,\n middlewareCtx,\n this.#logger,\n )\n\n if (result.allow) {\n return { type: \"allowed\", message }\n }\n return { type: \"rejected\" }\n }\n\n /**\n * Process a batch of messages through middleware.\n * Each message is checked individually; only allowed messages are returned.\n *\n * @param channelId - The channel the messages came from\n * @param messages - The messages to process\n * @returns Processing result with allowed messages\n */\n async processBatch(\n channelId: ChannelId,\n messages: BatchableMsg[],\n ): Promise<ProcessResult> {\n if (!this.hasMiddleware) {\n return { type: \"no-middleware\" }\n }\n\n const model = this.#getModel()\n const channel = model.channels.get(channelId)\n if (!channel) {\n return { type: \"no-middleware\" }\n }\n\n const peerContext = this.#buildPeerContextFromChannel(model, channel)\n if (!peerContext) {\n return { type: \"no-middleware\" }\n }\n\n // Process each message through middleware\n const results = await Promise.all(\n messages.map(async msg => {\n const middlewareCtx = this.#buildMiddlewareContext(\n model,\n msg,\n peerContext,\n )\n const result = await runMiddleware(\n this.#middleware,\n middlewareCtx,\n this.#logger,\n )\n return { msg, allowed: result.allow }\n }),\n )\n\n const allowedMessages = results.filter(r => r.allowed).map(r => r.msg)\n\n if (allowedMessages.length === 0) {\n return { type: \"rejected\" }\n }\n\n if (allowedMessages.length === 1) {\n return { type: \"allowed\", message: allowedMessages[0] }\n }\n\n return { type: \"allowed-batch\", messages: allowedMessages }\n }\n\n /**\n * Build peer context from a channel for middleware.\n * Returns undefined if channel is not established or peer state not found.\n */\n #buildPeerContextFromChannel(\n model: ModelAccessor,\n channel: Channel,\n ): PeerContext | undefined {\n if (!isEstablished(channel)) {\n return undefined\n }\n\n const peerState = model.peers.get(channel.peerId)\n if (!peerState) {\n return undefined\n }\n\n return {\n peerId: peerState.identity.peerId,\n peerName: peerState.identity.name,\n peerType: peerState.identity.type,\n channelId: channel.channelId,\n channelKind: channel.kind,\n }\n }\n\n /**\n * Build the full middleware context for a message.\n */\n #buildMiddlewareContext(\n model: ModelAccessor,\n message: ChannelMsg,\n peerContext: PeerContext,\n ): MiddlewareContext {\n const { docId, transmission } = this.#extractContextFromMessage(message)\n\n let docContext: DocContext | undefined\n if (docId) {\n const doc = model.documents.get(docId)\n if (doc) {\n docContext = { id: docId, doc: doc.doc }\n }\n }\n\n return {\n message,\n peer: peerContext,\n document: docContext,\n transmission,\n }\n }\n\n /**\n * Extract document and transmission context from a channel message.\n * Used to provide full context to middleware.\n */\n #extractContextFromMessage(message: ChannelMsg): {\n docId?: DocId\n transmission?: { type: \"snapshot\" | \"update\"; sizeBytes: number }\n } {\n // Handle messages with docId field\n if (\"docId\" in message && typeof message.docId === \"string\") {\n const docId = message.docId as DocId\n\n // Handle sync-response and update messages with transmission data\n if (\n (message.type === \"channel/sync-response\" ||\n message.type === \"channel/update\") &&\n \"transmission\" in message\n ) {\n const t = message.transmission\n if (\n (t.type === \"snapshot\" || t.type === \"update\") &&\n \"data\" in t &&\n t.data instanceof Uint8Array\n ) {\n return {\n docId,\n transmission: { type: t.type, sizeBytes: t.data.length },\n }\n }\n }\n\n return { docId }\n }\n\n // Handle sync-request (has docs array, not single docId)\n // For middleware, we don't provide document context for multi-doc messages\n // Middleware can inspect message.docs directly if needed\n\n return {}\n }\n}\n","import type {\n AddressedEstablishedEnvelope,\n BatchableMsg,\n ChannelMsgBatch,\n} from \"../channel.js\"\nimport type { ChannelId } from \"../types.js\"\n\n/**\n * OutboundBatcher - Batches outbound messages by channel for efficient transmission\n *\n * Messages are aggregated by channel and flushed at quiescence.\n * Single messages are sent directly; multiple messages are wrapped in a batch.\n *\n * @example\n * ```typescript\n * const batcher = new OutboundBatcher()\n *\n * // Queue messages during processing\n * batcher.queue(channelId1, syncResponse1)\n * batcher.queue(channelId1, syncResponse2)\n * batcher.queue(channelId2, ephemeralMsg)\n *\n * // Flush at quiescence\n * batcher.flush((envelope) => adapters.send(envelope))\n * // channelId1 gets a batch with 2 messages\n * // channelId2 gets a single message (no batch wrapper)\n * ```\n */\nexport class OutboundBatcher {\n #buffer: Map<ChannelId, BatchableMsg[]> = new Map()\n\n /**\n * Queue a message to be sent to a channel.\n * Messages are aggregated by channel and flushed at quiescence.\n */\n queue(channelId: ChannelId, message: BatchableMsg): void {\n const queue = this.#buffer.get(channelId) ?? []\n queue.push(message)\n this.#buffer.set(channelId, queue)\n }\n\n /**\n * Flush all buffered outbound messages, aggregating by channel.\n * Single messages are sent directly; multiple messages are wrapped in a batch.\n *\n * The buffer is cleared before sending to handle reentrancy safely\n * (synchronous adapter replies will queue to a fresh buffer).\n *\n * @param send - Function to send an addressed envelope\n */\n flush(send: (envelope: AddressedEstablishedEnvelope) => void): void {\n // Snapshot and clear to handle reentrancy safely\n // (synchronous adapter replies will queue to a fresh buffer)\n const toSend = new Map(this.#buffer)\n this.#buffer.clear()\n\n for (const [channelId, messages] of toSend) {\n if (messages.length === 0) continue\n\n if (messages.length === 1) {\n // Single message - send directly without batch wrapper\n send({ toChannelIds: [channelId], message: messages[0] })\n } else {\n // Multiple messages - wrap in batch\n const batchMessage: ChannelMsgBatch = {\n type: \"channel/batch\",\n messages,\n }\n send({ toChannelIds: [channelId], message: batchMessage })\n }\n }\n }\n\n /**\n * Get the number of channels with pending messages.\n * Useful for testing and debugging.\n */\n get pendingChannelCount(): number {\n return this.#buffer.size\n }\n\n /**\n * Get the total number of pending messages across all channels.\n * Useful for testing and debugging.\n */\n get pendingMessageCount(): number {\n let count = 0\n for (const messages of this.#buffer.values()) {\n count += messages.length\n }\n return count\n }\n\n /**\n * Check if there are any pending messages.\n */\n get hasPending(): boolean {\n return this.#buffer.size > 0\n }\n}\n","import type { SynchronizerModel } from \"../synchronizer-program.js\"\nimport type { DocId, ReadyState, ReadyStateChannelMeta } from \"../types.js\"\n\n/**\n * Get ready states for all channels for a document\n *\n * Converts peer-centric state (documentAwareness) to channel-centric UI state (ReadyState[])\n */\nexport function getReadyStates(\n model: SynchronizerModel,\n docId: DocId,\n): ReadyState[] {\n const readyStates: ReadyState[] = []\n\n /**\n * 1. Include ready state of the document in our own repo\n *\n * Note: there is no \"unknown\" state with regard to our own repo--we can always positively conclude that we\n * either have the document (aware/loaded) or we do not have the document (absent).\n */\n const myDoc = model.documents.get(docId)\n if (!myDoc) {\n readyStates.push({\n status: \"absent\",\n docId,\n identity: { ...model.identity },\n channels: [], // Local repo has no channels\n })\n } else {\n if (myDoc.doc.opCount() > 0) {\n readyStates.push({\n status: \"synced\",\n docId,\n identity: { ...model.identity },\n channels: [],\n })\n } else {\n readyStates.push({\n status: \"pending\",\n docId,\n identity: { ...model.identity },\n channels: [],\n })\n }\n }\n\n /**\n * 2. Include ready state of document in all other repos (peers)\n */\n for (const peer of model.peers.values()) {\n const awareness = peer.docSyncStates.get(docId)\n\n if (!awareness || awareness.status === \"unknown\") {\n continue\n }\n\n if (awareness.status === \"synced\" || awareness.status === \"pending\") {\n const channels: ReadyStateChannelMeta[] = []\n\n for (const channelId of peer.channels) {\n const channel = model.channels.get(channelId)\n if (!channel) continue\n\n channels.push({\n kind: channel.kind,\n state: channel.type,\n adapterType: channel.adapterType,\n })\n }\n\n // \"synced\" means we know their version (loaded)\n // \"pending\" means they have it but we don't know their version yet (aware)\n const status = awareness.status === \"pending\" ? \"pending\" : \"synced\"\n readyStates.push({\n status,\n docId,\n identity: { ...peer.identity },\n channels,\n })\n } else if (awareness.status === \"absent\") {\n // Build channels list for absent state too\n const channels: ReadyStateChannelMeta[] = []\n for (const channelId of peer.channels) {\n const channel = model.channels.get(channelId)\n if (!channel) continue\n\n channels.push({\n kind: channel.kind,\n state: channel.type,\n adapterType: channel.adapterType,\n })\n }\n\n readyStates.push({\n status: \"absent\",\n docId,\n identity: { ...peer.identity },\n channels,\n })\n } else {\n throw new Error(\"invalid awareness state\")\n }\n }\n\n return readyStates\n}\n","/**\n * WorkQueue - Unified work queue for deferred execution\n *\n * Prevents recursion when adapters deliver messages synchronously\n * (e.g., BridgeAdapter, StorageAdapter). Work items are queued and\n * processed iteratively rather than recursively.\n *\n * @example\n * ```typescript\n * const queue = new WorkQueue(() => {\n * // Called at quiescence (when queue is empty)\n * flushOutboundMessages()\n * })\n *\n * queue.enqueue(() => processMessage(msg1))\n * queue.enqueue(() => processMessage(msg2))\n * // Both messages processed, then onQuiescent called\n * ```\n */\nexport class WorkQueue {\n #queue: Array<() => void> = []\n #isProcessing = false\n readonly #onQuiescent: () => void\n\n /**\n * Create a new WorkQueue.\n *\n * @param onQuiescent - Callback invoked when the queue becomes empty.\n * Use this to flush batched operations.\n */\n constructor(onQuiescent: () => void) {\n this.#onQuiescent = onQuiescent\n }\n\n /**\n * Enqueue work to be processed.\n *\n * If not currently processing, starts processing immediately.\n * If already processing, work is added to the queue and will be\n * processed in order.\n */\n enqueue(work: () => void): void {\n this.#queue.push(work)\n this.#processUntilQuiescent()\n }\n\n /**\n * Returns true if currently processing the queue.\n *\n * Use this to decide whether to enqueue work or execute inline:\n * - If processing, execute inline to avoid unnecessary queueing\n * - If not processing, enqueue to ensure proper batching\n */\n get isProcessing(): boolean {\n return this.#isProcessing\n }\n\n /**\n * Process all queued work until quiescence, then call onQuiescent.\n * Uses a guard flag to prevent recursive processing.\n */\n #processUntilQuiescent(): void {\n if (this.#isProcessing) return\n\n this.#isProcessing = true\n try {\n let work = this.#queue.shift()\n while (work) {\n work()\n work = this.#queue.shift()\n }\n // Quiescent: invoke callback\n this.#onQuiescent()\n } finally {\n this.#isProcessing = false\n }\n\n // If onQuiescent generated new work (via synchronous adapter replies), process it\n if (this.#queue.length > 0) {\n this.#processUntilQuiescent()\n }\n }\n}\n","/**\n * Synchronizer Program - Core orchestration for document discovery and synchronization\n *\n * This module implements the main state machine for the loro-extended synchronization protocol.\n * It follows The Elm Architecture (TEA) pattern with immutable updates via the mutative library.\n *\n * ## Architecture Overview\n *\n * The synchronizer uses a **pull-based discovery model** with two main message flows:\n *\n * 1. **Discovery Flow** (what documents exist):\n * - `directory-request/response` - Peers announce and discover documents\n * - Controlled by `permissions.visibility`\n *\n * 2. **Sync Flow** (transferring document data):\n * - `sync-request/response` - Peers explicitly request and receive document data\n * - Controlled by `permissions.mutability`\n *\n * ## Key Design Principles\n *\n * - **Separation of Concerns**: Discovery and sync are separate, explicit steps\n * - **Privacy by Design**: Permissions checked at every decision point\n * - **Symmetric Protocol**: Both peers use the same patterns (no client/server roles)\n * - **Pull-Based**: Peers announce documents, interested peers request them\n *\n * ## Message Flow Patterns\n *\n * ### Pattern 1: New Document Created\n * ```\n * 1. local-doc-change triggered\n * 2. Send directory-response (announcement) to channels where visibility=true\n * 3. Interested peers send sync-request\n * 4. Send sync-response with document data\n * ```\n *\n * ### Pattern 2: Existing Document Modified\n * ```\n * 1. local-doc-change triggered\n * 2. If peer has previously requested (peerWantsUpdates=true):\n * - Send sync-response directly (real-time update)\n * 3. Otherwise: Send directory-response announcement\n * ```\n *\n * ### Pattern 3: Peer Connection Established\n * ```\n * 1. establish-request/response handshake\n * 2. Both peers send directory-request\n * 3. Both peers send sync-request for their own documents\n * 4. Discovery and sync happen in parallel\n * ```\n *\n * @see docs/discovery-and-sync-architecture.md for detailed architecture documentation\n */\n\nimport { getLogger, type Logger } from \"@logtape/logtape\"\nimport type { VersionVector } from \"loro-crdt\"\nimport type { Patch } from \"mutative\"\nimport type {\n AddressedEstablishedEnvelope,\n AddressedEstablishmentEnvelope,\n Channel,\n ConnectedChannel,\n EphemeralStoreData,\n ReturnEnvelope,\n} from \"./channel.js\"\nimport type { Permissions } from \"./permissions.js\"\nimport { synchronizerDispatcher } from \"./synchronizer/synchronizer-dispatcher.js\"\nimport type {\n ChannelId,\n DocId,\n DocState,\n PeerID,\n PeerIdentityDetails,\n PeerState,\n} from \"./types.js\"\nimport { makeImmutableUpdate } from \"./utils/make-immutable-update.js\"\n\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n// STATE\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n/**\n * The synchronizer's state model\n *\n * This represents the complete state of the synchronization system at any point in time.\n * All state updates are immutable (via mutative library).\n */\nexport type SynchronizerModel = {\n /** Our own peer identity */\n identity: PeerIdentityDetails\n\n /** All documents we know about (local and synced from peers) */\n documents: Map<DocId, DocState>\n\n /** All active channels (storage adapters, network peers) */\n channels: Map<ChannelId, Channel>\n\n /**\n * Peer state tracking for reconnection optimization\n *\n * Tracks what each peer knows about our documents to enable:\n * - Optimized sync on reconnection (only send changed docs)\n * - Awareness-based message routing (announcements vs updates)\n */\n peers: Map<PeerID, PeerState>\n}\n\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n// MESSAGES (inputs to the update function)\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n/**\n * Messages that drive the synchronizer state machine\n *\n * These are the inputs to the update function. Each message triggers\n * a state transition and may produce commands as side effects.\n */\nexport type SynchronizerMessage =\n // A heartbeat signal given to us from Synchronizer runtime; used for ephemeral store\n | { type: \"synchronizer/heartbeat\" }\n | {\n type: \"synchronizer/ephemeral-local-change\"\n docId: DocId\n namespace: string\n }\n\n // Channel lifecycle messages\n | { type: \"synchronizer/channel-added\"; channel: ConnectedChannel }\n | { type: \"synchronizer/establish-channel\"; channelId: ChannelId }\n | { type: \"synchronizer/channel-removed\"; channel: Channel }\n\n // Document lifecycle messages\n | { type: \"synchronizer/doc-ensure\"; docId: DocId }\n | { type: \"synchronizer/local-doc-change\"; docId: DocId }\n | { type: \"synchronizer/doc-delete\"; docId: DocId }\n | {\n type: \"synchronizer/doc-imported\"\n docId: DocId\n fromPeerId: PeerID\n }\n\n // Channel message received (from network or storage)\n | { type: \"synchronizer/channel-receive-message\"; envelope: ReturnEnvelope }\n\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n// COMMANDS (outputs of the update function)\n// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n/**\n * Commands are side effects produced by the update function\n *\n * The synchronizer is pure - it doesn't perform side effects directly.\n * Instead, it returns commands that the runtime executes.\n */\nexport type Command =\n // Channel operations\n | { type: \"cmd/stop-channel\"; channel: Channel }\n | {\n type: \"cmd/send-establishment-message\"\n envelope: AddressedEstablishmentEnvelope\n }\n | { type: \"cmd/send-message\"; envelope: AddressedEstablishedEnvelope }\n | {\n type: \"cmd/send-sync-response\"\n docId: DocId\n requesterDocVersion: VersionVector\n toChannelId: ChannelId\n /** Whether to include ephemeral snapshot in the response */\n includeEphemeral?: boolean\n }\n | {\n type: \"cmd/send-sync-request\"\n toChannelId: ChannelId\n docs: {\n docId: DocId\n requesterDocVersion: VersionVector\n }[]\n bidirectional: boolean\n /** Whether to include ephemeral data for each doc in the request */\n includeEphemeral?: boolean\n }\n\n // Document operations\n | { type: \"cmd/subscribe-doc\"; docId: DocId }\n | {\n type: \"cmd/import-doc-data\"\n docId: DocId\n data: Uint8Array\n fromPeerId: PeerID\n }\n // Apply ephemeral data - new format with stores array\n | {\n type: \"cmd/apply-ephemeral\"\n docId: DocId\n stores: EphemeralStoreData[]\n }\n | {\n /** Broadcast a single namespace's ephemeral data for a document */\n type: \"cmd/broadcast-ephemeral-namespace\"\n docId: DocId\n namespace: string\n hopsRemaining: number\n toChannelIds: ChannelId[]\n }\n | {\n /**\n * Macro command: expands into multiple cmd/broadcast-ephemeral-namespace commands.\n * Used by heartbeat to broadcast all namespaces for multiple docs to a single peer.\n * Each sub-command queues messages; the deferred send layer aggregates them at flush time.\n */\n type: \"cmd/broadcast-ephemeral-batch\"\n docIds: DocId[]\n hopsRemaining: number\n toChannelId: ChannelId\n }\n | {\n type: \"cmd/remove-ephemeral-peer\"\n peerId: PeerID\n }\n\n // Events\n | {\n type: \"cmd/emit-ephemeral-change\"\n docId: DocId\n }\n\n // Utilities\n | { type: \"cmd/dispatch\"; dispatch: SynchronizerMessage }\n | { type: \"cmd/batch\"; commands: Command[] }\n\n/**\n * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n *\n * PROGRAM DEFINITION\n *\n * Inspired by \"The Elm Architecture\" (TEA) as a basis for a state machine.\n *\n * To understand the pattern that inspired the synchronizer-program, check out raj:\n *\n * - https://github.com/andrejewski/raj-by-example\n * - https://github.com/andrejewski/raj-ts/blob/main/src/runtime.ts\n *\n * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n */\n\n/**\n * Initialize the synchronizer with a peer identity\n *\n * @param identity - Our peer identity (name and stable peerId)\n * @returns Initial model state with no documents, channels, or peers\n */\nexport function init(\n identity: PeerIdentityDetails,\n): [SynchronizerModel, Command?] {\n return [\n {\n identity,\n documents: new Map(),\n channels: new Map(),\n peers: new Map(),\n },\n ]\n}\n\ntype CreateSynchronizerUpdateParams = {\n permissions: Permissions\n logger?: Logger\n onUpdate?: (patches: Patch[]) => void\n}\n\n/**\n * Creates the main synchronizer update function\n *\n * This is the public API for creating a synchronizer. It wraps the mutative\n * update logic with immutability guarantees via the mutative library.\n *\n * ## Usage\n *\n * ```typescript\n * const update = createSynchronizerUpdate({\n * permissions: {\n * visibility: (doc, peer) => peer.channelKind === \"storage\" || isOwner(doc, peer),\n * mutability: (doc, peer) => peer.channelKind === \"storage\" || hasWriteAccess(doc, peer),\n * },\n * logger: getLogger([\"my-app\", \"sync\"]),\n * onUpdate: (patches) => console.log(\"State changed:\", patches),\n * })\n * ```\n *\n * @param permissions - Permissions for visibility, mutability, creation, and deletion checks\n * @param logger - Optional logger (defaults to @loro-extended/repo logger)\n * @param onUpdate - Optional callback for debugging state changes\n * @returns Immutable update function compatible with TEA pattern\n */\nexport function createSynchronizerUpdate({\n permissions,\n logger,\n onUpdate,\n}: CreateSynchronizerUpdateParams) {\n return makeImmutableUpdate(\n createSynchronizerLogic(\n permissions,\n logger ?? getLogger([\"@loro-extended\", \"repo\"]),\n ),\n onUpdate,\n )\n}\n\n/**\n * Creates the core synchronizer update logic with permissions captured in closure\n *\n * This function creates a mutative update function that's easier to write and reason about.\n * The mutative library automatically converts it to an immutable update function.\n *\n * ## Message Routing\n *\n * The synchronizer handles two categories of messages:\n *\n * 1. **Synchronizer Messages** (synchronizer/*):\n * - Channel lifecycle (added, removed, establish)\n * - Document lifecycle (ensure, change, delete)\n * - Handled directly in this switch statement\n *\n * 2. **Channel Messages** (channel/*):\n * - Protocol messages from peers (establish, sync, directory)\n * - Routed to mutatingChannelUpdate for dispatch\n *\n * @param permissions - Permissions for visibility, mutability, creation, and deletion checks\n * @param synchronizerLogger - Logger for tracing message flow\n * @returns Mutative update function (converted to immutable by makeImmutableUpdate)\n */\nfunction createSynchronizerLogic(\n permissions: Permissions,\n synchronizerLogger: Logger,\n) {\n const logger = synchronizerLogger.getChild(\"program\")\n\n // A mutating update function is easier to read and write, because we need only concern ourselves\n // with what needs to change, using standard assignment and JS operations. But the machinery\n // around this function turns it back into an immutable `update` function like TEA expects.\n return function mutatingUpdate(\n msg: SynchronizerMessage,\n model: SynchronizerModel,\n ): Command | undefined {\n // Log all messages except channel-receive-message (too noisy)\n if (msg.type !== \"synchronizer/channel-receive-message\") {\n const detail = \"data\" in msg ? { ...msg, data: \"[omitted]\" } : msg\n logger.trace(\"{type}\", detail)\n }\n\n return synchronizerDispatcher(msg, model, permissions, logger)\n }\n}\n","import type { VersionVector } from \"loro-crdt\"\nimport type { ConnectedChannel } from \"../channel.js\"\nimport type { SynchronizerModel } from \"../synchronizer-program.js\"\nimport type {\n ChannelId,\n DocId,\n DocState,\n PeerDocSyncState,\n PeerID,\n PeerIdentityDetails,\n PeerState,\n} from \"../types.js\"\n\n/**\n * Get or create peer state (replaces temporary peerId generation)\n */\nexport function ensurePeerState(\n model: SynchronizerModel,\n identity: PeerIdentityDetails,\n channelId: ChannelId,\n): PeerState {\n const peerId = identity.peerId\n let peerState = model.peers.get(peerId)\n\n if (!peerState) {\n peerState = {\n identity,\n docSyncStates: new Map(),\n subscriptions: new Set(),\n channels: new Set(),\n }\n model.peers.set(peerId, peerState)\n }\n\n // Track this channel for the peer\n peerState.channels.add(channelId)\n\n return peerState\n}\n\n/**\n * Add a document to peer's subscriptions\n */\nexport function addPeerSubscription(peerState: PeerState, docId: DocId): void {\n peerState.subscriptions.add(docId)\n}\n\n/**\n * Remove a document from peer's subscriptions\n */\nexport function removePeerSubscription(\n peerState: PeerState,\n docId: DocId,\n): void {\n peerState.subscriptions.delete(docId)\n}\n\n/**\n * Check if peer has subscribed to a document\n */\nexport function hasPeerSubscription(\n peerState: PeerState,\n docId: DocId,\n): boolean {\n return peerState.subscriptions.has(docId)\n}\n\n/**\n * Update peer's document awareness\n */\nexport function setPeerDocumentAwareness(\n peerState: PeerState,\n docId: DocId,\n awareness: \"unknown\" | \"absent\" | \"pending\",\n): void\nexport function setPeerDocumentAwareness(\n peerState: PeerState,\n docId: DocId,\n awareness: \"synced\",\n version: VersionVector,\n): void\nexport function setPeerDocumentAwareness(\n peerState: PeerState,\n docId: DocId,\n awareness: \"unknown\" | \"synced\" | \"absent\" | \"pending\",\n version?: VersionVector,\n): void {\n const lastUpdated = new Date()\n if (awareness === \"synced\") {\n if (!version) {\n throw new Error(\"version is required when awareness is 'has-doc'\")\n }\n peerState.docSyncStates.set(docId, {\n status: awareness,\n lastKnownVersion: version,\n lastUpdated,\n })\n } else {\n peerState.docSyncStates.set(docId, {\n status: awareness,\n lastUpdated,\n })\n }\n}\n\n/**\n * Get all channels connected to a peer\n *\n * This utility function returns all active channels for a given peer.\n * A peer may have multiple channels (e.g., reconnection scenarios, multiple\n * network transports).\n *\n * ## Use Cases\n *\n * - Sending messages to all channels of a specific peer\n * - Checking if a peer is currently connected\n * - Debugging connection state\n *\n * ## Example\n *\n * ```typescript\n * const channels = getChannelsForPeer(model, peerId)\n * if (channels.length > 0) {\n * // Peer is connected via at least one channel\n * }\n * ```\n *\n * @param model - The synchronizer model\n * @param peerId - The peer ID to look up\n * @returns Array of connected channels for this peer (empty if peer not found)\n */\nexport function getChannelsForPeer(\n model: SynchronizerModel,\n peerId: PeerID,\n): ConnectedChannel[] {\n const peerState = model.peers.get(peerId)\n if (!peerState) return []\n\n return Array.from(peerState.channels)\n .map(channelId => model.channels.get(channelId))\n .filter((ch): ch is ConnectedChannel => ch !== undefined)\n}\n\n/**\n * Get all peers that have a document\n *\n * This utility function returns all peers that have explicitly indicated they\n * have a copy of the specified document (awareness === \"synced\" or \"pending\").\n *\n * ## Use Cases\n *\n * - Finding which peers to request a document from\n * - Checking document availability across the network\n * - Implementing custom replication strategies\n * - Debugging document distribution\n *\n * ## Example\n *\n * ```typescript\n * const peers = getPeersWithDocument(model, \"my-doc\")\n * console.log(`Document available from ${peers.length} peers`)\n * ```\n *\n * @param model - The synchronizer model\n * @param docId - The document ID to look up\n * @returns Array of peer states that have this document\n */\nexport function getPeersWithDocument(\n model: SynchronizerModel,\n docId: DocId,\n): PeerState[] {\n return Array.from(model.peers.values()).filter(peer => {\n const awareness = peer.docSyncStates.get(docId)\n return awareness?.status === \"synced\" || awareness?.status === \"pending\"\n })\n}\n\n/**\n * Check if we should sync with peer (based on version vectors)\n */\nexport function shouldSyncWithPeer(\n docState: DocState,\n peerAwareness: PeerDocSyncState | undefined,\n): boolean {\n if (!peerAwareness) return true // Unknown, should sync\n if (peerAwareness.status === \"unknown\") return true // Unknown, should sync\n if (peerAwareness.status === \"absent\") return false // They don't have it\n if (peerAwareness.status === \"pending\") return true // They have it but we don't know their version, should sync\n\n // TypeScript now knows peerAwareness.awareness === \"synced\"\n // so lastKnownVersion is guaranteed to exist\n const ourVersion = docState.doc.version()\n const theirVersion = peerAwareness.lastKnownVersion\n\n const comparison = ourVersion.compare(theirVersion)\n\n // We should sync if we are ahead (1) OR if versions are concurrent (undefined)\n // Concurrent means we have changes they don't have, and they have changes we don't have\n return comparison === 1 || comparison === undefined\n}\n","import type { EstablishedChannel } from \"../channel.js\"\nimport { isEstablished } from \"../channel.js\"\nimport type { DocContext, PeerContext } from \"../permissions.js\"\nimport type { SynchronizerModel } from \"../synchronizer-program.js\"\nimport type { DocState } from \"../types.js\"\n\n/**\n * Result of getting permission context.\n * Contains both DocContext and PeerContext for permission checks.\n */\nexport type PermissionContext = {\n doc: DocContext\n peer: PeerContext\n}\n\n/**\n * Get permission context for permission checks.\n *\n * @returns PermissionContext if successful, Error if context cannot be built\n */\nexport function getPermissionContext({\n channel,\n docState,\n model,\n}: {\n channel: EstablishedChannel | undefined\n docState: DocState | undefined\n model?: SynchronizerModel\n}): PermissionContext | Error {\n if (!channel || !isEstablished(channel)) {\n return new Error(\"can't get permission context for non-established channel\")\n }\n\n if (!docState) {\n return new Error(\"can't get permission context for undefined docState\")\n }\n\n // Get peer state from model if available\n const peerState = model?.peers.get(channel.peerId)\n if (!peerState) {\n return new Error(`can't get peer state for peerId ${channel.peerId}`)\n }\n\n return {\n doc: {\n id: docState.docId,\n doc: docState.doc,\n },\n peer: {\n peerId: peerState.identity.peerId,\n peerName: peerState.identity.name,\n peerType: peerState.identity.type,\n channelId: channel.channelId,\n channelKind: channel.kind,\n },\n }\n}\n\n/**\n * Get peer context only (for creation checks where doc doesn't exist yet).\n *\n * @returns PeerContext if successful, Error if context cannot be built\n */\nexport function getPeerContext({\n channel,\n model,\n}: {\n channel: EstablishedChannel | undefined\n model?: SynchronizerModel\n}): PeerContext | Error {\n if (!channel || !isEstablished(channel)) {\n return new Error(\"can't get peer context for non-established channel\")\n }\n\n // Get peer state from model if available\n const peerState = model?.peers.get(channel.peerId)\n if (!peerState) {\n return new Error(`can't get peer state for peerId ${channel.peerId}`)\n }\n\n return {\n peerId: peerState.identity.peerId,\n peerName: peerState.identity.name,\n peerType: peerState.identity.type,\n channelId: channel.channelId,\n channelKind: channel.kind,\n }\n}\n","import type { VersionVector } from \"loro-crdt\"\nimport type { EstablishedChannel } from \"../channel.js\"\nimport type { Permissions } from \"../permissions.js\"\nimport type { Command, SynchronizerModel } from \"../synchronizer-program.js\"\nimport type { DocId, DocState, PeerState } from \"../types.js\"\n\n/**\n * Type for docs array used by cmd/send-sync-request\n */\nexport type SyncRequestDoc = {\n docId: DocId\n requesterDocVersion: VersionVector\n}\n\nimport { shouldSyncWithPeer } from \"./peer-state-helpers.js\"\nimport { getPermissionContext } from \"./permission-context.js\"\n\n/**\n * Batch multiple commands into a single command if needed\n */\nexport function batchAsNeeded(\n ...commandSequence: (Command | undefined)[]\n): Command | undefined {\n const definedCommands: Command[] = commandSequence.flatMap(c =>\n c ? [c] : [],\n )\n\n if (definedCommands.length === 0) {\n return\n }\n\n if (definedCommands.length === 1) {\n return definedCommands[0]\n }\n\n return { type: \"cmd/batch\", commands: definedCommands }\n}\n\nexport function filterAllowedDocs(\n documents: Map<string, DocState>,\n channel: EstablishedChannel,\n model: SynchronizerModel,\n permissions: Permissions,\n): Map<string, DocState> {\n const allowedDocs = new Map<string, DocState>()\n const peerState = model.peers.get(channel.peerId)\n\n for (const [docId, docState] of documents) {\n // Check if peer already has the document\n const peerAwareness = peerState?.docSyncStates.get(docId)\n const peerHasDoc = peerAwareness?.status === \"synced\"\n\n if (peerHasDoc) {\n // Peer already knows about it, so we allow it regardless of visibility\n // (visibility bypass for subscribed peers)\n allowedDocs.set(docId, docState)\n continue\n }\n\n const context = getPermissionContext({ channel, docState, model })\n if (context instanceof Error) continue\n if (permissions.visibility(context.doc, context.peer)) {\n allowedDocs.set(docId, docState)\n }\n }\n return allowedDocs\n}\n\nexport function getAllDocsToSync(documents: Map<string, DocState>) {\n return Array.from(documents.values()).map(({ doc, docId }) => {\n const requesterDocVersion = doc.version()\n return { docId, requesterDocVersion }\n })\n}\n\nexport function getChangedDocsToSync(\n peerState: PeerState,\n documents: Map<string, DocState>,\n): SyncRequestDoc[] {\n const docsToSync: SyncRequestDoc[] = []\n\n for (const [docId, docState] of documents.entries()) {\n const peerAwareness = peerState.docSyncStates.get(docId)\n\n if (!peerAwareness) {\n // We have a new document created since last connection that\n // peer doesn't know about yet\n docsToSync.push({\n docId,\n requesterDocVersion: docState.doc.version(),\n })\n } else if (peerAwareness.status === \"synced\") {\n // Peer had this document - check if our version is ahead\n if (shouldSyncWithPeer(docState, peerAwareness)) {\n docsToSync.push({\n docId,\n requesterDocVersion:\n peerAwareness.lastKnownVersion ?? docState.doc.version(),\n })\n }\n } else {\n // Skip if peerAwareness.awareness === \"absent\" (they don't have it)\n }\n }\n\n return docsToSync\n}\n","/**\n * Handle establish-request - Server side of connection handshake\n *\n * This is the first message in the connection protocol. When a peer wants to connect,\n * they send an establish-request with their identity. We respond with our identity\n * to complete the handshake.\n *\n * ## Protocol Flow\n *\n * ```\n * Peer A Peer B (us)\n * | |\n * |-- establish-request ---->| (this handler)\n * | | 1. Establish channel\n * | | 2. Create/update peer state\n * |<-- establish-response ---| 3. Send our identity\n * | |\n * ```\n *\n * ## Important Design Decision\n *\n * We **only** send establish-response here, NOT sync-request or directory-request.\n * This keeps the handshake clean and symmetric:\n * - The requester (client) will send directory-request after receiving our response\n * - Both sides then discover and sync documents in parallel\n *\n * This prevents the \"dual sync-response\" problem where both sides try to sync\n * simultaneously during establishment.\n *\n * @see docs/discovery-and-sync-architecture.md - Pattern 3: Peer Connection Established\n * @see handle-establish-response.ts - Client side of handshake\n */\n\nimport type {\n ChannelMsgEstablishRequest,\n ChannelMsgSyncRequest,\n EstablishedChannel,\n} from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { ensurePeerState } from \"../peer-state-helpers.js\"\nimport type { ChannelHandlerContext } from \"../types.js\"\nimport { batchAsNeeded, filterAllowedDocs, getAllDocsToSync } from \"../utils.js\"\n\nexport function handleEstablishRequest(\n message: ChannelMsgEstablishRequest,\n { channel, model, fromChannelId, permissions }: ChannelHandlerContext,\n): Command | undefined {\n const commands: Command[] = []\n\n // 1. Extract stable peerId from identity and establish the peer connection\n const peerId = message.identity.peerId\n const establishedChannel: EstablishedChannel = {\n ...channel,\n type: \"established\",\n peerId,\n }\n Object.assign(channel, establishedChannel)\n\n // 2. Get or create peer state for reconnection optimization\n ensurePeerState(model, message.identity, channel.channelId)\n\n // 3. Send establish-response back to the requester\n commands.push({\n type: \"cmd/send-establishment-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: {\n type: \"channel/establish-response\",\n // Copy the identity object here to avoid needing mutative's slower `current()` function\n // (Normally objects can't outlive a mutative change, and current gets around that)\n identity: {\n type: model.identity.type,\n name: model.identity.name,\n peerId: model.identity.peerId,\n },\n },\n },\n })\n\n // 4. Send sync-request for all allowed documents\n // This ensures the client discovers our documents even without directory-request\n const allowedDocs = filterAllowedDocs(\n model.documents,\n establishedChannel,\n model,\n permissions,\n )\n const docsToSync = getAllDocsToSync(allowedDocs)\n\n if (docsToSync.length === 1) {\n // Single document - send single sync-request\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: {\n type: \"channel/sync-request\",\n docId: docsToSync[0].docId,\n requesterDocVersion: docsToSync[0].requesterDocVersion,\n bidirectional: true,\n },\n },\n })\n } else if (docsToSync.length > 1) {\n // Multiple documents - batch sync-requests\n const syncRequests: ChannelMsgSyncRequest[] = docsToSync.map(doc => ({\n type: \"channel/sync-request\",\n docId: doc.docId,\n requesterDocVersion: doc.requesterDocVersion,\n bidirectional: true,\n }))\n\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: {\n type: \"channel/batch\",\n messages: syncRequests,\n },\n },\n })\n }\n\n return batchAsNeeded(...commands)\n}\n","/**\n * Handle establish-response - Complete connection handshake (client side)\n *\n * This is the response to our establish-request. The peer has accepted our connection\n * and sent us their identity. Now we can start syncing documents.\n *\n * ## Two Connection Paths\n *\n * ### 1. New Peer (First Connection)\n * - No cached peer state exists\n * - Send sync-request for all our documents\n * - Send ephemeral (presence) data\n *\n * ### 2. Reconnection (Known Peer)\n * - Cached peer state exists with document awareness\n * - Send optimized sync-request only for:\n * - New documents created since last connection\n * - Documents that changed since last connection (version comparison)\n * - Also send ephemeral (presence) data\n *\n * ## Protocol Flow (New Peer)\n *\n * ```\n * Us Peer\n * | |\n * |-- establish-request ----->|\n * | |\n * |<-- establish-response ----| (this handler)\n * | [peer identity] | 1. Mark channel as established\n * | | 2. Create/update peer state\n * | | 3. Send sync-request (all docs)\n * | | 4. Send our presence data (all docs)\n * |-- sync-request ---------->|\n * ```\n *\n * ## Protocol Flow (Reconnection)\n *\n * ```\n * Us Peer\n * | |\n * |-- establish-request ----->|\n * | |\n * |<-- establish-response ----| (this handler)\n * | [peer identity] | 1. Mark channel as established\n * | | 2. Update peer state (lastSeen)\n * | | 3. Send optimized sync-request\n * |-- sync-request ---------->| 4. Send our presence data (a docs)\n * | [only new/changed docs] |\n * ```\n *\n * @see docs/discovery-and-sync-architecture.md - Connection Establishment\n * @see handle-establish-request.ts - Server side of handshake\n */\n\nimport type {\n ChannelMsgEstablishResponse,\n EstablishedChannel,\n} from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { ensurePeerState } from \"../peer-state-helpers.js\"\nimport type { ChannelHandlerContext } from \"../types.js\"\nimport {\n batchAsNeeded,\n filterAllowedDocs,\n getAllDocsToSync,\n getChangedDocsToSync,\n type SyncRequestDoc,\n} from \"../utils.js\"\n\nexport function handleEstablishResponse(\n message: ChannelMsgEstablishResponse,\n { channel, model, logger, permissions }: ChannelHandlerContext,\n): Command | undefined {\n const commands: Command[] = []\n\n // This handler's main job!\n // Mark the channel as established, and remember the peer identity\n const peerId = message.identity.peerId\n const establishedChannel: EstablishedChannel = {\n ...channel,\n type: \"established\",\n peerId,\n }\n Object.assign(channel, establishedChannel)\n\n // Check if this is a reconnection to a known peer\n const isReconnection = model.peers.has(peerId)\n\n // Get or create our representation of the remote peer's state\n const peerState = ensurePeerState(model, message.identity, channel.channelId)\n\n // Note: We don't set visibility or subscriptions during establishment\n // - visibility will be checked on-the-fly when needed\n // - Subscriptions will be set when peer sends sync-request\n\n let docsToSync: SyncRequestDoc[] = []\n\n // Filter documents based on visibility permission\n const allowedDocs = filterAllowedDocs(\n model.documents,\n establishedChannel,\n model,\n permissions,\n )\n\n if (!isReconnection) {\n // ============================================================\n // NEW PEER PATH - Full discovery\n // ============================================================\n\n // Build full sync request--ask for all documents we have\n docsToSync = getAllDocsToSync(allowedDocs)\n\n logger.debug(\n \"establish-response (new peer): sending full sync-request to {peerId} for {docCount} docs ({docIds})\",\n () => ({\n peerId,\n docCount: docsToSync.length,\n docIds: docsToSync.map(d => d.docId),\n }),\n )\n } else {\n // ============================================================\n // RECONNECTION PATH - Optimized discovery using cached awareness\n // ============================================================\n\n // Build optimized sync request based on cached knowledge\n docsToSync = getChangedDocsToSync(peerState, allowedDocs)\n\n if (docsToSync.length > 0) {\n logger.debug(\n \"establish-response (known peer): sending optimized sync-request to {peerId} for {docCount} docs ({docIds})\",\n () => ({\n peerId,\n docCount: docsToSync.length,\n docIds: docsToSync.map(d => d.docId),\n }),\n )\n } else {\n logger.debug(\n \"establish-response (known peer): no sync needed for reconnection\",\n {\n channelId: channel.channelId,\n },\n )\n }\n }\n\n // Request our docs from peer, and suggest a reciprocal sync-request\n // for bidirectional syncing\n // Use cmd/send-sync-request to include ephemeral data with the request\n if (docsToSync.length > 0) {\n commands.push({\n type: \"cmd/send-sync-request\",\n toChannelId: channel.channelId,\n docs: docsToSync,\n bidirectional: true,\n includeEphemeral: true,\n })\n }\n\n return batchAsNeeded(...commands)\n}\n","import type { ChannelMsgDirectoryRequest } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { getPermissionContext } from \"../permission-context.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\n\nexport function handleDirectoryRequest(\n _message: ChannelMsgDirectoryRequest,\n {\n channel,\n model,\n fromChannelId,\n permissions,\n logger,\n }: EstablishedHandlerContext,\n): Command | undefined {\n // Filter documents based on visibility permission\n // We use a Result type to track both successes and errors\n type Result =\n | { success: true; docId: string }\n | { success: false; error: Error }\n\n const docResults: Result[] = Array.from(\n model.documents.keys(),\n ).flatMap<Result>(docId => {\n // Get permission context for permission checking\n const context = getPermissionContext({\n channel,\n docState: model.documents.get(docId),\n model,\n })\n\n // If we can't get context (e.g., missing peer state), log error\n if (context instanceof Error) {\n logger.warn(`directory-request error: ${context.message}`)\n return []\n }\n\n // Check visibility permission - can we tell this peer about this document?\n if (permissions.visibility(context.doc, context.peer)) {\n return [{ success: true, docId }]\n } else {\n // Permission denied - don't reveal this document\n return []\n }\n })\n\n // Separate successful docIds from errors\n const allowedDocIds = docResults.flatMap(result =>\n result.success ? [result.docId] : [],\n )\n\n // Send directory-response with filtered list\n const sendMessageCmd: Command = {\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: {\n type: \"channel/directory-response\",\n docIds: allowedDocIds,\n },\n },\n }\n\n return batchAsNeeded(sendMessageCmd)\n}\n","import {\n type Container,\n LoroDoc,\n type PeerID,\n type VersionVector,\n} from \"loro-crdt\"\nimport type { ChannelMeta } from \"./channel.js\"\n\nexport type { PeerID } from \"loro-crdt\"\n\nexport type DocId = string\nexport type ChannelId = number\nexport type AdapterType = string\nexport type DocContent = Record<string, Container>\n\nexport type LoroDocMutator<T extends DocContent> = (doc: LoroDoc<T>) => void\n\nexport type PeerIdentityDetails = {\n peerId: PeerID // Globally unique, stable identifier (not generated per-connection)\n name?: string // Optional - peer can give itself a name; this is not unique\n type: \"user\" | \"bot\" | \"service\"\n // publicKey?: Uint8Array // Future: For cryptographic identity\n}\n\nexport type ReadyStateChannelMeta = ChannelMeta & {\n state: \"established\" | \"connected\"\n}\n\nexport type ReadyState = {\n docId: DocId\n identity: PeerIdentityDetails\n channels: ReadyStateChannelMeta[]\n status: \"pending\" | \"synced\" | \"absent\"\n}\n\n/**\n * Discriminated union for peer document awareness.\n * - \"unknown\": We don't know if the peer has this document\n * - \"absent\": Peer explicitly doesn't have this document\n * - \"pending\": Peer has this document but we don't know their version yet\n * (e.g., they announced via new-doc but we haven't synced yet)\n * - \"synced\": Peer has this document with a known version\n */\nexport type PeerDocSyncState =\n | { status: \"unknown\"; lastUpdated: Date }\n | { status: \"absent\"; lastUpdated: Date }\n | { status: \"pending\"; lastUpdated: Date }\n | { status: \"synced\"; lastKnownVersion: VersionVector; lastUpdated: Date }\n\nexport type PeerState = {\n identity: PeerIdentityDetails\n docSyncStates: Map<DocId, PeerDocSyncState>\n subscriptions: Set<DocId>\n channels: Set<ChannelId>\n}\n\n/**\n * Pending network request waiting for storage to be consulted.\n */\nexport type PendingNetworkRequest = {\n channelId: ChannelId\n requesterDocVersion: VersionVector\n}\n\nexport type DocState = {\n doc: LoroDoc\n docId: DocId\n\n /**\n * Storage channels we're waiting to hear from before responding to network requests.\n * When this set becomes empty, we process pendingNetworkRequests.\n *\n * - undefined or empty: No pending storage check\n * - non-empty: Waiting for these storage channels to respond\n */\n pendingStorageChannels?: Set<ChannelId>\n\n /**\n * Network sync-requests waiting for storage to be consulted.\n * When all storage channels have responded (pendingStorageChannels is empty),\n * we send sync-responses to all of these.\n */\n pendingNetworkRequests?: PendingNetworkRequest[]\n}\n\n/**\n * Creates a new DocState with a LoroDoc configured with the given peerId.\n *\n * The peerId is required to ensure proper UndoManager behavior and change attribution.\n * Each LoroDoc must have its peerId set to match the Repo's identity.peerId so that:\n * 1. UndoManager correctly identifies which changes belong to the local peer\n * 2. Changes are properly attributed in the oplog\n * 3. External tools that rely on PeerID matching work correctly\n *\n * @param docId - The document ID\n * @param peerId - The peer ID to set on the LoroDoc (must be a valid numeric string)\n */\nexport function createDocState({\n docId,\n peerId,\n}: {\n docId: DocId\n peerId: PeerID\n}): DocState {\n const doc = new LoroDoc()\n doc.setPeerId(peerId)\n return {\n doc,\n docId,\n // pendingStorageChannels and pendingNetworkRequests are undefined by default\n // They're only set when a network request arrives for an unknown doc with storage adapters\n }\n}\n","/**\n * Handle directory-response - Discover documents from a peer\n *\n * This is the response to our directory-request, or an unsolicited announcement\n * of new documents. The peer is telling us what documents they have (filtered\n * by their `visibility` permissions).\n *\n * ## Pull-Based Discovery Model\n *\n * This handler implements the \"pull\" side of the pull-based discovery:\n * 1. Peer announces documents (via directory-response)\n * 2. We decide whether we want them\n * 3. We send sync-request for documents we want\n * 4. Peer sends sync-response with the data\n *\n * ## Behavior\n *\n * For each announced document:\n * 1. Create local document state if it doesn't exist\n * 2. Update peer awareness (peer has this document)\n * 3. Add to sync-request (we want the data)\n *\n * Note: This implementation is \"eager\" - we request all announced documents.\n * A selective sync implementation could filter here based on user preferences.\n *\n * ## Protocol Flow\n *\n * ```\n * Peer Us\n * | |\n * |-- directory-response ---->| (this handler)\n * | [docId1, docId2] | 1. Create doc states\n * | | 2. Update peer awareness\n * |<-- sync-request -----------| 3. Request document data\n * | [docId1, docId2] |\n * |-- sync-response ---------->| 4. Receive data\n * ```\n *\n * ## Storage Adapter Behavior\n *\n * Storage adapters use this same flow:\n * - Receive directory-response announcement\n * - Immediately request all announced documents (eager)\n * - Persist the data when sync-response arrives\n *\n * ## Selective Sync Example\n *\n * To implement selective sync (e.g., mobile client):\n * ```typescript\n * // Instead of requesting all documents:\n * if (shouldSyncDocument(docId, userPreferences)) {\n * docsToSync.push({ docId, requesterDocVersion })\n * }\n * ```\n *\n * @see docs/discovery-and-sync-architecture.md - Pattern 1: Client Refresh\n * @see docs/discovery-and-sync-architecture.md - Scenario: Selective Sync\n * @see handle-directory-request.ts - How peers filter announcements\n */\n\nimport type {\n ChannelMsgDirectoryResponse,\n ChannelMsgSyncRequest,\n} from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { createDocState } from \"../../types.js\"\nimport { setPeerDocumentAwareness } from \"../peer-state-helpers.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\n\nexport function handleDirectoryResponse(\n message: ChannelMsgDirectoryResponse,\n {\n channel,\n peerState,\n model,\n fromChannelId,\n logger,\n }: EstablishedHandlerContext,\n): Command | undefined {\n const commands: (Command | undefined)[] = []\n const syncRequests: ChannelMsgSyncRequest[] = []\n\n // Process each announced document\n for (const docId of message.docIds) {\n let docState = model.documents.get(docId)\n\n // Create document state if we don't have it yet\n if (!docState) {\n docState = createDocState({ docId, peerId: model.identity.peerId })\n model.documents.set(docId, docState)\n commands.push({ type: \"cmd/subscribe-doc\", docId })\n }\n\n // Update peer awareness - peer has revealed they have this document\n // Note: Subscription NOT set yet - they haven't requested from us\n // That will be set when they send sync-request\n // We don't know their actual version yet - we'll learn it when we sync\n setPeerDocumentAwareness(peerState, docId, \"pending\")\n\n // Since peer has the doc, send our ephemeral state\n commands.push({\n type: \"cmd/broadcast-ephemeral-batch\",\n docIds: [docId],\n hopsRemaining: 0,\n toChannelId: fromChannelId,\n })\n\n logger.debug(\"directory-response: updated peer awareness\", {\n peerId: channel.peerId,\n docId,\n awareness: \"pending\",\n })\n\n // Add sync-request to actually load the document data\n // This is the \"pull\" in pull-based discovery - we explicitly request\n syncRequests.push({\n type: \"channel/sync-request\",\n docId,\n requesterDocVersion: docState.doc.version(), // Empty for new docs\n bidirectional: true,\n })\n }\n\n // Send sync-requests to load the actual document data\n // This completes the discovery → request → transfer flow\n // Use channel/batch if multiple documents, single message otherwise\n if (syncRequests.length === 1) {\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: syncRequests[0],\n },\n })\n } else if (syncRequests.length > 1) {\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: {\n type: \"channel/batch\",\n messages: syncRequests,\n },\n },\n })\n }\n\n return batchAsNeeded(...commands)\n}\n","/**\n * Handle new-doc - Discover documents announced by a peer\n *\n * This is an unsolicited announcement from a peer that they have new documents.\n * The peer is telling us what documents they have (filtered by their `visibility` permissions).\n *\n * ## Pull-Based Discovery Model\n *\n * This handler implements the \"pull\" side of the pull-based discovery:\n * 1. Peer announces documents (via new-doc)\n * 2. We decide whether we want them\n * 3. We send sync-request for documents we want\n * 4. Peer sends sync-response with the data\n *\n * ## Behavior\n *\n * For each announced document:\n * 1. Create local document state if it doesn't exist\n * 2. Update peer awareness (peer has this document)\n * 3. Add to sync-request (we want the data)\n *\n * Note: This implementation is \"eager\" - we request all announced documents.\n * A selective sync implementation could filter here based on user preferences.\n *\n * ## Protocol Flow\n *\n * ```\n * Peer Us\n * | |\n * |-- new-doc --------------->| (this handler)\n * | [docId1, docId2] | 1. Create doc states\n * | | 2. Update peer awareness\n * |<-- sync-request -----------| 3. Request document data\n * | [docId1, docId2] |\n * |-- sync-response ---------->| 4. Receive data\n * ```\n *\n * ## Storage Adapter Behavior\n *\n * Storage adapters use this same flow:\n * - Receive new-doc announcement\n * - Immediately request all announced documents (eager)\n * - Persist the data when sync-response arrives\n *\n * ## Selective Sync Example\n *\n * To implement selective sync (e.g., mobile client):\n * ```typescript\n * // Instead of requesting all documents:\n * if (shouldSyncDocument(docId, userPreferences)) {\n * docsToSync.push({ docId, requesterDocVersion })\n * }\n * ```\n *\n * @see handle-directory-response.ts - Similar handler for directory-request/response flow\n */\n\nimport type {\n BatchableMsg,\n ChannelMsgNewDoc,\n ChannelMsgSyncRequest,\n} from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { createDocState } from \"../../types.js\"\nimport { setPeerDocumentAwareness } from \"../peer-state-helpers.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\n\nexport function handleNewDoc(\n message: ChannelMsgNewDoc,\n {\n channel,\n peerState,\n model,\n fromChannelId,\n logger,\n }: EstablishedHandlerContext,\n): Command | undefined {\n const commands: (Command | undefined)[] = []\n const syncRequests: ChannelMsgSyncRequest[] = []\n\n // Process each announced document\n for (const docId of message.docIds) {\n let docState = model.documents.get(docId)\n\n // Create document state if we don't have it yet\n if (!docState) {\n docState = createDocState({ docId, peerId: model.identity.peerId })\n model.documents.set(docId, docState)\n commands.push({ type: \"cmd/subscribe-doc\", docId })\n }\n\n // Update peer awareness - peer has revealed they have this document\n // Note: Subscription NOT set yet - they haven't requested from us\n // That will be set when they send sync-request\n // We don't know their actual version yet - we'll learn it when we sync\n setPeerDocumentAwareness(peerState, docId, \"pending\")\n\n // Since peer has the doc, send our ephemeral state\n commands.push({\n type: \"cmd/broadcast-ephemeral-batch\",\n docIds: [docId],\n hopsRemaining: 0,\n toChannelId: fromChannelId,\n })\n\n logger.debug(\"new-doc: updated peer awareness\", {\n peerId: channel.peerId,\n docId,\n awareness: \"pending\",\n })\n\n // Add sync-request to actually load the document data\n // This is the \"pull\" in pull-based discovery - we explicitly request\n syncRequests.push({\n type: \"channel/sync-request\",\n docId,\n requesterDocVersion: docState.doc.version(), // Empty for new docs\n bidirectional: true,\n })\n }\n\n // Send sync-requests to load the actual document data\n // This completes the discovery → request → transfer flow\n // Use channel/batch if multiple documents, single message otherwise\n if (syncRequests.length === 1) {\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: syncRequests[0],\n },\n })\n } else if (syncRequests.length > 1) {\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: {\n type: \"channel/batch\",\n messages: syncRequests as BatchableMsg[],\n },\n },\n })\n }\n\n return batchAsNeeded(...commands)\n}\n","import type { ChannelMsgEphemeral } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { getEstablishedChannelsForDoc } from \"../../utils/get-established-channels-for-doc.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\n\nexport function handleEphemeral(\n message: ChannelMsgEphemeral,\n { model, fromChannelId }: EstablishedHandlerContext,\n): Command | undefined {\n const commands: Command[] = []\n\n // First, apply the ephemeral data locally\n // The new format uses stores array with per-peer data\n commands.push({\n type: \"cmd/apply-ephemeral\",\n docId: message.docId,\n stores: message.stores,\n })\n\n // If hops remaining, relay the SAME data to other peers (hub-and-spoke relay)\n // This is critical: we forward the original message data, not re-encode our own data\n if (message.hopsRemaining > 0) {\n // Get all established channels for this document, excluding the sender\n const allChannelIds = getEstablishedChannelsForDoc(\n model.channels,\n model.peers,\n message.docId,\n )\n\n // Filter out the channel that sent us this message to avoid echo\n const toChannelIds = allChannelIds.filter(id => id !== fromChannelId)\n\n if (toChannelIds.length > 0) {\n // Use cmd/send-message to forward the original data unchanged\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds,\n message: {\n type: \"channel/ephemeral\",\n docId: message.docId,\n hopsRemaining: message.hopsRemaining - 1,\n stores: message.stores, // Forward the original stores, not re-encoded\n },\n },\n })\n }\n }\n\n return batchAsNeeded(...commands)\n}\n","/**\n * Handle delete-request - Process a deletion request from a remote peer\n *\n * This is called when a remote peer sends a `channel/delete-request` message,\n * indicating they want us to delete a document.\n *\n * ## Permission Check\n *\n * Before deleting, we check the `deletion` permission. If the permission\n * returns `false`, we ignore the request and the document remains.\n *\n * ## What Gets Deleted\n *\n * If permitted, we delete:\n * - Document state (Loro document instance)\n * - All synchronization metadata\n *\n * ## Response\n *\n * We send a `channel/delete-response` back to the peer indicating:\n * - `deleted` - The document was deleted\n * - `ignored` - The request was denied (permission check failed)\n *\n * @see handle-doc-delete.ts - Local deletion (app-initiated)\n * @see permissions.ts - Deletion permission\n */\n\nimport type { ChannelMsgDeleteRequest } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { getPermissionContext } from \"../permission-context.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\n\nexport function handleDeleteRequest(\n message: ChannelMsgDeleteRequest,\n { channel, model, permissions, logger }: EstablishedHandlerContext,\n): Command | undefined {\n const { docId } = message\n\n const docState = model.documents.get(docId)\n\n // If document doesn't exist, nothing to delete\n if (!docState) {\n logger.debug(\"delete-request: document {docId} not found, ignoring\", {\n docId,\n })\n return {\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [channel.channelId],\n message: {\n type: \"channel/delete-response\",\n docId,\n status: \"ignored\",\n },\n },\n }\n }\n\n // Check deletion permission\n const context = getPermissionContext({ channel, docState, model })\n\n if (context instanceof Error) {\n logger.warn(\"delete-request: unable to get permission context: {error}\", {\n error: context.message,\n })\n return {\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [channel.channelId],\n message: {\n type: \"channel/delete-response\",\n docId,\n status: \"ignored\",\n },\n },\n }\n }\n\n if (!permissions.deletion(context.doc, context.peer)) {\n logger.info(\n \"delete-request: deletion denied for {docId} from peer {peerName}\",\n {\n docId,\n peerName: context.peer.peerName,\n },\n )\n return {\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [channel.channelId],\n message: {\n type: \"channel/delete-response\",\n docId,\n status: \"ignored\",\n },\n },\n }\n }\n\n // Permission granted - delete the document\n logger.info(\"delete-request: deleting {docId} as requested by {peerName}\", {\n docId,\n peerName: context.peer.peerName,\n })\n\n model.documents.delete(docId)\n\n return {\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [channel.channelId],\n message: {\n type: \"channel/delete-response\",\n docId,\n status: \"deleted\",\n },\n },\n }\n}\n","/**\n * Handle sync-request - Peer explicitly requests document data\n *\n * This is the \"pull\" in the pull-based sync model. The peer has discovered\n * a document (via directory-response) and now explicitly requests the data.\n *\n * ## Key Behaviors\n *\n * 1. **Send sync-response** with document data (snapshot or update)\n * 2. **Add to peer's subscriptions** - Peer has subscribed to this document\n * 3. **Update peer awareness** - Track that peer has this document\n *\n * ## Storage-First Sync (for network requests)\n *\n * When a network peer requests a document we don't have, we first check with\n * all storage adapters before responding. This prevents the race condition where\n * we respond \"unavailable\" before storage has loaded the document.\n *\n * Flow for network request when doc doesn't exist:\n * 1. Create doc with pendingStorageChannels set\n * 2. Queue the network request in pendingNetworkRequests\n * 3. Send sync-request to all storage adapters\n * 4. When all storage responds, process queued network requests\n *\n * ## Subscription Model\n *\n * When a peer sends sync-request, they're implicitly subscribing to future updates:\n * - We add the document to the peer's `subscriptions` set\n * - Future local changes will send sync-response directly (real-time updates)\n * - No need for announcements - peer already knows about the document\n *\n * ## Version Vector Semantics\n *\n * The `requesterDocVersion` tells us what the peer has:\n * - **Empty version**: Peer has nothing → send snapshot (full document)\n * - **Non-empty version**: Peer has this version → send update (delta)\n * - **Up-to-date**: Peer has latest → send \"up-to-date\" response\n *\n * ## Protocol Flow\n *\n * ```\n * Peer Us\n * | |\n * |-- sync-request ---------->| (this handler)\n * | [docId, version] | 1. Check if we have doc\n * | | 2. Add to peer's subscriptions\n * | | 3. Update peer awareness\n * |<-- sync-response ---------| 4. Send document data\n * | [data or up-to-date] |\n * | |\n * |<-- sync-response ---------|\n * | [data or up-to-date] |\n * | |\n * |<-- sync-response ---------|\n * | [data or up-to-date] |\n * ```\n *\n * ## Storage Adapter Behavior\n *\n * Storage adapters:\n * - Send sync-request for all announced documents (eager)\n * - Always have subscriptions after first request\n * - Receive all future updates automatically\n *\n * @see docs/discovery-and-sync-architecture.md - Sync Data Transfer\n * @see handle-sync-response.ts - How we handle responses from peers\n * @see handle-local-doc-change.ts - How we send updates to subscribed peers\n */\n\nimport { VersionVector } from \"loro-crdt\"\nimport type { ChannelMsgSyncRequest } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { createDocState } from \"../../types.js\"\nimport { getEstablishedChannelsForDoc } from \"../../utils/get-established-channels-for-doc.js\"\nimport { getStorageChannelIds } from \"../../utils/get-storage-channel-ids.js\"\nimport {\n addPeerSubscription,\n setPeerDocumentAwareness,\n} from \"../peer-state-helpers.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\n\nexport function handleSyncRequest(\n message: ChannelMsgSyncRequest,\n {\n channel,\n peerState,\n model,\n fromChannelId,\n logger,\n permissions,\n }: EstablishedHandlerContext,\n): Command | undefined {\n const {\n docId,\n requesterDocVersion,\n ephemeral,\n bidirectional = true,\n } = message\n const commands: (Command | undefined)[] = []\n\n // ALWAYS track subscription\n // The peer is explicitly telling us they want this document\n // This ensures that if we get the document later, we know to send it to them\n addPeerSubscription(peerState, docId)\n\n // Set awareness to \"pending\" (maps to \"aware\" state)\n // We know the peer is interested in this doc, but we don't know if they have data\n // to give us yet. The requesterDocVersion is what they HAVE, not what they're offering.\n // We'll upgrade to \"synced\" when we receive their sync-response.\n setPeerDocumentAwareness(peerState, docId, \"pending\")\n\n let docState = model.documents.get(docId)\n\n logger.debug(\n \"sync-request: updated peer {peerId} awareness ({awareness}) and subscription ({docId})\",\n {\n peerId: channel.peerId,\n docId,\n awareness: \"pending\",\n },\n )\n\n // If we don't have the document, create it!\n // This allows peers to initialize documents on the server just by requesting them\n if (!docState) {\n // Check if peer is allowed to create this document\n // Use creation permission with peer context\n const peerContext = {\n peerId: peerState.identity.peerId,\n peerName: peerState.identity.name,\n peerType: peerState.identity.type,\n channelId: channel.channelId,\n channelKind: channel.kind,\n }\n\n if (!permissions.creation(docId, peerContext)) {\n logger.warn(\n \"sync-request: peer {peerId} not allowed to create document {docId}, ignoring request\",\n {\n docId,\n peerId: channel.peerId,\n },\n )\n // Can't create the document, return early\n return\n }\n\n // Check if this is a network request and we have storage adapters\n // If so, we need to consult storage before responding\n const storageChannelIds = getStorageChannelIds(model.channels)\n const isNetworkRequest = channel.kind === \"network\"\n\n if (isNetworkRequest && storageChannelIds.length > 0) {\n // Storage-first sync: queue the network request and ask storage first\n logger.debug(\n \"sync-request: network request for unknown doc {docId}, consulting {count} storage adapter(s) first\",\n {\n docId,\n count: storageChannelIds.length,\n peerId: channel.peerId,\n },\n )\n\n // Create doc with pending storage state\n docState = createDocState({ docId, peerId: model.identity.peerId })\n docState.pendingStorageChannels = new Set(storageChannelIds)\n docState.pendingNetworkRequests = [\n { channelId: fromChannelId, requesterDocVersion },\n ]\n model.documents.set(docId, docState)\n\n // Subscribe to the doc for future updates\n commands.push({\n type: \"cmd/subscribe-doc\",\n docId,\n })\n\n // Ask all storage adapters if they have this document\n // Use empty version to get full snapshot if they have it\n for (const storageChannelId of storageChannelIds) {\n commands.push({\n type: \"cmd/send-sync-request\",\n toChannelId: storageChannelId,\n docs: [{ docId, requesterDocVersion: new VersionVector(null) }],\n bidirectional: false, // We don't need storage to request back\n })\n }\n\n // Don't respond to network yet - wait for storage\n return batchAsNeeded(...commands)\n }\n\n // No storage adapters or this is a storage request - create doc and respond immediately\n logger.debug(\n \"sync-request: creating new document ({docId}) from peer request\",\n {\n docId,\n peerId: channel.peerId,\n },\n )\n docState = createDocState({ docId, peerId: model.identity.peerId })\n model.documents.set(docId, docState)\n commands.push({\n type: \"cmd/subscribe-doc\",\n docId,\n })\n }\n\n // Check if this doc is waiting for storage and this is another network request\n // If so, queue this request too\n if (\n docState.pendingStorageChannels &&\n docState.pendingStorageChannels.size > 0 &&\n channel.kind === \"network\"\n ) {\n logger.debug(\n \"sync-request: doc {docId} is waiting for storage, queueing network request from {peerId}\",\n {\n docId,\n peerId: channel.peerId,\n },\n )\n\n // Add to pending requests\n if (!docState.pendingNetworkRequests) {\n docState.pendingNetworkRequests = []\n }\n docState.pendingNetworkRequests.push({\n channelId: fromChannelId,\n requesterDocVersion,\n })\n\n // Don't respond yet - wait for storage\n return\n }\n\n // Apply incoming ephemeral data from the requester if provided\n // ephemeral is now EphemeralStoreData[]: { peerId, data, namespace }[]\n if (ephemeral && ephemeral.length > 0) {\n for (const store of ephemeral) {\n logger.debug(\n \"sync-request: applying ephemeral data from {peerId} for {docId} namespace {namespace}\",\n {\n peerId: store.peerId,\n docId,\n namespace: store.namespace,\n },\n )\n commands.push({\n type: \"cmd/apply-ephemeral\",\n docId,\n stores: [\n {\n peerId: store.peerId,\n data: store.data,\n namespace: store.namespace,\n },\n ],\n })\n\n // Relay requester's ephemeral to other peers (not back to requester)\n const otherChannelIds = getEstablishedChannelsForDoc(\n model.channels,\n model.peers,\n docId,\n ).filter(id => id !== fromChannelId)\n\n if (otherChannelIds.length > 0) {\n logger.debug(\n \"sync-request: relaying ephemeral from {peerId} to {count} other peers for {docId}\",\n {\n peerId: store.peerId,\n count: otherChannelIds.length,\n docId,\n },\n )\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: otherChannelIds,\n message: {\n type: \"channel/ephemeral\",\n docId,\n hopsRemaining: 0, // Direct relay only\n stores: [\n {\n peerId: store.peerId,\n data: store.data,\n namespace: store.namespace,\n },\n ],\n },\n },\n })\n }\n }\n }\n\n logger.debug(\"sending sync-response due to channel/sync-request\", {\n docId,\n peerId: channel.peerId,\n })\n\n // Send sync-response with document data and ephemeral snapshot\n // The cmd/send-sync-response command will determine whether to send\n // a snapshot (full doc) or update (delta) based on requesterDocVersion\n // The includeEphemeral flag tells it to include all known ephemeral state\n commands.push({\n type: \"cmd/send-sync-response\",\n toChannelId: fromChannelId,\n docId,\n requesterDocVersion,\n includeEphemeral: true,\n })\n\n // Send reciprocal sync-request if bidirectional\n // If bidirectional is true, we want to ensure we are also subscribed to this document\n // and have the latest version from the peer.\n if (bidirectional) {\n logger.debug(\"sending reciprocal sync-request to {peerId} for {docId}\", {\n peerId: channel.peerId,\n docId,\n })\n\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [fromChannelId],\n message: {\n type: \"channel/sync-request\",\n docId,\n requesterDocVersion: docState.doc.version(),\n bidirectional: false, // Prevent infinite loops\n },\n },\n })\n }\n\n return batchAsNeeded(...commands)\n}\n","import { type Channel, isEstablished } from \"../channel.js\"\nimport type { ChannelId } from \"../types.js\"\n\n/**\n * Get all established storage channel IDs.\n *\n * Used by the storage-first sync feature to determine which storage adapters\n * need to be consulted before responding to network sync-requests.\n */\nexport function getStorageChannelIds(\n channels: Map<ChannelId, Channel>,\n): ChannelId[] {\n const storageChannelIds: ChannelId[] = []\n\n for (const [channelId, channel] of channels) {\n if (isEstablished(channel) && channel.kind === \"storage\") {\n storageChannelIds.push(channelId)\n }\n }\n\n return storageChannelIds\n}\n","import type { ChannelMsgSyncResponse, ChannelMsgUpdate } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { setPeerDocumentAwareness } from \"../peer-state-helpers.js\"\nimport { getPermissionContext } from \"../permission-context.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\n\n/**\n * Shared logic for applying sync transmissions (snapshot/update/up-to-date)\n * Used by both handle-sync-response (initial sync) and handle-update (ongoing updates)\n */\nexport function applySyncTransmission(\n message: ChannelMsgSyncResponse | ChannelMsgUpdate,\n { channel, peerState, model, permissions, logger }: EstablishedHandlerContext,\n): Command[] {\n const docState = model.documents.get(message.docId)\n const commands: Command[] = []\n\n // Handle different transmission types\n switch (message.transmission.type) {\n case \"up-to-date\": {\n // CASE 1: Document is already up to date\n // Peer has the document and our version matches theirs\n // No data to apply, just update metadata\n\n // Update peer awareness for reconnection optimization\n setPeerDocumentAwareness(\n peerState,\n message.docId,\n \"synced\",\n message.transmission.version,\n )\n\n break\n }\n\n case \"snapshot\":\n case \"update\": {\n // CASE 2: Peer is sending us document data\n // Either full snapshot or delta update\n\n if (!docState) {\n logger.warn(\n `sync transmission: docState missing for ${message.docId} (should have been created)`,\n )\n return []\n }\n\n // Check mutability permission before applying data\n // This enforces write rules and enables read-only replicas\n const context = getPermissionContext({ channel, docState, model })\n if (context instanceof Error) {\n logger.warn(`can't check mutability: ${context.message}`)\n return []\n }\n if (!permissions.mutability(context.doc, context.peer)) {\n logger.warn(`rejecting update from ${context.peer.peerName}`)\n return []\n }\n\n // IMPORTANT: Import and propagation strategy\n //\n // We use a two-phase approach to prevent echo loops:\n // 1. Import the data via cmd/import-doc-data\n // 2. After import, dispatch doc-imported to propagate to OTHER peers\n //\n // Peer awareness is updated AFTER import via cmd/update-peer-awareness-after-import\n // to ensure we set it to our CURRENT version (which includes both local and imported\n // changes), preventing the echo loop.\n commands.push({\n type: \"cmd/import-doc-data\",\n docId: message.docId,\n data: message.transmission.data,\n fromPeerId: channel.peerId,\n })\n\n break\n }\n\n case \"unavailable\": {\n // CASE 3: Peer doesn't have the document (yet)\n // We requested but peer doesn't have it\n //\n // IMPORTANT: Don't change subscriptions!\n // - Keep subscription (we sent sync-request)\n // - This ensures future updates will be sent when document is created\n // - Particularly important for storage adapters that request before persisting\n\n // Update peer awareness - peer explicitly doesn't have this doc\n setPeerDocumentAwareness(peerState, message.docId, \"absent\")\n break\n }\n }\n\n return commands\n}\n","/**\n * Handle sync-response - Receive document data from a peer\n *\n * This is the response to our sync-request. The peer is sending us document data\n * (or telling us they don't have it, or it's up-to-date).\n *\n * ## Transmission Types\n *\n * 1. **snapshot** - Full document (peer sent everything)\n * - Used when we have empty version (new document)\n * - Contains complete document state\n *\n * 2. **update** - Delta from our version\n * - Used when we have non-empty version\n * - Contains only changes since our version\n *\n * 3. **up-to-date** - No changes needed\n * - Our version matches peer's version\n * - No data transferred\n *\n * 4. **unavailable** - Peer doesn't have this document\n * - We requested but peer doesn't have it (yet)\n * - Important: Keep subscription for future updates\n *\n * ## Storage-First Sync\n *\n * When a storage adapter responds, we check if there are pending network requests\n * waiting for this storage response. If all storage adapters have responded,\n * we process the pending network requests.\n *\n * ## Permission Checking\n *\n * Before applying snapshot/update data, we check `canUpdate` permission:\n * - Enforces write rules (who can send us data)\n * - Enables read-only replicas\n * - Prevents unauthorized updates\n *\n * ## Storage Adapter Behavior\n *\n * Storage adapters:\n * - Receive sync-response for all requested documents\n * - Apply and persist the data\n * - Keep subscriptions for future updates\n *\n * ## Protocol Flow\n *\n * ```\n * Us Peer\n * | |\n * |-- sync-request ---------->|\n * | |\n * |<-- sync-response ---------| (this handler)\n * | [snapshot/update/ | 1. Check rules\n * | up-to-date/unavailable]| 2. Apply data (if any)\n * | | 3. Update peer awareness\n * | | 4. Emit ready-state-changed\n * | | 5. Process pending network requests (if storage)\n * ```\n *\n * @see docs/discovery-and-sync-architecture.md - Sync Data Transfer\n * @see handle-sync-request.ts - How peers respond to our requests\n */\n\nimport type { ChannelMsgSyncResponse } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport { createDocState } from \"../../types.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\nimport { applySyncTransmission } from \"./utils.js\"\n\nexport function handleSyncResponse(\n message: ChannelMsgSyncResponse,\n context: EstablishedHandlerContext,\n): Command | undefined {\n const { channel, model, fromChannelId, logger } = context\n\n let docState = model.documents.get(message.docId)\n const commands: Command[] = []\n\n // Create document state if we don't have it yet\n // This can happen when peer announces a document we didn't know about\n if (!docState) {\n // Only create the document if the peer actually sent data\n // If they sent \"unavailable\" or \"up-to-date\", we shouldn't create a new document\n // (especially if we just deleted it locally)\n const shouldCreate =\n message.transmission.type === \"snapshot\" ||\n message.transmission.type === \"update\"\n\n if (shouldCreate) {\n logger.debug(\"sync-response: creating new document from peer\", {\n docId: message.docId,\n peerId: channel.peerId,\n })\n docState = createDocState({\n docId: message.docId,\n peerId: model.identity.peerId,\n })\n model.documents.set(message.docId, docState)\n commands.push({\n type: \"cmd/subscribe-doc\",\n docId: message.docId,\n })\n }\n }\n\n // Apply the sync transmission\n commands.push(...applySyncTransmission(message, context))\n\n // Apply incoming ephemeral data if provided in the sync-response\n // This contains all known presence data from the responder\n // ephemeral is now EphemeralStoreData[]: { peerId, data, namespace }[]\n if (message.ephemeral && message.ephemeral.length > 0) {\n logger.debug(\n \"sync-response: applying ephemeral data from {peerId} for {docId} ({count} peer stores)\",\n {\n peerId: channel.peerId,\n docId: message.docId,\n count: message.ephemeral.length,\n },\n )\n commands.push({\n type: \"cmd/apply-ephemeral\",\n docId: message.docId,\n stores: message.ephemeral.map(ep => ({\n peerId: ep.peerId,\n data: ep.data,\n namespace: ep.namespace,\n })),\n })\n }\n\n // Storage-first sync: Check if this is a storage response we were waiting for\n if (docState?.pendingStorageChannels?.has(fromChannelId)) {\n // Remove this storage channel from the pending set\n docState.pendingStorageChannels.delete(fromChannelId)\n\n logger.debug(\n \"sync-response: storage channel {channelId} responded for {docId}, {remaining} storage channel(s) remaining\",\n {\n channelId: fromChannelId,\n docId: message.docId,\n remaining: docState.pendingStorageChannels.size,\n },\n )\n\n // If all storage channels have responded, process pending network requests\n if (docState.pendingStorageChannels.size === 0) {\n const pendingRequests = docState.pendingNetworkRequests ?? []\n\n if (pendingRequests.length > 0) {\n logger.debug(\n \"sync-response: all storage responded for {docId}, processing {count} pending network request(s)\",\n {\n docId: message.docId,\n count: pendingRequests.length,\n },\n )\n\n // Send sync-response to all pending network requests\n for (const req of pendingRequests) {\n commands.push({\n type: \"cmd/send-sync-response\",\n toChannelId: req.channelId,\n docId: message.docId,\n requesterDocVersion: req.requesterDocVersion,\n includeEphemeral: true,\n })\n }\n\n // Clear the pending requests\n docState.pendingNetworkRequests = []\n }\n\n // Clear the pending storage channels set\n docState.pendingStorageChannels = undefined\n }\n }\n\n return batchAsNeeded(...commands)\n}\n","import type { ChannelMsgUpdate } from \"../../channel.js\"\nimport type { Command } from \"../../synchronizer-program.js\"\nimport type { EstablishedHandlerContext } from \"../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\nimport { applySyncTransmission } from \"./utils.js\"\n\n/**\n * Handle sync-update - Receive spontaneous document updates from a peer\n *\n * This is used for ongoing updates AFTER the initial sync handshake.\n * Unlike sync-response, this does NOT trigger initialization logic like\n * broadcasting ephemeral state.\n */\nexport function handleSyncUpdate(\n message: ChannelMsgUpdate,\n context: EstablishedHandlerContext,\n): Command | undefined {\n const commands = applySyncTransmission(message, context)\n return batchAsNeeded(...commands)\n}\n","import type { Logger } from \"@logtape/logtape\"\nimport { type ChannelMsg, isEstablished } from \"../channel.js\"\nimport type { Permissions } from \"../permissions.js\"\nimport type { Command, SynchronizerModel } from \"../synchronizer-program.js\"\nimport type { ChannelId } from \"../types.js\"\nimport { handleEstablishRequest } from \"./connection/handle-establish-request.js\"\nimport { handleEstablishResponse } from \"./connection/handle-establish-response.js\"\nimport { handleDirectoryRequest } from \"./discovery/handle-directory-request.js\"\nimport { handleDirectoryResponse } from \"./discovery/handle-directory-response.js\"\nimport { handleNewDoc } from \"./discovery/handle-new-doc.js\"\nimport { handleEphemeral } from \"./ephemeral/handle-ephemeral.js\"\nimport { handleDeleteRequest } from \"./sync/handle-delete-request.js\"\nimport { handleSyncRequest } from \"./sync/handle-sync-request.js\"\nimport { handleSyncResponse } from \"./sync/handle-sync-response.js\"\nimport { handleSyncUpdate } from \"./sync/handle-sync-update.js\"\nimport type {\n ChannelHandlerContext,\n EstablishedHandlerContext,\n} from \"./types.js\"\nimport { batchAsNeeded } from \"./utils.js\"\n\n/** Omit specified keys from an object */\nfunction omit<T extends object, K extends keyof T>(\n obj: T,\n keys: K[],\n): Omit<T, K> {\n const result = { ...obj }\n for (const key of keys) {\n delete result[key]\n }\n return result as Omit<T, K>\n}\n\n/**\n * Dispatches channel protocol messages to their handlers\n *\n * Channel messages implement the discovery and sync protocol between peers.\n * This function:\n * 1. Validates the channel exists\n * 2. Logs the message for debugging\n * 3. Routes to the appropriate handler based on message type\n *\n * ## Message Types\n *\n * **Establishment** (connection setup):\n * - `establish-request` - Peer wants to connect\n * - `establish-response` - Connection accepted\n *\n * **Discovery** (what documents exist):\n * - `directory-request` - Ask peer what documents they have\n * - `directory-response` - Announce documents (filtered by visibility)\n *\n * **Sync** (transfer document data):\n * - `sync-request` - Request document data\n * - `sync-response` - Send document data (filtered by mutability)\n *\n * @see docs/discovery-and-sync-architecture.md for protocol details\n */\nexport function channelDispatcher(\n channelMessage: ChannelMsg,\n model: SynchronizerModel,\n fromChannelId: ChannelId,\n permissions: Permissions,\n logger: Logger,\n): Command | undefined {\n const channel = model.channels.get(fromChannelId)\n\n if (!channel) {\n logger.warn(\n \"channel not found corresponding to from-channel-id: {fromChannelId}\",\n { fromChannelId },\n )\n return\n }\n\n // Determine sender name for logging\n const from = isEstablished(channel)\n ? model.peers.get(channel.peerId)?.identity.name\n : channelMessage.type === \"channel/establish-request\"\n ? channelMessage.identity.name\n : channelMessage.type === \"channel/establish-response\"\n ? channelMessage.identity.name\n : \"unknown\"\n\n // Log all channel messages for debugging\n logger.trace(\"Received {type} from {from} via {via}\", {\n type: channelMessage.type,\n from,\n to: model.identity.name,\n via: fromChannelId,\n dir: \"recv\",\n channelMessage: omit(channelMessage, [\"type\"]),\n })\n\n // Build context for establishment handlers (any channel state)\n const ctx: ChannelHandlerContext = {\n channel,\n model,\n fromChannelId,\n permissions,\n logger,\n }\n\n // Route establishment messages - these work with any channel state\n switch (channelMessage.type) {\n case \"channel/establish-request\":\n return handleEstablishRequest(channelMessage, ctx)\n\n case \"channel/establish-response\":\n return handleEstablishResponse(channelMessage, ctx)\n\n case \"channel/batch\":\n // Dispatch each message in the batch and collect commands\n // This allows multiple messages to be sent in a single network payload\n // while still being processed individually by their handlers\n return batchAsNeeded(\n ...channelMessage.messages.map(msg =>\n channelDispatcher(msg, model, fromChannelId, permissions, logger),\n ),\n )\n }\n\n // All other messages require an established channel\n // Single validation point - not repeated in handlers!\n if (!isEstablished(channel)) {\n logger.warn(\n `rejecting ${channelMessage.type} from non-established channel ${fromChannelId}`,\n )\n return\n }\n\n const peerState = model.peers.get(channel.peerId)\n if (!peerState) {\n logger.warn(\n `rejecting ${channelMessage.type}: peer state not found for ${channel.peerId}`,\n )\n return\n }\n\n // Build established context with narrowed types\n const establishedCtx: EstablishedHandlerContext = {\n channel, // TypeScript knows this is EstablishedChannel\n peerState, // Guaranteed to exist\n model,\n fromChannelId,\n permissions,\n logger,\n }\n\n // Route to handlers that require established channel\n switch (channelMessage.type) {\n case \"channel/sync-request\":\n return handleSyncRequest(channelMessage, establishedCtx)\n\n case \"channel/sync-response\":\n return handleSyncResponse(channelMessage, establishedCtx)\n\n case \"channel/update\":\n return handleSyncUpdate(channelMessage, establishedCtx)\n\n case \"channel/directory-request\":\n return handleDirectoryRequest(channelMessage, establishedCtx)\n\n case \"channel/directory-response\":\n return handleDirectoryResponse(channelMessage, establishedCtx)\n\n case \"channel/new-doc\":\n return handleNewDoc(channelMessage, establishedCtx)\n\n case \"channel/ephemeral\":\n return handleEphemeral(channelMessage, establishedCtx)\n\n case \"channel/delete-request\":\n return handleDeleteRequest(channelMessage, establishedCtx)\n\n case \"channel/delete-response\":\n // Delete responses are informational - log and continue\n logger.info(\"delete-response received: {docId} status={status}\", {\n docId: channelMessage.docId,\n status: channelMessage.status,\n })\n return\n }\n}\n","/**\n * Handle channel-added - Register a new channel in the synchronizer\n *\n * This is called when a new channel (storage adapter or network peer) is added\n * to the system. We simply register it in our model without initiating any\n * protocol messages.\n *\n * ## Two-Phase Channel Initialization\n *\n * Channel setup happens in two phases:\n * 1. **channel-added** (this handler) - Register the channel\n * 2. **establish-channel** - Send establish-request to start handshake\n *\n * This separation allows the caller to control when the handshake begins,\n * which is useful for:\n * - Batching multiple channel additions\n * - Delaying establishment until ready\n * - Testing scenarios\n *\n * ## Channel Types\n *\n * Channels can be:\n * - **Storage adapters** - Local persistence (IndexedDB, LevelDB, etc.)\n * - **Network peers** - Remote synchronization (SSE, WebSocket, etc.)\n *\n * Both types follow the same channel protocol but may have different\n * permission rules (e.g., storage can see all docs, peers may be restricted).\n *\n * @see handle-establish-channel.ts - Phase 2: Start handshake\n * @see handle-channel-removed.ts - Cleanup when channel is removed\n */\n\nimport type { ConnectedChannel } from \"../../channel.js\"\nimport type { SynchronizerModel } from \"../../synchronizer-program.js\"\n\nexport function handleChannelAdded(\n msg: { type: \"synchronizer/channel-added\"; channel: ConnectedChannel },\n model: SynchronizerModel,\n): undefined {\n // Register the channel in our model\n // Note: We don't send establish-request yet - that happens in establish-channel\n model.channels.set(msg.channel.channelId, msg.channel)\n return\n}\n","/**\n * Handle channel-removed - Clean up when a channel is disconnected\n *\n * This is called when a channel (storage adapter or network peer) is being\n * removed from the system. We perform comprehensive cleanup while preserving\n * peer state for potential reconnection.\n *\n * ## Cleanup Steps\n *\n * 1. **De-initialize the channel** - Stop the channel's internal operations\n * 2. **Update peer state** - Mark peer as disconnected, remove channel reference\n * 3. **Remove from model** - Delete channel from synchronizer state\n * 4. **Clean document state** - Remove channel-specific document metadata\n * 5. **Handle storage-first sync** - Process pending requests if storage disconnects\n *\n * ## Peer State Preservation\n *\n * When a channel is removed, we:\n * - Keep the peer state (don't delete it)\n * - Update lastSeen timestamp\n * - Remove this channel from peer's channel set\n * - Preserve document awareness cache\n *\n * This enables optimized reconnection - when the peer reconnects via a new\n * channel, we can use cached awareness to skip unchanged documents.\n *\n * ## Document State Cleanup\n *\n * We remove channel-specific state from all documents:\n * - Loading states (found/not-found)\n * - Peer subscriptions\n * - Pending storage channels (for storage-first sync)\n * - Any other channel-specific metadata\n *\n * This ensures clean state and prevents memory leaks.\n *\n * ## Storage-First Sync Cleanup\n *\n * If a storage channel is removed while documents are waiting for its response:\n * - Remove the channel from pendingStorageChannels\n * - If no more storage channels pending, process pending network requests\n *\n * ## Channel Types\n *\n * This handler works for both:\n * - **Storage adapters** - When storage is disconnected/closed\n * - **Network peers** - When peer disconnects or connection fails\n *\n * @see handle-channel-added.ts - How channels are added\n * @see handle-establish-channel.ts - How channels are established\n */\n\nimport type { Logger } from \"@logtape/logtape\"\nimport { current } from \"mutative\"\nimport { type Channel, isEstablished } from \"../../channel.js\"\nimport type { Command, SynchronizerModel } from \"../../synchronizer-program.js\"\nimport type { DocId } from \"../../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\n\nexport function handleChannelRemoved(\n msg: { type: \"synchronizer/channel-removed\"; channel: Channel },\n model: SynchronizerModel,\n logger: Logger,\n): Command | undefined {\n // Step 1: De-initialize the channel\n // This stops the channel's internal operations (close connections, etc.)\n const channel = model.channels.get(msg.channel.channelId)\n\n const commands: Command[] = []\n\n if (channel) {\n commands.push({\n type: \"cmd/stop-channel\",\n channel: current(channel),\n })\n } else {\n logger.warn(\"channel didn't exist when removing: {channelId}\", {\n channelId: msg.channel.channelId,\n })\n }\n\n const affectedDocIds: Set<DocId> = new Set()\n\n // Step 2: Update peer state if channel was established\n // We keep the peer state for reconnection optimization\n if (channel && isEstablished(channel)) {\n const peerState = model.peers.get(channel.peerId)\n if (peerState) {\n // Remove this channel from peer's channel set\n peerState.channels.delete(channel.channelId)\n\n // If this was the last channel for this peer, we should remove their ephemeral data\n // This prevents \"ghost\" cursors/presence from lingering until timeout\n if (peerState.channels.size === 0) {\n commands.push({\n type: \"cmd/remove-ephemeral-peer\",\n peerId: channel.peerId,\n })\n }\n\n // Track which documents may be affected by this channel removal\n for (const docId of peerState.docSyncStates.keys()) {\n affectedDocIds.add(docId)\n }\n\n // IMPORTANT: Keep peer state even if no channels remain\n // This preserves document awareness cache for reconnection\n }\n }\n\n // Step 3: Handle storage-first sync cleanup\n // If this channel was a storage channel that documents were waiting for,\n // we need to remove it from pendingStorageChannels and potentially process\n // pending network requests\n const removedChannelId = msg.channel.channelId\n for (const [docId, docState] of model.documents) {\n if (docState.pendingStorageChannels?.has(removedChannelId)) {\n // Remove this storage channel from pending set\n docState.pendingStorageChannels.delete(removedChannelId)\n\n logger.debug(\n \"channel-removed: removed storage channel {channelId} from pending set for {docId}, {remaining} remaining\",\n {\n channelId: removedChannelId,\n docId,\n remaining: docState.pendingStorageChannels.size,\n },\n )\n\n // If no more storage channels pending, process pending network requests\n if (docState.pendingStorageChannels.size === 0) {\n const pendingRequests = docState.pendingNetworkRequests ?? []\n\n if (pendingRequests.length > 0) {\n logger.debug(\n \"channel-removed: all storage responded for {docId}, processing {count} pending network request(s)\",\n {\n docId,\n count: pendingRequests.length,\n },\n )\n\n // Send sync-response to all pending network requests\n for (const req of pendingRequests) {\n commands.push({\n type: \"cmd/send-sync-response\",\n toChannelId: req.channelId,\n docId,\n requesterDocVersion: req.requesterDocVersion,\n includeEphemeral: true,\n })\n }\n\n // Clear the pending requests\n docState.pendingNetworkRequests = []\n }\n\n // Clear the pending storage channels set\n docState.pendingStorageChannels = undefined\n }\n }\n\n // Also clean up pending network requests from this channel if it was a network channel\n if (docState.pendingNetworkRequests) {\n const originalLength = docState.pendingNetworkRequests.length\n docState.pendingNetworkRequests = docState.pendingNetworkRequests.filter(\n req => req.channelId !== removedChannelId,\n )\n if (docState.pendingNetworkRequests.length < originalLength) {\n logger.debug(\n \"channel-removed: removed pending network request from {docId} for disconnected channel {channelId}\",\n {\n docId,\n channelId: removedChannelId,\n },\n )\n }\n }\n }\n\n // Step 4: Remove the channel from our model\n model.channels.delete(msg.channel.channelId)\n\n return batchAsNeeded(...commands)\n}\n","/**\n * Handle establish-channel - Initiate connection handshake\n *\n * This is the second phase of channel initialization. After a channel has been\n * added to the system, this handler sends the establish-request to begin the\n * connection handshake.\n *\n * ## Two-Phase Channel Initialization\n *\n * 1. **channel-added** - Register the channel in the model\n * 2. **establish-channel** (this handler) - Send establish-request\n *\n * This separation allows the caller to control when the handshake begins.\n *\n * ## Connection Handshake\n *\n * After sending establish-request, the protocol flow is:\n * ```\n * Us Peer/Storage\n * | |\n * |-- establish-request ----->| (this handler sends)\n * | [our identity] |\n * | |\n * |<-- establish-response ----| (peer responds)\n * | [their identity] |\n * | |\n * |-- directory-request ----->| (we discover their docs)\n * |-- sync-request ---------->| (we request our docs)\n * ```\n *\n * ## Identity Exchange\n *\n * The establish-request includes our identity (name, peerId), which:\n * - Provides a stable peer identifier across reconnections\n * - Enables peer awareness caching for optimized reconnection\n * - Allows permission rules to identify the peer\n *\n * ## Usage\n *\n * Typically called immediately after channel-added, but can be delayed:\n * ```typescript\n * // Add channel\n * dispatch({ type: \"synchronizer/channel-added\", channel })\n *\n * // Start handshake (can be delayed if needed)\n * dispatch({ type: \"synchronizer/establish-channel\", channelId })\n * ```\n *\n * @see handle-channel-added.ts - Phase 1: Register channel\n * @see handle-establish-request.ts - How peer responds to our request\n * @see handle-establish-response.ts - How we handle their response\n */\n\nimport type { Logger } from \"@logtape/logtape\"\nimport { current } from \"mutative\"\nimport type { Command, SynchronizerModel } from \"../../synchronizer-program.js\"\nimport type { ChannelId } from \"../../types.js\"\n\nexport function handleEstablishChannel(\n msg: { type: \"synchronizer/establish-channel\"; channelId: ChannelId },\n model: SynchronizerModel,\n logger: Logger,\n): Command | undefined {\n // Look up the channel\n const channel = model.channels.get(msg.channelId)\n if (!channel) {\n logger.warn(\"establish-channel: channel {channelId} not found\", {\n channelId: msg.channelId,\n })\n return\n }\n\n // Send establish-request to begin handshake\n // Note: We use current() to safely extract identity from mutative context\n return {\n type: \"cmd/send-establishment-message\",\n envelope: {\n toChannelIds: [msg.channelId],\n message: {\n type: \"channel/establish-request\",\n identity: current(model.identity),\n },\n },\n }\n}\n","/**\n * Handle doc-delete - Remove a document from the synchronizer\n *\n * This is called when the application wants to delete a document locally.\n * We remove it from the synchronizer's model, which stops tracking and\n * synchronizing it.\n *\n * ## What Gets Deleted\n *\n * - Document state (Loro document instance)\n * - Channel-specific state (loading states, subscriptions)\n * - All synchronization metadata\n *\n * ## What Doesn't Get Deleted\n *\n * - Peer awareness (peers still know we had this document)\n * - Persisted data in storage adapters (separate operation)\n * - Copies on remote peers (they keep their copies)\n *\n * ## Storage Adapter Behavior\n *\n * This handler does NOT automatically delete from storage. If you want to\n * delete persisted data, you must:\n * 1. Call this handler to stop synchronization\n * 2. Separately call storage adapter's delete method\n *\n * ## Peer Synchronization\n *\n * After deletion:\n * - We stop sending updates for this document\n * - We stop responding to sync-requests for it\n * - Peers keep their copies (no deletion propagation)\n * - If peer sends updates, we ignore them (no doc state)\n *\n * ## Idempotency\n *\n * If the document doesn't exist, we log a warning but don't fail.\n * This makes it safe to call multiple times.\n *\n * ## Usage Example\n *\n * ```typescript\n * // Delete from synchronizer\n * dispatch({\n * type: \"synchronizer/doc-delete\",\n * docId: \"my-document\"\n * })\n *\n * // Optionally delete from storage (separate operation)\n * await storageAdapter.delete(\"my-document\")\n * ```\n *\n * ## Future Considerations\n *\n * This is a local-only deletion. For distributed deletion (tombstones,\n * deletion propagation), additional protocol messages would be needed.\n *\n * @see handle-doc-ensure.ts - Create/load document\n * @see handle-doc-change.ts - Update document\n */\n\nimport type { Logger } from \"@logtape/logtape\"\nimport type { Command, SynchronizerModel } from \"../../synchronizer-program.js\"\nimport type { ChannelId, DocId } from \"../../types.js\"\n\nexport function handleDocDelete(\n msg: { type: \"synchronizer/doc-delete\"; docId: DocId },\n model: SynchronizerModel,\n logger: Logger,\n): Command | undefined {\n const { docId } = msg\n\n const docState = model.documents.get(docId)\n\n // If document doesn't exist, log warning but don't fail\n if (!docState) {\n logger.warn(\"doc-delete: unable to find doc-state {docId}\", { docId })\n return\n }\n\n // Get channels to notify BEFORE deleting\n // We need to notify all peers who have subscribed to this document\n const channelIds: ChannelId[] = []\n for (const peerState of model.peers.values()) {\n if (peerState.subscriptions.has(docId)) {\n channelIds.push(...peerState.channels)\n }\n }\n\n // Remove the document from the model\n // This removes:\n // - The Loro document instance\n // - All synchronization metadata\n model.documents.delete(docId)\n\n // Return send command if there are channels to notify\n if (channelIds.length > 0) {\n return {\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: channelIds,\n message: {\n type: \"channel/delete-request\",\n docId,\n },\n },\n }\n }\n\n return undefined\n}\n","/**\n * Handle doc-ensure - Create or load a document\n *\n * This is called when the application wants to ensure a document exists locally.\n * If the document doesn't exist yet, we create it and request data from all\n * available channels (storage and peers).\n *\n * ## Document Creation\n *\n * When creating a new document:\n * 1. Create empty Loro document with the specified docId\n * 2. Register it in the synchronizer model\n * 3. Send sync-request to all channels (filtered by visibility permission)\n * 4. Subscribe to local changes\n *\n * ## Permission Filtering\n *\n * We only request from channels where `visibility` permits:\n * - Storage adapters typically see all documents\n * - Network peers may be restricted by permission rules\n * - This prevents leaking document existence to unauthorized peers\n *\n * ## Pull-Based Loading\n *\n * This handler implements pull-based document loading:\n * - Application explicitly requests document\n * - We send sync-request to all channels\n * - Channels respond with data (or unavailable)\n * - First response with data wins\n *\n * ## Storage Adapter Behavior\n *\n * Storage adapters will:\n * 1. Receive sync-request for this document\n * 2. Check if they have persisted data\n * 3. Respond with snapshot (if found) or unavailable (if not)\n * 4. Subscribe to future updates (added to subscriptions)\n *\n * ## Idempotency\n *\n * If the document already exists, this is a no-op. This makes it safe to call\n * multiple times without side effects.\n *\n * ## Usage Example\n *\n * ```typescript\n * // Application wants to load/create a document\n * dispatch({\n * type: \"synchronizer/local-doc-ensure\",\n * docId: \"my-document\"\n * })\n *\n * // Synchronizer will:\n * // 1. Create empty doc (if needed)\n * // 2. Request from storage\n * // 3. Request from peers (if allowed)\n * // 4. Subscribe to changes\n * ```\n *\n * @see handle-local-doc-change.ts - Propagate changes after document is loaded\n * @see handle-local-doc-delete.ts - Remove document\n * @see handle-sync-response.ts - How channels respond with data\n */\n\nimport { isEstablished } from \"../../channel.js\"\nimport type { Permissions } from \"../../permissions.js\"\nimport type { Command, SynchronizerModel } from \"../../synchronizer-program.js\"\nimport { createDocState, type DocId } from \"../../types.js\"\nimport { getPermissionContext } from \"../permission-context.js\"\nimport { batchAsNeeded } from \"../utils.js\"\n\nexport function handleDocEnsure(\n msg: { type: \"synchronizer/doc-ensure\"; docId: DocId },\n model: SynchronizerModel,\n permissions: Permissions,\n): Command | undefined {\n const { docId } = msg\n\n let docState = model.documents.get(docId)\n\n // If document already exists, nothing to do\n if (docState) {\n return\n }\n\n // Create new document state with the local peer's ID\n docState = createDocState({ docId, peerId: model.identity.peerId })\n model.documents.set(docId, docState)\n\n const commands: Command[] = []\n\n // Send sync-request to all established channels where visibility permits\n for (const channel of model.channels.values()) {\n if (isEstablished(channel)) {\n const context = getPermissionContext({\n channel,\n docState,\n model,\n })\n\n // Check visibility permission - can we ask this channel about this document?\n if (\n !(context instanceof Error) &&\n permissions.visibility(context.doc, context.peer)\n ) {\n // Send sync-request to load document data\n // Note: When channel responds, it will add to peer's subscriptions\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [channel.channelId],\n message: {\n type: \"channel/sync-request\",\n docId,\n requesterDocVersion: docState.doc.version(),\n bidirectional: true,\n },\n },\n })\n }\n }\n }\n\n // Subscribe to changes on this document\n commands.push({ type: \"cmd/subscribe-doc\", docId })\n\n return batchAsNeeded(...commands)\n}\n","/**\n * Propagate document changes to peers\n *\n * This utility contains the shared logic for propagating document changes to peers.\n * It's used by both:\n * - `handle-local-doc-change.ts` - For local changes (user edits)\n * - `handle-doc-imported.ts` - For imported changes (from other peers)\n *\n * ## Decision Tree\n *\n * For each established channel where `visibility=true`:\n *\n * 1. **If peer has subscribed** (in peer's `subscriptions` set):\n * - Send `sync-response` with update data directly\n * - Enables real-time collaboration\n *\n * 2. **If peer awareness is \"unknown\"**:\n * - Send `new-doc` as announcement\n * - Peer can then decide whether to request the document\n * - Respects peer autonomy (no forced sync)\n *\n * 3. **If peer awareness is \"absent\"**:\n * - Send nothing (peer explicitly doesn't have/want this doc)\n *\n * @see docs/discovery-and-sync-architecture.md - Pattern 2: Local Document Changes\n */\n\nimport type { Logger } from \"@logtape/logtape\"\nimport type { VersionVector } from \"loro-crdt\"\nimport type { SyncTransmission } from \"../../channel.js\"\nimport { type EstablishedChannel, isEstablished } from \"../../channel.js\"\nimport type { Permissions } from \"../../permissions.js\"\nimport type { Command, SynchronizerModel } from \"../../synchronizer-program.js\"\nimport type { DocId, DocState, PeerID } from \"../../types.js\"\nimport {\n setPeerDocumentAwareness,\n shouldSyncWithPeer,\n} from \"../peer-state-helpers.js\"\nimport { getPermissionContext } from \"../permission-context.js\"\n\nexport type PropagationOptions = {\n /** The document ID to propagate */\n docId: DocId\n /** The document state */\n docState: DocState\n /** Our current version (after any import) */\n ourVersion: VersionVector\n /** The synchronizer model */\n model: SynchronizerModel\n /** Permissions for visibility checks */\n permissions: Permissions\n /** Logger for debugging */\n logger: Logger\n /** Optional: Peer ID to exclude from propagation (e.g., the source of an import) */\n excludePeerId?: PeerID\n /** Log prefix for debugging (e.g., \"local-doc-change\" or \"doc-imported\") */\n logPrefix: string\n}\n\n/**\n * Propagate document changes to all eligible peers.\n *\n * @returns Array of commands to send to peers\n */\nexport function propagateToPeers(options: PropagationOptions): Command[] {\n const {\n docId,\n docState,\n ourVersion,\n model,\n permissions,\n logger,\n excludePeerId,\n logPrefix,\n } = options\n\n const commands: Command[] = []\n\n // Iterate through all established channels to propagate the change\n for (const channel of model.channels.values()) {\n if (!isEstablished(channel)) {\n logger.debug(\n `${logPrefix}: skipping non-established channel {channelId}`,\n {\n channelId: channel.channelId,\n },\n )\n continue\n }\n\n // Skip excluded peer (e.g., the source of an import)\n if (excludePeerId && channel.peerId === excludePeerId) {\n logger.trace(\n `${logPrefix}: skipping excluded peer {peerId} on channel {channelId}`,\n {\n channelId: channel.channelId,\n peerId: channel.peerId,\n },\n )\n continue\n }\n\n const peerCommands = propagateToPeer({\n channel,\n docId,\n docState,\n ourVersion,\n model,\n permissions,\n logger,\n logPrefix,\n })\n\n commands.push(...peerCommands)\n }\n\n return commands\n}\n\ntype PropagateToSinglePeerOptions = {\n channel: EstablishedChannel\n docId: DocId\n docState: DocState\n ourVersion: VersionVector\n model: SynchronizerModel\n permissions: Permissions\n logger: Logger\n logPrefix: string\n}\n\n/**\n * Propagate document changes to a single peer.\n *\n * @returns Array of commands to send to this peer\n */\nfunction propagateToPeer(options: PropagateToSinglePeerOptions): Command[] {\n const {\n channel,\n docId,\n docState,\n ourVersion,\n model,\n permissions,\n logger,\n logPrefix,\n } = options\n\n const commands: Command[] = []\n\n const peerState = model.peers.get(channel.peerId)\n const peerAwareness = peerState?.docSyncStates.get(docId)\n const isSubscribed = peerState?.subscriptions.has(docId)\n\n // Check if we're allowed to reveal this document to this channel\n // This enforces privacy rules (e.g., tenant isolation, repo permissions)\n // NOTE: If the peer is already subscribed, they know about the document, so we skip this check\n // (visibility bypass for subscribed peers)\n if (!isSubscribed) {\n const context = getPermissionContext({\n channel,\n docState,\n model,\n })\n\n if (\n context instanceof Error ||\n !permissions.visibility(context.doc, context.peer)\n ) {\n logger.debug(\n `${logPrefix}: skipping channel {channelId} due to permissions`,\n {\n channelId: channel.channelId,\n },\n )\n return commands // Not allowed to reveal to this channel\n }\n }\n\n logger.debug(`${logPrefix}: checking peer {peerId} on channel {channelId}`, {\n channelId: channel.channelId,\n peerId: channel.peerId,\n isSubscribed,\n awareness: peerAwareness?.status,\n hasPeerState: !!peerState,\n })\n\n // Decision tree based on peer's relationship with this document:\n\n if (isSubscribed && peerState) {\n // CASE 1: Peer has explicitly requested this document\n\n // Check if peer needs this update\n // If peer has \"absent\" awareness but is subscribed, they want it but don't have it.\n // We should send a snapshot.\n let shouldSync = false\n if (peerAwareness?.status === \"absent\") {\n shouldSync = true\n } else {\n shouldSync = shouldSyncWithPeer(docState, peerAwareness)\n }\n\n if (shouldSync) {\n // Export update specifically for this peer based on their version\n // With discriminated union, lastKnownVersion only exists when awareness === \"synced\"\n const theirVersion =\n peerAwareness?.status === \"synced\"\n ? peerAwareness.lastKnownVersion\n : undefined\n\n // Determine transmission type and export data\n let transmission: SyncTransmission\n\n if (\n !theirVersion ||\n theirVersion.length() === 0 ||\n peerAwareness?.status === \"absent\"\n ) {\n // Peer has no version or explicitly no doc - send snapshot\n const data = docState.doc.export({ mode: \"snapshot\" })\n transmission = { type: \"snapshot\", data, version: ourVersion }\n } else {\n // Peer has a version - send update from their version\n const data = docState.doc.export({\n mode: \"update\",\n from: theirVersion,\n })\n transmission = { type: \"update\", data, version: ourVersion }\n }\n\n // Send real-time update directly (enables collaboration)\n logger.debug(\n `${logPrefix}: sending sync-response ({transmissionType}) for {docId} to {channelId}`,\n {\n channelId: channel.channelId,\n docId,\n transmissionType: transmission.type,\n ourVersion: ourVersion.toJSON(),\n theirVersion: theirVersion?.toJSON(),\n },\n )\n\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [channel.channelId],\n message: {\n type: \"channel/update\",\n docId,\n transmission,\n },\n },\n })\n\n // Update peer's known version after sending\n setPeerDocumentAwareness(peerState, docId, \"synced\", ourVersion)\n } else {\n logger.debug(\n `${logPrefix}: skipping sync-response for {docId} to {channelId} - peer is up-to-date`,\n {\n channelId: channel.channelId,\n docId,\n ourVersion: ourVersion.toJSON(),\n theirVersion:\n peerAwareness?.status === \"synced\"\n ? peerAwareness.lastKnownVersion.toJSON()\n : undefined,\n },\n )\n }\n } else if (\n !peerAwareness ||\n peerAwareness.status === \"unknown\" ||\n peerAwareness.status === \"pending\" ||\n (peerAwareness.status === \"synced\" &&\n shouldSyncWithPeer(docState, peerAwareness))\n ) {\n // CASE 2: Peer doesn't know about this document yet OR they have it but are behind\n // Send announcement (peer can then decide whether to request)\n logger.debug(\n `${logPrefix}: sending new-doc announcement for {docId} to {channelId} (reason: {reason})`,\n {\n channelId: channel.channelId,\n docId,\n reason: !peerAwareness ? \"no-awareness\" : peerAwareness.status,\n shouldSync: peerAwareness\n ? shouldSyncWithPeer(docState, peerAwareness)\n : \"N/A\",\n },\n )\n\n commands.push({\n type: \"cmd/send-message\",\n envelope: {\n toChannelIds: [channel.channelId],\n message: {\n type: \"channel/new-doc\",\n docIds: [docId],\n },\n },\n })\n }\n // CASE 3: peerAwareness === \"absent\"\n // Peer explicitly doesn't have this document - send nothing\n\n return commands\n}\n","/**\n * Handle doc-imported - Propagate imported document changes to other peers\n *\n * This is triggered after we import data from a peer via sync-response.\n * It handles two critical tasks:\n *\n * 1. **Update peer awareness** - Set the source peer's awareness to our CURRENT\n * version (after import). This prevents echo loops because our version now\n * includes both local and imported changes.\n *\n * 2. **Multi-hop propagation** - Forward the changes to OTHER peers who are\n * subscribed to this document. This enables hub-and-spoke topologies where\n * a server relays changes between clients.\n *\n * ## Why This Exists\n *\n * Previously, doc.subscribe() fired synchronously during import, before peer\n * awareness could be updated. This caused echo loops:\n *\n * 1. Peer A sends us data (version {A: 5})\n * 2. We set peer awareness to {A: 5}\n * 3. We import, our version becomes {A: 5, B: 3} (if we had local changes)\n * 4. doc.subscribe() fires, triggers doc-change\n * 5. doc-change sees our version {A: 5, B: 3} > peer awareness {A: 5}\n * 6. We send our local changes back to peer A (ECHO!)\n *\n * Now, doc.subscribe() only fires for \"local\" events. Import events are\n * handled here, where we can update peer awareness BEFORE propagating.\n *\n * @see handle-sync-response.ts - Where imports are initiated\n * @see handle-local-doc-change.ts - Similar logic for local changes\n * @see propagate-to-peers.ts - Shared propagation logic\n */\n\nimport type { Logger } from \"@logtape/logtape\"\nimport type { Permissions } from \"../../permissions.js\"\nimport type { Command, SynchronizerModel } from \"../../synchronizer-program.js\"\nimport type { DocId, PeerID } from \"../../types.js\"\nimport { setPeerDocumentAwareness } from \"../peer-state-helpers.js\"\nimport { batchAsNeeded } from \"../utils.js\"\nimport { propagateToPeers } from \"./propagate-to-peers.js\"\n\nexport function handleDocImported(\n msg: {\n type: \"synchronizer/doc-imported\"\n docId: DocId\n fromPeerId: PeerID\n },\n model: SynchronizerModel,\n permissions: Permissions,\n logger: Logger,\n): Command | undefined {\n const { docId, fromPeerId } = msg\n\n const docState = model.documents.get(docId)\n\n if (!docState) {\n logger.warn(\"doc-imported: unable to find doc-state {docId}\", { docId })\n return\n }\n\n // Get our current version AFTER import\n const ourVersion = docState.doc.version()\n\n // STEP 1: Update the source peer's awareness to our CURRENT version\n // This prevents echo loops - they sent us data, and now we know they have\n // everything we have (since we just imported their data)\n const sourcePeerState = model.peers.get(fromPeerId)\n if (sourcePeerState) {\n setPeerDocumentAwareness(sourcePeerState, docId, \"synced\", ourVersion)\n logger.trace(\n \"doc-imported: updated peer awareness for {peerId} to our version\",\n {\n docId,\n peerId: fromPeerId,\n ourVersion: ourVersion.toJSON(),\n },\n )\n }\n\n logger.trace(\n \"doc-imported processing for {docId} from {fromPeerId} with {channelCount} channels\",\n {\n docId,\n fromPeerId,\n channelCount: model.channels.size,\n },\n )\n\n // STEP 2: Propagate to OTHER peers (multi-hop)\n // Skip the source peer - they already have this data!\n const commands = propagateToPeers({\n docId,\n docState,\n ourVersion,\n model,\n permissions,\n logger,\n logPrefix: \"doc-imported\",\n excludePeerId: fromPeerId,\n })\n\n return batchAsNeeded(...commands)\n}\n","/**\n * Handle local-doc-change - Propagate LOCAL document changes to peers\n *\n * This is triggered whenever a document is modified LOCALLY (user edits via\n * doc.subscribe with event.by === \"local\"). It implements the **pull-based\n * discovery model** where we announce changes but let peers decide whether\n * to request the data.\n *\n * ## When This Fires\n *\n * This handler is triggered by doc.subscribeLocalUpdates()\n *\n * This means:\n * - User edits via DocHandle.change()\n * - Direct mutations to doc via handle.doc\n * - Any local operation that modifies the document\n *\n * It does NOT fire for:\n * - Imported changes from peers (handled by handle-doc-imported.ts)\n * - Checkout operations (ignored for now)\n *\n * ## Protocol Flows\n *\n * ### Flow 1: New Document Created\n * ```\n * User creates doc → local-doc-change\n * → Send directory-response (announcement) to all channels\n * → Storage adapter sends sync-request (eager)\n * → Network peer may send sync-request (if interested)\n * ```\n *\n * ### Flow 2: Existing Document Modified\n * ```\n * User edits doc → local-doc-change\n * → Send sync-response to peers who requested (real-time update)\n * → Send directory-response to peers who don't know about it\n * ```\n *\n * @see docs/discovery-and-sync-architecture.md - Pattern 2: Local Document Changes\n * @see handle-doc-imported.ts - Similar logic for imported changes\n * @see propagate-to-peers.ts - Shared propagation logic\n */\n\nimport type { Logger } from \"@logtape/logtape\"\nimport type { Permissions } from \"../../permissions.js\"\nimport type { Command, SynchronizerModel } from \"../../synchronizer-program.js\"\nimport type { DocId } from \"../../types.js\"\nimport { batchAsNeeded } from \"../utils.js\"\nimport { propagateToPeers } from \"./propagate-to-peers.js\"\n\nexport function handleLocalDocChange(\n msg: {\n type: \"synchronizer/local-doc-change\"\n docId: DocId\n },\n model: SynchronizerModel,\n permissions: Permissions,\n logger: Logger,\n): Command | undefined {\n const { docId } = msg\n\n const docState = model.documents.get(docId)\n\n if (!docState) {\n logger.warn(\"local-doc-change: unable to find doc-state {docId}\", { docId })\n return\n }\n\n logger.debug(\n \"local-doc-change processing for {docId} with {channelCount} channels\",\n {\n docId,\n channelCount: model.channels.size,\n },\n )\n\n const ourVersion = docState.doc.version()\n\n const commands = propagateToPeers({\n docId,\n docState,\n ourVersion,\n model,\n permissions,\n logger,\n logPrefix: \"local-doc-change\",\n })\n\n return batchAsNeeded(...commands)\n}\n","import type { Logger } from \"@logtape/logtape\"\nimport type { Permissions } from \"../permissions.js\"\nimport type {\n Command,\n SynchronizerMessage,\n SynchronizerModel,\n} from \"../synchronizer-program.js\"\nimport type { ChannelId, DocId } from \"../types.js\"\nimport { getEstablishedChannelsForDoc } from \"../utils/get-established-channels-for-doc.js\"\nimport { channelDispatcher } from \"./channel-dispatcher.js\"\nimport { handleChannelAdded } from \"./connection/handle-channel-added.js\"\nimport { handleChannelRemoved } from \"./connection/handle-channel-removed.js\"\nimport { handleEstablishChannel } from \"./connection/handle-establish-channel.js\"\nimport { handleDocDelete } from \"./sync/handle-doc-delete.js\"\nimport { handleDocEnsure } from \"./sync/handle-doc-ensure.js\"\nimport { handleDocImported } from \"./sync/handle-doc-imported.js\"\nimport { handleLocalDocChange } from \"./sync/handle-local-doc-change.js\"\n\nexport function synchronizerDispatcher(\n msg: SynchronizerMessage,\n model: SynchronizerModel,\n permissions: Permissions,\n logger: Logger,\n): Command | undefined {\n switch (msg.type) {\n case \"synchronizer/heartbeat\": {\n // Broadcast all ephemeral state for all documents to all peers\n // Optimization: Group documents by peer to send one batched message per peer\n // This reduces O(docs × peers) messages to O(peers) messages\n\n // Step 1: Build a map of channelId -> docIds\n const peerDocs = new Map<ChannelId, DocId[]>()\n\n for (const docId of model.documents.keys()) {\n const channelIds = getEstablishedChannelsForDoc(\n model.channels,\n model.peers,\n docId,\n )\n\n for (const channelId of channelIds) {\n const docs = peerDocs.get(channelId) ?? []\n docs.push(docId)\n peerDocs.set(channelId, docs)\n }\n }\n\n // Step 2: Create one cmd/broadcast-ephemeral-batch per peer\n // This is a macro command that expands into per-namespace broadcasts\n const commands: Command[] = []\n\n for (const [channelId, docIds] of peerDocs) {\n commands.push({\n type: \"cmd/broadcast-ephemeral-batch\",\n docIds,\n hopsRemaining: 1, // Allow server to relay heartbeat to other clients\n toChannelId: channelId,\n })\n }\n\n return commands.length > 0 ? { type: \"cmd/batch\", commands } : undefined\n }\n\n case \"synchronizer/ephemeral-local-change\": {\n const channelIds = getEstablishedChannelsForDoc(\n model.channels,\n model.peers,\n msg.docId,\n )\n\n return {\n type: \"cmd/batch\",\n commands: [\n {\n type: \"cmd/emit-ephemeral-change\",\n docId: msg.docId,\n },\n {\n type: \"cmd/broadcast-ephemeral-namespace\",\n docId: msg.docId,\n namespace: msg.namespace,\n // Allow a hub-and-spoke server to propagate one more hop\n hopsRemaining: 1,\n toChannelIds: channelIds,\n },\n ],\n }\n }\n\n case \"synchronizer/channel-added\":\n return handleChannelAdded(msg, model)\n\n case \"synchronizer/establish-channel\":\n return handleEstablishChannel(msg, model, logger)\n\n case \"synchronizer/channel-removed\":\n return handleChannelRemoved(msg, model, logger)\n\n case \"synchronizer/doc-ensure\":\n return handleDocEnsure(msg, model, permissions)\n\n case \"synchronizer/local-doc-change\":\n return handleLocalDocChange(msg, model, permissions, logger)\n\n case \"synchronizer/doc-imported\":\n return handleDocImported(msg, model, permissions, logger)\n\n case \"synchronizer/doc-delete\":\n return handleDocDelete(msg, model, logger)\n\n case \"synchronizer/channel-receive-message\":\n // Channel messages are routed through the channel dispatcher\n return channelDispatcher(\n msg.envelope.message,\n model,\n msg.envelope.fromChannelId,\n permissions,\n logger,\n )\n }\n}\n","import { create, type Patch } from \"mutative\"\n\n/**\n * Creates a TEA-compatible immutable update function from an update function that uses mutations\n * (via `mutative`) to capture what state should change.\n *\n * The input (a mutative update function) directly mutates the model (draft) and returns only a\n * Command. The transformer handles the immutability contract of TEA, as well as optionally offers\n * patch generation.\n *\n * @param mutativeUpdate - Function that mutates the model and returns a command\n * @param onPatch - Optional callback to receive patches for debugging\n * @returns A TEA-compatible update function that returns [Model, Command?]\n */\nexport function makeImmutableUpdate<Msg, Model, Command>(\n mutativeUpdate: (msg: Msg, model: Model) => Command | undefined,\n onPatch?: (patches: Patch[]) => void,\n): (msg: Msg, model: Model) => [Model, Command | undefined] {\n return (msg: Msg, model: Model) => {\n let command: Command | undefined\n\n const result = create(\n model,\n draft => {\n command = mutativeUpdate(msg, draft as Model)\n },\n { enablePatches: !!onPatch },\n )\n\n // When enablePatches is true, result is [newModel, patches, inversePatches]\n // When enablePatches is false, result is just newModel\n const newModel = Array.isArray(result) ? result[0] : result\n const patches = Array.isArray(result) ? result[1] : []\n\n if (onPatch && patches.length > 0) {\n onPatch(patches)\n }\n\n return [newModel, command]\n }\n}\n","import type { PeerID } from \"../types.js\"\n\n/**\n * Generate a cryptographically random PeerID.\n *\n * PeerID must be an unsigned 64-bit integer represented as a decimal string.\n * This function uses crypto.getRandomValues to generate a random 64-bit value\n * that is globally unique with extremely high probability.\n *\n * @returns A random PeerID suitable for use with Loro\n *\n * @example\n * ```typescript\n * const peerId = generatePeerId()\n * doc.setPeerId(peerId)\n * ```\n */\nexport function generatePeerId(): PeerID {\n // Generate 8 random bytes (64 bits)\n const randomBytes = new Uint8Array(8)\n crypto.getRandomValues(randomBytes)\n\n // Convert to a 64-bit unsigned integer\n const view = new DataView(randomBytes.buffer)\n const randomBigInt = view.getBigUint64(0, false) // false = big-endian\n\n // Convert to decimal string and cast to PeerID type\n return `${randomBigInt}` as PeerID\n}\n","import type { PeerID } from \"../types.js\"\n\n/**\n * Validates that a peerId is compatible with Loro's `${number}` PeerID type.\n * A valid peerId must be a string representing a non-negative integer (unsigned 64-bit).\n *\n * @param peerId - The peerId string to validate\n * @throws Error if the peerId is not a valid numeric string\n */\nexport function validatePeerId(peerId: string): asserts peerId is PeerID {\n // Must be a non-empty string of digits only (no leading zeros except for \"0\" itself)\n if (!/^(0|[1-9]\\d*)$/.test(peerId)) {\n throw new Error(\n `Invalid peerId: \"${peerId}\". PeerID must be a non-negative integer string (e.g., \"123456789\").`,\n )\n }\n\n // Check if it's within unsigned 64-bit integer range (0 to 2^64 - 1)\n const MAX_UINT64 = BigInt(\"18446744073709551615\") // 2^64 - 1\n try {\n const value = BigInt(peerId)\n if (value < 0n || value > MAX_UINT64) {\n throw new Error(\n `Invalid peerId: \"${peerId}\". PeerID must be within unsigned 64-bit integer range (0 to ${MAX_UINT64}).`,\n )\n }\n } catch (e) {\n if (e instanceof Error && e.message.startsWith(\"Invalid peerId:\")) {\n throw e\n }\n throw new Error(\n `Invalid peerId: \"${peerId}\". PeerID must be a valid integer string.`,\n )\n }\n}\n","import { LoroDoc, type PeerID, type VersionVector } from \"loro-crdt\"\nimport { Adapter } from \"../adapter/adapter.js\"\nimport type {\n BatchableMsg,\n ChannelMsg,\n ChannelMsgBatch,\n ChannelMsgDeleteRequest,\n ChannelMsgDirectoryRequest,\n ChannelMsgNewDoc,\n ChannelMsgSyncRequest,\n ConnectedChannel,\n GeneratedChannel,\n} from \"../channel.js\"\nimport type { DocId } from \"../types.js\"\nimport { generatePeerId } from \"../utils/generate-peer-id.js\"\n\nexport type StorageKey = string[]\n\nexport type Chunk = {\n key: StorageKey\n data: Uint8Array\n}\n\n/**\n * A base class for storage adapters.\n *\n * This base class extends Adapter<void> and handles all channel communication\n * behind the scenes. Subclasses only need to implement the following storage\n * operations, and do not need specialized knowledge of Adapter message protocol:\n * - load, save, remove\n * - loadRange, removeRange\n *\n * The base class automatically:\n * - Creates a single channel for storage operations\n * - Responds to channel establishment requests\n * - Responds to document sync requests\n * - Translates channel messages into storage operations\n *\n * The StorageAdapter essentially mimics what would happen if there were another\n * repo to communicate with, but instead intercepts and responds with appropriate\n * messages itself.\n */\nexport abstract class StorageAdapter extends Adapter<void> {\n /**\n * Storage adapters always create storage channels.\n * This overrides the default \"network\" kind from the base Adapter class.\n */\n override readonly kind = \"storage\" as const\n\n protected storageChannel?: ConnectedChannel\n private lastTimestamp = 0\n private counter = 0\n\n // Since a StorageAdapter mimics the behavior of a peer, we need a PeerId\n private readonly storagePeerId: PeerID = generatePeerId()\n\n /**\n * Generate channel actions for storage operations.\n * The kind and adapterType are automatically added by the base class.\n */\n protected generate(): GeneratedChannel {\n return {\n kind: this.kind,\n adapterType: this.adapterType,\n send: this.handleChannelMessage.bind(this),\n stop: () => {},\n }\n }\n\n /**\n * Start the storage adapter by creating its single channel.\n * Storage is always \"ready\" - no async initialization needed.\n */\n async onStart(): Promise<void> {\n this.storageChannel = this.addChannel()\n\n // Establish the channel to trigger the establishment handshake\n this.establishChannel(this.storageChannel.channelId)\n }\n\n /**\n * Stop the storage adapter and clean up resources.\n */\n async onStop(): Promise<void> {\n if (this.storageChannel) {\n this.removeChannel(this.storageChannel.channelId)\n this.storageChannel = undefined\n }\n }\n\n /**\n * Handle incoming channel messages and translate them into storage operations.\n */\n private async handleChannelMessage(msg: ChannelMsg): Promise<void> {\n this.logger.trace(\"handleChannelMessage\", { type: msg.type })\n\n try {\n switch (msg.type) {\n case \"channel/establish-request\":\n return await this.handleEstablishRequest()\n case \"channel/establish-response\":\n // Nothing to do\n break\n case \"channel/sync-request\":\n return await this.handleSyncRequest(msg)\n case \"channel/sync-response\":\n return await this.handleSyncResponse(msg)\n case \"channel/update\":\n return await this.handleUpdate(msg)\n case \"channel/directory-request\":\n return await this.handleDirectoryRequest(msg)\n case \"channel/directory-response\":\n // directory-response is only for request/response flow (future glob feature)\n // Storage adapters don't need to handle this\n break\n case \"channel/new-doc\":\n return await this.handleNewDoc(msg)\n case \"channel/delete-request\":\n return await this.handleDeleteRequest(msg)\n case \"channel/delete-response\":\n // Nothing to do\n break\n case \"channel/ephemeral\":\n // Storage adapters ignore ephemeral messages\n return\n case \"channel/batch\":\n // Handle batched messages by dispatching each one\n return await this.handleBatch(msg)\n default:\n this.logger.warn(\"unhandled message type\", {\n type: (msg as ChannelMsg).type,\n })\n }\n } catch (error) {\n this.logger.error(\"error handling channel message\", { error, msg })\n }\n }\n\n /**\n * Handle batched messages by dispatching each one.\n */\n private async handleBatch(msg: ChannelMsgBatch): Promise<void> {\n for (const innerMsg of msg.messages) {\n await this.handleChannelMessage(innerMsg)\n }\n }\n\n // ==========================================================================\n // Message Handlers\n // ==========================================================================\n\n /**\n * Automatically respond to establishment requests.\n * Storage has no concept of \"connection establishment\" - it's always ready.\n * We immediately respond with our identity so the channel becomes established.\n *\n * NOTE: We intentionally do NOT call requestStoredDocuments() here.\n * Storage is lazy-loaded - documents are loaded on-demand when network clients\n * request them via the storage-first sync mechanism. This approach:\n * - Scales to millions of documents\n * - Reduces startup time\n * - Avoids race conditions with eager loading\n */\n private async handleEstablishRequest(): Promise<void> {\n this.logger.debug(\"handleEstablishRequest: responding with identity\")\n // Small delay to ensure the channel is fully registered\n await Promise.resolve()\n this.reply({\n type: \"channel/establish-response\",\n identity: {\n peerId: this.storagePeerId,\n name: this.adapterType,\n type: \"service\",\n },\n })\n\n // Storage is now lazy - documents are loaded on-demand via handleSyncRequest\n // when network clients request them. No eager loading needed.\n }\n\n /**\n * Handle sync requests by loading documents from storage.\n *\n * This implementation:\n * 1. Loads snapshot + incremental updates using loadRange\n * 2. Reconstructs document in temporary LoroDoc (order doesn't matter - Loro handles it)\n * 3. Uses requesterDocVersion to export only needed changes\n * 4. Enables efficient incremental sync\n *\n * WARNING: This implementation loads all chunks for a document into memory at once.\n * For very large documents or documents with long histories, this could lead to\n * high memory usage. A future improvement would be to stream chunks or use\n * a more memory-efficient reconstruction strategy.\n */\n private async handleSyncRequest(msg: ChannelMsgSyncRequest): Promise<void> {\n const { docId, requesterDocVersion, bidirectional } = msg\n\n this.logger.debug(\"handleSyncRequest: received request\", {\n docId,\n bidirectional,\n })\n\n try {\n // Load all data for this document (snapshot + updates)\n const chunks = await this.loadRange([docId])\n this.logger.debug(\"handleSyncRequest: loaded chunks\", {\n docId,\n count: chunks.length,\n })\n\n if (chunks.length === 0) {\n // Document not found in storage yet\n // Send \"unavailable\" to indicate we don't have the data\n this.logger.debug(\"handleSyncRequest: document not found in storage\", {\n docId,\n })\n this.replyUnavailable(docId)\n\n // Even though we don't have the document, we want to receive future updates\n // Send reciprocal sync-request with empty version\n this.replyWithSyncRequest(\n [{ docId, requesterDocVersion: new LoroDoc().oplogVersion() }],\n false,\n )\n return\n }\n\n // Reconstruct document from storage chunks\n // Note: Order doesn't matter - Loro's CRDT is commutative\n const tempDoc = new LoroDoc()\n\n try {\n const updates = chunks.map(chunk => chunk.data)\n tempDoc.importBatch(updates)\n this.logger.debug(\"handleSyncRequest: imported chunks into tempDoc\", {\n docId,\n chunkCount: chunks.length,\n })\n } catch (error) {\n this.logger.warn(\"failed to import chunk batch\", {\n docId,\n error,\n })\n }\n\n // Export version-aware response\n const currentVersion = tempDoc.oplogVersion()\n\n // Use Loro's built-in version comparison\n const comparison = requesterDocVersion.compare(currentVersion)\n this.logger.debug(\"handleSyncRequest: version comparison\", {\n docId,\n comparison,\n requesterVersionLength: requesterDocVersion.length(),\n currentVersionLength: currentVersion.length(),\n })\n\n if (comparison === 0) {\n // Versions are equal - requester is up to date\n this.logger.debug(\"handleSyncRequest: replying up-to-date\", { docId })\n this.replyUpToDate(docId, currentVersion)\n } else if (comparison === 1) {\n // Requester version is greater - they're ahead (shouldn't happen normally)\n this.logger.debug(\n \"handleSyncRequest: requester ahead, replying up-to-date\",\n { docId },\n )\n this.replyUpToDate(docId, currentVersion)\n } else {\n // Requester version is less than or concurrent - send updates\n const data = tempDoc.export({\n mode: \"update\",\n from: requesterDocVersion,\n })\n this.logger.debug(\"handleSyncRequest: sending update\", {\n docId,\n dataLength: data.length,\n })\n\n this.replyWithSyncResponse(docId, data, currentVersion)\n }\n\n // Send reciprocal sync-request to get added to the Repo's subscriptions\n // This ensures we receive future updates for this document\n this.logger.debug(\n \"handleSyncRequest: sending reciprocal sync-request for subscription\",\n { docId },\n )\n this.replyWithSyncRequest(\n [{ docId, requesterDocVersion: currentVersion }],\n false,\n )\n } catch (error) {\n this.logger.error(\"sync request failed\", { docId, error })\n this.replyUnavailable(docId)\n\n // Still want updates even if we failed to load\n this.replyWithSyncRequest(\n [{ docId, requesterDocVersion: new LoroDoc().oplogVersion() }],\n false,\n )\n }\n }\n\n /**\n * Handle sync responses by saving document updates to storage.\n * This is called once in response to a sync-request.\n */\n private async handleSyncResponse(msg: ChannelMsg): Promise<void> {\n if (msg.type !== \"channel/sync-response\") return\n\n const { docId, transmission } = msg\n\n this.logger.debug(\"handleSyncResponse: received\", {\n docId,\n transmissionType: transmission.type,\n dataLength: \"data\" in transmission ? transmission.data.length : 0,\n })\n\n // Only save if we received actual data\n if (transmission.type === \"update\" || transmission.type === \"snapshot\") {\n this.logger.debug(\n \"handleSyncResponse: about to save data (this creates a new chunk!)\",\n {\n docId,\n transmissionType: transmission.type,\n dataLength: transmission.data.length,\n },\n )\n await this.saveDocumentData(docId, transmission.data)\n }\n }\n\n /**\n * Handle ongoing updates from subscribed documents.\n * This is called when a document changes after the initial sync.\n */\n private async handleUpdate(msg: ChannelMsg): Promise<void> {\n if (msg.type !== \"channel/update\") return\n\n const { docId, transmission } = msg\n\n this.logger.debug(\"handleUpdate: received\", {\n docId,\n transmissionType: transmission.type,\n dataLength: \"data\" in transmission ? transmission.data.length : 0,\n })\n\n // Only save if we received actual data\n if (transmission.type === \"update\" || transmission.type === \"snapshot\") {\n this.logger.debug(\n \"handleUpdate: about to save data (this creates a new chunk!)\",\n {\n docId,\n transmissionType: transmission.type,\n dataLength: transmission.data.length,\n },\n )\n await this.saveDocumentData(docId, transmission.data)\n }\n }\n\n /**\n * Handle directory requests by listing available documents.\n */\n private async handleDirectoryRequest(\n msg: ChannelMsgDirectoryRequest,\n ): Promise<void> {\n try {\n if (msg.docIds) {\n // Check specific docIds\n const available = await this.checkDocIds(msg.docIds)\n this.replyWithDirectoryResponse(available)\n } else {\n // List all documents\n const chunks = await this.loadRange([])\n // Extract unique docIds from chunks (each doc may have multiple chunks)\n const docIds = Array.from(new Set(chunks.map(chunk => chunk.key[0])))\n this.replyWithDirectoryResponse(docIds)\n }\n } catch (error) {\n this.logger.error(\"directory request failed\", { error })\n this.replyWithDirectoryResponse([])\n }\n }\n\n /**\n * Handle new-doc announcements by eagerly requesting documents.\n * Storage adapters are \"eager\" - they automatically request all announced documents.\n */\n private async handleNewDoc(msg: ChannelMsgNewDoc): Promise<void> {\n const { docIds } = msg\n\n if (docIds.length === 0) return\n\n this.logger.debug(\"received new-doc announcement\", {\n docIds,\n count: docIds.length,\n })\n\n // Storage is eager - request all announced documents\n // Use empty version to get full snapshot\n const docs = docIds.map(docId => ({\n docId,\n requesterDocVersion: new LoroDoc().version(),\n }))\n\n this.replyWithSyncRequest(docs, false)\n }\n\n /**\n * Handle delete requests by removing documents from storage.\n */\n private async handleDeleteRequest(\n msg: ChannelMsgDeleteRequest,\n ): Promise<void> {\n try {\n await this.remove([msg.docId])\n this.replyWithDeleteResponse(msg.docId, \"deleted\")\n } catch (error) {\n this.logger.warn(\"delete failed\", { docId: msg.docId, error })\n this.replyWithDeleteResponse(msg.docId, \"ignored\")\n }\n }\n\n // ==========================================================================\n // Helper methods\n // ==========================================================================\n\n /**\n * Save document data to storage with a unique timestamped key.\n */\n private async saveDocumentData(\n docId: DocId,\n data: Uint8Array,\n ): Promise<void> {\n // Generate a unique key for this update\n // Format: [docId, \"update\", timestamp]\n const now = Date.now()\n if (now === this.lastTimestamp) {\n this.counter++\n } else {\n this.lastTimestamp = now\n this.counter = 0\n }\n\n const timestamp = `${now}-${this.counter.toString().padStart(4, \"0\")}`\n const key: StorageKey = [docId, \"update\", timestamp]\n\n await this.save(key, data)\n }\n\n /**\n * Send a reply message through the storage channel.\n * Throws an error if the channel is not properly initialized.\n *\n * Delivers messages synchronously. The Synchronizer's receive queue handles\n * recursion prevention by queuing messages and processing them iteratively.\n */\n private reply(msg: ChannelMsg): void {\n if (!this.storageChannel) {\n throw new Error(\"Cannot reply: storage channel not initialized\")\n }\n // Deliver synchronously - the Synchronizer's receive queue prevents recursion\n this.storageChannel.onReceive(msg)\n }\n\n /**\n * Check which of the given docIds are available in storage.\n */\n private async checkDocIds(docIds: DocId[]): Promise<DocId[]> {\n const available: DocId[] = []\n for (const docId of docIds) {\n try {\n const data = await this.load([docId])\n if (data) {\n available.push(docId)\n }\n } catch (error) {\n this.logger.warn(\"error checking docId\", { docId, error })\n }\n }\n return available\n }\n\n /**\n * Reply with sync request(s) for the given documents.\n * Uses channel/batch if multiple documents, single message otherwise.\n */\n private replyWithSyncRequest(\n docs: Array<{ docId: DocId; requesterDocVersion: VersionVector }>,\n bidirectional: boolean,\n ): void {\n if (docs.length === 0) {\n return\n }\n\n if (docs.length === 1) {\n // Single document - send single sync-request\n this.reply({\n type: \"channel/sync-request\",\n docId: docs[0].docId,\n requesterDocVersion: docs[0].requesterDocVersion,\n bidirectional,\n })\n } else {\n // Multiple documents - batch sync-requests\n const syncRequests: ChannelMsgSyncRequest[] = docs.map(doc => ({\n type: \"channel/sync-request\",\n docId: doc.docId,\n requesterDocVersion: doc.requesterDocVersion,\n bidirectional,\n }))\n\n this.reply({\n type: \"channel/batch\",\n messages: syncRequests as BatchableMsg[],\n })\n }\n }\n\n /**\n * Reply with a sync response containing document data.\n */\n private replyWithSyncResponse(\n docId: DocId,\n data: Uint8Array,\n version: VersionVector,\n ): void {\n this.reply({\n type: \"channel/sync-response\",\n docId,\n transmission: {\n type: \"update\",\n data,\n version,\n },\n })\n }\n\n /**\n * Reply that the requester already has the latest version.\n */\n private replyUpToDate(docId: DocId, version: VersionVector): void {\n this.reply({\n type: \"channel/sync-response\",\n docId,\n transmission: {\n type: \"up-to-date\",\n version,\n },\n })\n }\n\n /**\n * Reply that the document is not available.\n */\n private replyUnavailable(docId: DocId): void {\n this.reply({\n type: \"channel/sync-response\",\n docId,\n transmission: { type: \"unavailable\" },\n })\n }\n\n /**\n * Reply with a directory listing of available docIds.\n */\n private replyWithDirectoryResponse(docIds: DocId[]): void {\n this.reply({\n type: \"channel/directory-response\",\n docIds,\n })\n }\n\n /**\n * Reply with the result of a delete operation.\n */\n private replyWithDeleteResponse(\n docId: DocId,\n status: \"deleted\" | \"ignored\",\n ): void {\n this.reply({\n type: \"channel/delete-response\",\n docId,\n status,\n })\n }\n\n // Abstract storage interface - implemented by subclasses\n\n /** Load a binary blob for a given key. */\n abstract load(key: StorageKey): Promise<Uint8Array | undefined>\n\n /** Save a binary blob to a given key. */\n abstract save(key: StorageKey, data: Uint8Array): Promise<void>\n\n /** Remove a binary blob from a given key. */\n abstract remove(key: StorageKey): Promise<void>\n\n /** Load all chunks whose keys begin with the given prefix. */\n abstract loadRange(keyPrefix: StorageKey): Promise<Chunk[]>\n\n /** Remove all chunks whose keys begin with the given prefix. */\n abstract removeRange(keyPrefix: StorageKey): Promise<void>\n}\n","import {\n type Chunk,\n StorageAdapter,\n type StorageKey,\n} from \"./storage-adapter.js\"\n\nexport class InMemoryStorageAdapter extends StorageAdapter {\n #data = new Map<string, Uint8Array>()\n\n constructor(\n sharedDataOrOptions?:\n | Map<string, Uint8Array>\n | {\n sharedData?: Map<string, Uint8Array>\n adapterType?: string\n /**\n * Unique identifier for this adapter instance.\n * If not provided, auto-generated as `{adapterType}-{uuid}`.\n */\n adapterId?: string\n },\n ) {\n // Handle both old API (just sharedData) and new API (options object)\n const options =\n sharedDataOrOptions instanceof Map\n ? { sharedData: sharedDataOrOptions, adapterType: \"in-memory\" }\n : { adapterType: \"in-memory\", ...sharedDataOrOptions }\n\n super({ adapterType: options.adapterType, adapterId: options.adapterId })\n\n if (options.sharedData) {\n this.#data = options.sharedData\n }\n }\n\n /**\n * Get the underlying storage map for sharing between instances\n */\n getStorage(): Map<string, Uint8Array> {\n return this.#data\n }\n\n async load(key: StorageKey): Promise<Uint8Array | undefined> {\n return this.#data.get(this.#keyToString(key))\n }\n\n async save(key: StorageKey, data: Uint8Array): Promise<void> {\n this.#data.set(this.#keyToString(key), data)\n }\n\n async remove(key: StorageKey): Promise<void> {\n this.#data.delete(this.#keyToString(key))\n }\n\n async loadRange(keyPrefix: StorageKey): Promise<Chunk[]> {\n const results: Chunk[] = []\n for (const [keyStr, data] of this.#data.entries()) {\n const key = this.#stringToKey(keyStr)\n if (this.#isPrefix(keyPrefix, key)) {\n results.push({ key, data })\n }\n }\n return results\n }\n\n async removeRange(keyPrefix: StorageKey): Promise<void> {\n for (const keyStr of this.#data.keys()) {\n const key = this.#stringToKey(keyStr)\n if (this.#isPrefix(keyPrefix, key)) {\n this.#data.delete(keyStr)\n }\n }\n }\n\n #isPrefix(prefix: StorageKey, key: StorageKey): boolean {\n if (prefix.length > key.length) {\n return false\n }\n return prefix.every((val, i) => val === key[i])\n }\n\n #keyToString(key: StorageKey): string {\n return JSON.stringify(key)\n }\n\n #stringToKey(key: string): StorageKey {\n return JSON.parse(key)\n }\n}\n","export const anyMap = new WeakMap();\nexport const eventsMap = new WeakMap();\nexport const producersMap = new WeakMap();\n","import {anyMap, producersMap, eventsMap} from './maps.js';\n\nconst anyProducer = Symbol('anyProducer');\nconst resolvedPromise = Promise.resolve();\n\n// Define symbols for \"meta\" events.\nconst listenerAdded = Symbol('listenerAdded');\nconst listenerRemoved = Symbol('listenerRemoved');\n\nlet canEmitMetaEvents = false;\nlet isGlobalDebugEnabled = false;\n\nconst isEventKeyType = key => typeof key === 'string' || typeof key === 'symbol' || typeof key === 'number';\n\nfunction assertEventName(eventName) {\n\tif (!isEventKeyType(eventName)) {\n\t\tthrow new TypeError('`eventName` must be a string, symbol, or number');\n\t}\n}\n\nfunction assertListener(listener) {\n\tif (typeof listener !== 'function') {\n\t\tthrow new TypeError('listener must be a function');\n\t}\n}\n\nfunction getListeners(instance, eventName) {\n\tconst events = eventsMap.get(instance);\n\tif (!events.has(eventName)) {\n\t\treturn;\n\t}\n\n\treturn events.get(eventName);\n}\n\nfunction getEventProducers(instance, eventName) {\n\tconst key = isEventKeyType(eventName) ? eventName : anyProducer;\n\tconst producers = producersMap.get(instance);\n\tif (!producers.has(key)) {\n\t\treturn;\n\t}\n\n\treturn producers.get(key);\n}\n\nfunction enqueueProducers(instance, eventName, eventData) {\n\tconst producers = producersMap.get(instance);\n\tif (producers.has(eventName)) {\n\t\tfor (const producer of producers.get(eventName)) {\n\t\t\tproducer.enqueue(eventData);\n\t\t}\n\t}\n\n\tif (producers.has(anyProducer)) {\n\t\tconst item = Promise.all([eventName, eventData]);\n\t\tfor (const producer of producers.get(anyProducer)) {\n\t\t\tproducer.enqueue(item);\n\t\t}\n\t}\n}\n\nfunction iterator(instance, eventNames) {\n\teventNames = Array.isArray(eventNames) ? eventNames : [eventNames];\n\n\tlet isFinished = false;\n\tlet flush = () => {};\n\tlet queue = [];\n\n\tconst producer = {\n\t\tenqueue(item) {\n\t\t\tqueue.push(item);\n\t\t\tflush();\n\t\t},\n\t\tfinish() {\n\t\t\tisFinished = true;\n\t\t\tflush();\n\t\t},\n\t};\n\n\tfor (const eventName of eventNames) {\n\t\tlet set = getEventProducers(instance, eventName);\n\t\tif (!set) {\n\t\t\tset = new Set();\n\t\t\tconst producers = producersMap.get(instance);\n\t\t\tproducers.set(eventName, set);\n\t\t}\n\n\t\tset.add(producer);\n\t}\n\n\treturn {\n\t\tasync next() {\n\t\t\tif (!queue) {\n\t\t\t\treturn {done: true};\n\t\t\t}\n\n\t\t\tif (queue.length === 0) {\n\t\t\t\tif (isFinished) {\n\t\t\t\t\tqueue = undefined;\n\t\t\t\t\treturn this.next();\n\t\t\t\t}\n\n\t\t\t\tawait new Promise(resolve => {\n\t\t\t\t\tflush = resolve;\n\t\t\t\t});\n\n\t\t\t\treturn this.next();\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tdone: false,\n\t\t\t\tvalue: await queue.shift(),\n\t\t\t};\n\t\t},\n\n\t\tasync return(value) {\n\t\t\tqueue = undefined;\n\n\t\t\tfor (const eventName of eventNames) {\n\t\t\t\tconst set = getEventProducers(instance, eventName);\n\t\t\t\tif (set) {\n\t\t\t\t\tset.delete(producer);\n\t\t\t\t\tif (set.size === 0) {\n\t\t\t\t\t\tconst producers = producersMap.get(instance);\n\t\t\t\t\t\tproducers.delete(eventName);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tflush();\n\n\t\t\treturn arguments.length > 0\n\t\t\t\t? {done: true, value: await value}\n\t\t\t\t: {done: true};\n\t\t},\n\n\t\t[Symbol.asyncIterator]() {\n\t\t\treturn this;\n\t\t},\n\t};\n}\n\nfunction defaultMethodNamesOrAssert(methodNames) {\n\tif (methodNames === undefined) {\n\t\treturn allEmitteryMethods;\n\t}\n\n\tif (!Array.isArray(methodNames)) {\n\t\tthrow new TypeError('`methodNames` must be an array of strings');\n\t}\n\n\tfor (const methodName of methodNames) {\n\t\tif (!allEmitteryMethods.includes(methodName)) {\n\t\t\tif (typeof methodName !== 'string') {\n\t\t\t\tthrow new TypeError('`methodNames` element must be a string');\n\t\t\t}\n\n\t\t\tthrow new Error(`${methodName} is not Emittery method`);\n\t\t}\n\t}\n\n\treturn methodNames;\n}\n\nconst isMetaEvent = eventName => eventName === listenerAdded || eventName === listenerRemoved;\n\nfunction emitMetaEvent(emitter, eventName, eventData) {\n\tif (!isMetaEvent(eventName)) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\tcanEmitMetaEvents = true;\n\t\temitter.emit(eventName, eventData);\n\t} finally {\n\t\tcanEmitMetaEvents = false;\n\t}\n}\n\nexport default class Emittery {\n\tstatic mixin(emitteryPropertyName, methodNames) {\n\t\tmethodNames = defaultMethodNamesOrAssert(methodNames);\n\t\treturn target => {\n\t\t\tif (typeof target !== 'function') {\n\t\t\t\tthrow new TypeError('`target` must be function');\n\t\t\t}\n\n\t\t\tfor (const methodName of methodNames) {\n\t\t\t\tif (target.prototype[methodName] !== undefined) {\n\t\t\t\t\tthrow new Error(`The property \\`${methodName}\\` already exists on \\`target\\``);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfunction getEmitteryProperty() {\n\t\t\t\tObject.defineProperty(this, emitteryPropertyName, {\n\t\t\t\t\tenumerable: false,\n\t\t\t\t\tvalue: new Emittery(),\n\t\t\t\t});\n\t\t\t\treturn this[emitteryPropertyName];\n\t\t\t}\n\n\t\t\tObject.defineProperty(target.prototype, emitteryPropertyName, {\n\t\t\t\tenumerable: false,\n\t\t\t\tget: getEmitteryProperty,\n\t\t\t});\n\n\t\t\tconst emitteryMethodCaller = methodName => function (...args) {\n\t\t\t\treturn this[emitteryPropertyName][methodName](...args);\n\t\t\t};\n\n\t\t\tfor (const methodName of methodNames) {\n\t\t\t\tObject.defineProperty(target.prototype, methodName, {\n\t\t\t\t\tenumerable: false,\n\t\t\t\t\tvalue: emitteryMethodCaller(methodName),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn target;\n\t\t};\n\t}\n\n\tstatic get isDebugEnabled() {\n\t\t// In a browser environment, `globalThis.process` can potentially reference a DOM Element with a `#process` ID,\n\t\t// so instead of just type checking `globalThis.process`, we need to make sure that `globalThis.process.env` exists.\n\t\t// eslint-disable-next-line n/prefer-global/process\n\t\tif (typeof globalThis.process?.env !== 'object') {\n\t\t\treturn isGlobalDebugEnabled;\n\t\t}\n\n\t\t// eslint-disable-next-line n/prefer-global/process\n\t\tconst {env} = globalThis.process ?? {env: {}};\n\t\treturn env.DEBUG === 'emittery' || env.DEBUG === '*' || isGlobalDebugEnabled;\n\t}\n\n\tstatic set isDebugEnabled(newValue) {\n\t\tisGlobalDebugEnabled = newValue;\n\t}\n\n\tconstructor(options = {}) {\n\t\tanyMap.set(this, new Set());\n\t\teventsMap.set(this, new Map());\n\t\tproducersMap.set(this, new Map());\n\n\t\tproducersMap.get(this).set(anyProducer, new Set());\n\n\t\tthis.debug = options.debug ?? {};\n\n\t\tif (this.debug.enabled === undefined) {\n\t\t\tthis.debug.enabled = false;\n\t\t}\n\n\t\tif (!this.debug.logger) {\n\t\t\tthis.debug.logger = (type, debugName, eventName, eventData) => {\n\t\t\t\ttry {\n\t\t\t\t\t// TODO: Use https://github.com/sindresorhus/safe-stringify when the package is more mature. Just copy-paste the code.\n\t\t\t\t\teventData = JSON.stringify(eventData);\n\t\t\t\t} catch {\n\t\t\t\t\teventData = `Object with the following keys failed to stringify: ${Object.keys(eventData).join(',')}`;\n\t\t\t\t}\n\n\t\t\t\tif (typeof eventName === 'symbol' || typeof eventName === 'number') {\n\t\t\t\t\teventName = eventName.toString();\n\t\t\t\t}\n\n\t\t\t\tconst currentTime = new Date();\n\t\t\t\tconst logTime = `${currentTime.getHours()}:${currentTime.getMinutes()}:${currentTime.getSeconds()}.${currentTime.getMilliseconds()}`;\n\t\t\t\tconsole.log(`[${logTime}][emittery:${type}][${debugName}] Event Name: ${eventName}\\n\\tdata: ${eventData}`);\n\t\t\t};\n\t\t}\n\t}\n\n\tlogIfDebugEnabled(type, eventName, eventData) {\n\t\tif (Emittery.isDebugEnabled || this.debug.enabled) {\n\t\t\tthis.debug.logger(type, this.debug.name, eventName, eventData);\n\t\t}\n\t}\n\n\ton(eventNames, listener, {signal} = {}) {\n\t\tassertListener(listener);\n\n\t\teventNames = Array.isArray(eventNames) ? eventNames : [eventNames];\n\t\tfor (const eventName of eventNames) {\n\t\t\tassertEventName(eventName);\n\t\t\tlet set = getListeners(this, eventName);\n\t\t\tif (!set) {\n\t\t\t\tset = new Set();\n\t\t\t\tconst events = eventsMap.get(this);\n\t\t\t\tevents.set(eventName, set);\n\t\t\t}\n\n\t\t\tset.add(listener);\n\n\t\t\tthis.logIfDebugEnabled('subscribe', eventName, undefined);\n\n\t\t\tif (!isMetaEvent(eventName)) {\n\t\t\t\temitMetaEvent(this, listenerAdded, {eventName, listener});\n\t\t\t}\n\t\t}\n\n\t\tconst off = () => {\n\t\t\tthis.off(eventNames, listener);\n\t\t\tsignal?.removeEventListener('abort', off);\n\t\t};\n\n\t\tsignal?.addEventListener('abort', off, {once: true});\n\n\t\tif (signal?.aborted) {\n\t\t\toff();\n\t\t}\n\n\t\treturn off;\n\t}\n\n\toff(eventNames, listener) {\n\t\tassertListener(listener);\n\n\t\teventNames = Array.isArray(eventNames) ? eventNames : [eventNames];\n\t\tfor (const eventName of eventNames) {\n\t\t\tassertEventName(eventName);\n\t\t\tconst set = getListeners(this, eventName);\n\t\t\tif (set) {\n\t\t\t\tset.delete(listener);\n\t\t\t\tif (set.size === 0) {\n\t\t\t\t\tconst events = eventsMap.get(this);\n\t\t\t\t\tevents.delete(eventName);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.logIfDebugEnabled('unsubscribe', eventName, undefined);\n\n\t\t\tif (!isMetaEvent(eventName)) {\n\t\t\t\temitMetaEvent(this, listenerRemoved, {eventName, listener});\n\t\t\t}\n\t\t}\n\t}\n\n\tonce(eventNames, predicate) {\n\t\tif (predicate !== undefined && typeof predicate !== 'function') {\n\t\t\tthrow new TypeError('predicate must be a function');\n\t\t}\n\n\t\tlet off_;\n\n\t\tconst promise = new Promise(resolve => {\n\t\t\toff_ = this.on(eventNames, data => {\n\t\t\t\tif (predicate && !predicate(data)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\toff_();\n\t\t\t\tresolve(data);\n\t\t\t});\n\t\t});\n\n\t\tpromise.off = off_;\n\t\treturn promise;\n\t}\n\n\tevents(eventNames) {\n\t\teventNames = Array.isArray(eventNames) ? eventNames : [eventNames];\n\t\tfor (const eventName of eventNames) {\n\t\t\tassertEventName(eventName);\n\t\t}\n\n\t\treturn iterator(this, eventNames);\n\t}\n\n\tasync emit(eventName, eventData) {\n\t\tassertEventName(eventName);\n\n\t\tif (isMetaEvent(eventName) && !canEmitMetaEvents) {\n\t\t\tthrow new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');\n\t\t}\n\n\t\tthis.logIfDebugEnabled('emit', eventName, eventData);\n\n\t\tenqueueProducers(this, eventName, eventData);\n\n\t\tconst listeners = getListeners(this, eventName) ?? new Set();\n\t\tconst anyListeners = anyMap.get(this);\n\t\tconst staticListeners = [...listeners];\n\t\tconst staticAnyListeners = isMetaEvent(eventName) ? [] : [...anyListeners];\n\n\t\tawait resolvedPromise;\n\t\tawait Promise.all([\n\t\t\t...staticListeners.map(async listener => {\n\t\t\t\tif (listeners.has(listener)) {\n\t\t\t\t\treturn listener(eventData);\n\t\t\t\t}\n\t\t\t}),\n\t\t\t...staticAnyListeners.map(async listener => {\n\t\t\t\tif (anyListeners.has(listener)) {\n\t\t\t\t\treturn listener(eventName, eventData);\n\t\t\t\t}\n\t\t\t}),\n\t\t]);\n\t}\n\n\tasync emitSerial(eventName, eventData) {\n\t\tassertEventName(eventName);\n\n\t\tif (isMetaEvent(eventName) && !canEmitMetaEvents) {\n\t\t\tthrow new TypeError('`eventName` cannot be meta event `listenerAdded` or `listenerRemoved`');\n\t\t}\n\n\t\tthis.logIfDebugEnabled('emitSerial', eventName, eventData);\n\n\t\tconst listeners = getListeners(this, eventName) ?? new Set();\n\t\tconst anyListeners = anyMap.get(this);\n\t\tconst staticListeners = [...listeners];\n\t\tconst staticAnyListeners = [...anyListeners];\n\n\t\tawait resolvedPromise;\n\t\t/* eslint-disable no-await-in-loop */\n\t\tfor (const listener of staticListeners) {\n\t\t\tif (listeners.has(listener)) {\n\t\t\t\tawait listener(eventData);\n\t\t\t}\n\t\t}\n\n\t\tfor (const listener of staticAnyListeners) {\n\t\t\tif (anyListeners.has(listener)) {\n\t\t\t\tawait listener(eventName, eventData);\n\t\t\t}\n\t\t}\n\t\t/* eslint-enable no-await-in-loop */\n\t}\n\n\tonAny(listener, {signal} = {}) {\n\t\tassertListener(listener);\n\n\t\tthis.logIfDebugEnabled('subscribeAny', undefined, undefined);\n\n\t\tanyMap.get(this).add(listener);\n\t\temitMetaEvent(this, listenerAdded, {listener});\n\n\t\tconst offAny = () => {\n\t\t\tthis.offAny(listener);\n\t\t\tsignal?.removeEventListener('abort', offAny);\n\t\t};\n\n\t\tsignal?.addEventListener('abort', offAny, {once: true});\n\n\t\tif (signal?.aborted) {\n\t\t\toffAny();\n\t\t}\n\n\t\treturn offAny;\n\t}\n\n\tanyEvent() {\n\t\treturn iterator(this);\n\t}\n\n\toffAny(listener) {\n\t\tassertListener(listener);\n\n\t\tthis.logIfDebugEnabled('unsubscribeAny', undefined, undefined);\n\n\t\temitMetaEvent(this, listenerRemoved, {listener});\n\t\tanyMap.get(this).delete(listener);\n\t}\n\n\tclearListeners(eventNames) {\n\t\teventNames = Array.isArray(eventNames) ? eventNames : [eventNames];\n\n\t\tfor (const eventName of eventNames) {\n\t\t\tthis.logIfDebugEnabled('clear', eventName, undefined);\n\n\t\t\tif (isEventKeyType(eventName)) {\n\t\t\t\tconst set = getListeners(this, eventName);\n\t\t\t\tif (set) {\n\t\t\t\t\tset.clear();\n\t\t\t\t}\n\n\t\t\t\tconst producers = getEventProducers(this, eventName);\n\t\t\t\tif (producers) {\n\t\t\t\t\tfor (const producer of producers) {\n\t\t\t\t\t\tproducer.finish();\n\t\t\t\t\t}\n\n\t\t\t\t\tproducers.clear();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tanyMap.get(this).clear();\n\n\t\t\t\tfor (const [eventName, listeners] of eventsMap.get(this).entries()) {\n\t\t\t\t\tlisteners.clear();\n\t\t\t\t\teventsMap.get(this).delete(eventName);\n\t\t\t\t}\n\n\t\t\t\tfor (const [eventName, producers] of producersMap.get(this).entries()) {\n\t\t\t\t\tfor (const producer of producers) {\n\t\t\t\t\t\tproducer.finish();\n\t\t\t\t\t}\n\n\t\t\t\t\tproducers.clear();\n\t\t\t\t\tproducersMap.get(this).delete(eventName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tlistenerCount(eventNames) {\n\t\teventNames = Array.isArray(eventNames) ? eventNames : [eventNames];\n\t\tlet count = 0;\n\n\t\tfor (const eventName of eventNames) {\n\t\t\tif (isEventKeyType(eventName)) {\n\t\t\t\tcount += anyMap.get(this).size\n\t\t\t\t\t+ (getListeners(this, eventName)?.size ?? 0)\n\t\t\t\t\t+ (getEventProducers(this, eventName)?.size ?? 0)\n\t\t\t\t\t+ (getEventProducers(this)?.size ?? 0);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (eventName !== undefined) {\n\t\t\t\tassertEventName(eventName);\n\t\t\t}\n\n\t\t\tcount += anyMap.get(this).size;\n\n\t\t\tfor (const value of eventsMap.get(this).values()) {\n\t\t\t\tcount += value.size;\n\t\t\t}\n\n\t\t\tfor (const value of producersMap.get(this).values()) {\n\t\t\t\tcount += value.size;\n\t\t\t}\n\t\t}\n\n\t\treturn count;\n\t}\n\n\tbindMethods(target, methodNames) {\n\t\tif (typeof target !== 'object' || target === null) {\n\t\t\tthrow new TypeError('`target` must be an object');\n\t\t}\n\n\t\tmethodNames = defaultMethodNamesOrAssert(methodNames);\n\n\t\tfor (const methodName of methodNames) {\n\t\t\tif (target[methodName] !== undefined) {\n\t\t\t\tthrow new Error(`The property \\`${methodName}\\` already exists on \\`target\\``);\n\t\t\t}\n\n\t\t\tObject.defineProperty(target, methodName, {\n\t\t\t\tenumerable: false,\n\t\t\t\tvalue: this[methodName].bind(this),\n\t\t\t});\n\t\t}\n\t}\n}\n\nconst allEmitteryMethods = Object.getOwnPropertyNames(Emittery.prototype).filter(v => v !== 'constructor');\n\nObject.defineProperty(Emittery, 'listenerAdded', {\n\tvalue: listenerAdded,\n\twritable: false,\n\tenumerable: true,\n\tconfigurable: false,\n});\nObject.defineProperty(Emittery, 'listenerRemoved', {\n\tvalue: listenerRemoved,\n\twritable: false,\n\tenumerable: true,\n\tconfigurable: false,\n});\n","import { dataTypes } from './constant';\n\nexport const enum DraftType {\n Object,\n Array,\n Map,\n Set,\n}\n\nexport const Operation = {\n Remove: 'remove',\n Replace: 'replace',\n Add: 'add',\n} as const;\n\nexport type DataType = keyof typeof dataTypes;\n\nexport type PatchesOptions =\n | boolean\n | {\n /**\n * The default value is `true`. If it's `true`, the path will be an array, otherwise it is a string.\n */\n pathAsArray?: boolean;\n /**\n * The default value is `true`. If it's `true`, the array length will be included in the patches, otherwise no include array length.\n */\n arrayLengthAssignment?: boolean;\n };\n\nexport interface Finalities {\n draft: ((patches?: Patches, inversePatches?: Patches) => void)[];\n revoke: (() => void)[];\n handledSet: WeakSet<any>;\n draftsCache: WeakSet<object>;\n}\n\nexport interface ProxyDraft<T = any> {\n type: DraftType;\n operated?: boolean;\n finalized: boolean;\n original: T;\n copy: T | null;\n proxy: T | null;\n finalities: Finalities;\n options: Options<any, any> & { updatedValues?: WeakMap<any, any> };\n parent?: ProxyDraft | null;\n key?: string | number | symbol;\n setMap?: Map<any, ProxyDraft>;\n assignedMap?: Map<any, boolean>;\n callbacks?: ((patches?: Patches, inversePatches?: Patches) => void)[];\n}\n\nexport interface IPatch {\n op: (typeof Operation)[keyof typeof Operation];\n value?: any;\n}\n\nexport type Patch<P extends PatchesOptions = any> = P extends {\n pathAsArray: false;\n}\n ? IPatch & {\n path: string;\n }\n : P extends true | object\n ? IPatch & {\n path: (string | number)[];\n }\n : IPatch & {\n path: string | (string | number)[];\n };\n\nexport type Patches<P extends PatchesOptions = any> = Patch<P>[];\n\nexport type Result<\n T extends any,\n O extends PatchesOptions,\n F extends boolean,\n> = O extends true | object\n ? [F extends true ? Immutable<T> : T, Patches<O>, Patches<O>]\n : F extends true\n ? Immutable<T>\n : T;\n\nexport type CreateResult<\n T extends any,\n O extends PatchesOptions,\n F extends boolean,\n R extends void | Promise<void> | T | Promise<T>,\n> = R extends Promise<void> | Promise<T>\n ? Promise<Result<T, O, F>>\n : Result<T, O, F>;\n\ntype BaseMark = null | undefined | DataType;\ntype MarkWithCopy = BaseMark | (() => any);\n\nexport type Mark<O extends PatchesOptions, F extends boolean> = (\n target: any,\n types: typeof dataTypes\n) => O extends true | object\n ? BaseMark\n : F extends true\n ? BaseMark\n : MarkWithCopy;\n\nexport interface ApplyMutableOptions {\n /**\n * If it's `true`, the state will be mutated directly.\n */\n mutable?: boolean;\n}\n\nexport interface Options<O extends PatchesOptions, F extends boolean> {\n /**\n * In strict mode, Forbid accessing non-draftable values and forbid returning a non-draft value.\n */\n strict?: boolean;\n /**\n * Enable patch, and return the patches and inversePatches.\n */\n enablePatches?: O;\n /**\n * Enable autoFreeze, and return frozen state.\n */\n enableAutoFreeze?: F;\n /**\n * Set a mark to determine if the object is mutable or if an instance is an immutable.\n * And it can also return a shallow copy function(AutoFreeze and Patches should both be disabled).\n */\n mark?: Mark<O, F>;\n}\n\nexport interface ExternalOptions<O extends PatchesOptions, F extends boolean> {\n /**\n * In strict mode, Forbid accessing non-draftable values and forbid returning a non-draft value.\n */\n strict?: boolean;\n /**\n * Enable patch, and return the patches and inversePatches.\n */\n enablePatches?: O;\n /**\n * Enable autoFreeze, and return frozen state.\n */\n enableAutoFreeze?: F;\n /**\n * Set a mark to determine if the object is mutable or if an instance is an immutable.\n * And it can also return a shallow copy function(AutoFreeze and Patches should both be disabled).\n */\n mark?: Mark<O, F>[] | Mark<O, F>;\n}\n\n// Exclude `symbol`\ntype Primitive = string | number | bigint | boolean | null | undefined;\n\ntype ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;\ntype ImmutableSet<T> = ReadonlySet<Immutable<T>>;\ntype ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]> };\n\nexport type IfAvailable<T, Fallback = void> = true | false extends (\n T extends never ? true : false\n)\n ? Fallback\n : keyof T extends never\n ? Fallback\n : T;\ntype WeakReferences =\n | IfAvailable<WeakMap<any, any>>\n | IfAvailable<WeakSet<any>>;\ntype AtomicObject = Function | Promise<any> | Date | RegExp;\n\nexport type Immutable<T> = T extends Primitive | AtomicObject\n ? T\n : T extends IfAvailable<ReadonlyMap<infer K, infer V>>\n ? ImmutableMap<K, V>\n : T extends IfAvailable<ReadonlySet<infer V>>\n ? ImmutableSet<V>\n : T extends WeakReferences\n ? T\n : T extends object\n ? ImmutableObject<T>\n : T;\n\ntype DraftedMap<K, V> = Map<K, Draft<V>>;\ntype DraftedSet<T> = Set<Draft<T>>;\nexport type DraftedObject<T> = {\n -readonly [K in keyof T]: Draft<T[K]>;\n};\n\nexport type Draft<T> = T extends Primitive | AtomicObject\n ? T\n : T extends IfAvailable<ReadonlyMap<infer K, infer V>>\n ? DraftedMap<K, V>\n : T extends IfAvailable<ReadonlySet<infer V>>\n ? DraftedSet<V>\n : T extends WeakReferences\n ? T\n : T extends object\n ? DraftedObject<T>\n : T;\n\nexport type ApplyOptions<F extends boolean> =\n | Pick<\n Options<boolean, F>,\n Exclude<keyof Options<boolean, F>, 'enablePatches'>\n >\n | ApplyMutableOptions;\n\nexport type ApplyResult<\n T extends object,\n F extends boolean = false,\n A extends ApplyOptions<F> = ApplyOptions<F>,\n> = A extends { mutable: true } ? void : T;\n","// Don't use `Symbol()` just for 3rd party access the draft\nexport const PROXY_DRAFT = Symbol.for('__MUTATIVE_PROXY_DRAFT__');\nexport const RAW_RETURN_SYMBOL = Symbol('__MUTATIVE_RAW_RETURN_SYMBOL__');\n\nexport const iteratorSymbol: typeof Symbol.iterator = Symbol.iterator;\n\nexport const dataTypes = {\n mutable: 'mutable',\n immutable: 'immutable',\n} as const;\n","import { createDraft } from './draft';\n\nexport const internal = {} as {\n createDraft: typeof createDraft;\n};\n","export function has(target: object, key: PropertyKey) {\n return target instanceof Map\n ? target.has(key)\n : Object.prototype.hasOwnProperty.call(target, key);\n}\n\nexport function getDescriptor(target: object, key: PropertyKey) {\n if (key in target) {\n let prototype = Reflect.getPrototypeOf(target);\n while (prototype) {\n const descriptor = Reflect.getOwnPropertyDescriptor(prototype, key);\n if (descriptor) return descriptor;\n prototype = Reflect.getPrototypeOf(prototype);\n }\n }\n return;\n}\n\nexport function isBaseSetInstance(obj: any) {\n return Object.getPrototypeOf(obj) === Set.prototype;\n}\n\nexport function isBaseMapInstance(obj: any) {\n return Object.getPrototypeOf(obj) === Map.prototype;\n}\n","import { DraftType, Mark, ProxyDraft } from '../interface';\nimport { dataTypes, PROXY_DRAFT } from '../constant';\nimport { has } from './proto';\n\nexport function latest<T = any>(proxyDraft: ProxyDraft): T {\n return proxyDraft.copy ?? proxyDraft.original;\n}\n\n/**\n * Check if the value is a draft\n */\nexport function isDraft(target: any) {\n return !!getProxyDraft(target);\n}\n\nexport function getProxyDraft<T extends any>(value: T): ProxyDraft | null {\n if (typeof value !== 'object') return null;\n return (value as { [PROXY_DRAFT]: any })?.[PROXY_DRAFT];\n}\n\nexport function getValue<T extends object>(value: T): T {\n const proxyDraft = getProxyDraft(value);\n return proxyDraft ? (proxyDraft.copy ?? proxyDraft.original) : value;\n}\n\n/**\n * Check if a value is draftable\n */\nexport function isDraftable(value: any, options?: { mark?: Mark<any, any> }) {\n if (!value || typeof value !== 'object') return false;\n let markResult: any;\n return (\n Object.getPrototypeOf(value) === Object.prototype ||\n Array.isArray(value) ||\n value instanceof Map ||\n value instanceof Set ||\n (!!options?.mark &&\n ((markResult = options.mark(value, dataTypes)) === dataTypes.immutable ||\n typeof markResult === 'function'))\n );\n}\n\nexport function getPath(\n target: ProxyDraft,\n path: any[] = []\n): (string | number | object)[] | null {\n if (Object.hasOwnProperty.call(target, 'key')) {\n // check if the parent is a draft and the original value is not equal to the current value\n const parentCopy = target.parent!.copy;\n const proxyDraft = getProxyDraft(get(parentCopy, target.key!));\n if (proxyDraft !== null && proxyDraft?.original !== target.original) {\n return null;\n }\n const isSet = target.parent!.type === DraftType.Set;\n const key = isSet\n ? Array.from(target.parent!.setMap!.keys()).indexOf(target.key)\n : target.key;\n // check if the key is still in the next state parent\n if (\n !((isSet && parentCopy.size > (key as number)) || has(parentCopy, key!))\n )\n return null;\n path.push(key);\n }\n if (target.parent) {\n return getPath(target.parent, path);\n }\n // `target` is root draft.\n path.reverse();\n try {\n // check if the path is valid\n resolvePath(target.copy, path);\n } catch (e) {\n return null;\n }\n return path;\n}\n\nexport function getType(target: any) {\n if (Array.isArray(target)) return DraftType.Array;\n if (target instanceof Map) return DraftType.Map;\n if (target instanceof Set) return DraftType.Set;\n return DraftType.Object;\n}\n\nexport function get(target: any, key: PropertyKey) {\n return getType(target) === DraftType.Map ? target.get(key) : target[key];\n}\n\nexport function set(target: any, key: PropertyKey, value: any) {\n const type = getType(target);\n if (type === DraftType.Map) {\n target.set(key, value);\n } else {\n target[key] = value;\n }\n}\n\nexport function peek(target: any, key: PropertyKey) {\n const state = getProxyDraft(target);\n const source = state ? latest(state) : target;\n return source[key];\n}\n\nexport function isEqual(x: any, y: any) {\n if (x === y) {\n return x !== 0 || 1 / x === 1 / y;\n } else {\n return x !== x && y !== y;\n }\n}\n\nexport function revokeProxy(proxyDraft: ProxyDraft | null) {\n if (!proxyDraft) return;\n while (proxyDraft.finalities.revoke.length > 0) {\n const revoke = proxyDraft.finalities.revoke.pop()!;\n revoke();\n }\n}\n\n// handle JSON Pointer path with spec https://www.rfc-editor.org/rfc/rfc6901\nexport function escapePath(path: string[], pathAsArray: boolean) {\n return pathAsArray\n ? path\n : ['']\n .concat(path)\n .map((_item) => {\n const item = `${_item}`;\n if (item.indexOf('/') === -1 && item.indexOf('~') === -1) return item;\n return item.replace(/~/g, '~0').replace(/\\//g, '~1');\n })\n .join('/');\n}\n\nexport function unescapePath(path: string | (string | number)[]) {\n if (Array.isArray(path)) return path;\n return path\n .split('/')\n .map((_item) => _item.replace(/~1/g, '/').replace(/~0/g, '~'))\n .slice(1);\n}\n\nexport function resolvePath(base: any, path: (string | number)[]) {\n for (let index = 0; index < path.length - 1; index += 1) {\n const key = path[index];\n // use `index` in Set draft\n base = get(getType(base) === DraftType.Set ? Array.from(base) : base, key);\n if (typeof base !== 'object') {\n throw new Error(`Cannot resolve patch at '${path.join('/')}'.`);\n }\n }\n return base;\n}\n","import type { Options, ProxyDraft } from '../interface';\nimport { dataTypes } from '../constant';\nimport { getValue, isDraft, isDraftable } from './draft';\nimport { isBaseMapInstance, isBaseSetInstance } from './proto';\n\nfunction strictCopy(target: any) {\n const copy = Object.create(Object.getPrototypeOf(target));\n Reflect.ownKeys(target).forEach((key: any) => {\n let desc = Reflect.getOwnPropertyDescriptor(target, key)!;\n if (desc.enumerable && desc.configurable && desc.writable) {\n copy[key] = target[key];\n return;\n }\n // for freeze\n if (!desc.writable) {\n desc.writable = true;\n desc.configurable = true;\n }\n if (desc.get || desc.set)\n desc = {\n configurable: true,\n writable: true,\n enumerable: desc.enumerable,\n value: target[key],\n };\n Reflect.defineProperty(copy, key, desc);\n });\n return copy;\n}\n\nconst propIsEnum = Object.prototype.propertyIsEnumerable;\n\nexport function shallowCopy(original: any, options?: Options<any, any>) {\n let markResult: any;\n if (Array.isArray(original)) {\n return Array.prototype.concat.call(original);\n } else if (original instanceof Set) {\n if (!isBaseSetInstance(original)) {\n const SubClass = Object.getPrototypeOf(original).constructor;\n return new SubClass(original.values());\n }\n return Set.prototype.difference\n ? Set.prototype.difference.call(original, new Set())\n : new Set(original.values());\n } else if (original instanceof Map) {\n if (!isBaseMapInstance(original)) {\n const SubClass = Object.getPrototypeOf(original).constructor;\n return new SubClass(original);\n }\n return new Map(original);\n } else if (\n options?.mark &&\n ((markResult = options.mark(original, dataTypes)),\n markResult !== undefined) &&\n markResult !== dataTypes.mutable\n ) {\n if (markResult === dataTypes.immutable) {\n return strictCopy(original);\n } else if (typeof markResult === 'function') {\n if (__DEV__ && (options.enablePatches || options.enableAutoFreeze)) {\n throw new Error(\n `You can't use mark and patches or auto freeze together.`\n );\n }\n return markResult();\n }\n throw new Error(`Unsupported mark result: ${markResult}`);\n } else if (\n typeof original === 'object' &&\n Object.getPrototypeOf(original) === Object.prototype\n ) {\n // For best performance with shallow copies,\n // don't use `Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));` by default.\n const copy: Record<string | symbol, any> = {};\n Object.keys(original).forEach((key) => {\n copy[key] = original[key];\n });\n Object.getOwnPropertySymbols(original).forEach((key) => {\n if (propIsEnum.call(original, key)) {\n copy[key] = original[key];\n }\n });\n return copy;\n } else {\n throw new Error(\n `Please check mark() to ensure that it is a stable marker draftable function.`\n );\n }\n}\n\nexport function ensureShallowCopy(target: ProxyDraft) {\n if (target.copy) return;\n target.copy = shallowCopy(target.original, target.options)!;\n}\n\nfunction deepClone<T>(target: T): T;\nfunction deepClone(target: any) {\n if (!isDraftable(target)) return getValue(target);\n if (Array.isArray(target)) return target.map(deepClone);\n if (target instanceof Map) {\n const iterable = Array.from(target.entries()).map(([k, v]) => [\n k,\n deepClone(v),\n ]) as Iterable<readonly [any, any]>;\n if (!isBaseMapInstance(target)) {\n const SubClass = Object.getPrototypeOf(target).constructor;\n return new SubClass(iterable);\n }\n return new Map(iterable);\n }\n if (target instanceof Set) {\n const iterable = Array.from(target).map(deepClone);\n if (!isBaseSetInstance(target)) {\n const SubClass = Object.getPrototypeOf(target).constructor;\n return new SubClass(iterable);\n }\n return new Set(iterable);\n }\n const copy = Object.create(Object.getPrototypeOf(target));\n for (const key in target) copy[key] = deepClone(target[key]);\n return copy;\n}\n\nexport function cloneIfNeeded<T>(target: T): T {\n return isDraft(target) ? deepClone(target) : target;\n}\n\nexport { deepClone };\n","import { ProxyDraft } from '../interface';\n\nexport function markChanged(proxyDraft: ProxyDraft) {\n proxyDraft.assignedMap = proxyDraft.assignedMap ?? new Map();\n if (!proxyDraft.operated) {\n proxyDraft.operated = true;\n if (proxyDraft.parent) {\n markChanged(proxyDraft.parent);\n }\n }\n}\n","import { DraftType } from '../interface';\nimport { getType, isDraft } from './draft';\n\nfunction throwFrozenError() {\n throw new Error('Cannot modify frozen object');\n}\n\nfunction isFreezable(value: any) {\n return (\n __DEV__ || (value && typeof value === 'object' && !Object.isFrozen(value))\n );\n}\n\nexport function deepFreeze(\n target: any,\n subKey?: any,\n updatedValues?: WeakMap<any, any>,\n stack?: any[],\n keys?: any[]\n) {\n if (__DEV__) {\n updatedValues = updatedValues ?? new WeakMap();\n stack = stack ?? [];\n keys = keys ?? [];\n const value = updatedValues.has(target)\n ? updatedValues.get(target)\n : target;\n if (stack.length > 0) {\n const index = stack.indexOf(value);\n if (value && typeof value === 'object' && index !== -1) {\n if (stack[0] === value) {\n throw new Error(`Forbids circular reference`);\n }\n throw new Error(\n `Forbids circular reference: ~/${keys\n .slice(0, index)\n .map((key, index) => {\n if (typeof key === 'symbol') return `[${key.toString()}]`;\n const parent = stack![index];\n if (\n typeof key === 'object' &&\n (parent instanceof Map || parent instanceof Set)\n )\n return Array.from(parent.keys()).indexOf(key);\n return key;\n })\n .join('/')}`\n );\n }\n stack.push(value);\n keys.push(subKey);\n } else {\n stack.push(value);\n }\n }\n if (Object.isFrozen(target) || isDraft(target)) {\n if (__DEV__) {\n stack!.pop();\n keys!.pop();\n }\n return;\n }\n const type = getType(target);\n switch (type) {\n case DraftType.Map:\n for (const [key, value] of target) {\n if (isFreezable(key)) deepFreeze(key, key, updatedValues, stack, keys);\n if (isFreezable(value))\n deepFreeze(value, key, updatedValues, stack, keys);\n }\n target.set = target.clear = target.delete = throwFrozenError;\n break;\n case DraftType.Set:\n for (const value of target) {\n if (isFreezable(value))\n deepFreeze(value, value, updatedValues, stack, keys);\n }\n target.add = target.clear = target.delete = throwFrozenError;\n break;\n case DraftType.Array:\n Object.freeze(target);\n let index = 0;\n for (const value of target) {\n if (isFreezable(value))\n deepFreeze(value, index, updatedValues, stack, keys);\n index += 1;\n }\n break;\n default:\n Object.freeze(target);\n // ignore non-enumerable or symbol properties\n Object.keys(target).forEach((name) => {\n const value = target[name];\n if (isFreezable(value))\n deepFreeze(value, name, updatedValues, stack, keys);\n });\n }\n if (__DEV__) {\n stack!.pop();\n keys!.pop();\n }\n}\n","import { DraftType } from '../interface';\nimport { getType } from './draft';\n\nexport function forEach<T extends object>(\n target: T,\n iter: (key: string | number | symbol, value: any, source: T) => void\n) {\n const type = getType(target);\n if (type === DraftType.Object) {\n Reflect.ownKeys(target).forEach((key) => {\n iter(key, (target as any)[key], target);\n });\n } else if (type === DraftType.Array) {\n let index = 0;\n for (const entry of target as any[]) {\n iter(index, entry, target);\n index += 1;\n }\n } else {\n (target as Map<any, any> | Set<any>).forEach((entry: any, index: any) =>\n iter(index, entry, target)\n );\n }\n}\n","import { DraftType, Patches, ProxyDraft } from '../interface';\nimport { ensureShallowCopy } from './copy';\nimport {\n get,\n getPath,\n getProxyDraft,\n getValue,\n isDraft,\n isDraftable,\n isEqual,\n set,\n} from './draft';\nimport { forEach } from './forEach';\n\nexport function handleValue(\n target: any,\n handledSet: WeakSet<any>,\n options?: ProxyDraft['options']\n) {\n if (\n isDraft(target) ||\n !isDraftable(target, options) ||\n handledSet.has(target) ||\n Object.isFrozen(target)\n )\n return;\n const isSet = target instanceof Set;\n const setMap: Map<any, any> | undefined = isSet ? new Map() : undefined;\n handledSet.add(target);\n forEach(target, (key, value) => {\n if (isDraft(value)) {\n const proxyDraft = getProxyDraft(value)!;\n ensureShallowCopy(proxyDraft);\n // A draft where a child node has been changed, or assigned a value\n const updatedValue =\n proxyDraft.assignedMap?.size || proxyDraft.operated\n ? proxyDraft.copy\n : proxyDraft.original;\n // final update value\n set(isSet ? setMap! : target, key, updatedValue);\n } else {\n handleValue(value, handledSet, options);\n }\n });\n if (setMap) {\n const set = target as Set<any>;\n const values = Array.from(set);\n set.clear();\n values.forEach((value) => {\n set.add(setMap!.has(value) ? setMap!.get(value) : value);\n });\n }\n}\n\nexport function finalizeAssigned(proxyDraft: ProxyDraft, key: PropertyKey) {\n // handle the draftable assigned values, and the value is not a draft\n const copy =\n proxyDraft.type === DraftType.Set ? proxyDraft.setMap : proxyDraft.copy;\n if (\n proxyDraft.finalities.revoke.length > 1 &&\n proxyDraft.assignedMap!.get(key) &&\n copy\n ) {\n handleValue(\n get(copy, key),\n proxyDraft.finalities.handledSet,\n proxyDraft.options\n );\n }\n}\n\nexport type GeneratePatches = (\n proxyState: ProxyDraft,\n basePath: any[],\n patches: Patches,\n inversePatches: Patches\n) => void;\n\nexport function finalizeSetValue(target: ProxyDraft) {\n if (target.type === DraftType.Set && target.copy) {\n target.copy.clear();\n target.setMap!.forEach((value) => {\n target.copy!.add(getValue(value));\n });\n }\n}\n\nexport function finalizePatches(\n target: ProxyDraft,\n generatePatches: GeneratePatches,\n patches?: Patches,\n inversePatches?: Patches\n) {\n const shouldFinalize =\n target.operated &&\n target.assignedMap &&\n target.assignedMap.size > 0 &&\n !target.finalized;\n if (shouldFinalize) {\n if (patches && inversePatches) {\n const basePath = getPath(target);\n if (basePath) {\n generatePatches(target, basePath, patches, inversePatches);\n }\n }\n target.finalized = true;\n }\n}\n\nexport function markFinalization(\n target: ProxyDraft,\n key: any,\n value: any,\n generatePatches: GeneratePatches\n) {\n const proxyDraft = getProxyDraft(value);\n if (proxyDraft) {\n // !case: assign the draft value\n if (!proxyDraft.callbacks) {\n proxyDraft.callbacks = [];\n }\n proxyDraft.callbacks.push((patches, inversePatches) => {\n const copy = target.type === DraftType.Set ? target.setMap : target.copy;\n if (isEqual(get(copy, key), value)) {\n let updatedValue = proxyDraft.original;\n if (proxyDraft.copy) {\n updatedValue = proxyDraft.copy;\n }\n finalizeSetValue(target);\n finalizePatches(target, generatePatches, patches, inversePatches);\n if (__DEV__ && target.options.enableAutoFreeze) {\n target.options.updatedValues =\n target.options.updatedValues ?? new WeakMap();\n target.options.updatedValues.set(updatedValue, proxyDraft.original);\n }\n // final update value\n set(copy, key, updatedValue);\n }\n });\n if (target.options.enableAutoFreeze) {\n // !case: assign the draft value in cross draft tree\n if (proxyDraft.finalities !== target.finalities) {\n target.options.enableAutoFreeze = false;\n }\n }\n }\n if (isDraftable(value, target.options)) {\n // !case: assign the non-draft value\n target.finalities.draft.push(() => {\n const copy = target.type === DraftType.Set ? target.setMap : target.copy;\n if (isEqual(get(copy, key), value)) {\n finalizeAssigned(target, key);\n }\n });\n }\n}\n","import { DraftType, Operation, Patches, ProxyDraft } from './interface';\nimport { cloneIfNeeded, escapePath, get, has, isEqual } from './utils';\n\nfunction generateArrayPatches(\n proxyState: ProxyDraft<Array<any>>,\n basePath: any[],\n patches: Patches,\n inversePatches: Patches,\n pathAsArray: boolean\n) {\n let { original, assignedMap, options } = proxyState;\n let copy = proxyState.copy!;\n if (copy.length < original.length) {\n [original, copy] = [copy, original];\n [patches, inversePatches] = [inversePatches, patches];\n }\n for (let index = 0; index < original.length; index += 1) {\n if (assignedMap!.get(index.toString()) && copy[index] !== original[index]) {\n const _path = basePath.concat([index]);\n const path = escapePath(_path, pathAsArray);\n patches.push({\n op: Operation.Replace,\n path,\n // If it is a draft, it needs to be deep cloned, and it may also be non-draft.\n value: cloneIfNeeded(copy[index]),\n });\n inversePatches.push({\n op: Operation.Replace,\n path,\n // If it is a draft, it needs to be deep cloned, and it may also be non-draft.\n value: cloneIfNeeded(original[index]),\n });\n }\n }\n for (let index = original.length; index < copy.length; index += 1) {\n const _path = basePath.concat([index]);\n const path = escapePath(_path, pathAsArray);\n patches.push({\n op: Operation.Add,\n path,\n // If it is a draft, it needs to be deep cloned, and it may also be non-draft.\n value: cloneIfNeeded(copy[index]),\n });\n }\n if (original.length < copy.length) {\n // https://www.rfc-editor.org/rfc/rfc6902#appendix-A.4\n // For performance, here we only generate an operation that replaces the length of the array,\n // which is inconsistent with JSON Patch specification\n const { arrayLengthAssignment = true } = options.enablePatches;\n if (arrayLengthAssignment) {\n const _path = basePath.concat(['length']);\n const path = escapePath(_path, pathAsArray);\n inversePatches.push({\n op: Operation.Replace,\n path,\n value: original.length,\n });\n } else {\n for (let index = copy.length; original.length < index; index -= 1) {\n const _path = basePath.concat([index - 1]);\n const path = escapePath(_path, pathAsArray);\n inversePatches.push({\n op: Operation.Remove,\n path,\n });\n }\n }\n }\n}\n\nfunction generatePatchesFromAssigned(\n { original, copy, assignedMap }: ProxyDraft<Record<string, any>>,\n basePath: any[],\n patches: Patches,\n inversePatches: Patches,\n pathAsArray: boolean\n) {\n assignedMap!.forEach((assignedValue, key) => {\n const originalValue = get(original, key);\n const value = cloneIfNeeded(get(copy, key));\n const op = !assignedValue\n ? Operation.Remove\n : has(original, key)\n ? Operation.Replace\n : Operation.Add;\n if (isEqual(originalValue, value) && op === Operation.Replace) return;\n const _path = basePath.concat(key);\n const path = escapePath(_path, pathAsArray);\n patches.push(op === Operation.Remove ? { op, path } : { op, path, value });\n inversePatches.push(\n op === Operation.Add\n ? { op: Operation.Remove, path }\n : op === Operation.Remove\n ? { op: Operation.Add, path, value: originalValue }\n : { op: Operation.Replace, path, value: originalValue }\n );\n });\n}\n\nfunction generateSetPatches(\n { original, copy }: ProxyDraft<Set<any>>,\n basePath: any[],\n patches: Patches,\n inversePatches: Patches,\n pathAsArray: boolean\n) {\n let index = 0;\n original.forEach((value: any) => {\n if (!copy!.has(value)) {\n const _path = basePath.concat([index]);\n const path = escapePath(_path, pathAsArray);\n patches.push({\n op: Operation.Remove,\n path,\n value,\n });\n inversePatches.unshift({\n op: Operation.Add,\n path,\n value,\n });\n }\n index += 1;\n });\n index = 0;\n copy!.forEach((value: any) => {\n if (!original.has(value)) {\n const _path = basePath.concat([index]);\n const path = escapePath(_path, pathAsArray);\n patches.push({\n op: Operation.Add,\n path,\n value,\n });\n inversePatches.unshift({\n op: Operation.Remove,\n path,\n value,\n });\n }\n index += 1;\n });\n}\n\nexport function generatePatches(\n proxyState: ProxyDraft,\n basePath: any[],\n patches: Patches,\n inversePatches: Patches\n) {\n const { pathAsArray = true } = proxyState.options.enablePatches;\n switch (proxyState.type) {\n case DraftType.Object:\n case DraftType.Map:\n return generatePatchesFromAssigned(\n proxyState,\n basePath,\n patches,\n inversePatches,\n pathAsArray\n );\n case DraftType.Array:\n return generateArrayPatches(\n proxyState,\n basePath,\n patches,\n inversePatches,\n pathAsArray\n );\n case DraftType.Set:\n return generateSetPatches(\n proxyState,\n basePath,\n patches,\n inversePatches,\n pathAsArray\n );\n }\n}\n","import { Options } from './interface';\nimport { isDraftable } from './utils';\n\nlet readable = false;\n\nexport const checkReadable = (\n value: any,\n options: Options<any, any>,\n ignoreCheckDraftable = false\n) => {\n if (\n typeof value === 'object' &&\n value !== null &&\n (!isDraftable(value, options) || ignoreCheckDraftable) &&\n !readable\n ) {\n throw new Error(\n `Strict mode: Mutable data cannot be accessed directly, please use 'unsafe(callback)' wrap.`\n );\n }\n};\n\n/**\n * `unsafe(callback)` to access mutable data directly in strict mode.\n *\n * ## Example\n *\n * ```ts\n * import { create, unsafe } from '../index';\n *\n * class Foobar {\n * bar = 1;\n * }\n *\n * const baseState = { foobar: new Foobar() };\n * const state = create(\n * baseState,\n * (draft) => {\n * unsafe(() => {\n * draft.foobar.bar = 2;\n * });\n * },\n * {\n * strict: true,\n * }\n * );\n *\n * expect(state).toBe(baseState);\n * expect(state.foobar).toBe(baseState.foobar);\n * expect(state.foobar.bar).toBe(2);\n * ```\n */\nexport function unsafe<T>(callback: () => T): T {\n readable = true;\n let result: T;\n try {\n result = callback();\n } finally {\n readable = false;\n }\n return result;\n}\n","import { dataTypes, iteratorSymbol } from './constant';\nimport { internal } from './internal';\nimport { generatePatches } from './patch';\nimport { checkReadable } from './unsafe';\nimport {\n ensureShallowCopy,\n getProxyDraft,\n isDraftable,\n isEqual,\n latest,\n markChanged,\n markFinalization,\n} from './utils';\n\nexport const mapHandler = {\n get size() {\n const current: Map<any, any> = latest(getProxyDraft(this)!);\n return current.size;\n },\n has(key: any): boolean {\n return latest(getProxyDraft(this)!).has(key);\n },\n set(key: any, value: any) {\n const target = getProxyDraft(this)!;\n const source = latest(target);\n if (!source.has(key) || !isEqual(source.get(key), value)) {\n ensureShallowCopy(target);\n markChanged(target);\n target.assignedMap!.set(key, true);\n target.copy.set(key, value);\n markFinalization(target, key, value, generatePatches);\n }\n return this;\n },\n delete(key: any): boolean {\n if (!this.has(key)) {\n return false;\n }\n const target = getProxyDraft(this)!;\n ensureShallowCopy(target);\n markChanged(target);\n if (target.original.has(key)) {\n target.assignedMap!.set(key, false);\n } else {\n target.assignedMap!.delete(key);\n }\n target.copy.delete(key);\n return true;\n },\n clear() {\n const target = getProxyDraft(this)!;\n if (!this.size) return;\n ensureShallowCopy(target);\n markChanged(target);\n target.assignedMap = new Map();\n for (const [key] of target.original) {\n target.assignedMap.set(key, false);\n }\n target.copy!.clear();\n },\n forEach(callback: (value: any, key: any, self: any) => void, thisArg?: any) {\n const target = getProxyDraft(this)!;\n latest(target).forEach((_value: any, _key: any) => {\n callback.call(thisArg, this.get(_key), _key, this);\n });\n },\n get(key: any): any {\n const target = getProxyDraft(this)!;\n const value = latest(target).get(key);\n const mutable =\n target.options.mark?.(value, dataTypes) === dataTypes.mutable;\n if (target.options.strict) {\n checkReadable(value, target.options, mutable);\n }\n if (mutable) {\n return value;\n }\n if (target.finalized || !isDraftable(value, target.options)) {\n return value;\n }\n // drafted or reassigned\n if (value !== target.original.get(key)) {\n return value;\n }\n const draft = internal.createDraft({\n original: value,\n parentDraft: target,\n key,\n finalities: target.finalities,\n options: target.options,\n });\n ensureShallowCopy(target);\n target.copy.set(key, draft);\n return draft;\n },\n keys(): IterableIterator<any> {\n return latest(getProxyDraft(this)!).keys();\n },\n values(): IterableIterator<any> {\n const iterator = this.keys();\n return {\n [iteratorSymbol]: () => this.values(),\n next: () => {\n const result = iterator.next();\n if (result.done) return result;\n const value = this.get(result.value);\n return {\n done: false,\n value,\n };\n },\n } as any;\n },\n entries(): IterableIterator<[any, any]> {\n const iterator = this.keys();\n return {\n [iteratorSymbol]: () => this.entries(),\n next: () => {\n const result = iterator.next();\n if (result.done) return result;\n const value = this.get(result.value);\n return {\n done: false,\n value: [result.value, value],\n };\n },\n } as any;\n },\n [iteratorSymbol]() {\n return this.entries();\n },\n};\n\nexport const mapHandlerKeys = Reflect.ownKeys(mapHandler);\n","import { ProxyDraft } from './interface';\nimport { dataTypes, iteratorSymbol } from './constant';\nimport { internal } from './internal';\nimport {\n ensureShallowCopy,\n getProxyDraft,\n isDraftable,\n markChanged,\n markFinalization,\n} from './utils';\nimport { checkReadable } from './unsafe';\nimport { generatePatches } from './patch';\n\nconst getNextIterator =\n (\n target: ProxyDraft<any>,\n iterator: IterableIterator<any>,\n { isValuesIterator }: { isValuesIterator: boolean }\n ) =>\n () => {\n const result = iterator.next();\n if (result.done) return result;\n const key = result.value as any;\n let value = target.setMap!.get(key);\n const currentDraft = getProxyDraft(value);\n const mutable =\n target.options.mark?.(value, dataTypes) === dataTypes.mutable;\n if (target.options.strict) {\n checkReadable(key, target.options, mutable);\n }\n if (\n !mutable &&\n !currentDraft &&\n isDraftable(key, target.options) &&\n !target.finalized &&\n target.original!.has(key)\n ) {\n // draft a draftable original set item\n const proxy = internal.createDraft({\n original: key,\n parentDraft: target,\n key,\n finalities: target.finalities,\n options: target.options,\n });\n target.setMap!.set(key, proxy);\n value = proxy;\n } else if (currentDraft) {\n // drafted\n value = currentDraft.proxy;\n }\n return {\n done: false,\n value: isValuesIterator ? value : [value, value],\n };\n };\n\nexport const setHandler = {\n get size() {\n const target: ProxyDraft<any> = getProxyDraft(this)!;\n return target.setMap!.size;\n },\n has(value: any) {\n const target = getProxyDraft(this)!;\n // reassigned or non-draftable values\n if (target.setMap!.has(value)) return true;\n ensureShallowCopy(target);\n const valueProxyDraft = getProxyDraft(value)!;\n // drafted\n if (valueProxyDraft && target.setMap!.has(valueProxyDraft.original))\n return true;\n return false;\n },\n add(value: any) {\n const target = getProxyDraft(this)!;\n if (!this.has(value)) {\n ensureShallowCopy(target);\n markChanged(target);\n target.assignedMap!.set(value, true);\n target.setMap!.set(value, value);\n markFinalization(target, value, value, generatePatches);\n }\n return this;\n },\n delete(value: any): boolean {\n if (!this.has(value)) {\n return false;\n }\n const target = getProxyDraft(this)!;\n ensureShallowCopy(target);\n markChanged(target);\n const valueProxyDraft = getProxyDraft(value)!;\n if (valueProxyDraft && target.setMap!.has(valueProxyDraft.original)) {\n // delete drafted\n target.assignedMap!.set(valueProxyDraft.original, false);\n return target.setMap!.delete(valueProxyDraft.original);\n }\n if (!valueProxyDraft && target.setMap!.has(value)) {\n // non-draftable values\n target.assignedMap!.set(value, false);\n } else {\n // reassigned\n target.assignedMap!.delete(value);\n }\n // delete reassigned or non-draftable values\n return target.setMap!.delete(value);\n },\n clear() {\n if (!this.size) return;\n const target = getProxyDraft(this)!;\n ensureShallowCopy(target);\n markChanged(target);\n for (const value of target.original) {\n target.assignedMap!.set(value, false);\n }\n target.setMap!.clear();\n },\n values(): IterableIterator<any> {\n const target = getProxyDraft(this)!;\n ensureShallowCopy(target);\n const iterator = target.setMap!.keys();\n return {\n [Symbol.iterator]: () => this.values(),\n next: getNextIterator(target, iterator, { isValuesIterator: true }),\n };\n },\n entries(): IterableIterator<[any, any]> {\n const target = getProxyDraft(this)!;\n ensureShallowCopy(target);\n const iterator = target.setMap!.keys();\n return {\n [Symbol.iterator]: () => this.entries(),\n next: getNextIterator(target, iterator, {\n isValuesIterator: false,\n }) as () => IteratorReturnResult<any>,\n };\n },\n keys(): IterableIterator<any> {\n return this.values();\n },\n [iteratorSymbol]() {\n return this.values();\n },\n forEach(callback: any, thisArg?: any) {\n const iterator = this.values();\n let result = iterator.next();\n while (!result.done) {\n callback.call(thisArg, result.value, result.value, this);\n result = iterator.next();\n }\n },\n};\n\nif (Set.prototype.difference) {\n // for compatibility with new Set methods\n // https://github.com/tc39/proposal-set-methods\n // And `https://github.com/tc39/proposal-set-methods/blob/main/details.md#symbolspecies` has some details about the `@@species` symbol.\n // So we can't use SubSet instance constructor to get the constructor of the SubSet instance.\n Object.assign(setHandler, {\n intersection(this: Set<any>, other: ReadonlySetLike<any>): Set<any> {\n return Set.prototype.intersection.call(new Set(this.values()), other);\n },\n union(this: Set<any>, other: ReadonlySetLike<any>): Set<any> {\n return Set.prototype.union.call(new Set(this.values()), other);\n },\n difference(this: Set<any>, other: ReadonlySetLike<any>): Set<any> {\n return Set.prototype.difference.call(new Set(this.values()), other);\n },\n symmetricDifference(this: Set<any>, other: ReadonlySetLike<any>): Set<any> {\n return Set.prototype.symmetricDifference.call(\n new Set(this.values()),\n other\n );\n },\n isSubsetOf(this: Set<any>, other: ReadonlySetLike<any>): boolean {\n return Set.prototype.isSubsetOf.call(new Set(this.values()), other);\n },\n isSupersetOf(this: Set<any>, other: ReadonlySetLike<any>): boolean {\n return Set.prototype.isSupersetOf.call(new Set(this.values()), other);\n },\n isDisjointFrom(this: Set<any>, other: ReadonlySetLike<any>): boolean {\n return Set.prototype.isDisjointFrom.call(new Set(this.values()), other);\n },\n });\n}\n\nexport const setHandlerKeys = Reflect.ownKeys(setHandler);\n","import {\n DraftType,\n Finalities,\n Patches,\n ProxyDraft,\n Options,\n Operation,\n} from './interface';\nimport { dataTypes, PROXY_DRAFT } from './constant';\nimport { mapHandler, mapHandlerKeys } from './map';\nimport { setHandler, setHandlerKeys } from './set';\nimport { internal } from './internal';\nimport {\n deepFreeze,\n ensureShallowCopy,\n getDescriptor,\n getProxyDraft,\n getType,\n getValue,\n has,\n isEqual,\n isDraftable,\n latest,\n markChanged,\n peek,\n get,\n set,\n revokeProxy,\n finalizeSetValue,\n markFinalization,\n finalizePatches,\n isDraft,\n} from './utils';\nimport { checkReadable } from './unsafe';\nimport { generatePatches } from './patch';\n\nconst proxyHandler: ProxyHandler<ProxyDraft> = {\n get(target: ProxyDraft, key: string | number | symbol, receiver: any) {\n const copy = target.copy?.[key];\n // Improve draft reading performance by caching the draft copy.\n if (copy && target.finalities.draftsCache.has(copy)) {\n return copy;\n }\n if (key === PROXY_DRAFT) return target;\n let markResult: any;\n if (target.options.mark) {\n // handle `Uncaught TypeError: Method get Map.prototype.size called on incompatible receiver #<Map>`\n // or `Uncaught TypeError: Method get Set.prototype.size called on incompatible receiver #<Set>`\n const value =\n key === 'size' &&\n (target.original instanceof Map || target.original instanceof Set)\n ? Reflect.get(target.original, key)\n : Reflect.get(target.original, key, receiver);\n markResult = target.options.mark(value, dataTypes);\n if (markResult === dataTypes.mutable) {\n if (target.options.strict) {\n checkReadable(value, target.options, true);\n }\n return value;\n }\n }\n const source = latest(target);\n\n if (source instanceof Map && mapHandlerKeys.includes(key as any)) {\n if (key === 'size') {\n return Object.getOwnPropertyDescriptor(mapHandler, 'size')!.get!.call(\n target.proxy\n );\n }\n const handle = mapHandler[key as keyof typeof mapHandler] as Function;\n return handle.bind(target.proxy);\n }\n\n if (source instanceof Set && setHandlerKeys.includes(key as any)) {\n if (key === 'size') {\n return Object.getOwnPropertyDescriptor(setHandler, 'size')!.get!.call(\n target.proxy\n );\n }\n const handle = setHandler[key as keyof typeof setHandler] as Function;\n return handle.bind(target.proxy);\n }\n\n if (!has(source, key)) {\n const desc = getDescriptor(source, key);\n return desc\n ? `value` in desc\n ? desc.value\n : // !case: support for getter\n desc.get?.call(target.proxy)\n : undefined;\n }\n const value = source[key];\n if (target.options.strict) {\n checkReadable(value, target.options);\n }\n if (target.finalized || !isDraftable(value, target.options)) {\n return value;\n }\n // Ensure that the assigned values are not drafted\n if (value === peek(target.original, key)) {\n ensureShallowCopy(target);\n target.copy![key] = createDraft({\n original: target.original[key],\n parentDraft: target,\n key: target.type === DraftType.Array ? Number(key) : key,\n finalities: target.finalities,\n options: target.options,\n });\n // !case: support for custom shallow copy function\n if (typeof markResult === 'function') {\n const subProxyDraft = getProxyDraft(target.copy![key])!;\n ensureShallowCopy(subProxyDraft);\n // Trigger a custom shallow copy to update to a new copy\n markChanged(subProxyDraft);\n return subProxyDraft.copy;\n }\n return target.copy![key];\n }\n if (isDraft(value)) {\n target.finalities.draftsCache.add(value);\n }\n return value;\n },\n set(target: ProxyDraft, key: string | number | symbol, value: any) {\n if (target.type === DraftType.Set || target.type === DraftType.Map) {\n throw new Error(\n `Map/Set draft does not support any property assignment.`\n );\n }\n let _key: number;\n if (\n target.type === DraftType.Array &&\n key !== 'length' &&\n !(\n Number.isInteger((_key = Number(key))) &&\n _key >= 0 &&\n (key === 0 || _key === 0 || String(_key) === String(key))\n )\n ) {\n throw new Error(\n `Only supports setting array indices and the 'length' property.`\n );\n }\n const desc = getDescriptor(latest(target), key);\n if (desc?.set) {\n // !case: cover the case of setter\n desc.set.call(target.proxy, value);\n return true;\n }\n const current = peek(latest(target), key);\n const currentProxyDraft = getProxyDraft(current);\n if (currentProxyDraft && isEqual(currentProxyDraft.original, value)) {\n // !case: ignore the case of assigning the original draftable value to a draft\n target.copy![key] = value;\n target.assignedMap = target.assignedMap ?? new Map();\n target.assignedMap.set(key, false);\n return true;\n }\n // !case: handle new props with value 'undefined'\n if (\n isEqual(value, current) &&\n (value !== undefined || has(target.original, key))\n )\n return true;\n ensureShallowCopy(target);\n markChanged(target);\n if (has(target.original, key) && isEqual(value, target.original[key])) {\n // !case: handle the case of assigning the original non-draftable value to a draft\n target.assignedMap!.delete(key);\n } else {\n target.assignedMap!.set(key, true);\n }\n target.copy![key] = value;\n markFinalization(target, key, value, generatePatches);\n return true;\n },\n has(target: ProxyDraft, key: string | symbol) {\n return key in latest(target);\n },\n ownKeys(target: ProxyDraft) {\n return Reflect.ownKeys(latest(target));\n },\n getOwnPropertyDescriptor(target: ProxyDraft, key: string | symbol) {\n const source = latest(target);\n const descriptor = Reflect.getOwnPropertyDescriptor(source, key);\n if (!descriptor) return descriptor;\n return {\n writable: true,\n configurable: target.type !== DraftType.Array || key !== 'length',\n enumerable: descriptor.enumerable,\n value: source[key],\n };\n },\n getPrototypeOf(target: ProxyDraft) {\n return Reflect.getPrototypeOf(target.original);\n },\n setPrototypeOf() {\n throw new Error(`Cannot call 'setPrototypeOf()' on drafts`);\n },\n defineProperty() {\n throw new Error(`Cannot call 'defineProperty()' on drafts`);\n },\n deleteProperty(target: ProxyDraft, key: string | symbol) {\n if (target.type === DraftType.Array) {\n return proxyHandler.set!.call(this, target, key, undefined, target.proxy);\n }\n if (peek(target.original, key) !== undefined || key in target.original) {\n // !case: delete an existing key\n ensureShallowCopy(target);\n markChanged(target);\n target.assignedMap!.set(key, false);\n } else {\n target.assignedMap = target.assignedMap ?? new Map();\n // The original non-existent key has been deleted\n target.assignedMap.delete(key);\n }\n if (target.copy) delete target.copy[key];\n return true;\n },\n};\n\nexport function createDraft<T extends object>(createDraftOptions: {\n original: T;\n parentDraft?: ProxyDraft | null;\n key?: string | number | symbol;\n finalities: Finalities;\n options: Options<any, any>;\n}): T {\n const { original, parentDraft, key, finalities, options } =\n createDraftOptions;\n const type = getType(original);\n const proxyDraft: ProxyDraft = {\n type,\n finalized: false,\n parent: parentDraft,\n original,\n copy: null,\n proxy: null,\n finalities,\n options,\n // Mapping of draft Set items to their corresponding draft values.\n setMap:\n type === DraftType.Set\n ? new Map((original as Set<any>).entries())\n : undefined,\n };\n // !case: undefined as a draft map key\n if (key || 'key' in createDraftOptions) {\n proxyDraft.key = key;\n }\n const { proxy, revoke } = Proxy.revocable<any>(\n type === DraftType.Array ? Object.assign([], proxyDraft) : proxyDraft,\n proxyHandler\n );\n finalities.revoke.push(revoke);\n proxyDraft.proxy = proxy;\n if (parentDraft) {\n const target = parentDraft;\n target.finalities.draft.push((patches, inversePatches) => {\n const oldProxyDraft = getProxyDraft(proxy)!;\n // if target is a Set draft, `setMap` is the real Set copies proxy mapping.\n let copy = target.type === DraftType.Set ? target.setMap : target.copy;\n const draft = get(copy, key!);\n const proxyDraft = getProxyDraft(draft);\n if (proxyDraft) {\n // assign the updated value to the copy object\n let updatedValue = proxyDraft.original;\n if (proxyDraft.operated) {\n updatedValue = getValue(draft);\n }\n finalizeSetValue(proxyDraft);\n finalizePatches(proxyDraft, generatePatches, patches, inversePatches);\n if (__DEV__ && target.options.enableAutoFreeze) {\n target.options.updatedValues =\n target.options.updatedValues ?? new WeakMap();\n target.options.updatedValues.set(updatedValue, proxyDraft.original);\n }\n // final update value\n set(copy, key!, updatedValue);\n }\n // !case: handle the deleted key\n oldProxyDraft.callbacks?.forEach((callback) => {\n callback(patches, inversePatches);\n });\n });\n } else {\n // !case: handle the root draft\n const target = getProxyDraft(proxy)!;\n target.finalities.draft.push((patches, inversePatches) => {\n finalizeSetValue(target);\n finalizePatches(target, generatePatches, patches, inversePatches);\n });\n }\n return proxy;\n}\n\ninternal.createDraft = createDraft;\n\nexport function finalizeDraft<T>(\n result: T,\n returnedValue: [T] | [],\n patches?: Patches,\n inversePatches?: Patches,\n enableAutoFreeze?: boolean\n) {\n const proxyDraft = getProxyDraft(result);\n const original = proxyDraft?.original ?? result;\n const hasReturnedValue = !!returnedValue.length;\n if (proxyDraft?.operated) {\n while (proxyDraft.finalities.draft.length > 0) {\n const finalize = proxyDraft.finalities.draft.pop()!;\n finalize(patches, inversePatches);\n }\n }\n const state = hasReturnedValue\n ? returnedValue[0]\n : proxyDraft\n ? proxyDraft.operated\n ? proxyDraft.copy\n : proxyDraft.original\n : result;\n if (proxyDraft) revokeProxy(proxyDraft);\n if (enableAutoFreeze) {\n deepFreeze(state, state, proxyDraft?.options.updatedValues);\n }\n return [\n state,\n patches && hasReturnedValue\n ? [{ op: Operation.Replace, path: [], value: returnedValue[0] }]\n : patches,\n inversePatches && hasReturnedValue\n ? [{ op: Operation.Replace, path: [], value: original }]\n : inversePatches,\n ] as [T, Patches | undefined, Patches | undefined];\n}\n","import {\n Finalities,\n Options,\n Patches,\n PatchesOptions,\n Result,\n} from './interface';\nimport { createDraft, finalizeDraft } from './draft';\nimport { isDraftable } from './utils';\nimport { dataTypes } from './constant';\n\nexport function draftify<\n T extends object,\n O extends PatchesOptions = false,\n F extends boolean = false,\n>(\n baseState: T,\n options: Options<O, F>\n): [T, (returnedValue: [T] | []) => Result<T, O, F>] {\n const finalities: Finalities = {\n draft: [],\n revoke: [],\n handledSet: new WeakSet<any>(),\n draftsCache: new WeakSet<object>(),\n };\n let patches: Patches | undefined;\n let inversePatches: Patches | undefined;\n if (options.enablePatches) {\n patches = [];\n inversePatches = [];\n }\n const isMutable =\n options.mark?.(baseState, dataTypes) === dataTypes.mutable ||\n !isDraftable(baseState, options);\n const draft = isMutable\n ? baseState\n : createDraft({\n original: baseState,\n parentDraft: null,\n finalities,\n options,\n });\n return [\n draft,\n (returnedValue: [T] | [] = []) => {\n const [finalizedState, finalizedPatches, finalizedInversePatches] =\n finalizeDraft(\n draft,\n returnedValue,\n patches,\n inversePatches,\n options.enableAutoFreeze\n );\n return (\n options.enablePatches\n ? [finalizedState, finalizedPatches, finalizedInversePatches]\n : finalizedState\n ) as Result<T, O, F>;\n },\n ];\n}\n","import { type Draft, DraftType, type ProxyDraft } from './interface';\nimport {\n forEach,\n get,\n getProxyDraft,\n getType,\n isBaseMapInstance,\n isBaseSetInstance,\n isDraft,\n isDraftable,\n isEqual,\n set,\n shallowCopy,\n} from './utils';\n\nexport function handleReturnValue<T extends object>(options: {\n rootDraft: ProxyDraft<any> | undefined;\n value: T;\n useRawReturn?: boolean;\n isContainDraft?: boolean;\n isRoot?: boolean;\n}) {\n const { rootDraft, value, useRawReturn = false, isRoot = true } = options;\n forEach(value, (key, item, source) => {\n const proxyDraft = getProxyDraft(item);\n // just handle the draft which is created by the same rootDraft\n if (\n proxyDraft &&\n rootDraft &&\n proxyDraft.finalities === rootDraft.finalities\n ) {\n options.isContainDraft = true;\n const currentValue = proxyDraft.original;\n // final update value, but just handle return value\n if (source instanceof Set) {\n const arr = Array.from(source);\n source.clear();\n arr.forEach((_item) =>\n source.add(key === _item ? currentValue : _item)\n );\n } else {\n set(source, key, currentValue);\n }\n } else if (typeof item === 'object' && item !== null) {\n options.value = item;\n options.isRoot = false;\n handleReturnValue(options);\n }\n });\n if (__DEV__ && isRoot) {\n if (!options.isContainDraft)\n console.warn(\n `The return value does not contain any draft, please use 'rawReturn()' to wrap the return value to improve performance.`\n );\n\n if (useRawReturn) {\n console.warn(\n `The return value contains drafts, please don't use 'rawReturn()' to wrap the return value.`\n );\n }\n }\n}\n\nfunction getCurrent(target: any) {\n const proxyDraft = getProxyDraft(target);\n if (!isDraftable(target, proxyDraft?.options)) return target;\n const type = getType(target);\n if (proxyDraft && !proxyDraft.operated) return proxyDraft.original;\n let currentValue: any;\n function ensureShallowCopy() {\n currentValue =\n type === DraftType.Map\n ? !isBaseMapInstance(target)\n ? new (Object.getPrototypeOf(target).constructor)(target)\n : new Map(target)\n : type === DraftType.Set\n ? Array.from(proxyDraft!.setMap!.values()!)\n : shallowCopy(target, proxyDraft?.options);\n }\n\n if (proxyDraft) {\n // It's a proxy draft, let's create a shallow copy eagerly\n proxyDraft.finalized = true;\n try {\n ensureShallowCopy();\n } finally {\n proxyDraft.finalized = false;\n }\n } else {\n // It's not a proxy draft, let's use the target directly and let's see\n // lazily if we need to create a shallow copy\n currentValue = target;\n }\n\n forEach(currentValue, (key, value) => {\n if (proxyDraft && isEqual(get(proxyDraft.original, key), value)) return;\n const newValue = getCurrent(value);\n if (newValue !== value) {\n if (currentValue === target) ensureShallowCopy();\n set(currentValue, key, newValue);\n }\n });\n if (type === DraftType.Set) {\n const value = proxyDraft?.original ?? currentValue;\n return !isBaseSetInstance(value)\n ? new (Object.getPrototypeOf(value).constructor)(currentValue)\n : new Set(currentValue);\n }\n return currentValue;\n}\n\n/**\n * `current(draft)` to get current state in the draft mutation function.\n *\n * ## Example\n *\n * ```ts\n * import { create, current } from '../index';\n *\n * const baseState = { foo: { bar: 'str' }, arr: [] };\n * const state = create(\n * baseState,\n * (draft) => {\n * draft.foo.bar = 'str2';\n * expect(current(draft.foo)).toEqual({ bar: 'str2' });\n * },\n * );\n * ```\n */\nexport function current<T extends object>(target: Draft<T>): T;\n/** @deprecated You should call current only on `Draft<T>` types. */\nexport function current<T extends object>(target: T): T;\nexport function current<T extends object>(target: T | Draft<T>): T {\n if (!isDraft(target)) {\n throw new Error(`current() is only used for Draft, parameter: ${target}`);\n }\n return getCurrent(target);\n}\n","import {\n CreateResult,\n Draft,\n Mark,\n Options,\n ExternalOptions,\n PatchesOptions,\n Result,\n} from './interface';\nimport { draftify } from './draftify';\nimport {\n getProxyDraft,\n isDraft,\n isDraftable,\n isEqual,\n revokeProxy,\n} from './utils';\nimport { current, handleReturnValue } from './current';\nimport { RAW_RETURN_SYMBOL, dataTypes } from './constant';\n\ntype MakeCreator = <\n _F extends boolean = false,\n _O extends PatchesOptions = false,\n>(\n options?: ExternalOptions<_O, _F>\n) => {\n <\n T extends any,\n F extends boolean = _F,\n O extends PatchesOptions = _O,\n R extends void | Promise<void> | T | Promise<T> = void,\n >(\n base: T,\n mutate: (draft: Draft<T>) => R,\n options?: ExternalOptions<O, F>\n ): CreateResult<T, O, F, R>;\n <\n T extends any,\n F extends boolean = _F,\n O extends PatchesOptions = _O,\n R extends void | Promise<void> = void,\n >(\n base: T,\n mutate: (draft: T) => R,\n options?: ExternalOptions<O, F>\n ): CreateResult<T, O, F, R>;\n <\n T extends any,\n P extends any[] = [],\n F extends boolean = _F,\n O extends PatchesOptions = _O,\n R extends void | Promise<void> = void,\n >(\n mutate: (draft: Draft<T>, ...args: P) => R,\n options?: ExternalOptions<O, F>\n ): (base: T, ...args: P) => CreateResult<T, O, F, R>;\n <T extends any, O extends PatchesOptions = _O, F extends boolean = _F>(\n base: T,\n options?: ExternalOptions<O, F>\n ): [Draft<T>, () => Result<T, O, F>];\n};\n\n/**\n * `makeCreator(options)` to make a creator function.\n *\n * ## Example\n *\n * ```ts\n * import { makeCreator } from '../index';\n *\n * const baseState = { foo: { bar: 'str' }, arr: [] };\n * const create = makeCreator({ enableAutoFreeze: true });\n * const state = create(\n * baseState,\n * (draft) => {\n * draft.foo.bar = 'str2';\n * },\n * );\n *\n * expect(state).toEqual({ foo: { bar: 'str2' }, arr: [] });\n * expect(state).not.toBe(baseState);\n * expect(state.foo).not.toBe(baseState.foo);\n * expect(state.arr).toBe(baseState.arr);\n * expect(Object.isFrozen(state)).toBeTruthy();\n * ```\n */\nexport const makeCreator: MakeCreator = (arg) => {\n if (\n __DEV__ &&\n arg !== undefined &&\n Object.prototype.toString.call(arg) !== '[object Object]'\n ) {\n throw new Error(\n `Invalid options: ${String(arg)}, 'options' should be an object.`\n );\n }\n return function create(arg0: any, arg1: any, arg2?: any): any {\n if (typeof arg0 === 'function' && typeof arg1 !== 'function') {\n return function (this: any, base: any, ...args: any[]) {\n return create(\n base,\n (draft: any) => arg0.call(this, draft, ...args),\n arg1\n );\n };\n }\n const base = arg0;\n const mutate = arg1 as (...args: any[]) => any;\n let options = arg2;\n if (typeof arg1 !== 'function') {\n options = arg1;\n }\n if (\n __DEV__ &&\n options !== undefined &&\n Object.prototype.toString.call(options) !== '[object Object]'\n ) {\n throw new Error(\n `Invalid options: ${options}, 'options' should be an object.`\n );\n }\n options = {\n ...arg,\n ...options,\n };\n const state = isDraft(base) ? current(base) : base;\n const mark = Array.isArray(options.mark)\n ? (((value: unknown, types: typeof dataTypes) => {\n for (const mark of options.mark as Mark<any, any>[]) {\n if (__DEV__ && typeof mark !== 'function') {\n throw new Error(\n `Invalid mark: ${mark}, 'mark' should be a function.`\n );\n }\n const result = mark(value, types);\n if (result) {\n return result;\n }\n }\n return;\n }) as Mark<any, any>)\n : options.mark;\n const enablePatches = options.enablePatches ?? false;\n const strict = options.strict ?? false;\n const enableAutoFreeze = options.enableAutoFreeze ?? false;\n const _options: Options<any, any> = {\n enableAutoFreeze,\n mark,\n strict,\n enablePatches,\n };\n if (\n !isDraftable(state, _options) &&\n typeof state === 'object' &&\n state !== null\n ) {\n throw new Error(\n `Invalid base state: create() only supports plain objects, arrays, Set, Map or using mark() to mark the state as immutable.`\n );\n }\n const [draft, finalize] = draftify(state, _options);\n if (typeof arg1 !== 'function') {\n if (!isDraftable(state, _options)) {\n throw new Error(\n `Invalid base state: create() only supports plain objects, arrays, Set, Map or using mark() to mark the state as immutable.`\n );\n }\n return [draft, finalize];\n }\n let result: any;\n try {\n result = mutate(draft);\n } catch (error) {\n revokeProxy(getProxyDraft(draft));\n throw error;\n }\n const returnValue = (value: any) => {\n const proxyDraft = getProxyDraft(draft)!;\n if (!isDraft(value)) {\n if (\n value !== undefined &&\n !isEqual(value, draft) &&\n proxyDraft?.operated\n ) {\n throw new Error(\n `Either the value is returned as a new non-draft value, or only the draft is modified without returning any value.`\n );\n }\n const rawReturnValue = value?.[RAW_RETURN_SYMBOL] as [any] | undefined;\n if (rawReturnValue) {\n const _value = rawReturnValue[0];\n if (_options.strict && typeof value === 'object' && value !== null) {\n handleReturnValue({\n rootDraft: proxyDraft,\n value,\n useRawReturn: true,\n });\n }\n return finalize([_value]);\n }\n if (value !== undefined) {\n if (typeof value === 'object' && value !== null) {\n handleReturnValue({ rootDraft: proxyDraft, value });\n }\n return finalize([value]);\n }\n }\n if (value === draft || value === undefined) {\n return finalize([]);\n }\n const returnedProxyDraft = getProxyDraft(value)!;\n if (_options === returnedProxyDraft.options) {\n if (returnedProxyDraft.operated) {\n throw new Error(`Cannot return a modified child draft.`);\n }\n return finalize([current(value)]);\n }\n return finalize([value]);\n };\n if (result instanceof Promise) {\n return result.then(returnValue, (error) => {\n revokeProxy(getProxyDraft(draft)!);\n throw error;\n });\n }\n return returnValue(result);\n };\n};\n","import { makeCreator } from './makeCreator';\n\n/**\n * `create(baseState, callback, options)` to create the next state\n *\n * ## Example\n *\n * ```ts\n * import { create } from '../index';\n *\n * const baseState = { foo: { bar: 'str' }, arr: [] };\n * const state = create(\n * baseState,\n * (draft) => {\n * draft.foo.bar = 'str2';\n * },\n * );\n *\n * expect(state).toEqual({ foo: { bar: 'str2' }, arr: [] });\n * expect(state).not.toBe(baseState);\n * expect(state.foo).not.toBe(baseState.foo);\n * expect(state.arr).toBe(baseState.arr);\n * ```\n */\nconst create = makeCreator();\n\nexport { create };\n","import { Operation, DraftType } from './interface';\nimport type {\n Draft,\n Patches,\n ApplyMutableOptions,\n ApplyOptions,\n ApplyResult,\n} from './interface';\nimport { deepClone, get, getType, isDraft, unescapePath } from './utils';\nimport { create } from './create';\n\n/**\n * `apply(state, patches)` to apply patches to state\n *\n * ## Example\n *\n * ```ts\n * import { create, apply } from '../index';\n *\n * const baseState = { foo: { bar: 'str' }, arr: [] };\n * const [state, patches] = create(\n * baseState,\n * (draft) => {\n * draft.foo.bar = 'str2';\n * },\n * { enablePatches: true }\n * );\n * expect(state).toEqual({ foo: { bar: 'str2' }, arr: [] });\n * expect(patches).toEqual([{ op: 'replace', path: ['foo', 'bar'], value: 'str2' }]);\n * expect(state).toEqual(apply(baseState, patches));\n * ```\n */\nexport function apply<\n T extends object,\n F extends boolean = false,\n A extends ApplyOptions<F> = ApplyOptions<F>,\n>(state: T, patches: Patches, applyOptions?: A): ApplyResult<T, F, A> {\n let i: number;\n for (i = patches.length - 1; i >= 0; i -= 1) {\n const { value, op, path } = patches[i];\n if (\n (!path.length && op === Operation.Replace) ||\n (path === '' && op === Operation.Add)\n ) {\n state = value;\n break;\n }\n }\n if (i > -1) {\n patches = patches.slice(i + 1);\n }\n const mutate = (draft: Draft<T> | T) => {\n patches.forEach((patch) => {\n const { path: _path, op } = patch;\n const path = unescapePath(_path);\n let base: any = draft;\n for (let index = 0; index < path.length - 1; index += 1) {\n const parentType = getType(base);\n let key = path[index];\n if (typeof key !== 'string' && typeof key !== 'number') {\n key = String(key);\n }\n if (\n ((parentType === DraftType.Object ||\n parentType === DraftType.Array) &&\n (key === '__proto__' || key === 'constructor')) ||\n (typeof base === 'function' && key === 'prototype')\n ) {\n throw new Error(\n `Patching reserved attributes like __proto__ and constructor is not allowed.`\n );\n }\n // use `index` in Set draft\n base = get(parentType === DraftType.Set ? Array.from(base) : base, key);\n if (typeof base !== 'object') {\n throw new Error(`Cannot apply patch at '${path.join('/')}'.`);\n }\n }\n\n const type = getType(base);\n // ensure the original patch is not modified.\n const value = deepClone(patch.value);\n const key = path[path.length - 1];\n switch (op) {\n case Operation.Replace:\n switch (type) {\n case DraftType.Map:\n return base.set(key, value);\n case DraftType.Set:\n throw new Error(`Cannot apply replace patch to set.`);\n default:\n return (base[key] = value);\n }\n case Operation.Add:\n switch (type) {\n case DraftType.Array:\n // If the \"-\" character is used to\n // index the end of the array (see [RFC6901](https://datatracker.ietf.org/doc/html/rfc6902)),\n // this has the effect of appending the value to the array.\n return key === '-'\n ? base.push(value)\n : base.splice(key as number, 0, value);\n case DraftType.Map:\n return base.set(key, value);\n case DraftType.Set:\n return base.add(value);\n default:\n return (base[key] = value);\n }\n case Operation.Remove:\n switch (type) {\n case DraftType.Array:\n return base.splice(key as number, 1);\n case DraftType.Map:\n return base.delete(key);\n case DraftType.Set:\n return base.delete(patch.value);\n default:\n return delete base[key];\n }\n default:\n throw new Error(`Unsupported patch operation: ${op}.`);\n }\n });\n };\n if ((applyOptions as ApplyMutableOptions)?.mutable) {\n if (__DEV__) {\n if (\n Object.keys(applyOptions!).filter((key) => key !== 'mutable').length\n ) {\n console.warn(\n 'The \"mutable\" option is not allowed to be used with other options.'\n );\n }\n }\n mutate(state);\n return undefined as ApplyResult<T, F, A>;\n }\n if (isDraft(state)) {\n if (applyOptions !== undefined) {\n throw new Error(`Cannot apply patches with options to a draft.`);\n }\n mutate(state as Draft<T>);\n return state as ApplyResult<T, F, A>;\n }\n return create<T, F>(state, mutate, {\n ...applyOptions,\n enablePatches: false,\n }) as T as ApplyResult<T, F, A>;\n}\n","import { getProxyDraft } from './utils';\n\n/**\n * `original(draft)` to get original state in the draft mutation function.\n *\n * ## Example\n *\n * ```ts\n * import { create, original } from '../index';\n *\n * const baseState = { foo: { bar: 'str' }, arr: [] };\n * const state = create(\n * baseState,\n * (draft) => {\n * draft.foo.bar = 'str2';\n * expect(original(draft.foo)).toEqual({ bar: 'str' });\n * }\n * );\n * ```\n */\nexport function original<T>(target: T): T {\n const proxyDraft = getProxyDraft(target);\n if (!proxyDraft) {\n throw new Error(\n `original() is only used for a draft, parameter: ${target}`\n );\n }\n return proxyDraft.original;\n}\n","import { RAW_RETURN_SYMBOL } from './constant';\n\n/**\n * Use rawReturn() to wrap the return value to skip the draft check and thus improve performance.\n *\n * ## Example\n *\n * ```ts\n * import { create, rawReturn } from '../index';\n *\n * const baseState = { foo: { bar: 'str' }, arr: [] };\n * const state = create(\n * baseState,\n * (draft) => {\n * return rawReturn(baseState);\n * },\n * );\n * expect(state).toBe(baseState);\n * ```\n */\nexport function rawReturn<T extends object | undefined>(value: T): T {\n if (arguments.length === 0) {\n throw new Error('rawReturn() must be called with a value.');\n }\n if (arguments.length > 1) {\n throw new Error('rawReturn() must be called with one argument.');\n }\n if (\n __DEV__ &&\n value !== undefined &&\n (typeof value !== 'object' || value === null)\n ) {\n console.warn(\n 'rawReturn() must be called with an object(including plain object, arrays, Set, Map, etc.) or `undefined`, other types do not need to be returned via rawReturn().'\n );\n }\n return {\n [RAW_RETURN_SYMBOL]: [value],\n } as never;\n}\n","import { dataTypes } from '../constant';\n\nconst constructorString = Object.prototype.constructor.toString();\n/**\n * Check if the value is a simple object(No prototype chain object or iframe same-origin object),\n * support case: https://github.com/unadlib/mutative/issues/17\n */\nconst isSimpleObject = (value: unknown) => {\n if (!value || typeof value !== 'object') return false;\n const prototype = Object.getPrototypeOf(value);\n if (prototype === null) {\n return true;\n }\n const constructor =\n Object.hasOwnProperty.call(prototype, 'constructor') &&\n prototype.constructor;\n\n if (constructor === Object) return true;\n\n return (\n typeof constructor === 'function' &&\n Function.toString.call(constructor) === constructorString\n );\n};\n\nexport const markSimpleObject = (value: unknown) => {\n if (isSimpleObject(value)) {\n return dataTypes.immutable;\n }\n return;\n};\n","import { Draft, Immutable } from '../interface';\n\n/**\n * Cast a value to an Draft type value.\n */\nexport function castDraft<T>(value: T): Draft<T> {\n return value as any;\n}\n\n/**\n * Cast a value to an Immutable type value.\n */\nexport function castImmutable<T>(value: T): Immutable<T> {\n return value as any;\n}\n\n/**\n * Cast a value to an Mutable type value.\n */\nexport function castMutable<T>(draft: Draft<T>): T {\n return draft as any;\n}\n","import { webcrypto as crypto } from 'node:crypto'\nimport { urlAlphabet as scopedUrlAlphabet } from './url-alphabet/index.js'\nexport { urlAlphabet } from './url-alphabet/index.js'\nconst POOL_SIZE_MULTIPLIER = 128\nlet pool, poolOffset\nfunction fillPool(bytes) {\n if (!pool || pool.length < bytes) {\n pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER)\n crypto.getRandomValues(pool)\n poolOffset = 0\n } else if (poolOffset + bytes > pool.length) {\n crypto.getRandomValues(pool)\n poolOffset = 0\n }\n poolOffset += bytes\n}\nexport function random(bytes) {\n fillPool((bytes |= 0))\n return pool.subarray(poolOffset - bytes, poolOffset)\n}\nexport function customRandom(alphabet, defaultSize, getRandom) {\n let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1\n let step = Math.ceil((1.6 * mask * defaultSize) / alphabet.length)\n return (size = defaultSize) => {\n if (!size) return ''\n let id = ''\n while (true) {\n let bytes = getRandom(step)\n let i = step\n while (i--) {\n id += alphabet[bytes[i] & mask] || ''\n if (id.length >= size) return id\n }\n }\n }\n}\nexport function customAlphabet(alphabet, size = 21) {\n return customRandom(alphabet, size, random)\n}\nexport function nanoid(size = 21) {\n fillPool((size |= 0))\n let id = ''\n for (let i = poolOffset - size; i < poolOffset; i++) {\n id += scopedUrlAlphabet[pool[i] & 63]\n }\n return id\n}\n","export const urlAlphabet =\n 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'\n","// src/index.ts\nimport {\n Shape as Shape3\n} from \"@loro-extended/change\";\n\n// src/epoch.ts\nvar EPOCH_CLOSE_CODES = {\n EPOCH_TOO_OLD: 4100\n};\nfunction formatEpochCloseReason(requiredEpoch) {\n return `epoch_too_old:${requiredEpoch}`;\n}\nfunction parseEpochFromReason(reason) {\n if (!reason.startsWith(\"epoch_too_old:\"))\n return null;\n const epochStr = reason.slice(\"epoch_too_old:\".length);\n const parsed = Number.parseInt(epochStr, 10);\n if (!Number.isFinite(parsed) || parsed < 1)\n return null;\n if (epochStr !== String(parsed))\n return null;\n return parsed;\n}\nvar DEFAULT_EPOCH = 2;\nfunction isEpochRejection(code, reason) {\n return code === EPOCH_CLOSE_CODES.EPOCH_TOO_OLD || reason?.startsWith(\"epoch_too_old\") === true;\n}\nfunction isEpochValid(clientEpoch, minimumEpoch) {\n return clientEpoch >= minimumEpoch;\n}\nfunction parseEpochParam(searchParams) {\n const epochParam = searchParams.get(\"epoch\");\n if (!epochParam)\n return null;\n const parsed = Number.parseInt(epochParam, 10);\n if (!Number.isFinite(parsed) || parsed < 1)\n return null;\n if (epochParam !== String(parsed))\n return null;\n return parsed;\n}\nfunction buildDocumentId(prefix, key, epoch) {\n if (prefix.includes(\":\") || key.includes(\":\")) {\n throw new Error(`Document ID parts must not contain colons: prefix=\"${prefix}\", key=\"${key}\"`);\n }\n return `${prefix}:${key}:${epoch}`;\n}\nfunction parseDocumentId(id) {\n const parts = id.split(\":\");\n if (parts.length !== 3)\n return null;\n const [prefix, key, epochStr] = parts;\n if (!prefix || !key || !epochStr)\n return null;\n const epoch = Number.parseInt(epochStr, 10);\n if (!Number.isFinite(epoch) || epoch < 1)\n return null;\n if (epochStr !== String(epoch))\n return null;\n return { prefix, key, epoch };\n}\n// src/ids.ts\nimport { nanoid } from \"nanoid\";\nvar LOCAL_USER_ID = \"local-user\";\nfunction generateTaskId() {\n return nanoid();\n}\nfunction generateSessionId() {\n return nanoid();\n}\nfunction toTaskId(value) {\n if (value.length === 0 || value.length > 128) {\n throw new Error(`Invalid TaskId: \"${value}\"`);\n }\n return value;\n}\nfunction toSessionId(value) {\n if (value.length === 0 || value.length > 128) {\n throw new Error(`Invalid SessionId: \"${value}\"`);\n }\n return value;\n}\n// src/plan-helpers.ts\nfunction extractPlanMarkdown(toolInput) {\n try {\n const parsed = JSON.parse(toolInput);\n return typeof parsed.plan === \"string\" ? parsed.plan : \"\";\n } catch {\n return \"\";\n }\n}\n// src/room-helpers.ts\nimport { change } from \"@loro-extended/change\";\nfunction addTaskToIndex(doc, entry) {\n change(doc, (draft) => {\n draft.taskIndex.set(entry.taskId, {\n taskId: entry.taskId,\n title: entry.title,\n status: entry.status,\n createdAt: entry.createdAt,\n updatedAt: entry.updatedAt\n });\n });\n}\nfunction updateTaskInIndex(doc, taskId, updates) {\n if (Object.keys(updates).length === 0)\n return;\n change(doc, (draft) => {\n if (!draft.taskIndex.has(taskId))\n return;\n const entry = draft.taskIndex.get(taskId);\n if (!entry)\n return;\n if (updates.title !== undefined) {\n entry.title = updates.title;\n }\n if (updates.status !== undefined) {\n entry.status = updates.status;\n }\n if (updates.updatedAt !== undefined) {\n entry.updatedAt = updates.updatedAt;\n }\n });\n}\nfunction removeTaskFromIndex(doc, taskId) {\n change(doc, (draft) => {\n if (!draft.taskIndex.has(taskId))\n return;\n draft.taskIndex.delete(taskId);\n });\n}\n// src/room-schema.ts\nimport { Shape as Shape2 } from \"@loro-extended/change\";\n\n// src/shapes.ts\nimport { Shape } from \"@loro-extended/change\";\nvar EpochDocumentSchema = Shape.doc({\n schema: Shape.struct({\n version: Shape.plain.number()\n })\n});\nvar CONTENT_BLOCK_TYPES = [\"text\", \"tool_use\", \"tool_result\", \"thinking\"];\nvar ContentBlockShape = Shape.plain.discriminatedUnion(\"type\", {\n text: Shape.plain.struct({\n type: Shape.plain.string(\"text\"),\n text: Shape.plain.string()\n }),\n tool_use: Shape.plain.struct({\n type: Shape.plain.string(\"tool_use\"),\n toolUseId: Shape.plain.string(),\n toolName: Shape.plain.string(),\n input: Shape.plain.string(),\n parentToolUseId: Shape.plain.string().nullable()\n }),\n tool_result: Shape.plain.struct({\n type: Shape.plain.string(\"tool_result\"),\n toolUseId: Shape.plain.string(),\n content: Shape.plain.string(),\n isError: Shape.plain.boolean(),\n parentToolUseId: Shape.plain.string().nullable()\n }),\n thinking: Shape.plain.struct({\n type: Shape.plain.string(\"thinking\"),\n text: Shape.plain.string()\n })\n});\nvar A2A_TASK_STATES = [\n \"submitted\",\n \"starting\",\n \"working\",\n \"input-required\",\n \"completed\",\n \"canceled\",\n \"failed\"\n];\nvar SESSION_STATES = [\"pending\", \"active\", \"completed\", \"failed\", \"interrupted\"];\nvar REASONING_EFFORTS = [\"low\", \"medium\", \"high\"];\nvar PERMISSION_MODES = [\"default\", \"accept-edits\", \"plan\", \"bypass\"];\nvar MessageShape = Shape.plain.struct({\n messageId: Shape.plain.string(),\n role: Shape.plain.string(\"user\", \"assistant\"),\n content: Shape.plain.array(ContentBlockShape),\n timestamp: Shape.plain.number(),\n model: Shape.plain.string().nullable(),\n machineId: Shape.plain.string().nullable(),\n reasoningEffort: Shape.plain.string(...REASONING_EFFORTS).nullable(),\n permissionMode: Shape.plain.string(...PERMISSION_MODES).nullable(),\n cwd: Shape.plain.string().nullable()\n});\nvar DiffFileShape = Shape.plain.struct({\n path: Shape.plain.string(),\n status: Shape.plain.string()\n});\nvar DiffStateShape = Shape.struct({\n unstaged: Shape.plain.string(),\n staged: Shape.plain.string(),\n files: Shape.list(DiffFileShape),\n updatedAt: Shape.plain.number(),\n branchDiff: Shape.plain.string(),\n branchFiles: Shape.list(DiffFileShape),\n branchBase: Shape.plain.string(),\n branchUpdatedAt: Shape.plain.number(),\n lastTurnDiff: Shape.plain.string(),\n lastTurnFiles: Shape.list(DiffFileShape),\n lastTurnUpdatedAt: Shape.plain.number()\n});\nvar SessionEntryShape = Shape.plain.struct({\n sessionId: Shape.plain.string(),\n agentSessionId: Shape.plain.string(),\n status: Shape.plain.string(...SESSION_STATES),\n cwd: Shape.plain.string(),\n model: Shape.plain.string().nullable(),\n machineId: Shape.plain.string().nullable(),\n createdAt: Shape.plain.number(),\n completedAt: Shape.plain.number().nullable(),\n totalCostUsd: Shape.plain.number().nullable(),\n durationMs: Shape.plain.number().nullable(),\n error: Shape.plain.string().nullable()\n});\nvar PLAN_REVIEW_STATUSES = [\"pending\", \"approved\", \"changes-requested\"];\nvar PlanVersionShape = Shape.plain.struct({\n planId: Shape.plain.string(),\n toolUseId: Shape.plain.string(),\n markdown: Shape.plain.string(),\n reviewStatus: Shape.plain.string(...PLAN_REVIEW_STATUSES),\n reviewFeedback: Shape.plain.string().nullable(),\n createdAt: Shape.plain.number()\n});\nvar COMMENT_AUTHOR_TYPES = [\"human\", \"agent\"];\nvar DIFF_COMMENT_SIDES = [\"old\", \"new\"];\nvar DIFF_COMMENT_SCOPES = [\"working-tree\", \"last-turn\"];\nvar DiffCommentShape = Shape.plain.struct({\n commentId: Shape.plain.string(),\n filePath: Shape.plain.string(),\n lineNumber: Shape.plain.number(),\n side: Shape.plain.string(...DIFF_COMMENT_SIDES),\n diffScope: Shape.plain.string(...DIFF_COMMENT_SCOPES),\n lineContentHash: Shape.plain.string(),\n body: Shape.plain.string(),\n authorType: Shape.plain.string(...COMMENT_AUTHOR_TYPES),\n authorId: Shape.plain.string(),\n createdAt: Shape.plain.number(),\n resolvedAt: Shape.plain.number().nullable()\n});\nvar TaskDocumentSchema = Shape.doc({\n meta: Shape.struct({\n id: Shape.plain.string(),\n title: Shape.plain.string(),\n status: Shape.plain.string(...A2A_TASK_STATES),\n createdAt: Shape.plain.number(),\n updatedAt: Shape.plain.number()\n }),\n conversation: Shape.list(MessageShape),\n sessions: Shape.list(SessionEntryShape),\n diffState: DiffStateShape,\n plans: Shape.list(PlanVersionShape),\n diffComments: Shape.record(DiffCommentShape)\n});\nvar TOOL_RISK_LEVELS = [\"low\", \"medium\", \"high\"];\nvar PERMISSION_DECISIONS = [\"approved\", \"denied\"];\nvar PermissionRequestEphemeral = Shape.plain.struct({\n toolName: Shape.plain.string(),\n toolInput: Shape.plain.string(),\n riskLevel: Shape.plain.string(...TOOL_RISK_LEVELS),\n reason: Shape.plain.string().nullable(),\n blockedPath: Shape.plain.string().nullable(),\n description: Shape.plain.string().nullable(),\n agentId: Shape.plain.string().nullable(),\n createdAt: Shape.plain.number()\n});\nvar PermissionResponseEphemeral = Shape.plain.struct({\n decision: Shape.plain.string(...PERMISSION_DECISIONS),\n persist: Shape.plain.boolean(),\n message: Shape.plain.string().nullable(),\n decidedAt: Shape.plain.number()\n});\nvar HIGH_RISK_TOOLS = new Set([\"Write\", \"NotebookEdit\"]);\nvar MEDIUM_RISK_TOOLS = new Set([\"Edit\", \"WebFetch\", \"WebSearch\"]);\nfunction classifyToolRisk(toolName, input) {\n if (toolName === \"Bash\") {\n const cmd = typeof input.command === \"string\" ? input.command : \"\";\n if (/\\brm\\b|--force|--hard|\\bdd\\b|\\bmkfs\\b/.test(cmd))\n return \"high\";\n return \"medium\";\n }\n if (HIGH_RISK_TOOLS.has(toolName))\n return \"high\";\n if (MEDIUM_RISK_TOOLS.has(toolName))\n return \"medium\";\n return \"low\";\n}\n\n// src/room-schema.ts\nvar TaskIndexEntryShape = Shape2.struct({\n taskId: Shape2.plain.string(),\n title: Shape2.plain.string(),\n status: Shape2.plain.string(...A2A_TASK_STATES),\n createdAt: Shape2.plain.number(),\n updatedAt: Shape2.plain.number()\n});\nvar TaskIndexDocumentSchema = Shape2.doc({\n taskIndex: Shape2.record(TaskIndexEntryShape)\n});\nvar ReasoningCapabilityShape = Shape2.plain.struct({\n efforts: Shape2.plain.array(Shape2.plain.string(...REASONING_EFFORTS)),\n defaultEffort: Shape2.plain.string(...REASONING_EFFORTS)\n});\nvar ModelInfoShape = Shape2.plain.struct({\n id: Shape2.plain.string(),\n label: Shape2.plain.string(),\n provider: Shape2.plain.string(),\n reasoning: ReasoningCapabilityShape.nullable()\n});\nvar GitRepoInfoShape = Shape2.plain.struct({\n path: Shape2.plain.string(),\n name: Shape2.plain.string(),\n branch: Shape2.plain.string(),\n remote: Shape2.plain.string().nullable()\n});\nvar MachineCapabilitiesEphemeral = Shape2.plain.struct({\n models: Shape2.plain.array(ModelInfoShape),\n environments: Shape2.plain.array(GitRepoInfoShape),\n permissionModes: Shape2.plain.array(Shape2.plain.string(...PERMISSION_MODES)),\n homeDir: Shape2.plain.string().nullable()\n});\nvar ROOM_EPHEMERAL_DECLARATIONS = {\n capabilities: MachineCapabilitiesEphemeral\n};\nexport {\n updateTaskInIndex,\n toTaskId,\n toSessionId,\n removeTaskFromIndex,\n parseEpochParam,\n parseEpochFromReason,\n parseDocumentId,\n isEpochValid,\n isEpochRejection,\n generateTaskId,\n generateSessionId,\n formatEpochCloseReason,\n extractPlanMarkdown,\n classifyToolRisk,\n buildDocumentId,\n addTaskToIndex,\n TaskIndexEntryShape,\n TaskIndexDocumentSchema,\n TaskDocumentSchema,\n TOOL_RISK_LEVELS,\n Shape3 as Shape,\n SessionEntryShape,\n SESSION_STATES,\n ROOM_EPHEMERAL_DECLARATIONS,\n REASONING_EFFORTS,\n PlanVersionShape,\n PermissionResponseEphemeral,\n PermissionRequestEphemeral,\n PLAN_REVIEW_STATUSES,\n PERMISSION_MODES,\n PERMISSION_DECISIONS,\n MessageShape,\n MachineCapabilitiesEphemeral,\n LOCAL_USER_ID,\n EpochDocumentSchema,\n EPOCH_CLOSE_CODES,\n DiffStateShape,\n DiffCommentShape,\n DIFF_COMMENT_SIDES,\n DIFF_COMMENT_SCOPES,\n DEFAULT_EPOCH,\n ContentBlockShape,\n CONTENT_BLOCK_TYPES,\n COMMENT_AUTHOR_TYPES,\n A2A_TASK_STATES\n};\n","import type { Dirent } from 'node:fs';\nimport { mkdir, readdir, readFile, rename, unlink, writeFile } from 'node:fs/promises';\nimport { dirname, join, sep } from 'node:path';\nimport { type Chunk, StorageAdapter, type StorageKey } from '@loro-extended/repo';\n\nexport class FileStorageAdapter extends StorageAdapter {\n readonly #dataDir: string;\n\n constructor(dataDir: string) {\n super({ adapterType: 'file' });\n this.#dataDir = dataDir;\n }\n\n async load(key: StorageKey): Promise<Uint8Array | undefined> {\n const filePath = this.#keyToPath(key);\n try {\n const buffer = await readFile(filePath);\n return new Uint8Array(buffer);\n } catch {}\n return undefined;\n }\n\n async save(key: StorageKey, data: Uint8Array): Promise<void> {\n const filePath = this.#keyToPath(key);\n const dir = dirname(filePath);\n await mkdir(dir, { recursive: true, mode: 0o700 });\n\n const tmpPath = `${filePath}.tmp`;\n await writeFile(tmpPath, data, { mode: 0o600 });\n await rename(tmpPath, filePath);\n }\n\n async remove(key: StorageKey): Promise<void> {\n const filePath = this.#keyToPath(key);\n try {\n await unlink(filePath);\n } catch {}\n }\n\n async loadRange(keyPrefix: StorageKey): Promise<Chunk[]> {\n const results: Chunk[] = [];\n await this.#walkDir(this.#dataDir, keyPrefix, results);\n return results;\n }\n\n async removeRange(keyPrefix: StorageKey): Promise<void> {\n const chunks = await this.loadRange(keyPrefix);\n await Promise.all(chunks.map((chunk) => this.remove(chunk.key)));\n }\n\n #keyToPath(key: StorageKey): string {\n const sanitized = key.map((part) => encodeURIComponent(part));\n return join(this.#dataDir, ...sanitized);\n }\n\n #pathToKey(filePath: string): StorageKey {\n const relative = filePath.slice(this.#dataDir.length + 1);\n return relative.split(sep).map((part) => decodeURIComponent(part));\n }\n\n #isPrefix(prefix: StorageKey, key: StorageKey): boolean {\n if (prefix.length > key.length) return false;\n return prefix.every((val, i) => val === key[i]);\n }\n\n async #walkDir(dir: string, keyPrefix: StorageKey, results: Chunk[]): Promise<void> {\n let entries: Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n await this.#walkDir(fullPath, keyPrefix, results);\n } else if (entry.isFile() && !entry.name.endsWith('.tmp')) {\n const key = this.#pathToKey(fullPath);\n if (this.#isPrefix(keyPrefix, key)) {\n const data = await readFile(fullPath);\n results.push({ key, data: new Uint8Array(data) });\n }\n }\n }\n }\n}\n","import pino from 'pino';\n\nexport const logger = pino({\n level: process.env.LOG_LEVEL ?? 'info',\n transport:\n process.env.NODE_ENV !== 'production'\n ? { target: 'pino-pretty', options: { colorize: true } }\n : undefined,\n});\n\nexport function createChildLogger(context: { taskId?: string; sessionId?: string; mode?: string }) {\n return logger.child(context);\n}\n","import { logger } from './logger.js';\n\n/**\n * Manages graceful shutdown for the daemon process.\n *\n * Tracks active AbortControllers so all in-flight agent sessions can be\n * cancelled on SIGTERM/SIGINT. Runs registered shutdown callbacks\n * (e.g., repo.shutdown()) before exiting.\n */\nexport class LifecycleManager {\n #abortControllers = new Set<AbortController>();\n #shutdownCallbacks: Array<() => Promise<void>> = [];\n #isShuttingDown = false;\n #signalHandlers: { signal: string; handler: () => void }[] = [];\n\n constructor() {\n const termHandler = () => void this.#shutdown('SIGTERM');\n const intHandler = () => void this.#shutdown('SIGINT');\n process.on('SIGTERM', termHandler);\n process.on('SIGINT', intHandler);\n this.#signalHandlers = [\n { signal: 'SIGTERM', handler: termHandler },\n { signal: 'SIGINT', handler: intHandler },\n ];\n }\n\n destroy(): void {\n for (const { signal, handler } of this.#signalHandlers) {\n process.removeListener(signal, handler);\n }\n this.#signalHandlers = [];\n this.#isShuttingDown = false;\n this.#shutdownCallbacks = [];\n this.#abortControllers.clear();\n }\n\n /**\n * Create an AbortController tracked by this manager.\n * On shutdown, all tracked controllers are aborted.\n * Controllers self-remove from tracking when aborted.\n */\n createAbortController(): AbortController {\n const controller = new AbortController();\n this.#abortControllers.add(controller);\n controller.signal.addEventListener('abort', () => {\n this.#abortControllers.delete(controller);\n });\n return controller;\n }\n\n /**\n * Register a callback to run during shutdown (e.g., repo.shutdown()).\n * Callbacks run sequentially in registration order.\n */\n onShutdown(callback: () => Promise<void>): void {\n this.#shutdownCallbacks.push(callback);\n }\n\n async #shutdown(signal: string): Promise<void> {\n if (this.#isShuttingDown) return;\n this.#isShuttingDown = true;\n\n logger.info({ signal }, 'Shutdown signal received');\n\n for (const controller of this.#abortControllers) {\n controller.abort();\n }\n this.#abortControllers.clear();\n\n for (const callback of this.#shutdownCallbacks) {\n try {\n await callback();\n } catch (error) {\n logger.error({ error }, 'Error during shutdown callback');\n }\n }\n\n logger.info('Shutdown complete');\n await new Promise((resolve) => setTimeout(resolve, 100));\n process.exit(0);\n }\n}\n","import { mkdir } from 'node:fs/promises';\nimport { homedir, hostname } from 'node:os';\nimport { resolve } from 'node:path';\nimport type { CanUseTool, PermissionResult } from '@anthropic-ai/claude-agent-sdk';\nimport { WebRtcDataChannelAdapter } from '@loro-extended/adapter-webrtc';\nimport { change, type TypedDoc } from '@loro-extended/change';\nimport type { HandleWithEphemerals } from '@loro-extended/repo';\nimport { Repo } from '@loro-extended/repo';\nimport {\n buildDocumentId,\n classifyToolRisk,\n DEFAULT_EPOCH,\n LOCAL_USER_ID,\n type MachineCapabilitiesEphemeralValue,\n type PermissionDecision,\n PermissionRequestEphemeral,\n PermissionResponseEphemeral,\n ROOM_EPHEMERAL_DECLARATIONS,\n TaskDocumentSchema,\n type TaskDocumentShape,\n TaskIndexDocumentSchema,\n type TaskIndexDocumentShape,\n updateTaskInIndex,\n} from '@shipyard/loro-schema';\nimport type { PersonalRoomServerMessage } from '@shipyard/session';\nimport { createBranchWatcher } from './branch-watcher.js';\nimport {\n captureTreeSnapshot,\n getBranchDiff,\n getBranchFiles,\n getChangedFiles,\n getDefaultBranch,\n getSnapshotDiff,\n getSnapshotFiles,\n getStagedDiff,\n getUnstagedDiff,\n} from './capabilities.js';\nimport type { Env } from './env.js';\nimport { FileStorageAdapter } from './file-storage-adapter.js';\nimport { LifecycleManager } from './lifecycle.js';\nimport { createChildLogger, logger } from './logger.js';\nimport {\n createPeerManager,\n type ICECandidate,\n type PeerManager,\n type SDPDescription,\n} from './peer-manager.js';\nimport { createPtyManager, type PtyManager } from './pty-manager.js';\nimport {\n SessionManager,\n type SessionResult,\n type StatusChangeCallback,\n} from './session-manager.js';\nimport type { DaemonSignaling } from './signaling.js';\nimport { createSignalingHandle } from './signaling-setup.js';\n\nfunction assertNever(x: never): never {\n throw new Error(`Unhandled message type: ${JSON.stringify(x)}`);\n}\n\ninterface TerminalDataChannel {\n send(data: string): void;\n close(): void;\n readyState?: string;\n onmessage: ((event: { data: string | ArrayBuffer }) => void) | null;\n onclose: (() => void) | null;\n}\n\nconst CONTROL_PREFIX = '\\x00\\x01\\x00';\nconst TERMINAL_BUFFER_MAX_BYTES = 1_048_576;\nconst TERMINAL_OPEN_TIMEOUT_MS = 10_000;\nconst TERMINAL_CWD_TIMEOUT_MS = 5_000;\n\n/**\n * Determine the best cwd for a new terminal session by checking the most\n * recently active task's cwd. Falls back to process.cwd().\n */\nfunction resolveTerminalCwd(\n activeTasks: Map<string, ActiveTask>,\n watchedTasks: Map<string, () => void>,\n repo: Repo\n): string {\n for (const taskId of activeTasks.keys()) {\n const epoch = DEFAULT_EPOCH;\n const taskDocId = buildDocumentId('task', taskId, epoch);\n try {\n const handle = repo.get(taskDocId, TaskDocumentSchema);\n const json = handle.doc.toJSON();\n const lastUserMsg = [...json.conversation].reverse().find((m) => m.role === 'user');\n if (lastUserMsg?.cwd) return lastUserMsg.cwd;\n } catch {\n // Skip if doc not available\n }\n }\n\n for (const taskId of watchedTasks.keys()) {\n if (activeTasks.has(taskId)) continue;\n const epoch = DEFAULT_EPOCH;\n const taskDocId = buildDocumentId('task', taskId, epoch);\n try {\n const handle = repo.get(taskDocId, TaskDocumentSchema);\n const json = handle.doc.toJSON();\n const lastUserMsg = [...json.conversation].reverse().find((m) => m.role === 'user');\n if (lastUserMsg?.cwd) return lastUserMsg.cwd;\n } catch {\n // Skip if doc not available\n }\n }\n\n return process.cwd();\n}\n\n/**\n * Ephemeral namespace declarations for task documents.\n * permReqs: daemon writes pending tool permission requests (browser reads)\n * permResps: browser writes permission decisions (daemon reads)\n */\nconst TaskEphemeralDeclarations = {\n permReqs: PermissionRequestEphemeral,\n permResps: PermissionResponseEphemeral,\n};\n\ntype TaskEphemeralDecls = typeof TaskEphemeralDeclarations;\ntype TaskHandle = HandleWithEphemerals<TaskDocumentShape, TaskEphemeralDecls>;\n\ninterface ActiveTask {\n taskId: string;\n abortController: AbortController;\n sessionManager: SessionManager;\n}\n\n/**\n * Run the daemon in serve mode: connect to signaling, register capabilities,\n * and stay alive waiting for task notifications via CRDT subscriptions.\n *\n * The process stays alive until SIGINT or SIGTERM is received, at which point\n * LifecycleManager gracefully shuts down and exits.\n */\nexport async function serve(env: Env): Promise<void> {\n if (!env.SHIPYARD_SIGNALING_URL) {\n logger.error('SHIPYARD_SIGNALING_URL is required for serve mode');\n process.exit(1);\n }\n\n const log = createChildLogger({ mode: 'serve' });\n const lifecycle = new LifecycleManager();\n\n const handle = await createSignalingHandle(env, log);\n if (!handle) {\n logger.error('SHIPYARD_SIGNALING_URL is required for serve mode');\n process.exit(1);\n }\n\n const { signaling, connection, capabilities } = handle;\n const activeTasks = new Map<string, ActiveTask>();\n const watchedTasks = new Map<string, () => void>();\n\n const machineId = env.SHIPYARD_MACHINE_ID ?? hostname();\n\n const dataDir = resolve(env.SHIPYARD_DATA_DIR.replace('~', homedir()));\n await mkdir(dataDir, { recursive: true, mode: 0o700 });\n\n const storage = new FileStorageAdapter(dataDir);\n const webrtcAdapter = new WebRtcDataChannelAdapter();\n const repo = new Repo({\n identity: { name: 'shipyard-daemon' },\n adapters: [storage, webrtcAdapter],\n });\n\n const terminalPtys = new Map<string, PtyManager>();\n\n const peerManager = createPeerManager({\n webrtcAdapter,\n onAnswer(targetMachineId, answer) {\n connection.send({\n type: 'webrtc-answer',\n targetMachineId,\n answer,\n });\n },\n onIceCandidate(targetMachineId, candidate) {\n connection.send({\n type: 'webrtc-ice',\n targetMachineId,\n candidate,\n });\n },\n onTerminalChannel(fromMachineId, rawChannel) {\n // eslint-disable-next-line no-restricted-syntax -- node-datachannel channel type is opaque\n const channel = rawChannel as TerminalDataChannel;\n const termLog = createChildLogger({ mode: `terminal:${fromMachineId}` });\n\n const existingPty = terminalPtys.get(fromMachineId);\n if (existingPty) {\n termLog.info('Disposing existing PTY for reconnecting machine');\n existingPty.dispose();\n terminalPtys.delete(fromMachineId);\n }\n\n const ptyManager = createPtyManager();\n terminalPtys.set(fromMachineId, ptyManager);\n let ptySpawned = false;\n\n /**\n * Buffer PTY output until the data channel is fully open.\n *\n * node-datachannel fires ondatachannel when the remote-created channel\n * arrives, but the channel may still be in \"connecting\" state. Calling\n * send() before it transitions to \"open\" throws InvalidStateError,\n * which silently drops the shell prompt and any early output -- resulting\n * in a blank xterm.js screen on the browser side.\n */\n let channelOpen = channel.readyState === 'open';\n const pendingBuffer: string[] = [];\n let pendingBufferBytes = 0;\n\n /** Buffer user input that arrives before the PTY is spawned. */\n const preSpawnInputBuffer: string[] = [];\n\n function disposeAndClose(reason: string): void {\n termLog.warn({ reason }, 'Disposing terminal');\n clearTimeout(openTimeout);\n clearTimeout(cwdTimeout);\n ptyManager.dispose();\n terminalPtys.delete(fromMachineId);\n if (channel.readyState === 'open') {\n channel.close();\n }\n }\n\n function flushPendingBuffer(): void {\n for (const chunk of pendingBuffer) {\n try {\n channel.send(chunk);\n } catch {\n // Channel may have closed during flush\n }\n }\n pendingBuffer.length = 0;\n pendingBufferBytes = 0;\n }\n\n function sendOrBuffer(data: string): void {\n if (channelOpen) {\n try {\n channel.send(data);\n } catch {\n // Channel may have closed between check and send\n }\n } else {\n const byteLen = Buffer.byteLength(data);\n if (pendingBufferBytes + byteLen > TERMINAL_BUFFER_MAX_BYTES) {\n disposeAndClose('Pending buffer exceeded max size');\n return;\n }\n pendingBuffer.push(data);\n pendingBufferBytes += byteLen;\n }\n }\n\n /** Timeout: if channel never opens, clean up. */\n const openTimeout = setTimeout(() => {\n if (!channelOpen) {\n disposeAndClose('Data channel did not open within timeout');\n }\n }, TERMINAL_OPEN_TIMEOUT_MS);\n\n // eslint-disable-next-line no-restricted-syntax -- node-datachannel polyfill RTCDataChannel extends EventTarget\n const dcAsEventTarget = rawChannel as unknown as EventTarget;\n dcAsEventTarget.addEventListener('open', () => {\n termLog.info('Terminal data channel now open, flushing buffered output');\n channelOpen = true;\n clearTimeout(openTimeout);\n flushPendingBuffer();\n });\n\n /**\n * Spawn the PTY with the given cwd, wire up data/exit handlers,\n * and flush any pre-spawn user input.\n */\n function spawnPty(cwd: string): void {\n if (ptySpawned) return;\n ptySpawned = true;\n clearTimeout(cwdTimeout);\n\n try {\n ptyManager.spawn({ cwd });\n } catch (err: unknown) {\n termLog.error({ err }, 'Failed to spawn terminal PTY');\n channel.close();\n terminalPtys.delete(fromMachineId);\n return;\n }\n\n ptyManager.onData((data) => {\n sendOrBuffer(data);\n });\n\n ptyManager.onExit((exitCode, signal) => {\n termLog.info({ exitCode, signal }, 'Terminal PTY exited');\n if (channel.readyState === 'open') {\n channel.close();\n }\n terminalPtys.delete(fromMachineId);\n });\n\n for (const input of preSpawnInputBuffer) {\n try {\n ptyManager.write(input);\n } catch {\n // PTY may have exited\n }\n }\n preSpawnInputBuffer.length = 0;\n\n termLog.info(\n { cwd, pid: ptyManager.pid, channelReady: channelOpen },\n 'Terminal PTY wired to data channel'\n );\n }\n\n /** Timeout: if no cwd message arrives, fall back to heuristic. */\n const cwdTimeout = setTimeout(() => {\n if (!ptySpawned) {\n termLog.info('No cwd control message received, falling back to heuristic');\n const fallbackCwd = resolveTerminalCwd(activeTasks, watchedTasks, repo);\n spawnPty(fallbackCwd);\n }\n }, TERMINAL_CWD_TIMEOUT_MS);\n\n function handleControlMessage(payload: string): void {\n try {\n // eslint-disable-next-line no-restricted-syntax -- JSON.parse returns unknown; fields validated on next lines\n const ctrl = JSON.parse(payload) as {\n type: string;\n cols?: number;\n rows?: number;\n path?: string;\n };\n if (ctrl.type === 'cwd' && typeof ctrl.path === 'string') {\n spawnPty(ctrl.path);\n } else if (\n ctrl.type === 'resize' &&\n typeof ctrl.cols === 'number' &&\n typeof ctrl.rows === 'number' &&\n ptySpawned\n ) {\n ptyManager.resize(ctrl.cols, ctrl.rows);\n }\n } catch {\n termLog.warn('Invalid control message received');\n }\n }\n\n function handleDataInput(raw: string): void {\n if (!ptySpawned) {\n preSpawnInputBuffer.push(raw);\n return;\n }\n try {\n ptyManager.write(raw);\n } catch {\n // PTY may have exited\n }\n }\n\n channel.onmessage = (event) => {\n const raw =\n typeof event.data === 'string' ? event.data : new TextDecoder().decode(event.data);\n if (raw.startsWith(CONTROL_PREFIX)) {\n handleControlMessage(raw.slice(CONTROL_PREFIX.length));\n } else {\n handleDataInput(raw);\n }\n };\n\n channel.onclose = () => {\n termLog.info('Terminal data channel closed');\n channelOpen = false;\n clearTimeout(openTimeout);\n clearTimeout(cwdTimeout);\n ptyManager.dispose();\n terminalPtys.delete(fromMachineId);\n };\n },\n });\n\n /**\n * Write machine capabilities to the room document's ephemeral namespace.\n * The browser reads these to populate model/environment/permission pickers.\n * Keyed by machineId so each machine's capabilities are addressable.\n */\n const roomDocId = buildDocumentId('room', LOCAL_USER_ID, DEFAULT_EPOCH);\n // eslint-disable-next-line no-restricted-syntax -- loro-extended generics require explicit cast\n const roomHandle = repo.get(\n roomDocId,\n TaskIndexDocumentSchema as never,\n ROOM_EPHEMERAL_DECLARATIONS\n );\n\n function publishCapabilities(caps: typeof capabilities): void {\n const value: MachineCapabilitiesEphemeralValue = {\n models: caps.models.map((m) => ({\n ...m,\n reasoning: m.reasoning ?? null,\n })),\n environments: caps.environments.map((e) => ({\n ...e,\n remote: e.remote ?? null,\n })),\n permissionModes: caps.permissionModes,\n homeDir: caps.homeDir ?? null,\n };\n roomHandle.capabilities.set(machineId, value);\n log.info({ machineId }, 'Published capabilities to room ephemeral');\n }\n\n publishCapabilities(capabilities);\n\n const branchWatcher = createBranchWatcher({\n environments: capabilities.environments,\n onUpdate: (updatedEnvs) => {\n capabilities.environments = updatedEnvs;\n publishCapabilities(capabilities);\n },\n });\n\n connection.onStateChange((state) => {\n log.info({ state }, 'Connection state changed');\n });\n\n connection.onMessage((msg) => {\n handleMessage(msg, {\n log,\n signaling,\n connection,\n repo,\n roomDoc: roomHandle.doc as TypedDoc<TaskIndexDocumentShape>,\n lifecycle,\n activeTasks,\n watchedTasks,\n peerManager,\n env,\n machineId,\n });\n });\n\n connection.connect();\n\n log.info('Daemon running in serve mode, waiting for tasks...');\n\n lifecycle.onShutdown(async () => {\n log.info('Shutting down serve mode...');\n\n branchWatcher.close();\n\n for (const task of activeTasks.values()) {\n task.sessionManager.closeSession();\n task.abortController.abort();\n }\n activeTasks.clear();\n for (const timer of diffDebounceTimers.values()) {\n clearTimeout(timer);\n }\n diffDebounceTimers.clear();\n for (const timer of branchDiffTimers.values()) {\n clearTimeout(timer);\n }\n branchDiffTimers.clear();\n for (const unsub of watchedTasks.values()) {\n unsub();\n }\n watchedTasks.clear();\n\n for (const [id, ptyMgr] of terminalPtys) {\n ptyMgr.dispose();\n terminalPtys.delete(id);\n }\n\n peerManager.destroy();\n signaling.unregister();\n await new Promise((resolve) => setTimeout(resolve, 200));\n signaling.destroy();\n connection.disconnect();\n repo.reset();\n });\n\n /** Block forever. LifecycleManager handles SIGINT/SIGTERM and calls process.exit(0). */\n await new Promise<never>(() => {});\n}\n\ninterface MessageHandlerContext {\n log: ReturnType<typeof createChildLogger>;\n signaling: DaemonSignaling;\n connection: { send: (msg: import('@shipyard/session').PersonalRoomClientMessage) => void };\n repo: Repo;\n roomDoc: TypedDoc<TaskIndexDocumentShape>;\n lifecycle: LifecycleManager;\n activeTasks: Map<string, ActiveTask>;\n watchedTasks: Map<string, () => void>;\n peerManager: PeerManager;\n env: Env;\n machineId: string;\n}\n\nconst DIFF_DEBOUNCE_MS = 2_000;\nconst BRANCH_DIFF_DEBOUNCE_MS = 10_000;\nconst diffDebounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\nconst branchDiffTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\nfunction debouncedDiffCapture(\n taskId: string,\n cwd: string,\n taskHandle: TaskHandle,\n log: ReturnType<typeof createChildLogger>\n): void {\n const existing = diffDebounceTimers.get(taskId);\n if (existing) clearTimeout(existing);\n\n diffDebounceTimers.set(\n taskId,\n setTimeout(() => {\n diffDebounceTimers.delete(taskId);\n captureDiffState(cwd, taskHandle, log).catch((err: unknown) => {\n log.warn({ err }, 'Failed to capture diff state');\n });\n }, DIFF_DEBOUNCE_MS)\n );\n}\n\nasync function captureDiffState(\n cwd: string,\n taskHandle: TaskHandle,\n log: ReturnType<typeof createChildLogger>\n): Promise<void> {\n const [unstaged, staged, files] = await Promise.all([\n getUnstagedDiff(cwd),\n getStagedDiff(cwd),\n getChangedFiles(cwd),\n ]);\n change(taskHandle.doc, (draft) => {\n draft.diffState.unstaged = unstaged;\n draft.diffState.staged = staged;\n const fileList = draft.diffState.files;\n if (fileList.length > 0) {\n fileList.delete(0, fileList.length);\n }\n for (const file of files) {\n fileList.push(file);\n }\n draft.diffState.updatedAt = Date.now();\n });\n log.debug({ fileCount: files.length }, 'Diff state captured');\n}\n\nfunction debouncedBranchDiffCapture(\n taskId: string,\n cwd: string,\n taskHandle: TaskHandle,\n log: ReturnType<typeof createChildLogger>\n): void {\n const existing = branchDiffTimers.get(taskId);\n if (existing) clearTimeout(existing);\n\n branchDiffTimers.set(\n taskId,\n setTimeout(() => {\n branchDiffTimers.delete(taskId);\n captureBranchDiffState(cwd, taskHandle, log).catch((err: unknown) => {\n log.warn({ err }, 'Failed to capture branch diff state');\n });\n }, BRANCH_DIFF_DEBOUNCE_MS)\n );\n}\n\nasync function captureBranchDiffState(\n cwd: string,\n taskHandle: TaskHandle,\n log: ReturnType<typeof createChildLogger>\n): Promise<void> {\n const baseBranch = await getDefaultBranch(cwd);\n if (!baseBranch) {\n log.debug('No default branch found, skipping branch diff');\n return;\n }\n\n const [branchDiff, branchFiles] = await Promise.all([\n getBranchDiff(cwd, baseBranch),\n getBranchFiles(cwd, baseBranch),\n ]);\n\n change(taskHandle.doc, (draft) => {\n draft.diffState.branchDiff = branchDiff;\n draft.diffState.branchBase = baseBranch;\n const fileList = draft.diffState.branchFiles;\n if (fileList.length > 0) {\n fileList.delete(0, fileList.length);\n }\n for (const file of branchFiles) {\n fileList.push(file);\n }\n draft.diffState.branchUpdatedAt = Date.now();\n });\n log.debug({ baseBranch, fileCount: branchFiles.length }, 'Branch diff state captured');\n}\n\nasync function captureTurnDiff(\n cwd: string,\n turnStartRef: string | null,\n taskHandle: TaskHandle,\n log: ReturnType<typeof createChildLogger>\n): Promise<void> {\n const turnEndRef = await captureTreeSnapshot(cwd);\n if (!turnStartRef || !turnEndRef) {\n log.debug('No turn diff to capture (refs missing)');\n return;\n }\n\n let turnDiff = '';\n let turnFiles: Array<{ path: string; status: string }> = [];\n\n if (turnStartRef !== turnEndRef) {\n [turnDiff, turnFiles] = await Promise.all([\n getSnapshotDiff(cwd, turnStartRef, turnEndRef),\n getSnapshotFiles(cwd, turnStartRef, turnEndRef),\n ]);\n }\n\n if (!turnDiff && turnFiles.length === 0) {\n [turnDiff, turnFiles] = await Promise.all([getUnstagedDiff(cwd), getChangedFiles(cwd)]);\n }\n\n if (!turnDiff && turnFiles.length === 0) {\n log.debug('No turn diff to capture (no changes)');\n return;\n }\n\n change(taskHandle.doc, (draft) => {\n draft.diffState.lastTurnDiff = turnDiff;\n const fileList = draft.diffState.lastTurnFiles;\n if (fileList.length > 0) {\n fileList.delete(0, fileList.length);\n }\n for (const file of turnFiles) {\n fileList.push(file);\n }\n draft.diffState.lastTurnUpdatedAt = Date.now();\n });\n log.debug({ fromRef: turnStartRef, toRef: turnEndRef }, 'Turn diff captured');\n}\n\nfunction handleMessage(msg: PersonalRoomServerMessage, ctx: MessageHandlerContext): void {\n switch (msg.type) {\n case 'agents-list':\n ctx.log.info({ count: msg.agents.length }, 'Agents online');\n break;\n\n case 'notify-task':\n handleNotifyTask(msg, ctx);\n break;\n\n case 'task-ack':\n ctx.log.debug({ requestId: msg.requestId, taskId: msg.taskId }, 'Received task-ack echo');\n break;\n\n case 'webrtc-offer': {\n const offerFrom = msg.fromMachineId ?? msg.targetMachineId;\n ctx.log.debug({ from: offerFrom }, 'Received WebRTC offer');\n // eslint-disable-next-line no-restricted-syntax -- WebRTC payloads are opaque (z.unknown) bridged to node-datachannel API\n ctx.peerManager.handleOffer(offerFrom, msg.offer as SDPDescription).catch((err: unknown) => {\n ctx.log.error({ err, from: offerFrom }, 'Failed to handle WebRTC offer');\n });\n break;\n }\n\n case 'webrtc-answer': {\n const answerFrom = msg.fromMachineId ?? msg.targetMachineId;\n ctx.log.debug({ from: answerFrom }, 'Received WebRTC answer');\n // eslint-disable-next-line no-restricted-syntax -- WebRTC payloads are opaque (z.unknown) bridged to node-datachannel API\n ctx.peerManager\n .handleAnswer(answerFrom, msg.answer as SDPDescription)\n .catch((err: unknown) => {\n ctx.log.error({ err, from: answerFrom }, 'Failed to handle WebRTC answer');\n });\n break;\n }\n\n case 'webrtc-ice': {\n const iceFrom = msg.fromMachineId ?? msg.targetMachineId;\n ctx.log.debug({ from: iceFrom }, 'Received WebRTC ICE candidate');\n // eslint-disable-next-line no-restricted-syntax -- WebRTC payloads are opaque (z.unknown) bridged to node-datachannel API\n ctx.peerManager.handleIce(iceFrom, msg.candidate as ICECandidate).catch((err: unknown) => {\n ctx.log.error({ err, from: iceFrom }, 'Failed to handle WebRTC ICE');\n });\n break;\n }\n\n case 'authenticated':\n case 'agent-joined':\n case 'agent-left':\n case 'agent-status-changed':\n case 'error':\n ctx.log.debug({ type: msg.type }, 'Server notification');\n break;\n\n default:\n assertNever(msg);\n }\n}\n\n/**\n * Handle a notify-task message from the browser (relayed via signaling).\n *\n * This is a content-free discovery signal. The browser sends it when:\n * 1. A new task is created (primary trigger for daemon to start watching)\n * 2. Daemon restarts and browser re-sends for active tasks (recovery)\n *\n * The daemon responds with task-ack and begins watching the task document.\n */\nfunction handleNotifyTask(\n msg: Extract<PersonalRoomServerMessage, { type: 'notify-task' }>,\n ctx: MessageHandlerContext\n): void {\n const { taskId, requestId } = msg;\n const taskLog = createChildLogger({ mode: 'serve', taskId });\n\n if (!ctx.env.ANTHROPIC_API_KEY) {\n taskLog.error('ANTHROPIC_API_KEY is required to run agents');\n ctx.connection.send({\n type: 'task-ack',\n requestId,\n taskId,\n accepted: false,\n error: 'ANTHROPIC_API_KEY not configured on daemon',\n });\n return;\n }\n\n if (ctx.watchedTasks.has(taskId)) {\n taskLog.debug('Task already watched, sending ack');\n ctx.connection.send({\n type: 'task-ack',\n requestId,\n taskId,\n accepted: true,\n });\n return;\n }\n\n taskLog.info('Received notify-task, starting watch');\n\n ctx.connection.send({\n type: 'task-ack',\n requestId,\n taskId,\n accepted: true,\n });\n\n watchTaskDocument(taskId, taskLog, ctx).catch((err: unknown) => {\n const errMsg = err instanceof Error ? err.message : String(err);\n taskLog.error({ err: errMsg }, 'Failed to start watching task document');\n });\n}\n\n/**\n * Subscribe to a task document's conversation changes and react when\n * a new user message arrives.\n *\n * Detection algorithm:\n * 1. Get the task handle from the repo (triggers Loro new-doc sync if needed)\n * 2. Wait for storage sync to load any persisted state\n * 3. Subscribe to the conversation list via the handle's path-based subscription\n * 4. On each change where data was imported (remote):\n * - Check if last message role === 'user' AND meta.status !== 'working'\n * - Read config for model/cwd/permissionMode\n * - Check sessions: empty -> createSession(), has agentSessionId -> resumeSession()\n * - Set meta.status = 'working'\n */\nasync function watchTaskDocument(\n taskId: string,\n taskLog: ReturnType<typeof createChildLogger>,\n ctx: MessageHandlerContext\n): Promise<void> {\n const epoch = DEFAULT_EPOCH;\n const taskDocId = buildDocumentId('task', taskId, epoch);\n taskLog.info({ taskDocId, epoch }, 'Watching task document');\n\n const taskHandle = ctx.repo.get(taskDocId, TaskDocumentSchema, TaskEphemeralDeclarations);\n\n try {\n await taskHandle.waitForSync({ kind: 'storage', timeout: 5_000 });\n } catch {\n taskLog.debug({ taskDocId }, 'No existing task data in storage');\n }\n\n const json = taskHandle.doc.toJSON();\n const lastUserMsg = [...json.conversation].reverse().find((m) => m.role === 'user');\n const initialCwd = lastUserMsg?.cwd ?? process.cwd();\n captureBranchDiffState(initialCwd, taskHandle, taskLog).catch((err: unknown) => {\n taskLog.warn({ err }, 'Failed to capture initial branch diff');\n });\n\n const opCountBefore = taskHandle.loroDoc.opCount();\n taskLog.info({ taskDocId, opCount: opCountBefore }, 'Doc state before subscribe');\n\n const unsubscribe = taskHandle.subscribe((event) => {\n taskLog.info({ taskDocId, eventBy: event.by }, 'Subscription event received');\n if (event.by === 'local') return;\n\n onTaskDocChanged(taskId, taskHandle, taskLog, ctx);\n });\n\n ctx.watchedTasks.set(taskId, unsubscribe);\n taskLog.info({ taskDocId }, 'Subscribed to task document changes');\n\n /**\n * Also check immediately in case the doc already has a pending user message\n * (daemon restart scenario where the browser already wrote the message).\n */\n const opCountAfter = taskHandle.loroDoc.opCount();\n taskLog.info({ taskDocId, opCount: opCountAfter }, 'Doc state after subscribe');\n if (opCountAfter > 0) {\n const json = taskHandle.doc.toJSON();\n taskLog.info(\n { taskDocId, status: json.meta.status, conversationLen: json.conversation.length },\n 'Checking existing doc data'\n );\n onTaskDocChanged(taskId, taskHandle, taskLog, ctx);\n }\n}\n\nfunction handleFollowUp(\n activeTask: ActiveTask | undefined,\n taskLog: ReturnType<typeof createChildLogger>\n): void {\n if (!activeTask) return;\n if (!activeTask.sessionManager.isStreaming) {\n taskLog.debug('Task already running but not streaming, skipping');\n return;\n }\n const prompt = activeTask.sessionManager.getLatestUserPrompt();\n if (prompt) {\n try {\n taskLog.info('Sending follow-up to active streaming session');\n activeTask.sessionManager.sendFollowUp(prompt);\n } catch (err: unknown) {\n taskLog.warn({ err }, 'Failed to send follow-up to streaming session');\n }\n }\n}\n\n/**\n * Called when a task document changes (from a remote import).\n * Checks if there is new work to do and dispatches accordingly.\n */\nfunction onTaskDocChanged(\n taskId: string,\n taskHandle: TaskHandle,\n taskLog: ReturnType<typeof createChildLogger>,\n ctx: MessageHandlerContext\n): void {\n const doc = taskHandle.doc;\n const json = doc.toJSON();\n\n taskLog.info(\n {\n status: json.meta.status,\n conversationLen: json.conversation.length,\n lastRole: json.conversation[json.conversation.length - 1]?.role,\n isActive: ctx.activeTasks.has(taskId),\n },\n 'onTaskDocChanged evaluation'\n );\n\n if (ctx.activeTasks.has(taskId)) {\n const conversation = json.conversation;\n const lastMessage = conversation[conversation.length - 1];\n if (lastMessage?.role === 'user') {\n handleFollowUp(ctx.activeTasks.get(taskId), taskLog);\n }\n\n const activeLastUserMsg = [...conversation].reverse().find((m) => m.role === 'user');\n const activeCwd = activeLastUserMsg?.cwd ?? process.cwd();\n debouncedDiffCapture(taskId, activeCwd, taskHandle, taskLog);\n debouncedBranchDiffCapture(taskId, activeCwd, taskHandle, taskLog);\n return;\n }\n\n if (\n json.meta.status === 'working' ||\n json.meta.status === 'input-required' ||\n json.meta.status === 'starting'\n ) {\n taskLog.debug({ status: json.meta.status }, 'Status blocks new work, skipping');\n return;\n }\n\n const conversation = json.conversation;\n if (conversation.length === 0) {\n taskLog.debug('No conversation messages, skipping');\n return;\n }\n\n const lastMessage = conversation[conversation.length - 1];\n if (!lastMessage || lastMessage.role !== 'user') {\n return;\n }\n\n taskLog.info('New user message detected, starting agent');\n\n const cwd = lastMessage.cwd ?? process.cwd();\n const model = lastMessage.model ?? undefined;\n const permissionMode = mapPermissionMode(lastMessage.permissionMode);\n const effort = lastMessage.reasoningEffort ?? undefined;\n\n const abortController = ctx.lifecycle.createAbortController();\n\n const onStatusChange: StatusChangeCallback = (status) => {\n updateTaskInIndex(ctx.roomDoc, taskId, { status, updatedAt: Date.now() });\n };\n const manager = new SessionManager(doc, onStatusChange);\n\n const activeTask: ActiveTask = { taskId, abortController, sessionManager: manager };\n ctx.activeTasks.set(taskId, activeTask);\n\n ctx.signaling.updateStatus('running', taskId);\n\n const turnStartRefPromise = captureTreeSnapshot(cwd);\n\n turnStartRefPromise\n .then((ref) => taskLog.debug({ turnStartRef: ref }, 'Captured turn start snapshot'))\n .catch((err: unknown) => taskLog.warn({ err }, 'Failed to capture turn start snapshot'));\n\n runTask({\n sessionManager: manager,\n taskHandle,\n taskId,\n roomDoc: ctx.roomDoc,\n cwd,\n model,\n permissionMode,\n effort,\n machineId: ctx.machineId,\n abortController,\n log: taskLog,\n })\n .then((result) => {\n taskLog.info(\n {\n sessionId: result.sessionId,\n status: result.status,\n totalCostUsd: result.totalCostUsd,\n durationMs: result.durationMs,\n },\n 'Task complete'\n );\n })\n .catch((err: unknown) => {\n const errMsg = err instanceof Error ? err.message : String(err);\n taskLog.error({ err: errMsg }, 'Task failed');\n })\n .finally(() =>\n cleanupTaskRun({\n taskId,\n cwd,\n taskHandle,\n taskLog,\n turnStartRefPromise,\n abortController,\n ctx,\n })\n );\n}\n\ninterface CleanupTaskRunOptions {\n taskId: string;\n cwd: string;\n taskHandle: TaskHandle;\n taskLog: ReturnType<typeof createChildLogger>;\n turnStartRefPromise: Promise<string | null>;\n abortController: AbortController;\n ctx: MessageHandlerContext;\n}\n\nasync function cleanupTaskRun(opts: CleanupTaskRunOptions): Promise<void> {\n const { taskId, cwd, taskHandle, taskLog, turnStartRefPromise, abortController, ctx } = opts;\n\n const activeTask = ctx.activeTasks.get(taskId);\n activeTask?.sessionManager.closeSession();\n\n clearDebouncedTimer(diffDebounceTimers, taskId);\n clearDebouncedTimer(branchDiffTimers, taskId);\n\n try {\n await captureDiffState(cwd, taskHandle, taskLog);\n } catch (err: unknown) {\n taskLog.warn({ err }, 'Failed to capture final diff state');\n }\n\n try {\n await captureBranchDiffState(cwd, taskHandle, taskLog);\n } catch (err: unknown) {\n taskLog.warn({ err }, 'Failed to capture final branch diff state');\n }\n\n try {\n const turnStartRef = await turnStartRefPromise;\n await captureTurnDiff(cwd, turnStartRef, taskHandle, taskLog);\n } catch (err: unknown) {\n taskLog.warn({ err }, 'Failed to capture turn diff');\n }\n\n abortController.abort();\n\n for (const [key] of taskHandle.permReqs.getAll()) {\n taskHandle.permReqs.delete(key);\n }\n for (const [key] of taskHandle.permResps.getAll()) {\n taskHandle.permResps.delete(key);\n }\n\n ctx.activeTasks.delete(taskId);\n const unsub = ctx.watchedTasks.get(taskId);\n if (unsub) {\n unsub();\n ctx.watchedTasks.delete(taskId);\n }\n ctx.signaling.updateStatus('idle');\n}\n\nfunction clearDebouncedTimer(\n timers: Map<string, ReturnType<typeof setTimeout>>,\n taskId: string\n): void {\n const timer = timers.get(taskId);\n if (timer) {\n clearTimeout(timer);\n timers.delete(taskId);\n }\n}\n\n/**\n * Map the CRDT permission mode string to the Agent SDK PermissionMode type.\n */\nfunction mapPermissionMode(\n mode: string | null\n): 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan' | undefined {\n switch (mode) {\n case 'accept-edits':\n return 'acceptEdits';\n case 'plan':\n return 'plan';\n case 'bypass':\n return 'bypassPermissions';\n case 'default':\n return 'default';\n default:\n return undefined;\n }\n}\n\n/**\n * Build a canUseTool callback that tunnels permission requests to the browser\n * via Loro ephemeral state and waits for the browser's response.\n *\n * Flow:\n * 1. Daemon writes a PermissionRequest to the permReqs ephemeral namespace (keyed by toolUseID)\n * 2. Daemon sets task status to 'input-required' via CRDT\n * 3. Daemon subscribes to permResps ephemeral namespace for the matching toolUseID\n * 4. Browser reads permReqs, shows UI, writes decision to permResps\n * 5. Daemon receives the response, cleans up ephemeral entries, resolves the promise\n *\n * Concurrent safety: Each tool call gets its own toolUseID key, so multiple\n * concurrent canUseTool calls do not interfere with each other.\n */\n/**\n * Convert a browser permission response into the Agent SDK's PermissionResult.\n *\n * `updatedInput` is set to the original input as a defensive identity\n * pass-through. The SDK uses `updatedInput ?? originalInput` internally,\n * so this is a no-op. If input modification is ever needed (e.g., letting\n * the browser edit tool input before approval), this is where it would go.\n *\n * `updatedPermissions` forwards the SDK's suggestions so the SDK can apply\n * session-scoped permission rules (e.g., \"allow Bash for this directory\").\n */\nfunction toPermissionResult(\n decision: PermissionDecision,\n input: Record<string, unknown>,\n suggestions: import('@anthropic-ai/claude-agent-sdk').PermissionUpdate[] | undefined,\n message: string | null\n): PermissionResult {\n if (decision === 'approved') {\n return {\n behavior: 'allow',\n updatedInput: input,\n updatedPermissions: suggestions,\n };\n }\n return {\n behavior: 'deny',\n message: message ?? 'User denied permission',\n };\n}\n\ninterface PermissionResponseContext {\n taskHandle: TaskHandle;\n roomDoc: TypedDoc<TaskIndexDocumentShape>;\n taskId: string;\n taskLog: ReturnType<typeof createChildLogger>;\n toolName: string;\n toolUseID: string;\n input: Record<string, unknown>;\n suggestions: import('@anthropic-ai/claude-agent-sdk').PermissionUpdate[] | undefined;\n value: { decision: string; persist: boolean; message: string | null };\n}\n\n/**\n * Process a browser permission response: clean up ephemeral entries,\n * update task status back to 'working', log the response, and return\n * the SDK-compatible PermissionResult.\n */\nfunction resolvePermissionResponse(ctx: PermissionResponseContext): PermissionResult {\n const { taskHandle, roomDoc, taskId, taskLog, toolName, toolUseID, input, suggestions, value } =\n ctx;\n\n taskHandle.permReqs.delete(toolUseID);\n taskHandle.permResps.delete(toolUseID);\n\n change(taskHandle.doc, (draft) => {\n draft.meta.status = 'working';\n draft.meta.updatedAt = Date.now();\n });\n updateTaskInIndex(roomDoc, taskId, { status: 'working', updatedAt: Date.now() });\n\n if (toolName === 'ExitPlanMode') {\n const plans = taskHandle.doc.toJSON().plans;\n const planIndex = plans.findIndex((p) => p.toolUseId === toolUseID);\n if (planIndex >= 0) {\n const reviewStatus = value.decision === 'approved' ? 'approved' : 'changes-requested';\n change(taskHandle.doc, (draft) => {\n const plan = draft.plans.get(planIndex);\n if (plan) {\n plan.reviewStatus = reviewStatus;\n plan.reviewFeedback = value.message ?? null;\n }\n });\n taskLog.info(\n { toolUseID, reviewStatus, hasFeedback: !!value.message },\n 'Updated plan reviewStatus in CRDT'\n );\n }\n }\n\n taskLog.info(\n {\n toolName,\n toolUseID,\n decision: value.decision,\n persist: value.persist,\n hasSuggestions: !!suggestions?.length,\n },\n 'Permission response received'\n );\n\n const decision = value.decision === 'approved' ? 'approved' : 'denied';\n return toPermissionResult(decision, input, suggestions, value.message);\n}\n\nfunction buildCanUseTool(\n taskHandle: TaskHandle,\n taskLog: ReturnType<typeof createChildLogger>,\n roomDoc: TypedDoc<TaskIndexDocumentShape>,\n taskId: string\n): CanUseTool {\n return async (toolName, input, options) => {\n const { signal, toolUseID, blockedPath, decisionReason, agentID, suggestions } = options;\n\n if (signal.aborted) {\n return { behavior: 'deny', message: 'Task was aborted' };\n }\n\n const riskLevel = classifyToolRisk(toolName, input);\n\n taskHandle.permReqs.set(toolUseID, {\n toolName,\n toolInput: JSON.stringify(input),\n riskLevel,\n reason: decisionReason ?? null,\n blockedPath: blockedPath ?? null,\n description: null,\n agentId: agentID ?? null,\n createdAt: Date.now(),\n });\n\n change(taskHandle.doc, (draft) => {\n draft.meta.status = 'input-required';\n draft.meta.updatedAt = Date.now();\n });\n updateTaskInIndex(roomDoc, taskId, { status: 'input-required', updatedAt: Date.now() });\n\n taskLog.info(\n {\n toolName,\n toolUseID,\n riskLevel,\n decisionReason,\n blockedPath,\n hasSuggestions: !!suggestions?.length,\n },\n 'Permission request sent to browser'\n );\n\n return new Promise<PermissionResult>((resolve) => {\n let unsub: (() => void) | undefined;\n\n const onAbort = () => {\n unsub?.();\n taskHandle.permReqs.delete(toolUseID);\n resolve({ behavior: 'deny', message: 'Task was aborted' });\n };\n\n signal.addEventListener('abort', onAbort, { once: true });\n\n unsub = taskHandle.permResps.subscribe(({ key, value, source }) => {\n if (source === 'local') return;\n if (key !== toolUseID || !value) return;\n\n unsub?.();\n signal.removeEventListener('abort', onAbort);\n\n resolve(\n resolvePermissionResponse({\n taskHandle,\n roomDoc,\n taskId,\n taskLog,\n toolName,\n toolUseID,\n input,\n suggestions,\n value,\n })\n );\n });\n });\n };\n}\n\ninterface RunTaskOptions {\n sessionManager: SessionManager;\n taskHandle: TaskHandle;\n taskId: string;\n roomDoc: TypedDoc<TaskIndexDocumentShape>;\n cwd: string;\n model?: string;\n permissionMode?: 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan';\n effort?: 'low' | 'medium' | 'high';\n machineId: string;\n abortController: AbortController;\n log: ReturnType<typeof createChildLogger>;\n}\n\nasync function runTask(opts: RunTaskOptions): Promise<SessionResult> {\n const {\n sessionManager: manager,\n taskHandle,\n taskId,\n roomDoc,\n cwd,\n model,\n permissionMode,\n effort,\n machineId,\n abortController,\n log,\n } = opts;\n\n const prompt = manager.getLatestUserPrompt();\n if (!prompt) {\n throw new Error(`No user message found in task ${taskId}`);\n }\n\n log.info({ prompt: prompt.slice(0, 100) }, 'Running task with prompt from CRDT');\n\n const canUseTool =\n permissionMode === 'bypassPermissions'\n ? undefined\n : buildCanUseTool(taskHandle, log, roomDoc, taskId);\n\n const stderr = (data: string) => {\n const trimmed = data.trim();\n if (!trimmed) return;\n if (trimmed.includes('Error') || trimmed.includes('error')) {\n log.error({ stderr: trimmed }, 'SDK subprocess error');\n } else {\n log.debug({ stderr: trimmed }, 'SDK subprocess stderr');\n }\n };\n\n const resumeInfo = manager.shouldResume();\n if (resumeInfo.resume && resumeInfo.sessionId) {\n log.info({ sessionId: resumeInfo.sessionId }, 'Resuming existing session');\n return manager.resumeSession(resumeInfo.sessionId, prompt, {\n abortController,\n machineId,\n model,\n permissionMode,\n effort,\n canUseTool,\n stderr,\n allowDangerouslySkipPermissions: permissionMode === 'bypassPermissions' ? true : undefined,\n });\n }\n\n return manager.createSession({\n prompt,\n cwd,\n machineId,\n model,\n permissionMode,\n effort,\n abortController,\n canUseTool,\n stderr,\n allowDangerouslySkipPermissions: permissionMode === 'bypassPermissions' ? true : undefined,\n });\n}\n","import {\n Adapter,\n type ChannelId,\n type ChannelMsg,\n deserializeChannelMsg,\n type GeneratedChannel,\n type PeerID,\n serializeChannelMsg,\n} from \"@loro-extended/repo\"\n\n/**\n * Context for each data channel - stores the remote peer ID\n */\ntype DataChannelContext = {\n remotePeerId: PeerID\n dataChannel: RTCDataChannel\n}\n\n/**\n * Internal tracking for attached data channels\n */\ntype AttachedChannel = {\n remotePeerId: PeerID\n dataChannel: RTCDataChannel\n channelId: ChannelId | null\n cleanup: () => void\n}\n\n/**\n * WebRTC Data Channel Adapter for loro-extended\n *\n * This adapter enables peer-to-peer document synchronization over WebRTC data channels.\n * It follows a \"Bring Your Own Data Channel\" approach - developers create and manage\n * their own WebRTC connections (e.g., using simple-peer), then attach the data channels\n * to this adapter for Loro sync.\n *\n * ## Usage\n *\n * ```typescript\n * import { WebRtcDataChannelAdapter } from \"@loro-extended/adapter-webrtc\"\n *\n * const webrtcAdapter = new WebRtcDataChannelAdapter()\n *\n * // Add to repo config\n * const config = {\n * identity: { peerId, name, type: \"user\" },\n * adapters: [sseAdapter, webrtcAdapter],\n * }\n *\n * // When a WebRTC connection is established (e.g., via simple-peer)\n * peer.on(\"connect\", () => {\n * const dataChannel = peer._pc.createDataChannel(\"loro-sync\", { ordered: true })\n * webrtcAdapter.attachDataChannel(remotePeerId, dataChannel)\n * })\n *\n * // When the connection closes\n * peer.on(\"close\", () => {\n * webrtcAdapter.detachDataChannel(remotePeerId)\n * })\n * ```\n *\n * ## Key Features\n *\n * - **Non-intrusive**: Doesn't manage WebRTC connections - works with any WebRTC setup\n * - **Multi-peer**: Supports multiple simultaneous peer connections\n * - **Automatic lifecycle**: Handles data channel open/close events\n * - **JSON serialization**: Compatible with other loro-extended adapters\n */\nexport class WebRtcDataChannelAdapter extends Adapter<DataChannelContext> {\n /**\n * Map of remotePeerId -> attached channel info\n */\n private attachedChannels = new Map<PeerID, AttachedChannel>()\n\n constructor() {\n super({ adapterType: \"webrtc-datachannel\" })\n }\n\n /**\n * Generate a channel for a data channel context.\n * Called by the base Adapter class when addChannel() is invoked.\n */\n protected generate(context: DataChannelContext): GeneratedChannel {\n const { remotePeerId, dataChannel } = context\n\n return {\n kind: \"network\",\n adapterType: this.adapterType,\n send: (msg: ChannelMsg) => {\n if (dataChannel.readyState !== \"open\") {\n this.logger.warn(\n \"Cannot send message: data channel not open for peer {remotePeerId}\",\n { remotePeerId },\n )\n return\n }\n\n const serialized = serializeChannelMsg(msg)\n dataChannel.send(JSON.stringify(serialized))\n },\n stop: () => {\n // Clean up is handled by detachDataChannel\n // This is called when the Loro channel is removed\n },\n }\n }\n\n /**\n * Called when the adapter starts.\n * For WebRTC, we don't create any channels here - they're created\n * dynamically when attachDataChannel() is called.\n */\n async onStart(): Promise<void> {\n this.logger.debug(\"WebRTC adapter started\")\n }\n\n /**\n * Called when the adapter stops.\n * Clean up all attached data channels.\n */\n async onStop(): Promise<void> {\n this.logger.debug(\"WebRTC adapter stopping, cleaning up all channels\")\n\n // Detach all channels\n for (const remotePeerId of this.attachedChannels.keys()) {\n this.detachDataChannel(remotePeerId)\n }\n }\n\n /**\n * Attach a data channel for a remote peer.\n *\n * Creates a Loro channel when the data channel is open (or when it opens).\n * The Loro channel will be used for document synchronization with the remote peer.\n *\n * @param remotePeerId - The stable peer ID of the remote peer\n * @param dataChannel - The RTCDataChannel to use for communication\n * @returns A cleanup function to detach the channel\n */\n attachDataChannel(\n remotePeerId: PeerID,\n dataChannel: RTCDataChannel,\n ): () => void {\n // Check if already attached\n if (this.attachedChannels.has(remotePeerId)) {\n this.logger.warn(\n \"Data channel already attached for peer {remotePeerId}, detaching old one\",\n { remotePeerId },\n )\n this.detachDataChannel(remotePeerId)\n }\n\n this.logger.debug(\n \"Attaching data channel for peer {remotePeerId}, readyState: {readyState}\",\n { remotePeerId, readyState: dataChannel.readyState },\n )\n\n // Event handlers\n const onOpen = () => {\n this.logger.debug(\"Data channel opened for peer {remotePeerId}\", {\n remotePeerId,\n })\n this.createLoroChannel(remotePeerId, dataChannel)\n }\n\n const onClose = () => {\n this.logger.debug(\"Data channel closed for peer {remotePeerId}\", {\n remotePeerId,\n })\n this.removeLoroChannel(remotePeerId)\n }\n\n const onError = (event: Event) => {\n this.logger.warn(\"Data channel error for peer {remotePeerId}: {error}\", {\n remotePeerId,\n error: event,\n })\n this.removeLoroChannel(remotePeerId)\n }\n\n const onMessage = (event: MessageEvent) => {\n this.handleMessage(remotePeerId, event)\n }\n\n // Cleanup function to remove all event listeners\n const cleanup = () => {\n dataChannel.removeEventListener(\"open\", onOpen)\n dataChannel.removeEventListener(\"close\", onClose)\n dataChannel.removeEventListener(\"error\", onError)\n dataChannel.removeEventListener(\"message\", onMessage)\n }\n\n // Add event listeners\n dataChannel.addEventListener(\"open\", onOpen)\n dataChannel.addEventListener(\"close\", onClose)\n dataChannel.addEventListener(\"error\", onError)\n dataChannel.addEventListener(\"message\", onMessage)\n\n // Track the attached channel\n const attached: AttachedChannel = {\n remotePeerId,\n dataChannel,\n channelId: null,\n cleanup,\n }\n this.attachedChannels.set(remotePeerId, attached)\n\n // If already open, create the Loro channel immediately\n if (dataChannel.readyState === \"open\") {\n this.createLoroChannel(remotePeerId, dataChannel)\n }\n\n // Return cleanup function\n return () => this.detachDataChannel(remotePeerId)\n }\n\n /**\n * Detach a data channel for a remote peer.\n *\n * Removes the Loro channel and cleans up event listeners.\n *\n * @param remotePeerId - The peer ID to detach\n */\n detachDataChannel(remotePeerId: PeerID): void {\n const attached = this.attachedChannels.get(remotePeerId)\n if (!attached) {\n this.logger.debug(\"No data channel attached for peer {remotePeerId}\", {\n remotePeerId,\n })\n return\n }\n\n this.logger.debug(\"Detaching data channel for peer {remotePeerId}\", {\n remotePeerId,\n })\n\n // Remove the Loro channel if it exists\n this.removeLoroChannel(remotePeerId)\n\n // Clean up event listeners\n attached.cleanup()\n\n // Remove from tracking\n this.attachedChannels.delete(remotePeerId)\n }\n\n /**\n * Check if a data channel is attached for a peer.\n *\n * @param remotePeerId - The peer ID to check\n * @returns true if a data channel is attached\n */\n hasDataChannel(remotePeerId: PeerID): boolean {\n return this.attachedChannels.has(remotePeerId)\n }\n\n /**\n * Get all attached peer IDs.\n *\n * @returns Array of peer IDs with attached data channels\n */\n getAttachedPeerIds(): PeerID[] {\n return Array.from(this.attachedChannels.keys())\n }\n\n /**\n * Create a Loro channel for an open data channel.\n */\n private createLoroChannel(\n remotePeerId: PeerID,\n dataChannel: RTCDataChannel,\n ): void {\n const attached = this.attachedChannels.get(remotePeerId)\n if (!attached) {\n this.logger.warn(\n \"Cannot create Loro channel: no attached channel for peer {remotePeerId}\",\n { remotePeerId },\n )\n return\n }\n\n // Don't create if already exists\n if (attached.channelId !== null) {\n this.logger.debug(\"Loro channel already exists for peer {remotePeerId}\", {\n remotePeerId,\n })\n return\n }\n\n // Create the Loro channel\n const channel = this.addChannel({ remotePeerId, dataChannel })\n attached.channelId = channel.channelId\n\n this.logger.debug(\n \"Created Loro channel {channelId} for peer {remotePeerId}\",\n { channelId: channel.channelId, remotePeerId },\n )\n\n // Establish the channel to start the handshake\n this.establishChannel(channel.channelId)\n }\n\n /**\n * Remove the Loro channel for a peer.\n */\n private removeLoroChannel(remotePeerId: PeerID): void {\n const attached = this.attachedChannels.get(remotePeerId)\n if (!attached || attached.channelId === null) {\n return\n }\n\n this.logger.debug(\n \"Removing Loro channel {channelId} for peer {remotePeerId}\",\n { channelId: attached.channelId, remotePeerId },\n )\n\n this.removeChannel(attached.channelId)\n attached.channelId = null\n }\n\n /**\n * Handle incoming messages from a data channel.\n */\n private handleMessage(remotePeerId: PeerID, event: MessageEvent): void {\n const attached = this.attachedChannels.get(remotePeerId)\n if (!attached || attached.channelId === null) {\n this.logger.warn(\n \"Received message but no Loro channel for peer {remotePeerId}\",\n { remotePeerId },\n )\n return\n }\n\n const channel = this.channels.get(attached.channelId)\n if (!channel) {\n this.logger.warn(\"Received message but channel {channelId} not found\", {\n channelId: attached.channelId,\n })\n return\n }\n\n try {\n const data =\n typeof event.data === \"string\"\n ? event.data\n : new TextDecoder().decode(event.data)\n const serialized = JSON.parse(data)\n const message = deserializeChannelMsg(serialized)\n\n this.logger.trace(\n \"Received message from peer {remotePeerId}: {messageType}\",\n { remotePeerId, messageType: message.type },\n )\n\n channel.onReceive(message)\n } catch (error) {\n this.logger.warn(\n \"Failed to parse message from peer {remotePeerId}: {error}\",\n { remotePeerId, error },\n )\n }\n }\n}\n","import { type FSWatcher, watch } from 'node:fs';\nimport { join } from 'node:path';\nimport type { GitRepoInfo } from '@shipyard/session';\nimport { getRepoMetadata } from './capabilities.js';\nimport { logger } from './logger.js';\n\nconst DEBOUNCE_MS = 500;\n\nexport interface BranchWatcherOptions {\n environments: GitRepoInfo[];\n onUpdate: (updated: GitRepoInfo[]) => void;\n}\n\n/**\n * Watch `.git/HEAD` for each discovered git repo and call `onUpdate`\n * whenever a branch changes (checkout, rebase, switch, etc.).\n *\n * Returns a handle with a `close()` method that tears down all watchers.\n */\nexport function createBranchWatcher(options: BranchWatcherOptions): { close: () => void } {\n const log = logger.child({ component: 'branch-watcher' });\n const watchers = new Map<string, FSWatcher>();\n const branches = new Map<string, string>();\n const debounceTimers = new Map<string, ReturnType<typeof setTimeout>>();\n let environments = [...options.environments];\n\n for (const env of environments) {\n branches.set(env.path, env.branch);\n startWatching(env.path);\n }\n\n log.info({ count: environments.length }, 'Branch watcher started');\n\n function startWatching(repoPath: string): void {\n const headPath = join(repoPath, '.git', 'HEAD');\n\n try {\n const watcher = watch(headPath, () => {\n debouncedCheck(repoPath);\n });\n\n watcher.on('error', (err) => {\n log.debug({ repoPath, err: err.message }, 'Watcher error, removing');\n removeWatcher(repoPath);\n });\n\n watchers.set(repoPath, watcher);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n log.debug({ repoPath, err: msg }, 'Failed to watch .git/HEAD');\n }\n }\n\n function removeWatcher(repoPath: string): void {\n const watcher = watchers.get(repoPath);\n if (watcher) {\n watcher.close();\n watchers.delete(repoPath);\n }\n const timer = debounceTimers.get(repoPath);\n if (timer) {\n clearTimeout(timer);\n debounceTimers.delete(repoPath);\n }\n }\n\n function debouncedCheck(repoPath: string): void {\n const existing = debounceTimers.get(repoPath);\n if (existing) {\n clearTimeout(existing);\n }\n\n debounceTimers.set(\n repoPath,\n setTimeout(() => {\n debounceTimers.delete(repoPath);\n checkBranch(repoPath);\n }, DEBOUNCE_MS)\n );\n }\n\n function checkBranch(repoPath: string): void {\n getRepoMetadata(repoPath)\n .then((metadata) => {\n if (!metadata) {\n log.debug({ repoPath }, 'Repo no longer accessible, removing watcher');\n removeWatcher(repoPath);\n environments = environments.filter((e) => e.path !== repoPath);\n options.onUpdate(environments);\n return;\n }\n\n const previousBranch = branches.get(repoPath);\n if (metadata.branch === previousBranch) {\n return;\n }\n\n log.info({ repoPath, from: previousBranch, to: metadata.branch }, 'Branch changed');\n\n branches.set(repoPath, metadata.branch);\n environments = environments.map((e) => (e.path === repoPath ? metadata : e));\n options.onUpdate(environments);\n })\n .catch((err: unknown) => {\n const msg = err instanceof Error ? err.message : String(err);\n log.debug({ repoPath, err: msg }, 'Failed to check branch');\n });\n }\n\n return {\n close() {\n for (const timer of debounceTimers.values()) {\n clearTimeout(timer);\n }\n debounceTimers.clear();\n\n for (const watcher of watchers.values()) {\n watcher.close();\n }\n watchers.clear();\n\n log.info('Branch watcher closed');\n },\n };\n}\n","import { execFile } from 'node:child_process';\nimport { readdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport {\n type GitRepoInfo,\n type MachineCapabilities,\n type ModelInfo,\n PermissionModeSchema,\n} from '@shipyard/session';\n\nconst TIMEOUT_MS = 5_000;\n\nfunction run(command: string, args: string[], cwd?: string): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(command, args, { timeout: TIMEOUT_MS, cwd }, (error, stdout) => {\n if (error) {\n reject(error);\n return;\n }\n resolve(stdout.trim());\n });\n });\n}\n\nfunction runWithTimeout(\n command: string,\n args: string[],\n cwd: string,\n timeoutMs: number\n): Promise<string> {\n return new Promise((resolve, reject) => {\n execFile(\n command,\n args,\n { timeout: timeoutMs, cwd, maxBuffer: 2 * 1024 * 1024 },\n (error, stdout) => {\n if (error) {\n reject(error);\n return;\n }\n resolve(stdout.trim());\n }\n );\n });\n}\n\nconst DIFF_TIMEOUT_MS = 15_000;\nconst MAX_DIFF_SIZE = 200_000;\n\nasync function withIntentToAdd<T>(cwd: string, fn: () => Promise<T>): Promise<T> {\n let added = false;\n try {\n const untracked = await runWithTimeout(\n 'git',\n ['ls-files', '--others', '--exclude-standard'],\n cwd,\n TIMEOUT_MS\n );\n if (untracked) {\n await runWithTimeout('git', ['add', '-N', '.'], cwd, TIMEOUT_MS);\n added = true;\n }\n return await fn();\n } finally {\n if (added) {\n await runWithTimeout('git', ['reset'], cwd, TIMEOUT_MS).catch(() => {});\n }\n }\n}\n\nexport async function getUnstagedDiff(cwd: string): Promise<string> {\n const result = await withIntentToAdd(cwd, () =>\n runWithTimeout('git', ['diff', '--no-color'], cwd, DIFF_TIMEOUT_MS)\n );\n return result.length > MAX_DIFF_SIZE\n ? `${result.slice(0, MAX_DIFF_SIZE)}\\n\\n... diff truncated (exceeds 1MB) ...\\n`\n : result;\n}\n\nexport async function getStagedDiff(cwd: string): Promise<string> {\n const result = await runWithTimeout(\n 'git',\n ['diff', '--cached', '--no-color'],\n cwd,\n DIFF_TIMEOUT_MS\n );\n return result.length > MAX_DIFF_SIZE\n ? `${result.slice(0, MAX_DIFF_SIZE)}\\n\\n... diff truncated (exceeds 1MB) ...\\n`\n : result;\n}\n\nexport async function getChangedFiles(\n cwd: string\n): Promise<Array<{ path: string; status: string }>> {\n const out = await runWithTimeout('git', ['status', '--porcelain'], cwd, DIFF_TIMEOUT_MS);\n if (!out) return [];\n return out\n .split('\\n')\n .filter(Boolean)\n .map((line) => ({\n status: line.slice(0, 2).trim(),\n path: line.slice(3),\n }));\n}\n\nconst BRANCH_DIFF_TIMEOUT_MS = 30_000;\n\nexport async function getDefaultBranch(cwd: string): Promise<string | null> {\n try {\n const ref = await runWithTimeout(\n 'git',\n ['symbolic-ref', 'refs/remotes/origin/HEAD', '--short'],\n cwd,\n TIMEOUT_MS\n );\n return ref || null;\n } catch {\n /* symbolic-ref failed, try common defaults */\n }\n\n for (const candidate of ['origin/main', 'origin/master']) {\n try {\n await runWithTimeout('git', ['rev-parse', '--verify', candidate], cwd, TIMEOUT_MS);\n return candidate;\n } catch {\n /* candidate does not exist */\n }\n }\n\n return null;\n}\n\nexport async function getMergeBase(cwd: string, baseBranch: string): Promise<string | null> {\n try {\n return await runWithTimeout('git', ['merge-base', baseBranch, 'HEAD'], cwd, TIMEOUT_MS);\n } catch {\n return null;\n }\n}\n\nexport async function getBranchDiff(cwd: string, baseBranch: string): Promise<string> {\n const mergeBase = await getMergeBase(cwd, baseBranch);\n if (!mergeBase) return '';\n\n try {\n const result = await runWithTimeout(\n 'git',\n ['diff', `${mergeBase}..HEAD`, '--no-color'],\n cwd,\n BRANCH_DIFF_TIMEOUT_MS\n );\n return result.length > MAX_DIFF_SIZE\n ? `${result.slice(0, MAX_DIFF_SIZE)}\\n\\n... diff truncated (exceeds 1MB) ...\\n`\n : result;\n } catch {\n return '';\n }\n}\n\nexport async function getBranchFiles(\n cwd: string,\n baseBranch: string\n): Promise<Array<{ path: string; status: string }>> {\n const mergeBase = await getMergeBase(cwd, baseBranch);\n if (!mergeBase) return [];\n\n try {\n const out = await runWithTimeout(\n 'git',\n ['diff', '--name-status', `${mergeBase}..HEAD`],\n cwd,\n BRANCH_DIFF_TIMEOUT_MS\n );\n if (!out) return [];\n return out\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const parts = line.split('\\t');\n return {\n status: parts[0] ?? '',\n path: parts[1] ?? '',\n };\n });\n } catch {\n return [];\n }\n}\n\nexport async function captureTreeSnapshot(cwd: string): Promise<string | null> {\n try {\n const stashRef = await runWithTimeout('git', ['stash', 'create'], cwd, DIFF_TIMEOUT_MS);\n if (stashRef) return stashRef;\n\n return await runWithTimeout('git', ['rev-parse', 'HEAD'], cwd, DIFF_TIMEOUT_MS);\n } catch {\n return null;\n }\n}\n\nexport async function getSnapshotDiff(\n cwd: string,\n fromRef: string,\n toRef: string\n): Promise<string> {\n try {\n const result = await runWithTimeout(\n 'git',\n ['diff', fromRef, toRef, '--no-color'],\n cwd,\n DIFF_TIMEOUT_MS\n );\n return result.length > MAX_DIFF_SIZE\n ? `${result.slice(0, MAX_DIFF_SIZE)}\\n\\n... diff truncated (exceeds 1MB) ...\\n`\n : result;\n } catch {\n return '';\n }\n}\n\nexport async function getSnapshotFiles(\n cwd: string,\n fromRef: string,\n toRef: string\n): Promise<Array<{ path: string; status: string }>> {\n try {\n const out = await runWithTimeout(\n 'git',\n ['diff', '--name-status', fromRef, toRef],\n cwd,\n DIFF_TIMEOUT_MS\n );\n if (!out) return [];\n return out\n .split('\\n')\n .filter(Boolean)\n .map((line) => {\n const parts = line.split('\\t');\n return {\n status: parts[0] ?? '',\n path: parts[1] ?? '',\n };\n });\n } catch {\n return [];\n }\n}\n\nexport async function detectModels(): Promise<ModelInfo[]> {\n const models: ModelInfo[] = [];\n\n try {\n await run('which', ['claude']);\n models.push(\n {\n id: 'claude-opus-4-6',\n label: 'Claude Opus 4.6',\n provider: 'claude-code',\n reasoning: { efforts: ['low', 'medium', 'high'], defaultEffort: 'high' },\n },\n {\n id: 'claude-opus-4-6[1m]',\n label: 'Claude Opus 4.6 (1M)',\n provider: 'claude-code',\n reasoning: { efforts: ['low', 'medium', 'high'], defaultEffort: 'high' },\n },\n {\n id: 'claude-sonnet-4-5-20250929',\n label: 'Claude Sonnet 4.5',\n provider: 'claude-code',\n },\n {\n id: 'claude-haiku-4-5-20251001',\n label: 'Claude Haiku 4.5',\n provider: 'claude-code',\n }\n );\n } catch {}\n\n try {\n await run('which', ['codex']);\n models.push(\n {\n id: 'gpt-5.3-codex',\n label: 'GPT-5.3 Codex',\n provider: 'codex',\n },\n {\n id: 'gpt-5.2-codex',\n label: 'GPT-5.2 Codex',\n provider: 'codex',\n reasoning: { efforts: ['low', 'medium', 'high'], defaultEffort: 'medium' },\n }\n );\n } catch {}\n\n return models;\n}\n\nconst EXCLUDE_DIRS = new Set([\n 'node_modules',\n 'Library',\n 'Applications',\n 'Pictures',\n 'Music',\n 'Movies',\n 'go',\n '.Trash',\n]);\n\nconst MAX_DEPTH = 4;\n\nexport async function findGitRepos(dir: string, depth = 0): Promise<string[]> {\n if (depth > MAX_DEPTH) return [];\n\n try {\n const entries = await readdir(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.name === '.git') {\n return [dir];\n }\n }\n\n if (depth >= MAX_DEPTH) return [];\n\n const promises: Promise<string[]>[] = [];\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n if (entry.name.startsWith('.')) continue;\n if (EXCLUDE_DIRS.has(entry.name)) continue;\n promises.push(findGitRepos(join(dir, entry.name), depth + 1));\n }\n\n const results = await Promise.all(promises);\n return results.flat();\n } catch {\n return [];\n }\n}\n\nexport async function getRepoMetadata(repoPath: string): Promise<GitRepoInfo | null> {\n try {\n const [branchResult, remoteResult] = await Promise.allSettled([\n run('git', ['branch', '--show-current'], repoPath),\n run('git', ['remote', 'get-url', 'origin'], repoPath),\n ]);\n\n const branch = branchResult.status === 'fulfilled' ? branchResult.value || 'HEAD' : 'HEAD';\n const remote =\n remoteResult.status === 'fulfilled' ? remoteResult.value || undefined : undefined;\n\n return {\n path: repoPath,\n name: basename(repoPath),\n branch,\n ...(remote && { remote }),\n };\n } catch {\n return null;\n }\n}\n\nexport async function detectEnvironments(): Promise<GitRepoInfo[]> {\n const repoPaths = await findGitRepos(homedir());\n const repoInfos = await Promise.all(repoPaths.map(getRepoMetadata));\n return repoInfos.filter((info): info is GitRepoInfo => info !== null);\n}\n\nexport async function detectCapabilities(): Promise<MachineCapabilities> {\n const [models, environments] = await Promise.all([detectModels(), detectEnvironments()]);\n\n const permissionModes = [...PermissionModeSchema.options];\n\n return { models, environments, permissionModes, homeDir: homedir() };\n}\n","import type { WebRtcDataChannelAdapter } from '@loro-extended/adapter-webrtc';\nimport type { PeerID } from 'loro-crdt';\nimport { logger } from './logger.js';\n\nconst ICE_SERVERS = [{ urls: 'stun:stun.l.google.com:19302' }];\n\n/** SDP offer/answer passed over the signaling channel. */\nexport interface SDPDescription {\n type: 'offer' | 'answer';\n sdp?: string;\n}\n\n/** ICE candidate passed over the signaling channel. */\nexport interface ICECandidate {\n candidate?: string;\n sdpMid?: string | null;\n sdpMLineIndex?: number | null;\n}\n\n/** Minimal interface for a peer connection (subset of RTCPeerConnection). */\nexport interface MinimalPeerConnection {\n connectionState: string;\n onicecandidate:\n | ((ev: {\n candidate: {\n candidate: string;\n sdpMid: string | null;\n sdpMLineIndex: number | null;\n } | null;\n }) => void)\n | null;\n ondatachannel: ((ev: { channel: unknown }) => void) | null;\n onconnectionstatechange: (() => void) | null;\n setRemoteDescription(desc: SDPDescription): Promise<void>;\n createAnswer(): Promise<SDPDescription>;\n setLocalDescription(desc: SDPDescription): Promise<void>;\n addIceCandidate(candidate: ICECandidate): Promise<void>;\n close(): void;\n}\n\nexport interface PeerManagerConfig {\n webrtcAdapter: WebRtcDataChannelAdapter;\n onAnswer: (targetMachineId: string, answer: SDPDescription) => void;\n onIceCandidate: (targetMachineId: string, candidate: ICECandidate) => void;\n onTerminalChannel?: (machineId: string, channel: unknown) => void;\n /** Factory to create peer connections. Defaults to node-datachannel/polyfill. */\n createPeerConnection?: () => MinimalPeerConnection;\n}\n\nexport interface PeerManager {\n handleOffer(fromMachineId: string, offer: SDPDescription): Promise<void>;\n handleAnswer(fromMachineId: string, answer: SDPDescription): Promise<void>;\n handleIce(fromMachineId: string, candidate: ICECandidate): Promise<void>;\n destroy(): void;\n}\n\nfunction machineIdToPeerId(machineId: string): PeerID {\n // eslint-disable-next-line no-restricted-syntax -- PeerID is `${number}` branded but adapter uses it as opaque string key\n return machineId as unknown as PeerID;\n}\n\n/** Default factory that uses node-datachannel/polyfill. */\nasync function loadDefaultFactory(): Promise<() => MinimalPeerConnection> {\n const { RTCPeerConnection } = await import('node-datachannel/polyfill');\n return () => {\n // eslint-disable-next-line no-restricted-syntax -- node-datachannel config is compatible\n const pc = new RTCPeerConnection({ iceServers: ICE_SERVERS } as never);\n // eslint-disable-next-line no-restricted-syntax -- MinimalPeerConnection subset\n return pc as unknown as MinimalPeerConnection;\n };\n}\n\nexport function createPeerManager(config: PeerManagerConfig): PeerManager {\n const peers = new Map<string, MinimalPeerConnection>();\n const pendingCreates = new Map<string, Promise<MinimalPeerConnection>>();\n let factoryPromise: Promise<() => MinimalPeerConnection> | null = null;\n\n async function getFactory(): Promise<() => MinimalPeerConnection> {\n if (config.createPeerConnection) {\n return config.createPeerConnection;\n }\n if (!factoryPromise) {\n factoryPromise = loadDefaultFactory();\n }\n return factoryPromise;\n }\n\n function setupPeerHandlers(machineId: string, pc: MinimalPeerConnection): void {\n pc.onicecandidate = (event) => {\n if (event.candidate) {\n config.onIceCandidate(machineId, {\n candidate: event.candidate.candidate,\n sdpMid: event.candidate.sdpMid,\n sdpMLineIndex: event.candidate.sdpMLineIndex,\n });\n }\n };\n\n pc.ondatachannel = (event) => {\n // eslint-disable-next-line no-restricted-syntax -- node-datachannel channel type is opaque\n const channel = event.channel as { label?: string };\n if (channel.label === 'terminal-io') {\n logger.info({ machineId }, 'Terminal data channel received');\n config.onTerminalChannel?.(machineId, event.channel);\n } else {\n logger.info({ machineId }, 'Data channel received from browser');\n // eslint-disable-next-line no-restricted-syntax -- RTCDataChannel from node-datachannel satisfies the adapter interface\n config.webrtcAdapter.attachDataChannel(\n machineIdToPeerId(machineId),\n event.channel as never\n );\n logger.info({ machineId }, 'Data channel attached to Loro adapter');\n }\n };\n\n pc.onconnectionstatechange = () => {\n const state = pc.connectionState;\n logger.info({ machineId, state }, 'Peer connection state changed');\n\n if (state === 'failed' || state === 'closed') {\n config.webrtcAdapter.detachDataChannel(machineIdToPeerId(machineId));\n peers.delete(machineId);\n pc.close();\n }\n };\n\n // eslint-disable-next-line no-restricted-syntax -- node-datachannel polyfill supports these handlers\n (pc as unknown as { onsignalingstatechange: (() => void) | null }).onsignalingstatechange =\n () => {\n // eslint-disable-next-line no-restricted-syntax -- reading state from underlying connection\n const sigState = (pc as unknown as { signalingState: string }).signalingState;\n logger.info({ machineId, signalingState: sigState }, 'Signaling state changed');\n };\n\n // eslint-disable-next-line no-restricted-syntax -- node-datachannel polyfill supports these handlers\n (\n pc as unknown as { onicegatheringstatechange: (() => void) | null }\n ).onicegatheringstatechange = () => {\n // eslint-disable-next-line no-restricted-syntax -- reading state from underlying connection\n const iceState = (pc as unknown as { iceGatheringState: string }).iceGatheringState;\n logger.info({ machineId, iceGatheringState: iceState }, 'ICE gathering state changed');\n };\n }\n\n return {\n async handleOffer(fromMachineId, offer) {\n logger.info({ fromMachineId }, 'Handling WebRTC offer');\n const existing = peers.get(fromMachineId);\n if (existing) {\n logger.debug({ fromMachineId }, 'Closing existing peer connection');\n existing.close();\n peers.delete(fromMachineId);\n }\n\n const promise = (async () => {\n const factory = await getFactory();\n const pc = factory();\n logger.debug({ fromMachineId }, 'Created peer connection');\n setupPeerHandlers(fromMachineId, pc);\n logger.debug({ fromMachineId }, 'Setting remote description (offer)');\n await pc.setRemoteDescription(offer);\n logger.debug({ fromMachineId }, 'Creating answer');\n const answer = await pc.createAnswer();\n logger.debug(\n { fromMachineId, hasAnswerSdp: !!answer.sdp },\n 'Setting local description (answer)'\n );\n await pc.setLocalDescription(answer);\n peers.set(fromMachineId, pc);\n pendingCreates.delete(fromMachineId);\n logger.info({ fromMachineId }, 'Sending WebRTC answer');\n config.onAnswer(fromMachineId, { type: 'answer', sdp: answer.sdp });\n return pc;\n })();\n\n pendingCreates.set(fromMachineId, promise);\n await promise;\n },\n\n async handleAnswer(fromMachineId, answer) {\n logger.debug({ fromMachineId }, 'Handling WebRTC answer');\n let pc = peers.get(fromMachineId);\n if (!pc) {\n const pending = pendingCreates.get(fromMachineId);\n if (pending) {\n pc = await pending;\n } else {\n logger.warn({ fromMachineId }, 'Received answer for unknown peer');\n return;\n }\n }\n await pc.setRemoteDescription(answer);\n logger.debug({ fromMachineId }, 'Remote description (answer) set');\n },\n\n async handleIce(fromMachineId, candidate) {\n logger.debug({ fromMachineId }, 'Handling WebRTC ICE candidate');\n let pc = peers.get(fromMachineId);\n if (!pc) {\n const pending = pendingCreates.get(fromMachineId);\n if (pending) {\n pc = await pending;\n } else {\n logger.warn({ fromMachineId }, 'Received ICE candidate for unknown peer');\n return;\n }\n }\n await pc.addIceCandidate(candidate);\n logger.debug({ fromMachineId }, 'ICE candidate added');\n },\n\n destroy() {\n for (const [machineId, pc] of peers) {\n config.webrtcAdapter.detachDataChannel(machineIdToPeerId(machineId));\n pc.close();\n }\n peers.clear();\n },\n };\n}\n","import * as pty from 'node-pty';\nimport { createChildLogger } from './logger.js';\n\nexport interface PtySpawnOptions {\n shell?: string;\n cwd: string;\n cols?: number;\n rows?: number;\n env?: Record<string, string>;\n}\n\nexport interface PtyManager {\n readonly pid: number | undefined;\n readonly alive: boolean;\n spawn(options: PtySpawnOptions): void;\n write(data: string): void;\n resize(cols: number, rows: number): void;\n onData(callback: (data: string) => void): void;\n onExit(callback: (exitCode: number, signal?: number) => void): void;\n kill(): void;\n dispose(): void;\n}\n\nconst KILL_TIMEOUT_MS = 5_000;\nconst DEFAULT_COLS = 80;\nconst DEFAULT_ROWS = 24;\n\nexport function createPtyManager(): PtyManager {\n const log = createChildLogger({ mode: 'pty' });\n\n let process: pty.IPty | null = null;\n let isAlive = false;\n let killTimer: ReturnType<typeof setTimeout> | null = null;\n const dataCallbacks: Array<(data: string) => void> = [];\n const exitCallbacks: Array<(exitCode: number, signal?: number) => void> = [];\n\n function getDefaultShell(): string {\n return globalThis.process.env.SHELL ?? '/bin/zsh';\n }\n\n function spawn(options: PtySpawnOptions): void {\n if (isAlive) {\n throw new Error('PTY already spawned. Call kill() or dispose() first.');\n }\n\n const shell = options.shell ?? getDefaultShell();\n const cols = options.cols ?? DEFAULT_COLS;\n const rows = options.rows ?? DEFAULT_ROWS;\n\n const env: Record<string, string> = {};\n for (const [key, val] of Object.entries({ ...globalThis.process.env, ...options.env })) {\n if (val !== undefined) env[key] = val;\n }\n\n log.info({ shell, cwd: options.cwd, cols, rows }, 'Spawning PTY');\n\n try {\n process = pty.spawn(shell, ['--login'], {\n name: 'xterm-256color',\n cols,\n rows,\n cwd: options.cwd,\n env,\n });\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n log.error({ err: msg, shell }, 'Failed to spawn PTY');\n throw new Error(`Failed to spawn PTY: ${msg}`);\n }\n\n isAlive = true;\n\n process.onData((data) => {\n for (const cb of dataCallbacks) {\n cb(data);\n }\n });\n\n process.onExit(({ exitCode, signal }) => {\n log.info({ exitCode, signal, pid: process?.pid }, 'PTY exited');\n isAlive = false;\n clearKillTimer();\n for (const cb of exitCallbacks) {\n cb(exitCode, signal);\n }\n });\n\n log.info({ pid: process.pid }, 'PTY spawned');\n }\n\n function write(data: string): void {\n if (!process || !isAlive) {\n throw new Error('PTY is not running');\n }\n process.write(data);\n }\n\n function resize(cols: number, rows: number): void {\n if (!process || !isAlive) {\n throw new Error('PTY is not running');\n }\n process.resize(cols, rows);\n }\n\n function onData(callback: (data: string) => void): void {\n dataCallbacks.push(callback);\n }\n\n function onExit(callback: (exitCode: number, signal?: number) => void): void {\n exitCallbacks.push(callback);\n }\n\n function clearKillTimer(): void {\n if (killTimer) {\n clearTimeout(killTimer);\n killTimer = null;\n }\n }\n\n function kill(): void {\n if (!process || !isAlive) return;\n\n const proc = process;\n log.info({ pid: proc.pid }, 'Killing PTY (SIGTERM)');\n proc.kill('SIGTERM');\n\n killTimer = setTimeout(() => {\n log.warn({ pid: proc.pid }, 'PTY did not exit after SIGTERM, sending SIGKILL');\n try {\n proc.kill('SIGKILL');\n } catch {\n // Process may have already exited\n }\n }, KILL_TIMEOUT_MS);\n }\n\n function dispose(): void {\n kill();\n dataCallbacks.length = 0;\n exitCallbacks.length = 0;\n process = null;\n isAlive = false;\n }\n\n return {\n get pid() {\n return process?.pid;\n },\n get alive() {\n return isAlive;\n },\n spawn,\n write,\n resize,\n onData,\n onExit,\n kill,\n dispose,\n };\n}\n","import type {\n CanUseTool,\n PermissionMode,\n Query,\n SDKMessage,\n SettingSource,\n} from '@anthropic-ai/claude-agent-sdk';\nimport { query } from '@anthropic-ai/claude-agent-sdk';\nimport type { TypedDoc } from '@loro-extended/change';\nimport { change } from '@loro-extended/change';\nimport type {\n A2ATaskState,\n ContentBlock,\n SessionState,\n TaskDocumentShape,\n} from '@shipyard/loro-schema';\nimport { extractPlanMarkdown } from '@shipyard/loro-schema';\nimport { nanoid } from 'nanoid';\nimport { logger } from './logger.js';\nimport { StreamingInputController } from './streaming-input-controller.js';\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return '{}';\n }\n}\n\nconst SHIPYARD_SYSTEM_PROMPT_APPEND = `\n# Shipyard Permission System\n\nYou are running inside Shipyard, a collaborative workspace with a built-in permission system.\n\nCRITICAL: Never ask the user conversationally for permission to perform an action. Always attempt the tool call directly. The permission system will prompt the user for approval automatically when needed. If a tool call is denied, you will receive the denial as a tool result — do not preemptively refuse or ask \"should I proceed?\" for file operations, bash commands, or any other tool use. Just call the tool.\n`;\n\nfunction parseToolResultBlock(\n block: Record<string, unknown>,\n parentToolUseId: string | null\n): ContentBlock | null {\n if (typeof block.tool_use_id !== 'string') return null;\n const resultContent =\n typeof block.content === 'string' ? block.content : JSON.stringify(block.content ?? '');\n return {\n type: 'tool_result',\n toolUseId: block.tool_use_id,\n content: resultContent,\n isError: typeof block.is_error === 'boolean' ? block.is_error : false,\n parentToolUseId,\n };\n}\n\nfunction parseToolUseBlock(\n block: Record<string, unknown>,\n parentToolUseId: string | null\n): ContentBlock | null {\n if (typeof block.id !== 'string' || typeof block.name !== 'string') return null;\n return {\n type: 'tool_use',\n toolUseId: block.id,\n toolName: block.name,\n input: safeStringify(block.input ?? {}),\n parentToolUseId,\n };\n}\n\n/**\n * Parse a single SDK content block (untyped record) into a typed ContentBlock.\n * Returns null for unrecognized or invalid block types (server_tool_use, redacted_thinking, etc.)\n */\nfunction parseSdkBlock(\n block: Record<string, unknown>,\n parentToolUseId: string | null\n): ContentBlock | null {\n switch (block.type) {\n case 'text':\n return typeof block.text === 'string' ? { type: 'text', text: block.text } : null;\n case 'tool_use':\n return parseToolUseBlock(block, parentToolUseId);\n case 'tool_result':\n return parseToolResultBlock(block, parentToolUseId);\n case 'thinking':\n return typeof block.thinking === 'string' ? { type: 'thinking', text: block.thinking } : null;\n default:\n return null;\n }\n}\n\nexport interface CreateSessionOptions {\n prompt: string;\n cwd: string;\n machineId?: string;\n model?: string;\n effort?: 'low' | 'medium' | 'high';\n allowedTools?: string[];\n permissionMode?: PermissionMode;\n maxTurns?: number;\n abortController?: AbortController;\n allowDangerouslySkipPermissions?: boolean;\n settingSources?: SettingSource[];\n systemPrompt?: string | { type: 'preset'; preset: 'claude_code'; append?: string };\n canUseTool?: CanUseTool;\n stderr?: (data: string) => void;\n}\n\nexport interface SessionResult {\n sessionId: string;\n agentSessionId: string;\n status: SessionState;\n resultText?: string;\n totalCostUsd?: number;\n durationMs?: number;\n error?: string;\n}\n\n/**\n * Manages Claude Code sessions via the Agent SDK, syncing all state\n * transitions and conversation messages to a Loro CRDT task document.\n *\n * V1 streaming mode: keeps the subprocess alive between turns by using\n * an AsyncGenerator prompt. New user messages are pushed via sendFollowUp()\n * instead of spawning a new query() subprocess.\n *\n * Session lifecycle: pending -> active -> completed | failed\n * Task status mirrors: submitted -> working -> completed | failed\n */\nexport type StatusChangeCallback = (status: A2ATaskState) => void;\n\nexport class SessionManager {\n readonly #taskDoc: TypedDoc<TaskDocumentShape>;\n readonly #onStatusChange: StatusChangeCallback | undefined;\n #currentModel: string | null = null;\n #machineId: string | null = null;\n #inputController: StreamingInputController | null = null;\n #activeQuery: Query | null = null;\n\n constructor(taskDoc: TypedDoc<TaskDocumentShape>, onStatusChange?: StatusChangeCallback) {\n this.#taskDoc = taskDoc;\n this.#onStatusChange = onStatusChange;\n }\n\n get isStreaming(): boolean {\n return this.#inputController !== null && !this.#inputController.isDone;\n }\n\n #notifyStatusChange(status: A2ATaskState): void {\n this.#onStatusChange?.(status);\n }\n\n /**\n * Extract the latest user message text from the conversation.\n * Walks backwards from the end to find the most recent user turn,\n * then concatenates all text parts.\n *\n * Returns null if no user message exists.\n */\n getLatestUserPrompt(): string | null {\n const conversation = this.#taskDoc.toJSON().conversation;\n for (let i = conversation.length - 1; i >= 0; i--) {\n const msg = conversation[i];\n if (msg?.role === 'user') {\n return msg.content\n .filter((block): block is ContentBlock & { type: 'text' } => block.type === 'text')\n .map((block) => block.text)\n .join('\\n');\n }\n }\n return null;\n }\n\n /**\n * Determine whether to resume an existing session or start fresh.\n *\n * Walks backwards through sessions to find the most recent one with a\n * non-empty agentSessionId that has not failed. If found, returns\n * { resume: true, sessionId } so the caller can pass it to resumeSession().\n */\n shouldResume(): { resume: boolean; sessionId?: string } {\n const sessions = this.#taskDoc.toJSON().sessions;\n if (sessions.length === 0) return { resume: false };\n\n for (let i = sessions.length - 1; i >= 0; i--) {\n const session = sessions[i];\n if (session?.agentSessionId && session.status !== 'failed') {\n return { resume: true, sessionId: session.sessionId };\n }\n }\n return { resume: false };\n }\n\n /**\n * Create a new Claude Code session using streaming input mode.\n *\n * 1. Creates a StreamingInputController and pushes the first message\n * 2. Calls query() with the controller's async iterable as prompt\n * 3. Stores the Query and controller for follow-up messages\n * 4. Processes messages until the session fully ends\n * 5. Returns the final SessionResult\n */\n async createSession(opts: CreateSessionOptions): Promise<SessionResult> {\n this.#currentModel = opts.model ?? null;\n this.#machineId = opts.machineId ?? null;\n const sessionId = nanoid();\n const now = Date.now();\n\n change(this.#taskDoc, (draft) => {\n draft.sessions.push({\n sessionId,\n agentSessionId: '',\n status: 'pending',\n cwd: opts.cwd,\n model: opts.model ?? null,\n machineId: opts.machineId ?? null,\n createdAt: now,\n completedAt: null,\n totalCostUsd: null,\n durationMs: null,\n error: null,\n });\n draft.meta.status = 'starting';\n draft.meta.updatedAt = now;\n });\n this.#notifyStatusChange('starting');\n\n const controller = new StreamingInputController();\n controller.push(opts.prompt);\n\n const response: Query = query({\n prompt: controller.iterable(),\n options: {\n cwd: opts.cwd,\n model: opts.model,\n effort: opts.effort,\n allowedTools: opts.allowedTools,\n permissionMode: opts.permissionMode,\n maxTurns: opts.maxTurns,\n abortController: opts.abortController,\n allowDangerouslySkipPermissions: opts.allowDangerouslySkipPermissions,\n settingSources: opts.settingSources ?? ['project'],\n systemPrompt: opts.systemPrompt ?? {\n type: 'preset',\n preset: 'claude_code',\n append: SHIPYARD_SYSTEM_PROMPT_APPEND,\n },\n canUseTool: opts.canUseTool,\n stderr: opts.stderr,\n },\n });\n\n this.#inputController = controller;\n this.#activeQuery = response;\n\n return this.#processMessages(response, sessionId);\n }\n\n /**\n * Send a follow-up message to the active streaming session.\n * The controller feeds the message to the generator, which wakes the\n * agent subprocess for the next turn without a cold start.\n */\n sendFollowUp(prompt: string): void {\n if (!this.#inputController || this.#inputController.isDone) {\n throw new Error('No active streaming session to send follow-up to');\n }\n this.#inputController.push(prompt);\n\n change(this.#taskDoc, (draft) => {\n draft.meta.status = 'working';\n draft.meta.updatedAt = Date.now();\n });\n this.#notifyStatusChange('working');\n }\n\n /**\n * Gracefully close the active streaming session.\n * Ends the input generator and closes the query subprocess.\n */\n closeSession(): void {\n this.#inputController?.end();\n this.#activeQuery?.close();\n this.#inputController = null;\n this.#activeQuery = null;\n }\n\n /**\n * Change the model used by the active streaming session between turns.\n */\n async setModel(model: string): Promise<void> {\n await this.#activeQuery?.setModel(model);\n this.#currentModel = model;\n }\n\n /**\n * Resume an existing Claude Code session using streaming input mode.\n * Looks up the agentSessionId from the task doc and passes it as `resume`.\n */\n async resumeSession(\n sessionId: string,\n prompt: string,\n opts?: {\n abortController?: AbortController;\n machineId?: string;\n model?: string;\n effort?: 'low' | 'medium' | 'high';\n allowedTools?: string[];\n permissionMode?: PermissionMode;\n maxTurns?: number;\n allowDangerouslySkipPermissions?: boolean;\n canUseTool?: CanUseTool;\n stderr?: (data: string) => void;\n }\n ): Promise<SessionResult> {\n const sessions = this.#taskDoc.toJSON().sessions;\n const sessionEntry = sessions.find((s) => s.sessionId === sessionId);\n if (!sessionEntry) {\n throw new Error(`Session ${sessionId} not found in task doc`);\n }\n\n if (!sessionEntry.agentSessionId) {\n throw new Error(`Session ${sessionId} has no agentSessionId`);\n }\n\n this.#currentModel = opts?.model ?? sessionEntry.model ?? null;\n this.#machineId = opts?.machineId ?? sessionEntry.machineId ?? null;\n const newSessionId = nanoid();\n const now = Date.now();\n\n change(this.#taskDoc, (draft) => {\n draft.sessions.push({\n sessionId: newSessionId,\n agentSessionId: sessionEntry.agentSessionId,\n status: 'pending',\n cwd: sessionEntry.cwd,\n model: opts?.model ?? sessionEntry.model,\n machineId: opts?.machineId ?? sessionEntry.machineId,\n createdAt: now,\n completedAt: null,\n totalCostUsd: null,\n durationMs: null,\n error: null,\n });\n draft.meta.status = 'starting';\n draft.meta.updatedAt = now;\n });\n this.#notifyStatusChange('starting');\n\n const controller = new StreamingInputController();\n controller.push(prompt);\n\n const response: Query = query({\n prompt: controller.iterable(),\n options: {\n resume: sessionEntry.agentSessionId,\n cwd: sessionEntry.cwd,\n model: opts?.model,\n effort: opts?.effort,\n allowedTools: opts?.allowedTools,\n permissionMode: opts?.permissionMode,\n maxTurns: opts?.maxTurns,\n abortController: opts?.abortController,\n allowDangerouslySkipPermissions: opts?.allowDangerouslySkipPermissions,\n canUseTool: opts?.canUseTool,\n stderr: opts?.stderr,\n settingSources: ['project'],\n systemPrompt: {\n type: 'preset',\n preset: 'claude_code',\n append: SHIPYARD_SYSTEM_PROMPT_APPEND,\n },\n },\n });\n\n this.#inputController = controller;\n this.#activeQuery = response;\n\n return this.#processMessages(response, newSessionId);\n }\n\n async #processMessages(response: Query, sessionId: string): Promise<SessionResult> {\n let agentSessionId = '';\n\n try {\n for await (const message of response) {\n const result = this.#handleMessage(message, sessionId, agentSessionId);\n if (result.agentSessionId) {\n agentSessionId = result.agentSessionId;\n }\n if (result.sessionResult) {\n return result.sessionResult;\n }\n }\n } catch (error: unknown) {\n const errorMsg = error instanceof Error ? error.message : String(error);\n this.#markFailed(sessionId, errorMsg);\n\n return {\n sessionId,\n agentSessionId,\n status: 'failed',\n error: errorMsg,\n };\n } finally {\n this.#inputController = null;\n this.#activeQuery = null;\n }\n\n this.#markFailed(sessionId, 'Session ended without result message');\n return {\n sessionId,\n agentSessionId,\n status: 'failed',\n error: 'Session ended without result message',\n };\n }\n\n /**\n * Find the current index of a session by its sessionId.\n * This is looked up at mutation time to avoid stale indices from\n * concurrent CRDT syncs that may shift list positions.\n */\n #findSessionIndex(sessionId: string): number {\n const sessions = this.#taskDoc.toJSON().sessions;\n return sessions.findIndex((s) => s.sessionId === sessionId);\n }\n\n #handleMessage(\n message: SDKMessage,\n sessionId: string,\n agentSessionId: string\n ): { agentSessionId?: string; sessionResult?: SessionResult } {\n if (message.type === 'system' && 'subtype' in message && message.subtype === 'init') {\n const initSessionId = message.session_id;\n if ('model' in message && typeof message.model === 'string') {\n this.#currentModel = message.model;\n }\n const idx = this.#findSessionIndex(sessionId);\n change(this.#taskDoc, (draft) => {\n const session = idx >= 0 ? draft.sessions.get(idx) : undefined;\n if (session) {\n session.agentSessionId = initSessionId;\n session.status = 'active';\n }\n draft.meta.status = 'working';\n draft.meta.updatedAt = Date.now();\n });\n this.#notifyStatusChange('working');\n return { agentSessionId: initSessionId };\n }\n\n if (message.type === 'assistant') {\n if ('error' in message && message.error) {\n logger.warn({ error: message.error, sessionId }, 'Assistant message carried an error');\n }\n this.#appendAssistantMessage(message);\n return {};\n }\n\n if (message.type === 'user' && !('isReplay' in message && message.isReplay)) {\n this.#appendUserToolResults(message);\n return {};\n }\n\n if (message.type === 'result') {\n return {\n sessionResult: this.#handleResult(message, sessionId, agentSessionId),\n };\n }\n\n return {};\n }\n\n /**\n * Extract tool_result blocks from SDK user messages (which carry tool outputs)\n * and append them to the last assistant conversation entry so the UI can\n * display tool completion status alongside the tool_use that triggered them.\n */\n #appendUserToolResults(message: SDKMessage & { type: 'user' }): void {\n const rawContent = message.message.content;\n if (!Array.isArray(rawContent)) return;\n\n const rawParent = 'parent_tool_use_id' in message ? message.parent_tool_use_id : null;\n const parentToolUseId = typeof rawParent === 'string' ? rawParent : null;\n\n // eslint-disable-next-line no-restricted-syntax -- SDK content blocks typed as unknown[], need narrowing\n const sdkBlocks = rawContent as Array<Record<string, unknown>>;\n const toolResultBlocks: ContentBlock[] = [];\n for (const block of sdkBlocks) {\n if (block.type === 'tool_result') {\n const parsed = parseSdkBlock(block, parentToolUseId);\n if (parsed) toolResultBlocks.push(parsed);\n }\n }\n\n if (toolResultBlocks.length === 0) return;\n\n const conversation = this.#taskDoc.toJSON().conversation;\n const lastMsg = conversation[conversation.length - 1];\n\n if (lastMsg && lastMsg.role === 'assistant') {\n const lastIdx = conversation.length - 1;\n change(this.#taskDoc, (draft) => {\n for (const block of toolResultBlocks) {\n draft.conversation.get(lastIdx)?.content.push(block);\n }\n draft.meta.updatedAt = Date.now();\n });\n } else {\n /** NOTE: No preceding assistant message -- store as a standalone assistant entry */\n change(this.#taskDoc, (draft) => {\n draft.conversation.push({\n messageId: nanoid(),\n role: 'assistant',\n content: toolResultBlocks,\n timestamp: Date.now(),\n model: this.#currentModel,\n machineId: this.#machineId,\n reasoningEffort: null,\n permissionMode: null,\n cwd: null,\n });\n draft.meta.updatedAt = Date.now();\n });\n }\n }\n\n #appendAssistantMessage(message: SDKMessage & { type: 'assistant' }): void {\n const rawContent = message.message.content;\n if (!Array.isArray(rawContent)) return;\n\n const rawParent = 'parent_tool_use_id' in message ? message.parent_tool_use_id : null;\n const parentToolUseId = typeof rawParent === 'string' ? rawParent : null;\n\n // eslint-disable-next-line no-restricted-syntax -- SDK content blocks typed as unknown[], need narrowing\n const sdkBlocks = rawContent as Array<Record<string, unknown>>;\n const contentBlocks: ContentBlock[] = [];\n for (const block of sdkBlocks) {\n const parsed = parseSdkBlock(block, parentToolUseId);\n if (parsed) contentBlocks.push(parsed);\n }\n\n if (contentBlocks.length === 0) return;\n\n change(this.#taskDoc, (draft) => {\n draft.conversation.push({\n messageId: nanoid(),\n role: 'assistant',\n content: contentBlocks,\n timestamp: Date.now(),\n model: this.#currentModel,\n machineId: this.#machineId,\n reasoningEffort: null,\n permissionMode: null,\n cwd: null,\n });\n draft.meta.updatedAt = Date.now();\n });\n\n this.#extractPlansFromBlocks(contentBlocks);\n }\n\n /**\n * Detect ExitPlanMode tool calls in content blocks and append plan versions\n * to the task document's plans list.\n */\n #extractPlansFromBlocks(blocks: ContentBlock[]): void {\n for (const block of blocks) {\n if (block.type !== 'tool_use' || block.toolName !== 'ExitPlanMode') continue;\n\n const planMarkdown = extractPlanMarkdown(block.input);\n if (!planMarkdown) {\n logger.warn(\n { toolUseId: block.toolUseId },\n 'Failed to parse ExitPlanMode tool input as JSON'\n );\n continue;\n }\n\n const existingPlans = this.#taskDoc.toJSON().plans;\n if (existingPlans.some((p) => p.toolUseId === block.toolUseId)) {\n logger.debug(\n { toolUseId: block.toolUseId },\n 'Plan already exists in CRDT, skipping duplicate'\n );\n continue;\n }\n\n change(this.#taskDoc, (draft) => {\n draft.plans.push({\n planId: nanoid(),\n toolUseId: block.toolUseId,\n markdown: planMarkdown,\n reviewStatus: 'pending',\n reviewFeedback: null,\n createdAt: Date.now(),\n });\n });\n\n logger.info({ toolUseId: block.toolUseId }, 'Extracted plan from ExitPlanMode tool call');\n }\n }\n\n #handleResult(\n message: SDKMessage & { type: 'result' },\n sessionId: string,\n agentSessionId: string\n ): SessionResult {\n const isSuccess = message.subtype === 'success';\n const completedAt = Date.now();\n\n const errorText =\n !isSuccess &&\n 'errors' in message &&\n Array.isArray(message.errors) &&\n message.errors.length > 0\n ? message.errors.join('; ')\n : null;\n\n const idx = this.#findSessionIndex(sessionId);\n const taskStatus: A2ATaskState = isSuccess ? 'completed' : 'failed';\n change(this.#taskDoc, (draft) => {\n const session = idx >= 0 ? draft.sessions.get(idx) : undefined;\n if (session) {\n session.status = isSuccess ? 'completed' : 'failed';\n session.completedAt = completedAt;\n session.totalCostUsd = message.total_cost_usd ?? null;\n session.durationMs = message.duration_ms ?? null;\n if (!isSuccess) {\n session.error = errorText ?? `Agent SDK error: ${message.subtype}`;\n }\n }\n draft.meta.status = taskStatus;\n draft.meta.updatedAt = completedAt;\n });\n this.#notifyStatusChange(taskStatus);\n\n const resultText =\n 'result' in message && typeof message.result === 'string' ? message.result : undefined;\n\n return {\n sessionId,\n agentSessionId,\n status: isSuccess ? 'completed' : 'failed',\n resultText,\n totalCostUsd: message.total_cost_usd,\n durationMs: message.duration_ms,\n error: !isSuccess ? (errorText ?? message.subtype) : undefined,\n };\n }\n\n #markFailed(sessionId: string, errorMsg: string): void {\n const idx = this.#findSessionIndex(sessionId);\n change(this.#taskDoc, (draft) => {\n const session = idx >= 0 ? draft.sessions.get(idx) : undefined;\n if (session) {\n session.status = 'failed';\n session.completedAt = Date.now();\n session.error = errorMsg;\n }\n draft.meta.status = 'failed';\n draft.meta.updatedAt = Date.now();\n });\n this.#notifyStatusChange('failed');\n }\n}\n","import type { SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';\n\ntype Resolver = (result: IteratorResult<SDKUserMessage>) => void;\n\nexport class StreamingInputController {\n #queue: SDKUserMessage[] = [];\n #waiting: Resolver | null = null;\n #done = false;\n\n push(message: string): void {\n const sdkMessage: SDKUserMessage = {\n type: 'user',\n message: {\n role: 'user',\n content: message,\n },\n parent_tool_use_id: null,\n session_id: '',\n };\n\n if (this.#done) return;\n\n if (this.#waiting) {\n const resolve = this.#waiting;\n this.#waiting = null;\n resolve({ value: sdkMessage, done: false });\n } else {\n this.#queue.push(sdkMessage);\n }\n }\n\n end(): void {\n this.#done = true;\n if (this.#waiting) {\n const resolve = this.#waiting;\n this.#waiting = null;\n // eslint-disable-next-line no-restricted-syntax -- IteratorResult requires value even when done\n resolve({ value: undefined as never, done: true });\n }\n }\n\n get isDone(): boolean {\n return this.#done;\n }\n\n iterable(): AsyncIterable<SDKUserMessage> {\n const self = this;\n return {\n [Symbol.asyncIterator]() {\n return {\n next(): Promise<IteratorResult<SDKUserMessage>> {\n if (self.#queue.length > 0) {\n const next = self.#queue.shift();\n if (!next) return Promise.resolve({ value: undefined as never, done: true });\n return Promise.resolve({ value: next, done: false });\n }\n if (self.#done) {\n // eslint-disable-next-line no-restricted-syntax -- IteratorResult requires value even when done\n return Promise.resolve({ value: undefined as never, done: true });\n }\n return new Promise<IteratorResult<SDKUserMessage>>((resolve) => {\n self.#waiting = resolve;\n });\n },\n };\n },\n };\n }\n}\n","import { hostname } from 'node:os';\nimport type { MachineCapabilities } from '@shipyard/session';\nimport { PersonalRoomConnection, ROUTES } from '@shipyard/session';\nimport { detectCapabilities } from './capabilities.js';\nimport type { Env } from './env.js';\nimport type { createChildLogger } from './logger.js';\nimport { createDaemonSignaling, type DaemonSignaling } from './signaling.js';\n\nexport interface SignalingHandle {\n signaling: DaemonSignaling;\n connection: PersonalRoomConnection;\n capabilities: MachineCapabilities;\n}\n\n/**\n * Build the WebSocket URL, detect machine capabilities, create\n * PersonalRoomConnection + DaemonSignaling, and wire auto-register\n * on connect.\n *\n * Capabilities are detected but NOT sent via signaling. They are\n * written to Loro ephemeral on the room document in serve.ts instead.\n *\n * Returns null when SHIPYARD_SIGNALING_URL is not configured.\n */\nexport async function createSignalingHandle(\n env: Env,\n log: ReturnType<typeof createChildLogger>\n): Promise<SignalingHandle | null> {\n if (!env.SHIPYARD_SIGNALING_URL) {\n return null;\n }\n\n const machineId = env.SHIPYARD_MACHINE_ID ?? hostname();\n const machineName = env.SHIPYARD_MACHINE_NAME ?? hostname();\n const wsUrl = new URL(env.SHIPYARD_SIGNALING_URL);\n\n if (!wsUrl.pathname.includes('/personal/')) {\n if (!env.SHIPYARD_USER_ID) {\n log.error(\n 'No user ID available to construct signaling WebSocket path. Run `shipyard login` first.'\n );\n return null;\n }\n wsUrl.pathname = ROUTES.WS_PERSONAL.replace(':userId', env.SHIPYARD_USER_ID);\n }\n\n if (env.SHIPYARD_USER_TOKEN) {\n wsUrl.searchParams.set('token', env.SHIPYARD_USER_TOKEN);\n }\n wsUrl.searchParams.set('clientType', 'agent');\n\n const capabilities = await detectCapabilities();\n log.info(\n { models: capabilities.models.length, environments: capabilities.environments.length },\n 'Detected machine capabilities'\n );\n\n const connection = new PersonalRoomConnection({ url: wsUrl.toString() });\n const signaling = createDaemonSignaling({\n connection,\n machineId,\n machineName,\n agentType: 'daemon',\n });\n\n connection.onStateChange((state) => {\n if (state === 'connected') {\n signaling.register();\n log.info({ machineId, machineName }, 'Registered with signaling server');\n }\n });\n\n return { signaling, connection, capabilities };\n}\n","import type { PersonalRoomClientMessage } from '@shipyard/session';\nimport { nanoid } from 'nanoid';\n\nexport interface SignalingConnection {\n send(msg: PersonalRoomClientMessage): void;\n}\n\nexport interface DaemonSignalingConfig {\n connection: SignalingConnection;\n machineId: string;\n machineName: string;\n agentType: string;\n}\n\nexport interface DaemonSignaling {\n register(): void;\n updateStatus(status: 'idle' | 'running' | 'error', taskId?: string): void;\n unregister(): void;\n destroy(): void;\n}\n\nexport function createDaemonSignaling(config: DaemonSignalingConfig): DaemonSignaling {\n const agentId = nanoid();\n\n function send(msg: PersonalRoomClientMessage): void {\n config.connection.send(msg);\n }\n\n return {\n register() {\n send({\n type: 'register-agent',\n agentId,\n machineId: config.machineId,\n machineName: config.machineName,\n agentType: config.agentType,\n });\n },\n\n updateStatus(status, taskId) {\n send({\n type: 'agent-status',\n agentId,\n status,\n ...(taskId !== undefined && { activeTaskId: taskId }),\n });\n },\n\n unregister() {\n send({\n type: 'unregister-agent',\n agentId,\n });\n },\n\n destroy() {},\n };\n}\n"],"mappings":"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","names":["mkdir","homedir","resolve","LoroDoc","LoroCounter","LoroList","LoroMap","LoroMovableList","LoroText","current","value","cachedItem","ref","containerValue","LoroCounter","LoroList","LoroMovableList","LoroMap","LoroText","internal","a: LogLevel","b: LogLevel","category: string | readonly string[]","LoggerImpl","rootLogger: LoggerImpl | null","parent: LoggerImpl | null","category: readonly string[]","subcategory:\n | string\n | readonly [string]\n | readonly [string, ...(readonly string[])]","child: LoggerImpl | undefined","logger","properties: Record<string, unknown>","record: LogRecord","level: LogLevel","record: Omit<LogRecord, \"category\"> | LogRecord","bypassSinks?: Set<Sink>","rawMessage: string","properties: Record<string, unknown> | (() => Record<string, unknown>)","cachedProps: Record<string, unknown> | undefined","callback: LogCallback","rawMessage: TemplateStringsArray | undefined","msg: unknown[] | undefined","messageTemplate: TemplateStringsArray","values: unknown[]","message:\n | TemplateStringsArray\n | string\n | LogCallback\n | Record<string, unknown>","LoggerCtx","logger: LoggerImpl","subcategory: string | readonly [string] | readonly [string, ...string[]]","message: string","record: Omit<LogRecord, \"category\">","key: string","obj: unknown","path: string","fromIndex: number","segment: string | number","current: unknown","current","template: string","message: unknown[]","prop: unknown","template: TemplateStringsArray","values: readonly unknown[]","categoryPrefixSymbol: unique symbol","result: Record<string, unknown>","LoroDoc","VersionVector","set","resolve","eventName","index","set","generatePatches","current","iterator","value","proxyDraft","ensureShallowCopy","create","base","draft","mark","result","LoroDoc","VersionVector","LoroDoc","VersionVector","resolve","logger","getLogger","jsonpath","wrappedCallback","logger","getLogger","LoroDoc","VersionVector","current","create","crypto","crypto","resolve","mkdir","homedir","hostname","join","readdir","join","resolve","readdir","join","join","process","spawn","resolve","hostname","homedir","mkdir","resolve","json","conversation","lastMessage","mkdir","resolve","homedir"]}