@happyvertical/smrt-content 0.43.4 → 0.43.5

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.
Files changed (34) hide show
  1. package/AGENTS.md +9 -86
  2. package/agents/content-list.md +869 -0
  3. package/dist/content-query.d.ts +310 -0
  4. package/dist/content-query.d.ts.map +1 -0
  5. package/dist/contents.d.ts +22 -0
  6. package/dist/contents.d.ts.map +1 -1
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +672 -4
  10. package/dist/index.js.map +1 -1
  11. package/dist/manifest.json +22 -2
  12. package/dist/smrt-knowledge.json +38 -5
  13. package/dist/svelte/components/ContentList.svelte +941 -30
  14. package/dist/svelte/components/ContentList.svelte.d.ts +44 -1
  15. package/dist/svelte/components/ContentList.svelte.d.ts.map +1 -1
  16. package/dist/svelte/content-list-controller.d.ts +98 -1
  17. package/dist/svelte/content-list-controller.d.ts.map +1 -1
  18. package/dist/svelte/content-list-controller.js +290 -19
  19. package/dist/svelte/content-list-query.d.ts +498 -0
  20. package/dist/svelte/content-list-query.d.ts.map +1 -0
  21. package/dist/svelte/content-list-query.js +1294 -0
  22. package/dist/svelte/content-list-saved-views.d.ts +172 -0
  23. package/dist/svelte/content-list-saved-views.d.ts.map +1 -0
  24. package/dist/svelte/content-list-saved-views.js +298 -0
  25. package/dist/svelte/content-list-url-state.d.ts +211 -0
  26. package/dist/svelte/content-list-url-state.d.ts.map +1 -0
  27. package/dist/svelte/content-list-url-state.js +856 -0
  28. package/dist/svelte/i18n.contribution.d.ts +24 -0
  29. package/dist/svelte/i18n.contribution.d.ts.map +1 -1
  30. package/dist/svelte/i18n.contribution.js +26 -0
  31. package/dist/svelte/index.d.ts +5 -1
  32. package/dist/svelte/index.d.ts.map +1 -1
  33. package/dist/svelte/index.js +8 -1
  34. package/package.json +16 -15
@@ -0,0 +1,498 @@
1
+ /**
2
+ * Server-backed ContentList queries (#2452).
3
+ *
4
+ * This module is the seam between the ContentList adapter's *view state* and
5
+ * the canonical bounded data-query protocol (#2444) that
6
+ * `POST /api/v1/contents/query` speaks. It owns three things:
7
+ *
8
+ * 1. {@link contentListViewStateToDataQueryRequest} — the translator. It turns
9
+ * search, declarative filters, sorting, and paging into a
10
+ * `DataQueryRequest`, dropping (never throwing on) anything the protocol
11
+ * cannot express and reporting what it dropped.
12
+ * 2. {@link createContentListQueryTransport} — a `fetch` transport for that
13
+ * route, which unwraps the generated `{ action, result }` envelope and turns
14
+ * the `{ error: { … } }` envelope into a thrown, coded error.
15
+ * 3. {@link ContentListQueryBinding} — the structural seam a caller binds a
16
+ * remote query through.
17
+ *
18
+ * ## Three id namespaces
19
+ *
20
+ * A content list value crosses three vocabularies, and they do not agree:
21
+ *
22
+ * | Namespace | Example | Owner |
23
+ * |---|---|---|
24
+ * | adapter column id | `updated` | `content-list-controller.ts` |
25
+ * | `ContentData` client field | `updatedAt` | `mock-smrt-client.ts` |
26
+ * | server data-query field id | `updated_at` | the registered `Content` model |
27
+ *
28
+ * {@link CONTENT_LIST_QUERY_FIELDS} is the single explicit column → server
29
+ * field map, and `content-list-query.test.ts` asserts it against the field ids
30
+ * and declared operators of the real `buildContentQuerySchema()`. A model
31
+ * rename therefore breaks a test rather than production.
32
+ *
33
+ * A column with no server field is not queryable server-side and is dropped
34
+ * from the request: `site` is derived in the browser from `url`/`source`, so
35
+ * there is nothing for the server to filter or sort on.
36
+ *
37
+ * ## Deliberate structural mirror
38
+ *
39
+ * The request/result types here mirror `@happyvertical/smrt-types` (and
40
+ * `@happyvertical/smrt-web`'s browser copy) structurally rather than by import.
41
+ * `@happyvertical/smrt-content` must not pull the browser data runtime into its
42
+ * Svelte barrel: that runtime is code-split precisely so it never loads on
43
+ * public content pages, and a barrel-level import would defeat that. The mirror
44
+ * is exact, so a `RemoteQueryBinding` from
45
+ * `@happyvertical/smrt-svelte/web` satisfies {@link ContentListQueryBinding}
46
+ * without a cast.
47
+ *
48
+ * ## Documented limits
49
+ *
50
+ * - **Offset paging only.** The content query schema declares
51
+ * `supports.cursorPagination: false`.
52
+ * - **`body` is not queryable.** It is a document, not list data.
53
+ * - **`metadata` path filtering is unavailable.** JSON columns have no portable
54
+ * predicate, so the schema declares no filter operators for them.
55
+ * - **No ETag/version slot.** The canonical envelope carries a
56
+ * `queryFingerprint` plus `freshness.asOf` instead.
57
+ * - **Filters compare exactly.** The server compares the stored value. The
58
+ * adapter folds case only for the token columns (`type`, `status`, `state`),
59
+ * because free text has to reach the server as the operator typed it.
60
+ * - **NULL semantics are aligned end to end.** `ne`/`notIn` union `IS NULL`
61
+ * server-side, as `in` already did — unless the caller listed `null`, which
62
+ * inverts the meaning, and a NEGATED ordered comparison unions so that a
63
+ * predicate and its negation stay complements. The ordered comparisons,
64
+ * `isNull`/`isNotNull`, and the `type`/`title` display fallbacks were aligned
65
+ * on the local side instead, by consulting the original `ContentData` rather
66
+ * than the flattened display text. See `agents/content-list.md`.
67
+ */
68
+ import type { DataTableViewState } from '@happyvertical/smrt-ui/data';
69
+ import type { ContentData } from '../mock-smrt-client.js';
70
+ import type { ContentListColumnId } from './content-list-controller.js';
71
+ import { type ContentListStateDropScope } from './content-list-url-state.js';
72
+ export type ContentListQueryScalar = string | number | boolean | null;
73
+ export type ContentListQueryFilterOperator = 'eq' | 'ne' | 'gt' | 'gte' | 'lt' | 'lte' | 'in' | 'notIn' | 'like';
74
+ export type ContentListQueryFilter = {
75
+ kind: 'condition';
76
+ field: string;
77
+ operator: ContentListQueryFilterOperator;
78
+ value: ContentListQueryScalar | ContentListQueryScalar[];
79
+ } | {
80
+ kind: 'all' | 'any';
81
+ filters: ContentListQueryFilter[];
82
+ } | {
83
+ kind: 'not';
84
+ filter: ContentListQueryFilter;
85
+ };
86
+ export interface ContentListDataQueryRequest {
87
+ version: 1;
88
+ requestId: string;
89
+ mode: 'rows' | 'count' | 'facets';
90
+ projection?: string[];
91
+ filter?: ContentListQueryFilter;
92
+ sort?: Array<{
93
+ field: string;
94
+ direction: 'asc' | 'desc';
95
+ }>;
96
+ page?: {
97
+ kind: 'offset';
98
+ offset: number;
99
+ limit: number;
100
+ } | {
101
+ kind: 'cursor';
102
+ after?: string;
103
+ limit: number;
104
+ };
105
+ consistency?: {
106
+ mode: 'eventual' | 'snapshot';
107
+ asOf?: string;
108
+ };
109
+ facets?: Array<{
110
+ field: string;
111
+ limit: number;
112
+ }>;
113
+ }
114
+ export type ContentListQueryTotal = {
115
+ kind: 'exact' | 'estimated';
116
+ value: number;
117
+ asOf?: string;
118
+ } | {
119
+ kind: 'unavailable';
120
+ reason?: string;
121
+ };
122
+ export interface ContentListDataQueryResult {
123
+ version: 1;
124
+ requestId: string;
125
+ queryFingerprint: string;
126
+ identityField: string;
127
+ rows: Array<Record<string, unknown>>;
128
+ page?: {
129
+ kind: 'offset';
130
+ limit: number;
131
+ offset: number;
132
+ hasMore: boolean;
133
+ } | {
134
+ kind: 'cursor';
135
+ limit: number;
136
+ nextCursor?: string;
137
+ hasMore: boolean;
138
+ };
139
+ total: ContentListQueryTotal;
140
+ freshness: {
141
+ state: 'fresh' | 'stale' | 'unknown';
142
+ asOf?: string;
143
+ };
144
+ warnings: string[];
145
+ truncated: boolean;
146
+ }
147
+ /** The declared type of a server field, mirroring `DataQueryFieldDescriptor`. */
148
+ export type ContentListQueryFieldType = 'string' | 'number' | 'boolean' | 'datetime' | 'json';
149
+ export interface ContentListQueryField {
150
+ /** Server data-query field id (an SMRT field name). */
151
+ field: string;
152
+ type: ContentListQueryFieldType;
153
+ }
154
+ /**
155
+ * The single explicit adapter-column → server-field map.
156
+ *
157
+ * `null` means the column has no server field at all and is therefore neither
158
+ * filterable nor sortable server-side. Only `site` is in that state: it is
159
+ * derived from `url`/`source` in the browser, so the server has nothing to
160
+ * order or compare.
161
+ */
162
+ export declare const CONTENT_LIST_QUERY_FIELDS: Readonly<Record<ContentListColumnId, ContentListQueryField | null>>;
163
+ /** Row identity, matching `CONTENT_QUERY_IDENTITY_FIELD`. */
164
+ export declare const CONTENT_LIST_QUERY_IDENTITY_FIELD = "id";
165
+ /**
166
+ * The schema's `defaultSort`, mirrored so the translator can send it rather
167
+ * than let the normalizer inject it. Cross-asserted against the real schema in
168
+ * `content-list-query.test.ts`.
169
+ */
170
+ export declare const CONTENT_LIST_QUERY_DEFAULT_SORT: ReadonlyArray<{
171
+ field: string;
172
+ direction: 'asc' | 'desc';
173
+ }>;
174
+ /**
175
+ * The server fields the list actually renders. Kept deliberately narrow: the
176
+ * envelope has a byte budget, and a projection is the cheapest place to keep a
177
+ * page inside it.
178
+ */
179
+ export declare const CONTENT_LIST_QUERY_PROJECTION: readonly string[];
180
+ /**
181
+ * Every server field the content query schema declares as projectable.
182
+ *
183
+ * A host may override `query.request.projection` with any of these. Naming
184
+ * anything else — a typo, a field that was removed, `body`, `tenantId` — is
185
+ * refused by the normalizer with `DATA_QUERY_PROJECTION_NOT_ALLOWED`, which
186
+ * fails the whole list rather than degrading it, so the translator drops the
187
+ * entry instead. Cross-asserted against `buildContentQuerySchema()`.
188
+ */
189
+ export declare const CONTENT_LIST_QUERY_PROJECTABLE_FIELDS: readonly string[];
190
+ /** `stringValue()`'s default ceiling, applied to every field id in a request. */
191
+ export declare const CONTENT_LIST_QUERY_MAX_FIELD_ID_LENGTH = 256;
192
+ /**
193
+ * Fields free-text search reaches, mirroring the adapter's searchable columns
194
+ * (`title`, `author`, and the hidden search-only `description`).
195
+ */
196
+ export declare const CONTENT_LIST_QUERY_SEARCH_FIELDS: readonly string[];
197
+ /**
198
+ * Page size used when the view state carries none. Matches the server's
199
+ * `CONTENT_QUERY_DEFAULT_PAGE_LIMIT`, so a client default and a server default
200
+ * never disagree about how many rows a page holds.
201
+ */
202
+ export declare const CONTENT_LIST_QUERY_DEFAULT_PAGE_SIZE = 50;
203
+ /** Mirrors `MAX_DATA_QUERY_OFFSET`; a larger offset is refused outright. */
204
+ export declare const CONTENT_LIST_QUERY_MAX_OFFSET = 1000000;
205
+ /**
206
+ * The request normalizer's input caps, mirrored from
207
+ * `@happyvertical/smrt-core`. Exceeding any of them fails the *entire* request
208
+ * with a 400 — which turns the translator's "drop, never fail" contract into an
209
+ * error panel — so each one is enforced client-side and reported as a drop.
210
+ *
211
+ * - `MAX_DATA_QUERY_IN_VALUES` — entries in one `in`/`notIn` list.
212
+ * - `MAX_DATA_QUERY_FILTERS` — total filter nodes, counting every `all`/`any`
213
+ * container as a node exactly the way `normalizeFilter` does.
214
+ * - the scalar cap — characters in any one filter value, wildcards included.
215
+ */
216
+ export declare const CONTENT_LIST_QUERY_MAX_IN_VALUES = 100;
217
+ export declare const CONTENT_LIST_QUERY_MAX_FILTER_NODES = 50;
218
+ export declare const CONTENT_LIST_QUERY_MAX_VALUE_LENGTH = 4096;
219
+ /** `MAX_DATA_QUERY_REQUEST_BYTES` — the whole serialized request. */
220
+ export declare const CONTENT_LIST_QUERY_MAX_REQUEST_BYTES = 100000;
221
+ /** `MAX_DATA_QUERY_FILTERS` also caps the projection array. */
222
+ export declare const CONTENT_LIST_QUERY_MAX_PROJECTION_FIELDS = 50;
223
+ /** `stringValue(object.requestId, …, 128)` — non-empty, at most 128 chars. */
224
+ export declare const CONTENT_LIST_QUERY_MAX_REQUEST_ID_LENGTH = 128;
225
+ /**
226
+ * `MAX_CONTENT_QUERY_OR_BRANCHES` — the executor's ceiling on the disjunctive
227
+ * normal form it lowers a filter into. Null-safe `ne`/`notIn` cost two branches
228
+ * each and an `all` multiplies, so this one is reachable from a crafted link.
229
+ */
230
+ export declare const CONTENT_LIST_QUERY_MAX_OR_BRANCHES = 128;
231
+ /**
232
+ * Why one part of a view state could not be expressed as a server query.
233
+ *
234
+ * A superset of `ContentListStateDropReason` so one notice can list restore
235
+ * drops and translation drops together.
236
+ */
237
+ export type ContentListQueryDropReason =
238
+ /** The column carries no server field (only `site` today). */
239
+ 'no-server-field'
240
+ /** The column id is not published by the adapter at all. */
241
+ | 'unknown-column'
242
+ /** The operator has no sound server expression. */
243
+ | 'unsupported-operator'
244
+ /** The value cannot be expressed for the server field's declared type. */
245
+ | 'unsupported-value'
246
+ /** The value was clamped to stay inside a protocol or policy bound. */
247
+ | 'out-of-range'
248
+ /**
249
+ * A bound could not be met without changing which rows come back, and the
250
+ * change is one the operator did not ask for: a filter that had to be left
251
+ * out entirely, or one applied more loosely than requested.
252
+ *
253
+ * Kept distinct from `out-of-range` deliberately. A clamp that NARROWS — an
254
+ * `in` list cut to its first hundred values, a page size reduced — still
255
+ * answers a subset of the question. A filter that widens hands back rows the
256
+ * operator excluded, and calling that "clamped" tells them the opposite of
257
+ * what happened.
258
+ */
259
+ | 'filter-widened'
260
+ /**
261
+ * The value is live and applied, but outside the vocabulary the toolbar can
262
+ * display. Reported so an operator is never shown an apparently unfiltered
263
+ * toolbar over an empty list.
264
+ */
265
+ | 'unlisted-value'
266
+ /**
267
+ * A live filter a single-select control cannot express at all — a non-`equals`
268
+ * operator, a list value, or a valueless one. Reported so the toolbar never
269
+ * silently states something other than the query being run.
270
+ */
271
+ | 'unrepresentable-filter'
272
+ /**
273
+ * An unpaginated view was requested, which a server query cannot express —
274
+ * the endpoint always applies a page limit. Coerced to the page size.
275
+ */
276
+ | 'unpaginated-unsupported';
277
+ /** One discarded piece of a translated query, reported rather than thrown. */
278
+ export interface ContentListQueryDrop {
279
+ scope: ContentListStateDropScope;
280
+ reason: ContentListQueryDropReason;
281
+ columnId?: string;
282
+ detail?: string;
283
+ }
284
+ export interface ContentListQueryTranslation {
285
+ request: ContentListDataQueryRequest;
286
+ /** Everything the translator refused, for reporting to the operator. */
287
+ dropped: ContentListQueryDrop[];
288
+ /**
289
+ * The 1-based page this request actually reads. Equal to `state.page` unless
290
+ * the offset had to be capped, in which case the caller must move its own
291
+ * page marker here — otherwise the UI labels the answer with a page the
292
+ * server never read, and paging from it is meaningless.
293
+ */
294
+ effectivePage: number;
295
+ }
296
+ export interface ContentListQueryRequestOptions {
297
+ /** Overrides the projected server fields. */
298
+ projection?: readonly string[];
299
+ /** Page size used when the view state has none. */
300
+ defaultPageSize?: number;
301
+ /** Ceiling on a requested page size. Defaults to `CONTENT_LIST_MAX_PAGE_SIZE`. */
302
+ maxPageSize?: number;
303
+ /** Injectable id factory, for deterministic tests. */
304
+ createRequestId?: () => string;
305
+ }
306
+ export declare function escapeContentListQueryLikeValue(value: string): string;
307
+ /**
308
+ * The one page-size ceiling, resolved from every configured limit.
309
+ *
310
+ * Every candidate narrows: a host that sets a server row budget through
311
+ * `query.request.maxPageSize` must not have it discarded because a looser
312
+ * `urlState.options.maxPageSize` also exists. The schema's `maxPageLimit`
313
+ * (mirrored by `CONTENT_LIST_MAX_PAGE_SIZE`) is always one of the candidates,
314
+ * so the result can never exceed what the endpoint itself enforces.
315
+ *
316
+ * Callers pass this ONE value to the controller seed, the URL sanitizer, the
317
+ * saved-view sanitizer, and the translator, which is what makes it impossible
318
+ * for the page the UI reports and the page the server returns to disagree.
319
+ */
320
+ export declare function resolveContentListMaxPageSize(...candidates: ReadonlyArray<number | null | undefined>): number;
321
+ /**
322
+ * Translates a content-list view state into a bounded `DataQueryRequest`.
323
+ *
324
+ * Everything unmappable is dropped and reported rather than thrown: a stale
325
+ * saved view or a crafted link must still produce a valid query, minus the
326
+ * parts the server cannot express.
327
+ *
328
+ * Selection and expansion are never translated — they address rendered rows,
329
+ * not a query.
330
+ */
331
+ export declare function contentListViewStateToDataQueryRequest(state: Partial<DataTableViewState>, options?: ContentListQueryRequestOptions): ContentListQueryTranslation;
332
+ /**
333
+ * A stable identity for the *semantics* of a request.
334
+ *
335
+ * `requestId` is correlation metadata, not query identity, so it is excluded:
336
+ * a component can compare two translations to decide whether the query actually
337
+ * changed rather than re-fetching on every state transition.
338
+ */
339
+ export declare function contentListQueryRequestKey(request: ContentListDataQueryRequest): string;
340
+ /**
341
+ * Maps one result row onto the `ContentData` shape the presentations render.
342
+ * Unprojected and unknown fields are simply absent; `toContentListRows` already
343
+ * treats a missing field as empty text.
344
+ */
345
+ export declare function contentFromContentListQueryRow(row: Record<string, unknown>): ContentData;
346
+ /** Maps a whole result page. Order is preserved: the server already sorted. */
347
+ export declare function contentListQueryRowsToContents(rows: ReadonlyArray<Record<string, unknown>>): ContentData[];
348
+ /**
349
+ * The row count to DISPLAY a pager against, or `undefined` when the server
350
+ * could not produce one (`total.kind === 'unavailable'`).
351
+ *
352
+ * Accepts an estimate: an approximate page count is what an estimate is for.
353
+ * Do NOT clamp a page against this — see
354
+ * {@link contentListQueryExactTotal}.
355
+ */
356
+ export declare function contentListQueryTotalValue(total: ContentListQueryTotal | undefined): number | undefined;
357
+ /**
358
+ * The row count a page may be CLAMPED against, or `undefined` when none exists.
359
+ *
360
+ * Clamping moves the operator, so it may only act on a count that is exactly
361
+ * right. `DataQueryTotal` has three kinds and only one of them qualifies:
362
+ *
363
+ * - `exact` — authoritative. Clamp.
364
+ * - `estimated` — an approximation, and clamping on one can strand a page that
365
+ * really exists: an estimate of 100 rows on a 300-row query hides pages 3
366
+ * onward, and the operator has no way to reach content that is there. The
367
+ * opposite risk, offering a page that turns out to be empty, is visible and
368
+ * self-correcting — they navigate, see nothing, and come back. Refusing to
369
+ * hide reachable rows is the same rule as "truncation only when it narrows".
370
+ * - `unavailable` — the total is UNKNOWN. Not zero, and emphatically not the
371
+ * length of the page in hand, which would send every page above the first
372
+ * back to page one the moment the request settled.
373
+ */
374
+ export declare function contentListQueryExactTotal(total: ContentListQueryTotal | undefined): number | undefined;
375
+ /** A content query failure carrying the server's machine-readable code. */
376
+ export declare class ContentListQueryError extends Error {
377
+ /** Server error code, for example `DATA_QUERY_FILTER_NOT_ALLOWED`. */
378
+ readonly code: string;
379
+ /** HTTP status, when the failure came from a response. */
380
+ readonly status: number | undefined;
381
+ constructor(message: string, options?: {
382
+ code?: string;
383
+ status?: number;
384
+ cause?: unknown;
385
+ });
386
+ }
387
+ /** The transport seam `createContentListQueryTransport` implements. */
388
+ export interface ContentListQueryTransport {
389
+ query(request: ContentListDataQueryRequest, options?: {
390
+ signal?: AbortSignal;
391
+ }): Promise<unknown>;
392
+ }
393
+ export interface ContentListQueryTransportOptions {
394
+ /** REST base path. Defaults to `/api/v1`, matching `ContentList`. */
395
+ apiBaseUrl?: string;
396
+ /** Route path under the base. Defaults to `contents/query`. */
397
+ path?: string;
398
+ /** Injectable fetch, for tests and for server-side rendering. */
399
+ fetch?: typeof globalThis.fetch;
400
+ /** Extra headers (an auth header, a tenant hint). Resolved per request. */
401
+ headers?: HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
402
+ /** Forwarded to `fetch`; set `'include'` for cookie-authenticated hosts. */
403
+ credentials?: RequestCredentials;
404
+ }
405
+ /**
406
+ * A `fetch` transport for `POST /api/v1/contents/query`.
407
+ *
408
+ * The generated route wraps a success as `{ action: 'queryAction', result }`
409
+ * and a refusal as `{ error: { ok: false, status, code, message } }`. This
410
+ * unwraps the first and throws the second as a {@link ContentListQueryError} so
411
+ * a binding's error state carries the server's code rather than a generic
412
+ * "request failed".
413
+ *
414
+ * Non-JSON bodies and HTTP failures are never swallowed, and an `AbortError`
415
+ * propagates untouched so cancellation stays distinguishable from a failure.
416
+ */
417
+ export declare function createContentListQueryTransport(options?: ContentListQueryTransportOptions): ContentListQueryTransport;
418
+ /**
419
+ * The reactive query binding `ContentList` reads.
420
+ *
421
+ * Structurally satisfied by `RemoteQueryBinding<Record<string, unknown>>` from
422
+ * `@happyvertical/smrt-svelte/web`, which is the intended implementation:
423
+ *
424
+ * ```ts
425
+ * import { remoteQuery } from '@happyvertical/smrt-svelte/web';
426
+ * import { createContentListQueryTransport } from '@happyvertical/smrt-content/svelte';
427
+ *
428
+ * const transport = createContentListQueryTransport({ apiBaseUrl: '/api/v1' });
429
+ * // inside the host component's initialization
430
+ * const query = { bind: () => remoteQuery(collection, transport) };
431
+ * ```
432
+ *
433
+ * It is declared structurally rather than imported so the content Svelte barrel
434
+ * does not drag the browser data runtime onto every page that renders content.
435
+ */
436
+ export interface ContentListQueryBinding {
437
+ /** The current page of result rows, keyed by server field id. */
438
+ readonly rows: ReadonlyArray<Record<string, unknown>>;
439
+ /** Row count for the whole query, not just this page. */
440
+ readonly total: ContentListQueryTotal | undefined;
441
+ /** True while a first fill is in flight. */
442
+ readonly loading: boolean;
443
+ /** True while a revalidation over already-rendered rows is in flight. */
444
+ readonly refreshing: boolean;
445
+ /**
446
+ * True when the rendered rows are known to be out of date. Part of the seam
447
+ * so a binding satisfies it structurally; the freshness affordance that reads
448
+ * it lands with #2455.
449
+ */
450
+ readonly stale: boolean;
451
+ /** The last failure, or a falsy value when the query is healthy. */
452
+ readonly error: unknown;
453
+ /**
454
+ * True when the server had to shorten the answer to fit its byte budget.
455
+ * Optional because `RemoteQueryBinding` does not surface it; when a binding
456
+ * omits it, `ContentList` reads it off the result its own `execute` resolved.
457
+ */
458
+ readonly truncated?: boolean;
459
+ /** Server-side warnings for the same reason, and for shortened values. */
460
+ readonly warnings?: ReadonlyArray<string>;
461
+ execute(request: ContentListDataQueryRequest, options?: {
462
+ signal?: AbortSignal;
463
+ }): Promise<unknown>;
464
+ retry(): Promise<unknown>;
465
+ }
466
+ /**
467
+ * What the server said about the completeness of an answer.
468
+ *
469
+ * `executeContentQuery` drops trailing rows to stay inside `maxResultBytes` and
470
+ * shortens over-long values, flagging both. That matters to a paging client:
471
+ * the next page is computed from `page * limit`, so rows the server dropped are
472
+ * skipped on the following page too. Reporting it is the difference between a
473
+ * short page and silently missing content.
474
+ */
475
+ export interface ContentListQueryNotices {
476
+ truncated: boolean;
477
+ warnings: string[];
478
+ }
479
+ /** Reads the completeness flags off a result envelope, defensively. */
480
+ export declare function readContentListQueryNotices(result: unknown): ContentListQueryNotices;
481
+ /**
482
+ * The opt-in server-query prop.
483
+ *
484
+ * `bind` is called exactly once, during `ContentList` initialization, so a
485
+ * binding created by `remoteQuery(...)` registers its teardown in the
486
+ * component's own effect scope and is disposed with it.
487
+ */
488
+ export interface ContentListQuerySource {
489
+ bind(): ContentListQueryBinding;
490
+ /** Translator options — projection, default page size, page-size ceiling. */
491
+ request?: ContentListQueryRequestOptions;
492
+ }
493
+ /**
494
+ * A human-readable message for a binding error, for the list's error panel.
495
+ * Returns `null` when there is no error.
496
+ */
497
+ export declare function contentListQueryErrorMessage(error: unknown): string | null;
498
+ //# sourceMappingURL=content-list-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-list-query.d.ts","sourceRoot":"","sources":["../../src/svelte/content-list-query.ts"],"names":[],"mappings":"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"}