@org-quicko/silo-client 1.0.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/README.md +313 -0
- package/dist/collections/collection-definition.d.cts +10 -0
- package/dist/collections/collection-definition.d.ts +10 -0
- package/dist/collections/collection-handle.d.cts +54 -0
- package/dist/collections/collection-handle.d.ts +54 -0
- package/dist/collections/collection-schema.d.cts +16 -0
- package/dist/collections/collection-schema.d.ts +16 -0
- package/dist/collections/collection-summary.d.cts +10 -0
- package/dist/collections/collection-summary.d.ts +10 -0
- package/dist/collections/collections.d.cts +19 -0
- package/dist/collections/collections.d.ts +19 -0
- package/dist/collections/json-schema.d.cts +9 -0
- package/dist/collections/json-schema.d.ts +9 -0
- package/dist/collections/reserved-field-names.d.cts +9 -0
- package/dist/collections/reserved-field-names.d.ts +9 -0
- package/dist/entries/entry-base.d.cts +31 -0
- package/dist/entries/entry-base.d.ts +31 -0
- package/dist/entries/entry-list-query.d.cts +11 -0
- package/dist/entries/entry-list-query.d.ts +11 -0
- package/dist/entries/entry-mapper.d.cts +13 -0
- package/dist/entries/entry-mapper.d.ts +13 -0
- package/dist/entries/entry-page-stream.d.cts +14 -0
- package/dist/entries/entry-page-stream.d.ts +14 -0
- package/dist/entries/entry-page.d.cts +16 -0
- package/dist/entries/entry-page.d.ts +16 -0
- package/dist/entries/entry-payload.d.cts +12 -0
- package/dist/entries/entry-payload.d.ts +12 -0
- package/dist/entries/entry-reader.d.cts +26 -0
- package/dist/entries/entry-reader.d.ts +26 -0
- package/dist/entries/entry-stream.d.cts +5 -0
- package/dist/entries/entry-stream.d.ts +5 -0
- package/dist/entries/entry.d.cts +25 -0
- package/dist/entries/entry.d.ts +25 -0
- package/dist/entries/resolved-entry.d.cts +11 -0
- package/dist/entries/resolved-entry.d.ts +11 -0
- package/dist/errors/conflict-error.d.cts +6 -0
- package/dist/errors/conflict-error.d.ts +6 -0
- package/dist/errors/error-code.d.cts +4 -0
- package/dist/errors/error-code.d.ts +4 -0
- package/dist/errors/error-factory.d.cts +15 -0
- package/dist/errors/error-factory.d.ts +15 -0
- package/dist/errors/error-payload.d.cts +13 -0
- package/dist/errors/error-payload.d.ts +13 -0
- package/dist/errors/forbidden-error.d.cts +5 -0
- package/dist/errors/forbidden-error.d.ts +5 -0
- package/dist/errors/internal-error.d.cts +6 -0
- package/dist/errors/internal-error.d.ts +6 -0
- package/dist/errors/invalid-response-error.d.cts +11 -0
- package/dist/errors/invalid-response-error.d.ts +11 -0
- package/dist/errors/media-delete-stalled-error.d.cts +14 -0
- package/dist/errors/media-delete-stalled-error.d.ts +14 -0
- package/dist/errors/media-in-use-error.d.cts +21 -0
- package/dist/errors/media-in-use-error.d.ts +21 -0
- package/dist/errors/network-error.d.cts +11 -0
- package/dist/errors/network-error.d.ts +11 -0
- package/dist/errors/not-found-error.d.cts +6 -0
- package/dist/errors/not-found-error.d.ts +6 -0
- package/dist/errors/request-aborted-error.d.cts +10 -0
- package/dist/errors/request-aborted-error.d.ts +10 -0
- package/dist/errors/silo-error.d.cts +12 -0
- package/dist/errors/silo-error.d.ts +12 -0
- package/dist/errors/timeout-error.d.cts +11 -0
- package/dist/errors/timeout-error.d.ts +11 -0
- package/dist/errors/unauthorized-error.d.cts +5 -0
- package/dist/errors/unauthorized-error.d.ts +5 -0
- package/dist/errors/validation-detail.d.cts +8 -0
- package/dist/errors/validation-detail.d.ts +8 -0
- package/dist/errors/validation-failed-error.d.cts +11 -0
- package/dist/errors/validation-failed-error.d.ts +11 -0
- package/dist/index.cjs +2095 -0
- package/dist/index.d.cts +96 -0
- package/dist/index.d.ts +96 -0
- package/dist/index.js +2053 -0
- package/dist/instance/health-report.d.cts +5 -0
- package/dist/instance/health-report.d.ts +5 -0
- package/dist/media/media-asset-mapper.d.cts +31 -0
- package/dist/media/media-asset-mapper.d.ts +31 -0
- package/dist/media/media-asset-payload.d.cts +20 -0
- package/dist/media/media-asset-payload.d.ts +20 -0
- package/dist/media/media-asset.d.cts +63 -0
- package/dist/media/media-asset.d.ts +63 -0
- package/dist/media/media-delete-failure.d.cts +16 -0
- package/dist/media/media-delete-failure.d.ts +16 -0
- package/dist/media/media-delete-options.d.cts +9 -0
- package/dist/media/media-delete-options.d.ts +9 -0
- package/dist/media/media-delete-report.d.cts +13 -0
- package/dist/media/media-delete-report.d.ts +13 -0
- package/dist/media/media-folder-delete.d.cts +10 -0
- package/dist/media/media-folder-delete.d.ts +10 -0
- package/dist/media/media-folder-move.d.cts +9 -0
- package/dist/media/media-folder-move.d.ts +9 -0
- package/dist/media/media-folders.d.cts +22 -0
- package/dist/media/media-folders.d.ts +22 -0
- package/dist/media/media-page-stream.d.cts +10 -0
- package/dist/media/media-page-stream.d.ts +10 -0
- package/dist/media/media-page.d.cts +19 -0
- package/dist/media/media-page.d.ts +19 -0
- package/dist/media/media-query.d.cts +24 -0
- package/dist/media/media-query.d.ts +24 -0
- package/dist/media/media-reference.d.cts +18 -0
- package/dist/media/media-reference.d.ts +18 -0
- package/dist/media/media-stream.d.cts +7 -0
- package/dist/media/media-stream.d.ts +7 -0
- package/dist/media/media-upload.d.cts +18 -0
- package/dist/media/media-upload.d.ts +18 -0
- package/dist/media/media-usage-page.d.cts +35 -0
- package/dist/media/media-usage-page.d.ts +35 -0
- package/dist/media/media-usage.d.cts +13 -0
- package/dist/media/media-usage.d.ts +13 -0
- package/dist/media/media.d.cts +37 -0
- package/dist/media/media.d.ts +37 -0
- package/dist/pagination/page-window.d.cts +14 -0
- package/dist/pagination/page-window.d.ts +14 -0
- package/dist/pagination/page.d.cts +27 -0
- package/dist/pagination/page.d.ts +27 -0
- package/dist/pagination/row-stream.d.cts +28 -0
- package/dist/pagination/row-stream.d.ts +28 -0
- package/dist/query/field-path.d.cts +14 -0
- package/dist/query/field-path.d.ts +14 -0
- package/dist/query/filter-expression.d.cts +15 -0
- package/dist/query/filter-expression.d.ts +15 -0
- package/dist/query/filter-field.d.cts +19 -0
- package/dist/query/filter-field.d.ts +19 -0
- package/dist/query/filter-node.d.cts +9 -0
- package/dist/query/filter-node.d.ts +9 -0
- package/dist/query/filter-operator.d.cts +7 -0
- package/dist/query/filter-operator.d.ts +7 -0
- package/dist/query/filter.d.cts +18 -0
- package/dist/query/filter.d.ts +18 -0
- package/dist/query/sort-term.d.cts +13 -0
- package/dist/query/sort-term.d.ts +13 -0
- package/dist/query/sort.d.cts +15 -0
- package/dist/query/sort.d.ts +15 -0
- package/dist/query/typed-filter.d.cts +32 -0
- package/dist/query/typed-filter.d.ts +32 -0
- package/dist/request-options.d.cts +9 -0
- package/dist/request-options.d.ts +9 -0
- package/dist/scope/delete-options.d.cts +9 -0
- package/dist/scope/delete-options.d.ts +9 -0
- package/dist/scope/environment-handle.d.cts +29 -0
- package/dist/scope/environment-handle.d.ts +29 -0
- package/dist/scope/environment.d.cts +8 -0
- package/dist/scope/environment.d.ts +8 -0
- package/dist/scope/environments.d.cts +11 -0
- package/dist/scope/environments.d.ts +11 -0
- package/dist/scope/project-handle.d.cts +22 -0
- package/dist/scope/project-handle.d.ts +22 -0
- package/dist/scope/project.d.cts +8 -0
- package/dist/scope/project.d.ts +8 -0
- package/dist/scope/projects.d.cts +10 -0
- package/dist/scope/projects.d.ts +10 -0
- package/dist/scope/rename-options.d.cts +10 -0
- package/dist/scope/rename-options.d.ts +10 -0
- package/dist/scope/rename-report.d.cts +21 -0
- package/dist/scope/rename-report.d.ts +21 -0
- package/dist/scope/scope-reference.d.cts +12 -0
- package/dist/scope/scope-reference.d.ts +12 -0
- package/dist/search/search-engine.d.cts +3 -0
- package/dist/search/search-engine.d.ts +3 -0
- package/dist/search/search-hit.d.cts +18 -0
- package/dist/search/search-hit.d.ts +18 -0
- package/dist/search/search-page.d.cts +19 -0
- package/dist/search/search-page.d.ts +19 -0
- package/dist/search/search-query.d.cts +11 -0
- package/dist/search/search-query.d.ts +11 -0
- package/dist/search/search-reach.d.cts +12 -0
- package/dist/search/search-reach.d.ts +12 -0
- package/dist/search/search-snippet.d.cts +8 -0
- package/dist/search/search-snippet.d.ts +8 -0
- package/dist/search/search.d.cts +18 -0
- package/dist/search/search.d.ts +18 -0
- package/dist/silo-options.d.cts +12 -0
- package/dist/silo-options.d.ts +12 -0
- package/dist/silo.d.cts +42 -0
- package/dist/silo.d.ts +42 -0
- package/dist/transport/abort-signals.d.cts +23 -0
- package/dist/transport/abort-signals.d.ts +23 -0
- package/dist/transport/api-path.d.cts +36 -0
- package/dist/transport/api-path.d.ts +36 -0
- package/dist/transport/fetch-function.d.cts +11 -0
- package/dist/transport/fetch-function.d.ts +11 -0
- package/dist/transport/page-payload.d.cts +15 -0
- package/dist/transport/page-payload.d.ts +15 -0
- package/dist/transport/query-string.d.cts +10 -0
- package/dist/transport/query-string.d.ts +10 -0
- package/dist/transport/response-decoder.d.cts +14 -0
- package/dist/transport/response-decoder.d.ts +14 -0
- package/dist/transport/route-inventory.d.cts +22 -0
- package/dist/transport/route-inventory.d.ts +22 -0
- package/dist/transport/transport-request.d.cts +18 -0
- package/dist/transport/transport-request.d.ts +18 -0
- package/dist/transport/transport.d.cts +45 -0
- package/dist/transport/transport.d.ts +45 -0
- package/dist/variables/environment-variables.d.cts +14 -0
- package/dist/variables/environment-variables.d.ts +14 -0
- package/dist/variables/project-variables.d.cts +38 -0
- package/dist/variables/project-variables.d.ts +38 -0
- package/dist/variables/variable-declaration.d.cts +10 -0
- package/dist/variables/variable-declaration.d.ts +10 -0
- package/dist/variables/variable.d.cts +17 -0
- package/dist/variables/variable.d.ts +17 -0
- package/package.json +58 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Page } from "../pagination/page.cjs";
|
|
2
|
+
import type { RequestOptions } from "../request-options.cjs";
|
|
3
|
+
import type { Transport } from "../transport/transport.cjs";
|
|
4
|
+
import type { MediaUsage } from "./media-usage.cjs";
|
|
5
|
+
/** `MediaAsset.usages()`'s query. The wire echoes no window, so the
|
|
6
|
+
* page is built from what was asked for rather than what came back. */
|
|
7
|
+
export interface MediaUsageQuery {
|
|
8
|
+
limit?: number;
|
|
9
|
+
offset?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One page of an asset's referrers, and the awkward page shape. The wire gives a
|
|
13
|
+
* true `total` this key may not fully see, plus `visible` (what it may) and
|
|
14
|
+
* `visibleCapped`, and echoes no window at all. `total` still reports the
|
|
15
|
+
* true count via the base class; `pageCount`/`hasMore` are overridden here
|
|
16
|
+
* to derive from `visible` instead, since that is all these rows can ever
|
|
17
|
+
* add up to — not touching `Page` itself, since `total` keeps its normal
|
|
18
|
+
* meaning for every other page in the client.
|
|
19
|
+
*/
|
|
20
|
+
export declare class MediaUsagePage extends Page<MediaUsage> {
|
|
21
|
+
private readonly transport;
|
|
22
|
+
private readonly assetId;
|
|
23
|
+
readonly visible: number;
|
|
24
|
+
readonly visibleCapped: boolean;
|
|
25
|
+
private constructor();
|
|
26
|
+
get usages(): readonly MediaUsage[];
|
|
27
|
+
get pageCount(): number | null;
|
|
28
|
+
get hasMore(): boolean;
|
|
29
|
+
next(options?: RequestOptions): Promise<MediaUsagePage | null>;
|
|
30
|
+
previous(options?: RequestOptions): Promise<MediaUsagePage | null>;
|
|
31
|
+
/** `MediaAsset.usages()`'s entry point: builds the requested window itself,
|
|
32
|
+
* since the server does not echo one back. */
|
|
33
|
+
static load(transport: Transport, assetId: string, query: MediaUsageQuery, options?: RequestOptions): Promise<MediaUsagePage>;
|
|
34
|
+
private static loadWindow;
|
|
35
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Page } from "../pagination/page.js";
|
|
2
|
+
import type { RequestOptions } from "../request-options.js";
|
|
3
|
+
import type { Transport } from "../transport/transport.js";
|
|
4
|
+
import type { MediaUsage } from "./media-usage.js";
|
|
5
|
+
/** `MediaAsset.usages()`'s query. The wire echoes no window, so the
|
|
6
|
+
* page is built from what was asked for rather than what came back. */
|
|
7
|
+
export interface MediaUsageQuery {
|
|
8
|
+
limit?: number;
|
|
9
|
+
offset?: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* One page of an asset's referrers, and the awkward page shape. The wire gives a
|
|
13
|
+
* true `total` this key may not fully see, plus `visible` (what it may) and
|
|
14
|
+
* `visibleCapped`, and echoes no window at all. `total` still reports the
|
|
15
|
+
* true count via the base class; `pageCount`/`hasMore` are overridden here
|
|
16
|
+
* to derive from `visible` instead, since that is all these rows can ever
|
|
17
|
+
* add up to — not touching `Page` itself, since `total` keeps its normal
|
|
18
|
+
* meaning for every other page in the client.
|
|
19
|
+
*/
|
|
20
|
+
export declare class MediaUsagePage extends Page<MediaUsage> {
|
|
21
|
+
private readonly transport;
|
|
22
|
+
private readonly assetId;
|
|
23
|
+
readonly visible: number;
|
|
24
|
+
readonly visibleCapped: boolean;
|
|
25
|
+
private constructor();
|
|
26
|
+
get usages(): readonly MediaUsage[];
|
|
27
|
+
get pageCount(): number | null;
|
|
28
|
+
get hasMore(): boolean;
|
|
29
|
+
next(options?: RequestOptions): Promise<MediaUsagePage | null>;
|
|
30
|
+
previous(options?: RequestOptions): Promise<MediaUsagePage | null>;
|
|
31
|
+
/** `MediaAsset.usages()`'s entry point: builds the requested window itself,
|
|
32
|
+
* since the server does not echo one back. */
|
|
33
|
+
static load(transport: Transport, assetId: string, query: MediaUsageQuery, options?: RequestOptions): Promise<MediaUsagePage>;
|
|
34
|
+
private static loadWindow;
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One entry's reference to a media asset, mapped from the wire's snake_case
|
|
3
|
+
* (`media_id`, `env`, `entry_id`) by `MediaAssetMapper`. The one
|
|
4
|
+
* referrer type across the client — `MediaUsagePage` and `MediaInUseError`
|
|
5
|
+
* both use this rather than each declaring their own.
|
|
6
|
+
*/
|
|
7
|
+
export interface MediaUsage {
|
|
8
|
+
mediaId: string;
|
|
9
|
+
project: string;
|
|
10
|
+
environment: string;
|
|
11
|
+
collection: string;
|
|
12
|
+
entryId: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One entry's reference to a media asset, mapped from the wire's snake_case
|
|
3
|
+
* (`media_id`, `env`, `entry_id`) by `MediaAssetMapper`. The one
|
|
4
|
+
* referrer type across the client — `MediaUsagePage` and `MediaInUseError`
|
|
5
|
+
* both use this rather than each declaring their own.
|
|
6
|
+
*/
|
|
7
|
+
export interface MediaUsage {
|
|
8
|
+
mediaId: string;
|
|
9
|
+
project: string;
|
|
10
|
+
environment: string;
|
|
11
|
+
collection: string;
|
|
12
|
+
entryId: string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { RequestOptions } from "../request-options.cjs";
|
|
2
|
+
import type { Transport } from "../transport/transport.cjs";
|
|
3
|
+
import { MediaAsset } from "./media-asset.cjs";
|
|
4
|
+
import type { MediaDeleteOptions } from "./media-delete-options.cjs";
|
|
5
|
+
import { MediaDeleteReport } from "./media-delete-report.cjs";
|
|
6
|
+
import { MediaFolders } from "./media-folders.cjs";
|
|
7
|
+
import { MediaPage } from "./media-page.cjs";
|
|
8
|
+
import { MediaPageStream } from "./media-page-stream.cjs";
|
|
9
|
+
import type { MediaQuery } from "./media-query.cjs";
|
|
10
|
+
import { MediaStream } from "./media-stream.cjs";
|
|
11
|
+
import type { MediaUploadBytes, MediaUploadFileOptions } from "./media-upload.cjs";
|
|
12
|
+
/** The media library: instance-global, never scoped to a project or
|
|
13
|
+
* environment. */
|
|
14
|
+
export declare class Media {
|
|
15
|
+
private readonly transport;
|
|
16
|
+
readonly folders: MediaFolders;
|
|
17
|
+
constructor(transport: Transport);
|
|
18
|
+
upload(input: MediaUploadBytes, options?: RequestOptions): Promise<MediaAsset>;
|
|
19
|
+
upload(input: File | Blob, fileOptions?: MediaUploadFileOptions, options?: RequestOptions): Promise<MediaAsset>;
|
|
20
|
+
list(query?: MediaQuery, options?: RequestOptions): Promise<MediaPage>;
|
|
21
|
+
/** One `MediaAsset` at a time, across every page. */
|
|
22
|
+
all(query?: MediaQuery, options?: RequestOptions): MediaStream;
|
|
23
|
+
/** One whole `MediaPage` at a time, across every page. */
|
|
24
|
+
pages(query?: MediaQuery, options?: RequestOptions): MediaPageStream;
|
|
25
|
+
get(id: string, options?: RequestOptions): Promise<MediaAsset>;
|
|
26
|
+
/** Every distinct file extension actually in the library. */
|
|
27
|
+
extensions(options?: RequestOptions): Promise<string[]>;
|
|
28
|
+
/** Refuses locally past {@link BulkDeleteCap} — the server caps it too,
|
|
29
|
+
* and a local error reads better than a 400. Always answers `200`:
|
|
30
|
+
* per-id outcomes live in the report, not in a thrown error. */
|
|
31
|
+
deleteMany(ids: readonly string[], options?: MediaDeleteOptions): Promise<MediaDeleteReport>;
|
|
32
|
+
private static toWireQuery;
|
|
33
|
+
private static toBlob;
|
|
34
|
+
/** A `File` carries its own name; a bare `Blob` does not, and uploading it
|
|
35
|
+
* as "blob" is worse than refusing outright. */
|
|
36
|
+
private static filenameOf;
|
|
37
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { RequestOptions } from "../request-options.js";
|
|
2
|
+
import type { Transport } from "../transport/transport.js";
|
|
3
|
+
import { MediaAsset } from "./media-asset.js";
|
|
4
|
+
import type { MediaDeleteOptions } from "./media-delete-options.js";
|
|
5
|
+
import { MediaDeleteReport } from "./media-delete-report.js";
|
|
6
|
+
import { MediaFolders } from "./media-folders.js";
|
|
7
|
+
import { MediaPage } from "./media-page.js";
|
|
8
|
+
import { MediaPageStream } from "./media-page-stream.js";
|
|
9
|
+
import type { MediaQuery } from "./media-query.js";
|
|
10
|
+
import { MediaStream } from "./media-stream.js";
|
|
11
|
+
import type { MediaUploadBytes, MediaUploadFileOptions } from "./media-upload.js";
|
|
12
|
+
/** The media library: instance-global, never scoped to a project or
|
|
13
|
+
* environment. */
|
|
14
|
+
export declare class Media {
|
|
15
|
+
private readonly transport;
|
|
16
|
+
readonly folders: MediaFolders;
|
|
17
|
+
constructor(transport: Transport);
|
|
18
|
+
upload(input: MediaUploadBytes, options?: RequestOptions): Promise<MediaAsset>;
|
|
19
|
+
upload(input: File | Blob, fileOptions?: MediaUploadFileOptions, options?: RequestOptions): Promise<MediaAsset>;
|
|
20
|
+
list(query?: MediaQuery, options?: RequestOptions): Promise<MediaPage>;
|
|
21
|
+
/** One `MediaAsset` at a time, across every page. */
|
|
22
|
+
all(query?: MediaQuery, options?: RequestOptions): MediaStream;
|
|
23
|
+
/** One whole `MediaPage` at a time, across every page. */
|
|
24
|
+
pages(query?: MediaQuery, options?: RequestOptions): MediaPageStream;
|
|
25
|
+
get(id: string, options?: RequestOptions): Promise<MediaAsset>;
|
|
26
|
+
/** Every distinct file extension actually in the library. */
|
|
27
|
+
extensions(options?: RequestOptions): Promise<string[]>;
|
|
28
|
+
/** Refuses locally past {@link BulkDeleteCap} — the server caps it too,
|
|
29
|
+
* and a local error reads better than a 400. Always answers `200`:
|
|
30
|
+
* per-id outcomes live in the report, not in a thrown error. */
|
|
31
|
+
deleteMany(ids: readonly string[], options?: MediaDeleteOptions): Promise<MediaDeleteReport>;
|
|
32
|
+
private static toWireQuery;
|
|
33
|
+
private static toBlob;
|
|
34
|
+
/** A `File` carries its own name; a bare `Blob` does not, and uploading it
|
|
35
|
+
* as "blob" is worse than refusing outright. */
|
|
36
|
+
private static filenameOf;
|
|
37
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `limit` and `offset` a page answered — as the server clamped them, not
|
|
3
|
+
* as they were asked for. Navigation is arithmetic on this window, not
|
|
4
|
+
* on the request that produced it.
|
|
5
|
+
*/
|
|
6
|
+
export declare class PageWindow {
|
|
7
|
+
readonly limit: number;
|
|
8
|
+
readonly offset: number;
|
|
9
|
+
constructor(limit: number, offset: number);
|
|
10
|
+
/** The window one page ahead. */
|
|
11
|
+
next(): PageWindow;
|
|
12
|
+
/** The window one page back, or `null` before the start. */
|
|
13
|
+
previous(): PageWindow | null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `limit` and `offset` a page answered — as the server clamped them, not
|
|
3
|
+
* as they were asked for. Navigation is arithmetic on this window, not
|
|
4
|
+
* on the request that produced it.
|
|
5
|
+
*/
|
|
6
|
+
export declare class PageWindow {
|
|
7
|
+
readonly limit: number;
|
|
8
|
+
readonly offset: number;
|
|
9
|
+
constructor(limit: number, offset: number);
|
|
10
|
+
/** The window one page ahead. */
|
|
11
|
+
next(): PageWindow;
|
|
12
|
+
/** The window one page back, or `null` before the start. */
|
|
13
|
+
previous(): PageWindow | null;
|
|
14
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PageWindow } from "./page-window.cjs";
|
|
2
|
+
/**
|
|
3
|
+
* The shared shape of one page of results. Holds rows, the answered
|
|
4
|
+
* window, and the total, but does not load anything — a concrete page (an
|
|
5
|
+
* `EntryPage`, a `MediaPage`,...) declares its own `next()`/`previous()`
|
|
6
|
+
* that call its own loader and return its own type.
|
|
7
|
+
*
|
|
8
|
+
* `truncated` marks a page whose `total` counts what a scan examined rather
|
|
9
|
+
* than what exists: `pageCount` is then unknowable, and `hasMore`
|
|
10
|
+
* falls back to "this page came back full".
|
|
11
|
+
*/
|
|
12
|
+
export declare abstract class Page<Row> {
|
|
13
|
+
protected readonly rows: readonly Row[];
|
|
14
|
+
protected readonly window: PageWindow;
|
|
15
|
+
readonly total: number;
|
|
16
|
+
readonly truncated: boolean;
|
|
17
|
+
protected constructor(rows: readonly Row[], total: number, window: PageWindow, truncated?: boolean);
|
|
18
|
+
get limit(): number;
|
|
19
|
+
get offset(): number;
|
|
20
|
+
get pageNumber(): number;
|
|
21
|
+
get pageCount(): number | null;
|
|
22
|
+
get hasMore(): boolean;
|
|
23
|
+
/** The window the next page would load, or `null` when there is not one —
|
|
24
|
+
* so no subclass repeats the "only if there is more" arithmetic. */
|
|
25
|
+
protected windowForNext(): PageWindow | null;
|
|
26
|
+
[Symbol.iterator](): Iterator<Row>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PageWindow } from "./page-window.js";
|
|
2
|
+
/**
|
|
3
|
+
* The shared shape of one page of results. Holds rows, the answered
|
|
4
|
+
* window, and the total, but does not load anything — a concrete page (an
|
|
5
|
+
* `EntryPage`, a `MediaPage`,...) declares its own `next()`/`previous()`
|
|
6
|
+
* that call its own loader and return its own type.
|
|
7
|
+
*
|
|
8
|
+
* `truncated` marks a page whose `total` counts what a scan examined rather
|
|
9
|
+
* than what exists: `pageCount` is then unknowable, and `hasMore`
|
|
10
|
+
* falls back to "this page came back full".
|
|
11
|
+
*/
|
|
12
|
+
export declare abstract class Page<Row> {
|
|
13
|
+
protected readonly rows: readonly Row[];
|
|
14
|
+
protected readonly window: PageWindow;
|
|
15
|
+
readonly total: number;
|
|
16
|
+
readonly truncated: boolean;
|
|
17
|
+
protected constructor(rows: readonly Row[], total: number, window: PageWindow, truncated?: boolean);
|
|
18
|
+
get limit(): number;
|
|
19
|
+
get offset(): number;
|
|
20
|
+
get pageNumber(): number;
|
|
21
|
+
get pageCount(): number | null;
|
|
22
|
+
get hasMore(): boolean;
|
|
23
|
+
/** The window the next page would load, or `null` when there is not one —
|
|
24
|
+
* so no subclass repeats the "only if there is more" arithmetic. */
|
|
25
|
+
protected windowForNext(): PageWindow | null;
|
|
26
|
+
[Symbol.iterator](): Iterator<Row>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RequestOptions } from "../request-options.cjs";
|
|
2
|
+
import { PageWindow } from "./page-window.cjs";
|
|
3
|
+
/** Loads one page for a given window, and answers the window the server
|
|
4
|
+
* actually used. */
|
|
5
|
+
export type RowLoader<Row> = (window: PageWindow) => Promise<{
|
|
6
|
+
rows: Row[];
|
|
7
|
+
window: PageWindow;
|
|
8
|
+
}>;
|
|
9
|
+
/**
|
|
10
|
+
* The shared auto-pager behind `collection.all()` and similar.
|
|
11
|
+
* Advances by the window the server echoed, never by what was asked for, and
|
|
12
|
+
* stops on the first short or empty page — the sign that nothing more is
|
|
13
|
+
* behind it.
|
|
14
|
+
*
|
|
15
|
+
* Offset iteration over data being written concurrently is not a snapshot:
|
|
16
|
+
* an entry created ahead of the cursor can be missed, and one deleted behind
|
|
17
|
+
* it can shift a row into a page already yielded.
|
|
18
|
+
*/
|
|
19
|
+
export declare class RowStream<Row> implements AsyncIterable<Row> {
|
|
20
|
+
private readonly loader;
|
|
21
|
+
private readonly startingLimit;
|
|
22
|
+
private readonly options;
|
|
23
|
+
constructor(loader: RowLoader<Row>, startingLimit: number, options?: RequestOptions);
|
|
24
|
+
[Symbol.asyncIterator](): AsyncIterator<Row>;
|
|
25
|
+
/** Drains the whole stream, for a caller who knows the result set is
|
|
26
|
+
* small. */
|
|
27
|
+
toArray(): Promise<Row[]>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { RequestOptions } from "../request-options.js";
|
|
2
|
+
import { PageWindow } from "./page-window.js";
|
|
3
|
+
/** Loads one page for a given window, and answers the window the server
|
|
4
|
+
* actually used. */
|
|
5
|
+
export type RowLoader<Row> = (window: PageWindow) => Promise<{
|
|
6
|
+
rows: Row[];
|
|
7
|
+
window: PageWindow;
|
|
8
|
+
}>;
|
|
9
|
+
/**
|
|
10
|
+
* The shared auto-pager behind `collection.all()` and similar.
|
|
11
|
+
* Advances by the window the server echoed, never by what was asked for, and
|
|
12
|
+
* stops on the first short or empty page — the sign that nothing more is
|
|
13
|
+
* behind it.
|
|
14
|
+
*
|
|
15
|
+
* Offset iteration over data being written concurrently is not a snapshot:
|
|
16
|
+
* an entry created ahead of the cursor can be missed, and one deleted behind
|
|
17
|
+
* it can shift a row into a page already yielded.
|
|
18
|
+
*/
|
|
19
|
+
export declare class RowStream<Row> implements AsyncIterable<Row> {
|
|
20
|
+
private readonly loader;
|
|
21
|
+
private readonly startingLimit;
|
|
22
|
+
private readonly options;
|
|
23
|
+
constructor(loader: RowLoader<Row>, startingLimit: number, options?: RequestOptions);
|
|
24
|
+
[Symbol.asyncIterator](): AsyncIterator<Row>;
|
|
25
|
+
/** Drains the whole stream, for a caller who knows the result set is
|
|
26
|
+
* small. */
|
|
27
|
+
toArray(): Promise<Row[]>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the JSONPath strings the filter and sort AST address. A name may
|
|
3
|
+
* already carry a bracket segment (`tags[0]`, `tags[-1]`) or a dot for a
|
|
4
|
+
* nested field (`author.name`) — both pass through untouched, since prefixing
|
|
5
|
+
* is plain string concatenation.
|
|
6
|
+
*/
|
|
7
|
+
export declare class FieldPath {
|
|
8
|
+
/** `field("title")` is `$.data.title`. */
|
|
9
|
+
static field(name: string): string;
|
|
10
|
+
/** `each("tags")` is `$.data.tags[*]`, so nobody types the wildcard. */
|
|
11
|
+
static each(name: string): string;
|
|
12
|
+
/** `meta("updated_at")` addresses the envelope, not `data`: `$.updated_at`. */
|
|
13
|
+
static meta(name: string): string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the JSONPath strings the filter and sort AST address. A name may
|
|
3
|
+
* already carry a bracket segment (`tags[0]`, `tags[-1]`) or a dot for a
|
|
4
|
+
* nested field (`author.name`) — both pass through untouched, since prefixing
|
|
5
|
+
* is plain string concatenation.
|
|
6
|
+
*/
|
|
7
|
+
export declare class FieldPath {
|
|
8
|
+
/** `field("title")` is `$.data.title`. */
|
|
9
|
+
static field(name: string): string;
|
|
10
|
+
/** `each("tags")` is `$.data.tags[*]`, so nobody types the wildcard. */
|
|
11
|
+
static each(name: string): string;
|
|
12
|
+
/** `meta("updated_at")` addresses the envelope, not `data`: `$.updated_at`. */
|
|
13
|
+
static meta(name: string): string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FilterNode } from "./filter-node.cjs";
|
|
2
|
+
/**
|
|
3
|
+
* A built filter, ready to combine or send. Wraps one `FilterNode` and
|
|
4
|
+
* grows a bigger one on `and`/`or`/`not` rather than mutating what it wraps,
|
|
5
|
+
* so `left.and(right).or(other)` never surprises a caller holding `left`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class FilterExpression {
|
|
8
|
+
private readonly node;
|
|
9
|
+
constructor(node: FilterNode);
|
|
10
|
+
and(other: FilterExpression): FilterExpression;
|
|
11
|
+
or(other: FilterExpression): FilterExpression;
|
|
12
|
+
not(): FilterExpression;
|
|
13
|
+
/** The wire shape: what `?filter=` sends. */
|
|
14
|
+
toJSON(): FilterNode;
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FilterNode } from "./filter-node.js";
|
|
2
|
+
/**
|
|
3
|
+
* A built filter, ready to combine or send. Wraps one `FilterNode` and
|
|
4
|
+
* grows a bigger one on `and`/`or`/`not` rather than mutating what it wraps,
|
|
5
|
+
* so `left.and(right).or(other)` never surprises a caller holding `left`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class FilterExpression {
|
|
8
|
+
private readonly node;
|
|
9
|
+
constructor(node: FilterNode);
|
|
10
|
+
and(other: FilterExpression): FilterExpression;
|
|
11
|
+
or(other: FilterExpression): FilterExpression;
|
|
12
|
+
not(): FilterExpression;
|
|
13
|
+
/** The wire shape: what `?filter=` sends. */
|
|
14
|
+
toJSON(): FilterNode;
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FilterExpression } from "./filter-expression.cjs";
|
|
2
|
+
/**
|
|
3
|
+
* One path awaiting an operator. Generic over `Value` so `TypedFilter` can
|
|
4
|
+
* constrain what an operator accepts to the field's declared type, while
|
|
5
|
+
* `Filter`'s untyped statics leave it as `unknown`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class FilterField<Value = unknown> {
|
|
8
|
+
private readonly path;
|
|
9
|
+
constructor(path: string);
|
|
10
|
+
equals(value: Value): FilterExpression;
|
|
11
|
+
notEquals(value: Value): FilterExpression;
|
|
12
|
+
contains(value: Value): FilterExpression;
|
|
13
|
+
greaterThan(value: Value): FilterExpression;
|
|
14
|
+
atLeast(value: Value): FilterExpression;
|
|
15
|
+
lessThan(value: Value): FilterExpression;
|
|
16
|
+
atMost(value: Value): FilterExpression;
|
|
17
|
+
oneOf(values: Value[]): FilterExpression;
|
|
18
|
+
exists(): FilterExpression;
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { FilterExpression } from "./filter-expression.js";
|
|
2
|
+
/**
|
|
3
|
+
* One path awaiting an operator. Generic over `Value` so `TypedFilter` can
|
|
4
|
+
* constrain what an operator accepts to the field's declared type, while
|
|
5
|
+
* `Filter`'s untyped statics leave it as `unknown`.
|
|
6
|
+
*/
|
|
7
|
+
export declare class FilterField<Value = unknown> {
|
|
8
|
+
private readonly path;
|
|
9
|
+
constructor(path: string);
|
|
10
|
+
equals(value: Value): FilterExpression;
|
|
11
|
+
notEquals(value: Value): FilterExpression;
|
|
12
|
+
contains(value: Value): FilterExpression;
|
|
13
|
+
greaterThan(value: Value): FilterExpression;
|
|
14
|
+
atLeast(value: Value): FilterExpression;
|
|
15
|
+
lessThan(value: Value): FilterExpression;
|
|
16
|
+
atMost(value: Value): FilterExpression;
|
|
17
|
+
oneOf(values: Value[]): FilterExpression;
|
|
18
|
+
exists(): FilterExpression;
|
|
19
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FilterOperator } from "./filter-operator.cjs";
|
|
2
|
+
/** One node of the wire's filter AST: a leaf tests `path` against `value`, a
|
|
3
|
+
* group combines nested nodes in `args`. */
|
|
4
|
+
export interface FilterNode {
|
|
5
|
+
op: FilterOperator;
|
|
6
|
+
path?: string;
|
|
7
|
+
value?: unknown;
|
|
8
|
+
args?: FilterNode[];
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FilterOperator } from "./filter-operator.js";
|
|
2
|
+
/** One node of the wire's filter AST: a leaf tests `path` against `value`, a
|
|
3
|
+
* group combines nested nodes in `args`. */
|
|
4
|
+
export interface FilterNode {
|
|
5
|
+
op: FilterOperator;
|
|
6
|
+
path?: string;
|
|
7
|
+
value?: unknown;
|
|
8
|
+
args?: FilterNode[];
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** The closed set of operators the filter AST accepts: nine leaves that test
|
|
2
|
+
* one path, and three groups that combine nested nodes. */
|
|
3
|
+
export type FilterOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "contains" | "exists" | "and" | "or" | "not";
|
|
4
|
+
/** The same set at runtime, so a drift test can compare it against the
|
|
5
|
+
* server's own vocabulary. An operator silo adds and the client does not
|
|
6
|
+
* offer is a gap a type alone cannot detect. */
|
|
7
|
+
export declare const FilterOperators: readonly FilterOperator[];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** The closed set of operators the filter AST accepts: nine leaves that test
|
|
2
|
+
* one path, and three groups that combine nested nodes. */
|
|
3
|
+
export type FilterOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "contains" | "exists" | "and" | "or" | "not";
|
|
4
|
+
/** The same set at runtime, so a drift test can compare it against the
|
|
5
|
+
* server's own vocabulary. An operator silo adds and the client does not
|
|
6
|
+
* offer is a gap a type alone cannot detect. */
|
|
7
|
+
export declare const FilterOperators: readonly FilterOperator[];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FilterExpression } from "./filter-expression.cjs";
|
|
2
|
+
import { FilterField } from "./filter-field.cjs";
|
|
3
|
+
import type { FilterNode } from "./filter-node.cjs";
|
|
4
|
+
/**
|
|
5
|
+
* The untyped filter statics, for a filter built from user input at runtime
|
|
6
|
+
* or a caller not using `collection<Fields>()`. `TypedFilter` offers the
|
|
7
|
+
* same surface, typed to a collection's fields.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Filter {
|
|
10
|
+
static field(name: string): FilterField;
|
|
11
|
+
static each(name: string): FilterField;
|
|
12
|
+
static meta(name: string): FilterField;
|
|
13
|
+
static and(left: FilterExpression, right: FilterExpression): FilterExpression;
|
|
14
|
+
static or(left: FilterExpression, right: FilterExpression): FilterExpression;
|
|
15
|
+
static not(expression: FilterExpression): FilterExpression;
|
|
16
|
+
/** The escape hatch: wraps a hand-built node exactly as given. */
|
|
17
|
+
static raw(node: FilterNode): FilterExpression;
|
|
18
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FilterExpression } from "./filter-expression.js";
|
|
2
|
+
import { FilterField } from "./filter-field.js";
|
|
3
|
+
import type { FilterNode } from "./filter-node.js";
|
|
4
|
+
/**
|
|
5
|
+
* The untyped filter statics, for a filter built from user input at runtime
|
|
6
|
+
* or a caller not using `collection<Fields>()`. `TypedFilter` offers the
|
|
7
|
+
* same surface, typed to a collection's fields.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Filter {
|
|
10
|
+
static field(name: string): FilterField;
|
|
11
|
+
static each(name: string): FilterField;
|
|
12
|
+
static meta(name: string): FilterField;
|
|
13
|
+
static and(left: FilterExpression, right: FilterExpression): FilterExpression;
|
|
14
|
+
static or(left: FilterExpression, right: FilterExpression): FilterExpression;
|
|
15
|
+
static not(expression: FilterExpression): FilterExpression;
|
|
16
|
+
/** The escape hatch: wraps a hand-built node exactly as given. */
|
|
17
|
+
static raw(node: FilterNode): FilterExpression;
|
|
18
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Ascending unless `descending()` was called. */
|
|
2
|
+
export type SortDirection = "asc" | "desc";
|
|
3
|
+
/** One sort key: a path plus a direction. Stringifies to what the `sort`
|
|
4
|
+
* query parameter wants — the path alone when ascending, `-`-prefixed when
|
|
5
|
+
* descending. */
|
|
6
|
+
export declare class SortTerm {
|
|
7
|
+
private readonly path;
|
|
8
|
+
private readonly direction;
|
|
9
|
+
constructor(path: string, direction?: SortDirection);
|
|
10
|
+
ascending(): SortTerm;
|
|
11
|
+
descending(): SortTerm;
|
|
12
|
+
toString(): string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Ascending unless `descending()` was called. */
|
|
2
|
+
export type SortDirection = "asc" | "desc";
|
|
3
|
+
/** One sort key: a path plus a direction. Stringifies to what the `sort`
|
|
4
|
+
* query parameter wants — the path alone when ascending, `-`-prefixed when
|
|
5
|
+
* descending. */
|
|
6
|
+
export declare class SortTerm {
|
|
7
|
+
private readonly path;
|
|
8
|
+
private readonly direction;
|
|
9
|
+
constructor(path: string, direction?: SortDirection);
|
|
10
|
+
ascending(): SortTerm;
|
|
11
|
+
descending(): SortTerm;
|
|
12
|
+
toString(): string;
|
|
13
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SortTerm } from "./sort-term.cjs";
|
|
2
|
+
/**
|
|
3
|
+
* Sort statics. No `each`, deliberately: a sort path must select at most one
|
|
4
|
+
* node, so there is no wildcard variant to offer.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Sort {
|
|
7
|
+
static by(name: string): SortTerm;
|
|
8
|
+
static meta(name: string): SortTerm;
|
|
9
|
+
/** Sorts on `updated_at`, most recent first. Named for the field, not a
|
|
10
|
+
* vague idea of recency — `recentlyCreated` is a different order. */
|
|
11
|
+
static recentlyUpdated(): SortTerm;
|
|
12
|
+
static recentlyCreated(): SortTerm;
|
|
13
|
+
/** Joins terms with a comma: what the `sort` query parameter wants. */
|
|
14
|
+
static of(...terms: SortTerm[]): string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { SortTerm } from "./sort-term.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sort statics. No `each`, deliberately: a sort path must select at most one
|
|
4
|
+
* node, so there is no wildcard variant to offer.
|
|
5
|
+
*/
|
|
6
|
+
export declare class Sort {
|
|
7
|
+
static by(name: string): SortTerm;
|
|
8
|
+
static meta(name: string): SortTerm;
|
|
9
|
+
/** Sorts on `updated_at`, most recent first. Named for the field, not a
|
|
10
|
+
* vague idea of recency — `recentlyCreated` is a different order. */
|
|
11
|
+
static recentlyUpdated(): SortTerm;
|
|
12
|
+
static recentlyCreated(): SortTerm;
|
|
13
|
+
/** Joins terms with a comma: what the `sort` query parameter wants. */
|
|
14
|
+
static of(...terms: SortTerm[]): string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { FilterExpression } from "./filter-expression.cjs";
|
|
2
|
+
import { FilterField } from "./filter-field.cjs";
|
|
3
|
+
import type { FilterNode } from "./filter-node.cjs";
|
|
4
|
+
/** A plain field of `Fields`, or a dotted/bracketed extension of one —
|
|
5
|
+
* `"author.name"` and `"tags[0]"` stay valid even though neither is a key
|
|
6
|
+
* of `Fields` by itself. */
|
|
7
|
+
type TypedFieldPath<Fields> = (keyof Fields & string) | `${keyof Fields & string}.${string}` | `${keyof Fields & string}[${string}]`;
|
|
8
|
+
/** The value an operator on `Key` should accept: `Fields[Key]` when `Key` is
|
|
9
|
+
* a plain field, `unknown` for a dotted or bracketed extension, whose
|
|
10
|
+
* target type this client cannot resolve statically. */
|
|
11
|
+
type TypedFieldValue<Fields, Key extends string> = Key extends keyof Fields ? Fields[Key] : unknown;
|
|
12
|
+
/** `each` walks one element of an array field at a time, so its operators
|
|
13
|
+
* take the element type — `each("tags")` on `tags: string[]` should accept
|
|
14
|
+
* a `string`, not a `string[]`. */
|
|
15
|
+
type TypedEachValue<Fields, Key extends string> = Key extends keyof Fields ? Fields[Key] extends readonly (infer Element)[] ? Element : Fields[Key] : unknown;
|
|
16
|
+
/**
|
|
17
|
+
* `Filter`'s surface, typed to one collection's fields:
|
|
18
|
+
* `posts.filter.field("status")` autocompletes `keyof Post`, and
|
|
19
|
+
* `posts.filter.field("stauts")` does not compile. `meta`, `and`, `or`,
|
|
20
|
+
* `not` and `raw` are untyped, the same as on `Filter`, since they do not
|
|
21
|
+
* address `Fields` at all.
|
|
22
|
+
*/
|
|
23
|
+
export declare class TypedFilter<Fields> {
|
|
24
|
+
field<Key extends TypedFieldPath<Fields>>(name: Key): FilterField<TypedFieldValue<Fields, Key>>;
|
|
25
|
+
each<Key extends TypedFieldPath<Fields>>(name: Key): FilterField<TypedEachValue<Fields, Key>>;
|
|
26
|
+
meta(name: string): FilterField;
|
|
27
|
+
and(left: FilterExpression, right: FilterExpression): FilterExpression;
|
|
28
|
+
or(left: FilterExpression, right: FilterExpression): FilterExpression;
|
|
29
|
+
not(expression: FilterExpression): FilterExpression;
|
|
30
|
+
raw(node: FilterNode): FilterExpression;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { FilterExpression } from "./filter-expression.js";
|
|
2
|
+
import { FilterField } from "./filter-field.js";
|
|
3
|
+
import type { FilterNode } from "./filter-node.js";
|
|
4
|
+
/** A plain field of `Fields`, or a dotted/bracketed extension of one —
|
|
5
|
+
* `"author.name"` and `"tags[0]"` stay valid even though neither is a key
|
|
6
|
+
* of `Fields` by itself. */
|
|
7
|
+
type TypedFieldPath<Fields> = (keyof Fields & string) | `${keyof Fields & string}.${string}` | `${keyof Fields & string}[${string}]`;
|
|
8
|
+
/** The value an operator on `Key` should accept: `Fields[Key]` when `Key` is
|
|
9
|
+
* a plain field, `unknown` for a dotted or bracketed extension, whose
|
|
10
|
+
* target type this client cannot resolve statically. */
|
|
11
|
+
type TypedFieldValue<Fields, Key extends string> = Key extends keyof Fields ? Fields[Key] : unknown;
|
|
12
|
+
/** `each` walks one element of an array field at a time, so its operators
|
|
13
|
+
* take the element type — `each("tags")` on `tags: string[]` should accept
|
|
14
|
+
* a `string`, not a `string[]`. */
|
|
15
|
+
type TypedEachValue<Fields, Key extends string> = Key extends keyof Fields ? Fields[Key] extends readonly (infer Element)[] ? Element : Fields[Key] : unknown;
|
|
16
|
+
/**
|
|
17
|
+
* `Filter`'s surface, typed to one collection's fields:
|
|
18
|
+
* `posts.filter.field("status")` autocompletes `keyof Post`, and
|
|
19
|
+
* `posts.filter.field("stauts")` does not compile. `meta`, `and`, `or`,
|
|
20
|
+
* `not` and `raw` are untyped, the same as on `Filter`, since they do not
|
|
21
|
+
* address `Fields` at all.
|
|
22
|
+
*/
|
|
23
|
+
export declare class TypedFilter<Fields> {
|
|
24
|
+
field<Key extends TypedFieldPath<Fields>>(name: Key): FilterField<TypedFieldValue<Fields, Key>>;
|
|
25
|
+
each<Key extends TypedFieldPath<Fields>>(name: Key): FilterField<TypedEachValue<Fields, Key>>;
|
|
26
|
+
meta(name: string): FilterField;
|
|
27
|
+
and(left: FilterExpression, right: FilterExpression): FilterExpression;
|
|
28
|
+
or(left: FilterExpression, right: FilterExpression): FilterExpression;
|
|
29
|
+
not(expression: FilterExpression): FilterExpression;
|
|
30
|
+
raw(node: FilterNode): FilterExpression;
|
|
31
|
+
}
|
|
32
|
+
export {};
|