{"version":3,"sources":["../src/index.ts","../../node_modules/.pnpm/@hpke+common@1.10.1/node_modules/@hpke/common/esm/_dnt.shims.js","../../node_modules/.pnpm/@hpke+common@1.10.1/node_modules/@hpke/common/esm/src/consts.js","../../node_modules/.pnpm/@hpke+common@1.10.1/node_modules/@hpke/common/esm/src/kems/dhkemPrimitives/ec.js","../../node_modules/.pnpm/@hpke+common@1.10.1/node_modules/@hpke/common/esm/src/utils/noble.js","../../node_modules/.pnpm/@hpke+common@1.10.1/node_modules/@hpke/common/esm/src/hash/hash.js","../../node_modules/.pnpm/@hpke+common@1.10.1/node_modules/@hpke/common/esm/src/hash/hmac.js","../../node_modules/.pnpm/@hpke+common@1.10.1/node_modules/@hpke/common/esm/src/hash/u64.js","../../node_modules/.pnpm/@hpke+common@1.10.1/node_modules/@hpke/common/esm/src/hash/sha3.js","../../node_modules/.pnpm/@hpke+chacha20poly1305@1.8.0/node_modules/@hpke/chacha20poly1305/esm/src/chacha/utils.js","../../node_modules/.pnpm/@hpke+chacha20poly1305@1.8.0/node_modules/@hpke/chacha20poly1305/esm/src/chacha/_arx.js","../../node_modules/.pnpm/@hpke+chacha20poly1305@1.8.0/node_modules/@hpke/chacha20poly1305/esm/src/chacha/_poly1305.js","../../node_modules/.pnpm/@hpke+chacha20poly1305@1.8.0/node_modules/@hpke/chacha20poly1305/esm/src/chacha/chacha.js","../../node_modules/.pnpm/@hpke+core@1.9.0/node_modules/@hpke/core/esm/src/exporterContext.js","../../node_modules/.pnpm/@hpke+core@1.9.0/node_modules/@hpke/core/esm/src/mutex.js","../../node_modules/.pnpm/@hpke+core@1.9.0/node_modules/@hpke/core/esm/src/recipientContext.js","../../node_modules/.pnpm/@hpke+core@1.9.0/node_modules/@hpke/core/esm/src/senderContext.js","../../node_modules/.pnpm/@hpke+core@1.9.0/node_modules/@hpke/core/esm/src/cipherSuiteNative.js","../../node_modules/.pnpm/@hpke+core@1.9.0/node_modules/@hpke/core/esm/src/kems/dhkemPrimitives/x25519.js","../../node_modules/.pnpm/@hpke+core@1.9.0/node_modules/@hpke/core/esm/src/kems/dhkemPrimitives/x448.js","../../core/src/config.ts","../../core/src/errors.ts","../../core/src/platform.ts","../../core/src/pow.ts","../../core/src/sealed.ts","../../core/src/sealed-json.ts","../../core/src/sealed-keys.ts","../../core/src/url.ts","../../core/src/http.ts","../../core/src/token.ts","../src/errors.ts","../src/perf/url-redactor.ts","../src/sse.ts","../src/request.ts","../src/analytics-facade.ts","../src/auth-wire.ts","../src/passkey.ts","../src/auth-facade.ts","../src/calls/facade.ts","../../modules/flags/src/admin-client.ts","../../modules/flags/src/flags-client.ts","../../modules/flags/src/pooled-flags.ts","../src/flags-facade.ts","../src/messaging/deadline-calculator.ts","../src/messaging/delete-fold.ts","../src/messaging/edit-fold.ts","../src/messaging/util.ts","../src/messaging/wire.ts","../src/messaging/keydir.ts","../src/messaging/group-messaging.ts","../src/messaging/mention-ranges.ts","../src/messaging/reaction-fold.ts","../src/messaging/timer-fold.ts","../src/messaging/chat.ts","../src/messaging/delivery-source.ts","../src/messaging/disappearing.ts","../src/messaging/history.ts","../src/messaging/mention-elevation.ts","../src/messaging/wasm/pkg/palbe_mls_bg.js","../src/messaging/wasm/pkg/snippets/mls-rs-core-f99cdecbb456b09c/inline0.js","../src/messaging/wasm/loader.ts","../src/messaging/wasm/bridge.ts","../src/messaging/mls-engine.ts","../src/messaging/registry.ts","../src/messaging/storage.ts","../src/messaging/suppression.ts","../src/messaging/coordinator.ts","../src/messaging/facade.ts","../src/call.ts","../src/state.ts","../src/namespaces.ts","../src/runtime-metadata.ts","../src/realtime/anon-token.ts","../src/realtime/frames.ts","../src/realtime/connection.ts","../src/realtime/state.ts","../src/realtime/facade.ts","../src/storage.ts","../src/version.ts","../src/internal.ts","../src/room.ts","../src/upload.ts","../src/pb.ts"],"sourcesContent":["export type { OAuthOptions, OAuthProvider, OAuthPurpose, OAuthTransaction } from '@palbase/auth';\nexport type { AnalyticsProperties } from './analytics-facade.js';\nexport { PalbeAnalytics } from './analytics-facade.js';\nexport type {\n  AuthChangeEvent,\n  AuthState,\n  AuthSuccess,\n  AuthUser,\n  MagicLinkResult,\n  OAuthExchangeResult,\n  PalbePermissions,\n  SignInMethods,\n  Unsubscribe,\n} from './auth-facade.js';\nexport { PalbeAuth } from './auth-facade.js';\nexport type { Call, CallChangeCallback, CallParticipant, CallState } from './calls/facade.js';\nexport { PalbeCalls } from './calls/facade.js';\nexport type { PalbeConfig, PalbeOAuthConfig } from './config.js';\nexport type { BackendErrorKind, FieldError } from './errors.js';\nexport { BackendError, isBackendError } from './errors.js';\nexport type { FlagsView, FlagValue } from './flags-facade.js';\nexport { PalbeFlags } from './flags-facade.js';\nexport type { Chat, ChatBackend, ChatDraft } from './messaging/chat.js';\nexport { PalbeMessaging } from './messaging/facade.js';\n// `MentionRange` is the INPUT shape a caller passes to `Chat.send(text, { mentions })`\n// / `Chat.edit(..., { mentions })`; `ResolvedMention` is the RESOLVED span surfaced on\n// `ChatMessage.mentions` (normalized + roster displayName).\nexport type { MentionRange } from './messaging/group-messaging.js';\nexport type {\n  ChatKind,\n  ChatMember,\n  ChatMessage,\n  ChatMessageKind,\n  ChatRole,\n  ChatState,\n  CommsPrefs,\n  MessageDirection,\n  NotifyScope,\n  PresenceState,\n  ResolvedMention,\n  ResolvedReply,\n  SentReceipt,\n  UnreadView,\n} from './messaging/types.js';\nexport { initMls } from './messaging/wasm/loader.js';\nexport type { PB } from './pb.js';\nexport { pb } from './pb.js';\nexport type {\n  RealtimeChannelError,\n  RealtimeConnectionState,\n  RealtimeHandler,\n  RealtimePayload,\n  RealtimeStatus,\n  RealtimeStatusSnapshot,\n  RealtimeSubscription,\n} from './realtime/facade.js';\nexport { PalbeRealtime, RealtimeChannel } from './realtime/facade.js';\nexport type { CallOptions } from './request.js';\nexport type { RoomDescriptor, RoomHandle, RoomToken, RoomTransport } from './room.js';\n// Rooms: the generated client imports these types to declare its descriptors,\n// so they have to be reachable from the package root.\nexport { joinRoom } from './room.js';\nexport type { PersistedSession, SessionStorageAdapter } from './storage.js';\nexport { localStorageSessionStorage, memorySessionStorage } from './storage.js';\nexport type { UploadOptions, UploadProgress } from './upload.js';\nexport { VERSION } from './version.js';\n","const dntGlobals = {};\nexport const dntGlobalThis = createMergeProxy(globalThis, dntGlobals);\nfunction createMergeProxy(baseObj, extObj) {\n    return new Proxy(baseObj, {\n        get(_target, prop, _receiver) {\n            if (prop in extObj) {\n                return extObj[prop];\n            }\n            else {\n                return baseObj[prop];\n            }\n        },\n        set(_target, prop, value) {\n            if (prop in extObj) {\n                delete extObj[prop];\n            }\n            baseObj[prop] = value;\n            return true;\n        },\n        deleteProperty(_target, prop) {\n            let success = false;\n            if (prop in extObj) {\n                delete extObj[prop];\n                success = true;\n            }\n            if (prop in baseObj) {\n                delete baseObj[prop];\n                success = true;\n            }\n            return success;\n        },\n        ownKeys(_target) {\n            const baseKeys = Reflect.ownKeys(baseObj);\n            const extKeys = Reflect.ownKeys(extObj);\n            const extKeysSet = new Set(extKeys);\n            return [...baseKeys.filter((k) => !extKeysSet.has(k)), ...extKeys];\n        },\n        defineProperty(_target, prop, desc) {\n            if (prop in extObj) {\n                delete extObj[prop];\n            }\n            Reflect.defineProperty(baseObj, prop, desc);\n            return true;\n        },\n        getOwnPropertyDescriptor(_target, prop) {\n            if (prop in extObj) {\n                return Reflect.getOwnPropertyDescriptor(extObj, prop);\n            }\n            else {\n                return Reflect.getOwnPropertyDescriptor(baseObj, prop);\n            }\n        },\n        has(_target, prop) {\n            return prop in extObj || prop in baseObj;\n        },\n    });\n}\n","// The input length limit (psk, psk_id, info, exporter_context, ikm).\nexport const INPUT_LENGTH_LIMIT = 8192;\nexport const INFO_LENGTH_LIMIT = 268435456;\n// The minimum length of a PSK.\nexport const MINIMUM_PSK_LENGTH = 32;\n// b\"\"\nexport const EMPTY = /* @__PURE__ */ new Uint8Array(0);\n// Common BigInt constants\nexport const N_0 = 0n;\nexport const N_1 = 1n;\nexport const N_2 = 2n;\nexport const N_7 = 7n;\nexport const N_32 = 32n;\nexport const N_256 = 256n;\nexport const N_0x71 = 0x71n;\nexport const BYTE_TO_BIGINT_256 = /* @__PURE__ */ (() => {\n    const out = new Array(256);\n    let i = 0;\n    let value = 0n;\n    while (i < 256) {\n        out[i] = value;\n        i++;\n        value += 1n;\n    }\n    return out;\n})();\n","import { NativeAlgorithm } from \"../../algorithm.js\";\nimport { BYTE_TO_BIGINT_256, EMPTY } from \"../../consts.js\";\nimport { toArrayBuffer } from \"../../kdfs/hkdf.js\";\nimport { DeriveKeyPairError, DeserializeError, NotSupportedError, SerializeError, } from \"../../errors.js\";\nimport { KemId } from \"../../identifiers.js\";\nimport { KEM_USAGES, LABEL_DKP_PRK } from \"../../interfaces/dhkemPrimitives.js\";\nimport { Bignum } from \"../../utils/bignum.js\";\nimport { base64UrlToBytes, i2Osp } from \"../../utils/misc.js\";\n// b\"candidate\"\n// deno-fmt-ignore\nconst LABEL_CANDIDATE = /* @__PURE__ */ new Uint8Array([\n    99, 97, 110, 100, 105, 100, 97, 116, 101,\n]);\n// the order of the curve being used.\n// deno-fmt-ignore\nconst ORDER_P_256 = /* @__PURE__ */ new Uint8Array([\n    0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84,\n    0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,\n]);\n// deno-fmt-ignore\nconst ORDER_P_384 = /* @__PURE__ */ new Uint8Array([\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf,\n    0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a,\n    0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73,\n]);\n// deno-fmt-ignore\nconst ORDER_P_521 = /* @__PURE__ */ new Uint8Array([\n    0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n    0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f,\n    0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09,\n    0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c,\n    0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38,\n    0x64, 0x09,\n]);\n// deno-fmt-ignore\nconst PKCS8_ALG_ID_P_256 = /* @__PURE__ */ new Uint8Array([\n    48, 65, 2, 1, 0, 48, 19, 6, 7, 42,\n    134, 72, 206, 61, 2, 1, 6, 8, 42, 134,\n    72, 206, 61, 3, 1, 7, 4, 39, 48, 37,\n    2, 1, 1, 4, 32,\n]);\n// deno-fmt-ignore\nconst PKCS8_ALG_ID_P_384 = /* @__PURE__ */ new Uint8Array([\n    48, 78, 2, 1, 0, 48, 16, 6, 7, 42,\n    134, 72, 206, 61, 2, 1, 6, 5, 43, 129,\n    4, 0, 34, 4, 55, 48, 53, 2, 1, 1,\n    4, 48,\n]);\n// deno-fmt-ignore\nconst PKCS8_ALG_ID_P_521 = /* @__PURE__ */ new Uint8Array([\n    48, 96, 2, 1, 0, 48, 16, 6, 7, 42,\n    134, 72, 206, 61, 2, 1, 6, 5, 43, 129,\n    4, 0, 35, 4, 73, 48, 71, 2, 1, 1,\n    4, 66,\n]);\nconst EC_P_256_PARAMS = {\n    p: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,\n    b: 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bn,\n    gx: 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296n,\n    gy: 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5n,\n    coordinateSize: 32,\n};\nconst EC_P_384_PARAMS = {\n    p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,\n    b: 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefn,\n    gx: 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7n,\n    gy: 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fn,\n    coordinateSize: 48,\n};\nconst EC_P_521_PARAMS = {\n    p: (1n << 521n) - 1n,\n    b: 0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n,\n    gx: 0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66n,\n    gy: 0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n,\n    coordinateSize: 66,\n};\nfunction mod(a, p) {\n    const r = a % p;\n    return r >= 0n ? r : r + p;\n}\nfunction modPow(base, exponent, p) {\n    let result = 1n;\n    let b = mod(base, p);\n    let e = exponent;\n    while (e > 0n) {\n        if ((e & 1n) === 1n) {\n            result = mod(result * b, p);\n        }\n        b = mod(b * b, p);\n        e >>= 1n;\n    }\n    return result;\n}\nfunction modSqrt(rhs, p) {\n    // P-256/P-384/P-521 primes satisfy p % 4 == 3.\n    const y = modPow(rhs, (p + 1n) >> 2n, p);\n    if (mod(y * y, p) !== mod(rhs, p)) {\n        throw new Error(\"Invalid ECDH point\");\n    }\n    return y;\n}\nfunction bytesToBigInt(bytes) {\n    let v = 0n;\n    for (const b of bytes) {\n        v = (v << 8n) | BYTE_TO_BIGINT_256[b];\n    }\n    return v;\n}\nfunction bigIntToBytes(v, len) {\n    const out = new Uint8Array(len);\n    let n = v;\n    for (let i = len - 1; i >= 0; i--) {\n        out[i] = Number(n & 0xffn);\n        n >>= 8n;\n    }\n    if (n !== 0n) {\n        throw new Error(\"Invalid coordinate length\");\n    }\n    return out;\n}\nfunction buildRawUncompressedPublicKey(x, y, coordinateSize) {\n    const out = new Uint8Array(1 + coordinateSize * 2);\n    out[0] = 0x04;\n    out.set(bigIntToBytes(x, coordinateSize), 1);\n    out.set(bigIntToBytes(y, coordinateSize), 1 + coordinateSize);\n    return out;\n}\nexport class Ec extends NativeAlgorithm {\n    constructor(kem, hkdf) {\n        super();\n        Object.defineProperty(this, \"_hkdf\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_alg\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nPk\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nSk\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nDh\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        // EC specific arguments for deriving key pair.\n        Object.defineProperty(this, \"_order\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_bitmask\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_pkcs8AlgId\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_curveParams\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        this._hkdf = hkdf;\n        switch (kem) {\n            case KemId.DhkemP256HkdfSha256:\n                this._alg = { name: \"ECDH\", namedCurve: \"P-256\" };\n                this._nPk = 65;\n                this._nSk = 32;\n                this._nDh = 32;\n                this._order = ORDER_P_256;\n                this._bitmask = 0xFF;\n                this._pkcs8AlgId = PKCS8_ALG_ID_P_256;\n                this._curveParams = EC_P_256_PARAMS;\n                break;\n            case KemId.DhkemP384HkdfSha384:\n                this._alg = { name: \"ECDH\", namedCurve: \"P-384\" };\n                this._nPk = 97;\n                this._nSk = 48;\n                this._nDh = 48;\n                this._order = ORDER_P_384;\n                this._bitmask = 0xFF;\n                this._pkcs8AlgId = PKCS8_ALG_ID_P_384;\n                this._curveParams = EC_P_384_PARAMS;\n                break;\n            default:\n                // case KemId.DhkemP521HkdfSha512:\n                this._alg = { name: \"ECDH\", namedCurve: \"P-521\" };\n                this._nPk = 133;\n                this._nSk = 66;\n                this._nDh = 66;\n                this._order = ORDER_P_521;\n                this._bitmask = 0x01;\n                this._pkcs8AlgId = PKCS8_ALG_ID_P_521;\n                this._curveParams = EC_P_521_PARAMS;\n                break;\n        }\n    }\n    async serializePublicKey(key) {\n        await this._setup();\n        try {\n            return await this._api.exportKey(\"raw\", key);\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async deserializePublicKey(key) {\n        await this._setup();\n        try {\n            return await this._importRawKey(toArrayBuffer(key), true);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async serializePrivateKey(key) {\n        await this._setup();\n        try {\n            const jwk = await this._api.exportKey(\"jwk\", key);\n            if (!(\"d\" in jwk)) {\n                throw new Error(\"Not private key\");\n            }\n            return base64UrlToBytes(jwk[\"d\"]).buffer;\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async deserializePrivateKey(key) {\n        await this._setup();\n        try {\n            return await this._importRawKey(toArrayBuffer(key), false);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async importKey(format, key, isPublic) {\n        await this._setup();\n        try {\n            if (format === \"raw\") {\n                return await this._importRawKey(key, isPublic);\n            }\n            // jwk\n            if (key instanceof ArrayBuffer) {\n                throw new Error(\"Invalid jwk key format\");\n            }\n            return await this._importJWK(key, isPublic);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async generateKeyPair() {\n        await this._setup();\n        try {\n            return await this._api.generateKey(this._alg, true, KEM_USAGES);\n        }\n        catch (e) {\n            throw new NotSupportedError(e);\n        }\n    }\n    async deriveKeyPair(ikm) {\n        await this._setup();\n        try {\n            const rawIkm = toArrayBuffer(ikm);\n            const dkpPrk = await this._hkdf.labeledExtract(EMPTY, LABEL_DKP_PRK, new Uint8Array(rawIkm));\n            const bn = new Bignum(this._nSk);\n            for (let counter = 0; bn.isZero() || !bn.lessThan(this._order); counter++) {\n                if (counter > 255) {\n                    throw new Error(\"Faild to derive a key pair\");\n                }\n                const bytes = new Uint8Array(await this._hkdf.labeledExpand(dkpPrk, LABEL_CANDIDATE, i2Osp(counter, 1), this._nSk));\n                bytes[0] = bytes[0] & this._bitmask;\n                bn.set(bytes);\n            }\n            const sk = await this._deserializePkcs8Key(bn.val());\n            bn.reset();\n            return {\n                privateKey: sk,\n                publicKey: await this.derivePublicKey(sk),\n            };\n        }\n        catch (e) {\n            throw new DeriveKeyPairError(e);\n        }\n    }\n    async derivePublicKey(key) {\n        await this._setup();\n        try {\n            const jwk = await this._api.exportKey(\"jwk\", key);\n            delete jwk[\"d\"];\n            delete jwk[\"key_ops\"];\n            return await this._api.importKey(\"jwk\", jwk, this._alg, true, []);\n        }\n        catch {\n            try {\n                // Firefox fails to export JWK from some imported ECDH private keys.\n                return await this._derivePublicKeyWithoutJwkExport(key);\n            }\n            catch (e) {\n                throw new DeserializeError(e);\n            }\n        }\n    }\n    async dh(sk, pk) {\n        try {\n            await this._setup();\n            const bits = await this._api.deriveBits({\n                name: \"ECDH\",\n                public: pk,\n            }, sk, this._nDh * 8);\n            return bits;\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async _importRawKey(key, isPublic) {\n        if (isPublic && key.byteLength !== this._nPk) {\n            throw new Error(\"Invalid public key for the ciphersuite\");\n        }\n        if (!isPublic && key.byteLength !== this._nSk) {\n            throw new Error(\"Invalid private key for the ciphersuite\");\n        }\n        if (isPublic) {\n            return await this._api.importKey(\"raw\", key, this._alg, true, []);\n        }\n        return await this._deserializePkcs8Key(new Uint8Array(key));\n    }\n    async _importJWK(key, isPublic) {\n        if (typeof key.crv === \"undefined\" || key.crv !== this._alg.namedCurve) {\n            throw new Error(`Invalid crv: ${key.crv}`);\n        }\n        if (isPublic) {\n            if (typeof key.d !== \"undefined\") {\n                throw new Error(\"Invalid key: `d` should not be set\");\n            }\n            return await this._api.importKey(\"jwk\", key, this._alg, true, []);\n        }\n        if (typeof key.d === \"undefined\") {\n            throw new Error(\"Invalid key: `d` not found\");\n        }\n        return await this._api.importKey(\"jwk\", key, this._alg, true, KEM_USAGES);\n    }\n    async _deserializePkcs8Key(k) {\n        const pkcs8Key = new Uint8Array(this._pkcs8AlgId.length + k.length);\n        pkcs8Key.set(this._pkcs8AlgId, 0);\n        pkcs8Key.set(k, this._pkcs8AlgId.length);\n        return await this._api.importKey(\"pkcs8\", pkcs8Key, this._alg, true, KEM_USAGES);\n    }\n    async _derivePublicKeyWithoutJwkExport(key) {\n        const basePointRaw = buildRawUncompressedPublicKey(this._curveParams.gx, this._curveParams.gy, this._curveParams.coordinateSize);\n        const basePoint = await this._api.importKey(\"raw\", basePointRaw.buffer, this._alg, true, []);\n        const xBytes = new Uint8Array(await this._api.deriveBits({\n            name: \"ECDH\",\n            public: basePoint,\n        }, key, this._nDh * 8));\n        const p = this._curveParams.p;\n        const x = bytesToBigInt(xBytes);\n        const rhs = mod(modPow(x, 3n, p) - 3n * x + this._curveParams.b, p);\n        let y = modSqrt(rhs, p);\n        // Canonicalize sign so the encoded point is deterministic.\n        if ((y & 1n) === 1n) {\n            y = p - y;\n        }\n        const pubRaw = buildRawUncompressedPublicKey(x, y, this._curveParams.coordinateSize);\n        return await this._api.importKey(\"raw\", pubRaw.buffer, this._alg, true, []);\n    }\n}\n","// deno-lint-ignore-file no-explicit-any\n/**\n * This file is based on noble-curves (https://github.com/paulmillr/noble-curves).\n *\n * noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-curves/blob/b9d49d2b41d550571a0c5be443ecb62109fa3373/src/utils.ts\n */\n/**\n * Hex, bytes and number utilities.\n * @module\n */\nimport { loadCrypto } from \"./misc.js\";\nimport { N_0 } from \"../consts.js\";\n/** Checks if something is Uint8Array. Be careful: nodejs Buffer will return true. */\nexport function isBytes(a) {\n    return a instanceof Uint8Array ||\n        (ArrayBuffer.isView(a) && a.constructor.name === \"Uint8Array\");\n}\n/** Asserts something is positive integer. */\nexport function anumber(n, title = \"\") {\n    if (!Number.isSafeInteger(n) || n < 0) {\n        const prefix = title && `\"${title}\" `;\n        throw new Error(`${prefix}expected integer >0, got ${n}`);\n    }\n}\n/** Asserts something is Uint8Array. */\nexport function abytes(value, length, title = \"\") {\n    const bytes = isBytes(value);\n    const len = value?.length;\n    const needsLen = length !== undefined;\n    if (!bytes || (needsLen && len !== length)) {\n        const prefix = title && `\"${title}\" `;\n        const ofLen = needsLen ? ` of length ${length}` : \"\";\n        const got = bytes ? `length=${len}` : `type=${typeof value}`;\n        throw new Error(prefix + \"expected Uint8Array\" + ofLen + \", got \" + got);\n    }\n    return value;\n}\n// ahash function is now imported from ../hash/hash.ts\n/** Asserts a hash instance has not been destroyed / finished */\nexport function aexists(instance, checkFinished = true) {\n    if (instance.destroyed)\n        throw new Error(\"Hash instance has been destroyed\");\n    if (checkFinished && instance.finished) {\n        throw new Error(\"Hash#digest() has already been called\");\n    }\n}\n/** Asserts output is properly-sized byte array */\nexport function aoutput(out, instance) {\n    abytes(out, undefined, \"digestInto() output\");\n    const min = instance.outputLen;\n    if (out.length < min) {\n        throw new Error('\"digestInto() output\" expected to be of length >=' + min);\n    }\n}\n// Used in weierstrass, der\nfunction abignumer(n) {\n    if (typeof n === \"bigint\") {\n        if (!isPosBig(n))\n            throw new Error(\"positive bigint expected, got \" + n);\n    }\n    else\n        anumber(n);\n    return n;\n}\n/** Cast u8 / u16 / u32 to u32. */\nexport function u32(arr) {\n    return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));\n}\n/** Zeroize a byte array. Warning: JS provides no guarantees. */\nexport function clean(...arrays) {\n    for (let i = 0; i < arrays.length; i++) {\n        arrays[i].fill(0);\n    }\n}\n/** Pre-computed buffer for endianness detection */\nconst _endianTestBuffer = /* @__PURE__ */ new Uint32Array([0x11223344]);\nconst _endianTestBytes = /* @__PURE__ */ new Uint8Array(_endianTestBuffer.buffer);\n/** Is current platform little-endian? Most are. Big-Endian platform: IBM */\nexport const isLE = /* @__PURE__ */ _endianTestBytes[0] === 0x44;\n/** The byte swap operation for uint32 */\nexport function byteSwap(word) {\n    return (((word << 24) & 0xff000000) |\n        ((word << 8) & 0xff0000) |\n        ((word >>> 8) & 0xff00) |\n        ((word >>> 24) & 0xff));\n}\n/** Conditionally byte swap if on a big-endian platform */\nexport function swap8IfBE(n) {\n    return isLE ? n : byteSwap(n);\n}\n/** @deprecated */\nexport const byteSwapIfBE = swap8IfBE;\n/** In place byte swap for Uint32Array */\nexport function byteSwap32(arr) {\n    for (let i = 0; i < arr.length; i++) {\n        arr[i] = byteSwap(arr[i]);\n    }\n    return arr;\n}\nexport function swap32IfBE(u) {\n    return isLE ? u : byteSwap32(u);\n}\n/** Create DataView of an array for easy byte-level manipulation. */\nexport function createView(arr) {\n    return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n/** The rotate right (circular right shift) operation for uint32 */\nexport function rotr(word, shift) {\n    return (word << (32 - shift)) | (word >>> shift);\n}\n// Built-in hex conversion https://caniuse.com/mdn-javascript_builtins_uint8array_fromhex\nconst hasHexBuiltin = /* @__PURE__ */ (() => \n// @ts-ignore: to use toHex\ntypeof Uint8Array.from([]).toHex === \"function\" &&\n    // @ts-ignore: to use fromHex\n    typeof Uint8Array.fromHex === \"function\")();\n// Array where index 0xf0 (240) is mapped to string 'f0'\nconst hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, \"0\"));\nconst HEX_TO_BIGINT = /* @__PURE__ */ [\n    0n,\n    1n,\n    2n,\n    3n,\n    4n,\n    5n,\n    6n,\n    7n,\n    8n,\n    9n,\n    10n,\n    11n,\n    12n,\n    13n,\n    14n,\n    15n,\n];\n/**\n * Convert byte array to hex string. Uses built-in function, when available.\n * @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'\n */\nexport function bytesToHex(bytes) {\n    abytes(bytes);\n    // @ts-ignore: to use toHex\n    if (hasHexBuiltin)\n        return bytes.toHex();\n    // pre-caching improves the speed 6x\n    let hex = \"\";\n    for (let i = 0; i < bytes.length; i++) {\n        hex += hexes[bytes[i]];\n    }\n    return hex;\n}\n// We use optimized technique to convert hex string to byte array\nconst asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };\nfunction asciiToBase16(ch) {\n    if (ch >= asciis._0 && ch <= asciis._9)\n        return ch - asciis._0; // '2' => 50-48\n    if (ch >= asciis.A && ch <= asciis.F)\n        return ch - (asciis.A - 10); // 'B' => 66-(65-10)\n    if (ch >= asciis.a && ch <= asciis.f)\n        return ch - (asciis.a - 10); // 'b' => 98-(97-10)\n    return;\n}\n/**\n * Convert hex string to byte array. Uses built-in function, when available.\n * @example hexToBytes('cafe0123') // Uint8Array.from([0xca, 0xfe, 0x01, 0x23])\n */\nexport function hexToBytes(hex) {\n    if (typeof hex !== \"string\") {\n        throw new Error(\"hex string expected, got \" + typeof hex);\n    }\n    // @ts-ignore: to use fromHex\n    if (hasHexBuiltin)\n        return Uint8Array.fromHex(hex);\n    const hl = hex.length;\n    const al = hl / 2;\n    if (hl % 2) {\n        throw new Error(\"hex string expected, got unpadded hex of length \" + hl);\n    }\n    const array = new Uint8Array(al);\n    for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {\n        const n1 = asciiToBase16(hex.charCodeAt(hi));\n        const n2 = asciiToBase16(hex.charCodeAt(hi + 1));\n        if (n1 === undefined || n2 === undefined) {\n            const char = hex[hi] + hex[hi + 1];\n            throw new Error('hex string expected, got non-hex character \"' + char + '\" at index ' +\n                hi);\n        }\n        array[ai] = n1 * 16 + n2; // multiply first octet, e.g. 'a3' => 10*16+3 => 160 + 3 => 163\n    }\n    return array;\n}\n/**\n * Converts string to bytes using UTF8 encoding.\n * @example utf8ToBytes('abc') // Uint8Array.from([97, 98, 99])\n */\nexport function utf8ToBytes(str) {\n    if (typeof str !== \"string\")\n        throw new Error(\"string expected\");\n    return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809\n}\n/**\n * Converts bytes to string using UTF8 encoding.\n * @example bytesToUtf8(Uint8Array.from([97, 98, 99])) // 'abc'\n */\nexport function bytesToUtf8(bytes) {\n    return new TextDecoder().decode(bytes);\n}\nexport function numberToHexUnpadded(num) {\n    const hex = abignumer(num).toString(16);\n    return hex.length & 1 ? \"0\" + hex : hex;\n}\nexport function hexToNumber(hex) {\n    if (typeof hex !== \"string\") {\n        throw new Error(\"hex string expected, got \" + typeof hex);\n    }\n    let out = N_0;\n    for (let i = 0; i < hex.length; i++) {\n        const n = asciiToBase16(hex.charCodeAt(i));\n        if (n === undefined) {\n            throw new Error('hex string expected, got non-hex character \"' + hex[i] +\n                '\" at index ' + i);\n        }\n        out = (out << 4n) | HEX_TO_BIGINT[n];\n    }\n    return out; // Big Endian\n}\nexport function numberToBigint(num) {\n    anumber(num, \"numberToBigint\");\n    let n = num;\n    let out = N_0;\n    let bit = 1n;\n    while (n > 0) {\n        if (n % 2 === 1)\n            out += bit;\n        n = Math.floor(n / 2);\n        bit <<= 1n;\n    }\n    return out;\n}\n// BE: Big Endian, LE: Little Endian\nexport function bytesToNumberBE(bytes) {\n    return hexToNumber(bytesToHex(bytes));\n}\nexport function bytesToNumberLE(bytes) {\n    return hexToNumber(bytesToHex(copyBytes(abytes(bytes)).reverse()));\n}\nexport function numberToBytesBE(n, len) {\n    anumber(len);\n    n = abignumer(n);\n    const res = hexToBytes(n.toString(16).padStart(len * 2, \"0\"));\n    if (res.length !== len)\n        throw new Error(\"number too large\");\n    return res;\n}\nexport function numberToBytesLE(n, len) {\n    return numberToBytesBE(n, len).reverse();\n}\n/**\n * Copies Uint8Array. We can't use u8a.slice(), because u8a can be Buffer,\n * and Buffer#slice creates mutable copy. Never use Buffers!\n */\nexport function copyBytes(bytes) {\n    return Uint8Array.from(bytes);\n}\n/** Copies several Uint8Arrays into one. */\nexport function concatBytes(...arrays) {\n    let sum = 0;\n    for (let i = 0; i < arrays.length; i++) {\n        const a = arrays[i];\n        abytes(a);\n        sum += a.length;\n    }\n    const res = new Uint8Array(sum);\n    for (let i = 0, pad = 0; i < arrays.length; i++) {\n        const a = arrays[i];\n        res.set(a, pad);\n        pad += a.length;\n    }\n    return res;\n}\n/**\n * Decodes 7-bit ASCII string to Uint8Array, throws on non-ascii symbols\n * Should be safe to use for things expected to be ASCII.\n * Returns exact same result as utf8ToBytes for ASCII or throws.\n */\nexport function asciiToBytes(ascii) {\n    return Uint8Array.from(ascii, (c, i) => {\n        const charCode = c.charCodeAt(0);\n        if (c.length !== 1 || charCode > 127) {\n            throw new Error(`string contains non-ASCII character \"${ascii[i]}\" with code ${charCode} at position ${i}`);\n        }\n        return charCode;\n    });\n}\n// Is positive bigint\nfunction isPosBig(n) {\n    return typeof n === \"bigint\" && N_0 <= n;\n}\nexport function inRange(n, min, max) {\n    return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;\n}\n/**\n * Asserts min <= n < max. NOTE: It's < max and not <= max.\n * @example\n * aInRange('x', x, 1n, 256n); // would assume x is in (1n..255n)\n */\nexport function aInRange(title, n, min, max) {\n    // Why min <= n < max and not a (min < n < max) OR b (min <= n <= max)?\n    // consider P=256n, min=0n, max=P\n    // - a for min=0 would require -1:          `inRange('x', x, -1n, P)`\n    // - b would commonly require subtraction:  `inRange('x', x, 0n, P - 1n)`\n    // - our way is the cleanest:               `inRange('x', x, 0n, P)\n    if (!inRange(n, min, max)) {\n        throw new Error(\"expected valid \" + title + \": \" + min + \" <= n < \" + max + \", got \" + n);\n    }\n}\nexport function validateObject(object, fields = {}, optFields = {}) {\n    if (!object || typeof object !== \"object\") {\n        throw new Error(\"expected valid options object\");\n    }\n    function checkField(fieldName, expectedType, isOpt) {\n        const val = object[fieldName];\n        if (isOpt && val === undefined)\n            return;\n        const current = typeof val;\n        if (current !== expectedType || val === null) {\n            throw new Error(`param \"${fieldName}\" is invalid: expected ${expectedType}, got ${current}`);\n        }\n    }\n    const iter = (f, isOpt) => Object.entries(f).forEach(([k, v]) => checkField(k, v, isOpt));\n    iter(fields, false);\n    iter(optFields, true);\n}\n// createHasher function is now exported above with ahash\n// /** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\n// export function randomBytes(bytesLength = 32): Uint8Array {\n//   const cr = typeof globalThis != null && (globalThis as any).crypto;\n//   if (!cr || typeof cr.getRandomValues !== \"function\") {\n//     throw new Error(\"crypto.getRandomValues must be defined\");\n//   }\n//   return cr.getRandomValues(new Uint8Array(bytesLength));\n// }\n/** Cryptographically secure PRNG. Uses internal OS-level `crypto.getRandomValues`. */\nexport async function randomBytesAsync(bytesLength = 32) {\n    const api = await loadCrypto();\n    const rnd = new Uint8Array(bytesLength);\n    api.getRandomValues(rnd);\n    return rnd;\n}\n// 06 09 60 86 48 01 65 03 04 02\nexport function oidNist(suffix) {\n    return {\n        oid: Uint8Array.from([\n            0x06,\n            0x09,\n            0x60,\n            0x86,\n            0x48,\n            0x01,\n            0x65,\n            0x03,\n            0x04,\n            0x02,\n            suffix,\n        ]),\n    };\n}\n","/**\n * This file is based on noble-curves (https://github.com/paulmillr/noble-curves).\n *\n * noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-curves/blob/b9d49d2b41d550571a0c5be443ecb62109fa3373/src/utils.ts\n */\n/**\n * Hash utilities and type definitions extracted from noble.ts\n * @module\n */\nimport { anumber } from \"../utils/noble.js\";\n/** Asserts something is hash */\nexport function ahash(h) {\n    if (typeof h !== \"function\" || typeof h.create !== \"function\") {\n        throw new Error(\"Hash must wrapped by utils.createHasher\");\n    }\n    anumber(h.outputLen);\n    anumber(h.blockLen);\n}\nexport function createHasher(hashCons, info = {}) {\n    const hashFn = (msg, opts) => hashCons(opts).update(msg).digest();\n    const tmp = hashCons(undefined);\n    const hashC = Object.assign(hashFn, {\n        outputLen: tmp.outputLen,\n        blockLen: tmp.blockLen,\n        create: (opts) => hashCons(opts),\n        ...info,\n    });\n    return Object.freeze(hashC);\n}\n","// deno-lint-ignore-file no-explicit-any\n/**\n * This file is based on noble-hashes (https://github.com/paulmillr/noble-hashes).\n *\n * noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-hashes/blob/2e0c00e1aa134082ba1380bf3afb8b1641f60fed/src/hmac.ts\n */\n/**\n * HMAC: RFC2104 message authentication code.\n * @module\n */\nimport { abytes, aexists, clean } from \"../utils/noble.js\";\nimport { ahash } from \"./hash.js\";\nexport class _HMAC {\n    constructor(hash, key) {\n        Object.defineProperty(this, \"oHash\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"iHash\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"blockLen\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"outputLen\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"finished\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: false\n        });\n        Object.defineProperty(this, \"destroyed\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: false\n        });\n        ahash(hash);\n        abytes(key, undefined, \"key\");\n        this.iHash = hash.create();\n        if (typeof this.iHash.update !== \"function\") {\n            throw new Error(\"Expected instance of class which extends utils.Hash\");\n        }\n        this.blockLen = this.iHash.blockLen;\n        this.outputLen = this.iHash.outputLen;\n        const blockLen = this.blockLen;\n        const pad = new Uint8Array(blockLen);\n        // blockLen can be bigger than outputLen\n        pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);\n        for (let i = 0; i < pad.length; i++)\n            pad[i] ^= 0x36;\n        this.iHash.update(pad);\n        // By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone\n        this.oHash = hash.create();\n        // Undo internal XOR && apply outer XOR\n        for (let i = 0; i < pad.length; i++)\n            pad[i] ^= 0x36 ^ 0x5c;\n        this.oHash.update(pad);\n        clean(pad);\n    }\n    update(buf) {\n        aexists(this);\n        this.iHash.update(buf);\n        return this;\n    }\n    digestInto(out) {\n        aexists(this);\n        abytes(out, this.outputLen, \"output\");\n        this.finished = true;\n        this.iHash.digestInto(out);\n        this.oHash.update(out);\n        this.oHash.digestInto(out);\n        this.destroy();\n    }\n    digest() {\n        const out = new Uint8Array(this.oHash.outputLen);\n        this.digestInto(out);\n        return out;\n    }\n    _cloneInto(to) {\n        // Create new instance without calling constructor since key already in state and we don't know it.\n        to ||= Object.create(Object.getPrototypeOf(this), {});\n        const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;\n        to = to;\n        to.finished = finished;\n        to.destroyed = destroyed;\n        to.blockLen = blockLen;\n        to.outputLen = outputLen;\n        to.oHash = oHash._cloneInto(to.oHash);\n        to.iHash = iHash._cloneInto(to.iHash);\n        return to;\n    }\n    clone() {\n        return this._cloneInto();\n    }\n    destroy() {\n        this.destroyed = true;\n        this.oHash.destroy();\n        this.iHash.destroy();\n    }\n}\n/**\n * HMAC: RFC2104 message authentication code.\n * @param hash - function that would be used e.g. sha256\n * @param key - message key\n * @param message - message data\n * @example\n * import { hmac } from '@noble/hashes/hmac';\n * import { sha256 } from '@noble/hashes/sha2';\n * const mac1 = hmac(sha256, 'key', 'message');\n */\nexport const hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest();\nhmac.create = (hash, key) => new _HMAC(hash, key);\n","/**\n * This file is based on noble-hashes (https://github.com/paulmillr/noble-hashes).\n *\n * noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-hashes/blob/4e358a46d682adfb005ae6314ec999f2513086b9/src/_u64.ts\n */\n/**\n * Internal helpers for u64. BigUint64Array is too slow as per 2025, so we implement it using Uint32Array.\n * @todo re-check https://issues.chromium.org/issues/42212588\n * @module\n */\nconst U32_MASK64 = 0xffffffffn;\nconst _32n = 32n;\nfunction fromBig(n, le = false) {\n    if (le) {\n        return { h: Number(n & U32_MASK64), l: Number((n >> _32n) & U32_MASK64) };\n    }\n    return {\n        h: Number((n >> _32n) & U32_MASK64) | 0,\n        l: Number(n & U32_MASK64) | 0,\n    };\n}\nfunction split(lst, le = false) {\n    const len = lst.length;\n    const Ah = new Uint32Array(len);\n    const Al = new Uint32Array(len);\n    for (let i = 0; i < len; i++) {\n        const { h, l } = fromBig(lst[i], le);\n        [Ah[i], Al[i]] = [h, l];\n    }\n    return [Ah, Al];\n}\nconst toBig = (h, l) => (BigInt(h >>> 0) << _32n) | BigInt(l >>> 0);\n// for Shift in [0, 32)\nconst shrSH = (h, _l, s) => h >>> s;\nconst shrSL = (h, l, s) => (h << (32 - s)) | (l >>> s);\n// Right rotate for Shift in [1, 32)\nconst rotrSH = (h, l, s) => (h >>> s) | (l << (32 - s));\nconst rotrSL = (h, l, s) => (h << (32 - s)) | (l >>> s);\n// Right rotate for Shift in (32, 64), NOTE: 32 is special case.\nconst rotrBH = (h, l, s) => (h << (64 - s)) | (l >>> (s - 32));\nconst rotrBL = (h, l, s) => (h >>> (s - 32)) | (l << (64 - s));\n// Right rotate for shift===32 (just swaps l&h)\nconst rotr32H = (_h, l) => l;\nconst rotr32L = (h, _l) => h;\n// Left rotate for Shift in [1, 32)\nconst rotlSH = (h, l, s) => (h << s) | (l >>> (32 - s));\nconst rotlSL = (h, l, s) => (l << s) | (h >>> (32 - s));\n// Left rotate for Shift in (32, 64), NOTE: 32 is special case.\nconst rotlBH = (h, l, s) => (l << (s - 32)) | (h >>> (64 - s));\nconst rotlBL = (h, l, s) => (h << (s - 32)) | (l >>> (64 - s));\n// JS uses 32-bit signed integers for bitwise operations which means we cannot\n// simple take carry out of low bit sum by shift, we need to use division.\nfunction add(Ah, Al, Bh, Bl) {\n    const l = (Al >>> 0) + (Bl >>> 0);\n    return { h: (Ah + Bh + ((l / 2 ** 32) | 0)) | 0, l: l | 0 };\n}\n// Addition with more than 2 elements\nconst add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);\nconst add3H = (low, Ah, Bh, Ch) => (Ah + Bh + Ch + ((low / 2 ** 32) | 0)) | 0;\nconst add4L = (Al, Bl, Cl, Dl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0);\nconst add4H = (low, Ah, Bh, Ch, Dh) => (Ah + Bh + Ch + Dh + ((low / 2 ** 32) | 0)) | 0;\nconst add5L = (Al, Bl, Cl, Dl, El) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0) + (Dl >>> 0) + (El >>> 0);\nconst add5H = (low, Ah, Bh, Ch, Dh, Eh) => (Ah + Bh + Ch + Dh + Eh + ((low / 2 ** 32) | 0)) | 0;\n// prettier-ignore\nexport { add, add3H, add3L, add4H, add4L, add5H, add5L, fromBig, rotlBH, rotlBL, rotlSH, rotlSL, rotr32H, rotr32L, rotrBH, rotrBL, rotrSH, rotrSL, shrSH, shrSL, split, toBig, };\n// prettier-ignore\nconst u64 = {\n    fromBig,\n    split,\n    toBig,\n    shrSH,\n    shrSL,\n    rotrSH,\n    rotrSL,\n    rotrBH,\n    rotrBL,\n    rotr32H,\n    rotr32L,\n    rotlSH,\n    rotlSL,\n    rotlBH,\n    rotlBL,\n    add,\n    add3L,\n    add3H,\n    add4L,\n    add4H,\n    add5H,\n    add5L,\n};\nexport default u64;\n","/**\n * This file is based on noble-hashes (https://github.com/paulmillr/noble-hashes).\n *\n * noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-hashes/blob/4e358a46d682adfb005ae6314ec999f2513086b9/src/sha3.ts\n */\n/**\n * SHA3 (keccak) hash function, based on a new \"Sponge function\" design.\n * Different from older hashes, the internal state is bigger than output size.\n *\n * Check out [FIPS-202](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf),\n * [Website](https://keccak.team/keccak.html),\n * [the differences between SHA-3 and Keccak](https://crypto.stackexchange.com/questions/15727/what-are-the-key-differences-between-the-draft-sha-3-standard-and-the-keccak-sub).\n *\n * Check out `sha3-addons` module for cSHAKE, k12, and others.\n * @module\n */\nimport { rotlBH, rotlBL, rotlSH, rotlSL, split } from \"./u64.js\";\nimport { abytes, aexists, anumber, aoutput, clean, oidNist, swap32IfBE, u32, } from \"../utils/noble.js\";\nimport { createHasher, } from \"./hash.js\";\n// No __PURE__ annotations in sha3 header:\n// EVERYTHING is in fact used on every export.\n// Various per round constants calculations\nconst _0n = 0n;\nconst _1n = 1n;\nconst _2n = 2n;\nconst _7n = 7n;\nconst _256n = 256n;\nconst _0x71n = 0x71n;\nconst SHA3_PI = [];\nconst SHA3_ROTL = [];\nconst _SHA3_IOTA = []; // no pure annotation: var is always used\nfor (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {\n    // Pi\n    [x, y] = [y, (2 * x + 3 * y) % 5];\n    SHA3_PI.push(2 * (5 * y + x));\n    // Rotational\n    SHA3_ROTL.push((((round + 1) * (round + 2)) / 2) % 64);\n    // Iota\n    let t = _0n;\n    for (let j = 0; j < 7; j++) {\n        R = ((R << _1n) ^ ((R >> _7n) * _0x71n)) % _256n;\n        if (R & _2n)\n            t ^= _1n << ((_1n << BigInt(j)) - _1n);\n    }\n    _SHA3_IOTA.push(t);\n}\nconst IOTAS = split(_SHA3_IOTA, true);\nconst SHA3_IOTA_H = IOTAS[0];\nconst SHA3_IOTA_L = IOTAS[1];\n// Left rotation (without 0, 32, 64)\nconst rotlH = (h, l, s) => (s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s));\nconst rotlL = (h, l, s) => (s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s));\n/** `keccakf1600` internal function, additionally allows to adjust round count. */\nexport function keccakP(s, rounds = 24, B) {\n    if (!B)\n        B = new Uint32Array(10);\n    // NOTE: all indices are x2 since we store state as u32 instead of u64 (bigints to slow in js)\n    for (let round = 24 - rounds; round < 24; round++) {\n        // Theta θ\n        for (let x = 0; x < 10; x++) {\n            B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];\n        }\n        // for (let x = 0; x < 10; x += 2) {\n        //   const idx1 = (x + 8) % 10;\n        //   const idx0 = (x + 2) % 10;\n        //   const B0 = B[idx0];\n        //   const B1 = B[idx0 + 1];\n        //   const Th = rotlH(B0, B1, 1) ^ B[idx1];\n        //   const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];\n        //   for (let y = 0; y < 50; y += 10) {\n        //     s[x + y] ^= Th;\n        //     s[x + y + 1] ^= Tl;\n        //   }\n        // }\n        { // x=0: idx0=2, idx1=8\n            const Th = rotlH(B[2], B[3], 1) ^ B[8];\n            const Tl = rotlL(B[2], B[3], 1) ^ B[9];\n            s[0] ^= Th;\n            s[1] ^= Tl;\n            s[10] ^= Th;\n            s[11] ^= Tl;\n            s[20] ^= Th;\n            s[21] ^= Tl;\n            s[30] ^= Th;\n            s[31] ^= Tl;\n            s[40] ^= Th;\n            s[41] ^= Tl;\n        }\n        { // x=2: idx0=4, idx1=0\n            const Th = rotlH(B[4], B[5], 1) ^ B[0];\n            const Tl = rotlL(B[4], B[5], 1) ^ B[1];\n            s[2] ^= Th;\n            s[3] ^= Tl;\n            s[12] ^= Th;\n            s[13] ^= Tl;\n            s[22] ^= Th;\n            s[23] ^= Tl;\n            s[32] ^= Th;\n            s[33] ^= Tl;\n            s[42] ^= Th;\n            s[43] ^= Tl;\n        }\n        { // x=4: idx0=6, idx1=2\n            const Th = rotlH(B[6], B[7], 1) ^ B[2];\n            const Tl = rotlL(B[6], B[7], 1) ^ B[3];\n            s[4] ^= Th;\n            s[5] ^= Tl;\n            s[14] ^= Th;\n            s[15] ^= Tl;\n            s[24] ^= Th;\n            s[25] ^= Tl;\n            s[34] ^= Th;\n            s[35] ^= Tl;\n            s[44] ^= Th;\n            s[45] ^= Tl;\n        }\n        { // x=6: idx0=8, idx1=4\n            const Th = rotlH(B[8], B[9], 1) ^ B[4];\n            const Tl = rotlL(B[8], B[9], 1) ^ B[5];\n            s[6] ^= Th;\n            s[7] ^= Tl;\n            s[16] ^= Th;\n            s[17] ^= Tl;\n            s[26] ^= Th;\n            s[27] ^= Tl;\n            s[36] ^= Th;\n            s[37] ^= Tl;\n            s[46] ^= Th;\n            s[47] ^= Tl;\n        }\n        { // x=8: idx0=0, idx1=6\n            const Th = rotlH(B[0], B[1], 1) ^ B[6];\n            const Tl = rotlL(B[0], B[1], 1) ^ B[7];\n            s[8] ^= Th;\n            s[9] ^= Tl;\n            s[18] ^= Th;\n            s[19] ^= Tl;\n            s[28] ^= Th;\n            s[29] ^= Tl;\n            s[38] ^= Th;\n            s[39] ^= Tl;\n            s[48] ^= Th;\n            s[49] ^= Tl;\n        }\n        // Rho (ρ) and Pi (π) — fully unrolled\n        let curH = s[2];\n        let curL = s[3];\n        // for (let t = 0; t < 24; t++) {\n        //   const shift = SHA3_ROTL[t];\n        //   const Th = rotlH(curH, curL, shift);\n        //   const Tl = rotlL(curH, curL, shift);\n        //   const PI = SHA3_PI[t];\n        //   curH = s[PI];\n        //   curL = s[PI + 1];\n        //   s[PI] = Th;\n        //   s[PI + 1] = Tl;\n        // }\n        let Th, Tl;\n        // t=0: shift=1(S), PI=20\n        Th = rotlSH(curH, curL, 1);\n        Tl = rotlSL(curH, curL, 1);\n        curH = s[20];\n        curL = s[21];\n        s[20] = Th;\n        s[21] = Tl;\n        // t=1: shift=3(S), PI=14\n        Th = rotlSH(curH, curL, 3);\n        Tl = rotlSL(curH, curL, 3);\n        curH = s[14];\n        curL = s[15];\n        s[14] = Th;\n        s[15] = Tl;\n        // t=2: shift=6(S), PI=22\n        Th = rotlSH(curH, curL, 6);\n        Tl = rotlSL(curH, curL, 6);\n        curH = s[22];\n        curL = s[23];\n        s[22] = Th;\n        s[23] = Tl;\n        // t=3: shift=10(S), PI=34\n        Th = rotlSH(curH, curL, 10);\n        Tl = rotlSL(curH, curL, 10);\n        curH = s[34];\n        curL = s[35];\n        s[34] = Th;\n        s[35] = Tl;\n        // t=4: shift=15(S), PI=36\n        Th = rotlSH(curH, curL, 15);\n        Tl = rotlSL(curH, curL, 15);\n        curH = s[36];\n        curL = s[37];\n        s[36] = Th;\n        s[37] = Tl;\n        // t=5: shift=21(S), PI=6\n        Th = rotlSH(curH, curL, 21);\n        Tl = rotlSL(curH, curL, 21);\n        curH = s[6];\n        curL = s[7];\n        s[6] = Th;\n        s[7] = Tl;\n        // t=6: shift=28(S), PI=10\n        Th = rotlSH(curH, curL, 28);\n        Tl = rotlSL(curH, curL, 28);\n        curH = s[10];\n        curL = s[11];\n        s[10] = Th;\n        s[11] = Tl;\n        // t=7: shift=36(B), PI=32\n        Th = rotlBH(curH, curL, 36);\n        Tl = rotlBL(curH, curL, 36);\n        curH = s[32];\n        curL = s[33];\n        s[32] = Th;\n        s[33] = Tl;\n        // t=8: shift=45(B), PI=16\n        Th = rotlBH(curH, curL, 45);\n        Tl = rotlBL(curH, curL, 45);\n        curH = s[16];\n        curL = s[17];\n        s[16] = Th;\n        s[17] = Tl;\n        // t=9: shift=55(B), PI=42\n        Th = rotlBH(curH, curL, 55);\n        Tl = rotlBL(curH, curL, 55);\n        curH = s[42];\n        curL = s[43];\n        s[42] = Th;\n        s[43] = Tl;\n        // t=10: shift=2(S), PI=48\n        Th = rotlSH(curH, curL, 2);\n        Tl = rotlSL(curH, curL, 2);\n        curH = s[48];\n        curL = s[49];\n        s[48] = Th;\n        s[49] = Tl;\n        // t=11: shift=14(S), PI=8\n        Th = rotlSH(curH, curL, 14);\n        Tl = rotlSL(curH, curL, 14);\n        curH = s[8];\n        curL = s[9];\n        s[8] = Th;\n        s[9] = Tl;\n        // t=12: shift=27(S), PI=30\n        Th = rotlSH(curH, curL, 27);\n        Tl = rotlSL(curH, curL, 27);\n        curH = s[30];\n        curL = s[31];\n        s[30] = Th;\n        s[31] = Tl;\n        // t=13: shift=41(B), PI=46\n        Th = rotlBH(curH, curL, 41);\n        Tl = rotlBL(curH, curL, 41);\n        curH = s[46];\n        curL = s[47];\n        s[46] = Th;\n        s[47] = Tl;\n        // t=14: shift=56(B), PI=38\n        Th = rotlBH(curH, curL, 56);\n        Tl = rotlBL(curH, curL, 56);\n        curH = s[38];\n        curL = s[39];\n        s[38] = Th;\n        s[39] = Tl;\n        // t=15: shift=8(S), PI=26\n        Th = rotlSH(curH, curL, 8);\n        Tl = rotlSL(curH, curL, 8);\n        curH = s[26];\n        curL = s[27];\n        s[26] = Th;\n        s[27] = Tl;\n        // t=16: shift=25(S), PI=24\n        Th = rotlSH(curH, curL, 25);\n        Tl = rotlSL(curH, curL, 25);\n        curH = s[24];\n        curL = s[25];\n        s[24] = Th;\n        s[25] = Tl;\n        // t=17: shift=43(B), PI=4\n        Th = rotlBH(curH, curL, 43);\n        Tl = rotlBL(curH, curL, 43);\n        curH = s[4];\n        curL = s[5];\n        s[4] = Th;\n        s[5] = Tl;\n        // t=18: shift=62(B), PI=40\n        Th = rotlBH(curH, curL, 62);\n        Tl = rotlBL(curH, curL, 62);\n        curH = s[40];\n        curL = s[41];\n        s[40] = Th;\n        s[41] = Tl;\n        // t=19: shift=18(S), PI=28\n        Th = rotlSH(curH, curL, 18);\n        Tl = rotlSL(curH, curL, 18);\n        curH = s[28];\n        curL = s[29];\n        s[28] = Th;\n        s[29] = Tl;\n        // t=20: shift=39(B), PI=44\n        Th = rotlBH(curH, curL, 39);\n        Tl = rotlBL(curH, curL, 39);\n        curH = s[44];\n        curL = s[45];\n        s[44] = Th;\n        s[45] = Tl;\n        // t=21: shift=61(B), PI=18\n        Th = rotlBH(curH, curL, 61);\n        Tl = rotlBL(curH, curL, 61);\n        curH = s[18];\n        curL = s[19];\n        s[18] = Th;\n        s[19] = Tl;\n        // t=22: shift=20(S), PI=12\n        Th = rotlSH(curH, curL, 20);\n        Tl = rotlSL(curH, curL, 20);\n        curH = s[12];\n        curL = s[13];\n        s[12] = Th;\n        s[13] = Tl;\n        // t=23: shift=44(B), PI=2\n        Th = rotlBH(curH, curL, 44);\n        Tl = rotlBL(curH, curL, 44);\n        s[2] = Th;\n        s[3] = Tl;\n        // Chi (χ)\n        for (let y = 0; y < 50; y += 10) {\n            B[0] = s[y];\n            B[1] = s[y + 1];\n            B[2] = s[y + 2];\n            B[3] = s[y + 3];\n            B[4] = s[y + 4];\n            B[5] = s[y + 5];\n            B[6] = s[y + 6];\n            B[7] = s[y + 7];\n            B[8] = s[y + 8];\n            B[9] = s[y + 9];\n            s[y + 0] ^= ~B[2] & B[4];\n            s[y + 1] ^= ~B[3] & B[5];\n            s[y + 2] ^= ~B[4] & B[6];\n            s[y + 3] ^= ~B[5] & B[7];\n            s[y + 4] ^= ~B[6] & B[8];\n            s[y + 5] ^= ~B[7] & B[9];\n            s[y + 6] ^= ~B[8] & B[0];\n            s[y + 7] ^= ~B[9] & B[1];\n            s[y + 8] ^= ~B[0] & B[2];\n            s[y + 9] ^= ~B[1] & B[3];\n        }\n        // Iota (ι)\n        s[0] ^= SHA3_IOTA_H[round];\n        s[1] ^= SHA3_IOTA_L[round];\n    }\n}\n/** Keccak sponge function. */\nexport class Keccak {\n    // NOTE: we accept arguments in bytes instead of bits here.\n    constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {\n        Object.defineProperty(this, \"state\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"pos\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: 0\n        });\n        Object.defineProperty(this, \"posOut\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: 0\n        });\n        Object.defineProperty(this, \"finished\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: false\n        });\n        Object.defineProperty(this, \"state32\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"destroyed\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: false\n        });\n        Object.defineProperty(this, \"_B\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: new Uint32Array(10)\n        });\n        Object.defineProperty(this, \"blockLen\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"suffix\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"outputLen\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"enableXOF\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: false\n        });\n        Object.defineProperty(this, \"rounds\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        this.blockLen = blockLen;\n        this.suffix = suffix;\n        this.outputLen = outputLen;\n        this.enableXOF = enableXOF;\n        this.rounds = rounds;\n        // Can be passed from user as dkLen\n        anumber(outputLen, \"outputLen\");\n        // 1600 = 5x5 matrix of 64bit.  1600 bits === 200 bytes\n        // 0 < blockLen < 200\n        if (!(0 < blockLen && blockLen < 200)) {\n            throw new Error(\"only keccak-f1600 function is supported\");\n        }\n        this.state = new Uint8Array(200);\n        this.state32 = u32(this.state);\n    }\n    clone() {\n        return this._cloneInto();\n    }\n    /** Resets instance to initial (empty) state for reuse. */\n    reset() {\n        this.state.fill(0);\n        this.pos = 0;\n        this.posOut = 0;\n        this.finished = false;\n        this.destroyed = false;\n    }\n    keccak() {\n        swap32IfBE(this.state32);\n        keccakP(this.state32, this.rounds, this._B);\n        swap32IfBE(this.state32);\n        this.posOut = 0;\n        this.pos = 0;\n    }\n    update(data) {\n        aexists(this);\n        abytes(data);\n        return this.updateUnsafe(data);\n    }\n    /** Like update(), but skips validation. Caller must ensure valid state and input. */\n    updateUnsafe(data) {\n        const { blockLen, state } = this;\n        const len = data.length;\n        for (let pos = 0; pos < len;) {\n            const take = Math.min(blockLen - this.pos, len - pos);\n            for (let i = 0; i < take; i++)\n                state[this.pos++] ^= data[pos++];\n            if (this.pos === blockLen)\n                this.keccak();\n        }\n        return this;\n    }\n    finish() {\n        if (this.finished)\n            return;\n        this.finished = true;\n        const { state, suffix, pos, blockLen } = this;\n        // Do the padding\n        state[pos] ^= suffix;\n        if ((suffix & 0x80) !== 0 && pos === blockLen - 1)\n            this.keccak();\n        state[blockLen - 1] ^= 0x80;\n        this.keccak();\n    }\n    writeInto(out) {\n        aexists(this, false);\n        abytes(out);\n        return this.writeIntoUnsafe(out);\n    }\n    /** Like writeInto(), but skips validation. Caller must ensure valid state and output. */\n    writeIntoUnsafe(out) {\n        this.finish();\n        const bufferOut = this.state;\n        const { blockLen } = this;\n        for (let pos = 0, len = out.length; pos < len;) {\n            if (this.posOut >= blockLen)\n                this.keccak();\n            const take = Math.min(blockLen - this.posOut, len - pos);\n            out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);\n            this.posOut += take;\n            pos += take;\n        }\n        return out;\n    }\n    xofInto(out) {\n        // Sha3/Keccak usage with XOF is probably mistake, only SHAKE instances can do XOF\n        if (!this.enableXOF) {\n            throw new Error(\"XOF is not possible for this instance\");\n        }\n        return this.writeInto(out);\n    }\n    xof(bytes) {\n        anumber(bytes);\n        return this.xofInto(new Uint8Array(bytes));\n    }\n    digestInto(out) {\n        aoutput(out, this);\n        if (this.finished)\n            throw new Error(\"digest() was already called\");\n        this.writeInto(out);\n        this.destroy();\n        return out;\n    }\n    digest() {\n        return this.digestInto(new Uint8Array(this.outputLen));\n    }\n    destroy() {\n        this.destroyed = true;\n        clean(this.state);\n    }\n    _cloneInto(to) {\n        const { blockLen, suffix, outputLen, rounds, enableXOF } = this;\n        to ||= new Keccak(blockLen, suffix, outputLen, enableXOF, rounds);\n        to.state32.set(this.state32);\n        to.pos = this.pos;\n        to.posOut = this.posOut;\n        to.finished = this.finished;\n        to.rounds = rounds;\n        // Suffix can change in cSHAKE\n        to.suffix = suffix;\n        to.outputLen = outputLen;\n        to.enableXOF = enableXOF;\n        to.destroyed = this.destroyed;\n        return to;\n    }\n}\nconst genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info);\n// /** SHA3-224 hash function. */\n// export const sha3_224: CHash = /* @__PURE__ */ genKeccak(\n//   0x06,\n//   144,\n//   28,\n//   /* @__PURE__ */ oidNist(0x07),\n// );\n/** SHA3-256 hash function. Different from keccak-256. */\nexport const sha3_256 = /* @__PURE__ */ genKeccak(0x06, 136, 32, \n/* @__PURE__ */ oidNist(0x08));\n/** SHA3-384 hash function. */\nexport const sha3_384 = /* @__PURE__ */ genKeccak(0x06, 104, 48, \n/* @__PURE__ */ oidNist(0x09));\n/** SHA3-512 hash function. */\nexport const sha3_512 = /* @__PURE__ */ genKeccak(0x06, 72, 64, \n/* @__PURE__ */ oidNist(0x0a));\n/** keccak-224 hash function. */\nexport const keccak_224 = /* @__PURE__ */ genKeccak(0x01, 144, 28);\n/** keccak-256 hash function. Different from SHA3-256. */\nexport const keccak_256 = /* @__PURE__ */ genKeccak(0x01, 136, 32);\n/** keccak-384 hash function. */\nexport const keccak_384 = /* @__PURE__ */ genKeccak(0x01, 104, 48);\n/** keccak-512 hash function. */\nexport const keccak_512 = /* @__PURE__ */ genKeccak(0x01, 72, 64);\nconst genShake = (suffix, blockLen, outputLen, info = {}) => createHasher((opts = {}) => new Keccak(blockLen, suffix, opts.dkLen === undefined ? outputLen : opts.dkLen, true), info);\n/** SHAKE128 XOF with 128-bit security. */\nexport const shake128 = \n/* @__PURE__ */\ngenShake(0x1f, 168, 16, /* @__PURE__ */ oidNist(0x0b));\n/** SHAKE256 XOF with 256-bit security. */\nexport const shake256 = \n/* @__PURE__ */\ngenShake(0x1f, 136, 32, /* @__PURE__ */ oidNist(0x0c));\n// /** SHAKE128 XOF with 256-bit output (NIST version). */\n// export const shake128_32: CHashXOF<Keccak, ShakeOpts> =\n//   /* @__PURE__ */\n//   genShake(0x1f, 168, 32, /* @__PURE__ */ oidNist(0x0b));\n// /** SHAKE256 XOF with 512-bit output (NIST version). */\n// export const shake256_64: CHashXOF<Keccak, ShakeOpts> =\n//   /* @__PURE__ */\n//   genShake(0x1f, 136, 64, /* @__PURE__ */ oidNist(0x0c));\n","/**\n * This file is based on noble-ciphers (https://github.com/paulmillr/noble-ciphers).\n *\n * noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-ciphers/blob/749cdf9cd07ebdd19e9b957d0f172f1045179695/src/utils.ts\n */\n/**\n * Utilities for hex, bytes, CSPRNG.\n * @module\n */\nimport { abytes, aexists, anumber, aoutput, clean, copyBytes, createView, isLE, numberToBigint, u32, } from \"@hpke/common\";\nexport { abytes, aexists, anumber, aoutput, clean, copyBytes, createView, isLE, u32, };\n/** Asserts something is boolean. */\nexport function abool(b) {\n    if (typeof b !== \"boolean\")\n        throw new Error(`boolean expected, not ${b}`);\n}\n/** Cast u8 / u16 / u32 to u8. */\nexport function u8(arr) {\n    return new Uint8Array(arr.buffer, arr.byteOffset, arr.byteLength);\n}\n/**\n * Wraps a cipher: validates args, ensures encrypt() can only be called once.\n * @__NO_SIDE_EFFECTS__\n */\n// deno-lint-ignore no-explicit-any\nexport const wrapCipher = (params, constructor) => {\n    // deno-lint-ignore no-explicit-any\n    function wrappedCipher(key, ...args) {\n        // Validate key\n        abytes(key, undefined, \"key\");\n        // Big-Endian hardware is rare. Just in case someone still decides to run ciphers:\n        if (!isLE) {\n            throw new Error(\"Non little-endian hardware is not yet supported\");\n        }\n        // Validate nonce if nonceLength is present\n        if (params.nonceLength !== undefined) {\n            const nonce = args[0];\n            abytes(nonce, params.varSizeNonce ? undefined : params.nonceLength, \"nonce\");\n        }\n        // Validate AAD if tagLength present\n        const tagl = params.tagLength;\n        if (tagl && args[1] !== undefined)\n            abytes(args[1], undefined, \"AAD\");\n        const cipher = constructor(key, ...args);\n        const checkOutput = (fnLength, output) => {\n            if (output !== undefined) {\n                if (fnLength !== 2)\n                    throw new Error(\"cipher output not supported\");\n                abytes(output, undefined, \"output\");\n            }\n        };\n        // Create wrapped cipher with validation and single-use encryption\n        let called = false;\n        const wrCipher = {\n            encrypt(data, output) {\n                if (called) {\n                    throw new Error(\"cannot encrypt() twice with same key + nonce\");\n                }\n                called = true;\n                abytes(data);\n                checkOutput(cipher.encrypt.length, output);\n                return cipher.encrypt(data, output);\n            },\n            decrypt(data, output) {\n                abytes(data);\n                if (tagl && data.length < tagl) {\n                    throw new Error('\"ciphertext\" expected length bigger than tagLength=' + tagl);\n                }\n                checkOutput(cipher.decrypt.length, output);\n                return cipher.decrypt(data, output);\n            },\n        };\n        return wrCipher;\n    }\n    Object.assign(wrappedCipher, params);\n    return wrappedCipher;\n};\nexport function checkOpts(defaults, opts) {\n    if (opts == null || typeof opts !== \"object\") {\n        throw new Error(\"options must be defined\");\n    }\n    const merged = Object.assign(defaults, opts);\n    return merged;\n}\n/** Compares 2 uint8array-s in kinda constant time. */\nexport function equalBytes(a, b) {\n    if (a.length !== b.length)\n        return false;\n    let diff = 0;\n    for (let i = 0; i < a.length; i++)\n        diff |= a[i] ^ b[i];\n    return diff === 0;\n}\n/**\n * By default, returns u8a of length.\n * When out is available, it checks it for validity and uses it.\n */\nexport function getOutput(expectedLength, out, onlyAligned = true) {\n    if (out === undefined)\n        return new Uint8Array(expectedLength);\n    if (out.length !== expectedLength) {\n        throw new Error('\"output\" expected Uint8Array of length ' + expectedLength + \", got: \" +\n            out.length);\n    }\n    if (onlyAligned && !isAligned32(out)) {\n        throw new Error(\"invalid output, must be aligned\");\n    }\n    return out;\n}\nexport function u64Lengths(dataLength, aadLength, isLE) {\n    abool(isLE);\n    const num = new Uint8Array(16);\n    const view = createView(num);\n    view.setBigUint64(0, numberToBigint(aadLength), isLE);\n    view.setBigUint64(8, numberToBigint(dataLength), isLE);\n    return num;\n}\n// Is byte array aligned to 4 byte offset (u32)?\nexport function isAligned32(bytes) {\n    return bytes.byteOffset % 4 === 0;\n}\n// copy bytes to new u8a (aligned). Because Buffer.slice is broken.\n// Re-exported from @hpke/common.\n","/**\n * This file is based on noble-ciphers (https://github.com/paulmillr/noble-ciphers).\n *\n * noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-ciphers/blob/749cdf9cd07ebdd19e9b957d0f172f1045179695/src/_arx.ts\n */\n/**\n * Basic utils for ARX (add-rotate-xor) salsa and chacha ciphers.\n\nRFC8439 requires multi-step cipher stream, where\nauthKey starts with counter: 0, actual msg with counter: 1.\n\nFor this, we need a way to re-use nonce / counter:\n\n    const counter = new Uint8Array(4);\n    chacha(..., counter, ...); // counter is now 1\n    chacha(..., counter, ...); // counter is now 2\n\nThis is complicated:\n\n- 32-bit counters are enough, no need for 64-bit: max ArrayBuffer size in JS is 4GB\n- Original papers don't allow mutating counters\n- Counter overflow is undefined [^1]\n- Idea A: allow providing (nonce | counter) instead of just nonce, re-use it\n- Caveat: Cannot be re-used through all cases:\n- * chacha has (counter | nonce)\n- * xchacha has (nonce16 | counter | nonce16)\n- Idea B: separate nonce / counter and provide separate API for counter re-use\n- Caveat: there are different counter sizes depending on an algorithm.\n- salsa & chacha also differ in structures of key & sigma:\n  salsa20:      s[0] | k(4) | s[1] | nonce(2) | cnt(2) | s[2] | k(4) | s[3]\n  chacha:       s(4) | k(8) | cnt(1) | nonce(3)\n  chacha20orig: s(4) | k(8) | cnt(2) | nonce(2)\n- Idea C: helper method such as `setSalsaState(key, nonce, sigma, data)`\n- Caveat: we can't re-use counter array\n\nxchacha [^2] uses the subkey and remaining 8 byte nonce with ChaCha20 as normal\n(prefixed by 4 NUL bytes, since [RFC8439] specifies a 12-byte nonce).\n\n[^1]: https://mailarchive.ietf.org/arch/msg/cfrg/gsOnTJzcbgG6OqD8Sc0GO5aR_tU/\n[^2]: https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha#appendix-A.2\n\n * @module\n */\nimport { abool, abytes, anumber, checkOpts, clean, copyBytes, u32, } from \"./utils.js\";\n// Can't use similar utils.utf8ToBytes, because it uses `TextEncoder` - not available in all envs\nconst _utf8ToBytes = (str) => Uint8Array.from(str.split(\"\").map((c) => c.charCodeAt(0)));\nconst sigma16 = _utf8ToBytes(\"expand 16-byte k\");\nconst sigma32 = _utf8ToBytes(\"expand 32-byte k\");\nconst sigma16_32 = u32(sigma16);\nconst sigma32_32 = u32(sigma32);\n/** Rotate left. */\nexport function rotl(a, b) {\n    return (a << b) | (a >>> (32 - b));\n}\n// Is byte array aligned to 4 byte offset (u32)?\nfunction isAligned32(b) {\n    return b.byteOffset % 4 === 0;\n}\n// Salsa and Chacha block length is always 512-bit\nconst BLOCK_LEN = 64;\nconst BLOCK_LEN32 = 16;\n// new Uint32Array([2**32])   // => Uint32Array(1) [ 0 ]\n// new Uint32Array([2**32-1]) // => Uint32Array(1) [ 4294967295 ]\nconst MAX_COUNTER = 2 ** 32 - 1;\nconst U32_EMPTY = Uint32Array.of();\nfunction runCipher(core, sigma, key, nonce, data, output, counter, rounds) {\n    const len = data.length;\n    const block = new Uint8Array(BLOCK_LEN);\n    const b32 = u32(block);\n    // Make sure that buffers aligned to 4 bytes\n    const isAligned = isAligned32(data) && isAligned32(output);\n    const d32 = isAligned ? u32(data) : U32_EMPTY;\n    const o32 = isAligned ? u32(output) : U32_EMPTY;\n    for (let pos = 0; pos < len; counter++) {\n        core(sigma, key, nonce, b32, counter, rounds);\n        if (counter >= MAX_COUNTER)\n            throw new Error(\"arx: counter overflow\");\n        const take = Math.min(BLOCK_LEN, len - pos);\n        // aligned to 4 bytes\n        if (isAligned && take === BLOCK_LEN) {\n            const pos32 = pos / 4;\n            if (pos % 4 !== 0)\n                throw new Error(\"arx: invalid block position\");\n            for (let j = 0, posj; j < BLOCK_LEN32; j++) {\n                posj = pos32 + j;\n                o32[posj] = d32[posj] ^ b32[j];\n            }\n            pos += BLOCK_LEN;\n            continue;\n        }\n        for (let j = 0, posj; j < take; j++) {\n            posj = pos + j;\n            output[posj] = data[posj] ^ block[j];\n        }\n        pos += take;\n    }\n}\n/** Creates ARX-like (ChaCha, Salsa) cipher stream from core function. */\nexport function createCipher(core, opts) {\n    const { allowShortKeys, extendNonceFn, counterLength, counterRight, rounds } = checkOpts({\n        allowShortKeys: false,\n        counterLength: 8,\n        counterRight: false,\n        rounds: 20,\n    }, opts);\n    if (typeof core !== \"function\")\n        throw new Error(\"core must be a function\");\n    anumber(counterLength);\n    anumber(rounds);\n    abool(counterRight);\n    abool(allowShortKeys);\n    return (key, nonce, data, output, counter = 0) => {\n        abytes(key, undefined, \"key\");\n        abytes(nonce, undefined, \"nonce\");\n        abytes(data, undefined, \"data\");\n        const len = data.length;\n        if (output === undefined)\n            output = new Uint8Array(len);\n        abytes(output, undefined, \"output\");\n        anumber(counter);\n        if (counter < 0 || counter >= MAX_COUNTER) {\n            throw new Error(\"arx: counter overflow\");\n        }\n        if (output.length < len) {\n            throw new Error(`arx: output (${output.length}) is shorter than data (${len})`);\n        }\n        const toClean = [];\n        // Key & sigma\n        // key=16 -> sigma16, k=key|key\n        // key=32 -> sigma32, k=key\n        const l = key.length;\n        let k;\n        let sigma;\n        if (l === 32) {\n            toClean.push(k = copyBytes(key));\n            sigma = sigma32_32;\n        }\n        else if (l === 16 && allowShortKeys) {\n            k = new Uint8Array(32);\n            k.set(key);\n            k.set(key, 16);\n            sigma = sigma16_32;\n            toClean.push(k);\n        }\n        else {\n            abytes(key, 32, \"arx key\");\n            throw new Error(\"invalid key size\");\n            // throw new Error(`\"arx key\" expected Uint8Array of length 32, got length=${l}`);\n        }\n        // Nonce\n        // salsa20:      8   (8-byte counter)\n        // chacha20orig: 8   (8-byte counter)\n        // chacha20:     12  (4-byte counter)\n        // xsalsa20:     24  (16 -> hsalsa,  8 -> old nonce)\n        // xchacha20:    24  (16 -> hchacha, 8 -> old nonce)\n        // Align nonce to 4 bytes\n        if (!isAligned32(nonce))\n            toClean.push(nonce = copyBytes(nonce));\n        const k32 = u32(k);\n        // hsalsa & hchacha: handle extended nonce\n        if (extendNonceFn) {\n            if (nonce.length !== 24) {\n                throw new Error(`arx: extended nonce must be 24 bytes`);\n            }\n            extendNonceFn(sigma, k32, u32(nonce.subarray(0, 16)), k32);\n            nonce = nonce.subarray(16);\n        }\n        // Handle nonce counter\n        const nonceNcLen = 16 - counterLength;\n        if (nonceNcLen !== nonce.length) {\n            throw new Error(`arx: nonce must be ${nonceNcLen} or 16 bytes`);\n        }\n        // Pad counter when nonce is 64 bit\n        if (nonceNcLen !== 12) {\n            const nc = new Uint8Array(12);\n            nc.set(nonce, counterRight ? 0 : 12 - nonce.length);\n            nonce = nc;\n            toClean.push(nonce);\n        }\n        const n32 = u32(nonce);\n        runCipher(core, sigma, k32, n32, data, output, counter, rounds);\n        clean(...toClean);\n        return output;\n    };\n}\n","/**\n * This file is based on noble-ciphers (https://github.com/paulmillr/noble-ciphers).\n *\n * noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-ciphers/blob/749cdf9cd07ebdd19e9b957d0f172f1045179695/src/_poly1305.ts\n */\n/**\n * Poly1305 ([PDF](https://cr.yp.to/mac/poly1305-20050329.pdf),\n * [wiki](https://en.wikipedia.org/wiki/Poly1305))\n * is a fast and parallel secret-key message-authentication code suitable for\n * a wide variety of applications. It was standardized in\n * [RFC 8439](https://www.rfc-editor.org/rfc/rfc8439) and is now used in TLS 1.3.\n *\n * Polynomial MACs are not perfect for every situation:\n * they lack Random Key Robustness: the MAC can be forged, and can't be used in PAKE schemes.\n * See [invisible salamanders attack](https://keymaterial.net/2020/09/07/invisible-salamanders-in-aes-gcm-siv/).\n * To combat invisible salamanders, `hash(key)` can be included in ciphertext,\n * however, this would violate ciphertext indistinguishability:\n * an attacker would know which key was used - so `HKDF(key, i)`\n * could be used instead.\n *\n * Check out [original website](https://cr.yp.to/mac.html).\n * Based on Public Domain [poly1305-donna](https://github.com/floodyberry/poly1305-donna).\n * @module\n */\nimport { abytes, aexists, aoutput, clean, copyBytes, } from \"./utils.js\";\nfunction u8to16(a, i) {\n    return (a[i++] & 0xff) | ((a[i++] & 0xff) << 8);\n}\n// function bytesToNumberLE(bytes: Uint8Array): bigint {\n//   return hexToNumber(bytesToHex(Uint8Array.from(bytes).reverse()));\n// }\n// /** Small version of `poly1305` without loop unrolling. Unused, provided for auditability. */\n// function poly1305_small(msg: Uint8Array, key: Uint8Array): Uint8Array {\n//   abytes(msg);\n//   abytes(key, 32, \"key\");\n//   const POW_2_130_5 = 2n ** 130n - 5n; // 2^130-5\n//   const POW_2_128_1 = 2n ** 128n - 1n; // 2^128-1\n//   const CLAMP_R = 0x0ffffffc0ffffffc0ffffffc0fffffffn;\n//   const r = bytesToNumberLE(key.subarray(0, 16)) & CLAMP_R;\n//   const s = bytesToNumberLE(key.subarray(16));\n//   // Process by 16 byte chunks\n//   let acc = 0n;\n//   for (let i = 0; i < msg.length; i += 16) {\n//     const m = msg.subarray(i, i + 16);\n//     const n = bytesToNumberLE(m) | (1n << (8n * mLen)); // mLen: bigint\n//     acc = ((acc + n) * r) % POW_2_130_5;\n//   }\n//   const res = (acc + s) & POW_2_128_1;\n//   return numberToBytesBE(res, 16).reverse(); // LE\n// }\n// Can be used to replace `computeTag` in chacha.ts. Unused, provided for auditability.\n// function poly1305_computeTag_small(\n//   authKey: Uint8Array,\n//   lengths: Uint8Array,\n//   ciphertext: Uint8Array,\n//   AAD?: Uint8Array,\n// ): Uint8Array {\n//   const res = [];\n//   const updatePadded2 = (msg: Uint8Array) => {\n//     res.push(msg);\n//     const leftover = msg.length % 16;\n//     if (leftover) res.push(new Uint8Array(16).slice(leftover));\n//   };\n//   if (AAD) updatePadded2(AAD);\n//   updatePadded2(ciphertext);\n//   res.push(lengths);\n//   return poly1305_small(concatBytes(...res), authKey);\n// }\n/** Poly1305 class. Prefer poly1305() function instead. */\nexport class Poly1305 {\n    // Can be speed-up using BigUint64Array, at the cost of complexity\n    constructor(key) {\n        Object.defineProperty(this, \"blockLen\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: 16\n        });\n        Object.defineProperty(this, \"outputLen\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: 16\n        });\n        Object.defineProperty(this, \"buffer\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: new Uint8Array(16)\n        });\n        Object.defineProperty(this, \"r\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: new Uint16Array(10)\n        }); // Allocating 1 array with .subarray() here is slower than 3\n        Object.defineProperty(this, \"h\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: new Uint16Array(10)\n        });\n        Object.defineProperty(this, \"pad\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: new Uint16Array(8)\n        });\n        Object.defineProperty(this, \"pos\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: 0\n        });\n        Object.defineProperty(this, \"finished\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: false\n        });\n        key = copyBytes(abytes(key, 32, \"key\"));\n        const t0 = u8to16(key, 0);\n        const t1 = u8to16(key, 2);\n        const t2 = u8to16(key, 4);\n        const t3 = u8to16(key, 6);\n        const t4 = u8to16(key, 8);\n        const t5 = u8to16(key, 10);\n        const t6 = u8to16(key, 12);\n        const t7 = u8to16(key, 14);\n        // https://github.com/floodyberry/poly1305-donna/blob/e6ad6e091d30d7f4ec2d4f978be1fcfcbce72781/poly1305-donna-16.h#L47\n        this.r[0] = t0 & 0x1fff;\n        this.r[1] = ((t0 >>> 13) | (t1 << 3)) & 0x1fff;\n        this.r[2] = ((t1 >>> 10) | (t2 << 6)) & 0x1f03;\n        this.r[3] = ((t2 >>> 7) | (t3 << 9)) & 0x1fff;\n        this.r[4] = ((t3 >>> 4) | (t4 << 12)) & 0x00ff;\n        this.r[5] = (t4 >>> 1) & 0x1ffe;\n        this.r[6] = ((t4 >>> 14) | (t5 << 2)) & 0x1fff;\n        this.r[7] = ((t5 >>> 11) | (t6 << 5)) & 0x1f81;\n        this.r[8] = ((t6 >>> 8) | (t7 << 8)) & 0x1fff;\n        this.r[9] = (t7 >>> 5) & 0x007f;\n        for (let i = 0; i < 8; i++)\n            this.pad[i] = u8to16(key, 16 + 2 * i);\n    }\n    process(data, offset, isLast = false) {\n        const hibit = isLast ? 0 : 1 << 11;\n        const { h, r } = this;\n        const r0 = r[0];\n        const r1 = r[1];\n        const r2 = r[2];\n        const r3 = r[3];\n        const r4 = r[4];\n        const r5 = r[5];\n        const r6 = r[6];\n        const r7 = r[7];\n        const r8 = r[8];\n        const r9 = r[9];\n        const t0 = u8to16(data, offset + 0);\n        const t1 = u8to16(data, offset + 2);\n        const t2 = u8to16(data, offset + 4);\n        const t3 = u8to16(data, offset + 6);\n        const t4 = u8to16(data, offset + 8);\n        const t5 = u8to16(data, offset + 10);\n        const t6 = u8to16(data, offset + 12);\n        const t7 = u8to16(data, offset + 14);\n        const h0 = h[0] + (t0 & 0x1fff);\n        const h1 = h[1] + (((t0 >>> 13) | (t1 << 3)) & 0x1fff);\n        const h2 = h[2] + (((t1 >>> 10) | (t2 << 6)) & 0x1fff);\n        const h3 = h[3] + (((t2 >>> 7) | (t3 << 9)) & 0x1fff);\n        const h4 = h[4] + (((t3 >>> 4) | (t4 << 12)) & 0x1fff);\n        const h5 = h[5] + ((t4 >>> 1) & 0x1fff);\n        const h6 = h[6] + (((t4 >>> 14) | (t5 << 2)) & 0x1fff);\n        const h7 = h[7] + (((t5 >>> 11) | (t6 << 5)) & 0x1fff);\n        const h8 = h[8] + (((t6 >>> 8) | (t7 << 8)) & 0x1fff);\n        const h9 = h[9] + ((t7 >>> 5) | hibit);\n        let c = 0;\n        let d0 = c + h0 * r0 + h1 * (5 * r9) + h2 * (5 * r8) + h3 * (5 * r7) +\n            h4 * (5 * r6);\n        c = d0 >>> 13;\n        d0 &= 0x1fff;\n        d0 += h5 * (5 * r5) + h6 * (5 * r4) + h7 * (5 * r3) + h8 * (5 * r2) +\n            h9 * (5 * r1);\n        c += d0 >>> 13;\n        d0 &= 0x1fff;\n        let d1 = c + h0 * r1 + h1 * r0 + h2 * (5 * r9) + h3 * (5 * r8) +\n            h4 * (5 * r7);\n        c = d1 >>> 13;\n        d1 &= 0x1fff;\n        d1 += h5 * (5 * r6) + h6 * (5 * r5) + h7 * (5 * r4) + h8 * (5 * r3) +\n            h9 * (5 * r2);\n        c += d1 >>> 13;\n        d1 &= 0x1fff;\n        let d2 = c + h0 * r2 + h1 * r1 + h2 * r0 + h3 * (5 * r9) + h4 * (5 * r8);\n        c = d2 >>> 13;\n        d2 &= 0x1fff;\n        d2 += h5 * (5 * r7) + h6 * (5 * r6) + h7 * (5 * r5) + h8 * (5 * r4) +\n            h9 * (5 * r3);\n        c += d2 >>> 13;\n        d2 &= 0x1fff;\n        let d3 = c + h0 * r3 + h1 * r2 + h2 * r1 + h3 * r0 + h4 * (5 * r9);\n        c = d3 >>> 13;\n        d3 &= 0x1fff;\n        d3 += h5 * (5 * r8) + h6 * (5 * r7) + h7 * (5 * r6) + h8 * (5 * r5) +\n            h9 * (5 * r4);\n        c += d3 >>> 13;\n        d3 &= 0x1fff;\n        let d4 = c + h0 * r4 + h1 * r3 + h2 * r2 + h3 * r1 + h4 * r0;\n        c = d4 >>> 13;\n        d4 &= 0x1fff;\n        d4 += h5 * (5 * r9) + h6 * (5 * r8) + h7 * (5 * r7) + h8 * (5 * r6) +\n            h9 * (5 * r5);\n        c += d4 >>> 13;\n        d4 &= 0x1fff;\n        let d5 = c + h0 * r5 + h1 * r4 + h2 * r3 + h3 * r2 + h4 * r1;\n        c = d5 >>> 13;\n        d5 &= 0x1fff;\n        d5 += h5 * r0 + h6 * (5 * r9) + h7 * (5 * r8) + h8 * (5 * r7) +\n            h9 * (5 * r6);\n        c += d5 >>> 13;\n        d5 &= 0x1fff;\n        let d6 = c + h0 * r6 + h1 * r5 + h2 * r4 + h3 * r3 + h4 * r2;\n        c = d6 >>> 13;\n        d6 &= 0x1fff;\n        d6 += h5 * r1 + h6 * r0 + h7 * (5 * r9) + h8 * (5 * r8) + h9 * (5 * r7);\n        c += d6 >>> 13;\n        d6 &= 0x1fff;\n        let d7 = c + h0 * r7 + h1 * r6 + h2 * r5 + h3 * r4 + h4 * r3;\n        c = d7 >>> 13;\n        d7 &= 0x1fff;\n        d7 += h5 * r2 + h6 * r1 + h7 * r0 + h8 * (5 * r9) + h9 * (5 * r8);\n        c += d7 >>> 13;\n        d7 &= 0x1fff;\n        let d8 = c + h0 * r8 + h1 * r7 + h2 * r6 + h3 * r5 + h4 * r4;\n        c = d8 >>> 13;\n        d8 &= 0x1fff;\n        d8 += h5 * r3 + h6 * r2 + h7 * r1 + h8 * r0 + h9 * (5 * r9);\n        c += d8 >>> 13;\n        d8 &= 0x1fff;\n        let d9 = c + h0 * r9 + h1 * r8 + h2 * r7 + h3 * r6 + h4 * r5;\n        c = d9 >>> 13;\n        d9 &= 0x1fff;\n        d9 += h5 * r4 + h6 * r3 + h7 * r2 + h8 * r1 + h9 * r0;\n        c += d9 >>> 13;\n        d9 &= 0x1fff;\n        c = ((c << 2) + c) | 0;\n        c = (c + d0) | 0;\n        d0 = c & 0x1fff;\n        c = c >>> 13;\n        d1 += c;\n        h[0] = d0;\n        h[1] = d1;\n        h[2] = d2;\n        h[3] = d3;\n        h[4] = d4;\n        h[5] = d5;\n        h[6] = d6;\n        h[7] = d7;\n        h[8] = d8;\n        h[9] = d9;\n    }\n    finalize() {\n        const { h, pad } = this;\n        const g = new Uint16Array(10);\n        let c = h[1] >>> 13;\n        h[1] &= 0x1fff;\n        for (let i = 2; i < 10; i++) {\n            h[i] += c;\n            c = h[i] >>> 13;\n            h[i] &= 0x1fff;\n        }\n        h[0] += c * 5;\n        c = h[0] >>> 13;\n        h[0] &= 0x1fff;\n        h[1] += c;\n        c = h[1] >>> 13;\n        h[1] &= 0x1fff;\n        h[2] += c;\n        g[0] = h[0] + 5;\n        c = g[0] >>> 13;\n        g[0] &= 0x1fff;\n        for (let i = 1; i < 10; i++) {\n            g[i] = h[i] + c;\n            c = g[i] >>> 13;\n            g[i] &= 0x1fff;\n        }\n        g[9] -= 1 << 13;\n        let mask = (c ^ 1) - 1;\n        for (let i = 0; i < 10; i++)\n            g[i] &= mask;\n        mask = ~mask;\n        for (let i = 0; i < 10; i++)\n            h[i] = (h[i] & mask) | g[i];\n        h[0] = (h[0] | (h[1] << 13)) & 0xffff;\n        h[1] = ((h[1] >>> 3) | (h[2] << 10)) & 0xffff;\n        h[2] = ((h[2] >>> 6) | (h[3] << 7)) & 0xffff;\n        h[3] = ((h[3] >>> 9) | (h[4] << 4)) & 0xffff;\n        h[4] = ((h[4] >>> 12) | (h[5] << 1) | (h[6] << 14)) & 0xffff;\n        h[5] = ((h[6] >>> 2) | (h[7] << 11)) & 0xffff;\n        h[6] = ((h[7] >>> 5) | (h[8] << 8)) & 0xffff;\n        h[7] = ((h[8] >>> 8) | (h[9] << 5)) & 0xffff;\n        let f = h[0] + pad[0];\n        h[0] = f & 0xffff;\n        for (let i = 1; i < 8; i++) {\n            f = (((h[i] + pad[i]) | 0) + (f >>> 16)) | 0;\n            h[i] = f & 0xffff;\n        }\n        clean(g);\n    }\n    update(data) {\n        aexists(this);\n        abytes(data);\n        data = copyBytes(data);\n        const { buffer, blockLen } = this;\n        const len = data.length;\n        for (let pos = 0; pos < len;) {\n            const take = Math.min(blockLen - this.pos, len - pos);\n            // Fast path: we have at least one block in input\n            if (take === blockLen) {\n                for (; blockLen <= len - pos; pos += blockLen)\n                    this.process(data, pos);\n                continue;\n            }\n            buffer.set(data.subarray(pos, pos + take), this.pos);\n            this.pos += take;\n            pos += take;\n            if (this.pos === blockLen) {\n                this.process(buffer, 0, false);\n                this.pos = 0;\n            }\n        }\n        return this;\n    }\n    destroy() {\n        clean(this.h, this.r, this.buffer, this.pad);\n    }\n    digestInto(out) {\n        aexists(this);\n        aoutput(out, this);\n        this.finished = true;\n        const { buffer, h } = this;\n        let { pos } = this;\n        if (pos) {\n            buffer[pos++] = 1;\n            for (; pos < 16; pos++)\n                buffer[pos] = 0;\n            this.process(buffer, 0, true);\n        }\n        this.finalize();\n        let opos = 0;\n        for (let i = 0; i < 8; i++) {\n            out[opos++] = h[i] >>> 0;\n            out[opos++] = h[i] >>> 8;\n        }\n        return out;\n    }\n    digest() {\n        const { buffer, outputLen } = this;\n        this.digestInto(buffer);\n        const res = buffer.slice(0, outputLen);\n        this.destroy();\n        return res;\n    }\n}\nexport function wrapConstructorWithKey(hashCons) {\n    const hashC = (msg, key) => hashCons(key).update(msg).digest();\n    const tmp = hashCons(new Uint8Array(32)); // tmp array, used just once below\n    hashC.outputLen = tmp.outputLen;\n    hashC.blockLen = tmp.blockLen;\n    hashC.create = (key) => hashCons(key);\n    return hashC;\n}\n/** Poly1305 MAC from RFC 8439. */\nexport const poly1305 = \n/** @__PURE__ */ (() => wrapConstructorWithKey((key) => new Poly1305(key)))();\n","/**\n * This file is based on noble-ciphers (https://github.com/paulmillr/noble-ciphers).\n *\n * noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com)\n *\n * The original file is located at:\n * https://github.com/paulmillr/noble-ciphers/blob/749cdf9cd07ebdd19e9b957d0f172f1045179695/src/chacha.ts\n */\n/**\n * ChaCha stream cipher, released\n * in 2008. Developed after Salsa20, ChaCha aims to increase diffusion per round.\n * It was standardized in [RFC 8439](https://www.rfc-editor.org/rfc/rfc8439) and\n * is now used in TLS 1.3.\n *\n * [XChaCha20](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha)\n * extended-nonce variant is also provided. Similar to XSalsa, it's safe to use with\n * randomly-generated nonces.\n *\n * Check out [PDF](http://cr.yp.to/chacha/chacha-20080128.pdf) and\n * [wiki](https://en.wikipedia.org/wiki/Salsa20) and\n * [website](https://cr.yp.to/chacha.html).\n *\n * @module\n */\nimport { createCipher, rotl } from \"./_arx.js\";\nimport { poly1305 } from \"./_poly1305.js\";\nimport { abytes, clean, equalBytes, getOutput, u64Lengths, wrapCipher, } from \"./utils.js\";\n/**\n * ChaCha core function. It is implemented twice:\n * 1. Simple loop (chachaCore_small, hchacha_small)\n * 2. Unrolled loop (chachaCore, hchacha) - 4x faster, but larger & harder to read\n * The specific implementation is selected in `createCipher` below.\n */\nfunction chachaCore(s, k, n, out, cnt, rounds = 20) {\n    const y00 = s[0], y01 = s[1], y02 = s[2], y03 = s[3], // \"expa\"   \"nd 3\"  \"2-by\"  \"te k\"\n    y04 = k[0], y05 = k[1], y06 = k[2], y07 = k[3], // Key      Key     Key     Key\n    y08 = k[4], y09 = k[5], y10 = k[6], y11 = k[7], // Key      Key     Key     Key\n    y12 = cnt, y13 = n[0], y14 = n[1], y15 = n[2]; // Counter  Counter\tNonce   Nonce\n    // Save state to temporary variables\n    let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;\n    for (let r = 0; r < rounds; r += 2) {\n        x00 = (x00 + x04) | 0;\n        x12 = rotl(x12 ^ x00, 16);\n        x08 = (x08 + x12) | 0;\n        x04 = rotl(x04 ^ x08, 12);\n        x00 = (x00 + x04) | 0;\n        x12 = rotl(x12 ^ x00, 8);\n        x08 = (x08 + x12) | 0;\n        x04 = rotl(x04 ^ x08, 7);\n        x01 = (x01 + x05) | 0;\n        x13 = rotl(x13 ^ x01, 16);\n        x09 = (x09 + x13) | 0;\n        x05 = rotl(x05 ^ x09, 12);\n        x01 = (x01 + x05) | 0;\n        x13 = rotl(x13 ^ x01, 8);\n        x09 = (x09 + x13) | 0;\n        x05 = rotl(x05 ^ x09, 7);\n        x02 = (x02 + x06) | 0;\n        x14 = rotl(x14 ^ x02, 16);\n        x10 = (x10 + x14) | 0;\n        x06 = rotl(x06 ^ x10, 12);\n        x02 = (x02 + x06) | 0;\n        x14 = rotl(x14 ^ x02, 8);\n        x10 = (x10 + x14) | 0;\n        x06 = rotl(x06 ^ x10, 7);\n        x03 = (x03 + x07) | 0;\n        x15 = rotl(x15 ^ x03, 16);\n        x11 = (x11 + x15) | 0;\n        x07 = rotl(x07 ^ x11, 12);\n        x03 = (x03 + x07) | 0;\n        x15 = rotl(x15 ^ x03, 8);\n        x11 = (x11 + x15) | 0;\n        x07 = rotl(x07 ^ x11, 7);\n        x00 = (x00 + x05) | 0;\n        x15 = rotl(x15 ^ x00, 16);\n        x10 = (x10 + x15) | 0;\n        x05 = rotl(x05 ^ x10, 12);\n        x00 = (x00 + x05) | 0;\n        x15 = rotl(x15 ^ x00, 8);\n        x10 = (x10 + x15) | 0;\n        x05 = rotl(x05 ^ x10, 7);\n        x01 = (x01 + x06) | 0;\n        x12 = rotl(x12 ^ x01, 16);\n        x11 = (x11 + x12) | 0;\n        x06 = rotl(x06 ^ x11, 12);\n        x01 = (x01 + x06) | 0;\n        x12 = rotl(x12 ^ x01, 8);\n        x11 = (x11 + x12) | 0;\n        x06 = rotl(x06 ^ x11, 7);\n        x02 = (x02 + x07) | 0;\n        x13 = rotl(x13 ^ x02, 16);\n        x08 = (x08 + x13) | 0;\n        x07 = rotl(x07 ^ x08, 12);\n        x02 = (x02 + x07) | 0;\n        x13 = rotl(x13 ^ x02, 8);\n        x08 = (x08 + x13) | 0;\n        x07 = rotl(x07 ^ x08, 7);\n        x03 = (x03 + x04) | 0;\n        x14 = rotl(x14 ^ x03, 16);\n        x09 = (x09 + x14) | 0;\n        x04 = rotl(x04 ^ x09, 12);\n        x03 = (x03 + x04) | 0;\n        x14 = rotl(x14 ^ x03, 8);\n        x09 = (x09 + x14) | 0;\n        x04 = rotl(x04 ^ x09, 7);\n    }\n    // Write output\n    let oi = 0;\n    out[oi++] = (y00 + x00) | 0;\n    out[oi++] = (y01 + x01) | 0;\n    out[oi++] = (y02 + x02) | 0;\n    out[oi++] = (y03 + x03) | 0;\n    out[oi++] = (y04 + x04) | 0;\n    out[oi++] = (y05 + x05) | 0;\n    out[oi++] = (y06 + x06) | 0;\n    out[oi++] = (y07 + x07) | 0;\n    out[oi++] = (y08 + x08) | 0;\n    out[oi++] = (y09 + x09) | 0;\n    out[oi++] = (y10 + x10) | 0;\n    out[oi++] = (y11 + x11) | 0;\n    out[oi++] = (y12 + x12) | 0;\n    out[oi++] = (y13 + x13) | 0;\n    out[oi++] = (y14 + x14) | 0;\n    out[oi++] = (y15 + x15) | 0;\n}\n/**\n * ChaCha stream cipher. Conforms to RFC 8439 (IETF, TLS). 12-byte nonce, 4-byte counter.\n * With smaller nonce, it's not safe to make it random (CSPRNG), due to collision chance.\n */\nexport const chacha20 = /* @__PURE__ */ createCipher(chachaCore, {\n    counterRight: false,\n    counterLength: 4,\n    allowShortKeys: false,\n});\nconst ZEROS16 = /* @__PURE__ */ new Uint8Array(16);\n// Pad to digest size with zeros\nconst updatePadded = (h, msg) => {\n    h.update(msg);\n    const leftover = msg.length % 16;\n    if (leftover)\n        h.update(ZEROS16.subarray(leftover));\n};\nconst ZEROS32 = /* @__PURE__ */ new Uint8Array(32);\nfunction computeTag(fn, key, nonce, ciphertext, AAD) {\n    if (AAD !== undefined)\n        abytes(AAD, undefined, \"AAD\");\n    const authKey = fn(key, nonce, ZEROS32);\n    const lengths = u64Lengths(ciphertext.length, AAD ? AAD.length : 0, true);\n    // Methods below can be replaced with\n    // return poly1305_computeTag_small(authKey, lengths, ciphertext, AAD)\n    const h = poly1305.create(authKey);\n    if (AAD)\n        updatePadded(h, AAD);\n    updatePadded(h, ciphertext);\n    h.update(lengths);\n    const res = h.digest();\n    clean(authKey, lengths);\n    return res;\n}\n/**\n * AEAD algorithm from RFC 8439.\n * Salsa20 and chacha (RFC 8439) use poly1305 differently.\n * We could have composed them, but it's hard because of authKey:\n * In salsa20, authKey changes position in salsa stream.\n * In chacha, authKey can't be computed inside computeTag, it modifies the counter.\n */\nexport const _poly1305_aead = (xorStream) => (key, nonce, AAD) => {\n    const tagLength = 16;\n    return {\n        encrypt(plaintext, output) {\n            const plength = plaintext.length;\n            output = getOutput(plength + tagLength, output, false);\n            output.set(plaintext);\n            const oPlain = output.subarray(0, -tagLength);\n            // Actual encryption\n            xorStream(key, nonce, oPlain, oPlain, 1);\n            const tag = computeTag(xorStream, key, nonce, oPlain, AAD);\n            output.set(tag, plength); // append tag\n            clean(tag);\n            return output;\n        },\n        decrypt(ciphertext, output) {\n            output = getOutput(ciphertext.length - tagLength, output, false);\n            const data = ciphertext.subarray(0, -tagLength);\n            const passedTag = ciphertext.subarray(-tagLength);\n            const tag = computeTag(xorStream, key, nonce, data, AAD);\n            if (!equalBytes(passedTag, tag))\n                throw new Error(\"invalid tag\");\n            output.set(ciphertext.subarray(0, -tagLength));\n            // Actual decryption\n            xorStream(key, nonce, output, output, 1); // start stream with i=1\n            clean(tag);\n            return output;\n        },\n    };\n};\n/**\n * ChaCha20-Poly1305 from RFC 8439.\n *\n * Unsafe to use random nonces under the same key, due to collision chance.\n * Prefer XChaCha instead.\n */\nexport const chacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength: 12, tagLength: 16 }, _poly1305_aead(chacha20));\n","import { ExportError, INPUT_LENGTH_LIMIT, InvalidParamError, toArrayBuffer, } from \"@hpke/common\";\nimport { emitNotSupported } from \"./utils/emitNotSupported.js\";\n// b\"sec\"\nconst LABEL_SEC = new Uint8Array([115, 101, 99]);\nexport class ExporterContextImpl {\n    constructor(api, kdf, exporterSecret) {\n        Object.defineProperty(this, \"_api\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"exporterSecret\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_kdf\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        this._api = api;\n        this._kdf = kdf;\n        this.exporterSecret = exporterSecret;\n    }\n    async seal(_data, _aad) {\n        return await emitNotSupported();\n    }\n    async open(_data, _aad) {\n        return await emitNotSupported();\n    }\n    async export(exporterContext, len) {\n        const rawExporterContext = toArrayBuffer(exporterContext);\n        if (rawExporterContext.byteLength > INPUT_LENGTH_LIMIT) {\n            throw new InvalidParamError(\"Too long exporter context\");\n        }\n        try {\n            return await this._kdf.labeledExpand(this.exporterSecret, LABEL_SEC, new Uint8Array(rawExporterContext), len);\n        }\n        catch (e) {\n            throw new ExportError(e);\n        }\n    }\n}\nexport class RecipientExporterContextImpl extends ExporterContextImpl {\n}\nexport class SenderExporterContextImpl extends ExporterContextImpl {\n    constructor(api, kdf, exporterSecret, enc) {\n        super(api, kdf, exporterSecret);\n        Object.defineProperty(this, \"enc\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        this.enc = enc;\n        return;\n    }\n}\n","var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n    if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n    if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n    return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n    if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n    if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n    if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n    return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar _Mutex_locked;\nexport class Mutex {\n    constructor() {\n        _Mutex_locked.set(this, Promise.resolve());\n    }\n    async lock() {\n        let releaseLock;\n        const nextLock = new Promise((resolve) => {\n            releaseLock = resolve;\n        });\n        const previousLock = __classPrivateFieldGet(this, _Mutex_locked, \"f\");\n        __classPrivateFieldSet(this, _Mutex_locked, nextLock, \"f\");\n        await previousLock;\n        return releaseLock;\n    }\n}\n_Mutex_locked = new WeakMap();\n","var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n    if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n    if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n    return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n    if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n    if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n    if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n    return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar _RecipientContextImpl_mutex;\nimport { EMPTY, OpenError, toArrayBuffer } from \"@hpke/common\";\nimport { EncryptionContextImpl } from \"./encryptionContext.js\";\nimport { Mutex } from \"./mutex.js\";\nexport class RecipientContextImpl extends EncryptionContextImpl {\n    constructor() {\n        super(...arguments);\n        _RecipientContextImpl_mutex.set(this, void 0);\n    }\n    async open(data, aad = EMPTY.buffer) {\n        __classPrivateFieldSet(this, _RecipientContextImpl_mutex, __classPrivateFieldGet(this, _RecipientContextImpl_mutex, \"f\") ?? new Mutex(), \"f\");\n        const release = await __classPrivateFieldGet(this, _RecipientContextImpl_mutex, \"f\").lock();\n        let pt;\n        try {\n            pt = await this._ctx.key.open(this.computeNonce(this._ctx), toArrayBuffer(data), toArrayBuffer(aad));\n        }\n        catch (e) {\n            throw new OpenError(e);\n        }\n        finally {\n            release();\n        }\n        this.incrementSeq(this._ctx);\n        return pt;\n    }\n}\n_RecipientContextImpl_mutex = new WeakMap();\n","var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {\n    if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\n    if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\n    return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\n};\nvar __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {\n    if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\n    if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\n    if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\n    return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\n};\nvar _SenderContextImpl_mutex;\nimport { EMPTY, SealError, toArrayBuffer } from \"@hpke/common\";\nimport { EncryptionContextImpl } from \"./encryptionContext.js\";\nimport { Mutex } from \"./mutex.js\";\nexport class SenderContextImpl extends EncryptionContextImpl {\n    constructor(api, kdf, params, enc) {\n        super(api, kdf, params);\n        Object.defineProperty(this, \"enc\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        _SenderContextImpl_mutex.set(this, void 0);\n        this.enc = enc;\n    }\n    async seal(data, aad = EMPTY.buffer) {\n        __classPrivateFieldSet(this, _SenderContextImpl_mutex, __classPrivateFieldGet(this, _SenderContextImpl_mutex, \"f\") ?? new Mutex(), \"f\");\n        const release = await __classPrivateFieldGet(this, _SenderContextImpl_mutex, \"f\").lock();\n        let ct;\n        try {\n            ct = await this._ctx.key.seal(this.computeNonce(this._ctx), toArrayBuffer(data), toArrayBuffer(aad));\n        }\n        catch (e) {\n            throw new SealError(e);\n        }\n        finally {\n            release();\n        }\n        this.incrementSeq(this._ctx);\n        return ct;\n    }\n}\n_SenderContextImpl_mutex = new WeakMap();\n","import { AeadId, EMPTY, i2Osp, INFO_LENGTH_LIMIT, INPUT_LENGTH_LIMIT, InvalidParamError, MINIMUM_PSK_LENGTH, Mode, NativeAlgorithm, toUint8Array, } from \"@hpke/common\";\nimport { RecipientExporterContextImpl, SenderExporterContextImpl, } from \"./exporterContext.js\";\nimport { RecipientContextImpl } from \"./recipientContext.js\";\nimport { SenderContextImpl } from \"./senderContext.js\";\n// b\"base_nonce\"\n// deno-fmt-ignore\nconst LABEL_BASE_NONCE = new Uint8Array([\n    98, 97, 115, 101, 95, 110, 111, 110, 99, 101,\n]);\n// b\"exp\"\nconst LABEL_EXP = new Uint8Array([101, 120, 112]);\n// b\"info_hash\"\n// deno-fmt-ignore\nconst LABEL_INFO_HASH = new Uint8Array([\n    105, 110, 102, 111, 95, 104, 97, 115, 104,\n]);\n// b\"key\"\nconst LABEL_KEY = new Uint8Array([107, 101, 121]);\n// b\"psk_id_hash\"\n// deno-fmt-ignore\nconst LABEL_PSK_ID_HASH = new Uint8Array([\n    112, 115, 107, 95, 105, 100, 95, 104, 97, 115, 104,\n]);\n// b\"secret\"\nconst LABEL_SECRET = new Uint8Array([115, 101, 99, 114, 101, 116]);\n// b\"HPKE\"\n// deno-fmt-ignore\nconst SUITE_ID_HEADER_HPKE = new Uint8Array([\n    72, 80, 75, 69, 0, 0, 0, 0, 0, 0,\n]);\n/**\n * The Hybrid Public Key Encryption (HPKE) ciphersuite,\n * which is implemented using only\n * {@link https://www.w3.org/TR/WebCryptoAPI/ | Web Cryptography API}.\n *\n * This is the super class of {@link CipherSuite} and the same as\n * {@link https://jsr.io/@hpke/core/doc/~/CipherSuite | @hpke/core#CipherSuite} as follows:\n * which supports only the ciphersuites that can be implemented on the native\n * {@link https://www.w3.org/TR/WebCryptoAPI/ | Web Cryptography API}.\n * Therefore, the following cryptographic algorithms are not supported for now:\n *   - DHKEM(X25519, HKDF-SHA256)\n *   - DHKEM(X448, HKDF-SHA512)\n *   - ChaCha20Poly1305\n *\n * In addtion, the HKDF functions contained in this class can only derive\n * keys of the same length as the `hashSize`.\n *\n * If you want to use the unsupported cryptographic algorithms\n * above or derive keys longer than the `hashSize`,\n * please use {@link CipherSuite}.\n *\n * This class provides following functions:\n *\n * - Creates encryption contexts both for senders and recipients.\n *   - {@link createSenderContext}\n *   - {@link createRecipientContext}\n * - Provides single-shot encryption API.\n *   - {@link seal}\n *   - {@link open}\n *\n * The calling of the constructor of this class is the starting\n * point for HPKE operations for both senders and recipients.\n *\n * @example Use only ciphersuites supported by Web Cryptography API.\n *\n * ```ts\n * import {\n *   Aes128Gcm,\n *   DhkemP256HkdfSha256,\n *   HkdfSha256,\n *   CipherSuite,\n * } from \"@hpke/core\";\n *\n * const suite = new CipherSuite({\n *   kem: new DhkemP256HkdfSha256(),\n *   kdf: new HkdfSha256(),\n *   aead: new Aes128Gcm(),\n * });\n * ```\n *\n * @example Use a ciphersuite which is currently not supported by Web Cryptography API.\n *\n * ```ts\n * import { Aes128Gcm, HkdfSha256, CipherSuite } from \"@hpke/core\";\n * // Use an extension module.\n * import { DhkemX25519HkdfSha256 } from \"@hpke/dhkem-x25519\";\n *\n * const suite = new CipherSuite({\n *   kem: new DhkemX25519HkdfSha256(),\n *   kdf: new HkdfSha256(),\n *   aead: new Aes128Gcm(),\n * });\n * ```\n */\nexport class CipherSuiteNative extends NativeAlgorithm {\n    /**\n     * @param params A set of parameters for building a cipher suite.\n     *\n     * If the error occurred, throws {@link InvalidParamError}.\n     *\n     * @throws {@link InvalidParamError}\n     */\n    constructor(params) {\n        super();\n        Object.defineProperty(this, \"_kem\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_kdf\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_aead\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_suiteId\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        // KEM\n        if (typeof params.kem === \"number\") {\n            throw new InvalidParamError(\"KemId cannot be used\");\n        }\n        this._kem = params.kem;\n        // KDF\n        if (typeof params.kdf === \"number\") {\n            throw new InvalidParamError(\"KdfId cannot be used\");\n        }\n        this._kdf = params.kdf;\n        // AEAD\n        if (typeof params.aead === \"number\") {\n            throw new InvalidParamError(\"AeadId cannot be used\");\n        }\n        this._aead = params.aead;\n        this._suiteId = new Uint8Array(SUITE_ID_HEADER_HPKE);\n        this._suiteId.set(i2Osp(this._kem.id, 2), 4);\n        this._suiteId.set(i2Osp(this._kdf.id, 2), 6);\n        this._suiteId.set(i2Osp(this._aead.id, 2), 8);\n        this._kdf.init(this._suiteId);\n    }\n    /**\n     * Gets the KEM context of the ciphersuite.\n     */\n    get kem() {\n        return this._kem;\n    }\n    /**\n     * Gets the KDF context of the ciphersuite.\n     */\n    get kdf() {\n        return this._kdf;\n    }\n    /**\n     * Gets the AEAD context of the ciphersuite.\n     */\n    get aead() {\n        return this._aead;\n    }\n    /**\n     * Creates an encryption context for a sender.\n     *\n     * If the error occurred, throws {@link DecapError} | {@link ValidationError}.\n     *\n     * @param params A set of parameters for the sender encryption context.\n     * @returns A sender encryption context.\n     * @throws {@link EncapError}, {@link ValidationError}\n     */\n    async createSenderContext(params) {\n        this._validateInputLength(params);\n        await this._setup();\n        const dh = await this._kem.encap(params);\n        let mode;\n        if (params.psk !== undefined) {\n            mode = params.senderKey !== undefined ? Mode.AuthPsk : Mode.Psk;\n        }\n        else {\n            mode = params.senderKey !== undefined ? Mode.Auth : Mode.Base;\n        }\n        return await this._keyScheduleS(mode, dh.sharedSecret, dh.enc, params);\n    }\n    /**\n     * Creates an encryption context for a recipient.\n     *\n     * If the error occurred, throws {@link DecapError}\n     * | {@link DeserializeError} | {@link ValidationError}.\n     *\n     * @param params A set of parameters for the recipient encryption context.\n     * @returns A recipient encryption context.\n     * @throws {@link DecapError}, {@link DeserializeError}, {@link ValidationError}\n     */\n    async createRecipientContext(params) {\n        this._validateInputLength(params);\n        await this._setup();\n        const sharedSecret = await this._kem.decap(params);\n        let mode;\n        if (params.psk !== undefined) {\n            mode = params.senderPublicKey !== undefined ? Mode.AuthPsk : Mode.Psk;\n        }\n        else {\n            mode = params.senderPublicKey !== undefined ? Mode.Auth : Mode.Base;\n        }\n        return await this._keyScheduleR(mode, sharedSecret, params);\n    }\n    /**\n     * Encrypts a message to a recipient.\n     *\n     * If the error occurred, throws `EncapError` | `MessageLimitReachedError` | `SealError` | `ValidationError`.\n     *\n     * @param params A set of parameters for building a sender encryption context.\n     * @param pt A plain text as bytes to be encrypted.\n     * @param aad Additional authenticated data as bytes fed by an application.\n     * @returns A cipher text and an encapsulated key as bytes.\n     * @throws {@link EncapError}, {@link MessageLimitReachedError}, {@link SealError}, {@link ValidationError}\n     */\n    async seal(params, pt, aad = EMPTY.buffer) {\n        const ctx = await this.createSenderContext(params);\n        return {\n            ct: await ctx.seal(pt, aad),\n            enc: ctx.enc,\n        };\n    }\n    /**\n     * Decrypts a message from a sender.\n     *\n     * If the error occurred, throws `DecapError` | `DeserializeError` | `OpenError` | `ValidationError`.\n     *\n     * @param params A set of parameters for building a recipient encryption context.\n     * @param ct An encrypted text as bytes to be decrypted.\n     * @param aad Additional authenticated data as bytes fed by an application.\n     * @returns A decrypted plain text as bytes.\n     * @throws {@link DecapError}, {@link DeserializeError}, {@link OpenError}, {@link ValidationError}\n     */\n    async open(params, ct, aad = EMPTY.buffer) {\n        const ctx = await this.createRecipientContext(params);\n        return await ctx.open(ct, aad);\n    }\n    // private verifyPskInputs(mode: Mode, params: KeyScheduleParams) {\n    //   const gotPsk = (params.psk !== undefined);\n    //   const gotPskId = (params.psk !== undefined && params.psk.id.byteLength > 0);\n    //   if (gotPsk !== gotPskId) {\n    //     throw new Error('Inconsistent PSK inputs');\n    //   }\n    //   if (gotPsk && (mode === Mode.Base || mode === Mode.Auth)) {\n    //     throw new Error('PSK input provided when not needed');\n    //   }\n    //   if (!gotPsk && (mode === Mode.Psk || mode === Mode.AuthPsk)) {\n    //     throw new Error('Missing required PSK input');\n    //   }\n    //   return;\n    // }\n    async _keySchedule(mode, sharedSecret, params) {\n        // Currently, there is no point in executing this function\n        // because this hpke library does not allow users to explicitly specify the mode.\n        //\n        // this.verifyPskInputs(mode, params);\n        const pskId = params.psk === undefined\n            ? EMPTY\n            : toUint8Array(params.psk.id);\n        const pskIdHash = await this._kdf.labeledExtract(EMPTY, LABEL_PSK_ID_HASH, pskId);\n        const info = params.info === undefined ? EMPTY : toUint8Array(params.info);\n        const infoHash = await this._kdf.labeledExtract(EMPTY, LABEL_INFO_HASH, info);\n        const keyScheduleContext = new Uint8Array(1 + pskIdHash.byteLength + infoHash.byteLength);\n        keyScheduleContext.set(new Uint8Array([mode]), 0);\n        keyScheduleContext.set(new Uint8Array(pskIdHash), 1);\n        keyScheduleContext.set(new Uint8Array(infoHash), 1 + pskIdHash.byteLength);\n        const psk = params.psk === undefined ? EMPTY : toUint8Array(params.psk.key);\n        const ikm = this._kdf.buildLabeledIkm(LABEL_SECRET, psk);\n        const exporterSecretInfo = this._kdf.buildLabeledInfo(LABEL_EXP, keyScheduleContext, this._kdf.hashSize);\n        const exporterSecret = await this._kdf.extractAndExpand(sharedSecret, ikm, exporterSecretInfo, this._kdf.hashSize);\n        if (this._aead.id === AeadId.ExportOnly) {\n            return { aead: this._aead, exporterSecret: exporterSecret };\n        }\n        const keyInfo = this._kdf.buildLabeledInfo(LABEL_KEY, keyScheduleContext, this._aead.keySize);\n        const key = await this._kdf.extractAndExpand(sharedSecret, ikm, keyInfo, this._aead.keySize);\n        const baseNonceInfo = this._kdf.buildLabeledInfo(LABEL_BASE_NONCE, keyScheduleContext, this._aead.nonceSize);\n        const baseNonce = await this._kdf.extractAndExpand(sharedSecret, ikm, baseNonceInfo, this._aead.nonceSize);\n        return {\n            aead: this._aead,\n            exporterSecret: exporterSecret,\n            key: key,\n            baseNonce: new Uint8Array(baseNonce),\n            seq: 0,\n        };\n    }\n    async _keyScheduleS(mode, sharedSecret, enc, params) {\n        const res = await this._keySchedule(mode, sharedSecret, params);\n        if (res.key === undefined) {\n            return new SenderExporterContextImpl(this._api, this._kdf, res.exporterSecret, enc);\n        }\n        return new SenderContextImpl(this._api, this._kdf, res, enc);\n    }\n    async _keyScheduleR(mode, sharedSecret, params) {\n        const res = await this._keySchedule(mode, sharedSecret, params);\n        if (res.key === undefined) {\n            return new RecipientExporterContextImpl(this._api, this._kdf, res.exporterSecret);\n        }\n        return new RecipientContextImpl(this._api, this._kdf, res);\n    }\n    _validateInputLength(params) {\n        if (params.info !== undefined &&\n            params.info.byteLength > INFO_LENGTH_LIMIT) {\n            throw new InvalidParamError(\"Too long info\");\n        }\n        if (params.psk !== undefined) {\n            if (params.psk.key.byteLength < MINIMUM_PSK_LENGTH) {\n                throw new InvalidParamError(`PSK must have at least ${MINIMUM_PSK_LENGTH} bytes`);\n            }\n            if (params.psk.key.byteLength > INPUT_LENGTH_LIMIT) {\n                throw new InvalidParamError(\"Too long psk.key\");\n            }\n            if (params.psk.id.byteLength > INPUT_LENGTH_LIMIT) {\n                throw new InvalidParamError(\"Too long psk.id\");\n            }\n        }\n        return;\n    }\n}\n","import { base64UrlToBytes, DeriveKeyPairError, DeserializeError, EMPTY, KEM_USAGES, LABEL_DKP_PRK, LABEL_SK, NativeAlgorithm, NotSupportedError, SerializeError, toArrayBuffer, } from \"@hpke/common\";\nconst ALG_NAME = \"X25519\";\n// deno-fmt-ignore\nconst PKCS8_ALG_ID_X25519 = new Uint8Array([\n    0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06,\n    0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20,\n]);\nconst BASE_POINT_X25519 = /* @__PURE__ */ (() => {\n    const p = new Uint8Array(32);\n    p[0] = 9;\n    return p;\n})();\nexport class X25519 extends NativeAlgorithm {\n    constructor(hkdf) {\n        super();\n        Object.defineProperty(this, \"_hkdf\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_alg\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nPk\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nSk\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nDh\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_pkcs8AlgId\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        this._alg = { name: ALG_NAME };\n        this._hkdf = hkdf;\n        this._nPk = 32;\n        this._nSk = 32;\n        this._nDh = 32;\n        this._pkcs8AlgId = PKCS8_ALG_ID_X25519;\n    }\n    async serializePublicKey(key) {\n        await this._setup();\n        try {\n            return await this._api.exportKey(\"raw\", key);\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async deserializePublicKey(key) {\n        await this._setup();\n        try {\n            return await this._importRawKey(toArrayBuffer(key), true);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async serializePrivateKey(key) {\n        await this._setup();\n        try {\n            const jwk = await this._api.exportKey(\"jwk\", key);\n            if (!(\"d\" in jwk)) {\n                throw new Error(\"Not private key\");\n            }\n            return base64UrlToBytes(jwk[\"d\"]).buffer;\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async deserializePrivateKey(key) {\n        await this._setup();\n        try {\n            return await this._importRawKey(toArrayBuffer(key), false);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async importKey(format, key, isPublic) {\n        await this._setup();\n        try {\n            if (format === \"raw\") {\n                return await this._importRawKey(key, isPublic);\n            }\n            // jwk\n            if (key instanceof ArrayBuffer) {\n                throw new Error(\"Invalid jwk key format\");\n            }\n            return await this._importJWK(key, isPublic);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async generateKeyPair() {\n        await this._setup();\n        try {\n            return await this._api.generateKey(ALG_NAME, true, KEM_USAGES);\n        }\n        catch (e) {\n            throw new NotSupportedError(e);\n        }\n    }\n    async deriveKeyPair(ikm) {\n        await this._setup();\n        try {\n            const rawIkm = toArrayBuffer(ikm);\n            const dkpPrk = await this._hkdf.labeledExtract(EMPTY, LABEL_DKP_PRK, new Uint8Array(rawIkm));\n            const rawSk = await this._hkdf.labeledExpand(dkpPrk, LABEL_SK, EMPTY, this._nSk);\n            const rawSkBytes = new Uint8Array(rawSk);\n            const sk = await this._deserializePkcs8Key(rawSkBytes);\n            rawSkBytes.fill(0);\n            return {\n                privateKey: sk,\n                publicKey: await this.derivePublicKey(sk),\n            };\n        }\n        catch (e) {\n            throw new DeriveKeyPairError(e);\n        }\n    }\n    async derivePublicKey(key) {\n        await this._setup();\n        try {\n            const jwk = await this._api.exportKey(\"jwk\", key);\n            delete jwk[\"d\"];\n            delete jwk[\"key_ops\"];\n            return await this._api.importKey(\"jwk\", jwk, this._alg, true, []);\n        }\n        catch {\n            try {\n                // Firefox fails to export JWK from some imported X25519 private keys.\n                const bp = await this._api.importKey(\"raw\", BASE_POINT_X25519.buffer, this._alg, true, []);\n                const bits = await this._api.deriveBits({\n                    name: ALG_NAME,\n                    public: bp,\n                }, key, this._nPk * 8);\n                return await this._api.importKey(\"raw\", bits, this._alg, true, []);\n            }\n            catch (e) {\n                throw new DeserializeError(e);\n            }\n        }\n    }\n    async dh(sk, pk) {\n        await this._setup();\n        try {\n            const bits = await this._api.deriveBits({\n                name: ALG_NAME,\n                public: pk,\n            }, sk, this._nDh * 8);\n            return bits;\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async _importRawKey(key, isPublic) {\n        if (isPublic && key.byteLength !== this._nPk) {\n            throw new Error(\"Invalid public key for the ciphersuite\");\n        }\n        if (!isPublic && key.byteLength !== this._nSk) {\n            throw new Error(\"Invalid private key for the ciphersuite\");\n        }\n        if (isPublic) {\n            return await this._api.importKey(\"raw\", key, this._alg, true, []);\n        }\n        return await this._deserializePkcs8Key(new Uint8Array(key));\n    }\n    async _importJWK(key, isPublic) {\n        if (typeof key.kty === \"undefined\" || key.kty !== \"OKP\") {\n            throw new Error(`Invalid kty: ${key.crv}`);\n        }\n        if (typeof key.crv === \"undefined\" || key.crv !== ALG_NAME) {\n            throw new Error(`Invalid crv: ${key.crv}`);\n        }\n        if (isPublic) {\n            if (typeof key.d !== \"undefined\") {\n                throw new Error(\"Invalid key: `d` should not be set\");\n            }\n            return await this._api.importKey(\"jwk\", key, this._alg, true, []);\n        }\n        if (typeof key.d === \"undefined\") {\n            throw new Error(\"Invalid key: `d` not found\");\n        }\n        return await this._api.importKey(\"jwk\", key, this._alg, true, KEM_USAGES);\n    }\n    async _deserializePkcs8Key(k) {\n        const pkcs8Key = new Uint8Array(this._pkcs8AlgId.length + k.length);\n        pkcs8Key.set(this._pkcs8AlgId, 0);\n        pkcs8Key.set(k, this._pkcs8AlgId.length);\n        return await this._api.importKey(\"pkcs8\", pkcs8Key, this._alg, true, KEM_USAGES);\n    }\n}\n","import { base64UrlToBytes, DeriveKeyPairError, DeserializeError, EMPTY, KEM_USAGES, LABEL_DKP_PRK, LABEL_SK, NativeAlgorithm, NotSupportedError, SerializeError, toArrayBuffer, } from \"@hpke/common\";\nconst ALG_NAME = \"X448\";\n// deno-fmt-ignore\nconst PKCS8_ALG_ID_X448 = new Uint8Array([\n    0x30, 0x46, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06,\n    0x03, 0x2b, 0x65, 0x6f, 0x04, 0x3a, 0x04, 0x38,\n]);\nconst BASE_POINT_X448 = /* @__PURE__ */ (() => {\n    const p = new Uint8Array(56);\n    p[0] = 5;\n    return p;\n})();\nexport class X448 extends NativeAlgorithm {\n    constructor(hkdf) {\n        super();\n        Object.defineProperty(this, \"_hkdf\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_alg\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nPk\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nSk\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_nDh\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        Object.defineProperty(this, \"_pkcs8AlgId\", {\n            enumerable: true,\n            configurable: true,\n            writable: true,\n            value: void 0\n        });\n        this._alg = { name: ALG_NAME };\n        this._hkdf = hkdf;\n        this._nPk = 56;\n        this._nSk = 56;\n        this._nDh = 56;\n        this._pkcs8AlgId = PKCS8_ALG_ID_X448;\n    }\n    async serializePublicKey(key) {\n        await this._setup();\n        try {\n            return await this._api.exportKey(\"raw\", key);\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async deserializePublicKey(key) {\n        await this._setup();\n        try {\n            return await this._importRawKey(toArrayBuffer(key), true);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async serializePrivateKey(key) {\n        await this._setup();\n        try {\n            const jwk = await this._api.exportKey(\"jwk\", key);\n            if (!(\"d\" in jwk)) {\n                throw new Error(\"Not private key\");\n            }\n            return base64UrlToBytes(jwk[\"d\"]).buffer;\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async deserializePrivateKey(key) {\n        await this._setup();\n        try {\n            return await this._importRawKey(toArrayBuffer(key), false);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async importKey(format, key, isPublic) {\n        await this._setup();\n        try {\n            if (format === \"raw\") {\n                return await this._importRawKey(key, isPublic);\n            }\n            // jwk\n            if (key instanceof ArrayBuffer) {\n                throw new Error(\"Invalid jwk key format\");\n            }\n            return await this._importJWK(key, isPublic);\n        }\n        catch (e) {\n            throw new DeserializeError(e);\n        }\n    }\n    async generateKeyPair() {\n        await this._setup();\n        try {\n            return await this._api.generateKey(ALG_NAME, true, KEM_USAGES);\n        }\n        catch (e) {\n            throw new NotSupportedError(e);\n        }\n    }\n    async deriveKeyPair(ikm) {\n        await this._setup();\n        try {\n            const rawIkm = toArrayBuffer(ikm);\n            const dkpPrk = await this._hkdf.labeledExtract(EMPTY, LABEL_DKP_PRK, new Uint8Array(rawIkm));\n            const rawSk = await this._hkdf.labeledExpand(dkpPrk, LABEL_SK, EMPTY, this._nSk);\n            const rawSkBytes = new Uint8Array(rawSk);\n            const sk = await this._deserializePkcs8Key(rawSkBytes);\n            rawSkBytes.fill(0);\n            return {\n                privateKey: sk,\n                publicKey: await this.derivePublicKey(sk),\n            };\n        }\n        catch (e) {\n            throw new DeriveKeyPairError(e);\n        }\n    }\n    async derivePublicKey(key) {\n        await this._setup();\n        try {\n            const jwk = await this._api.exportKey(\"jwk\", key);\n            delete jwk[\"d\"];\n            delete jwk[\"key_ops\"];\n            return await this._api.importKey(\"jwk\", jwk, this._alg, true, []);\n        }\n        catch {\n            try {\n                // Some runtimes cannot export JWK from imported X448 private keys.\n                const bp = await this._api.importKey(\"raw\", BASE_POINT_X448.buffer, this._alg, true, []);\n                const bits = await this._api.deriveBits({\n                    name: ALG_NAME,\n                    public: bp,\n                }, key, this._nPk * 8);\n                return await this._api.importKey(\"raw\", bits, this._alg, true, []);\n            }\n            catch (e) {\n                throw new DeserializeError(e);\n            }\n        }\n    }\n    async dh(sk, pk) {\n        await this._setup();\n        try {\n            const bits = await this._api.deriveBits({\n                name: ALG_NAME,\n                public: pk,\n            }, sk, this._nDh * 8);\n            return bits;\n        }\n        catch (e) {\n            throw new SerializeError(e);\n        }\n    }\n    async _importRawKey(key, isPublic) {\n        if (isPublic && key.byteLength !== this._nPk) {\n            throw new Error(\"Invalid public key for the ciphersuite\");\n        }\n        if (!isPublic && key.byteLength !== this._nSk) {\n            throw new Error(\"Invalid private key for the ciphersuite\");\n        }\n        if (isPublic) {\n            return await this._api.importKey(\"raw\", key, this._alg, true, []);\n        }\n        return await this._deserializePkcs8Key(new Uint8Array(key));\n    }\n    async _importJWK(key, isPublic) {\n        if (typeof key.kty === \"undefined\" || key.kty !== \"OKP\") {\n            throw new Error(`Invalid kty: ${key.crv}`);\n        }\n        if (typeof key.crv === \"undefined\" || key.crv !== ALG_NAME) {\n            throw new Error(`Invalid crv: ${key.crv}`);\n        }\n        if (isPublic) {\n            if (typeof key.d !== \"undefined\") {\n                throw new Error(\"Invalid key: `d` should not be set\");\n            }\n            return await this._api.importKey(\"jwk\", key, this._alg, true, []);\n        }\n        if (typeof key.d === \"undefined\") {\n            throw new Error(\"Invalid key: `d` not found\");\n        }\n        return await this._api.importKey(\"jwk\", key, this._alg, true, KEM_USAGES);\n    }\n    async _deserializePkcs8Key(k) {\n        const pkcs8Key = new Uint8Array(this._pkcs8AlgId.length + k.length);\n        pkcs8Key.set(this._pkcs8AlgId, 0);\n        pkcs8Key.set(k, this._pkcs8AlgId.length);\n        return await this._api.importKey(\"pkcs8\", pkcs8Key, this._alg, true, KEM_USAGES);\n    }\n}\n","import type { HttpClient } from './http.js';\nimport type { ProjectConfig } from './types.js';\n\nconst CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes\n\nexport class ConfigFetcher {\n  protected readonly httpClient: HttpClient;\n  private cachedConfig: ProjectConfig | null = null;\n  private cacheTimestamp = 0;\n\n  constructor(httpClient: HttpClient) {\n    this.httpClient = httpClient;\n  }\n\n  async getConfig(): Promise<ProjectConfig | null> {\n    const now = Date.now();\n\n    if (this.cachedConfig && now - this.cacheTimestamp < CACHE_TTL_MS) {\n      return this.cachedConfig;\n    }\n\n    try {\n      const response = await this.httpClient.request<ProjectConfig>('GET', '/v1/config');\n\n      if (response.error || !response.data) {\n        return null;\n      }\n\n      this.cachedConfig = response.data;\n      this.cacheTimestamp = now;\n\n      return this.cachedConfig;\n    } catch {\n      return null;\n    }\n  }\n}\n","export class PalbaseError extends Error {\n  readonly code: string;\n  readonly status: number;\n  readonly details?: unknown;\n\n  constructor(code: string, message: string, status: number, details?: unknown) {\n    super(message);\n    this.name = 'PalbaseError';\n    this.code = code;\n    this.status = status;\n    this.details = details;\n  }\n}\n","export type Platform = 'browser' | 'node' | 'react-native' | 'deno' | 'bun';\n\ndeclare const Deno: unknown;\n\nexport function detectPlatform(): Platform {\n  if (typeof Deno !== 'undefined') {\n    return 'deno';\n  }\n\n  const runtime = globalThis as typeof globalThis & {\n    process?: { versions?: Record<string, string> };\n  };\n  if (runtime.process?.versions) {\n    if ('bun' in runtime.process.versions) {\n      return 'bun';\n    }\n    if ('node' in runtime.process.versions) {\n      return 'node';\n    }\n  }\n\n  if (typeof navigator !== 'undefined' && navigator.product === 'ReactNative') {\n    return 'react-native';\n  }\n\n  return 'browser';\n}\n\n/**\n * The platform word this SDK puts on the wire (`X-Platform`), which the server\n * reads to target flags and to label telemetry.\n *\n * It is NOT `detectPlatform()`'s value verbatim: that reports the JS host\n * (\"browser\"), while the wire wants the platform. iOS sends \"ios\", not the name\n * of its runtime, and a condition author writes `client.platform == 'web'` —\n * the word every other flag vendor uses too. Server hosts keep their own names,\n * where the distinction is the useful part.\n */\nexport function wirePlatform(): string {\n  const host = detectPlatform();\n  return host === 'browser' ? 'web' : host;\n}\n","// Proof-of-work: the bot gate in front of /auth/signup and /auth/login.\n//\n// The server answers an unsolved request with 403 and a challenge in the body:\n//\n//   { \"error\": \"pow_required\", \"challenge\": { \"id\", \"prefix\", \"difficulty\" } }\n//\n// A client finds any nonce whose SHA-256(prefix + nonce) begins with\n// `difficulty` zero bits, then repeats the request carrying the id and nonce as\n// headers. The work is the point: a person signing up pays it once and does not\n// notice, a script signing up ten thousand times pays it ten thousand times.\n//\n// # Why this lives in core, and not one layer up\n//\n// Until 2026-08-14 nothing shipped could solve it: the gate was written with the\n// server and its own integration harness, and every real client sent requests\n// without the headers and got 403. It was then solved in @palbase/web's own\n// request path — which covers `pb.call` and the module facades and NOT\n// `pb.auth.*`, because those go through @palbase/auth's client and from there\n// into core's HttpClient. So the fix landed everywhere except the two endpoints\n// the gate actually guards, and `npm i @palbase/web` still could not sign a\n// person in. Measured 2026-08-18 against a real stack, on the published 7.3.0.\n//\n// The lesson is where a retry belongs: at the layer that ISSUES the request.\n// Core owns fetch for every client in this repo, so core owns the challenge.\n//\n// WebCrypto rather than a hashing dependency: `crypto.subtle` is present in\n// browsers and in Node 18+, which is the same floor the rest of the SDK sets.\n// Measured at the server's default difficulty of 16: ~330ms, ~65k digests.\n\n/** The challenge a `pow_required` response carries. */\nexport interface PowChallenge {\n  id: string;\n  prefix: string;\n  difficulty: number;\n}\n\n/** Header names the retry must carry. Mirrors the server's constants. */\nexport const POW_CHALLENGE_ID_HEADER = 'X-PoW-Challenge-ID';\nexport const POW_NONCE_HEADER = 'X-PoW-Nonce';\n\n/**\n * Reads a challenge out of an error envelope, or returns null when the envelope\n * is not a `pow_required` one.\n *\n * The whole wire envelope is stored on the error, so the challenge arrives\n * without the HTTP layer having to know about proof-of-work at all.\n */\nexport function asPowChallenge(details: unknown): PowChallenge | null {\n  if (typeof details !== 'object' || details === null) return null;\n  const env = details as Record<string, unknown>;\n  if (env.error !== 'pow_required') return null;\n  const c = env.challenge;\n  if (typeof c !== 'object' || c === null) return null;\n  const { id, prefix, difficulty } = c as Record<string, unknown>;\n  if (typeof id !== 'string' || typeof prefix !== 'string') return null;\n  if (typeof difficulty !== 'number' || !Number.isInteger(difficulty) || difficulty < 0)\n    return null;\n  return { id, prefix, difficulty };\n}\n\nconst encoder = new TextEncoder();\n\n/**\n * One SHA-256, by the fastest route this runtime offers.\n *\n * Awaiting `crypto.subtle.digest` once per nonce is what made this expensive,\n * and the cost is the await rather than the hashing. Measured on one machine,\n * 200k digests of a 40-byte input:\n *\n *\tawaited crypto.subtle.digest     105,597 digests/s\n *\tsync node:crypto createHash    1,324,503 digests/s   — 12.5x\n *\n * That is the difference between difficulty 24 taking 159 seconds and taking\n * 13. Node, Bun and Deno all have the sync one; a browser has only WebCrypto,\n * and there it stays async.\n *\n * The specifier is assembled at runtime so a browser bundler does not try to\n * resolve `node:crypto` and fail the build over a branch that never runs there.\n */\ntype Hasher = (input: string) => Uint8Array | Promise<Uint8Array>;\n\nlet hasher: Hasher | null = null;\n\nasync function digester(): Promise<Hasher> {\n  if (hasher) return hasher;\n  // Read off globalThis with an inline shape rather than by naming `process`,\n  // which needs @types/node — a dependency this package does not have and should\n  // not grow for one branch. It typechecked locally only because those types\n  // were hoisted into node_modules by a sibling package; the publish workflow's\n  // clean checkout is what said so, which is exactly what it is for.\n  const runtime = globalThis as {\n    process?: { versions?: { node?: string; bun?: string } };\n  };\n  const nodeish =\n    runtime.process?.versions?.node !== undefined || runtime.process?.versions?.bun !== undefined;\n  if (nodeish) {\n    try {\n      const mod = (await import(/* @vite-ignore */ `${'node:'}crypto`)) as {\n        createHash?: (alg: string) => { update(s: string): { digest(): Uint8Array } };\n      };\n      if (typeof mod.createHash === 'function') {\n        const createHash = mod.createHash;\n        hasher = (input: string) => new Uint8Array(createHash('sha256').update(input).digest());\n        return hasher;\n      }\n    } catch {\n      // No node:crypto here. WebCrypto below is not a fallback in the apologetic\n      // sense — it is the only hash a browser has, and it is correct.\n    }\n  }\n  hasher = async (input: string) =>\n    new Uint8Array(await crypto.subtle.digest('SHA-256', encoder.encode(input)));\n  return hasher;\n}\n\n/** Monotonic where it exists, wall-clock where it does not. */\nconst now = (): number =>\n  typeof performance !== 'undefined' && typeof performance.now === 'function'\n    ? performance.now()\n    : Date.now();\n\n/** Counts leading zero bits, stopping at the first byte that has a one. */\nfunction leadingZeroBits(hash: Uint8Array): number {\n  let bits = 0;\n  for (const byte of hash) {\n    if (byte === 0) {\n      bits += 8;\n      continue;\n    }\n    // clz32 counts across 32 bits; a byte occupies the low 8, so the first 24\n    // are always zero and get subtracted back off.\n    return bits + Math.clz32(byte) - 24;\n  }\n  return bits;\n}\n\n/**\n * The hardest challenge this client will attempt.\n *\n * Not a taste: it is the server's own ceiling. palauth maps a risk score to a\n * difficulty and its worst case is 24 (`DifficultyForRisk`, bot/pow.go:156-166).\n * Anything above that cannot have come from a stack behaving as designed, and\n * the cost of humouring it falls entirely on this side — each step up DOUBLES\n * the work, so difficulty 30 is sixty-four times a legitimate worst case and, on\n * the web, sixty-four times a frozen main thread. Refused immediately, by name.\n */\nexport const MAX_POW_DIFFICULTY = 24;\n\n/**\n * Finds a nonce satisfying the challenge and returns the headers a retry needs.\n *\n * THE BUDGET SCALES WITH THE CHALLENGE, and the first version of this did not.\n * It bounded the search at a flat `1 << 24` — which is not a generous bound for\n * difficulty 24, it is the EXPECTED number of attempts. Finding a nonce is a\n * geometric process: the chance of needing more than 2^d attempts is 1/e, so a\n * flat 2^24 would have failed roughly 37% of legitimate hardest-risk challenges,\n * and failed them for precisely the users the gate exists to slow down — who\n * would have been unable to sign in at all rather than made to wait.\n *\n * Eight times expected puts that at e^-8, about three in ten thousand, while\n * leaving the common case (the server's default 16, and 12 for an unremarkable\n * caller) exactly as cheap as it was.\n *\n * `powBudget` is exported and separate so the RELATIONSHIP can be asserted\n * directly. A test that only watches a cheap challenge succeed cannot tell this\n * budget from the flat one it replaced — measured: reinstating `1 << 24` left\n * such a test green.\n */\nexport function powBudget(difficulty: number): number {\n  return 8 * 2 ** difficulty;\n}\n\n/**\n * The longest a solve may be ALLOWED to take, and the difference from a\n * deadline is the whole point.\n *\n * The first version of this was a flat 120s deadline, and it was measured to be\n * worse than the flat iteration budget it was meant to backstop: at ~105k\n * digests/s, difficulty 24 EXPECTS 159 seconds, so a 120s clock killed the\n * majority of legitimate hardest-risk solves — reintroducing, larger, exactly\n * the class of defect that replacing `1 << 24` had removed. Guessing a number\n * for an unknown machine cannot work: the same difficulty is 13 seconds on a\n * runtime with a sync hasher and 159 on one without.\n *\n * So the machine is MEASURED, and the decision moves to the front. A short\n * calibration gives the rate this process actually hashes at; if the whole\n * iteration budget cannot fit in this window at that rate, the solve is refused\n * IMMEDIATELY, naming the numbers. A caller then learns in milliseconds that\n * this difficulty is unpayable here, instead of after two minutes of work\n * thrown away.\n *\n * What remains after that is a guarantee rather than a gamble: a solve that\n * starts can always finish inside its budget, so the only failure left is the\n * budget's own e^-8.\n */\nexport const POW_TIME_BUDGET_MS = 120_000;\n\n/**\n * The window the rate is measured over, and the warm-up it deliberately skips.\n *\n * All of these are REAL attempts — the search starts at nonce 0 and never\n * restarts — so calibration costs nothing but the reading. The first 1024 are\n * excluded from the timing because they include this loop's own JIT warm-up:\n * measured, timing from zero reported 747k digests/s on a machine whose steady\n * rate is 1.32M, and the decision below would have refused a difficulty this\n * machine can pay in half the allowance.\n */\nconst CALIBRATION_WARMUP = 1024;\nconst CALIBRATION_END = 9216;\n\nexport async function solvePowChallenge(\n  challenge: PowChallenge,\n  maxIterations = powBudget(challenge.difficulty),\n  // The caller's AbortSignal, honoured INSIDE the loop rather than only around\n  // the fetch it precedes — for the callers that have one. `pb.auth.signIn` does\n  // NOT: it reaches the network through @palbase/auth's client, which takes\n  // credentials and nothing else. So it is the extra a caller can opt into, and\n  // POW_TIME_BUDGET_MS below is what actually bounds the work.\n  signal?: AbortSignal,\n): Promise<Record<string, string>> {\n  if (challenge.difficulty > MAX_POW_DIFFICULTY) {\n    throw new Error(\n      `proof-of-work: refusing difficulty ${challenge.difficulty}; this client attempts at most ${MAX_POW_DIFFICULTY}, which is the highest a Palbase stack issues`,\n    );\n  }\n\n  const digest = await digester();\n  let warmedAt = 0;\n  let calibrated = false;\n  // Armed by the calibration below, never before it: until the rate is known\n  // there is no honest number to put here.\n  let deadline = Number.POSITIVE_INFINITY;\n\n  for (let nonce = 0; nonce < maxIterations; nonce++) {\n    // Checked in batches: reading them is cheap but not free, and a\n    // 1024-digest granularity bounds the delay at a few milliseconds.\n    if ((nonce & 1023) === 0) {\n      if (signal?.aborted) {\n        throw new DOMException('proof-of-work solve aborted', 'AbortError');\n      }\n      if (now() > deadline) {\n        throw new Error(\n          `proof-of-work: gave up on difficulty ${challenge.difficulty} after ${POW_TIME_BUDGET_MS / 1000}s ` +\n            `and ${nonce.toLocaleString()} attempts — the tail this run drew is longer than the allowance`,\n        );\n      }\n    }\n\n    // THE DECISION, TAKEN ONCE AND TAKEN EARLY.\n    //\n    // After CALIBRATION_DIGESTS real attempts the rate of THIS process is\n    // known, so the question \"can this machine pay this difficulty\" has an\n    // answer instead of an assumption. If the whole budget cannot fit in the\n    // time budget, refuse here — milliseconds in, with the numbers — rather\n    // than spend two minutes and throw them away. If it fits, everything after\n    // this point is guaranteed to finish inside the window, so the only\n    // remaining failure is the budget's own e^-8.\n    if (nonce === CALIBRATION_WARMUP) {\n      warmedAt = now();\n    }\n    if (!calibrated && nonce === CALIBRATION_END) {\n      calibrated = true;\n      const elapsed = Math.max(now() - warmedAt, 0.001);\n      const rate = (CALIBRATION_END - CALIBRATION_WARMUP) / (elapsed / 1000);\n      // EXPECTED, not worst case, and the difference is the whole judgement.\n      //\n      // Finding a nonce is geometric: 2^difficulty attempts on average, with a\n      // long tail the 8x budget covers. Refusing because the TAIL will not fit\n      // would turn away work whose expected cost is seventeen seconds — measured\n      // exactly that on this machine at difficulty 24. Refusing on the EXPECTED\n      // cost turns away only what is genuinely unpayable here, and what it lets\n      // through is then cut by the clock with probability e^-(budget/expected):\n      // at 120s against a 17s expectation that is one run in a thousand, and at\n      // difficulty 20 on a browser it is one in a hundred and fifty thousand.\n      const expectedMs = (2 ** challenge.difficulty / rate) * 1000;\n      if (expectedMs > POW_TIME_BUDGET_MS) {\n        throw new Error(\n          `proof-of-work: difficulty ${challenge.difficulty} needs about ${Math.round(expectedMs / 1000)}s here ` +\n            `(${Math.round(rate).toLocaleString()} digests/s) and this client allows ${POW_TIME_BUDGET_MS / 1000}s; ` +\n            `refusing before spending the time rather than after`,\n        );\n      }\n      deadline = now() + (POW_TIME_BUDGET_MS - (now() - warmedAt));\n    }\n\n    const hash = await digest(challenge.prefix + nonce);\n    if (leadingZeroBits(hash) >= challenge.difficulty) {\n      return {\n        [POW_CHALLENGE_ID_HEADER]: challenge.id,\n        [POW_NONCE_HEADER]: String(nonce),\n      };\n    }\n  }\n  throw new Error(\n    `proof-of-work: no nonce found for difficulty ${challenge.difficulty} within ${maxIterations} attempts`,\n  );\n}\n","import { Chacha20Poly1305 } from '@hpke/chacha20poly1305';\nimport { CipherSuite, HkdfSha256 } from '@hpke/core';\nimport { DhkemX25519HkdfSha256 } from '@hpke/dhkem-x25519';\nimport { PalbaseError } from './errors.js';\nimport { fromBase64, toBase64 } from './sealed-json.js';\nimport type { SealingKey } from './sealed-keys.js';\n\nexport const SEALED_CONTENT_TYPE = 'application/palbase-sealed+json';\nexport const SEALED_HEADER = 'X-Palbase-Sealed';\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder('utf-8', { fatal: true });\nconst responseLabel = 'palbase-sealed/response/v1';\n\nexport function sealingRequired(path: string): boolean {\n  // Mirrors v2/internal/server/sealed.go. Tenant/runtime routes cannot unseal.\n  return new URL(path, 'https://unused.invalid').pathname.startsWith('/auth/');\n}\n\nexport function requestAAD(\n  host: string,\n  method: string,\n  path: string,\n  ict: string,\n  ts: number,\n  idem: string,\n): Uint8Array<ArrayBuffer> {\n  const fields = [host, method, path, ict, idem].map((field) => encoder.encode(field));\n  const bytes = new Uint8Array(fields.reduce((size, field) => size + 4 + field.length, 8));\n  const view = new DataView(bytes.buffer);\n  let offset = 0;\n  for (const [index, field] of fields.entries()) {\n    if (index === 4) {\n      view.setBigUint64(offset, BigInt(ts));\n      offset += 8;\n    }\n    view.setUint32(offset, field.length);\n    offset += 4;\n    bytes.set(field, offset);\n    offset += field.length;\n  }\n  return bytes;\n}\n\nexport function sealingSuite(): CipherSuite {\n  return new CipherSuite({\n    kem: new DhkemX25519HkdfSha256(),\n    kdf: new HkdfSha256(),\n    aead: new Chacha20Poly1305(),\n  });\n}\n\nexport async function sealRequest(\n  key: SealingKey,\n  url: string,\n  init: RequestInit,\n): Promise<Uint8Array<ArrayBuffer>> {\n  const suite = sealingSuite();\n  const sender = await suite.createSenderContext({\n    recipientPublicKey: await suite.kem.importKey('raw', key.publicKey.buffer),\n  });\n  const headers = new Headers(init.headers);\n  const ict = headers.get('content-type') ?? 'application/json';\n  const ts = Math.floor(Date.now() / 1000);\n  const target = new URL(url);\n  const method = init.method ?? 'GET';\n  // Go binds r.URL.Path (decoded, without the query), not RequestURI.\n  const aad = requestAAD(\n    target.host,\n    method,\n    decodeURIComponent(target.pathname),\n    ict,\n    ts,\n    headers.get('idempotency-key') ?? '',\n  );\n  const ct = await sender.seal(encoder.encode(typeof init.body === 'string' ? init.body : ''), aad);\n  const envelope = JSON.stringify({\n    v: 2,\n    kid: key.kid,\n    enc: toBase64(new Uint8Array(sender.enc)),\n    ct: toBase64(new Uint8Array(ct)),\n    ict,\n    ts,\n  });\n  if (method === 'GET' || method === 'HEAD' || init.body === undefined) {\n    headers.set(\n      SEALED_HEADER,\n      toBase64(encoder.encode(envelope)).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, ''),\n    );\n    delete init.body;\n  } else {\n    headers.delete(SEALED_HEADER);\n    headers.set('Content-Type', SEALED_CONTENT_TYPE);\n    init.body = envelope;\n  }\n  headers.delete('Content-Length');\n  init.headers = Object.fromEntries(headers.entries());\n  // Do not redirect a credential-bearing envelope to a different endpoint.\n  init.redirect = 'error';\n  return new Uint8Array(await sender.export(encoder.encode(responseLabel), 32));\n}\n\nexport async function openSealedResponse(\n  response: Response,\n  exporter: Uint8Array | undefined,\n  method: string,\n): Promise<Response> {\n  if (\n    response.headers.get('content-type')?.split(';')[0]?.trim().toLowerCase() !==\n    SEALED_CONTENT_TYPE\n  ) {\n    // Edge/middleware errors are plaintext. A successful auth result cannot be.\n    if (exporter && response.ok && method !== 'HEAD') {\n      throw new PalbaseError(\n        'sealed_response_invalid',\n        'The server returned an unencrypted response.',\n        response.status,\n      );\n    }\n    return response;\n  }\n  // HTTP HEAD has no response body, including when the handler sealed it.\n  if (method === 'HEAD') return response;\n  try {\n    if (!exporter) throw new Error('No sealing context');\n    const envelope = (await response.json()) as {\n      v: number;\n      n: string;\n      ct: string;\n      ict: string;\n      st: number;\n    };\n    if (\n      envelope.v !== 2 ||\n      !Number.isInteger(envelope.st) ||\n      envelope.st < 200 ||\n      envelope.st > 599 ||\n      typeof envelope.ict !== 'string'\n    ) {\n      throw new Error('Invalid response envelope');\n    }\n    const plaintext = await new Chacha20Poly1305()\n      .createEncryptionContext(exporter)\n      .open(\n        fromBase64(envelope.n),\n        fromBase64(envelope.ct),\n        encoder.encode(`${responseLabel}\\n${envelope.ict}\\n${envelope.st}`),\n      );\n    const headers = new Headers(response.headers);\n    headers.set('Content-Type', envelope.ict);\n    headers.delete('Content-Length');\n    headers.delete('Content-Encoding');\n    // The outer status is always 200; auth failures and PoW live inside the seal.\n    return new Response([204, 205, 304].includes(envelope.st) ? null : decoder.decode(plaintext), {\n      status: envelope.st,\n      headers,\n    });\n  } catch {\n    throw new PalbaseError(\n      'sealed_response_invalid',\n      'The encrypted server response could not be verified.',\n      response.status,\n    );\n  }\n}\n","// Signatures cover the original JSON bytes, not JSON.stringify(JSON.parse(raw)).\n// Go's encoder preserves struct field order and escapes characters differently.\nexport function rawObjectFields(raw: string): Map<string, string> {\n  const parsed: unknown = JSON.parse(raw);\n  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw new Error('Expected a JSON object');\n  }\n  const fields = new Map<string, string>();\n  let i = 0;\n  const space = () => {\n    while (/\\s/.test(raw[i] ?? '') && i < raw.length) i++;\n  };\n  const stringEnd = (start: number) => {\n    let end = start + 1;\n    while (end < raw.length) {\n      if (raw[end] === '\\\\') end += 2;\n      else if (raw[end++] === '\"') return end;\n    }\n    throw new Error('Unterminated JSON string');\n  };\n  space();\n  i++; // opening object, already validated by JSON.parse\n  while (true) {\n    space();\n    if (raw[i] === '}') return fields;\n    const nameEnd = stringEnd(i);\n    const name = JSON.parse(raw.slice(i, nameEnd)) as string;\n    i = nameEnd;\n    space();\n    i++; // colon\n    space();\n    const start = i;\n    if (raw[i] === '\"') i = stringEnd(i);\n    else if (raw[i] === '{' || raw[i] === '[') {\n      let depth = 0;\n      do {\n        const c = raw[i];\n        if (c === '\"') {\n          i = stringEnd(i);\n          continue;\n        }\n        if (c === '{' || c === '[') depth++;\n        if (c === '}' || c === ']') depth--;\n        i++;\n      } while (depth > 0 && i < raw.length);\n    } else {\n      while (i < raw.length && !/[\\s,}]/.test(raw[i] ?? '')) i++;\n    }\n    // A first-match slice and JSON.parse's last-match value must never disagree.\n    if (fields.has(name)) throw new Error('Duplicate JSON field');\n    fields.set(name, raw.slice(start, i));\n    space();\n    if (raw[i] === ',') i++;\n  }\n}\n\nexport function fromBase64(value: string): Uint8Array<ArrayBuffer> {\n  return Uint8Array.from(atob(value), (c) => c.charCodeAt(0));\n}\n\nexport function toBase64(bytes: Uint8Array): string {\n  // Avoid a spread: envelopes can exceed the engine's argument-count limit.\n  let binary = '';\n  for (const byte of bytes) binary += String.fromCharCode(byte);\n  return btoa(binary);\n}\n","import { ed25519 } from '@noble/curves/ed25519.js';\nimport { PalbaseError } from './errors.js';\nimport { fromBase64, rawObjectFields } from './sealed-json.js';\nimport type { HttpClientOptions } from './types.js';\nimport { endpointUrl } from './url.js';\n\nexport const SEALED_KEYSET_PATH = '/palbase-sealed-keys.json';\nexport const SEALED_SUITE = 'DHKEM-X25519-HKDF-SHA256/HKDF-SHA256/ChaCha20Poly1305';\n// Fleet PUBLIC key, identical to the iOS SDK pin. Never learned from a response.\nconst FLEET_ROOT = 'mRDTIWzhW0JCk0e2Jvkn679VeZBB38zOOfPTMO6vBpU=';\nconst REFRESH_MS = 5 * 60_000;\nconst FAILURE_COOLDOWN_MS = 60_000;\nconst encoder = new TextEncoder();\n\nexport interface SealingKey {\n  kid: string;\n  publicKey: Uint8Array<ArrayBuffer>;\n  expires: number;\n  version: number;\n}\n\nexport function expectedSealedStack(baseUrl: string, apiKey: string): string {\n  // Fleet tenant hosts name the stack even when a legacy key says pb_project_.\n  // Apex/custom/self-host URLs instead need the key's ref (or an explicit pin).\n  const host = new URL(baseUrl).hostname;\n  return (\n    /^([a-z0-9]{4,24})\\.(?:(?:dev|staging)\\.)?palbase\\.studio$/.exec(host)?.[1] ??\n    /^pb_([^_]+)_/.exec(apiKey)?.[1] ??\n    ''\n  );\n}\n\nfunction record(raw: string | undefined): Record<string, unknown> {\n  if (!raw) throw new Error('Missing signed object');\n  rawObjectFields(raw); // also refuses duplicate fields\n  return JSON.parse(raw) as Record<string, unknown>;\n}\n\nfunction string(value: unknown): string {\n  if (typeof value !== 'string' || !value) throw new Error('Missing string');\n  return value;\n}\n\nfunction integer(value: unknown): number {\n  if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {\n    throw new Error('Invalid integer');\n  }\n  return value;\n}\n\nfunction verifySignature(raw: string, signed: Record<string, unknown>, publicKey: Uint8Array) {\n  if (\n    signed.alg !== 'ed25519' ||\n    publicKey.length !== 32 ||\n    !ed25519.verify(fromBase64(string(signed.sig)), encoder.encode(raw), publicKey, {\n      zip215: false,\n    })\n  )\n    throw new Error('Invalid sealed key signature');\n}\n\n/** Verify fleet → expected stack → keyset, retaining the exact signed bytes. */\nexport function verifySealingKey(\n  raw: string,\n  expectedRef: string,\n  root: string,\n  lastVersion: number,\n  now: number,\n): SealingKey {\n  const fields = rawObjectFields(raw);\n  const signed = record(raw);\n  const statementRaw = fields.get('binding');\n  const statement = record(statementRaw);\n  const bindingRaw = rawObjectFields(statementRaw ?? '').get('binding');\n  if (!bindingRaw || statement.rootKid !== 'sealed-root-v1') {\n    throw new Error('Unknown sealed trust root');\n  }\n  verifySignature(bindingRaw, statement, fromBase64(root));\n  const binding = record(bindingRaw);\n  if (\n    binding.v !== 1 ||\n    !expectedRef ||\n    string(binding.stackRef).trim().toLowerCase() !== expectedRef.toLowerCase()\n  ) {\n    throw new Error('Sealed binding belongs to another stack');\n  }\n  const bindingExpiry = integer(binding.expires);\n  if (bindingExpiry * 1000 <= now) throw new Error('Expired sealed binding');\n  const keysetRaw = fields.get('keyset');\n  if (!keysetRaw) throw new Error('Missing sealed keyset');\n  verifySignature(keysetRaw, signed, fromBase64(string(binding.signingKey)));\n  const keyset = record(keysetRaw);\n  const version = integer(keyset.version);\n  const expires = Math.min(integer(keyset.expires), bindingExpiry);\n  if (version < lastVersion) throw new Error('Sealed keyset version went backwards');\n  if (expires * 1000 <= now) throw new Error('Expired sealed keyset');\n  if (keyset.v !== 1 || !Array.isArray(keyset.keys)) throw new Error('Invalid sealed keyset');\n  for (const item of keyset.keys) {\n    if (item === null || typeof item !== 'object') continue;\n    const entry = item as Record<string, unknown>;\n    if (entry.alg !== SEALED_SUITE) continue;\n    const publicKey = fromBase64(string(entry.pub));\n    if (publicKey.length !== 32) throw new Error('Invalid sealing public key');\n    return { kid: string(entry.kid), publicKey, expires, version };\n  }\n  throw new Error('No supported sealing key');\n}\n\nexport class SealedKeyStore {\n  private cached?: SealingKey;\n  private pending?: Promise<SealingKey>;\n  private fetchedAt = 0;\n  private retryAfter = 0;\n  private lastVersion = 0;\n  private lastError?: PalbaseError;\n  private rotationRefreshAt = 0;\n\n  constructor(\n    private readonly baseUrl: string,\n    private readonly apiKey: string,\n    private readonly options?: Exclude<HttpClientOptions['sealed'], false>,\n  ) {}\n\n  async current(signal?: AbortSignal, rotate = false): Promise<SealingKey> {\n    signal?.throwIfAborted();\n    const now = Date.now();\n    const valid = this.cached && this.cached.expires * 1000 > now ? this.cached : undefined;\n    if (this.pending) return this.waitFor(this.pending, signal);\n    // A forged unknown-kid response cannot turn every request into a key fetch.\n    if (rotate && now - this.rotationRefreshAt >= FAILURE_COOLDOWN_MS) {\n      this.fetchedAt = 0;\n      this.retryAfter = 0;\n      this.rotationRefreshAt = now;\n    }\n    if (valid && now - this.fetchedAt < REFRESH_MS) return valid;\n    if (now < this.retryAfter) {\n      if (valid) return valid;\n      throw this.lastError;\n    }\n    const pending = this.fetchKey()\n      .then((key) => {\n        this.cached = key;\n        this.lastVersion = key.version;\n        this.fetchedAt = Date.now();\n        this.retryAfter = 0;\n        return key;\n      })\n      .catch((error: unknown) => {\n        this.retryAfter = Date.now() + FAILURE_COOLDOWN_MS;\n        this.lastError =\n          error instanceof PalbaseError\n            ? error\n            : new PalbaseError(\n                'sealed_key_unavailable',\n                'The server encryption key could not be verified. Please try again later.',\n                0,\n              );\n        // A transient refresh failure may reuse a verified, unexpired key only.\n        if (this.cached && this.cached.expires * 1000 > Date.now()) return this.cached;\n        throw this.lastError;\n      })\n      .finally(() => {\n        this.pending = undefined;\n      });\n    this.pending = pending;\n    return this.waitFor(pending, signal);\n  }\n\n  private async fetchKey(): Promise<SealingKey> {\n    const controller = new AbortController();\n    const timer = setTimeout(() => controller.abort(), 15_000);\n    try {\n      const response = await fetch(endpointUrl(this.baseUrl, SEALED_KEYSET_PATH), {\n        headers: this.apiKey ? { apikey: this.apiKey } : {},\n        signal: controller.signal,\n        cache: 'no-store',\n        redirect: 'error',\n      });\n      if (!response.ok) throw new Error('Sealed keyset unavailable');\n      const raw = await response.text();\n      if (raw.length > 64 * 1024) throw new Error('Sealed keyset too large');\n      const expectedRef = this.options?.stackRef ?? expectedSealedStack(this.baseUrl, this.apiKey);\n      return verifySealingKey(\n        raw,\n        expectedRef,\n        this.options?.root ?? FLEET_ROOT,\n        this.lastVersion,\n        Date.now(),\n      );\n    } finally {\n      clearTimeout(timer);\n    }\n  }\n\n  // One caller's cancellation must not abort a shared key fetch for other calls.\n  private waitFor(pending: Promise<SealingKey>, signal?: AbortSignal): Promise<SealingKey> {\n    if (!signal) return pending;\n    return new Promise((resolve, reject) => {\n      const aborted = () => reject(signal.reason);\n      signal.addEventListener('abort', aborted, { once: true });\n      pending.then(resolve, reject).finally(() => signal.removeEventListener('abort', aborted));\n      if (signal.aborted) aborted();\n    });\n  }\n}\n","/**\n * Join the configured base URL with an SDK path.\n *\n * A BASE URL MAY CARRY A PATH, NOT JUST AN ORIGIN — a self-host published\n * under `https://api.example.com/palbase`, or an app that routes the browser\n * through its own server (`<origin>/pb`, rewritten upstream) because the\n * Environment's edge does not answer its origin with CORS headers.\n *\n * `new URL('/palbase-sealed-keys.json', base)` reads as the careful way to do\n * this and is the one form that DROPS that path: the leading slash makes the\n * path absolute against the base's ORIGIN. The sealed key store used it while\n * every ordinary request concatenated, so one request in the client asked a\n * different server than all the others — measured live 2026-09-11, the keyset\n * fetch landed on the app's own 404 page and every sealed call failed with\n * `sealed_key_unavailable`. The other two SDK surfaces never had the split:\n * iOS appends (`SealedKeyStore.swift`), Android concatenates onto a\n * slash-trimmed base (`SealedKeyStore.kt`) — this is their shape.\n */\nexport function endpointUrl(base: string, path: string): string {\n  return `${base.replace(/\\/+$/, '')}${path}`;\n}\n","import { PalbaseError } from './errors.js';\nimport { wirePlatform } from './platform.js';\nimport { asPowChallenge, solvePowChallenge } from './pow.js';\nimport { openSealedResponse, sealingRequired, sealRequest } from './sealed.js';\nimport { SealedKeyStore } from './sealed-keys.js';\nimport type { TokenManager } from './token.js';\nimport type { HttpClientOptions, PalbaseResponse, RequestOptions } from './types.js';\nimport { endpointUrl } from './url.js';\n\n/**\n * Default production host. Dev / staging / local callers override via\n * `options.url`. Apex-style routing is the only supported production path;\n * Kong resolves Environment identity from the API key.\n */\nconst PALBASE_DEFAULT_HOST = 'api.palbase.studio';\n\n/**\n * Parse the Environment ref from a Palbase API key.\n *\n * Canonical shape: `pb_{environment_ref}_c{random}`, where the Environment ref\n * is 4-24 lowercase ASCII alphanumeric characters and random is AT LEAST 20\n * base62 chars.\n *\n * The length is a floor, not an equality. The stack's own minter writes 20\n * (v2/cmd/palsvc/initenv.go) and the cloud control plane writes 32\n * (cloud/platform/server/services/keys.ts), and the door that admits the\n * request refuses to rule on the difference: *\"a shorter or longer secret is\n * not a security property this door can rule on\"*\n * (v2/internal/platform/identitymw.go: parseAPIKey). A client that is stricter\n * than the server does not add safety — it just refuses working keys, which is\n * exactly what this one did to every cloud project until 2026-08-25.\n *\n * Returns the Environment ref on match; `null` otherwise.\n */\nconst API_KEY_RE = /^pb_([a-z0-9]{4,24})_c[A-Za-z0-9]{20,}$/;\n\nfunction parseEnvironmentRef(apiKey: string): string | null {\n  return API_KEY_RE.exec(apiKey)?.[1] ?? null;\n}\nconst MAX_RETRIES = 3;\nconst INITIAL_BACKOFF_MS = 200;\n/**\n * Upper bound on a single 429 retry sleep. A server may return a long\n * Retry-After (a locked account can send minutes/hours); honoring it verbatim\n * would HANG the request for that whole window. Cap each retry at 10s — after\n * MAX_RETRIES the 429 envelope surfaces to the caller (fail fast, don't sleep\n * minutes). The clamp never skips a retry; it only bounds how long each waits.\n */\nconst MAX_RETRY_DELAY_MS = 10_000;\n\n/**\n * The edge's refusals this client is allowed to WAIT for — an ALLOWLIST.\n *\n * NEVER a denylist. Enumerating the exceptions cannot see the set GROW: a name\n * added at the edge tomorrow would be waited for by a client that never heard\n * of it. The client waits only for what it was taught.\n *\n * `request_too_large` is absent on purpose — the same body earns the same\n * refusal, so waiting cannot help. `handoff_failed` is absent because the\n * project may ALREADY have applied the request: the edge counts a hand-off\n * ATTEMPT before it knows the outcome, and a connection can break after the\n * body was fully delivered. A silent retry there writes an insert twice.\n */\nconst RETRYABLE_HOLD_REFUSALS: ReadonlySet<string> = new Set([\n  'holder_full',\n  'wake_budget_exceeded',\n]);\n\n/**\n * How long to wait for a held-request refusal, or null when it must surface.\n *\n * READS THE NAME, NEVER THE STATUS: an unnamed 503 is Envoy's `no healthy\n * upstream` and this client keeps surfacing it exactly as it does today.\n *\n * READS THE HINT FROM THE PARSED BODY, never from the header alone. A browser\n * cannot see `Retry-After` unless CORS exposes it, and the edge does not — it\n * was measured live on an AWAKE project, whose expose list carries\n * `x-request-id, palbase-auth-contract, etag` and not `Retry-After`. A\n * header-only read is inert exactly where this fix matters.\n */\nfunction heldRefusalWait(\n  status: number,\n  body: { error?: string; retry_after?: number } | undefined,\n): number | null {\n  if (status !== 503) return null;\n  if (body?.error === undefined || !RETRYABLE_HOLD_REFUSALS.has(body.error)) return null;\n  const seconds = body.retry_after;\n  const advertised =\n    typeof seconds === 'number' && Number.isFinite(seconds) && seconds > 0\n      ? seconds * 1000\n      : INITIAL_BACKOFF_MS;\n  // The 429 path's own ceiling — no second backoff is invented.\n  return Math.min(advertised, MAX_RETRY_DELAY_MS);\n}\n\n/**\n * Carry a 429's retry hint into the error envelope when only the header has it.\n *\n * A REFUSAL FROM THE EDGE CARRIES NOTHING BUT THE HEADER. Envoy and the\n * gateway limiter answer before any Palbase service is reached, so their 429\n * has no `retry_after` and no `data.retryAfter` — and every reader above this\n * layer (`@palbase/web`'s BackendError, the iOS SDK) looks in the BODY. The\n * seconds were on the wire and unreachable to all of them.\n *\n * Lifted under `retry_after`, the platform's own name for it (palauth's\n * rate-limit envelope), never overwriting a hint the service itself sent — a\n * service knows its window, the edge only knows its own.\n */\nfunction withRetryHint(\n  body: Record<string, unknown> | undefined,\n  response: Response,\n): Record<string, unknown> | undefined {\n  // 429, OR a 503 the edge NAMED as a held request. NOT \"any 503\": an unnamed\n  // 503 is Envoy's `no healthy upstream` and FR-006 keeps it exactly as it is\n  // today — gaining a hint would already be a behaviour change.\n  const namedHold =\n    response.status === 503 &&\n    typeof body?.error === 'string' &&\n    RETRYABLE_HOLD_REFUSALS.has(body.error);\n  if (response.status !== 429 && !namedHold) return body;\n  const data = body?.data;\n  const alreadyStated =\n    typeof body?.retry_after === 'number' ||\n    (typeof data === 'object' && data !== null && 'retryAfter' in data);\n  if (alreadyStated) return body;\n  const seconds = Number.parseInt(response.headers.get('Retry-After') ?? '', 10);\n  if (Number.isNaN(seconds) || seconds <= 0) return body;\n  return { ...body, retry_after: seconds };\n}\n\n/**\n * Request interceptor. Runs before every HTTP request.\n * Can modify headers, body, or reject the request.\n */\nexport type RequestInterceptor = (request: {\n  headers: Record<string, string>;\n  method: string;\n  path: string;\n}) => void | Promise<void>;\n\nexport class HttpClient {\n  protected readonly apiKey: string;\n  protected readonly options?: HttpClientOptions;\n\n  tokenManager: TokenManager | null = null;\n\n  /**\n   * Admin JWT used for platform admin endpoints (/admin/*).\n   * When set, takes precedence over tokenManager access token in the\n   * Authorization header.\n   */\n  adminToken: string | null = null;\n\n  private readonly interceptors: RequestInterceptor[] = [];\n  private readonly forbiddenListeners = new Set<(body: Record<string, unknown>) => void>();\n  private sealedKeys?: SealedKeyStore;\n\n  constructor(apiKey: string, options?: HttpClientOptions) {\n    this.apiKey = apiKey;\n    this.options = options;\n  }\n\n  /** Set (or clear) the admin JWT used on admin endpoints. */\n  setAdminToken(token: string | null): void {\n    this.adminToken = token;\n  }\n\n  /**\n   * Called with the RAW body of every 403 this client receives (FR-010). Core\n   * does not know the envelope's fields — the layer that does (palbe) reads\n   * `required` out of it. Nothing is retried or swallowed: the error still\n   * returns to the caller.\n   */\n  onForbidden(handler: (body: Record<string, unknown>) => void): () => void {\n    this.forbiddenListeners.add(handler);\n    return () => {\n      this.forbiddenListeners.delete(handler);\n    };\n  }\n\n  /**\n   * Create a scoped HttpClient that adds the given extra headers to every\n   * request. The returned client shares the admin token and token manager\n   * with the parent at runtime — later changes on the parent propagate to\n   * the scope and vice versa.\n   *\n   * Typical use: adding an Environment-routing header for an admin call.\n   */\n  withHeaders(extra: Record<string, string>): HttpClient {\n    const mergedHeaders = { ...(this.options?.headers ?? {}), ...extra };\n\n    const scoped: HttpClient = new HttpClient(this.apiKey, {\n      ...this.options,\n      headers: mergedHeaders,\n    });\n    scoped.tokenManager = this.tokenManager;\n    // Delegate adminToken reads + writes to the parent so the scope always\n    // sees the latest token, and setAdminToken on the scope affects the parent.\n    // The scope shares the parent's 403 listeners: a refusal is a refusal\n    // whichever header set the request carried.\n    Object.defineProperty(scoped, 'forbiddenListeners', {\n      get: () => this.forbiddenListeners,\n    });\n    Object.defineProperty(scoped, 'adminToken', {\n      get: () => this.adminToken,\n      set: (v: string | null) => {\n        this.adminToken = v;\n      },\n      configurable: true,\n    });\n    Object.defineProperty(scoped, 'sealedKeys', {\n      get: () => this.sealedKeys,\n      set: (v: SealedKeyStore | undefined) => {\n        this.sealedKeys = v;\n      },\n    });\n    return scoped;\n  }\n\n  /** Add a request interceptor. Runs before every request. */\n  addInterceptor(interceptor: RequestInterceptor): void {\n    this.interceptors.push(interceptor);\n  }\n\n  async request<T>(\n    method: string,\n    path: string,\n    options?: RequestOptions,\n  ): Promise<PalbaseResponse<T>> {\n    // If token is expired and refresh is available, refresh before making the request\n    if (\n      !options?.skipSessionRefresh &&\n      this.tokenManager?.isExpired() &&\n      this.tokenManager.getRefreshToken() &&\n      this.tokenManager.refreshFunction\n    ) {\n      try {\n        await this.tokenManager.refreshSession();\n      } catch (e) {\n        const status = e instanceof PalbaseError ? e.status : 0;\n        if (status === 400 || status === 401 || status === 403) {\n          // Terminal: the refresh token is dead (revoked/expired/forbidden).\n          // Clear the session (listeners persist the sign-out) and proceed\n          // unauthenticated — the endpoint will 401 into the normal error\n          // envelope instead of bricking every subsequent call including\n          // the recovery sign-in.\n          this.tokenManager.clearSession();\n        } else {\n          throw e; // network/5xx: transient, stay loud\n        }\n      }\n    }\n\n    return this.executeWithRetry<T>(method.toUpperCase(), path, options, 0);\n  }\n\n  /**\n   * A response read as it arrives, for `text/event-stream` routes.\n   *\n   * Deliberately NOT `executeWithRetry`: a retry replays the request, and a\n   * stream the caller has already begun reading cannot be replayed — the frames\n   * it handed over would arrive a second time. A stream that fails to open fails\n   * to the caller, once, with its status.\n   *\n   * The buffered path's headers, base URL and interceptors are reused verbatim,\n   * so a streaming call is authenticated exactly like every other call; only the\n   * body handling differs. `Accept` says what the caller wants, and the status\n   * is returned beside the body because the CALLER decides what a non-2xx means\n   * (an error envelope arrives as an ordinary buffered body).\n   */\n  async requestStream(\n    method: string,\n    path: string,\n    options?: RequestOptions,\n  ): Promise<{ status: number; body: ReadableStream<Uint8Array> | null; contentType: string }> {\n    method = method.toUpperCase();\n    if (\n      !options?.skipSessionRefresh &&\n      this.tokenManager?.isExpired() &&\n      this.tokenManager.getRefreshToken() &&\n      this.tokenManager.refreshFunction\n    ) {\n      try {\n        await this.tokenManager.refreshSession();\n      } catch (e) {\n        const status = e instanceof PalbaseError ? e.status : 0;\n        if (status === 400 || status === 401 || status === 403) {\n          this.tokenManager.clearSession();\n        } else {\n          throw e;\n        }\n      }\n    }\n\n    const url = endpointUrl(this.getBaseUrl(), path);\n    const headers = { ...this.buildHeaders(options), Accept: 'text/event-stream' };\n    for (const interceptor of this.interceptors) {\n      await interceptor({ headers, method, path });\n    }\n\n    const fetchOptions: RequestInit = { method, headers, signal: options?.signal };\n    if (options?.body !== undefined) fetchOptions.body = JSON.stringify(options.body);\n    const exporter = await this.prepareSealed(url, path, fetchOptions);\n\n    const response = await openSealedResponse(await fetch(url, fetchOptions), exporter, method);\n    return {\n      status: response.status,\n      body: response.body,\n      contentType: response.headers.get('content-type') ?? '',\n    };\n  }\n\n  private async prepareSealed(\n    url: string,\n    path: string,\n    init: RequestInit,\n  ): Promise<Uint8Array<ArrayBuffer> | undefined> {\n    if (this.options?.sealed === false || !sealingRequired(path)) return undefined;\n    this.sealedKeys ??= new SealedKeyStore(this.getBaseUrl(), this.apiKey, this.options?.sealed);\n    const key = await this.sealedKeys.current(init.signal ?? undefined);\n    init.signal?.throwIfAborted();\n    try {\n      return await sealRequest(key, url, init);\n    } catch (error) {\n      init.signal?.throwIfAborted();\n      if (error instanceof PalbaseError) throw error;\n      throw new PalbaseError('sealed_request_failed', 'The request could not be encrypted.', 0);\n    }\n  }\n\n  private getBaseUrl(): string {\n    // Explicit URL always wins (local dev, staging, test rigs).\n    if (this.options?.url) {\n      return this.options.url;\n    }\n\n    // Validate the key shape up front so apex-routed callers still\n    // fail loud on a malformed key instead of hitting the gateway\n    // with bad credentials.\n    if (this.apiKey && parseEnvironmentRef(this.apiKey) === null) {\n      throw new PalbaseError(\n        'invalid_api_key',\n        'Invalid API key format. Expected pb_{environment_ref}_c{at least 20 base62 chars}. For dev/staging pass `url: \"https://api.dev.palbase.studio\"` via options.',\n        0,\n      );\n    }\n\n    return `https://${PALBASE_DEFAULT_HOST}`;\n  }\n\n  private buildHeaders(options?: RequestOptions): Record<string, string> {\n    const headers: Record<string, string> = {\n      'Content-Type': 'application/json',\n      // Client identity, the web counterpart of the iOS SDK's\n      // ClientInfo.augment(). The server reads these to resolve flag targeting\n      // conditions and to label telemetry, so an app declares nothing and calls\n      // nothing — whatever the SDK can know, it sends.\n      'X-Platform': wirePlatform(),\n    };\n    // The host app's own version is not knowable on the web (no bundle to read\n    // it from), so it is opt-in; when given it fills the same header iOS fills\n    // from CFBundleShortVersionString.\n    const appVersion = this.options?.appVersion?.trim();\n    if (appVersion) {\n      headers['X-Palbase-Client-Version'] = appVersion;\n    }\n\n    // Palbase Environment keys live in the `apikey` header — never in\n    // `Authorization` — because Kong's key-auth resolves them on that\n    // header and the gateway's pre-function plugin stamps the downstream\n    // identity.\n    const effectiveKey = this.apiKey;\n    if (effectiveKey) {\n      headers['apikey'] = effectiveKey;\n    }\n\n    // User session token, if any. Kong's pre-function plugin strips\n    // Authorization on /v1/* routes anyway (PostgREST has no JWT\n    // secret and would crash on a Bearer it can't decode), but\n    // sending it preserves the contract for /auth/* endpoints that\n    // do consume the bearer (e.g. session refresh).\n    const token = this.tokenManager?.getAccessToken();\n    if (token) {\n      headers['Authorization'] = `Bearer ${token}`;\n    }\n\n    // adminToken (platform admin JWT) takes precedence — used by the\n    // @palbase/admin internal flows that hit /admin/* routes; those\n    // routes verify the bearer themselves and aren't subject to the\n    // /v1/* Authorization-strip rule.\n    if (this.adminToken) {\n      headers['Authorization'] = `Bearer ${this.adminToken}`;\n    }\n\n    // Merge global custom headers\n    if (this.options?.headers) {\n      Object.assign(headers, this.options.headers);\n    }\n\n    // Merge per-request headers\n    if (options?.headers) {\n      Object.assign(headers, options.headers);\n    }\n\n    return headers;\n  }\n\n  private async executeWithRetry<T>(\n    method: string,\n    path: string,\n    options: RequestOptions | undefined,\n    attempt: number,\n    // Headers a PREVIOUS attempt earned and this one has to carry. Today that\n    // is only the solved proof-of-work pair; it is a parameter rather than a\n    // field because it belongs to one request's second try, and a field would\n    // leak it onto every later call made through this client.\n    earned?: Record<string, string>,\n    rotated = false,\n  ): Promise<PalbaseResponse<T>> {\n    const url = endpointUrl(this.getBaseUrl(), path);\n    const headers = { ...this.buildHeaders(options), ...earned };\n\n    // Run interceptors\n    for (const interceptor of this.interceptors) {\n      await interceptor({ headers, method, path });\n    }\n\n    const fetchOptions: RequestInit = {\n      method,\n      headers,\n      signal: options?.signal,\n    };\n\n    if (options?.body !== undefined) {\n      fetchOptions.body = JSON.stringify(options.body);\n    }\n    // A fresh HPKE encapsulation on EVERY attempt: reusing an envelope trips\n    // the server replay guard, even when the first response was lost.\n    const exporter = await this.prepareSealed(url, path, fetchOptions);\n\n    let response: Response;\n    try {\n      response = await fetch(url, fetchOptions);\n    } catch (error) {\n      options?.signal?.throwIfAborted();\n      // Network error — retry with backoff\n      if (options?.retry !== false && attempt < MAX_RETRIES - 1) {\n        const backoff = INITIAL_BACKOFF_MS * 2 ** attempt;\n        await this.delay(backoff);\n        // WITHOUT `earned`, and that is the whole point of this line.\n        //\n        // A network error means the response was lost, not that the request\n        // was. If it reached the server, the challenge is already SPENT —\n        // palauth's VerifyChallenge reads and deletes in one step\n        // (bot/pow.go:96-104), deliberately, because a proof presented twice is\n        // not proof. Replaying the nonce would then answer `pow_invalid`, and\n        // the one-solve guard below would refuse to try again: a request one\n        // fresh solve away from succeeding, failed. Dropping it costs nothing\n        // in the other case — if the server never saw the request, a fresh\n        // challenge works exactly as well as the old one.\n        return this.executeWithRetry<T>(method, path, options, attempt + 1, undefined, rotated);\n      }\n\n      // All retries exhausted — throw PalbaseError\n      throw new PalbaseError(\n        'network_error',\n        error instanceof Error ? error.message : 'Network request failed',\n        0,\n      );\n    }\n    response = await openSealedResponse(response, exporter, method);\n\n    // Handle 429 Too Many Requests — retry with Retry-After or backoff;\n    // if retries exhausted, fall through to normal error response handling below\n    if (response.status === 429) {\n      if (options?.retry !== false && attempt < MAX_RETRIES - 1) {\n        const retryAfter = response.headers.get('Retry-After');\n        const parsed = retryAfter ? Number.parseInt(retryAfter, 10) : Number.NaN;\n        // Clamp the server-requested wait: a long Retry-After (locked account)\n        // must not hang the request — cap each sleep, exhaust MAX_RETRIES, then\n        // fall through to surface the 429 envelope below.\n        const delayMs = Number.isNaN(parsed)\n          ? INITIAL_BACKOFF_MS * 2 ** attempt\n          : Math.min(parsed * 1000, MAX_RETRY_DELAY_MS);\n        await this.delay(delayMs);\n        // WITH `earned`, unlike the network path above: a 429 is a refusal the\n        // server issued INSTEAD of doing the work, so the challenge was never\n        // consumed. The edge's rate limiter answers before palsvc, and on the\n        // auth routes palauth's own limiter runs BEFORE the proof-of-work\n        // middleware (auth/internal/server/server.go: rl.LoginByIP, then powMW).\n        return this.executeWithRetry<T>(method, path, options, attempt + 1, earned, rotated);\n      }\n    }\n\n    // Parse response body\n    let data: T | null = null;\n    let errorBody:\n      | {\n          error?: string;\n          error_description?: string;\n          status?: number;\n          required?: string;\n          retry_after?: number;\n        }\n      | undefined;\n\n    // HEAD responses have no body by spec — skip parsing.\n    const contentType = response.headers.get('Content-Type');\n    if (\n      method !== 'HEAD' &&\n      ![204, 205, 304].includes(response.status) &&\n      contentType?.includes('json')\n    ) {\n      if (response.ok) {\n        data = (await response.json()) as T;\n      } else {\n        // A REFUSAL WHOSE BODY DID NOT ARRIVE WHOLE IS STILL A REFUSAL.\n        //\n        // This path became REACHABLE with the edge's named envelope: before it,\n        // a held-request refusal was `text/plain` and was never parsed, so a\n        // truncated body could not surface. Now the edge answers 503 with\n        // `application/json`, and a body cut short mid-flight would throw a\n        // bare `SyntaxError` straight out of this client — no `PalbaseError`,\n        // no status, nothing the application can read. That is exactly the\n        // failure this whole change exists to remove, re-entering through the\n        // door it opened.\n        //\n        // The refusal keeps its status and surfaces as `unknown_error` below;\n        // an unreadable body costs the NAME, not the answer.\n        //\n        // Only on the error path: a SUCCESS body that cannot be parsed is a\n        // real failure and must keep throwing — swallowing it would hand the\n        // caller `{ data: null, error: null }`, which is a silent lie.\n        errorBody = (await response.json().catch(() => undefined)) as typeof errorBody;\n      }\n    }\n\n    // A HELD REQUEST IS NOT AN ERROR — the edge is starting a sleeping project.\n    //\n    // This sits AFTER the body parse, and not beside the 429 check above, on\n    // purpose: the name and the hint live in the BODY, and the body does not\n    // exist yet where the 429 block runs.\n    if (options?.retry !== false && attempt < MAX_RETRIES - 1) {\n      const heldWait = heldRefusalWait(response.status, errorBody);\n      if (heldWait !== null) {\n        await this.delay(heldWait);\n        // WITH `earned`, like the 429 path: the edge refused INSTEAD of doing\n        // the work, so the challenge was never consumed.\n        return this.executeWithRetry<T>(method, path, options, attempt + 1, earned, rotated);\n      }\n    }\n\n    if (\n      exporter &&\n      !rotated &&\n      response.status === 400 &&\n      errorBody?.error === 'sealed_unknown_kid'\n    ) {\n      await this.sealedKeys?.current(options?.signal, true);\n      return this.executeWithRetry<T>(method, path, options, attempt, earned, true);\n    }\n\n    // Proof-of-work: /auth/signup and /auth/token sit behind a bot gate that\n    // answers an unsolved request with 403 and the challenge in the body. Solve\n    // it and repeat the request carrying the two headers; the caller never\n    // learns the gate is there.\n    //\n    // HERE, in core, because this is the layer that issues the request for every\n    // client in the repo — @palbase/auth's sign-in, @palbase/web's facades, the\n    // server SDK. The same retry lived one layer up in @palbase/web until\n    // 2026-08-18 and covered everything EXCEPT `pb.auth.*`, which reaches the\n    // network through this method; so the gate stayed unsatisfiable on exactly\n    // the two endpoints it guards.\n    //\n    // ONE retry, and only when the body really carries a challenge: `earned`\n    // being set already means this IS the second try. A 403 that says\n    // pow_required without a challenge is a server the client cannot satisfy,\n    // and looping on it would turn a broken gate into a hang.\n    if (response.status === 403 && !earned) {\n      const challenge = asPowChallenge(errorBody);\n      if (challenge) {\n        return this.executeWithRetry<T>(\n          method,\n          path,\n          options,\n          attempt,\n          await solvePowChallenge(challenge, undefined, options?.signal),\n          rotated,\n        );\n      }\n    }\n\n    if (!response.ok) {\n      if (response.status === 403 && errorBody !== undefined) {\n        const body: Record<string, unknown> = errorBody;\n        for (const listener of this.forbiddenListeners) {\n          try {\n            listener(body);\n          } catch {\n            // A consumer's handler must not turn a well-formed refusal into a\n            // thrown error, nor stop the listeners after it (same rule as\n            // internal.ts' configured listeners).\n          }\n        }\n      }\n      return {\n        data: null,\n        error: new PalbaseError(\n          errorBody?.error ?? 'unknown_error',\n          errorBody?.error_description ?? response.statusText,\n          response.status,\n          withRetryHint(errorBody, response),\n        ),\n        status: response.status,\n      };\n    }\n\n    // Parse PostgREST Content-Range for count queries (e.g. \"0-9/42\" or \"*/42\").\n    const contentRange = response.headers.get('Content-Range');\n    let count: number | undefined;\n    if (contentRange) {\n      const slash = contentRange.lastIndexOf('/');\n      if (slash >= 0) {\n        const totalPart = contentRange.slice(slash + 1);\n        if (totalPart !== '*') {\n          const parsed = Number.parseInt(totalPart, 10);\n          if (!Number.isNaN(parsed)) {\n            count = parsed;\n          }\n        }\n      }\n    }\n\n    // Header names are case-insensitive and `Headers.get` already honours that;\n    // the wire spells this one lowercase.\n    const etag = response.headers.get('etag');\n\n    return {\n      data,\n      error: null,\n      status: response.status,\n      ...(count !== undefined ? { count } : {}),\n      ...(etag ? { etag } : {}),\n    };\n  }\n\n  private delay(ms: number): Promise<void> {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n  }\n}\n","import type { AuthStateCallback, Session, Unsubscribe } from './types.js';\n\nexport class TokenManager {\n  private session: Session | null = null;\n  private listeners: Set<AuthStateCallback> = new Set();\n  private refreshPromise: Promise<void> | null = null;\n  private refreshing = false;\n\n  refreshFunction: ((refreshToken: string) => Promise<Session>) | null = null;\n\n  setSession(session: Session): void {\n    this.session = session;\n    this.notify('SESSION_SET', session);\n  }\n\n  getAccessToken(): string | null {\n    return this.session?.accessToken ?? null;\n  }\n\n  getRefreshToken(): string | null {\n    return this.session?.refreshToken ?? null;\n  }\n\n  clearSession(): void {\n    this.session = null;\n    this.notify('SESSION_CLEARED', null);\n  }\n\n  isExpired(): boolean {\n    if (!this.session) return true;\n    return Date.now() >= this.session.expiresAt;\n  }\n\n  async refreshSession(): Promise<void> {\n    if (!this.session?.refreshToken || !this.refreshFunction) {\n      return;\n    }\n\n    // Collapse concurrent refresh calls into a single request\n    if (this.refreshPromise) {\n      return this.refreshPromise;\n    }\n\n    // Re-entrancy guard: the wired refreshFunction issues its own HTTP request\n    // (POST /auth/token/refresh) through HttpClient, whose pre-flight calls\n    // refreshSession() again SYNCHRONOUSLY — before `refreshPromise` below is\n    // assigned (the whole chain runs before the first real await). Without\n    // this flag that recursion is unbounded (stack overflow). Returning early\n    // lets the refresh request itself proceed unauthenticated — it carries\n    // the refresh token in its body, not the Bearer header.\n    if (this.refreshing) {\n      return;\n    }\n\n    this.refreshing = true;\n    this.refreshPromise = this.executeRefresh(this.session.refreshToken);\n\n    try {\n      await this.refreshPromise;\n    } finally {\n      this.refreshPromise = null;\n      this.refreshing = false;\n    }\n  }\n\n  onAuthStateChange(callback: AuthStateCallback): Unsubscribe {\n    this.listeners.add(callback);\n    return () => {\n      this.listeners.delete(callback);\n    };\n  }\n\n  private async executeRefresh(refreshToken: string): Promise<void> {\n    if (!this.refreshFunction) return;\n    const startedSession = this.session;\n    try {\n      const newSession = await this.refreshFunction(refreshToken);\n      // Sign-out, a new sign-in, or another session adoption takes precedence\n      // over a refresh that started against an older session.\n      if (this.session === startedSession) this.setSession(newSession);\n    } catch (error) {\n      // The caller would clear its session on a terminal refresh error. An\n      // error from an older session must not clear a newer one.\n      if (this.session === startedSession) throw error;\n    }\n  }\n\n  private notify(event: 'SESSION_SET' | 'SESSION_CLEARED', session: Session | null): void {\n    for (const listener of this.listeners) {\n      listener(event, session);\n    }\n  }\n}\n","import { PalbaseError, type PalbaseResponse } from '@palbase/core';\n\nexport interface FieldError {\n  field: string;\n  message: string;\n}\n\nexport type BackendErrorKind =\n  | 'notConfigured'\n  | 'validation'\n  | 'unauthorized'\n  | 'rateLimited'\n  | 'server'\n  | 'network'\n  | 'decode';\n\ninterface BackendErrorParams {\n  code: string;\n  message: string;\n  status?: number;\n  requestId?: string;\n  fields?: FieldError[];\n  retryAfter?: number;\n  data?: unknown;\n}\n\nexport class BackendError extends Error {\n  readonly kind: BackendErrorKind;\n  readonly code: string;\n  readonly status: number;\n  readonly requestId?: string;\n  readonly fields?: FieldError[];\n  readonly retryAfter?: number;\n  readonly data?: unknown;\n\n  constructor(kind: BackendErrorKind, params: BackendErrorParams) {\n    super(params.message);\n    this.name = 'BackendError';\n    this.kind = kind;\n    this.code = params.code;\n    this.status = params.status ?? 0;\n    this.requestId = params.requestId;\n    this.fields = params.fields;\n    this.retryAfter = params.retryAfter;\n    this.data = params.data;\n  }\n\n  static notConfigured(): BackendError {\n    return new BackendError('notConfigured', {\n      code: 'not_configured',\n      message:\n        \"Palbe is not configured. Run 'palbase web link' in your project and make sure palbe.gen.ts is imported once at app startup.\",\n    });\n  }\n}\n\nfunction isFieldErrorArray(value: unknown): value is FieldError[] {\n  return (\n    Array.isArray(value) &&\n    value.length > 0 &&\n    value.every(\n      (v) =>\n        typeof v === 'object' &&\n        v !== null &&\n        typeof (v as Record<string, unknown>).field === 'string' &&\n        typeof (v as Record<string, unknown>).message === 'string',\n    )\n  );\n}\n\n/**\n * Find the field-error array in a wire envelope.\n *\n * `data.fields` IS THE CONTRACT: the backend SDK declares\n * `bad_request: { fields: [{ field, message }] }` in its error registry, so\n * codegen types it as `error.data.fields`, `throw new BadRequest({ fields })`\n * answers in that shape, and — since 22.1.0 — so do the engine's own automatic\n * `@Body`/`@QueryParams`/`@Headers` refusals.\n *\n * The top-level `fields` is the SAME array as emitted by backend 22.0.x and\n * earlier, which is still what every tenant deployed before that release\n * answers. A browser gets the SDK long before its tenant redeploys, so this\n * reader covers both until the fleet has rolled; drop it once it has.\n *\n * A nested `details: [{ field, message }]` was read here until 8.0.0 and is NOT\n * read any more: no Palbase surface has ever emitted it. Believing in it is why\n * `kind: 'validation'` was unreachable for every real 400 the platform sends.\n */\nfunction fieldErrorsOf(envelope: unknown): FieldError[] | undefined {\n  const scoped = pickField(pickField(envelope, 'data'), 'fields');\n  if (isFieldErrorArray(scoped)) return scoped;\n  const flat = pickField(envelope, 'fields');\n  return isFieldErrorArray(flat) ? flat : undefined;\n}\n\n/**\n * Find the rate-limit hint in a wire envelope.\n *\n * Two producers, both real and both measured. palauth answers a lockout with a\n * top-level `retry_after` (`auth/internal/ratelimit/limiter.go`). Everything\n * built on the backend SDK — the engine's per-route limiter, and\n * `throw new TooManyRequests({ retryAfter })` — answers with `data.retryAfter`,\n * the name its error registry publishes and codegen types.\n */\nfunction retryAfterOf(envelope: unknown): number | undefined {\n  return (\n    pickNumber(envelope, 'retry_after') ?? pickNumber(pickField(envelope, 'data'), 'retryAfter')\n  );\n}\n\nfunction pickField(value: unknown, key: string): unknown {\n  if (typeof value === 'object' && value !== null) {\n    return (value as Record<string, unknown>)[key];\n  }\n  return undefined;\n}\n\nfunction pickNumber(value: unknown, key: string): number | undefined {\n  const n = pickField(value, key);\n  return typeof n === 'number' ? n : undefined;\n}\n\nfunction pickString(value: unknown, key: string): string | undefined {\n  const s = pickField(value, key);\n  return typeof s === 'string' ? s : undefined;\n}\n\nexport function fromPalbaseError(err: PalbaseError): BackendError {\n  // HttpClient stores the WHOLE wire envelope as err.details:\n  // { error, error_description, status, request_id, retry_after?, data? }\n  const base: BackendErrorParams = {\n    code: err.code,\n    message: err.message,\n    status: err.status,\n    requestId: pickString(err.details, 'request_id'),\n    data: pickField(err.details, 'data'),\n  };\n  if (err.code === 'network_error') return new BackendError('network', base);\n  if (err.status === 401) return new BackendError('unauthorized', base);\n  if (err.status === 429)\n    return new BackendError('rateLimited', { ...base, retryAfter: retryAfterOf(err.details) });\n  const fields = fieldErrorsOf(err.details);\n  if (err.status === 400 && fields) return new BackendError('validation', { ...base, fields });\n  // Fallthrough also covers status-0 non-network errors (e.g. auth client's\n  // synthetic 'no_refresh_token' with status 0) — those intentionally map to 'server'.\n  return new BackendError('server', base);\n}\n\n/** Decode a raw wire body (used by paths that bypass HttpClient, e.g. upload). */\nexport function fromEnvelope(status: number, body: unknown): BackendError {\n  const code = pickString(body, 'error') ?? 'http_error';\n  const message = pickString(body, 'error_description') ?? `HTTP ${status}`;\n  const requestId = pickString(body, 'request_id');\n  const params: BackendErrorParams = {\n    code,\n    message,\n    status,\n    requestId,\n    data: pickField(body, 'data'),\n  };\n  if (status === 401) return new BackendError('unauthorized', params);\n  if (status === 429)\n    return new BackendError('rateLimited', { ...params, retryAfter: retryAfterOf(body) });\n  const fields = fieldErrorsOf(body);\n  if (status === 400 && fields) return new BackendError('validation', { ...params, fields });\n  return new BackendError('server', params);\n}\n\n/**\n * Type guard for BackendError that survives module-identity splits.\n * This package ships dual ESM + CJS builds; if both end up loaded (or the\n * package is installed twice), two distinct BackendError classes coexist and\n * `instanceof` fails for errors thrown by \"the other\" copy. Falls back to a\n * structural check on `name` + `kind`.\n */\nexport function isBackendError(e: unknown): e is BackendError {\n  return (\n    e instanceof BackendError ||\n    (typeof e === 'object' &&\n      e !== null &&\n      (e as Record<string, unknown>).name === 'BackendError' &&\n      typeof (e as Record<string, unknown>).kind === 'string')\n  );\n}\n\n/**\n * Structural fallback after instanceof for PalbaseError — same dual ESM+CJS\n * identity-split rationale as isBackendError above: two loaded PalbaseError\n * classes break `instanceof` across copies; the name check bridges that.\n * Returns the error as PalbaseError, or null when it isn't one.\n */\nexport function asPalbaseError(e: unknown): PalbaseError | null {\n  if (e instanceof PalbaseError) return e;\n  if (e instanceof Error && e.name === 'PalbaseError') return e as PalbaseError;\n  return null;\n}\n\n/** Convert an internal {data,error} envelope into data-or-throw. */\nexport function unwrap<T>(res: PalbaseResponse<T>): T {\n  if (res.error) throw fromPalbaseError(res.error);\n  return res.data as T;\n}\n","const ID_SEGMENT =\n  /^(?:\\d+|[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$/;\n\n// An email lands in a path segment as `jane@acme.com` or percent-encoded\n// `jane%40acme.com`. Either form is PII and must never survive into a metric\n// name, so a segment carrying an `@` (encoded or raw) is masked like an id.\nconst EMAIL_SEGMENT = /(?:@|%40)/i;\n\nfunction isSensitiveSegment(seg: string): boolean {\n  return ID_SEGMENT.test(seg) || EMAIL_SEGMENT.test(seg);\n}\n\n/**\n * Capture-time URL redaction (§4.1 privacy, client half). Collapses a request\n * URL to a PII-free, low-cardinality path pattern BEFORE it leaves the browser:\n * query string dropped wholesale, id-like segments masked. The ingest scrubber\n * re-applies server-side (defense in depth).\n *\n * Rules:\n *  - absolute URL → keep only `pathname` (scheme/host/query/hash dropped);\n *  - relative URL → drop everything from the first `?` onward;\n *  - any segment that is purely numeric, a UUID, or carries an email (`@` /\n *    `%40`) → `:id`;\n *  - credentials/tokens live in the query (dropped wholesale), emails in a\n *    path segment (masked), so neither survives into the metric name.\n */\nexport function redactUrl(rawUrl: string): string {\n  let path = rawUrl;\n  try {\n    // Absolute URLs: take the pathname (drops scheme/host/query/hash).\n    path = new URL(rawUrl).pathname;\n  } catch {\n    const q = path.indexOf('?');\n    if (q >= 0) path = path.slice(0, q);\n  }\n  return path\n    .split('/')\n    .map((seg) => (isSensitiveSegment(seg) ? ':id' : seg))\n    .join('/');\n}\n","import { BackendError } from './errors.js';\n\n/**\n * The web half of streaming responses.\n *\n * The rule the parser exists to keep: a frame ends at a BLANK line, never at a\n * chunk boundary. Nothing about how the bytes were split on the way here may\n * change what the caller sees — a `data:` line arriving in three pieces is one\n * frame, and two frames arriving in one piece are two.\n */\n\nexport interface SseFrame {\n  /** `undefined` for a plain `data:` frame; `\"error\"` for the terminal one. */\n  event?: string;\n  payload: string;\n}\n\n/** Incremental SSE parser. Feed it decoded text; it answers with completed frames. */\nexport class SseParser {\n  private pending = '';\n  private dataLines: string[] = [];\n  private eventName: string | undefined;\n\n  consume(chunk: string): SseFrame[] {\n    // CRLF is normalised on the way IN. A server that writes \\r\\n would\n    // otherwise leave a stray \\r on every field value, and `JSON.parse` of\n    // `{\"n\":1}\\r` throws — a decode failure invented by the transport.\n    this.pending += chunk.replace(/\\r\\n/g, '\\n');\n    const out: SseFrame[] = [];\n    let nl = this.pending.indexOf('\\n');\n    while (nl !== -1) {\n      const line = this.pending.slice(0, nl);\n      this.pending = this.pending.slice(nl + 1);\n      const trimmed = line.endsWith('\\r') ? line.slice(0, -1) : line;\n\n      if (trimmed === '') {\n        // A blank line with nothing accumulated is a keep-alive separator or the\n        // gap after a comment — emitting nothing for it is correct.\n        if (this.dataLines.length > 0) {\n          out.push({ event: this.eventName, payload: this.dataLines.join('\\n') });\n        }\n        this.dataLines = [];\n        this.eventName = undefined;\n      } else if (trimmed.startsWith(':')) {\n        // A comment — the conventional keep-alive. Ignored, not surfaced.\n      } else if (trimmed.startsWith('data:')) {\n        const v = trimmed.slice(5);\n        this.dataLines.push(v.startsWith(' ') ? v.slice(1) : v);\n      } else if (trimmed.startsWith('event:')) {\n        const v = trimmed.slice(6);\n        this.eventName = v.startsWith(' ') ? v.slice(1) : v;\n      }\n      // Unknown fields (id:, retry:) are ignored rather than refused: a reader\n      // that rejects a field it does not know breaks when the server adds one.\n      nl = this.pending.indexOf('\\n');\n    }\n    return out;\n  }\n}\n\n/**\n * Turn a byte stream into the decoded frames a generated client hands its caller.\n *\n * `controller` is aborted when the caller stops iterating — `for await`'s early\n * exit calls `return()` on the iterator, which reaches the `finally` below. That\n * is the whole cancellation story on the web, and it is what stops the server's\n * producer being pulled.\n */\nexport async function* sseIterable(\n  body: ReadableStream<Uint8Array>,\n  controller: AbortController,\n): AsyncGenerator<unknown, void, undefined> {\n  const reader = body.getReader();\n  const decoder = new TextDecoder();\n  const parser = new SseParser();\n  try {\n    for (;;) {\n      const { done, value } = await reader.read();\n      if (done) break;\n      for (const frame of parser.consume(decoder.decode(value, { stream: true }))) {\n        if (frame.event === 'error') {\n          // After the first frame the status line is already spent, so this is\n          // how a failure reaches the caller: as a throw out of their loop.\n          throw new BackendError('network', {\n            code: 'stream_failed',\n            message: `stream failed: ${frame.payload}`,\n          });\n        }\n        let decoded: unknown;\n        try {\n          decoded = JSON.parse(frame.payload);\n        } catch {\n          // A frame that will not decode ends the stream rather than being\n          // skipped: a silently dropped frame is a hole in the middle of the\n          // caller's data, and holes are worse than failures.\n          throw new BackendError('decode', {\n            code: 'invalid_frame',\n            message: `stream frame is not valid JSON: ${frame.payload.slice(0, 120)}`,\n          });\n        }\n        yield decoded;\n      }\n    }\n  } finally {\n    controller.abort();\n    try {\n      await reader.cancel();\n    } catch {\n      // The reader may already be closed — that is a normal ending, not a fault.\n    }\n  }\n}\n","import { asPowChallenge, solvePowChallenge } from '@palbase/core';\nimport {\n  asPalbaseError,\n  BackendError,\n  fromEnvelope,\n  fromPalbaseError,\n  isBackendError,\n  unwrap,\n} from './errors.js';\nimport { redactUrl } from './perf/url-redactor.js';\nimport type { PalbeRuntime } from './runtime.js';\nimport { sseIterable } from './sse.js';\n\nexport interface RequestSpec {\n  body?: unknown;\n  headers?: Record<string, string>;\n  signal?: AbortSignal;\n}\n\nexport interface CallOptions {\n  headers?: Record<string, string>;\n  signal?: AbortSignal;\n}\n\nconst MUTATING = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);\n\n// The perf flush (`POST /v1/analytics/perf`) and analytics event ingest\n// (`/v1/analytics/*`) BOTH funnel through `palbeRequest`. Tracing them would\n// make every flush emit another `network` item that the next flush ships,\n// then traces again — a self-measurement loop. Excluding the whole\n// `/v1/analytics/` prefix breaks it. This is the SAME self-exclusion shape as\n// the iOS network trace (1b-3), keyed on the identical ingest prefix.\nconst PERF_EXCLUDED_PREFIX = '/v1/analytics/';\n\nfunction isSelfTraced(path: string): boolean {\n  return path.startsWith(PERF_EXCLUDED_PREFIX);\n}\n\n/**\n * Codes meaning the server-side session is GONE — a token refresh cannot help\n * and the client must tear its local session down. `subject_fenced` is palauth's\n * wire-true erasure-fence code (`bridge.go`); `subject_erased` is accepted for\n * forward-compat. `session_revoked` is palauth's revoked-session 401.\n * A PLAIN 403 (ordinary authz / RLS denial) is intentionally NOT here — matching\n * all 403s would sign users out on routine permission errors.\n */\nfunction isSessionKilled(status: number, code: string): boolean {\n  if (status === 401) return code === 'session_revoked';\n  if (status === 403) return code === 'subject_fenced' || code === 'subject_erased';\n  return false;\n}\n\n/** Monotonic millisecond clock — `performance.now()` when present, else\n * `Date.now()`. Mirrors `perf-facade.ts`'s `nowMs()` so network durations and\n * custom-trace durations share one time base. */\nfunction nowMs(): number {\n  return typeof performance !== 'undefined' && typeof performance.now === 'function'\n    ? performance.now()\n    : Date.now();\n}\n\n/** An `AbortError` (caller-cancelled request) is NOT a completed network call,\n * so it must never produce a trace. */\nfunction isAbort(e: unknown): boolean {\n  return e instanceof Error && e.name === 'AbortError';\n}\n\n/**\n * `palbeRequest`'s streaming sibling: opens the response and hands back the\n * frames as an async iterable.\n *\n * No retry and no reactive-401 refresh loop here, on purpose. Both replay the\n * request, and a stream the caller has begun reading cannot be replayed — the\n * frames it already yielded would arrive twice. A stream that fails to OPEN\n * fails to the caller once, with the status the server gave.\n *\n * An `AbortController` is chained to the caller's signal so that leaving the\n * loop aborts the request: that is what stops the server's producer being\n * pulled, and it is the half that decides the customer's bill.\n */\nexport async function palbeStream(\n  rt: PalbeRuntime,\n  method: string,\n  path: string,\n  spec: RequestSpec = {},\n): Promise<AsyncIterable<unknown>> {\n  const controller = new AbortController();\n  if (spec.signal) {\n    if (spec.signal.aborted) controller.abort();\n    else spec.signal.addEventListener('abort', () => controller.abort(), { once: true });\n  }\n\n  const headers: Record<string, string> = { ...spec.headers };\n  const callerHasKey = Object.keys(headers).some((k) => k.toLowerCase() === 'idempotency-key');\n  if (MUTATING.has(method) && !callerHasKey) {\n    headers['Idempotency-Key'] = crypto.randomUUID();\n  }\n\n  const open = async (extra?: Record<string, string>) =>\n    rt.http.requestStream(method, path, {\n      body: spec.body,\n      headers: extra ? { ...headers, ...extra } : headers,\n      signal: controller.signal,\n    });\n\n  let opened: Awaited<ReturnType<typeof rt.http.requestStream>>;\n  try {\n    opened = await open();\n\n    // The abuse gate answers the same way here as anywhere else, and a stream\n    // that has not yielded a frame yet can be retried safely — nothing was\n    // handed to the caller. ONE solve, exactly as the buffered path: a 403 that\n    // says `pow_required` without a challenge is a gate the client cannot\n    // satisfy, and looping would turn it into a hang.\n    // Reactive 401, on the same terms as the buffered path. A route that a\n    // customer converts to `@Sse` must not silently lose session recovery: the\n    // failure would look like \"streaming is flaky\" and be blamed on streaming.\n    if (\n      opened.status === 401 &&\n      rt.tokenManager.getRefreshToken() &&\n      rt.tokenManager.refreshFunction\n    ) {\n      const text = opened.body ? await new Response(opened.body).text() : '';\n      let envelope: unknown;\n      try {\n        envelope = JSON.parse(text);\n      } catch {\n        envelope = undefined;\n      }\n      // A revoked session is terminal — a refresh cannot resurrect it.\n      const code = (envelope as { error?: string } | undefined)?.error;\n      if (code === 'session_revoked') throw fromEnvelope(401, envelope);\n      try {\n        await rt.tokenManager.refreshSession();\n      } catch (refreshErr) {\n        const pe = asPalbaseError(refreshErr);\n        const status = pe?.status ?? 0;\n        if (status === 400 || status === 401 || status === 403) {\n          // The refresh token is dead: sign out and surface the ORIGINAL 401.\n          rt.tokenManager.clearSession();\n          throw fromEnvelope(401, envelope);\n        }\n        throw pe ? fromPalbaseError(pe) : refreshErr;\n      }\n      opened = await open();\n    }\n\n    if (opened.status === 403) {\n      const text = opened.body ? await new Response(opened.body).text() : '';\n      let envelope: unknown;\n      try {\n        envelope = JSON.parse(text);\n      } catch {\n        envelope = undefined;\n      }\n      // `asPowChallenge` reads the WHOLE envelope (it checks `error` and\n      // `challenge` itself), so it is handed the parsed body rather than a\n      // hand-picked field — one place that knows the challenge's shape.\n      const challenge = asPowChallenge(envelope);\n      if (challenge) {\n        opened = await open(await solvePowChallenge(challenge));\n      } else {\n        // A 403 that is not a solvable challenge is an ordinary refusal.\n        throw fromEnvelope(403, envelope);\n      }\n    }\n  } catch (e) {\n    if (isBackendError(e)) throw e;\n    const pe = asPalbaseError(e);\n    throw pe ? fromPalbaseError(pe) : e;\n  }\n\n  if (opened.status < 200 || opened.status >= 300) {\n    // Before the first frame the status line is still available, so a failure\n    // here is an ORDINARY error — same shape as any other call's.\n    const text = opened.body ? await new Response(opened.body).text() : '';\n    let envelope: unknown;\n    try {\n      envelope = JSON.parse(text);\n    } catch {\n      envelope = undefined;\n    }\n\n    // The SAME mapping the buffered path uses. A streaming route that refuses\n    // must be indistinguishable, to the caller, from any other route refusing —\n    // a second status→kind table here would be a second chance to disagree.\n    throw fromEnvelope(opened.status, envelope);\n  }\n\n  if (!opened.body) {\n    throw new BackendError('network', {\n      code: 'empty_stream',\n      message: 'the server answered a streaming route with no body',\n    });\n  }\n\n  return sseIterable(opened.body, controller);\n}\n\nexport async function palbeRequest<T>(\n  rt: PalbeRuntime,\n  method: string,\n  path: string,\n  spec: RequestSpec = {},\n): Promise<T> {\n  const headers: Record<string, string> = { ...spec.headers };\n  // Case-insensitive scan: a caller-supplied `idempotency-key` must suppress\n  // generation, otherwise Headers merges both casings and dedup breaks.\n  const callerHasKey = Object.keys(headers).some((k) => k.toLowerCase() === 'idempotency-key');\n  if (MUTATING.has(method) && !callerHasKey) {\n    headers['Idempotency-Key'] = crypto.randomUUID();\n  }\n\n  // `extra` carries the proof-of-work headers on the one retry that needs them.\n  // The base `headers` are reused rather than rebuilt, so a retry keeps the same\n  // Idempotency-Key and the server still sees one logical request.\n  const attempt = async (extra?: Record<string, string>) => {\n    try {\n      return await rt.http.request<T>(method, path, {\n        body: spec.body,\n        headers: extra ? { ...headers, ...extra } : headers,\n        signal: spec.signal,\n        // A header alone does not implement server-side deduplication. A lost\n        // response can follow a successful COMMIT; replaying a write here may\n        // duplicate it. Surface overload too, so domain recovery is explicit.\n        retry: method === 'GET' || method === 'HEAD',\n      });\n    } catch (e) {\n      const pe = asPalbaseError(e);\n      throw pe ? fromPalbaseError(pe) : e;\n    }\n  };\n\n  // The single network-trace choke point: every SDK fetch funnels through\n  // `palbeRequest`, so timing it here records one `network` PerfItem per call —\n  // redacted URL + method + final HTTP status + wall-clock duration. The\n  // `/v1/analytics/` ingest paths are self-excluded (no recursion) and aborts\n  // are skipped (not a completed call).\n  // `rt.perf` is guarded too: `buildRuntime` always wires it, but a hand-built\n  // runtime (tests, embedders) may omit it — a missing facade must never break\n  // the request path.\n  const traced = !isSelfTraced(path) && rt.perf !== undefined;\n  const startedAt = traced ? nowMs() : 0;\n  // Exactly ONE trace per `palbeRequest`: the inner refresh-catch records with\n  // the precise status and rethrows; that rethrow is then caught by the outer\n  // catch, so the guard keeps the second `record()` a no-op (no double-count).\n  let recorded = false;\n  const record = (status: number): void => {\n    if (!traced || recorded) return;\n    recorded = true;\n    rt.perf.recordNetwork(method, redactUrl(path), status, nowMs() - startedAt);\n  };\n\n  let res: Awaited<ReturnType<typeof attempt>>;\n  try {\n    res = await attempt();\n\n    // Reactive 401: refresh once, retry once with the same Idempotency-Key.\n    // A revoked session (401 session_revoked) is terminal — a refresh cannot\n    // resurrect it, so skip straight to the teardown check below.\n    if (\n      res.error?.status === 401 &&\n      res.error.code !== 'session_revoked' &&\n      rt.tokenManager.getRefreshToken() &&\n      rt.tokenManager.refreshFunction\n    ) {\n      try {\n        await rt.tokenManager.refreshSession();\n      } catch (refreshErr) {\n        const pe = asPalbaseError(refreshErr);\n        const status = pe?.status ?? 0;\n        if (status === 400 || status === 401 || status === 403) {\n          // Terminal: the refresh token is dead. Sign out and surface the\n          // ORIGINAL 401 (mirrors HttpClient's pre-flight terminal split).\n          rt.tokenManager.clearSession();\n          record(res.error.status);\n          throw fromPalbaseError(res.error);\n        }\n        // Transient (network/5xx): keep the session, surface the refresh failure.\n        record(pe?.status ?? 0);\n        throw pe ? fromPalbaseError(pe) : refreshErr;\n      }\n      res = await attempt();\n    }\n\n    // Reactive proof-of-work: signup and login sit behind a bot gate that\n    // answers an unsolved request with 403 and the challenge in the body. Solve\n    // it once and repeat the request with the headers; the caller never learns\n    // the gate is there.\n    //\n    // Placed after the 401 branch so it sees whichever response is current — a\n    // refresh-and-retry can land on the gate just as a first attempt can.\n    //\n    // Only ONE retry, and only when the body really carries a challenge. A 403\n    // that merely says pow_required without one is a server the client cannot\n    // satisfy, and looping on it would turn a broken gate into a hang.\n    if (res.error?.status === 403 && res.error.code === 'pow_required') {\n      const challenge = asPowChallenge(res.error.details);\n      if (challenge) {\n        res = await attempt(await solvePowChallenge(challenge));\n      }\n    }\n  } catch (e) {\n    // A thrown error here is a network/transport failure (the `{data,error}`\n    // envelope never throws). Record it as a completed-with-error call unless\n    // the caller aborted — an abort is a cancellation, not a measurement.\n    if (!isAbort(e)) record(asPalbaseError(e)?.status ?? 0);\n    throw e;\n  }\n\n  // Reactive session teardown: a server-side session kill (subject erased /\n  // session revoked) means the local session is dead regardless of which facade\n  // issued this call — tear it down + emit signedOut{sessionInvalid} once. Scoped\n  // to the exact codes so an ordinary 403 authz denial does NOT sign the user out.\n  if (res.error && isSessionKilled(res.error.status, res.error.code)) {\n    rt.auth.reactiveTeardown();\n  }\n\n  // Response resolved (2xx or an error envelope): record the real HTTP status\n  // BEFORE `unwrap` may throw, so a 4xx/5xx is measured with its true status.\n  record(res.error?.status ?? 200);\n  return unwrap(res);\n}\n","// `pb.analytics` — the stateful analytics surface. Mirrors the iOS\n// `AnalyticsClient`/`AnalyticsStorage` pair (palbackend-ios-src\n// Sources/Palbe/Analytics/): anonymous distinct-id, in-memory buffer with\n// size/timer flushing, identify/alias/reset/optOut, and auth-lifecycle\n// bindings. Transport is direct `palbeRequest` to palanalytics' live\n// ingestion wire (verified against modules/analytics Go handlers):\n//\n//   POST /v1/analytics/batch     {events:[{event,distinct_id,properties?,timestamp,sent_at}]}\n//   POST /v1/analytics/capture   single event (server mode — no buffering)\n//   POST /v1/analytics/identify  {distinct_id,anonymous_id,traits?,timestamp,sent_at}\n//   POST /v1/analytics/alias     {from,to,timestamp,sent_at}\n//\n// Ingestion is fire-and-forget (iOS K11): nothing here ever throws into the\n// caller — failures are console.warn'ed and the events dropped. The only\n// awaited surface is `flush()`, which still never rejects.\n//\n// Wire decisions (documented deviations):\n// - screen() emits the SERVER-canonical mapping (event `$screen` +\n//   `properties.screen_name` — exactly what Go's /v1/analytics/screen\n//   shorthand stores), NOT iOS's event-named-after-the-screen variant, so\n//   batched screens and shorthand screens collapse to one stored shape.\n// - `sent_at` is stamped at SEND time (flush), not enqueue time like iOS:\n//   the server's skew correction (`timestamp + (received_at - sent_at)`)\n//   assumes send time; the iOS enqueue-time stamp inflates corrected\n//   timestamps by the buffering delay.\n// - optOut gates ALL ingest calls (capture/screen/identify/alias) — iOS\n//   parity. reset() and the X-Distinct-Id header are NOT gated (also iOS\n//   parity: the header resolver never checks opt-out).\n\nimport type { AuthChangeEvent } from './auth-facade.js';\nimport { palbeRequest } from './request.js';\nimport type { PalbeRuntime } from './runtime.js';\n\n/** Free-form event property bag (JSON object on the wire). */\nexport type AnalyticsProperties = Record<string, unknown>;\n\n/** Server event-name rule — matches modules/analytics/internal/validator/event.go\n * eventNameRegex exactly: leading letter or `$`, max 64 chars total,\n * MaxEventNameLen=64 (i.e. body up to 63 chars after the leading char). */\nconst EVENT_NAME_RE = /^[a-zA-Z$][a-zA-Z0-9_.:$-]{0,63}$/;\n\nconst FLUSH_AT = 20;\nconst FLUSH_INTERVAL_MS = 10_000;\n/** Server hard cap: /v1/analytics/batch rejects > 100 events per request. */\nconst MAX_BATCH_SIZE = 100;\n\n/** A buffered capture event — distinct_id is stamped at CAPTURE time so the\n * anon id is preserved on the wire for pre-login events (the gateway's Bearer\n * override applies to the REQUEST's X-Distinct-Id header, not the event body).\n * `sent_at` is added at flush time. */\ninterface CaptureWire {\n  event: string;\n  distinct_id: string;\n  properties?: AnalyticsProperties;\n  timestamp: number;\n}\n\nlet warnedInvalidEventName = false;\n\nfunction warnInvalidEventName(name: string): void {\n  if (warnedInvalidEventName) return;\n  warnedInvalidEventName = true;\n  console.warn(\n    `palbe analytics: dropping event \"${name}\" — names must match ^[a-zA-Z$][a-zA-Z0-9_.:$-]{0,63}$ (warned once per process)`,\n  );\n}\n\n/** Minimal persisted string store: localStorage in browsers, per-runtime\n * memory elsewhere (SSR anon ids are ephemeral by design). Browser detection\n * matches the facade (`document`, not localStorage presence) — server\n * runtimes must NEVER touch storage, even when a localStorage global exists\n * (the flags server-env contract pins that). */\ninterface StringStore {\n  get(key: string): string | null;\n  set(key: string, value: string): void;\n  remove(key: string): void;\n}\n\nfunction defaultStringStore(): StringStore {\n  if (typeof document !== 'undefined' && typeof localStorage !== 'undefined') {\n    return {\n      get: (key) => {\n        try {\n          return localStorage.getItem(key);\n        } catch {\n          return null;\n        }\n      },\n      set: (key, value) => {\n        try {\n          localStorage.setItem(key, value);\n        } catch {\n          // quota/private mode — the id just won't survive a reload\n        }\n      },\n      remove: (key) => {\n        try {\n          localStorage.removeItem(key);\n        } catch {\n          // ignore\n        }\n      },\n    };\n  }\n  const mem = new Map<string, string>();\n  return {\n    get: (key) => mem.get(key) ?? null,\n    set: (key, value) => {\n      mem.set(key, value);\n    },\n    remove: (key) => {\n      mem.delete(key);\n    },\n  };\n}\n\n/**\n * Runtime-scoped analytics identity — constructed EAGERLY in `buildRuntime`\n * (cheap: listener wiring only, no I/O) because the X-Distinct-Id header\n * interceptor must stamp every request from the first one, even when\n * `pb.analytics` is never touched (iOS: the resolver is wired at\n * PalBackend init). The facade wraps this state lazily.\n *\n * Auth events: while no facade exists, the state maintains identity only\n * (user id for the header, anon rotation on user-initiated sign-out). Once\n * the facade attaches, it takes over wholesale and adds the ingest\n * side-effects (flush + identify / flush + reset).\n */\nexport class AnalyticsState {\n  identifiedUserId: string | null = null;\n  /** Set by PalbeAnalytics on construction — delegates auth events to it. */\n  facadeAuthHandler: ((event: AuthChangeEvent) => void) | null = null;\n\n  private anonId: string | null = null;\n  private readonly store = defaultStringStore();\n  private readonly idKey: string;\n  private readonly optOutKey: string;\n\n  constructor(rt: PalbeRuntime) {\n    const ref = rt.projectRef;\n    this.idKey = ref ? `palbe.analytics.id.${ref}` : 'palbe.analytics.id';\n    this.optOutKey = ref ? `palbe.analytics.optout.${ref}` : 'palbe.analytics.optout';\n    rt.auth.onAuthEvent((event) => {\n      if (this.facadeAuthHandler) {\n        this.facadeAuthHandler(event);\n        return;\n      }\n      if (event.type === 'signedIn') {\n        // Identity for the header only — no identify POST without a facade\n        // (an app that never uses pb.analytics generates no analytics\n        // traffic). Opt-out gates the link, mirroring the gated identify.\n        if (!this.isOptedOut()) this.identifiedUserId = event.user.id;\n      } else if (event.type === 'signedOut' && event.reason === 'userInitiated') {\n        this.identifiedUserId = null;\n        this.rotateAnonymousId();\n      }\n      // sessionExpired / tokenRefreshed: identity preserved (iOS K9)\n    });\n  }\n\n  /** User id when identified, else the stable anon id. NEVER empty —\n   * this is what `identify()` links, so stamping it on every request lets\n   * the trace pipeline stitch pre-login activity to the user. */\n  distinctId(): string {\n    return this.identifiedUserId ?? this.anonymousId();\n  }\n\n  anonymousId(): string {\n    if (this.anonId) return this.anonId;\n    const stored = this.store.get(this.idKey);\n    if (stored) {\n      this.anonId = stored;\n      return stored;\n    }\n    return this.rotateAnonymousId();\n  }\n\n  rotateAnonymousId(): string {\n    const fresh = crypto.randomUUID();\n    this.store.set(this.idKey, fresh);\n    this.anonId = fresh;\n    return fresh;\n  }\n\n  isOptedOut(): boolean {\n    return this.store.get(this.optOutKey) === 'true';\n  }\n\n  setOptOut(on: boolean): void {\n    if (on) this.store.set(this.optOutKey, 'true');\n    else this.store.remove(this.optOutKey);\n  }\n}\n\nexport class PalbeAnalytics {\n  private readonly buffer: CaptureWire[] = [];\n  private flushTimer: ReturnType<typeof setTimeout> | null = null;\n  /** Browser → buffer + size/timer flush. Server (no document) → immediate\n   * per-call POST, zero timers (nothing leaks into RSC/route handlers). */\n  private readonly browser = typeof document !== 'undefined';\n\n  constructor(\n    private readonly rt: PalbeRuntime,\n    private readonly state: AnalyticsState,\n  ) {\n    this.state.facadeAuthHandler = (event) => {\n      this.handleAuthEvent(event);\n    };\n  }\n\n  /** Record an event. Invalid names are dropped (one warn per process). */\n  capture(event: string, properties?: AnalyticsProperties): void {\n    if (this.state.isOptedOut()) return;\n    if (!EVENT_NAME_RE.test(event)) {\n      warnInvalidEventName(event);\n      return;\n    }\n    this.ingest(event, properties);\n  }\n\n  /** Record a screen view — server-canonical `$screen` + `screen_name`.\n   * Validates non-empty only (the live wire at /v1/analytics/screen requires\n   * non-empty screen_name; the event-name regex does NOT apply here). */\n  screen(name: string, properties?: AnalyticsProperties): void {\n    if (this.state.isOptedOut()) return;\n    if (name.trim() === '') {\n      console.warn('palbe analytics: dropping screen() — name must be non-empty');\n      return;\n    }\n    this.ingest('$screen', { ...properties, screen_name: name });\n  }\n\n  /** Link the current anon id to `userId` and adopt it as the distinct id.\n   * Immediate POST (not buffered). Re-identifying a DIFFERENT user\n   * auto-resets first (iOS K10) so one anon id never links two users. */\n  identify(userId: string, traits?: AnalyticsProperties): void {\n    if (this.state.isOptedOut()) return;\n    const existing = this.state.identifiedUserId;\n    if (existing && existing !== userId) {\n      console.warn(\n        `palbe analytics: re-identify changes the user from ${existing} to ${userId} — auto-resetting (call reset() first if this is intentional)`,\n      );\n      this.reset();\n    }\n    const ts = Date.now();\n    const body: Record<string, unknown> = {\n      distinct_id: userId,\n      anonymous_id: this.state.anonymousId(),\n      timestamp: ts,\n      sent_at: ts,\n    };\n    if (traits) body.traits = traits;\n    this.state.identifiedUserId = userId;\n    void this.post('/v1/analytics/identify', body);\n  }\n\n  /** Merge distinct id `from` into `to` (identity stitching). Immediate POST. */\n  alias(from: string, to: string): void {\n    if (this.state.isOptedOut()) return;\n    const ts = Date.now();\n    void this.post('/v1/analytics/alias', { from, to, timestamp: ts, sent_at: ts });\n  }\n\n  /** Drop the buffer, clear the identified user and rotate the anon id\n   * (sign-out hygiene). Callers wanting pending events delivered flush first\n   * — the auth binding does. */\n  reset(): void {\n    this.buffer.length = 0;\n    this.cancelTimer();\n    this.state.identifiedUserId = null;\n    this.state.rotateAnonymousId();\n  }\n\n  /** Persisted GDPR opt-out. Opting out drops anything pending so nothing\n   * already-buffered leaks after the user said stop. */\n  setOptOut(on: boolean): void {\n    this.state.setOptOut(on);\n    if (on) {\n      this.buffer.length = 0;\n      this.cancelTimer();\n    }\n  }\n\n  /** Drain the buffer to /v1/analytics/batch (≤100 per request, sequential).\n   * Resolves when delivery finished; NEVER rejects — failed slices are\n   * dropped with one warn per flush. 207 partial-reject is also warned once\n   * (fire-and-forget: no retry for already-delivered batches). */\n  async flush(): Promise<void> {\n    this.cancelTimer();\n    if (this.buffer.length === 0) return;\n    const sentAt = Date.now();\n    let warned = false;\n    while (this.buffer.length > 0) {\n      const slice = this.buffer.splice(0, MAX_BATCH_SIZE);\n      try {\n        const result = await palbeRequest<{ accepted?: number; rejected?: unknown[] }>(\n          this.rt,\n          'POST',\n          '/v1/analytics/batch',\n          { body: { events: slice.map((e) => ({ ...e, sent_at: sentAt })) } },\n        );\n        if (Array.isArray(result?.rejected) && result.rejected.length > 0) {\n          console.warn(\n            `palbe analytics: batch partial-reject — ${result.rejected.length} event(s) rejected by server`,\n          );\n        }\n      } catch (err) {\n        if (!warned) {\n          warned = true;\n          console.warn('palbe analytics: batch flush failed — events dropped', err);\n        }\n      }\n    }\n  }\n\n  // ── internals ──────────────────────────────────────────\n\n  private ingest(event: string, properties?: AnalyticsProperties): void {\n    const wire: CaptureWire = {\n      event,\n      distinct_id: this.state.distinctId(), // stamped at capture time\n      timestamp: Date.now(),\n    };\n    if (properties) wire.properties = properties;\n    if (!this.browser) {\n      void this.post('/v1/analytics/capture', { ...wire, sent_at: wire.timestamp });\n      return;\n    }\n    this.buffer.push(wire);\n    if (this.buffer.length >= FLUSH_AT) void this.flush();\n    else this.startTimer();\n  }\n\n  /** iOS PalBackend auth-binding parity: signedIn → flush + identify;\n   * userInitiated signedOut → flush + reset; sessionExpired → flush only. */\n  private handleAuthEvent(event: AuthChangeEvent): void {\n    if (event.type === 'signedIn') {\n      void this.flush().then(() => {\n        this.identify(event.user.id);\n      });\n    } else if (event.type === 'signedOut') {\n      if (event.reason === 'userInitiated') {\n        void this.flush().then(() => {\n          this.reset();\n        });\n      } else {\n        void this.flush();\n      }\n    }\n    // tokenRefreshed: nothing\n  }\n\n  private startTimer(): void {\n    if (this.flushTimer !== null) return;\n    this.flushTimer = setTimeout(() => {\n      this.flushTimer = null;\n      void this.flush();\n    }, FLUSH_INTERVAL_MS);\n  }\n\n  private cancelTimer(): void {\n    if (this.flushTimer !== null) {\n      clearTimeout(this.flushTimer);\n      this.flushTimer = null;\n    }\n  }\n\n  private async post(path: string, body: unknown): Promise<void> {\n    try {\n      await palbeRequest(this.rt, 'POST', path, { body });\n    } catch (err) {\n      console.warn(`palbe analytics: POST ${path} failed`, err);\n    }\n  }\n}\n","/**\n * palauth AuthResult wire shape + its structural guard — shared by the auth\n * facade (sign-in / verify / code-exchange flows) and the palbe/next OAuth\n * callback handler, so both gate on the SAME shape rules.\n */\n\nexport interface WireUser {\n  id: string;\n  email?: string; // omitted for phone-only users\n  email_verified: boolean;\n  created_at: string;\n  /** Application roles from `auth.user_roles`. Optional on the wire only\n   * because a stack older than the roles surface omits it — a current one\n   * always sends `[]` when the caller holds none. */\n  roles?: string[];\n}\n\n/**\n * GET /auth/me. Distinct from WireUser (GET /auth/user): only this endpoint\n * reports which credentials the account actually has.\n *\n * `providers` is nullable ON PURPOSE and the difference carries meaning —\n * `[]` is \"asked, none linked\", `null` is \"could not determine\" (social login\n * unconfigured on the server, or the identity lookup failed). Collapsing null\n * to [] would report a social-only account as password-only, which is exactly\n * the wrong answer for the form this field exists to choose.\n */\nexport interface WireMe {\n  has_password: boolean;\n  has_mfa: boolean;\n  providers: string[] | null;\n}\n\nexport interface WireAuthResult {\n  access_token: string;\n  refresh_token: string;\n  expires_in: number;\n  user: WireUser;\n}\n\n/**\n * Structural guard for the palauth AuthResult wire shape. Consumers adopt\n * the session (persisting tokens to storage / cookies) BEFORE reading user\n * fields, so the full shape must be proven before adoption — a 200 body with\n * access_token but a missing/malformed user, refresh_token or expires_in\n * would otherwise half-adopt a zombie session (tokens stored, then TypeError\n * on user.id).\n */\nexport function asWireAuthResult(raw: unknown): WireAuthResult | null {\n  if (typeof raw !== 'object' || raw === null) return null;\n  const obj = raw as Record<string, unknown>;\n  if (typeof obj.access_token !== 'string') return null;\n  if (typeof obj.refresh_token !== 'string') return null;\n  if (typeof obj.expires_in !== 'number') return null;\n  const user = obj.user;\n  if (typeof user !== 'object' || user === null) return null;\n  if (typeof (user as Record<string, unknown>).id !== 'string') return null;\n  return raw as WireAuthResult;\n}\n\n/** FR-010: the permission a 403 said it required, or null. Only a string counts —\n * `required` is the cure the server names, and a cure the client cannot name is no cure. */\nexport function requiredPermission(body: unknown): string | null {\n  if (typeof body !== 'object' || body === null) return null;\n  const required = (body as Record<string, unknown>).required;\n  return typeof required === 'string' && required !== '' ? required : null;\n}\n","// Passkeys (WebAuthn platform credentials) for the browser, surfaced through\n// `pb.auth.*` with the SAME names the iOS SDK uses — signInWithPasskey,\n// signUpWithPasskey, registerPasskey — so the two surfaces are learned once.\n//\n// A passkey is DISCOVERABLE, so signing in needs no e-mail, no password and no\n// code: the browser lists the accounts stored for this relying party and the\n// user picks one.\n//\n// The three palauth calls are the same ones iOS makes:\n//   POST /auth/webauthn/login/begin    {}                   → assertion options\n//   POST /auth/webauthn/login/finish   <WebAuthn JSON>       → session\n//   POST /auth/webauthn/signup/begin   {email, user_name?}   → creation options + user_id\n//   POST /auth/webauthn/signup/finish?user_id=…  <WebAuthn JSON>\n//   POST /auth/webauthn/register/begin|finish                → add to a signed-in account\n//\n// This module is the ONLY place that translates between palauth's WebAuthn JSON\n// (base64URL strings) and the ArrayBuffers `navigator.credentials` wants. There\n// is deliberately no dependency added for it: @simplewebauthn is Studio's\n// internal choice, and a customer bundle should not grow one for ~60 lines of\n// base64URL.\n//\n// CROSS-DOMAIN NOTE. The relying-party id is the Environment's own host. A page\n// served from the customer's OWN domain can still use those passkeys, but only\n// through WebAuthn Related Origin Requests — the browser fetches\n// https://<rpId>/.well-known/webauthn and checks this origin against it. ROR is\n// not universal: Firefox on Android has it OFF by default, and a client without\n// it throws SecurityError rather than degrading. So `isPasskeySupported()`\n// exists and every caller needs a non-passkey fallback.\n\nimport { asWireAuthResult, type WireAuthResult } from './auth-wire.js';\nimport { palbeRequest } from './request.js';\nimport type { PalbeRuntime } from './runtime.js';\n\n/** palauth wraps both ceremonies' options as `{options: {publicKey: {…}}}`. */\ninterface OptionsEnvelope {\n  options: { publicKey: Record<string, unknown> };\n}\n\ninterface SignupBeginResponse extends OptionsEnvelope {\n  user_id: string;\n}\n\n/**\n * Decode WebAuthn's base64URL (RFC 4648 §5, no padding). Plain atob rejects\n * these strings, which is how a passkey integration fails at the first\n * challenge with an error that names nothing.\n */\nfunction base64UrlToBytes(value: string): Uint8Array<ArrayBuffer> {\n  const padded = value.replace(/-/g, '+').replace(/_/g, '/');\n  const binary = atob(padded.padEnd(padded.length + ((4 - (padded.length % 4)) % 4), '='));\n  const bytes = new Uint8Array(new ArrayBuffer(binary.length));\n  for (let i = 0; i < binary.length; i += 1) bytes[i] = binary.charCodeAt(i);\n  return bytes;\n}\n\n/** Encode as base64URL without padding — the only form WebAuthn accepts. */\nfunction bytesToBase64Url(buffer: ArrayBuffer): string {\n  const bytes = new Uint8Array(buffer);\n  let binary = '';\n  for (const b of bytes) binary += String.fromCharCode(b);\n  return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n}\n\nfunction requireString(source: Record<string, unknown>, key: string): string {\n  const value = source[key];\n  if (typeof value !== 'string' || value === '') {\n    throw new Error(`passkey options are missing ${key}`);\n  }\n  return value;\n}\n\n/**\n * Turn palauth's creation options into the shape navigator.credentials.create\n * wants. Only the fields the ceremony requires are translated; anything else\n * the server sends rides along untouched.\n */\nfunction toCreationOptions(publicKey: Record<string, unknown>): PublicKeyCredentialCreationOptions {\n  const rp = publicKey.rp as { id?: string; name?: string } | undefined;\n  const user = publicKey.user as { id?: string; name?: string; displayName?: string } | undefined;\n  if (!user?.id) {\n    throw new Error('passkey options carry no user id — the credential would be unusable');\n  }\n  const excludeCredentials = Array.isArray(publicKey.excludeCredentials)\n    ? (publicKey.excludeCredentials as Array<{ id: string; type: string }>).map((c) => ({\n        id: base64UrlToBytes(c.id),\n        type: 'public-key' as const,\n      }))\n    : undefined;\n\n  return {\n    challenge: base64UrlToBytes(requireString(publicKey, 'challenge')),\n    rp: { id: rp?.id, name: rp?.name ?? rp?.id ?? '' },\n    user: {\n      id: base64UrlToBytes(user.id),\n      name: user.name ?? '',\n      displayName: user.displayName ?? user.name ?? '',\n    },\n    pubKeyCredParams:\n      (publicKey.pubKeyCredParams as PublicKeyCredentialParameters[] | undefined) ?? [],\n    authenticatorSelection: publicKey.authenticatorSelection as\n      | AuthenticatorSelectionCriteria\n      | undefined,\n    timeout: publicKey.timeout as number | undefined,\n    attestation: publicKey.attestation as AttestationConveyancePreference | undefined,\n    excludeCredentials,\n  };\n}\n\n/** Assertion options carry `rpId` at the top level, not `rp.id`. */\nfunction toRequestOptions(publicKey: Record<string, unknown>): PublicKeyCredentialRequestOptions {\n  const allowCredentials = Array.isArray(publicKey.allowCredentials)\n    ? (publicKey.allowCredentials as Array<{ id: string }>).map((c) => ({\n        id: base64UrlToBytes(c.id),\n        type: 'public-key' as const,\n      }))\n    : undefined;\n\n  return {\n    challenge: base64UrlToBytes(requireString(publicKey, 'challenge')),\n    rpId: publicKey.rpId as string | undefined,\n    timeout: publicKey.timeout as number | undefined,\n    userVerification: publicKey.userVerification as UserVerificationRequirement | undefined,\n    allowCredentials,\n  };\n}\n\nfunction attestationToJSON(credential: PublicKeyCredential): Record<string, unknown> {\n  const response = credential.response as AuthenticatorAttestationResponse;\n  return {\n    id: credential.id,\n    rawId: bytesToBase64Url(credential.rawId),\n    type: credential.type,\n    response: {\n      clientDataJSON: bytesToBase64Url(response.clientDataJSON),\n      attestationObject: bytesToBase64Url(response.attestationObject),\n    },\n  };\n}\n\nfunction assertionToJSON(credential: PublicKeyCredential): Record<string, unknown> {\n  const response = credential.response as AuthenticatorAssertionResponse;\n  return {\n    id: credential.id,\n    rawId: bytesToBase64Url(credential.rawId),\n    type: credential.type,\n    response: {\n      clientDataJSON: bytesToBase64Url(response.clientDataJSON),\n      authenticatorData: bytesToBase64Url(response.authenticatorData),\n      signature: bytesToBase64Url(response.signature),\n      // The user handle is how palauth resolves WHO signed in on a discoverable\n      // login — there is no identifier in the request.\n      userHandle: response.userHandle ? bytesToBase64Url(response.userHandle) : null,\n    },\n  };\n}\n\n/**\n * Whether this browser can run a passkey ceremony at all.\n *\n * Callers MUST branch on this rather than assuming: a client without WebAuthn —\n * or without Related Origin Requests, when the page is on a different domain\n * than the relying party — throws instead of degrading, so the UI needs a\n * password or e-mail path beside the passkey button.\n */\nexport function isPasskeySupported(): boolean {\n  return (\n    typeof window !== 'undefined' &&\n    typeof window.PublicKeyCredential === 'function' &&\n    typeof navigator !== 'undefined' &&\n    navigator.credentials !== undefined\n  );\n}\n\nfunction ensureSupported(): void {\n  if (!isPasskeySupported()) {\n    throw new Error('This browser cannot use passkeys — offer a password or e-mail sign-in');\n  }\n}\n\nasync function createCredential(publicKey: Record<string, unknown>): Promise<PublicKeyCredential> {\n  const credential = await navigator.credentials.create({\n    publicKey: toCreationOptions(publicKey),\n  });\n  if (credential === null) {\n    throw new Error('the browser returned no credential');\n  }\n  return credential as PublicKeyCredential;\n}\n\nasync function getCredential(publicKey: Record<string, unknown>): Promise<PublicKeyCredential> {\n  const credential = await navigator.credentials.get({\n    publicKey: toRequestOptions(publicKey),\n  });\n  if (credential === null) {\n    throw new Error('the browser returned no credential');\n  }\n  return credential as PublicKeyCredential;\n}\n\n/** Sign in with a passkey already stored for this relying party. */\nexport async function passkeySignIn(rt: PalbeRuntime): Promise<WireAuthResult> {\n  ensureSupported();\n  // An EMPTY body is what makes this discoverable: palauth reads no user_id and\n  // asks the authenticator for whatever it holds for this relying party.\n  const envelope = await palbeRequest<OptionsEnvelope>(rt, 'POST', '/auth/webauthn/login/begin', {\n    body: {},\n  });\n  const credential = await getCredential(envelope.options.publicKey);\n  const raw = await palbeRequest<unknown>(rt, 'POST', '/auth/webauthn/login/finish', {\n    body: assertionToJSON(credential),\n  });\n  const result = asWireAuthResult(raw);\n  if (result === null) {\n    throw new Error('passkey sign-in returned an unusable session');\n  }\n  return result;\n}\n\n/**\n * Create an account whose only credential is a passkey — no password ever\n * exists for it.\n */\nexport async function passkeySignUp(\n  rt: PalbeRuntime,\n  email: string,\n  displayName?: string,\n): Promise<WireAuthResult> {\n  ensureSupported();\n  const begun = await palbeRequest<SignupBeginResponse>(rt, 'POST', '/auth/webauthn/signup/begin', {\n    body: { email, user_name: displayName },\n  });\n  const credential = await createCredential(begun.options.publicKey);\n  // user_id travels as a QUERY parameter: the server keys the pending ceremony\n  // by it. The account does NOT exist yet — begin writes nothing, and finish\n  // opens the account in the same transaction as the credential, so an\n  // abandoned ceremony leaves no row and burns no address.\n  await palbeRequest<unknown>(\n    rt,\n    'POST',\n    `/auth/webauthn/signup/finish?user_id=${encodeURIComponent(begun.user_id)}`,\n    { body: attestationToJSON(credential) },\n  );\n  // signup/finish returns the CREDENTIAL, not a session: the account exists but\n  // nobody is signed in. Signing in immediately is what a caller means by \"sign\n  // up\", and it also proves the credential just created actually works.\n  return await passkeySignIn(rt);\n}\n\n/**\n * Add a passkey to the account that is already signed in.\n *\n * Requires a RECENT sign-in: palauth answers 403 `reauthentication_required`\n * when the session is older than its freshness window, because a passkey keeps\n * working after a password reset and a merely-valid session must not be able to\n * enroll one. Callers should re-authenticate and retry.\n */\nexport async function passkeyRegister(rt: PalbeRuntime, name?: string): Promise<void> {\n  ensureSupported();\n  const envelope = await palbeRequest<OptionsEnvelope>(\n    rt,\n    'POST',\n    '/auth/webauthn/register/begin',\n    { body: { name } },\n  );\n  const credential = await createCredential(envelope.options.publicKey);\n  await palbeRequest<unknown>(rt, 'POST', '/auth/webauthn/register/finish', {\n    body: attestationToJSON(credential),\n  });\n}\n","import type {\n  User as AuthClientUser,\n  Identity,\n  OAuthOptions,\n  OAuthProvider,\n  OAuthTransaction,\n} from '@palbase/auth';\nimport type { Session } from '@palbase/core';\nimport {\n  asWireAuthResult,\n  requiredPermission,\n  type WireAuthResult,\n  type WireMe,\n  type WireUser,\n} from './auth-wire.js';\nimport { BackendError, unwrap } from './errors.js';\nimport { isPasskeySupported, passkeyRegister, passkeySignIn, passkeySignUp } from './passkey.js';\nimport type { RealtimeSubscription } from './realtime/facade.js';\nimport { palbeRequest } from './request.js';\nimport type { PalbeRuntime } from './runtime.js';\n\nexport type MagicLinkResult =\n  | ({ status: 'signedIn' } & AuthSuccess)\n  | { status: 'mfaRequired'; mfaToken: string; factors: string[] };\n\nexport type OAuthExchangeResult =\n  | ({ status: 'signedIn'; isNewUser: boolean } & AuthSuccess)\n  | { status: 'mfaRequired'; mfaToken: string; factors: string[] }\n  | { status: 'linked'; identity: Identity; userId: string };\n\nexport interface AuthUser {\n  id: string;\n  /** null for phone-only users (the server omits email). */\n  email: string | null;\n  emailVerified: boolean;\n  createdAt: string;\n  /**\n   * The caller's APPLICATION roles, as assigned in `auth.user_roles`.\n   *\n   * Compare against the generated `Roles` constants rather than string\n   * literals — a role withdrawn upstream disappears from that module, so code\n   * still naming it stops building instead of quietly losing access:\n   *\n   * ```ts\n   * import { Roles } from './palbe.gen';\n   * if (pb.auth.currentUser?.roles.includes(Roles.moderator)) …\n   * ```\n   *\n   * Empty array for a caller who holds none, never null: `.includes(…)` needs\n   * no guard. This is the UI's hint, not the boundary — the server decides,\n   * and it decides again on every request.\n   */\n  roles: string[];\n}\n\n/** What `pb.auth.getSignInMethods()` reports about an account's credentials. */\nexport interface SignInMethods {\n  /** A local password exists — offer \"change password\", not \"set password\". */\n  password: boolean;\n  /** An MFA factor is enrolled. */\n  mfa: boolean;\n  /**\n   * Linked OAuth providers, e.g. `['google']`. `[]` means none are linked;\n   * `null` means the server could not determine it (social login is not\n   * configured, or the lookup failed) — treat null as unknown, not as none.\n   */\n  providers: string[] | null;\n}\n\nexport interface AuthSuccess {\n  user: AuthUser;\n  session: Session;\n}\n\nexport type AuthState = { status: 'signedIn'; user: AuthUser } | { status: 'signedOut' };\n\nexport type AuthChangeEvent =\n  | { type: 'signedIn'; user: AuthUser }\n  | {\n      type: 'signedOut';\n      /**\n       * `userInitiated` — pb.auth.signOut(); `sessionExpired` — a refresh\n       * ultimately failed; `accountDeleted` — this device ran deleteAccount();\n       * `sessionInvalid` — a server-side session kill (erased/revoked subject)\n       * was observed on a request and the client tore down reactively.\n       */\n      reason: 'userInitiated' | 'sessionExpired' | 'accountDeleted' | 'sessionInvalid';\n    }\n  | { type: 'tokenRefreshed' };\n\nexport type Unsubscribe = () => void;\n\n/** Map the wire bare-user shape (GET /auth/user) to AuthUser. */\nfunction mapWireUser(raw: WireUser): AuthUser {\n  return {\n    id: raw.id,\n    email: raw.email ?? null,\n    emailVerified: raw.email_verified,\n    createdAt: raw.created_at,\n    // A stack older than the roles surface omits the key entirely; `[]` is the\n    // honest reading there — it holds no roles because it has none to hold.\n    roles: raw.roles ?? [],\n  };\n}\n\n/** Map @palbase/auth's camelCase User to palbe's AuthUser (drop extra fields). */\nfunction mapClientUser(u: AuthClientUser): AuthUser {\n  // AuthClient types email as a required string, but the wire omits it for\n  // phone-only users — normalize missing/empty to null at this boundary.\n  return {\n    id: u.id,\n    email: u.email || null,\n    emailVerified: u.emailVerified,\n    createdAt: u.createdAt,\n    roles: u.roles ?? [],\n  };\n}\n\n/** Key-order-proof equality on the four AuthUser fields (refreshUser change detection). */\nfunction usersEqual(a: AuthUser, b: AuthUser | null): boolean {\n  return (\n    b !== null &&\n    a.id === b.id &&\n    a.email === b.email &&\n    a.emailVerified === b.emailVerified &&\n    a.createdAt === b.createdAt\n  );\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null;\n}\nfunction isString(v: unknown): v is string {\n  return typeof v === 'string';\n}\n\n/** Process-wide `onPermissionDenied` handlers — survive a runtime re-`__configure`. */\nconst permissionDeniedHandlers = new Set<(required: string) => void>();\n\n/** Test-only (called by `__reset`): the relay outlives a runtime on purpose, a test run does not. */\nexport function __resetPermissionDeniedHandlers(): void {\n  permissionDeniedHandlers.clear();\n}\n\nexport class PalbeAuth {\n  private cachedUser: AuthUser | null = null;\n  private signingOut = false;\n  // Explicit signedOut reason pinned for the NEXT session clear (deleteAccount /\n  // reactiveTeardown set it before clearSession; the SIGNED_OUT handler consumes\n  // it exactly once, then resets to null → normal signOut/expiry split resumes).\n  private nextSignOutReason: 'accountDeleted' | 'sessionInvalid' | null = null;\n  private signingIn = false; // suppresses AuthClient's TOKEN_REFRESHED during re-signIn\n  private readonly oauthCompletions = new Map<\n    string,\n    { resultCode?: string; callbackURL?: string; promise: Promise<OAuthExchangeResult> }\n  >();\n  private signedInState = false; // dedupes AuthClient's repeated SIGNED_OUT events\n  private hydratingUser = false; // guards hydrateUser() to a single boot fetch\n  private readonly stateListeners = new Set<(state: AuthState) => void>();\n  private readonly eventListeners = new Set<(event: AuthChangeEvent) => void>();\n  private readonly userListeners = new Set<(user: AuthUser) => void>();\n\n  constructor(private readonly rt: PalbeRuntime) {\n    // Every runtime's HttpClient feeds the same process-wide relay (FR-010).\n    rt.http.onForbidden((body) => {\n      const required = requiredPermission(body);\n      if (required === null) return;\n      for (const handler of permissionDeniedHandlers) this.safeInvoke(() => handler(required));\n    });\n    // AuthClient fires SIGNED_OUT on any session clear and TOKEN_REFRESHED on\n    // refresh. SIGNED_IN is emitted by the facade itself (it knows the user);\n    // after hydration AuthClient never fires SIGNED_IN anyway (hasSession=true).\n    rt.authClient.onAuthStateChange((event, _session) => {\n      if (event === 'SIGNED_OUT') {\n        if (!this.signedInState) return; // duplicate clear — already signed out\n        this.signedInState = false;\n        this.cachedUser = null;\n        // A caller (deleteAccount / reactiveTeardown) may pin an explicit reason\n        // for THIS clear; otherwise fall back to the signOut-vs-expiry split.\n        const reason =\n          this.nextSignOutReason ?? (this.signingOut ? 'userInitiated' : 'sessionExpired');\n        this.nextSignOutReason = null;\n        this.emitState({ status: 'signedOut' });\n        this.emitEvent({ type: 'signedOut', reason });\n      } else if (event === 'TOKEN_REFRESHED') {\n        // Re-signIn while signed in makes AuthClient map the new session to\n        // TOKEN_REFRESHED (hasSession=true) — that would leak a tokenRefreshed\n        // with the OLD user just before signedIn. iOS emits exactly one\n        // signedIn per login; suppress it here.\n        if (this.signingIn) return;\n        this.emitEvent({ type: 'tokenRefreshed' });\n      }\n    });\n    // Hydrated runtime starts in a signed-in-ish state (pending refresh).\n    this.signedInState = rt.tokenManager.getRefreshToken() !== null;\n  }\n\n  // ── state ──────────────────────────────────────────────\n\n  get currentUser(): AuthUser | null {\n    return this.cachedUser;\n  }\n\n  get isSignedIn(): boolean {\n    return this.rt.tokenManager.getRefreshToken() !== null;\n  }\n\n  // ── core flows ─────────────────────────────────────────\n\n  /**\n   * Create an account.\n   *\n   * `locale` is an explicit choice of the language the account's mail is\n   * written in, and the stack STORES it. Left out, the request carries the\n   * PAGE's language (`<html lang>`) as its Accept-Language — the language the\n   * person is reading the sign-up form in — and nothing is stored: the stack\n   * reads it for this mail only (palgroup/palbase#24).\n   *\n   * Why not store the page language: a template's hard-coded `lang=\"en\"` is\n   * common, and a stored \"en\" would outrank every later request's language for\n   * good. Why not leave the browser's own header: it is the browser's interface\n   * language, and a Turkish page in an English browser would get English mail.\n   */\n  async signUp(params: { email: string; password: string; locale?: string }): Promise<AuthSuccess> {\n    this.signingIn = true;\n    try {\n      const lang = params.locale ? undefined : pageLanguage();\n      const data = unwrap(\n        await this.rt.authClient.signUp(\n          params,\n          lang ? { headers: { 'Accept-Language': lang } } : undefined,\n        ),\n      );\n      return this.adopt(data);\n    } finally {\n      this.signingIn = false;\n    }\n  }\n\n  async signIn(params: { email: string; password: string }): Promise<AuthSuccess> {\n    this.signingIn = true;\n    try {\n      const data = unwrap(await this.rt.authClient.signIn(params));\n      return this.adopt(data);\n    } finally {\n      this.signingIn = false;\n    }\n  }\n\n  async signOut(): Promise<void> {\n    this.signingOut = true;\n    try {\n      await this.rt.authClient.signOut();\n    } catch {\n      // local sign-out must win even when the server call fails (offline etc.)\n    } finally {\n      this.rt.tokenManager.clearSession(); // idempotent; deduped by signedInState\n      this.signingOut = false; // AFTER clear → reason stays userInitiated\n      this.rt.storage.clear();\n      this.cachedUser = null;\n    }\n  }\n\n  /**\n   * Self-service account erasure (\"right to be forgotten\"). Calls palauth\n   * `DELETE /auth/user` (session-authed + fresh re-auth): password users pass\n   * `{ password }`; passwordless/OAuth users rely on a freshly stepped-up\n   * session. The handler answers **204 with no body** — the erasure has already\n   * finished and every session is already revoked server-side — so we tear down\n   * local state (mirroring `signOut()`'s clear, minus the pointless `/logout`)\n   * and emit `signedOut{reason:'accountDeleted'}`.\n   *\n   * Returns nothing, because there is nothing to return: the handler used to\n   * answer 202 with an `{erasure_id}` naming an asynchronous run, and that id\n   * was removed along with the run (`gdpr_handlers.go:221-229`). Reading it\n   * here threw a `TypeError` AFTER the account was already gone — a success\n   * reported as a failure.\n   *\n   * On 401 `reauth_required` / 503 `not_configured` (or `erasure_unavailable`)\n   * the request throws BEFORE the teardown line, so the local session is left\n   * fully intact — the deletion did not happen and the user is still signed in.\n   */\n  async deleteAccount(params: { password?: string } = {}): Promise<void> {\n    await palbeRequest<null>(this.rt, 'DELETE', '/auth/user', {\n      body: params.password ? { password: params.password } : {},\n    });\n    // Reached only on 204 (2xx): sessions already revoked server-side.\n    this.nextSignOutReason = 'accountDeleted';\n    this.rt.tokenManager.clearSession(); // fires SIGNED_OUT → emits accountDeleted\n    this.rt.storage.clear();\n    this.cachedUser = null;\n  }\n\n  /**\n   * @internal — invoked by the transport choke point (`request.ts`), not app code.\n   * Reactive teardown when the server reports the session is gone: a 403\n   * `subject_fenced`/`subject_erased` (subject being erased) or a 401\n   * `session_revoked`. Clears local state and emits\n   * `signedOut{reason:'sessionInvalid'}` exactly once (deduped by\n   * `signedInState`). An ordinary 403 authz denial does NOT reach here —\n   * `request.ts` matches only the exact session-kill codes.\n   */\n  reactiveTeardown(): void {\n    if (!this.signedInState) return; // already torn down — exactly-once\n    this.nextSignOutReason = 'sessionInvalid';\n    this.rt.tokenManager.clearSession(); // fires SIGNED_OUT → emits sessionInvalid\n    this.rt.storage.clear();\n    this.cachedUser = null;\n  }\n\n  async getUser(): Promise<AuthUser> {\n    const raw = await palbeRequest<WireUser>(this.rt, 'GET', '/auth/user');\n    return mapWireUser(raw);\n  }\n\n  /**\n   * Which credentials this account actually has.\n   *\n   * An account reached through Google has no password, so showing it a\n   * \"current password\" field gives the user something they can never fill —\n   * and `getUser()` cannot tell you, because GET /auth/user carries no\n   * credential information. Read this before rendering any re-auth or\n   * change-password form.\n   */\n  async getSignInMethods(): Promise<SignInMethods> {\n    const raw = await palbeRequest<WireMe>(this.rt, 'GET', '/auth/me');\n    return {\n      password: raw.has_password,\n      mfa: raw.has_mfa,\n      providers: raw.providers ?? null,\n    };\n  }\n\n  async refreshUser(): Promise<AuthUser> {\n    const user = await this.getUser();\n    const changed = !usersEqual(user, this.cachedUser);\n    this.cachedUser = user;\n    if (changed) for (const cb of this.userListeners) this.safeInvoke(() => cb(user));\n    return user;\n  }\n\n  /**\n   * Restore the user after a session was rehydrated from storage (page reload).\n   * Hydration in buildRuntime restores the TOKENS synchronously, but the access\n   * token JWT does not carry emailVerified/createdAt, so the full AuthUser can't\n   * be reconstructed offline — this fetches GET /auth/user once and announces\n   * `signedIn`, so the app no longer has to `await pb.auth.refreshUser()` itself\n   * on boot. Idempotent (runs once), browser-safe (no-op when not signed in or\n   * a user is already cached), and never throws (a boot-time network failure\n   * must not break app startup — isSignedIn stays true, the app can retry).\n   */\n  hydrateUser(): void {\n    if (this.hydratingUser || this.cachedUser || !this.isSignedIn) return;\n    this.hydratingUser = true;\n    void this.refreshUser()\n      .then((user) => {\n        // Only announce if we're still signed in (a sign-out may have raced).\n        if (this.isSignedIn) {\n          this.signedInState = true;\n          this.emitState({ status: 'signedIn', user });\n        }\n      })\n      .catch(() => {\n        // Swallow: a failed boot fetch leaves isSignedIn true; the app can\n        // call refreshUser() again or the next authed request will 401→refresh.\n      })\n      .finally(() => {\n        this.hydratingUser = false;\n      });\n  }\n\n  // ── listeners ──────────────────────────────────────────\n\n  private permissionsStore: PalbePermissions | null = null;\n\n  /** The caller's live permission set — see PalbePermissions. Lazy: a server\n   * request that never asks pays nothing (no realtime socket). The FIRST access\n   * binds synchronously and lets a realtime refusal (no browser environment)\n   * THROW here, with the guided message — an empty set answered in silence\n   * would read as \"no permissions\". */\n  get permissions(): PalbePermissions {\n    if (!this.permissionsStore) {\n      const store = new PalbePermissions(this.rt);\n      store.attach(this);\n      this.permissionsStore = store;\n    }\n    return this.permissionsStore;\n  }\n\n  /** FR-010: fires with the permission a 403 named in `required`. Refetch the\n   * object the screen was drawn from; the error itself is thrown as always.\n   * Handlers live in a module-level relay (like iOS' PermissionDeniedRelay), so\n   * a re-`__configure` — which replaces the HttpClient — does not lose them. */\n  onPermissionDenied(handler: (required: string) => void): Unsubscribe {\n    permissionDeniedHandlers.add(handler);\n    return () => permissionDeniedHandlers.delete(handler);\n  }\n\n  /**\n   * Subscribe to signed-in/signed-out state. Fires immediately with the\n   * current snapshot (iOS parity). A restored session (page reload) hydrates\n   * the user asynchronously via `hydrateUser()` (fired once at boot), so the\n   * FIRST snapshot may report signedOut for a tick even when `isSignedIn` is\n   * true; the listener then fires again with `signedIn` once the user lands.\n   * Rely on `isSignedIn` for the session truth if you need it synchronously.\n   */\n  onAuthStateChange(callback: (state: AuthState) => void): Unsubscribe {\n    this.stateListeners.add(callback);\n    this.safeInvoke(() => callback(this.snapshotState()));\n    return () => this.stateListeners.delete(callback);\n  }\n\n  onAuthEvent(callback: (event: AuthChangeEvent) => void): Unsubscribe {\n    this.eventListeners.add(callback);\n    return () => this.eventListeners.delete(callback);\n  }\n\n  /** Subscribe to user-profile changes. Replays the cached user on subscribe (iOS parity). */\n  onUserChange(callback: (user: AuthUser) => void): Unsubscribe {\n    this.userListeners.add(callback);\n    const u = this.cachedUser;\n    if (u) this.safeInvoke(() => callback(u));\n    return () => this.userListeners.delete(callback);\n  }\n\n  // ── internals ──────────────────────────────────────────\n\n  private snapshotState(): AuthState {\n    return this.cachedUser && this.isSignedIn\n      ? { status: 'signedIn', user: this.cachedUser }\n      : { status: 'signedOut' };\n  }\n\n  /**\n   * Listener exception isolation: a throwing consumer callback must never\n   * break delivery to other listeners nor propagate into the emit caller\n   * (tokenManager.clearSession callers, pb.call paths, signOut, ...).\n   */\n  private safeInvoke(fn: () => void): void {\n    try {\n      fn();\n    } catch {\n      // consumer callback errors are intentionally swallowed\n    }\n  }\n\n  private emitState(state: AuthState): void {\n    for (const cb of this.stateListeners) this.safeInvoke(() => cb(state));\n  }\n\n  private emitEvent(event: AuthChangeEvent): void {\n    for (const cb of this.eventListeners) this.safeInvoke(() => cb(event));\n  }\n\n  /** Cache the user + announce sign-in. Session was already set by AuthClient. */\n  private adopt(data: { user: AuthClientUser; session: Session }): AuthSuccess {\n    const user = mapClientUser(data.user);\n    this.cachedUser = user;\n    this.signedInState = true;\n    this.emitState({ status: 'signedIn', user });\n    this.emitEvent({ type: 'signedIn', user });\n    return { user, session: data.session };\n  }\n\n  /** Adopt a raw palauth AuthResult wire shape: wire tokens, cache user, announce. */\n  private adoptWire(raw: WireAuthResult): AuthSuccess {\n    this.rt.authClient.setTokens(raw.access_token, raw.refresh_token, raw.expires_in);\n    const user = mapWireUser(raw.user);\n    this.cachedUser = user;\n    this.signedInState = true;\n    this.emitState({ status: 'signedIn', user });\n    this.emitEvent({ type: 'signedIn', user });\n    const session: Session = {\n      accessToken: raw.access_token,\n      refreshToken: raw.refresh_token,\n      expiresAt: Date.now() + raw.expires_in * 1000,\n    };\n    return { user, session };\n  }\n\n  /** Run a sign-in flow under the signingIn flag to suppress spurious tokenRefreshed. */\n  private async withSigningIn<T>(fn: () => Promise<T>): Promise<T> {\n    this.signingIn = true;\n    try {\n      return await fn();\n    } finally {\n      this.signingIn = false;\n    }\n  }\n\n  /**\n   * Defensively decode a 200 union body (AuthResult | mfa-required) and\n   * complete the flow. The wire contract promises one of the two shapes, but\n   * a literal-`null` (or otherwise malformed) JSON body must surface as\n   * BackendError('decode') — never a raw TypeError from probing a non-object.\n   * The mfa branch validates its fields: `mfa_token` is required; the factor\n   * list (named `factors` by magic-link verify, `mfa_factors` by the OAuth\n   * callback — extraction-verified against palauth) tolerates a missing or\n   * malformed value as []. The signedIn branch validates the FULL AuthResult\n   * shape (asWireAuthResult) — an incomplete body falls through to decode,\n   * never half-adopts.\n   */\n  private completeAuthUnion(\n    raw: unknown,\n    factorsKey: 'factors' | 'mfa_factors',\n    context: string,\n  ): MagicLinkResult {\n    if (typeof raw === 'object' && raw !== null) {\n      const obj = raw as Record<string, unknown>;\n      if (obj.mfa_required === true) {\n        if (typeof obj.mfa_token === 'string') {\n          const list = obj[factorsKey];\n          const factors = Array.isArray(list)\n            ? list.filter((f): f is string => typeof f === 'string')\n            : [];\n          return { status: 'mfaRequired', mfaToken: obj.mfa_token, factors };\n        }\n        // mfa_required without a usable mfa_token is unrecoverable — fall\n        // through to decode (NOT the signedIn branch).\n      } else {\n        const wire = asWireAuthResult(raw);\n        if (wire) return { status: 'signedIn', ...this.adoptWire(wire) };\n      }\n    }\n    // 200 body matching neither shape — never fabricate a result.\n    throw this.decodeError(context);\n  }\n\n  private decodeError(context: string): BackendError {\n    return new BackendError('decode', {\n      code: 'decode_error',\n      message: `Unexpected ${context} response`,\n    });\n  }\n\n  // ── additional auth flows ──────────────────────────────\n\n  async signInWithOTP(params: { phone: string }): Promise<void> {\n    // The server only supports the 'sms' channel (rejects anything else).\n    await palbeRequest(this.rt, 'POST', '/auth/otp', {\n      body: { phone: params.phone, channel: 'sms' },\n    });\n  }\n\n  async verifyOTP(params: { phone: string; token: string }): Promise<AuthSuccess> {\n    return this.withSigningIn(async () => {\n      const raw = await palbeRequest<unknown>(this.rt, 'POST', '/auth/otp/verify', {\n        body: params,\n      });\n      // The OTP-verify wire is AuthResult ONLY (palauth phoneLoginResponse —\n      // no MFA union on this route): the same zombie-session guard applies,\n      // and an mfa-shaped body here is a decode error, not an MFA result.\n      const wire = asWireAuthResult(raw);\n      if (!wire) throw this.decodeError('OTP verify');\n      return this.adoptWire(wire);\n    });\n  }\n\n  async resetPassword(email: string): Promise<void> {\n    unwrap(await this.rt.authClient.requestPasswordReset({ email }));\n  }\n\n  async confirmPasswordReset(params: { token: string; newPassword: string }): Promise<void> {\n    unwrap(\n      await this.rt.authClient.confirmPasswordReset({\n        token: params.token,\n        new_password: params.newPassword,\n      }),\n    );\n  }\n\n  async updatePassword(params: { currentPassword: string; newPassword: string }): Promise<void> {\n    unwrap(\n      await this.rt.authClient.changePassword({\n        current_password: params.currentPassword,\n        new_password: params.newPassword,\n      }),\n    );\n  }\n\n  /**\n   * Give a passwordless account its FIRST password, in-app.\n   *\n   * For accounts created with a passkey or a social provider: they have no\n   * current password, so `updatePassword` cannot serve them — it sends one and\n   * the server answers 401. Before this existed the only route was the\n   * password-RESET e-mail, which asks someone already signed in to go find\n   * their inbox.\n   *\n   * Requires a RECENT sign-in, not merely a session: a first password is a\n   * credential that outlives the rest, so the server answers 403\n   * `reauthentication_required` on a stale one — the same gate\n   * `registerPasskey` carries. An account that already has a password gets 409\n   * `password_already_set`; change it with `updatePassword` instead.\n   *\n   * The session stays valid — no re-login.\n   */\n  async setPassword(newPassword: string): Promise<void> {\n    unwrap(await this.rt.authClient.setPassword({ new_password: newPassword }));\n  }\n\n  async verifyEmail(params: { token: string } | { code: string; email: string }): Promise<void> {\n    unwrap(await this.rt.authClient.verifyEmail(params));\n  }\n\n  async resendVerification(email: string): Promise<void> {\n    unwrap(await this.rt.authClient.resendVerification(email));\n  }\n\n  async signInWithMagicLink(email: string): Promise<void> {\n    unwrap(await this.rt.authClient.requestMagicLink({ email }));\n  }\n\n  async verifyMagicLink(token: string): Promise<MagicLinkResult> {\n    return this.withSigningIn(async () => {\n      const raw = await palbeRequest<unknown>(this.rt, 'POST', '/auth/magic-link/verify', {\n        body: { token },\n      });\n      return this.completeAuthUnion(raw, 'factors', 'magic-link verify');\n    });\n  }\n\n  /**\n   * Sign in with a passkey stored for this Environment. No identifier is typed:\n   * the browser lists the accounts it holds and the user picks one.\n   *\n   * Throws when the browser cannot run a ceremony — check `passkeysSupported`\n   * first and keep a password or e-mail path beside the button.\n   */\n  async signInWithPasskey(): Promise<AuthSuccess> {\n    return this.withSigningIn(async () => this.adoptWire(await passkeySignIn(this.rt)));\n  }\n\n  /**\n   * Create an account whose only credential is a passkey — the e-mail is the\n   * identifier, the passkey is the credential, and no password ever exists.\n   */\n  async signUpWithPasskey(email: string, displayName?: string): Promise<AuthSuccess> {\n    return this.withSigningIn(async () =>\n      this.adoptWire(await passkeySignUp(this.rt, email, displayName)),\n    );\n  }\n\n  /**\n   * Add a passkey to the signed-in account, so the next sign-in is one tap.\n   *\n   * Rejects with a 403 `reauthentication_required` when the session is not\n   * recent: a passkey outlives a password reset, so enrolling one takes more\n   * than a valid session.\n   */\n  async registerPasskey(name?: string): Promise<void> {\n    await passkeyRegister(this.rt, name);\n  }\n\n  /** Whether this browser can run a passkey ceremony at all. */\n  get passkeysSupported(): boolean {\n    return isPasskeySupported();\n  }\n\n  async signInWithOAuth(params: {\n    provider: OAuthProvider;\n    redirectTo?: string;\n    /** Set false to skip the browser redirect (popup/manual flows). Default true. */\n    redirect?: boolean;\n  }): Promise<{ url: string }> {\n    const { redirect = true, ...opts } = params;\n    const transaction = await this.beginOAuth(opts);\n    const url = transaction.authorizationURL;\n    if (redirect && typeof window !== 'undefined' && typeof window.location !== 'undefined') {\n      window.location.assign(url);\n    }\n    return { url };\n  }\n\n  async beginOAuth(options: OAuthOptions): Promise<OAuthTransaction> {\n    return unwrap(await this.rt.authClient.beginOAuth(options));\n  }\n\n  /** Complete with the application's result_code; the provider code stays on the backend. */\n  exchangeCodeForSession(params: {\n    transactionId: string;\n    resultCode: string;\n    callbackURL?: string;\n  }): Promise<OAuthExchangeResult> {\n    return this.completeOAuth(params);\n  }\n\n  completeOAuth(params: {\n    transactionId: string;\n    resultCode?: string;\n    callbackURL?: string;\n  }): Promise<OAuthExchangeResult> {\n    const current = this.oauthCompletions.get(params.transactionId);\n    if (current) {\n      if (current.resultCode !== params.resultCode || current.callbackURL !== params.callbackURL) {\n        return Promise.reject(\n          new BackendError('validation', {\n            code: 'invalid_result_code',\n            message: 'A different OAuth completion is already in progress',\n          }),\n        );\n      }\n      return current.promise;\n    }\n    const operation = this.withSigningIn(async (): Promise<OAuthExchangeResult> => {\n      const result = unwrap(await this.rt.authClient.completeOAuth(params));\n      if (result.status === 'signedIn')\n        return { status: 'signedIn', isNewUser: result.isNewUser, ...this.adopt(result) };\n      return result;\n    });\n    this.oauthCompletions.set(params.transactionId, {\n      resultCode: params.resultCode,\n      callbackURL: params.callbackURL,\n      promise: operation,\n    });\n    void operation.then(\n      () => this.oauthCompletions.delete(params.transactionId),\n      () => this.oauthCompletions.delete(params.transactionId),\n    );\n    return operation;\n  }\n\n  async cancelOAuth(transactionId: string): Promise<void> {\n    unwrap(await this.rt.authClient.cancelOAuth(transactionId));\n  }\n\n  async linkIdentity(options: Omit<OAuthOptions, 'purpose'>): Promise<OAuthTransaction> {\n    return unwrap(await this.rt.authClient.linkIdentity(options));\n  }\n\n  async signInWithGoogle(opts?: { redirectTo?: string; redirect?: boolean }): Promise<{\n    url: string;\n  }> {\n    return this.signInWithOAuth({ provider: 'google', ...opts });\n  }\n\n  async signInWithApple(opts?: { redirectTo?: string; redirect?: boolean }): Promise<{\n    url: string;\n  }> {\n    return this.signInWithOAuth({ provider: 'apple', ...opts });\n  }\n}\n\n/**\n * `pb.auth.permissions` — the caller's live permission set (FR-020 = iOS\n * FR-016…019). Affordance, never authority: it decides what to draw, the\n * server decides what is allowed on every request. Bound to\n * `roles:<projectRef>:<uid>` through the general realtime state path, whose\n * gap→resync and reconnect→rejoin already cover FR-018.\n */\nexport class PalbePermissions {\n  /** True after an unreadable `values` push; a later `sync_version` alone must not restore a version. */\n  private unreadable = false;\n  private set: ReadonlySet<string> = new Set();\n  private version = '';\n  private userId: string | null = null;\n  private subs: RealtimeSubscription[] = [];\n  private readonly listeners = new Set<(set: ReadonlySet<string>) => void>();\n\n  constructor(private readonly rt: PalbeRuntime) {}\n\n  /** Bind to the auth lifecycle. The CURRENT state binds synchronously — a\n   * realtime refusal throws to the caller of `pb.auth.permissions`; later\n   * transitions bind inside the auth emitter, where a failure is reported\n   * rather than swallowed. */\n  attach(auth: PalbeAuth): void {\n    // Now, OUTSIDE the auth emitter (whose safeInvoke would swallow the refusal).\n    const current = auth.currentUser;\n    this.bind(current !== null && auth.isSignedIn ? current.id : null);\n    // Later transitions arrive through the emitter; the replay it fires first\n    // carries the state just bound and is a no-op. A failure there is reported,\n    // not hidden — and `userId` stays unset so the next transition retries.\n    auth.onAuthStateChange((state) => {\n      try {\n        this.bind(state.status === 'signedIn' ? state.user.id : null);\n      } catch (err) {\n        console.warn('palbe permissions: could not bind to the roles channel', err);\n      }\n    });\n  }\n\n  holds(permission: string): boolean {\n    return this.set.has(permission);\n  }\n  get all(): ReadonlySet<string> {\n    return this.set;\n  }\n  get syncVersion(): string {\n    return this.version;\n  }\n  onChange(callback: (set: ReadonlySet<string>) => void): Unsubscribe {\n    this.listeners.add(callback);\n    return () => this.listeners.delete(callback);\n  }\n  /** `for await (const set of pb.auth.permissions.changes())` — the current set first. */\n  async *changes(): AsyncIterable<ReadonlySet<string>> {\n    const queue: ReadonlySet<string>[] = [this.set];\n    let wake: (() => void) | null = null;\n    const off = this.onChange((set) => {\n      queue.push(set);\n      wake?.();\n      wake = null;\n    });\n    try {\n      while (true) {\n        while (queue.length > 0) yield queue.shift()!;\n        await new Promise<void>((resolve) => {\n          wake = resolve;\n        });\n      }\n    } finally {\n      off();\n    }\n  }\n\n  private bind(userId: string | null): void {\n    if (userId === this.userId) return;\n    for (const s of this.subs) s.cancel();\n    this.subs = [];\n    this.apply(new Set(), '');\n    if (userId === null) {\n      this.userId = null;\n      return;\n    }\n    // `channel()` can refuse (no browser realtime). userId is recorded only\n    // AFTER the subscriptions exist — and cleared BEFORE the attempt — so a\n    // refusal leaves the store unbound and the next auth transition (even back\n    // to the same user) retries instead of early-returning forever.\n    this.userId = null;\n    const channel = this.rt.realtime.channel(`roles:${this.rt.projectRef}:${userId}`);\n    this.subs = [\n      channel.onState('values', (value) => {\n        const decoded = PalbePermissions.decode(value);\n        // An UNREADABLE set is not \"no permissions as of version N\": the set is\n        // emptied AND the version forgotten, and stays forgotten until a readable\n        // set arrives — the same pair iOS refuses to produce (NFR-005).\n        this.unreadable = decoded === null;\n        this.apply(decoded ?? new Set(), decoded === null ? '' : this.version);\n      }),\n      channel.onState('sync_version', (value) => {\n        const v = isRecord(value) ? value.sync_version : undefined;\n        if (typeof v === 'number' && !this.unreadable) this.apply(this.set, String(v));\n      }),\n      // A refusal the socket will not retry means this channel is gone: a set\n      // kept from before it is stale-OPEN, the wrong direction to fail.\n      channel.onError((err) => {\n        if (!err.retryable) this.apply(new Set(), '');\n      }),\n    ];\n    this.userId = userId;\n  }\n\n  /** `values` is an array of permission names (NFR-004); anything else is\n   * UNREADABLE (null) — treated as \"none\" for the set, and as \"unknown\" for the\n   * version, never as \"none as of version N\". */\n  private static decode(value: unknown): ReadonlySet<string> | null {\n    return Array.isArray(value) && value.every(isString) ? new Set(value) : null;\n  }\n\n  private apply(next: ReadonlySet<string>, version: string): void {\n    this.version = version;\n    const same = next.size === this.set.size && [...next].every((p) => this.set.has(p));\n    if (same) return;\n    this.set = next;\n    for (const l of this.listeners) l(next);\n  }\n}\n\n/** The page's declared language (`<html lang>`), or undefined outside a browser or when unset. */\nfunction pageLanguage(): string | undefined {\n  if (typeof document === 'undefined') return undefined;\n  const lang = document.documentElement?.lang?.trim();\n  return lang ? lang : undefined;\n}\n","// `pb.calls` — SP-4 voice/video call surface for the web SDK.\n//\n// Architecture: thin wrapper around the embedded media engine (browser WebRTC) +\n// the messaging server's call REST endpoints:\n//   POST /v1/messaging/groups/{gid}/calls           → start a call\n//   POST /v1/messaging/groups/{gid}/calls/{cid}/accept  → join a call\n//   POST /v1/messaging/groups/{gid}/calls/{cid}/decline → decline\n//   POST /v1/messaging/groups/{gid}/calls/{cid}/mute    → mute/unmute (host)\n//   POST /v1/messaging/groups/{gid}/calls/{cid}/kick    → kick (host)\n//\n// The {gid} is a messaging group display-id (`grp_<uuidv7>`).\n//\n// ─── E2EE NOTE ─────────────────────────────────────────────────────────────\n// The media engine's hop-by-hop transport is already DTLS-SRTP encrypted.\n// Frame-level end-to-end encryption (MLS-derived keys via the engine's external\n// key provider) is the SP-1.x web-MLS work and is OUT OF SCOPE for this surface.\n// The `setMediaKey` method is wired to that key provider as a design seam; call\n// it AFTER web-MLS delivers a shared frame key. Until then, rooms connect without\n// e2ee.\n// TODO(SP-1-web): derive the frame key from the MLS exporter and call\n//   call.setMediaKey(derivedKeyArrayBuffer)\n// ───────────────────────────────────────────────────────────────────────────\n\nimport {\n  ExternalE2EEKeyProvider,\n  type RemoteParticipant,\n  type RemoteTrack,\n  type RemoteTrackPublication,\n  Room,\n  RoomEvent,\n  Track,\n} from 'livekit-client';\nimport type { Unsubscribe } from '../auth-facade.js';\nimport { BackendError } from '../errors.js';\nimport { palbeRequest } from '../request.js';\nimport type { PalbeRuntime } from '../runtime.js';\n\n// ─── Wire types ────────────────────────────────────────────────────────────\n\ninterface StartCallResponse {\n  call_id: string;\n  token: string;\n  edge_url: string;\n  max_members: number;\n}\n\ninterface AcceptCallResponse {\n  token: string;\n  edge_url: string;\n}\n\n// ─── Public types ──────────────────────────────────────────────────────────\n\nexport type CallState = 'connecting' | 'active' | 'ended';\n\nexport interface CallParticipant {\n  identity: string;\n  isSpeaking: boolean;\n  audioMuted: boolean;\n  videoEnabled: boolean;\n  /** The live <video> element for this participant, or null before track arrives. */\n  videoElement: HTMLVideoElement | null;\n  /** The live <audio> element for this participant, or null before track arrives. */\n  audioElement: HTMLAudioElement | null;\n}\n\nexport type CallChangeCallback = (call: Call) => void;\n\n/**\n * A live call session. Obtain via `pb.calls.start()` or `pb.calls.accept()`.\n *\n * Lifecycle:\n *   connecting → active (room joined, tracks flowing)\n *   active → ended   (leave() / remote disconnect)\n *\n * Subscribe to changes via `call.subscribe(cb)` which fires on state or\n * participant changes (mirrors flags `onChange` / realtime `on` pattern).\n */\nexport class Call {\n  readonly id: string;\n\n  private _state: CallState = 'connecting';\n  private readonly _participants = new Map<string, CallParticipant>();\n  private readonly _listeners = new Set<CallChangeCallback>();\n  private readonly _room: Room;\n  private readonly _keyProvider: ExternalE2EEKeyProvider;\n\n  // PRIVATE constructor + `@internal` factory: the media-engine types (`Room`,\n  // `ExternalE2EEKeyProvider`) appear ONLY on a private constructor and an\n  // `@internal` static factory, both of which `stripInternal` (set in this\n  // package's tsconfig) removes from the emitted public `.d.ts`. So no engine type\n  // ever reaches the public API surface — the same \"no engine type in the public\n  // interface\" contract the iOS SDK enforces. Consumers obtain a `Call` only\n  // through `pb.calls.start()` / `.accept()`.\n  private constructor(callId: string, room: Room, keyProvider: ExternalE2EEKeyProvider) {\n    this.id = callId;\n    this._room = room;\n    this._keyProvider = keyProvider;\n    this._wireMediaEvents();\n  }\n\n  /** @internal — facade-only factory; stripped from the public `.d.ts`. */\n  static _create(callId: string, room: Room, keyProvider: ExternalE2EEKeyProvider): Call {\n    return new Call(callId, room, keyProvider);\n  }\n\n  // ─── State ──────────────────────────────────────────────────────────────\n\n  get state(): CallState {\n    return this._state;\n  }\n\n  /** Snapshot of current remote participants (does NOT include the local participant). */\n  get participants(): readonly CallParticipant[] {\n    return Array.from(this._participants.values());\n  }\n\n  // (No `localParticipant` accessor: it would return a raw media-engine participant\n  // object and leak the engine type onto the public API. Local mic/camera control is\n  // exposed engine-agnostically via `mute()` / `setCamera()` below.)\n\n  // ─── Subscribe ──────────────────────────────────────────────────────────\n\n  /**\n   * Subscribe to call changes (state + participant updates).\n   * Returns an `Unsubscribe` function — matches the SDK's flags/auth pattern.\n   */\n  subscribe(callback: CallChangeCallback): Unsubscribe {\n    this._listeners.add(callback);\n    return () => {\n      this._listeners.delete(callback);\n    };\n  }\n\n  // ─── Controls ───────────────────────────────────────────────────────────\n\n  /** Mute / unmute the local microphone. */\n  async mute(on: boolean): Promise<void> {\n    await this._room.localParticipant.setMicrophoneEnabled(!on);\n  }\n\n  /** Enable / disable the local camera. */\n  async setCamera(on: boolean): Promise<void> {\n    await this._room.localParticipant.setCameraEnabled(on);\n  }\n\n  /**\n   * Set a raw frame encryption key (ArrayBuffer) for this call.\n   * Design seam for SP-1.x web-MLS: call this with the MLS exporter secret\n   * to enable frame-level E2EE via the media engine's external key provider.\n   *\n   * NOTE: The room must have been opened with `e2ee` options for this to take\n   * effect. Currently calls connect WITHOUT e2ee — see module docstring.\n   *\n   * TODO(SP-1-web): wire this to MLS-derived key on session join.\n   */\n  async setMediaKey(key: ArrayBuffer): Promise<void> {\n    await this._keyProvider.setKey(key);\n  }\n\n  /** Leave the call and disconnect from the media room. */\n  async leave(): Promise<void> {\n    await this._room.disconnect();\n    this._setState('ended');\n  }\n\n  // ─── Internal ───────────────────────────────────────────────────────────\n\n  private _setState(next: CallState): void {\n    if (this._state === next) return;\n    this._state = next;\n    this._emit();\n  }\n\n  private _emit(): void {\n    for (const cb of this._listeners) cb(this);\n  }\n\n  private _upsertParticipant(p: RemoteParticipant): void {\n    const existing = this._participants.get(p.identity);\n    const entry: CallParticipant = {\n      identity: p.identity,\n      isSpeaking: p.isSpeaking,\n      audioMuted: !p.isMicrophoneEnabled,\n      videoEnabled: p.isCameraEnabled,\n      videoElement: existing?.videoElement ?? null,\n      audioElement: existing?.audioElement ?? null,\n    };\n    this._participants.set(p.identity, entry);\n  }\n\n  private _attachTrack(track: RemoteTrack, participant: RemoteParticipant): void {\n    const element = track.attach();\n    const entry = this._participants.get(participant.identity);\n    if (track.kind === Track.Kind.Video) {\n      if (entry) {\n        entry.videoElement = element as HTMLVideoElement;\n      }\n    } else if (track.kind === Track.Kind.Audio) {\n      if (entry) {\n        entry.audioElement = element as HTMLAudioElement;\n        // Auto-play audio (browser policy: audio elements can autoplay when\n        // created by a user gesture chain; the call starts from a user tap).\n        (element as HTMLAudioElement).play().catch(() => {});\n      }\n    }\n    this._emit();\n  }\n\n  private _wireMediaEvents(): void {\n    this._room\n      .on(RoomEvent.Connected, () => {\n        this._setState('active');\n      })\n      .on(\n        RoomEvent.TrackSubscribed,\n        (track: RemoteTrack, _pub: RemoteTrackPublication, participant: RemoteParticipant) => {\n          this._upsertParticipant(participant);\n          this._attachTrack(track, participant);\n        },\n      )\n      .on(\n        RoomEvent.TrackUnsubscribed,\n        (_track: RemoteTrack, _pub: RemoteTrackPublication, participant: RemoteParticipant) => {\n          this._upsertParticipant(participant);\n          this._emit();\n        },\n      )\n      .on(RoomEvent.ParticipantConnected, (participant: RemoteParticipant) => {\n        this._upsertParticipant(participant);\n        this._emit();\n      })\n      .on(RoomEvent.ParticipantDisconnected, (participant: RemoteParticipant) => {\n        this._participants.delete(participant.identity);\n        this._emit();\n      })\n      .on(RoomEvent.ActiveSpeakersChanged, (speakers) => {\n        for (const [id, entry] of this._participants) {\n          entry.isSpeaking = speakers.some((s) => s.identity === id);\n        }\n        this._emit();\n      })\n      .on(RoomEvent.Disconnected, () => {\n        this._setState('ended');\n      });\n  }\n}\n\n// ─── Facade ────────────────────────────────────────────────────────────────\n\nexport class PalbeCalls {\n  private readonly rt: PalbeRuntime;\n\n  constructor(rt: PalbeRuntime) {\n    this.rt = rt;\n  }\n\n  /**\n   * Start a new call in a messaging group.\n   *\n   * @param groupId  - Messaging group display-id (`grp_<uuidv7>`)\n   * @param media    - Which media tracks to publish (default: audio + video)\n   * @returns        A `Call` in `connecting` state; transitions to `active` once the media room connects.\n   *\n   * Every failure below arrives as kind `'server'` — this SDK's error kinds are\n   * `notConfigured | validation | unauthorized | rateLimited | server | network\n   * | decode`, and only a 401, a 429 or a 400 carrying a field-error array gets\n   * its own kind. So branch on `err.code`, never on the kind.\n   *\n   * @throws BackendError('server', { code: 'calling_unavailable' })  no SFU configured on this stack (503)\n   * @throws BackendError('server', { code: 'not_group_member' })     the caller is not a member of the group (403)\n   * @throws BackendError('server', { code: 'call_room_full' })       the call is at its participant limit (409)\n   * @throws BackendError('server', { code: 'call_provider_error' })  the media provider failed upstream (502)\n   */\n  async start(\n    groupId: string,\n    { media = ['audio', 'video'] }: { media?: Array<'audio' | 'video'> } = {},\n  ): Promise<Call> {\n    if (!groupId) {\n      throw new BackendError('validation', {\n        code: 'invalid_group_id',\n        message: 'groupId must be a non-empty string',\n      });\n    }\n    const res = await palbeRequest<StartCallResponse>(\n      this.rt,\n      'POST',\n      `/v1/messaging/groups/${encodeURIComponent(groupId)}/calls`,\n      { body: { media } },\n    );\n    return this._connect(res.call_id, res.token, res.edge_url, media);\n  }\n\n  /**\n   * Accept an incoming call in a messaging group.\n   *\n   * @param groupId  - Messaging group display-id\n   * @param callId   - Call identifier, carried by the `call_invite` the server\n   *   fans onto the group's conversation topic\n   *   (`pb.realtime.channel('messaging:conv:<rfcGroupId>').on('call_invite', …)`).\n   *   This SDK ships no web push: on the web the invite arrives over realtime or\n   *   over whatever signalling the app already runs.\n   * @param media    - Which media tracks to publish (default: audio + video)\n   */\n  async accept(\n    groupId: string,\n    callId: string,\n    { media = ['audio', 'video'] }: { media?: Array<'audio' | 'video'> } = {},\n  ): Promise<Call> {\n    const res = await palbeRequest<AcceptCallResponse>(\n      this.rt,\n      'POST',\n      `/v1/messaging/groups/${encodeURIComponent(groupId)}/calls/${encodeURIComponent(callId)}/accept`,\n      { body: {} },\n    );\n    return this._connect(callId, res.token, res.edge_url, media);\n  }\n\n  /**\n   * Decline an incoming call.\n   *\n   * @param groupId  - Messaging group display-id\n   * @param callId   - Call identifier\n   * @param reason   - Optional decline reason string\n   */\n  async decline(groupId: string, callId: string, reason?: string): Promise<void> {\n    await palbeRequest<void>(\n      this.rt,\n      'POST',\n      `/v1/messaging/groups/${encodeURIComponent(groupId)}/calls/${encodeURIComponent(callId)}/decline`,\n      { body: { reason: reason ?? '' } },\n    );\n  }\n\n  // ─── Internal ─────────────────────────────────────────────────────────\n\n  private async _connect(\n    callId: string,\n    token: string,\n    edgeUrl: string,\n    media: Array<'audio' | 'video'>,\n  ): Promise<Call> {\n    // ExternalE2EEKeyProvider is the MLS seam (see module docstring).\n    // Constructed but NOT passed to Room options — we connect without e2ee.\n    // TODO(SP-1-web): pass { e2ee: { worker, keyProvider } } when MLS is ready.\n    const keyProvider = new ExternalE2EEKeyProvider();\n\n    const room = new Room({\n      adaptiveStream: true,\n      dynacast: true,\n    });\n\n    const call = Call._create(callId, room, keyProvider);\n\n    // Connect first; track publishing follows after Connected fires.\n    // LiveKit requires the room to be connected before publishing.\n    await room.connect(edgeUrl, token);\n\n    if (media.includes('audio')) {\n      await room.localParticipant.setMicrophoneEnabled(true);\n    }\n    if (media.includes('video')) {\n      await room.localParticipant.setCameraEnabled(true);\n    }\n\n    return call;\n  }\n}\n","import type { HttpClient, PalbaseResponse } from '@palbase/core';\nimport type { FlagValue } from './types.js';\n\n/**\n * Admin client for the user-flags module — wraps the system flag CRUD\n * and per-user override endpoints exposed by `modules/user-flags`.\n *\n * Two surfaces:\n *   - `.system.*` — project-wide flag defaults (platform auth)\n *   - `.users.*`  — per-user overrides (service-side)\n */\nexport class FlagsAdminClient {\n  readonly system: SystemFlagsAdminClient;\n  readonly users: UserFlagsAdminClient;\n\n  constructor(httpClient: HttpClient) {\n    this.system = new SystemFlagsAdminClient(httpClient);\n    this.users = new UserFlagsAdminClient(httpClient);\n  }\n}\n\nexport interface SystemFlag {\n  key: string;\n  value: FlagValue;\n  /** Optional variant label when the flag is variant-typed. */\n  variant?: string;\n  /** Optional targeting rules (shape passes through from the backend). */\n  rules?: unknown;\n  updated_at?: string;\n}\n\nexport interface UserFlagOverride {\n  user_id: string;\n  key: string;\n  value: FlagValue;\n  variant?: string;\n  updated_at?: string;\n}\n\nexport interface UserFlagsSnapshot {\n  user_id: string;\n  flags: Record<string, FlagValue>;\n}\n\nexport interface BatchFlagInput {\n  /** Optional: evaluate for these user IDs. */\n  user_ids?: string[];\n  /** Optional: evaluate a subset of flag keys. */\n  keys?: string[];\n}\n\nexport interface BatchFlagResult {\n  user_id: string;\n  flags: Record<string, FlagValue>;\n}\n\nexport class SystemFlagsAdminClient {\n  constructor(private readonly http: HttpClient) {}\n\n  list(): Promise<PalbaseResponse<SystemFlag[]>> {\n    return this.http.request<SystemFlag[]>('GET', '/v1/user-flags/system');\n  }\n\n  get(key: string): Promise<PalbaseResponse<SystemFlag>> {\n    return this.http.request<SystemFlag>('GET', `/v1/user-flags/system/${encodeURIComponent(key)}`);\n  }\n\n  put(\n    key: string,\n    input: { value: FlagValue; variant?: string; rules?: unknown },\n  ): Promise<PalbaseResponse<SystemFlag>> {\n    return this.http.request<SystemFlag>(\n      'PUT',\n      `/v1/user-flags/system/${encodeURIComponent(key)}`,\n      { body: input },\n    );\n  }\n\n  delete(key: string): Promise<PalbaseResponse<void>> {\n    return this.http.request<void>('DELETE', `/v1/user-flags/system/${encodeURIComponent(key)}`);\n  }\n}\n\nexport class UserFlagsAdminClient {\n  constructor(private readonly http: HttpClient) {}\n\n  /** Read evaluated flags for a user (defaults + overrides merged). */\n  get(userId: string): Promise<PalbaseResponse<UserFlagsSnapshot>> {\n    return this.http.request<UserFlagsSnapshot>(\n      'GET',\n      `/v1/user-flags/users/${encodeURIComponent(userId)}`,\n    );\n  }\n\n  /**\n   * Replace the full set of overrides for a user in one call. Any key not\n   * present in `overrides` is removed.\n   */\n  putBulk(\n    userId: string,\n    overrides: Record<string, FlagValue>,\n  ): Promise<PalbaseResponse<UserFlagsSnapshot>> {\n    return this.http.request<UserFlagsSnapshot>(\n      'PUT',\n      `/v1/user-flags/users/${encodeURIComponent(userId)}`,\n      { body: { overrides } },\n    );\n  }\n\n  putOverride(\n    userId: string,\n    key: string,\n    input: { value: FlagValue; variant?: string },\n  ): Promise<PalbaseResponse<UserFlagOverride>> {\n    return this.http.request<UserFlagOverride>(\n      'PUT',\n      `/v1/user-flags/users/${encodeURIComponent(userId)}/${encodeURIComponent(key)}`,\n      { body: input },\n    );\n  }\n\n  deleteOverride(userId: string, key: string): Promise<PalbaseResponse<void>> {\n    return this.http.request<void>(\n      'DELETE',\n      `/v1/user-flags/users/${encodeURIComponent(userId)}/${encodeURIComponent(key)}`,\n    );\n  }\n\n  deleteAllOverrides(userId: string): Promise<PalbaseResponse<void>> {\n    return this.http.request<void>('DELETE', `/v1/user-flags/users/${encodeURIComponent(userId)}`);\n  }\n\n  /** Evaluate flags for a batch of users / a subset of keys. */\n  batch(input?: BatchFlagInput): Promise<PalbaseResponse<BatchFlagResult[]>> {\n    return this.http.request<BatchFlagResult[]>('POST', '/v1/user-flags/batch', {\n      body: input ?? {},\n    });\n  }\n}\n","import type { HttpClient, PalbaseResponse } from '@palbase/core';\nimport type {\n  Flag,\n  FlagContext,\n  FlagSource,\n  FlagsDelta,\n  FlagsSnapshot,\n  FlagValue,\n  FlagVariant,\n} from './types.js';\n\nconst FLAG_NAME_RE = /^[a-zA-Z0-9_-]+$/;\n\n/**\n * Wire shape of the merged read endpoints `GET /v1/user-flags` (current auth\n * user) and `GET /v1/user-flags/users/{userId}` (a named user). Both return the\n * server-resolved flag values (system defaults + that user's overrides).\n */\ninterface MergedSnapshotResponse {\n  values: Record<string, FlagValue> | null;\n  fetched_at: string;\n}\n\n/** Coerce a resolved flag value to an enabled boolean. A boolean flag is itself;\n * any other present, non-empty, non-zero value counts as enabled; missing = off. */\nfunction flagEnabled(value: FlagValue | undefined): boolean {\n  if (typeof value === 'boolean') return value;\n  return value != null && value !== 0 && value !== '';\n}\n\n/** Derive a {@link FlagVariant} from a resolved flag value. A \"variant\" is the\n * value of a multivariate (string) flag, so a string flag's value IS its variant\n * name. Boolean / numeric / object flags and missing flags have no variant →\n * `null` (so a caller's `getVariant` resolves to null, per the \"no variant\"\n * contract). */\nfunction flagVariant(value: FlagValue | undefined): FlagVariant | null {\n  return typeof value === 'string' ? { name: value } : null;\n}\n\n/** Re-map the `data` of a successful response; pass errors / empty bodies through\n * unchanged (typed to the new payload). */\nfunction mapResponse<A, B>(res: PalbaseResponse<A>, fn: (data: A) => B): PalbaseResponse<B> {\n  if (res.error || res.data == null) {\n    return { ...res, data: null } as PalbaseResponse<B>;\n  }\n  return { ...res, data: fn(res.data) };\n}\n\n/**\n * Result of writing a single user override (`PUT .../{userId}/{key}`) — echoes\n * the resolved key/value with `source: \"override\"`.\n */\nexport interface SetOverrideResult {\n  key: string;\n  value: FlagValue;\n  source: FlagSource;\n}\n\n/**\n * Result of replacing all overrides for one user (`PUT .../{userId}`).\n * `values` is the resolved override set after the write.\n */\nexport interface SetOverridesResult {\n  values: Record<string, FlagValue>;\n}\n\n/**\n * Result of clearing a single override (`DELETE .../{userId}/{key}`). `value`\n * is the system (default) value the user falls back to after removal, with\n * `source: \"system\"`.\n */\nexport interface ClearOverrideResult {\n  key: string;\n  value: FlagValue;\n  source: FlagSource;\n}\n\n/** Result of clearing all overrides for a user (`DELETE .../{userId}`). */\nexport interface ClearAllOverridesResult {\n  deleted: number;\n}\n\n/** One cross-user override operation for {@link FlagsServiceClient.batchSetOverrides}. */\nexport interface BatchOverrideOperation {\n  userId: string;\n  values: Record<string, FlagValue>;\n}\n\n/** Result of a cross-user batch write (`POST /v1/user-flags/batch`). */\nexport interface BatchSetOverridesResult {\n  applied: number;\n}\n\n/**\n * Cross-user admin write surface, reached via {@link FlagsClient.asService}.\n *\n * These five methods set/clear overrides for an ARBITRARY user (named\n * explicitly), so they bypass the current-user scope that the default\n * `FlagsClient.setOverride(...)` is bound to. Mirrors the\n * `Database` / `Database.asService()` split: the privileged cross-user path is\n * moved OFF the default surface so it is greppable + intentional. Requires a\n * privileged key (service_role / managed runtime).\n */\nexport interface FlagsServiceClient {\n  /**\n   * Set (or replace) a single feature-flag override for one user.\n   * `PUT /v1/user-flags/users/{userId}/{key}` with body `{ value }`.\n   */\n  setOverrideForUser(\n    userId: string,\n    key: string,\n    value: FlagValue,\n  ): Promise<PalbaseResponse<SetOverrideResult>>;\n\n  /**\n   * Set multiple feature-flag overrides for one user in a single call.\n   * `PUT /v1/user-flags/users/{userId}` with body `{ values }`.\n   */\n  setOverridesForUser(\n    userId: string,\n    values: Record<string, FlagValue>,\n  ): Promise<PalbaseResponse<SetOverridesResult>>;\n\n  /**\n   * Clear a single override for one user, restoring the project (system)\n   * default for that key. `DELETE /v1/user-flags/users/{userId}/{key}`.\n   */\n  clearOverrideForUser(userId: string, key: string): Promise<PalbaseResponse<ClearOverrideResult>>;\n\n  /**\n   * Clear all overrides for one user, restoring project defaults for every\n   * key. `DELETE /v1/user-flags/users/{userId}`.\n   */\n  clearAllOverridesForUser(userId: string): Promise<PalbaseResponse<ClearAllOverridesResult>>;\n\n  /**\n   * Apply override writes across many users in one request (max 1000 ops).\n   * `POST /v1/user-flags/batch` with body `{ operations: [{ user_id, values }] }`.\n   */\n  batchSetOverrides(\n    operations: ReadonlyArray<BatchOverrideOperation>,\n  ): Promise<PalbaseResponse<BatchSetOverridesResult>>;\n}\n\n/**\n * Stateless, one-shot HTTP wrapper for the flags API. Reads (`isEnabled` /\n * `getVariant` / `getAll`) resolve against the live `GET /v1/user-flags` merged\n * endpoint and derive their result from the returned value map; it is also the\n * transport layer underneath `FlagsPool` (which adds caching, polling and\n * auth-state binding on top).\n *\n * Writes mirror the `Database` / `Database.asService()` model:\n * — {@link setOverride} (default) writes an override for the CURRENT user (the\n *   `getCurrentUserId` getter supplied at construction). No userId argument; it\n *   errors clearly when there is no signed-in user.\n * — {@link asService} returns the cross-user admin surface\n *   ({@link FlagsServiceClient}) for writing overrides for an arbitrary user.\n */\nexport class FlagsClient {\n  private readonly httpClient: HttpClient;\n  private readonly getCurrentUserId?: () => string | null | undefined;\n\n  /**\n   * @param httpClient transport.\n   * @param getCurrentUserId optional getter resolving the signed-in user's id\n   *   for {@link setOverride}. When omitted (or it returns no id), `setOverride`\n   *   errors and the caller must use {@link asService} for cross-user writes.\n   */\n  constructor(httpClient: HttpClient, getCurrentUserId?: () => string | null | undefined) {\n    this.httpClient = httpClient;\n    this.getCurrentUserId = getCurrentUserId;\n  }\n\n  async isEnabled(flagName: string, context?: FlagContext): Promise<PalbaseResponse<boolean>> {\n    if (!FLAG_NAME_RE.test(flagName)) {\n      throw new Error(\n        `Invalid flag name: \"${flagName}\". Flag names must match ${FLAG_NAME_RE.source}`,\n      );\n    }\n\n    const res = await this.httpClient.request<MergedSnapshotResponse>(\n      'GET',\n      this.mergedPath(context),\n    );\n    return mapResponse(res, (snap) => flagEnabled(snap.values?.[flagName]));\n  }\n\n  async getVariant(flagName: string, context?: FlagContext): Promise<PalbaseResponse<FlagVariant>> {\n    if (!FLAG_NAME_RE.test(flagName)) {\n      throw new Error(\n        `Invalid flag name: \"${flagName}\". Flag names must match ${FLAG_NAME_RE.source}`,\n      );\n    }\n\n    const res = await this.httpClient.request<MergedSnapshotResponse>(\n      'GET',\n      this.mergedPath(context),\n    );\n    // Inlined (not via mapResponse) so the `FlagVariant | null` payload stays\n    // assignable to the public `PalbaseResponse<FlagVariant>` return type.\n    if (res.error || res.data == null) {\n      return { ...res, data: null };\n    }\n    return { ...res, data: flagVariant(res.data.values?.[flagName]) };\n  }\n\n  async getAll(context?: FlagContext): Promise<PalbaseResponse<Flag[]>> {\n    const res = await this.httpClient.request<MergedSnapshotResponse>(\n      'GET',\n      this.mergedPath(context),\n    );\n    return mapResponse(res, (snap) => {\n      const values = snap.values ?? {};\n      return Object.keys(values).map((name) => {\n        const value = values[name];\n        const flag: Flag = { name, enabled: flagEnabled(value) };\n        if (typeof value === 'string') flag.variant = { name: value };\n        return flag;\n      });\n    });\n  }\n\n  /**\n   * Cold-start read: the full merged flag set for the current auth identity.\n   * With a Bearer token the backend returns the user-merged view; without one\n   * it returns project (system) defaults.\n   */\n  snapshot(validator?: string): Promise<PalbaseResponse<FlagsSnapshot>> {\n    return this.httpClient.request<FlagsSnapshot>(\n      'GET',\n      '/v1/user-flags/snapshot',\n      validator ? { headers: { 'If-None-Match': validator } } : undefined,\n    );\n  }\n\n  /**\n   * Incremental read of version-ordered ops since `sinceVersion`.\n   *\n   * `validator` is the ETag the SERVER last issued, echoed verbatim so an\n   * unchanged server can answer `304 Not Modified` cheaply. It used to be the\n   * cursor itself, and the server's ETag is `\"<sync_version>-<client-context\n   * hash>\"` — two values that can never compare equal, so the 304 this method\n   * exists to earn was unreachable in production (measured on centauri\n   * 2026-09-11: every 30s poll came back 200 with a full body).\n   *\n   * The hash half is not decoration: it is how the server notices the CLIENT\n   * CONTEXT changed (app version, locale, device targeting), a change that moves\n   * no row version and so cannot be seen through `since` alone. Sending nothing\n   * would earn a 304 for values that have genuinely re-resolved.\n   *\n   * The 304 surfaces as a `PalbaseResponse` with `status === 304` (the core http\n   * client maps non-2xx to an error/empty body); callers treat that as\n   * \"no change\".\n   */\n  delta(sinceVersion: string, validator?: string): Promise<PalbaseResponse<FlagsDelta>> {\n    return this.httpClient.request<FlagsDelta>(\n      'GET',\n      `/v1/user-flags/delta?since=${encodeURIComponent(sinceVersion)}`,\n      validator ? { headers: { 'If-None-Match': validator } } : undefined,\n    );\n  }\n\n  /**\n   * Set (or replace) a single feature-flag override for the CURRENT USER.\n   *\n   * Resolves the signed-in user from the `getCurrentUserId` getter supplied at\n   * construction and issues `PUT /v1/user-flags/users/{uid}/{key}` with body\n   * `{ value }`. No userId argument — the override is bound to the current\n   * user, so no admin power is required.\n   *\n   * Errors when there is no signed-in user (anonymous, or no getter supplied);\n   * use {@link asService}`.setOverrideForUser(userId, key, value)` to write a\n   * flag override for an arbitrary (cross-user) target.\n   */\n  setOverride(key: string, value: FlagValue): Promise<PalbaseResponse<SetOverrideResult>> {\n    const userId = this.getCurrentUserId?.();\n    if (!userId) {\n      throw new Error(\n        'setOverride requires a signed-in user; use FlagsClient.asService().setOverrideForUser(userId, key, value) for cross-user writes',\n      );\n    }\n    return this.httpClient.request<SetOverrideResult>(\n      'PUT',\n      `/v1/user-flags/users/${encodeURIComponent(userId)}/${encodeURIComponent(key)}`,\n      { body: { value } },\n    );\n  }\n\n  /**\n   * Return the cross-user admin write surface ({@link FlagsServiceClient}).\n   *\n   * Use sparingly and explicitly — the default {@link setOverride} path is\n   * bound to the current user; `asService()` is how you write a flag override\n   * for an ARBITRARY user. Mirrors `Database.asService()`. The returned client\n   * shares this client's transport (the privileged service_role key).\n   */\n  asService(): FlagsServiceClient {\n    const http = this.httpClient;\n    return {\n      setOverrideForUser(userId, key, value) {\n        return http.request<SetOverrideResult>(\n          'PUT',\n          `/v1/user-flags/users/${encodeURIComponent(userId)}/${encodeURIComponent(key)}`,\n          { body: { value } },\n        );\n      },\n      setOverridesForUser(userId, values) {\n        return http.request<SetOverridesResult>(\n          'PUT',\n          `/v1/user-flags/users/${encodeURIComponent(userId)}`,\n          { body: { values } },\n        );\n      },\n      clearOverrideForUser(userId, key) {\n        return http.request<ClearOverrideResult>(\n          'DELETE',\n          `/v1/user-flags/users/${encodeURIComponent(userId)}/${encodeURIComponent(key)}`,\n        );\n      },\n      clearAllOverridesForUser(userId) {\n        return http.request<ClearAllOverridesResult>(\n          'DELETE',\n          `/v1/user-flags/users/${encodeURIComponent(userId)}`,\n        );\n      },\n      batchSetOverrides(operations) {\n        return http.request<BatchSetOverridesResult>('POST', '/v1/user-flags/batch', {\n          body: {\n            operations: operations.map((op) => ({\n              user_id: op.userId,\n              values: op.values,\n            })),\n          },\n        });\n      },\n    };\n  }\n\n  /**\n   * Resolve the merged-read path for a context. With `context.userId` present the\n   * read targets that specific user's merged view (`/v1/user-flags/users/{id}`, a\n   * privileged cross-user read); otherwise the current auth user's view\n   * (`/v1/user-flags`). `context.properties` has no server-side targeting support\n   * in the user-flags module and is ignored.\n   */\n  private mergedPath(context?: FlagContext): string {\n    const uid = context?.userId;\n    return uid ? `/v1/user-flags/users/${encodeURIComponent(uid)}` : '/v1/user-flags';\n  }\n}\n","import type { FlagsClient } from './flags-client.js';\nimport type {\n  AuthStateSource,\n  FlagSource,\n  FlagsChangeListener,\n  FlagsSnapshot,\n  FlagValue,\n  Unsubscribe,\n} from './types.js';\n\n/** Options controlling pool behaviour. All have sensible defaults. */\nexport interface FlagsPoolOptions {\n  /** Delta poll interval in ms. Default 30_000. Set `0` to disable polling. */\n  pollIntervalMs?: number;\n  /**\n   * localStorage key for cold-start persistence. Default\n   * `palbase.flags.snapshot`. Ignored when localStorage is unavailable (SSR).\n   */\n  storageKey?: string;\n  /** Disable localStorage persistence even in the browser. Default false. */\n  persist?: boolean;\n  /**\n   * Auth-state source. When provided, the pool re-snapshots on sign-in and\n   * sign-out so the cache switches between user overrides and project defaults.\n   */\n  auth?: AuthStateSource;\n  /**\n   * Inject timer/visibility primitives for testing. Defaults to the global\n   * `setInterval`/`clearInterval` and the browser `document`/`window`.\n   */\n  env?: PoolEnv;\n}\n\n/** Injectable runtime seams (browser globals) so the pool stays testable. */\nexport interface PoolEnv {\n  now(): number;\n  setInterval(handler: () => void, ms: number): IntervalHandle;\n  clearInterval(handle: IntervalHandle): void;\n  /** localStorage-like store, or `null` when unavailable (SSR). */\n  storage: KeyValueStore | null;\n  /** Visibility source, or `null` when there is no document (SSR). */\n  visibility: VisibilitySource | null;\n}\n\nexport type IntervalHandle = ReturnType<typeof setInterval>;\n\nexport interface KeyValueStore {\n  getItem(key: string): string | null;\n  setItem(key: string, value: string): void;\n  removeItem(key: string): void;\n}\n\nexport interface VisibilitySource {\n  isHidden(): boolean;\n  onVisibilityChange(cb: () => void): Unsubscribe;\n}\n\nconst DEFAULT_POLL_MS = 30_000;\nconst DEFAULT_STORAGE_KEY = 'palbase.flags.snapshot';\n\ninterface CacheState {\n  values: Record<string, FlagValue>;\n  sources: Record<string, FlagSource>;\n  syncVersion: string | null;\n}\n\nconst EMPTY_STATE: CacheState = {\n  values: {},\n  sources: {},\n  syncVersion: null,\n};\n\n/**\n * Stateful, auto-pooling flag cache built on top of the stateless\n * {@link FlagsClient} transport.\n *\n * Responsibilities:\n *  - Cold start from a snapshot (and from localStorage for instant boot).\n *  - Poll deltas with conditional `If-None-Match` (304 → no-op).\n *  - Re-snapshot on a version gap / tombstone-expiry signalled by the backend.\n *  - Re-snapshot on auth sign-in / sign-out (override view ↔ defaults).\n *  - Notify subscribers (drives `useFlag`/`useFlags`).\n *\n * Resolution is server-side: `get(key, default)` returns the cached value or\n * the supplied default; the pool never merges.\n */\nexport class FlagsPool {\n  private readonly transport: FlagsClient;\n  private readonly pollIntervalMs: number;\n  private readonly storageKey: string;\n  private readonly persist: boolean;\n  private readonly env: PoolEnv;\n\n  private state: CacheState = EMPTY_STATE;\n  /**\n   * The validator the SERVER issued, echoed on the next conditional request.\n   *\n   * In memory only, deliberately: a cold boot hydrates values from storage and\n   * then asks for the truth unconditionally, so a stale or corrupt cached body\n   * can never be confirmed by a validator that outlived it.\n   */\n  private validator: string | undefined;\n  private readonly listeners = new Set<FlagsChangeListener>();\n\n  private timer: IntervalHandle | null = null;\n  private polling = false;\n  private started = false;\n  private destroyed = false;\n\n  private readyPromise: Promise<void>;\n  private resolveReady: (() => void) | null = null;\n  private firstLoadDone = false;\n\n  private authUnsub: Unsubscribe | null = null;\n  private visibilityUnsub: Unsubscribe | null = null;\n  private lastAuthHasSession: boolean | null = null;\n\n  /** Cached frozen view for `getSnapshot` identity stability (React). */\n  private frozenView: Readonly<Record<string, FlagValue>> = Object.freeze({});\n  private viewDirty = true;\n\n  constructor(transport: FlagsClient, options: FlagsPoolOptions = {}) {\n    this.transport = transport;\n    this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_MS;\n    this.storageKey = options.storageKey ?? DEFAULT_STORAGE_KEY;\n    this.persist = options.persist ?? true;\n    this.env = options.env ?? defaultEnv();\n\n    this.readyPromise = new Promise<void>((resolve) => {\n      this.resolveReady = resolve;\n    });\n\n    // Hydrate synchronously from persisted snapshot for instant cold-start.\n    this.hydrateFromStorage();\n\n    if (options.auth) {\n      this.bindAuth(options.auth);\n    }\n  }\n\n  // ---- public surface -----------------------------------------------------\n\n  /** Start cold-start fetch + polling + visibility binding. Idempotent. */\n  start(): void {\n    if (this.started || this.destroyed) {\n      return;\n    }\n    this.started = true;\n\n    void this.refresh();\n    this.startPolling();\n    this.bindVisibility();\n  }\n\n  /** Resolves once the first snapshot (or persisted hydrate) is available. */\n  ready(): Promise<void> {\n    if (this.firstLoadDone) {\n      return Promise.resolve();\n    }\n    if (!this.started) {\n      this.start();\n    }\n    return this.readyPromise;\n  }\n\n  /** Returns the cached value for `key`, or `fallback` when absent. */\n  get<T extends FlagValue>(key: string, fallback: T): T {\n    const value = this.state.values[key];\n    return value === undefined ? fallback : (value as T);\n  }\n\n  /** Boolean convenience: cached value strictly equals `true`, else `fallback`. */\n  isEnabled(key: string, fallback = false): boolean {\n    const value = this.state.values[key];\n    if (value === undefined) {\n      return fallback;\n    }\n    return value === true;\n  }\n\n  /** Returns the cached value's source (`system`/`user`) when known. */\n  getSource(key: string): FlagSource | undefined {\n    return this.state.sources[key];\n  }\n\n  /** Returns a frozen snapshot of all cached values (stable identity). */\n  all(): Readonly<Record<string, FlagValue>> {\n    if (this.viewDirty) {\n      this.frozenView = Object.freeze({ ...this.state.values });\n      this.viewDirty = false;\n    }\n    return this.frozenView;\n  }\n\n  /** Current opaque sync version (null before first load). */\n  get syncVersion(): string | null {\n    return this.state.syncVersion;\n  }\n\n  /** Subscribe to any change in the cached set. Returns unsubscribe. */\n  onChange(listener: FlagsChangeListener): Unsubscribe {\n    this.listeners.add(listener);\n    return () => {\n      this.listeners.delete(listener);\n    };\n  }\n\n  /**\n   * `useSyncExternalStore`-compatible subscribe. Auto-starts the pool on first\n   * subscription so a React component mount triggers cold-start.\n   */\n  subscribe = (listener: FlagsChangeListener): Unsubscribe => {\n    if (!this.started) {\n      this.start();\n    }\n    return this.onChange(listener);\n  };\n\n  /** Force an immediate re-snapshot (used on auth change / manual refresh). */\n  async refresh(): Promise<void> {\n    if (this.destroyed) {\n      return;\n    }\n    const res = await this.transport.snapshot(this.validator);\n    if (res.etag) {\n      this.validator = res.etag;\n    }\n    if (res.error || res.data == null) {\n      // Keep any persisted/previous state; still mark first load complete so\n      // `ready()` does not hang forever on a transient network failure.\n      this.markFirstLoadDone();\n      return;\n    }\n    this.applySnapshot(res.data);\n    this.markFirstLoadDone();\n  }\n\n  /** Stop timers and detach all auth/visibility listeners. */\n  destroy(): void {\n    this.destroyed = true;\n    this.stopPolling();\n    this.authUnsub?.();\n    this.authUnsub = null;\n    this.visibilityUnsub?.();\n    this.visibilityUnsub = null;\n    this.listeners.clear();\n  }\n\n  // ---- internals ----------------------------------------------------------\n\n  private async poll(): Promise<void> {\n    if (this.polling || this.destroyed) {\n      return;\n    }\n    const since = this.state.syncVersion;\n    if (since == null) {\n      // No baseline yet — fall back to a snapshot.\n      await this.refresh();\n      return;\n    }\n    this.polling = true;\n    try {\n      const res = await this.transport.delta(since, this.validator);\n      if (res.etag) {\n        this.validator = res.etag;\n      }\n      if (res.status === 304) {\n        return; // not modified — cheap no-op\n      }\n      if (res.error || res.data == null) {\n        // A version gap / expired tombstone window is signalled by 409/410.\n        if (res.status === 409 || res.status === 410) {\n          await this.refresh();\n        }\n        return;\n      }\n      this.applyDelta(res.data.ops as readonly unknown[], res.data.sync_version);\n    } finally {\n      this.polling = false;\n    }\n  }\n\n  private applySnapshot(snapshot: FlagsSnapshot): void {\n    this.state = {\n      values: { ...snapshot.values },\n      sources: { ...(snapshot.sources ?? {}) },\n      syncVersion: snapshot.sync_version,\n    };\n    this.viewDirty = true;\n    this.persistState();\n    this.notify();\n  }\n\n  private applyDelta(ops: readonly unknown[], nextVersion: string): void {\n    // Each op is re-narrowed defensively via `isDeltaOp`.\n    const values = { ...this.state.values };\n    const sources = { ...this.state.sources };\n    let changed = false;\n\n    for (const raw of ops) {\n      if (!isDeltaOp(raw)) {\n        continue;\n      }\n      if (raw.op === 'delete') {\n        if (raw.key in values) {\n          delete values[raw.key];\n          delete sources[raw.key];\n          changed = true;\n        }\n      } else {\n        values[raw.key] = raw.value;\n        if (raw.source) {\n          sources[raw.key] = raw.source;\n        }\n        changed = true;\n      }\n    }\n\n    this.state = { values, sources, syncVersion: this.advance(nextVersion) };\n    if (changed) {\n      this.viewDirty = true;\n      this.persistState();\n      this.notify();\n    } else {\n      // version still advances even with no value change\n      this.persistState();\n    }\n  }\n\n  private startPolling(): void {\n    if (this.pollIntervalMs <= 0 || this.timer != null) {\n      return;\n    }\n    this.timer = this.env.setInterval(() => {\n      void this.poll();\n    }, this.pollIntervalMs);\n  }\n\n  private stopPolling(): void {\n    if (this.timer != null) {\n      this.env.clearInterval(this.timer);\n      this.timer = null;\n    }\n  }\n\n  private bindVisibility(): void {\n    const vis = this.env.visibility;\n    if (!vis) {\n      return;\n    }\n    this.visibilityUnsub = vis.onVisibilityChange(() => {\n      if (vis.isHidden()) {\n        this.stopPolling();\n      } else {\n        // Came back to foreground: catch up immediately, then resume polling.\n        void this.poll();\n        this.startPolling();\n      }\n    });\n  }\n\n  private bindAuth(auth: AuthStateSource): void {\n    const handle = auth.onAuthStateChange((_event, session) => {\n      const hasSession = session != null;\n      // Fires immediately with current state on subscribe; only re-snapshot\n      // when the identity actually flips (sign-in ↔ sign-out), not on every\n      // token refresh, to avoid redundant cold-starts.\n      if (this.lastAuthHasSession === null) {\n        this.lastAuthHasSession = hasSession;\n        return;\n      }\n      if (hasSession !== this.lastAuthHasSession) {\n        this.lastAuthHasSession = hasSession;\n        if (this.started) {\n          void this.refresh();\n        }\n      }\n    });\n    // Normalize the Supabase-style handle to a plain unsubscribe.\n    this.authUnsub = () => handle.data.subscription.unsubscribe();\n  }\n\n  private notify(): void {\n    for (const listener of this.listeners) {\n      listener();\n    }\n  }\n\n  private markFirstLoadDone(): void {\n    if (!this.firstLoadDone) {\n      this.firstLoadDone = true;\n      this.resolveReady?.();\n      this.resolveReady = null;\n    }\n  }\n\n  private hydrateFromStorage(): void {\n    if (!this.persist) {\n      return;\n    }\n    const store = this.env.storage;\n    if (!store) {\n      return;\n    }\n    const raw = store.getItem(this.storageKey);\n    if (!raw) {\n      return;\n    }\n    const parsed = parsePersisted(raw);\n    if (!parsed) {\n      return;\n    }\n    this.state = parsed;\n    this.viewDirty = true;\n    // A persisted snapshot is enough to satisfy `ready()` instantly; a live\n    // `refresh()` will still run on `start()` to revalidate.\n    this.markFirstLoadDone();\n  }\n\n  /**\n   * A DELTA's cursor may not move backwards.\n   *\n   * `FlagsDelta.sync_version` is documented as monotonic in `types.ts`, and\n   * nothing enforced it. A delta carries a change set, never a whole truth, so a\n   * cursor lower than the one already held cannot be believed — believing it\n   * silently re-requests everything the client already has. Measured on centauri\n   * (8bbwb2pbm) 2026-09-11 against a stack whose delta reported the max row\n   * version in the response, and 0 when there were no rows:\n   *\n   *     since=0  -> ops up to 14, sync_version \"14\"\n   *     since=14 -> ops [],       sync_version \"0\"   <- the cursor fell to zero\n   *     since=0  -> the whole set again, every 30s, for ever\n   *\n   * The server side of that is fixed, but a published client outlives the stack\n   * version it happens to meet — tenants roll on their own schedule — so the\n   * invariant belongs on both sides.\n   *\n   * A genuine rewind (a restored stack) has its own channel: the backend answers\n   * 409/410 when it cannot serve incrementally from our version, and `poll()`\n   * re-snapshots on it. Silence is not that signal.\n   *\n   * A non-numeric cursor is adopted as-is: the format is the server's, and this\n   * client must not invent an ordering for one it cannot read.\n   */\n  private advance(proposed: string): string {\n    const current = this.state.syncVersion;\n    if (current == null) {\n      return proposed;\n    }\n    const next = Number(proposed);\n    const held = Number(current);\n    if (!Number.isFinite(next) || !Number.isFinite(held)) {\n      return proposed;\n    }\n    return next >= held ? proposed : current;\n  }\n\n  private persistState(): void {\n    if (!this.persist) {\n      return;\n    }\n    const store = this.env.storage;\n    if (!store || this.state.syncVersion == null) {\n      return;\n    }\n    try {\n      store.setItem(this.storageKey, JSON.stringify(this.state));\n    } catch {\n      // Quota / private-mode — persistence is best-effort.\n    }\n  }\n}\n\n// ---- guards / helpers -----------------------------------------------------\n\nfunction isDeltaOp(\n  value: unknown,\n): value is\n  | { op: 'put'; key: string; value: FlagValue; source?: FlagSource }\n  | { op: 'delete'; key: string } {\n  if (typeof value !== 'object' || value === null) {\n    return false;\n  }\n  const rec = value as Record<string, unknown>;\n  if (typeof rec.key !== 'string') {\n    return false;\n  }\n  if (rec.op === 'delete') {\n    return true;\n  }\n  return rec.op === 'put' && 'value' in rec;\n}\n\nfunction parsePersisted(raw: string): CacheState | null {\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch {\n    return null;\n  }\n  if (typeof parsed !== 'object' || parsed === null) {\n    return null;\n  }\n  const rec = parsed as Record<string, unknown>;\n  if (typeof rec.syncVersion !== 'string') {\n    return null;\n  }\n  if (typeof rec.values !== 'object' || rec.values === null) {\n    return null;\n  }\n  const sources =\n    typeof rec.sources === 'object' && rec.sources !== null\n      ? (rec.sources as Record<string, FlagSource>)\n      : {};\n  return {\n    values: rec.values as Record<string, FlagValue>,\n    sources,\n    syncVersion: rec.syncVersion,\n  };\n}\n\n/** Build the default browser/Node runtime seam, guarding all DOM globals. */\nfunction defaultEnv(): PoolEnv {\n  const storage = resolveStorage();\n  const visibility = resolveVisibility();\n  return {\n    now: () => Date.now(),\n    setInterval: (handler, ms) => setInterval(handler, ms),\n    clearInterval: (handle) => clearInterval(handle),\n    storage,\n    visibility,\n  };\n}\n\nfunction resolveStorage(): KeyValueStore | null {\n  try {\n    if (typeof localStorage === 'undefined') {\n      return null;\n    }\n    // Touch it to surface private-mode/security errors up front.\n    const probe = '__palbase_flags_probe__';\n    localStorage.setItem(probe, '1');\n    localStorage.removeItem(probe);\n    return localStorage;\n  } catch {\n    return null;\n  }\n}\n\nfunction resolveVisibility(): VisibilitySource | null {\n  if (typeof document === 'undefined') {\n    return null;\n  }\n  const doc = document;\n  return {\n    isHidden: () => doc.visibilityState === 'hidden',\n    onVisibilityChange: (cb) => {\n      doc.addEventListener('visibilitychange', cb);\n      return () => doc.removeEventListener('visibilitychange', cb);\n    },\n  };\n}\n","import type { PalbaseResponse } from '@palbase/core';\nimport {\n  type AuthStateSource,\n  FlagsClient,\n  FlagsPool,\n  type FlagsPoolOptions,\n  type FlagValue,\n  type FlagVariant,\n  type PoolEnv,\n} from '@palbase/flags';\nimport type { PalbeAuth, Unsubscribe } from './auth-facade.js';\nimport { BackendError } from './errors.js';\nimport type { PalbeRuntime } from './runtime.js';\n\nexport type { FlagValue } from '@palbase/flags';\n\n/** Frozen view of all cached flag values (what `all()` returns / `changes()` yields). */\nexport type FlagsView = Readonly<Record<string, FlagValue>>;\n\n/**\n * Adapt PalbeAuth's `(state: AuthState) => void` listener contract to the\n * Supabase-style `AuthStateSource` FlagsPool binds to (`(event, session)`\n * callback + `{ data: { subscription: { unsubscribe } } }` handle).\n *\n * PalbeAuth fires the callback IMMEDIATELY on subscribe (iOS parity); the\n * pool's bindAuth treats that first call as the baseline (its\n * `lastAuthHasSession === null` branch) and only re-snapshots on a later\n * identity flip — exactly the behaviour we want, no suppression needed.\n */\nexport function palbeAuthAdapter(auth: PalbeAuth): AuthStateSource {\n  return {\n    onAuthStateChange(callback) {\n      const unsubscribe = auth.onAuthStateChange(() => {\n        // Token truth, not state.status: a restored session (page reload) has\n        // no cachedUser yet, so snapshotState() reports signedOut while\n        // isSignedIn is true. Using the token-manager directly ensures the pool\n        // baseline matches the actual session presence on the first fire.\n        const signedIn = auth.isSignedIn;\n        callback(signedIn ? 'SIGNED_IN' : 'SIGNED_OUT', signedIn ? { signedIn } : null);\n      });\n      return { data: { subscription: { unsubscribe } } };\n    },\n  };\n}\n\n/**\n * Server-side pool seams: no storage, no visibility, and — because polling is\n * disabled via `pollIntervalMs: 0` — an interval seam that must never be\n * reached. Throwing keeps a future regression loud instead of leaking timers\n * into RSC/route-handler processes.\n */\nfunction serverPoolEnv(): PoolEnv {\n  return {\n    now: () => Date.now(),\n    setInterval: () => {\n      throw new Error('palbe flags: polling is disabled server-side');\n    },\n    clearInterval: () => {},\n    storage: null,\n    visibility: null,\n  };\n}\n\n/** Object.is for primitives; objects/arrays by JSON text. Snapshots are\n * re-frozen NEW references on every re-snapshot, so reference equality would\n * report structurally-identical values as \"changed\". JSON compare is\n * key-order-sensitive — a server that reorders keys without changing values\n * may fire a spurious per-key callback (accepted tradeoff, documented). */\nfunction sameFlagValue(a: FlagValue | undefined, b: FlagValue | undefined): boolean {\n  if (Object.is(a, b)) return true;\n  if (typeof a === 'object' && a !== null && typeof b === 'object' && b !== null) {\n    return JSON.stringify(a) === JSON.stringify(b);\n  }\n  return false;\n}\n\n/**\n * `pb.flags` — iOS-parity facade over `FlagsPool` (cache + delta polling +\n * auth binding) and `FlagsClient` (stateless transport).\n *\n * Start semantics: the facade is constructed lazily (first `pb.flags` touch).\n * - Browser: the pool starts right here in the constructor — cold snapshot +\n *   30s delta polling + visibility pause. \"First use starts the machinery\"\n *   without per-method start checks.\n * - Server (no `document`): NEVER auto-starts. `ready()`/`refresh()` are\n *   one-shot snapshot fetches with zero timers and zero storage access, so a\n *   pbServer request that reads flags pays exactly one HTTP call.\n *\n * localStorage persistence is scoped per environment ref (`palbe.flags.<ref>`),\n * mirroring the session-storage key convention.\n */\nexport class PalbeFlags {\n  private readonly transport: FlagsClient;\n  private readonly pool: FlagsPool;\n\n  constructor(rt: PalbeRuntime) {\n    this.transport = new FlagsClient(rt.http);\n    const browser = typeof document !== 'undefined';\n    const ref = rt.projectRef;\n    const options: FlagsPoolOptions = {\n      auth: palbeAuthAdapter(rt.auth),\n      ...(ref ? { storageKey: `palbe.flags.${ref}` } : {}),\n      ...(browser ? {} : { pollIntervalMs: 0, env: serverPoolEnv() }),\n    };\n    this.pool = new FlagsPool(this.transport, options);\n    if (browser) this.pool.start();\n  }\n\n  /** Resolves once the first snapshot (or persisted hydrate) is available. Auto-starts the pool. */\n  ready(): Promise<void> {\n    return this.pool.ready();\n  }\n\n  /** Force an immediate re-snapshot. */\n  refresh(): Promise<void> {\n    return this.pool.refresh();\n  }\n\n  /** Frozen snapshot of all cached values (identity-stable until a change). */\n  all(): FlagsView {\n    return this.pool.all();\n  }\n\n  /** Raw cached value for `key`, or `undefined` when not in the cache. */\n  get(key: string): FlagValue | undefined {\n    return this.pool.all()[key];\n  }\n\n  /** `true` only when the cached value is strictly `true`; `fallback` when the key is absent. */\n  isEnabled(key: string, fallback = false): boolean {\n    return this.pool.isEnabled(key, fallback);\n  }\n\n  /** Alias of {@link isEnabled} (iOS parity). */\n  bool(key: string, fallback = false): boolean {\n    return this.isEnabled(key, fallback);\n  }\n\n  /** Cached value when it is a string, else `fallback`. */\n  getString(key: string, fallback: string): string {\n    const value = this.pool.all()[key];\n    return typeof value === 'string' ? value : fallback;\n  }\n\n  /** Cached value when it is an integer number, else `fallback`. */\n  getInt(key: string, fallback: number): number {\n    const value = this.pool.all()[key];\n    return typeof value === 'number' && Number.isInteger(value) ? value : fallback;\n  }\n\n  /** Cached value when it is a number (integers included), else `fallback`. */\n  getDouble(key: string, fallback: number): number {\n    const value = this.pool.all()[key];\n    return typeof value === 'number' ? value : fallback;\n  }\n\n  /**\n   * Resolve the multivariate variant for `key` — the variant name, or `null`\n   * when the flag has no variant (or the read fails).\n   *\n   * Wire failures (network errors, 404, etc.) resolve to `null`.\n   * Invalid flag names throw `BackendError('validation', { code: 'invalid_flag_name' })`.\n   *\n   * DEVIATION from iOS sync-cache parity: the platform does not propagate\n   * variant metadata into the user-flags snapshot/delta cache, so this is an\n   * ASYNC transport read (derived from `GET /v1/user-flags`), not a cache lookup.\n   */\n  async getVariant(key: string): Promise<string | null> {\n    let res: PalbaseResponse<FlagVariant>;\n    try {\n      res = await this.transport.getVariant(key);\n    } catch (err) {\n      // FlagsClient throws synchronously for invalid flag names; map to a\n      // typed validation error so callers can distinguish \"bad name\" from\n      // \"no variant\" (which resolves null).\n      throw new BackendError('validation', {\n        code: 'invalid_flag_name',\n        message: err instanceof Error ? err.message : String(err),\n      });\n    }\n    return res.data?.name ?? null;\n  }\n\n  /** Subscribe to any change in the cached flag set. */\n  onChange(callback: () => void): Unsubscribe {\n    return this.pool.onChange(callback);\n  }\n\n  /**\n   * Observe ONE key: fires only when that key's value actually changes\n   * (per {@link sameFlagValue} — structural compare for objects), with the\n   * new value (`undefined` = deleted). P5 React-hook substrate.\n   */\n  subscribeKey(key: string, callback: (value: FlagValue | undefined) => void): Unsubscribe {\n    let last = this.pool.all()[key];\n    return this.pool.onChange(() => {\n      const next = this.pool.all()[key];\n      if (sameFlagValue(last, next)) return;\n      last = next;\n      callback(next);\n    });\n  }\n\n  /**\n   * Async iteration over flag changes: yields the new {@link all} view on\n   * every pool change notification. The listener is detached when the\n   * consumer `break`s/`return`s/`throw`s — including while a `next()` is\n   * still pending (it resolves `{ done: true }` instead of hanging, which a\n   * plain async-generator `finally` would not guarantee).\n   */\n  changes(): AsyncIterableIterator<FlagsView> {\n    const queue: FlagsView[] = [];\n    const pending: Array<(result: IteratorResult<FlagsView, undefined>) => void> = [];\n    let finished = false;\n    const unsubscribe = this.pool.onChange(() => {\n      const snapshot = this.pool.all();\n      const resolve = pending.shift();\n      if (resolve) resolve({ value: snapshot, done: false });\n      else queue.push(snapshot);\n    });\n    const finish = (): void => {\n      if (finished) return;\n      finished = true;\n      unsubscribe();\n      while (pending.length > 0) pending.shift()?.({ value: undefined, done: true });\n    };\n    return {\n      next: (): Promise<IteratorResult<FlagsView, undefined>> => {\n        if (finished) return Promise.resolve({ value: undefined, done: true });\n        const head = queue.shift();\n        if (head !== undefined) return Promise.resolve({ value: head, done: false });\n        return new Promise((resolve) => {\n          pending.push(resolve);\n        });\n      },\n      return: (): Promise<IteratorResult<FlagsView, undefined>> => {\n        finish();\n        return Promise.resolve({ value: undefined, done: true });\n      },\n      throw: (error?: unknown): Promise<IteratorResult<FlagsView, undefined>> => {\n        finish();\n        return Promise.reject(error);\n      },\n      [Symbol.asyncIterator](): AsyncIterableIterator<FlagsView> {\n        return this;\n      },\n    };\n  }\n\n  /** Stop polling and detach all listeners (auth + visibility + subscribers). */\n  destroy(): void {\n    this.pool.destroy();\n  }\n}\n","/**\n * Pure deadline math — the web mirror of iOS DeadlineCalculator (Codex-finalized\n * restart conversion rule). Identical algorithm; web uses ms internally and\n * compares against ttlSeconds (converted). Clock readings are passed in so it is\n * fully table-testable and byte-identical with iOS.\n *\n * NOTE on the send-vs-arrival clamp: like iOS T3, this Calculator stays PURE — it\n * consumes an already-resolved anchor + the current clock readings. The\n * `min(sender_send_ts + ttl, first_arrival_monotonic + ttl)` effective-deadline\n * basis is applied at ARM time by the caller (Chat, T10), which picks the anchor's\n * monotonic baseline; the Calculator only converts that anchor into remaining/purge.\n */\nexport interface AnchorTriple {\n  mAnchorMs: number; // performance.now() at capture\n  wAnchorEpochMs: number; // Date.now() at capture\n  bAnchorToken: string; // per-page-session token (changes across reload/reboot)\n}\n\nexport type DeadlineResult = { kind: 'remaining'; seconds: number } | { kind: 'purgeNow' };\n\nexport function remainingSeconds(args: {\n  ttlSeconds: number;\n  anchor: AnchorTriple;\n  nowMonotonicMs: number;\n  nowWallEpochMs: number;\n  nowBootToken: string;\n}): DeadlineResult {\n  const ttl = args.ttlSeconds;\n  const wallDeltaSec = (args.nowWallEpochMs - args.anchor.wAnchorEpochMs) / 1000;\n  let elapsed: number;\n  if (args.nowBootToken === args.anchor.bAnchorToken) {\n    const monoDeltaSec = Math.max(0, args.nowMonotonicMs - args.anchor.mAnchorMs) / 1000;\n    elapsed = Math.max(monoDeltaSec, wallDeltaSec); // larger-elapsed: backward wall can't extend\n  } else {\n    elapsed = wallDeltaSec; // reboot: monotonic meaningless → wall-only (best-effort, bounded)\n  }\n  const remaining = Math.min(ttl, ttl - elapsed); // clamp: never MORE than ttl of life\n  return remaining <= 0 ? { kind: 'purgeNow' } : { kind: 'remaining', seconds: remaining };\n}\n\n/** Impure clock seam. The boot token is minted once per page-session via\n * crypto.randomUUID() and persisted (sessionStorage), so it is stable within a\n * boot and changes across a reload/reboot — making the monotonic reading\n * comparable across a restart (same-boot vs reboot conversion). */\nlet cachedBootToken: string | null = null;\nexport const MonotonicClock = {\n  nowMs(): number {\n    return typeof performance !== 'undefined' ? performance.now() : Date.now();\n  },\n  nowWallEpochMs(): number {\n    return Date.now();\n  },\n  bootToken(): string {\n    if (cachedBootToken !== null) return cachedBootToken;\n    try {\n      const existing =\n        typeof sessionStorage !== 'undefined' ? sessionStorage.getItem('pb_boot_token') : null;\n      if (existing) {\n        cachedBootToken = existing;\n        return existing;\n      }\n      const fresh = crypto.randomUUID();\n      if (typeof sessionStorage !== 'undefined') sessionStorage.setItem('pb_boot_token', fresh);\n      cachedBootToken = fresh;\n      return fresh;\n    } catch {\n      cachedBootToken = crypto.randomUUID();\n      return cachedBootToken;\n    }\n  },\n};\n","/**\n * DeleteFold — pure fold of delete-for-everyone tombstones into a monotonic\n * `tombstoned` set.\n *\n * Algorithm mirrors iOS `DeleteFold` (DeleteFold.swift) byte-for-byte in\n * behaviour so the two SDKs compute the IDENTICAL tombstoned set from the same\n * events:\n *\n *  - **Dedup first** on `eventClientMsgId` (a re-delivered logical tombstone\n *    applies at most once). Dedup is recorded ONLY for events the fold could\n *    actually evaluate (target present, or parked in pending) — an unverifiable\n *    event (unresolved sender AND absent target) is held by its own id without\n *    being marked seen, so it can be re-attempted when more resolves.\n *  - **Author-gate (the #1 security property):** a tombstone scrubs a target\n *    ONLY when its resolved authenticated sender (`actorUserId`) equals the\n *    TARGET message's author (`authorOfTarget(target)`). A non-author tombstone\n *    is a forgery → IGNORED. This gate is enforced IDENTICALLY on the in-order\n *    path AND the deferred/pending path — there is NO code path that tombstones\n *    without passing it.\n *  - **ABSORBING / sticky (NOT LWW):** once a target is in `tombstoned` it is\n *    NEVER removed. No later event, no higher seq, no reevaluate can\n *    un-tombstone it. (Eviction within the retention window is the STORE's job,\n *    not the fold's.)\n *  - **Pending (dangling target):** a valid-shaped tombstone whose target isn't\n *    local yet is parked in `pending` CARRYING its authenticated actor, so the\n *    deferred sender-match can be enforced when the target finally arrives\n *    (`reevaluatePending`). A forged early tombstone parked in pending is\n *    DISCARDED on the target's arrival (sender-match fails) → the genuine\n *    message renders.\n *  - **Unresolved sender + absent target:** nothing can be verified yet (neither\n *    side resolved). The event is parked in `held` keyed by its\n *    `eventClientMsgId` and re-ingested on `reevaluatePending` — it never\n *    tombstones until BOTH the actor and the target's author are known AND match.\n *\n * Pure: no I/O, fully table-testable.\n */\n\n/**\n * One delete-for-everyone tombstone event for a target message. Carries\n * everything the fold needs and nothing it must read from the ciphertext: the\n * actor is the AUTHENTICATED sender resolved upstream (`actorUserId`), NEVER an\n * actor field on the wire.\n */\nexport interface DeleteEvent {\n  targetClientMsgId: string;\n  /** Resolved authenticated sender userId; null = unresolved sender. */\n  actorUserId: string | null;\n  epoch: number;\n  serverSeq: number;\n  /** Dedup key — the tombstone's own client_msg_id (unique per logical event). */\n  eventClientMsgId: string;\n}\n\nimport type { AuthorResolution } from './edit-fold.js';\n\n/**\n * Resolves the target message's author via {@link AuthorResolution} (the SAME\n * orphan-aware resolution the edit gate uses): `'author'` → run the author-gate;\n * `'unknown'` → defer (target absent locally → pending/held); `'purged'` → NO-OP\n * (the target was TTL-purged — a delete of an already-gone message is already\n * satisfied; never park in pending, never re-attempt).\n */\ntype AuthorOfTarget = (targetClientMsgId: string) => AuthorResolution;\n\nexport class DeleteFold {\n  // targets with a confirmed valid tombstone — MONOTONIC (never removed within retention).\n  private readonly tombstoned = new Set<string>();\n  // target → the tombstone's authenticated actor userId, awaiting the target's arrival.\n  private readonly pending = new Map<string, string>();\n  // dedup of real wire events the fold could evaluate (tombstoned or parked in pending).\n  private readonly seen = new Set<string>();\n  // events parked because NEITHER the actor NOR the target's author was resolvable at ingest;\n  // keyed by eventClientMsgId so a re-delivered unverifiable event is held exactly once.\n  private held: DeleteEvent[] = [];\n\n  /**\n   * Ingest one tombstone. `authorOfTarget` resolves the target message's author via\n   * {@link AuthorResolution}: `'author'` → run the author-gate; `'unknown'` → defer\n   * (target absent locally → pending/held); `'purged'` → NO-OP, mark seen (the target\n   * was TTL-purged — a delete of an already-gone message is already satisfied; never\n   * park in pending, never re-attempt).\n   */\n  ingest(e: DeleteEvent, authorOfTarget: AuthorOfTarget): void {\n    // Already absorbed → no-op (idempotent, absorbing).\n    if (this.tombstoned.has(e.targetClientMsgId)) return;\n    // Dedup of the same logical tombstone (only events we actually parked/evaluated are seen).\n    if (this.seen.has(e.eventClientMsgId)) return;\n    if (this.heldContains(e.eventClientMsgId)) return;\n\n    const res = authorOfTarget(e.targetClientMsgId);\n    if (res.kind === 'purged') {\n      // Target already TTL-purged → already gone. No-op, mark seen (never park in pending).\n      this.seen.add(e.eventClientMsgId);\n      return;\n    }\n    if (res.kind === 'author') {\n      // Target present → run the author-gate NOW.\n      this.seen.add(e.eventClientMsgId);\n      if (e.actorUserId === null || e.actorUserId !== res.userId) return; // forgery / unresolved actor → ignore\n      this.tombstoned.add(e.targetClientMsgId);\n    } else if (e.actorUserId !== null) {\n      // Target absent but actor resolved → park the authenticated actor for the deferred gate.\n      this.seen.add(e.eventClientMsgId);\n      this.pending.set(e.targetClientMsgId, e.actorUserId);\n    } else {\n      // Neither actor NOR target resolved — cannot verify anything yet. Hold by id and\n      // re-ingest on reevaluate; NOT marked seen so it stays re-attemptable.\n      this.held.push(e);\n    }\n  }\n\n  /** True once a valid tombstone has absorbed this target. */\n  isTombstoned(targetClientMsgId: string): boolean {\n    return this.tombstoned.has(targetClientMsgId);\n  }\n\n  /**\n   * When a target message newly arrives with a resolved `author`, re-check any\n   * pending tombstone for it AND re-attempt any held (unverifiable) tombstones\n   * whose target is now resolvable. The deferred gate is the SAME comparison as\n   * the in-order path.\n   */\n  reevaluatePending(target: string, author: AuthorResolution): void {\n    const res = author;\n    // Deferred gate for a parked pending tombstone.\n    const actor = this.pending.get(target);\n    if (actor !== undefined) {\n      // Absorbing: only ADD on a match; a mismatch DISCARDS the (forged) pending entry so it\n      // can never scrub the genuine message.\n      if (res.kind === 'author') {\n        if (actor === res.userId) this.tombstoned.add(target); // match → absorbed\n        this.pending.delete(target); // match → absorbed; mismatch → forged tombstone loses\n      } else if (res.kind === 'purged') {\n        // Target was TTL-purged → already gone; nothing left to scrub or defer. Discard.\n        this.pending.delete(target);\n      }\n      // 'unknown' → cannot decide yet, keep the pending entry.\n    }\n    // Re-attempt any held events whose target now has a resolvable author. Re-ingest runs the\n    // full gate (dedup via seen, author-match / purged no-op), so it can neither double-apply\n    // nor scrub without the match. Events that still don't resolve are re-held.\n    if (this.held.length === 0) return;\n    const pendingHeld = this.held;\n    this.held = [];\n    for (const e of pendingHeld) {\n      this.ingest(e, (t): AuthorResolution => (t === target ? res : { kind: 'unknown' }));\n    }\n  }\n\n  private heldContains(eventClientMsgId: string): boolean {\n    return this.held.some((h) => h.eventClientMsgId === eventClientMsgId);\n  }\n}\n","/**\n * EditFold — pure fold of edit-by-supersession events into a per-target winning\n * text + a write-once `edited` flag.\n *\n * Algorithm mirrors iOS `EditFold` (EditFold.swift) byte-for-byte in behaviour so\n * the two SDKs compute the IDENTICAL winning edit from the same events:\n *\n *  - **Author-gate first, dedup after** on `eventClientMsgId`. Dedup happens only\n *    AFTER the event is both resolvable (target+sender) and authorized, so a HELD\n *    event is never prematurely consumed by the seen-set (matching iOS ordering).\n *  - **HOLD (unresolved/dangling):** if the target's author is not yet resolvable\n *    (`authorOfTarget` returns null — target unknown), OR the sender is unresolved\n *    (`editorUserId == null` — roster gap), the event is parked in `held` (deduped\n *    by `eventClientMsgId`) and re-attempted by `reevaluateHeld(...)` once the\n *    roster/target arrives. Never folds an unresolved sender; never silently drops\n *    a holdable edit.\n *  - **Author-gate:** the edit's resolved sender (`editorUserId`) must equal the\n *    TARGET message's author (`authorOfTarget(target)`). A non-author edit is a\n *    forgery → DROPPED (not held). It is NOT marked seen — letting the gate re-drop\n *    a re-delivery is harmless and idempotent (it never reaches the winner state,\n *    so the winner is unaffected).\n *  - **LWW per target** on `(epoch, serverSeq)` ascending. An incoming order that\n *    is `< stored`, or `== stored` and loses the id backstop, is ignored.\n *  - **Exact-tie rule (cross-SDK contract — MUST match iOS):** on an exact\n *    `(epoch, serverSeq)` tie the edit whose `eventClientMsgId` is **lexicographically\n *    GREATER (`>`) wins**. Implemented as \"incoming `<= stored.lastEventId` → loses\"\n *    (identical comparison direction to iOS EditFold.swift). The server guarantees\n *    `(epoch, serverSeq)` is unique per logical event, so this is a theoretical\n *    backstop only — but it is fully deterministic + order-independent.\n *  - **Write-once `edited`:** once ANY valid edit applies to a target it stays\n *    edited forever (editing back to the original text still shows edited). Never\n *    unset.\n *\n * Pure: no I/O, fully table-testable.\n */\n\nimport type { MentionRange } from './group-messaging.js';\n\n/**\n * One edit-by-supersession event for the LATEST edit's text to be folded onto a\n * target message in place. Carries everything the fold needs and nothing it must\n * read from the ciphertext: the actor is the AUTHENTICATED sender resolved\n * upstream (`editorUserId`), never an actor field on the wire.\n */\nexport interface EditEvent {\n  targetClientMsgId: string;\n  /** Resolved sender userId; null = unresolved (roster gap) → HOLD. */\n  editorUserId: string | null;\n  newText: string;\n  epoch: number;\n  serverSeq: number;\n  /** Dedup key — the edit's own client_msg_id (unique per logical event). */\n  eventClientMsgId: string;\n  /**\n   * The edit's REPLACEMENT mention ranges (raw, un-normalized). The fold tracks them\n   * on the WINNING edit only, so the edited message's mentions re-resolve from the\n   * LWW-winning edit's ranges (mentions T6). Undefined/null = the edit carried none.\n   */\n  bodyRanges?: MentionRange[] | null;\n}\n\ninterface TargetState {\n  orderEpoch: number;\n  orderSeq: number;\n  lastEventId: string;\n  text: string;\n  /** The WINNING edit's replacement mention ranges (raw); null when it carried none. */\n  bodyRanges: MentionRange[] | null;\n}\n\n/**\n * Orphan-aware author resolution (web mirror of iOS `TargetAuthor`):\n *  - `{ kind: 'author'; userId }` — target present, author known → run the author-gate.\n *  - `{ kind: 'purged' }` — the target was TTL-purged (its `client_msg_id` is in the\n *    persistent `purgedClientMsgIds` STRING set, namespace-separate from the int\n *    `server_seq` tombstone) → DROP an edit (no held leak, never resurrects).\n *  - `{ kind: 'unknown' }` — target not locally resolvable yet → HOLD (re-attempt later).\n */\nexport type AuthorResolution =\n  | { kind: 'author'; userId: string }\n  | { kind: 'purged' }\n  | { kind: 'unknown' };\n\n/**\n * Resolves the target message's AUTHOR via {@link AuthorResolution}. ALL call-sites\n * (`chat.ts` author closure, `coordinator.ts` `projectHistory`) return this union\n * directly (the legacy `string | null` shim was deleted in Task 10).\n */\ntype AuthorOfTarget = (targetClientMsgId: string) => AuthorResolution;\n\n/**\n * Lexicographic (epoch, serverSeq) comparison. Returns true if a < b\n * (the incoming order is strictly older than the stored order).\n */\nfunction orderLt(aEpoch: number, aSeq: number, bEpoch: number, bSeq: number): boolean {\n  if (aEpoch !== bEpoch) return aEpoch < bEpoch;\n  return aSeq < bSeq;\n}\n\n/** True if (aEpoch, aSeq) equals (bEpoch, bSeq). */\nfunction orderEq(aEpoch: number, aSeq: number, bEpoch: number, bSeq: number): boolean {\n  return aEpoch === bEpoch && aSeq === bSeq;\n}\n\nexport class EditFold {\n  // target → winning edit state\n  private readonly states = new Map<string, TargetState>();\n  // dedup of real wire events that reached (and were resolvable enough to evaluate at) the fold\n  private readonly seenEvents = new Set<string>();\n  // events parked because target/author or sender was unresolved at ingest time\n  private held: EditEvent[] = [];\n  // targets that have had ≥1 valid edit applied (write-once)\n  private readonly editedTargets = new Set<string>();\n\n  /**\n   * Ingest one edit. `authorOfTarget` resolves the target message's author via\n   * {@link AuthorResolution}: `'author'` → run the author-gate; `'unknown'` → HOLD\n   * (target/author not yet known); `'purged'` → DROP (the target was TTL-purged —\n   * editing a disappeared message is a no-op; mark the event seen so it never re-holds\n   * and a later author \"resolution\" cannot resurrect it).\n   */\n  ingest(e: EditEvent, authorOfTarget: AuthorOfTarget): void {\n    const res = authorOfTarget(e.targetClientMsgId);\n    if (res.kind === 'unknown') {\n      this.holdIfNew(e); // target/author not yet known → HOLD\n      return;\n    }\n    if (res.kind === 'purged') {\n      this.seenEvents.add(e.eventClientMsgId); // mark seen → never re-held, never resurrects\n      return; // DROP: editing a disappeared message is a no-op\n    }\n    const author = res.userId;\n    // Sender not yet resolvable (roster gap) → hold; we must never fold an unattributed edit.\n    if (e.editorUserId === null) {\n      this.holdIfNew(e);\n      return;\n    }\n    // Author-gate: a non-author edit is a forgery — dropped, not held, not marked seen\n    // (the gate re-drops any re-delivery; it never touches winner state, so it's idempotent).\n    if (e.editorUserId !== author) return;\n\n    // Resolvable + authorized: dedup, then LWW.\n    if (this.seenEvents.has(e.eventClientMsgId)) return; // re-delivery of same logical edit\n    this.seenEvents.add(e.eventClientMsgId);\n\n    const prev = this.states.get(e.targetClientMsgId);\n    if (prev !== undefined) {\n      // stale / out-of-order\n      if (orderLt(e.epoch, e.serverSeq, prev.orderEpoch, prev.orderSeq)) return;\n      // exact (epoch, serverSeq) tie: lexicographically GREATER eventClientMsgId wins,\n      // so an incoming id <= the stored one loses (identical to iOS EditFold's `<=`).\n      if (\n        orderEq(e.epoch, e.serverSeq, prev.orderEpoch, prev.orderSeq) &&\n        e.eventClientMsgId <= prev.lastEventId\n      ) {\n        return;\n      }\n    }\n    this.states.set(e.targetClientMsgId, {\n      orderEpoch: e.epoch,\n      orderSeq: e.serverSeq,\n      lastEventId: e.eventClientMsgId,\n      text: e.newText,\n      bodyRanges: e.bodyRanges ?? null,\n    });\n    this.editedTargets.add(e.targetClientMsgId); // write-once\n  }\n\n  /**\n   * Park an event for later re-attempt, deduping held re-deliveries by\n   * eventClientMsgId so a repeatedly-delivered unresolvable edit is held exactly\n   * once (and never double-applies when it finally resolves on reevaluate).\n   */\n  private holdIfNew(e: EditEvent): void {\n    if (this.held.some((h) => h.eventClientMsgId === e.eventClientMsgId)) return;\n    this.held.push(e);\n  }\n\n  /** The winning edit text for a target, or null if no valid edit has applied. */\n  text(targetClientMsgId: string): string | null {\n    return this.states.get(targetClientMsgId)?.text ?? null;\n  }\n\n  /** Write-once: true once any valid edit applied to the target. */\n  isEdited(targetClientMsgId: string): boolean {\n    return this.editedTargets.has(targetClientMsgId);\n  }\n\n  /**\n   * The WINNING edit's replacement mention ranges for a target (raw, un-normalized),\n   * or null when no valid edit applied or the winning edit carried none. The Chat\n   * normalizes these against the edited text to compute the edited message's mentions\n   * (mentions T6). LWW-consistent: always the same edit that `text(...)` returns.\n   */\n  bodyRanges(targetClientMsgId: string): MentionRange[] | null {\n    return this.states.get(targetClientMsgId)?.bodyRanges ?? null;\n  }\n\n  /**\n   * Re-run HELD edits when the roster/target newly resolves (call on member/roster\n   * change and when a target message arrives). Clears `held` and re-ingests each\n   * event with the fresh `authorOfTarget` — events that still don't resolve are\n   * simply re-held; events that now resolve fold via the normal LWW path.\n   * Idempotent: re-ingest is deduped by `seenEvents` (applied events) and by\n   * `holdIfNew` (still-held events), so reevaluating repeatedly can neither\n   * double-apply nor lose an edit.\n   */\n  reevaluateHeld(authorOfTarget: AuthorOfTarget): void {\n    const pending = this.held;\n    this.held = [];\n    for (const e of pending) this.ingest(e, authorOfTarget);\n  }\n}\n","// Byte / base64 helpers — portable across browser and Node (no Buffer dep on\n// the browser path). All MLS blobs cross the wire as base64 strings.\n\n/** Encode bytes to a standard (non-url-safe) base64 string. */\nexport function toBase64(bytes: Uint8Array): string {\n  if (typeof Buffer !== 'undefined') {\n    return Buffer.from(bytes).toString('base64');\n  }\n  let binary = '';\n  const chunk = 0x8000;\n  for (let i = 0; i < bytes.length; i += chunk) {\n    binary += String.fromCharCode(...bytes.subarray(i, i + chunk));\n  }\n  return btoa(binary);\n}\n\n/** Decode a standard base64 string to bytes. */\nexport function fromBase64(b64: string): Uint8Array {\n  if (typeof Buffer !== 'undefined') {\n    return new Uint8Array(Buffer.from(b64, 'base64'));\n  }\n  const binary = atob(b64);\n  const out = new Uint8Array(binary.length);\n  for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);\n  return out;\n}\n\n/** Lowercase hex of a byte buffer (a stable string key for any blob). */\nexport function bytesToHex(bytes: Uint8Array): string {\n  let s = '';\n  for (let i = 0; i < bytes.length; i++) {\n    s += (bytes[i] ?? 0).toString(16).padStart(2, '0');\n  }\n  return s;\n}\n\nconst utf8Encoder = new TextEncoder();\nconst utf8Decoder = new TextDecoder();\n\nexport const encodeUtf8 = (s: string): Uint8Array => utf8Encoder.encode(s);\nexport const decodeUtf8 = (b: Uint8Array): string => utf8Decoder.decode(b);\n\n/** Bytes of a device id (the MLS credential identity == the `mdv_` device id). */\nexport const deviceIdBytes = (deviceId: string): Uint8Array => encodeUtf8(deviceId);\n\n/** A fresh client idempotency / id value (crypto-strong; never Math.random). */\nexport function randomId(): string {\n  return crypto.randomUUID();\n}\n\n/** Mint a client-side `mdv_<uuidv7>` device id (SP-1.6 client-minted). The\n * server (messaging `ValidateDeviceID`) requires the mdv_ prefix followed by a\n * canonical UUID *version 7* — a v4 (what `crypto.randomUUID()` emits) is\n * rejected with `invalid_device_id`. So mint a real v7 here: the version must\n * match the server's id-validator, not just the prefix. A random v7 bound to\n * the caller's iJWT sub stays squat-safe (ownership = sub, uniqueness = PK). */\nexport function mintDeviceId(): string {\n  return `mdv_${uuidV7()}`;\n}\n\n/**\n * Generate a canonical RFC 9562 UUID version 7 (time-ordered): 48-bit big-endian\n * Unix-ms timestamp, version nibble 7, variant bits 10, the rest CSPRNG random.\n * `crypto.randomUUID()` only emits v4, and the messaging server validates v7, so\n * the device-id minter cannot reuse it — this is the byte-shape the server's\n * `uuid.Version() == 7` check accepts.\n */\nexport function uuidV7(): string {\n  const bytes = new Uint8Array(16);\n  crypto.getRandomValues(bytes);\n  const ts = Date.now(); // ms since epoch fits in 48 bits until year 10889\n  // A DataView write avoids `noUncheckedIndexedAccess` \"possibly undefined\" on\n  // raw index assignment and writes the 48-bit timestamp big-endian in one shot.\n  const view = new DataView(bytes.buffer);\n  view.setUint32(0, Math.floor(ts / 2 ** 16)); // high 32 bits of the 48-bit ms\n  view.setUint16(4, ts & 0xffff); // low 16 bits\n  view.setUint8(6, (view.getUint8(6) & 0x0f) | 0x70); // version 7\n  view.setUint8(8, (view.getUint8(8) & 0x3f) | 0x80); // variant 10\n  const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/** The canonical sorted-pair direct_key for a 1:1 chat (`dm:<a>|<b>`). */\nexport function directKey(userA: string, userB: string): string {\n  const [a, b] = [userA, userB].sort();\n  return `dm:${a}|${b}`;\n}\n\n/** Mint a `msg_<32 hex>` client message id (matches iOS format). */\nexport function mintClientMsgId(): string {\n  const b = new Uint8Array(16);\n  crypto.getRandomValues(b);\n  return `msg_${Array.from(b, (x) => x.toString(16).padStart(2, '0')).join('')}`;\n}\n\n/** Truncate a string to 240 Unicode scalars (code points). Returns [truncated, wasTruncated]. */\nexport function truncateQuote(s: string): [string, boolean] {\n  const scalars = [...s];\n  if (scalars.length <= 240) return [s, false];\n  return [scalars.slice(0, 240).join(''), true];\n}\n","// The messaging wire protocol for the web SDK — paths + request/response shapes.\n//\n// CRITICAL (differs from iOS): the web HttpClient does a RAW JSON.stringify of\n// the request body (NO camel↔snake conversion — verified @palbase/core\n// HttpClient). So every field here is snake_case to match the server tags\n// VERBATIM. The field names are the live server JSON tags, cross-checked against\n// modules/messaging/internal/handler/{group,message,keypackage,trust}.go and the\n// iOS MessagingTypes.swift wire doc (live-proven). All blobs are base64 strings.\n//\n// Paths mirror the iOS MessagingPaths (the M3 #7 contract): a {gid} segment is\n// ALWAYS a `grp_<uuidv7>` display_id (url-safe), NEVER the base64 rfc_group_id.\n\n// ─── Paths ───────────────────────────────────────────────────────────────────\n\nconst GROUPS = '/v1/messaging/groups';\nconst DEVICES = '/v1/messaging/devices';\nconst KEYDIR = '/v1/messaging/keydir';\n\n/** encodeURIComponent a single path segment (defense in depth; the real fix is\n * passing the url-safe grp_/mdv_ id, never the base64 rfc_group_id — M3 #7). */\nconst seg = (s: string): string => encodeURIComponent(s);\n\nexport const MessagingPaths = {\n  groups: GROUPS,\n  groupsDirect: `${GROUPS}/direct`,\n  group: (displayId: string) => `${GROUPS}/${seg(displayId)}`,\n  groupMetadata: (displayId: string) => `${GROUPS}/${seg(displayId)}/metadata`,\n  groupMembers: (displayId: string) => `${GROUPS}/${seg(displayId)}/members`,\n  groupMemberDevice: (displayId: string, deviceId: string) =>\n    `${GROUPS}/${seg(displayId)}/members/${seg(deviceId)}`,\n  groupMessages: (displayId: string) => `${GROUPS}/${seg(displayId)}/messages`,\n  groupCommits: (displayId: string) => `${GROUPS}/${seg(displayId)}/commits`,\n  groupRead: (displayId: string) => `${GROUPS}/${seg(displayId)}/read`,\n  // Server-metadata cluster: the per-(user,group) notify scope (mute toggle, GET/PUT)\n  // + the caller's own unread view (GET). {gid} is the grp_ display_id (M3 #7).\n  groupNotify: (displayId: string) => `${GROUPS}/${seg(displayId)}/notify`,\n  groupUnread: (displayId: string) => `${GROUPS}/${seg(displayId)}/unread`,\n\n  deviceWelcomes: (deviceId: string) => `${DEVICES}/${seg(deviceId)}/welcomes`,\n  deviceQueue: (deviceId: string) => `${DEVICES}/${seg(deviceId)}/queue`,\n  deviceQueueAck: (deviceId: string) => `${DEVICES}/${seg(deviceId)}/queue/ack`,\n\n  keydirDevices: `${KEYDIR}/devices`,\n  keydirDeviceKeyPackages: (deviceId: string) => `${KEYDIR}/devices/${seg(deviceId)}/keypackages`,\n  keydirUserDevices: (userId: string) => `${KEYDIR}/users/${seg(userId)}/devices`,\n  keydirUserClaim: (userId: string) => `${KEYDIR}/users/${seg(userId)}/keypackages/claim`,\n  keydirPinsVerify: `${KEYDIR}/pins/verify`,\n\n  prefs: '/v1/messaging/prefs',\n} as const;\n\n/** True iff `s` is safe to place RAW in a URL path segment (M3 #7 gate). A\n * grp_/mdv_ id passes; a base64 rfc_group_id (`/`, `=`, `+`) FAILS. */\nexport function isUrlSafePathSegment(s: string): boolean {\n  return s.length > 0 && /^[A-Za-z0-9\\-._~]+$/.test(s);\n}\n\n// ─── Keydir (SP-0) ───────────────────────────────────────────────────────────\n\nexport type MessagingPlatform = 'android' | 'ios' | 'web';\n\nexport interface EnrollDeviceBody {\n  device_id: string;\n  platform: MessagingPlatform;\n  device_name?: string;\n  cipher_suite: number;\n  signature_key: string; // base64 raw curve public key\n  credential: string; // base64 TLS-encoded MLS Credential (identity == device_id)\n  capabilities: string; // base64\n}\n\nexport interface EnrollResponse {\n  device_id: string;\n  signature_key_fingerprint: string;\n  trust_tier: string;\n  one_time_count: number;\n}\n\nexport interface ReplenishBody {\n  key_packages: string[]; // base64 raw KeyPackages\n}\n\nexport interface DeviceInfo {\n  device_id: string;\n  signature_key: string;\n  credential: string;\n  cipher_suite: number;\n  key_epoch: number;\n  trust_tier: string;\n  first_seen_at: string;\n}\n\nexport interface DeviceListResponse {\n  device_set_version: string;\n  devices: DeviceInfo[];\n  warnings?: unknown[];\n}\n\nexport interface ClaimedKeyPackage {\n  device_id: string;\n  cipher_suite: number;\n  key_package: string; // base64\n  reused: boolean;\n}\n\nexport interface ClaimResponse {\n  key_packages: ClaimedKeyPackage[];\n  depleted_devices?: string[];\n}\n\nexport interface VerifyBody {\n  peer_user_id: string;\n  verified_device_set_hash: string;\n}\n\n// ─── Group create / direct ────────────────────────────────────────────────────\n\nexport interface CreateGroupBody {\n  rfc_group_id: string; // base64\n  cipher_suite: number;\n  creator_device_id: string;\n  creator_leaf_index: number;\n  metadata?: string; // base64 sealed-name blob; omitted on web (no exporter yet)\n}\n\nexport interface CreateGroupResponse {\n  display_id: string;\n  rfc_group_id: string;\n  current_epoch: number;\n  metadata?: string;\n}\n\nexport interface CreateDirectGroupBody {\n  direct_key: string;\n  peer_user_id: string;\n  rfc_group_id: string; // base64\n  cipher_suite: number;\n  creator_device_id: string;\n  creator_leaf_index: number;\n}\n\nexport interface CreateDirectGroupResponse {\n  display_id: string;\n  rfc_group_id: string;\n  current_epoch: number;\n  owner_user_id?: string;\n  exists?: boolean;\n}\n\nexport interface GroupReadResponse {\n  display_id: string;\n  rfc_group_id: string;\n  current_epoch: number;\n  status?: string;\n  metadata?: string;\n}\n\n// ─── Members ───────────────────────────────────────────────────────────────────\n\nexport type MessagingGroupRole = 'owner' | 'admin' | 'member';\n\nexport interface GroupMemberRow {\n  device_id: string;\n  user_id: string;\n  role: MessagingGroupRole;\n  leaf_index: number;\n}\n\nexport interface ListMembersResponse {\n  members: GroupMemberRow[];\n}\n\nexport interface WelcomeBody {\n  recipient_device_id: string;\n  recipient_user_id: string;\n  welcome_b64: string;\n}\n\n/** `POST /groups/{gid}/members` — declared add + opaque commit + welcomes. */\nexport interface AddMemberBody {\n  op: string;\n  commit_b64: string;\n  target_device_ids: string[];\n  leaf_indexes: number[];\n  user_ids: string[];\n  key_package_refs: string[];\n  welcomes: WelcomeBody[];\n}\n\n/** `DELETE /groups/{gid}/members/{deviceId}` — multi-remove / self-leave. */\nexport interface RemoveMembersBody {\n  op: string;\n  commit_b64: string;\n  target_device_ids: string[];\n  user_ids: string[];\n}\n\n/** `{ epoch }` — the advanced-to epoch a membership/commit write returns. */\nexport interface CommitAccepted {\n  epoch: number;\n}\n\n// ─── Messages ──────────────────────────────────────────────────────────────────\n\nexport interface SendMessageBody {\n  ciphertext_b64: string;\n  client_idem_key: string;\n}\n\nexport interface SentReceipt {\n  server_seq: number;\n  epoch: number;\n}\n\n/** One queue row from `GET /devices/{deviceId}/queue`. */\nexport interface QueuedMessage {\n  id: string;\n  epoch: number;\n  content_type: number; // 1=app, 2=proposal, 3=commit\n  wire_format: number; // 1=public, 2=private\n  ciphertext_b64: string;\n  server_seq: number;\n  // OPTIONAL group attribution + the fanned-out declaration (the live server\n  // does not fan these on queue rows yet — nil today, gate engages when present).\n  rfc_group_id_b64?: string;\n  sender_device_id?: string;\n  declared_added_device_ids?: string[];\n  declared_removed_device_ids?: string[];\n  declared_op?: string;\n}\n\nexport interface QueuePage {\n  messages: QueuedMessage[];\n}\n\n/** One row from `GET /devices/{deviceId}/welcomes` — a new-member bootstrap. */\nexport interface PendingWelcome {\n  id: string;\n  display_id: string; // the group's grp_ routing id (url-safe; NOT the base64 rfc)\n  rfc_group_id_b64: string;\n  welcome_b64: string;\n  added_at_epoch: number;\n}\n\nexport interface WelcomePage {\n  welcomes: PendingWelcome[];\n}\n\nexport interface AckBody {\n  message_ids: string[];\n}\n\n/** Queue-row content-type discriminator (matches the server `content_type`). */\nexport const ContentType = {\n  application: 1,\n  proposal: 2,\n  commit: 3,\n} as const;\n\n// ─── SP-3 comms (read receipts / prefs / presence / typing) ──────────────────\n\nexport interface MarkReadBody {\n  read_seq: number;\n  read_epoch: number;\n  is_private: boolean;\n}\n\nexport interface MarkReadResponse {\n  read_seq: number;\n  advanced: boolean;\n  broadcast: boolean;\n}\n\nexport interface CommsPrefsResponse {\n  share_presence: boolean;\n  share_receipts: boolean;\n  updated_at?: string;\n}\n\nexport interface SetPrefsBody {\n  share_presence?: boolean;\n  share_receipts?: boolean;\n}\n\nexport interface CommsPrefs {\n  sharePresence: boolean;\n  shareReceipts: boolean;\n}\n","// The MLS key directory (SP-0) mechanics — INTERNAL, mirroring the iOS\n// KeyDirectoryInternal. Hidden behind the coordinator's implicit enroll (the\n// first chat op self-enrolls). Byte-identical wire calls to iOS: same\n// /v1/messaging/keydir/* routes, same iJWT bearer (palbeRequest), same\n// snake_case bodies.\n\nimport { palbeRequest } from '../request.js';\nimport type { PalbeRuntime } from '../runtime.js';\nimport type { MlsEngine } from './mls-engine.js';\nimport type { DeviceIdStore } from './storage.js';\nimport { toBase64 } from './util.js';\nimport {\n  type ClaimResponse,\n  type DeviceListResponse,\n  type EnrollDeviceBody,\n  type EnrollResponse,\n  MessagingPaths,\n  type ReplenishBody,\n  type VerifyBody,\n} from './wire.js';\n\n/**\n * Enroll THIS device + publish its first KeyPackages from REAL engine material.\n * Idempotent: a returning user (persisted device id) skips the POST and just\n * replenishes. Returns the resolved device id.\n *\n * Flow (mirrors iOS enroll):\n *   1. engine.enrollmentMaterial() → { signatureKey, credential, capabilities }\n *   2. POST /keydir/devices (the server validates the client-minted mdv_ id +\n *      credential.identity == device_id + ownership == iJWT sub)\n *   3. generate N key packages → POST /keydir/devices/{id}/keypackages\n */\nexport async function enrollDevice(\n  rt: PalbeRuntime,\n  engine: MlsEngine,\n  deviceStore: DeviceIdStore,\n  opts: { keyPackageCount?: number; deviceName?: string } = {},\n): Promise<string> {\n  const keyPackageCount = opts.keyPackageCount ?? 10;\n  const deviceId = engine.deviceId;\n  const alreadyEnrolled = (await deviceStore.load(engine.userId)) === deviceId;\n\n  if (!alreadyEnrolled) {\n    const material = await engine.enrollmentMaterial();\n    const body: EnrollDeviceBody = {\n      device_id: deviceId,\n      platform: 'web',\n      device_name: opts.deviceName,\n      cipher_suite: 1,\n      signature_key: toBase64(material.signatureKey),\n      credential: toBase64(material.credential),\n      capabilities: toBase64(material.capabilities),\n    };\n    await palbeRequest<EnrollResponse>(rt, 'POST', MessagingPaths.keydirDevices, { body });\n    await deviceStore.save(engine.userId, deviceId);\n  }\n\n  if (keyPackageCount > 0) {\n    const raws: string[] = [];\n    for (let i = 0; i < keyPackageCount; i++) {\n      raws.push(toBase64(await engine.generateKeyPackage()));\n    }\n    await replenish(rt, deviceId, raws);\n  }\n  return deviceId;\n}\n\n/** Publish more one-use KeyPackages for a device. */\nexport async function replenish(\n  rt: PalbeRuntime,\n  deviceId: string,\n  rawKeyPackagesB64: string[],\n): Promise<void> {\n  const body: ReplenishBody = { key_packages: rawKeyPackagesB64 };\n  await palbeRequest<void>(rt, 'POST', MessagingPaths.keydirDeviceKeyPackages(deviceId), { body });\n}\n\n/** Claim a peer's KeyPackages (one per device) to add them to a group. */\nexport async function claimKeyPackages(rt: PalbeRuntime, userId: string): Promise<ClaimResponse> {\n  return palbeRequest<ClaimResponse>(rt, 'POST', MessagingPaths.keydirUserClaim(userId), {\n    body: {},\n  });\n}\n\n/** List a user's enrolled devices (for the safety number + roster resolution). */\nexport async function listDevices(rt: PalbeRuntime, userId: string): Promise<DeviceListResponse> {\n  return palbeRequest<DeviceListResponse>(rt, 'GET', MessagingPaths.keydirUserDevices(userId));\n}\n\n/** Record a TOFU verify pin for a peer's current device set. */\nexport async function verifyPeer(\n  rt: PalbeRuntime,\n  peerUserId: string,\n  verifiedDeviceSetHash: string,\n): Promise<void> {\n  const body: VerifyBody = {\n    peer_user_id: peerUserId,\n    verified_device_set_hash: verifiedDeviceSetHash,\n  };\n  await palbeRequest<void>(rt, 'POST', MessagingPaths.keydirPinsVerify, { body });\n}\n","// The membership/send orchestrator — the web mirror of iOS GroupMessaging.\n// Two correctness invariants (design §3, identical to iOS):\n//\n//  (1) ATOMIC-PERSIST AROUND A COMMIT. Stage a pending commit in the engine,\n//      POST it, apply ONLY on a 200. On a 409 epoch_conflict clearPendingCommit —\n//      the local epoch is NEVER ahead of the server-accepted epoch.\n//  (2) THE STALE-EPOCH REBASE LOOP. On 409 drain the winning commits, rebuild at\n//      the new epoch, re-POST — bounded + jittered. Exhaustion throws.\n//\n// sendMessage NEVER rebases: an application message is epoch-bound; a 422\n// stale_application surfaces to the caller (re-send after the delivery source\n// catches up). Only membership COMMITS rebase.\n//\n// WEB GAP vs iOS: there is no MLS exporter export in the WASM surface yet, so\n// the group NAME is not sealed (metadata omitted; the server stays blind and the\n// UI falls back to a friendly label). Text/membership flows are byte-identical.\n\nimport { BackendError, isBackendError } from '../errors.js';\nimport { palbeRequest } from '../request.js';\nimport type { PalbeRuntime } from '../runtime.js';\nimport type { MessageStore, StoredMessage } from './history.js';\nimport { claimKeyPackages } from './keydir.js';\nimport type { MlsEngine } from './mls-engine.js';\nimport type { ResolvedReply, SentReceipt } from './types.js';\nimport {\n  decodeUtf8,\n  deviceIdBytes,\n  encodeUtf8,\n  fromBase64,\n  directKey as makeDirectKey,\n  mintClientMsgId,\n  randomId,\n  toBase64,\n} from './util.js';\nimport {\n  type AddMemberBody,\n  type ClaimResponse,\n  type CommitAccepted,\n  ContentType,\n  type CreateDirectGroupBody,\n  type CreateDirectGroupResponse,\n  type CreateGroupBody,\n  type CreateGroupResponse,\n  type ListMembersResponse,\n  MessagingPaths,\n  type QueuePage,\n  type RemoveMembersBody,\n  type SendMessageBody,\n  type WelcomeBody,\n  type SentReceipt as WireReceipt,\n} from './wire.js';\n\n/** A resolved group as the SDK tracks it. `name` is always null on web (no exporter). */\nexport interface MessagingGroup {\n  displayId: string;\n  rfcGroupId: string; // base64 routing key\n  currentEpoch: number;\n  ownerUserId: string | null;\n  directKey: string | null;\n  name: string | null;\n}\n\nexport interface QuotePreview {\n  kind: string;\n  author_user_id: string;\n  body?: string;\n  body_truncated: boolean;\n}\nexport interface ReplyRef {\n  v: number;\n  client_msg_id: string;\n  preview?: QuotePreview;\n}\n\n/** A single mention range inside a message body.\n * Offsets are UTF-16 code units, half-open [start, start+length).\n * Wire: snake_case (mentioned_user_id, body_ranges) — web does RAW JSON, no case-convert.\n */\nexport interface MentionRange {\n  start: number;\n  length: number;\n  mentionedUserId: string;\n}\n\n/** The typed E2E message envelope (matches the iOS wire format exactly). */\ninterface MsgEnvelope {\n  v: 1;\n  type: 'text';\n  client_msg_id: string;\n  text: string;\n  reply_to?: ReplyRef;\n  body_ranges?: Array<{ start: number; length: number; mentioned_user_id: string }>;\n  // Per-message TTL — sender_send_ts present IFF start === 'send' (raw snake_case wire).\n  expiry?: { v: number; ttl_seconds: number; start: 'send' | 'read'; sender_send_ts?: number };\n}\n\nexport interface ReactionPayload {\n  targetClientMsgId: string;\n  emoji: string;\n  op: 'add' | 'remove';\n}\n\nexport interface EditPayload {\n  targetClientMsgId: string;\n  newText: string;\n}\n\nexport interface DeletePayload {\n  targetClientMsgId: string;\n  scope: string;\n}\n\n/** Per-message TTL spec (decoded). senderSendTs present iff start === 'send'. */\nexport interface ExpirySpec {\n  v: number;\n  ttlSeconds: number;\n  start: 'send' | 'read';\n  senderSendTs: number | null;\n}\n\n/** Encode a delete event into the wire envelope bytes. */\nexport function encodeDelete(args: { clientMsgId: string; targetClientMsgId: string }): Uint8Array {\n  return encodeUtf8(\n    JSON.stringify({\n      v: 1,\n      type: 'delete',\n      client_msg_id: args.clientMsgId,\n      target_client_msg_id: args.targetClientMsgId,\n      scope: 'everyone',\n    }),\n  );\n}\n\n/** Encode an edit event into the wire envelope bytes. */\nexport function encodeEdit(args: {\n  clientMsgId: string;\n  targetClientMsgId: string;\n  newText: string;\n  bodyRanges?: MentionRange[] | null;\n}): Uint8Array {\n  return encodeUtf8(\n    JSON.stringify({\n      v: 1,\n      type: 'edit',\n      client_msg_id: args.clientMsgId,\n      target_client_msg_id: args.targetClientMsgId,\n      new_text: args.newText,\n      ...(args.bodyRanges && args.bodyRanges.length > 0\n        ? {\n            body_ranges: args.bodyRanges.map((r) => ({\n              start: r.start,\n              length: r.length,\n              mentioned_user_id: r.mentionedUserId,\n            })),\n          }\n        : {}),\n    }),\n  );\n}\n\n/** Encode a reaction event into the wire envelope bytes. */\nexport function encodeReaction(args: {\n  clientMsgId: string;\n  targetClientMsgId: string;\n  emoji: string;\n  op: 'add' | 'remove';\n}): Uint8Array {\n  return encodeUtf8(\n    JSON.stringify({\n      v: 1,\n      type: 'reaction',\n      client_msg_id: args.clientMsgId,\n      target_client_msg_id: args.targetClientMsgId,\n      emoji: args.emoji,\n      op: args.op,\n    }),\n  );\n}\n\n/** Encode a text message into the wire envelope bytes. */\nexport function encodeEnvelope(args: {\n  text: string;\n  clientMsgId: string;\n  replyTo?: ReplyRef | null;\n  bodyRanges?: MentionRange[] | null;\n  expiry?: ExpirySpec | null;\n}): Uint8Array {\n  const env: MsgEnvelope = {\n    v: 1,\n    type: 'text',\n    client_msg_id: args.clientMsgId,\n    text: args.text,\n    ...(args.replyTo ? { reply_to: args.replyTo } : {}),\n    ...(args.bodyRanges && args.bodyRanges.length > 0\n      ? {\n          body_ranges: args.bodyRanges.map((r) => ({\n            start: r.start,\n            length: r.length,\n            mentioned_user_id: r.mentionedUserId,\n          })),\n        }\n      : {}),\n    ...(args.expiry\n      ? {\n          expiry: {\n            v: args.expiry.v,\n            ttl_seconds: args.expiry.ttlSeconds,\n            start: args.expiry.start,\n            // present IFF send (drop a stray senderSendTs on a read anchor)\n            ...(args.expiry.start === 'send' && args.expiry.senderSendTs != null\n              ? { sender_send_ts: args.expiry.senderSendTs }\n              : {}),\n          },\n        }\n      : {}),\n  };\n  return encodeUtf8(JSON.stringify(env));\n}\n\n/** Encode a per-chat default disappearing-timer control envelope. ttlSeconds === null\n * disables the chat default; it is OMITTED from the wire (absent === null === disable). */\nexport function encodeTimerSet(args: {\n  clientMsgId: string;\n  ttlSeconds: number | null;\n  start: 'send' | 'read';\n}): Uint8Array {\n  return encodeUtf8(\n    JSON.stringify({\n      v: 1,\n      type: 'timer_set',\n      client_msg_id: args.clientMsgId,\n      ...(args.ttlSeconds != null ? { ttl_seconds: args.ttlSeconds } : {}),\n      start: args.start,\n    }),\n  );\n}\n\n/** Decode an application plaintext (tolerant: bare-text or missing-v → legacy fallback). */\nexport function decodeEnvelope(bytes: Uint8Array): {\n  type?: string;\n  text: string | null;\n  clientMsgId: string;\n  replyTo: ReplyRef | null;\n  reaction?: ReactionPayload;\n  edit?: EditPayload;\n  delete?: DeletePayload;\n  bodyRanges?: MentionRange[];\n  expiry?: ExpirySpec;\n  timer?: { ttlSeconds: number | null; start: 'send' | 'read' };\n} {\n  const s = decodeUtf8(bytes);\n  try {\n    const o = JSON.parse(s) as {\n      type?: string;\n      v?: number;\n      text?: string;\n      client_msg_id?: string;\n      reply_to?: ReplyRef;\n      target_client_msg_id?: string;\n      emoji?: string;\n      op?: string;\n      new_text?: string;\n      scope?: string;\n      body_ranges?: Array<{ start: number; length: number; mentioned_user_id: string }>;\n      expiry?: unknown;\n      ttl_seconds?: number;\n      sender_send_ts?: number;\n      start?: string;\n    };\n    if (typeof o === 'object' && o !== null && o.type === 'timer_set') {\n      // timer_set control envelope — ttl_seconds absent === null === disable.\n      return {\n        type: 'timer_set',\n        text: null,\n        clientMsgId: o.client_msg_id ?? '',\n        replyTo: null,\n        timer: {\n          ttlSeconds: typeof o.ttl_seconds === 'number' ? o.ttl_seconds : null,\n          start: o.start === 'read' ? 'read' : 'send',\n        },\n      };\n    }\n    if (typeof o === 'object' && o !== null && o.type === 'delete') {\n      // Delete envelope.\n      return {\n        type: 'delete',\n        text: null,\n        clientMsgId: o.client_msg_id ?? '',\n        replyTo: null,\n        delete: {\n          targetClientMsgId: o.target_client_msg_id ?? '',\n          scope: o.scope ?? 'everyone',\n        },\n      };\n    }\n    if (typeof o === 'object' && o !== null && o.type === 'reaction') {\n      // Reaction envelope.\n      return {\n        type: 'reaction',\n        text: null,\n        clientMsgId: o.client_msg_id ?? '',\n        replyTo: null,\n        reaction: {\n          targetClientMsgId: o.target_client_msg_id ?? '',\n          emoji: o.emoji ?? '',\n          op: (o.op as 'add' | 'remove') ?? 'add',\n        },\n      };\n    }\n    if (typeof o === 'object' && o !== null && o.type === 'edit') {\n      // Edit envelope.\n      const editRanges = decodeBodyRanges(o.body_ranges);\n      return {\n        type: 'edit',\n        text: null,\n        clientMsgId: o.client_msg_id ?? '',\n        replyTo: null,\n        edit: {\n          targetClientMsgId: o.target_client_msg_id ?? '',\n          newText: o.new_text ?? '',\n        },\n        ...(editRanges ? { bodyRanges: editRanges } : {}),\n      };\n    }\n    if (typeof o === 'object' && o !== null && o.type === 'text' && typeof o.v === 'number') {\n      // Full v:1 envelope — extract all fields.\n      const textRanges = decodeBodyRanges(o.body_ranges);\n      const expiry = decodeExpiry(o.expiry);\n      return {\n        type: 'text',\n        text: o.text ?? null,\n        clientMsgId: o.client_msg_id ?? '',\n        replyTo: o.reply_to ?? null,\n        ...(textRanges ? { bodyRanges: textRanges } : {}),\n        ...(expiry ? { expiry } : {}),\n      };\n    }\n    if (typeof o === 'object' && o !== null && o.type === 'text') {\n      // Legacy envelope (no v) — extract text, no reply context.\n      return { type: 'text', text: o.text ?? null, clientMsgId: '', replyTo: null };\n    }\n    // A media envelope (not yet supported on web) → no text.\n    if (typeof o === 'object' && o !== null && o.type === 'media')\n      return { type: 'media', text: null, clientMsgId: '', replyTo: null };\n  } catch {\n    // legacy/bare plaintext\n  }\n  return { text: s, clientMsgId: '', replyTo: null };\n}\n\n/** Map a raw wire expiry object (snake_case) to ExpirySpec. Returns undefined if absent\n * or malformed (no ttl_seconds) — an old decoder with this branch stripped ignores it. */\nfunction decodeExpiry(raw: unknown): ExpirySpec | undefined {\n  if (typeof raw !== 'object' || raw === null) return undefined;\n  const o = raw as { v?: number; ttl_seconds?: number; start?: string; sender_send_ts?: number };\n  if (typeof o.ttl_seconds !== 'number') return undefined;\n  const start: 'send' | 'read' = o.start === 'read' ? 'read' : 'send';\n  return {\n    v: typeof o.v === 'number' ? o.v : 1,\n    ttlSeconds: o.ttl_seconds,\n    start,\n    // tolerant: only honor sender_send_ts on a send anchor; null otherwise.\n    senderSendTs:\n      start === 'send' && typeof o.sender_send_ts === 'number' ? o.sender_send_ts : null,\n  };\n}\n\n/** Map raw wire body_ranges (snake_case) to MentionRange[]. Returns undefined if absent or empty. */\nfunction decodeBodyRanges(\n  raw: Array<{ start: number; length: number; mentioned_user_id: string }> | undefined | null,\n): MentionRange[] | undefined {\n  if (!raw || raw.length === 0) return undefined;\n  return raw.map((r) => ({\n    start: r.start,\n    length: r.length,\n    mentionedUserId: r.mentioned_user_id,\n  }));\n}\n\n/**\n * Resolve a reply reference against local history.\n *\n * `lookup(clientMsgId)` should return `{ text, senderUserId }` when the parent\n * is in local history, or `null` when not found.\n *\n * Spoof defense: when the parent IS found, the REAL text from local history wins\n * over the embedded `preview.body` — an attacker cannot make a reply appear to\n * quote different text than what was actually sent.\n */\nexport function resolveReply(\n  ref: ReplyRef,\n  lookup: (clientMsgId: string) => { text: string; senderUserId: string } | null,\n): ResolvedReply {\n  const parent = lookup(ref.client_msg_id);\n  if (parent !== null) {\n    return {\n      parentClientMsgId: ref.client_msg_id,\n      state: 'resolved',\n      quoteSenderUserId: parent.senderUserId,\n      quoteText: parent.text,\n      quoteKind: ref.preview?.kind ?? 'text',\n    };\n  }\n  return {\n    parentClientMsgId: ref.client_msg_id,\n    state: 'unavailable',\n    quoteSenderUserId: ref.preview?.author_user_id ?? '',\n    quoteText: ref.preview?.body ?? null,\n    quoteKind: ref.preview?.kind ?? 'text',\n  };\n}\n\nexport interface RebaseOptions {\n  maxAttempts: number;\n  baseDelayMs: number;\n  jitterMs: number;\n}\n\nconst DEFAULT_REBASE: RebaseOptions = { maxAttempts: 6, baseDelayMs: 80, jitterMs: 120 };\n\n/** Thrown when the rebase loop exhausts its budget (the change did NOT land). */\nexport class RebaseExhausted extends Error {\n  constructor(\n    readonly attempts: number,\n    readonly lastKnownEpoch: number | null,\n  ) {\n    super(`commit rebase exhausted after ${attempts} attempts`);\n    this.name = 'RebaseExhausted';\n  }\n}\n\nexport class GroupMessaging {\n  constructor(\n    private readonly rt: PalbeRuntime,\n    private readonly engine: MlsEngine,\n    private readonly selfUserId: string,\n    private readonly selfDeviceId: string,\n    private readonly messageStore: MessageStore,\n    private readonly rebase: RebaseOptions = DEFAULT_REBASE,\n  ) {}\n\n  // ── Create ──\n\n  /** Create a group: mint the rfc_group_id, POST create, return the server group.\n   * No name sealing on web (metadata omitted — server-blind, label fallback). */\n  async createGroup(cipherSuite = 1): Promise<MessagingGroup> {\n    const rfcGroupId = await this.engine.createGroup();\n    const body: CreateGroupBody = {\n      rfc_group_id: toBase64(rfcGroupId),\n      cipher_suite: cipherSuite,\n      creator_device_id: this.selfDeviceId,\n      creator_leaf_index: 0,\n    };\n    const res = await palbeRequest<CreateGroupResponse>(this.rt, 'POST', MessagingPaths.groups, {\n      body,\n    });\n    return {\n      displayId: res.display_id,\n      rfcGroupId: res.rfc_group_id,\n      currentEpoch: res.current_epoch,\n      ownerUserId: this.selfUserId,\n      directKey: null,\n      name: null,\n    };\n  }\n\n  // ── Direct (1:1) get-or-create ──\n\n  /** Materialize a DIRECT chat keyed by the stable direct_key (sorted user pair).\n   * EXISTS → adopt (the Welcome drains via the pump); ABSENT → create + add peer. */\n  async getOrCreateDirect(peerUserId: string): Promise<MessagingGroup> {\n    const dk = makeDirectKey(this.selfUserId, peerUserId);\n    const rfcGroupId = await this.engine.createGroup(); // reserved (used only if INSERT)\n    const body: CreateDirectGroupBody = {\n      direct_key: dk,\n      peer_user_id: peerUserId,\n      rfc_group_id: toBase64(rfcGroupId),\n      cipher_suite: 1,\n      creator_device_id: this.selfDeviceId,\n      creator_leaf_index: 0,\n    };\n    const res = await palbeRequest<CreateDirectGroupResponse>(\n      this.rt,\n      'POST',\n      MessagingPaths.groupsDirect,\n      { body },\n    );\n\n    if (res.exists === true) {\n      // ADOPT — discard the reserved group; the founder's Welcome drains in.\n      await this.engine.clearPendingCommit(rfcGroupId);\n      return {\n        displayId: res.display_id,\n        rfcGroupId: res.rfc_group_id,\n        currentEpoch: res.current_epoch,\n        ownerUserId: res.owner_user_id ?? null,\n        directKey: dk,\n        name: null,\n      };\n    }\n\n    // CREATE branch — the server bound the group to direct_key; add the peer.\n    const group: MessagingGroup = {\n      displayId: res.display_id,\n      rfcGroupId: res.rfc_group_id,\n      currentEpoch: res.current_epoch,\n      ownerUserId: this.selfUserId,\n      directKey: dk,\n      name: null,\n    };\n    const claimed = await claimKeyPackages(this.rt, peerUserId);\n    await this.addMember(group, peerUserId, claimed);\n    return group;\n  }\n\n  // ── Members ──\n\n  /** The group roster (device leaves). The coordinator dedups to users. */\n  async listMembers(displayId: string): Promise<ListMembersResponse['members']> {\n    const res = await palbeRequest<ListMembersResponse>(\n      this.rt,\n      'GET',\n      MessagingPaths.groupMembers(displayId),\n    );\n    return res.members;\n  }\n\n  /** Add a member: claim → stage the add commit → run the rebase loop. SP-1.6:\n   * EVERY device of the user joins in ONE atomic commit (one shared Welcome). */\n  async addMember(group: MessagingGroup, userId: string, claimed?: ClaimResponse): Promise<void> {\n    const claim = claimed ?? (await claimKeyPackages(this.rt, userId));\n    const adds = claim.key_packages\n      .map((kp) => {\n        try {\n          return { deviceId: kp.device_id, kp: fromBase64(kp.key_package) };\n        } catch {\n          return null;\n        }\n      })\n      .filter((x): x is { deviceId: string; kp: Uint8Array } => x !== null);\n    if (adds.length === 0) {\n      throw new BackendError('validation', {\n        code: 'no_keypackage',\n        message: 'no claimable key package for user',\n        status: 422,\n      });\n    }\n    const userIds = adds.map(() => userId);\n\n    await this.commitWithRebase(group.rfcGroupId, async () => {\n      const out = await this.engine.commitChanges(\n        fromBase64(group.rfcGroupId),\n        adds.map((a) => a.kp),\n        [],\n      );\n      // One shared Welcome per added device (the engine returns one welcome for a\n      // single-Welcome multi-add; route it to each added device).\n      const welcomeB64 = out.welcome ? toBase64(out.welcome) : '';\n      const welcomes: WelcomeBody[] = adds.map((a) => ({\n        recipient_device_id: a.deviceId,\n        recipient_user_id: userId,\n        welcome_b64: welcomeB64,\n      }));\n      const memberBody: AddMemberBody = {\n        op: 'add',\n        commit_b64: toBase64(out.commit),\n        target_device_ids: adds.map((a) => a.deviceId),\n        leaf_indexes: out.addedLeafIndices,\n        user_ids: userIds,\n        key_package_refs: [],\n        welcomes,\n      };\n      return {\n        method: 'POST',\n        path: MessagingPaths.groupMembers(group.displayId),\n        body: memberBody,\n      };\n    });\n  }\n\n  /** Remove a user = evict ALL their device leaves in ONE commit (SP-1.6 D4). */\n  async removeMember(group: MessagingGroup, userId: string): Promise<void> {\n    const members = await this.listMembers(group.displayId);\n    const deviceIds = members.filter((m) => m.user_id === userId).map((m) => m.device_id);\n    if (deviceIds.length === 0) {\n      throw new BackendError('validation', {\n        code: 'not_a_member',\n        message: 'user has no device in this group',\n        status: 404,\n      });\n    }\n    await this.stageMultiRemove(group, deviceIds, [userId]);\n  }\n\n  /** Leave = remove the CALLING device's leaf only (per-device self-leave). */\n  async leaveGroup(group: MessagingGroup): Promise<void> {\n    await this.stageMultiRemove(group, [this.selfDeviceId], [this.selfUserId]);\n  }\n\n  private async stageMultiRemove(\n    group: MessagingGroup,\n    deviceIds: string[],\n    removedUserIds: string[],\n  ): Promise<void> {\n    const pathDeviceId = deviceIds[0];\n    if (!pathDeviceId) throw new Error('no device to remove');\n    await this.commitWithRebase(group.rfcGroupId, async () => {\n      const out = await this.engine.commitChanges(\n        fromBase64(group.rfcGroupId),\n        [],\n        deviceIds.map(deviceIdBytes),\n      );\n      const body: RemoveMembersBody = {\n        op: 'remove',\n        commit_b64: toBase64(out.commit),\n        target_device_ids: deviceIds,\n        user_ids: removedUserIds,\n      };\n      return {\n        method: 'DELETE',\n        path: MessagingPaths.groupMemberDevice(group.displayId, pathDeviceId),\n        body,\n      };\n    });\n  }\n\n  // ── Send ──\n\n  /** Send a text message. Encrypt at the current epoch, POST, return the receipt +\n   * the client-minted `clientMsgId` (needed by the Chat layer for reply indexing).\n   * NEVER rebases (a 422 stale_application surfaces to the caller). */\n  async sendText(\n    group: MessagingGroup,\n    text: string,\n    replyTo?: ReplyRef | null,\n    bodyRanges?: MentionRange[] | null,\n    expiry?: ExpirySpec | null,\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const clientMsgId = mintClientMsgId();\n    const plaintext = encodeEnvelope({ text, clientMsgId, replyTo, bodyRanges, expiry });\n    const ct = await this.engine.encryptApplication(fromBase64(group.rfcGroupId), plaintext);\n    const body: SendMessageBody = {\n      ciphertext_b64: toBase64(ct),\n      client_idem_key: randomId(),\n    };\n    const wire = await palbeRequest<WireReceipt>(\n      this.rt,\n      'POST',\n      MessagingPaths.groupMessages(group.displayId),\n      { body },\n    );\n\n    // Persist the OUTGOING copy — the ONLY durable form of an own-sent message\n    // (the sender can never decrypt its own ciphertext). Best-effort: the send\n    // already landed; a persist failure must not fail/re-trigger it.\n    const stored: StoredMessage = {\n      id: `${group.rfcGroupId}#${wire.server_seq}`,\n      direction: 'outgoing',\n      text,\n      senderDeviceId: this.selfDeviceId,\n      epoch: wire.epoch,\n      serverSeq: wire.server_seq,\n      at: Date.now(),\n      clientMsgId,\n      replyTo: replyTo\n        ? {\n            clientMsgId: replyTo.client_msg_id,\n            previewBody: replyTo.preview?.body ?? null,\n            previewAuthorUserId: replyTo.preview?.author_user_id ?? null,\n            previewKind: replyTo.preview?.kind ?? 'text',\n          }\n        : null,\n      // Persist the OUTGOING bubble's mention ranges so an own-sent mention re-resolves\n      // onto its bubble after a reload (own-send reload parity — the T4-reviewer Minor).\n      ...(bodyRanges && bodyRanges.length > 0 ? { bodyRanges } : {}),\n      // Disappearing T10: persist the per-message TTL so the own-send re-arms its purge\n      // after a cold launch (the projection derives the deadline from this row's expiry).\n      ...(expiry ? { expiry } : {}),\n    };\n    try {\n      await this.messageStore.append(group.rfcGroupId, stored);\n    } catch {\n      // logged at the coordinator level; never fails the send\n    }\n    return { receipt: { serverSeq: wire.server_seq, epoch: wire.epoch }, clientMsgId };\n  }\n\n  /** Send a per-chat default disappearing-timer control envelope (`timer_set`). Encrypts\n   * a `type:'timer_set'` envelope at the current epoch and sends through the SAME MLS\n   * application path as `sendText` (the server stays blind — it's an opaque app message,\n   * NEVER a bubble). `ttlSeconds === null` disables the default (omitted from the wire).\n   * Persists the outgoing `timer_set` row so the chat default re-folds on cold launch\n   * (the page-local TimerFold in projectHistory). NEVER rebases (epoch-bound). */\n  async sendTimerSet(\n    group: MessagingGroup,\n    args: { clientMsgId: string; ttlSeconds: number | null; start: 'send' | 'read' },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const plaintext = encodeTimerSet({\n      clientMsgId: args.clientMsgId,\n      ttlSeconds: args.ttlSeconds,\n      start: args.start,\n    });\n    const ct = await this.engine.encryptApplication(fromBase64(group.rfcGroupId), plaintext);\n    const body: SendMessageBody = {\n      ciphertext_b64: toBase64(ct),\n      client_idem_key: randomId(),\n    };\n    const wire = await palbeRequest<WireReceipt>(\n      this.rt,\n      'POST',\n      MessagingPaths.groupMessages(group.displayId),\n      { body },\n    );\n\n    // Persist the OUTGOING timer_set copy (same rationale as sendText: the sender can't\n    // decrypt its own ciphertext). text is null — a timer_set is never a bubble; the\n    // envelopeType + timer fields drive the chat-default re-fold on reload.\n    const stored: StoredMessage = {\n      id: `${group.rfcGroupId}#${wire.server_seq}`,\n      direction: 'outgoing',\n      text: null,\n      senderDeviceId: this.selfDeviceId,\n      epoch: wire.epoch,\n      serverSeq: wire.server_seq,\n      at: Date.now(),\n      clientMsgId: args.clientMsgId,\n      replyTo: null,\n      envelopeType: 'timer_set',\n      timer: { ttlSeconds: args.ttlSeconds, start: args.start },\n    };\n    try {\n      await this.messageStore.append(group.rfcGroupId, stored);\n    } catch {\n      // best-effort, identical to sendText/sendReaction/sendEdit/sendDelete\n    }\n    return {\n      receipt: { serverSeq: wire.server_seq, epoch: wire.epoch },\n      clientMsgId: args.clientMsgId,\n    };\n  }\n\n  /** Send a reaction (add/remove of an emoji on a target message). Encrypts a\n   * `type:'reaction'` envelope at the current epoch and sends through the SAME\n   * MLS application path as `sendText` (the server stays blind — a reaction is\n   * just another application message). Persists the outgoing reaction row so it\n   * re-folds onto its target after a reload (the own-send half of the reload\n   * parity). NEVER rebases (epoch-bound like any application message). */\n  async sendReaction(\n    group: MessagingGroup,\n    args: { clientMsgId: string; targetClientMsgId: string; emoji: string; op: 'add' | 'remove' },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const plaintext = encodeReaction({\n      clientMsgId: args.clientMsgId,\n      targetClientMsgId: args.targetClientMsgId,\n      emoji: args.emoji,\n      op: args.op,\n    });\n    const ct = await this.engine.encryptApplication(fromBase64(group.rfcGroupId), plaintext);\n    const body: SendMessageBody = {\n      ciphertext_b64: toBase64(ct),\n      client_idem_key: randomId(),\n    };\n    const wire = await palbeRequest<WireReceipt>(\n      this.rt,\n      'POST',\n      MessagingPaths.groupMessages(group.displayId),\n      { body },\n    );\n\n    // Persist the OUTGOING reaction copy (same rationale as sendText: the sender\n    // can't decrypt its own ciphertext). text is null — a reaction is never a\n    // bubble; the envelopeType + reaction fields drive the re-fold on reload.\n    const stored: StoredMessage = {\n      id: `${group.rfcGroupId}#${wire.server_seq}`,\n      direction: 'outgoing',\n      text: null,\n      senderDeviceId: this.selfDeviceId,\n      epoch: wire.epoch,\n      serverSeq: wire.server_seq,\n      at: Date.now(),\n      clientMsgId: args.clientMsgId,\n      replyTo: null,\n      envelopeType: 'reaction',\n      reaction: {\n        targetClientMsgId: args.targetClientMsgId,\n        emoji: args.emoji,\n        op: args.op,\n      },\n    };\n    try {\n      await this.messageStore.append(group.rfcGroupId, stored);\n    } catch {\n      // best-effort, identical to sendText\n    }\n    return {\n      receipt: { serverSeq: wire.server_seq, epoch: wire.epoch },\n      clientMsgId: args.clientMsgId,\n    };\n  }\n\n  /** Send an edit (edit-by-supersession on a target message). Encrypts a\n   * `type:'edit'` envelope at the current epoch and sends through the SAME MLS\n   * application path as `sendText` (the server stays blind — an edit is just\n   * another application message). Persists the outgoing edit row so it re-folds\n   * onto its target's text after a reload (the own-send half of the reload\n   * parity). NEVER rebases (epoch-bound like any application message). */\n  async sendEdit(\n    group: MessagingGroup,\n    args: {\n      clientMsgId: string;\n      targetClientMsgId: string;\n      newText: string;\n      bodyRanges?: MentionRange[] | null;\n    },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const plaintext = encodeEdit({\n      clientMsgId: args.clientMsgId,\n      targetClientMsgId: args.targetClientMsgId,\n      newText: args.newText,\n      bodyRanges: args.bodyRanges,\n    });\n    const ct = await this.engine.encryptApplication(fromBase64(group.rfcGroupId), plaintext);\n    const body: SendMessageBody = {\n      ciphertext_b64: toBase64(ct),\n      client_idem_key: randomId(),\n    };\n    const wire = await palbeRequest<WireReceipt>(\n      this.rt,\n      'POST',\n      MessagingPaths.groupMessages(group.displayId),\n      { body },\n    );\n\n    // Persist the OUTGOING edit copy (same rationale as sendText: the sender can't\n    // decrypt its own ciphertext). text is null — an edit is never a bubble; the\n    // envelopeType + edit fields drive the re-fold onto the target on reload.\n    const stored: StoredMessage = {\n      id: `${group.rfcGroupId}#${wire.server_seq}`,\n      direction: 'outgoing',\n      text: null,\n      senderDeviceId: this.selfDeviceId,\n      epoch: wire.epoch,\n      serverSeq: wire.server_seq,\n      at: Date.now(),\n      clientMsgId: args.clientMsgId,\n      replyTo: null,\n      envelopeType: 'edit',\n      edit: {\n        targetClientMsgId: args.targetClientMsgId,\n        newText: args.newText,\n        // Persist the edit's REPLACEMENT ranges so the edited message's mentions\n        // re-resolve from this edit after a reload (own-send reload parity — T6).\n        ...(args.bodyRanges && args.bodyRanges.length > 0 ? { bodyRanges: args.bodyRanges } : {}),\n      },\n    };\n    try {\n      await this.messageStore.append(group.rfcGroupId, stored);\n    } catch {\n      // best-effort, identical to sendText/sendReaction\n    }\n    return {\n      receipt: { serverSeq: wire.server_seq, epoch: wire.epoch },\n      clientMsgId: args.clientMsgId,\n    };\n  }\n\n  /** Send a delete-for-everyone tombstone on a target message. Encrypts a\n   * `type:'delete'` envelope at the current epoch and sends through the SAME MLS\n   * application path as `sendText` (the server stays blind — a delete is just\n   * another opaque application message; the original ciphertext row is NOT\n   * removed). Persists the outgoing delete row so the tombstone re-folds onto its\n   * target after a reload (the own-send half of the reload parity — the iOS-review\n   * CRITICAL boundary; the projection's `.delete` branch re-folds it). NEVER\n   * rebases (epoch-bound like any application message). */\n  async sendDelete(\n    group: MessagingGroup,\n    args: { clientMsgId: string; targetClientMsgId: string },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const plaintext = encodeDelete({\n      clientMsgId: args.clientMsgId,\n      targetClientMsgId: args.targetClientMsgId,\n    });\n    const ct = await this.engine.encryptApplication(fromBase64(group.rfcGroupId), plaintext);\n    const body: SendMessageBody = {\n      ciphertext_b64: toBase64(ct),\n      client_idem_key: randomId(),\n    };\n    const wire = await palbeRequest<WireReceipt>(\n      this.rt,\n      'POST',\n      MessagingPaths.groupMessages(group.displayId),\n      { body },\n    );\n\n    // Persist the OUTGOING delete copy (same rationale as sendText: the sender can't\n    // decrypt its own ciphertext). text is null — a delete is never a bubble; the\n    // envelopeType + delete fields drive the re-fold onto the target on reload.\n    const stored: StoredMessage = {\n      id: `${group.rfcGroupId}#${wire.server_seq}`,\n      direction: 'outgoing',\n      text: null,\n      senderDeviceId: this.selfDeviceId,\n      epoch: wire.epoch,\n      serverSeq: wire.server_seq,\n      at: Date.now(),\n      clientMsgId: args.clientMsgId,\n      replyTo: null,\n      envelopeType: 'delete',\n      delete: {\n        targetClientMsgId: args.targetClientMsgId,\n        scope: 'everyone',\n      },\n    };\n    try {\n      await this.messageStore.append(group.rfcGroupId, stored);\n    } catch {\n      // best-effort, identical to sendText/sendReaction/sendEdit\n    }\n    return {\n      receipt: { serverSeq: wire.server_seq, epoch: wire.epoch },\n      clientMsgId: args.clientMsgId,\n    };\n  }\n\n  // ── The rebase loop ──\n\n  private async commitWithRebase(\n    rfcGroupId: string,\n    build: () => Promise<{ method: string; path: string; body: unknown }>,\n  ): Promise<void> {\n    const gidBytes = fromBase64(rfcGroupId);\n    let lastEpoch: number | null = null;\n    for (let attempt = 1; attempt <= this.rebase.maxAttempts; attempt++) {\n      const pending = await build();\n      try {\n        await palbeRequest<CommitAccepted>(this.rt, pending.method, pending.path, {\n          body: pending.body,\n        });\n        await this.engine.applyPendingCommit(gidBytes);\n        return;\n      } catch (e) {\n        if (isBackendError(e) && e.code === 'epoch_conflict') {\n          await this.engine.clearPendingCommit(gidBytes);\n          const ce = (e.data as { current_epoch?: number } | undefined)?.current_epoch;\n          if (typeof ce === 'number') lastEpoch = ce;\n          if (attempt === this.rebase.maxAttempts) break;\n          await this.drain(rfcGroupId);\n          await this.backoff(attempt);\n          continue; // rebuild + re-POST\n        }\n        throw e;\n      }\n    }\n    await this.engine.clearPendingCommit(gidBytes);\n    throw new RebaseExhausted(this.rebase.maxAttempts, lastEpoch);\n  }\n\n  /** Pull the device queue, process the winning commit(s) so the engine advances\n   * to the new epoch, ack the commits (the delivery source owns app messages). */\n  private async drain(rfcGroupId: string): Promise<void> {\n    const page = await palbeRequest<QueuePage>(\n      this.rt,\n      'GET',\n      MessagingPaths.deviceQueue(this.selfDeviceId),\n    );\n    const gidBytes = fromBase64(rfcGroupId);\n    const ackIds: string[] = [];\n    for (const row of page.messages) {\n      if (row.content_type !== ContentType.commit) continue;\n      try {\n        await this.engine.processIncoming(gidBytes, fromBase64(row.ciphertext_b64));\n      } catch {\n        // a non-applicable commit (own / consumed) — still ack so it isn't redelivered\n      }\n      ackIds.push(row.id);\n    }\n    if (ackIds.length > 0) {\n      await palbeRequest<void>(this.rt, 'POST', MessagingPaths.deviceQueueAck(this.selfDeviceId), {\n        body: { message_ids: ackIds },\n      });\n    }\n  }\n\n  private async backoff(attempt: number): Promise<void> {\n    const base = this.rebase.baseDelayMs * attempt;\n    const jitter = this.rebase.jitterMs === 0 ? 0 : Math.random() * this.rebase.jitterMs;\n    const total = base + jitter;\n    if (total <= 0) return;\n    await new Promise((r) => setTimeout(r, total));\n  }\n}\n","import type { MentionRange } from './group-messaging.js';\n\n// Mentions (design 2026-06-20) — the PURE, deterministic decode-time normalization of\n// `body_ranges`. BOTH SDKs (iOS `Palbe` + web `@palbase/web`) apply this exact\n// algorithm bit-identically so a malformed or adversarial `body_ranges` produces the\n// SAME surviving spans on both runtimes. A cross-binding golden (T7) locks this — if\n// one SDK clamped where the other dropped, both could pass their own tests yet diverge\n// on the wire. This is a single PINNED contract, not implementer's choice.\n//\n// OFFSET UNIT = UTF-16 code units (JS string .length IS UTF-16 code units — native).\n// NEVER use [...text] (scalar/codepoint iteration) — mixing units corrupts spans over\n// emoji/surrogate pairs. Use text.length / text.charCodeAt / text.slice only.\n// The `…Utf16` suffix names the unit so an accidental scalar use is visible.\n//\n// THE EXACT ORDERED ALGORITHM (offsets are UTF-16 code units; N = text.length):\n//   1.  DROP-invalid (not clamp): drop if start < 0 || length <= 0 || start + length > N.\n//   1b. DROP-surrogate-boundary: drop if `start` OR `start+length` index falls mid\n//       surrogate pair (the unit BEFORE the index is a high surrogate 0xD800–0xDBFF AND\n//       the unit AT the index is a low surrogate 0xDC00–0xDFFF). Splitting a pair is\n//       invalid. Index 0 and index N never trigger.\n//   2.  SORT: ascending by `start`; ties broken by `length` DESCENDING (wider survives an\n//       equal-start collision); then by original index ascending (stable). Sort BEFORE\n//       the overlap walk — mandatory; walking unsorted input changes which range survives.\n//   3.  DROP-overlap (not merge) + drop-duplicate: walk left-to-right; keep a range only\n//       if its `start >= previous-KEPT range's (start+length)`; otherwise DROP it (the\n//       later overlapper). Exact duplicates fall out as a sub-case. NEVER merge.\n//\n// PURE: no I/O, never throws. A fully-invalid input returns []; the message text always\n// renders regardless. The self-mention-by-sender \"render-but-don't-elevate\" rule is NOT\n// applied here — normalize is purely structural; that gate lives at the elevation\n// decision (T3).\n\n/**\n * Deterministically normalize decode-time mention ranges per the pinned cross-SDK\n * contract (drop-invalid → drop-surrogate-boundary → sort[start asc, length DESC, idx\n * asc] → drop-overlap/duplicate). Offsets are UTF-16 code units into `text`. Pure.\n *\n * Mirrors iOS `normalizeMentionRangesUtf16` BIT-IDENTICALLY (T7 cross-binding golden\n * locks this). NEVER uses `[...text]` scalar spread — only `text.length` / `charCodeAt`.\n */\nexport function normalizeMentionRangesUtf16(ranges: MentionRange[], text: string): MentionRange[] {\n  const n = text.length; // UTF-16 code unit count — native JS string .length\n\n  // True iff splitting `text` AT `index` would cut a surrogate pair — i.e. the unit\n  // just before `index` is a high surrogate and the unit at `index` is a low surrogate.\n  // Boundary indices 0 and n are always safe (no unit before / no unit at).\n  function splitsSurrogatePair(index: number): boolean {\n    if (index <= 0 || index >= n) return false;\n    const before = text.charCodeAt(index - 1);\n    const at = text.charCodeAt(index);\n    const beforeIsHigh = before >= 0xd800 && before <= 0xdbff;\n    const atIsLow = at >= 0xdc00 && at <= 0xdfff;\n    return beforeIsHigh && atIsLow;\n  }\n\n  // Steps 1 + 1b — DROP-invalid then DROP-surrogate-boundary. Retain the original index\n  // for the stable tie-break in step 2.\n  const survivors: Array<{ idx: number; range: MentionRange }> = [];\n  for (let idx = 0; idx < ranges.length; idx++) {\n    const r = ranges[idx];\n    if (r === undefined) continue;\n    // Step 1: validity (drop, do not clamp).\n    if (r.start < 0 || r.length <= 0 || r.start + r.length > n) continue;\n    // Step 1b: surrogate-pair boundary (drop). r.start + r.length <= n is guaranteed\n    // by step 1, so both indices are in [0, n].\n    if (splitsSurrogatePair(r.start) || splitsSurrogatePair(r.start + r.length)) continue;\n    survivors.push({ idx, range: r });\n  }\n\n  // Step 2: sort ascending by start; ties by length DESCENDING (wider wins); then by\n  // original index ascending (stable). Done BEFORE the overlap walk.\n  survivors.sort((lhs, rhs) => {\n    if (lhs.range.start !== rhs.range.start) return lhs.range.start - rhs.range.start;\n    if (lhs.range.length !== rhs.range.length) return rhs.range.length - lhs.range.length; // DESC\n    return lhs.idx - rhs.idx;\n  });\n\n  // Step 3: drop the later overlapper (and exact duplicates as a sub-case) — never merge.\n  const kept: MentionRange[] = [];\n  let prevEnd = Number.NEGATIVE_INFINITY; // exclusive end of the last KEPT range\n  for (const s of survivors) {\n    if (s.range.start >= prevEnd) {\n      kept.push(s.range);\n      prevEnd = s.range.start + s.range.length;\n    }\n    // else: overlaps (or duplicates) the previous kept range → DROP.\n  }\n  return kept;\n}\n","/**\n * ReactionFold — pure fold of reaction events into a per-target emoji tally.\n *\n * Algorithm mirrors iOS `ReactionFold` (ReactionFold.swift) byte-for-byte in\n * behaviour: LWW per (target, actorUserId) on (epoch, serverSeq), idempotent\n * on eventClientMsgId.\n *\n * Tie assumption (same as iOS doc-comment):\n *   The server guarantees (epoch, serverSeq) is unique per logical event, so\n *   exact-order ties cannot occur in practice. The `<=` stale-check (first-\n *   arriving wins on an exact tie) is therefore safe. Re-delivery of the SAME\n *   logical event is already handled by the seenEvents dedup and never reaches\n *   this check.\n */\n\nexport interface ReactionEvent {\n  targetClientMsgId: string;\n  actorUserId: string;\n  emoji: string;\n  op: 'add' | 'remove';\n  epoch: number;\n  serverSeq: number;\n  /** Dedup key — unique per logical event (e.g. the reaction message's clientMsgId). */\n  eventClientMsgId: string;\n}\n\n/** Lexicographic (epoch, serverSeq) comparison. Returns true if a <= b. */\nfunction orderLte(aEpoch: number, aSeq: number, bEpoch: number, bSeq: number): boolean {\n  if (aEpoch !== bEpoch) return aEpoch < bEpoch;\n  return aSeq <= bSeq;\n}\n\ninterface UserState {\n  orderEpoch: number;\n  orderSeq: number;\n  emoji: string | null; // null = removed\n}\n\nexport class ReactionFold {\n  // Map<targetClientMsgId, Map<actorUserId, UserState>>\n  private readonly states = new Map<string, Map<string, UserState>>();\n  // Dedup set: eventClientMsgId values already applied.\n  private readonly seenEvents = new Set<string>();\n\n  ingest(e: ReactionEvent): void {\n    // Idempotency: skip if this exact event was already applied.\n    if (this.seenEvents.has(e.eventClientMsgId)) return;\n    this.seenEvents.add(e.eventClientMsgId);\n\n    let byUser = this.states.get(e.targetClientMsgId);\n    if (byUser === undefined) {\n      byUser = new Map<string, UserState>();\n      this.states.set(e.targetClientMsgId, byUser);\n    }\n\n    const prev = byUser.get(e.actorUserId);\n    if (prev !== undefined) {\n      // Stale / out-of-order: ignore if new order <= stored order.\n      if (orderLte(e.epoch, e.serverSeq, prev.orderEpoch, prev.orderSeq)) return;\n    }\n\n    byUser.set(e.actorUserId, {\n      orderEpoch: e.epoch,\n      orderSeq: e.serverSeq,\n      emoji: e.op === 'add' ? e.emoji : null,\n    });\n  }\n\n  /**\n   * Returns a tally of `{ emoji → sorted userIds[] }` for the given target\n   * message. Users whose last event was a `remove` (emoji === null) are\n   * excluded. userId arrays are sorted for deterministic output (render\n   * stability + golden tests).\n   */\n  tally(targetClientMsgId: string): Record<string, string[]> {\n    const byUser = this.states.get(targetClientMsgId);\n    if (byUser === undefined) return {};\n\n    const out = new Map<string, string[]>();\n    for (const [userId, st] of byUser) {\n      if (st.emoji === null) continue;\n      let users = out.get(st.emoji);\n      if (users === undefined) {\n        users = [];\n        out.set(st.emoji, users);\n      }\n      users.push(userId);\n    }\n\n    // Sort userId arrays for determinism (render stability + golden tests).\n    const result: Record<string, string[]> = {};\n    for (const [emoji, users] of out) {\n      result[emoji] = users.sort();\n    }\n    return result;\n  }\n}\n","/**\n * TimerFold — pure per-chat fold of `timer_set` events into ONE active default\n * cell. LWW on (epoch, serverSeq); idempotent on eventClientMsgId. Mirrors iOS\n * `TimerFold` byte-for-byte in behaviour (and reactions' (epoch,seq) machinery),\n * keyed at the chat level rather than per-target. `actorUserId` is the\n * AUTHENTICATED sender resolved upstream — never a wire field.\n */\nexport interface TimerEvent {\n  ttlSeconds: number | null;\n  start: 'send' | 'read';\n  actorUserId: string;\n  epoch: number;\n  serverSeq: number;\n  eventClientMsgId: string;\n}\n\n/** Lexicographic (epoch, serverSeq) comparison. Returns true if a <= b. */\nfunction orderLte(aEpoch: number, aSeq: number, bEpoch: number, bSeq: number): boolean {\n  if (aEpoch !== bEpoch) return aEpoch < bEpoch;\n  return aSeq <= bSeq;\n}\n\ninterface Cell {\n  orderEpoch: number;\n  orderSeq: number;\n  ttlSeconds: number | null;\n  start: 'send' | 'read';\n  actor: string;\n}\n\nexport class TimerFold {\n  private cell: Cell | null = null;\n  private readonly seenEvents = new Set<string>();\n\n  ingest(e: TimerEvent): void {\n    // Idempotency: skip if this exact event was already applied.\n    if (this.seenEvents.has(e.eventClientMsgId)) return;\n    this.seenEvents.add(e.eventClientMsgId);\n\n    // Stale / out-of-order: ignore if new order <= stored order. The server\n    // guarantees (epoch, serverSeq) is unique per logical event, so exact-order\n    // ties cannot occur in practice; first-arriving wins on an exact tie. SAME\n    // logical event re-delivery is already caught by the seenEvents dedup above.\n    if (\n      this.cell !== null &&\n      orderLte(e.epoch, e.serverSeq, this.cell.orderEpoch, this.cell.orderSeq)\n    ) {\n      return;\n    }\n    this.cell = {\n      orderEpoch: e.epoch,\n      orderSeq: e.serverSeq,\n      ttlSeconds: e.ttlSeconds,\n      start: e.start,\n      actor: e.actorUserId,\n    };\n  }\n\n  /**\n   * The active chat default, or null if no timer_set has applied.\n   * `ttlSeconds === null` means DISABLED (still applied — distinct from \"never\n   * set\"). `start` is meaningful only when ttlSeconds !== null.\n   */\n  active(): { ttlSeconds: number | null; start: 'send' | 'read' } | null {\n    if (this.cell === null) return null;\n    return { ttlSeconds: this.cell.ttlSeconds, start: this.cell.start };\n  }\n\n  /** The userId behind the winning timer_set (for the optional system line). null if unset. */\n  lastActor(): string | null {\n    return this.cell?.actor ?? null;\n  }\n}\n","// The Chat — the one object a chat screen binds to. A DM or a group, uniformly.\n// Web idiom of the iOS `@Observable Chat`: an event-emitter exposing `onChange`\n// returning an Unsubscribe (matches flags/realtime), plus snapshot getters\n// (messages/members/typing/unreadCount/lastMessage). React hooks wrap it with\n// useSyncExternalStore.\n//\n// WhatsApp-lazy: a direct/group chat opens as a `.draft` (no network); the first\n// `send` MATERIALIZES it (claim → create/get-or-create → add → register), flips\n// to `.active`, wires live subscriptions, and hydrates durable history.\n\nimport { type AnchorTriple, MonotonicClock, remainingSeconds } from './deadline-calculator.js';\nimport { DeleteFold } from './delete-fold.js';\nimport type { IncomingMessage } from './delivery-source.js';\nimport { type AuthorResolution, EditFold } from './edit-fold.js';\nimport {\n  type ExpirySpec,\n  type MentionRange,\n  type MessagingGroup,\n  type ReplyRef,\n  resolveReply,\n} from './group-messaging.js';\nimport { normalizeMentionRangesUtf16 } from './mention-ranges.js';\nimport { ReactionFold } from './reaction-fold.js';\nimport { TimerFold } from './timer-fold.js';\nimport type {\n  ChatKind,\n  ChatMember,\n  ChatMessage,\n  ChatMessageKind,\n  ChatState,\n  MessageDirection,\n  NotifyScope,\n  PresenceState,\n  ResolvedMention,\n  ResolvedReply,\n  SentReceipt,\n  UnreadView,\n  Unsubscribe,\n} from './types.js';\nimport { mintClientMsgId, truncateQuote } from './util.js';\n\n/**\n * The neutral copy shown in place of a deleted-for-everyone message. Cooperative\n * erasure — it does NOT imply cryptographic erasure (the design's honest caveat).\n * The single source of truth for the descriptor, used by BOTH the live Chat render\n * precedence and the coordinator history projection so they render identically.\n */\nexport const DELETED_DESCRIPTOR = '🚫 This message was deleted';\n\n/** The intended participants of a draft chat (held until the first send). */\nexport interface ChatDraft {\n  mode: { kind: 'direct'; peerUserId: string } | { kind: 'group'; members: string[] };\n  /** The reserved local id a draft shows before it materializes. */\n  reservedId: string;\n}\n\n/** The seam the Chat talks to for the work needing the resolved machinery. */\nexport interface ChatBackend {\n  selfUserId: string;\n  /** Materialize a draft → the active group (DM get-or-create / group create+add). */\n  materialize(draft: ChatDraft): Promise<MessagingGroup>;\n  sendText(\n    group: MessagingGroup,\n    text: string,\n    replyTo?: ReplyRef | null,\n    bodyRanges?: MentionRange[] | null,\n    expiry?: ExpirySpec | null,\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }>;\n  /** Send a reaction (add/remove an emoji on a target message) through the same\n   * MLS application path as `sendText`. Returns the receipt + the wire clientMsgId. */\n  sendReaction(\n    group: MessagingGroup,\n    args: { clientMsgId: string; targetClientMsgId: string; emoji: string; op: 'add' | 'remove' },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }>;\n  /** Send an edit (edit-by-supersession on a target message) through the same MLS\n   * application path as `sendText`. Returns the receipt + the wire clientMsgId. */\n  sendEdit(\n    group: MessagingGroup,\n    args: {\n      clientMsgId: string;\n      targetClientMsgId: string;\n      newText: string;\n      bodyRanges?: MentionRange[] | null;\n    },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }>;\n  /** Send a delete-for-everyone tombstone on a target message through the same MLS\n   * application path as `sendText` (the server stays blind — a delete is just\n   * another opaque application message). Returns the receipt + the wire clientMsgId. */\n  sendDelete(\n    group: MessagingGroup,\n    args: { clientMsgId: string; targetClientMsgId: string },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }>;\n  history(group: MessagingGroup, limit: number, before?: number): Promise<ChatMessage[]>;\n  members(group: MessagingGroup): Promise<ChatMember[]>;\n  addMember(group: MessagingGroup, userId: string): Promise<void>;\n  removeMember(group: MessagingGroup, userId: string): Promise<void>;\n  leave(group: MessagingGroup): Promise<void>;\n  registerActive(group: MessagingGroup): void;\n  setTyping(group: MessagingGroup, isTyping: boolean): void;\n  markRead(group: MessagingGroup, upToServerSeq: number): Promise<void>;\n  /** Server-metadata cluster: set/get the per-(user,group) notify scope (mute) and\n   * fetch the caller's own unread view. The server stays MLS-blind (opaque metadata). */\n  setNotifyScope(group: MessagingGroup, scope: NotifyScope): Promise<NotifyScope>;\n  getNotifyScope(group: MessagingGroup): Promise<NotifyScope>;\n  unread(group: MessagingGroup): Promise<UnreadView>;\n  /** Subscribe live message + conv (presence/typing/read/delivered) for an active group. */\n  subscribeLive(group: MessagingGroup, chat: Chat): Unsubscribe;\n  /** Resolve a sender device id → its owning user id (for senderUserId). */\n  userIdForDevice(group: MessagingGroup, deviceId: string): Promise<string | null>;\n  /** Load this chat's persisted delete-for-me suppression keys (durable, no wire). */\n  loadSuppressed(group: MessagingGroup): Promise<string[]>;\n  /** Persist this chat's delete-for-me suppression keys (durable, no wire). */\n  saveSuppressed(group: MessagingGroup, keys: string[]): Promise<void>;\n  /** Load this chat's persisted self-elevation dedup keys (durable, no wire) so a\n   * re-delivered mention does not re-fire `onMentionElevation` after a cold launch. */\n  loadElevated(group: MessagingGroup): Promise<string[]>;\n  /** Persist this chat's self-elevation dedup keys (durable, no wire). */\n  saveElevated(group: MessagingGroup, keys: string[]): Promise<void>;\n\n  // ── Disappearing / TTL (T10) ──\n\n  /** Send a per-chat default disappearing-timer control envelope (`timer_set`). Goes\n   * through the SAME MLS application path as `sendText` — server-blind, never a bubble.\n   * `ttlSeconds === null` disables the default. Returns the receipt + the wire clientMsgId. */\n  sendTimerSet(\n    group: MessagingGroup,\n    args: { clientMsgId: string; ttlSeconds: number | null; start: 'send' | 'read' },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }>;\n  /** The persisted INTEGER `server_seq` tombstone set for a chat — drives transcript\n   * exclusion (cold-launch) + redelivery drop (live arrival). Durable, no wire. */\n  tombstonedSeqs(group: MessagingGroup): Promise<Set<number>>;\n  /** The persisted STRING `client_msg_id` purge set — drives the orphan-fold resolver\n   * (`authorOfTarget → 'purged'`) so a late edit DROPs / a late delete no-ops. */\n  purgedClientMsgIds(group: MessagingGroup): Promise<Set<string>>;\n  /** The persisted write-once anchor triple for a `clientMsgId`, or null if none. */\n  anchor(group: MessagingGroup, clientMsgId: string): Promise<AnchorTriple | null>;\n  /** Write-once: capture the first-arrival/first-read anchor triple for a `clientMsgId`\n   * (a second call for the same id is a no-op, so the deadline never resets). */\n  writeAnchorOnce(group: MessagingGroup, clientMsgId: string, a: AnchorTriple): Promise<void>;\n  /** Tombstone-first purge commit point: persist the int `server_seq` + string\n   * `client_msg_id` purge id in ONE durable record (idempotent). */\n  tombstone(group: MessagingGroup, serverSeq: number, clientMsgId: string): Promise<void>;\n}\n\nexport class Chat {\n  /** Stable, URL/log-safe id (the grp_ display id once active; a reserved local id while draft). */\n  id: string;\n  readonly kind: ChatKind;\n  private _state: ChatState;\n\n  private _group: MessagingGroup | null;\n  private _draft: ChatDraft | null;\n  private readonly backend: ChatBackend;\n\n  private messageList: ChatMessage[] = [];\n  private memberCache: ChatMember[] = [];\n  private typingList: ChatMember[] = [];\n  private presenceStates = new Map<string, PresenceState>();\n  private readWatermark = -1;\n  private titleOverride: string | null = null;\n\n  private readonly seenKeys = new Set<string>();\n  /** Index: clientMsgId → { text, senderUserId } for resolveReply lookups. */\n  private readonly byClientMsgId = new Map<string, { text: string; senderUserId: string }>();\n  /** The single authoritative reaction fold for this chat (live + own-send + history). */\n  private readonly reactionFold = new ReactionFold();\n  /** The single authoritative edit fold for this chat (live + own-send + history). */\n  private readonly editFold = new EditFold();\n  /** The single authoritative delete-for-everyone fold (live + own-send + history).\n   * A tombstone scrubs its target in place (delete DOMINATES edit at render). */\n  private readonly deleteFold = new DeleteFold();\n  /** The per-chat default disappearing-timer fold — the latest valid `timer_set` (LWW\n   * on (epoch, serverSeq), author = the resolved MLS sender). A `timer_set` is NEVER a\n   * bubble; it routes here. The active default governs a subsequent bubble that carries\n   * no per-message expiry (disappearing T10). */\n  private readonly timerFold = new TimerFold();\n  /** Advisory in-memory purge timers, keyed by serverSeq. The DURABLE truth is the\n   * persisted anchor + a re-check on every load; this just drives live eviction while\n   * the tab is open. Cancelled when the message purges (disappearing T10). */\n  private readonly purgeTimers = new Map<number, ReturnType<typeof setTimeout>>();\n  /** In-memory mirror of the durable `purgedClientMsgIds` set (the STRING namespace),\n   * hydrated from `backend.purgedClientMsgIds` and grown by each live purge. Consulted\n   * by `authorOfTarget` so a late edit/delete targeting a TTL-purged message resolves to\n   * `'purged'` (DROP / no-op — never resurrects). Namespace-separate from the int seq\n   * tombstone (disappearing T10). */\n  private readonly purgedCids = new Set<string>();\n  private purgedLoaded = false;\n  /** delete-for-me suppression keys (clientMsgId, or `seq:<serverSeq>` for legacy)\n   * — the message is OMITTED from this view. Local + persisted per chat, NO wire. */\n  private readonly suppressed = new Set<string>();\n  /** True once the persisted suppression set has been loaded (so the omit applies\n   * even on the cold-launch hydrate path before a fresh deleteForMe). */\n  private suppressedLoaded = false;\n  /** Self-elevation dedup keys (`<selfUserId>|<clientMsgId or seq:n>`). Once a\n   * mention of me from another sender fires `onMentionElevation`, its key lands here\n   * + is persisted, so a re-delivery / cold-launch re-hydrate never re-fires. */\n  private readonly elevated = new Set<string>();\n  /** True once the persisted elevation set has been loaded (so a re-delivered mention\n   * on the cold-launch hydrate path dedups against the persisted decision). */\n  private elevatedLoaded = false;\n  /** Per-target BASE (original) text, so the rendered text is `edit ?? original`.\n   * Seeded once per target (write-once base) so a 2nd own edit can't corrupt it. */\n  private readonly originalTextByClientMsgId = new Map<string, string | null>();\n  /** Per-target AUTHOR userId — the EditFold author-gate input (filled at bubble\n   * projection time from senderUserId; '' = resolved-but-unknown peer). */\n  private readonly authorByClientMsgId = new Map<string, string>();\n  private loadedEarliestSeq: number | null = null;\n  private historyLoaded = false;\n  private wired = false;\n  private liveUnsub: Unsubscribe | null = null;\n\n  private readonly listeners = new Set<() => void>();\n\n  /**\n   * Fires ONCE per `(selfUserId, clientMsgId)` when an INCOMING message mentions THIS\n   * user from ANOTHER sender (not an edit). The dedup survives re-delivery + reload\n   * via the persisted elevation set, so this never double-fires for one mention. The\n   * app wires it to a buzz/badge (e.g. an in-app banner). Best-effort cooperative —\n   * the SDK guarantees the DECISION, not the buzz. Mirrors iOS `Chat.onMentionElevation`.\n   */\n  onMentionElevation?: (message: ChatMessage) => void;\n\n  /** @internal — obtain via pb.messaging.directChat / groupChat / chat(id). */\n  constructor(\n    args:\n      | { group: MessagingGroup; kind: ChatKind; backend: ChatBackend }\n      | { draft: ChatDraft; kind: ChatKind; backend: ChatBackend },\n  ) {\n    this.backend = args.backend;\n    if ('group' in args) {\n      this.id = args.group.displayId;\n      this.kind = args.kind;\n      this._state = 'active';\n      this._group = args.group;\n      this._draft = null;\n      this.seedMembersFromGroup(args.group);\n    } else {\n      this.id = args.draft.reservedId;\n      this.kind = args.kind;\n      this._state = 'draft';\n      this._group = null;\n      this._draft = args.draft;\n      this.seedDraftMembers(args.draft);\n    }\n  }\n\n  // ── Observability ──\n\n  /** Subscribe to any change in this chat (messages/members/typing/state). */\n  onChange(cb: () => void): Unsubscribe {\n    this.listeners.add(cb);\n    // Lazily wire live + hydrate history on first observe of an active chat.\n    this.ensureWired();\n    return () => this.listeners.delete(cb);\n  }\n\n  private emit(): void {\n    for (const cb of this.listeners) cb();\n  }\n\n  // ── Snapshot getters ──\n\n  get state(): ChatState {\n    return this._state;\n  }\n  get isDirect(): boolean {\n    return this.kind === 'direct';\n  }\n  get messages(): readonly ChatMessage[] {\n    return this.surfaced();\n  }\n  get members(): readonly ChatMember[] {\n    return this.memberCache;\n  }\n  get typing(): readonly ChatMember[] {\n    return this.typingList;\n  }\n  get lastMessage(): ChatMessage | null {\n    return this.surfaced().at(-1) ?? null;\n  }\n  get unreadCount(): number {\n    // A tombstoned (deleted-for-everyone) message carries no real content, so it\n    // must not inflate the unread badge (mirrors the iOS T3 fix).\n    return this.surfaced().filter(\n      (m) => m.direction === 'incoming' && !m.isDeleted && m.serverSeq > this.readWatermark,\n    ).length;\n  }\n\n  /**\n   * The RENDER PRECEDENCE — the single composition point (live AND history project\n   * through it identically). Over the raw `messageList` (which already carries the\n   * folded edit text + reactions + reply):\n   *   (1) in the delete-for-me suppression set → OMIT the message entirely;\n   *   (2) else tombstoned (delete-for-everyone) → the neutral \"deleted\" descriptor\n   *       with reactions/reply/edit HIDDEN (delete DOMINATES edit — short-circuit);\n   *   (3) else the row as-is (edit overlay + reactions + reply already applied).\n   * Pure over (messageList, deleteFold, suppressed) — recomputed on every read so a\n   * just-folded delete / just-suppressed key takes effect without rewriting rows.\n   */\n  private surfaced(): ChatMessage[] {\n    const out: ChatMessage[] = [];\n    for (const m of this.messageList) {\n      const key = this.suppressionKey(m);\n      if (this.suppressed.has(key)) continue; // (1) for-me → omit\n      // Tombstoned by THIS chat's live fold OR already scrubbed by the coordinator\n      // history projection (the cold-launch path — its own fold pre-applied the\n      // scrub; the Chat's deleteFold is empty until a live re-delivery).\n      const tombstoned =\n        (m.clientMsgId && this.deleteFold.isTombstoned(m.clientMsgId)) || m.isDeleted;\n      if (tombstoned) {\n        // (2) tombstone DOMINATES — scrub to the descriptor, hide everything else\n        // (reactions, reply, edit AND mentions — delete dominates mentions too).\n        out.push({\n          ...m,\n          text: DELETED_DESCRIPTOR,\n          reactions: {},\n          replyTo: null,\n          edited: false,\n          isDeleted: true,\n          mentions: [],\n          // delete DOMINATES disappearing too — a tombstoned message carries no deadline.\n          expiresAt: null,\n        });\n        continue;\n      }\n      out.push(m); // (3) raw row (edit/reactions/reply already overlaid)\n    }\n    return out;\n  }\n\n  /** The delete-for-me suppression key: clientMsgId when present, else `seq:<n>`. */\n  private suppressionKey(m: ChatMessage): string {\n    return m.clientMsgId ? m.clientMsgId : `seq:${m.serverSeq}`;\n  }\n  get title(): string {\n    if (this.titleOverride) return this.titleOverride;\n    if (this._group?.name) return this._group.name;\n    // A DM is named after the PERSON, in EVERY state. `kind` — not `_draft` —\n    // is what makes it a DM: materializeIfNeeded clears `_draft`, so keying on\n    // it renamed a live one-to-one conversation to `Group <last4>` the moment\n    // its first message was sent. The roster survives that transition (the\n    // draft seed, then refreshMembers), so it is the peer's home in both.\n    if (this.kind === 'direct') {\n      const peer = this.memberCache.find((m) => !m.isSelf);\n      return peer?.displayName ?? 'Chat';\n    }\n    if (this._draft) return 'Group';\n    // Active group, no name (web has no exporter yet) — friendly fallback.\n    const tail = this.id.startsWith('grp_') ? this.id.slice(4) : this.id;\n    const short = tail.slice(-4);\n    return short ? `Group ${short}` : 'Group';\n  }\n\n  presence(userId: string): PresenceState | null {\n    return this.presenceStates.get(userId) ?? null;\n  }\n\n  // ── Wiring (live + history) ──\n\n  private ensureWired(): void {\n    if (this.wired || this._state !== 'active' || !this._group) return;\n    this.wired = true;\n    this.liveUnsub = this.backend.subscribeLive(this._group, this);\n    // Load the persisted delete-for-me suppression set FIRST so a for-me'd message\n    // stays omitted from the moment history hydrates (the cold-launch parity). The\n    // hydrate is async too; the load races it but a late load still re-emits so the\n    // omit applies (surfaced() reads the set live on every render).\n    void this.loadSuppressed();\n    // Load the persisted self-elevation dedup set FIRST too, so a re-delivered mention\n    // already-buzzed in a previous session does not re-fire on the cold-launch hydrate.\n    void this.loadElevated();\n    // Load the durable purge set (STRING namespace) BEFORE hydrating history, so the live\n    // fold's `authorOfTarget` resolves a TTL-purged target to 'purged' from the first merge\n    // (a late edit/delete against a disappeared message DROPs/no-ops). Chained so the order\n    // holds; the cold-launch transcript exclusion itself comes from projectHistory.\n    void this.loadPurged().then(() => this.hydrateHistory());\n    void this.refreshMembers();\n  }\n\n  /** Hydrate the durable `purgedClientMsgIds` set (once) into the in-memory mirror so the\n   * live Edit/Delete fold author-gate sees TTL-purged targets as 'purged' on cold launch\n   * (disappearing T10). No re-emit: it only gates the orphan-fold resolution. */\n  private async loadPurged(): Promise<void> {\n    if (this.purgedLoaded || !this._group) return;\n    this.purgedLoaded = true;\n    try {\n      const ids = await this.backend.purgedClientMsgIds(this._group);\n      for (const id of ids) this.purgedCids.add(id);\n    } catch {\n      // best-effort — a load failure just means the mirror starts empty this session\n    }\n  }\n\n  /** Hydrate the persisted delete-for-me suppression keys (once), then re-emit so\n   * any already-surfaced suppressed message is omitted (cold-launch parity). */\n  private async loadSuppressed(): Promise<void> {\n    if (this.suppressedLoaded || !this._group) return;\n    this.suppressedLoaded = true;\n    try {\n      const keys = await this.backend.loadSuppressed(this._group);\n      let changed = false;\n      for (const k of keys) {\n        if (!this.suppressed.has(k)) {\n          this.suppressed.add(k);\n          changed = true;\n        }\n      }\n      if (changed) this.emit();\n    } catch {\n      // best-effort — a load failure just means the set starts empty this session\n    }\n  }\n\n  /** Hydrate the persisted self-elevation dedup keys (once). No re-emit: the set only\n   * gates the elevation DECISION, it does not change what renders. */\n  private async loadElevated(): Promise<void> {\n    if (this.elevatedLoaded || !this._group) return;\n    this.elevatedLoaded = true;\n    try {\n      const keys = await this.backend.loadElevated(this._group);\n      for (const k of keys) this.elevated.add(k);\n    } catch {\n      // best-effort — a load failure just means the set starts empty this session\n    }\n  }\n\n  private async hydrateHistory(): Promise<void> {\n    if (this.historyLoaded || !this._group) return;\n    this.historyLoaded = true;\n    const entries = await this.backend.history(this._group, 50);\n    this.mergeHistory(entries);\n  }\n\n  private mergeHistory(incoming: ChatMessage[]): void {\n    let changed = false;\n    // Pass 1: populate byClientMsgId + the edit base/author maps from all new\n    // history rows (so replies + dangling edits within the same page and against\n    // already-indexed live messages resolve correctly).\n    for (const m of incoming) {\n      if (m.serverSeq <= 0) continue;\n      // A coordinator-scrubbed delete row carries the descriptor as `text`; never\n      // index it as reply text nor seed it as an edit base (it has no real body).\n      if (m.clientMsgId && m.text !== null && !m.isDeleted) {\n        // Index ANY row with a non-empty clientMsgId + non-null text, regardless\n        // of direction. For incoming rows senderUserId is null — use '' so the\n        // lookup entry exists and resolveReply returns state:'resolved' (real text\n        // wins over attacker-controlled preview). Spoof defense covers peer messages.\n        this.byClientMsgId.set(m.clientMsgId, {\n          text: m.text,\n          senderUserId: m.senderUserId ?? '',\n        });\n      }\n      // Seed the edit base/author. The coordinator's page-local fold already\n      // overlaid `text`/`edited` onto this row, but the row's text IS the latest\n      // edit (or original) — for the Chat's authoritative fold we want the ORIGINAL\n      // base. When the fold knows nothing for this target the upstream text IS the\n      // original; when it does know (cross-page/live), recomputeEdit uses fold.text.\n      if (m.clientMsgId && !m.isDeleted) {\n        this.seedEditBase(m.clientMsgId, m.text, m.senderUserId ?? '');\n      }\n    }\n    this.editFold.reevaluateHeld(this.authorOfTarget);\n    // Pass 2: merge into messageList (replyTo is already resolved by coordinator).\n    // The coordinator already page-local-folded reactions + edits and attached each\n    // surfaced row's tally/text; applyReactionTally + applyEditOverlay let the\n    // Chat's authoritative folds (live/own-send/cross-page) override when they hold.\n    for (const m of incoming) {\n      if (m.serverSeq <= 0) continue;\n      const key = this.internalKey(m.serverSeq);\n      if (this.seenKeys.has(key)) continue;\n      this.seenKeys.add(key);\n      // A live tombstone parked in the Chat's fold re-checks its deferred gate when\n      // an older target pages in (loadEarlier). A coordinator-scrubbed row already\n      // carries isDeleted; surfaced() honors either path (delete DOMINATES).\n      if (m.clientMsgId && !m.isDeleted) {\n        this.deleteFold.reevaluatePending(m.clientMsgId, this.authorOfTarget(m.clientMsgId));\n      }\n      // Mentions T6: re-resolve roster names on the projection's null-name spans\n      // (resolution is LIVE), then overlay the live folds (an edit replaces mentions).\n      this.messageList.push(\n        this.applyEditOverlay(this.applyReactionTally(this.resolveMentionNames(m))),\n      );\n      changed = true;\n      this.loadedEarliestSeq = Math.min(this.loadedEarliestSeq ?? m.serverSeq, m.serverSeq);\n      // Disappearing T10 (the cold-launch re-arm — the M1-trap-confirmed gap): re-arm the\n      // purge from the projection's derived EFFECTIVE deadline (own per-message expiry ELSE\n      // the chat default folded forward-only AS OF this message's order, computed in the\n      // pure projectHistory). This makes a default-governed message re-arm from HISTORY on\n      // a fresh tab, not only from a live timer_set (mirrors iOS mergeHistory armPurge).\n      if (m.expiresAt && m.clientMsgId && !m.isDeleted) {\n        void this.armFromDeadline(m.expiresAt, m.serverSeq, m.clientMsgId);\n      }\n    }\n    if (changed) {\n      this.messageList.sort((a, b) => a.serverSeq - b.serverSeq);\n      this.emit();\n    }\n  }\n\n  /** @internal — called by the backend's live subscription. */\n  async ingestLive(incoming: IncomingMessage): Promise<void> {\n    if (!this._group) return;\n    if (incoming.kind === 'commit') {\n      await this.refreshMembers();\n      return;\n    }\n    if (incoming.serverSeq <= 0) return; // welcome/proposal — not a row\n    // Disappearing T10 (redelivery-drop, the M1-trap arrival half): a message whose\n    // server_seq is already TTL-tombstoned in the durable store is DROPPED on arrival and\n    // NEVER re-surfaced. A purge is crash-safe because the tombstone is written FIRST; if\n    // the same seq is re-delivered after a purge it must not resurface (the cold-launch\n    // projectHistory enforces the SAME exclusion on reload). Checked BEFORE the seenKeys\n    // dedup so a purged-then-redelivered seq is dropped, not silently consumed.\n    if ((await this.backend.tombstonedSeqs(this._group)).has(incoming.serverSeq)) return;\n    const key = this.internalKey(incoming.serverSeq);\n    if (this.seenKeys.has(key)) return;\n    this.seenKeys.add(key);\n    let senderUser: string | null = null;\n    if (incoming.senderDeviceId) {\n      senderUser = await this.backend.userIdForDevice(this._group, incoming.senderDeviceId);\n    }\n    const direction: MessageDirection =\n      senderUser !== null && senderUser === this.backend.selfUserId ? 'outgoing' : 'incoming';\n\n    // Disappearing T10: a `timer_set` is a control envelope, NOT a bubble. Route it into\n    // the chat-default `TimerFold` (actor = the AUTHENTICATED sender, resolved device→user;\n    // own-send → self). An unresolvable actor DROPs it (no spoofable timer). Never appends\n    // a row, never notifies, never increments unread (mirrors iOS T5).\n    if (incoming.envelopeType === 'timer_set' && incoming.timer) {\n      const actorUserId = direction === 'outgoing' ? this.backend.selfUserId : senderUser;\n      if (actorUserId !== null) {\n        this.timerFold.ingest({\n          ttlSeconds: incoming.timer.ttlSeconds,\n          start: incoming.timer.start,\n          actorUserId,\n          epoch: incoming.epoch,\n          serverSeq: incoming.serverSeq,\n          eventClientMsgId: incoming.clientMsgId,\n        });\n      }\n      return; // no bubble, no unread, no push\n    }\n\n    // A reaction is NEVER a visible bubble — it folds into the target's tally and\n    // re-emits, so it also never notifies like a message (mirrors iOS T3).\n    if (incoming.envelopeType === 'reaction' && incoming.reaction) {\n      // actorUserId = the resolved sender (own-send → selfUserId). An unresolvable\n      // sender would yield a spoofable actor — drop it (no fold).\n      const actorUserId = direction === 'outgoing' ? this.backend.selfUserId : senderUser;\n      if (actorUserId !== null) {\n        this.reactionFold.ingest({\n          targetClientMsgId: incoming.reaction.targetClientMsgId,\n          actorUserId,\n          emoji: incoming.reaction.emoji,\n          op: incoming.reaction.op,\n          epoch: incoming.epoch,\n          serverSeq: incoming.serverSeq,\n          eventClientMsgId: incoming.clientMsgId,\n        });\n        this.recomputeReactions(incoming.reaction.targetClientMsgId);\n      }\n      return;\n    }\n\n    // An edit is NEVER a visible bubble — it folds the latest author edit's text\n    // onto the target in place and re-emits, so it also never notifies like a\n    // message (mirrors iOS T3). editorUserId = the resolved sender (own-send →\n    // selfUserId); null → the fold HOLDs until the roster resolves.\n    if (incoming.envelopeType === 'edit' && incoming.edit) {\n      const editorUserId = direction === 'outgoing' ? this.backend.selfUserId : senderUser;\n      this.editFold.ingest(\n        {\n          targetClientMsgId: incoming.edit.targetClientMsgId,\n          editorUserId,\n          newText: incoming.edit.newText,\n          epoch: incoming.epoch,\n          serverSeq: incoming.serverSeq,\n          eventClientMsgId: incoming.clientMsgId,\n          // Mentions T6: carry the edit's REPLACEMENT ranges so the edited message's\n          // mentions reflect them (recomputed against the new text on recomputeEdit).\n          bodyRanges: incoming.bodyRanges,\n        },\n        this.authorOfTarget,\n      );\n      this.recomputeEdit(incoming.edit.targetClientMsgId);\n      return;\n    }\n\n    // A delete-for-everyone is NEVER a visible bubble — it folds a tombstone onto\n    // its target (author-gated) and re-emits, so it also never notifies like a\n    // message (mirrors iOS T3). actorUserId = the resolved sender (own-send →\n    // selfUserId); null → the fold parks it in held until the roster resolves. The\n    // authorOfTarget closure resolves the TARGET message's author for the gate.\n    if (incoming.envelopeType === 'delete' && incoming.delete) {\n      const actorUserId = direction === 'outgoing' ? this.backend.selfUserId : senderUser;\n      this.deleteFold.ingest(\n        {\n          targetClientMsgId: incoming.delete.targetClientMsgId,\n          actorUserId,\n          epoch: incoming.epoch,\n          serverSeq: incoming.serverSeq,\n          eventClientMsgId: incoming.clientMsgId,\n        },\n        this.authorOfTarget,\n      );\n      // A tombstone that arrived BEFORE its target lands parked in pending; the\n      // target's own insert below re-checks it. Re-emit so an in-order scrub shows.\n      this.emit();\n      return;\n    }\n\n    // clientMsgId and replyRef are decoded by the delivery source (decodeEnvelope)\n    // and carried on IncomingMessage. Legacy/system messages carry empty string / null.\n    const incomingClientMsgId = incoming.clientMsgId;\n    const incomingReplyRef = incoming.replyRef;\n\n    // Resolve reply if present.\n    let resolvedReplyTo: ResolvedReply | null = null;\n    if (incomingReplyRef) {\n      resolvedReplyTo = resolveReply(incomingReplyRef, (id) => this.byClientMsgId.get(id) ?? null);\n    }\n\n    // Mentions T6: resolve the decode-time mention spans (normalize + roster name)\n    // for this NORMAL text bubble. A mention is carried on the message's own text (no\n    // fold) — the bubble renders normally with these spans for highlighting.\n    const mentions = this.resolveMentions(incoming.text, incoming.bodyRanges);\n\n    const msg: ChatMessage = {\n      id: this.publicId(incoming.serverSeq),\n      kind: this.kindOf(incoming),\n      direction,\n      senderUserId: senderUser,\n      text: incoming.text,\n      serverSeq: incoming.serverSeq,\n      sentAt: incoming.receivedAt,\n      clientMsgId: incomingClientMsgId,\n      replyTo: resolvedReplyTo,\n      // Attach any tally already folded for this message (a reaction that arrived\n      // BEFORE its target — the dangling case — renders the moment the target lands).\n      reactions: incomingClientMsgId ? this.reactionFold.tally(incomingClientMsgId) : {},\n      // Default false; applyEditOverlay below folds any edit that arrived first.\n      edited: false,\n      // Default false; surfaced() applies the tombstone scrub if a delete folded.\n      isDeleted: false,\n      mentions,\n      // Disappearing T10: the LOCAL deadline (own per-message expiry ELSE the chat default\n      // active AS OF arrival). null when this message is non-disappearing.\n      expiresAt: this.deadlineFor(this.toExpirySpec(incoming.expiry) ?? this.defaultExpiry()),\n    };\n\n    // Self-elevation decision (best-effort cooperative, dedup-once via the persisted\n    // set). Compute on the INCOMING bubble BEFORE projection — an edit never lands here\n    // (it routed to the EditFold above), satisfying the not-edit gate.\n    this.elevateIfMentioned(msg, mentions, senderUser, incoming.envelopeType);\n\n    // Index non-empty clientMsgId for future resolveReply lookups.\n    // Index ANY incoming message (senderUser may be null for peers); use '' for\n    // the senderUserId so resolveReply still returns state:'resolved' (real text\n    // wins over attacker-controlled preview). Spoof defense covers peer messages.\n    if (incomingClientMsgId && incoming.text !== null) {\n      this.byClientMsgId.set(incomingClientMsgId, {\n        text: incoming.text,\n        senderUserId: senderUser ?? '',\n      });\n    }\n\n    // Record this bubble's BASE text + AUTHOR for the edit fold BEFORE\n    // reevaluateHeld, so a dangling edit whose target just arrived author-gates\n    // correctly. Base text is seeded once (write-once) so a folded edit overlay\n    // never overwrites the original we render `edit ?? original` against.\n    if (incomingClientMsgId) {\n      this.seedEditBase(incomingClientMsgId, incoming.text, senderUser);\n      this.editFold.reevaluateHeld(this.authorOfTarget);\n      // A pending/held tombstone for this just-arrived target re-checks its\n      // deferred author-gate here — a forged early tombstone is discarded (the\n      // message renders), a genuine one scrubs (mirrors iOS T3 reevaluatePending).\n      this.deleteFold.reevaluatePending(\n        incomingClientMsgId,\n        this.authorOfTarget(incomingClientMsgId),\n      );\n    }\n\n    this.messageList.push(this.applyEditOverlay(msg));\n    this.messageList.sort((a, b) => a.serverSeq - b.serverSeq);\n    this.loadedEarliestSeq = Math.min(\n      this.loadedEarliestSeq ?? incoming.serverSeq,\n      incoming.serverSeq,\n    );\n    this.emit();\n    // Disappearing T10: a normal bubble carrying a per-message `expiry` arms its purge on\n    // first decrypt-and-display (the durable write-once anchor + the advisory timer); a\n    // bubble with NO per-message expiry falls back to the chat default (`timerFold`).\n    // own-expiry WINS over the default. Fire-and-forget — best-effort; never blocks ingest.\n    void this.armPurge(\n      this.toExpirySpec(incoming.expiry) ?? this.defaultExpiry(),\n      incoming.serverSeq,\n      incomingClientMsgId,\n    );\n  }\n\n  // ── Disappearing (TTL — T10) ──\n\n  /** Normalize a decoded `IncomingMessage.expiry` / `StoredMessage.expiry` into the\n   * `ExpirySpec` the arm path consumes (or null when absent). */\n  private toExpirySpec(\n    e:\n      | { v: number; ttlSeconds: number; start: 'send' | 'read'; senderSendTs: number | null }\n      | null\n      | undefined,\n  ): ExpirySpec | null {\n    return e\n      ? { v: e.v, ttlSeconds: e.ttlSeconds, start: e.start, senderSendTs: e.senderSendTs }\n      : null;\n  }\n\n  /** The chat-default expiry derived from the active `timer_set` fold, as an `ExpirySpec`\n   * so a bubble with no per-message expiry inherits it. null when no default is active or\n   * the default was explicitly DISABLED (`ttlSeconds === null`). `senderSendTs` is null —\n   * the default has no per-message sender clock; the arrival anchor drives the deadline\n   * (mirrors iOS `defaultExpiry()`). */\n  private defaultExpiry(): ExpirySpec | null {\n    const active = this.timerFold.active();\n    if (!active || active.ttlSeconds === null) return null;\n    return { v: 1, ttlSeconds: active.ttlSeconds, start: active.start, senderSendTs: null };\n  }\n\n  /** The surfaced display deadline for an effective expiry (a local, monotonic-derived\n   * value — the wall-clock projection of the TTL from now). null for a non-disappearing\n   * message. The durable purge is driven by `armPurge`'s write-once anchor; this is the\n   * UI countdown baseline. */\n  private deadlineFor(expiry: ExpirySpec | null): Date | null {\n    if (!expiry) return null;\n    return new Date(Date.now() + expiry.ttlSeconds * 1000);\n  }\n\n  /** Arm a message's TTL purge on first decrypt-and-display. Captures the WRITE-ONCE\n   * monotonic/wall/boot anchor (so the deadline survives a reload — a re-arm after relaunch\n   * reads back the ORIGINAL capture, never a fresh one → the deadline never resets),\n   * computes the remaining time via `remainingSeconds`, applies the send-anchor clamp\n   * `min(sender_send_ts+ttl, first_arrival+ttl)` (read-anchor uses the write-once first-read\n   * capture), then either purges immediately or schedules an advisory `setTimeout`. A null\n   * expiry / empty clientMsgId is a no-op. Mirrors iOS `armPurge`. */\n  private async armPurge(\n    expiry: ExpirySpec | null,\n    serverSeq: number,\n    clientMsgId: string,\n  ): Promise<void> {\n    if (!expiry || !clientMsgId || !this._group) return;\n    const group = this._group;\n    // Write-once arrival/first-read anchor (durable so the deadline survives a reload).\n    const fresh: AnchorTriple = {\n      mAnchorMs: MonotonicClock.nowMs(),\n      wAnchorEpochMs: MonotonicClock.nowWallEpochMs(),\n      bAnchorToken: MonotonicClock.bootToken(),\n    };\n    await this.backend.writeAnchorOnce(group, clientMsgId, fresh);\n    // Use the PERSISTED anchor (the write-once one) for the deadline math.\n    const effective = (await this.backend.anchor(group, clientMsgId)) ?? fresh;\n    const result = remainingSeconds({\n      ttlSeconds: expiry.ttlSeconds,\n      anchor: effective,\n      nowMonotonicMs: MonotonicClock.nowMs(),\n      nowWallEpochMs: MonotonicClock.nowWallEpochMs(),\n      nowBootToken: MonotonicClock.bootToken(),\n    });\n    // Send-anchor clamp: the sender's intended deadline is sender_send_ts + ttl; a\n    // clock-skew / late arrival can only SHORTEN, never extend, the message's life.\n    let purgeInSeconds: number | null;\n    if (result.kind === 'purgeNow') {\n      purgeInSeconds = 0;\n    } else if (expiry.start === 'send' && expiry.senderSendTs !== null) {\n      const sendRemaining =\n        expiry.senderSendTs + expiry.ttlSeconds - MonotonicClock.nowWallEpochMs() / 1000;\n      purgeInSeconds = sendRemaining <= 0 ? 0 : Math.min(result.seconds, sendRemaining);\n    } else {\n      purgeInSeconds = result.seconds;\n    }\n    // Cancel any prior timer for this seq (idempotent re-arm) before scheduling.\n    const prior = this.purgeTimers.get(serverSeq);\n    if (prior) clearTimeout(prior);\n    this.purgeTimers.delete(serverSeq);\n    if (purgeInSeconds <= 0) {\n      await this.purge(serverSeq, clientMsgId);\n      return;\n    }\n    const handle = setTimeout(() => {\n      void this.purge(serverSeq, clientMsgId);\n    }, purgeInSeconds * 1000);\n    this.purgeTimers.set(serverSeq, handle);\n  }\n\n  /** Re-arm a purge from a derived deadline (cold-launch hydrate path). The deadline is\n   * the projection's monotonic-derived `expiresAt`; schedule an advisory timer for the\n   * remaining time (purge immediately if the deadline has already passed). The durable\n   * tombstone is written by `purge` when it fires (the crash-safe commit point). */\n  private async armFromDeadline(\n    deadline: Date,\n    serverSeq: number,\n    clientMsgId: string,\n  ): Promise<void> {\n    if (!this._group) return;\n    const remainingMs = deadline.getTime() - Date.now();\n    const prior = this.purgeTimers.get(serverSeq);\n    if (prior) clearTimeout(prior);\n    this.purgeTimers.delete(serverSeq);\n    if (remainingMs <= 0) {\n      await this.purge(serverSeq, clientMsgId);\n      return;\n    }\n    const handle = setTimeout(() => {\n      void this.purge(serverSeq, clientMsgId);\n    }, remainingMs);\n    this.purgeTimers.set(serverSeq, handle);\n  }\n\n  /** Purge message M (TTL eviction). TOMBSTONE-FIRST (the crash-safe commit point):\n   * persist the `server_seq` tombstone + the `client_msg_id` purge id in ONE durable\n   * record, THEN drop M's body from `messageList` + `emit()`, then re-evaluate any HELD\n   * edit / PARKED delete targeting the now-purged cid so an orphan annotation DROPs/no-ops\n   * (the resolver now returns `'purged'`). Idempotent. Mirrors iOS `purge`. */\n  private async purge(serverSeq: number, clientMsgId: string): Promise<void> {\n    if (!this._group) return;\n    const prior = this.purgeTimers.get(serverSeq);\n    if (prior) clearTimeout(prior);\n    this.purgeTimers.delete(serverSeq);\n    // Tombstone FIRST (durable commit point) — records clientMsgId in purgedClientMsgIds.\n    await this.backend.tombstone(this._group, serverSeq, clientMsgId);\n    if (clientMsgId) this.purgedCids.add(clientMsgId); // live-mirror the purge set\n    // Drop the body from the transcript, then re-emit.\n    this.messageList = this.messageList.filter((m) => m.serverSeq !== serverSeq);\n    this.seenKeys.delete(this.internalKey(serverSeq));\n    this.emit();\n    // The purge now resolves this cid to 'purged' — re-evaluate any held edit / parked\n    // delete so an orphan annotation targeting the disappeared message DROPs/no-ops.\n    this.editFold.reevaluateHeld(this.authorOfTarget);\n    if (clientMsgId) {\n      this.deleteFold.reevaluatePending(clientMsgId, this.authorOfTarget(clientMsgId));\n    }\n  }\n\n  /** The Edit/Delete fold author-gate input via {@link AuthorResolution} (disappearing\n   * T10 — the orphan-aware resolver): `'purged'` when the target's clientMsgId is in the\n   * durable purge set (a late edit DROPs / a late delete no-ops — never resurrects a\n   * disappeared message); `'author'` when its author is locally known → run the\n   * author-gate; `'unknown'` otherwise → HOLD. The live twin of `projectHistory`'s\n   * resolver. Captured as a bound arrow so it can be passed to the pure folds. */\n  private readonly authorOfTarget = (targetClientMsgId: string): AuthorResolution => {\n    if (this.purgedCids.has(targetClientMsgId)) return { kind: 'purged' };\n    const a = this.authorByClientMsgId.get(targetClientMsgId);\n    return a !== undefined ? { kind: 'author', userId: a } : { kind: 'unknown' };\n  };\n\n  // ── Mentions (mentions T6) ──\n\n  /** Resolve a message's decode-time mention spans: NORMALIZE the raw `body_ranges`\n   * against `text` (the pinned `normalizeMentionRangesUtf16` cross-SDK contract) then\n   * resolve each surviving range's `mentionedUserId` to a roster display name. An id\n   * not in the roster resolves to `null` (the renderer falls back to the `text` slice).\n   * Pure over (text, bodyRanges, memberCache); never throws. Mirrors iOS T3. */\n  private resolveMentions(\n    text: string | null,\n    bodyRanges: MentionRange[] | null | undefined,\n  ): ResolvedMention[] {\n    if (text === null || !bodyRanges || bodyRanges.length === 0) return [];\n    const normalized = normalizeMentionRangesUtf16(bodyRanges, text);\n    if (normalized.length === 0) return [];\n    return normalized.map((r) => ({\n      start: r.start,\n      length: r.length,\n      mentionedUserId: r.mentionedUserId,\n      displayName: this.displayNameOf(r.mentionedUserId),\n    }));\n  }\n\n  /** Re-resolve the roster display name on already-NORMALIZED spans (the history\n   * projection produces them with null names — resolution is LIVE, not snapshotted).\n   * A member rename then reflects on old messages. Returns the message unchanged when\n   * it has no mentions (the common case) or no name changed. Mirrors iOS T3. */\n  private resolveMentionNames(m: ChatMessage): ChatMessage {\n    // Tolerate a row that predates the mentions field (an older persisted projection /\n    // a hand-built history row) — treat absent as `[]`, never throw.\n    if (!m.mentions || m.mentions.length === 0) {\n      return m.mentions ? m : { ...m, mentions: [] };\n    }\n    let changed = false;\n    const reresolved = m.mentions.map((span) => {\n      const name = this.displayNameOf(span.mentionedUserId);\n      if (name === span.displayName) return span;\n      changed = true;\n      return { ...span, displayName: name };\n    });\n    if (!changed) return m;\n    return { ...m, mentions: reresolved };\n  }\n\n  /** The WINNING edit's resolved mentions for a target (normalize its replacement\n   * ranges against the new text + roster names), or `[]` if no winning edit / no\n   * ranges. The edited message's mentions reflect the EDIT's ranges (mirrors iOS T3). */\n  private editMentions(targetClientMsgId: string, newText: string | null): ResolvedMention[] {\n    const ranges = this.editFold.bodyRanges(targetClientMsgId);\n    if (!ranges) return [];\n    return this.resolveMentions(newText, ranges);\n  }\n\n  /** Resolve a userId → its roster display name (null if not a known member). */\n  private displayNameOf(userId: string): string | null {\n    return this.memberCache.find((mm) => mm.userId === userId)?.displayName ?? null;\n  }\n\n  /** Compute the SELF-ELEVATION decision for a freshly-ingested INCOMING bubble and,\n   * when it fires, record the dedup key (persisted) + invoke `onMentionElevation`.\n   * Gate (mirrors iOS T3): a surviving mention targets THIS user AND the sender is not\n   * me AND it's NOT an edit AND the `(selfUserId, clientMsgId|seq)` key isn't already\n   * elevated. Dedup-once: the in-memory set gates the session, the persisted set\n   * survives reload. An EDIT never reaches here (it folds, not a bubble) — the\n   * `envelopeType !== 'edit'` guard is belt-and-braces. */\n  private elevateIfMentioned(\n    message: ChatMessage,\n    mentions: ResolvedMention[],\n    senderUserId: string | null,\n    envelopeType: string | undefined,\n  ): void {\n    const me = this.backend.selfUserId;\n    if (envelopeType === 'edit') return; // edits never elevate\n    if (senderUserId === me) return; // self-mention never buzzes me\n    if (!mentions.some((mm) => mm.mentionedUserId === me)) return; // not mentioned\n    const idPart = message.clientMsgId ? message.clientMsgId : `seq:${message.serverSeq}`;\n    const key = `${me}|${idPart}`;\n    if (this.elevated.has(key)) return; // already elevated → no re-buzz\n    this.elevated.add(key);\n    // Persist the dedup set (fire-and-forget — the in-memory record already gates this\n    // session; the write makes it survive a cold launch).\n    if (this._group) {\n      void this.backend.saveElevated(this._group, [...this.elevated]).catch(() => {});\n    }\n    this.onMentionElevation?.(message);\n  }\n\n  /** Seed the per-target base text + author for the edit fold. Base is write-once\n   * (a later own/peer edit must not overwrite the original we render against). The\n   * author is (re)recorded whenever a non-empty resolution is available. */\n  private seedEditBase(clientMsgId: string, text: string | null, author: string | null): void {\n    if (!this.originalTextByClientMsgId.has(clientMsgId)) {\n      this.originalTextByClientMsgId.set(clientMsgId, text);\n    }\n    if (author !== null) this.authorByClientMsgId.set(clientMsgId, author);\n  }\n\n  /**\n   * Rebuild the target message's `reactions` from the authoritative fold and\n   * re-emit. No-op when the target isn't present yet (its tally is attached the\n   * moment it lands, via the append/merge paths) or when the tally is unchanged.\n   */\n  private recomputeReactions(targetClientMsgId: string): void {\n    if (!targetClientMsgId) return;\n    const tally = this.reactionFold.tally(targetClientMsgId);\n    let changed = false;\n    this.messageList = this.messageList.map((m) => {\n      if (m.clientMsgId !== targetClientMsgId) return m;\n      if (sameReactions(m.reactions, tally)) return m;\n      changed = true;\n      return { ...m, reactions: tally };\n    });\n    if (changed) this.emit();\n  }\n\n  /**\n   * Overlay the authoritative fold's tally onto a message as it is appended/merged.\n   * The Chat fold WINS when it has a non-empty tally; otherwise the tally already\n   * attached upstream (the coordinator's page-local history fold) is preserved.\n   */\n  private applyReactionTally(m: ChatMessage): ChatMessage {\n    if (!m.clientMsgId) return m;\n    const tally = this.reactionFold.tally(m.clientMsgId);\n    if (Object.keys(tally).length === 0) return m; // fold has nothing — keep upstream tally\n    if (sameReactions(m.reactions, tally)) return m;\n    return { ...m, reactions: tally };\n  }\n\n  /**\n   * Rebuild the target message's rendered `text` + `edited` flag from the\n   * authoritative edit fold and re-emit, PRESERVING `.reactions` and `.replyTo`\n   * (the reaction-polish lesson — never clobber). text = `editFold.text(cid) ??\n   * base`; base is the seeded original so a forged/ignored edit leaves it intact.\n   * No-op when the target isn't present yet (the fold already recorded it; the\n   * overlay applies the moment the target lands) or when unchanged.\n   */\n  private recomputeEdit(targetClientMsgId: string): void {\n    if (!targetClientMsgId) return;\n    const editText = this.editFold.text(targetClientMsgId);\n    const foldEdited = this.editFold.isEdited(targetClientMsgId);\n    let changed = false;\n    this.messageList = this.messageList.map((m) => {\n      if (m.clientMsgId !== targetClientMsgId) return m;\n      const base = this.originalTextByClientMsgId.has(targetClientMsgId)\n        ? (this.originalTextByClientMsgId.get(targetClientMsgId) ?? null)\n        : m.text;\n      const text = editText ?? base;\n      // Write-once edited: the Chat fold OR an already-set flag (e.g. the\n      // coordinator's page-local history projection). Never downgrade true → false.\n      const edited = foldEdited || m.edited;\n      // Mentions T6: when an edit WINS, the edited message's mentions reflect the\n      // EDIT's replacement ranges (recomputed against the new text); otherwise keep\n      // the message's existing mentions.\n      const mentions = editText !== null ? this.editMentions(targetClientMsgId, text) : m.mentions;\n      if (m.text === text && m.edited === edited && sameMentions(m.mentions, mentions)) return m;\n      changed = true;\n      return { ...m, text, edited, mentions }; // PRESERVES reactions + replyTo (spread keeps them)\n    });\n    if (changed) this.emit();\n  }\n\n  /**\n   * Overlay the authoritative edit fold's winning text + flag onto a message as it\n   * is appended/merged. The fold WINS when it has an edit for this target;\n   * otherwise the upstream `text`/`edited` (e.g. the coordinator's page-local\n   * history fold) is preserved. PRESERVES reactions + replyTo.\n   */\n  private applyEditOverlay(m: ChatMessage): ChatMessage {\n    if (!m.clientMsgId) return m;\n    const editText = this.editFold.text(m.clientMsgId);\n    const foldEdited = this.editFold.isEdited(m.clientMsgId);\n    if (editText === null && !foldEdited) return m; // fold has nothing — keep upstream\n    const text = editText ?? m.text;\n    // Write-once: never downgrade an already-edited flag (the upstream projection).\n    const edited = foldEdited || m.edited;\n    // Mentions T6: when the LIVE fold has a winning edit for this target, the edited\n    // message's mentions come from that edit's replacement ranges; otherwise keep the\n    // mentions the message ALREADY carries (e.g. the coordinator's page-local overlay).\n    const mentions = editText !== null ? this.editMentions(m.clientMsgId, text) : m.mentions;\n    if (m.text === text && m.edited === edited && sameMentions(m.mentions, mentions)) return m;\n    return { ...m, text, edited, mentions };\n  }\n\n  /** @internal — called by the backend's conv subscription. */\n  applyConv(event: string, payload: Record<string, unknown>): void {\n    const userId = typeof payload.user_id === 'string' ? payload.user_id : null;\n    if (!userId || userId === this.backend.selfUserId) return;\n    if (event === 'typing') {\n      const isTyping = payload.typing === true;\n      const member = this.memberCache.find((m) => m.userId === userId) ?? {\n        id: userId,\n        userId,\n        displayName: null,\n        role: 'member' as const,\n        isSelf: false,\n      };\n      this.typingList = isTyping\n        ? [...this.typingList.filter((m) => m.userId !== userId), member]\n        : this.typingList.filter((m) => m.userId !== userId);\n      this.emit();\n    } else if (event === 'presence') {\n      const online = payload.online === true;\n      const ts = typeof payload.ts === 'number' ? payload.ts : null;\n      this.presenceStates.set(userId, {\n        userId,\n        isOnline: online,\n        lastSeenAt: ts ? new Date(ts * 1000) : null,\n      });\n      this.emit();\n    } else if (event === 'delivered' || event === 'read') {\n      // Server-metadata cluster — the double-tick fold (parity with iOS T11). A peer's\n      // `delivered`/`read` broadcast carries the acking device_id + an `up_to_server_seq`\n      // high-watermark. We fold it onto THIS user's OWN (outgoing) messages whose\n      // serverSeq is at or below the acked seq, USER-LEVEL (any peer/device counts) and\n      // MONOTONIC (`max` — a stale lower incoming tick NEVER lowers the displayed tick;\n      // the same guard the iOS `foldDeliveredTick` applies). `read` STAYS gated by the\n      // peer's share_receipts server-side (the broadcast simply never arrives when muted);\n      // the client fold is identical (delivered mirrors read).\n      const seq = typeof payload.up_to_server_seq === 'number' ? payload.up_to_server_seq : null;\n      if (seq === null) return;\n      let changed = false;\n      this.messageList = this.messageList.map((m) => {\n        if (m.direction !== 'outgoing' || m.serverSeq > seq) return m;\n        const cur = event === 'delivered' ? (m.deliveredUpTo ?? -1) : (m.readUpTo ?? -1);\n        if (seq <= cur) return m; // monotonic: a stale/equal tick never lowers it\n        changed = true;\n        return event === 'delivered' ? { ...m, deliveredUpTo: seq } : { ...m, readUpTo: seq };\n      });\n      if (changed) this.emit();\n    }\n  }\n\n  private kindOf(incoming: IncomingMessage): ChatMessageKind {\n    if (incoming.kind === 'commit' || incoming.kind === 'proposal' || incoming.kind === 'welcome')\n      return 'system';\n    return 'text';\n  }\n\n  private internalKey(serverSeq: number): string {\n    return this._group ? `${this._group.rfcGroupId}#${serverSeq}` : `draft#${serverSeq}`;\n  }\n  private publicId(serverSeq: number): string {\n    return `${this.id}#${serverSeq}`;\n  }\n\n  /** Page older messages in. Returns how many were prepended. */\n  async loadEarlier(limit = 50): Promise<number> {\n    if (!this._group) return 0;\n    const before = this.loadedEarliestSeq ?? undefined;\n    const older = await this.backend.history(this._group, limit, before);\n    const before0 = this.messageList.length;\n    this.mergeHistory(older);\n    return this.messageList.length - before0;\n  }\n\n  // ── Members ──\n\n  private async refreshMembers(): Promise<void> {\n    if (!this._group) return;\n    const m = await this.backend.members(this._group);\n    if (m.length > 0) {\n      this.memberCache = m;\n      this.emit();\n    }\n    // On a roster change a previously-unresolvable editor may now resolve — re-run\n    // held edits + recompute any target whose edit just landed (mirrors iOS T3's\n    // refreshMembers hook).\n    this.editFold.reevaluateHeld(this.authorOfTarget);\n    for (const cid of this.originalTextByClientMsgId.keys()) this.recomputeEdit(cid);\n    // Mentions T6: a member's display name may now be known — re-resolve mention names\n    // on every message (resolution is LIVE, never snapshotted; a rename reflects here).\n    this.reresolveAllMentionNames();\n  }\n\n  /** Re-resolve roster display names across the whole transcript (called on a roster\n   * change). Re-emits only if any name actually changed. */\n  private reresolveAllMentionNames(): void {\n    let changed = false;\n    this.messageList = this.messageList.map((m) => {\n      const reresolved = this.resolveMentionNames(m);\n      if (reresolved !== m) changed = true;\n      return reresolved;\n    });\n    if (changed) this.emit();\n  }\n\n  private seedMembersFromGroup(group: MessagingGroup): void {\n    const seed: ChatMember[] = [\n      {\n        id: this.backend.selfUserId,\n        userId: this.backend.selfUserId,\n        displayName: null,\n        role: 'owner',\n        isSelf: true,\n      },\n    ];\n    if (group.ownerUserId && group.ownerUserId !== this.backend.selfUserId) {\n      seed.push({\n        id: group.ownerUserId,\n        userId: group.ownerUserId,\n        displayName: null,\n        role: 'owner',\n        isSelf: false,\n      });\n    }\n    this.memberCache = seed;\n  }\n\n  private seedDraftMembers(draft: ChatDraft): void {\n    const seed: ChatMember[] = [\n      {\n        id: this.backend.selfUserId,\n        userId: this.backend.selfUserId,\n        displayName: null,\n        role: draft.mode.kind === 'group' ? 'owner' : 'member',\n        isSelf: true,\n      },\n    ];\n    if (draft.mode.kind === 'direct') {\n      seed.push({\n        id: draft.mode.peerUserId,\n        userId: draft.mode.peerUserId,\n        displayName: null,\n        role: 'member',\n        isSelf: false,\n      });\n    } else {\n      for (const uid of draft.mode.members) {\n        seed.push({ id: uid, userId: uid, displayName: null, role: 'member', isSelf: false });\n      }\n    }\n    this.memberCache = seed;\n  }\n\n  // ── Send (with WhatsApp lazy materialize) ──\n\n  async send(\n    text: string,\n    opts?: {\n      replyTo?: ChatMessage;\n      mentions?: MentionRange[];\n      expiresIn?: { ttlSeconds: number; start?: 'send' | 'read' };\n    },\n  ): Promise<SentReceipt> {\n    const group = await this.materializeIfNeeded();\n\n    // Build ReplyRef from the parent ChatMessage if provided (and replyable).\n    let replyRef: ReplyRef | null = null;\n    let resolvedReplyTo: ResolvedReply | null = null;\n    const parent = opts?.replyTo;\n    if (parent?.clientMsgId && parent.kind !== 'system') {\n      const [previewBody, wasTruncated] = parent.text ? truncateQuote(parent.text) : ['', false];\n      replyRef = {\n        v: 1,\n        client_msg_id: parent.clientMsgId,\n        preview: {\n          kind: 'text',\n          author_user_id: parent.senderUserId ?? '',\n          body: previewBody || undefined,\n          body_truncated: wasTruncated,\n        },\n      };\n      // Resolve the reply against local history immediately (the parent IS local).\n      resolvedReplyTo = resolveReply(replyRef, (id) => this.byClientMsgId.get(id) ?? null);\n    }\n\n    // Mentions T6: carry the caller's mention ranges onto the wire envelope (encoded\n    // as `body_ranges`). The own-sent bubble resolves them locally for its own render.\n    const bodyRanges = opts?.mentions ?? null;\n    // Disappearing T10: a per-message TTL rides INSIDE the ciphertext as an `expiry` spec\n    // — the server stays MLS-blind (no expires_at, no new route). `start === 'send'`\n    // (default) anchors the deadline to the sender's compose-time (stamps sender_send_ts,\n    // clamped on receipt by the local first-arrival); `read` anchors it to first-read.\n    //\n    // COMPOSE-TIME STAMPING (spec §\"Per-message vs per-chat\"): a message's effective TTL\n    // is its OWN explicit `expiresIn` IF present, ELSE the chat's active default timer\n    // STAMPED ONTO IT NOW. The per-message `expiry` field is the durable record — so a\n    // plain send under an active default carries the (frozen) default on the wire, making\n    // sender and receiver symmetric (both arm from the SAME stamped expiry, forward-only).\n    const effectiveExpiry = this.composeExpiry(opts?.expiresIn);\n    const { receipt, clientMsgId } = await this.backend.sendText(\n      group,\n      text,\n      replyRef,\n      bodyRanges,\n      effectiveExpiry,\n    );\n    this.appendOwnSend(text, receipt, clientMsgId, resolvedReplyTo, bodyRanges, effectiveExpiry);\n    // The own-send arms its OWN purge on the same rule (the stamped expiry is the basis).\n    // FIRE-AND-FORGET ADVISORY: we return on the LOCAL emit — there is NO peer-enforcement.\n    if (effectiveExpiry) void this.armPurge(effectiveExpiry, receipt.serverSeq, clientMsgId);\n    return receipt; // fire-and-forget advisory: local emit only, no peer-enforcement signal\n  }\n\n  /** Resolve a send's effective per-message expiry at COMPOSE TIME: the caller's explicit\n   * `expiresIn` if present, ELSE the chat's active default timer stamped onto the message\n   * NOW (the durable record per spec §\"Compose-time stamping\"). A `send`-anchored expiry\n   * (explicit or default-inherited) stamps `senderSendTs` = the sender's compose epoch\n   * seconds; a `read`-anchored one carries none (the deadline is the recipient's local\n   * first-read). Returns null when there is neither an explicit expiry nor an active\n   * default (a plain, non-disappearing send). Mirrors the iOS compose-time stamping. */\n  private composeExpiry(explicit?: {\n    ttlSeconds: number;\n    start?: 'send' | 'read';\n  }): ExpirySpec | null {\n    const base: ExpirySpec | null = explicit\n      ? {\n          v: 1,\n          ttlSeconds: explicit.ttlSeconds,\n          start: explicit.start ?? 'send',\n          senderSendTs: null,\n        }\n      : this.defaultExpiry();\n    if (!base) return null;\n    return {\n      ...base,\n      senderSendTs: base.start === 'send' ? Math.floor(Date.now() / 1000) : null,\n    };\n  }\n\n  /** Set (or DISABLE) this chat's DEFAULT disappearing timer. Emits a `timer_set` control\n   * envelope (server-blind — an opaque application message, NEVER a bubble) and folds the\n   * own-set locally so the default applies immediately to subsequent sends that carry no\n   * per-message expiry. `ttlSeconds === null` DISABLES the default. FIRE-AND-FORGET\n   * ADVISORY: returns on the LOCAL emit only; it exposes NO \"active for all peers\" signal.\n   * Mirrors iOS `setDisappearing(ttlSeconds:start:)`. */\n  async setDisappearing(opts: {\n    ttlSeconds: number | null;\n    start?: 'send' | 'read';\n  }): Promise<void> {\n    const group = await this.materializeIfNeeded();\n    const clientMsgId = mintClientMsgId();\n    const start = opts.start ?? 'send';\n    const { receipt } = await this.backend.sendTimerSet(group, {\n      clientMsgId,\n      ttlSeconds: opts.ttlSeconds,\n      start,\n    });\n    // Fold the own-set locally (actor = self) at the server-assigned order so the default\n    // applies immediately. The fold dedups on the event clientMsgId, so the durable echo on\n    // the next pump is a no-op. A timer_set is NOT a bubble.\n    this.timerFold.ingest({\n      ttlSeconds: opts.ttlSeconds,\n      start,\n      actorUserId: this.backend.selfUserId,\n      epoch: receipt.epoch,\n      serverSeq: receipt.serverSeq,\n      eventClientMsgId: clientMsgId,\n    });\n    // fire-and-forget advisory: returns on local emit; no \"active for all peers\" signal.\n  }\n\n  private appendOwnSend(\n    text: string,\n    receipt: SentReceipt,\n    clientMsgId: string,\n    resolvedReplyTo: ResolvedReply | null,\n    bodyRanges?: MentionRange[] | null,\n    expiry?: ExpirySpec | null,\n  ): void {\n    if (receipt.serverSeq <= 0) return;\n    const key = this.internalKey(receipt.serverSeq);\n    if (this.seenKeys.has(key)) return;\n    this.seenKeys.add(key);\n\n    // Index own-sent clientMsgId for future resolveReply lookups (self-reply support).\n    if (clientMsgId) {\n      this.byClientMsgId.set(clientMsgId, { text, senderUserId: this.backend.selfUserId });\n      // Seed the edit base + author (self) so a later own edit author-gates and the\n      // overlay renders `edit ?? original`.\n      this.seedEditBase(clientMsgId, text, this.backend.selfUserId);\n    }\n\n    this.messageList.push({\n      id: this.publicId(receipt.serverSeq),\n      kind: 'text',\n      direction: 'outgoing',\n      senderUserId: this.backend.selfUserId,\n      text,\n      serverSeq: receipt.serverSeq,\n      sentAt: new Date(),\n      clientMsgId,\n      replyTo: resolvedReplyTo,\n      // Attach any tally already folded for this own-sent message (rare, but keeps\n      // the dangling-target invariant uniform across every append path).\n      reactions: clientMsgId ? this.reactionFold.tally(clientMsgId) : {},\n      // Own-sent edits fold via edit() after the fact; new sends start unedited.\n      edited: false,\n      // Own-sent deletes fold via deleteForEveryone() after the fact; start live.\n      isDeleted: false,\n      // Mentions T6: resolve the own-sent bubble's mentions for its own render (the\n      // sender never gets a wire echo of its own message — this is the only local copy).\n      mentions: this.resolveMentions(text, bodyRanges),\n      // Disappearing T10: the surfaced deadline reflects the message's effective expiry\n      // (explicit `expiresIn` OR the chat default stamped at compose time). null only when\n      // this send is non-disappearing. armPurge re-derives the durable monotonic deadline;\n      // this is the immediate UI countdown baseline (own sender and receiver are symmetric).\n      expiresAt: this.deadlineFor(expiry ?? null),\n    });\n    this.messageList.sort((a, b) => a.serverSeq - b.serverSeq);\n    this.emit();\n  }\n\n  private async materializeIfNeeded(): Promise<MessagingGroup> {\n    if (this._group) return this._group;\n    if (!this._draft) throw new Error('messaging_not_configured');\n    const group = await this.backend.materialize(this._draft);\n    this._group = group;\n    this.id = group.displayId;\n    this._state = 'active';\n    this._draft = null;\n    this.backend.registerActive(group);\n    this.ensureWired();\n    this.emit();\n    return group;\n  }\n\n  // ── Membership (groups only) ──\n\n  async addMemberUser(userId: string): Promise<void> {\n    if (this.kind !== 'group') throw new Error('chat_is_direct');\n    const group = await this.materializeIfNeeded();\n    await this.backend.addMember(group, userId);\n    await this.refreshMembers();\n  }\n\n  async removeMemberUser(userId: string): Promise<void> {\n    if (this.kind !== 'group') throw new Error('chat_is_direct');\n    if (!this._group) throw new Error('messaging_not_configured');\n    await this.backend.removeMember(this._group, userId);\n    await this.refreshMembers();\n  }\n\n  async leave(): Promise<void> {\n    if (!this._group) return;\n    await this.backend.leave(this._group);\n    this.liveUnsub?.();\n    this.liveUnsub = null;\n  }\n\n  // ── Imperative ──\n\n  setTyping(isTyping: boolean): void {\n    if (this._group) this.backend.setTyping(this._group, isTyping);\n  }\n\n  async markRead(message: ChatMessage): Promise<void> {\n    if (!this._group) return;\n    await this.backend.markRead(this._group, message.serverSeq);\n    this.readWatermark = Math.max(this.readWatermark, message.serverSeq);\n    this.emit();\n  }\n\n  // ── Server-metadata cluster: notify scope (mute) + server unread ──\n\n  /** Set this chat's notify scope (the mute toggle). `'none'` mutes the push wake;\n   * `'all'` unmutes (the default). Materializes a draft first (the scope is a\n   * per-(user,group) server row), PUTs `/notify`, and returns the server-echoed scope.\n   * Mirrors iOS `Chat.setNotifyScope`. */\n  async setNotifyScope(scope: NotifyScope): Promise<NotifyScope> {\n    const group = await this.materializeIfNeeded();\n    return this.backend.setNotifyScope(group, scope);\n  }\n\n  /** Refresh + return this chat's notify scope from the server (fail-OPEN to `'all'`).\n   * Returns `'all'` for a draft chat (no server row yet). */\n  async getNotifyScope(): Promise<NotifyScope> {\n    if (!this._group) return 'all';\n    return this.backend.getNotifyScope(this._group);\n  }\n\n  /** Fetch the caller's authoritative SERVER unread count (opaque server metadata).\n   * Returns the clamped count (`max(0, …)`); `0` for a draft chat. The local computed\n   * `unreadCount` getter stays the instant, offline best-effort badge — this is the\n   * canonical count on demand. Named distinctly so it does not shadow the observable\n   * `unreadCount` snapshot getter. Mirrors iOS `Chat.refreshUnread`. */\n  async unreadCountFromServer(): Promise<number> {\n    if (!this._group) return 0;\n    const v = await this.backend.unread(this._group);\n    return Math.max(0, v.unreadCount);\n  }\n\n  // ── Reactions ──\n\n  /** Add an emoji reaction to a message. No-op if the message isn't reactable\n   * (empty clientMsgId — a legacy/system row). The reaction folds locally with\n   * the server receipt's `(epoch, serverSeq)` so the target's tally updates\n   * instantly; the durable echo on the next pump is a fold no-op (dedup on the\n   * SAME wire clientMsgId). Never appends a bubble. */\n  async react(message: ChatMessage, emoji: string): Promise<void> {\n    await this.sendReaction(message, emoji, 'add');\n  }\n\n  /** Remove this user's emoji reaction from a message (op:'remove'). */\n  async unreact(message: ChatMessage, emoji: string): Promise<void> {\n    await this.sendReaction(message, emoji, 'remove');\n  }\n\n  private async sendReaction(\n    message: ChatMessage,\n    emoji: string,\n    op: 'add' | 'remove',\n  ): Promise<void> {\n    if (!message.clientMsgId) return; // not reactable\n    const group = await this.materializeIfNeeded();\n    const clientMsgId = mintClientMsgId();\n    const { receipt } = await this.backend.sendReaction(group, {\n      clientMsgId,\n      targetClientMsgId: message.clientMsgId,\n      emoji,\n      op,\n    });\n    // Fold the own-send locally (actor = self) using the SAME wire clientMsgId so\n    // the durable echo dedups (no double-fold), ordered by the receipt's (epoch,\n    // serverSeq) for LWW. Then recompute the target's tally + emit.\n    this.reactionFold.ingest({\n      targetClientMsgId: message.clientMsgId,\n      actorUserId: this.backend.selfUserId,\n      emoji,\n      op,\n      epoch: receipt.epoch,\n      serverSeq: receipt.serverSeq,\n      eventClientMsgId: clientMsgId,\n    });\n    this.recomputeReactions(message.clientMsgId);\n  }\n\n  // ── Edit ──\n\n  /** Edit an own text message (edit-by-supersession). No-op if the message isn't\n   * editable (empty clientMsgId, or not a `text` kind). The edit folds locally\n   * with the server receipt's `(epoch, serverSeq)` so the target's text updates\n   * instantly; the durable echo on the next pump is a fold no-op (dedup on the\n   * SAME wire clientMsgId). Never appends a bubble; PRESERVES the target's\n   * reactions + reply context. Only the original author's edits count — for an own\n   * message self IS the author, so the author-gate passes. `opts.mentions` carries the\n   * edit's REPLACEMENT mention ranges → the edited message's mentions reflect them. */\n  async edit(\n    message: ChatMessage,\n    newText: string,\n    opts?: { mentions?: MentionRange[] },\n  ): Promise<void> {\n    if (!message.clientMsgId || message.kind !== 'text') return; // not editable\n    const group = await this.materializeIfNeeded();\n    const clientMsgId = mintClientMsgId();\n    const bodyRanges = opts?.mentions ?? null;\n    const { receipt } = await this.backend.sendEdit(group, {\n      clientMsgId,\n      targetClientMsgId: message.clientMsgId,\n      newText,\n      bodyRanges,\n    });\n    // Seed the base text + author (self) if not already recorded — a 2nd own edit\n    // must not corrupt the base (the seed is write-once). self IS the author of an\n    // own message, so authorOfTarget gates the own edit.\n    this.seedEditBase(message.clientMsgId, message.text, this.backend.selfUserId);\n    // Fold the own-send locally (editor = self) using the SAME wire clientMsgId so\n    // the durable echo dedups (no double-fold), ordered by the receipt's (epoch,\n    // serverSeq) for LWW. Carry the edit's replacement ranges so the edited message's\n    // mentions reflect them. Then recompute the target's text + edited in place.\n    this.editFold.ingest(\n      {\n        targetClientMsgId: message.clientMsgId,\n        editorUserId: this.backend.selfUserId,\n        newText,\n        epoch: receipt.epoch,\n        serverSeq: receipt.serverSeq,\n        eventClientMsgId: clientMsgId,\n        bodyRanges,\n      },\n      this.authorOfTarget,\n    );\n    this.recomputeEdit(message.clientMsgId);\n  }\n\n  // ── Delete ──\n\n  /** Delete a message for EVERYONE (a cooperative encrypted tombstone). Only the\n   * ORIGINAL SENDER can do this — for an own message self IS the author, so the\n   * author-gate passes. Legacy messages (empty clientMsgId) are DISABLED (a\n   * tombstone keys on the target's clientMsgId, which they lack) — no-op. Sends a\n   * `type:'delete'` envelope through the SAME MLS path as a text message (the\n   * server stays blind), folds the own delete locally so the target scrubs in\n   * place instantly (the durable echo dedups on the SAME wire clientMsgId), and\n   * re-emits. NEVER appends a bubble. delete-for-me'ing the target becomes moot. */\n  async deleteForEveryone(message: ChatMessage): Promise<void> {\n    if (!message.clientMsgId) return; // legacy → for-everyone disabled\n    const group = await this.materializeIfNeeded();\n    const clientMsgId = mintClientMsgId();\n    const { receipt } = await this.backend.sendDelete(group, {\n      clientMsgId,\n      targetClientMsgId: message.clientMsgId,\n    });\n    // Seed the author (self) so the own delete author-gates: self IS the author of\n    // an own message. The base text seed is write-once + harmless here.\n    this.seedEditBase(message.clientMsgId, message.text, this.backend.selfUserId);\n    // Fold the own delete locally (actor = self = author). Absorbing — the durable\n    // echo on the next pump dedups on the SAME wire clientMsgId.\n    this.deleteFold.ingest(\n      {\n        targetClientMsgId: message.clientMsgId,\n        actorUserId: this.backend.selfUserId,\n        epoch: receipt.epoch,\n        serverSeq: receipt.serverSeq,\n        eventClientMsgId: clientMsgId,\n      },\n      this.authorOfTarget,\n    );\n    this.emit(); // surfaced() re-reads the fold → the target renders \"deleted\"\n  }\n\n  /** Delete a message for ME only — a LOCAL, per-device suppression. NO wire, NO\n   * attribution, no server contact: the message is OMITTED from THIS view and the\n   * suppression key persists per chat (survives reload). The key is the message's\n   * clientMsgId when present, else `seq:<serverSeq>` for legacy messages. */\n  async deleteForMe(message: ChatMessage): Promise<void> {\n    const key = message.clientMsgId ? message.clientMsgId : `seq:${message.serverSeq}`;\n    if (this.suppressed.has(key)) return; // idempotent\n    this.suppressed.add(key);\n    this.emit(); // surfaced() omits it immediately (no wire — nothing sent)\n    // Persist the full set per chat (fire-and-forget; the omit already applied).\n    if (this._group) {\n      try {\n        await this.backend.saveSuppressed(this._group, [...this.suppressed]);\n      } catch {\n        // best-effort — the in-memory omit holds this session even if persist fails\n      }\n    }\n  }\n}\n\n/** Order-sensitive equality of two resolved-mention lists (normalize is deterministic,\n * so equal spans imply equal order). Cheap shortcut so the overlay paths can no-op. */\nfunction sameMentions(a: ResolvedMention[], b: ResolvedMention[]): boolean {\n  if (a.length !== b.length) return false;\n  for (let i = 0; i < a.length; i++) {\n    const x = a[i];\n    const y = b[i];\n    if (!x || !y) return false;\n    if (\n      x.start !== y.start ||\n      x.length !== y.length ||\n      x.mentionedUserId !== y.mentionedUserId ||\n      x.displayName !== y.displayName\n    ) {\n      return false;\n    }\n  }\n  return true;\n}\n\n/** Shallow-equal two reaction tallies (emoji → sorted userIds[]). */\nfunction sameReactions(a: Record<string, string[]>, b: Record<string, string[]>): boolean {\n  const ak = Object.keys(a);\n  const bk = Object.keys(b);\n  if (ak.length !== bk.length) return false;\n  for (const k of ak) {\n    const av = a[k];\n    const bv = b[k];\n    if (!bv || av === undefined || av.length !== bv.length) return false;\n    for (let i = 0; i < av.length; i++) if (av[i] !== bv[i]) return false;\n  }\n  return true;\n}\n","// The live delivery source — the web mirror of iOS MessageDeliverySource.\n// Subscribes the device wake topic `messaging:device:<id>` over pb.realtime\n// (new_message wake → pumpOnce), and on each pump drains:\n//\n//   1. welcomes  → engine.joinFromWelcome → register the group + emit `welcome`\n//   2. device queue → for each row:\n//        - COMMIT: processIncoming (applies), bump epoch, emit `commit`\n//        - APPLICATION: decrypt → persist plaintext → emit `message`\n//   3. ack everything consumed.\n//\n// The realtime wake is notification-only; the authoritative messages come from\n// the authenticated queue pull (never the broadcast payload), exactly as iOS.\n//\n// SERVER WIRE GAP (same as iOS): queue rows do NOT yet carry rfc_group_id or the\n// fanned declaration. When absent, route a blob to the SOLE known group (the\n// common 1:1/small-group case). The reconciliation-gate hook (describeIncoming)\n// is ready for the day the server fans the declaration — a pure server change.\n\nimport { palbeRequest } from '../request.js';\nimport type { PalbeRuntime } from '../runtime.js';\nimport {\n  type DeletePayload,\n  decodeEnvelope,\n  type EditPayload,\n  type ExpirySpec,\n  GroupMessaging,\n  type MentionRange,\n  type MessagingGroup,\n  type ReactionPayload,\n  type ReplyRef,\n} from './group-messaging.js';\nimport type { MessageStore, StoredMessage } from './history.js';\nimport type { MlsEngine } from './mls-engine.js';\nimport type { GroupRegistry } from './registry.js';\nimport type { NotifyScope, UnreadView } from './types.js';\nimport { decodeUtf8, fromBase64, toBase64 } from './util.js';\nimport {\n  ContentType,\n  MessagingPaths,\n  type QueuedMessage,\n  type QueuePage,\n  type WelcomePage,\n} from './wire.js';\n\n/** A decoded incoming message handed to chat listeners. */\nexport interface IncomingMessage {\n  kind: 'application' | 'commit' | 'proposal' | 'welcome';\n  group: MessagingGroup;\n  text: string | null;\n  senderDeviceId: string | null;\n  epoch: number;\n  serverSeq: number;\n  receivedAt: Date;\n  /** The client-minted idempotency id from the decoded envelope (empty string for legacy/system). */\n  clientMsgId: string;\n  /** The decoded reply reference, if present in the envelope. */\n  replyRef: ReplyRef | null;\n  /**\n   * The decoded envelope discriminator (`'text'`/`'reaction'`/`'media'`/…).\n   * Defaults to `'text'` at every existing call site — only the reaction branch\n   * sets `'reaction'`, so the Chat can route a reaction into its fold instead of\n   * appending a visible bubble. Optional for forward-compat with old emitters.\n   */\n  envelopeType?: string;\n  /** The decoded reaction payload, present only when `envelopeType === 'reaction'`. */\n  reaction?: ReactionPayload | null;\n  /** The decoded edit payload, present only when `envelopeType === 'edit'`. Lets\n   * the Chat route an edit into its EditFold instead of appending a visible bubble. */\n  edit?: EditPayload | null;\n  /** The decoded delete payload, present only when `envelopeType === 'delete'`. Lets\n   * the Chat route a delete-for-everyone tombstone into its DeleteFold instead of\n   * appending a visible bubble. */\n  delete?: DeletePayload | null;\n  /** The decoded mention ranges (raw, un-normalized). Present on a `'text'` bubble\n   * with `body_ranges` OR on an `'edit'` (the edit's replacement ranges). The Chat\n   * normalizes + resolves roster names → `ChatMessage.mentions` (mentions T6). */\n  bodyRanges?: MentionRange[] | null;\n  /** The decoded `timer_set` payload, present only when `envelopeType === 'timer_set'`\n   * (disappearing T10). Lets the Chat route a chat-default timer into its TimerFold\n   * instead of appending a visible bubble. */\n  timer?: { ttlSeconds: number | null; start: 'send' | 'read' } | null;\n  /** The decoded per-message TTL spec, present only on a `'text'` bubble that carried an\n   * `expiry` (disappearing T10). Lets the Chat arm the message's purge on first display. */\n  expiry?: ExpirySpec | null;\n}\n\ntype MessageListener = (m: IncomingMessage) => void;\ntype ConvEvent = { event: string; payload: Record<string, unknown> };\ntype ConvListener = (e: ConvEvent) => void;\n\n/** A tiny per-group fan-out hub (the web analogue of the iOS message/conv hubs). */\nexport class MessageHub {\n  private readonly messageListeners = new Map<string, Set<MessageListener>>();\n  private readonly convListeners = new Map<string, Set<ConvListener>>();\n\n  onMessage(displayId: string, fn: MessageListener): () => void {\n    return this.add(this.messageListeners, displayId, fn);\n  }\n  emitMessage(displayId: string, m: IncomingMessage): void {\n    for (const fn of this.messageListeners.get(displayId) ?? []) fn(m);\n  }\n  onConv(displayId: string, fn: ConvListener): () => void {\n    return this.add(this.convListeners, displayId, fn);\n  }\n  emitConv(displayId: string, e: ConvEvent): void {\n    for (const fn of this.convListeners.get(displayId) ?? []) fn(e);\n  }\n  /** How many live conv listeners a group still has — the census the LAST\n   * subscriber reads before tearing the conv topic (and its presence) down. */\n  convListenerCount(displayId: string): number {\n    return this.convListeners.get(displayId)?.size ?? 0;\n  }\n\n  private add<T>(map: Map<string, Set<T>>, key: string, fn: T): () => void {\n    let set = map.get(key);\n    if (!set) {\n      set = new Set();\n      map.set(key, set);\n    }\n    set.add(fn);\n    return () => {\n      set?.delete(fn);\n    };\n  }\n}\n\n/**\n * Decode the MLS-authenticated sender identity (`received.sender`) into the\n * `mdv_…` device id. The leaf-credential identity is exactly the SP-0 device id\n * UTF-8 bytes (see MlsEngine: `idBytes = utf8.encode(deviceId)`), so a plain\n * UTF-8 decode recovers it. Returns null for an empty/garbage identity so the\n * downstream `if (senderDeviceId)` guard stays sound (no spoofable empty actor).\n */\nfunction decodeSenderDeviceId(sender: Uint8Array): string | null {\n  if (sender.length === 0) return null;\n  const id = decodeUtf8(sender);\n  return id.length > 0 ? id : null;\n}\n\nexport class MessageDeliverySource {\n  private started = false;\n  private wakeUnsub: (() => void) | null = null;\n  // Per-observed-group conv subscription + heartbeat (presence/typing/read).\n  // `teardown` is the ONE departure path: it stops the heartbeat, broadcasts the\n  // offline frame and drops the subscriptions, so no caller can tear an\n  // observation down without saying goodbye (see observeConversation).\n  private readonly observed = new Map<string, { teardown: () => void }>();\n\n  constructor(\n    private readonly rt: PalbeRuntime,\n    private readonly engine: MlsEngine,\n    private readonly hub: MessageHub,\n    private readonly registry: GroupRegistry,\n    private readonly messageStore: MessageStore,\n    private readonly deviceId: string,\n    private readonly selfUserId: string,\n  ) {}\n\n  /** Subscribe the device wake topic + run an initial drain. Idempotent. */\n  async start(): Promise<void> {\n    if (this.started) return;\n    this.started = true;\n    try {\n      const channel = this.rt.realtime.channel(`messaging:device:${this.deviceId}`);\n      const sub = channel.on('new_message', () => {\n        void this.pumpOnce();\n      });\n      // Re-pump on every (re)connect to catch wakes missed while offline.\n      const offConn = this.rt.realtime.status.onChange((s) => {\n        if (s.state === 'connected') void this.pumpOnce();\n      });\n      this.wakeUnsub = () => {\n        sub.cancel();\n        offConn();\n      };\n    } catch {\n      // No WebSocket (SSR/Node) — the wake source is inert; explicit pumps still work.\n    }\n    await this.pumpOnce();\n  }\n\n  stop(): void {\n    this.wakeUnsub?.();\n    this.wakeUnsub = null;\n    for (const [, o] of this.observed) o.teardown();\n    this.observed.clear();\n    this.started = false;\n  }\n\n  /** One full drain: welcomes → queue (decrypt + emit) → ack. Never throws. */\n  async pumpOnce(): Promise<void> {\n    try {\n      await this.pullWelcomes();\n    } catch {\n      // transient — the next wake retries\n    }\n    try {\n      await this.pullQueue();\n    } catch {\n      // transient — the next wake retries\n    }\n  }\n\n  // ── Welcomes ──\n\n  private async pullWelcomes(): Promise<void> {\n    const page = await palbeRequest<WelcomePage>(\n      this.rt,\n      'GET',\n      MessagingPaths.deviceWelcomes(this.deviceId),\n    );\n    for (const w of page.welcomes) {\n      try {\n        const gidBytes = await this.engine.joinFromWelcome(fromBase64(w.welcome_b64));\n        // Register under the server-minted grp_ display_id (url-safe), NEVER the\n        // base64 rfc_group_id (which would 404 the members route — M3 #7).\n        const group: MessagingGroup = {\n          displayId: w.display_id,\n          rfcGroupId: toBase64(gidBytes),\n          currentEpoch: w.added_at_epoch,\n          ownerUserId: null,\n          directKey: null,\n          name: null,\n        };\n        this.registry.register(group);\n        this.hub.emitMessage(group.displayId, {\n          kind: 'welcome',\n          group,\n          text: null,\n          senderDeviceId: null,\n          epoch: w.added_at_epoch,\n          serverSeq: 0,\n          receivedAt: new Date(),\n          clientMsgId: '',\n          replyRef: null,\n        });\n      } catch {\n        // POISON-PILL GUARD: a re-served welcome whose one-time KeyPackage was\n        // already consumed (a duplicate for a membership we hold) fails join\n        // forever — skip quietly when the group is already known.\n        const known = this.registry.all().some((g) => g.displayId === w.display_id);\n        if (!known) {\n          // genuinely unknown group — swallow (best-effort pump); next wake retries\n        }\n      }\n    }\n  }\n\n  // ── Queue ──\n\n  private async pullQueue(): Promise<void> {\n    const page = await palbeRequest<QueuePage>(\n      this.rt,\n      'GET',\n      MessagingPaths.deviceQueue(this.deviceId),\n    );\n    const ackIds: string[] = [];\n    for (const row of page.messages) {\n      if (await this.process(row)) ackIds.push(row.id);\n    }\n    if (ackIds.length > 0) {\n      await palbeRequest<void>(this.rt, 'POST', MessagingPaths.deviceQueueAck(this.deviceId), {\n        body: { message_ids: ackIds },\n      });\n    }\n  }\n\n  /** Process one queue row; returns true if consumed (should ack). */\n  private async process(row: QueuedMessage): Promise<boolean> {\n    let blob: Uint8Array;\n    try {\n      blob = fromBase64(row.ciphertext_b64);\n    } catch {\n      return true; // junk → drop\n    }\n    // Resolve the target group: prefer the row's own rfc, else the sole group.\n    const group =\n      (row.rfc_group_id_b64 ? this.registry.group(row.rfc_group_id_b64) : undefined) ??\n      this.registry.soleGroup();\n    if (!group) return false; // unresolvable → leave unacked\n\n    try {\n      const received = await this.engine.processIncoming(fromBase64(group.rfcGroupId), blob);\n      if (received.type === 'application') {\n        const decoded = decodeEnvelope(received.data);\n        const { text, clientMsgId, replyTo } = decoded;\n        const isReaction = decoded.type === 'reaction' && decoded.reaction != null;\n        const isEdit = decoded.type === 'edit' && decoded.edit != null;\n        const isDelete = decoded.type === 'delete' && decoded.delete != null;\n        const isTimerSet = decoded.type === 'timer_set' && decoded.timer != null;\n        // SENDER ATTRIBUTION: prefer the server's `sender_device_id`, but the live\n        // server does NOT yet fan that field onto queue rows (same gap as\n        // `rfc_group_id` — see QueuedMessage). So fall back to the MLS-decrypted\n        // sender (`received.sender`), which IS the device's leaf-credential\n        // identity bytes (`mdv_…`, the SP-0 device id). This is the\n        // cryptographically authenticated sender — strictly stronger than a\n        // server-asserted field, and unspoofable. Without it, a peer's reaction\n        // arrives with a null sender → the Chat fold can't resolve the actor and\n        // SILENTLY DROPS it (text still renders, reactions vanish — the live bug).\n        const senderDeviceId = row.sender_device_id ?? decodeSenderDeviceId(received.sender);\n        const stored: StoredMessage = {\n          id: `${group.rfcGroupId}#${row.server_seq}`,\n          direction: 'incoming',\n          text,\n          senderDeviceId,\n          epoch: row.epoch,\n          serverSeq: row.server_seq,\n          at: Date.now(),\n          clientMsgId: clientMsgId || undefined,\n          replyTo: replyTo\n            ? {\n                clientMsgId: replyTo.client_msg_id,\n                previewBody: replyTo.preview?.body ?? null,\n                previewAuthorUserId: replyTo.preview?.author_user_id ?? null,\n                previewKind: replyTo.preview?.kind ?? 'text',\n              }\n            : null,\n          // Thread the reaction discriminator + fields through the persisted row so\n          // a reaction folded LIVE re-folds onto its target after a reload (the\n          // reload-parity boundary — mirrors iOS T3). Omitted for non-reactions →\n          // old rows hydrate as `'text'`/no-reaction (backward-compat).\n          ...(isReaction && decoded.reaction\n            ? {\n                envelopeType: 'reaction' as const,\n                reaction: {\n                  targetClientMsgId: decoded.reaction.targetClientMsgId,\n                  emoji: decoded.reaction.emoji,\n                  op: decoded.reaction.op,\n                },\n              }\n            : {}),\n          // Thread the edit discriminator + new text through the persisted row so an\n          // edit folded LIVE re-folds onto its target after a reload (the reload-parity\n          // boundary — mirrors iOS T3). Omitted for non-edits → old rows hydrate as\n          // `'text'`/no-edit (backward-compat). The edit's replacement body_ranges ride\n          // along so the edited message's mentions re-resolve on cold launch (T6).\n          ...(isEdit && decoded.edit\n            ? {\n                envelopeType: 'edit' as const,\n                edit: {\n                  targetClientMsgId: decoded.edit.targetClientMsgId,\n                  newText: decoded.edit.newText,\n                  ...(decoded.bodyRanges ? { bodyRanges: decoded.bodyRanges } : {}),\n                },\n              }\n            : {}),\n          // Thread the TEXT bubble's mention ranges (raw) through the persisted row so a\n          // mention surfaced LIVE re-resolves onto its bubble after a reload (the\n          // reload-parity boundary for mentions — T6, mirrors iOS T3). Only on a text\n          // bubble (not a reaction/edit/delete row); omitted when absent (backward-compat).\n          ...(!isReaction && !isEdit && !isDelete && decoded.bodyRanges\n            ? { bodyRanges: decoded.bodyRanges }\n            : {}),\n          // Thread the delete discriminator + target through the persisted row so a\n          // delete-for-everyone tombstone folded LIVE re-folds onto its target after\n          // a reload (the reload-parity boundary — the iOS-review CRITICAL lesson;\n          // the projection's `.delete` branch re-folds it so it never leaks a blank\n          // bubble). Omitted for non-deletes → old rows hydrate as `'text'`/no-delete.\n          ...(isDelete && decoded.delete\n            ? {\n                envelopeType: 'delete' as const,\n                delete: {\n                  targetClientMsgId: decoded.delete.targetClientMsgId,\n                  scope: decoded.delete.scope,\n                },\n              }\n            : {}),\n          // Disappearing T10: thread the timer_set discriminator + payload through the\n          // persisted row so the chat default re-folds on cold launch (the page-local\n          // TimerFold in projectHistory). Omitted for non-timer_set rows (backward-compat).\n          ...(isTimerSet && decoded.timer\n            ? {\n                envelopeType: 'timer_set' as const,\n                timer: { ttlSeconds: decoded.timer.ttlSeconds, start: decoded.timer.start },\n              }\n            : {}),\n          // Disappearing T10: thread a TEXT bubble's per-message expiry through the persisted\n          // row so the message re-arms its purge on cold launch (the projection derives the\n          // deadline from this). Only on a text bubble; omitted when absent (backward-compat).\n          ...(!isReaction && !isEdit && !isDelete && !isTimerSet && decoded.expiry\n            ? { expiry: decoded.expiry }\n            : {}),\n        };\n        try {\n          await this.messageStore.append(group.rfcGroupId, stored);\n        } catch {\n          return false; // persist failed → NOT acked, re-served next pump\n        }\n        this.hub.emitMessage(group.displayId, {\n          kind: 'application',\n          group,\n          text,\n          senderDeviceId,\n          epoch: row.epoch,\n          serverSeq: row.server_seq,\n          receivedAt: new Date(),\n          clientMsgId,\n          replyRef: replyTo,\n          envelopeType: decoded.type ?? 'text',\n          reaction: isReaction ? decoded.reaction : null,\n          edit: isEdit ? decoded.edit : null,\n          delete: isDelete ? decoded.delete : null,\n          // The raw mention ranges (text bubble or the edit's replacement ranges); the\n          // Chat normalizes + resolves names → ChatMessage.mentions (T6).\n          bodyRanges: decoded.bodyRanges ?? null,\n          // Disappearing T10: the decoded timer_set payload (chat default control) + a text\n          // bubble's per-message expiry. The Chat routes timer_set into its TimerFold and\n          // arms a bubble's purge from the expiry (or the active default).\n          timer: isTimerSet ? decoded.timer : null,\n          expiry:\n            !isReaction && !isEdit && !isDelete && !isTimerSet ? (decoded.expiry ?? null) : null,\n        });\n        return true;\n      }\n      if (received.type === 'commitApplied') {\n        const newEpoch = Math.max(row.epoch, group.currentEpoch + 1);\n        this.registry.bumpEpoch(group.rfcGroupId, newEpoch);\n        const fresh = this.registry.group(group.rfcGroupId) ?? group;\n        this.hub.emitMessage(group.displayId, {\n          kind: 'commit',\n          group: fresh,\n          text: null,\n          senderDeviceId: row.sender_device_id ?? null,\n          epoch: newEpoch,\n          serverSeq: 0,\n          receivedAt: new Date(),\n          clientMsgId: '',\n          replyRef: null,\n        });\n        return true;\n      }\n      return true; // proposal / other — consumed\n    } catch (e) {\n      // Own-sent echo or consumed-key: mls-rs refuses to decrypt own ciphertext /\n      // a replayed generation. ACK + skip (the durable copy is the send path's).\n      if (isOwnEchoOrConsumed(e)) return true;\n      return false; // decode/transient → leave unacked for retry\n    }\n  }\n\n  // ── Conv topic (presence / typing / read) ──\n\n  /** Begin observing a group's conv topic; fans events into the hub. Idempotent. */\n  observeConversation(group: MessagingGroup): void {\n    if (this.observed.has(group.displayId)) return;\n    try {\n      const channel = this.rt.realtime.channel(`messaging:conv:${group.rfcGroupId}`);\n      // Server-metadata cluster: subscribe `delivered` alongside `read` (its exact 3-key\n      // twin `{user_id, device_id, up_to_server_seq}`) so the sender's \"delivered\" tick\n      // advances. The Chat consumes both via applyConv → the per-message user-level\n      // monotonic watermark fold (mirrors iOS MessageDeliverySource's delivered case).\n      const subs = ['presence', 'typing', 'read', 'delivered'].map((ev) =>\n        channel.on(ev, (payload) => {\n          this.hub.emitConv(group.displayId, { event: ev, payload });\n        }),\n      );\n      // Announce online + heartbeat every 25s.\n      const emitPresence = (online: boolean) =>\n        channel.send('presence', {\n          user_id: this.selfUserId,\n          device_id: this.deviceId,\n          online,\n          ts: Date.now() / 1000,\n        });\n      emitPresence(true);\n      const heartbeat = setInterval(() => emitPresence(true), 25_000);\n      this.observed.set(group.displayId, {\n        teardown: () => {\n          // Stop the heartbeat BEFORE the goodbye so no beat can land after it.\n          clearInterval(heartbeat);\n          // The departure frame. Presence is broadcast-only — a peer's light is\n          // lit and unlit solely by these frames, and the server keeps no\n          // expiry that would time this device out — so leaving without it\n          // leaves every peer showing us online for the rest of their session.\n          try {\n            emitPresence(false);\n          } catch {\n            // socket already gone — nothing left to say goodbye through\n          }\n          for (const s of subs) s.cancel();\n        },\n      });\n    } catch {\n      // no socket (SSR) — presence/typing simply unavailable\n    }\n  }\n\n  /** Stop observing a group's conv topic: announce OFFLINE, stop the heartbeat\n   * and drop the subscriptions. Idempotent — an unobserved group is a no-op. */\n  unobserveConversation(group: MessagingGroup): void {\n    const o = this.observed.get(group.displayId);\n    if (!o) return;\n    this.observed.delete(group.displayId);\n    o.teardown();\n  }\n\n  /** Announce typing on a group's conv topic (the app calls per keystroke). */\n  setTyping(group: MessagingGroup, isTyping: boolean): void {\n    this.observeConversation(group);\n    try {\n      this.rt.realtime.channel(`messaging:conv:${group.rfcGroupId}`).send('typing', {\n        user_id: this.selfUserId,\n        device_id: this.deviceId,\n        typing: isTyping,\n      });\n    } catch {\n      // no socket\n    }\n  }\n\n  /** Advance this device's read cursor (idempotent; the server clamps). */\n  async markRead(group: MessagingGroup, upToServerSeq: number): Promise<void> {\n    await palbeRequest<void>(this.rt, 'POST', MessagingPaths.groupRead(group.displayId), {\n      body: { read_seq: upToServerSeq, read_epoch: group.currentEpoch, is_private: false },\n    });\n  }\n\n  // ── Server-metadata cluster: notify scope (mute) + unread (HTTP) ──\n\n  /** PUT `/v1/messaging/groups/{gid}/notify` — set the caller's per-(user,group) notify\n   * scope (`'all'`|`'none'`). The server stores the opaque enum verbatim and stays blind.\n   * Returns the server-echoed scope (fail-OPEN to `'all'` on an unknown value). */\n  async setNotifyScope(group: MessagingGroup, scope: NotifyScope): Promise<NotifyScope> {\n    const res = await palbeRequest<{ notify_scope: string }>(\n      this.rt,\n      'PUT',\n      MessagingPaths.groupNotify(group.displayId),\n      { body: { notify_scope: scope } },\n    );\n    return res.notify_scope === 'none' ? 'none' : 'all';\n  }\n\n  /** GET `/v1/messaging/groups/{gid}/notify` — the caller's notify scope. An absent\n   * server row / unknown value reads as `'all'` (fail-OPEN — never silently mutes). */\n  async getNotifyScope(group: MessagingGroup): Promise<NotifyScope> {\n    const res = await palbeRequest<{ notify_scope: string }>(\n      this.rt,\n      'GET',\n      MessagingPaths.groupNotify(group.displayId),\n    );\n    return res.notify_scope === 'none' ? 'none' : 'all';\n  }\n\n  /** GET `/v1/messaging/groups/{gid}/unread` — the caller's OWN unread view (opaque\n   * server metadata). Maps the snake_case wire → the camelCase `UnreadView`. */\n  async unread(group: MessagingGroup): Promise<UnreadView> {\n    const res = await palbeRequest<{\n      group_max_seq: number;\n      last_read_seq: number;\n      delivered_seq: number;\n      unread_count: number;\n    }>(this.rt, 'GET', MessagingPaths.groupUnread(group.displayId));\n    return {\n      groupMaxSeq: res.group_max_seq,\n      lastReadSeq: res.last_read_seq,\n      deliveredSeq: res.delivered_seq,\n      unreadCount: res.unread_count,\n    };\n  }\n}\n\n/** mls-rs own-echo (\"message from self can't be processed\") or consumed-key\n * (\"key not available, invalid generation\") — both ACK-and-skip on the receiver. */\nfunction isOwnEchoOrConsumed(e: unknown): boolean {\n  const msg = e instanceof Error ? e.message : String(e);\n  return msg.includes('message from self') || msg.includes('key not available, invalid generation');\n}\n\n// keep GroupMessaging/ContentType referenced for the wire-gap declaration hook\nvoid GroupMessaging;\nvoid ContentType;\n","// The disappearing/TTL durable store — the web mirror of iOS `DisappearingStore`.\n//\n// Holds the crash-safe purge state for disappearing messages, sealed at rest by the\n// same durable KV (IndexedDB + WebCrypto AES-GCM in the browser) that seals the\n// message store, so it survives a cold launch / mid-purge crash.\n//\n// TWO SEPARATE persistent purge sets, two key namespaces that CANNOT collide:\n//   (a) `tombstonedSeqs` — an INTEGER `server_seq` tombstone. Written FIRST (the purge\n//       commit point), it drives transcript exclusion (rebuilt-from-store skips a\n//       tombstoned seq) + redelivery drop (a redelivered tombstoned seq is dropped on\n//       arrival). A mid-purge crash AFTER this write resurrects the tombstone on reload.\n//   (b) `purgedClientMsgIds` — a STRING `client_msg_id` set. It drives the orphan-fold\n//       resolver (`authorOfTarget → 'purged'`) so a late edit DROPs and a late delete\n//       no-ops against a TTL-purged target.\n// The int seq and the string id live in distinct JSON fields; one is NEVER keyed off\n// the other (per the TTL global constraint).\n//\n// Anchors are WRITE-ONCE per `(device, clientMsgId)`: the first arrival captures the\n// monotonic/wall/boot anchor triple; a later re-arm for the same clientMsgId is a\n// no-op, so the deadline never resets.\n\nimport type { AnchorTriple } from './deadline-calculator.js';\nimport type { DurableKV } from './storage.js';\nimport { decodeUtf8, encodeUtf8 } from './util.js';\n\ninterface DisappearingRecord {\n  tombstonedSeqs: number[];\n  purgedClientMsgIds: string[];\n  anchors: Record<string, AnchorTriple>;\n}\n\n/**\n * Per-chat IndexedDB-backed store for disappearing durable state (keyed by\n * `disappear:<rfcGroupId>`). Mirrors `SuppressionStore`'s DurableKV/JSON pattern.\n */\nexport class DisappearingStore {\n  constructor(private readonly kv: DurableKV) {}\n\n  private key(rfc: string): string {\n    return `disappear:${rfc}`;\n  }\n\n  private async load(rfc: string): Promise<DisappearingRecord> {\n    const raw = await this.kv.get(this.key(rfc));\n    if (!raw) return { tombstonedSeqs: [], purgedClientMsgIds: [], anchors: {} };\n    try {\n      const r = JSON.parse(decodeUtf8(raw)) as Partial<DisappearingRecord>;\n      return {\n        tombstonedSeqs: r.tombstonedSeqs ?? [],\n        purgedClientMsgIds: r.purgedClientMsgIds ?? [],\n        anchors: r.anchors ?? {},\n      };\n    } catch {\n      return { tombstonedSeqs: [], purgedClientMsgIds: [], anchors: {} };\n    }\n  }\n\n  private async save(rfc: string, rec: DisappearingRecord): Promise<void> {\n    await this.kv.set(this.key(rfc), encodeUtf8(JSON.stringify(rec)));\n  }\n\n  /** The persisted INTEGER `server_seq` tombstone set for a chat (transcript exclusion + redelivery drop). */\n  async tombstonedSeqs(rfc: string): Promise<Set<number>> {\n    return new Set((await this.load(rfc)).tombstonedSeqs);\n  }\n\n  /** The persisted STRING `client_msg_id` purge set for a chat (orphan-fold → `'purged'`). */\n  async purgedClientMsgIds(rfc: string): Promise<Set<string>> {\n    return new Set((await this.load(rfc)).purgedClientMsgIds);\n  }\n\n  /**\n   * Tombstone-first commit point: the INTEGER seq and the STRING client_msg_id are\n   * written together in ONE durable record. Idempotent (re-tombstoning the same seq /\n   * id is a no-op). This write is THE purge commit — once it lands, a transcript rebuilt\n   * from the store excludes the seq and a redelivery is dropped, even across a crash.\n   */\n  async tombstone(rfc: string, serverSeq: number, clientMsgId: string): Promise<void> {\n    const rec = await this.load(rfc);\n    if (!rec.tombstonedSeqs.includes(serverSeq)) rec.tombstonedSeqs.push(serverSeq);\n    if (clientMsgId && !rec.purgedClientMsgIds.includes(clientMsgId)) {\n      rec.purgedClientMsgIds.push(clientMsgId);\n    }\n    await this.save(rfc, rec);\n  }\n\n  /** The persisted write-once anchor triple for a `clientMsgId`, or null if none. */\n  async anchor(rfc: string, clientMsgId: string): Promise<AnchorTriple | null> {\n    return (await this.load(rfc)).anchors[clientMsgId] ?? null;\n  }\n\n  /** Write-once: a second call for the same `clientMsgId` is a no-op (deadline never resets). */\n  async writeAnchorOnce(rfc: string, clientMsgId: string, a: AnchorTriple): Promise<void> {\n    const rec = await this.load(rfc);\n    if (rec.anchors[clientMsgId]) return;\n    rec.anchors[clientMsgId] = a;\n    await this.save(rfc, rec);\n  }\n}\n","// Local decrypted-message history + the group catalog — the web mirror of iOS\n// MessageStore + GroupCatalog. MLS decrypt-once means a received message's key\n// is erased on first decrypt, so you can NEVER refetch+redecrypt it from the\n// server: the decrypted plaintext MUST be persisted locally (sealed at rest by\n// the durable KV — IndexedDB+WebCrypto-AES-GCM in the browser). The own-sent\n// copy is likewise the only durable form (the sender can't decrypt its own\n// ciphertext).\n\nimport type { MentionRange } from './group-messaging.js';\nimport type { DurableKV } from './storage.js';\nimport type { MessageDirection } from './types.js';\nimport { decodeUtf8, encodeUtf8 } from './util.js';\n\n/** A durable stored message (one row in the local sealed transcript). */\nexport interface StoredMessage {\n  /** Stable across reloads: `<rfcGroupId>#<serverSeq>`. */\n  id: string;\n  direction: MessageDirection;\n  text: string | null;\n  senderDeviceId: string | null;\n  epoch: number;\n  serverSeq: number;\n  /** ms since epoch. */\n  at: number;\n  /**\n   * Client-minted idempotency id from the decoded envelope.\n   * Optional for backward-compat: old persisted rows without this key\n   * are treated as '' (no id) on read.\n   */\n  clientMsgId?: string;\n  /**\n   * The decoded reply reference, if the message was a reply.\n   * Optional for backward-compat: old persisted rows without this key\n   * are treated as null on read.\n   */\n  replyTo?: {\n    clientMsgId: string;\n    previewBody: string | null;\n    previewAuthorUserId: string | null;\n    previewKind: string;\n  } | null;\n  /**\n   * The decoded envelope discriminator (`'text'`/`'reaction'`/…).\n   * Optional for backward-compat: old persisted rows without this key are treated\n   * as `'text'` (a non-reaction) on read, so a pre-reactions row never re-folds.\n   */\n  envelopeType?: string;\n  /**\n   * The decoded reaction payload, present only when `envelopeType === 'reaction'`.\n   * Optional + backward-compat (old rows → undefined → no re-fold). Threading this\n   * through the persisted shape is the reload-parity boundary: a reaction folded\n   * LIVE re-folds onto its target after a cold launch.\n   */\n  reaction?: {\n    targetClientMsgId: string;\n    emoji: string;\n    op: 'add' | 'remove';\n  } | null;\n  /**\n   * The decoded edit payload, present only when `envelopeType === 'edit'`.\n   * Optional + backward-compat (old rows → undefined → no re-fold). Threading this\n   * through the persisted shape is the reload-parity boundary for edits: an edit\n   * folded LIVE re-folds onto its target's text after a cold launch.\n   */\n  edit?: {\n    targetClientMsgId: string;\n    newText: string;\n    /**\n     * The edit's REPLACEMENT mention ranges (raw, un-normalized). Optional +\n     * backward-compat (old rows → undefined). Threaded so an edited message's\n     * mentions re-resolve from the WINNING edit's ranges after a reload (mentions T6).\n     */\n    bodyRanges?: MentionRange[] | null;\n  } | null;\n  /**\n   * The decoded mention ranges on a TEXT/media bubble (raw, un-normalized — the\n   * Chat/projection normalizes + resolves names). Present only on `'text'` rows that\n   * carried `body_ranges`. Optional + backward-compat (old rows → undefined → no\n   * mentions). Threading this through the persisted shape is the reload-parity\n   * boundary for mentions: a mention surfaced LIVE re-resolves onto its bubble after a\n   * cold launch (mentions T6, mirrors iOS T3).\n   */\n  bodyRanges?: MentionRange[] | null;\n  /**\n   * The decoded delete payload, present only when `envelopeType === 'delete'`.\n   * Optional + backward-compat (old rows → undefined → no re-fold). Threading this\n   * through the persisted shape is the reload-parity boundary for deletes: a\n   * delete-for-everyone tombstone folded LIVE re-folds onto its target after a\n   * cold launch (and never leaks as a blank bubble — the iOS-review CRITICAL\n   * lesson: the projection MUST have a `.delete` branch).\n   */\n  delete?: {\n    targetClientMsgId: string;\n    scope: string;\n  } | null;\n  /**\n   * The decoded per-message TTL spec (own-sent / decoded), present only on a text/media\n   * row that carried an `expiry` (disappearing T10). Optional + backward-compat (old rows\n   * → undefined → no re-arm). Threaded so an own-send TTL re-arms its purge after a cold\n   * launch, and so the cold-launch `projectHistory` derives the message's effective TTL.\n   */\n  expiry?: {\n    v: number;\n    ttlSeconds: number;\n    start: 'send' | 'read';\n    senderSendTs: number | null;\n  } | null;\n  /**\n   * The decoded `timer_set` payload, present only when `envelopeType === 'timer_set'`\n   * (disappearing T10). Optional + backward-compat (old rows → undefined → no re-fold).\n   * Threaded so the chat default disappearing timer re-folds on a cold launch (the\n   * page-local `TimerFold` in `projectHistory`). `ttlSeconds === null` disables the default.\n   */\n  timer?: {\n    ttlSeconds: number | null;\n    start: 'send' | 'read';\n  } | null;\n}\n\n/** Persist decrypted messages per group, newest-last, deduped by id. */\nexport class MessageStore {\n  constructor(private readonly kv: DurableKV) {}\n\n  private key(rfcGroupId: string): string {\n    return `msgs:${rfcGroupId}`;\n  }\n\n  /** Append (idempotent on id) and persist the group's transcript. */\n  async append(rfcGroupId: string, msg: StoredMessage): Promise<void> {\n    const list = await this.load(rfcGroupId);\n    if (list.some((m) => m.id === msg.id)) return; // dedup by stable id\n    list.push(msg);\n    list.sort((a, b) => a.serverSeq - b.serverSeq);\n    await this.save(rfcGroupId, list);\n  }\n\n  /** True if a message id is already durable (the consumed-key recovery check). */\n  async contains(rfcGroupId: string, id: string): Promise<boolean> {\n    const list = await this.load(rfcGroupId);\n    return list.some((m) => m.id === id);\n  }\n\n  /**\n   * Read history for a group, newest-last. `before` pages older: returns up to\n   * `limit` rows with serverSeq < before. nil `before` returns the newest page.\n   */\n  async history(rfcGroupId: string, limit: number, before?: number): Promise<StoredMessage[]> {\n    const list = await this.load(rfcGroupId);\n    const filtered = before == null ? list : list.filter((m) => m.serverSeq < before);\n    return filtered.slice(Math.max(0, filtered.length - limit));\n  }\n\n  async load(rfcGroupId: string): Promise<StoredMessage[]> {\n    const raw = await this.kv.get(this.key(rfcGroupId));\n    if (!raw) return [];\n    try {\n      return JSON.parse(decodeUtf8(raw)) as StoredMessage[];\n    } catch {\n      return [];\n    }\n  }\n\n  private async save(rfcGroupId: string, list: StoredMessage[]): Promise<void> {\n    await this.kv.set(this.key(rfcGroupId), encodeUtf8(JSON.stringify(list)));\n  }\n\n  async wipe(): Promise<void> {\n    for (const k of await this.kv.keys('msgs:')) await this.kv.delete(k);\n  }\n}\n\n/** A persisted group entry (the catalog row — survives reloads). */\nexport interface CatalogGroup {\n  displayId: string;\n  rfcGroupId: string;\n  currentEpoch: number;\n  ownerUserId: string | null;\n  directKey: string | null;\n  name: string | null;\n}\n\n/** Durable list of known groups (the web mirror of iOS GroupCatalog), so a\n * reload hydrates the chat list + lets queue rows route before the first pump. */\nexport class GroupCatalog {\n  constructor(private readonly kv: DurableKV) {}\n\n  async upsert(g: CatalogGroup): Promise<void> {\n    await this.kv.set(`cat:${g.rfcGroupId}`, encodeUtf8(JSON.stringify(g)));\n  }\n\n  async remove(rfcGroupId: string): Promise<void> {\n    await this.kv.delete(`cat:${rfcGroupId}`);\n  }\n\n  async all(): Promise<CatalogGroup[]> {\n    const keys = await this.kv.keys('cat:');\n    const out: CatalogGroup[] = [];\n    for (const k of keys) {\n      const raw = await this.kv.get(k);\n      if (!raw) continue;\n      try {\n        out.push(JSON.parse(decodeUtf8(raw)) as CatalogGroup);\n      } catch {\n        // skip a corrupt row\n      }\n    }\n    return out;\n  }\n\n  async wipe(): Promise<void> {\n    for (const k of await this.kv.keys('cat:')) await this.kv.delete(k);\n  }\n}\n","// The self-elevation dedup store — the web mirror of iOS `MentionElevationStore`.\n//\n// WHY THIS EXISTS (mentions design §\"Self-elevation idempotency\"): when an INCOMING\n// message mentions THIS device's user (and the sender isn't me, and it isn't an edit),\n// the Chat fires `onMentionElevation` exactly ONCE. Re-delivery (a reconnect re-pump),\n// a backfill, and a cold-launch relaunch must NOT re-fire. The in-memory set gates a\n// session; this persisted set makes the dedup survive reload — a re-delivered mention\n// after a cold launch finds its key already set and is a no-op.\n//\n// POSTURE — identical to `SuppressionStore`: a persisted per-chat `Set<elevationKey>`\n// (keyed by rfcGroupId) where `elevationKey` is `\"<selfUserId>|<idPart>\"` (idPart =\n// the mention message's client_msg_id, or `seq:<serverSeq>` for a legacy message). The\n// `selfUserId` scoping means a multi-account device never crosses dedup sets. Sealed at\n// rest by the same durable KV (IndexedDB + WebCrypto AES-GCM in the browser) that seals\n// the message store — so \"which messages buzzed me\" stays private (a soft mention-graph\n// signal) and the dedup survives a cold launch.\n\nimport type { DurableKV } from './storage.js';\nimport { decodeUtf8, encodeUtf8 } from './util.js';\n\n/** Persist a per-chat self-elevation dedup key set (keyed by rfcGroupId). */\nexport class MentionElevationStore {\n  constructor(private readonly kv: DurableKV) {}\n\n  private key(rfcGroupId: string): string {\n    return `elev:${rfcGroupId}`;\n  }\n\n  /** Load the persisted elevation keys for a chat (empty array if none). */\n  async load(rfcGroupId: string): Promise<string[]> {\n    const raw = await this.kv.get(this.key(rfcGroupId));\n    if (!raw) return [];\n    try {\n      const parsed = JSON.parse(decodeUtf8(raw));\n      return Array.isArray(parsed) ? (parsed as string[]) : [];\n    } catch {\n      return [];\n    }\n  }\n\n  /** Persist the full elevation key set for a chat (deterministic, deduped order). */\n  async save(rfcGroupId: string, keys: string[]): Promise<void> {\n    const sorted = [...new Set(keys)].sort();\n    await this.kv.set(this.key(rfcGroupId), encodeUtf8(JSON.stringify(sorted)));\n  }\n\n  async wipe(): Promise<void> {\n    for (const k of await this.kv.keys('elev:')) await this.kv.delete(k);\n  }\n}\n","/**\n * Browser binding of [`PalbeMlsClient`]. Holds the same `Arc<PalbeMlsClient>`\n * the native FFI would; every method delegates to the engine.\n */\nexport class MlsClient {\n    static __wrap(ptr) {\n        const obj = Object.create(MlsClient.prototype);\n        obj.__wbg_ptr = ptr;\n        MlsClientFinalization.register(obj, obj.__wbg_ptr, obj);\n        return obj;\n    }\n    __destroy_into_raw() {\n        const ptr = this.__wbg_ptr;\n        this.__wbg_ptr = 0;\n        MlsClientFinalization.unregister(this);\n        return ptr;\n    }\n    free() {\n        const ptr = this.__destroy_into_raw();\n        wasm.__wbg_mlsclient_free(ptr, 0);\n    }\n    /**\n     * The MLS Capabilities wire bytes (the keydir's `capabilities`).\n     * @returns {Uint8Array}\n     */\n    capabilities() {\n        const ret = wasm.mlsclient_capabilities(this.__wbg_ptr);\n        var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n        return v1;\n    }\n    /**\n     * Create a new group at epoch 0. `groupId` `undefined`/`null` lets mls-rs\n     * mint a globally-unique id (the rfc_group_id routing key).\n     * @param {Uint8Array | null} [group_id]\n     * @returns {MlsGroup}\n     */\n    createGroup(group_id) {\n        var ptr0 = isLikeNone(group_id) ? 0 : passArray8ToWasm0(group_id, wasm.__wbindgen_malloc);\n        var len0 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsclient_createGroup(this.__wbg_ptr, ptr0, len0);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return MlsGroup.__wrap(ret[0]);\n    }\n    /**\n     * The MLS Credential wire bytes (the keydir's `credential`).\n     * @returns {Uint8Array}\n     */\n    credential() {\n        const ret = wasm.mlsclient_credential(this.__wbg_ptr);\n        var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n        return v1;\n    }\n    /**\n     * The MLS-encoded enrollment material `{ signatureKey, credential,\n     * capabilities }` (byte fields as arrays-of-numbers — wrap in Uint8Array as\n     * needed). Base64 these into the SP-0 keydir enroll body.\n     * @returns {any}\n     */\n    enrollmentMaterial() {\n        const ret = wasm.mlsclient_enrollmentMaterial(this.__wbg_ptr);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return takeFromExternrefTable0(ret[0]);\n    }\n    /**\n     * Mint a one-use KeyPackage (RAW RFC 9420 §10 bytes) — uploaded to the\n     * keydir, consumed by an adder's `addMember`.\n     * @returns {Uint8Array}\n     */\n    generateKeyPackage() {\n        const ret = wasm.mlsclient_generateKeyPackage(this.__wbg_ptr);\n        if (ret[3]) {\n            throw takeFromExternrefTable0(ret[2]);\n        }\n        var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n        return v1;\n    }\n    /**\n     * Join a group from a Welcome (opaque MLSMessage bytes).\n     * @param {Uint8Array} welcome\n     * @returns {MlsGroup}\n     */\n    joinGroup(welcome) {\n        const ptr0 = passArray8ToWasm0(welcome, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsclient_joinGroup(this.__wbg_ptr, ptr0, len0);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return MlsGroup.__wrap(ret[0]);\n    }\n    /**\n     * Re-hydrate a previously-persisted group by its `groupId` (restart-safe\n     * reload of an already-joined group).\n     * @param {Uint8Array} group_id\n     * @returns {MlsGroup}\n     */\n    loadGroup(group_id) {\n        const ptr0 = passArray8ToWasm0(group_id, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsclient_loadGroup(this.__wbg_ptr, ptr0, len0);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return MlsGroup.__wrap(ret[0]);\n    }\n    /**\n     * The serialized STABLE signature keypair (secret-bearing). Persist sealed\n     * and pass back as `signatureKeypair` on restart so the device keeps the\n     * SAME MLS signing identity.\n     * @returns {Uint8Array}\n     */\n    signatureKeypair() {\n        const ret = wasm.mlsclient_signatureKeypair(this.__wbg_ptr);\n        var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n        return v1;\n    }\n    /**\n     * The device's STABLE signature PUBLIC key bytes (the keydir's\n     * `signature_key`).\n     * @returns {Uint8Array}\n     */\n    signaturePublicKey() {\n        const ret = wasm.mlsclient_signaturePublicKey(this.__wbg_ptr);\n        var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n        return v1;\n    }\n}\nif (Symbol.dispose) MlsClient.prototype[Symbol.dispose] = MlsClient.prototype.free;\n\n/**\n * Browser binding of [`PalbeMlsGroup`].\n */\nexport class MlsGroup {\n    static __wrap(ptr) {\n        const obj = Object.create(MlsGroup.prototype);\n        obj.__wbg_ptr = ptr;\n        MlsGroupFinalization.register(obj, obj.__wbg_ptr, obj);\n        return obj;\n    }\n    __destroy_into_raw() {\n        const ptr = this.__wbg_ptr;\n        this.__wbg_ptr = 0;\n        MlsGroupFinalization.unregister(this);\n        return ptr;\n    }\n    free() {\n        const ptr = this.__destroy_into_raw();\n        wasm.__wbg_mlsgroup_free(ptr, 0);\n    }\n    /**\n     * Stage a member add. Returns `{ commit, welcome?, addedLeafIndices }`\n     * (byte fields as arrays-of-numbers). The group is PENDING after this.\n     * @param {Uint8Array} key_package_msg\n     * @returns {any}\n     */\n    addMember(key_package_msg) {\n        const ptr0 = passArray8ToWasm0(key_package_msg, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsgroup_addMember(this.__wbg_ptr, ptr0, len0);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return takeFromExternrefTable0(ret[0]);\n    }\n    /**\n     * Apply the staged commit (advances the local epoch). Call ONLY after the\n     * server accepted the commit.\n     */\n    applyPendingCommit() {\n        const ret = wasm.mlsgroup_applyPendingCommit(this.__wbg_ptr);\n        if (ret[1]) {\n            throw takeFromExternrefTable0(ret[0]);\n        }\n    }\n    /**\n     * Discard the staged commit without advancing (the 409-rebase path).\n     */\n    clearPendingCommit() {\n        wasm.mlsgroup_clearPendingCommit(this.__wbg_ptr);\n    }\n    /**\n     * Stage a SINGLE atomic add+remove commit. `addKeyPackages` is an\n     * `Array<Uint8Array>` of one-use key packages; `removeMemberIds` an\n     * `Array<Uint8Array>` of member identity bytes. Returns the same\n     * `AddResult` shape as `addMember`. PENDING after this.\n     * @param {Uint8Array[]} add_key_packages\n     * @param {Uint8Array[]} remove_member_ids\n     * @returns {any}\n     */\n    commitChanges(add_key_packages, remove_member_ids) {\n        const ptr0 = passArrayJsValueToWasm0(add_key_packages, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ptr1 = passArrayJsValueToWasm0(remove_member_ids, wasm.__wbindgen_malloc);\n        const len1 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsgroup_commitChanges(this.__wbg_ptr, ptr0, len0, ptr1, len1);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return takeFromExternrefTable0(ret[0]);\n    }\n    /**\n     * The current (applied) epoch as a JS BigInt (u64 exceeds safe-integer).\n     * @returns {bigint}\n     */\n    currentEpoch() {\n        const ret = wasm.mlsgroup_currentEpoch(this.__wbg_ptr);\n        return BigInt.asUintN(64, ret);\n    }\n    /**\n     * Inspect an incoming Commit and return the membership delta it WOULD\n     * effect WITHOUT applying it (the reconciliation gate's crypto-truth).\n     * Returns `{ kind, addedIdentities, removedIdentities }`.\n     * @param {Uint8Array} commit_msg\n     * @returns {any}\n     */\n    describeIncomingCommit(commit_msg) {\n        const ptr0 = passArray8ToWasm0(commit_msg, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsgroup_describeIncomingCommit(this.__wbg_ptr, ptr0, len0);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return takeFromExternrefTable0(ret[0]);\n    }\n    /**\n     * Encrypt an application message at the current epoch. Returns the opaque\n     * MLSMessage bytes (PrivateMessage).\n     * @param {Uint8Array} plaintext\n     * @returns {Uint8Array}\n     */\n    encryptApplicationMessage(plaintext) {\n        const ptr0 = passArray8ToWasm0(plaintext, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsgroup_encryptApplicationMessage(this.__wbg_ptr, ptr0, len0);\n        if (ret[3]) {\n            throw takeFromExternrefTable0(ret[2]);\n        }\n        var v2 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n        return v2;\n    }\n    /**\n     * Derive the group's current-epoch exporter secret (RFC 9420 §8.5) — the SAME\n     * engine call iOS uses (uniffi `exportSecret`), so a cross-platform call/group\n     * derives a byte-identical key. The SP-4 web call sets this as the LiveKit\n     * frame key (server + SFU stay blind); also group-name/media sealing.\n     * @param {Uint8Array} label\n     * @param {Uint8Array} context\n     * @param {bigint} len\n     * @returns {Uint8Array}\n     */\n    exportSecret(label, context, len) {\n        const ptr0 = passArray8ToWasm0(label, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ptr1 = passArray8ToWasm0(context, wasm.__wbindgen_malloc);\n        const len1 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsgroup_exportSecret(this.__wbg_ptr, ptr0, len0, ptr1, len1, len);\n        if (ret[3]) {\n            throw takeFromExternrefTable0(ret[2]);\n        }\n        var v3 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n        return v3;\n    }\n    /**\n     * The MLS group id (the rfc_group_id routing key / storage key).\n     * @returns {Uint8Array}\n     */\n    groupId() {\n        const ret = wasm.mlsgroup_groupId(this.__wbg_ptr);\n        var v1 = getArrayU8FromWasm0(ret[0], ret[1]).slice();\n        wasm.__wbindgen_free(ret[0], ret[1] * 1, 1);\n        return v1;\n    }\n    /**\n     * True while a staged (unapplied) commit exists.\n     * @returns {boolean}\n     */\n    hasPendingCommit() {\n        const ret = wasm.mlsgroup_hasPendingCommit(this.__wbg_ptr);\n        return ret !== 0;\n    }\n    /**\n     * Process an incoming MLSMessage and apply its effect. Returns a\n     * `ReceivedMessage` plain object (serde-tagged enum): e.g.\n     * `{ Application: { sender, data } }`, `{ CommitApplied: { epoch,\n     * removedSelf } }`, `\"Proposal\"`, or `\"Other\"`.\n     * @param {Uint8Array} message\n     * @returns {any}\n     */\n    processIncomingMessage(message) {\n        const ptr0 = passArray8ToWasm0(message, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsgroup_processIncomingMessage(this.__wbg_ptr, ptr0, len0);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return takeFromExternrefTable0(ret[0]);\n    }\n    /**\n     * Stage a member remove (by the member's identity bytes). Returns\n     * `{ commit }`. PENDING after this.\n     * @param {Uint8Array} member_id\n     * @returns {any}\n     */\n    removeMember(member_id) {\n        const ptr0 = passArray8ToWasm0(member_id, wasm.__wbindgen_malloc);\n        const len0 = WASM_VECTOR_LEN;\n        const ret = wasm.mlsgroup_removeMember(this.__wbg_ptr, ptr0, len0);\n        if (ret[2]) {\n            throw takeFromExternrefTable0(ret[1]);\n        }\n        return takeFromExternrefTable0(ret[0]);\n    }\n    /**\n     * Persist the current group state through the JS group storage callback.\n     */\n    writeToStorage() {\n        const ret = wasm.mlsgroup_writeToStorage(this.__wbg_ptr);\n        if (ret[1]) {\n            throw takeFromExternrefTable0(ret[0]);\n        }\n    }\n}\nif (Symbol.dispose) MlsGroup.prototype[Symbol.dispose] = MlsGroup.prototype.free;\n\n/**\n * Mint a device MLS client (browser binding of [`engine::generate_client`]).\n *\n * - `id`: the member identity bytes (the SP-0 device id `mdv_`).\n * - `group_storage`: a JS object implementing `IGroupStateStorage`.\n * - `key_package_storage`: a JS object implementing `IKeyPackageStorage`.\n * - `signature_keypair`: `undefined`/`null` on first run (a fresh keypair is\n *   minted), or the previously-persisted serialized secret-key bytes on restart.\n * @param {Uint8Array} id\n * @param {IGroupStateStorage} group_storage\n * @param {IKeyPackageStorage} key_package_storage\n * @param {Uint8Array | null} [signature_keypair]\n * @returns {MlsClient}\n */\nexport function generateClient(id, group_storage, key_package_storage, signature_keypair) {\n    const ptr0 = passArray8ToWasm0(id, wasm.__wbindgen_malloc);\n    const len0 = WASM_VECTOR_LEN;\n    var ptr1 = isLikeNone(signature_keypair) ? 0 : passArray8ToWasm0(signature_keypair, wasm.__wbindgen_malloc);\n    var len1 = WASM_VECTOR_LEN;\n    const ret = wasm.generateClient(ptr0, len0, group_storage, key_package_storage, ptr1, len1);\n    if (ret[2]) {\n        throw takeFromExternrefTable0(ret[1]);\n    }\n    return MlsClient.__wrap(ret[0]);\n}\n\n/**\n * Install the browser console panic hook so a Rust panic shows a readable\n * stack in the devtools console instead of an opaque `unreachable`. Idempotent;\n * the TS facade calls this once at module init.\n */\nexport function setPanicHook() {\n    wasm.setPanicHook();\n}\nexport function __wbg_BigInt_231999d28f899902() { return handleError(function (arg0) {\n    const ret = BigInt(arg0);\n    return ret;\n}, arguments); }\nexport function __wbg_Error_fdd633d4bb5dd76a(arg0, arg1) {\n    const ret = Error(getStringFromWasm0(arg0, arg1));\n    return ret;\n}\nexport function __wbg_String_8564e559799eccda(arg0, arg1) {\n    const ret = String(arg1);\n    const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n    const len1 = WASM_VECTOR_LEN;\n    getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);\n    getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);\n}\nexport function __wbg___wbindgen_bigint_get_as_i64_d9e915702856f831(arg0, arg1) {\n    const v = arg1;\n    const ret = typeof(v) === 'bigint' ? v : undefined;\n    getDataViewMemory0().setBigInt64(arg0 + 8 * 1, isLikeNone(ret) ? BigInt(0) : ret, true);\n    getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);\n}\nexport function __wbg___wbindgen_debug_string_8a447059637473e2(arg0, arg1) {\n    const ret = debugString(arg1);\n    const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n    const len1 = WASM_VECTOR_LEN;\n    getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);\n    getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);\n}\nexport function __wbg___wbindgen_is_function_acc5528be2b923f2(arg0) {\n    const ret = typeof(arg0) === 'function';\n    return ret;\n}\nexport function __wbg___wbindgen_is_null_6d937fbfb6478470(arg0) {\n    const ret = arg0 === null;\n    return ret;\n}\nexport function __wbg___wbindgen_is_object_0beba4a1980d3eea(arg0) {\n    const val = arg0;\n    const ret = typeof(val) === 'object' && val !== null;\n    return ret;\n}\nexport function __wbg___wbindgen_is_string_1fca8072260dd261(arg0) {\n    const ret = typeof(arg0) === 'string';\n    return ret;\n}\nexport function __wbg___wbindgen_is_undefined_721f8decd50c87a3(arg0) {\n    const ret = arg0 === undefined;\n    return ret;\n}\nexport function __wbg___wbindgen_jsval_eq_4e8c38722cb8ff51(arg0, arg1) {\n    const ret = arg0 === arg1;\n    return ret;\n}\nexport function __wbg___wbindgen_memory_9751d9a3017e7c25() {\n    const ret = wasm.memory;\n    return ret;\n}\nexport function __wbg___wbindgen_number_get_1cc01dd708740256(arg0, arg1) {\n    const obj = arg1;\n    const ret = typeof(obj) === 'number' ? obj : undefined;\n    getDataViewMemory0().setFloat64(arg0 + 8 * 1, isLikeNone(ret) ? 0 : ret, true);\n    getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);\n}\nexport function __wbg___wbindgen_string_get_71bb4348194e31f0(arg0, arg1) {\n    const obj = arg1;\n    const ret = typeof(obj) === 'string' ? obj : undefined;\n    var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n    var len1 = WASM_VECTOR_LEN;\n    getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);\n    getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);\n}\nexport function __wbg___wbindgen_throw_ea4887a5f8f9a9db(arg0, arg1) {\n    throw new Error(getStringFromWasm0(arg0, arg1));\n}\nexport function __wbg_buffer_7447b9cc2267a9e5(arg0) {\n    const ret = arg0.buffer;\n    return ret;\n}\nexport function __wbg_call_67f43c91d09298f2() { return handleError(function (arg0, arg1, arg2) {\n    const ret = arg0.call(arg1, arg2);\n    return ret;\n}, arguments); }\nexport function __wbg_call_b51415974987aa44() { return handleError(function (arg0, arg1) {\n    const ret = arg0.call(arg1);\n    return ret;\n}, arguments); }\nexport function __wbg_crypto_38df2bab126b63dc(arg0) {\n    const ret = arg0.crypto;\n    return ret;\n}\nexport function __wbg_delete_21fafcbc7bb82c85() { return handleError(function (arg0, arg1) {\n    arg0.delete(arg1);\n}, arguments); }\nexport function __wbg_epoch_15c000ffe3004541() { return handleError(function (arg0, arg1, arg2) {\n    const ret = arg0.epoch(arg1, BigInt.asUintN(64, arg2));\n    return ret;\n}, arguments); }\nexport function __wbg_error_a6fa202b58aa1cd3(arg0, arg1) {\n    let deferred0_0;\n    let deferred0_1;\n    try {\n        deferred0_0 = arg0;\n        deferred0_1 = arg1;\n        console.error(getStringFromWasm0(arg0, arg1));\n    } finally {\n        wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);\n    }\n}\nexport function __wbg_getRandomValues_c44a50d8cfdaebeb() { return handleError(function (arg0, arg1) {\n    arg0.getRandomValues(arg1);\n}, arguments); }\nexport function __wbg_get_615446055a48103f() { return handleError(function (arg0, arg1) {\n    const ret = arg0.get(arg1);\n    return ret;\n}, arguments); }\nexport function __wbg_globalThis_6d268067835e6709() { return handleError(function () {\n    const ret = globalThis.globalThis;\n    return ret;\n}, arguments); }\nexport function __wbg_global_3fe6c6c8ad6e6fb2() { return handleError(function () {\n    const ret = global.global;\n    return ret;\n}, arguments); }\nexport function __wbg_insert_2d611f2bf9b60fee() { return handleError(function (arg0, arg1, arg2) {\n    arg0.insert(arg1, arg2);\n}, arguments); }\nexport function __wbg_instanceof_Error_38f854307ecab4ce(arg0) {\n    let result;\n    try {\n        result = arg0 instanceof Error;\n    } catch (_) {\n        result = false;\n    }\n    const ret = result;\n    return ret;\n}\nexport function __wbg_length_c552db98817b9523(arg0) {\n    const ret = arg0.length;\n    return ret;\n}\nexport function __wbg_maxEpochId_0b176768b2f352fb() { return handleError(function (arg0, arg1) {\n    const ret = arg0.maxEpochId(arg1);\n    return ret;\n}, arguments); }\nexport function __wbg_message_a05fcf872473ffc5(arg0) {\n    const ret = arg0.message;\n    return ret;\n}\nexport function __wbg_msCrypto_bd5a034af96bcba6(arg0) {\n    const ret = arg0.msCrypto;\n    return ret;\n}\nexport function __wbg_new_227d7c05414eb861() {\n    const ret = new Error();\n    return ret;\n}\nexport function __wbg_new_32de5cbf49ca7dcb(arg0) {\n    const ret = new Uint8Array(arg0);\n    return ret;\n}\nexport function __wbg_new_364c96143b8f3496() {\n    const ret = new Object();\n    return ret;\n}\nexport function __wbg_new_b8b71ca8104fc178(arg0, arg1) {\n    const ret = new Error(getStringFromWasm0(arg0, arg1));\n    return ret;\n}\nexport function __wbg_new_d9762fd75876aafe() {\n    const ret = new Array();\n    return ret;\n}\nexport function __wbg_new_no_args_4010ad257320fa4f(arg0, arg1) {\n    const ret = new Function(getStringFromWasm0(arg0, arg1));\n    return ret;\n}\nexport function __wbg_new_with_byte_offset_and_length_8b21e3b1308deb48(arg0, arg1, arg2) {\n    const ret = new Uint8Array(arg0, arg1 >>> 0, arg2 >>> 0);\n    return ret;\n}\nexport function __wbg_new_with_length_5fdafe029be917a5(arg0) {\n    const ret = new Uint8Array(arg0 >>> 0);\n    return ret;\n}\nexport function __wbg_node_84ea875411254db1(arg0) {\n    const ret = arg0.node;\n    return ret;\n}\nexport function __wbg_process_44c7a14e11e9f69e(arg0) {\n    const ret = arg0.process;\n    return ret;\n}\nexport function __wbg_push_1303ce035391aed3(arg0, arg1) {\n    const ret = arg0.push(arg1);\n    return ret;\n}\nexport function __wbg_randomFillSync_6c25eac9869eb53c() { return handleError(function (arg0, arg1) {\n    arg0.randomFillSync(arg1);\n}, arguments); }\nexport function __wbg_require_b4edbdcf3e2a1ef0() { return handleError(function () {\n    const ret = module.require;\n    return ret;\n}, arguments); }\nexport function __wbg_self_1035a7cbd1b0d959() { return handleError(function () {\n    const ret = self.self;\n    return ret;\n}, arguments); }\nexport function __wbg_set_047d1ea37bb67c19(arg0, arg1, arg2) {\n    arg0.set(arg1, arg2 >>> 0);\n}\nexport function __wbg_set_1ddc4b8cd44d0da4() { return handleError(function (arg0, arg1, arg2) {\n    const ret = Reflect.set(arg0, arg1, arg2);\n    return ret;\n}, arguments); }\nexport function __wbg_set_28cba565792ec75f(arg0, arg1, arg2) {\n    arg0[arg1 >>> 0] = arg2;\n}\nexport function __wbg_set_6be42768c690e380(arg0, arg1, arg2) {\n    arg0[arg1] = arg2;\n}\nexport function __wbg_set_name_b4c29a3a72ebbddc(arg0, arg1, arg2) {\n    arg0.name = getStringFromWasm0(arg1, arg2);\n}\nexport function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {\n    const ret = arg1.stack;\n    const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);\n    const len1 = WASM_VECTOR_LEN;\n    getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);\n    getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);\n}\nexport function __wbg_state_bd20456c0f3efbc9() { return handleError(function (arg0, arg1) {\n    const ret = arg0.state(arg1);\n    return ret;\n}, arguments); }\nexport function __wbg_subarray_e0162dcdea48eb3a(arg0, arg1, arg2) {\n    const ret = arg0.subarray(arg1 >>> 0, arg2 >>> 0);\n    return ret;\n}\nexport function __wbg_versions_276b2795b1c6a219(arg0) {\n    const ret = arg0.versions;\n    return ret;\n}\nexport function __wbg_window_9c17850b5e99c0ab() { return handleError(function () {\n    const ret = window.window;\n    return ret;\n}, arguments); }\nexport function __wbg_write_56b1cf5bb0e780d6() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {\n    arg0.write(arg1, arg2, arg3, arg4);\n}, arguments); }\nexport function __wbindgen_cast_0000000000000001(arg0) {\n    // Cast intrinsic for `F64 -> Externref`.\n    const ret = arg0;\n    return ret;\n}\nexport function __wbindgen_cast_0000000000000002(arg0, arg1) {\n    // Cast intrinsic for `Ref(String) -> Externref`.\n    const ret = getStringFromWasm0(arg0, arg1);\n    return ret;\n}\nexport function __wbindgen_cast_0000000000000003(arg0) {\n    // Cast intrinsic for `U64 -> Externref`.\n    const ret = BigInt.asUintN(64, arg0);\n    return ret;\n}\nexport function __wbindgen_init_externref_table() {\n    const table = wasm.__wbindgen_externrefs;\n    const offset = table.grow(4);\n    table.set(0, undefined);\n    table.set(offset + 0, undefined);\n    table.set(offset + 1, null);\n    table.set(offset + 2, true);\n    table.set(offset + 3, false);\n}\nconst MlsClientFinalization = (typeof FinalizationRegistry === 'undefined')\n    ? { register: () => {}, unregister: () => {} }\n    : new FinalizationRegistry(ptr => wasm.__wbg_mlsclient_free(ptr, 1));\nconst MlsGroupFinalization = (typeof FinalizationRegistry === 'undefined')\n    ? { register: () => {}, unregister: () => {} }\n    : new FinalizationRegistry(ptr => wasm.__wbg_mlsgroup_free(ptr, 1));\n\nfunction addToExternrefTable0(obj) {\n    const idx = wasm.__externref_table_alloc();\n    wasm.__wbindgen_externrefs.set(idx, obj);\n    return idx;\n}\n\nfunction debugString(val) {\n    // primitive types\n    const type = typeof val;\n    if (type == 'number' || type == 'boolean' || val == null) {\n        return  `${val}`;\n    }\n    if (type == 'string') {\n        return `\"${val}\"`;\n    }\n    if (type == 'symbol') {\n        const description = val.description;\n        if (description == null) {\n            return 'Symbol';\n        } else {\n            return `Symbol(${description})`;\n        }\n    }\n    if (type == 'function') {\n        const name = val.name;\n        if (typeof name == 'string' && name.length > 0) {\n            return `Function(${name})`;\n        } else {\n            return 'Function';\n        }\n    }\n    // objects\n    if (Array.isArray(val)) {\n        const length = val.length;\n        let debug = '[';\n        if (length > 0) {\n            debug += debugString(val[0]);\n        }\n        for(let i = 1; i < length; i++) {\n            debug += ', ' + debugString(val[i]);\n        }\n        debug += ']';\n        return debug;\n    }\n    // Test for built-in\n    const builtInMatches = /\\[object ([^\\]]+)\\]/.exec(toString.call(val));\n    let className;\n    if (builtInMatches && builtInMatches.length > 1) {\n        className = builtInMatches[1];\n    } else {\n        // Failed to match the standard '[object ClassName]'\n        return toString.call(val);\n    }\n    if (className == 'Object') {\n        // we're a user defined class or Object\n        // JSON.stringify avoids problems with cycles, and is generally much\n        // easier than looping through ownProperties of `val`.\n        try {\n            return 'Object(' + JSON.stringify(val) + ')';\n        } catch (_) {\n            return 'Object';\n        }\n    }\n    // errors\n    if (val instanceof Error) {\n        return `${val.name}: ${val.message}\\n${val.stack}`;\n    }\n    // TODO we could test for more things here, like `Set`s and `Map`s.\n    return className;\n}\n\nfunction getArrayU8FromWasm0(ptr, len) {\n    ptr = ptr >>> 0;\n    return getUint8ArrayMemory0().subarray(ptr / 1, ptr / 1 + len);\n}\n\nlet cachedDataViewMemory0 = null;\nfunction getDataViewMemory0() {\n    if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {\n        cachedDataViewMemory0 = new DataView(wasm.memory.buffer);\n    }\n    return cachedDataViewMemory0;\n}\n\nfunction getStringFromWasm0(ptr, len) {\n    return decodeText(ptr >>> 0, len);\n}\n\nlet cachedUint8ArrayMemory0 = null;\nfunction getUint8ArrayMemory0() {\n    if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {\n        cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);\n    }\n    return cachedUint8ArrayMemory0;\n}\n\nfunction handleError(f, args) {\n    try {\n        return f.apply(this, args);\n    } catch (e) {\n        const idx = addToExternrefTable0(e);\n        wasm.__wbindgen_exn_store(idx);\n    }\n}\n\nfunction isLikeNone(x) {\n    return x === undefined || x === null;\n}\n\nfunction passArray8ToWasm0(arg, malloc) {\n    const ptr = malloc(arg.length * 1, 1) >>> 0;\n    getUint8ArrayMemory0().set(arg, ptr / 1);\n    WASM_VECTOR_LEN = arg.length;\n    return ptr;\n}\n\nfunction passArrayJsValueToWasm0(array, malloc) {\n    const ptr = malloc(array.length * 4, 4) >>> 0;\n    for (let i = 0; i < array.length; i++) {\n        const add = addToExternrefTable0(array[i]);\n        getDataViewMemory0().setUint32(ptr + 4 * i, add, true);\n    }\n    WASM_VECTOR_LEN = array.length;\n    return ptr;\n}\n\nfunction passStringToWasm0(arg, malloc, realloc) {\n    if (realloc === undefined) {\n        const buf = cachedTextEncoder.encode(arg);\n        const ptr = malloc(buf.length, 1) >>> 0;\n        getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);\n        WASM_VECTOR_LEN = buf.length;\n        return ptr;\n    }\n\n    let len = arg.length;\n    let ptr = malloc(len, 1) >>> 0;\n\n    const mem = getUint8ArrayMemory0();\n\n    let offset = 0;\n\n    for (; offset < len; offset++) {\n        const code = arg.charCodeAt(offset);\n        if (code > 0x7F) break;\n        mem[ptr + offset] = code;\n    }\n    if (offset !== len) {\n        if (offset !== 0) {\n            arg = arg.slice(offset);\n        }\n        ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;\n        const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);\n        const ret = cachedTextEncoder.encodeInto(arg, view);\n\n        offset += ret.written;\n        ptr = realloc(ptr, len, offset, 1) >>> 0;\n    }\n\n    WASM_VECTOR_LEN = offset;\n    return ptr;\n}\n\nfunction takeFromExternrefTable0(idx) {\n    const value = wasm.__wbindgen_externrefs.get(idx);\n    wasm.__externref_table_dealloc(idx);\n    return value;\n}\n\nlet cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });\ncachedTextDecoder.decode();\nconst MAX_SAFARI_DECODE_BYTES = 2146435072;\nlet numBytesDecoded = 0;\nfunction decodeText(ptr, len) {\n    numBytesDecoded += len;\n    if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) {\n        cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });\n        cachedTextDecoder.decode();\n        numBytesDecoded = len;\n    }\n    return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));\n}\n\nconst cachedTextEncoder = new TextEncoder();\n\nif (!('encodeInto' in cachedTextEncoder)) {\n    cachedTextEncoder.encodeInto = function (arg, view) {\n        const buf = cachedTextEncoder.encode(arg);\n        view.set(buf);\n        return {\n            read: arg.length,\n            written: buf.length\n        };\n    };\n}\n\nlet WASM_VECTOR_LEN = 0;\n\n\nlet wasm;\nexport function __wbg_set_wasm(val) {\n    wasm = val;\n}\n","\nexport function date_now() {\n  return Date.now();\n}","// Portable WASM loader for the palbe-mls engine — works in browser bundles and\n// Node without filesystem paths, public URLs, or runtime network requests.\n//\n// Why not just `import * as wasm from './palbe_mls_bg.wasm'` (the bundler\n// target's own entry, `palbe_mls.js`)? Because that import form only works in\n// bundlers that special-case `.wasm` (webpack/Vite with config) and NEVER in\n// Node — so the two-client crypto smoke (vitest, Node) could not run the real\n// engine. Instead we replicate what the wasm-pack `web`/`nodejs` targets do\n// internally: build the import object from the glue module's named exports +\n// the inline snippet, then `WebAssembly.instantiate` the bytes ourselves. The\n// bytes live in a private, lazily imported JavaScript package target, so a\n// consumer bundler can code-split them without needing a `.wasm` loader.\n//\n// init is idempotent + races-safe: concurrent callers share one in-flight\n// promise, and a second call after success is a no-op returning the same glue.\n\n// The glue exports every user-facing binding (MlsClient/MlsGroup/generateClient/\n// setPanicHook) AND all the `__wbg_*` import functions the `.wasm` needs, plus\n// `__wbg_set_wasm` (hand the instantiated exports back to the glue) and\n// `__wbindgen_start` (run wasm-bindgen's start section). We import it as a\n// namespace so we can both call the bindings and assemble the import object.\nimport * as glue from './pkg/palbe_mls_bg.js';\n// The single inline snippet the `.wasm` imports directly (Date.now()).\nimport * as snippet from './pkg/snippets/mls-rs-core-f99cdecbb456b09c/inline0.js';\n\n/** The subset of the glue surface the bridge calls. */\nexport interface MlsGlue {\n  generateClient: typeof glue.generateClient;\n  setPanicHook: typeof glue.setPanicHook;\n  MlsClient: typeof glue.MlsClient;\n  MlsGroup: typeof glue.MlsGroup;\n}\n\n// The two import-module specifiers the `.wasm` declares (verified via\n// WebAssembly.Module.imports — './palbe_mls_bg.js' + the inline snippet).\nconst GLUE_MODULE = './palbe_mls_bg.js';\nconst SNIPPET_MODULE = './snippets/mls-rs-core-f99cdecbb456b09c/inline0.js';\n\nlet inflight: Promise<MlsGlue> | null = null;\nlet ready: MlsGlue | null = null;\n\nfunction decodeBase64(encoded: unknown): ArrayBuffer {\n  if (\n    typeof encoded !== 'string' ||\n    encoded.length === 0 ||\n    typeof globalThis.atob !== 'function'\n  ) {\n    throw new Error('palbe-mls WASM asset is invalid');\n  }\n\n  let binary: string;\n  try {\n    binary = globalThis.atob(encoded);\n  } catch {\n    throw new Error('palbe-mls WASM asset is invalid');\n  }\n\n  const bytes = new Uint8Array(binary.length);\n  for (let index = 0; index < binary.length; index += 1) {\n    bytes[index] = binary.charCodeAt(index);\n  }\n  return bytes.buffer;\n}\n\nasync function loadWasmModule(): Promise<WebAssembly.Module> {\n  const asset = await import('#palbase-mls-wasm');\n  return WebAssembly.compile(decodeBase64(asset.default));\n}\n\n/** Assemble the import object the `.wasm` expects from the glue + snippet. */\nfunction buildImports(): WebAssembly.Imports {\n  return {\n    [GLUE_MODULE]: glue as unknown as WebAssembly.ModuleImports,\n    [SNIPPET_MODULE]: snippet as unknown as WebAssembly.ModuleImports,\n  };\n}\n\n/**\n * Initialize the MLS WASM engine. Idempotent — call it once before any\n * messaging crypto op (the facade does this on `pb.messaging.start()` and\n * before the first chat op). Returns the glue surface (the bridge uses it).\n */\nexport function initMls(): Promise<MlsGlue> {\n  if (ready) return Promise.resolve(ready);\n  if (inflight) return inflight;\n  const attempt = (async () => {\n    const module = await loadWasmModule();\n    const instance = await WebAssembly.instantiate(module, buildImports());\n    // Hand the instance's exports back to the glue (its module-level `wasm`)…\n    const setWasm = (glue as unknown as { __wbg_set_wasm: (e: unknown) => void }).__wbg_set_wasm;\n    setWasm(instance.exports);\n    // …then run wasm-bindgen's start section (sets up the heap, etc).\n    (instance.exports as { __wbindgen_start?: () => void }).__wbindgen_start?.();\n    const g: MlsGlue = {\n      generateClient: glue.generateClient,\n      setPanicHook: glue.setPanicHook,\n      MlsClient: glue.MlsClient,\n      MlsGroup: glue.MlsGroup,\n    };\n    // Surface Rust panics as readable console errors in the browser.\n    try {\n      g.setPanicHook();\n    } catch {\n      // best-effort: a missing console_error_panic_hook must not fail init\n    }\n    ready = g;\n    return g;\n  })();\n  inflight = attempt;\n  void attempt.catch(() => {\n    if (inflight === attempt) inflight = null;\n  });\n  return attempt;\n}\n\n/** True once `initMls()` has completed (the engine is usable synchronously). */\nexport function isMlsReady(): boolean {\n  return ready !== null;\n}\n\n/** The initialized glue, or throw if `initMls()` has not completed. */\nexport function requireMls(): MlsGlue {\n  if (!ready) {\n    throw new Error('palbe-mls WASM not initialized — await initMls() first');\n  }\n  return ready;\n}\n","// Typed bridge over the raw WASM `MlsClient`/`MlsGroup`. It normalizes the two\n// byte conventions the engine uses and presents clean TS records:\n//\n//  · Direct byte methods (signaturePublicKey, generateKeyPackage,\n//    encryptApplicationMessage, groupId, …) already return `Uint8Array`.\n//  · serde records/enums (enrollmentMaterial, addMember/commitChanges result,\n//    processIncomingMessage, describeIncomingCommit) cross via\n//    serde-wasm-bindgen, where `Vec<u8>` fields serialize as ARRAYS OF NUMBERS\n//    (documented in src/wasm.rs §Records). We wrap those back into Uint8Array.\n//\n// Field names are camelCase (the engine derives `serde(rename_all =\n// \"camelCase\")`). The `ReceivedMessage` enum is externally tagged:\n//   { Application: { sender, data } } | { CommitApplied: { epoch, removedSelf } }\n//   | \"Proposal\" | \"Other\"\n//\n// Everything here is SYNC — the engine methods are synchronous (mls-rs storage\n// is sync in this build). Serialization of state happens through the JS storage\n// callbacks the host supplies (see ../storage.ts).\n\nimport { requireMls } from './loader.js';\nimport type {\n  IGroupStateStorage,\n  IKeyPackageStorage,\n  MlsClient as RawClientType,\n  MlsGroup as RawGroup,\n} from './pkg/palbe_mls.types.d.ts';\n\nexport type { IGroupStateStorage, IKeyPackageStorage };\n\n/** Coerce a serde byte field (array-of-numbers OR Uint8Array) to Uint8Array. */\nfunction toBytes(v: unknown): Uint8Array {\n  if (v instanceof Uint8Array) return v;\n  if (Array.isArray(v)) return Uint8Array.from(v as number[]);\n  if (v == null) return new Uint8Array(0);\n  // ArrayBuffer / typed-array view fallthrough.\n  if (ArrayBuffer.isView(v)) return new Uint8Array((v as ArrayBufferView).buffer);\n  throw new Error('expected byte field (Uint8Array | number[])');\n}\n\nfunction optBytes(v: unknown): Uint8Array | undefined {\n  if (v == null) return undefined;\n  return toBytes(v);\n}\n\n// ─── Record types (normalized) ───────────────────────────────────────────────\n\n/** `{ signatureKey, credential, capabilities }` — the SP-0 enroll material. */\nexport interface EnrollmentMaterial {\n  signatureKey: Uint8Array;\n  credential: Uint8Array;\n  capabilities: Uint8Array;\n}\n\n/** Result of staging an add/commit-changes: commit + optional welcome + leaves. */\nexport interface AddResult {\n  commit: Uint8Array;\n  welcome?: Uint8Array;\n  addedLeafIndices: number[];\n}\n\n/** Result of staging a remove: just the commit. */\nexport interface RemoveResult {\n  commit: Uint8Array;\n}\n\nexport type CommitKind = 'Add' | 'Remove' | 'Update' | 'Mixed' | 'Other';\n\n/** The membership delta a commit WOULD effect (the reconciliation gate truth). */\nexport interface CommitDescription {\n  kind: CommitKind;\n  addedIdentities: Uint8Array[];\n  removedIdentities: Uint8Array[];\n}\n\n/** What `processIncomingMessage` decoded (the normalized form of the serde enum). */\nexport type ReceivedMessage =\n  | { type: 'application'; sender: Uint8Array; data: Uint8Array }\n  | { type: 'commitApplied'; epoch: number; removedSelf: boolean }\n  | { type: 'proposal' }\n  | { type: 'other' };\n\n// ─── Group wrapper ───────────────────────────────────────────────────────────\n\n/** Typed wrapper over a raw `MlsGroup`. */\nexport class MlsGroupHandle {\n  /** @internal */\n  constructor(private readonly raw: RawGroup) {}\n\n  /** The MLS rfc_group_id (routing key / storage key) bytes. */\n  groupId(): Uint8Array {\n    return this.raw.groupId();\n  }\n\n  /** Current applied epoch (BigInt → number; epochs stay well under 2^53). */\n  currentEpoch(): number {\n    return Number(this.raw.currentEpoch());\n  }\n\n  /** Stage a member add (PENDING after). */\n  addMember(keyPackageMsg: Uint8Array): AddResult {\n    return normalizeAddResult(this.raw.addMember(keyPackageMsg));\n  }\n\n  /** Stage a member remove by identity bytes (PENDING after). */\n  removeMember(memberId: Uint8Array): RemoveResult {\n    const r = this.raw.removeMember(memberId) as { commit: unknown };\n    return { commit: toBytes(r.commit) };\n  }\n\n  /** Stage a SINGLE atomic add+remove commit (PENDING after). */\n  commitChanges(addKeyPackages: Uint8Array[], removeMemberIds: Uint8Array[]): AddResult {\n    return normalizeAddResult(this.raw.commitChanges(addKeyPackages, removeMemberIds));\n  }\n\n  /** Apply the staged commit (advance the local epoch). Only after server-accept. */\n  applyPendingCommit(): void {\n    this.raw.applyPendingCommit();\n  }\n\n  /** Discard the staged commit without advancing (the 409-rebase path). */\n  clearPendingCommit(): void {\n    this.raw.clearPendingCommit();\n  }\n\n  /** True while a staged (unapplied) commit exists. */\n  hasPendingCommit(): boolean {\n    return this.raw.hasPendingCommit();\n  }\n\n  /** Encrypt an application message at the current epoch → PrivateMessage bytes. */\n  encryptApplicationMessage(plaintext: Uint8Array): Uint8Array {\n    return this.raw.encryptApplicationMessage(plaintext);\n  }\n\n  /** Process an incoming MLSMessage and apply its effect (normalized result). */\n  processIncomingMessage(message: Uint8Array): ReceivedMessage {\n    return normalizeReceived(this.raw.processIncomingMessage(message));\n  }\n\n  /** Inspect an incoming Commit WITHOUT applying it (the gate's crypto-truth). */\n  describeIncomingCommit(commitMsg: Uint8Array): CommitDescription {\n    const d = this.raw.describeIncomingCommit(commitMsg) as {\n      kind: CommitKind;\n      addedIdentities: unknown[];\n      removedIdentities: unknown[];\n    };\n    return {\n      kind: d.kind,\n      addedIdentities: d.addedIdentities.map(toBytes),\n      removedIdentities: d.removedIdentities.map(toBytes),\n    };\n  }\n\n  /** Persist the current group state through the JS group-storage callback. */\n  writeToStorage(): void {\n    this.raw.writeToStorage();\n  }\n}\n\nfunction normalizeAddResult(v: unknown): AddResult {\n  const r = v as { commit: unknown; welcome?: unknown; addedLeafIndices?: unknown[] };\n  return {\n    commit: toBytes(r.commit),\n    welcome: optBytes(r.welcome),\n    addedLeafIndices: (r.addedLeafIndices ?? []).map((n) => Number(n)),\n  };\n}\n\nfunction normalizeReceived(v: unknown): ReceivedMessage {\n  // Unit variants serialize as the bare string (\"Proposal\" / \"Other\").\n  if (v === 'Proposal') return { type: 'proposal' };\n  if (v === 'Other') return { type: 'other' };\n  const obj = v as Record<string, unknown>;\n  if (obj.Application) {\n    const a = obj.Application as { sender: unknown; data: unknown };\n    return { type: 'application', sender: toBytes(a.sender), data: toBytes(a.data) };\n  }\n  if (obj.CommitApplied) {\n    const c = obj.CommitApplied as { epoch: unknown; removedSelf: unknown };\n    return { type: 'commitApplied', epoch: Number(c.epoch), removedSelf: Boolean(c.removedSelf) };\n  }\n  return { type: 'other' };\n}\n\n// ─── Client wrapper ──────────────────────────────────────────────────────────\n\n/** Typed wrapper over a raw `MlsClient`. */\nexport class MlsClientHandle {\n  /** @internal */\n  constructor(private readonly raw: RawClientType) {}\n\n  /** The SP-0 keydir enroll material (`{ signatureKey, credential, capabilities }`). */\n  enrollmentMaterial(): EnrollmentMaterial {\n    const m = this.raw.enrollmentMaterial() as {\n      signatureKey: unknown;\n      credential: unknown;\n      capabilities: unknown;\n    };\n    return {\n      signatureKey: toBytes(m.signatureKey),\n      credential: toBytes(m.credential),\n      capabilities: toBytes(m.capabilities),\n    };\n  }\n\n  /** The device's STABLE signature PUBLIC key bytes (the keydir `signature_key`). */\n  signaturePublicKey(): Uint8Array {\n    return this.raw.signaturePublicKey();\n  }\n\n  /** The MLS Credential wire bytes (the keydir `credential`). */\n  credential(): Uint8Array {\n    return this.raw.credential();\n  }\n\n  /** The MLS Capabilities wire bytes (the keydir `capabilities`). */\n  capabilities(): Uint8Array {\n    return this.raw.capabilities();\n  }\n\n  /** The serialized STABLE signature keypair (secret-bearing — persist sealed). */\n  signatureKeypair(): Uint8Array {\n    return this.raw.signatureKeypair();\n  }\n\n  /** Mint a one-use KeyPackage (RAW RFC 9420 §10 bytes). */\n  generateKeyPackage(): Uint8Array {\n    return this.raw.generateKeyPackage();\n  }\n\n  /** Create a new group at epoch 0 (engine mints the rfc_group_id). */\n  createGroup(groupId?: Uint8Array): MlsGroupHandle {\n    return new MlsGroupHandle(this.raw.createGroup(groupId ?? undefined));\n  }\n\n  /** Join a group from a Welcome (opaque MLSMessage bytes). */\n  joinGroup(welcome: Uint8Array): MlsGroupHandle {\n    return new MlsGroupHandle(this.raw.joinGroup(welcome));\n  }\n\n  /** Re-hydrate an already-joined group by its rfc_group_id bytes. */\n  loadGroup(groupId: Uint8Array): MlsGroupHandle {\n    return new MlsGroupHandle(this.raw.loadGroup(groupId));\n  }\n}\n\n/**\n * Mint a device MLS client. `initMls()` MUST have completed first\n * (the facade enforces this). `signatureKeypair` is undefined on first run, or\n * the previously-persisted sealed keypair bytes on restart (same MLS identity).\n */\nexport function generateClient(\n  id: Uint8Array,\n  groupStorage: IGroupStateStorage,\n  keyPackageStorage: IKeyPackageStorage,\n  signatureKeypair?: Uint8Array,\n): MlsClientHandle {\n  const { generateClient: gen } = requireMls();\n  return new MlsClientHandle(\n    gen(id, groupStorage, keyPackageStorage, signatureKeypair ?? undefined),\n  );\n}\n","// The web mirror of iOS `MLSEngine` — a single serialized owner of the WASM\n// MlsClient + the per-group MlsGroup handles. Every public method runs through\n// a promise-chain mutex (`enqueue`) so the synchronous engine critical section\n// is never re-entered concurrently (the engine is single-threaded; two awaited\n// ops interleaving would corrupt the storage write-through cache).\n//\n// DURABILITY BOUNDARY: a mutating engine op (create / join / commit / encrypt /\n// process / applyPending) is followed by an awaited storage flush before the\n// host treats the op as done — so an acked message / applied commit is always\n// durable (the engine erases a message key on first decrypt; the durable copy\n// is the only recoverable form, mirroring the iOS D3/D5 ordering).\n//\n// IDENTITY: the MLS credential identity is the SP-0 device id (`mdv_`), passed\n// as the `id` bytes to generateClient (SP-1.6 per-device leaf identity).\n\nimport type { GroupStateStorage, KeyPackageStorage, SignatureKeyStore } from './storage.js';\nimport { bytesToHex } from './util.js';\nimport {\n  type AddResult,\n  type CommitDescription,\n  generateClient,\n  type MlsClientHandle,\n  type MlsGroupHandle,\n  type ReceivedMessage,\n} from './wasm/bridge.js';\nimport { initMls } from './wasm/loader.js';\n\nconst utf8 = new TextEncoder();\n\n/** The rfc_group_id keyed by its hex form (the per-group handle cache key). */\nconst gidHex = bytesToHex;\n\nexport interface EngineEnrollmentMaterial {\n  signatureKey: Uint8Array;\n  credential: Uint8Array;\n  capabilities: Uint8Array;\n}\n\n/**\n * The serialized MLS engine. Built once per (userId, deviceId). All crypto +\n * storage flows through here; `GroupMessaging` and `MessageDeliverySource` hold\n * the SAME instance so one MLS identity backs enroll + group ops + delivery.\n */\nexport class MlsEngine {\n  private readonly groups = new Map<string, MlsGroupHandle>();\n  private chain: Promise<unknown> = Promise.resolve();\n\n  private constructor(\n    readonly userId: string,\n    readonly deviceId: string,\n    private readonly client: MlsClientHandle,\n    private readonly groupStore: GroupStateStorage,\n    private readonly kpStore: KeyPackageStorage,\n  ) {}\n\n  /**\n   * Build the engine: init the WASM, hydrate the durable stores into the sync\n   * caches, generate (or restore) the device client. Idempotent restore: the\n   * persisted signature keypair keeps the SAME MLS signing identity across\n   * reloads; the group-state cache makes already-joined groups reloadable.\n   */\n  static async create(opts: {\n    userId: string;\n    deviceId: string;\n    groupStore: GroupStateStorage;\n    kpStore: KeyPackageStorage;\n    sigStore: SignatureKeyStore;\n  }): Promise<MlsEngine> {\n    await initMls();\n    // Hydrate the durable state into the sync caches BEFORE generateClient so a\n    // restart sees its persisted groups + key-package secrets.\n    await Promise.all([opts.groupStore.hydrate(), opts.kpStore.hydrate()]);\n    const persistedKeypair = await opts.sigStore.load(opts.userId);\n    const idBytes = utf8.encode(opts.deviceId);\n    const client = generateClient(idBytes, opts.groupStore, opts.kpStore, persistedKeypair);\n    // Persist the (possibly freshly minted) signature keypair so the next reload\n    // restores the SAME identity.\n    if (!persistedKeypair) {\n      await opts.sigStore.save(opts.userId, client.signatureKeypair());\n    }\n    return new MlsEngine(opts.userId, opts.deviceId, client, opts.groupStore, opts.kpStore);\n  }\n\n  /** Serialize an engine op onto the chain so the critical section is exclusive. */\n  private enqueue<T>(fn: () => T | Promise<T>): Promise<T> {\n    const run = this.chain.then(fn, fn);\n    // Keep the chain alive but swallow rejections so one failure doesn't poison\n    // every later op (each caller still sees its own rejection via `run`).\n    this.chain = run.then(\n      () => undefined,\n      () => undefined,\n    );\n    return run;\n  }\n\n  /** Flush both storage caches durably (the post-mutation durability boundary). */\n  private async flush(): Promise<void> {\n    await Promise.all([this.groupStore.flush(), this.kpStore.flush()]);\n  }\n\n  // ── Enroll material / key packages ──\n\n  enrollmentMaterial(): Promise<EngineEnrollmentMaterial> {\n    return this.enqueue(() => this.client.enrollmentMaterial());\n  }\n\n  signaturePublicKey(): Promise<Uint8Array> {\n    return this.enqueue(() => this.client.signaturePublicKey());\n  }\n\n  generateKeyPackage(): Promise<Uint8Array> {\n    return this.enqueue(async () => {\n      const kp = this.client.generateKeyPackage();\n      // A generated key package stores its private bits via the kp store — flush.\n      await this.flush();\n      return kp;\n    });\n  }\n\n  // ── Group create / join / reload ──\n\n  /** Create a group; returns its rfc_group_id (the routing key). */\n  createGroup(): Promise<Uint8Array> {\n    return this.enqueue(async () => {\n      const group = this.client.createGroup();\n      const gid = group.groupId();\n      this.groups.set(gidHex(gid), group);\n      group.writeToStorage();\n      await this.flush();\n      return gid;\n    });\n  }\n\n  /** Join from a Welcome; returns the joined group's rfc_group_id. */\n  joinFromWelcome(welcome: Uint8Array): Promise<Uint8Array> {\n    return this.enqueue(async () => {\n      const group = this.client.joinGroup(welcome);\n      const gid = group.groupId();\n      this.groups.set(gidHex(gid), group);\n      group.writeToStorage();\n      await this.flush();\n      return gid;\n    });\n  }\n\n  /** The current applied epoch for a group (0 if unknown). */\n  epoch(rfcGroupId: Uint8Array): Promise<number> {\n    return this.enqueue(() => {\n      const g = this.handle(rfcGroupId);\n      return g ? g.currentEpoch() : 0;\n    });\n  }\n\n  // ── Membership commits (staged → applied/cleared by the rebase loop) ──\n\n  /** Stage a SINGLE atomic add+remove commit. Returns the AddResult (PENDING). */\n  commitChanges(\n    rfcGroupId: Uint8Array,\n    adds: Uint8Array[],\n    removeMemberIds: Uint8Array[],\n  ): Promise<AddResult> {\n    return this.enqueue(() => {\n      const g = this.requireHandle(rfcGroupId);\n      return g.commitChanges(adds, removeMemberIds);\n    });\n  }\n\n  /** Apply the staged commit (advance the epoch). Only after a server-accept. */\n  applyPendingCommit(rfcGroupId: Uint8Array): Promise<void> {\n    return this.enqueue(async () => {\n      const g = this.requireHandle(rfcGroupId);\n      g.applyPendingCommit();\n      g.writeToStorage();\n      await this.flush();\n    });\n  }\n\n  /** Discard the staged commit (the 409-rebase path). */\n  clearPendingCommit(rfcGroupId: Uint8Array): Promise<void> {\n    return this.enqueue(() => {\n      const g = this.handle(rfcGroupId);\n      if (g?.hasPendingCommit()) g.clearPendingCommit();\n    });\n  }\n\n  // ── Application messages ──\n\n  /** Encrypt a plaintext at the current epoch → PrivateMessage bytes. */\n  encryptApplication(rfcGroupId: Uint8Array, plaintext: Uint8Array): Promise<Uint8Array> {\n    return this.enqueue(async () => {\n      const g = this.requireHandle(rfcGroupId);\n      const ct = g.encryptApplicationMessage(plaintext);\n      // The sender ratchet advanced — checkpoint.\n      g.writeToStorage();\n      await this.flush();\n      return ct;\n    });\n  }\n\n  /**\n   * Process an incoming MLSMessage (decrypt application / apply commit). Returns\n   * the normalized ReceivedMessage. `describeIncomingCommit` could gate a commit\n   * before applying when the server fans a declaration; today the live server\n   * does not, so we process directly (parity with the iOS nil-declaration path).\n   */\n  processIncoming(rfcGroupId: Uint8Array, blob: Uint8Array): Promise<ReceivedMessage> {\n    return this.enqueue(async () => {\n      const g = this.requireHandle(rfcGroupId);\n      const received = g.processIncomingMessage(blob);\n      // A commit/decrypt mutated state — checkpoint before the host acks.\n      g.writeToStorage();\n      await this.flush();\n      return received;\n    });\n  }\n\n  /** Inspect a commit WITHOUT applying (the reconciliation gate's crypto-truth). */\n  describeIncomingCommit(rfcGroupId: Uint8Array, commit: Uint8Array): Promise<CommitDescription> {\n    return this.enqueue(() => this.requireHandle(rfcGroupId).describeIncomingCommit(commit));\n  }\n\n  /** Persist the current group state (explicit checkpoint). */\n  writeToStorage(rfcGroupId: Uint8Array): Promise<void> {\n    return this.enqueue(async () => {\n      const g = this.handle(rfcGroupId);\n      if (g) {\n        g.writeToStorage();\n        await this.flush();\n      }\n    });\n  }\n\n  // ── Handle resolution ──\n\n  /** Resolve (or reload from storage) the handle for a group, or undefined. */\n  private handle(rfcGroupId: Uint8Array): MlsGroupHandle | undefined {\n    const key = gidHex(rfcGroupId);\n    const cached = this.groups.get(key);\n    if (cached) return cached;\n    // Try to reload from the hydrated group-state cache (restart-safe).\n    try {\n      const g = this.client.loadGroup(rfcGroupId);\n      this.groups.set(key, g);\n      return g;\n    } catch {\n      return undefined;\n    }\n  }\n\n  private requireHandle(rfcGroupId: Uint8Array): MlsGroupHandle {\n    const g = this.handle(rfcGroupId);\n    if (!g) throw new Error(`MLS group not loaded: ${gidHex(rfcGroupId)}`);\n    return g;\n  }\n}\n","// The group registry — maps rfc_group_id ↔ the resolved MessagingGroup and\n// drives the observable chat list. Web mirror of the iOS GroupRegistry: a SET\n// change (register-new / remove / hydrate) publishes a fresh [Chat] snapshot;\n// an in-place epoch bump does NOT (a chatty group must not invalidate the list).\n\nimport type { Chat } from './chat.js';\nimport type { MessagingGroup } from './group-messaging.js';\nimport type { GroupCatalog } from './history.js';\n\n/** A pointer-stable Chat factory: one Chat per rfc_group_id. */\nexport type ChatFactory = (group: MessagingGroup) => Chat;\n\nexport class GroupRegistry {\n  private readonly byRfc = new Map<string, MessagingGroup>();\n  private catalog: GroupCatalog | null = null;\n  private chatFactory: ChatFactory | null = null;\n  private onListChange: ((chats: Chat[]) => void) | null = null;\n\n  /** Wire the observable chat-list sink + the pointer-stable Chat factory, then\n   * replay the current set so a sink attached after groups loaded reflects them. */\n  attachChatList(onListChange: (chats: Chat[]) => void, factory: ChatFactory): void {\n    this.onListChange = onListChange;\n    this.chatFactory = factory;\n    this.publish();\n  }\n\n  /** Hydrate from the durable catalog (live entries win — fresher epoch). */\n  async attachCatalog(catalog: GroupCatalog): Promise<void> {\n    this.catalog = catalog;\n    let changed = false;\n    for (const c of await catalog.all()) {\n      if (!this.byRfc.has(c.rfcGroupId)) {\n        this.byRfc.set(c.rfcGroupId, {\n          displayId: c.displayId,\n          rfcGroupId: c.rfcGroupId,\n          currentEpoch: c.currentEpoch,\n          ownerUserId: c.ownerUserId,\n          directKey: c.directKey,\n          name: c.name,\n        });\n        changed = true;\n      }\n    }\n    if (changed) this.publish();\n  }\n\n  register(group: MessagingGroup): void {\n    const isNew = !this.byRfc.has(group.rfcGroupId);\n    this.byRfc.set(group.rfcGroupId, group);\n    void this.persist(group);\n    if (isNew) this.publish();\n  }\n\n  remove(rfcGroupId: string): void {\n    if (!this.byRfc.has(rfcGroupId)) return;\n    this.byRfc.delete(rfcGroupId);\n    if (this.catalog) void this.catalog.remove(rfcGroupId);\n    this.publish();\n  }\n\n  group(rfcGroupId: string): MessagingGroup | undefined {\n    return this.byRfc.get(rfcGroupId);\n  }\n\n  /** The single known group, if exactly one (the wire-gap routing fallback). */\n  soleGroup(): MessagingGroup | undefined {\n    return this.byRfc.size === 1 ? this.byRfc.values().next().value : undefined;\n  }\n\n  all(): MessagingGroup[] {\n    return [...this.byRfc.values()];\n  }\n\n  /** Advance a cached epoch (after a processed commit). Does NOT publish (the\n   * group SET is unchanged — only metadata). */\n  bumpEpoch(rfcGroupId: string, epoch: number): void {\n    const g = this.byRfc.get(rfcGroupId);\n    if (!g) return;\n    const bumped = { ...g, currentEpoch: epoch };\n    this.byRfc.set(rfcGroupId, bumped);\n    void this.persist(bumped);\n  }\n\n  private publish(): void {\n    const factory = this.chatFactory;\n    if (!this.onListChange || !factory) return;\n    const chats = this.all().map((g) => factory(g));\n    this.onListChange(chats);\n  }\n\n  private async persist(group: MessagingGroup): Promise<void> {\n    if (!this.catalog) return;\n    try {\n      await this.catalog.upsert({\n        displayId: group.displayId,\n        rfcGroupId: group.rfcGroupId,\n        currentEpoch: group.currentEpoch,\n        ownerUserId: group.ownerUserId,\n        directKey: group.directKey,\n        name: group.name,\n      });\n    } catch {\n      // best-effort persistence — never blocks the live path\n    }\n  }\n}\n","// The persistence layer for web messaging — the web mirror of the iOS\n// Keychain-sealed MLS stores (MessagingGroupStateStorage / KeyPackageStorage /\n// MessagingDeviceIDStore / MessagingSignatureKeyStore / MessageStore /\n// GroupCatalog).\n//\n// The CRITICAL contract (src/wasm.rs §Storage): mls-rs calls IGroupStateStorage\n// / IKeyPackageStorage methods SYNCHRONOUSLY inside the engine's locked\n// critical section. So those are backed by an in-memory write-through cache\n// (sync reads/writes) and flushed to a durable, encrypted-at-rest backend\n// (IndexedDB + WebCrypto AES-GCM) ASYNCHRONOUSLY, OUTSIDE the engine call. The\n// engine never awaits I/O; the host (the engine wrapper) awaits the flush after\n// each mutating op so an acked message is always durable.\n//\n// At-rest encryption: a per-device AES-GCM key, non-extractable, kept in\n// IndexedDB as a CryptoKey (browsers persist CryptoKey objects in IDB without\n// exposing raw bytes — the web analogue of the iOS Keychain seal key). In Node\n// (vitest / SSR) there is no IndexedDB; a pure in-memory durable backend stands\n// in (the crypto smoke needs durability WITHIN a process, not across reloads).\n\nimport { bytesToHex } from './util.js';\nimport type { IGroupStateStorage, IKeyPackageStorage } from './wasm/bridge.js';\n\n// ─── Durable KV backend (IndexedDB in browser, memory in Node) ──────────────\n\n/** A namespaced async key→bytes store. Values are sealed before write. */\nexport interface DurableKV {\n  get(key: string): Promise<Uint8Array | undefined>;\n  set(key: string, value: Uint8Array): Promise<void>;\n  delete(key: string): Promise<void>;\n  /** All keys under a prefix (for hydrating a store on launch). */\n  keys(prefix: string): Promise<string[]>;\n}\n\nconst hasIndexedDB = (): boolean =>\n  typeof indexedDB !== 'undefined' && typeof crypto !== 'undefined' && !!crypto.subtle;\n\n/** A tight, non-shared ArrayBuffer copy of a byte view (WebCrypto BufferSource). */\nfunction copyToArrayBuffer(view: Uint8Array): ArrayBuffer {\n  const out = new ArrayBuffer(view.byteLength);\n  new Uint8Array(out).set(view);\n  return out;\n}\n\n// ── In-memory backend (Node/SSR/tests) ──────────────────────────────────────\n\nclass MemoryKV implements DurableKV {\n  private readonly map = new Map<string, Uint8Array>();\n  get(key: string): Promise<Uint8Array | undefined> {\n    return Promise.resolve(this.map.get(key));\n  }\n  set(key: string, value: Uint8Array): Promise<void> {\n    this.map.set(key, value.slice());\n    return Promise.resolve();\n  }\n  delete(key: string): Promise<void> {\n    this.map.delete(key);\n    return Promise.resolve();\n  }\n  keys(prefix: string): Promise<string[]> {\n    return Promise.resolve([...this.map.keys()].filter((k) => k.startsWith(prefix)));\n  }\n}\n\n// ── IndexedDB backend (browser) with WebCrypto AES-GCM seal at rest ─────────\n\nconst DB_NAME = 'palbe.messaging';\nconst STORE = 'kv';\nconst KEY_STORE = 'keys';\nconst SEAL_KEY_ID = 'seal-key-v1';\n\nfunction openDb(): Promise<IDBDatabase> {\n  return new Promise((resolve, reject) => {\n    const req = indexedDB.open(DB_NAME, 1);\n    req.onupgradeneeded = () => {\n      const db = req.result;\n      if (!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE);\n      if (!db.objectStoreNames.contains(KEY_STORE)) db.createObjectStore(KEY_STORE);\n    };\n    req.onsuccess = () => resolve(req.result);\n    req.onerror = () => reject(req.error);\n  });\n}\n\nfunction idbReq<T>(req: IDBRequest<T>): Promise<T> {\n  return new Promise((resolve, reject) => {\n    req.onsuccess = () => resolve(req.result);\n    req.onerror = () => reject(req.error);\n  });\n}\n\n/** Get-or-create the non-extractable AES-GCM seal key (persisted as a CryptoKey). */\nasync function getSealKey(db: IDBDatabase): Promise<CryptoKey> {\n  const existing = await idbReq(\n    db.transaction(KEY_STORE, 'readonly').objectStore(KEY_STORE).get(SEAL_KEY_ID),\n  );\n  if (existing) return existing as CryptoKey;\n  const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, false, [\n    'encrypt',\n    'decrypt',\n  ]);\n  // Storing a non-extractable CryptoKey keeps the raw bytes inside the browser's\n  // key store — the page can use it to seal/open but can never read it out.\n  await idbReq(db.transaction(KEY_STORE, 'readwrite').objectStore(KEY_STORE).put(key, SEAL_KEY_ID));\n  return key;\n}\n\nclass IndexedDbKV implements DurableKV {\n  private dbPromise: Promise<IDBDatabase> | null = null;\n  private keyPromise: Promise<CryptoKey> | null = null;\n\n  private db(): Promise<IDBDatabase> {\n    if (!this.dbPromise) this.dbPromise = openDb();\n    return this.dbPromise;\n  }\n  private async sealKey(): Promise<CryptoKey> {\n    if (!this.keyPromise) this.keyPromise = this.db().then(getSealKey);\n    return this.keyPromise;\n  }\n\n  private async seal(plain: Uint8Array): Promise<Uint8Array> {\n    const key = await this.sealKey();\n    const iv = crypto.getRandomValues(new Uint8Array(12));\n    const ct = new Uint8Array(\n      await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, copyToArrayBuffer(plain)),\n    );\n    const out = new Uint8Array(iv.length + ct.length);\n    out.set(iv, 0);\n    out.set(ct, iv.length);\n    return out;\n  }\n\n  private async open(sealed: Uint8Array): Promise<Uint8Array> {\n    const key = await this.sealKey();\n    const iv = copyToArrayBuffer(sealed.subarray(0, 12));\n    const ct = copyToArrayBuffer(sealed.subarray(12));\n    const pt = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ct);\n    return new Uint8Array(pt);\n  }\n\n  async get(k: string): Promise<Uint8Array | undefined> {\n    const db = await this.db();\n    const sealed = (await idbReq(db.transaction(STORE, 'readonly').objectStore(STORE).get(k))) as\n      | Uint8Array\n      | undefined;\n    if (!sealed) return undefined;\n    return this.open(sealed);\n  }\n  async set(k: string, v: Uint8Array): Promise<void> {\n    const db = await this.db();\n    const sealed = await this.seal(v);\n    await idbReq(db.transaction(STORE, 'readwrite').objectStore(STORE).put(sealed, k));\n  }\n  async delete(k: string): Promise<void> {\n    const db = await this.db();\n    await idbReq(db.transaction(STORE, 'readwrite').objectStore(STORE).delete(k));\n  }\n  async keys(prefix: string): Promise<string[]> {\n    const db = await this.db();\n    const all = (await idbReq(\n      db.transaction(STORE, 'readonly').objectStore(STORE).getAllKeys(),\n    )) as IDBValidKey[];\n    return all.map(String).filter((k) => k.startsWith(prefix));\n  }\n}\n\n/** Build the durable KV for this environment (IndexedDB in browser, memory else). */\nexport function createDurableKV(): DurableKV {\n  return hasIndexedDB() ? new IndexedDbKV() : new MemoryKV();\n}\n\n// ─── Byte / hex helpers ──────────────────────────────────────────────────────\n\nfunction bytesKey(prefix: string, id: Uint8Array): string {\n  // Hex the id bytes so any blob can be a string key.\n  return prefix + bytesToHex(id);\n}\n\n// ─── Sync write-through cache (the IGroupStateStorage / IKeyPackageStorage seam)\n\n/**\n * The synchronous group-state storage mls-rs calls inside the engine. Reads/\n * writes hit an in-memory cache (sync); a durable flush to the encrypted KV is\n * scheduled and awaited by the engine wrapper OUTSIDE the engine call.\n *\n * Layout per group (keyed by hex(groupId)):\n *   state:<gid>            → latest serialized group state\n *   epoch:<gid>:<epochId>  → a stored prior-epoch record\n *   maxEpoch:<gid>         → highest stored prior-epoch id (decimal string bytes)\n */\nexport class GroupStateStorage implements IGroupStateStorage {\n  // In-memory authoritative cache (the engine reads/writes this synchronously).\n  private readonly stateCache = new Map<string, Uint8Array>();\n  private readonly epochCache = new Map<string, Uint8Array>();\n  private readonly maxEpochCache = new Map<string, bigint>();\n  // Keys touched since the last flush (durable write queue).\n  private readonly dirty = new Set<string>();\n\n  constructor(private readonly kv: DurableKV) {}\n\n  // ── sync engine seam ──\n  state(groupId: Uint8Array): Uint8Array | undefined {\n    return this.stateCache.get(bytesKey('', groupId));\n  }\n  epoch(groupId: Uint8Array, epochId: bigint): Uint8Array | undefined {\n    return this.epochCache.get(`${bytesKey('', groupId)}:${epochId}`);\n  }\n  write(\n    groupId: Uint8Array,\n    groupState: Uint8Array,\n    epochInserts: { id: bigint; data: Uint8Array }[],\n    epochUpdates: { id: bigint; data: Uint8Array }[],\n  ): void {\n    const gid = bytesKey('', groupId);\n    this.stateCache.set(gid, groupState.slice());\n    this.dirty.add(`state:${gid}`);\n    let max = this.maxEpochCache.get(gid) ?? -1n;\n    for (const rec of [...epochInserts, ...epochUpdates]) {\n      this.epochCache.set(`${gid}:${rec.id}`, rec.data.slice());\n      this.dirty.add(`epoch:${gid}:${rec.id}`);\n      if (rec.id > max) max = rec.id;\n    }\n    if (max >= 0n) {\n      this.maxEpochCache.set(gid, max);\n      this.dirty.add(`maxEpoch:${gid}`);\n    }\n  }\n  maxEpochId(groupId: Uint8Array): bigint | undefined {\n    return this.maxEpochCache.get(bytesKey('', groupId));\n  }\n\n  // ── async durable flush (called by the engine wrapper after a mutating op) ──\n  async flush(): Promise<void> {\n    if (this.dirty.size === 0) return;\n    const pending = [...this.dirty];\n    this.dirty.clear();\n    await Promise.all(\n      pending.map(async (key) => {\n        if (key.startsWith('state:')) {\n          const gid = key.slice('state:'.length);\n          const v = this.stateCache.get(gid);\n          if (v) await this.kv.set(`gss:state:${gid}`, v);\n        } else if (key.startsWith('epoch:')) {\n          const rest = key.slice('epoch:'.length);\n          const v = this.epochCache.get(rest);\n          if (v) await this.kv.set(`gss:epoch:${rest}`, v);\n        } else if (key.startsWith('maxEpoch:')) {\n          const gid = key.slice('maxEpoch:'.length);\n          const max = this.maxEpochCache.get(gid);\n          if (max != null) await this.kv.set(`gss:maxEpoch:${gid}`, encodeBigint(max));\n        }\n      }),\n    );\n  }\n\n  /** Hydrate the in-memory cache from the durable KV (call before generateClient). */\n  async hydrate(): Promise<void> {\n    const keys = await this.kv.keys('gss:');\n    for (const k of keys) {\n      const v = await this.kv.get(k);\n      if (!v) continue;\n      if (k.startsWith('gss:state:')) {\n        this.stateCache.set(k.slice('gss:state:'.length), v);\n      } else if (k.startsWith('gss:epoch:')) {\n        this.epochCache.set(k.slice('gss:epoch:'.length), v);\n      } else if (k.startsWith('gss:maxEpoch:')) {\n        this.maxEpochCache.set(k.slice('gss:maxEpoch:'.length), decodeBigint(v));\n      }\n    }\n  }\n\n  async wipe(): Promise<void> {\n    this.stateCache.clear();\n    this.epochCache.clear();\n    this.maxEpochCache.clear();\n    this.dirty.clear();\n    for (const k of await this.kv.keys('gss:')) await this.kv.delete(k);\n  }\n}\n\n/**\n * The synchronous key-package secret storage mls-rs calls. Secret-bearing (HPKE\n * private keys) — sealed at rest by the KV. Same sync-cache + async-flush shape.\n */\nexport class KeyPackageStorage implements IKeyPackageStorage {\n  private readonly cache = new Map<string, Uint8Array>();\n  private readonly dirtySet = new Set<string>();\n  private readonly dirtyDelete = new Set<string>();\n\n  constructor(private readonly kv: DurableKV) {}\n\n  // ── sync engine seam ──\n  delete(id: Uint8Array): void {\n    const k = bytesKey('', id);\n    this.cache.delete(k);\n    this.dirtyDelete.add(k);\n    this.dirtySet.delete(k);\n  }\n  insert(id: Uint8Array, data: Uint8Array): void {\n    const k = bytesKey('', id);\n    this.cache.set(k, data.slice());\n    this.dirtySet.add(k);\n    this.dirtyDelete.delete(k);\n  }\n  get(id: Uint8Array): Uint8Array | undefined {\n    return this.cache.get(bytesKey('', id));\n  }\n\n  // ── async durable flush ──\n  async flush(): Promise<void> {\n    if (this.dirtySet.size === 0 && this.dirtyDelete.size === 0) return;\n    const sets = [...this.dirtySet];\n    const dels = [...this.dirtyDelete];\n    this.dirtySet.clear();\n    this.dirtyDelete.clear();\n    await Promise.all([\n      ...sets.map((k) => {\n        const v = this.cache.get(k);\n        return v ? this.kv.set(`kps:${k}`, v) : Promise.resolve();\n      }),\n      ...dels.map((k) => this.kv.delete(`kps:${k}`)),\n    ]);\n  }\n\n  async hydrate(): Promise<void> {\n    for (const k of await this.kv.keys('kps:')) {\n      const v = await this.kv.get(k);\n      if (v) this.cache.set(k.slice('kps:'.length), v);\n    }\n  }\n\n  async wipe(): Promise<void> {\n    this.cache.clear();\n    this.dirtySet.clear();\n    this.dirtyDelete.clear();\n    for (const k of await this.kv.keys('kps:')) await this.kv.delete(k);\n  }\n}\n\nfunction encodeBigint(n: bigint): Uint8Array {\n  return new TextEncoder().encode(n.toString());\n}\nfunction decodeBigint(b: Uint8Array): bigint {\n  return BigInt(new TextDecoder().decode(b));\n}\n\n// ─── Device-id + signature-keypair stores (small singletons) ────────────────\n\nconst enc = new TextEncoder();\nconst dec = new TextDecoder();\n\n/** Persisted server-minted device id, keyed by user id (enroll idempotency). */\nexport class DeviceIdStore {\n  constructor(private readonly kv: DurableKV) {}\n  async load(userId: string): Promise<string | undefined> {\n    const v = await this.kv.get(`devid:${userId}`);\n    return v ? dec.decode(v) : undefined;\n  }\n  async save(userId: string, deviceId: string): Promise<void> {\n    await this.kv.set(`devid:${userId}`, enc.encode(deviceId));\n  }\n  async clear(userId: string): Promise<void> {\n    await this.kv.delete(`devid:${userId}`);\n  }\n}\n\n/** Persisted STABLE signature keypair bytes, keyed by user id (same MLS identity). */\nexport class SignatureKeyStore {\n  constructor(private readonly kv: DurableKV) {}\n  async load(userId: string): Promise<Uint8Array | undefined> {\n    return this.kv.get(`sigkey:${userId}`);\n  }\n  async save(userId: string, keypair: Uint8Array): Promise<void> {\n    await this.kv.set(`sigkey:${userId}`, keypair);\n  }\n}\n","// The delete-for-me suppression store — the web mirror of iOS `SuppressionStore`.\n//\n// delete-for-me is a PURELY LOCAL, per-device, unsynced \"hide this message\"\n// intent: NO wire, NO attribution, no server contact. It is a persisted per-chat\n// `Set<suppressionKey>` where `suppressionKey` is the message's `client_msg_id`\n// when present, else `seq:<server_seq>` for legacy messages (which lack a\n// client_msg_id but are always server-acked, so `server_seq` is stable). At\n// render time a message whose key is in the set is OMITTED from the transcript.\n//\n// Sealed at rest by the same durable KV (IndexedDB + WebCrypto AES-GCM in the\n// browser) that seals the message store — so the suppression intent survives a\n// cold launch and a for-me'd message stays hidden after reload (the reload-parity\n// boundary for delete-for-me, mirroring the message store's reaction/edit/delete\n// re-fold parity).\n\nimport type { DurableKV } from './storage.js';\nimport { decodeUtf8, encodeUtf8 } from './util.js';\n\n/** Persist a per-chat delete-for-me suppression key set (keyed by rfcGroupId). */\nexport class SuppressionStore {\n  constructor(private readonly kv: DurableKV) {}\n\n  private key(rfcGroupId: string): string {\n    return `supp:${rfcGroupId}`;\n  }\n\n  /** Load the persisted suppression keys for a chat (empty array if none). */\n  async load(rfcGroupId: string): Promise<string[]> {\n    const raw = await this.kv.get(this.key(rfcGroupId));\n    if (!raw) return [];\n    try {\n      const parsed = JSON.parse(decodeUtf8(raw));\n      return Array.isArray(parsed) ? (parsed as string[]) : [];\n    } catch {\n      return [];\n    }\n  }\n\n  /** Persist the full suppression key set for a chat (deterministic order). */\n  async save(rfcGroupId: string, keys: string[]): Promise<void> {\n    const sorted = [...new Set(keys)].sort();\n    await this.kv.set(this.key(rfcGroupId), encodeUtf8(JSON.stringify(sorted)));\n  }\n\n  async wipe(): Promise<void> {\n    for (const k of await this.kv.keys('supp:')) await this.kv.delete(k);\n  }\n}\n","// The messaging coordinator — the web mirror of iOS MessagingCoordinator +\n// MessagingGroupState. Builds the engine/storage/delivery-source ONCE (lazily,\n// on first chat op after sign-in), implements the ChatBackend seam, mints\n// pointer-stable Chats (one per rfc id), and owns the observable chat list.\n//\n// Process-shared singleton (one runtime per browser tab), like the iOS shared\n// holder. Bound to ONE PalbeRuntime (the configured pb).\n\nimport type { PalbeRuntime } from '../runtime.js';\nimport { Chat, type ChatBackend, type ChatDraft, DELETED_DESCRIPTOR } from './chat.js';\nimport type { AnchorTriple } from './deadline-calculator.js';\nimport { DeleteFold } from './delete-fold.js';\nimport { type IncomingMessage, MessageDeliverySource, MessageHub } from './delivery-source.js';\nimport { DisappearingStore } from './disappearing.js';\nimport { type AuthorResolution, EditFold } from './edit-fold.js';\nimport {\n  type ExpirySpec,\n  GroupMessaging,\n  type MentionRange,\n  type MessagingGroup,\n  type ReplyRef,\n  resolveReply,\n} from './group-messaging.js';\nimport { GroupCatalog, MessageStore, type StoredMessage } from './history.js';\nimport { enrollDevice, listDevices } from './keydir.js';\nimport { MentionElevationStore } from './mention-elevation.js';\nimport { normalizeMentionRangesUtf16 } from './mention-ranges.js';\nimport { MlsEngine } from './mls-engine.js';\nimport { ReactionFold } from './reaction-fold.js';\nimport { GroupRegistry } from './registry.js';\nimport {\n  createDurableKV,\n  DeviceIdStore,\n  type DurableKV,\n  GroupStateStorage,\n  KeyPackageStorage,\n  SignatureKeyStore,\n} from './storage.js';\nimport { SuppressionStore } from './suppression.js';\nimport { TimerFold } from './timer-fold.js';\nimport type {\n  ChatMember,\n  ChatMessage,\n  NotifyScope,\n  ResolvedMention,\n  ResolvedReply,\n  SentReceipt,\n  UnreadView,\n  Unsubscribe,\n} from './types.js';\nimport { directKey as makeDirectKey, mintDeviceId } from './util.js';\n\ninterface Resolved {\n  engine: MlsEngine;\n  groups: GroupMessaging;\n  source: MessageDeliverySource;\n  hub: MessageHub;\n  messageStore: MessageStore;\n  catalog: GroupCatalog;\n  registry: GroupRegistry;\n  deviceId: string;\n  userId: string;\n}\n\nexport class MessagingCoordinator implements ChatBackend {\n  private readonly kv: DurableKV;\n  private readonly deviceStore: DeviceIdStore;\n  private readonly sigStore: SignatureKeyStore;\n  private readonly groupStore: GroupStateStorage;\n  private readonly kpStore: KeyPackageStorage;\n  private readonly suppressionStore: SuppressionStore;\n  private readonly elevationStore: MentionElevationStore;\n  private readonly disappearingStore: DisappearingStore;\n  private readonly registry = new GroupRegistry();\n\n  private resolved: Resolved | null = null;\n  private resolvePromise: Promise<Resolved> | null = null;\n\n  // Pointer-stable Chat cache (one per rfc id) + the observable chat list.\n  private readonly chatByRfc = new Map<string, Chat>();\n  private chatList: Chat[] = [];\n  private readonly listListeners = new Set<() => void>();\n\n  constructor(private readonly rt: PalbeRuntime) {\n    this.kv = createDurableKV();\n    this.deviceStore = new DeviceIdStore(this.kv);\n    this.sigStore = new SignatureKeyStore(this.kv);\n    this.groupStore = new GroupStateStorage(this.kv);\n    this.kpStore = new KeyPackageStorage(this.kv);\n    // The delete-for-me suppression store is durable-only (no engine) — build it\n    // eagerly so loadSuppressed/saveSuppressed work without forcing MLS resolution.\n    this.suppressionStore = new SuppressionStore(this.kv);\n    // The self-elevation dedup store is durable-only (no engine) — build it eagerly so\n    // loadElevated/saveElevated work without forcing MLS resolution (mirrors suppression).\n    this.elevationStore = new MentionElevationStore(this.kv);\n    // The disappearing/TTL purge store is durable-only (no engine) — build it eagerly so\n    // the tombstone/purge/anchor seam works without forcing MLS resolution (T10).\n    this.disappearingStore = new DisappearingStore(this.kv);\n    // Wire the registry → observable chat list with the pointer-stable factory.\n    this.registry.attachChatList(\n      (chats) => {\n        this.chatList = chats;\n        this.emitList();\n      },\n      (group) => this.chatFor(group),\n    );\n  }\n\n  // ── ChatBackend identity ──\n\n  get selfUserId(): string {\n    const u = this.rt.auth.currentUser;\n    if (!u) throw new Error('not_signed_in');\n    return u.id;\n  }\n\n  // ── Public surface (used by the facade) ──\n\n  /** Self-enroll + start the delivery source (idempotent). The first chat op\n   * calls this implicitly; pb.messaging.start() is the opt-in warm-at-sign-in. */\n  async ensureEnrolled(): Promise<void> {\n    await this.resolve();\n  }\n\n  /** Open the ONE direct chat with userId. INSTANT + LOCAL (no network); the\n   * group materializes on the first send. Pointer-stable per peer pair. */\n  directChat(peerUserId: string): Chat {\n    const selfId = this.selfUserId;\n    const dk = makeDirectKey(selfId, peerUserId);\n    // If an active direct chat with this key already exists, return it.\n    for (const chat of this.chatByRfc.values()) {\n      if (chat.isDirect && chat.state === 'active') {\n        // best-effort: match the active group's direct key via the registry\n        const g = this.registry.all().find((x) => x.displayId === chat.id);\n        if (g?.directKey === dk) return chat;\n      }\n    }\n    const draft: ChatDraft = {\n      mode: { kind: 'direct', peerUserId },\n      reservedId: `draft:${dk}`,\n    };\n    // Cache the draft under its reserved id so two opens converge.\n    const cached = this.chatByRfc.get(draft.reservedId);\n    if (cached) return cached;\n    const chat = new Chat({ draft, kind: 'direct', backend: this });\n    this.chatByRfc.set(draft.reservedId, chat);\n    // Fire-and-forget enroll so a peer's DM/Welcome can drain in.\n    void this.ensureEnrolled().catch(() => {});\n    return chat;\n  }\n\n  /** Open a multi-party group chat (LOCAL + LAZY; created on first send). */\n  groupChat(members: string[] = []): Chat {\n    const draft: ChatDraft = {\n      mode: { kind: 'group', members },\n      reservedId: `draft:group:${crypto.randomUUID()}`,\n    };\n    const chat = new Chat({ draft, kind: 'group', backend: this });\n    this.chatByRfc.set(draft.reservedId, chat);\n    void this.ensureEnrolled().catch(() => {});\n    return chat;\n  }\n\n  /** Look up an active chat by id (grp_ display id). */\n  chatById(id: string): Chat | null {\n    const g = this.registry.all().find((x) => x.displayId === id);\n    return g ? this.chatFor(g) : (this.chatByRfc.get(id) ?? null);\n  }\n\n  /** The observable chat list (active chats only). */\n  get chats(): readonly Chat[] {\n    void this.ensureEnrolled().catch(() => {});\n    return this.chatList;\n  }\n\n  onChatsChange(cb: () => void): Unsubscribe {\n    this.listListeners.add(cb);\n    void this.ensureEnrolled().catch(() => {});\n    return () => this.listListeners.delete(cb);\n  }\n\n  private emitList(): void {\n    for (const cb of this.listListeners) cb();\n  }\n\n  /** Pointer-stable Chat for a group (one per rfc id). */\n  private chatFor(group: MessagingGroup): Chat {\n    const existing = this.chatByRfc.get(group.rfcGroupId);\n    if (existing) return existing;\n    const chat = new Chat({\n      group,\n      kind: group.directKey ? 'direct' : 'group',\n      backend: this,\n    });\n    this.chatByRfc.set(group.rfcGroupId, chat);\n    return chat;\n  }\n\n  // ── Resolution (build-once) ──\n\n  private resolve(): Promise<Resolved> {\n    if (this.resolved) return Promise.resolve(this.resolved);\n    if (this.resolvePromise) return this.resolvePromise;\n    this.resolvePromise = this.buildResolved();\n    return this.resolvePromise;\n  }\n\n  private async buildResolved(): Promise<Resolved> {\n    const userId = this.selfUserId;\n    // Resolve (or mint + persist) the device id BEFORE building the engine — the\n    // engine's MLS credential identity IS the device id (SP-1.6).\n    const deviceId = (await this.deviceStore.load(userId)) ?? mintDeviceId();\n\n    const engine = await MlsEngine.create({\n      userId,\n      deviceId,\n      groupStore: this.groupStore,\n      kpStore: this.kpStore,\n      sigStore: this.sigStore,\n    });\n\n    const messageStore = new MessageStore(this.kv);\n    const catalog = new GroupCatalog(this.kv);\n    const hub = new MessageHub();\n    const groups = new GroupMessaging(this.rt, engine, userId, deviceId, messageStore);\n    const source = new MessageDeliverySource(\n      this.rt,\n      engine,\n      hub,\n      this.registry,\n      messageStore,\n      deviceId,\n      userId,\n    );\n\n    // Enroll this device (idempotent — persists the id, publishes key packages).\n    await enrollDevice(this.rt, engine, this.deviceStore, {});\n\n    // Hydrate the registry from the durable catalog BEFORE the first pump.\n    await this.registry.attachCatalog(catalog);\n\n    const resolved: Resolved = {\n      engine,\n      groups,\n      source,\n      hub,\n      messageStore,\n      catalog,\n      registry: this.registry,\n      deviceId,\n      userId,\n    };\n    this.resolved = resolved;\n\n    // Start the live delivery source (subscribe wake + initial drain).\n    await source.start();\n    return resolved;\n  }\n\n  // ── ChatBackend impl ──\n\n  async materialize(draft: ChatDraft): Promise<MessagingGroup> {\n    const r = await this.resolve();\n    let group: MessagingGroup;\n    if (draft.mode.kind === 'direct') {\n      group = await r.groups.getOrCreateDirect(draft.mode.peerUserId);\n    } else {\n      group = await r.groups.createGroup();\n      for (const userId of draft.mode.members) {\n        await r.groups.addMember(group, userId);\n      }\n    }\n    void r.catalog.upsert({\n      displayId: group.displayId,\n      rfcGroupId: group.rfcGroupId,\n      currentEpoch: group.currentEpoch,\n      ownerUserId: group.ownerUserId,\n      directKey: group.directKey,\n      name: group.name,\n    });\n    return group;\n  }\n\n  async sendText(\n    group: MessagingGroup,\n    text: string,\n    replyTo?: ReplyRef | null,\n    bodyRanges?: MentionRange[] | null,\n    expiry?: ExpirySpec | null,\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const r = await this.resolve();\n    // Disappearing T10: forward the per-message/default-stamped `expiry` to the wire.\n    // Dropping it here (the facade declared only 4 params) silently stripped the\n    // per-message TTL from the ciphertext, so a recipient decoded a plain text and\n    // never armed — invisible on the sender's own screen (it arms from effectiveExpiry\n    // directly) and missed by unit tests that drove groups.sendText directly. Caught by\n    // the live 2-browser A↔B gate; locked by the coordinator-forwarding regression test.\n    return r.groups.sendText(group, text, replyTo, bodyRanges, expiry);\n  }\n\n  async sendReaction(\n    group: MessagingGroup,\n    args: { clientMsgId: string; targetClientMsgId: string; emoji: string; op: 'add' | 'remove' },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const r = await this.resolve();\n    return r.groups.sendReaction(group, args);\n  }\n\n  async sendEdit(\n    group: MessagingGroup,\n    args: {\n      clientMsgId: string;\n      targetClientMsgId: string;\n      newText: string;\n      bodyRanges?: MentionRange[] | null;\n    },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const r = await this.resolve();\n    return r.groups.sendEdit(group, args);\n  }\n\n  async sendDelete(\n    group: MessagingGroup,\n    args: { clientMsgId: string; targetClientMsgId: string },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const r = await this.resolve();\n    return r.groups.sendDelete(group, args);\n  }\n\n  async sendTimerSet(\n    group: MessagingGroup,\n    args: { clientMsgId: string; ttlSeconds: number | null; start: 'send' | 'read' },\n  ): Promise<{ receipt: SentReceipt; clientMsgId: string }> {\n    const r = await this.resolve();\n    return r.groups.sendTimerSet(group, args);\n  }\n\n  /** Load this chat's persisted delete-for-me suppression keys (durable-only). */\n  loadSuppressed(group: MessagingGroup): Promise<string[]> {\n    return this.suppressionStore.load(group.rfcGroupId);\n  }\n\n  /** Persist this chat's delete-for-me suppression keys (durable-only, no wire). */\n  saveSuppressed(group: MessagingGroup, keys: string[]): Promise<void> {\n    return this.suppressionStore.save(group.rfcGroupId, keys);\n  }\n\n  /** Load this chat's persisted self-elevation dedup keys (durable-only). */\n  loadElevated(group: MessagingGroup): Promise<string[]> {\n    return this.elevationStore.load(group.rfcGroupId);\n  }\n\n  /** Persist this chat's self-elevation dedup keys (durable-only, no wire). */\n  saveElevated(group: MessagingGroup, keys: string[]): Promise<void> {\n    return this.elevationStore.save(group.rfcGroupId, keys);\n  }\n\n  // ── Disappearing / TTL seam (durable-only, no wire) ──\n\n  tombstonedSeqs(group: MessagingGroup): Promise<Set<number>> {\n    return this.disappearingStore.tombstonedSeqs(group.rfcGroupId);\n  }\n\n  purgedClientMsgIds(group: MessagingGroup): Promise<Set<string>> {\n    return this.disappearingStore.purgedClientMsgIds(group.rfcGroupId);\n  }\n\n  anchor(group: MessagingGroup, clientMsgId: string): Promise<AnchorTriple | null> {\n    return this.disappearingStore.anchor(group.rfcGroupId, clientMsgId);\n  }\n\n  writeAnchorOnce(group: MessagingGroup, clientMsgId: string, a: AnchorTriple): Promise<void> {\n    return this.disappearingStore.writeAnchorOnce(group.rfcGroupId, clientMsgId, a);\n  }\n\n  tombstone(group: MessagingGroup, serverSeq: number, clientMsgId: string): Promise<void> {\n    return this.disappearingStore.tombstone(group.rfcGroupId, serverSeq, clientMsgId);\n  }\n\n  async history(group: MessagingGroup, limit: number, before?: number): Promise<ChatMessage[]> {\n    const r = await this.resolve();\n    const rows = await r.messageStore.history(group.rfcGroupId, limit, before);\n    // Disappearing T10: the REAL cold-launch path passes the durable per-chat purge state\n    // so projectHistory excludes tombstoned seqs + resolves purged orphans + arms the chat\n    // default — the SAME pure function the reload-parity test drives (the M1 shared helper).\n    const tombstoned = await this.disappearingStore.tombstonedSeqs(group.rfcGroupId);\n    const purged = await this.disappearingStore.purgedClientMsgIds(group.rfcGroupId);\n    return projectHistory(group.displayId, rows, this.selfUserId, undefined, tombstoned, purged);\n  }\n\n  async members(group: MessagingGroup): Promise<ChatMember[]> {\n    const r = await this.resolve();\n    try {\n      const rows = await r.groups.listMembers(group.displayId);\n      // Dedup device rows → users.\n      const byUser = new Map<string, ChatMember>();\n      for (const row of rows) {\n        if (!byUser.has(row.user_id)) {\n          byUser.set(row.user_id, {\n            id: row.user_id,\n            userId: row.user_id,\n            displayName: null,\n            role: row.role,\n            isSelf: row.user_id === this.selfUserId,\n          });\n        }\n      }\n      return [...byUser.values()];\n    } catch {\n      return [];\n    }\n  }\n\n  async addMember(group: MessagingGroup, userId: string): Promise<void> {\n    const r = await this.resolve();\n    await r.groups.addMember(group, userId);\n  }\n\n  async removeMember(group: MessagingGroup, userId: string): Promise<void> {\n    const r = await this.resolve();\n    await r.groups.removeMember(group, userId);\n  }\n\n  async leave(group: MessagingGroup): Promise<void> {\n    const r = await this.resolve();\n    await r.groups.leaveGroup(group);\n    r.registry.remove(group.rfcGroupId);\n  }\n\n  registerActive(group: MessagingGroup): void {\n    this.registry.register(group);\n  }\n\n  setTyping(group: MessagingGroup, isTyping: boolean): void {\n    void this.resolve().then((r) => r.source.setTyping(group, isTyping));\n  }\n\n  async markRead(group: MessagingGroup, upToServerSeq: number): Promise<void> {\n    const r = await this.resolve();\n    await r.source.markRead(group, upToServerSeq);\n  }\n\n  // ── Server-metadata cluster: notify scope (mute) + unread ──\n\n  async setNotifyScope(group: MessagingGroup, scope: NotifyScope): Promise<NotifyScope> {\n    const r = await this.resolve();\n    return r.source.setNotifyScope(group, scope);\n  }\n\n  async getNotifyScope(group: MessagingGroup): Promise<NotifyScope> {\n    const r = await this.resolve();\n    return r.source.getNotifyScope(group);\n  }\n\n  async unread(group: MessagingGroup): Promise<UnreadView> {\n    const r = await this.resolve();\n    return r.source.unread(group);\n  }\n\n  subscribeLive(group: MessagingGroup, chat: Chat): Unsubscribe {\n    let offMsg: (() => void) | null = null;\n    let offConv: (() => void) | null = null;\n    let resolved: Resolved | null = null;\n    // The runtime resolves on a promise, so a component that mounts and unmounts\n    // inside one tick unsubscribes BEFORE this body runs. Wiring it up anyway\n    // would leave listeners nobody can drop and — the whole point of the\n    // departure frame — a device announcing itself on a topic no Chat is\n    // holding, with no unsubscribe left to take it down.\n    let cancelled = false;\n    void this.resolve().then((r) => {\n      if (cancelled) return;\n      resolved = r;\n      offMsg = r.hub.onMessage(group.displayId, (m: IncomingMessage) => {\n        void chat.ingestLive(m);\n      });\n      r.source.observeConversation(group);\n      offConv = r.hub.onConv(group.displayId, (e) => chat.applyConv(e.event, e.payload));\n    });\n    return () => {\n      cancelled = true;\n      offMsg?.();\n      offConv?.();\n      // The conv topic (and the presence heartbeat riding it) belongs to the\n      // group, not to one Chat — so it comes down only when the LAST live\n      // subscriber has left. Presence is broadcast-only with no server-side\n      // expiry: without this the departing device stays lit for every peer.\n      if (resolved && resolved.hub.convListenerCount(group.displayId) === 0) {\n        resolved.source.unobserveConversation(group);\n      }\n    };\n  }\n\n  async userIdForDevice(group: MessagingGroup, deviceId: string): Promise<string | null> {\n    const r = await this.resolve();\n    try {\n      const rows = await r.groups.listMembers(group.displayId);\n      return rows.find((m) => m.device_id === deviceId)?.user_id ?? null;\n    } catch {\n      return null;\n    }\n  }\n\n  // ── Trust (chat-scoped) ──\n\n  /** List a user's devices (used by safety-number computation). */\n  async listUserDevices(userId: string): Promise<string[]> {\n    const res = await listDevices(this.rt, userId);\n    return res.devices.map((d) => d.device_id);\n  }\n}\n\n/**\n * Project a page of stored rows → surfaced `ChatMessage[]`, page-local-folding\n * reaction rows into their targets' tallies (the web mirror of the iOS\n * `MessagingCoordinator.history()` reaction-vs-bubble loop).\n *\n * A `'reaction'`/`'edit'`/`'delete'` row NEVER becomes a bubble — each folds into a\n * page-local `ReactionFold`/`EditFold`/`DeleteFold` and is skipped. Every surfaced\n * message carries its tally + the winning edit text, UNLESS a valid tombstone folded\n * onto it — then it renders the neutral \"deleted\" descriptor with reactions/reply/edit\n * HIDDEN (the render precedence: delete DOMINATES edit). Backward-compat: old rows (no\n * `envelopeType`) project as ordinary messages. Actor attribution at the store layer:\n * outgoing rows = self; incoming rows use `resolveActor(senderDeviceId)` when provided\n * (the live Chat fold, which resolves device→user, remains authoritative cross-page).\n *\n * Exported so the reaction/edit/delete reload-parity boundary is testable with a REAL\n * `MessageStore` (real persist → unseal → project → re-fold), not a bypass — and so the\n * REAL cold-launch path folds deletes (the iOS-review CRITICAL `.delete` branch lives\n * HERE, the same function `coordinator.history()` calls, so a persisted tombstone can\n * never leak as a blank bubble).\n */\nexport function projectHistory(\n  displayId: string,\n  rows: StoredMessage[],\n  selfUserId: string,\n  resolveActor?: (senderDeviceId: string | null) => string | null,\n  tombstonedSeqs: Set<number> = new Set(),\n  purgedClientMsgIds: Set<string> = new Set(),\n): ChatMessage[] {\n  // Disappearing T10 (the M1-trap cold-launch parity): drop every row whose serverSeq is\n  // in `tombstonedSeqs` BEFORE any fold sees it — a TTL-purged message is NEVER\n  // re-projected (the transcript-reader half of the live `ingestLive` redelivery-drop).\n  const visible = rows.filter((s) => !tombstonedSeqs.has(s.serverSeq));\n\n  // Page-local fold: ingest every reaction row before projecting, so a surfaced\n  // message in the same page renders its tally on cold launch.\n  const fold = new ReactionFold();\n  for (const s of visible) {\n    if (s.envelopeType !== 'reaction' || !s.reaction) continue;\n    const actor =\n      s.direction === 'outgoing' ? selfUserId : (resolveActor?.(s.senderDeviceId ?? null) ?? null);\n    if (actor === null) continue; // unresolvable peer actor — leave to the live fold\n    fold.ingest({\n      targetClientMsgId: s.reaction.targetClientMsgId,\n      actorUserId: actor,\n      emoji: s.reaction.emoji,\n      op: s.reaction.op,\n      epoch: s.epoch,\n      serverSeq: s.serverSeq,\n      eventClientMsgId: s.clientMsgId ?? `${s.id}`,\n    });\n  }\n\n  // Page-local edit fold: an `'edit'` row NEVER becomes a bubble — it folds the\n  // latest author edit's text onto its target in place. The author-gate resolves\n  // each bubble's author from a page map (outgoing = self; incoming = resolveActor,\n  // else unresolved → unknown so the edit HOLDs). A target in `purgedClientMsgIds`\n  // resolves to 'purged' so a late edit DROPs (never resurrects). After the batch,\n  // reevaluateHeld handles an out-of-order page (an edit row before its target).\n  const editFold = new EditFold();\n  // Page-local delete fold: a `'delete'` row NEVER becomes a bubble — it folds a\n  // delete-for-everyone tombstone onto its target (author-gated). After the batch\n  // a tombstoned target is mapped to the neutral \"deleted\" descriptor with\n  // reactions/reply/edit HIDDEN (delete DOMINATES edit). This is the iOS-review\n  // CRITICAL branch: the REAL projection MUST fold deletes, else a persisted\n  // tombstone leaks as a blank bubble + never scrubs on cold launch. The reload\n  // test drives THIS exact function (the same one coordinator.history() calls), so\n  // the boundary is genuinely locked, not a test-local re-implementation.\n  const deleteFold = new DeleteFold();\n  // Disappearing T10 (the M1-trap cold-launch chat-default arming): a `'timer_set'` row is\n  // NEVER a bubble — fold it into a page-local TimerFold so a bubble with no per-message\n  // expiry inherits the chat default active AS OF its order. Because we iterate\n  // oldest-first and fold each timer_set BEFORE reaching a later bubble, `active()` at a\n  // bubble reflects only timer_set events at a LOWER (epoch, serverSeq) order → FORWARD-ONLY\n  // (a message ordered BEFORE the governing timer_set inherits nothing).\n  const pageTimerFold = new TimerFold();\n  const authorByClientMsgId = new Map<string, string>();\n  for (const s of visible) {\n    // A non-bubble row (reaction/edit/delete/timer_set) is not itself a target — only the\n    // surfaced text/media rows author-gate the folds.\n    if (\n      s.envelopeType === 'reaction' ||\n      s.envelopeType === 'edit' ||\n      s.envelopeType === 'delete' ||\n      s.envelopeType === 'timer_set'\n    )\n      continue;\n    const cid = s.clientMsgId ?? '';\n    if (!cid) continue;\n    const author =\n      s.direction === 'outgoing' ? selfUserId : resolveActor?.(s.senderDeviceId ?? null);\n    if (author != null) authorByClientMsgId.set(cid, author);\n  }\n  // Disappearing T10: the orphan-aware resolver — a target whose clientMsgId is in\n  // `purgedClientMsgIds` resolves to 'purged' (a late edit DROPs / a late delete no-ops),\n  // else 'author' from the page map, else 'unknown' (HOLD). Same shape the live\n  // `Chat.authorOfTarget` uses, so the cold-launch fold and the live fold never diverge.\n  const authorOfTarget = (cid: string): AuthorResolution => {\n    if (purgedClientMsgIds.has(cid)) return { kind: 'purged' };\n    const a = authorByClientMsgId.get(cid);\n    return a !== undefined ? { kind: 'author', userId: a } : { kind: 'unknown' };\n  };\n  for (const s of visible) {\n    if (s.envelopeType !== 'edit' || !s.edit) continue;\n    const editor =\n      s.direction === 'outgoing' ? selfUserId : (resolveActor?.(s.senderDeviceId ?? null) ?? null);\n    editFold.ingest(\n      {\n        targetClientMsgId: s.edit.targetClientMsgId,\n        editorUserId: editor,\n        newText: s.edit.newText,\n        epoch: s.epoch,\n        serverSeq: s.serverSeq,\n        eventClientMsgId: s.clientMsgId ?? `${s.id}`,\n        // Mentions T6: the edit's replacement ranges ride the fold so the WINNING\n        // edit's ranges drive the edited message's mentions on cold launch.\n        bodyRanges: s.edit.bodyRanges ?? null,\n      },\n      authorOfTarget,\n    );\n  }\n  editFold.reevaluateHeld(authorOfTarget);\n  // Fold every delete row through the same author-gate (actor = resolved sender;\n  // outgoing = self). A pending/held tombstone whose target sits later in the page\n  // is re-evaluated by the post-loop sweep below.\n  for (const s of visible) {\n    if (s.envelopeType !== 'delete' || !s.delete) continue;\n    const actor =\n      s.direction === 'outgoing' ? selfUserId : (resolveActor?.(s.senderDeviceId ?? null) ?? null);\n    deleteFold.ingest(\n      {\n        targetClientMsgId: s.delete.targetClientMsgId,\n        actorUserId: actor,\n        epoch: s.epoch,\n        serverSeq: s.serverSeq,\n        eventClientMsgId: s.clientMsgId ?? `${s.id}`,\n      },\n      authorOfTarget,\n    );\n  }\n  // Sweep: re-evaluate any pending/held tombstone now that every target's author\n  // is known (an out-of-order tombstone before its target in the same page).\n  for (const [cid] of authorByClientMsgId) deleteFold.reevaluatePending(cid, authorOfTarget(cid));\n\n  // Reply lookup over the surfaced (non-fold) rows.\n  const lookup = new Map<string, { text: string; senderUserId: string }>();\n  for (const s of visible) {\n    if (\n      s.envelopeType === 'reaction' ||\n      s.envelopeType === 'edit' ||\n      s.envelopeType === 'delete' ||\n      s.envelopeType === 'timer_set'\n    )\n      continue;\n    const cid = s.clientMsgId ?? '';\n    if (cid && s.text !== null) {\n      // selfUserId for outgoing rows; '' for incoming (peer user unresolved at\n      // history time — the empty string still yields state:'resolved').\n      const senderUserId = s.direction === 'outgoing' ? selfUserId : '';\n      lookup.set(cid, { text: s.text, senderUserId });\n    }\n  }\n\n  const out: ChatMessage[] = [];\n  // The page-local timer fold is consumed INLINE as we iterate oldest-first (so a bubble\n  // sees only the chat default at a LOWER order — forward-only). A timer_set row never\n  // becomes a bubble; it folds + is skipped.\n  for (const s of visible) {\n    if (s.envelopeType === 'timer_set') {\n      // Fold the chat default (no bubble) — actor = the resolved sender USER; an\n      // unresolvable actor drops it (no spoofable timer). own-send (outgoing) → self.\n      const actor =\n        s.direction === 'outgoing'\n          ? selfUserId\n          : (resolveActor?.(s.senderDeviceId ?? null) ?? null);\n      if (actor !== null && s.timer) {\n        pageTimerFold.ingest({\n          ttlSeconds: s.timer.ttlSeconds,\n          start: s.timer.start,\n          actorUserId: actor,\n          epoch: s.epoch,\n          serverSeq: s.serverSeq,\n          eventClientMsgId: s.clientMsgId ?? `${s.id}`,\n        });\n      }\n      continue; // never projected as a row\n    }\n    if (s.envelopeType === 'reaction' || s.envelopeType === 'edit' || s.envelopeType === 'delete')\n      continue; // folded, never a bubble\n    const clientMsgId = s.clientMsgId ?? '';\n    // RENDER PRECEDENCE (history side; suppression is applied later by the Chat):\n    // (1) tombstoned → the neutral \"deleted\" descriptor, HIDE reactions/reply/edit\n    // (delete DOMINATES edit — short-circuit the overlay); (2) else edit overlay +\n    // reactions + reply. Identical to the live Chat composition so a cold launch\n    // and a live delete render the same.\n    const isDeleted = clientMsgId ? deleteFold.isTombstoned(clientMsgId) : false;\n    if (isDeleted) {\n      out.push({\n        id: `${displayId}#${s.serverSeq}`,\n        kind: 'text',\n        direction: s.direction,\n        senderUserId: s.direction === 'outgoing' ? selfUserId : null,\n        text: DELETED_DESCRIPTOR,\n        serverSeq: s.serverSeq,\n        sentAt: new Date(s.at),\n        clientMsgId,\n        replyTo: null,\n        reactions: {},\n        edited: false,\n        isDeleted: true,\n        // Mentions T6: delete DOMINATES mentions too — a tombstoned message has none.\n        mentions: [],\n        // delete DOMINATES disappearing too — a tombstoned message carries no deadline.\n        expiresAt: null,\n      });\n      continue;\n    }\n    // Disappearing T10 (cold-launch arming): the message's EFFECTIVE TTL = its OWN\n    // per-message `expiry` if present, ELSE the chat default active AS OF this message's\n    // order (forward-only — `pageTimerFold.active()` reflects only timer_set events at a\n    // LOWER (epoch, serverSeq) order because we fold them inline oldest-first). own-expiry\n    // WINS. The deadline is derived purely from the row's send time `s.at` + the TTL — a\n    // monotonic-derived local value, never a wire field; the Chat re-arms the durable\n    // write-once anchor + the advisory purge timer off it on merge.\n    let expiresAt: Date | null = null;\n    if (s.expiry) {\n      expiresAt = new Date(s.at + s.expiry.ttlSeconds * 1000);\n    } else {\n      const active = pageTimerFold.active();\n      if (active && active.ttlSeconds !== null) {\n        expiresAt = new Date(s.at + active.ttlSeconds * 1000);\n      }\n    }\n    let replyTo: ResolvedReply | null = null;\n    if (s.replyTo) {\n      const ref: ReplyRef = {\n        v: 1,\n        client_msg_id: s.replyTo.clientMsgId,\n        preview: {\n          kind: s.replyTo.previewKind,\n          author_user_id: s.replyTo.previewAuthorUserId ?? '',\n          body: s.replyTo.previewBody ?? undefined,\n          body_truncated: false,\n        },\n      };\n      replyTo = resolveReply(ref, (id) => lookup.get(id) ?? null);\n    }\n    // Overlay the winning edit's text + flag onto the row in place: the ORIGINAL\n    // decrypted text stays on the persisted row; the projection computes\n    // `text = edit ?? original` + `edited` so a cold-launched screen renders the\n    // edited text without a new bubble (mirrors iOS T3 history projection).\n    const editText = clientMsgId ? editFold.text(clientMsgId) : null;\n    const edited = clientMsgId ? editFold.isEdited(clientMsgId) : false;\n    const text = editText ?? s.text;\n    // Mentions T6: NORMALIZE the row's raw body_ranges against the SURFACED text → spans\n    // with a null displayName (name resolution is LIVE — the Chat re-resolves on merge,\n    // the projection has no roster). When an edit WON, the surfaced mentions come from the\n    // WINNING edit's replacement ranges (against the edited text); else the bubble's own.\n    const rawRanges = editText !== null ? editFold.bodyRanges(clientMsgId) : s.bodyRanges;\n    const mentions = normalizeMentionsNullNames(rawRanges, text);\n    out.push({\n      id: `${displayId}#${s.serverSeq}`,\n      kind: s.text != null ? 'text' : 'system',\n      direction: s.direction,\n      senderUserId: s.direction === 'outgoing' ? selfUserId : null,\n      text,\n      serverSeq: s.serverSeq,\n      sentAt: new Date(s.at),\n      clientMsgId,\n      replyTo,\n      reactions: clientMsgId ? fold.tally(clientMsgId) : {},\n      edited,\n      isDeleted: false,\n      mentions,\n      expiresAt,\n    });\n  }\n  return out;\n}\n\n/** NORMALIZE raw mention ranges against `text` → `ResolvedMention[]` with `displayName:\n * null` (the history projection has no roster — names are resolved LIVE by the Chat on\n * merge). Returns `[]` when there is no text or no surviving range. */\nfunction normalizeMentionsNullNames(\n  raw: MentionRange[] | null | undefined,\n  text: string | null,\n): ResolvedMention[] {\n  if (text === null || !raw || raw.length === 0) return [];\n  return normalizeMentionRangesUtf16(raw, text).map((r) => ({\n    start: r.start,\n    length: r.length,\n    mentionedUserId: r.mentionedUserId,\n    displayName: null,\n  }));\n}\n","// `pb.messaging` — the chat-centric E2E-encrypted messaging surface (Web-MLS\n// Phase 2). The web mirror of the iOS `pb.messaging`: the dev's mental model is\n// a CHAT (a DM or a group), so the top-level noun is `Chat`, bundling its own\n// messages + typing + presence + members.\n//\n//   const dm = pb.messaging.directChat(peerUserId);   // INSTANT, LOCAL, no network\n//   await dm.send('hi');                               // first send MATERIALIZES it\n//   const off = pb.messaging.onChatsChange(() => render(pb.messaging.chats));\n//\n// The MLS protocol underneath (keydir enroll/claim, group commits, queue pull)\n// is INTERNAL — the first chat op self-enrolls. `messaging` is a reserved\n// namespace (no backend endpoint may be named `messaging`).\n\nimport type { PalbeRuntime } from '../runtime.js';\nimport type { Chat } from './chat.js';\nimport { MessagingCoordinator } from './coordinator.js';\nimport type { Unsubscribe } from './types.js';\n\nexport class PalbeMessaging {\n  private readonly coordinator: MessagingCoordinator;\n\n  constructor(rt: PalbeRuntime) {\n    this.coordinator = new MessagingCoordinator(rt);\n  }\n\n  /**\n   * Warm messaging at sign-in (optional). Enrolls this device + starts the live\n   * delivery source so incoming DMs/Welcomes drain before the chat list opens.\n   * Never REQUIRED — any chat op self-enrolls. Idempotent.\n   */\n  async start(): Promise<void> {\n    await this.coordinator.ensureEnrolled();\n  }\n\n  /**\n   * Open the ONE direct chat with `userId`. INSTANT + LOCAL — no network, nothing\n   * created yet. Returns a draft `Chat` to show immediately; the server group +\n   * MLS material materialize LAZILY on the first `chat.send`. Idempotent + stable:\n   * the same two users always resolve to the SAME Chat.\n   */\n  directChat(userId: string): Chat {\n    return this.coordinator.directChat(userId);\n  }\n\n  /**\n   * Open a multi-party group chat. LOCAL + LAZY like `directChat`: pick the\n   * members, get a draft Chat, the group is created on the FIRST `chat.send`.\n   */\n  groupChat(opts: { members?: string[] } = {}): Chat {\n    return this.coordinator.groupChat(opts.members ?? []);\n  }\n\n  /** Look up a chat by id (e.g. from a push payload / deep link). null if unknown. */\n  chat(id: string): Chat | null {\n    return this.coordinator.chatById(id);\n  }\n\n  /** The observable chat list (DMs + groups, active only). Read it after an\n   * `onChatsChange` subscription to render the inbox. */\n  get chats(): readonly Chat[] {\n    return this.coordinator.chats;\n  }\n\n  /** Subscribe to chat-list changes (a chat added/removed/hydrated). */\n  onChatsChange(cb: () => void): Unsubscribe {\n    return this.coordinator.onChatsChange(cb);\n  }\n}\n","import { BackendError } from './errors.js';\nimport { type CallOptions, palbeRequest } from './request.js';\nimport type { PalbeRuntime } from './runtime.js';\n\n/**\n * Runtime resolution is deferred behind `resolveRt` (global pb passes\n * `getRuntime`, bound clients pass `() => rt`) — but name validation runs\n * FIRST so an empty name fails as `validation` even before `notConfigured`.\n */\nexport async function callEndpoint<O>(\n  resolveRt: () => PalbeRuntime,\n  name: string,\n  input?: unknown,\n  options?: CallOptions,\n): Promise<O> {\n  if (!name || name === '/') {\n    throw new BackendError('validation', {\n      code: 'invalid_endpoint_name',\n      message: 'Endpoint name must be a non-empty path like \"todos/create\"',\n    });\n  }\n  const rt = resolveRt();\n  const path = name.startsWith('/') ? name : `/${name}`;\n  return palbeRequest<O>(rt, 'POST', path, {\n    body: input,\n    headers: options?.headers,\n    signal: options?.signal,\n  });\n}\n","import type { NamespaceTree } from './namespaces.js';\nimport type { PalbeRuntime } from './runtime.js';\n\nexport interface PalbeGlobalState {\n  runtime: PalbeRuntime | null;\n  registry: NamespaceTree;\n  /** Memoized materialized namespaces (per top-level key); reset on (re-)register. */\n  nsCache: Record<string, unknown>;\n  /** Listeners fired synchronously after every successful __configure call. */\n  configuredListeners: Set<() => void>;\n}\n\n/**\n * Module-level state would split between the ESM and CJS bundles of the two\n * entries (esbuild only code-splits ESM) and between dual-package copies in\n * one process. A globalThis slot keyed by Symbol.for converges them all.\n */\nconst STATE_KEY: unique symbol = Symbol.for('palbe.state.v1');\n\ninterface PalbeGlobals {\n  [STATE_KEY]?: PalbeGlobalState;\n}\n\nexport function palbeState(): PalbeGlobalState {\n  // Single direct widening view of globalThis — typed via the unique-symbol\n  // key above so reads/writes of the slot stay fully typed.\n  const g = globalThis as PalbeGlobals;\n  let state = g[STATE_KEY];\n  if (!state) {\n    state = { runtime: null, registry: {}, nsCache: {}, configuredListeners: new Set() };\n    g[STATE_KEY] = state;\n  }\n  return state;\n}\n","import { BackendError, isBackendError } from './errors.js';\nimport { getRuntime } from './internal.js';\nimport { type CallOptions, palbeRequest, palbeStream } from './request.js';\nimport type { PalbeRuntime } from './runtime.js';\nimport { palbeState } from './state.js';\n\nexport interface EndpointDescriptor {\n  method: string;\n  path: string;\n  /** `{name}` segments consumed as leading call args, in order. */\n  pathParams?: string[];\n  /**\n   * 'body' (default for non-GET) | 'query' (serialize input into the URL) |\n   * 'none' (no input arg — options come straight after path params).\n   */\n  input?: 'body' | 'query' | 'none';\n  /** wire error code → lift fn; the materializer rethrows the lifted error. */\n  errors?: Record<string, (e: BackendError) => Error>;\n  /**\n   * The route answers `text/event-stream`. Emitted by the generator for an\n   * operation carrying `x-palbase-sse`, and it changes what the call RETURNS:\n   * an async iterable of frames instead of one parsed body. Without this branch\n   * the generated signature would be a lie — it declares `AsyncIterable<T>`\n   * while the buffered path hands back a single object (measured 2026-08-30,\n   * against a real stack).\n   */\n  sse?: boolean;\n}\n\nexport type NamespaceTree = { [key: string]: NamespaceTree | EndpointDescriptor };\n\n// Reserved surface names on pb — cannot be shadowed at the top level by codegen\n// namespaces. `perf` sits next to `analytics`: `pb.perf` is the PalPerf facade,\n// so a generated controller named `perf` must NOT collide with it.\nexport const RESERVED = new Set([\n  'call',\n  'upload',\n  'auth',\n  'flags',\n  'realtime',\n  'analytics',\n  'calls',\n  'messaging',\n  'perf',\n]);\n\nfunction reservedNamespaceError(key: string): BackendError {\n  return new BackendError('validation', {\n    code: 'reserved_namespace',\n    message: `Cannot register endpoint namespace '${key}': the name is reserved on pb.`,\n  });\n}\n\nfunction isDescriptor(node: NamespaceTree | EndpointDescriptor): node is EndpointDescriptor {\n  return (\n    typeof (node as EndpointDescriptor).path === 'string' &&\n    typeof (node as EndpointDescriptor).method === 'string'\n  );\n}\n\n/**\n * Validate + normalize one tree level, recursively:\n * - plain-object guard (a literal `__proto__:` in a hand-written tree would\n *   swap the node's prototype — cheap proto-pollution insurance);\n * - reject 'then' at EVERY level (a nested then makes that namespace object\n *   thenable → `await pb.rooms` hangs) and every Object.prototype member\n *   name (`'valueOf' in {}` is true — covers toString, __proto__, …);\n * - uppercase descriptor methods (request.ts matches mutating methods\n *   against an uppercase set; a codegen 'get' would otherwise send a body\n *   and an Idempotency-Key).\n */\nfunction validateDescriptorExtensions(d: EndpointDescriptor, path: string): void {\n  if (d.pathParams !== undefined) {\n    if (!Array.isArray(d.pathParams) || !d.pathParams.every((p) => typeof p === 'string')) {\n      throw new BackendError('validation', {\n        code: 'invalid_namespace_tree',\n        message: `Descriptor '${path}': pathParams must be an array of strings.`,\n      });\n    }\n    // Cross-check: a pathParams entry without a matching placeholder would\n    // silently consume a call arg and substitute nothing — fail at registration.\n    for (const p of d.pathParams) {\n      if (!d.path.includes(`{${p}}`)) {\n        throw new BackendError('validation', {\n          code: 'invalid_namespace_tree',\n          message: `Descriptor '${path}': pathParams entry '${p}' has no '{${p}}' placeholder in the path.`,\n        });\n      }\n    }\n  }\n  if (d.sse !== undefined && typeof d.sse !== 'boolean') {\n    throw new BackendError('validation', {\n      code: 'invalid_namespace_tree',\n      message: `Descriptor '${path}': sse must be a boolean.`,\n    });\n  }\n  if (d.sse === true && d.input === 'query') {\n    // A streaming route's input travels in the body; serializing it into the\n    // query would silently send nothing. Refuse at registration, not at 3am.\n    throw new BackendError('validation', {\n      code: 'invalid_namespace_tree',\n      message: `Descriptor '${path}': an sse endpoint cannot take query input.`,\n    });\n  }\n  if (d.input !== undefined && d.input !== 'body' && d.input !== 'query' && d.input !== 'none') {\n    throw new BackendError('validation', {\n      code: 'invalid_namespace_tree',\n      message: `Descriptor '${path}': input must be 'body', 'query' or 'none'.`,\n    });\n  }\n  if (d.errors !== undefined) {\n    for (const [code, fn] of Object.entries(d.errors)) {\n      if (typeof fn !== 'function') {\n        throw new BackendError('validation', {\n          code: 'invalid_namespace_tree',\n          message: `Descriptor '${path}': errors['${code}'] must be a function.`,\n        });\n      }\n    }\n  }\n}\n\nfunction validateTree(node: NamespaceTree): void {\n  const proto = Object.getPrototypeOf(node) as unknown;\n  if (proto !== Object.prototype && proto !== null) {\n    throw new BackendError('validation', {\n      code: 'invalid_namespace_tree',\n      message: 'Namespace tree nodes must be plain objects.',\n    });\n  }\n  for (const [key, child] of Object.entries(node)) {\n    if (key === 'then' || key in {}) throw reservedNamespaceError(key);\n    if (isDescriptor(child)) {\n      child.method = child.method.toUpperCase();\n      validateDescriptorExtensions(child, child.path);\n    } else {\n      validateTree(child);\n    }\n  }\n}\n\nexport function __registerNamespaces(tree: NamespaceTree): void {\n  for (const key of Object.keys(tree)) {\n    if (RESERVED.has(key)) throw reservedNamespaceError(key);\n  }\n  validateTree(tree);\n  const state = palbeState();\n  state.registry = tree;\n  state.nsCache = {};\n}\n\nexport function resetNamespaces(): void {\n  const state = palbeState();\n  state.registry = {};\n  state.nsCache = {};\n}\n\nexport function getRegistry(): NamespaceTree {\n  return palbeState().registry;\n}\n\nfunction serializeQuery(input: unknown): string {\n  if (input === undefined || input === null) return '';\n  const entries = Object.entries(input as Record<string, unknown>)\n    .filter(([, v]) => v !== undefined && v !== null)\n    .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));\n  if (entries.length === 0) return '';\n  const parts = entries.map(([k, v]) => {\n    if (typeof v !== 'string' && typeof v !== 'number' && typeof v !== 'boolean') {\n      // Objects/arrays would stringify to '[object Object]' on the wire — fail loud.\n      throw new BackendError('validation', {\n        code: 'invalid_query_value',\n        message: `Query parameter '${k}' must be a string, number, or boolean.`,\n      });\n    }\n    return `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`;\n  });\n  return `?${parts.join('&')}`;\n}\n\nasync function invokeDescriptor(\n  rt: PalbeRuntime,\n  d: EndpointDescriptor,\n  args: unknown[],\n): Promise<unknown> {\n  const params = d.pathParams ?? [];\n  let path = d.path;\n  for (let i = 0; i < params.length; i++) {\n    const v = args[i];\n    if (typeof v !== 'string' && typeof v !== 'number') {\n      throw new BackendError('validation', {\n        code: 'missing_path_param',\n        message: `${d.path}: path parameter '${params[i]}' must be a string or number`,\n      });\n    }\n    path = path.replace(`{${params[i]}}`, encodeURIComponent(String(v)));\n  }\n  // input:'none' ops have NO input slot — options come straight after the\n  // path params (a generated `get(id, options?)` would otherwise drop its\n  // options into the input slot: GET throws, POST sends them as the body).\n  if (d.input === 'none' && args.length > params.length + 1) {\n    throw new BackendError('validation', {\n      code: 'unexpected_argument',\n      message: `${d.path}: endpoint takes no input — pass only path params and options`,\n    });\n  }\n  const input = d.input === 'none' ? undefined : args[params.length];\n  const optionsSlot = d.input === 'none' ? params.length : params.length + 1;\n  const options = args[optionsSlot] as CallOptions | undefined;\n  let body: unknown;\n  if (d.input === 'query') {\n    path += serializeQuery(input);\n  } else if (d.input !== 'none') {\n    if (d.method === 'GET') {\n      if (input !== undefined) {\n        throw new BackendError('validation', {\n          code: 'unsupported_get_input',\n          message: `${d.path}: GET endpoints take no body input`,\n        });\n      }\n    } else {\n      body = input;\n    }\n  }\n  try {\n    if (d.sse === true) {\n      return await palbeStream(rt, d.method, path, {\n        body,\n        headers: options?.headers,\n        signal: options?.signal,\n      });\n    }\n    return await palbeRequest(rt, d.method, path, {\n      body,\n      headers: options?.headers,\n      signal: options?.signal,\n    });\n  } catch (e) {\n    if (d.errors && isBackendError(e)) {\n      const lift = d.errors[e.code];\n      if (lift) throw lift(e);\n    }\n    throw e;\n  }\n}\n\n/**\n * The runtime is resolved AT CALL TIME via `resolveRt` (late binding): the\n * global path passes `getRuntime` so a `__configure` swap is picked up by\n * already-materialized namespaces; bound clients pass `() => rt` so the\n * captured runtime never changes.\n */\nfunction materialize(\n  node: NamespaceTree | EndpointDescriptor,\n  resolveRt: () => PalbeRuntime,\n): unknown {\n  if (isDescriptor(node)) {\n    // async wrapper: resolveRt() may throw (notConfigured) — endpoint methods\n    // must ALWAYS reject, never throw synchronously (callers use .catch()).\n    return async (...args: unknown[]) => invokeDescriptor(resolveRt(), node, args);\n  }\n  const out: Record<string, unknown> = {};\n  for (const [key, child] of Object.entries(node)) {\n    out[key] = materialize(child, resolveRt);\n  }\n  return out;\n}\n\n/** Global path: resolves the global runtime slot, memoizes in the global nsCache. */\nexport function getNamespace(name: string): unknown {\n  const state = palbeState();\n  const cached = state.nsCache[name];\n  if (cached !== undefined) return cached;\n  const node = state.registry[name];\n  if (node === undefined) return undefined;\n  const ns = materialize(node, getRuntime);\n  state.nsCache[name] = ns;\n  return ns;\n}\n\n/**\n * Bound path: namespaces materialize against ONE fixed runtime, memoized in a\n * per-client closure cache (the global nsCache stays global-only — a bound\n * entry there would leak one request's runtime into every other client).\n * The cache is invalidated when the registry object is swapped\n * (__registerNamespaces replaces it wholesale, e.g. watch-mode regen).\n */\nexport function boundNamespaceAccessor(rt: PalbeRuntime): (name: string) => unknown {\n  let cacheRegistry = palbeState().registry;\n  let cache: Record<string, unknown> = {};\n  return (name: string): unknown => {\n    const registry = palbeState().registry;\n    if (registry !== cacheRegistry) {\n      cacheRegistry = registry;\n      cache = {};\n    }\n    const cached = cache[name];\n    if (cached !== undefined) return cached;\n    const node = registry[name];\n    if (node === undefined) return undefined;\n    const ns = materialize(node, () => rt);\n    cache[name] = ns;\n    return ns;\n  };\n}\n","const APP_METADATA_HEADER = 'X-Palbase-Bundle';\n\n/**\n * Stamp the live browser origin metadata on an app-key request. Final headers\n * are inspected case-insensitively so an explicit caller/config value wins.\n * The authenticated app identity is the app-bound API key plus its app_id;\n * this header is diagnostic metadata, not an authorization proof. Server\n * runtimes have no browser origin and intentionally add nothing.\n */\nexport function applyBrowserOriginHeader(headers: Record<string, string>): void {\n  if (Object.keys(headers).some((key) => key.toLowerCase() === 'x-palbase-bundle')) return;\n  const origin =\n    typeof window !== 'undefined' && typeof window.location !== 'undefined'\n      ? window.location.origin\n      : '';\n  if (origin !== '') headers[APP_METADATA_HEADER] = origin;\n}\n","// Anonymous-token minting for the realtime WebSocket — a port of the iOS\n// `AnonTokenProvider` actor (palbackend-ios-src Sources/Palbe/Realtime/\n// AnonTokenProvider.swift).\n//\n// Why this exists: Realtime validates every connection's token against the\n// tenant's JWKS (palauth's ES256 signing key). A signed-in user already has a\n// palauth-issued Bearer that validates there. An anonymous caller only holds\n// the Environment's publishable API key (`pb_<environmentRef>_c…`) — NOT a JWT, so Realtime\n// rejects it with MalformedJWT. `POST /auth/anonymous` mints the missing\n// piece: a role=anon ES256 JWT signed by the same key Realtime trusts.\n//\n// Deliberately SEPARATE from TokenManager (which owns the user-session\n// lifecycle and auth-state events): an anonymous token has no user, no\n// refresh token, and emits no auth events. The provider memoises one token\n// and re-mints it shortly before expiry.\n\nimport { BackendError, fromEnvelope } from '../errors.js';\nimport type { PalbeRuntime } from '../runtime.js';\nimport { applyBrowserOriginHeader } from '../runtime-metadata.js';\n\ninterface AnonToken {\n  accessToken: string;\n  expiresAt: number; // epoch ms\n}\n\n/** Re-mint this long before real expiry so a long-lived socket never presents\n * an expired token on reconnect/join (iOS refreshSkew = 60s). */\nconst REFRESH_SKEW_MS = 60_000;\n\nexport class AnonTokenProvider {\n  private readonly rt: PalbeRuntime;\n  private cached: AnonToken | null = null;\n  private inFlight: Promise<string> | null = null;\n\n  constructor(rt: PalbeRuntime) {\n    this.rt = rt;\n  }\n\n  /**\n   * Return a valid anonymous access token, minting (or re-minting) one when\n   * the cache is empty or within the skew of expiry. Concurrent callers\n   * collapse onto a single in-flight mint.\n   */\n  token(): Promise<string> {\n    if (this.cached && Date.now() < this.cached.expiresAt - REFRESH_SKEW_MS) {\n      return Promise.resolve(this.cached.accessToken);\n    }\n    if (this.inFlight) return this.inFlight;\n    const mint = this.mint().then(\n      (token) => {\n        this.cached = token;\n        this.inFlight = null;\n        return token.accessToken;\n      },\n      (e: unknown) => {\n        this.inFlight = null; // a failed mint must not poison future attempts\n        throw e;\n      },\n    );\n    this.inFlight = mint;\n    return mint;\n  }\n\n  /**\n   * Raw fetch, deliberately NOT through HttpClient/palbeRequest: the mint\n   * must carry the Environment API key and NEVER a Bearer (iOS keeps\n   * `/auth/anonymous` on the unauthenticated-path list), and HttpClient's\n   * pre-flight would try to refresh a stale session before an anon mint —\n   * exactly the entanglement this provider exists to avoid.\n   */\n  private async mint(): Promise<AnonToken> {\n    const base = this.rt.config.url.replace(/\\/+$/, '');\n    const headers: Record<string, string> = {\n      apikey: this.rt.config.apiKey,\n      ...this.rt.config.headers,\n    };\n    applyBrowserOriginHeader(headers);\n    let response: Response;\n    try {\n      response = await fetch(`${base}/auth/anonymous`, {\n        method: 'POST',\n        headers,\n      });\n    } catch (e) {\n      throw new BackendError('network', {\n        code: 'network_error',\n        message: e instanceof Error ? e.message : 'Network request failed',\n      });\n    }\n    const body: unknown = await response.json().catch(() => null);\n    if (!response.ok) throw fromEnvelope(response.status, body);\n    // Wire shape: { access_token, token_type: \"Bearer\", expires_in: seconds }.\n    const obj = (typeof body === 'object' && body !== null ? body : {}) as Record<string, unknown>;\n    const accessToken = obj.access_token;\n    const expiresIn = obj.expires_in;\n    if (typeof accessToken !== 'string' || accessToken === '' || typeof expiresIn !== 'number') {\n      throw new BackendError('decode', {\n        code: 'decode_error',\n        message:\n          'POST /auth/anonymous returned an unexpected shape (expected {access_token, expires_in}).',\n      });\n    }\n    return { accessToken, expiresAt: Date.now() + expiresIn * 1000 };\n  }\n}\n\n/**\n * The realtime connection's token closure (iOS PalBackend.swift parity):\n * 1. the signed-in user Bearer when present and unexpired (user-override\n *    flag topics + private channels authorize);\n * 2. else an anonymous palauth JWT (role=anon);\n * 3. else — ONLY when the mint fails — the bare Environment API key. Realtime\n *    would reject it, but it keeps the closure total: the connect proceeds,\n *    fails, and the backoff loop retries the mint on the next attempt.\n */\nexport function realtimeTokenProvider(\n  rt: PalbeRuntime,\n  anon: AnonTokenProvider,\n): () => Promise<string> {\n  return async () => {\n    const bearer = rt.tokenManager.getAccessToken();\n    if (bearer && !rt.tokenManager.isExpired()) return bearer;\n    try {\n      return await anon.token();\n    } catch {\n      return rt.config.apiKey;\n    }\n  };\n}\n","// Phoenix Channels v2 frame codec — the realtime wire format.\n//\n// Every shape here is byte-locked to the iOS encoder (palbackend-ios-src\n// Sources/Palbe/Realtime/RealtimeConnection.swift), the proven-live ground\n// truth against the platform's Supabase Realtime (Elixir/Phoenix):\n//\n//   join:      [join_ref, ref, \"realtime:<topic>\", \"phx_join\", {access_token, config}]\n//   reply:     [join_ref, ref, \"realtime:<topic>\", \"phx_reply\", {status, response}]\n//   heartbeat: [null, ref, \"phoenix\", \"heartbeat\", {}]\n//   leave:     [null, ref, \"realtime:<topic>\", \"phx_leave\", {}]\n//   broadcast: [join_ref, ref, \"realtime:<topic>\", \"broadcast\", {type, event, payload}]\n//\n// Refs are stringified monotonic ints. Topics are bare sub-topics in the API\n// (\"room:42\"); the codec adds the \"realtime:\" prefix on the way out and strips\n// it on the way in. Goldens: __tests__/realtime-frames.test.ts.\n\nexport const REALTIME_PREFIX = 'realtime:';\n\n/** A decoded Phoenix v2 frame. Only topic/event/payload matter for routing. */\nexport interface PhoenixFrame {\n  joinRef: unknown;\n  ref: unknown;\n  topic: string;\n  event: string;\n  payload: unknown;\n}\n\n/** An inbound broadcast routed to channel handlers: bare topic + inner event/payload. */\nexport interface RealtimeInbound {\n  topic: string;\n  event: string;\n  payload: Record<string, unknown>;\n}\n\n/**\n * Join a topic. join_ref = ref (iOS sends the same ref in both slots). The\n * config mirrors iOS exactly: broadcast self=false, no presence key, public\n * channel, no postgres_changes.\n */\nexport function encodeJoin(ref: number, topic: string, accessToken: string): string {\n  const r = String(ref);\n  return JSON.stringify([\n    r,\n    r,\n    REALTIME_PREFIX + topic,\n    'phx_join',\n    {\n      access_token: accessToken,\n      config: {\n        broadcast: { self: false },\n        presence: { key: '' },\n        private: false,\n        postgres_changes: [],\n      },\n    },\n  ]);\n}\n\nexport function encodeLeave(ref: number, topic: string): string {\n  return JSON.stringify([null, String(ref), REALTIME_PREFIX + topic, 'phx_leave', {}]);\n}\n\nexport function encodeHeartbeat(ref: number): string {\n  return JSON.stringify([null, String(ref), 'phoenix', 'heartbeat', {}]);\n}\n\n/**\n * Client-side broadcast push (web addition — iOS is receive-only). The payload\n * envelope {type:\"broadcast\", event, payload} matches what the server fans out\n * to other subscribers (Realtime's BroadcastHandler re-broadcasts it verbatim),\n * so receivers unwrap pushes from peers and from the backend identically.\n * joinRef is the topic's CURRENT join ref — Phoenix drops channel messages\n * whose join_ref does not match the live channel instance.\n */\nexport function encodeBroadcast(\n  joinRef: string,\n  ref: number,\n  topic: string,\n  event: string,\n  payload: Record<string, unknown>,\n): string {\n  return JSON.stringify([\n    joinRef,\n    String(ref),\n    REALTIME_PREFIX + topic,\n    'broadcast',\n    { type: 'broadcast', event, payload },\n  ]);\n}\n\n/** Decode a Phoenix v2 frame; null when the text is not a valid 5-slot array. */\nexport function decodeFrame(text: string): PhoenixFrame | null {\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(text);\n  } catch {\n    return null;\n  }\n  if (!Array.isArray(parsed)) return null;\n  const [joinRef, ref, topic, event, payload] = parsed as unknown[];\n  if (typeof topic !== 'string' || typeof event !== 'string') return null;\n  return { joinRef, ref, topic, event, payload };\n}\n\nfunction asObject(value: unknown): Record<string, unknown> | null {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) return null;\n  return value as Record<string, unknown>;\n}\n\n/**\n * Route an inbound frame: only `broadcast` events carry channel traffic\n * (replies/acks/presence are connection bookkeeping — iOS ignores them the\n * same way; reconnect re-joins every topic, so socket health drives recovery).\n * Missing inner event defaults to '' and a non-object payload to {} — exact\n * iOS decoder behavior.\n */\nexport function unwrapBroadcast(frame: PhoenixFrame): RealtimeInbound | null {\n  if (frame.event !== 'broadcast') return null;\n  const body = asObject(frame.payload);\n  if (!body) return null;\n  const event = typeof body.event === 'string' ? body.event : '';\n  const payload = asObject(body.payload) ?? {};\n  return { topic: stripRealtimePrefix(frame.topic), event, payload };\n}\n\nexport function stripRealtimePrefix(topic: string): string {\n  return topic.startsWith(REALTIME_PREFIX) ? topic.slice(REALTIME_PREFIX.length) : topic;\n}\n\n// ── the state vocabulary ─────────────────────────────────────────────────────\n//\n// New event names on the SAME 5-slot envelope, byte-locked to the server's\n// goldens (internal/modules/rt/frames_state_test.go). A client that speaks only\n// broadcast is unaffected.\n\n/** Write one entry on a channel's shared state. */\nexport function encodeStateSet(\n  joinRef: string,\n  ref: number,\n  topic: string,\n  key: string,\n  value: unknown,\n  life: 'ephemeral' | 'durable',\n): string {\n  return JSON.stringify([\n    joinRef,\n    String(ref),\n    REALTIME_PREFIX + topic,\n    'state_set',\n    { key, value, life },\n  ]);\n}\n\n/** Remove one entry. The server refuses a key this connection does not own. */\nexport function encodeStateDel(joinRef: string, ref: number, topic: string, key: string): string {\n  return JSON.stringify([joinRef, String(ref), REALTIME_PREFIX + topic, 'state_del', { key }]);\n}\n\n/** Ask for a fresh snapshot — the answer to a detected gap. */\nexport function encodeStateResync(joinRef: string, ref: number, topic: string): string {\n  return JSON.stringify([joinRef, String(ref), REALTIME_PREFIX + topic, 'state_resync', {}]);\n}\n\n/** Present a fresher credential for the SAME principal without rejoining.\n * A rejoin would reset presence and force a full resync; this does not. */\nexport function encodeAccessToken(\n  joinRef: string,\n  ref: number,\n  topic: string,\n  token: string,\n): string {\n  return JSON.stringify([\n    joinRef,\n    String(ref),\n    REALTIME_PREFIX + topic,\n    'access_token',\n    { access_token: token },\n  ]);\n}\n","// The Phoenix-Channels WebSocket transport for Palbase Realtime — a port of\n// the proven-live iOS `RealtimeConnection` actor (palbackend-ios-src\n// Sources/Palbe/Realtime/RealtimeConnection.swift), the wire ground truth\n// against the platform's Supabase Realtime (Elixir/Phoenix):\n//\n//   connect:   wss://<host>/realtime/v1/websocket?apikey=<jwt>&vsn=2.0.0\n//   join:      [join_ref, ref, \"realtime:<topic>\", \"phx_join\", {access_token, config}]\n//   heartbeat: [null, ref, \"phoenix\", \"heartbeat\", {}]            (~every 25s)\n//   recv:      [null, null, \"realtime:<topic>\", \"broadcast\", {type, event, payload}]\n//\n// ONE socket is shared by every subscribed channel (the Supabase model —\n// multiplex all topics over a single connection). This class is a generic\n// frame pump; the facade (facade.ts) owns per-channel handlers and refcounts.\n//\n// DEVIATION from iOS (documented): iOS sends the auth token in the\n// `x-api-key` HTTP header on the WS upgrade. Browsers cannot set headers on\n// a WebSocket handshake, so the web client uses the server's query fallback —\n// Realtime's user_socket.ex reads `x-api-key` first, then `params[\"apikey\"]`.\n//\n// Resilience mirrors iOS: a dropped socket reconnects with exponential\n// backoff (1,2,4…s capped at 30s + deterministic ref jitter); on reconnect\n// every previously-joined topic is re-joined with a FRESH token and fresh\n// refs. The 25s heartbeat keeps Kong's idle WS timeout (180s) from closing\n// the connection. One behavioral adaptation: iOS promotes to `connected` on\n// the first RECEIVED frame because `URLSessionWebSocketTask.resume()` does\n// not signal handshake completion — a browser WebSocket's `open` event fires\n// only after a successful HTTP-101 handshake, so promotion happens there.\n\nimport {\n  decodeFrame,\n  encodeAccessToken,\n  encodeBroadcast,\n  encodeHeartbeat,\n  encodeJoin,\n  encodeLeave,\n  encodeStateDel,\n  encodeStateResync,\n  encodeStateSet,\n  type RealtimeInbound,\n  stripRealtimePrefix,\n  unwrapBroadcast,\n} from './frames.js';\nimport type { DiffBody, SnapshotBody } from './state.js';\n\n/**\n * The connection state of the shared realtime WebSocket (iOS enum parity), plus\n * `'error'` — surfaced when a channel could not be recovered after a\n * token-expiry close exhausted its rejoin attempts (the socket itself may still\n * be up; the app should stop expecting events on the dead channel).\n */\nexport type RealtimeConnectionState = 'idle' | 'connected' | 'reconnecting' | 'error';\n\n/** Connection-level callbacks the owner (the realtime facade) installs once. */\nexport interface RealtimeSocketHandlers {\n  /** A broadcast arrived for a topic (bare sub-topic, inner event/payload). */\n  onInbound: (inbound: RealtimeInbound) => void;\n  /** The socket (re)connected — fires on EVERY successful open, first included. */\n  onReconnect: () => void;\n  /** The socket's connection state changed (idle/connected/reconnecting). */\n  onStateChange: (state: RealtimeConnectionState) => void;\n  /** A channel's whole state arrived — on join, and in answer to a resync. */\n  onStateSnapshot: (topic: string, body: SnapshotBody) => void;\n  /** A change to a channel's state. The owner applies it and, when it reports a\n   * gap, asks for a snapshot. */\n  onStateDiff: (topic: string, body: DiffBody) => void;\n  /** The join was acked, carrying who this connection is ON THAT CHANNEL.\n   * Presence is keyed by it, so nothing can be written until it is known. */\n  onJoinInfo: (\n    topic: string,\n    info: { conn?: string; occupancy?: number; state_seq?: number },\n  ) => void;\n  /**\n   * A single channel died for good (token-expiry rejoin exhausted N attempts).\n   * The socket is still up; the owner surfaces this on the channel's status so\n   * the app stops expecting events on that topic. Distinct from onStateChange,\n   * which is connection-global — one bad channel must not flag the whole socket.\n   */\n  onChannelError: (topic: string) => void;\n  /**\n   * The server REFUSED a join, and said why.\n   *\n   * Distinct from onChannelError, which reports a channel that died after\n   * having worked. This one never started: `unauthorized` is the authorization\n   * model answering \"you may not\", `unavailable` is it answering \"I could not\n   * ask\". The owner has to keep those apart, because they demand opposite\n   * things of the caller — one says stop, the other says try again.\n   */\n  onChannelRefused: (topic: string, reason: string) => void;\n}\n\n/**\n * Refusals that asking again can still answer differently.\n *\n * `unavailable` is the project not being reachable to decide. The two ceilings\n * belong here too and did not: they are sent on the JOIN path, so they carry the\n * join's ref and pass the correlation gate as channel refusals — and being\n * treated as FINAL meant a client caught in a reconnect storm dropped the topic\n * from its rejoin set and never came back to it. The server's own ratelimit\n * comment is explicit that these two are \"slow down\" and \"you are holding too\n * much\", which are the two things a client can act on and recover from.\n */\nconst RETRYABLE_REFUSALS = new Set(['unavailable', 'rate_limited', 'too_many_channels']);\n\n/** The structural slice of the DOM WebSocket the transport needs (injectable). */\nexport interface WebSocketLike {\n  readonly readyState: number;\n  send(data: string): void;\n  close(code?: number): void;\n  onopen: (() => void) | null;\n  onmessage: ((event: { data: unknown }) => void) | null;\n  onclose: (() => void) | null;\n  onerror: (() => void) | null;\n}\n\nexport type WebSocketCtor = new (url: string) => WebSocketLike;\n\nexport interface RealtimeSocketOptions {\n  /** https base, e.g. https://ref.dev.palbase.studio (PalbeConfig.url). */\n  baseUrl: string;\n  /**\n   * Resolves the token used as the WS `apikey` query + per-join `access_token`.\n   * Bearer when signed in, else anon JWT, else the Environment API key (see\n   * anon-token.ts). Re-invoked on every connect AND every join, so a token\n   * rotated while offline is picked up by the next reconnect.\n   */\n  tokenProvider: () => Promise<string>;\n  /** Injectable for non-DOM hosts; defaults to globalThis.WebSocket, resolved per connect. */\n  webSocket?: WebSocketCtor;\n  /** Heartbeat cadence; default 25s (under Kong's 180s idle WS cap). */\n  heartbeatIntervalMs?: number;\n  /** Reconnect backoff cap; default 30s. */\n  maxBackoffSeconds?: number;\n}\n\nconst WS_OPEN = 1;\nconst DEFAULT_HEARTBEAT_MS = 25_000;\nconst DEFAULT_MAX_BACKOFF_SECONDS = 30;\n// How many times a single channel may be rejoined after a token-expiry close\n// before we give up on it (the rejoin-storm guard). A genuinely-bad token (not\n// just expired) would close every rejoin immediately; capping turns that into a\n// surfaced channel error instead of a tight loop. The first rejoin is attempt 0.\nconst MAX_CHANNEL_REJOIN_ATTEMPTS = 3;\n\n/**\n * Build the Phoenix WS URL: https→wss (http→ws), trailing slashes stripped,\n * Kong's `/realtime/v1/websocket` path, `apikey` + `vsn=2.0.0` query.\n * Port of iOS `websocketURL` — plus the browser apikey-query deviation\n * documented in the file header.\n */\nexport function websocketUrl(base: string, token: string): string {\n  let s = base;\n  if (s.startsWith('https://')) {\n    s = `wss://${s.slice('https://'.length)}`;\n  } else if (s.startsWith('http://')) {\n    s = `ws://${s.slice('http://'.length)}`;\n  }\n  while (s.endsWith('/')) s = s.slice(0, -1);\n  return `${s}/realtime/v1/websocket?apikey=${encodeURIComponent(token)}&vsn=2.0.0`;\n}\n\n/**\n * Exponential reconnect backoff: 2^attempt seconds capped at `cap`, plus up\n * to 1s of deterministic jitter derived from the ref counter (iOS formula —\n * nondeterministic RNG is banned, and ref-based jitter is enough to de-sync\n * reconnect storms). Pure so growth/cap are unit-testable without sleeping.\n */\nexport function backoffDelaySeconds(attempt: number, refCounter: number, cap: number): number {\n  const base = Math.min(2 ** attempt, cap);\n  const jitter = (refCounter % 1000) / 1000;\n  return base + jitter;\n}\n\ninterface PendingBroadcast {\n  topic: string;\n  event: string;\n  payload: Record<string, unknown>;\n}\n\nexport class RealtimeSocket {\n  private readonly options: RealtimeSocketOptions;\n  private handlers: RealtimeSocketHandlers | null = null;\n\n  private ws: WebSocketLike | null = null;\n  // Membership intent (bare sub-topics): re-joined on every (re)connect. A\n  // topic stays in this set from joinTopic() until leaveTopic().\n  private readonly joinedTopics = new Set<string>();\n  // topic → join_ref of the LIVE join on the current socket. Phoenix drops\n  // channel messages whose join_ref doesn't match, so broadcasts carry this.\n  // Cleared on disconnect (the next socket gets fresh joins/refs).\n  private readonly joinRefs = new Map<string, string>();\n  // Broadcasts pushed before the topic's join is live — flushed right after it.\n  private pendingBroadcasts: PendingBroadcast[] = [];\n  // Per-topic rejoin attempt counter for the token-expiry channel-death guard.\n  // Bumped on every channel rejoin; reset to 0 when the topic delivers a live\n  // broadcast (proof the channel recovered). At MAX_CHANNEL_REJOIN_ATTEMPTS the\n  // channel is given up on (onChannelError) instead of looping forever.\n  private readonly channelRejoinAttempts = new Map<string, number>();\n  // Pending per-topic rejoin backoff timers — separate from the socket-level\n  // reconnectTimer so a channel backoff never clobbers socket reconnection.\n  private readonly channelRejoinTimers = new Map<string, ReturnType<typeof setTimeout>>();\n\n  // Monotonic Phoenix message ref. Every outbound frame carries a unique ref.\n  private refCounter = 0;\n  private connected = false;\n  private started = false;\n  private stopped = false;\n  // Reset ONLY on a genuine open, so a never-opening socket walks\n  // attempt 0,1,2,… → delays 1,2,4,…,cap instead of hammering (iOS parity).\n  private reconnectAttempt = 0;\n  // Invalidates async continuations (token awaits) from a superseded connect.\n  private connectEpoch = 0;\n\n  private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n  private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\n  constructor(options: RealtimeSocketOptions) {\n    this.options = options;\n  }\n\n  // MARK: lifecycle\n\n  /** Install handlers and open the socket. Idempotent while started. */\n  start(handlers: RealtimeSocketHandlers): void {\n    this.handlers = handlers;\n    if (this.started) return;\n    this.started = true;\n    this.stopped = false;\n    void this.connect();\n  }\n\n  /** Tear down the socket, stop reconnecting, emit `idle`. Idempotent. */\n  stop(): void {\n    this.stopped = true;\n    this.started = false;\n    this.connected = false;\n    this.connectEpoch += 1; // invalidate in-flight connect continuations\n    this.stopHeartbeat();\n    if (this.reconnectTimer !== null) {\n      clearTimeout(this.reconnectTimer);\n      this.reconnectTimer = null;\n    }\n    this.clearAllChannelRejoins();\n    const ws = this.ws;\n    this.ws = null;\n    this.joinRefs.clear();\n    ws?.close(1000);\n    this.handlers?.onStateChange('idle');\n  }\n\n  // MARK: topic membership\n\n  /**\n   * Join a topic (bare sub-topic, no \"realtime:\" prefix). Idempotent. Sent\n   * immediately when the socket is up, else on the next (re)connect.\n   */\n  joinTopic(topic: string): void {\n    if (this.joinedTopics.has(topic)) return;\n    this.joinedTopics.add(topic);\n    if (this.connected) void this.sendJoin(topic);\n  }\n\n  /**\n   * Leave a topic: sends `phx_leave` when connected and always drops it from\n   * the re-join set (a future reconnect won't restore it). Pending broadcasts\n   * for the topic are discarded.\n   */\n  leaveTopic(topic: string): void {\n    if (!this.joinedTopics.delete(topic)) return;\n    this.joinRefs.delete(topic);\n    this.pendingBroadcasts = this.pendingBroadcasts.filter((p) => p.topic !== topic);\n    this.clearChannelRejoin(topic); // cancel any pending token-expiry rejoin\n    if (this.isOpen()) this.send(encodeLeave(this.nextRef(), topic));\n  }\n\n  /**\n   * Push a broadcast onto a topic (web addition — iOS is receive-only). Sent\n   * synchronously when the topic's join is live on the current socket;\n   * otherwise queued and flushed right after the join goes out.\n   */\n  sendBroadcast(topic: string, event: string, payload: Record<string, unknown>): void {\n    const joinRef = this.joinRefs.get(topic);\n    if (joinRef !== undefined && this.isOpen()) {\n      this.send(encodeBroadcast(joinRef, this.nextRef(), topic, event, payload));\n    } else {\n      this.pendingBroadcasts.push({ topic, event, payload });\n    }\n  }\n\n  // MARK: connect / reconnect\n\n  private async connect(): Promise<void> {\n    if (this.stopped) return;\n    const epoch = ++this.connectEpoch;\n    let token: string;\n    try {\n      token = await this.options.tokenProvider();\n    } catch {\n      // The provider is total by design (apikey fallback) — but a throw must\n      // not kill the reconnect loop.\n      this.scheduleReconnect();\n      return;\n    }\n    if (this.stopped || epoch !== this.connectEpoch) return;\n\n    // Resolved per attempt (not cached) so an environment that gains a\n    // WebSocket later (test stubs, polyfill load order) recovers on retry.\n    const Ctor = this.options.webSocket ?? (globalThis as { WebSocket?: WebSocketCtor }).WebSocket;\n    if (!Ctor) {\n      this.scheduleReconnect();\n      return;\n    }\n\n    const ws = new Ctor(websocketUrl(this.options.baseUrl, token));\n    this.ws = ws;\n    // Every callback gates on `ws === this.ws` so events from a superseded\n    // socket (replaced during reconnect) can't corrupt the live one's state.\n    ws.onopen = () => {\n      if (ws === this.ws) void this.handleOpen();\n    };\n    ws.onmessage = (event) => {\n      if (ws === this.ws) this.handleMessage(event.data);\n    };\n    ws.onclose = () => {\n      if (ws === this.ws) this.handleClose();\n    };\n    // Browsers always follow `error` with `close` — onclose drives recovery.\n    ws.onerror = () => {};\n  }\n\n  /**\n   * The browser `open` event proves the HTTP-101 handshake completed (the\n   * analogue of iOS promoteToConnected): flip connected, announce, then\n   * (re)join every topic with a fresh token + fresh refs. Backoff is NOT\n   * reset here — it resets on the first inbound frame (iOS parity), so a\n   * server that opens but immediately closes still grows the backoff.\n   */\n  private async handleOpen(): Promise<void> {\n    if (this.stopped) return;\n    this.connected = true;\n    this.handlers?.onStateChange('connected');\n    this.handlers?.onReconnect();\n    this.startHeartbeat();\n    for (const topic of this.joinedTopics) {\n      await this.sendJoin(topic);\n    }\n  }\n\n  private handleClose(): void {\n    if (this.stopped) return;\n    this.ws = null;\n    this.joinRefs.clear();\n    // The socket reconnect rejoins ALL topics fresh — drop per-channel rejoin\n    // state so a pending channel backoff doesn't race the rejoin-all.\n    this.clearAllChannelRejoins();\n    this.stopHeartbeat();\n    this.scheduleReconnect();\n  }\n\n  private scheduleReconnect(): void {\n    if (this.stopped || !this.started) return;\n    this.connected = false;\n    this.handlers?.onStateChange('reconnecting');\n    const attempt = this.reconnectAttempt;\n    this.reconnectAttempt += 1;\n    const cap = this.options.maxBackoffSeconds ?? DEFAULT_MAX_BACKOFF_SECONDS;\n    const delaySeconds = backoffDelaySeconds(attempt, this.refCounter, cap);\n    this.reconnectTimer = setTimeout(() => {\n      this.reconnectTimer = null;\n      void this.connect();\n    }, delaySeconds * 1000);\n  }\n\n  // MARK: frames out\n\n  /**\n   * Join carries a freshly-resolved token (iOS parity — `sendJoin` awaits the\n   * provider), so a Bearer rotated while offline rides the next rejoin.\n   */\n  private async sendJoin(topic: string): Promise<void> {\n    const token = await this.options.tokenProvider();\n    // Re-validate after the await: the socket may have dropped or the topic\n    // may have been left while the token resolved.\n    if (!this.isOpen() || !this.joinedTopics.has(topic)) return;\n    const ref = this.nextRef();\n    this.joinRefs.set(topic, String(ref));\n    this.send(encodeJoin(ref, topic, token));\n    this.flushPending(topic);\n  }\n\n  private flushPending(topic: string): void {\n    const ready = this.pendingBroadcasts.filter((p) => p.topic === topic);\n    if (ready.length === 0) return;\n    this.pendingBroadcasts = this.pendingBroadcasts.filter((p) => p.topic !== topic);\n    for (const p of ready) this.sendBroadcast(p.topic, p.event, p.payload);\n  }\n\n  private startHeartbeat(): void {\n    this.stopHeartbeat();\n    const interval = this.options.heartbeatIntervalMs ?? DEFAULT_HEARTBEAT_MS;\n    this.heartbeatTimer = setInterval(() => {\n      if (this.isOpen()) this.send(encodeHeartbeat(this.nextRef()));\n    }, interval);\n  }\n\n  private stopHeartbeat(): void {\n    if (this.heartbeatTimer !== null) {\n      clearInterval(this.heartbeatTimer);\n      this.heartbeatTimer = null;\n    }\n  }\n\n  /** Drop-if-not-open: a send racing a disconnect is recovered by the rejoin-all on reconnect. */\n  private send(text: string): void {\n    if (this.ws && this.ws.readyState === WS_OPEN) this.ws.send(text);\n  }\n\n  // MARK: frames in\n\n  private handleMessage(data: unknown): void {\n    if (typeof data !== 'string') return;\n    const frame = decodeFrame(data);\n    if (!frame) return;\n    // Any valid inbound frame proves the server is actually delivering data\n    // (not just completing the TCP handshake). Reset backoff here — iOS parity:\n    // iOS promotes to connected on the first frame because URLSession does not\n    // surface a separate handshake-complete signal. A server that opens then\n    // immediately closes does NOT trigger this, so backoff keeps growing.\n    this.reconnectAttempt = 0;\n    // Token-expiry channel death (the cross-SDK P4 bug): at JWT TTL the server\n    // kills just THIS channel (`{:stop, :normal}`) while the socket stays up\n    // (heartbeats hold it past Kong's idle cap). Phoenix v2 pushes a per-topic\n    // phx_close carrying the channel's join_ref ([<joinRef>,null,topic,\"phx_close\",{}];\n    // phx_error on a crash). We rejoin that one topic with a FRESH token rather\n    // than letting it silently die. Socket-level reconnect rejoins ALL topics —\n    // this handles the case where only ONE channel was killed.\n    if (frame.event === 'phx_close' || frame.event === 'phx_error') {\n      this.handleChannelClose(frame);\n      return;\n    }\n    // State frames are routed by NAME, before the broadcast unwrap: they are a\n    // different vocabulary on the same envelope, and unwrapBroadcast does not\n    // recognise them.\n    if (frame.event === 'state_snapshot') {\n      this.handlers?.onStateSnapshot(\n        stripRealtimePrefix(frame.topic),\n        frame.payload as SnapshotBody,\n      );\n      return;\n    }\n    if (frame.event === 'state_diff') {\n      this.handlers?.onStateDiff(stripRealtimePrefix(frame.topic), frame.payload as DiffBody);\n      return;\n    }\n    // A join ack carries this connection's identity ON THAT CHANNEL. It is the\n    // only place that identity exists, and presence cannot be written without it.\n    if (frame.event === 'phx_reply') {\n      const body = frame.payload as {\n        status?: string;\n        response?: Record<string, unknown>;\n      } | null;\n      const topic = stripRealtimePrefix(frame.topic);\n      if (body && body.status === 'ok' && body.response && typeof body.response === 'object') {\n        this.handlers?.onJoinInfo(topic, body.response);\n        return;\n      }\n      // A refusal — but of WHAT?\n      //\n      // The server answers a refused PUSH with exactly the same envelope as a\n      // refused join: a handler that threw, a state key you do not own, a rate\n      // limit. Reading every error reply as a channel refusal tears down a\n      // working channel from ordinary app code — one bid the project rejects\n      // would drop every handler on `auction:7` and stop the socket ever\n      // rejoining it.\n      //\n      // The ref separates them. A join's reply carries the join's own ref\n      // (encodeJoin puts it in both slots); a push's reply carries the push's.\n      // Anything that is not the live join's ref is one operation being\n      // refused, and the channel is untouched.\n      if (body && body.status === 'error' && String(frame.ref) === this.joinRefs.get(topic)) {\n        const reason =\n          typeof body.response?.['reason'] === 'string'\n            ? (body.response['reason'] as string)\n            : 'unauthorized';\n        // A final refusal stops being a subscription: leaving the topic in the\n        // set would rejoin it on every reconnect, forever, against a decision\n        // that will not change. A transient one stays — the reconnect IS the\n        // retry it asks for.\n        if (!RETRYABLE_REFUSALS.has(reason)) {\n          this.joinedTopics.delete(topic);\n          this.joinRefs.delete(topic);\n        }\n        this.handlers?.onChannelRefused(topic, reason);\n      }\n      return;\n    }\n    // Only `broadcast` events carry channel traffic; replies/acks/presence\n    // are bookkeeping (iOS ignores them identically).\n    const inbound = unwrapBroadcast(frame);\n    if (inbound) {\n      // A live broadcast proves the channel recovered — reset its rejoin guard.\n      this.channelRejoinAttempts.delete(inbound.topic);\n      this.handlers?.onInbound(inbound);\n    }\n  }\n\n  /**\n   * Recover (or give up on) a single channel the server closed for token\n   * reasons. Ignored unless the close targets a topic we still intend to be\n   * joined AND its join_ref matches the LIVE join — so a stale close from a\n   * superseded join, or a close arriving after our OWN phx_leave (the topic is\n   * already dropped from joinedTopics/joinRefs), does NOT trigger a rejoin.\n   */\n  private handleChannelClose(frame: { topic: string; joinRef: unknown }): void {\n    const topic = stripRealtimePrefix(frame.topic);\n    // Intentional-leave / stale-close guard: leaveTopic() removes the topic\n    // from joinedTopics and its joinRefs entry, so neither check passes here.\n    if (!this.joinedTopics.has(topic)) return;\n    if (this.joinRefs.get(topic) !== frame.joinRef) return;\n    // The current join is dead; drop its ref so a queued send won't use it.\n    this.joinRefs.delete(topic);\n\n    const attempt = this.channelRejoinAttempts.get(topic) ?? 0;\n    if (attempt >= MAX_CHANNEL_REJOIN_ATTEMPTS) {\n      // A genuinely-bad token (not just expired) closes every rejoin at once —\n      // give up on this channel instead of tight-looping.\n      this.joinedTopics.delete(topic);\n      this.channelRejoinAttempts.delete(topic);\n      this.handlers?.onChannelError(topic);\n      return;\n    }\n    this.channelRejoinAttempts.set(topic, attempt + 1);\n    if (attempt === 0) {\n      // First close: rejoin immediately (the common case — token simply expired).\n      void this.sendJoin(topic);\n      return;\n    }\n    // Repeated closes: back off (reuse the socket reconnect curve) so a flapping\n    // channel doesn't hammer the server. Replaces any pending rejoin for the topic.\n    const cap = this.options.maxBackoffSeconds ?? DEFAULT_MAX_BACKOFF_SECONDS;\n    const delayMs = backoffDelaySeconds(attempt, this.refCounter, cap) * 1000;\n    const existing = this.channelRejoinTimers.get(topic);\n    if (existing !== undefined) clearTimeout(existing);\n    const timer = setTimeout(() => {\n      this.channelRejoinTimers.delete(topic);\n      if (this.joinedTopics.has(topic)) void this.sendJoin(topic);\n    }, delayMs);\n    this.channelRejoinTimers.set(topic, timer);\n  }\n\n  // MARK: state\n\n  /** Write one entry on a joined channel's state. Dropped when the topic has no\n   * live join: the server refuses state on a channel this socket is not on, and\n   * the reconnect's join brings a fresh snapshot anyway. */\n  sendStateSet(topic: string, key: string, value: unknown, life: 'ephemeral' | 'durable'): void {\n    const joinRef = this.joinRefs.get(topic);\n    if (joinRef === undefined || !this.isOpen()) return;\n    this.send(encodeStateSet(joinRef, this.nextRef(), topic, key, value, life));\n  }\n\n  /** Remove one entry. The server refuses a key this connection does not own. */\n  sendStateDel(topic: string, key: string): void {\n    const joinRef = this.joinRefs.get(topic);\n    if (joinRef === undefined || !this.isOpen()) return;\n    this.send(encodeStateDel(joinRef, this.nextRef(), topic, key));\n  }\n\n  /** Ask for a fresh snapshot — the answer to a detected gap. */\n  sendStateResync(topic: string): void {\n    const joinRef = this.joinRefs.get(topic);\n    if (joinRef === undefined || !this.isOpen()) return;\n    this.send(encodeStateResync(joinRef, this.nextRef(), topic));\n  }\n\n  /**\n   * Present a fresher credential on every joined channel WITHOUT rejoining.\n   *\n   * The alternative — dropping and rejoining — reaps this connection's\n   * ephemeral entries (its presence) and forces a full resync on every channel.\n   * A token rotation is not a reconnection and must not look like one.\n   */\n  sendAccessToken(token: string): void {\n    if (!this.isOpen()) return;\n    for (const [topic, joinRef] of this.joinRefs) {\n      this.send(encodeAccessToken(joinRef, this.nextRef(), topic, token));\n    }\n  }\n\n  // MARK: helpers\n\n  /** Drop a single topic's token-expiry rejoin state (cancel its pending timer). */\n  private clearChannelRejoin(topic: string): void {\n    const timer = this.channelRejoinTimers.get(topic);\n    if (timer !== undefined) {\n      clearTimeout(timer);\n      this.channelRejoinTimers.delete(topic);\n    }\n    this.channelRejoinAttempts.delete(topic);\n  }\n\n  /** Drop all per-channel rejoin state (socket teardown / full reconnect). */\n  private clearAllChannelRejoins(): void {\n    for (const timer of this.channelRejoinTimers.values()) clearTimeout(timer);\n    this.channelRejoinTimers.clear();\n    this.channelRejoinAttempts.clear();\n  }\n\n  private isOpen(): boolean {\n    return this.connected && this.ws !== null && this.ws.readyState === WS_OPEN;\n  }\n\n  private nextRef(): number {\n    this.refCounter += 1;\n    return this.refCounter;\n  }\n}\n","// state.ts — the client half of the channel state primitive.\n//\n// The server keeps a keyed, last-writer-wins map per channel and hands it out\n// two ways: a SNAPSHOT (the whole picture, on join and on resync) and DIFFS\n// (what changed, after that). This applies both to a local map and — the part\n// that matters — DETECTS when a diff cannot be applied.\n//\n// That detection is the reason state can travel over a transport that is\n// allowed to drop frames. A diff carries the sequence it moves the channel\n// FROM as well as the one it moves it TO, so a client holding less than\n// `from_seq` knows it missed something. It says so instead of guessing, and the\n// caller answers by asking for a fresh snapshot. Without it a dropped frame\n// would leave a client quietly, permanently wrong — which looks exactly like a\n// frame that never arrived.\n\n/** One entry as it travels: the value, and whether it outlives its writer. */\nexport interface StateEntryWire {\n  v: unknown;\n  life: string;\n}\n\nexport interface SnapshotBody {\n  seq: number;\n  entries: Record<string, StateEntryWire>;\n}\n\nexport interface DiffBody {\n  from_seq: number;\n  seq: number;\n  set: Record<string, StateEntryWire>;\n  del: string[];\n}\n\n/** What applying a diff did. `gap` means the caller must resync. */\nexport type DiffResult = 'applied' | 'gap';\n\n/** The key prefix presence entries use. One per connection, and the connection\n * id is the suffix — which is how a client tells its own entry from everyone\n * else's. */\nexport const PRESENCE_PREFIX = '$p:';\n\nexport class ChannelState {\n  /** The sequence this local copy is current as of. */\n  seq = 0;\n  /** key → value. Lifetimes are the server's business; a reader only needs the\n   * values, and presence is derived from the key shape. */\n  readonly entries = new Map<string, unknown>();\n\n  /** Replace everything. A snapshot is the WHOLE picture, never a merge —\n   * merging one would keep entries the server has since removed. */\n  applySnapshot(body: SnapshotBody): void {\n    this.entries.clear();\n    for (const [k, e] of Object.entries(body.entries ?? {})) {\n      this.entries.set(k, e.v);\n    }\n    this.seq = body.seq;\n  }\n\n  /**\n   * Apply a diff, or report that it cannot be applied.\n   *\n   * `gap` when this copy is behind the diff's starting point: frames were\n   * missed, and applying anyway would produce a state that never existed on the\n   * server. The state is left untouched so the caller can resync from something\n   * consistent.\n   *\n   * A diff at or below the current sequence is already applied — a resend after\n   * a retry — and is silently accepted so duplicates are harmless.\n   */\n  applyDiff(body: DiffBody): DiffResult {\n    if (this.seq < body.from_seq) return 'gap';\n    if (body.seq <= this.seq) return 'applied';\n\n    for (const [k, e] of Object.entries(body.set ?? {})) this.entries.set(k, e.v);\n    for (const k of body.del ?? []) this.entries.delete(k);\n    this.seq = body.seq;\n    return 'applied';\n  }\n\n  /**\n   * Everyone else's presence.\n   *\n   * `selfConn` is this connection's id, as the join reply reported it. Its own\n   * entry is excluded because an app rendering \"who else is here\" would\n   * otherwise always show one extra face — itself.\n   */\n  presence(selfConn: string | undefined): unknown[] {\n    const own = selfConn === undefined ? undefined : PRESENCE_PREFIX + selfConn;\n    const out: unknown[] = [];\n    for (const [k, v] of this.entries) {\n      if (!k.startsWith(PRESENCE_PREFIX) || k === own) continue;\n      out.push(v);\n    }\n    return out;\n  }\n}\n","// `pb.realtime` — the public, customer-facing realtime surface. Mirrors the\n// iOS `Facade+Realtime` + `RealtimeClient` pair (palbackend-ios-src\n// Sources/Palbe/Realtime/): a channel/handler manager multiplexing every\n// subscription over ONE shared, auto-reconnecting WebSocket (connection.ts).\n//\n//     const channel = pb.realtime.channel('room:42');\n//     const sub = channel.on('message', (payload) => { ... });\n//     channel.send('message', { text: 'hi' });   // web addition — iOS is receive-only\n//     // later: sub.cancel()  (last cancel on the channel → phx_leave)\n//\n// Channel names are app-defined bare sub-topics — do NOT prefix with\n// \"realtime:\" (that's internal to the transport). `realtime` is a reserved\n// namespace: a backend endpoint cannot be named `realtime` (namespaces.ts\n// RESERVED, alongside auth/flags).\n//\n// Realtime is CLIENT-ONLY: on a host with no WebSocket (SSR/RSC/route\n// handlers), `channel()` throws a guided validation error. Reading\n// `status` is always safe (it just reports `idle`).\n\nimport type { Unsubscribe } from '../auth-facade.js';\nimport { BackendError } from '../errors.js';\nimport type { PalbeRuntime } from '../runtime.js';\nimport { AnonTokenProvider, realtimeTokenProvider } from './anon-token.js';\nimport { type RealtimeConnectionState, RealtimeSocket } from './connection.js';\nimport type { RealtimeInbound } from './frames.js';\nimport { ChannelState, type DiffBody, type SnapshotBody } from './state.js';\n\nexport type { RealtimeConnectionState } from './connection.js';\n\n/** An inbound broadcast payload (the inner `payload` of the Phoenix envelope). */\nexport type RealtimePayload = Record<string, unknown>;\nexport type RealtimeHandler = (payload: RealtimePayload) => void;\n\n/** A cancellable realtime subscription. `cancel()` removes the handler and,\n * when it was the channel's last, leaves the channel on the shared socket.\n * Cancelling twice is a no-op. */\nexport interface RealtimeSubscription {\n  cancel(): void;\n}\n\nexport interface RealtimeStatusSnapshot {\n  state: RealtimeConnectionState;\n  lastEventAt: Date | null;\n}\n\n/**\n * The observable connection status (`pb.realtime.status`) — the plain-JS\n * analogue of the iOS `@Observable RealtimeStatusStore`. `state` drives a\n * live \"connected\" badge; `lastEventAt` proves a push actually arrived.\n * `onChange` fires on state transitions and on every recorded event.\n */\nexport interface RealtimeStatus {\n  readonly state: RealtimeConnectionState;\n  readonly lastEventAt: Date | null;\n  onChange(callback: (status: RealtimeStatusSnapshot) => void): Unsubscribe;\n}\n\nclass StatusStore implements RealtimeStatus {\n  private currentState: RealtimeConnectionState = 'idle';\n  private lastEvent: Date | null = null;\n  private readonly listeners = new Set<(status: RealtimeStatusSnapshot) => void>();\n\n  get state(): RealtimeConnectionState {\n    return this.currentState;\n  }\n\n  get lastEventAt(): Date | null {\n    return this.lastEvent;\n  }\n\n  onChange(callback: (status: RealtimeStatusSnapshot) => void): Unsubscribe {\n    this.listeners.add(callback);\n    return () => {\n      this.listeners.delete(callback);\n    };\n  }\n\n  /** No-op on equal state (iOS setState guard) — listeners see transitions only. */\n  setState(state: RealtimeConnectionState): void {\n    if (state === this.currentState) return;\n    this.currentState = state;\n    this.emit();\n  }\n\n  recordEvent(at: Date): void {\n    this.lastEvent = at;\n    this.emit();\n  }\n\n  private emit(): void {\n    const snapshot: RealtimeStatusSnapshot = {\n      state: this.currentState,\n      lastEventAt: this.lastEvent,\n    };\n    for (const listener of this.listeners) listener(snapshot);\n  }\n}\n\ninterface HandlerEntry {\n  topic: string;\n  event: string;\n  handler: RealtimeHandler;\n}\n\n/**\n * Refusals worth asking about again — the same set the transport uses to decide\n * whether to keep a topic in its rejoin list. `unavailable` is the project being\n * unreachable; the two ceilings are \"slow down\" and \"you are holding too much\",\n * both of which pass with time.\n */\nconst RETRYABLE_REASONS = new Set(['unavailable', 'rate_limited', 'too_many_channels']);\n\n/** Why the server refused a channel. */\nexport interface RealtimeChannelError {\n  /** The channel this is about. */\n  topic: string;\n  /** Exactly what the server said: `\"unauthorized\"` or `\"unavailable\"`. */\n  reason: string;\n  /**\n   * Whether asking again could succeed. `unavailable` (the project could not be\n   * reached to decide) is retryable and the socket retries it on reconnect;\n   * `unauthorized` is a settled answer and is not.\n   */\n  retryable: boolean;\n}\n\ninterface ErrorHandlerEntry {\n  topic: string;\n  handler: (error: RealtimeChannelError) => void;\n}\n\n/**\n * A subscription handle for one realtime channel (returned by\n * `pb.realtime.channel(name)` — the SAME instance per name). A channel is\n * joined on the shared socket when its first handler is added (or on the\n * first `send`) and left when its last handler cancels.\n */\nexport class RealtimeChannel {\n  /** The app-defined channel name (bare sub-topic, no \"realtime:\" prefix). */\n  readonly name: string;\n  private readonly owner: PalbeRealtime;\n\n  /** @internal — obtain channels via `pb.realtime.channel(name)`. */\n  constructor(name: string, owner: PalbeRealtime) {\n    this.name = name;\n    this.owner = owner;\n  }\n\n  /**\n   * Subscribe `handler` to `event` on this channel. Fire-and-forget: the\n   * join rides the shared socket asynchronously. Hold the returned\n   * subscription and `cancel()` it to stop.\n   */\n  on(event: string, handler: RealtimeHandler): RealtimeSubscription {\n    return this.owner.subscribe(this.name, event, handler);\n  }\n\n  /**\n   * Called when the server REFUSES this channel.\n   *\n   * A join is an authorization decision, and a decision the app never hears is\n   * the same as no decision at all: silence looks exactly like a slow network.\n   * This is where a refusal arrives, carrying the server's own distinction —\n   * `retryable: false` means \"you may not\" and asking again will not help;\n   * `retryable: true` means the project could not be asked, and the socket's\n   * next reconnect retries on its own.\n   *\n   *     pb.realtime.channel('room:42').onError((err) => {\n   *       if (!err.retryable) showJoinDenied()\n   *     })\n   */\n  onError(handler: (error: RealtimeChannelError) => void): RealtimeSubscription {\n    return this.owner.subscribeError(this.name, handler);\n  }\n\n  /**\n   * Broadcast `payload` to the channel's other subscribers (web addition —\n   * iOS is receive-only). Joins the channel if it isn't already; queued\n   * until the join is live on the socket.\n   */\n  send(event: string, payload: RealtimePayload = {}): void {\n    this.owner.send(this.name, event, payload);\n  }\n\n  /**\n   * Watch one key of the channel's shared state.\n   *\n   * The handler is called with the CURRENT value straight away when there is\n   * one, and again on every change. That is the difference from `on()`: a\n   * subscriber to an event learns nothing until the next one, while state is\n   * already there when you ask.\n   */\n  onState(key: string, handler: (value: unknown) => void): RealtimeSubscription {\n    return this.owner.subscribeState(this.name, key, handler);\n  }\n\n  /** Read one key without subscribing. */\n  stateValue(key: string): unknown {\n    return this.owner.stateOf(this.name).entries.get(key);\n  }\n\n  /** Write one key. `durable` outlives this connection; `ephemeral` is reaped\n   * when it closes, which is what presence is built on. */\n  setState(key: string, value: unknown, opts: { life?: 'ephemeral' | 'durable' } = {}): void {\n    this.owner.writeState(this.name, key, value, opts.life ?? 'durable');\n  }\n\n  /** Remove a key this connection wrote. */\n  clearState(key: string): void {\n    this.owner.clearState(this.name, key);\n  }\n\n  /**\n   * Announce this client on the channel. `meta` is whatever other participants\n   * should see — a name, an avatar, a cursor.\n   *\n   * It is ephemeral state keyed by this connection, so it disappears when the\n   * socket does. Nothing has to be un-announced on a crash.\n   */\n  presenceEnter(meta: RealtimePayload): void {\n    this.owner.presenceWrite(this.name, meta);\n  }\n\n  /** Replace the announced value — a cursor moving is this, at whatever rate\n   * the app likes: the server conflates writes it cannot deliver fast enough. */\n  presenceUpdate(meta: RealtimePayload): void {\n    this.owner.presenceWrite(this.name, meta);\n  }\n\n  /** Leave early. Closing the socket does this on its own. */\n  presenceLeave(): void {\n    this.owner.presenceClear(this.name);\n  }\n\n  /** Everyone else currently announced, this client excluded. */\n  presenceOthers(): unknown[] {\n    return this.owner.presenceOthers(this.name);\n  }\n\n  /** Watch the announced set. Called on every change. */\n  onPresence(handler: (others: unknown[]) => void): RealtimeSubscription {\n    return this.owner.subscribePresence(this.name, handler);\n  }\n}\n\nexport class PalbeRealtime {\n  private readonly rt: PalbeRuntime;\n  private socket: RealtimeSocket | null = null;\n  private readonly channels = new Map<string, RealtimeChannel>();\n  private readonly statusStore = new StatusStore();\n  // Per-(topic, event) handlers — an event may have multiple handlers\n  // (multiple .on calls); entry identity is the unsubscribe token.\n  private readonly handlers = new Set<HandlerEntry>();\n  // Per-topic refusal handlers. Kept apart from `handlers` because they are not\n  // refcounted: registering one must not join a channel, and cancelling the\n  // last one must not leave a channel that still has event handlers on it.\n  private readonly errorHandlers = new Set<ErrorHandlerEntry>();\n  // Joins are refcounted per topic so the socket only leaves a topic when\n  // its last handler cancels (iOS RealtimeClient parity).\n  private readonly topicRefcount = new Map<string, number>();\n  // Per-topic shared state, and this connection's identity on each topic (from\n  // the join ack). Presence is keyed by that identity, so a write before the\n  // ack has nowhere to go and is queued until it arrives.\n  private readonly states = new Map<string, ChannelState>();\n  private readonly connIds = new Map<string, string>();\n  private readonly pendingPresence = new Map<string, RealtimePayload>();\n  private readonly stateWatchers = new Set<{\n    topic: string;\n    key: string;\n    handler: (v: unknown) => void;\n  }>();\n  private readonly presenceWatchers = new Set<{\n    topic: string;\n    handler: (others: unknown[]) => void;\n  }>();\n\n  constructor(rt: PalbeRuntime) {\n    this.rt = rt;\n  }\n\n  /**\n   * Get the handle for an app-defined channel (e.g. \"room:42\"). The same\n   * name returns the SAME instance. Throws a guided error on server-side\n   * hosts (SSR/RSC/Node) — realtime is client-only.\n   */\n  channel(name: string): RealtimeChannel {\n    // Primary: detect server environment by the absence of the browser globals\n    // `document` and `window`. Node ≥22 ships a global WebSocket, so the old\n    // `typeof WebSocket === 'undefined'` check is no-op there — server code\n    // would silently open real sockets.\n    if (typeof document === 'undefined' && typeof window === 'undefined') {\n      throw new BackendError('validation', {\n        code: 'realtime_unavailable',\n        message:\n          'pb.realtime requires a browser environment: document and window are not defined ' +\n          '(server/SSR/RSC). Subscribe from browser code instead — e.g. a client component or useEffect.',\n      });\n    }\n    // Secondary: browser polyfill may be missing even with document/window present.\n    if (typeof WebSocket === 'undefined') {\n      throw new BackendError('validation', {\n        code: 'realtime_unavailable',\n        message:\n          'pb.realtime is client-only: this environment has no WebSocket. ' +\n          'Subscribe from browser code instead — e.g. a client component or useEffect.',\n      });\n    }\n    let channel = this.channels.get(name);\n    if (!channel) {\n      channel = new RealtimeChannel(name, this);\n      this.channels.set(name, channel);\n    }\n    return channel;\n  }\n\n  /**\n   * Tear down the shared socket and clear all channel state. Called by\n   * `__configure` and `__reset` when the runtime is replaced, so old sockets\n   * are not left open and heartbeat timers do not leak.\n   */\n  destroy(): void {\n    this.socket?.stop();\n    this.socket = null;\n    this.channels.clear();\n  }\n\n  /** The observable connection status. Safe to read anywhere (reports `idle` until a socket exists). */\n  get status(): RealtimeStatus {\n    return this.statusStore;\n  }\n\n  /**\n   * Hand the socket a fresher credential for the SAME user, without rejoining.\n   *\n   * Called when the app's token rotates. The alternative — letting the channels\n   * die at expiry and rejoining — reaps this connection's ephemeral entries\n   * (its presence, on every channel) and forces a full state resync. A token\n   * getting older is not a disconnection and must not cost one.\n   *\n   * A no-op before a socket exists: the first connect resolves a fresh token\n   * on its own.\n   */\n  refreshToken(token: string): void {\n    this.socket?.sendAccessToken(token);\n  }\n\n  /** @internal */\n  subscribe(topic: string, event: string, handler: RealtimeHandler): RealtimeSubscription {\n    const socket = this.ensureSocket();\n    const entry: HandlerEntry = { topic, event, handler };\n    this.handlers.add(entry);\n    const count = (this.topicRefcount.get(topic) ?? 0) + 1;\n    this.topicRefcount.set(topic, count);\n    if (count === 1) socket.joinTopic(topic);\n\n    let cancelled = false;\n    return {\n      cancel: () => {\n        if (cancelled) return;\n        cancelled = true;\n        this.handlers.delete(entry);\n        // A count that is GONE means this topic was already torn down — by a\n        // final refusal, which deletes the count while the app still holds live\n        // cancel handles. Reading a missing count as 1 and decrementing it to 0\n        // then leaves the channel: an app that re-subscribed after\n        // re-authenticating, and only afterwards tidied up its old handle, had\n        // the new subscription silently severed. iOS guards this; this did not.\n        const held = this.topicRefcount.get(topic);\n        if (held === undefined) return;\n        const next = held - 1;\n        if (next <= 0) {\n          this.topicRefcount.delete(topic);\n          socket.leaveTopic(topic);\n        } else {\n          this.topicRefcount.set(topic, next);\n        }\n      },\n    };\n  }\n\n  /**\n   * Register a refusal handler for one topic. Does NOT join: watching for a\n   * refusal is not a subscription, and an app that registers one before its\n   * first `.on()` should not be joining anything yet.\n   *\n   * @internal\n   */\n  subscribeError(\n    topic: string,\n    handler: (error: RealtimeChannelError) => void,\n  ): RealtimeSubscription {\n    const entry: ErrorHandlerEntry = { topic, handler };\n    this.errorHandlers.add(entry);\n    let cancelled = false;\n    return {\n      cancel: () => {\n        if (cancelled) return;\n        cancelled = true;\n        this.errorHandlers.delete(entry);\n      },\n    };\n  }\n\n  /** @internal */\n  send(topic: string, event: string, payload: RealtimePayload): void {\n    const socket = this.ensureSocket();\n    // Phoenix only accepts pushes on joined topics. Idempotent when already\n    // joined; a send-only channel stays joined until its handlers (if any\n    // are ever added) all cancel.\n    socket.joinTopic(topic);\n    socket.sendBroadcast(topic, event, payload);\n  }\n\n  /** Lazily build + start the shared socket on first subscription/send. */\n  private ensureSocket(): RealtimeSocket {\n    if (!this.socket) {\n      const anon = new AnonTokenProvider(this.rt);\n      this.socket = new RealtimeSocket({\n        baseUrl: this.rt.config.url,\n        tokenProvider: realtimeTokenProvider(this.rt, anon),\n      });\n      this.socket.start({\n        onInbound: (inbound) => this.route(inbound),\n        // Rejoin-all already happens inside the socket; nothing to refresh\n        // here (no managed flags-sync on web yet — pb.flags polls).\n        onReconnect: () => {},\n        onStateChange: (state) => this.statusStore.setState(state),\n        onChannelError: (topic) => this.handleChannelError(topic),\n        onChannelRefused: (topic, reason) => this.handleChannelRefused(topic, reason),\n        onStateSnapshot: (topic, body) => this.applySnapshot(topic, body),\n        onStateDiff: (topic, body) => this.applyDiff(topic, body),\n        onJoinInfo: (topic, info) => this.applyJoinInfo(topic, info),\n      });\n    }\n    return this.socket;\n  }\n\n  private route(inbound: RealtimeInbound): void {\n    // Any inbound broadcast counts as a \"live event\" (iOS parity) — even one\n    // without a matching handler proves the socket is delivering.\n    this.statusStore.recordEvent(new Date());\n    for (const entry of this.handlers) {\n      if (entry.topic === inbound.topic && entry.event === inbound.event) {\n        entry.handler(inbound.payload);\n      }\n    }\n  }\n\n  /**\n  /**\n   * The server refused a channel. Tell whoever asked, and — when the answer is\n   * final — stop pretending the app is subscribed to it.\n   *\n   * `unavailable` leaves everything in place: the project could not be reached\n   * to decide, the socket rejoins on its next reconnect, and dropping the app's\n   * handlers would make a momentary outage look like a permanent denial.\n   */\n  private handleChannelRefused(topic: string, reason: string): void {\n    const retryable = RETRYABLE_REASONS.has(reason);\n    for (const entry of this.errorHandlers) {\n      if (entry.topic === topic) entry.handler({ topic, reason, retryable });\n    }\n    if (retryable) return;\n    // A final refusal ends every kind of subscription on this channel, not just\n    // the event handlers. A state or presence watcher left registered here would\n    // wait forever: no snapshot or diff can arrive for a channel the server has\n    // refused, so the app sits on a callback that will never fire again and has\n    // nothing telling it why.\n    this.forgetTopic(topic);\n  }\n\n  /**\n   * A channel died for good — a token-expiry rejoin that exhausted its attempts.\n   * The app must stop expecting anything on it, and the status observable flips\n   * to `'error'` (the React `useChannel` hook reports that).\n   *\n   * It clears the SAME registries a final refusal clears, and used to clear only\n   * the event handlers. A state or presence watcher left behind here waits\n   * forever for a snapshot that cannot arrive, and fires twice if the app ever\n   * re-subscribes — the identical failure its sibling three functions up\n   * describes, on a channel that was given up on rather than refused.\n   */\n  private handleChannelError(topic: string): void {\n    this.forgetTopic(topic);\n    this.statusStore.setState('error');\n  }\n\n  /** Drop every registration this topic holds. One place, because \"which\n   *  registries\" is a question two callers must never answer differently. */\n  private forgetTopic(topic: string): void {\n    for (const entry of this.handlers) {\n      if (entry.topic === topic) this.handlers.delete(entry);\n    }\n    for (const entry of this.stateWatchers) {\n      if (entry.topic === topic) this.stateWatchers.delete(entry);\n    }\n    for (const entry of this.presenceWatchers) {\n      if (entry.topic === topic) this.presenceWatchers.delete(entry);\n    }\n    this.pendingPresence.delete(topic);\n    this.states.delete(topic);\n    this.connIds.delete(topic);\n    this.topicRefcount.delete(topic);\n  }\n\n  // ── state ──────────────────────────────────────────────────────────────────\n\n  /** @internal */\n  stateOf(topic: string): ChannelState {\n    let st = this.states.get(topic);\n    if (!st) {\n      st = new ChannelState();\n      this.states.set(topic, st);\n    }\n    return st;\n  }\n\n  /** @internal */\n  subscribeState(\n    topic: string,\n    key: string,\n    handler: (value: unknown) => void,\n  ): RealtimeSubscription {\n    const socket = this.ensureSocket();\n    const entry = { topic, key, handler };\n    this.stateWatchers.add(entry);\n    this.retainTopic(topic, socket);\n    // The current value, if there is one: state is already there when you ask,\n    // and making the caller wait for a change would defeat the point.\n    const known = this.stateOf(topic).entries.get(key);\n    if (known !== undefined) handler(known);\n\n    let cancelled = false;\n    return {\n      cancel: () => {\n        if (cancelled) return;\n        cancelled = true;\n        this.stateWatchers.delete(entry);\n        this.releaseTopic(topic, socket);\n      },\n    };\n  }\n\n  /** @internal */\n  subscribePresence(topic: string, handler: (others: unknown[]) => void): RealtimeSubscription {\n    const socket = this.ensureSocket();\n    const entry = { topic, handler };\n    this.presenceWatchers.add(entry);\n    this.retainTopic(topic, socket);\n    handler(this.presenceOthers(topic));\n\n    let cancelled = false;\n    return {\n      cancel: () => {\n        if (cancelled) return;\n        cancelled = true;\n        this.presenceWatchers.delete(entry);\n        this.releaseTopic(topic, socket);\n      },\n    };\n  }\n\n  /** @internal */\n  writeState(topic: string, key: string, value: unknown, life: 'ephemeral' | 'durable'): void {\n    const socket = this.ensureSocket();\n    socket.joinTopic(topic);\n    socket.sendStateSet(topic, key, value, life);\n  }\n\n  /** @internal */\n  clearState(topic: string, key: string): void {\n    this.ensureSocket().sendStateDel(topic, key);\n  }\n\n  /** @internal */\n  presenceWrite(topic: string, meta: RealtimePayload): void {\n    const socket = this.ensureSocket();\n    socket.joinTopic(topic);\n    const conn = this.connIds.get(topic);\n    if (conn === undefined) {\n      // The join ack has not arrived, so this connection has no identity on the\n      // channel yet and the entry would have no key. Held, and written the\n      // moment the ack lands — announcing under a guessed key would leave a\n      // ghost nothing ever reaps.\n      this.pendingPresence.set(topic, meta);\n      return;\n    }\n    socket.sendStateSet(topic, PRESENCE_KEY(conn), meta, 'ephemeral');\n  }\n\n  /** @internal */\n  presenceClear(topic: string): void {\n    this.pendingPresence.delete(topic);\n    const conn = this.connIds.get(topic);\n    if (conn === undefined) return;\n    this.ensureSocket().sendStateDel(topic, PRESENCE_KEY(conn));\n  }\n\n  /** @internal */\n  presenceOthers(topic: string): unknown[] {\n    return this.stateOf(topic).presence(this.connIds.get(topic));\n  }\n\n  private retainTopic(topic: string, socket: RealtimeSocket): void {\n    const count = (this.topicRefcount.get(topic) ?? 0) + 1;\n    this.topicRefcount.set(topic, count);\n    if (count === 1) socket.joinTopic(topic);\n  }\n\n  private releaseTopic(topic: string, socket: RealtimeSocket): void {\n    const next = (this.topicRefcount.get(topic) ?? 1) - 1;\n    if (next <= 0) {\n      this.topicRefcount.delete(topic);\n      socket.leaveTopic(topic);\n      return;\n    }\n    this.topicRefcount.set(topic, next);\n  }\n\n  private applySnapshot(topic: string, body: SnapshotBody): void {\n    this.stateOf(topic).applySnapshot(body);\n    this.notifyState(topic);\n  }\n\n  private applyDiff(topic: string, body: DiffBody): void {\n    if (this.stateOf(topic).applyDiff(body) === 'gap') {\n      // Frames were missed. Asking for the whole picture is the only honest\n      // recovery: applying the diff anyway would produce a state that never\n      // existed on the server.\n      this.socket?.sendStateResync(topic);\n      return;\n    }\n    this.notifyState(topic);\n  }\n\n  private applyJoinInfo(topic: string, info: { conn?: string; state_seq?: number }): void {\n    if (typeof info.conn !== 'string' || info.conn === '') return;\n    this.connIds.set(topic, info.conn);\n\n    // ADOPT THE SERVER'S SEQUENCE. The ack says which sequence the state we are\n    // about to receive describes, and until now nothing read it.\n    //\n    // It matters because the server's sequence can go BACKWARDS between our\n    // joins: a channel everybody left and that held nothing is forgotten, and\n    // the next write starts again at 1. A client that kept its old local\n    // sequence — say 11 — then reads the fresh `state_diff{from_seq:0, seq:1}`\n    // as one it has already applied (`seq <= this.seq`) and silently discards\n    // it, along with every change after it until the server passes 11. Its\n    // picture is wrong and nothing ever heals it, which is the exact failure\n    // the store's own eviction guard exists to prevent — reached by another\n    // door.\n    //\n    // Behind the server means our copy is stale, not ahead: drop it and take\n    // what arrives. A snapshot follows when there is anything to send, and when\n    // there is not, empty IS the truth.\n    const seq = info.state_seq;\n    if (typeof seq === 'number' && seq < this.stateOf(topic).seq) {\n      this.stateOf(topic).applySnapshot({ seq, entries: {} });\n    }\n    const held = this.pendingPresence.get(topic);\n    if (held !== undefined) {\n      this.pendingPresence.delete(topic);\n      this.socket?.sendStateSet(topic, PRESENCE_KEY(info.conn), held, 'ephemeral');\n    }\n    this.notifyState(topic);\n  }\n\n  private notifyState(topic: string): void {\n    this.statusStore.recordEvent(new Date());\n    const st = this.stateOf(topic);\n    for (const w of this.stateWatchers) {\n      if (w.topic === topic) w.handler(st.entries.get(w.key));\n    }\n    if (this.presenceWatchers.size > 0) {\n      const others = this.presenceOthers(topic);\n      for (const w of this.presenceWatchers) {\n        if (w.topic === topic) w.handler(others);\n      }\n    }\n  }\n}\n\n/** Presence is state keyed by the connection that announced it. */\nconst PRESENCE_KEY = (conn: string) => `$p:${conn}`;\n","/**\n * Persisted session. The refresh token is the durable credential; access\n * token + expiry ride along (when available) so a reload — or a server-side\n * cookie read — can reuse a still-fresh access token instead of burning a\n * refresh per hydration (rotation storm under SSR).\n */\nexport interface PersistedSession {\n  refreshToken: string;\n  accessToken?: string;\n  /** ms epoch */\n  expiresAt?: number;\n}\n\nexport interface SessionStorageAdapter {\n  load(): PersistedSession | null;\n  save(session: PersistedSession): void;\n  clear(): void;\n  /** Serialize refresh read/exchange/write across users of this store. */\n  withLock?<T>(operation: () => Promise<T>): Promise<T>;\n}\n\ntype SessionLock = NonNullable<SessionStorageAdapter['withLock']>;\n\nfunction serialLock(): SessionLock {\n  let tail: Promise<unknown> = Promise.resolve();\n  return (operation) => {\n    const result = tail.then(operation);\n    tail = result.then(\n      () => undefined,\n      () => undefined,\n    );\n    return result;\n  };\n}\n\nexport function memorySessionStorage(): SessionStorageAdapter {\n  let current: PersistedSession | null = null;\n  return {\n    withLock: serialLock(),\n    load: () => current,\n    save: (s) => {\n      current = s;\n    },\n    clear: () => {\n      current = null;\n    },\n  };\n}\n\nconst DEFAULT_KEY = 'palbe.session';\nconst realmLocks = new Map<string, SessionLock>();\n\nexport function localStorageSessionStorage(key: string = DEFAULT_KEY): SessionStorageAdapter {\n  let fallback = realmLocks.get(key);\n  if (!fallback) {\n    fallback = serialLock();\n    realmLocks.set(key, fallback);\n  }\n  const realmLock = fallback;\n  return {\n    withLock: async (operation) => {\n      // Web Locks covers other same-origin tabs, including a newly reloaded\n      // tab. The fallback only coordinates runtimes in this JS realm.\n      const locks = typeof navigator !== 'undefined' ? navigator.locks : undefined;\n      return await (locks\n        ? locks.request(`palbase:${key}:refresh`, operation)\n        : realmLock(operation));\n    },\n    load: () => {\n      try {\n        const raw = localStorage.getItem(key);\n        if (!raw) return null;\n        const parsed: unknown = JSON.parse(raw);\n        if (typeof parsed === 'object' && parsed !== null) {\n          const obj = parsed as Record<string, unknown>;\n          if (typeof obj.refreshToken === 'string') {\n            // Optional fields are validated as a PAIR: a wrong-typed (or lone)\n            // access token / expiry degrades to the legacy {refreshToken}\n            // shape — never null the whole session over the optional part.\n            if (typeof obj.accessToken === 'string' && typeof obj.expiresAt === 'number') {\n              return {\n                refreshToken: obj.refreshToken,\n                accessToken: obj.accessToken,\n                expiresAt: obj.expiresAt,\n              };\n            }\n            return { refreshToken: obj.refreshToken };\n          }\n        }\n        return null;\n      } catch {\n        return null;\n      }\n    },\n    save: (s) => {\n      try {\n        localStorage.setItem(key, JSON.stringify(s));\n      } catch {\n        // quota/SSR — non-fatal: session just won't survive reload\n      }\n    },\n    clear: () => {\n      try {\n        localStorage.removeItem(key);\n      } catch {\n        // ignore\n      }\n    },\n  };\n}\n\n/**\n * Browser → localStorage, else memory. Pass an environment-scoped key\n * (`palbe.session.<environmentRef>`) — the bare default key would collide\n * between two Palbase environments served from the same origin.\n */\nexport function defaultSessionStorage(key?: string): SessionStorageAdapter {\n  if (typeof localStorage !== 'undefined') return localStorageSessionStorage(key);\n  return memorySessionStorage();\n}\n","// AUTO-GENERATED from package.json — do not edit\nexport const VERSION = '11.2.2';\n","import { __resetPermissionDeniedHandlers } from './auth-facade.js';\nimport type { PalbeConfig } from './config.js';\nimport { BackendError } from './errors.js';\nimport { __registerNamespaces, resetNamespaces } from './namespaces.js';\nimport { buildRuntime, type PalbeRuntime } from './runtime.js';\nimport { palbeState } from './state.js';\n\n// Runtime lives in a process-global slot (see state.ts) so every build copy\n// (ESM/CJS, palbe + palbe/internal entries) converges on one singleton.\n// This is the BROWSER path (one runtime per tab). Server-side per-request\n// runtimes arrive with palbe/next (P3); do not sign in from shared server\n// code against this singleton.\n\n/**\n * Called by the generated palbe.gen.ts on import. REPLACES the runtime\n * (re-runs storage hydration) — safe to call repeatedly, e.g. watch-mode\n * regen. The namespace registry intentionally survives re-configure: the\n * gen file re-registers its static descriptors right after.\n */\nexport function __configure(config: PalbeConfig): void {\n  const state = palbeState();\n  // Destroy the old realtime facade if it was constructed — closes the socket\n  // and clears heartbeat timers so they do not outlive the replaced runtime.\n  state.runtime?.destroyRealtime();\n  state.runtime = buildRuntime(config);\n  // Fire after the runtime is in place so listeners that read pb.* immediately\n  // (e.g. useSyncExternalStore getSnapshot) see the new runtime.\n  for (const cb of state.configuredListeners) {\n    try {\n      cb();\n    } catch {\n      // consumer errors must not abort delivery to other listeners\n    }\n  }\n}\n\n/**\n * Register a callback that fires synchronously after every successful\n * `__configure` call (including re-configure / watch-mode regen).\n *\n * Returns an unsubscribe function. Safe to call before the first `__configure`.\n *\n * Consumed by `palbe/react`; not part of the public `palbe` surface — which is\n * what the separate `palbe/internal` ENTRY expresses, and the only thing that\n * may. DO NOT mark this doc comment with the TSDoc internal tag (not even in\n * prose — the compiler matches the token anywhere in the block): `stripInternal`\n * in tsconfig.json reads the whole src tree, so the tag deletes this declaration\n * from the shipped `internal.d.ts` while the JS keeps exporting it, and every\n * honest importer fails typecheck (WEB-9).\n */\nexport function onConfigured(cb: () => void): () => void {\n  const state = palbeState();\n  state.configuredListeners.add(cb);\n  return () => state.configuredListeners.delete(cb);\n}\n\n/** The configured runtime, or a guided `notConfigured` throw. Package-internal\n * (hence the `palbe/internal` entry) but part of THAT entry's shipped surface —\n * carries no TSDoc internal tag, which `stripInternal` would honour by deleting\n * this declaration from `internal.d.ts` (see `onConfigured` above). */\nexport function getRuntime(): PalbeRuntime {\n  const rt = palbeState().runtime;\n  if (!rt) throw BackendError.notConfigured();\n  return rt;\n}\n\n/** Test-only: drop runtime + registered namespaces. */\nexport function __reset(): void {\n  __resetPermissionDeniedHandlers();\n  const state = palbeState();\n  state.runtime?.destroyRealtime();\n  state.runtime = null;\n  state.configuredListeners.clear();\n  resetNamespaces();\n}\n\nexport type { EndpointDescriptor, NamespaceTree } from './namespaces.js';\nexport type { PB } from './pb.js';\nexport { createBoundClient } from './pb.js';\nexport type { PalbeConfig, PalbeRuntime };\n// Server-adapter seams (palbe/next): per-request runtime + bound client.\nexport { __registerNamespaces, buildRuntime };\n","// room.ts — the TYPED cap over a realtime channel, on the web side.\n//\n// Realtime arrives untyped today: a handler is given `Record<string, unknown>`\n// and every field is a cast. A room changes that — the backend DECLARES its\n// events and its messages, the generator emits them as real types, and this file\n// is where those types meet the socket.\n//\n// What this file deliberately does NOT do is manage membership. `PalbeRealtime`\n// already joins a channel on its first handler and leaves on its last, so FR-016\n// is satisfied by DELEGATING to that count. A second refcount here would be a\n// second thing to get wrong, and the two would disagree the first time an app\n// mixed `pb.join` with `pb.realtime.channel`.\n\nimport type { RealtimePayload, RealtimeSubscription } from './realtime/facade.js';\n\n/** What a room needs from the socket. `PalbeRealtime` provides it; a test\n *  supplies its own, so the typed layer can be measured without a connection. */\nexport interface RoomTransport {\n  /** Subscribe to one event on one topic. Returns the undo. */\n  subscribe(topic: string, event: string, handler: (payload: RealtimePayload) => void): () => void;\n  /** Push one client frame. */\n  send(topic: string, event: string, payload: RealtimePayload): void;\n}\n\n/**\n * A room, as the generator emits one. An app never writes this by hand.\n *\n * `send` and `event` are TYPE CARRIERS — their values are never read. They exist\n * so `room.send('say', {...})` checks the payload against the right shape\n * without the app ever naming that shape.\n */\nexport interface RoomDescriptor<\n  E extends { event: string; payload: unknown },\n  S,\n  P extends readonly string[] = readonly string[],\n> {\n  /** The channel pattern the backend declared: `ai:{sessionId}`. */\n  pattern: string;\n  /** The `{param}` names, in pattern order.\n   *\n   *  Typed as a literal tuple (the generator emits `as const`) so `join` can\n   *  demand EXACTLY these keys. Without that, `params` is `Record<string,\n   *  string>` and a typo'd key type-checks — it then builds a topic with an\n   *  unfilled `{param}`, which matches no room on the server and fails as\n   *  SILENCE. Measured: the runtime guard caught it, the compiler did not. */\n  params: P;\n  /** The declared event names — what the handle subscribes to. Without the list\n   *  it would have to guess, and a room's events are what it must not guess. */\n  events: readonly string[];\n  /** The declared message names. `send` is a TYPE carrier with no runtime keys,\n   *  so this is the half a JavaScript caller can be checked against. */\n  messages: readonly string[];\n  send: S;\n  event: E;\n}\n\n/** A live room. Hold it for as long as the view is on screen. */\nexport interface RoomHandle<E extends { event: string; payload: unknown }, S> {\n  /** The topic this handle is attached to. An app never has to build it. */\n  readonly topic: string;\n  /** Start receiving. Returns a token for `off`. */\n  on(handler: (event: E) => void): RoomToken;\n  /** Stop one callback. */\n  off(token: RoomToken): void;\n  /** Send one declared message. The event name comes from the descriptor. */\n  send<K extends keyof S & string>(name: K, payload: S[K]): void;\n  /** Drop every callback this handle registered. */\n  leave(): void;\n}\n\n/** Opaque handle to one registration. Callback + token, deliberately: a room\n *  routinely has several interested parties (a transcript, a badge, a logger),\n *  and an async iterator has exactly one consumer. */\nexport type RoomToken = { readonly __room: unique symbol } | symbol;\n\n/**\n * Attach to a room.\n *\n *     const room = pb.join(AiSessionIdRoom, { sessionId })\n *     const token = room.on((e) => {\n *       switch (e.event) {\n *         case 'token': transcript.push(e.payload.text); break\n *         case 'done':  finish(e.payload.reason); break\n *       }\n *     })\n *     room.send('say', { text: 'hello' })\n *     room.off(token)\n *\n * `switch` is exhaustive: when the backend adds an event, the compiler points at\n * every place that has to handle it.\n */\nexport function joinRoom<\n  E extends { event: string; payload: unknown },\n  S,\n  P extends readonly string[],\n>(\n  descriptor: RoomDescriptor<E, S, P>,\n  params: Record<P[number], string>,\n  transport: RoomTransport,\n): RoomHandle<E, S> {\n  const topic = fillPattern(descriptor.pattern, params as Record<string, string>);\n  // One app-facing callback holds several socket unsubscribes — one per declared\n  // event — so `off` has to undo all of them together.\n  const registrations = new Map<symbol, (() => void)[]>();\n\n  return {\n    topic,\n\n    on(handler) {\n      const token = Symbol('room');\n      const undos: (() => void)[] = [];\n      for (const name of descriptor.events) {\n        undos.push(\n          transport.subscribe(topic, name, (payload) => {\n            handler({ event: name, payload } as E);\n          }),\n        );\n      }\n      registrations.set(token, undos);\n      return token;\n    },\n\n    off(token) {\n      const undos = registrations.get(token as symbol);\n      if (!undos) return;\n      registrations.delete(token as symbol);\n      for (const undo of undos) undo();\n    },\n\n    send(name, payload) {\n      if (!descriptor.messages.includes(name)) {\n        // NAMED, and before the socket is touched. TypeScript already refuses\n        // this, but a JavaScript caller has no compiler — and a message the room\n        // never declared is dropped server-side with nothing said, which is the\n        // hardest failure shape to trace back.\n        throw new Error(\n          `room \"${descriptor.pattern}\" declares no message \"${String(name)}\" — ` +\n            `check the backend's @OnMessage names and re-run the generator.`,\n        );\n      }\n      transport.send(topic, name, payload as RealtimePayload);\n    },\n\n    leave() {\n      for (const undos of registrations.values()) {\n        for (const undo of undos) undo();\n      }\n      registrations.clear();\n    },\n  };\n}\n\n/** Build the live topic. A `{param}` left unfilled would produce a topic that\n *  matches no room on the server and fails as SILENCE — the hardest failure to\n *  trace — so it is refused here, by name. */\nfunction fillPattern(pattern: string, params: Record<string, string>): string {\n  return pattern\n    .split(':')\n    .map((seg) => {\n      if (!seg.startsWith('{') || !seg.endsWith('}')) return seg;\n      const name = seg.slice(1, -1);\n      const value = params[name];\n      if (value === undefined || value === '') {\n        throw new Error(`room \"${pattern}\" needs a value for \"${name}\".`);\n      }\n      return value;\n    })\n    .join(':');\n}\n\nexport type { RealtimeSubscription };\n","import { asPalbaseError, BackendError, fromEnvelope, fromPalbaseError } from './errors.js';\nimport type { PalbeRuntime } from './runtime.js';\nimport { applyBrowserOriginHeader } from './runtime-metadata.js';\nimport { VERSION } from './version.js';\n\nexport interface UploadProgress {\n  /** Bytes sent so far. */\n  sent: number;\n  /**\n   * Total bytes. Always > 0 when delivered — progress events whose length is\n   * not computable are skipped entirely.\n   */\n  total: number;\n}\n\nexport interface UploadOptions {\n  file: Blob;\n  filename?: string;\n  contentType?: string;\n  /**\n   * The request body sent beside the file. Folded into the single `body` part\n   * storage reads and handed to the route's schema — pass a pre-encoded JSON\n   * string as `body` to own the envelope yourself.\n   */\n  fields?: Record<string, string>;\n  onProgress?: (progress: UploadProgress) => void;\n  signal?: AbortSignal;\n  headers?: Record<string, string>;\n  /** Client-side pre-send validation (iOS parity). */\n  constraints?: { maxSize?: number; allowedTypes?: string[] };\n}\n\n/** Storage's client-facing door: `POST /v1/storage/upload/{route...}`. */\nconst UPLOAD_PATH = '/v1/storage/upload';\n\nfunction abortError(): BackendError {\n  return new BackendError('network', { code: 'aborted', message: 'Upload aborted' });\n}\n\nfunction checkConstraints(options: UploadOptions): void {\n  const c = options.constraints;\n  if (!c) return;\n  if (c.maxSize !== undefined && options.file.size > c.maxSize) {\n    const message = `File size ${options.file.size} exceeds max ${c.maxSize} bytes`;\n    throw new BackendError('validation', {\n      code: 'file_too_large',\n      message,\n      fields: [{ field: 'file', message }],\n    });\n  }\n  // Empty allowedTypes = no type check (iOS contract). Validate the EFFECTIVE\n  // type: a contentType override wins over file.type (it is what gets sent).\n  const effType = options.contentType ?? options.file.type;\n  if (c.allowedTypes && c.allowedTypes.length > 0 && !c.allowedTypes.includes(effType)) {\n    const message = `File type '${effType}' is not allowed`;\n    throw new BackendError('validation', {\n      code: 'file_type_not_allowed',\n      message,\n      fields: [{ field: 'file', message }],\n    });\n  }\n}\n\nasync function buildHeaders(\n  rt: PalbeRuntime,\n  extra?: Record<string, string>,\n): Promise<Record<string, string>> {\n  // Pre-flight refresh: mirrors the pattern in request.ts / HttpClient.\n  if (\n    rt.tokenManager.isExpired() &&\n    rt.tokenManager.getRefreshToken() &&\n    rt.tokenManager.refreshFunction\n  ) {\n    try {\n      await rt.tokenManager.refreshSession();\n    } catch (e) {\n      const pe = asPalbaseError(e);\n      const status = pe?.status ?? 0;\n      if (status === 400 || status === 401 || status === 403) {\n        rt.tokenManager.clearSession(); // terminal — proceed unauthenticated\n      } else {\n        throw pe ? fromPalbaseError(pe) : e;\n      }\n    }\n  }\n\n  // Uploads bypass @palbase/core to stream multipart bodies. Kong derives the\n  // Environment identity from the API key, matching the iOS upload path.\n  const headers: Record<string, string> = {\n    apikey: rt.config.apiKey,\n    'X-Client-Info': `palbe-web/${VERSION}`,\n    ...rt.config.headers,\n  };\n  const token = rt.tokenManager.getAccessToken();\n  if (token) headers.Authorization = `Bearer ${token}`;\n  // Case-insensitive scan (mirrors request.ts): a caller-supplied\n  // `idempotency-key` in any casing must suppress generation.\n  const callerHasKey = Object.keys(extra ?? {}).some((k) => k.toLowerCase() === 'idempotency-key');\n  if (!callerHasKey) headers['Idempotency-Key'] = crypto.randomUUID();\n  // extra spreads LAST so a caller-pinned Authorization wins (HttpClient/iOS precedence).\n  const merged = { ...headers, ...extra };\n  applyBrowserOriginHeader(merged);\n  return merged;\n}\n\nfunction buildForm(options: UploadOptions): FormData {\n  const form = new FormData();\n  // The handler's own body travels as a SINGLE `body` part carrying JSON, not\n  // as loose form fields: storage reads exactly `r.FormValue(\"body\")` and hands\n  // that to the route's schema (`upload.go`, receiveUpload). One part per field\n  // was appended here and every one of them was dropped on the other side — the\n  // upload still answered 200 and the handler's `@Body` was `undefined`.\n  // Same folding as the iOS SDK (BackendUpload.swift): a caller who supplies\n  // `body` themselves has already encoded the envelope, so it is sent verbatim.\n  const { body, ...loose } = options.fields ?? {};\n  if (body !== undefined) form.append('body', body);\n  else if (Object.keys(loose).length > 0) form.append('body', JSON.stringify(loose));\n  const file =\n    options.contentType && options.file.type !== options.contentType\n      ? new Blob([options.file], { type: options.contentType })\n      : options.file;\n  const filename =\n    options.filename ??\n    (typeof File !== 'undefined' && options.file instanceof File ? options.file.name : 'file');\n  form.append('file', file, filename);\n  return form;\n}\n\nfunction decode<O>(status: number, text: string): O {\n  let body: unknown;\n  try {\n    body = text === '' ? null : JSON.parse(text);\n  } catch {\n    if (status >= 200 && status < 300) {\n      throw new BackendError('decode', {\n        code: 'decode_error',\n        message: 'Invalid JSON in response',\n        status,\n      });\n    }\n    body = text;\n  }\n  if (status < 200 || status >= 300) throw fromEnvelope(status, body);\n  return body as O;\n}\n\nfunction uploadViaXHR<O>(\n  url: string,\n  form: FormData,\n  headers: Record<string, string>,\n  options: UploadOptions,\n): Promise<O> {\n  return new Promise<O>((resolve, reject) => {\n    // Pre-aborted signal: never send. (xhr.abort() before send() fires no\n    // abort event per spec, so routing this through onabort would hang.)\n    if (options.signal?.aborted) {\n      reject(abortError());\n      return;\n    }\n    const xhr = new XMLHttpRequest();\n    xhr.open('POST', url);\n    for (const [k, v] of Object.entries(headers)) xhr.setRequestHeader(k, v);\n    xhr.upload.onprogress = (e: { lengthComputable: boolean; loaded: number; total: number }) => {\n      if (!e.lengthComputable) return;\n      options.onProgress?.({ sent: e.loaded, total: e.total });\n    };\n    const onAbort = () => xhr.abort();\n    const cleanup = () => options.signal?.removeEventListener('abort', onAbort);\n    xhr.onload = () => {\n      cleanup();\n      try {\n        resolve(decode<O>(xhr.status, xhr.responseText));\n      } catch (err) {\n        reject(err);\n      }\n    };\n    xhr.onerror = () => {\n      cleanup();\n      reject(new BackendError('network', { code: 'network_error', message: 'Upload failed' }));\n    };\n    xhr.onabort = () => {\n      cleanup();\n      reject(abortError());\n    };\n    options.signal?.addEventListener('abort', onAbort, { once: true });\n    xhr.send(form);\n  });\n}\n\nasync function uploadViaFetch<O>(\n  url: string,\n  form: FormData,\n  headers: Record<string, string>,\n  options: UploadOptions,\n): Promise<O> {\n  let res: Response;\n  try {\n    res = await fetch(url, { method: 'POST', body: form, headers, signal: options.signal });\n  } catch (e) {\n    // DOMException extends Error in modern runtimes — name check covers both.\n    if (e instanceof Error && e.name === 'AbortError') throw abortError();\n    throw new BackendError('network', {\n      code: 'network_error',\n      message: e instanceof Error ? e.message : 'Upload failed',\n    });\n  }\n  return decode<O>(res.status, await res.text());\n}\n\n/** Runtime resolution deferred behind `resolveRt` — see call.ts for the pattern. */\nexport async function uploadEndpoint<O>(\n  resolveRt: () => PalbeRuntime,\n  name: string,\n  options: UploadOptions,\n): Promise<O> {\n  const rt = resolveRt();\n  checkConstraints(options); // pre-send guard — rejects before any network I/O\n  // `name` is the tenant ROUTE, and the door is STORAGE's — storage authorizes\n  // against the route's own `@Upload` declaration, writes the bytes, renders\n  // the variants and only then calls the handler. Posting the multipart\n  // straight at the route is what the runtime refuses (\"this endpoint accepts\n  // uploads through storage, not directly\"), so every upload from a browser was\n  // a 401 no app could act on. Mirrors the iOS path (BackendUpload.swift).\n  const route = name.startsWith('/') ? name : `/${name}`;\n  const url = `${rt.config.url}${UPLOAD_PATH}${route}`;\n  const headers = await buildHeaders(rt, options.headers);\n  const form = buildForm(options);\n  const useXHR = options.onProgress !== undefined && typeof XMLHttpRequest !== 'undefined';\n  return useXHR\n    ? uploadViaXHR<O>(url, form, headers, options)\n    : uploadViaFetch<O>(url, form, headers, options);\n}\n","import type { PalbeAnalytics } from './analytics-facade.js';\nimport type { PalbeAuth } from './auth-facade.js';\nimport { callEndpoint } from './call.js';\nimport type { PalbeCalls } from './calls/facade.js';\nimport type { PalbeFlags } from './flags-facade.js';\nimport { getRuntime } from './internal.js';\nimport type { PalbeMessaging } from './messaging/facade.js';\nimport { boundNamespaceAccessor, getNamespace, getRegistry } from './namespaces.js';\nimport type { PalbePerf } from './perf/perf-facade.js';\nimport type { PalbeRealtime } from './realtime/facade.js';\nimport type { CallOptions } from './request.js';\nimport { joinRoom, type RoomDescriptor, type RoomHandle } from './room.js';\nimport type { PalbeRuntime } from './runtime.js';\nimport type { UploadOptions } from './upload.js';\nimport { uploadEndpoint } from './upload.js';\n\n/**\n * The Palbe surface. Codegen augments this interface with typed endpoint\n * namespaces:  declare module '@palbase/web' { interface PB { rooms: ... } }\n */\nexport interface PB {\n  call<O = unknown>(name: string, input?: unknown, options?: CallOptions): Promise<O>;\n  upload<O = unknown>(name: string, options: UploadOptions): Promise<O>;\n  readonly auth: PalbeAuth;\n  readonly flags: PalbeFlags;\n  readonly realtime: PalbeRealtime;\n  /**\n   * Join a room the backend declared with `@Room`.\n   *\n   *     const room = pb.join(AiSessionIdRoom, { sessionId })\n   *     const token = room.on((e) => { … })\n   *     room.send('say', { text: 'hello' })\n   *\n   * The descriptor is GENERATED: the pattern, the event names and the message\n   * names all come from the backend's declaration, so the app writes no channel\n   * string and no payload type of its own.\n   */\n  join<E extends { event: string; payload: unknown }, S, P extends readonly string[]>(\n    descriptor: RoomDescriptor<E, S, P>,\n    params: Record<P[number], string>,\n  ): RoomHandle<E, S>;\n  readonly analytics: PalbeAnalytics;\n  readonly calls: PalbeCalls;\n  readonly messaging: PalbeMessaging;\n  /** The PalPerf surface: custom traces (`startTrace`) + the buffered flush of\n   * network/app-start/custom items. `pb.perf.record(...)` is also how the\n   * runtime feeds the cold-start measurement in. */\n  readonly perf: PalbePerf;\n  /** Mark (or unmark) this client's traffic as test — flips the facade's flag\n   * so every subsequent perf flush carries `X-Palbase-Test-Device: 1` (the\n   * SAME header the iOS SDK sends; the server reads it → `is_test_traffic`). */\n  setTestDevice(on: boolean): void;\n}\n\n/**\n * One proxy construction for BOTH client flavors:\n * - global `pb`: resolveRt = getRuntime (late-bound — a __configure swap is\n *   visible to every subsequent call), nsAccessor = the globally-cached path;\n * - bound clients: resolveRt = () => rt (captured once, immune to global\n *   swaps), nsAccessor = a per-client cache (see namespaces.ts).\n */\nfunction createClientProxy(\n  resolveRt: () => PalbeRuntime,\n  nsAccessor: (name: string) => unknown,\n): PB {\n  const base = {\n    call<O = unknown>(name: string, input?: unknown, options?: CallOptions): Promise<O> {\n      return callEndpoint<O>(resolveRt, name, input, options);\n    },\n    upload<O = unknown>(name: string, options: UploadOptions): Promise<O> {\n      return uploadEndpoint<O>(resolveRt, name, options);\n    },\n    get auth(): PalbeAuth {\n      return resolveRt().auth;\n    },\n    get flags(): PalbeFlags {\n      return resolveRt().flags;\n    },\n    get realtime(): PalbeRealtime {\n      return resolveRt().realtime;\n    },\n    /**\n     * Join a room the backend declared with `@Room`.\n     *\n     *     const room = pb.join(AiSessionIdRoom, { sessionId })\n     *     const token = room.on((e) => {\n     *       switch (e.event) {\n     *         case 'token': transcript.push(e.payload.text); break\n     *         case 'done':  finish(e.payload.reason); break\n     *       }\n     *     })\n     *     room.send('say', { text: 'hello' })\n     *     room.off(token)\n     *\n     * The descriptor is GENERATED, so the app writes no channel string and no\n     * payload type of its own. Several handles on the same room share ONE\n     * subscription and the room is left when the last one goes \\u2014 the socket's\n     * own refcount, not a second one.\n     */\n    join<E extends { event: string; payload: unknown }, S, P extends readonly string[]>(\n      descriptor: RoomDescriptor<E, S, P>,\n      params: Record<P[number], string>,\n    ): RoomHandle<E, S> {\n      const realtime = resolveRt().realtime;\n      return joinRoom(descriptor, params, {\n        subscribe(topic, event, handler) {\n          const sub = realtime.subscribe(topic, event, handler);\n          return () => sub.cancel();\n        },\n        send(topic, event, payload) {\n          realtime.send(topic, event, payload);\n        },\n      });\n    },\n    get analytics(): PalbeAnalytics {\n      return resolveRt().analytics;\n    },\n    get calls(): PalbeCalls {\n      return resolveRt().calls;\n    },\n    get messaging(): PalbeMessaging {\n      return resolveRt().messaging;\n    },\n    get perf(): PalbePerf {\n      return resolveRt().perf;\n    },\n    setTestDevice(on: boolean): void {\n      resolveRt().perf.setTestDevice(on);\n    },\n  };\n  return new Proxy(base, {\n    get(target, prop, receiver) {\n      if (prop in target) return Reflect.get(target, prop, receiver);\n      // `then` must NEVER resolve to a namespace: a thenable pb would make\n      // `await pb` (or Promise.resolve(pb)) hang on the proxy. Registration\n      // also rejects it (see namespaces.ts) — this is defense in depth.\n      if (prop === 'then') return undefined;\n      if (typeof prop === 'string') {\n        const ns = nsAccessor(prop);\n        if (ns !== undefined) return ns;\n      }\n      return undefined;\n    },\n    has(target, prop) {\n      if (prop in target) return true;\n      return typeof prop === 'string' && prop !== 'then' && getRegistry()[prop] !== undefined;\n    },\n  }) as PB;\n}\n\nexport const pb: PB = createClientProxy(getRuntime, getNamespace);\n\n/**\n * A `PB` client permanently bound to ONE runtime — typed namespaces, `call`,\n * `upload` and `auth` all resolve `rt`, NEVER the global slot. This is the\n * per-request isolation primitive for server adapters (palbe/next pbServer):\n * two bound clients serving concurrent requests cannot leak each other's\n * sessions, and global `__configure` swaps don't touch them.\n */\nexport function createBoundClient(rt: PalbeRuntime): PB {\n  return createClientProxy(() => rt, boundNamespaceAccessor(rt));\n}\n"],"mappings":"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","names":["isLE","isAligned32","mod","encoder","encoder","seg","decoder","base64UrlToBytes","orderLte","add","ptr","module","generateClient","generateClient","chat","ready","seg"]}