{"version":3,"file":"model.mjs","names":[],"sources":["../src/model/make-model.ts","../src/model/make-store.ts","../src/model/use-collection.ts","../src/model/use-model.ts"],"sourcesContent":["import {\n  action,\n  makeObservable,\n  observable,\n  runInAction,\n  toJS,\n  type AnnotationMapEntry,\n} from \"mobx\";\nimport { flattenVariants, type UnionSchema } from \"../util/union-schema\";\nimport { WeakRefMap } from \"../util/weak-ref-map\";\nimport * as T from \"typebox\";\nimport * as Value from \"typebox/value\";\n\n// -----------------------------------------------------------------------------\n// Public structural contract\n// -----------------------------------------------------------------------------\n\n/** What a model reports to its stores. Loads never emit — only mutations do. */\nexport type ModelEventType = \"created\" | \"updated\" | \"deleted\";\n\n/**\n * The one thing a store exposes for a model to keep it in step. Stores register themselves with the\n * model class, held weakly, so a model needs no reference to any store — which is what lets several\n * stores over the same resource all stay consistent.\n */\nexport interface ModelListener {\n  onModelEvent(type: ModelEventType, model: any): void;\n}\n\n/**\n * Root schema for a model: a single object (`makeModel`) or a discriminated\n * union of objects (`makeUnionModel`) — nested at any depth, since a union of\n * unions is just a longer flat union. Shared by both factories and by\n * `makeStore`, which accepts either.\n */\nexport type ModelSchema = T.TObject | UnionSchema;\n\n/**\n * Fold several values into one map key. A lone value is handed back as it stands, so a numeric id\n * stays a number; several are joined on `\\u0000`, which no real id contains — so no two different\n * combinations can spell the same key.\n *\n * Shared by the identity map and by a store's keyed collections, which is the point: a record and\n * the params that select it serialize the same way.\n */\nexport const serializeKey = (values: readonly unknown[]): string | number =>\n  values.length === 1 ? (values[0] as string | number) : values.map(String).join(\"\\u0000\");\n\n/**\n * @internal When a record's fields were last replaced. Stamped by `setData`, so every path that\n * loads a record — `instantiate` from a list, `get`, `reload`, `update`, a custom action — refreshes\n * it through one choke point.\n *\n * A symbol so it never collides with a schema field and never reaches `toJSON`, and deliberately\n * *not* observable: it is metadata read imperatively by `get`, and making it observable would\n * re-render every consumer of a record on each load for nothing.\n */\nexport const LOADED_AT = Symbol(\"loadedAt\");\n\n/** The registry key a singleton (`keys: []`) maps to. Prefixed so no real id can collide with it. */\nconst SINGLETON_KEY = \"\\u0000singleton\";\n\n/**\n * Every property name across the schema. For a union this is the merged set of\n * all variants' keys, so all of them are made observable up front — that keeps\n * `setData` reactive even when it switches the active variant. `toJSON` runs\n * `Value.Clean` to emit only the keys of the variant the data currently matches.\n */\nfunction getPropertyNames(schema: ModelSchema): string[] {\n  if (!T.IsUnion(schema)) return Object.keys(schema.properties);\n  const names = new Set<string>();\n  for (const variant of flattenVariants(schema)) {\n    for (const key of Object.keys(variant.properties)) names.add(key);\n  }\n  return [...names];\n}\n\n// -----------------------------------------------------------------------------\n// Type plumbing\n// -----------------------------------------------------------------------------\n\ntype Resource<S extends ModelSchema> = T.Static<S>;\n\n/**\n * What `keys` may hold: the schema fields that identify one record, or `false` to declare that this\n * model has no identity at all. `[]` is neither of those — a resource with no identifying fields is\n * a singleton, so it identity-maps to exactly one instance.\n */\nexport type KeySpec<S extends ModelSchema> = readonly (keyof Resource<S>)[] | false;\n\n/**\n * Every field name across the schema. For a union this is the union of *all* variants' keys, not\n * just the shared ones — `keyof` a union type resolves to the shared keys alone, but the\n * constructor annotates every variant's fields, so a variant-specific field is a real field at\n * runtime and must be nameable here.\n */\ntype FieldName<S extends ModelSchema> =\n  Resource<S> extends infer R ? (R extends unknown ? keyof R & string : never) : never;\n\n/**\n * Per-field observability overrides, keyed by schema field. Anything left out keeps the default of\n * `observable.ref`.\n */\nexport type FieldAnnotations<S extends ModelSchema> = Partial<\n  Record<FieldName<S>, AnnotationMapEntry>\n>;\n\n/** The identity-key names as a string union — `never` for a model that declared no identity. */\ntype KeyName<K> = K extends readonly (infer Name)[] ? Name & string : never;\n\n/**\n * What `updateData` accepts on a single-object model: any schema field except the identity keys.\n *\n * Keys are excluded because the identity map is keyed on them and `updateData` does not re-register\n * — changing one locally would leave the instance filed under its old key, so `peek` and\n * `instantiate` would hand back a record whose id disagrees with theirs.\n */\ntype ObjectPatch<S extends ModelSchema, K> = Partial<Omit<Resource<S>, KeyName<K>>>;\n\n/**\n * What `updateData` accepts on a union model, resolved against the *narrowed* instance.\n *\n * `Self` is the polymorphic `this`, so an un-narrowed instance exposes only the shared fields and a\n * patch can name only those. Passing through `is`/`as` first widens `this` to that variant, and its\n * fields become patchable — which is what stops a patch from grafting one variant's fields onto\n * another. The discriminator is excluded outright: changing it is a change of variant, which is a\n * whole-record replacement and so belongs to `setData`.\n */\ntype UnionPatch<S extends ModelSchema, D extends PropertyKey, K, Self> = Partial<\n  Pick<Self, Exclude<Extract<FieldName<S>, keyof Self>, D | KeyName<K>>>\n>;\n\n/**\n * The variant a union instance is currently known to be, resolved from `Self` — the polymorphic\n * `this`, whose discriminator narrows to a single literal once `is`/`as` has been through it.\n *\n * Inferred rather than indexed (`Self[D]`): the interface only constrains `D` against\n * `Resource<S>`, so TypeScript will not accept it as a key of `this`.\n */\ntype VariantOf<S extends ModelSchema, D extends PropertyKey, Self> =\n  Self extends Record<D, infer V> ? Extract<Resource<S>, Record<D, V>> : Resource<S>;\n\n/**\n * Whether the model's methods take a leading params argument. True for both `keys: false` and\n * `keys: []`, which leave nothing to build params from.\n *\n * The empty-array case is asked through `K[number]` rather than `K extends readonly []` because an\n * inline `keys: []` infers as `never[]`, which is not assignable to `readonly []` and so would read\n * as keyed — leaving `buildParams()` typed `{}` and stripping the body argument off `update` and\n * every action. Via `K[number]`, `keys: []` and `keys: [] as const` are identical.\n */\ntype Keyless<K> = [K] extends [readonly any[]]\n  ? [K[number]] extends [never]\n    ? true\n    : false\n  : true;\n\n/**\n * Whether the identity map is available. `keys: false` — and the config-less `makeModel(schema)`,\n * which resolves to the same `false` — drop `instantiate` and the rest of the registry statics off\n * the class type, so reaching for identity you never declared fails to compile rather than throwing.\n */\ntype HasIdentity<K> = [K] extends [false] ? false : true;\n\ntype KeyShape<S extends ModelSchema, K> =\n  Keyless<K> extends true\n    ? undefined\n    : Pick<Resource<S>, K extends readonly any[] ? K[number] : never>;\n\ntype KeyedFn<S extends ModelSchema, K, R> =\n  Keyless<K> extends true\n    ? (...args: any[]) => Promise<R>\n    : (params: KeyShape<S, K>, ...rest: any[]) => Promise<R>;\n\ntype KeyedBodyFn<S extends ModelSchema, K, R> =\n  Keyless<K> extends true\n    ? (body: any, ...rest: any[]) => Promise<R>\n    : (params: KeyShape<S, K>, body: any, ...rest: any[]) => Promise<R>;\n\ntype IsAny<T> = 0 extends 1 & T ? true : false;\n\n/**\n * The property names a config function's first parameter carries beyond the declared keys.\n *\n * Asked of the keys rather than by assignability, which is blind to this: `{ id }` and\n * `{ id; orgId? }` are *mutually* assignable, so a fetcher declaring more still satisfies the slot.\n *\n * `any` and an index signature say nothing about which fields exist, so neither is judged — a mock\n * or a loosely typed client passes through, and with it the risk this guards against.\n */\ntype ParamsBeyondKeys<S extends ModelSchema, K, F> = F extends (p: infer P, ...rest: any[]) => any\n  ? IsAny<P> extends true\n    ? never\n    : string extends keyof P\n      ? never\n      : Exclude<keyof P, keyof KeyShape<S, K>>\n  : never;\n\n/**\n * Rejects a config function whose first parameter carries more than the declared keys.\n *\n * The invariant: the params that identify a record are the params every call uses. The instance\n * methods rebuild that argument from `buildParams()`, which knows only the keys — so a fetcher\n * taking anything else would be called by `reload()`, `update()`, `delete()` and the actions with\n * the rest missing, quietly addressing a different record than the load did. `reload()` can also\n * run on its own, from a background refresh under `optimistic`, so the divergence need not even be\n * traceable to a call you wrote.\n *\n * If a value scopes the record, declare it as a key — then it is part of identity and\n * `buildParams()` can rebuild it. If it doesn't, bind it in the config where it cannot drift:\n * `get: (params) => api.getUser({ ...params, expand: \"roles\" })`.\n */\ntype ParamsMustBeKeys<S extends ModelSchema, K, Cfg> =\n  Keyless<K> extends true\n    ? unknown\n    : [\n          | ParamsBeyondKeys<S, K, Cfg extends { get: infer F } ? F : never>\n          | ParamsBeyondKeys<S, K, Cfg extends { delete: infer F } ? F : never>\n          | ParamsBeyondKeys<S, K, Cfg extends { update: infer F } ? F : never>\n          | (Cfg extends { actions: infer A }\n              ? { [N in keyof A]: ParamsBeyondKeys<S, K, A[N]> }[keyof A]\n              : never),\n        ] extends [never]\n      ? unknown\n      : {\n          /** The name is the message: TypeScript reports it as the property the config is missing. */\n          readonly __firstParameterMustCarryOnlyTheDeclaredKeys: never;\n        };\n\n// Strip the first arg when keys is non-empty — model methods don't take the params.\ntype StripParams<K, F> =\n  Keyless<K> extends true\n    ? F\n    : F extends (params: any, ...rest: infer R) => infer Ret\n      ? (...args: R) => Ret\n      : never;\n\n// Replace a function's Promise return with Promise<R>.\ntype ReplaceReturn<F, R> = F extends (...args: infer A) => Promise<any>\n  ? (...args: A) => Promise<R>\n  : never;\n\ntype ReservedActionKey = \"reload\" | \"update\" | \"delete\" | \"setData\" | \"toJSON\";\n\ntype ActionsConfig<S extends ModelSchema, K> = {\n  [name: string]: KeyedFn<S, K, Resource<S>>;\n} & { [Key in ReservedActionKey]?: never };\n\n/**\n * How long a loaded record stays usable without going back to the API. `false` (the default) always\n * fetches, `true` reuses a loaded record indefinitely, and `{ for: ms }` reuses one loaded within\n * that window.\n *\n * The identity map is the cache — there is no second store of records — so this is purely a policy\n * over what is already there. It only ever applies to a model that declared `keys`; without identity\n * there is nothing to reuse.\n */\nexport type CacheSpec = boolean | { for: number };\n\nexport interface ModelConfig<S extends ModelSchema, K> {\n  /**\n   * The schema fields that identify one record, or `false` for a model with no identity. `[]` marks\n   * a singleton resource — one with no identifying fields, and so exactly one instance.\n   */\n  keys: K;\n  /**\n   * Override how individual schema fields are made observable. Every field defaults to\n   * `observable.ref`: a model is a projection of a server resource, replaced wholesale by\n   * `setData`, so reassigning a field is reactive but mutating the value inside it is not. That\n   * keeps `instantiate` cheap on a list of hundreds and stops in-place edits to nested data that\n   * the next load would silently discard.\n   *\n   * Name a field here when it really is edited in place — a draft, a locally-managed array:\n   *\n   * ```ts\n   * makeModel(UserSchema, { keys: [\"id\"], annotations: { tags: observable } })\n   * ```\n   *\n   * `false` opts a field out of observability altogether. This is the only way to change a schema\n   * field's annotation: mobx forbids re-annotating, so a subclass calling `makeObservable` for a\n   * field the base already annotated throws. Subclasses annotate their *own* new members that way\n   * — see the README.\n   *\n   * Only schema fields may be named; anything else is a typo and throws when the class is built.\n   */\n  annotations?: FieldAnnotations<S>;\n  /**\n   * Fetch one record. Exposed as the static `Model.get(params)`, which returns the identity-mapped\n   * instance, and used to derive the instance's `reload()` — so the endpoint is declared once.\n   */\n  get?: KeyedFn<S, K, Resource<S>>;\n  /**\n   * Whether `Model.get` may answer from the identity map instead of the API, and for how long.\n   * Defaults to `false`.\n   *\n   * Only turn this on when this model's payload is the *same shape* wherever it is loaded from. A\n   * list endpoint returning a projection and a detail endpoint returning the whole record are two\n   * different models, not one cached model — see the note on `setData` being a full replace.\n   *\n   * `Model.reload()` ignores this and always goes to the API; `Model.peek()` reads the map without\n   * one.\n   */\n  cache?: CacheSpec;\n  /**\n   * When `cache` has expired but the record is still in the identity map, hand back the record now\n   * and refresh it in the background rather than making the caller wait. Defaults to `false`.\n   *\n   * The refreshed fields land on the same instance, so anything observing it re-renders when they\n   * do. Only meaningful alongside `cache`: with nothing cached there is nothing to answer with.\n   *\n   * A background refresh that fails is logged and clears the record's load stamp, so the *next*\n   * `get()` goes to the API and reports its failure through the normal path. Nothing new to catch.\n   */\n  optimistic?: boolean;\n  /**\n   * Create a record. Exposed as the static `Model.create(body)`.\n   *\n   * The body is deliberately unconstrained: its real type comes from whatever you attach or\n   * annotate, and that flows through to `Model.create`. Defaulting it to a partial of the resource\n   * looks more helpful but *rejects* any body sharing no field names with it — TypeScript's\n   * weak-type rule — and a rejected slot makes the whole config fall back to its constraint,\n   * silently removing every generated method.\n   */\n  create?: (body: any, ...rest: any[]) => Promise<Resource<S>>;\n  update?: KeyedBodyFn<S, K, Resource<S>>;\n  delete?: KeyedFn<S, K, any>;\n  actions?: ActionsConfig<S, K>;\n}\n\n// Instance method shape from config. Self-mutating methods return Promise<any>;\n// the instance is mutated in place via setData, so callers typically read fields\n// off the same reference instead of chaining the return.\n// `reload` is derived from `get`: refreshing an instance is the same endpoint as fetching one.\ntype ModelMethods<K, Cfg> = (Cfg extends { get: infer F }\n  ? { reload: ReplaceReturn<StripParams<K, F>, any> }\n  : {}) &\n  (Cfg extends { update: infer F } ? { update: ReplaceReturn<StripParams<K, F>, any> } : {}) &\n  (Cfg extends { delete: infer F } ? { delete: StripParams<K, F> } : {}) &\n  (Cfg extends { actions: infer A }\n    ? {\n        [N in keyof A]: A[N] extends (...args: any[]) => any\n          ? ReplaceReturn<StripParams<K, A[N]>, any>\n          : never;\n      }\n    : {});\n\n// -----------------------------------------------------------------------------\n// Constructor type\n// -----------------------------------------------------------------------------\n\ntype ModelInstance<S extends ModelSchema, K, Cfg> = Resource<S> & {\n  setData(data: Resource<S>): void;\n  /**\n   * Apply a partial, purely local edit — every field in one action, so reactions see one\n   * consistent change rather than a torn intermediate state.\n   *\n   * This is local only: no endpoint is called and no `updated` event is emitted, because a store\n   * hearing one would mark its lists stale and refetch, discarding the very edit just made. Nor is\n   * the load stamp refreshed — the record now disagrees with the server, and telling `cache`\n   * otherwise would let a stale record look fresh. To persist an edit, go through `update`.\n   *\n   * Identity keys are not patchable; a key change is a different record, not an edit to this one.\n   */\n  updateData(patch: ObjectPatch<S, K>): void;\n  toJSON(): Resource<S>;\n  buildParams(): KeyShape<S, K>;\n} & ModelMethods<K, Cfg>;\n\n/**\n * Mutation fan-out, which every model class has whatever it declared for `keys` — a model with no\n * identity still creates, updates and deletes records, and stores still need to hear about it.\n */\nexport interface ModelEvents<I extends object> {\n  /**\n   * Start hearing about mutations to this resource. Held weakly, so registering never keeps a\n   * listener alive — a store that goes out of scope is dropped on the next event. Called for you by\n   * `makeStore`; only needed directly for something hand-rolled that has to stay in step.\n   */\n  addListener(listener: ModelListener): void;\n  /** @internal Fan a mutation out to every live listener. */\n  notifyListeners(type: ModelEventType, model: I): void;\n}\n\n/**\n * The identity-map statics. Present only on a model that declared identity — `keys: false`, and the\n * config-less `makeModel(schema)` that means the same thing, leave these off the class type.\n */\nexport interface ModelIdentity<S extends ModelSchema, K, I extends object> {\n  readonly identityCache: WeakRefMap<string | number, I>;\n  /**\n   * The record for these params if it is already in the identity map, without ever fetching.\n   * Synchronous, so it can answer during render.\n   *\n   * Presence, not freshness: a record `cache` would consider stale still comes back. Use it to\n   * decide whether a fetch is needed at all, or to reach a record you know is loaded.\n   */\n  peek(params: KeyShape<S, K>): I | undefined;\n  /** The registry key for a payload or model. Override on a subclass to scope identity. */\n  identityKey(source: Resource<S> | I): string | number;\n  /**\n   * The one instance for this record — existing and updated, or newly created and registered.\n   * Typed through the class it is called on, so a subclass's own members come through:\n   * `Admin.instantiate(data)` is an `Admin`, not a base instance.\n   */\n  instantiate<This extends new (...args: any[]) => any>(\n    this: This,\n    data: Resource<S>,\n  ): InstanceType<This>;\n  /** Drop this record's entry so the next `instantiate` builds a fresh instance. */\n  forget(source: Resource<S> | I): boolean;\n  /** Forget every record. For teardown — a logout, or switching tenant. */\n  clearIdentity(): void;\n}\n\n/**\n * Statics generated from the config slots that don't need an instance. Both are typed through the\n * class they are called on, exactly as `instantiate` is — a generated model class is always\n * subclassed, and a static that hardcoded the base instance would drop the subclass's own members:\n * `Admin.get(...)` is an `Admin`, not a base instance.\n */\ntype ModelStatics<Cfg> = (Cfg extends { get: (...args: infer A) => any }\n  ? {\n      /**\n       * Fetch this record, or hand back the one in the identity map when `cache` allows — see the\n       * `cache` and `optimistic` config.\n       */\n      get<This extends new (...args: any[]) => any>(\n        this: This,\n        ...args: A\n      ): Promise<InstanceType<This>>;\n      /**\n       * Fetch this record from the API, whatever `cache` says, and apply it to the identity-mapped\n       * instance. The static mirror of `instance.reload()`: same endpoint, params passed in rather\n       * than read off a record you already hold.\n       */\n      reload<This extends new (...args: any[]) => any>(\n        this: This,\n        ...args: A\n      ): Promise<InstanceType<This>>;\n    }\n  : {}) &\n  (Cfg extends { create: (...args: infer A) => any }\n    ? {\n        create<This extends new (...args: any[]) => any>(\n          this: This,\n          ...args: A\n        ): Promise<InstanceType<This>>;\n      }\n    : {});\n\nexport type ModelConstructor<S extends ModelSchema, K, Cfg> = {\n  new (data: Resource<S>): ModelInstance<S, K, Cfg>;\n  readonly schema: S;\n  /** Exactly what was declared, so `Model.keys` reads back the tuple — or `false`. */\n  readonly keys: K;\n} & ModelEvents<ModelInstance<S, K, Cfg>> &\n  (HasIdentity<K> extends true ? ModelIdentity<S, K, ModelInstance<S, K, Cfg>> : {}) &\n  ModelStatics<Cfg>;\n\n// -----------------------------------------------------------------------------\n// Shared class builder\n// -----------------------------------------------------------------------------\n\n// Builds the observable model class used by both makeModel and makeUnionModel.\n// Handles object and union schemas at runtime; the public factories layer the\n// appropriate types (and, for unions, the `is`/`as` guards) on top.\nfunction createModelClass(schema: ModelSchema, config?: ModelConfig<any, any>): any {\n  // `keys: false` opts out of identity, and no config at all means the same thing. `keys: []` is a\n  // different declaration: a resource with no identifying fields is a singleton, so it maps to one\n  // instance under a fixed key rather than to none.\n  const keySpec = (config?.keys ?? false) as readonly PropertyKey[] | false;\n  const hasIdentity = Array.isArray(keySpec);\n  const keys = (hasIdentity ? keySpec : []) as readonly PropertyKey[];\n  const isSingleton = hasIdentity && keys.length === 0;\n  const isUnion = T.IsUnion(schema);\n  const propertyNames = getPropertyNames(schema);\n\n  // Per-field observability overrides, resolved once here rather than per instance. A name that is\n  // not a schema field can only be a typo — mobx would report it as \"Field not found\" from inside a\n  // constructor, so catch it while the class is being built, where the config is in view.\n  const fieldAnnotations = (config?.annotations ?? {}) as Record<string, AnnotationMapEntry>;\n  for (const key of Object.keys(fieldAnnotations)) {\n    if (!propertyNames.includes(key)) {\n      throw new Error(\n        `[makeModel] annotations names \"${key}\", which is not a field of this schema. ` +\n          `Known fields: ${propertyNames.join(\", \")}. ` +\n          `To annotate a member a subclass adds, call makeObservable in the subclass constructor.`,\n      );\n    }\n  }\n\n  abstract class BaseModel {\n    static readonly schema = schema;\n    static readonly keys = keySpec;\n\n    /**\n     * Identity registry for this class. Created per class on first access — via an own property\n     * rather than an inherited one — so a subclass never shares its parent's registry and can\n     * never be handed a parent instance in its place.\n     */\n    static get identityCache(): WeakRefMap<string | number, any> {\n      if (!Object.hasOwn(this, \"_identityCache\")) {\n        Object.defineProperty(this, \"_identityCache\", {\n          value: new WeakRefMap<string | number, any>(),\n          configurable: true,\n        });\n      }\n      return (this as any)._identityCache;\n    }\n\n    /**\n     * The registry key for a payload or a model — both expose the schema's fields. Override on a\n     * subclass to scope identity, e.g. to fold in a tenant id so ids from different tenants can't\n     * collide.\n     */\n    static identityKey(source: any): string | number {\n      if (!hasIdentity) {\n        throw new Error(\n          \"This model has no identity — it was declared with `keys: false`, or with no config at all. Use `new Model(data)` for a detached instance, or declare `keys` to identity-map it.\",\n        );\n      }\n      // A singleton has no identifying fields to read, and only ever occupies this one entry.\n      if (isSingleton) return SINGLETON_KEY;\n      return serializeKey(keys.map((key) => source[key as keyof typeof source]));\n    }\n\n    /**\n     * The one instance for this record: the existing one with `data` applied to it, or a new one\n     * registered for next time. Use in place of `new Model(...)` so every part of the app that\n     * loads the same record ends up holding the same object.\n     */\n    static instantiate(data: any): any {\n      const key = this.identityKey(data);\n      const existing = this.identityCache.get(key);\n      if (existing) {\n        existing.setData(data);\n        return existing;\n      }\n      return this.identityCache.add(key, new (this as any)(data));\n    }\n\n    /**\n     * The instance already registered for these params, or `undefined`. Never fetches, so it is\n     * safe to call during render.\n     */\n    static peek(params?: any): any {\n      return this.identityCache.get(this.identityKey(params));\n    }\n\n    /**\n     * Drop a record's registry entry, so the next `instantiate` builds a fresh instance rather\n     * than reviving this one. Called automatically by `delete()`.\n     */\n    static forget(source: any): boolean {\n      return this.identityCache.delete(this.identityKey(source));\n    }\n\n    /** Forget every record. For teardown — a logout, or switching tenant. */\n    static clearIdentity(): void {\n      this.identityCache.clear();\n    }\n\n    /**\n     * Listeners, held weakly and per class, exactly as `identityCache` is. Weak because the model\n     * class outlives everything: a strong set would keep every store ever created alive, which for\n     * a scoped store means leaking it and every model in its collections.\n     */\n    static get listeners(): Set<WeakRef<ModelListener>> {\n      if (!Object.hasOwn(this, \"_listeners\")) {\n        Object.defineProperty(this, \"_listeners\", {\n          value: new Set<WeakRef<ModelListener>>(),\n          configurable: true,\n        });\n      }\n      return (this as any)._listeners;\n    }\n\n    static addListener(listener: ModelListener): void {\n      this.listeners.add(new WeakRef(listener));\n    }\n\n    /** Fan a mutation out, pruning any listener that has since been collected. */\n    static notifyListeners(type: ModelEventType, model: any): void {\n      for (const ref of this.listeners) {\n        const listener = ref.deref();\n        if (listener) listener.onModelEvent(type, model);\n        else this.listeners.delete(ref);\n      }\n    }\n\n    constructor(data: any) {\n      // Make every property of every variant observable up front, so `setData`\n      // stays reactive even when it switches the active variant. Foreign-variant\n      // fields sit as `undefined`; TypeScript hides them, and `toJSON` cleans them out.\n      const annotations: Record<string, any> = {};\n      for (const key of propertyNames) {\n        Object.defineProperty(this, key, {\n          value: (data as any)[key],\n          enumerable: true,\n          configurable: true,\n          writable: true,\n        });\n        annotations[key] = fieldAnnotations[key] ?? observable.ref;\n      }\n\n      // The constructor populates fields directly rather than through `setData`, so it carries its\n      // own stamp — a record built from a payload is loaded as of now, however it was built.\n      // Non-enumerable so it never rides along in a spread of the instance.\n      Object.defineProperty(this, LOADED_AT, {\n        value: Date.now(),\n        writable: true,\n        configurable: true,\n        enumerable: false,\n      });\n\n      makeObservable(this, { ...annotations, setData: action });\n    }\n\n    /**\n     * Replace the model's data with a complete resource. Every property is\n     * reassigned (fields absent from `data` — e.g. another variant's — become\n     * `undefined`), so the model always holds a coherent, whole variant rather\n     * than a partial merge that could mix fields across the union.\n     */\n    setData(data: any): void {\n      for (const key of propertyNames) {\n        (this as any)[key] = (data as any)[key];\n      }\n      // Refresh the stamp: every load of an *existing* record lands here, as the constructor does\n      // for a new one.\n      (this as any)[LOADED_AT] = Date.now();\n    }\n\n    /**\n     * Apply a partial, purely local edit. One action, so several fields land as one change and no\n     * reaction ever observes a torn intermediate state.\n     *\n     * Deliberately not a mutation in the API sense: no endpoint, no `updated` event — a store\n     * hearing one would mark its lists stale and refetch, throwing away this very edit — and no\n     * load-stamp refresh, since the record now disagrees with the server and `cache` must not treat\n     * it as freshly loaded.\n     */\n    updateData(patch: any): void {\n      const data = this as any;\n      const discriminator = (this.constructor as { discriminator?: string }).discriminator;\n\n      // The types forbid four things here; only two of them are worth re-checking at runtime, and\n      // they are the two that say *which record this is* rather than what it holds:\n      //\n      // - an identity key: the record stays filed under its old key while `buildParams` starts\n      //   reporting the new one, so `reload`/`update`/`delete` would address a different record.\n      // - the discriminator: the record then matches no variant, and `toJSON` emits a payload that\n      //   is invalid against the schema.\n      //\n      // The other two need no guard, because nothing downstream is fooled: an unknown field is\n      // ignored by `toJSON`, and a foreign variant's field is stripped by its `Value.Clean` — which\n      // that call already exists to do. Checking either would cost a schema or variant lookup per\n      // key to prevent a no-op.\n      const identifying = (key: string): boolean => key === discriminator || keys.includes(key);\n\n      // Checked in full before anything is written: a mobx action batches notifications but does\n      // not roll back, so assigning as we go would leave a rejected patch half-applied *and* would\n      // notify observers of that torn state.\n      const patchKeys = Object.keys(patch);\n      for (const key of patchKeys) {\n        if (identifying(key)) {\n          throw new Error(\n            `[updateData] \"${key}\" identifies which record this is and cannot be patched. ` +\n              `To make this a different record, pass a whole resource to setData.`,\n          );\n        }\n      }\n      runInAction(() => {\n        for (const key of patchKeys) data[key] = patch[key];\n      });\n    }\n\n    /**\n     * Build the params object passed as the first arg to keyed API methods.\n     * Default extracts each property in `keys` from the model. Override on a\n     * subclass when the model field name differs from the API param name, or\n     * to construct composite params from derived values.\n     */\n    buildParams(): any {\n      if (keys.length === 0) return undefined;\n      const data = this as any;\n      return Object.fromEntries(keys.map((k) => [k, data[k]]));\n    }\n\n    toJSON(): any {\n      const data = this as any;\n      const snapshot = propertyNames.reduce(\n        (obj, key) => {\n          if (data[key] !== undefined) obj[key] = toJS(data[key]);\n          return obj;\n        },\n        {} as Record<string, any>,\n      );\n      // For a union, strip any fields not belonging to the variant the current\n      // data matches (e.g. a stale field left over from a previous variant).\n      return isUnion ? Value.Clean(schema, snapshot) : snapshot;\n    }\n  }\n\n  const proto = BaseModel.prototype as any;\n\n  if (config?.get) {\n    const get = config.get as (...args: any[]) => Promise<any>;\n    const cache = config.cache ?? false;\n    const optimistic = config.optimistic ?? false;\n    // Cache is a policy over the identity map, so a model without one can never answer from it.\n    const cacheable = hasIdentity && cache !== false;\n\n    /**\n     * Whether a record may be answered with as it stands. An absent stamp always means no — that is\n     * how a failed background refresh forces the next `get` back to the API even under `cache: true`.\n     */\n    const isFresh = (model: any): boolean => {\n      const loadedAt = model[LOADED_AT];\n      if (loadedAt === undefined) return false;\n      if (cache === true) return true;\n      return Date.now() - loadedAt < (cache as { for: number }).for;\n    };\n\n    (BaseModel as any).reload = function (this: any, ...args: any[]) {\n      // Without identity there is nothing to map through, and the opt-out was explicit — so hand\n      // back a detached instance rather than throwing.\n      return get(...args).then((data: any) =>\n        hasIdentity ? this.instantiate(data) : new this(data),\n      );\n    };\n\n    (BaseModel as any).get = function (this: any, ...args: any[]) {\n      if (cacheable) {\n        // A keyed model is called as `get(params, ...rest)`; a singleton has no params, so every\n        // argument is rest. `identityKey` ignores its source for a singleton either way.\n        const rest = keys.length === 0 ? args : args.slice(1);\n        const existing = this.peek(args[0]);\n\n        if (existing) {\n          if (isFresh(existing)) return Promise.resolve(existing);\n\n          if (optimistic) {\n            // Answer now, refresh behind. A failure has nowhere to surface — this promise has\n            // already resolved — so it clears the stamp instead, which sends the next `get` to the\n            // API where the error can be reported normally.\n            void existing.reload(...rest).catch((cause: unknown) => {\n              console.error(cause);\n              existing[LOADED_AT] = undefined;\n            });\n            return Promise.resolve(existing);\n          }\n        }\n      }\n\n      return this.reload(...args);\n    };\n  }\n\n  if (config?.create) {\n    const create = config.create as (...args: any[]) => Promise<any>;\n    (BaseModel as any).create = function (this: any, ...args: any[]) {\n      return create(...args).then((data: any) => {\n        const model = hasIdentity ? this.instantiate(data) : new this(data);\n        this.notifyListeners(\"created\", model);\n        return model;\n      });\n    };\n  }\n\n  // One endpoint declaration serves both: `Model.get(params)` and the instance's `reload()`.\n  if (config?.get) {\n    const reload = config.get as (...args: any[]) => Promise<any>;\n    proto.reload = async function (...rest: any[]) {\n      const params = this.buildParams();\n      const data = params === undefined ? await reload(...rest) : await reload(params, ...rest);\n      runInAction(() => this.setData(data));\n      return this;\n    };\n  }\n\n  if (config?.update) {\n    const update = config.update as (...args: any[]) => Promise<any>;\n    proto.update = async function (body: any, ...rest: any[]) {\n      const params = this.buildParams();\n      const data =\n        params === undefined ? await update(body, ...rest) : await update(params, body, ...rest);\n      runInAction(() => this.setData(data));\n      (this.constructor as typeof BaseModel).notifyListeners(\"updated\", this);\n      return this;\n    };\n  }\n\n  if (config?.delete) {\n    const del = config.delete as (...args: any[]) => Promise<any>;\n    proto.delete = async function (...rest: any[]) {\n      const params = this.buildParams();\n      const result = params === undefined ? await del(...rest) : await del(params, ...rest);\n      // Every store listening to this model drops it, and a later payload for its key must not\n      // revive the instance.\n      (this.constructor as typeof BaseModel).notifyListeners(\"deleted\", this);\n      if (hasIdentity) (this.constructor as typeof BaseModel).forget(this);\n      return result;\n    };\n  }\n\n  if (config?.actions) {\n    for (const [name, fn] of Object.entries(config.actions)) {\n      const call = fn as (...args: any[]) => Promise<any>;\n      proto[name] = async function (body?: any, ...rest: any[]) {\n        const params = this.buildParams();\n        let data: any;\n        if (params === undefined) {\n          data = body === undefined ? await call() : await call(body, ...rest);\n        } else {\n          data = body === undefined ? await call(params) : await call(params, body, ...rest);\n        }\n        runInAction(() => this.setData(data));\n        (this.constructor as typeof BaseModel).notifyListeners(\"updated\", this);\n        return this;\n      };\n    }\n  }\n\n  return BaseModel;\n}\n\n// -----------------------------------------------------------------------------\n// makeModel (single object schemas)\n// -----------------------------------------------------------------------------\n\n// No config means no identity, which is exactly what `keys: false` declares — so it resolves to the\n// same `false` rather than being a rule of its own.\nexport function makeModel<S extends T.TObject>(schema: S): ModelConstructor<S, false, {}>;\nexport function makeModel<S extends T.TObject, K extends KeySpec<S>, Cfg extends ModelConfig<S, K>>(\n  schema: S,\n  config: Cfg & { keys: K } & ParamsMustBeKeys<S, K, Cfg>,\n): ModelConstructor<S, K, Cfg>;\nexport function makeModel<S extends T.TObject>(\n  schema: S,\n  config?: ModelConfig<S, KeySpec<S>>,\n): any {\n  return createModelClass(schema, config);\n}\n\n// -----------------------------------------------------------------------------\n// makeUnionModel (discriminated union schemas)\n// -----------------------------------------------------------------------------\n\n// Properties common to every variant (`keyof` a union resolves to shared keys).\ntype SharedFields<S extends UnionSchema> = { [K in keyof Resource<S>]: Resource<S>[K] };\n\n// The full static shape of the variant whose discriminator `D` equals `V`.\ntype VariantFields<S extends UnionSchema, D extends keyof Resource<S>, V> = Extract<\n  Resource<S>,\n  Record<D, V>\n>;\n\n// The members makeUnionModel adds. An interface (not a type-alias literal) so the\n// polymorphic `this` in `is`/`as` is allowed; at a call site `this` resolves to\n// the full instance, so the guard reveals the variant's fields on it.\ninterface UnionModelMembers<S extends UnionSchema, D extends keyof Resource<S>, K> {\n  setData(data: Resource<S>): void;\n  /**\n   * Apply a partial, purely local edit — every field in one action. Local only: no endpoint, no\n   * `updated` event, and no load-stamp refresh (see the note on the single-object form).\n   *\n   * On a union, the patch is typed against the *narrowed* instance. Un-narrowed, only the shared\n   * fields can be named; reach a variant's fields by narrowing first, which is what keeps a patch\n   * from grafting one variant's fields onto another:\n   *\n   * ```ts\n   * payment.updateData({ digits: [\"4\"] });        // ✗ not a shared field\n   * payment.as(\"card\")?.updateData({ digits: [\"4\"] }); // ✓\n   * ```\n   *\n   * The discriminator is not patchable: changing variant replaces the whole record, so it goes\n   * through `setData`. Identity keys are not patchable either.\n   */\n  updateData(patch: UnionPatch<S, D, K, this>): void;\n  /**\n   * The record as plain data, with any field outside its current variant stripped.\n   *\n   * The return type follows `this` the way `updateData`'s patch does, so a narrowed instance\n   * yields that variant alone rather than the whole union — `payment.as(\"card\")?.toJSON().digits`\n   * compiles, where the un-narrowed `payment.toJSON().digits` correctly does not.\n   */\n  toJSON(): VariantOf<S, D, this>;\n  buildParams(): KeyShape<S, K>;\n  /** Type guard: true when the discriminator equals `value`, revealing that variant's fields on this same instance. */\n  is<V extends Resource<S>[D]>(value: V): this is this & VariantFields<S, D, V>;\n  /** This instance narrowed to the `value` variant (fields exposed directly), or `undefined` if it doesn't match. */\n  as<V extends Resource<S>[D]>(value: V): (this & VariantFields<S, D, V>) | undefined;\n}\n\n// Base instance exposes only the shared fields (a single object type, so it can\n// be subclassed). Variant-specific fields exist at runtime but are revealed on\n// the type only through `is`/`as`.\ntype UnionModelInstance<\n  S extends UnionSchema,\n  D extends keyof Resource<S>,\n  K,\n  Cfg,\n> = SharedFields<S> & UnionModelMembers<S, D, K> & ModelMethods<K, Cfg>;\n\nexport type UnionModelConstructor<S extends UnionSchema, D extends keyof Resource<S>, K, Cfg> = {\n  new (data: Resource<S>): UnionModelInstance<S, D, K, Cfg>;\n  readonly schema: S;\n  readonly discriminator: D;\n  readonly keys: K;\n} & ModelEvents<UnionModelInstance<S, D, K, Cfg>> &\n  (HasIdentity<K> extends true ? ModelIdentity<S, K, UnionModelInstance<S, D, K, Cfg>> : {}) &\n  ModelStatics<Cfg>;\n\nexport function makeUnionModel<S extends UnionSchema, D extends keyof Resource<S> & string>(\n  schema: S,\n  discriminator: D,\n): UnionModelConstructor<S, D, false, {}>;\nexport function makeUnionModel<\n  S extends UnionSchema,\n  D extends keyof Resource<S> & string,\n  K extends KeySpec<S>,\n  Cfg extends ModelConfig<S, K>,\n>(\n  schema: S,\n  discriminator: D,\n  config: Cfg & { keys: K } & ParamsMustBeKeys<S, K, Cfg>,\n): UnionModelConstructor<S, D, K, Cfg>;\nexport function makeUnionModel(\n  schema: UnionSchema,\n  discriminator: string,\n  config?: ModelConfig<any, any>,\n): any {\n  const ModelClass = createModelClass(schema, config);\n  ModelClass.discriminator = discriminator;\n\n  const proto = ModelClass.prototype as any;\n  proto.is = function (value: unknown): boolean {\n    return (this as any)[discriminator] === value;\n  };\n  proto.as = function (value: unknown): unknown {\n    return (this as any)[discriminator] === value ? this : undefined;\n  };\n\n  return ModelClass;\n}\n\nexport type { AnnotationMapEntry };\nexport { WeakRefMap };\n","import * as T from \"typebox\";\nimport {\n  lazyArray,\n  lazyPages,\n  type LazyFetch,\n  type LazyFetchOptions,\n  type LazyInvalidateOptions,\n  type LazyArray,\n  type LazyOptions,\n  type LazyPageRequest,\n  type LazyPageResult,\n  type LazyPages,\n  type LazyPagesOptions,\n} from \"../lazy/lazy\";\nimport { action, makeObservable, runInAction } from \"mobx\";\nimport { serializeKey, type ModelEventType, type ModelSchema } from \"./make-model\";\n\n// -----------------------------------------------------------------------------\n// Type plumbing\n// -----------------------------------------------------------------------------\n\n/** Orders a collection, like `Array#sort` — but over model instances rather than payloads. */\nexport type Comparator<M> = (a: M, b: M) => number;\n\n/** Per-list options: everything a lazy observable takes, plus staleness and ordering. */\nexport interface CollectionOptions<M = any> extends LazyOptions {\n  /**\n   * Which mutations to this resource mark this list stale. Defaults to the store's `invalidateOn`,\n   * itself `[\"created\"]`. A deletion always removes the model from the list regardless.\n   */\n  invalidateOn?: readonly ModelEventType[];\n  /**\n   * Order this list. Defaults to the store's `sort`, since one ordering usually applies to every\n   * collection over a resource. Pass `false` to keep server order on this list alone.\n   */\n  sort?: Comparator<M> | false;\n  /**\n   * Show a record from `create()` in this list straight away, without waiting for the refetch that\n   * the `created` event triggers. Defaults to the store's `optimisticCreate`, itself `false`.\n   *\n   * Off by default because only the server knows whether a new record belongs in a given list: a\n   * filtered or searched collection would flash a row that does not belong to it. Turn it on for\n   * the lists a new record certainly joins — usually the unfiltered one.\n   */\n  optimisticCreate?: boolean;\n  /**\n   * Drop this list's rows while it refetches after being marked stale, rather than keeping them\n   * readable. Defaults to the store's `discardOnInvalidate`, itself `false`.\n   *\n   * Keeping them is usually right — the rows are still broadly correct and the list doesn't blank\n   * on every mutation. Discard when stale rows would actively mislead: a filtered list whose\n   * membership an `update` may have changed, for one.\n   */\n  discardOnInvalidate?: boolean;\n}\n\n/**\n * Per-list options for a paged collection: every {@link LazyPagesOptions} option, plus the two\n * store-level concerns that still apply.\n *\n * **`sort` is deliberately absent.** A comparator can only ever see the page in front of it, so\n * ordering a paged list client-side would sort each page against itself and leave the list\n * globally unordered — the order is the server's, and it is the server's for the same reason the\n * filtering is. A store-level `sort` is therefore *not* inherited here; nothing silently applies it\n * to one page at a time.\n */\nexport interface PagedCollectionOptions<M = any, Q = undefined>\n  extends LazyPagesOptions<M, Q>, Omit<CollectionOptions<M>, keyof LazyOptions | \"sort\"> {}\n\n/**\n * How a paged collection is declared to `createStore`: its fetch alone, or its fetch plus that\n * list's own options — the same two shapes as {@link CollectionSpec}.\n */\nexport type PagedCollectionSpec<R, M, Q = undefined> =\n  | ((request: LazyPageRequest<Q>) => Promise<LazyPageResult<R>>)\n  | ({\n      fetch: (request: LazyPageRequest<Q>) => Promise<LazyPageResult<R>>;\n    } & PagedCollectionOptions<M, Q>);\n\nexport interface StoreConfig<M = any> {\n  /**\n   * Order every collection on this store. Sorting is usually the one thing standing between an API\n   * client and being attached directly, and the same ordering almost always applies to every list\n   * over a resource — so it is declared once here, and a single collection can still override it.\n   *\n   * Runs over model instances on every load.\n   */\n  sort?: Comparator<M>;\n  /**\n   * Whether a record from `create()` appears in this store's lists before the refetch confirms it.\n   * Defaults to `false`; a single collection can still opt in or out.\n   */\n  optimisticCreate?: boolean;\n  /**\n   * Whether a list drops its rows while refetching after being marked stale, rather than keeping\n   * them readable. Defaults to `false`; a single collection can still opt in or out.\n   */\n  discardOnInvalidate?: boolean;\n  /**\n   * Which mutations to this resource — from *any* store, or from the model's own statics — mark this\n   * list stale. Defaults to `[\"created\"]`: a new record is the only event whose effect on a list\n   * can't be worked out locally, since only the server knows whether it belongs here.\n   *\n   * `\"updated\"` is not a default because identity means every list already shows the change — add it\n   * when membership depends on a field that can change. `\"deleted\"` is not a default either: the\n   * record is removed from every list outright, which needs no refetch — list it only when a deletion\n   * changes the list in some *other* way, a server-side count or ordering, say.\n   */\n  invalidateOn?: readonly ModelEventType[];\n}\n\n/**\n * How a collection is declared to `createStore`: its fetch alone, or its fetch plus that list's own\n * options. The verbose form is what lets a single collection override the store's `sort`, set its\n * own `invalidateOn`, or take any lazy option.\n */\nexport type CollectionSpec<R, M> =\n  | LazyFetch<R[]>\n  | ({ fetch: LazyFetch<R[]> } & CollectionOptions<M>);\n\n/**\n * A family of collections, one per key — the same list fetched separately per tenant, per parent\n * record, per page. Call it to get that key's list, building it on first use.\n */\nexport interface CollectionMap<K, M> {\n  (key: K): LazyArray<M>;\n  /**\n   * Drop one key's list, unregistering it from the store's mutation handling. For a key that is\n   * gone for good — an organization the user just left — so the map doesn't hold a list nothing\n   * will ask for again. The next call for that key builds a fresh one.\n   */\n  forget(key: K): boolean;\n  /** Drop every list this map has built. For teardown: a logout, a tenant switch. */\n  clear(): void;\n}\n\n/** Options for the free-form form of `collectionMap`, whose key is whatever you say it is. */\nexport interface CollectionMapOptions<K, M> extends CollectionOptions<M> {\n  /**\n   * Spell a key as something a map can hold. Only needed for a key that isn't already a string or\n   * a number — a filter object, a params tuple. The declared-fields form has no use for it: those\n   * serialize exactly as the identity map does.\n   */\n  keyOf?: (key: K) => string | number;\n}\n\n/** The payload a store's collections resolve to arrays of, read off the model class's schema. */\ntype StoreResource<MC> = MC extends { schema: infer S extends ModelSchema } ? T.Static<S> : never;\n\n/**\n * The fields a collection may be keyed by: those holding something that can be a map key on its\n * own. Anything else has no obvious spelling, so it belongs in the free-form form with a `keyOf`.\n */\ntype ScalarField<R> = {\n  [P in keyof R]-?: NonNullable<R[P]> extends string | number ? P : never;\n}[keyof R];\n\n/** Names a collection may not take, since each is already a member of the store. */\nexport type ReservedCollectionName =\n  | \"remove\"\n  | \"collection\"\n  | \"collectionMap\"\n  | \"pagedCollection\"\n  | \"invalidateCollections\"\n  | \"onModelEvent\"\n  | \"get\"\n  | \"create\";\n\n/**\n * `createStore` config: everything `makeStore` takes, plus the collections themselves. They live in\n * the config here because there is no subclass to hang them off — the moment you do subclass, every\n * collection is declared the same way, as a field built with `this.collection(...)`.\n */\nexport interface CreateStoreConfig<R, M> extends StoreConfig<M> {\n  collections: Record<string, CollectionSpec<R, M>> & {\n    [N in ReservedCollectionName]?: never;\n  };\n  /**\n   * Accumulating lists, declared alongside the ordinary ones and kept apart from them because they\n   * are a different shape of fetch: a page rather than the whole list. Each becomes a\n   * {@link LazyPages} on the instance, under its own name.\n   *\n   * ```ts\n   * createStore(SurveyModel, {\n   *   collections: { drafts: api.listDraftSurveys },\n   *   pagedCollections: { feed: ({ cursor, limit }) => api.listSurveys({ cursor, limit }) },\n   * });\n   * ```\n   */\n  pagedCollections?: Record<string, PagedCollectionSpec<R, M>> & {\n    [N in ReservedCollectionName]?: never;\n  };\n}\n\n// Final store-instance shape. `get`/`create` are delegated from the model class, so their presence\n// is keyed off the *class* rather than off an inferred config object. Each slot is declared as a\n// method rather than a function-valued property, so a subclass can override it with a method —\n// which TypeScript forbids when the base declares a property.\nexport type StoreInstance<M, MC, Cfg> = {\n  remove(model: M): void;\n  /**\n   * Mark every collection on this store stale, for a change no model event describes — a tenant\n   * switch, a filter reset, a refresh button. Unlike the event path this ignores `invalidateOn`: a\n   * list that opted out of refetching on *events* has not opted out of being told directly.\n   *\n   * Named for what it covers: a subclass may hold lazies that aren't collections — a count, a\n   * summary — and those are left alone.\n   */\n  invalidateCollections(options?: LazyInvalidateOptions): void;\n  onModelEvent(type: ModelEventType, model: M): void;\n  /**\n   * Build another list on this store. Payloads become models, the list joins this\n   * store's mutation handling, and every lazy option is available — so a search, a filtered view, or\n   * a polled list is a field on a subclass:\n   *\n   * ```ts\n   * class SurveySearch extends makeStore(SurveyModel) {\n   *   query = \"\";\n   *   results = this.collection((options) => api.search({ q: this.query, ...options }), {\n   *     trackDependencies: { throttle: 300 },\n   *   });\n   * }\n   * ```\n   */\n  collection(\n    fetch: LazyFetch<MC extends { schema: infer S extends ModelSchema } ? T.Static<S>[] : never[]>,\n    options?: CollectionOptions<M>,\n  ): LazyArray<M>;\n  /**\n   * Build an **accumulating** list on this store — one that grows a page at a time, for a dataset\n   * too large to hand over whole. Payloads become models and the list joins this store's mutation\n   * handling exactly as `collection()`'s does; what differs is that the fetch resolves one page:\n   *\n   * ```ts\n   * class Surveys extends makeStore(SurveyModel) {\n   *   feed = this.pagedCollection(({ cursor, limit, signal }) =>\n   *     api.listSurveys({ cursor, limit, signal }),\n   *   );\n   * }\n   *\n   * surveys.feed.loadMore();\n   * surveys.feed.total;\n   * ```\n   *\n   * `Q` is the query type the list is driven by — `TableQuery` when a table owns it. Deduplication\n   * defaults to the model's `identityKey`, and `sort` is not an option: see\n   * {@link PagedCollectionOptions}.\n   */\n  pagedCollection<Q = undefined>(\n    fetch: (\n      request: LazyPageRequest<Q>,\n    ) => Promise<\n      LazyPageResult<MC extends { schema: infer S extends ModelSchema } ? T.Static<S> : never>\n    >,\n    options?: PagedCollectionOptions<M, Q>,\n  ): LazyPages<M, Q>;\n  /**\n   * Build a *family* of lists on this store, one per key, for a resource that has to be fetched\n   * separately per tenant, per parent record, or per page — keys you can't enumerate in advance.\n   * Each list is built on first use and behaves exactly as a `collection()` does from then on.\n   *\n   * Name the fields that select a list and the fetch's params are typed from the schema, the same\n   * way a model's `keys` type its statics:\n   *\n   * ```ts\n   * class Surveys extends makeStore(SurveyModel) {\n   *   byOrg = this.collectionMap([\"orgId\"], ({ orgId }, options) =>\n   *     api.listSurveys({ orgId, ...options }),\n   *   );\n   * }\n   *\n   * surveys.byOrg({ orgId }).getOrLoad();\n   * ```\n   *\n   * Reach for the free-form form below when the key isn't a field on the resource — a page number,\n   * a filter of your own.\n   */\n  collectionMap<F extends ScalarField<StoreResource<MC>>>(\n    keys: readonly [F, ...F[]],\n    fetch: (\n      params: Pick<StoreResource<MC>, F>,\n      options: LazyFetchOptions,\n    ) => Promise<StoreResource<MC>[]>,\n    options?: CollectionOptions<M>,\n  ): CollectionMap<Pick<StoreResource<MC>, F>, M>;\n  /**\n   * Keyed by something that isn't a field on the resource:\n   *\n   * ```ts\n   * pages = this.collectionMap((page: number, options) =>\n   *   api.listSurveys({ page, ...options }),\n   * );\n   * ```\n   */\n  collectionMap<K extends string | number>(\n    fetch: (key: K, options: LazyFetchOptions) => Promise<StoreResource<MC>[]>,\n    options?: CollectionOptions<M>,\n  ): CollectionMap<K, M>;\n  /** Keyed by a value a map can't hold as it stands, so `keyOf` says how to spell it. */\n  collectionMap<K>(\n    fetch: (key: K, options: LazyFetchOptions) => Promise<StoreResource<MC>[]>,\n    options: CollectionMapOptions<K, M> & { keyOf: (key: K) => string | number },\n  ): CollectionMap<K, M>;\n} & (MC extends { get: (...args: infer A) => any } ? { get(...args: A): Promise<M> } : {}) &\n  (Cfg extends { collections: infer C } ? { [N in keyof C]: LazyArray<M> } : {}) &\n  // Each paged entry's query type is carried through from its own fetch, so a list a table drives\n  // types `query` inside that fetch rather than falling back to `undefined`.\n  (Cfg extends { pagedCollections: infer P }\n    ? {\n        [N in keyof P]: P[N] extends PagedCollectionSpec<any, any, infer Q>\n          ? LazyPages<M, Q>\n          : LazyPages<M>;\n      }\n    : {}) &\n  (MC extends { create: (...args: infer A) => any } ? { create(...args: A): Promise<M> } : {});\n\nexport type StoreConstructor<M, MC, Cfg> = {\n  new (): StoreInstance<M, MC, Cfg>;\n};\n\n// -----------------------------------------------------------------------------\n// makeStore\n// -----------------------------------------------------------------------------\n\n/**\n * A class produced by `makeModel`/`makeUnionModel`: it carries its own schema, so passing one to\n * `makeStore` means not repeating the schema, and its identity map is wired up by default.\n */\nexport type AnyModelClass = {\n  readonly schema: ModelSchema;\n  new (data: any, store?: any): any;\n};\n\nexport function makeStore<MC extends AnyModelClass>(\n  model: MC,\n): StoreConstructor<InstanceType<MC>, MC, {}>;\nexport function makeStore<MC extends AnyModelClass, Cfg extends StoreConfig<InstanceType<MC>>>(\n  model: MC,\n  config: Cfg,\n): StoreConstructor<InstanceType<MC>, MC, Cfg>;\nexport function makeStore(\n  ModelClass: AnyModelClass,\n  config?: StoreConfig<any> & {\n    collections?: Record<string, CollectionSpec<any, any>>;\n    pagedCollections?: Record<string, PagedCollectionSpec<any, any>>;\n  },\n): StoreConstructor<any, any, any> {\n  type R = any;\n\n  const Model = ModelClass as any;\n\n  // Route through the model's identity map whenever it has one, so every list, `get`, and `create`\n  // hands back the same instance for a record. `keys` is `false` on a model that declared no\n  // identity; an empty array is a singleton, which still maps.\n  const buildModel = (data: R) =>\n    Array.isArray(Model.keys) ? Model.instantiate(data) : new Model(data);\n\n  class Store {\n    /** Every list this store owns, with the events that mark each stale and how each is ordered. */\n    private readonly _collections: {\n      lazy: LazyArray<any>;\n      invalidateOn: readonly ModelEventType[];\n      sort: Comparator<any> | undefined;\n      optimisticCreate: boolean;\n      discardOnInvalidate: boolean;\n    }[] = [];\n\n    constructor() {\n      makeObservable<this, \"_collections\" | \"unregister\">(this, {\n        _collections: false,\n        unregister: false,\n        remove: action,\n        invalidateCollections: action,\n        onModelEvent: action,\n      });\n\n      // `createStore` puts collections in the config, since it has no subclass to hang them off.\n      // They go through the same `collection()` a subclass field would.\n      for (const [name, spec] of Object.entries(config?.collections ?? {})) {\n        if (name in this) {\n          throw new Error(`Collection \"${name}\" would shadow a member the store already has.`);\n        }\n        const { fetch, ...options } = typeof spec === \"function\" ? { fetch: spec } : spec;\n        (this as any)[name] = this.collection(fetch, options);\n      }\n\n      for (const [name, spec] of Object.entries(config?.pagedCollections ?? {})) {\n        if (name in this) {\n          throw new Error(`Collection \"${name}\" would shadow a member the store already has.`);\n        }\n        const { fetch, ...options } = typeof spec === \"function\" ? { fetch: spec } : spec;\n        (this as any)[name] = this.pagedCollection(fetch, options);\n      }\n\n      // Held weakly, so registering never keeps this store alive.\n      Model.addListener?.(this);\n    }\n\n    /**\n     * Build another list on this store: payloads become models, and the list joins this store's\n     * mutation handling. Call it in a subclass field initializer.\n     */\n    collection(fetch: LazyFetch<R[]>, options?: CollectionOptions<any>): LazyArray<any> {\n      const { invalidateOn, sort, optimisticCreate, discardOnInvalidate, ...lazyOptions } =\n        options ?? {};\n      // Omitted means \"use the store's\"; `false` means this one list keeps server order.\n      const comparator = (sort === undefined ? config?.sort : sort) || undefined;\n      const lazy = lazyArray(\n        async (fetchOptions) => {\n          const items = await fetch(fetchOptions);\n          const models = items.map((item) => buildModel(item));\n          return comparator ? models.sort(comparator) : models;\n        },\n        // deep: false — models are observable in their own right, so nothing needs converting.\n        { deep: false, ...lazyOptions },\n      );\n      this._collections.push({\n        lazy,\n        invalidateOn: invalidateOn ?? config?.invalidateOn ?? [\"created\"],\n        sort: comparator,\n        optimisticCreate: optimisticCreate ?? config?.optimisticCreate ?? false,\n        discardOnInvalidate: discardOnInvalidate ?? config?.discardOnInvalidate ?? false,\n      });\n      return lazy;\n    }\n\n    /**\n     * Build an **accumulating** list on this store: one that grows a page at a time rather than\n     * arriving whole. Payloads become models exactly as `collection()` does, and the list joins\n     * this store's mutation handling identically — `invalidateCollections()` reaches it, a\n     * `created` event marks it stale, a deletion drops the model from it.\n     *\n     * ```ts\n     * class Surveys extends makeStore(SurveyModel) {\n     *   feed = this.pagedCollection(({ cursor, limit, signal }) =>\n     *     api.listSurveys({ cursor, limit, signal }),\n     *   );\n     * }\n     * ```\n     *\n     * The fetch resolves a page rather than the list — a bare array, or an envelope carrying\n     * `cursor` / `total` / `hasMore`. The envelope is unwrapped, its items become models, and it is\n     * handed on intact, so the paging fields reach `lazyPages` and `total` is readable off the list.\n     * That is the whole of what a store had to add: `collection()` maps `R[] -> M[]`, and this maps\n     * the `items` inside whatever shape they arrived in.\n     *\n     * **Deduplication is on by default** for an identity-mapped model, keyed on `identityKey`.\n     * That is not a nicety: a record served on two pages — a cursor over a non-unique sort key, an\n     * offset while rows are being inserted — is *literally the same object* under identity, so it\n     * would appear twice in one array. A table keys its rows by identity, so that means two rows\n     * sharing a React key and one selection toggle hitting both. Pass your own `dedupeBy` to\n     * override, or a model with no identity gets none (there is nothing to key on).\n     *\n     * An invalidation restarts the list at page one, which is what marking a *paged* list stale has\n     * to mean: the membership and ordering of every page after the first depend on the first.\n     *\n     * See {@link PagedCollectionOptions} for why `sort` is not among the options.\n     */\n    pagedCollection(\n      fetch: (request: LazyPageRequest<any>) => Promise<LazyPageResult<R>>,\n      options?: PagedCollectionOptions<any, any>,\n    ): LazyPages<any, any> {\n      const { invalidateOn, optimisticCreate, discardOnInvalidate, dedupeBy, ...pagesOptions } =\n        options ?? {};\n\n      const list = lazyPages(\n        async (request) => {\n          const page = await fetch(request);\n          if (Array.isArray(page)) return page.map((item) => buildModel(item));\n          // Spread rather than rebuild: `lazyPages` treats the *presence* of `cursor` as\n          // authoritative for `hasMore`, so a key that arrived has to survive the trip even when\n          // its value is null.\n          return { ...page, items: page.items.map((item) => buildModel(item)) };\n        },\n        {\n          // deep: false — models are observable in their own right, so nothing needs converting.\n          deep: false,\n          // Identity is exactly the right key, and the failure it prevents is invisible otherwise.\n          ...(Array.isArray(Model.keys) ? { dedupeBy: (m: any) => Model.identityKey(m) } : {}),\n          ...pagesOptions,\n          ...(dedupeBy ? { dedupeBy } : {}),\n        },\n      );\n\n      this._collections.push({\n        lazy: list,\n        invalidateOn: invalidateOn ?? config?.invalidateOn ?? [\"created\"],\n        // Never a comparator: see `PagedCollectionOptions`. A store-level `sort` stops here rather\n        // than being applied to one page at a time — which also means `create()` prepends an\n        // optimistic row instead of placing it.\n        sort: undefined,\n        optimisticCreate: optimisticCreate ?? config?.optimisticCreate ?? false,\n        discardOnInvalidate: discardOnInvalidate ?? config?.discardOnInvalidate ?? false,\n      });\n      return list;\n    }\n\n    /**\n     * Build a family of lists, one per key, each built on first use and registered exactly as a\n     * `collection()` is — so every key's list joins this store's mutation handling, is marked\n     * stale by `invalidateCollections()`, and drops a deleted model like any other list.\n     *\n     * The two forms differ only in how a key is spelled: declared fields serialize through the\n     * same `serializeKey` the identity map uses, and a free-form key is used as-is unless `keyOf`\n     * says otherwise.\n     */\n    collectionMap(\n      keysOrFetch: readonly string[] | ((key: any, options: any) => Promise<R[]>),\n      fetchOrOptions?: any,\n      maybeOptions?: CollectionOptions<any>,\n    ): any {\n      const fields = Array.isArray(keysOrFetch) ? (keysOrFetch as readonly string[]) : undefined;\n      const fetch = (fields ? fetchOrOptions : keysOrFetch) as (\n        key: any,\n        options: any,\n      ) => Promise<R[]>;\n      // `keyOf` is ours, not a lazy option — it must not travel on to `collection()`.\n      const { keyOf, ...options } = ((fields ? maybeOptions : fetchOrOptions) ??\n        {}) as CollectionMapOptions<any, any>;\n\n      const serialize = fields\n        ? (params: any) => serializeKey(fields.map((field) => params[field]))\n        : (keyOf ?? ((key: any) => key as string | number));\n\n      const byKey = new Map<string | number, LazyArray<any>>();\n\n      const map = (key: any): LazyArray<any> => {\n        const id = serialize(key);\n        const existing = byKey.get(id);\n        if (existing) return existing;\n        // Only the declared fields reach the fetch, so selecting a list with a whole record is the\n        // same call as selecting it with the fields alone — and whatever else the first caller\n        // happened to pass can't leak into a list every later caller shares.\n        const params = fields\n          ? Object.fromEntries(fields.map((field) => [field, key[field]]))\n          : key;\n        const lazy = this.collection((fetchOptions) => fetch(params, fetchOptions), options);\n        byKey.set(id, lazy);\n        return lazy;\n      };\n\n      return Object.assign(map, {\n        forget: (key: any): boolean => {\n          const id = serialize(key);\n          const lazy = byKey.get(id);\n          if (!lazy) return false;\n          this.unregister(lazy);\n          return byKey.delete(id);\n        },\n        clear: (): void => {\n          for (const lazy of byKey.values()) this.unregister(lazy);\n          byKey.clear();\n        },\n      });\n    }\n\n    /**\n     * Take a list back out of this store's mutation handling. Only a keyed collection is ever\n     * dropped — a field collection lives as long as the store does, so there is nothing to\n     * unregister and no public method for it.\n     */\n    private unregister(lazy: LazyArray<any>): void {\n      const at = this._collections.findIndex((entry) => entry.lazy === lazy);\n      if (at !== -1) this._collections.splice(at, 1);\n    }\n\n    /** Drop a model from every list on this store, without implying the record is gone. */\n    remove(model: any): void {\n      for (const { lazy } of this._collections) lazy.value?.remove(model);\n    }\n\n    /**\n     * Mark every collection on this store stale. For a change no model event describes — a tenant\n     * switch, a filter reset, a refresh button. `invalidateOn` is deliberately not consulted: it\n     * governs which *events* reach a list, not whether you can refetch one on purpose.\n     *\n     * Only collections: a subclass's own lazies are its business, and it can invalidate them in\n     * whatever handler already knows they need it.\n     */\n    invalidateCollections(options?: LazyInvalidateOptions): void {\n      for (const { lazy, discardOnInvalidate } of this._collections) {\n        // An explicit `discard` wins; otherwise each list's own declaration stands.\n        lazy.invalidate({ discard: options?.discard ?? discardOnInvalidate });\n      }\n    }\n\n    /**\n     * A mutation happened somewhere — this store, another store over the same resource, or the\n     * model's own statics. A deletion always drops the model from this list; whether any event also\n     * marks the list stale is up to `invalidateOn`.\n     */\n    onModelEvent(type: ModelEventType, model: any): void {\n      for (const { lazy, invalidateOn, discardOnInvalidate } of this._collections) {\n        // Removal is unconditional: the record is gone, and dropping it is always correct.\n        if (type === \"deleted\") lazy.value?.remove(model);\n        if (invalidateOn.includes(type)) lazy.invalidate({ discard: discardOnInvalidate });\n      }\n    }\n  }\n\n  const proto = Store.prototype as any;\n\n  if (typeof Model.get === \"function\") {\n    // The static already returns the identity-mapped instance, and removal travels by event rather\n    // than by ownership, so there is nothing for the store to add.\n    proto.get = function (...args: any[]) {\n      return Model.get(...args);\n    };\n  }\n\n  if (typeof Model.create === \"function\") {\n    proto.create = async function (...args: any[]) {\n      const model = await Model.create(...args);\n      return runInAction(() => {\n        // Show it immediately in the lists that asked for it; the `created` event has already\n        // marked them stale, so the server still gets the last word on position and membership.\n        // Identity means the refetch reuses this instance, so the row moves rather than flickering.\n        for (const { lazy, sort, optimisticCreate } of this._collections) {\n          if (!optimisticCreate) continue;\n          const rows = lazy.value;\n          if (rows.includes(model)) continue;\n          if (!sort) {\n            rows.unshift(model);\n            continue;\n          }\n          // Land it where the configured order puts it, rather than at the top where the next\n          // load would visibly move it.\n          const at = rows.findIndex((existing: any) => sort(model, existing) < 0);\n          rows.splice(at === -1 ? rows.length : at, 0, model);\n        }\n        return model;\n      });\n    };\n  }\n\n  return Store as unknown as StoreConstructor<any, any, any>;\n}\n\n/**\n * `makeStore` plus `new`, for a store you don't need to subclass. Its collections are named in the\n * config and land on the instance under those names — so `createStore` is the whole story when a\n * store is just lists over a resource, and the moment you need behaviour of your own you move to\n * `makeStore` and declare every collection as a field.\n *\n * ```ts\n * const surveys = createStore(SurveyModel, {\n *   sort: (a, b) => a.name.localeCompare(b.name),\n *   collections: {\n *     all: (options) => api.listSurveys(options),\n *     drafts: { fetch: (options) => api.listSurveys({ status: \"draft\", ...options }), sort: false },\n *   },\n * });\n *\n * surveys.all.getOrLoad();\n * ```\n */\nexport function createStore<\n  MC extends AnyModelClass,\n  Cfg extends CreateStoreConfig<T.Static<MC[\"schema\"]>, InstanceType<MC>>,\n>(model: MC, config: Cfg): StoreInstance<InstanceType<MC>, MC, Cfg>;\n\nexport function createStore(model: AnyModelClass, config: CreateStoreConfig<any, any>): any {\n  return new (makeStore(model, config as any))();\n}\n\nexport type { LazyArray };\n","import { useObservableBox } from \"../util/use-observable-box\";\nimport { useStable } from \"../react-util/useStable\";\nimport type * as T from \"typebox\";\nimport type {\n  LazyFetch,\n  LazyFetchOptions,\n  LazyArray,\n  LazyPageRequest,\n  LazyPageResult,\n  LazyPages,\n} from \"../lazy/lazy\";\nimport {\n  makeStore,\n  type AnyModelClass,\n  type CollectionOptions,\n  type PagedCollectionOptions,\n} from \"./make-store\";\n\n/** The payload a model's collections resolve to arrays of. */\ntype Payload<MC extends AnyModelClass> = T.Static<MC[\"schema\"]>;\n\n/**\n * `CollectionOptions` plus the component's own inputs. Their type is inferred from what you pass,\n * so the fetch's first argument is typed without declaring anything twice — and since they are the\n * one reactive part, `trackDependencies` defaults to `true` when they are present.\n */\nexport interface UseCollectionOptions<P, M> extends CollectionOptions<M> {\n  params: P;\n}\n\n/**\n * {@link PagedCollectionOptions} plus the component's own inputs, which arrive as the fetch's\n * first argument. Same params-first shape as `useCollection`, and the same consequence:\n * `trackDependencies` defaults to `true` when they are present, because reading them is what makes\n * a change restart the list.\n */\nexport interface UsePagedCollectionOptions<P, M, Q = undefined> extends PagedCollectionOptions<\n  M,\n  Q\n> {\n  params: P;\n}\n\n/**\n * One store per model class, rather than one per component: `makeStore` builds a class, and there\n * is no reason for two components over the same model to each build their own.\n */\nconst storeClasses = new WeakMap<AnyModelClass, new () => any>();\n\nconst storeClassFor = (model: AnyModelClass): new () => any => {\n  let StoreClass = storeClasses.get(model);\n  if (!StoreClass) {\n    StoreClass = makeStore(model) as unknown as new () => any;\n    storeClasses.set(model, StoreClass);\n  }\n  return StoreClass;\n};\n\n/**\n * A collection that belongs to one component: `store.collection()`, for a list whose parameters are\n * the component's own — a filter, a search box, a route param — where a shared store is the wrong\n * home for them.\n *\n * ```tsx\n * const list = useCollection(SurveyModel, (options) => api.listSurveys(options));\n * ```\n *\n * Pass `params` and they arrive as the fetch's first argument, ahead of the lazy's own options —\n * the same params-first shape `collectionMap` uses. They are plain React values; the hook keeps\n * them in an observable the fetch reads through, so a change refetches while leaving the current\n * rows readable and aborting the request it supersedes:\n *\n * ```tsx\n * const [query, setQuery] = useState(\"\");\n *\n * const list = useCollection(\n *   SurveyModel,\n *   ({ orgId, query }, options) => api.listSurveys({ orgId, q: query, ...options }),\n *   { params: { orgId, query }, trackDependencies: { throttle: 300 } },\n * );\n * ```\n *\n * Being component-scoped costs nothing global: the model's identity map still hands out one\n * instance per record, and mutations still fan out — so an edit here shows in the app-wide store\n * and vice versa. Nothing needs disposing either, since the model holds its listeners weakly.\n */\nexport function useCollection<MC extends AnyModelClass>(\n  model: MC,\n  fetch: LazyFetch<Payload<MC>[]>,\n  // `params?: never` is what keeps this overload out of the way of the one below. Without it,\n  // options carrying `params` *and* anything else — `{ params, trackDependencies }` — resolved to\n  // neither overload: this one is only rejected by an excess-property check, which TypeScript\n  // stops applying once another key matches, so the params-form arrow got no contextual type and\n  // every one of its parameters read as an implicit `any`. Spelled the same way `UseTableConfig`\n  // separates its two arms.\n  options?: CollectionOptions<InstanceType<MC>> & { params?: never },\n): LazyArray<InstanceType<MC>>;\nexport function useCollection<MC extends AnyModelClass, P extends object>(\n  model: MC,\n  fetch: (params: P, options: LazyFetchOptions) => Promise<Payload<MC>[]>,\n  options: UseCollectionOptions<P, InstanceType<MC>>,\n): LazyArray<InstanceType<MC>>;\n\nexport function useCollection(model: AnyModelClass, fetch: any, options?: any): any {\n  const hasParams = options !== undefined && \"params\" in options;\n  const { params, ...collectionOptions } = options ?? {};\n\n  // Built once per component and garbage the moment it unmounts: the model holds its listeners\n  // weakly, so a component-scoped store needs no disposal.\n  const store = useStable(() => new (storeClassFor(model))(), []);\n  const box = useObservableBox(params);\n\n  // No deps: a collection's params are inputs to this one list, read through the box, so a change\n  // refetches rather than building a different list.\n  return useStable(\n    () =>\n      store.collection(\n        hasParams\n          ? (fetchOptions: LazyFetchOptions) => fetch(box.get(), fetchOptions)\n          : (fetchOptions: LazyFetchOptions) => fetch(fetchOptions),\n        {\n          // Reading the box is what makes a param change refetch, so tracking has to be on. Without\n          // params there is nothing to track and `collection()`'s own default stands.\n          ...(hasParams ? { trackDependencies: true } : {}),\n          ...collectionOptions,\n        },\n      ),\n    [],\n  );\n}\n\n/**\n * An accumulating list that belongs to one component — an infinite feed, a load-more table — whose\n * parameters are the component's own.\n *\n * ```tsx\n * const feed = usePagedCollection(SurveyModel, ({ cursor, limit, signal }) =>\n *   api.listSurveys({ cursor, limit, signal }),\n * );\n * ```\n *\n * Everything `pagedCollection()` gives a store-owned list applies here: payloads become\n * identity-mapped models, duplicates across page boundaries are dropped on `identityKey`, a\n * `created` event restarts the list, and a deletion removes the record from it. Being\n * component-scoped costs none of that — the model's identity map and event fan-out are global, so\n * an edit here shows up in the app-wide store and vice versa, and nothing needs disposing because\n * the model holds its listeners weakly.\n *\n * **Bound to a table, there is nothing else to write.** The table infers `mode: \"server\"`, pushes\n * its query in, and asks for the next page as the window nears the end:\n *\n * ```tsx\n * const feed = usePagedCollection<typeof SurveyModel, TableQuery>(\n *   SurveyModel,\n *   ({ query, cursor, limit, signal }) =>\n *     api.listSurveys({ where: query.filters, sort: query.sorts, cursor, limit, signal }),\n * );\n * const table = useTable({ data: feed, columns });\n * ```\n *\n * `params` are for inputs the *table doesn't own* — a route param, a parent record. They arrive as\n * the fetch's first argument and a change restarts the list, leaving the rows readable while page\n * one of the new list loads.\n */\nexport function usePagedCollection<MC extends AnyModelClass, Q = undefined>(\n  model: MC,\n  fetch: (request: LazyPageRequest<Q>) => Promise<LazyPageResult<Payload<MC>>>,\n  // See the note on `useCollection`'s first overload for why `params?: never` is here.\n  options?: PagedCollectionOptions<InstanceType<MC>, Q> & { params?: never },\n): LazyPages<InstanceType<MC>, Q>;\nexport function usePagedCollection<MC extends AnyModelClass, P extends object, Q = undefined>(\n  model: MC,\n  fetch: (params: P, request: LazyPageRequest<Q>) => Promise<LazyPageResult<Payload<MC>>>,\n  options: UsePagedCollectionOptions<P, InstanceType<MC>, Q>,\n): LazyPages<InstanceType<MC>, Q>;\n\nexport function usePagedCollection(model: AnyModelClass, fetch: any, options?: any): any {\n  const hasParams = options !== undefined && \"params\" in options;\n  const { params, ...collectionOptions } = options ?? {};\n\n  const store = useStable(() => new (storeClassFor(model))(), []);\n  const box = useObservableBox(params);\n\n  // No deps, for the same reason `useCollection` has none: params are inputs to *this* list, read\n  // through the box, so a change restarts it rather than building a different one.\n  return useStable(\n    () =>\n      store.pagedCollection(\n        hasParams\n          ? (request: LazyPageRequest<any>) => fetch(box.get(), request)\n          : (request: LazyPageRequest<any>) => fetch(request),\n        {\n          // Reading the box is what makes a param change restart the list, so tracking has to be\n          // on. Note this survives a `setQuery` from a table: the reload it triggers reinstalls the\n          // tracking reaction, and the pager's own state stays out of the dependency set because it\n          // is read inside an action.\n          ...(hasParams ? { trackDependencies: true } : {}),\n          ...collectionOptions,\n        },\n      ),\n    [],\n  );\n}\n","import { useLazy } from \"../lazy/use-lazy\";\nimport type { Lazy, LazyFetchOptions, LazyOptions } from \"../lazy/lazy\";\nimport type { AnyModelClass } from \"./make-store\";\n\n/**\n * The params `Model.get` takes, read off the model itself — so a keyed model requires exactly the\n * fields it declared and a keyless one takes `undefined`, without any of that being restated here.\n *\n * A conditional rather than a constraint, matching how `makeStore` reads the same statics: the\n * generated `get` is generic over the class it is called on, which a plain structural constraint\n * fails to match. A model with no `get` resolves to `never`, so there is nothing that can be passed\n * for `params` and the call fails at the argument rather than the type parameter.\n */\ntype GetParams<MC> = MC extends { get: (params: infer P, ...rest: any[]) => any } ? P : never;\n\n/**\n * Whether the model declared no key params, so `Model.get` takes none.\n *\n * Asked through `K[number]` rather than `K extends readonly []` for the reason `makeModel` documents\n * on its own `Keyless`: an inline `keys: []` infers as `never[]`, which is not assignable to\n * `readonly []` and would read as keyed. This is the same question `buildParams()` answers at\n * runtime, so the type and the call can't disagree about which argument is which.\n */\ntype Keyless<MC> = MC extends { keys: infer K }\n  ? [K] extends [readonly any[]]\n    ? [K[number]] extends [never]\n      ? true\n      : false\n    : true\n  : true;\n\n/**\n * What `Model.get` takes after its params — the part of the fetcher's signature this hook has to\n * be able to satisfy on its own.\n */\ntype FetchArgs<MC> =\n  Keyless<MC> extends true\n    ? MC extends { get: (...args: infer A) => any }\n      ? A\n      : never\n    : MC extends { get: (params: any, ...rest: infer R) => any }\n      ? R\n      : never;\n\n/**\n * Whether the hook can drive this model's `get`.\n *\n * Every other layer that calls a fetch *declares* the shape it will call — `lazy` takes a\n * `LazyFetch`, `collection` the same, `collectionMap` a `(key, options)`, `pagedCollection` a\n * `(request)` — so a fetcher with an argument they can't fill is rejected where it is attached.\n * This hook is the one that inherits its fetcher's signature from the model config, which is\n * deliberately pass-through, so it has to state the same contract here instead.\n *\n * The contract is `get(keys, options?)`, or `get(options?)` with no keys, and the question asked of\n * that trailing parameter is whether a `LazyFetchOptions` can *satisfy* it — not whether it is\n * spelled one. That admits the partial shapes a client declares for itself: `RequestInit`,\n * `{ signal?: AbortSignal }`, an optional bag, a required one. It also admits a fetcher taking\n * nothing after its params, where the bag is ignored as in any JavaScript call, and one with an\n * untyped rest, where there is nothing to check.\n *\n * What it rejects is a parameter the bag cannot stand in for: `expand: string`, an options type\n * needing more than a signal, or a required argument past the bag. Optionality doesn't rescue any\n * of them, because arguments go by position — `(keys, expand?: string, o?)` would receive the bag\n * as its `expand`, and the request would get no signal at all.\n */\ntype HookFetchable<MC> =\n  FetchArgs<MC> extends [] ? true : [LazyFetchOptions] extends FetchArgs<MC> ? true : false;\n\n/**\n * Attached to the model argument so an unreachable fetcher fails here, at the hook, rather than by\n * sending the options bag to whatever argument happened to be in the way. Named as a sentence\n * against the repo's usual style on purpose: TypeScript prints the alias name and elides the\n * structure, so the name is the only part of this the reader will see.\n */\ntype UseLazyInstead_GetTakesMoreThanParamsAndFetchOptions = {\n  readonly __useLazyInstead: never;\n};\n\n/**\n * Everything after the model. A keyless model has nothing to pass for params, so it takes options\n * directly rather than a placeholder ahead of them.\n */\ntype UseModelArgs<MC> =\n  Keyless<MC> extends true\n    ? [options?: LazyOptions]\n    : [params: GetParams<MC>, options?: LazyOptions];\n\n/**\n * Turn `params` into a dependency list. Sorted by key so a differently-ordered object of the same\n * values isn't read as a change, and keys are included alongside values so adding or removing one\n * counts.\n */\nconst paramsToDeps = (params: unknown): unknown[] => {\n  if (params === undefined || params === null || typeof params !== \"object\") return [params];\n  return Object.entries(params as Record<string, unknown>)\n    .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n    .flat();\n};\n\n/**\n * One record, loaded in a component — the detail-page counterpart to {@link useCollection}.\n *\n * ```tsx\n * const StudyPage = observer(({ studyId }: { studyId: string }) => {\n *   const study = useModel(StudyModel, { id: studyId });\n *\n *   return (\n *     <LazyObserver observe={study} placeholder={<Spinner />}>\n *       {(s) => <StudyDetail study={s} />}\n *     </LazyObserver>\n *   );\n * });\n * ```\n *\n * What comes back is an ordinary `lazy` over the model's own `get`, so it loads when\n * something observes it, honours whatever the model declared for `cache`, and hands back the\n * identity-mapped instance — an edit made anywhere else in the app shows up here.\n *\n * **The params are the dependencies.** There is no dependency array to keep in step with them, which\n * is the whole reason this exists rather than spelling it out with `useLazy`:\n *\n * ```tsx\n * useLazy((o) => StudyModel.get({ id, orgId }, o), [id]); // `orgId` forgotten — silently stale\n * useModel(StudyModel, { id, orgId }); // can't desync\n * ```\n *\n * They are compared shallowly, so rebuilding the object every render costs nothing. A change builds\n * a new lazy — the value starts empty and loads again, which is what you want for a record: showing\n * the study you navigated away from while the next one loads would be a lie.\n *\n * A model with no key params (`keys: []` or `keys: false`) takes no params argument at all —\n * `useModel(SettingsModel)`, and `useModel(SettingsModel, { keepOnUnobserved: true })` for options.\n */\nexport function useModel<MC extends AnyModelClass>(\n  model: MC &\n    (HookFetchable<MC> extends true\n      ? unknown\n      : UseLazyInstead_GetTakesMoreThanParamsAndFetchOptions),\n  ...args: UseModelArgs<MC>\n): Lazy<InstanceType<MC>> {\n  // Which argument holds what depends on whether the model declared keys — the same question\n  // `buildParams()` asks, so a keyless model's `get` is called with the fetch options first rather\n  // than with a placeholder ahead of them.\n  const keys = (model as { keys?: unknown }).keys;\n  const keyed = Array.isArray(keys) && keys.length > 0;\n  const params = keyed ? (args[0] as object) : undefined;\n  const options = (keyed ? args[1] : args[0]) as LazyOptions | undefined;\n\n  // `get` is generic over the class it is called on, so it can't be reached through a structural\n  // type — the conditional above is what types the params, and this is what reaches the function.\n  const get = (model as unknown as { get: (...a: any[]) => Promise<InstanceType<MC>> }).get.bind(\n    model,\n  );\n  return useLazy<InstanceType<MC>>(\n    (fetchOptions) => (params === undefined ? get(fetchOptions) : get(params, fetchOptions)),\n    [model, ...paramsToDeps(params)],\n    {\n      // Models are observable in their own right, so nothing needs converting on the way in — the\n      // same default `store.collection` uses. Harmless either way, since MobX leaves an already\n      // observable value alone; this just skips the check.\n      deep: false,\n      ...options,\n    },\n  );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AA6CA,MAAa,gBAAgB,WAC3B,OAAO,WAAW,IAAK,OAAO,KAAyB,OAAO,IAAI,MAAM,CAAC,CAAC,KAAK,IAAQ;;;;;;;;;;AAWzF,MAAa,YAAY,OAAO,UAAU;;AAG1C,MAAM,gBAAgB;;;;;;;AAQtB,SAAS,iBAAiB,QAA+B;CACvD,IAAI,CAAC,EAAE,QAAQ,MAAM,GAAG,OAAO,OAAO,KAAK,OAAO,UAAU;CAC5D,MAAM,wBAAQ,IAAI,IAAY;CAC9B,KAAK,MAAM,WAAW,gBAAgB,MAAM,GAC1C,KAAK,MAAM,OAAO,OAAO,KAAK,QAAQ,UAAU,GAAG,MAAM,IAAI,GAAG;CAElE,OAAO,CAAC,GAAG,KAAK;AAClB;AAuYA,SAAS,iBAAiB,QAAqB,QAAqC;CAIlF,MAAM,UAAW,QAAQ,QAAQ;CACjC,MAAM,cAAc,MAAM,QAAQ,OAAO;CACzC,MAAM,OAAQ,cAAc,UAAU,CAAC;CACvC,MAAM,cAAc,eAAe,KAAK,WAAW;CACnD,MAAM,UAAU,EAAE,QAAQ,MAAM;CAChC,MAAM,gBAAgB,iBAAiB,MAAM;CAK7C,MAAM,mBAAoB,QAAQ,eAAe,CAAC;CAClD,KAAK,MAAM,OAAO,OAAO,KAAK,gBAAgB,GAC5C,IAAI,CAAC,cAAc,SAAS,GAAG,GAC7B,MAAM,IAAI,MACR,kCAAkC,IAAI,wDACnB,cAAc,KAAK,IAAI,EAAE,yFAE9C;CAIJ,MAAe,UAAU;EACvB,OAAgB,SAAS;EACzB,OAAgB,OAAO;;;;;;EAOvB,WAAW,gBAAkD;GAC3D,IAAI,CAAC,OAAO,OAAO,MAAM,gBAAgB,GACvC,OAAO,eAAe,MAAM,kBAAkB;IAC5C,OAAO,IAAI,WAAiC;IAC5C,cAAc;GAChB,CAAC;GAEH,OAAQ,KAAa;EACvB;;;;;;EAOA,OAAO,YAAY,QAA8B;GAC/C,IAAI,CAAC,aACH,MAAM,IAAI,MACR,iLACF;GAGF,IAAI,aAAa,OAAO;GACxB,OAAO,aAAa,KAAK,KAAK,QAAQ,OAAO,IAA2B,CAAC;EAC3E;;;;;;EAOA,OAAO,YAAY,MAAgB;GACjC,MAAM,MAAM,KAAK,YAAY,IAAI;GACjC,MAAM,WAAW,KAAK,cAAc,IAAI,GAAG;GAC3C,IAAI,UAAU;IACZ,SAAS,QAAQ,IAAI;IACrB,OAAO;GACT;GACA,OAAO,KAAK,cAAc,IAAI,KAAK,IAAK,KAAa,IAAI,CAAC;EAC5D;;;;;EAMA,OAAO,KAAK,QAAmB;GAC7B,OAAO,KAAK,cAAc,IAAI,KAAK,YAAY,MAAM,CAAC;EACxD;;;;;EAMA,OAAO,OAAO,QAAsB;GAClC,OAAO,KAAK,cAAc,OAAO,KAAK,YAAY,MAAM,CAAC;EAC3D;;EAGA,OAAO,gBAAsB;GAC3B,KAAK,cAAc,MAAM;EAC3B;;;;;;EAOA,WAAW,YAAyC;GAClD,IAAI,CAAC,OAAO,OAAO,MAAM,YAAY,GACnC,OAAO,eAAe,MAAM,cAAc;IACxC,uBAAO,IAAI,IAA4B;IACvC,cAAc;GAChB,CAAC;GAEH,OAAQ,KAAa;EACvB;EAEA,OAAO,YAAY,UAA+B;GAChD,KAAK,UAAU,IAAI,IAAI,QAAQ,QAAQ,CAAC;EAC1C;;EAGA,OAAO,gBAAgB,MAAsB,OAAkB;GAC7D,KAAK,MAAM,OAAO,KAAK,WAAW;IAChC,MAAM,WAAW,IAAI,MAAM;IAC3B,IAAI,UAAU,SAAS,aAAa,MAAM,KAAK;SAC1C,KAAK,UAAU,OAAO,GAAG;GAChC;EACF;EAEA,YAAY,MAAW;GAIrB,MAAM,cAAmC,CAAC;GAC1C,KAAK,MAAM,OAAO,eAAe;IAC/B,OAAO,eAAe,MAAM,KAAK;KAC/B,OAAQ,KAAa;KACrB,YAAY;KACZ,cAAc;KACd,UAAU;IACZ,CAAC;IACD,YAAY,OAAO,iBAAiB,QAAQ,WAAW;GACzD;GAKA,OAAO,eAAe,MAAM,WAAW;IACrC,OAAO,KAAK,IAAI;IAChB,UAAU;IACV,cAAc;IACd,YAAY;GACd,CAAC;GAED,eAAe,MAAM;IAAE,GAAG;IAAa,SAAS;GAAO,CAAC;EAC1D;;;;;;;EAQA,QAAQ,MAAiB;GACvB,KAAK,MAAM,OAAO,eAChB,AAAC,KAAa,OAAQ,KAAa;GAIrC,AAAC,KAAa,aAAa,KAAK,IAAI;EACtC;;;;;;;;;;EAWA,WAAW,OAAkB;GAC3B,MAAM,OAAO;GACb,MAAM,gBAAiB,KAAK,YAA2C;GAcvE,MAAM,eAAe,QAAyB,QAAQ,iBAAiB,KAAK,SAAS,GAAG;GAKxF,MAAM,YAAY,OAAO,KAAK,KAAK;GACnC,KAAK,MAAM,OAAO,WAChB,IAAI,YAAY,GAAG,GACjB,MAAM,IAAI,MACR,iBAAiB,IAAI,4HAEvB;GAGJ,kBAAkB;IAChB,KAAK,MAAM,OAAO,WAAW,KAAK,OAAO,MAAM;GACjD,CAAC;EACH;;;;;;;EAQA,cAAmB;GACjB,IAAI,KAAK,WAAW,GAAG,OAAO;GAC9B,MAAM,OAAO;GACb,OAAO,OAAO,YAAY,KAAK,KAAK,MAAM,CAAC,GAAG,KAAK,EAAE,CAAC,CAAC;EACzD;EAEA,SAAc;GACZ,MAAM,OAAO;GACb,MAAM,WAAW,cAAc,QAC5B,KAAK,QAAQ;IACZ,IAAI,KAAK,SAAS,QAAW,IAAI,OAAO,KAAK,KAAK,IAAI;IACtD,OAAO;GACT,GACA,CAAC,CACH;GAGA,OAAO,UAAU,MAAM,MAAM,QAAQ,QAAQ,IAAI;EACnD;CACF;CAEA,MAAM,QAAQ,UAAU;CAExB,IAAI,QAAQ,KAAK;EACf,MAAM,MAAM,OAAO;EACnB,MAAM,QAAQ,OAAO,SAAS;EAC9B,MAAM,aAAa,OAAO,cAAc;EAExC,MAAM,YAAY,eAAe,UAAU;;;;;EAM3C,MAAM,WAAW,UAAwB;GACvC,MAAM,WAAW,MAAM;GACvB,IAAI,aAAa,QAAW,OAAO;GACnC,IAAI,UAAU,MAAM,OAAO;GAC3B,OAAO,KAAK,IAAI,IAAI,WAAY,MAA0B;EAC5D;EAEA,AAAC,UAAkB,SAAS,SAAqB,GAAG,MAAa;GAG/D,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC,MAAM,SACxB,cAAc,KAAK,YAAY,IAAI,IAAI,IAAI,KAAK,IAAI,CACtD;EACF;EAEA,AAAC,UAAkB,MAAM,SAAqB,GAAG,MAAa;GAC5D,IAAI,WAAW;IAGb,MAAM,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,MAAM,CAAC;IACpD,MAAM,WAAW,KAAK,KAAK,KAAK,EAAE;IAElC,IAAI,UAAU;KACZ,IAAI,QAAQ,QAAQ,GAAG,OAAO,QAAQ,QAAQ,QAAQ;KAEtD,IAAI,YAAY;MAId,AAAK,SAAS,OAAO,GAAG,IAAI,CAAC,CAAC,OAAO,UAAmB;OACtD,QAAQ,MAAM,KAAK;OACnB,SAAS,aAAa;MACxB,CAAC;MACD,OAAO,QAAQ,QAAQ,QAAQ;KACjC;IACF;GACF;GAEA,OAAO,KAAK,OAAO,GAAG,IAAI;EAC5B;CACF;CAEA,IAAI,QAAQ,QAAQ;EAClB,MAAM,SAAS,OAAO;EACtB,AAAC,UAAkB,SAAS,SAAqB,GAAG,MAAa;GAC/D,OAAO,OAAO,GAAG,IAAI,CAAC,CAAC,MAAM,SAAc;IACzC,MAAM,QAAQ,cAAc,KAAK,YAAY,IAAI,IAAI,IAAI,KAAK,IAAI;IAClE,KAAK,gBAAgB,WAAW,KAAK;IACrC,OAAO;GACT,CAAC;EACH;CACF;CAGA,IAAI,QAAQ,KAAK;EACf,MAAM,SAAS,OAAO;EACtB,MAAM,SAAS,eAAgB,GAAG,MAAa;GAC7C,MAAM,SAAS,KAAK,YAAY;GAChC,MAAM,OAAO,WAAW,SAAY,MAAM,OAAO,GAAG,IAAI,IAAI,MAAM,OAAO,QAAQ,GAAG,IAAI;GACxF,kBAAkB,KAAK,QAAQ,IAAI,CAAC;GACpC,OAAO;EACT;CACF;CAEA,IAAI,QAAQ,QAAQ;EAClB,MAAM,SAAS,OAAO;EACtB,MAAM,SAAS,eAAgB,MAAW,GAAG,MAAa;GACxD,MAAM,SAAS,KAAK,YAAY;GAChC,MAAM,OACJ,WAAW,SAAY,MAAM,OAAO,MAAM,GAAG,IAAI,IAAI,MAAM,OAAO,QAAQ,MAAM,GAAG,IAAI;GACzF,kBAAkB,KAAK,QAAQ,IAAI,CAAC;GACpC,AAAC,KAAK,YAAiC,gBAAgB,WAAW,IAAI;GACtE,OAAO;EACT;CACF;CAEA,IAAI,QAAQ,QAAQ;EAClB,MAAM,MAAM,OAAO;EACnB,MAAM,SAAS,eAAgB,GAAG,MAAa;GAC7C,MAAM,SAAS,KAAK,YAAY;GAChC,MAAM,SAAS,WAAW,SAAY,MAAM,IAAI,GAAG,IAAI,IAAI,MAAM,IAAI,QAAQ,GAAG,IAAI;GAGpF,AAAC,KAAK,YAAiC,gBAAgB,WAAW,IAAI;GACtE,IAAI,aAAa,AAAC,KAAK,YAAiC,OAAO,IAAI;GACnE,OAAO;EACT;CACF;CAEA,IAAI,QAAQ,SACV,KAAK,MAAM,CAAC,MAAM,OAAO,OAAO,QAAQ,OAAO,OAAO,GAAG;EACvD,MAAM,OAAO;EACb,MAAM,QAAQ,eAAgB,MAAY,GAAG,MAAa;GACxD,MAAM,SAAS,KAAK,YAAY;GAChC,IAAI;GACJ,IAAI,WAAW,QACb,OAAO,SAAS,SAAY,MAAM,KAAK,IAAI,MAAM,KAAK,MAAM,GAAG,IAAI;QAEnE,OAAO,SAAS,SAAY,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,QAAQ,MAAM,GAAG,IAAI;GAEnF,kBAAkB,KAAK,QAAQ,IAAI,CAAC;GACpC,AAAC,KAAK,YAAiC,gBAAgB,WAAW,IAAI;GACtE,OAAO;EACT;CACF;CAGF,OAAO;AACT;AAaA,SAAgB,UACd,QACA,QACK;CACL,OAAO,iBAAiB,QAAQ,MAAM;AACxC;AAqFA,SAAgB,eACd,QACA,eACA,QACK;CACL,MAAM,aAAa,iBAAiB,QAAQ,MAAM;CAClD,WAAW,gBAAgB;CAE3B,MAAM,QAAQ,WAAW;CACzB,MAAM,KAAK,SAAU,OAAyB;EAC5C,OAAQ,KAAa,mBAAmB;CAC1C;CACA,MAAM,KAAK,SAAU,OAAyB;EAC5C,OAAQ,KAAa,mBAAmB,QAAQ,OAAO;CACzD;CAEA,OAAO;AACT;;;;AC7lBA,SAAgB,UACd,YACA,QAIiC;CAGjC,MAAM,QAAQ;CAKd,MAAM,cAAc,SAClB,MAAM,QAAQ,MAAM,IAAI,IAAI,MAAM,YAAY,IAAI,IAAI,IAAI,MAAM,IAAI;CAEtE,MAAM,MAAM;;EAEV,AAAiB,eAMX,CAAC;EAEP,cAAc;GACZ,eAAoD,MAAM;IACxD,cAAc;IACd,YAAY;IACZ,QAAQ;IACR,uBAAuB;IACvB,cAAc;GAChB,CAAC;GAID,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,QAAQ,eAAe,CAAC,CAAC,GAAG;IACpE,IAAI,QAAQ,MACV,MAAM,IAAI,MAAM,eAAe,KAAK,+CAA+C;IAErF,MAAM,EAAE,OAAO,GAAG,YAAY,OAAO,SAAS,aAAa,EAAE,OAAO,KAAK,IAAI;IAC7E,AAAC,KAAa,QAAQ,KAAK,WAAW,OAAO,OAAO;GACtD;GAEA,KAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,QAAQ,oBAAoB,CAAC,CAAC,GAAG;IACzE,IAAI,QAAQ,MACV,MAAM,IAAI,MAAM,eAAe,KAAK,+CAA+C;IAErF,MAAM,EAAE,OAAO,GAAG,YAAY,OAAO,SAAS,aAAa,EAAE,OAAO,KAAK,IAAI;IAC7E,AAAC,KAAa,QAAQ,KAAK,gBAAgB,OAAO,OAAO;GAC3D;GAGA,MAAM,cAAc,IAAI;EAC1B;;;;;EAMA,WAAW,OAAuB,SAAkD;GAClF,MAAM,EAAE,cAAc,MAAM,kBAAkB,qBAAqB,GAAG,gBACpE,WAAW,CAAC;GAEd,MAAM,cAAc,SAAS,SAAY,QAAQ,OAAO,SAAS;GACjE,MAAM,OAAO,UACX,OAAO,iBAAiB;IAEtB,MAAM,UAAS,MADK,MAAM,YAAY,EAClB,CAAC,KAAK,SAAS,WAAW,IAAI,CAAC;IACnD,OAAO,aAAa,OAAO,KAAK,UAAU,IAAI;GAChD,GAEA;IAAE,MAAM;IAAO,GAAG;GAAY,CAChC;GACA,KAAK,aAAa,KAAK;IACrB;IACA,cAAc,gBAAgB,QAAQ,gBAAgB,CAAC,SAAS;IAChE,MAAM;IACN,kBAAkB,oBAAoB,QAAQ,oBAAoB;IAClE,qBAAqB,uBAAuB,QAAQ,uBAAuB;GAC7E,CAAC;GACD,OAAO;EACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCA,gBACE,OACA,SACqB;GACrB,MAAM,EAAE,cAAc,kBAAkB,qBAAqB,UAAU,GAAG,iBACxE,WAAW,CAAC;GAEd,MAAM,OAAO,UACX,OAAO,YAAY;IACjB,MAAM,OAAO,MAAM,MAAM,OAAO;IAChC,IAAI,MAAM,QAAQ,IAAI,GAAG,OAAO,KAAK,KAAK,SAAS,WAAW,IAAI,CAAC;IAInE,OAAO;KAAE,GAAG;KAAM,OAAO,KAAK,MAAM,KAAK,SAAS,WAAW,IAAI,CAAC;IAAE;GACtE,GACA;IAEE,MAAM;IAEN,GAAI,MAAM,QAAQ,MAAM,IAAI,IAAI,EAAE,WAAW,MAAW,MAAM,YAAY,CAAC,EAAE,IAAI,CAAC;IAClF,GAAG;IACH,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;GACjC,CACF;GAEA,KAAK,aAAa,KAAK;IACrB,MAAM;IACN,cAAc,gBAAgB,QAAQ,gBAAgB,CAAC,SAAS;IAIhE,MAAM;IACN,kBAAkB,oBAAoB,QAAQ,oBAAoB;IAClE,qBAAqB,uBAAuB,QAAQ,uBAAuB;GAC7E,CAAC;GACD,OAAO;EACT;;;;;;;;;;EAWA,cACE,aACA,gBACA,cACK;GACL,MAAM,SAAS,MAAM,QAAQ,WAAW,IAAK,cAAoC;GACjF,MAAM,QAAS,SAAS,iBAAiB;GAKzC,MAAM,EAAE,OAAO,GAAG,aAAc,SAAS,eAAe,mBACtD,CAAC;GAEH,MAAM,YAAY,UACb,WAAgB,aAAa,OAAO,KAAK,UAAU,OAAO,MAAM,CAAC,IACjE,WAAW,QAAa;GAE7B,MAAM,wBAAQ,IAAI,IAAqC;GAEvD,MAAM,OAAO,QAA6B;IACxC,MAAM,KAAK,UAAU,GAAG;IACxB,MAAM,WAAW,MAAM,IAAI,EAAE;IAC7B,IAAI,UAAU,OAAO;IAIrB,MAAM,SAAS,SACX,OAAO,YAAY,OAAO,KAAK,UAAU,CAAC,OAAO,IAAI,MAAM,CAAC,CAAC,IAC7D;IACJ,MAAM,OAAO,KAAK,YAAY,iBAAiB,MAAM,QAAQ,YAAY,GAAG,OAAO;IACnF,MAAM,IAAI,IAAI,IAAI;IAClB,OAAO;GACT;GAEA,OAAO,OAAO,OAAO,KAAK;IACxB,SAAS,QAAsB;KAC7B,MAAM,KAAK,UAAU,GAAG;KACxB,MAAM,OAAO,MAAM,IAAI,EAAE;KACzB,IAAI,CAAC,MAAM,OAAO;KAClB,KAAK,WAAW,IAAI;KACpB,OAAO,MAAM,OAAO,EAAE;IACxB;IACA,aAAmB;KACjB,KAAK,MAAM,QAAQ,MAAM,OAAO,GAAG,KAAK,WAAW,IAAI;KACvD,MAAM,MAAM;IACd;GACF,CAAC;EACH;;;;;;EAOA,AAAQ,WAAW,MAA4B;GAC7C,MAAM,KAAK,KAAK,aAAa,WAAW,UAAU,MAAM,SAAS,IAAI;GACrE,IAAI,OAAO,IAAI,KAAK,aAAa,OAAO,IAAI,CAAC;EAC/C;;EAGA,OAAO,OAAkB;GACvB,KAAK,MAAM,EAAE,UAAU,KAAK,cAAc,KAAK,OAAO,OAAO,KAAK;EACpE;;;;;;;;;EAUA,sBAAsB,SAAuC;GAC3D,KAAK,MAAM,EAAE,MAAM,yBAAyB,KAAK,cAE/C,KAAK,WAAW,EAAE,SAAS,SAAS,WAAW,oBAAoB,CAAC;EAExE;;;;;;EAOA,aAAa,MAAsB,OAAkB;GACnD,KAAK,MAAM,EAAE,MAAM,cAAc,yBAAyB,KAAK,cAAc;IAE3E,IAAI,SAAS,WAAW,KAAK,OAAO,OAAO,KAAK;IAChD,IAAI,aAAa,SAAS,IAAI,GAAG,KAAK,WAAW,EAAE,SAAS,oBAAoB,CAAC;GACnF;EACF;CACF;CAEA,MAAM,QAAQ,MAAM;CAEpB,IAAI,OAAO,MAAM,QAAQ,YAGvB,MAAM,MAAM,SAAU,GAAG,MAAa;EACpC,OAAO,MAAM,IAAI,GAAG,IAAI;CAC1B;CAGF,IAAI,OAAO,MAAM,WAAW,YAC1B,MAAM,SAAS,eAAgB,GAAG,MAAa;EAC7C,MAAM,QAAQ,MAAM,MAAM,OAAO,GAAG,IAAI;EACxC,OAAO,kBAAkB;GAIvB,KAAK,MAAM,EAAE,MAAM,MAAM,sBAAsB,KAAK,cAAc;IAChE,IAAI,CAAC,kBAAkB;IACvB,MAAM,OAAO,KAAK;IAClB,IAAI,KAAK,SAAS,KAAK,GAAG;IAC1B,IAAI,CAAC,MAAM;KACT,KAAK,QAAQ,KAAK;KAClB;IACF;IAGA,MAAM,KAAK,KAAK,WAAW,aAAkB,KAAK,OAAO,QAAQ,IAAI,CAAC;IACtE,KAAK,OAAO,OAAO,KAAK,KAAK,SAAS,IAAI,GAAG,KAAK;GACpD;GACA,OAAO;EACT,CAAC;CACH;CAGF,OAAO;AACT;AAyBA,SAAgB,YAAY,OAAsB,QAA0C;CAC1F,OAAO,KAAK,UAAU,OAAO,MAAa,GAAG;AAC/C;;;;;;;;ACxmBA,MAAM,+BAAe,IAAI,QAAsC;AAE/D,MAAM,iBAAiB,UAAwC;CAC7D,IAAI,aAAa,aAAa,IAAI,KAAK;CACvC,IAAI,CAAC,YAAY;EACf,aAAa,UAAU,KAAK;EAC5B,aAAa,IAAI,OAAO,UAAU;CACpC;CACA,OAAO;AACT;AA+CA,SAAgB,cAAc,OAAsB,OAAY,SAAoB;CAClF,MAAM,YAAY,YAAY,UAAa,YAAY;CACvD,MAAM,EAAE,QAAQ,GAAG,sBAAsB,WAAW,CAAC;CAIrD,MAAM,QAAQ,gBAAgB,KAAK,cAAc,KAAK,GAAG,GAAG,CAAC,CAAC;CAC9D,MAAM,MAAM,iBAAiB,MAAM;CAInC,OAAO,gBAEH,MAAM,WACJ,aACK,iBAAmC,MAAM,IAAI,IAAI,GAAG,YAAY,KAChE,iBAAmC,MAAM,YAAY,GAC1D;EAGE,GAAI,YAAY,EAAE,mBAAmB,KAAK,IAAI,CAAC;EAC/C,GAAG;CACL,CACF,GACF,CAAC,CACH;AACF;AA+CA,SAAgB,mBAAmB,OAAsB,OAAY,SAAoB;CACvF,MAAM,YAAY,YAAY,UAAa,YAAY;CACvD,MAAM,EAAE,QAAQ,GAAG,sBAAsB,WAAW,CAAC;CAErD,MAAM,QAAQ,gBAAgB,KAAK,cAAc,KAAK,GAAG,GAAG,CAAC,CAAC;CAC9D,MAAM,MAAM,iBAAiB,MAAM;CAInC,OAAO,gBAEH,MAAM,gBACJ,aACK,YAAkC,MAAM,IAAI,IAAI,GAAG,OAAO,KAC1D,YAAkC,MAAM,OAAO,GACpD;EAKE,GAAI,YAAY,EAAE,mBAAmB,KAAK,IAAI,CAAC;EAC/C,GAAG;CACL,CACF,GACF,CAAC,CACH;AACF;;;;;;;;;AC9GA,MAAM,gBAAgB,WAA+B;CACnD,IAAI,WAAW,UAAa,WAAW,QAAQ,OAAO,WAAW,UAAU,OAAO,CAAC,MAAM;CACzF,OAAO,OAAO,QAAQ,MAAiC,CAAC,CACrD,MAAM,CAAC,IAAI,CAAC,OAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,CAAE,CAAC,CAChD,KAAK;AACV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,SACd,OAIA,GAAG,MACqB;CAIxB,MAAM,OAAQ,MAA6B;CAC3C,MAAM,QAAQ,MAAM,QAAQ,IAAI,KAAK,KAAK,SAAS;CACnD,MAAM,SAAS,QAAS,KAAK,KAAgB;CAC7C,MAAM,UAAW,QAAQ,KAAK,KAAK,KAAK;CAIxC,MAAM,MAAO,MAAyE,IAAI,KACxF,KACF;CACA,OAAO,SACJ,iBAAkB,WAAW,SAAY,IAAI,YAAY,IAAI,IAAI,QAAQ,YAAY,GACtF,CAAC,OAAO,GAAG,aAAa,MAAM,CAAC,GAC/B;EAIE,MAAM;EACN,GAAG;CACL,CACF;AACF"}