@kontsedal/olas-core 0.0.5 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +0 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +109 -27
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +109 -27
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +0 -0
- package/dist/index.mjs.map +1 -1
- package/dist/{root-DqWolle_.mjs → root-Byq-QYTp.mjs} +1478 -347
- package/dist/root-Byq-QYTp.mjs.map +1 -0
- package/dist/{root-lBp7qziQ.cjs → root-CPSL5kpR.cjs} +1483 -346
- package/dist/root-CPSL5kpR.cjs.map +1 -0
- package/dist/testing.cjs +5 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +3 -2
- package/dist/testing.d.cts.map +1 -1
- package/dist/testing.d.mts +3 -2
- package/dist/testing.d.mts.map +1 -1
- package/dist/testing.mjs +5 -2
- package/dist/testing.mjs.map +1 -1
- package/dist/{types-BH1o6nYa.d.mts → types-Brp-4WaZ.d.mts} +244 -23
- package/dist/types-Brp-4WaZ.d.mts.map +1 -0
- package/dist/{types-C4Vtkxbn.d.cts → types-DzDIypPo.d.cts} +244 -23
- package/dist/types-DzDIypPo.d.cts.map +1 -0
- package/package.json +4 -1
- package/src/controller/instance.ts +360 -94
- package/src/controller/root.ts +58 -30
- package/src/controller/types.ts +66 -4
- package/src/emitter.ts +8 -2
- package/src/errors.ts +39 -3
- package/src/forms/field.ts +219 -25
- package/src/forms/form-types.ts +16 -3
- package/src/forms/form.ts +360 -38
- package/src/forms/index.ts +3 -1
- package/src/forms/types.ts +27 -1
- package/src/forms/validators.ts +45 -11
- package/src/index.ts +13 -7
- package/src/query/client.ts +237 -58
- package/src/query/define.ts +0 -0
- package/src/query/entry.ts +259 -15
- package/src/query/focus-online.ts +53 -11
- package/src/query/infinite.ts +351 -47
- package/src/query/keys.ts +33 -2
- package/src/query/local.ts +3 -0
- package/src/query/mutation.ts +27 -6
- package/src/query/plugin.ts +43 -4
- package/src/query/types.ts +76 -6
- package/src/query/use.ts +53 -10
- package/src/selection.ts +49 -12
- package/src/signals/readonly.ts +3 -0
- package/src/signals/runtime.ts +27 -0
- package/src/signals/types.ts +10 -0
- package/src/testing.ts +9 -0
- package/src/timing/debounced.ts +106 -23
- package/src/timing/index.ts +1 -1
- package/src/timing/throttled.ts +85 -28
- package/src/utils.ts +15 -2
- package/dist/root-DqWolle_.mjs.map +0 -1
- package/dist/root-lBp7qziQ.cjs.map +0 -1
- package/dist/types-BH1o6nYa.d.mts.map +0 -1
- package/dist/types-C4Vtkxbn.d.cts.map +0 -1
package/dist/index.cjs
CHANGED
|
Binary file
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["signal","computed","signal","effect","signal","effect"],"sources":["../src/signals/readonly.ts","../src/forms/standard-schema.ts","../src/forms/validators.ts","../src/query/define.ts","../src/scope.ts","../src/selection.ts","../src/timing/debounced.ts","../src/timing/throttled.ts"],"sourcesContent":["import type { ReadSignal } from './types'\n\n/**\n * Project a Signal (or any object with a reactive `value` + `peek` + `subscribe`)\n * as a `ReadSignal`. The returned object does not expose `set` / `update` /\n * settable `value`, so it can be returned from APIs without callers mutating it.\n *\n * Internal helper — not exported from the package's public surface.\n */\nexport function readOnly<T>(source: ReadSignal<T>): ReadSignal<T> {\n return Object.freeze({\n get value() {\n return source.value\n },\n peek() {\n return source.peek()\n },\n subscribe(handler: (value: T) => void) {\n return source.subscribe(handler)\n },\n })\n}\n","/**\n * Standard Schema v1 — the cross-library validation contract adopted by\n * Zod 4, Valibot 1, ArkType 2, and others. See https://standardschema.dev.\n *\n * We type-only-import the shape so consumers don't take a new runtime dep:\n * any object with a `~standard.validate(value)` method conforming to this\n * structure works.\n */\nexport type StandardSchemaV1Issue = {\n readonly message: string\n readonly path?: ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>\n}\n\nexport type StandardSchemaV1Result<O> =\n | { readonly value: O; readonly issues?: undefined }\n | { readonly issues: ReadonlyArray<StandardSchemaV1Issue> }\n\nexport type StandardSchemaV1<I = unknown, O = I> = {\n readonly '~standard': {\n readonly version: 1\n readonly vendor: string\n validate(value: unknown): StandardSchemaV1Result<O> | Promise<StandardSchemaV1Result<O>>\n readonly types?: { readonly input: I; readonly output: O } | undefined\n }\n}\n\n/**\n * Heuristic: does `x` look like a Standard Schema?\n */\nexport function isStandardSchema(x: unknown): x is StandardSchemaV1<unknown, unknown> {\n return (\n x !== null &&\n typeof x === 'object' &&\n '~standard' in x &&\n typeof (x as { '~standard': { validate?: unknown } })['~standard']?.validate === 'function'\n )\n}\n","import { isStandardSchema, type StandardSchemaV1 } from './standard-schema'\nimport type { Validator } from './types'\n\n/**\n * Wrap any Standard-Schema-compatible schema (Zod 4, Valibot 1, ArkType 2,\n * …) as an Olas validator. The validator returns the first issue's message\n * on failure (or `'Invalid'` if no issues are produced), `null` on success.\n *\n * Standard Schema validators may be sync or async; this wrapper threads\n * through whichever the schema returns — `Promise<string|null>` only when\n * the underlying validate call is itself async.\n *\n * `signal` is accepted to match the `Validator<T>` shape but isn't forwarded\n * — Standard Schema v1 has no cancellation surface.\n */\nexport function validator<I, O>(schema: StandardSchemaV1<I, O>): Validator<I> {\n return (value, signal) => {\n void signal\n const result = schema['~standard'].validate(value)\n if (result instanceof Promise) {\n return result.then(messageFromResult)\n }\n return messageFromResult(result)\n }\n}\n\nfunction messageFromResult(result: { issues?: ReadonlyArray<{ message: string }> }): string | null {\n if (result.issues === undefined || result.issues.length === 0) return null\n return result.issues[0]?.message ?? 'Invalid'\n}\n\nexport { isStandardSchema, type StandardSchemaV1 } from './standard-schema'\n\nconst isEmpty = (value: unknown): boolean => {\n if (value === undefined || value === null) return true\n if (typeof value === 'string') return value.length === 0\n if (Array.isArray(value)) return value.length === 0\n return false\n}\n\n/** Reject empty values (undefined, null, empty string, empty array). */\nexport const required =\n <T>(message = 'Required'): Validator<T> =>\n (value) =>\n isEmpty(value) ? message : null\n\n/** Reject strings / arrays shorter than `n`. Allows null/undefined (use with `required` to forbid). */\nexport const minLength =\n (n: number, message?: string): Validator<string | readonly unknown[]> =>\n (value) => {\n if (value == null) return null\n if (value.length >= n) return null\n return message ?? `Must be at least ${n} characters`\n }\n\n/** Reject strings / arrays longer than `n`. */\nexport const maxLength =\n (n: number, message?: string): Validator<string | readonly unknown[]> =>\n (value) => {\n if (value == null) return null\n if (value.length <= n) return null\n return message ?? `Must be no more than ${n} characters`\n }\n\n/** Reject numbers less than `n`. */\nexport const min =\n (n: number, message?: string): Validator<number> =>\n (value) => {\n if (value == null) return null\n if (value >= n) return null\n return message ?? `Must be at least ${n}`\n }\n\n/** Reject numbers greater than `n`. */\nexport const max =\n (n: number, message?: string): Validator<number> =>\n (value) => {\n if (value == null) return null\n if (value <= n) return null\n return message ?? `Must be no more than ${n}`\n }\n\n// RFC-5322-light. Pragmatic, not exhaustive — production forms should\n// rely on server-side validation for definitive answers.\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\n/** Reject strings that don't look like an email. Empty / null pass (use with `required` to forbid). */\nexport const email =\n (message = 'Invalid email address'): Validator<string> =>\n (value) => {\n if (value == null || value === '') return null\n return EMAIL_RE.test(value) ? null : message\n }\n\n/** Reject strings that don't match the supplied `RegExp`. */\nexport const pattern =\n (re: RegExp, message = 'Invalid format'): Validator<string> =>\n (value) => {\n if (value == null || value === '') return null\n return re.test(value) ? null : message\n }\n","import type { QueryClient } from './client'\nimport type { InfiniteQuery, InfiniteQuerySpec } from './infinite'\nimport { type RegisteredQuery, registerQueryById } from './plugin'\nimport type { Query, QuerySpec, Snapshot } from './types'\n\ntype QueryInternal<Args extends unknown[], T> = Query<Args, T> & {\n readonly __spec: QuerySpec<Args, T>\n __clients: Set<QueryClient>\n}\n\nconst warnedMissingId = new WeakSet<object>()\n\nfunction registerQueryId(spec: { queryId?: string; crossTab?: boolean }, query: object): void {\n if (spec.queryId != null) {\n registerQueryById(spec.queryId, query as RegisteredQuery)\n } else if (spec.crossTab === true) {\n // Plugins can't route a message without a `queryId`. Warn once per\n // offending spec — repeated warnings on every render would be noisy.\n if (__DEV__ && !warnedMissingId.has(spec as object)) {\n warnedMissingId.add(spec as object)\n console.warn(\n '[olas] defineQuery({ crossTab: true }) requires a stable `queryId`. ' +\n 'Add `queryId: \"<unique-string>\"` to the spec. Cross-tab sync is disabled for this query.',\n )\n }\n }\n}\n\n/**\n * Define a keyed, shared query. The returned Query value lives at module\n * scope; per-root QueryClients bind their own entry registries to it.\n */\nexport function defineQuery<Args extends unknown[], T>(spec: QuerySpec<Args, T>): Query<Args, T> {\n const clients = new Set<QueryClient>()\n const query = {\n __olas: 'query' as const,\n __spec: spec,\n __clients: clients,\n\n invalidate(...args: Args): void {\n for (const client of clients) {\n client.invalidate(query as Query<Args, T>, args)\n }\n },\n\n invalidateAll(): void {\n for (const client of clients) {\n client.invalidateAll(query as Query<Args, T>)\n }\n },\n\n setData(...rest: [...Args, updater: (prev: T | undefined) => T]): Snapshot {\n const updater = rest[rest.length - 1] as (prev: T | undefined) => T\n const keyArgs = rest.slice(0, -1) as unknown as Args\n const childSnapshots: Snapshot[] = []\n for (const client of clients) {\n childSnapshots.push(client.setData(query as Query<Args, T>, keyArgs, updater))\n }\n return {\n rollback: () => {\n for (const s of childSnapshots) s.rollback()\n },\n finalize: () => {\n for (const s of childSnapshots) s.finalize()\n },\n }\n },\n\n prefetch(...args: Args): Promise<T> {\n // Single-client common case; if none, throw.\n const [first] = clients\n if (!first) {\n return Promise.reject(new Error('[olas] prefetch called before any root has subscribed'))\n }\n if (__DEV__ && clients.size > 1) {\n // eslint-disable-next-line no-console\n console.warn(\n '[olas] query.prefetch() is ambiguous when multiple roots are registered; ' +\n 'using an arbitrary root. Call `root.prefetch(query, args)` (or per-root) to be explicit.',\n )\n }\n return first.prefetch(query as Query<Args, T>, args)\n },\n } satisfies QueryInternal<Args, T>\n\n registerQueryId(spec, query)\n return query as Query<Args, T>\n}\n\ntype InfiniteQueryInternal<Args extends unknown[], TPage, TItem> = InfiniteQuery<\n Args,\n TPage,\n TItem\n> & {\n readonly __spec: InfiniteQuerySpec<Args, any, TPage, TItem>\n __clients: Set<QueryClient>\n}\n\n/**\n * Define a paginated query (chat-style \"load more\", infinite scrolling). Pages\n * are kept in order and concatenated via `getNextPageParam` /\n * `getPreviousPageParam`. The returned handle is module-scoped — bind\n * subscribers via `ctx.use(infiniteQuery, () => [...args])`. Spec §5.7,\n * §20.4.\n */\nexport function defineInfiniteQuery<Args extends unknown[], PageParam, TPage, TItem = TPage>(\n spec: InfiniteQuerySpec<Args, PageParam, TPage, TItem>,\n): InfiniteQuery<Args, TPage, TItem> {\n const clients = new Set<QueryClient>()\n const query = {\n __olas: 'infiniteQuery' as const,\n __spec: spec,\n __clients: clients,\n\n invalidate(...args: Args): void {\n for (const client of clients) {\n client.invalidateInfinite(query as InfiniteQuery<Args, TPage, TItem>, args)\n }\n },\n\n invalidateAll(): void {\n for (const client of clients) {\n client.invalidateAllInfinite(query as InfiniteQuery<Args, TPage, TItem>)\n }\n },\n\n setData(...rest: [...Args, updater: (prev: TPage[] | undefined) => TPage[]]): Snapshot {\n const updater = rest[rest.length - 1] as (prev: TPage[] | undefined) => TPage[]\n const keyArgs = rest.slice(0, -1) as unknown as Args\n const childSnapshots: Snapshot[] = []\n for (const client of clients) {\n childSnapshots.push(\n client.setInfiniteData<Args, TPage>(\n query as InfiniteQuery<Args, TPage, TItem>,\n keyArgs,\n updater,\n ),\n )\n }\n return {\n rollback: () => {\n for (const s of childSnapshots) s.rollback()\n },\n finalize: () => {\n for (const s of childSnapshots) s.finalize()\n },\n }\n },\n\n prefetch(...args: Args): Promise<TPage> {\n const [first] = clients\n if (!first) {\n return Promise.reject(new Error('[olas] prefetch called before any root has subscribed'))\n }\n if (__DEV__ && clients.size > 1) {\n // eslint-disable-next-line no-console\n console.warn(\n '[olas] infiniteQuery.prefetch() is ambiguous when multiple roots are registered; ' +\n 'using an arbitrary root. Call `root.prefetch(query, args)` (or per-root) to be explicit.',\n )\n }\n return first.prefetchInfinite(query as InfiniteQuery<Args, TPage, TItem>, args)\n },\n } satisfies InfiniteQueryInternal<Args, TPage, TItem>\n\n registerQueryId(spec, query)\n return query as InfiniteQuery<Args, TPage, TItem>\n}\n","/**\n * Typed cross-tree data slot. Provided by an ancestor via `ctx.provide(scope, value)`\n * and consumed anywhere in its subtree via `ctx.inject(scope)`. Defined at module\n * scope so the identity is stable across calls. See spec §10.3.\n */\nexport type Scope<T> = {\n readonly __olas: 'scope'\n /** Per-scope identity; matches across `provide` / `inject`. */\n readonly __id: symbol\n /** Optional human-readable name (used in error messages). */\n readonly name?: string\n /** Default value used when no provider exists; `undefined` if none was set. */\n readonly default?: T\n /** True iff `defineScope` was called with a `default` (even `default: undefined`). */\n readonly hasDefault: boolean\n // Phantom for inference — typed `T` is preserved through the scope's lifetime.\n readonly __t?: T\n}\n\nexport type ScopeOptions<T> = {\n default?: T\n name?: string\n}\n\n/**\n * Create a scope. The returned value is the typed handle passed to\n * `ctx.provide(scope, value)` and `ctx.inject(scope)`. Identity is keyed by\n * an internal symbol so two `defineScope()` calls — even with identical\n * options — yield distinct scopes.\n */\nexport function defineScope<T>(options?: ScopeOptions<T>): Scope<T> {\n const hasDefault = options !== undefined && 'default' in options\n const name = options?.name\n const scope: Scope<T> = {\n __olas: 'scope',\n __id: Symbol(name ?? 'scope'),\n hasDefault,\n ...(name !== undefined ? { name } : {}),\n ...(hasDefault ? { default: options?.default as T } : {}),\n }\n return scope\n}\n","import { computed, signal } from './signals'\nimport { readOnly } from './signals/readonly'\nimport type { ReadSignal } from './signals/types'\n\n/**\n * Multi-select state for tables / lists with bulk actions (spec §17.5).\n *\n * Plain function — not bound to `ctx`. Place it in a controller's closure so\n * it dies with the closure. The phantom `T` parameter brands the selection by\n * item type; IDs are always strings.\n */\n// biome-ignore lint/correctness/noUnusedVariables: phantom branding param (spec §17.5)\nexport type Selection<T = unknown> = {\n selectedIds: ReadSignal<ReadonlySet<string>>\n size: ReadSignal<number>\n isSelected(id: string): ReadSignal<boolean>\n\n select(id: string): void\n deselect(id: string): void\n toggle(id: string): void\n clear(): void\n selectAll(ids: readonly string[]): void\n\n handleClick(\n id: string,\n mods: { shift?: boolean; meta?: boolean },\n ordered: readonly string[],\n ): void\n}\n\n/**\n * Create a `Selection<T>`. Optional `initial` seeds the selected set.\n *\n * `handleClick` encapsulates the standard click semantics:\n * - plain click → select only `id` (anchor moves to `id`)\n * - meta-click → toggle `id` (anchor moves to `id` on add)\n * - shift-click → range from anchor to `id` along `ordered` (anchor sticks,\n * so subsequent shift-clicks extend from the same origin)\n *\n * Spec §16.5 / §17.5.\n */\nexport function selection<T = unknown>(options?: { initial?: readonly string[] }): Selection<T> {\n const ids = signal<ReadonlySet<string>>(new Set(options?.initial))\n let anchor: string | null = options?.initial?.length\n ? (options.initial[options.initial.length - 1] ?? null)\n : null\n // Snapshot of the selection just before the first shift-click of a run.\n // Subsequent shift-clicks re-compute the range against this snapshot so the\n // user can shrink or grow the range. Reset on any non-shift click.\n let preShiftSelection: ReadonlySet<string> | null = null\n\n const size = computed(() => ids.value.size)\n\n const isSelected = (id: string): ReadSignal<boolean> => computed(() => ids.value.has(id))\n\n const select = (id: string): void => {\n const prev = ids.peek()\n if (!prev.has(id)) {\n const next = new Set(prev)\n next.add(id)\n ids.set(next)\n }\n anchor = id\n }\n\n const deselect = (id: string): void => {\n const prev = ids.peek()\n if (!prev.has(id)) return\n const next = new Set(prev)\n next.delete(id)\n ids.set(next)\n }\n\n const toggle = (id: string): void => {\n const prev = ids.peek()\n const next = new Set(prev)\n if (prev.has(id)) {\n next.delete(id)\n } else {\n next.add(id)\n anchor = id\n }\n ids.set(next)\n }\n\n const clear = (): void => {\n if (ids.peek().size === 0) {\n anchor = null\n return\n }\n ids.set(new Set())\n anchor = null\n }\n\n const selectAll = (incoming: readonly string[]): void => {\n ids.set(new Set(incoming))\n anchor = incoming.length > 0 ? (incoming[incoming.length - 1] ?? null) : null\n }\n\n const handleClick = (\n id: string,\n mods: { shift?: boolean; meta?: boolean },\n ordered: readonly string[],\n ): void => {\n if (mods.shift && anchor !== null) {\n const anchorIdx = ordered.indexOf(anchor)\n const targetIdx = ordered.indexOf(id)\n if (anchorIdx === -1 || targetIdx === -1) {\n // anchor or target not visible — fall back to plain select\n ids.set(new Set([id]))\n anchor = id\n preShiftSelection = null\n return\n }\n if (preShiftSelection === null) {\n preShiftSelection = ids.peek()\n }\n const [lo, hi] = anchorIdx < targetIdx ? [anchorIdx, targetIdx] : [targetIdx, anchorIdx]\n const next = new Set(preShiftSelection)\n for (const k of ordered.slice(lo, hi + 1)) next.add(k)\n ids.set(next)\n // Anchor stays — subsequent shift-clicks extend from the same origin.\n return\n }\n // Any non-shift click ends the shift run.\n preShiftSelection = null\n if (mods.meta) {\n toggle(id)\n return\n }\n ids.set(new Set([id]))\n anchor = id\n }\n\n return {\n selectedIds: readOnly(ids),\n size,\n isSelected,\n select,\n deselect,\n toggle,\n clear,\n selectAll,\n handleClick,\n }\n}\n","import { effect, signal } from '../signals'\nimport type { ReadSignal } from '../signals/types'\n\n/**\n * Lag a signal by `ms`. The returned signal updates only after the source has\n * been unchanged for `ms`. Each new write resets the timer.\n *\n * Pass `options.signal` (an `AbortSignal`) to tie the internal effect to a\n * lifecycle — when the signal aborts the effect disposes, the pending timer\n * clears, and the subscriber chain on `source` drops. Without `signal`, the\n * effect lives as long as `source` does; pass a signal whenever the source\n * outlives the consumer.\n */\nexport function debounced<T>(\n source: ReadSignal<T>,\n ms: number,\n options?: { signal?: AbortSignal },\n): ReadSignal<T> {\n const out = signal<T>(source.peek())\n let timer: ReturnType<typeof setTimeout> | null = null\n let initial = true\n\n const dispose = effect(() => {\n const value = source.value\n if (initial) {\n // The first effect run reads the source for tracking; we already\n // initialized `out` to the same value, so skip scheduling.\n initial = false\n return\n }\n if (timer != null) clearTimeout(timer)\n timer = setTimeout(() => {\n out.set(value)\n timer = null\n }, ms)\n })\n\n const sig = options?.signal\n if (sig) {\n const stop = () => {\n if (timer != null) {\n clearTimeout(timer)\n timer = null\n }\n dispose()\n }\n if (sig.aborted) stop()\n else sig.addEventListener('abort', stop, { once: true })\n }\n\n return out\n}\n","import { effect, signal } from '../signals'\nimport type { ReadSignal } from '../signals/types'\n\n/**\n * Rate-limit a signal so it emits at most once per `ms` (leading + trailing).\n * The first change passes through immediately. Subsequent changes within the\n * window are coalesced; the latest value is emitted when the window expires.\n *\n * Pass `options.signal` to tie the internal effect to a lifecycle — when the\n * signal aborts the effect disposes and any pending trailing timer clears.\n * Without `signal`, the effect lives as long as `source` does.\n */\nexport function throttled<T>(\n source: ReadSignal<T>,\n ms: number,\n options?: { signal?: AbortSignal },\n): ReadSignal<T> {\n const out = signal<T>(source.peek())\n let lastEmit = Number.NEGATIVE_INFINITY\n let trailingTimer: ReturnType<typeof setTimeout> | null = null\n let trailingValue: T = source.peek()\n let initial = true\n\n const dispose = effect(() => {\n const value = source.value\n if (initial) {\n initial = false\n return\n }\n const now = Date.now()\n const elapsed = now - lastEmit\n if (elapsed >= ms) {\n out.set(value)\n lastEmit = now\n if (trailingTimer != null) {\n clearTimeout(trailingTimer)\n trailingTimer = null\n }\n } else {\n trailingValue = value\n if (trailingTimer == null) {\n trailingTimer = setTimeout(() => {\n out.set(trailingValue)\n lastEmit = Date.now()\n trailingTimer = null\n }, ms - elapsed)\n }\n }\n })\n\n const sig = options?.signal\n if (sig) {\n const stop = () => {\n if (trailingTimer != null) {\n clearTimeout(trailingTimer)\n trailingTimer = null\n }\n dispose()\n }\n if (sig.aborted) stop()\n else sig.addEventListener('abort', stop, { once: true })\n }\n\n return out\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["signal","computed","readOnly","signal","effect","readOnly","signal","effect","readOnly"],"sources":["../src/forms/standard-schema.ts","../src/forms/validators.ts","../src/query/define.ts","../src/scope.ts","../src/selection.ts","../src/timing/debounced.ts","../src/timing/throttled.ts"],"sourcesContent":["/**\n * Standard Schema v1 — the cross-library validation contract adopted by\n * Zod 4, Valibot 1, ArkType 2, and others. See https://standardschema.dev.\n *\n * We type-only-import the shape so consumers don't take a new runtime dep:\n * any object with a `~standard.validate(value)` method conforming to this\n * structure works.\n */\nexport type StandardSchemaV1Issue = {\n readonly message: string\n readonly path?: ReadonlyArray<PropertyKey | { readonly key: PropertyKey }>\n}\n\nexport type StandardSchemaV1Result<O> =\n | { readonly value: O; readonly issues?: undefined }\n | { readonly issues: ReadonlyArray<StandardSchemaV1Issue> }\n\nexport type StandardSchemaV1<I = unknown, O = I> = {\n readonly '~standard': {\n readonly version: 1\n readonly vendor: string\n validate(value: unknown): StandardSchemaV1Result<O> | Promise<StandardSchemaV1Result<O>>\n readonly types?: { readonly input: I; readonly output: O } | undefined\n }\n}\n\n/**\n * Heuristic: does `x` look like a Standard Schema?\n */\nexport function isStandardSchema(x: unknown): x is StandardSchemaV1<unknown, unknown> {\n return (\n x !== null &&\n typeof x === 'object' &&\n '~standard' in x &&\n typeof (x as { '~standard': { validate?: unknown } })['~standard']?.validate === 'function'\n )\n}\n","import type { StandardSchemaV1, StandardSchemaV1Issue } from './standard-schema'\nimport type { FormIssue, Validator } from './types'\n\n/**\n * Wrap any Standard-Schema-compatible schema (Zod 4, Valibot 1, ArkType 2,\n * …) as an Olas validator. Returns **all** issues as `FormIssue[]`, each\n * carrying the schema's own `path` — so a whole-form schema used as a\n * form-level validator routes each issue onto the matching field (T5.2),\n * and a leaf schema (whose issues have empty paths) still reports on the\n * field it's attached to. An empty array means \"valid\".\n *\n * Standard Schema validators may be sync or async; this wrapper threads\n * through whichever the schema returns — `Promise<FormIssue[]>` only when\n * the underlying validate call is itself async.\n *\n * `signal` is accepted to match the `Validator<T>` shape but isn't forwarded\n * — Standard Schema v1 has no cancellation surface.\n */\nexport function validator<I, O>(schema: StandardSchemaV1<I, O>): Validator<I> {\n return (value, signal) => {\n void signal\n const result = schema['~standard'].validate(value)\n if (result instanceof Promise) {\n return result.then(issuesFromResult)\n }\n return issuesFromResult(result)\n }\n}\n\nfunction issuesFromResult(result: { issues?: ReadonlyArray<StandardSchemaV1Issue> }): FormIssue[] {\n if (result.issues === undefined || result.issues.length === 0) return []\n return result.issues.map((issue) => ({\n path: normalizeIssuePath(issue.path),\n message: issue.message ?? 'Invalid',\n }))\n}\n\n/**\n * Standard Schema issue paths are `(PropertyKey | { key: PropertyKey })[]`.\n * Flatten to the `(string | number)[]` shape `FormIssue` uses: numeric keys\n * stay numeric (array indices), everything else stringifies.\n */\nfunction normalizeIssuePath(path: StandardSchemaV1Issue['path']): (string | number)[] {\n if (path === undefined) return []\n const out: (string | number)[] = []\n for (const seg of path) {\n const key = typeof seg === 'object' && seg !== null ? seg.key : seg\n out.push(typeof key === 'number' ? key : String(key))\n }\n return out\n}\n\nexport { isStandardSchema, type StandardSchemaV1 } from './standard-schema'\n\nconst isEmpty = (value: unknown): boolean => {\n if (value === undefined || value === null) return true\n if (typeof value === 'string') return value.length === 0\n if (Array.isArray(value)) return value.length === 0\n // A boolean `false` is a legitimate value (a toggle set to \"off\"), NOT empty\n // — `required` accepts it. For a consent / confirm checkbox that MUST be\n // ticked, use `mustBeTrue` instead (T5.3).\n return false\n}\n\n/** Reject empty values (undefined, null, empty string, empty array). Booleans always pass. */\nexport const required =\n <T>(message = 'Required'): Validator<T> =>\n (value) =>\n isEmpty(value) ? message : null\n\n/**\n * Reject any value that isn't boolean `true` — the \"you must check this box\"\n * rule for consent / terms-of-service / confirm checkboxes. Unlike `required`\n * (which now accepts `false` as a valid boolean), this fails on `false`.\n */\nexport const mustBeTrue =\n (message = 'Required'): Validator<boolean> =>\n (value) =>\n value === true ? null : message\n\n/** Reject strings / arrays shorter than `n`. Allows null/undefined (use with `required` to forbid). */\nexport const minLength =\n (n: number, message?: string): Validator<string | readonly unknown[]> =>\n (value) => {\n if (value == null) return null\n if (value.length >= n) return null\n return message ?? `Must be at least ${n} characters`\n }\n\n/** Reject strings / arrays longer than `n`. */\nexport const maxLength =\n (n: number, message?: string): Validator<string | readonly unknown[]> =>\n (value) => {\n if (value == null) return null\n if (value.length <= n) return null\n return message ?? `Must be no more than ${n} characters`\n }\n\n/** Reject numbers less than `n`. */\nexport const min =\n (n: number, message?: string): Validator<number> =>\n (value) => {\n if (value == null) return null\n if (value >= n) return null\n return message ?? `Must be at least ${n}`\n }\n\n/** Reject numbers greater than `n`. */\nexport const max =\n (n: number, message?: string): Validator<number> =>\n (value) => {\n if (value == null) return null\n if (value <= n) return null\n return message ?? `Must be no more than ${n}`\n }\n\n// RFC-5322-light. Pragmatic, not exhaustive — production forms should\n// rely on server-side validation for definitive answers.\nconst EMAIL_RE = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\n/** Reject strings that don't look like an email. Empty / null pass (use with `required` to forbid). */\nexport const email =\n (message = 'Invalid email address'): Validator<string> =>\n (value) => {\n if (value == null || value === '') return null\n return EMAIL_RE.test(value) ? null : message\n }\n\n/** Reject strings that don't match the supplied `RegExp`. */\nexport const pattern =\n (re: RegExp, message = 'Invalid format'): Validator<string> =>\n (value) => {\n if (value == null || value === '') return null\n return re.test(value) ? null : message\n }\n","import type { QueryClient } from './client'\nimport type { InfiniteQuery, InfiniteQuerySpec } from './infinite'\nimport { type RegisteredQuery, registerQueryById } from './plugin'\nimport type { Query, QuerySpec, Snapshot } from './types'\n\ntype QueryInternal<Args extends unknown[], T> = Query<Args, T> & {\n readonly __spec: QuerySpec<Args, T>\n /** Stable identity for SSR hydration matching — see `assignQueryId`. */\n readonly __id: string\n __clients: Set<QueryClient>\n}\n\nconst warnedMissingId = new WeakSet<object>()\n\n/**\n * Assign a stable identity used to namespace SSR dehydrate/hydrate so a\n * subscriber of one query can't adopt a colliding-key payload from another\n * (spec §15). Prefer the explicit `queryId` (which doubles as the plugin\n * routing id, so `__id === queryId` there); otherwise auto-assign a\n * registration id. Auto ids are stable across a server/client pair that\n * evaluate the same bundle in the same order (the common, non-code-split\n * case). If they ever drift (code-split, differing import order), the\n * mismatch degrades *safely* to a hydration miss + refetch — never a\n * cross-query adoption. Set an explicit `queryId` for a hard guarantee. The\n * `\u0000` prefix keeps auto ids out of the practical user-string namespace (JSON-safe).\n */\nlet autoQueryIdCounter = 0\nfunction assignQueryId(spec: { queryId?: string }): string {\n return spec.queryId ?? `\u0000auto:${autoQueryIdCounter++}`\n}\n\nfunction registerQueryId(\n // The param stays wide so a JS / cast caller passing a removed value is\n // caught at runtime; the PUBLIC `QuerySpec.crossTab` type is `boolean | 'data'`.\n spec: { queryId?: string; crossTab?: boolean | 'data' | 'infinite' | 'both' },\n query: object,\n): void {\n if (__DEV__ && (spec.crossTab === 'infinite' || spec.crossTab === 'both')) {\n // Removed in T6.4: core's `applyRemoteSetData` / `applyRemoteInvalidate`\n // early-return for infinite (non-`'query'`) defs, so an infinite/both\n // broadcast was pure channel noise no peer could apply. Degrade to `'data'`\n // (regular writes still sync). Infinite cross-tab is tracked in BACKLOG.md.\n console.warn(\n \"[olas] crossTab: 'infinite' / 'both' is no longer supported — peers can't apply \" +\n \"infinite-query page arrays cross-tab. Treated as 'data' (regular writes still sync).\",\n )\n }\n if (spec.queryId != null) {\n registerQueryById(spec.queryId, query as RegisteredQuery)\n } else if (spec.crossTab === true) {\n // Plugins can't route a message without a `queryId`. Warn once per\n // offending spec — repeated warnings on every render would be noisy.\n if (__DEV__ && !warnedMissingId.has(spec as object)) {\n warnedMissingId.add(spec as object)\n console.warn(\n '[olas] defineQuery({ crossTab: true }) requires a stable `queryId`. ' +\n 'Add `queryId: \"<unique-string>\"` to the spec. Cross-tab sync is disabled for this query.',\n )\n }\n }\n}\n\n/**\n * Define a keyed, shared query. The returned Query value lives at module\n * scope; per-root QueryClients bind their own entry registries to it.\n */\nexport function defineQuery<Args extends unknown[], T>(spec: QuerySpec<Args, T>): Query<Args, T> {\n const clients = new Set<QueryClient>()\n const query = {\n __olas: 'query' as const,\n __spec: spec,\n __id: assignQueryId(spec),\n __clients: clients,\n\n invalidate(...args: Args): void {\n for (const client of clients) {\n client.invalidate(query as Query<Args, T>, args)\n }\n },\n\n invalidateAll(): void {\n for (const client of clients) {\n client.invalidateAll(query as Query<Args, T>)\n }\n },\n\n cancel(...args: Args): void {\n for (const client of clients) {\n client.cancel(query as Query<Args, T>, args)\n }\n },\n\n cancelAll(): void {\n for (const client of clients) {\n client.cancelAll(query as Query<Args, T>)\n }\n },\n\n setData(...rest: [...Args, updater: (prev: T | undefined) => T]): Snapshot {\n const updater = rest[rest.length - 1] as (prev: T | undefined) => T\n const keyArgs = rest.slice(0, -1) as unknown as Args\n const childSnapshots: Snapshot[] = []\n for (const client of clients) {\n childSnapshots.push(client.setData(query as Query<Args, T>, keyArgs, updater))\n }\n return {\n rollback: () => {\n for (const s of childSnapshots) s.rollback()\n },\n finalize: () => {\n for (const s of childSnapshots) s.finalize()\n },\n }\n },\n\n prefetch(...args: Args): Promise<T> {\n // Single-client common case; if none, throw.\n const [first] = clients\n if (!first) {\n return Promise.reject(new Error('[olas] prefetch called before any root has subscribed'))\n }\n if (__DEV__ && clients.size > 1) {\n // eslint-disable-next-line no-console\n console.warn(\n '[olas] query.prefetch() is ambiguous when multiple roots are registered; ' +\n 'using an arbitrary root. Call `root.prefetch(query, args)` (or per-root) to be explicit.',\n )\n }\n return first.prefetch(query as Query<Args, T>, args)\n },\n } satisfies QueryInternal<Args, T>\n\n registerQueryId(spec, query)\n return query as Query<Args, T>\n}\n\ntype InfiniteQueryInternal<Args extends unknown[], TPage, TItem> = InfiniteQuery<\n Args,\n TPage,\n TItem\n> & {\n readonly __spec: InfiniteQuerySpec<Args, any, TPage, TItem>\n /** Stable identity for SSR hydration matching — see `assignQueryId`. */\n readonly __id: string\n __clients: Set<QueryClient>\n}\n\n/**\n * Define a paginated query (chat-style \"load more\", infinite scrolling). Pages\n * are kept in order and concatenated via `getNextPageParam` /\n * `getPreviousPageParam`. The returned handle is module-scoped — bind\n * subscribers via `ctx.use(infiniteQuery, () => [...args])`. Spec §5.7,\n * §20.4.\n */\nexport function defineInfiniteQuery<Args extends unknown[], PageParam, TPage, TItem = TPage>(\n spec: InfiniteQuerySpec<Args, PageParam, TPage, TItem>,\n): InfiniteQuery<Args, TPage, TItem> {\n const clients = new Set<QueryClient>()\n const query = {\n __olas: 'infiniteQuery' as const,\n __spec: spec,\n __id: assignQueryId(spec),\n __clients: clients,\n\n invalidate(...args: Args): void {\n for (const client of clients) {\n client.invalidateInfinite(query as InfiniteQuery<Args, TPage, TItem>, args)\n }\n },\n\n invalidateAll(): void {\n for (const client of clients) {\n client.invalidateAllInfinite(query as InfiniteQuery<Args, TPage, TItem>)\n }\n },\n\n cancel(...args: Args): void {\n for (const client of clients) {\n client.cancelInfinite(query as InfiniteQuery<Args, TPage, TItem>, args)\n }\n },\n\n cancelAll(): void {\n for (const client of clients) {\n client.cancelAllInfinite(query as InfiniteQuery<Args, TPage, TItem>)\n }\n },\n\n setData(...rest: [...Args, updater: (prev: TPage[] | undefined) => TPage[]]): Snapshot {\n const updater = rest[rest.length - 1] as (prev: TPage[] | undefined) => TPage[]\n const keyArgs = rest.slice(0, -1) as unknown as Args\n const childSnapshots: Snapshot[] = []\n for (const client of clients) {\n childSnapshots.push(\n client.setInfiniteData<Args, TPage>(\n query as InfiniteQuery<Args, TPage, TItem>,\n keyArgs,\n updater,\n ),\n )\n }\n return {\n rollback: () => {\n for (const s of childSnapshots) s.rollback()\n },\n finalize: () => {\n for (const s of childSnapshots) s.finalize()\n },\n }\n },\n\n prefetch(...args: Args): Promise<TPage> {\n const [first] = clients\n if (!first) {\n return Promise.reject(new Error('[olas] prefetch called before any root has subscribed'))\n }\n if (__DEV__ && clients.size > 1) {\n // eslint-disable-next-line no-console\n console.warn(\n '[olas] infiniteQuery.prefetch() is ambiguous when multiple roots are registered; ' +\n 'using an arbitrary root. Call `root.prefetch(query, args)` (or per-root) to be explicit.',\n )\n }\n return first.prefetchInfinite(query as InfiniteQuery<Args, TPage, TItem>, args)\n },\n } satisfies InfiniteQueryInternal<Args, TPage, TItem>\n\n registerQueryId(spec, query)\n return query as InfiniteQuery<Args, TPage, TItem>\n}\n","/**\n * Typed cross-tree data slot. Provided by an ancestor via `ctx.provide(scope, value)`\n * and consumed anywhere in its subtree via `ctx.inject(scope)`. Defined at module\n * scope so the identity is stable across calls. See spec §10.3.\n */\nexport type Scope<T> = {\n readonly __olas: 'scope'\n /** Per-scope identity; matches across `provide` / `inject`. */\n readonly __id: symbol\n /** Optional human-readable name (used in error messages). */\n readonly name?: string\n /** Default value used when no provider exists; `undefined` if none was set. */\n readonly default?: T\n /** True iff `defineScope` was called with a `default` (even `default: undefined`). */\n readonly hasDefault: boolean\n // Phantom for inference — typed `T` is preserved through the scope's lifetime.\n readonly __t?: T\n}\n\nexport type ScopeOptions<T> = {\n default?: T\n name?: string\n}\n\n/**\n * Create a scope. The returned value is the typed handle passed to\n * `ctx.provide(scope, value)` and `ctx.inject(scope)`. Identity is keyed by\n * an internal symbol so two `defineScope()` calls — even with identical\n * options — yield distinct scopes.\n */\nexport function defineScope<T>(options?: ScopeOptions<T>): Scope<T> {\n const hasDefault = options !== undefined && 'default' in options\n const name = options?.name\n const scope: Scope<T> = {\n __olas: 'scope',\n __id: Symbol(name ?? 'scope'),\n hasDefault,\n ...(name !== undefined ? { name } : {}),\n ...(hasDefault ? { default: options?.default as T } : {}),\n }\n return scope\n}\n","import { computed, signal } from './signals'\nimport { readOnly } from './signals/readonly'\nimport type { ReadSignal } from './signals/types'\n\n/**\n * Multi-select state for tables / lists with bulk actions (spec §17.5).\n *\n * Plain function — not bound to `ctx`. Place it in a controller's closure so\n * it dies with the closure. The phantom `T` parameter brands the selection by\n * item type; IDs are always strings.\n */\n// biome-ignore lint/correctness/noUnusedVariables: phantom branding param (spec §17.5)\nexport type Selection<T = unknown> = {\n selectedIds: ReadSignal<ReadonlySet<string>>\n size: ReadSignal<number>\n isSelected(id: string): ReadSignal<boolean>\n\n select(id: string): void\n deselect(id: string): void\n toggle(id: string): void\n clear(): void\n selectAll(ids: readonly string[]): void\n\n handleClick(\n id: string,\n mods: { shift?: boolean; meta?: boolean },\n ordered: readonly string[] | ReadonlyMap<string, number>,\n ): void\n}\n\n/**\n * Create a `Selection<T>`. Optional `initial` seeds the selected set.\n *\n * `handleClick` encapsulates the standard click semantics:\n * - plain click → select only `id` (anchor moves to `id`)\n * - meta-click → toggle `id` (anchor moves to `id` on add)\n * - shift-click → range from anchor to `id` along `ordered` (anchor sticks,\n * so subsequent shift-clicks extend from the same origin)\n *\n * Spec §16.5 / §17.5.\n */\nexport function selection<T = unknown>(options?: { initial?: readonly string[] }): Selection<T> {\n const ids = signal<ReadonlySet<string>>(new Set(options?.initial))\n let anchor: string | null = options?.initial?.length\n ? (options.initial[options.initial.length - 1] ?? null)\n : null\n // Snapshot of the selection just before the first shift-click of a run.\n // Subsequent shift-clicks re-compute the range against this snapshot so the\n // user can shrink or grow the range. Reset on any non-shift click.\n let preShiftSelection: ReadonlySet<string> | null = null\n\n const size = computed(() => ids.value.size)\n\n const isSelected = (id: string): ReadSignal<boolean> => computed(() => ids.value.has(id))\n\n const select = (id: string): void => {\n const prev = ids.peek()\n if (!prev.has(id)) {\n const next = new Set(prev)\n next.add(id)\n ids.set(next)\n }\n anchor = id\n }\n\n const deselect = (id: string): void => {\n const prev = ids.peek()\n if (!prev.has(id)) return\n const next = new Set(prev)\n next.delete(id)\n ids.set(next)\n // Clear the anchor if we just removed it — a subsequent shift-click\n // would otherwise range from an id that's no longer in the selection.\n if (anchor === id) anchor = null\n }\n\n const toggle = (id: string): void => {\n const prev = ids.peek()\n const next = new Set(prev)\n if (prev.has(id)) {\n next.delete(id)\n } else {\n next.add(id)\n anchor = id\n }\n ids.set(next)\n }\n\n const clear = (): void => {\n if (ids.peek().size === 0) {\n anchor = null\n return\n }\n ids.set(new Set())\n anchor = null\n }\n\n const selectAll = (incoming: readonly string[]): void => {\n ids.set(new Set(incoming))\n anchor = incoming.length > 0 ? (incoming[incoming.length - 1] ?? null) : null\n }\n\n const handleClick = (\n id: string,\n mods: { shift?: boolean; meta?: boolean },\n ordered: readonly string[] | ReadonlyMap<string, number>,\n ): void => {\n if (mods.shift && anchor !== null) {\n // Accept either a positional array (back-compat, O(n) lookup) OR a\n // precomputed `Map<id, index>` for O(1) shift-click on large lists\n // (a 100k-row virtualized table doesn't want to scan the array twice\n // per click). The caller decides which to pass — `Map` is cheap to\n // build once when the row list changes.\n let anchorIdx: number\n let targetIdx: number\n let slice: readonly string[]\n if (Array.isArray(ordered)) {\n const arr = ordered as readonly string[]\n anchorIdx = arr.indexOf(anchor)\n targetIdx = arr.indexOf(id)\n if (anchorIdx === -1 || targetIdx === -1) {\n ids.set(new Set([id]))\n anchor = id\n preShiftSelection = null\n return\n }\n const [lo, hi] = anchorIdx < targetIdx ? [anchorIdx, targetIdx] : [targetIdx, anchorIdx]\n slice = arr.slice(lo, hi + 1)\n } else {\n const map = ordered as ReadonlyMap<string, number>\n anchorIdx = map.get(anchor) ?? -1\n targetIdx = map.get(id) ?? -1\n if (anchorIdx === -1 || targetIdx === -1) {\n ids.set(new Set([id]))\n anchor = id\n preShiftSelection = null\n return\n }\n const [lo, hi] = anchorIdx < targetIdx ? [anchorIdx, targetIdx] : [targetIdx, anchorIdx]\n // The Map gives O(1) index lookup. To materialise the range we\n // still need keys at [lo, hi]; iterate the insertion-ordered Map\n // once and bail when we've collected enough. The 0..hi prefix is\n // O(hi) — bounded by the range length, not the full list.\n const keys: string[] = []\n let i = 0\n for (const k of map.keys()) {\n if (i >= lo && i <= hi) keys.push(k)\n if (i >= hi) break\n i += 1\n }\n slice = keys\n }\n if (preShiftSelection === null) {\n preShiftSelection = ids.peek()\n }\n const next = new Set(preShiftSelection)\n for (const k of slice) next.add(k)\n ids.set(next)\n // Anchor stays — subsequent shift-clicks extend from the same origin.\n return\n }\n // Any non-shift click ends the shift run.\n preShiftSelection = null\n if (mods.meta) {\n toggle(id)\n return\n }\n ids.set(new Set([id]))\n anchor = id\n }\n\n return {\n selectedIds: readOnly(ids),\n size,\n isSelected,\n select,\n deselect,\n toggle,\n clear,\n selectAll,\n handleClick,\n }\n}\n","import { effect, signal } from '../signals'\nimport { readOnly } from '../signals/readonly'\nimport type { ReadSignal } from '../signals/types'\n\n/**\n * A `ReadSignal<T>` returned by `debounced` / `throttled`. Extends the\n * subscription surface with manual `cancel()` and `flush()`.\n *\n * - `cancel()` drops any pending emission without firing. Useful when a\n * navigation away from the screen should discard the latest in-flight\n * draft instead of writing it through to the debounced output.\n * - `flush()` immediately emits the pending value (if any). Useful at\n * submit time: \"commit whatever the user just typed without waiting\n * for the debounce timer to fire.\"\n *\n * Both are no-ops when nothing is pending.\n */\nexport type TimingSignal<T> = ReadSignal<T> & {\n cancel(): void\n flush(): void\n /**\n * Tear down the internal effect (drop the subscription to `source`) and\n * clear any pending timer. Idempotent. Call this when the timing signal\n * has no `options.signal` tying its lifecycle to an AbortController —\n * otherwise the effect keeps `source` subscribed forever.\n */\n dispose(): void\n}\n\n/**\n * Lag a signal by `ms`. The returned signal updates only after the source has\n * been unchanged for `ms`. Each new write resets the timer.\n *\n * - `leading: true` (default `false`) emits immediately on the first write,\n * then suppresses further writes until `ms` has passed since the last\n * emission. Combine with trailing (default `true`) for \"first + last\"\n * semantics.\n * - `trailing: false` disables the trailing emission. Pair with\n * `leading: true` for \"only fire on the leading edge\" semantics.\n * - `options.signal` (`AbortSignal`) ties the internal effect to a\n * lifecycle — when the signal aborts the effect disposes, the pending\n * timer clears, and the subscriber chain on `source` drops.\n */\nexport function debounced<T>(\n source: ReadSignal<T>,\n ms: number,\n options?: { signal?: AbortSignal; leading?: boolean; trailing?: boolean },\n): TimingSignal<T> {\n const leading = options?.leading ?? false\n const trailing = options?.trailing ?? true\n if (!leading && !trailing) {\n throw new Error(\n '[olas] debounced: at least one of `leading` or `trailing` must be true (both false never emits).',\n )\n }\n const out = signal<T>(source.peek())\n let timer: ReturnType<typeof setTimeout> | null = null\n let pendingValue: T = source.peek()\n let hasPending = false\n let initial = true\n let inCooldown = false\n\n const fireTrailing = () => {\n timer = null\n inCooldown = false\n if (hasPending && trailing) {\n out.set(pendingValue)\n hasPending = false\n }\n }\n\n const disposeEffect = effect(() => {\n const value = source.value\n if (initial) {\n initial = false\n return\n }\n pendingValue = value\n if (timer != null) clearTimeout(timer)\n if (leading && !inCooldown) {\n // Leading edge — emit now, start a cooldown timer that, if untouched\n // by another write, fires the trailing edge with the same value.\n out.set(value)\n hasPending = false\n inCooldown = true\n timer = setTimeout(fireTrailing, ms)\n } else {\n // Pending only matters if a trailing emit can actually happen. With\n // `trailing: false` the timer just resets the cooldown and must NOT\n // leave a value for a later `flush()` to emit. (T2.7)\n hasPending = trailing\n timer = setTimeout(fireTrailing, ms)\n }\n })\n\n const cancel = () => {\n if (timer != null) {\n clearTimeout(timer)\n timer = null\n }\n hasPending = false\n inCooldown = false\n }\n const flush = () => {\n if (timer != null) {\n clearTimeout(timer)\n timer = null\n }\n if (hasPending) {\n out.set(pendingValue)\n hasPending = false\n }\n inCooldown = false\n }\n\n const dispose = () => {\n cancel()\n disposeEffect()\n }\n\n const sig = options?.signal\n if (sig) {\n if (sig.aborted) dispose()\n else sig.addEventListener('abort', dispose, { once: true })\n }\n\n // Expose a read-only projection of `out` plus the control surface. The old\n // `out as TimingSignal` cast leaked `out.set` to callers. (T2.7)\n const handle = Object.assign(Object.create(readOnly(out)), {\n cancel,\n flush,\n dispose,\n }) as TimingSignal<T>\n return handle\n}\n","import { effect, signal } from '../signals'\nimport { readOnly } from '../signals/readonly'\nimport type { ReadSignal } from '../signals/types'\nimport type { TimingSignal } from './debounced'\n\n/**\n * Time source — `Date.now()`. Stays in lockstep with `vi.setSystemTime()`\n * for tests that exercise time-jumps; downstream consumers that need a\n * monotonic clock can pass `options.signal` and gate on system-time\n * changes externally.\n */\nfunction now(): number {\n return Date.now()\n}\n\n/**\n * Rate-limit a signal so it emits at most once per `ms` (leading + trailing).\n * The first change passes through immediately. Subsequent changes within the\n * window are coalesced; the latest value is emitted when the window expires.\n *\n * - `leading: false` (default `true`) skips the immediate leading-edge\n * emission. Useful for \"fire only after the window settles\" semantics.\n * - `trailing: false` (default `true`) skips the windowed trailing emit.\n * Combine with `leading: true` for \"only fire on the leading edge.\"\n * - `options.signal` ties the internal effect to a lifecycle.\n *\n * The returned handle exposes `cancel()` / `flush()` — see `TimingSignal`.\n */\nexport function throttled<T>(\n source: ReadSignal<T>,\n ms: number,\n options?: { signal?: AbortSignal; leading?: boolean; trailing?: boolean },\n): TimingSignal<T> {\n const leading = options?.leading ?? true\n const trailing = options?.trailing ?? true\n if (!leading && !trailing) {\n throw new Error(\n '[olas] throttled: at least one of `leading` or `trailing` must be true (both false never emits).',\n )\n }\n const out = signal<T>(source.peek())\n let lastEmit = Number.NEGATIVE_INFINITY\n let trailingTimer: ReturnType<typeof setTimeout> | null = null\n let trailingValue: T = source.peek()\n let hasPending = false\n let initial = true\n\n const fireTrailing = () => {\n trailingTimer = null\n if (hasPending && trailing) {\n out.set(trailingValue)\n lastEmit = now()\n hasPending = false\n }\n }\n\n const disposeEffect = effect(() => {\n const value = source.value\n if (initial) {\n initial = false\n return\n }\n const t = now()\n const elapsed = t - lastEmit\n if (elapsed >= ms && leading) {\n out.set(value)\n lastEmit = t\n hasPending = false\n // The leading emit consumed the value — drop any stale trailing-pending.\n if (trailingTimer != null) {\n clearTimeout(trailingTimer)\n trailingTimer = null\n }\n } else if (trailing) {\n // Coalesce into the trailing edge. With `trailing: false` we schedule\n // nothing and never set `hasPending`, so a later `flush()` can't emit a\n // value the option said should never fire. (T2.7)\n trailingValue = value\n hasPending = true\n const delay = elapsed >= ms ? ms : ms - elapsed\n if (trailingTimer == null) trailingTimer = setTimeout(fireTrailing, delay)\n }\n })\n\n const cancel = () => {\n if (trailingTimer != null) {\n clearTimeout(trailingTimer)\n trailingTimer = null\n }\n hasPending = false\n }\n const flush = () => {\n if (trailingTimer != null) {\n clearTimeout(trailingTimer)\n trailingTimer = null\n }\n if (hasPending) {\n out.set(trailingValue)\n lastEmit = now()\n hasPending = false\n }\n }\n\n const dispose = () => {\n cancel()\n disposeEffect()\n }\n\n const sig = options?.signal\n if (sig) {\n if (sig.aborted) dispose()\n else sig.addEventListener('abort', dispose, { once: true })\n }\n\n // Read-only projection + control surface; the old cast leaked `out.set`. (T2.7)\n const handle = Object.assign(Object.create(readOnly(out)), {\n cancel,\n flush,\n dispose,\n }) as TimingSignal<T>\n return handle\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as UseOptions, A as Mutation, B as InfiniteQuerySubscription, C as QueryClientPluginApi, Ct as EmitterErrorReporter, E as SetDataEvent, F as DebugBus, G as LocalCache, H as AsyncStatus, I as DebugCacheEntry, J as QuerySpec, K as NetworkMode, L as DebugEvent, M as MutationDef, N as MutationSpec, O as lookupRegisteredMutation, P as defineMutation, Q as Snapshot, R as InfiniteQuery, S as QueryClientPlugin, St as Emitter, T as RegisteredQuery, U as DehydratedEntry, V as AsyncState, W as DehydratedState, X as RetryDelay, Y as QuerySubscription, Z as RetryPolicy, _ as defineScope, _t as ReadSignal, a as CollectionFactoryResult, at as FieldArrayValue, b as MutationEnqueueEvent, bt as ErrorContextInput, c as CtrlApi, ct as FormOptions, d as Field, dt as FormValue, et as DeepPartial, f as LazyChild, ft as ItemInitial, g as ScopeOptions, gt as Computed, h as Scope, ht as ValidatorResult, i as CollectionFactoryOptions, it as FieldArrayValidator, j as MutationConcurrency, k as lookupRegisteredQuery, l as CtrlProps, lt as FormSchema, m as RootOptions, mt as Validator, n as Collection, nt as FieldArrayItemErrors, o as CollectionHomogeneousOptions, ot as Form, p as Root, pt as FormIssue, q as Query, r as CollectionFactoryApi, rt as FieldArrayOptions, s as ControllerDef, st as FormErrors, t as AmbientDeps, tt as FieldArray, u as Ctx, ut as FormValidator, v as GcEvent, vt as Signal, w as RegisteredMutation, wt as createEmitter, x as MutationSettleEvent, xt as ErrorHandler, y as InvalidateEvent, yt as ErrorContext, z as InfiniteQuerySpec } from "./types-DzDIypPo.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/signals/runtime.d.ts
|
|
4
4
|
/**
|
|
@@ -66,7 +66,52 @@ declare function defineController<Props = void, Api = unknown>(factory: (ctx: Ct
|
|
|
66
66
|
* Construct a root controller. Root factories take no props — startup config
|
|
67
67
|
* goes in `deps`.
|
|
68
68
|
*/
|
|
69
|
-
declare function createRoot<Api, TDeps extends Record<string, unknown> = AmbientDeps>(def: ControllerDef<void, Api>, options: RootOptions<TDeps>): Root<Api>;
|
|
69
|
+
declare function createRoot<Api extends object, TDeps extends Record<string, unknown> = AmbientDeps>(def: ControllerDef<void, Api>, options: RootOptions<TDeps>): Root<Api>;
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/forms/field.d.ts
|
|
72
|
+
/**
|
|
73
|
+
* When a field's validators are first allowed to run.
|
|
74
|
+
*
|
|
75
|
+
* - `'change'` (default) — validators run on every `set()`. Matches the
|
|
76
|
+
* current behavior, ideal for "type and see errors live."
|
|
77
|
+
* - `'blur'` — first run is gated on `markTouched()`. After that, subsequent
|
|
78
|
+
* value changes do trigger re-validation. UI binding should call
|
|
79
|
+
* `markTouched()` on `onBlur`.
|
|
80
|
+
* - `'submit'` — first run is gated on `revalidate()` / `Form.submit()`.
|
|
81
|
+
* After that, subsequent value changes re-validate. Use when you want
|
|
82
|
+
* "show errors only after the user explicitly tried to submit."
|
|
83
|
+
*
|
|
84
|
+
* `revalidate()` always unlocks the field regardless of mode.
|
|
85
|
+
*/
|
|
86
|
+
type ValidateOn = 'change' | 'blur' | 'submit';
|
|
87
|
+
/**
|
|
88
|
+
* A bidirectional `T ↔ string` transform, suitable for HTML input bindings
|
|
89
|
+
* where DOM values are always strings.
|
|
90
|
+
*
|
|
91
|
+
* `parse(raw)` converts the input's string value into the field's type;
|
|
92
|
+
* `format(value)` converts the field's typed value back into a string for
|
|
93
|
+
* the input. Both must be pure — `useFieldInput` calls them on every
|
|
94
|
+
* render and every input event respectively.
|
|
95
|
+
*
|
|
96
|
+
* ```ts
|
|
97
|
+
* const numberTransform: FieldTransform<number> = {
|
|
98
|
+
* parse: (raw) => Number(raw),
|
|
99
|
+
* format: (v) => String(v),
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
type FieldTransform<T> = {
|
|
104
|
+
parse: (raw: string) => T;
|
|
105
|
+
format: (value: T) => string;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Wrap an async validator with a debounce. The debounce timer resets on every
|
|
109
|
+
* value change. While debouncing or the request is in flight, the field's
|
|
110
|
+
* `isValidating` is true and `isValid` HOLDS its last settled value (T5.3) — so
|
|
111
|
+
* editing an already-valid field doesn't strobe a submit button to disabled on
|
|
112
|
+
* every keystroke. A field with no prior settled validation defaults to valid.
|
|
113
|
+
*/
|
|
114
|
+
declare function debouncedValidator<T>(fn: (value: T, signal: AbortSignal) => Promise<string | null>, ms: number): (value: T, signal: AbortSignal) => Promise<string | null>;
|
|
70
115
|
//#endregion
|
|
71
116
|
//#region src/forms/standard-schema.d.ts
|
|
72
117
|
/**
|
|
@@ -108,19 +153,28 @@ declare function isStandardSchema(x: unknown): x is StandardSchemaV1<unknown, un
|
|
|
108
153
|
//#region src/forms/validators.d.ts
|
|
109
154
|
/**
|
|
110
155
|
* Wrap any Standard-Schema-compatible schema (Zod 4, Valibot 1, ArkType 2,
|
|
111
|
-
* …) as an Olas validator.
|
|
112
|
-
*
|
|
156
|
+
* …) as an Olas validator. Returns **all** issues as `FormIssue[]`, each
|
|
157
|
+
* carrying the schema's own `path` — so a whole-form schema used as a
|
|
158
|
+
* form-level validator routes each issue onto the matching field (T5.2),
|
|
159
|
+
* and a leaf schema (whose issues have empty paths) still reports on the
|
|
160
|
+
* field it's attached to. An empty array means "valid".
|
|
113
161
|
*
|
|
114
162
|
* Standard Schema validators may be sync or async; this wrapper threads
|
|
115
|
-
* through whichever the schema returns — `Promise<
|
|
163
|
+
* through whichever the schema returns — `Promise<FormIssue[]>` only when
|
|
116
164
|
* the underlying validate call is itself async.
|
|
117
165
|
*
|
|
118
166
|
* `signal` is accepted to match the `Validator<T>` shape but isn't forwarded
|
|
119
167
|
* — Standard Schema v1 has no cancellation surface.
|
|
120
168
|
*/
|
|
121
169
|
declare function validator<I, O>(schema: StandardSchemaV1<I, O>): Validator<I>;
|
|
122
|
-
/** Reject empty values (undefined, null, empty string, empty array). */
|
|
170
|
+
/** Reject empty values (undefined, null, empty string, empty array). Booleans always pass. */
|
|
123
171
|
declare const required: <T>(message?: string) => Validator<T>;
|
|
172
|
+
/**
|
|
173
|
+
* Reject any value that isn't boolean `true` — the "you must check this box"
|
|
174
|
+
* rule for consent / terms-of-service / confirm checkboxes. Unlike `required`
|
|
175
|
+
* (which now accepts `false` as a valid boolean), this fails on `false`.
|
|
176
|
+
*/
|
|
177
|
+
declare const mustBeTrue: (message?: string) => Validator<boolean>;
|
|
124
178
|
/** Reject strings / arrays shorter than `n`. Allows null/undefined (use with `required` to forbid). */
|
|
125
179
|
declare const minLength: (n: number, message?: string) => Validator<string | readonly unknown[]>;
|
|
126
180
|
/** Reject strings / arrays longer than `n`. */
|
|
@@ -134,14 +188,6 @@ declare const email: (message?: string) => Validator<string>;
|
|
|
134
188
|
/** Reject strings that don't match the supplied `RegExp`. */
|
|
135
189
|
declare const pattern: (re: RegExp, message?: string) => Validator<string>;
|
|
136
190
|
//#endregion
|
|
137
|
-
//#region src/forms/field.d.ts
|
|
138
|
-
/**
|
|
139
|
-
* Wrap an async validator with a debounce. The debounce timer resets on every
|
|
140
|
-
* value change. While debouncing or the request is in flight, the field's
|
|
141
|
-
* `isValidating` is true and `isValid` is false (treat-as-invalid-until-proven-valid).
|
|
142
|
-
*/
|
|
143
|
-
declare function debouncedValidator<T>(fn: (value: T, signal: AbortSignal) => Promise<string | null>, ms: number): Validator<T>;
|
|
144
|
-
//#endregion
|
|
145
191
|
//#region src/query/define.d.ts
|
|
146
192
|
/**
|
|
147
193
|
* Define a keyed, shared query. The returned Query value lives at module
|
|
@@ -161,7 +207,7 @@ declare function defineInfiniteQuery<Args extends unknown[], PageParam, TPage, T
|
|
|
161
207
|
/**
|
|
162
208
|
* Stable string hash of a key tuple. Two equal-by-content args produce the
|
|
163
209
|
* same string regardless of property iteration order. Handles primitives,
|
|
164
|
-
* arrays, plain objects, Date.
|
|
210
|
+
* arrays, plain objects, Date, BigInt, NaN, ±Infinity.
|
|
165
211
|
*
|
|
166
212
|
* Functions and symbols throw — keys must be serializable so distinct
|
|
167
213
|
* subscribers can share entries.
|
|
@@ -188,7 +234,7 @@ type Selection<T = unknown> = {
|
|
|
188
234
|
handleClick(id: string, mods: {
|
|
189
235
|
shift?: boolean;
|
|
190
236
|
meta?: boolean;
|
|
191
|
-
}, ordered: readonly string[]): void;
|
|
237
|
+
}, ordered: readonly string[] | ReadonlyMap<string, number>): void;
|
|
192
238
|
};
|
|
193
239
|
/**
|
|
194
240
|
* Create a `Selection<T>`. Optional `initial` seeds the selected set.
|
|
@@ -206,19 +252,49 @@ declare function selection<T = unknown>(options?: {
|
|
|
206
252
|
}): Selection<T>;
|
|
207
253
|
//#endregion
|
|
208
254
|
//#region src/timing/debounced.d.ts
|
|
255
|
+
/**
|
|
256
|
+
* A `ReadSignal<T>` returned by `debounced` / `throttled`. Extends the
|
|
257
|
+
* subscription surface with manual `cancel()` and `flush()`.
|
|
258
|
+
*
|
|
259
|
+
* - `cancel()` drops any pending emission without firing. Useful when a
|
|
260
|
+
* navigation away from the screen should discard the latest in-flight
|
|
261
|
+
* draft instead of writing it through to the debounced output.
|
|
262
|
+
* - `flush()` immediately emits the pending value (if any). Useful at
|
|
263
|
+
* submit time: "commit whatever the user just typed without waiting
|
|
264
|
+
* for the debounce timer to fire."
|
|
265
|
+
*
|
|
266
|
+
* Both are no-ops when nothing is pending.
|
|
267
|
+
*/
|
|
268
|
+
type TimingSignal<T> = ReadSignal<T> & {
|
|
269
|
+
cancel(): void;
|
|
270
|
+
flush(): void;
|
|
271
|
+
/**
|
|
272
|
+
* Tear down the internal effect (drop the subscription to `source`) and
|
|
273
|
+
* clear any pending timer. Idempotent. Call this when the timing signal
|
|
274
|
+
* has no `options.signal` tying its lifecycle to an AbortController —
|
|
275
|
+
* otherwise the effect keeps `source` subscribed forever.
|
|
276
|
+
*/
|
|
277
|
+
dispose(): void;
|
|
278
|
+
};
|
|
209
279
|
/**
|
|
210
280
|
* Lag a signal by `ms`. The returned signal updates only after the source has
|
|
211
281
|
* been unchanged for `ms`. Each new write resets the timer.
|
|
212
282
|
*
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
*
|
|
283
|
+
* - `leading: true` (default `false`) emits immediately on the first write,
|
|
284
|
+
* then suppresses further writes until `ms` has passed since the last
|
|
285
|
+
* emission. Combine with trailing (default `true`) for "first + last"
|
|
286
|
+
* semantics.
|
|
287
|
+
* - `trailing: false` disables the trailing emission. Pair with
|
|
288
|
+
* `leading: true` for "only fire on the leading edge" semantics.
|
|
289
|
+
* - `options.signal` (`AbortSignal`) ties the internal effect to a
|
|
290
|
+
* lifecycle — when the signal aborts the effect disposes, the pending
|
|
291
|
+
* timer clears, and the subscriber chain on `source` drops.
|
|
218
292
|
*/
|
|
219
293
|
declare function debounced<T>(source: ReadSignal<T>, ms: number, options?: {
|
|
220
294
|
signal?: AbortSignal;
|
|
221
|
-
|
|
295
|
+
leading?: boolean;
|
|
296
|
+
trailing?: boolean;
|
|
297
|
+
}): TimingSignal<T>;
|
|
222
298
|
//#endregion
|
|
223
299
|
//#region src/timing/throttled.d.ts
|
|
224
300
|
/**
|
|
@@ -226,13 +302,19 @@ declare function debounced<T>(source: ReadSignal<T>, ms: number, options?: {
|
|
|
226
302
|
* The first change passes through immediately. Subsequent changes within the
|
|
227
303
|
* window are coalesced; the latest value is emitted when the window expires.
|
|
228
304
|
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
305
|
+
* - `leading: false` (default `true`) skips the immediate leading-edge
|
|
306
|
+
* emission. Useful for "fire only after the window settles" semantics.
|
|
307
|
+
* - `trailing: false` (default `true`) skips the windowed trailing emit.
|
|
308
|
+
* Combine with `leading: true` for "only fire on the leading edge."
|
|
309
|
+
* - `options.signal` ties the internal effect to a lifecycle.
|
|
310
|
+
*
|
|
311
|
+
* The returned handle exposes `cancel()` / `flush()` — see `TimingSignal`.
|
|
232
312
|
*/
|
|
233
313
|
declare function throttled<T>(source: ReadSignal<T>, ms: number, options?: {
|
|
234
314
|
signal?: AbortSignal;
|
|
235
|
-
|
|
315
|
+
leading?: boolean;
|
|
316
|
+
trailing?: boolean;
|
|
317
|
+
}): TimingSignal<T>;
|
|
236
318
|
//#endregion
|
|
237
319
|
//#region src/utils.d.ts
|
|
238
320
|
/**
|
|
@@ -245,5 +327,5 @@ declare function throttled<T>(source: ReadSignal<T>, ms: number, options?: {
|
|
|
245
327
|
*/
|
|
246
328
|
declare function isAbortError(err: unknown): boolean;
|
|
247
329
|
//#endregion
|
|
248
|
-
export { type AmbientDeps, type AsyncState, type AsyncStatus, type Collection, type CollectionFactoryApi, type CollectionFactoryOptions, type CollectionFactoryResult, type CollectionHomogeneousOptions, type Computed, type ControllerDef, type CtrlApi, type CtrlProps, type Ctx, type DebugBus, type DebugCacheEntry, type DebugEvent, type DeepPartial, type DehydratedEntry, type DehydratedState, type Emitter, type EmitterErrorReporter, type ErrorContext, type Field, type FieldArray, type FieldArrayItemErrors, type FieldArrayOptions, type FieldArrayValidator, type FieldArrayValue, type Form, type FormErrors, type FormOptions, type FormSchema, type FormValidator, type FormValue, type GcEvent, type InfiniteQuery, type InfiniteQuerySpec, type InfiniteQuerySubscription, type InvalidateEvent, type ItemInitial, type LazyChild, type LocalCache, type Mutation, type MutationConcurrency, type MutationDef, type MutationEnqueueEvent, type MutationSettleEvent, type MutationSpec, type Query, type QueryClientPlugin, type QueryClientPluginApi, type QuerySpec, type QuerySubscription, type ReadSignal, type RegisteredMutation, type RegisteredQuery, type RetryDelay, type RetryPolicy, type Root, type RootOptions, type Scope, type ScopeOptions, type Selection, type SetDataEvent, type Signal, type Snapshot, type StandardSchemaV1, type UseOptions, type Validator,
|
|
330
|
+
export { type AmbientDeps, type AsyncState, type AsyncStatus, type Collection, type CollectionFactoryApi, type CollectionFactoryOptions, type CollectionFactoryResult, type CollectionHomogeneousOptions, type Computed, type ControllerDef, type CtrlApi, type CtrlProps, type Ctx, type DebugBus, type DebugCacheEntry, type DebugEvent, type DeepPartial, type DehydratedEntry, type DehydratedState, type Emitter, type EmitterErrorReporter, type ErrorContext, type ErrorContextInput, type ErrorHandler, type Field, type FieldArray, type FieldArrayItemErrors, type FieldArrayOptions, type FieldArrayValidator, type FieldArrayValue, type FieldTransform, type Form, type FormErrors, type FormIssue, type FormOptions, type FormSchema, type FormValidator, type FormValue, type GcEvent, type InfiniteQuery, type InfiniteQuerySpec, type InfiniteQuerySubscription, type InvalidateEvent, type ItemInitial, type LazyChild, type LocalCache, type Mutation, type MutationConcurrency, type MutationDef, type MutationEnqueueEvent, type MutationSettleEvent, type MutationSpec, type NetworkMode, type Query, type QueryClientPlugin, type QueryClientPluginApi, type QuerySpec, type QuerySubscription, type ReadSignal, type RegisteredMutation, type RegisteredQuery, type RetryDelay, type RetryPolicy, type Root, type RootOptions, type Scope, type ScopeOptions, type Selection, type SetDataEvent, type Signal, type Snapshot, type StandardSchemaV1, type TimingSignal, type UseOptions, type ValidateOn, type Validator, type ValidatorResult, batch, computed, createEmitter, createRoot, debounced, debouncedValidator, defineController, defineInfiniteQuery, defineMutation, defineQuery, defineScope, effect, email, isAbortError, isStandardSchema, lookupRegisteredMutation, lookupRegisteredQuery, max, maxLength, min, minLength, mustBeTrue, pattern, required, selection, signal, stableHash, throttled, untracked, validator };
|
|
249
331
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/signals/runtime.ts","../src/controller/define.ts","../src/controller/root.ts","../src/forms/
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/signals/runtime.ts","../src/controller/define.ts","../src/controller/root.ts","../src/forms/field.ts","../src/forms/standard-schema.ts","../src/forms/validators.ts","../src/query/define.ts","../src/query/keys.ts","../src/selection.ts","../src/timing/debounced.ts","../src/timing/throttled.ts","../src/utils.ts"],"mappings":"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"}
|