@contentchef/contentchef-types 11.0.0 → 11.1.0-alpha.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,382 @@
1
+ import { AuthorResponse } from './Author';
2
+ import { PagedListResponse } from './common';
3
+ import { AttributeViolation, ContentDefinitionId, GetContentDefinitionResponse, SchemaFieldViolationsErrors } from './ContentDefinition';
4
+ import { FragmentDefinition } from './ContentDefinitionSchema';
5
+ /**
6
+ * The component unique id
7
+ */
8
+ export type ComponentId = number;
9
+ /**
10
+ * A component's mnemonicId must match this pattern. It becomes the fragment's name in every definition
11
+ * using the component, so it is unique in the space, case insensitively, and never changes
12
+ */
13
+ export declare const COMPONENT_NAME_PATTERN: RegExp;
14
+ /**
15
+ * This type represent the fragment a component defines: its fields and optionally its labels, nothing
16
+ * else. Its labels, hints, placeholders and list value labels need at least one locale, any locale
17
+ */
18
+ export type ComponentFragment = Omit<FragmentDefinition, 'component'>;
19
+ /**
20
+ * This type represent field names, by what happened to them between two versions of a fragment.
21
+ * A field whose type changed is `changed`
22
+ */
23
+ export type FieldChanges = {
24
+ added: string[];
25
+ removed: string[];
26
+ changed: string[];
27
+ };
28
+ /**
29
+ * This type represent the author of a component, or of one of its versions
30
+ */
31
+ export type ComponentAuthor = Pick<AuthorResponse, 'authorId' | 'fullName'>;
32
+ /**
33
+ * This type represent a published version of a component, which never changes
34
+ */
35
+ export type ComponentVersion = ComponentFragment & {
36
+ /**
37
+ * The version number, from 1
38
+ */
39
+ version: number;
40
+ /**
41
+ * The changes from the version before. Version 1 lists every field as added
42
+ */
43
+ changes: FieldChanges;
44
+ /**
45
+ * The note given when publishing
46
+ */
47
+ note?: string;
48
+ publishedBy: ComponentAuthor;
49
+ publishedDate: Date;
50
+ };
51
+ /**
52
+ * This type represent a version of a component without its fragment
53
+ */
54
+ export type ComponentVersionSummary = Omit<ComponentVersion, 'labels' | 'fields'>;
55
+ /**
56
+ * This type represent a definition using a component
57
+ */
58
+ export type ComponentUsedBy = {
59
+ definitionId: ContentDefinitionId;
60
+ definitionMnemonicId: string;
61
+ definitionName: string;
62
+ /**
63
+ * The component version the definition copies
64
+ */
65
+ version: number;
66
+ };
67
+ /**
68
+ * This type represent a component as the list components API request answers it
69
+ *
70
+ * A component is a fragment a space defines once, for any of its definitions to use. Publishing its
71
+ * draft makes its next version, and a definition moves to a newer version only when it is upgraded
72
+ */
73
+ export type ComponentSummary = {
74
+ id: ComponentId;
75
+ /**
76
+ * The component mnemonic id, matching [[COMPONENT_NAME_PATTERN]]
77
+ */
78
+ mnemonicId: string;
79
+ name: string;
80
+ /**
81
+ * An archived component keeps working in the definitions using it, and cannot be added to another
82
+ * definition or component
83
+ */
84
+ archived: boolean;
85
+ /**
86
+ * The latest version, null until the first publish
87
+ */
88
+ latestVersion: number | null;
89
+ /**
90
+ * Whether the draft differs from the latest version, true before the first publish
91
+ */
92
+ draftChanged: boolean;
93
+ /**
94
+ * How many definitions use the component, and how many of those are on an older version
95
+ */
96
+ usage: {
97
+ definitions: number;
98
+ behind: number;
99
+ };
100
+ };
101
+ /**
102
+ * This type represent the model of a component, as every component API request but list answers it
103
+ */
104
+ export type ComponentResponse = ComponentSummary & {
105
+ archivedDate: Date | null;
106
+ /**
107
+ * The fragment being edited
108
+ */
109
+ draft: ComponentFragment;
110
+ /**
111
+ * The version asked for, the latest by default, null before the first publish
112
+ */
113
+ version: ComponentVersion | null;
114
+ /**
115
+ * Every version, newest first
116
+ */
117
+ versions: ComponentVersionSummary[];
118
+ usedBy: ComponentUsedBy[];
119
+ createdDate: Date;
120
+ lastModifiedDate: Date;
121
+ author: ComponentAuthor;
122
+ latestContributor: ComponentAuthor;
123
+ };
124
+ /**
125
+ * This type represent all possible filters used to retrieve a list of components
126
+ */
127
+ export type ListComponentsFilters = {
128
+ /**
129
+ * Matches the name or the mnemonic id, case insensitively, anywhere in it. At most 100 characters
130
+ */
131
+ name?: string;
132
+ /**
133
+ * Left out, the list holds both archived and not archived components
134
+ */
135
+ archived?: boolean;
136
+ };
137
+ /**
138
+ * This type represent the data needed to make a list components API request
139
+ */
140
+ export type ListComponentsRequest = {
141
+ /**
142
+ * The number of components to skip, 0 by default
143
+ */
144
+ skip?: number;
145
+ /**
146
+ * The number of components to take, 10 by default and at most 100
147
+ */
148
+ take?: number;
149
+ filters?: ListComponentsFilters;
150
+ };
151
+ /**
152
+ * This type represent the response of a list components API request
153
+ */
154
+ export type ListComponentsResponse = PagedListResponse<ComponentSummary>;
155
+ /**
156
+ * This type represent the data needed to make a get component API request, by id or by mnemonic id
157
+ */
158
+ export type GetComponentRequest = ({
159
+ id: ComponentId;
160
+ } | {
161
+ mnemonicId: string;
162
+ }) & {
163
+ /**
164
+ * The version to answer with, the latest by default
165
+ */
166
+ version?: number;
167
+ };
168
+ /**
169
+ * This type represent the response of a get component API request
170
+ */
171
+ export type GetComponentResponse = ComponentResponse;
172
+ /**
173
+ * This type represent the data needed to make a create component API request
174
+ */
175
+ export type CreateComponentRequest = {
176
+ /**
177
+ * The component mnemonic id, matching [[COMPONENT_NAME_PATTERN]]
178
+ */
179
+ mnemonicId: string;
180
+ name: string;
181
+ draft: ComponentFragment;
182
+ };
183
+ /**
184
+ * This type represent the response of a create component API request, with no version yet
185
+ */
186
+ export type CreateComponentResponse = ComponentResponse;
187
+ /**
188
+ * This type represent the data needed to make an update component API request. The name and the whole
189
+ * draft are replaced, and the last save wins
190
+ */
191
+ export type UpdateComponentRequest = {
192
+ id: ComponentId;
193
+ name: string;
194
+ draft: ComponentFragment;
195
+ };
196
+ /**
197
+ * This type represent the response of an update component API request
198
+ */
199
+ export type UpdateComponentResponse = ComponentResponse;
200
+ /**
201
+ * This type represent the data needed to make a publish component API request
202
+ */
203
+ export type PublishComponentRequest = {
204
+ id: ComponentId;
205
+ /**
206
+ * A note on the version, at most 2000 characters
207
+ */
208
+ note?: string;
209
+ };
210
+ /**
211
+ * This type represent the response of a publish component API request, its `version` the one just
212
+ * published
213
+ */
214
+ export type PublishComponentResponse = ComponentResponse;
215
+ /**
216
+ * This type represent the data needed to make a toggle archived component API request
217
+ */
218
+ export type ToggleArchivedComponentRequest = {
219
+ id: ComponentId;
220
+ archived: boolean;
221
+ };
222
+ /**
223
+ * This type represent the response of a toggle archived component API request
224
+ */
225
+ export type ToggleArchivedComponentResponse = ComponentResponse;
226
+ /**
227
+ * This type represent the data needed to make an adopt component API request: the definition's own
228
+ * fragment named `mnemonicId` becomes the managed fragment of that component version
229
+ */
230
+ export type AdoptComponentRequest = {
231
+ definitionId: ContentDefinitionId;
232
+ mnemonicId: string;
233
+ version: number;
234
+ };
235
+ /**
236
+ * This type represent the response of an adopt component API request: the definition, as the get
237
+ * content definition API request answers it
238
+ */
239
+ export type AdoptComponentResponse = NonNullable<GetContentDefinitionResponse>;
240
+ /**
241
+ * This type represent the data needed to make a promote component API request: the definition's own
242
+ * fragment becomes version 1 of a new component, whose mnemonic id is the fragment's name
243
+ */
244
+ export type PromoteComponentRequest = {
245
+ definitionId: ContentDefinitionId;
246
+ fragment: string;
247
+ /**
248
+ * The component name, the fragment's name by default
249
+ */
250
+ name?: string;
251
+ };
252
+ /**
253
+ * This type represent the response of a promote component API request
254
+ */
255
+ export type PromoteComponentResponse = {
256
+ component: ComponentResponse;
257
+ /**
258
+ * The definition, as the get content definition API request answers it
259
+ */
260
+ definition: NonNullable<GetContentDefinitionResponse>;
261
+ };
262
+ /**
263
+ * Thin enum represent the error types of the component API requests, and of the content definition
264
+ * ones using components. Each is the `type` of a `RequestError`, whose `details` is a [[ComponentError]]
265
+ */
266
+ export declare enum ComponentErrorTypes {
267
+ componentNotFound = "ComponentNotFound",
268
+ componentVersionNotFound = "ComponentVersionNotFound",
269
+ failedComponentValidation = "FailedComponentValidation",
270
+ componentVersionRefused = "ComponentVersionRefused",
271
+ nothingToPublish = "NothingToPublish",
272
+ mnemonicIdNotUnique = "MnemonicIdNotUnique",
273
+ managedFragmentEdited = "ManagedFragmentEdited",
274
+ componentArchived = "ComponentArchived",
275
+ componentAdoptionRequired = "ComponentAdoptionRequired",
276
+ componentDowngradeRefused = "ComponentDowngradeRefused",
277
+ componentUpgradeBlocked = "ComponentUpgradeBlocked",
278
+ noFragmentToAdopt = "NoFragmentToAdopt",
279
+ noFragmentToPromote = "NoFragmentToPromote"
280
+ }
281
+ /**
282
+ * Thin enum represent the codes of a [[ComponentVersionViolation]]
283
+ */
284
+ export declare enum ComponentVersionViolationCodes {
285
+ /**
286
+ * An added field, or one whose type changed, must be optional
287
+ */
288
+ requiredField = "component.requiredField",
289
+ /**
290
+ * An added field, or one whose type changed, can be neither compact nor a facet
291
+ */
292
+ compactOrFacet = "component.compactOrFacet",
293
+ /**
294
+ * A kept field may only change its texts, or loosen its constraints
295
+ */
296
+ notLooser = "component.notLooser"
297
+ }
298
+ /**
299
+ * This type represent a field a new version may not change as the draft does
300
+ */
301
+ export type ComponentVersionViolation = {
302
+ field: string;
303
+ /**
304
+ * One of [[ComponentVersionViolationCodes]]
305
+ */
306
+ code: string;
307
+ message: string;
308
+ };
309
+ /**
310
+ * This type represent a field an upgrade removes or changes while contents hold a value in it
311
+ */
312
+ export type ComponentUpgradeBlockingField = {
313
+ field: string;
314
+ /**
315
+ * How many contents, archived ones and translations included, hold a value in the field
316
+ */
317
+ contents: number;
318
+ /**
319
+ * Up to 20 of their content ids
320
+ */
321
+ examples: number[];
322
+ };
323
+ type ComponentErrorOf<T extends ComponentErrorTypes, D = {}> = {
324
+ type: T;
325
+ message: string;
326
+ } & D;
327
+ /**
328
+ * This type represent the `details` of a `RequestError` whose `type` is one of [[ComponentErrorTypes]].
329
+ * Where present, `fragment` names the definition's fragment at fault
330
+ */
331
+ export type ComponentError = ComponentErrorOf<ComponentErrorTypes.componentNotFound, {
332
+ fragment?: string;
333
+ }> | ComponentErrorOf<ComponentErrorTypes.componentVersionNotFound, {
334
+ fragment?: string;
335
+ }> | ComponentErrorOf<ComponentErrorTypes.failedComponentValidation, {
336
+ /**
337
+ * The draft's violations, as a definition fragment's. A component a field references while
338
+ * unpublished or archived is reported on its `constraints` as `componentNotPublished` or
339
+ * `componentArchived`, with the components at fault as affected attributes
340
+ */
341
+ validation: (SchemaFieldViolationsErrors | AttributeViolation)[];
342
+ }> | ComponentErrorOf<ComponentErrorTypes.componentVersionRefused, {
343
+ violations: ComponentVersionViolation[];
344
+ /**
345
+ * Set by an adoption, naming the fragment it refuses
346
+ */
347
+ fragment?: string;
348
+ }> | ComponentErrorOf<ComponentErrorTypes.nothingToPublish> | ComponentErrorOf<ComponentErrorTypes.mnemonicIdNotUnique, {
349
+ mnemonicId: string;
350
+ /**
351
+ * Set by a promotion: every component mnemonic id already taken, whatever its case. Adopt
352
+ * those components instead
353
+ */
354
+ mnemonicIds?: string[];
355
+ }> | ComponentErrorOf<ComponentErrorTypes.managedFragmentEdited, {
356
+ fragment: string;
357
+ mnemonicId: string;
358
+ version: number;
359
+ }> | ComponentErrorOf<ComponentErrorTypes.componentArchived, {
360
+ fragment: string;
361
+ }> | ComponentErrorOf<ComponentErrorTypes.componentAdoptionRequired, {
362
+ fragment: string;
363
+ }> | ComponentErrorOf<ComponentErrorTypes.componentDowngradeRefused, {
364
+ fragment: string;
365
+ mnemonicId: string;
366
+ from: number;
367
+ to: number;
368
+ }> | ComponentErrorOf<ComponentErrorTypes.componentUpgradeBlocked, {
369
+ fragment: string;
370
+ mnemonicId: string;
371
+ /**
372
+ * Null when the definition's own fragment is adopted
373
+ */
374
+ from: number | null;
375
+ to: number;
376
+ fields: ComponentUpgradeBlockingField[];
377
+ }> | ComponentErrorOf<ComponentErrorTypes.noFragmentToAdopt, {
378
+ fragment: string;
379
+ }> | ComponentErrorOf<ComponentErrorTypes.noFragmentToPromote, {
380
+ fragment: string;
381
+ }>;
382
+ export {};
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ComponentVersionViolationCodes = exports.ComponentErrorTypes = exports.COMPONENT_NAME_PATTERN = void 0;
4
+ /**
5
+ * A component's mnemonicId must match this pattern. It becomes the fragment's name in every definition
6
+ * using the component, so it is unique in the space, case insensitively, and never changes
7
+ */
8
+ exports.COMPONENT_NAME_PATTERN = /^[a-zA-Z0-9_]+$/;
9
+ /**
10
+ * Thin enum represent the error types of the component API requests, and of the content definition
11
+ * ones using components. Each is the `type` of a `RequestError`, whose `details` is a [[ComponentError]]
12
+ */
13
+ var ComponentErrorTypes;
14
+ (function (ComponentErrorTypes) {
15
+ ComponentErrorTypes["componentNotFound"] = "ComponentNotFound";
16
+ ComponentErrorTypes["componentVersionNotFound"] = "ComponentVersionNotFound";
17
+ ComponentErrorTypes["failedComponentValidation"] = "FailedComponentValidation";
18
+ ComponentErrorTypes["componentVersionRefused"] = "ComponentVersionRefused";
19
+ ComponentErrorTypes["nothingToPublish"] = "NothingToPublish";
20
+ ComponentErrorTypes["mnemonicIdNotUnique"] = "MnemonicIdNotUnique";
21
+ ComponentErrorTypes["managedFragmentEdited"] = "ManagedFragmentEdited";
22
+ ComponentErrorTypes["componentArchived"] = "ComponentArchived";
23
+ ComponentErrorTypes["componentAdoptionRequired"] = "ComponentAdoptionRequired";
24
+ ComponentErrorTypes["componentDowngradeRefused"] = "ComponentDowngradeRefused";
25
+ ComponentErrorTypes["componentUpgradeBlocked"] = "ComponentUpgradeBlocked";
26
+ ComponentErrorTypes["noFragmentToAdopt"] = "NoFragmentToAdopt";
27
+ ComponentErrorTypes["noFragmentToPromote"] = "NoFragmentToPromote";
28
+ })(ComponentErrorTypes || (exports.ComponentErrorTypes = ComponentErrorTypes = {}));
29
+ /**
30
+ * Thin enum represent the codes of a [[ComponentVersionViolation]]
31
+ */
32
+ var ComponentVersionViolationCodes;
33
+ (function (ComponentVersionViolationCodes) {
34
+ /**
35
+ * An added field, or one whose type changed, must be optional
36
+ */
37
+ ComponentVersionViolationCodes["requiredField"] = "component.requiredField";
38
+ /**
39
+ * An added field, or one whose type changed, can be neither compact nor a facet
40
+ */
41
+ ComponentVersionViolationCodes["compactOrFacet"] = "component.compactOrFacet";
42
+ /**
43
+ * A kept field may only change its texts, or loosen its constraints
44
+ */
45
+ ComponentVersionViolationCodes["notLooser"] = "component.notLooser";
46
+ })(ComponentVersionViolationCodes || (exports.ComponentVersionViolationCodes = ComponentVersionViolationCodes = {}));
@@ -1,6 +1,7 @@
1
1
  import { AuthorResponse } from './Author';
2
2
  import { PagedListResponse } from './common';
3
- import { ContentDefinitionSchema, Field, I18NDictionary } from './ContentDefinitionSchema';
3
+ import { FieldChanges } from './Component';
4
+ import { ComponentMarker, ContentDefinitionSchema, ContentDefinitionSchemaInput, Field, I18NDictionary } from './ContentDefinitionSchema';
4
5
  import { Extension } from './Extension';
5
6
  /**
6
7
  * This type represent the unique content definition id type
@@ -100,7 +101,7 @@ export type CreateContentDefinitionRequest = {
100
101
  /**
101
102
  * The content definition fields schema
102
103
  */
103
- schema: ContentDefinitionSchema;
104
+ schema: ContentDefinitionSchemaInput;
104
105
  /**
105
106
  * will bypass content definition mnemonicId validation for every linked-content field
106
107
  */
@@ -125,7 +126,7 @@ export type UpdateContentDefinitionRequest = {
125
126
  /**
126
127
  * The content definition fields schema
127
128
  */
128
- schema: ContentDefinitionSchema;
129
+ schema: ContentDefinitionSchemaInput;
129
130
  /**
130
131
  * will bypass content definition mnemonicId validation for every linked-content field
131
132
  */
@@ -175,6 +176,29 @@ export type ContentDefinitionResponse = {
175
176
  * Valued with paths to each array or null if definition is legacy
176
177
  */
177
178
  trackableArrayFields?: ArrayField[] | null;
179
+ /**
180
+ * The components the definition's managed fragments copy, one per component
181
+ */
182
+ components: ComponentMarker[];
183
+ };
184
+ /**
185
+ * This type represent one component a definition uses, as the get content definition API request
186
+ * describes it
187
+ */
188
+ export type DefinitionComponent = ComponentMarker & {
189
+ /**
190
+ * The component latest version
191
+ */
192
+ latestVersion: number;
193
+ /**
194
+ * The archived status of the component
195
+ */
196
+ archived: boolean;
197
+ /**
198
+ * What upgrading from `version` to `latestVersion` would add, remove and change, all empty when up
199
+ * to date. Whether the upgrade would be blocked by the contents is only known by trying it
200
+ */
201
+ changes: FieldChanges;
178
202
  };
179
203
  /**
180
204
  * This type represent the response of a create content definition API request
@@ -187,7 +211,12 @@ export type UpdateContentDefinitionResponse = ContentDefinitionResponse;
187
211
  /**
188
212
  * This type represent the response of a get content definition API request
189
213
  */
190
- export type GetContentDefinitionResponse = ContentDefinitionResponse | undefined;
214
+ export type GetContentDefinitionResponse = (Omit<ContentDefinitionResponse, 'components'> & {
215
+ /**
216
+ * The components the definition uses, each with its latest version and what upgrading to it changes
217
+ */
218
+ components: DefinitionComponent[];
219
+ }) | undefined;
191
220
  /**
192
221
  * This type represent the data needed to make a validate definition field API request
193
222
  */
@@ -389,5 +418,8 @@ export declare enum SchemaFieldViolationCodes {
389
418
  translatableNotAllowed = "translatableNotAllowed",
390
419
  invalidEnumValue = "invalidEnumValue",
391
420
  compactCannotBeNested = "compactCannotBeNested",
392
- variantTypeNotAllowed = "variantTypeNotAllowed"
421
+ variantTypeNotAllowed = "variantTypeNotAllowed",
422
+ componentArchived = "componentArchived",
423
+ componentNotPublished = "componentNotPublished",
424
+ invalidComponentMarker = "invalidComponentMarker"
393
425
  }
@@ -46,4 +46,7 @@ var SchemaFieldViolationCodes;
46
46
  SchemaFieldViolationCodes["invalidEnumValue"] = "invalidEnumValue";
47
47
  SchemaFieldViolationCodes["compactCannotBeNested"] = "compactCannotBeNested";
48
48
  SchemaFieldViolationCodes["variantTypeNotAllowed"] = "variantTypeNotAllowed";
49
+ SchemaFieldViolationCodes["componentArchived"] = "componentArchived";
50
+ SchemaFieldViolationCodes["componentNotPublished"] = "componentNotPublished";
51
+ SchemaFieldViolationCodes["invalidComponentMarker"] = "invalidComponentMarker";
49
52
  })(SchemaFieldViolationCodes || (exports.SchemaFieldViolationCodes = SchemaFieldViolationCodes = {}));
@@ -71,6 +71,43 @@ export type FragmentDefinition = {
71
71
  * The friendly labels of the fragment
72
72
  */
73
73
  labels?: I18NDictionary;
74
+ /**
75
+ * Set on a managed fragment: a copy of a component version, keyed by the component's mnemonic id,
76
+ * that the backend writes and nobody edits by hand. Saving a definition with the marker alone has
77
+ * the backend fill in labels and fields, and saving it with a later `version` upgrades the fragment
78
+ */
79
+ component?: ComponentMarker;
80
+ };
81
+ /**
82
+ * This type represent a content definition schema as the create and update content definition API
83
+ * requests take it, whose managed fragments may leave out their labels and fields
84
+ */
85
+ export type ContentDefinitionSchemaInput = Omit<ContentDefinitionSchema, 'fragments'> & {
86
+ fragments: {
87
+ [name: string]: FragmentDefinition | ManagedFragmentInput;
88
+ };
89
+ };
90
+ /**
91
+ * This type represent a managed fragment as a definition save may send it: labels and fields left out
92
+ * are filled in from the component version, and labels and fields sent must be the version's
93
+ */
94
+ export type ManagedFragmentInput = {
95
+ component: ComponentMarker;
96
+ labels?: I18NDictionary;
97
+ fields?: Field[];
98
+ };
99
+ /**
100
+ * This type represent the marker of a managed fragment, naming the component and the version it copies
101
+ */
102
+ export type ComponentMarker = {
103
+ /**
104
+ * The component mnemonic id, which is also the fragment's key in the schema
105
+ */
106
+ mnemonicId: string;
107
+ /**
108
+ * The component version the fragment copies
109
+ */
110
+ version: number;
74
111
  };
75
112
  /**
76
113
  * This type represent the base model of a schema field
@@ -3,6 +3,7 @@ export * from './AuditLog';
3
3
  export * from './Author';
4
4
  export * from './Channel';
5
5
  export * from './Content';
6
+ export * from './Component';
6
7
  export * from './ContentDefinition';
7
8
  export * from './ContentDefinitionSchema';
8
9
  export * from './ContentExportImport';
package/dist/api/index.js CHANGED
@@ -19,6 +19,7 @@ __exportStar(require("./AuditLog"), exports);
19
19
  __exportStar(require("./Author"), exports);
20
20
  __exportStar(require("./Channel"), exports);
21
21
  __exportStar(require("./Content"), exports);
22
+ __exportStar(require("./Component"), exports);
22
23
  __exportStar(require("./ContentDefinition"), exports);
23
24
  __exportStar(require("./ContentDefinitionSchema"), exports);
24
25
  __exportStar(require("./ContentExportImport"), exports);
@@ -0,0 +1,401 @@
1
+ import { AuthorResponse } from './Author';
2
+ import { PagedListResponse } from './common';
3
+ import {
4
+ AttributeViolation,
5
+ ContentDefinitionId,
6
+ GetContentDefinitionResponse,
7
+ SchemaFieldViolationsErrors
8
+ } from './ContentDefinition';
9
+ import { FragmentDefinition } from './ContentDefinitionSchema';
10
+
11
+ /**
12
+ * The component unique id
13
+ */
14
+ export type ComponentId = number;
15
+
16
+ /**
17
+ * A component's mnemonicId must match this pattern. It becomes the fragment's name in every definition
18
+ * using the component, so it is unique in the space, case insensitively, and never changes
19
+ */
20
+ export const COMPONENT_NAME_PATTERN = /^[a-zA-Z0-9_]+$/;
21
+
22
+ /**
23
+ * This type represent the fragment a component defines: its fields and optionally its labels, nothing
24
+ * else. Its labels, hints, placeholders and list value labels need at least one locale, any locale
25
+ */
26
+ export type ComponentFragment = Omit<FragmentDefinition, 'component'>;
27
+
28
+ /**
29
+ * This type represent field names, by what happened to them between two versions of a fragment.
30
+ * A field whose type changed is `changed`
31
+ */
32
+ export type FieldChanges = {
33
+ added: string[];
34
+ removed: string[];
35
+ changed: string[];
36
+ };
37
+
38
+ /**
39
+ * This type represent the author of a component, or of one of its versions
40
+ */
41
+ export type ComponentAuthor = Pick<AuthorResponse, 'authorId' | 'fullName'>;
42
+
43
+ /**
44
+ * This type represent a published version of a component, which never changes
45
+ */
46
+ export type ComponentVersion = ComponentFragment & {
47
+ /**
48
+ * The version number, from 1
49
+ */
50
+ version: number;
51
+ /**
52
+ * The changes from the version before. Version 1 lists every field as added
53
+ */
54
+ changes: FieldChanges;
55
+ /**
56
+ * The note given when publishing
57
+ */
58
+ note?: string;
59
+ publishedBy: ComponentAuthor;
60
+ publishedDate: Date;
61
+ };
62
+
63
+ /**
64
+ * This type represent a version of a component without its fragment
65
+ */
66
+ export type ComponentVersionSummary = Omit<ComponentVersion, 'labels' | 'fields'>;
67
+
68
+ /**
69
+ * This type represent a definition using a component
70
+ */
71
+ export type ComponentUsedBy = {
72
+ definitionId: ContentDefinitionId;
73
+ definitionMnemonicId: string;
74
+ definitionName: string;
75
+ /**
76
+ * The component version the definition copies
77
+ */
78
+ version: number;
79
+ };
80
+
81
+ /**
82
+ * This type represent a component as the list components API request answers it
83
+ *
84
+ * A component is a fragment a space defines once, for any of its definitions to use. Publishing its
85
+ * draft makes its next version, and a definition moves to a newer version only when it is upgraded
86
+ */
87
+ export type ComponentSummary = {
88
+ id: ComponentId;
89
+ /**
90
+ * The component mnemonic id, matching [[COMPONENT_NAME_PATTERN]]
91
+ */
92
+ mnemonicId: string;
93
+ name: string;
94
+ /**
95
+ * An archived component keeps working in the definitions using it, and cannot be added to another
96
+ * definition or component
97
+ */
98
+ archived: boolean;
99
+ /**
100
+ * The latest version, null until the first publish
101
+ */
102
+ latestVersion: number | null;
103
+ /**
104
+ * Whether the draft differs from the latest version, true before the first publish
105
+ */
106
+ draftChanged: boolean;
107
+ /**
108
+ * How many definitions use the component, and how many of those are on an older version
109
+ */
110
+ usage: { definitions: number; behind: number };
111
+ };
112
+
113
+ /**
114
+ * This type represent the model of a component, as every component API request but list answers it
115
+ */
116
+ export type ComponentResponse = ComponentSummary & {
117
+ archivedDate: Date | null;
118
+ /**
119
+ * The fragment being edited
120
+ */
121
+ draft: ComponentFragment;
122
+ /**
123
+ * The version asked for, the latest by default, null before the first publish
124
+ */
125
+ version: ComponentVersion | null;
126
+ /**
127
+ * Every version, newest first
128
+ */
129
+ versions: ComponentVersionSummary[];
130
+ usedBy: ComponentUsedBy[];
131
+ createdDate: Date;
132
+ lastModifiedDate: Date;
133
+ author: ComponentAuthor;
134
+ latestContributor: ComponentAuthor;
135
+ };
136
+
137
+ /**
138
+ * This type represent all possible filters used to retrieve a list of components
139
+ */
140
+ export type ListComponentsFilters = {
141
+ /**
142
+ * Matches the name or the mnemonic id, case insensitively, anywhere in it. At most 100 characters
143
+ */
144
+ name?: string;
145
+ /**
146
+ * Left out, the list holds both archived and not archived components
147
+ */
148
+ archived?: boolean;
149
+ };
150
+
151
+ /**
152
+ * This type represent the data needed to make a list components API request
153
+ */
154
+ export type ListComponentsRequest = {
155
+ /**
156
+ * The number of components to skip, 0 by default
157
+ */
158
+ skip?: number;
159
+ /**
160
+ * The number of components to take, 10 by default and at most 100
161
+ */
162
+ take?: number;
163
+ filters?: ListComponentsFilters;
164
+ };
165
+
166
+ /**
167
+ * This type represent the response of a list components API request
168
+ */
169
+ export type ListComponentsResponse = PagedListResponse<ComponentSummary>;
170
+
171
+ /**
172
+ * This type represent the data needed to make a get component API request, by id or by mnemonic id
173
+ */
174
+ export type GetComponentRequest = ({ id: ComponentId } | { mnemonicId: string }) & {
175
+ /**
176
+ * The version to answer with, the latest by default
177
+ */
178
+ version?: number;
179
+ };
180
+
181
+ /**
182
+ * This type represent the response of a get component API request
183
+ */
184
+ export type GetComponentResponse = ComponentResponse;
185
+
186
+ /**
187
+ * This type represent the data needed to make a create component API request
188
+ */
189
+ export type CreateComponentRequest = {
190
+ /**
191
+ * The component mnemonic id, matching [[COMPONENT_NAME_PATTERN]]
192
+ */
193
+ mnemonicId: string;
194
+ name: string;
195
+ draft: ComponentFragment;
196
+ };
197
+
198
+ /**
199
+ * This type represent the response of a create component API request, with no version yet
200
+ */
201
+ export type CreateComponentResponse = ComponentResponse;
202
+
203
+ /**
204
+ * This type represent the data needed to make an update component API request. The name and the whole
205
+ * draft are replaced, and the last save wins
206
+ */
207
+ export type UpdateComponentRequest = {
208
+ id: ComponentId;
209
+ name: string;
210
+ draft: ComponentFragment;
211
+ };
212
+
213
+ /**
214
+ * This type represent the response of an update component API request
215
+ */
216
+ export type UpdateComponentResponse = ComponentResponse;
217
+
218
+ /**
219
+ * This type represent the data needed to make a publish component API request
220
+ */
221
+ export type PublishComponentRequest = {
222
+ id: ComponentId;
223
+ /**
224
+ * A note on the version, at most 2000 characters
225
+ */
226
+ note?: string;
227
+ };
228
+
229
+ /**
230
+ * This type represent the response of a publish component API request, its `version` the one just
231
+ * published
232
+ */
233
+ export type PublishComponentResponse = ComponentResponse;
234
+
235
+ /**
236
+ * This type represent the data needed to make a toggle archived component API request
237
+ */
238
+ export type ToggleArchivedComponentRequest = {
239
+ id: ComponentId;
240
+ archived: boolean;
241
+ };
242
+
243
+ /**
244
+ * This type represent the response of a toggle archived component API request
245
+ */
246
+ export type ToggleArchivedComponentResponse = ComponentResponse;
247
+
248
+ /**
249
+ * This type represent the data needed to make an adopt component API request: the definition's own
250
+ * fragment named `mnemonicId` becomes the managed fragment of that component version
251
+ */
252
+ export type AdoptComponentRequest = {
253
+ definitionId: ContentDefinitionId;
254
+ mnemonicId: string;
255
+ version: number;
256
+ };
257
+
258
+ /**
259
+ * This type represent the response of an adopt component API request: the definition, as the get
260
+ * content definition API request answers it
261
+ */
262
+ export type AdoptComponentResponse = NonNullable<GetContentDefinitionResponse>;
263
+
264
+ /**
265
+ * This type represent the data needed to make a promote component API request: the definition's own
266
+ * fragment becomes version 1 of a new component, whose mnemonic id is the fragment's name
267
+ */
268
+ export type PromoteComponentRequest = {
269
+ definitionId: ContentDefinitionId;
270
+ fragment: string;
271
+ /**
272
+ * The component name, the fragment's name by default
273
+ */
274
+ name?: string;
275
+ };
276
+
277
+ /**
278
+ * This type represent the response of a promote component API request
279
+ */
280
+ export type PromoteComponentResponse = {
281
+ component: ComponentResponse;
282
+ /**
283
+ * The definition, as the get content definition API request answers it
284
+ */
285
+ definition: NonNullable<GetContentDefinitionResponse>;
286
+ };
287
+
288
+ /**
289
+ * Thin enum represent the error types of the component API requests, and of the content definition
290
+ * ones using components. Each is the `type` of a `RequestError`, whose `details` is a [[ComponentError]]
291
+ */
292
+ export enum ComponentErrorTypes {
293
+ componentNotFound = 'ComponentNotFound',
294
+ componentVersionNotFound = 'ComponentVersionNotFound',
295
+ failedComponentValidation = 'FailedComponentValidation',
296
+ componentVersionRefused = 'ComponentVersionRefused',
297
+ nothingToPublish = 'NothingToPublish',
298
+ mnemonicIdNotUnique = 'MnemonicIdNotUnique',
299
+ managedFragmentEdited = 'ManagedFragmentEdited',
300
+ componentArchived = 'ComponentArchived',
301
+ componentAdoptionRequired = 'ComponentAdoptionRequired',
302
+ componentDowngradeRefused = 'ComponentDowngradeRefused',
303
+ componentUpgradeBlocked = 'ComponentUpgradeBlocked',
304
+ noFragmentToAdopt = 'NoFragmentToAdopt',
305
+ noFragmentToPromote = 'NoFragmentToPromote'
306
+ }
307
+
308
+ /**
309
+ * Thin enum represent the codes of a [[ComponentVersionViolation]]
310
+ */
311
+ export enum ComponentVersionViolationCodes {
312
+ /**
313
+ * An added field, or one whose type changed, must be optional
314
+ */
315
+ requiredField = 'component.requiredField',
316
+ /**
317
+ * An added field, or one whose type changed, can be neither compact nor a facet
318
+ */
319
+ compactOrFacet = 'component.compactOrFacet',
320
+ /**
321
+ * A kept field may only change its texts, or loosen its constraints
322
+ */
323
+ notLooser = 'component.notLooser'
324
+ }
325
+
326
+ /**
327
+ * This type represent a field a new version may not change as the draft does
328
+ */
329
+ export type ComponentVersionViolation = {
330
+ field: string;
331
+ /**
332
+ * One of [[ComponentVersionViolationCodes]]
333
+ */
334
+ code: string;
335
+ message: string;
336
+ };
337
+
338
+ /**
339
+ * This type represent a field an upgrade removes or changes while contents hold a value in it
340
+ */
341
+ export type ComponentUpgradeBlockingField = {
342
+ field: string;
343
+ /**
344
+ * How many contents, archived ones and translations included, hold a value in the field
345
+ */
346
+ contents: number;
347
+ /**
348
+ * Up to 20 of their content ids
349
+ */
350
+ examples: number[];
351
+ };
352
+
353
+ type ComponentErrorOf<T extends ComponentErrorTypes, D = {}> = { type: T; message: string } & D;
354
+
355
+ /**
356
+ * This type represent the `details` of a `RequestError` whose `type` is one of [[ComponentErrorTypes]].
357
+ * Where present, `fragment` names the definition's fragment at fault
358
+ */
359
+ export type ComponentError =
360
+ | ComponentErrorOf<ComponentErrorTypes.componentNotFound, { fragment?: string }>
361
+ | ComponentErrorOf<ComponentErrorTypes.componentVersionNotFound, { fragment?: string }>
362
+ | ComponentErrorOf<ComponentErrorTypes.failedComponentValidation, {
363
+ /**
364
+ * The draft's violations, as a definition fragment's. A component a field references while
365
+ * unpublished or archived is reported on its `constraints` as `componentNotPublished` or
366
+ * `componentArchived`, with the components at fault as affected attributes
367
+ */
368
+ validation: (SchemaFieldViolationsErrors | AttributeViolation)[];
369
+ }>
370
+ | ComponentErrorOf<ComponentErrorTypes.componentVersionRefused, {
371
+ violations: ComponentVersionViolation[];
372
+ /**
373
+ * Set by an adoption, naming the fragment it refuses
374
+ */
375
+ fragment?: string;
376
+ }>
377
+ | ComponentErrorOf<ComponentErrorTypes.nothingToPublish>
378
+ | ComponentErrorOf<ComponentErrorTypes.mnemonicIdNotUnique, {
379
+ mnemonicId: string;
380
+ /**
381
+ * Set by a promotion: every component mnemonic id already taken, whatever its case. Adopt
382
+ * those components instead
383
+ */
384
+ mnemonicIds?: string[];
385
+ }>
386
+ | ComponentErrorOf<ComponentErrorTypes.managedFragmentEdited, { fragment: string; mnemonicId: string; version: number }>
387
+ | ComponentErrorOf<ComponentErrorTypes.componentArchived, { fragment: string }>
388
+ | ComponentErrorOf<ComponentErrorTypes.componentAdoptionRequired, { fragment: string }>
389
+ | ComponentErrorOf<ComponentErrorTypes.componentDowngradeRefused, { fragment: string; mnemonicId: string; from: number; to: number }>
390
+ | ComponentErrorOf<ComponentErrorTypes.componentUpgradeBlocked, {
391
+ fragment: string;
392
+ mnemonicId: string;
393
+ /**
394
+ * Null when the definition's own fragment is adopted
395
+ */
396
+ from: number | null;
397
+ to: number;
398
+ fields: ComponentUpgradeBlockingField[];
399
+ }>
400
+ | ComponentErrorOf<ComponentErrorTypes.noFragmentToAdopt, { fragment: string }>
401
+ | ComponentErrorOf<ComponentErrorTypes.noFragmentToPromote, { fragment: string }>;
@@ -1,6 +1,7 @@
1
1
  import { AuthorResponse } from './Author';
2
2
  import { PagedListResponse } from './common';
3
- import { ContentDefinitionSchema, Field, I18NDictionary } from './ContentDefinitionSchema';
3
+ import { FieldChanges } from './Component';
4
+ import { ComponentMarker, ContentDefinitionSchema, ContentDefinitionSchemaInput, Field, I18NDictionary } from './ContentDefinitionSchema';
4
5
  import { Extension } from './Extension';
5
6
 
6
7
  /**
@@ -108,7 +109,7 @@ export type CreateContentDefinitionRequest = {
108
109
  /**
109
110
  * The content definition fields schema
110
111
  */
111
- schema: ContentDefinitionSchema;
112
+ schema: ContentDefinitionSchemaInput;
112
113
 
113
114
  /**
114
115
  * will bypass content definition mnemonicId validation for every linked-content field
@@ -135,7 +136,7 @@ export type UpdateContentDefinitionRequest = {
135
136
  /**
136
137
  * The content definition fields schema
137
138
  */
138
- schema: ContentDefinitionSchema;
139
+ schema: ContentDefinitionSchemaInput;
139
140
 
140
141
  /**
141
142
  * will bypass content definition mnemonicId validation for every linked-content field
@@ -189,6 +190,31 @@ export type ContentDefinitionResponse = {
189
190
  * Valued with paths to each array or null if definition is legacy
190
191
  */
191
192
  trackableArrayFields?: ArrayField[] | null;
193
+
194
+ /**
195
+ * The components the definition's managed fragments copy, one per component
196
+ */
197
+ components: ComponentMarker[];
198
+ };
199
+
200
+ /**
201
+ * This type represent one component a definition uses, as the get content definition API request
202
+ * describes it
203
+ */
204
+ export type DefinitionComponent = ComponentMarker & {
205
+ /**
206
+ * The component latest version
207
+ */
208
+ latestVersion: number;
209
+ /**
210
+ * The archived status of the component
211
+ */
212
+ archived: boolean;
213
+ /**
214
+ * What upgrading from `version` to `latestVersion` would add, remove and change, all empty when up
215
+ * to date. Whether the upgrade would be blocked by the contents is only known by trying it
216
+ */
217
+ changes: FieldChanges;
192
218
  };
193
219
 
194
220
  /**
@@ -202,7 +228,12 @@ export type UpdateContentDefinitionResponse = ContentDefinitionResponse;
202
228
  /**
203
229
  * This type represent the response of a get content definition API request
204
230
  */
205
- export type GetContentDefinitionResponse = ContentDefinitionResponse | undefined;
231
+ export type GetContentDefinitionResponse = (Omit<ContentDefinitionResponse, 'components'> & {
232
+ /**
233
+ * The components the definition uses, each with its latest version and what upgrading to it changes
234
+ */
235
+ components: DefinitionComponent[];
236
+ }) | undefined;
206
237
 
207
238
  /**
208
239
  * This type represent the data needed to make a validate definition field API request
@@ -416,5 +447,8 @@ export enum SchemaFieldViolationCodes {
416
447
  translatableNotAllowed = 'translatableNotAllowed',
417
448
  invalidEnumValue = 'invalidEnumValue',
418
449
  compactCannotBeNested = 'compactCannotBeNested',
419
- variantTypeNotAllowed = 'variantTypeNotAllowed'
450
+ variantTypeNotAllowed = 'variantTypeNotAllowed',
451
+ componentArchived = 'componentArchived',
452
+ componentNotPublished = 'componentNotPublished',
453
+ invalidComponentMarker = 'invalidComponentMarker'
420
454
  }
@@ -76,6 +76,46 @@ export type FragmentDefinition = {
76
76
  * The friendly labels of the fragment
77
77
  */
78
78
  labels?: I18NDictionary;
79
+ /**
80
+ * Set on a managed fragment: a copy of a component version, keyed by the component's mnemonic id,
81
+ * that the backend writes and nobody edits by hand. Saving a definition with the marker alone has
82
+ * the backend fill in labels and fields, and saving it with a later `version` upgrades the fragment
83
+ */
84
+ component?: ComponentMarker;
85
+ };
86
+
87
+ /**
88
+ * This type represent a content definition schema as the create and update content definition API
89
+ * requests take it, whose managed fragments may leave out their labels and fields
90
+ */
91
+ export type ContentDefinitionSchemaInput = Omit<ContentDefinitionSchema, 'fragments'> & {
92
+ fragments: {
93
+ [name: string]: FragmentDefinition | ManagedFragmentInput;
94
+ };
95
+ };
96
+
97
+ /**
98
+ * This type represent a managed fragment as a definition save may send it: labels and fields left out
99
+ * are filled in from the component version, and labels and fields sent must be the version's
100
+ */
101
+ export type ManagedFragmentInput = {
102
+ component: ComponentMarker;
103
+ labels?: I18NDictionary;
104
+ fields?: Field[];
105
+ };
106
+
107
+ /**
108
+ * This type represent the marker of a managed fragment, naming the component and the version it copies
109
+ */
110
+ export type ComponentMarker = {
111
+ /**
112
+ * The component mnemonic id, which is also the fragment's key in the schema
113
+ */
114
+ mnemonicId: string;
115
+ /**
116
+ * The component version the fragment copies
117
+ */
118
+ version: number;
79
119
  };
80
120
 
81
121
  /**
package/lib/api/index.ts CHANGED
@@ -3,6 +3,7 @@ export * from './AuditLog';
3
3
  export * from './Author';
4
4
  export * from './Channel';
5
5
  export * from './Content';
6
+ export * from './Component';
6
7
  export * from './ContentDefinition';
7
8
  export * from './ContentDefinitionSchema';
8
9
  export * from './ContentExportImport';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentchef/contentchef-types",
3
- "version": "11.0.0",
3
+ "version": "11.1.0-alpha.0",
4
4
  "description": "ContentChef types",
5
5
  "author": "PierpaoloIannone <piannone@byte-code.com>",
6
6
  "homepage": "https://github.com/ContentChef/contentchef-management-js-client#readme",
@@ -34,5 +34,5 @@
34
34
  "devDependencies": {
35
35
  "typescript": "^5.9.3"
36
36
  },
37
- "gitHead": "4590d085381430e5b56e98a2dabdf03911d05e3e"
37
+ "gitHead": "06b0724c9e74c0e2975a4af2917924010858759d"
38
38
  }