@byline/client 0.9.3
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/LICENSE +373 -0
- package/README.md +20 -0
- package/dist/client.d.ts +60 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +158 -0
- package/dist/client.js.map +1 -0
- package/dist/collection-handle.d.ts +182 -0
- package/dist/collection-handle.d.ts.map +1 -0
- package/dist/collection-handle.js +511 -0
- package/dist/collection-handle.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/response.d.ts +27 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +80 -0
- package/dist/response.js.map +1 -0
- package/dist/types.d.ts +323 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +71 -0
package/dist/response.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Coerce a storage-layer date value into a Date. Throws when the value is
|
|
10
|
+
* missing — every document version row carries created_at/updated_at, so a
|
|
11
|
+
* nullish value here indicates a malformed row (not a shaping concern).
|
|
12
|
+
*/
|
|
13
|
+
function toDate(value, fieldName) {
|
|
14
|
+
if (value instanceof Date)
|
|
15
|
+
return value;
|
|
16
|
+
if (typeof value === 'string' || typeof value === 'number')
|
|
17
|
+
return new Date(value);
|
|
18
|
+
throw new Error(`shapeDocument: missing or invalid ${fieldName}`);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Shape an internal document (snake_case, storage layer format) into the
|
|
22
|
+
* public ClientDocument format (camelCase). The generic `F` types the
|
|
23
|
+
* `fields` property for callers that know their collection's shape.
|
|
24
|
+
*/
|
|
25
|
+
export function shapeDocument(raw) {
|
|
26
|
+
return {
|
|
27
|
+
id: raw.document_id ?? '',
|
|
28
|
+
versionId: raw.document_version_id ?? '',
|
|
29
|
+
path: raw.path ?? '',
|
|
30
|
+
status: raw.status ?? '',
|
|
31
|
+
createdAt: toDate(raw.created_at, 'created_at'),
|
|
32
|
+
updatedAt: toDate(raw.updated_at, 'updated_at'),
|
|
33
|
+
fields: (raw.fields ?? {}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Detect a raw (storage-shape) document vs a shaped `ClientDocument` vs a
|
|
38
|
+
* plain object. Raw docs carry `document_id` + `fields` and have NOT yet
|
|
39
|
+
* been through `shapeDocument` (no `versionId`).
|
|
40
|
+
*/
|
|
41
|
+
function isRawDocument(v) {
|
|
42
|
+
if (v === null || typeof v !== 'object' || Array.isArray(v))
|
|
43
|
+
return false;
|
|
44
|
+
const o = v;
|
|
45
|
+
return typeof o.document_id === 'string' && typeof o.fields === 'object' && !('versionId' in o);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* After `populateDocuments` replaces relation leaves with raw
|
|
49
|
+
* storage-shape documents, walk the tree and convert each one to a
|
|
50
|
+
* `ClientDocument` in place. Preserves reference equality for
|
|
51
|
+
* non-document values so stubs (`_resolved: false`, `_cycle: true`) and
|
|
52
|
+
* rich-text blobs are not rewritten.
|
|
53
|
+
*
|
|
54
|
+
* Call on `shaped.fields` after the top-level doc has already been
|
|
55
|
+
* shaped. The function mutates arrays in place (replacing populated
|
|
56
|
+
* entries) and returns the possibly-rewritten value for scalar inputs.
|
|
57
|
+
*/
|
|
58
|
+
export function shapePopulatedInPlace(value) {
|
|
59
|
+
if (value == null)
|
|
60
|
+
return value;
|
|
61
|
+
if (Array.isArray(value)) {
|
|
62
|
+
for (let i = 0; i < value.length; i++) {
|
|
63
|
+
value[i] = shapePopulatedInPlace(value[i]);
|
|
64
|
+
}
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
if (typeof value !== 'object')
|
|
68
|
+
return value;
|
|
69
|
+
if (isRawDocument(value)) {
|
|
70
|
+
const shaped = shapeDocument(value);
|
|
71
|
+
shaped.fields = shapePopulatedInPlace(shaped.fields);
|
|
72
|
+
return shaped;
|
|
73
|
+
}
|
|
74
|
+
const obj = value;
|
|
75
|
+
for (const k of Object.keys(obj)) {
|
|
76
|
+
obj[k] = shapePopulatedInPlace(obj[k]);
|
|
77
|
+
}
|
|
78
|
+
return obj;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.js","sourceRoot":"","sources":["../src/response.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;GAIG;AACH,SAAS,MAAM,CAAC,KAAc,EAAE,SAAiB;IAC/C,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,KAAK,CAAA;IACvC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,CAAA;IAClF,MAAM,IAAI,KAAK,CAAC,qCAAqC,SAAS,EAAE,CAAC,CAAA;AACnE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAwB;IAExB,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,WAAW,IAAI,EAAE;QACzB,SAAS,EAAE,GAAG,CAAC,mBAAmB,IAAI,EAAE;QACxC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE;QACpB,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE;QACxB,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC;QAC/C,SAAS,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC;QAC/C,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAAM;KAChC,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,CAAU;IAC/B,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IACzE,MAAM,CAAC,GAAG,CAAwB,CAAA;IAClC,OAAO,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,CAAA;AACjG,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,KAAK,CAAA;IAC/B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,KAAK,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5C,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IAE3C,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,CAAA;QACnC,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,MAAM,CAAwB,CAAA;QAC3E,OAAO,MAAM,CAAA;IACf,CAAC;IAED,MAAM,GAAG,GAAG,KAA4B,CAAA;IACxC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,GAAG,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
import type { RequestContext } from '@byline/auth';
|
|
9
|
+
import type { BylineLogger, CollectionDefinition, IDbAdapter, IStorageProvider, PopulateSpec, PredicateValue, QueryPredicate, ReadContext, ReadMode, RichTextPopulateFn, ServerConfig, SlugifierFn, SortSpec } from '@byline/core';
|
|
10
|
+
export type { FilterOperators, PredicateValue, QueryPredicate, SortDirection, SortSpec, } from '@byline/core';
|
|
11
|
+
export interface BylineClientConfig {
|
|
12
|
+
/**
|
|
13
|
+
* Convenience shorthand: pass an already-resolved `ServerConfig` (typically
|
|
14
|
+
* from `getServerConfig()`) to seed `db`, `collections`, `storage`,
|
|
15
|
+
* `slugifier`, and `defaultLocale` in one go. Each disaggregated prop
|
|
16
|
+
* below is still accepted and overrides the corresponding value pulled
|
|
17
|
+
* from `config`, so tests and migrations can substitute pieces:
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* createBylineClient({
|
|
21
|
+
* config: getServerConfig(),
|
|
22
|
+
* requestContext: () => createRequestContext({ readMode: 'published' }),
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* The SDK does *not* call `getServerConfig()` itself — the caller does —
|
|
27
|
+
* so seeds, scripts, and tests that want to construct a client without a
|
|
28
|
+
* registered server config can keep passing the disaggregated props.
|
|
29
|
+
*/
|
|
30
|
+
config?: ServerConfig;
|
|
31
|
+
/** The database adapter (e.g. from @byline/db-postgres). Required when `config` is omitted. */
|
|
32
|
+
db?: IDbAdapter;
|
|
33
|
+
/** All registered collection definitions. Required when `config` is omitted. */
|
|
34
|
+
collections?: CollectionDefinition[];
|
|
35
|
+
/** Optional storage provider — needed for delete file cleanup. */
|
|
36
|
+
storage?: IStorageProvider;
|
|
37
|
+
/**
|
|
38
|
+
* Optional logger. Used by the write path to emit structured events
|
|
39
|
+
* from `document-lifecycle`. When omitted, the client falls back to
|
|
40
|
+
* `getLogger()` if `initBylineCore()` has registered one, else uses a
|
|
41
|
+
* silent no-op logger so scripts and tests run without setup.
|
|
42
|
+
*/
|
|
43
|
+
logger?: BylineLogger;
|
|
44
|
+
/**
|
|
45
|
+
* Default content locale. Forwarded to `DocumentLifecycleContext` and
|
|
46
|
+
* used to anchor `path` derivation. Defaults to `'en'` when omitted.
|
|
47
|
+
*/
|
|
48
|
+
defaultLocale?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Optional installation slugifier, forwarded to the lifecycle. When
|
|
51
|
+
* omitted, the lifecycle uses the default `slugify` from `@byline/core`.
|
|
52
|
+
*/
|
|
53
|
+
slugifier?: SlugifierFn;
|
|
54
|
+
/**
|
|
55
|
+
* Optional richtext server-side populate function. Threaded into
|
|
56
|
+
* `populateDocuments` so populated targets get their rich-text leaves
|
|
57
|
+
* refreshed before `afterRead` fires; also called for source documents
|
|
58
|
+
* after relation populate completes. When omitted (and not provided via
|
|
59
|
+
* the `config` shorthand's `fields.richText.populate`), rich-text
|
|
60
|
+
* populate is skipped — the read returns whatever was embedded at
|
|
61
|
+
* write time.
|
|
62
|
+
*/
|
|
63
|
+
richTextPopulate?: RichTextPopulateFn;
|
|
64
|
+
/**
|
|
65
|
+
* Request-scoped auth context. Required in practice — every read and
|
|
66
|
+
* write call from this client resolves a context and enforces
|
|
67
|
+
* `collections.<path>.<verb>` at the service boundary.
|
|
68
|
+
*
|
|
69
|
+
* Accepts either:
|
|
70
|
+
* - a static `RequestContext` — convenient for long-lived processes
|
|
71
|
+
* that authenticate once (seeds, migrations, CLI tooling); or
|
|
72
|
+
* - a factory `() => RequestContext | Promise<RequestContext>` —
|
|
73
|
+
* resolved per-call so each operation picks up the current
|
|
74
|
+
* authenticated request (the pattern Phase 5's admin webapp will
|
|
75
|
+
* use to thread middleware-derived actors).
|
|
76
|
+
*
|
|
77
|
+
* When omitted, calls fail closed with `ERR_UNAUTHENTICATED`. Scripts
|
|
78
|
+
* and tests pass `createSuperAdminContext()` from `@byline/auth`.
|
|
79
|
+
*/
|
|
80
|
+
requestContext?: RequestContext | (() => RequestContext | Promise<RequestContext>);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Common populate options shared by every read method. `populate` names
|
|
84
|
+
* the relations (or passes `true` for all) to replace with their target
|
|
85
|
+
* documents; `depth` caps the traversal (default 1 when populate is set,
|
|
86
|
+
* 0 otherwise). Clamped to the request's internal `ReadContext.maxDepth`.
|
|
87
|
+
*/
|
|
88
|
+
interface PopulateControls {
|
|
89
|
+
populate?: PopulateSpec;
|
|
90
|
+
depth?: number;
|
|
91
|
+
/**
|
|
92
|
+
* Escape hatch for read-side hook re-entry. Carries the visited set,
|
|
93
|
+
* depth clamp, and `afterReadFired` set across nested reads so the
|
|
94
|
+
* A→B→A recursion guard stays intact.
|
|
95
|
+
*
|
|
96
|
+
* Threading rules:
|
|
97
|
+
*
|
|
98
|
+
* - **Public callers**: leave undefined. A fresh context is created
|
|
99
|
+
* per top-level read.
|
|
100
|
+
* - **Inside `afterRead` / lifecycle hooks**: if the hook calls back
|
|
101
|
+
* into the client, pass `readContext` through as `_readContext`
|
|
102
|
+
* verbatim. Do not fabricate a new one — doing so bypasses the
|
|
103
|
+
* "once per document per logical request" guard and risks
|
|
104
|
+
* unbounded hook re-firing.
|
|
105
|
+
* - **Don't reuse across top-level calls**: a context from a
|
|
106
|
+
* previous `find()` still carries that request's visited set, so
|
|
107
|
+
* reusing it will silently suppress `afterRead` on documents
|
|
108
|
+
* already seen. Contexts are per-request, not per-client.
|
|
109
|
+
*
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
_readContext?: ReadContext;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Read-mode selector shared by every read method.
|
|
116
|
+
*
|
|
117
|
+
* - `'published'` (client default) — return the latest *published*
|
|
118
|
+
* version of each document, falling back past newer drafts so public
|
|
119
|
+
* readers keep seeing previously-published content while editors
|
|
120
|
+
* work on an unpublished draft. A document with no published
|
|
121
|
+
* version is invisible in this mode. Populated relation targets
|
|
122
|
+
* follow the same rule.
|
|
123
|
+
* - `'any'` — return the latest version regardless of status.
|
|
124
|
+
* Admin UIs (which surface in-progress drafts) should pass this
|
|
125
|
+
* explicitly.
|
|
126
|
+
*
|
|
127
|
+
* Distinct from `where.status`, which is an *exact-match filter* on the
|
|
128
|
+
* selected version's status column ("show me all drafts"). `status` is
|
|
129
|
+
* the *source view* selector.
|
|
130
|
+
*/
|
|
131
|
+
interface StatusControls {
|
|
132
|
+
status?: ReadMode;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Read-side access-control escape hatch shared by every read method.
|
|
136
|
+
*
|
|
137
|
+
* - `_bypassBeforeRead?: true` — skip the `CollectionHooks.beforeRead`
|
|
138
|
+
* hook for this read. Reserved for admin tooling, migrations, and
|
|
139
|
+
* seed scripts that need unscoped access; never use from application
|
|
140
|
+
* code, since it deliberately disables the predicate that enforces
|
|
141
|
+
* row-level read access (multi-tenant scoping, owner-only-drafts,
|
|
142
|
+
* soft-delete hide, etc).
|
|
143
|
+
*
|
|
144
|
+
* @internal
|
|
145
|
+
*/
|
|
146
|
+
interface BeforeReadControls {
|
|
147
|
+
_bypassBeforeRead?: true;
|
|
148
|
+
}
|
|
149
|
+
export interface FindOptions<F = Record<string, any>> extends PopulateControls, StatusControls, BeforeReadControls {
|
|
150
|
+
/** Filter documents. Keys are field names or reserved names (status, path). */
|
|
151
|
+
where?: WhereClause;
|
|
152
|
+
/** Return only these fields. Omit for all fields. */
|
|
153
|
+
select?: (keyof F & string)[] | string[];
|
|
154
|
+
/** Sort specification. Keys are field names or document-level columns. */
|
|
155
|
+
sort?: SortSpec;
|
|
156
|
+
/** Locale for field value resolution. Defaults to 'en'. */
|
|
157
|
+
locale?: string;
|
|
158
|
+
/** Page number (1-based). Defaults to 1. */
|
|
159
|
+
page?: number;
|
|
160
|
+
/** Documents per page. Defaults to 20. */
|
|
161
|
+
pageSize?: number;
|
|
162
|
+
}
|
|
163
|
+
export interface FindOneOptions<F = Record<string, any>> extends PopulateControls, StatusControls, BeforeReadControls {
|
|
164
|
+
where?: WhereClause;
|
|
165
|
+
select?: (keyof F & string)[] | string[];
|
|
166
|
+
locale?: string;
|
|
167
|
+
}
|
|
168
|
+
export interface FindByIdOptions<F = Record<string, any>> extends PopulateControls, StatusControls, BeforeReadControls {
|
|
169
|
+
select?: (keyof F & string)[] | string[];
|
|
170
|
+
locale?: string;
|
|
171
|
+
}
|
|
172
|
+
export interface FindByPathOptions<F = Record<string, any>> extends PopulateControls, StatusControls, BeforeReadControls {
|
|
173
|
+
select?: (keyof F & string)[] | string[];
|
|
174
|
+
locale?: string;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Options for `CollectionHandle.history(documentId, options)`. The history
|
|
178
|
+
* endpoint is paginated; `order` / `desc` mirror the storage adapter's
|
|
179
|
+
* version-row sort axes. `_bypassBeforeRead` skips the `findById` access
|
|
180
|
+
* gate for admin tooling.
|
|
181
|
+
*/
|
|
182
|
+
export interface HistoryOptions extends BeforeReadControls {
|
|
183
|
+
locale?: string;
|
|
184
|
+
page?: number;
|
|
185
|
+
pageSize?: number;
|
|
186
|
+
order?: string;
|
|
187
|
+
desc?: boolean;
|
|
188
|
+
/** @internal — see `_readContext` on read options. */
|
|
189
|
+
_readContext?: ReadContext;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Options for `CollectionHandle.findByVersion(versionId, options)`. No
|
|
193
|
+
* `BeforeReadControls` — `findByVersion` is a low-level pass-through
|
|
194
|
+
* intended for admin diff views; row-level scoping is the caller's
|
|
195
|
+
* responsibility (typically by gating with a prior `findById` call).
|
|
196
|
+
*/
|
|
197
|
+
export interface FindByVersionOptions<F = Record<string, any>> {
|
|
198
|
+
select?: (keyof F & string)[] | string[];
|
|
199
|
+
locale?: string;
|
|
200
|
+
}
|
|
201
|
+
export interface CreateOptions {
|
|
202
|
+
/** Locale for field value resolution. Defaults to 'en'. */
|
|
203
|
+
locale?: string;
|
|
204
|
+
/**
|
|
205
|
+
* Initial workflow status. When omitted, `document-lifecycle` derives
|
|
206
|
+
* the collection's default (usually `'draft'`).
|
|
207
|
+
*/
|
|
208
|
+
status?: string;
|
|
209
|
+
/**
|
|
210
|
+
* Explicit `documentVersions.path` override. When omitted the lifecycle
|
|
211
|
+
* derives a path from `definition.useAsPath` (or falls back to a UUID).
|
|
212
|
+
*/
|
|
213
|
+
path?: string;
|
|
214
|
+
}
|
|
215
|
+
export interface UpdateOptions {
|
|
216
|
+
/** Locale for field value resolution. Defaults to 'en'. */
|
|
217
|
+
locale?: string;
|
|
218
|
+
/**
|
|
219
|
+
* Explicit path override. When omitted, the previous version's path
|
|
220
|
+
* carries forward unchanged (sticky).
|
|
221
|
+
*/
|
|
222
|
+
path?: string;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* A where clause maps field names (or reserved document-level names like
|
|
226
|
+
* `status` and `path`) to either a bare value (equality), an operator
|
|
227
|
+
* object, or — for relation fields — a nested where clause against the
|
|
228
|
+
* target collection. Reserved keys:
|
|
229
|
+
* - `status` — exact match on document version status column
|
|
230
|
+
* - `query` — text search across the collection's configured search fields
|
|
231
|
+
* - `path` — document version path column (supports operators)
|
|
232
|
+
*
|
|
233
|
+
* All other keys are resolved against the collection's field definitions
|
|
234
|
+
* and compiled into EXISTS subqueries over the EAV store tables. When a
|
|
235
|
+
* relation field's value is a plain object with no `$`-prefixed keys it
|
|
236
|
+
* is treated as a nested where against the target collection — the
|
|
237
|
+
* adapter emits a nested EXISTS through `store_relation`, recursing into
|
|
238
|
+
* the target's own EAV stores:
|
|
239
|
+
*
|
|
240
|
+
* ```ts
|
|
241
|
+
* where: {
|
|
242
|
+
* category: { path: 'news' }, // → docs whose category's path is 'news'
|
|
243
|
+
* title: { $contains: 'launch' }, // ordinary field filter
|
|
244
|
+
* }
|
|
245
|
+
* ```
|
|
246
|
+
*
|
|
247
|
+
* `WhereClause` is a backwards-compatible alias for the canonical
|
|
248
|
+
* `QueryPredicate` from `@byline/core`. The client-facing `where` clause
|
|
249
|
+
* and a `CollectionHooks.beforeRead` return value share one structure, so
|
|
250
|
+
* combinators (`$and`, `$or`) are usable on both surfaces.
|
|
251
|
+
*/
|
|
252
|
+
export type WhereClause = QueryPredicate;
|
|
253
|
+
/** Backwards-compatible alias for `PredicateValue` from `@byline/core`. */
|
|
254
|
+
export type WhereValue = PredicateValue;
|
|
255
|
+
/**
|
|
256
|
+
* Shape of a document returned by the client API.
|
|
257
|
+
*
|
|
258
|
+
* The generic parameter `F` types the `fields` object. Callers that know
|
|
259
|
+
* their collection's shape can narrow it:
|
|
260
|
+
*
|
|
261
|
+
* ```ts
|
|
262
|
+
* interface Post { title: string; body: string }
|
|
263
|
+
* const post = await client.collection('posts').findById<Post>(id)
|
|
264
|
+
* post?.fields.title // typed as string
|
|
265
|
+
* ```
|
|
266
|
+
*
|
|
267
|
+
* Defaults to `Record<string, any>` when no shape is provided.
|
|
268
|
+
*/
|
|
269
|
+
export interface ClientDocument<F = Record<string, any>> {
|
|
270
|
+
/** Logical document ID. */
|
|
271
|
+
id: string;
|
|
272
|
+
/** The specific version ID for this document. */
|
|
273
|
+
versionId: string;
|
|
274
|
+
/** URL-friendly slug/path for this document. */
|
|
275
|
+
path: string;
|
|
276
|
+
/** Workflow status (e.g. 'draft', 'published'). */
|
|
277
|
+
status: string;
|
|
278
|
+
/** When this version was created. */
|
|
279
|
+
createdAt: Date;
|
|
280
|
+
/** When this version was last updated. */
|
|
281
|
+
updatedAt: Date;
|
|
282
|
+
/** Reconstructed field data. */
|
|
283
|
+
fields: F;
|
|
284
|
+
}
|
|
285
|
+
export interface FindResult<F = Record<string, any>> {
|
|
286
|
+
docs: ClientDocument<F>[];
|
|
287
|
+
meta: {
|
|
288
|
+
total: number;
|
|
289
|
+
page: number;
|
|
290
|
+
pageSize: number;
|
|
291
|
+
totalPages: number;
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* The shape a populated relation leaf takes when `populate` (or `populate: '*'`)
|
|
296
|
+
* is in scope for that field. Wraps the populated target as a `ClientDocument<T>`
|
|
297
|
+
* on `.document`. Optional because the slot may also resolve to an
|
|
298
|
+
* unresolved (`_resolved: false`) or cycle (`_cycle: true`) marker, in which
|
|
299
|
+
* cases `document` is absent.
|
|
300
|
+
*/
|
|
301
|
+
export interface PopulatedRelation<T> {
|
|
302
|
+
document?: ClientDocument<T>;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Re-type one key of a schema-inferred fields type as a populated relation.
|
|
306
|
+
* Use to overlay populate's per-call enrichment on top of the unpopulated
|
|
307
|
+
* shape that `CollectionFieldData<typeof X>` derives from the schema.
|
|
308
|
+
*
|
|
309
|
+
* Homomorphic mapped form preserves the optionality of the underlying key —
|
|
310
|
+
* an optional relation field stays optional after populate is layered on.
|
|
311
|
+
*
|
|
312
|
+
* ```ts
|
|
313
|
+
* type NewsPopulated = WithPopulated<
|
|
314
|
+
* WithPopulated<NewsFields, 'category', NewsCategoryFields>,
|
|
315
|
+
* 'featureImage', MediaFields
|
|
316
|
+
* >
|
|
317
|
+
* client.collection('news').find<NewsPopulated>({ populate: { category: '*', featureImage: '*' } })
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
export type WithPopulated<F, K extends keyof F, Target> = {
|
|
321
|
+
[P in keyof F]: P extends K ? PopulatedRelation<Target> : F[P];
|
|
322
|
+
};
|
|
323
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This Source Code is subject to the terms of the Mozilla Public
|
|
3
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
4
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) Infonomic Company Limited
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@byline/client",
|
|
3
|
+
"private": false,
|
|
4
|
+
"license": "MPL-2.0",
|
|
5
|
+
"version": "0.9.3",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20.9.0"
|
|
8
|
+
},
|
|
9
|
+
"description": "Byline CMS client API — DSL-like query and mutation layer",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"cms",
|
|
12
|
+
"headless cms",
|
|
13
|
+
"content management"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://github.com/Byline-CMS/bylinecms.dev",
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/Byline-CMS/bylinecms.dev/issues"
|
|
18
|
+
},
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/Byline-CMS/bylinecms.dev.git",
|
|
22
|
+
"directory": "packages/client"
|
|
23
|
+
},
|
|
24
|
+
"type": "module",
|
|
25
|
+
"main": "dist/index.js",
|
|
26
|
+
"index": "dist/index.js",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/index.js",
|
|
32
|
+
"require": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"npm-run-all": "^4.1.5",
|
|
41
|
+
"@byline/auth": "0.9.3",
|
|
42
|
+
"@byline/core": "0.9.3"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@biomejs/biome": "2.4.14",
|
|
46
|
+
"@types/node": "^25.6.0",
|
|
47
|
+
"chokidar": "^5.0.0",
|
|
48
|
+
"chokidar-cli": "^3.0.0",
|
|
49
|
+
"dotenv": "^17.4.2",
|
|
50
|
+
"tsc-alias": "^1.8.17",
|
|
51
|
+
"tsx": "^4.21.0",
|
|
52
|
+
"typescript": "6.0.3",
|
|
53
|
+
"vitest": "^4.1.5",
|
|
54
|
+
"@byline/db-postgres": "0.9.3"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public",
|
|
58
|
+
"index": "dist/index.js",
|
|
59
|
+
"registry": "https://registry.npmjs.org/"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"dev": "chokidar 'src/**/*' -c 'npm-run-all build'",
|
|
63
|
+
"build": "tsc -p tsconfig.json && tsc-alias",
|
|
64
|
+
"clean": "rimraf node_modules dist build .turbo",
|
|
65
|
+
"lint": "biome check --write --unsafe --diagnostic-level=error",
|
|
66
|
+
"test": "vitest run --mode=node",
|
|
67
|
+
"test:watch": "vitest --mode=node",
|
|
68
|
+
"test:integration": "vitest run --mode=integration",
|
|
69
|
+
"typecheck": "tsc --noEmit"
|
|
70
|
+
}
|
|
71
|
+
}
|