@plume-press/cli 0.0.0-stage → 0.4.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.
@@ -0,0 +1,230 @@
1
+ export type JsonValue = null | boolean | number | string | JsonValue[] | {
2
+ [key: string]: JsonValue;
3
+ };
4
+ export type RecordData = {
5
+ [key: string]: JsonValue;
6
+ };
7
+ type FieldBase = {
8
+ name: string;
9
+ label: string;
10
+ required?: boolean;
11
+ locked?: boolean;
12
+ /** Authoring default for new Items; must validate as the Field's value. */
13
+ default?: JsonValue;
14
+ };
15
+ export type ScalarField = FieldBase & ({
16
+ kind: "richText" | "number" | "boolean" | "link";
17
+ }
18
+ /** `multiline` is a form hint only; `maxLength` counts characters. */
19
+ | {
20
+ kind: "text";
21
+ multiline?: boolean;
22
+ maxLength?: number;
23
+ }
24
+ /** `time: true` stores UTC timestamps, `false` dates only; absent allows both. */
25
+ | {
26
+ kind: "date";
27
+ time?: boolean;
28
+ }
29
+ /** `from` names a sibling text Field the CMS can generate the slug from. */
30
+ | {
31
+ kind: "slug";
32
+ from?: string;
33
+ } | {
34
+ kind: "select";
35
+ options: readonly string[];
36
+ multiple?: boolean;
37
+ } | {
38
+ kind: "reference";
39
+ collection: string;
40
+ multiple?: boolean;
41
+ }
42
+ /** `accept` lists MIME types (`image/png`, `image/*`) or extensions (`.pdf`). */
43
+ | {
44
+ kind: "image" | "file";
45
+ multiple?: boolean;
46
+ accept?: readonly string[];
47
+ });
48
+ export type Field = ScalarField | (FieldBase & {
49
+ kind: "list";
50
+ fields: readonly ScalarField[];
51
+ });
52
+ export type Collection = {
53
+ name: string;
54
+ label: string;
55
+ fields: readonly Field[];
56
+ /** The website page that shows an Item, e.g. `/work/{slug}`: `{id}` is the Item ID,
57
+ * `{<field>}` a text or slug Field's value. See `resolvePreviewPath`. */
58
+ previewPath?: string;
59
+ };
60
+ export type Singleton = {
61
+ name: string;
62
+ label: string;
63
+ fields: readonly Field[];
64
+ /** The website page that shows this Singleton; a fixed path, without placeholders. */
65
+ previewPath?: string;
66
+ };
67
+ export type SchemaDefinition = {
68
+ collections: readonly Collection[];
69
+ singletons?: readonly Singleton[];
70
+ };
71
+ export type MediaReference = {
72
+ id: string;
73
+ alt?: string;
74
+ };
75
+ /** Stored link. `newTab` applies to `url` links only. */
76
+ export type LinkValue = {
77
+ kind: "url" | "email" | "phone";
78
+ value: string;
79
+ newTab?: boolean;
80
+ };
81
+ export type FieldValue<F extends Field> = F extends {
82
+ kind: "number";
83
+ } ? number : F extends {
84
+ kind: "boolean";
85
+ } ? boolean : F extends {
86
+ kind: "link";
87
+ } ? LinkValue : F extends {
88
+ kind: "image" | "file";
89
+ } ? F extends {
90
+ multiple: true;
91
+ } ? MediaReference[] : MediaReference : F extends {
92
+ kind: "select";
93
+ options: readonly (infer O extends string)[];
94
+ } ? F extends {
95
+ multiple: true;
96
+ } ? O[] : O : F extends {
97
+ kind: "reference";
98
+ } ? F extends {
99
+ multiple: true;
100
+ } ? string[] : string : F extends {
101
+ kind: "list";
102
+ fields: infer L extends readonly ScalarField[];
103
+ } ? InferFields<L>[] : string;
104
+ /** Stored record shape, read with optional Fields present as `null` when unset.
105
+ * The SDK delivers `DeliveredFields`, which projects link, image and file values. */
106
+ export type InferFields<F extends readonly Field[]> = {
107
+ [P in F[number] as P extends {
108
+ required: true;
109
+ } ? P["name"] : never]: FieldValue<P>;
110
+ } & {
111
+ [P in F[number] as P extends {
112
+ required: true;
113
+ } ? never : P["name"]]: FieldValue<P> | null;
114
+ };
115
+ export type InferCollection<S extends SchemaDefinition, N extends S["collections"][number]["name"]> = InferFields<Extract<S["collections"][number], {
116
+ name: N;
117
+ }>["fields"]>;
118
+ export type InferSingleton<S extends SchemaDefinition, N extends NonNullable<S["singletons"]>[number]["name"]> = InferFields<Extract<NonNullable<S["singletons"]>[number], {
119
+ name: N;
120
+ }>["fields"]>;
121
+ /** A delivered link: `href` is ready for `<a href>`; only `url` links open a new tab. */
122
+ export type DeliveredLink = {
123
+ kind: "url" | "email" | "phone";
124
+ href: string;
125
+ newTab: boolean;
126
+ };
127
+ /** `width`/`height` are null for assets uploaded before dimensions were recorded
128
+ * or whose header could not be read. `alt` is "" when the Editor left it empty. */
129
+ export type DeliveredImage = {
130
+ url: string;
131
+ width: number | null;
132
+ height: number | null;
133
+ alt: string;
134
+ };
135
+ /** `name` is the uploaded filename, `size` its byte length, `mime` its media type. */
136
+ export type DeliveredFile = {
137
+ url: string;
138
+ name: string;
139
+ size: number;
140
+ mime: string;
141
+ };
142
+ /** Every delivered Item; timestamps are ISO 8601 strings. */
143
+ export type ContentItem<T> = {
144
+ id: string;
145
+ data: T;
146
+ createdAt: string;
147
+ updatedAt: string;
148
+ };
149
+ export type DeliveredValue<F extends Field> = F extends {
150
+ kind: "link";
151
+ } ? DeliveredLink : F extends {
152
+ kind: "image";
153
+ } ? F extends {
154
+ multiple: true;
155
+ } ? DeliveredImage[] : DeliveredImage : F extends {
156
+ kind: "file";
157
+ } ? F extends {
158
+ multiple: true;
159
+ } ? DeliveredFile[] : DeliveredFile : F extends {
160
+ kind: "list";
161
+ fields: infer L extends readonly ScalarField[];
162
+ } ? DeliveredFields<L>[] : FieldValue<F>;
163
+ /** Delivered record shape: optional Fields are always present, `null` when unset. */
164
+ export type DeliveredFields<F extends readonly Field[]> = {
165
+ [P in F[number] as P extends {
166
+ required: true;
167
+ } ? P["name"] : never]: DeliveredValue<P>;
168
+ } & {
169
+ [P in F[number] as P extends {
170
+ required: true;
171
+ } ? never : P["name"]]: DeliveredValue<P> | null;
172
+ };
173
+ export type DeliveredCollection<S extends SchemaDefinition, N extends S["collections"][number]["name"]> = DeliveredFields<Extract<S["collections"][number], {
174
+ name: N;
175
+ }>["fields"]>;
176
+ export type DeliveredSingleton<S extends SchemaDefinition, N extends NonNullable<S["singletons"]>[number]["name"]> = DeliveredFields<Extract<NonNullable<S["singletons"]>[number], {
177
+ name: N;
178
+ }>["fields"]>;
179
+ /** A media Field path inside one Item, e.g. `["blocks", 0, "photo"]`. */
180
+ export type MediaPath = (string | number)[];
181
+ export type FieldIssue = {
182
+ path: string;
183
+ code: "required" | "type" | "format" | "unknown_field" | "unknown_collection" | "invalid_json";
184
+ message: string;
185
+ };
186
+ /** Rejects lossy JSON representations, accessors and prototype-bearing objects. */
187
+ export declare function canonicalJson(value: JsonValue): string;
188
+ /** Schema configuration is data only. Executable validators/transforms are unsupported. */
189
+ export declare function defineSchema<const S extends SchemaDefinition>(schema: S): S;
190
+ /** A schema stored with content, which an older Plume accepted: checked like
191
+ * `defineSchema`, except that a `previewPath` this version's grammar rejects is reported
192
+ * to `ignored` and left inert (`resolvePreviewPath` gives it no path), so that content
193
+ * stays readable. Defining or registering a schema stays strict. */
194
+ export declare function readStoredSchema(schema: unknown, ignored?: (problem: string) => void): SchemaDefinition;
195
+ /** A path on the Site's own website: one leading `/`, no backslash, whitespace or control
196
+ * character, at most 2048 characters, and still a path of the same site once a URL parser
197
+ * normalises it (`/./`, `..`), so no browser or parser reads it as another host. */
198
+ export declare function isLocalPath(path: unknown): path is string;
199
+ /** The website path showing one Item or Singleton, or null when the entity has no valid
200
+ * `previewPath` or a placeholder has no value: Plume never guesses a route. `{id}` is the
201
+ * Item ID (even when a Field is named `id`), `{<field>}` that text or slug Field's value,
202
+ * each trimmed and URL-encoded. The result is always an `isLocalPath`. */
203
+ export declare function resolvePreviewPath(entity: Collection | Singleton, recordId: string, data: JsonValue | undefined): string | null;
204
+ /** Hashes a schema as stored: a `previewPath` an older Plume accepted doesn't change or
205
+ * block its identity (see `readStoredSchema`). */
206
+ export declare function schemaHash(schema: SchemaDefinition): Promise<string>;
207
+ /** Validates shape only; richText HTML requires sanitization at the write/render boundary.
208
+ * Slug uniqueness, reference targets and media `accept` need the whole content and are
209
+ * checked where it is available (save, preparation, local store). */
210
+ export declare function validateRecord(schema: SchemaDefinition, name: string, data: unknown, options: {
211
+ publication: boolean;
212
+ }): FieldIssue[];
213
+ /** Removes `null` (unset) optional values so stored records stay canonical. */
214
+ export declare function stripNullFields(fields: readonly Field[], data: RecordData): RecordData;
215
+ /** Delivered shape: every unset optional Field is present as `null`, one list level deep. */
216
+ export declare function withNullFields(fields: readonly Field[], data: RecordData): RecordData;
217
+ /** The record IDs a reference value names, single or `multiple`. */
218
+ export declare function referenceIds(value: JsonValue | undefined): string[];
219
+ /** Resolves optional references to Items that no longer exist to `null` (unset):
220
+ * a single reference is removed, a `multiple` one loses the missing IDs. Required
221
+ * references are kept so the caller can refuse them. Returns null when unchanged. */
222
+ export declare function dropMissingReferences(fields: readonly Field[], data: RecordData, exists: (collection: string, id: string) => boolean): RecordData | null;
223
+ /** Lowercase hyphen-separated slug from free text, in the slug Field's format. */
224
+ export declare function slugify(value: string): string;
225
+ /** Whether a stored asset satisfies a media Field's `accept` list (absent accepts all). */
226
+ export declare function mediaAccepted(accept: readonly string[] | undefined, asset: {
227
+ mediaType: string;
228
+ filename: string;
229
+ }): boolean;
230
+ export {};