@nascentdigital/funnel-cms 4.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/api/AssetClient.d.ts +53 -0
  2. package/dist/api/AssetClient.js +2 -0
  3. package/dist/api/AssetUploadClient.d.ts +17 -0
  4. package/dist/api/AssetUploadClient.js +26 -0
  5. package/dist/api/AuthClient.d.ts +29 -0
  6. package/dist/api/AuthClient.js +2 -0
  7. package/dist/api/ChangeSetClient.d.ts +84 -0
  8. package/dist/api/ChangeSetClient.js +31 -0
  9. package/dist/api/CollectionClient.d.ts +187 -0
  10. package/dist/api/CollectionClient.js +2 -0
  11. package/dist/api/ContentClient.d.ts +43 -0
  12. package/dist/api/ContentClient.js +34 -0
  13. package/dist/api/IAssetApiClient.d.ts +9 -0
  14. package/dist/api/IAssetApiClient.js +2 -0
  15. package/dist/api/PageClient.d.ts +264 -0
  16. package/dist/api/PageClient.js +2 -0
  17. package/dist/api/SiteClient.d.ts +23 -0
  18. package/dist/api/SiteClient.js +2 -0
  19. package/dist/api/SiteConfigClient.d.ts +26 -0
  20. package/dist/api/SiteConfigClient.js +2 -0
  21. package/dist/api/UpgradeClient.d.ts +16 -0
  22. package/dist/api/UpgradeClient.js +2 -0
  23. package/dist/api/UserClient.d.ts +46 -0
  24. package/dist/api/UserClient.js +2 -0
  25. package/dist/api/index.d.ts +11 -0
  26. package/dist/api/index.js +27 -0
  27. package/dist/errors/CMSError.d.ts +8 -0
  28. package/dist/errors/CMSError.js +17 -0
  29. package/dist/errors/CMSErrors.d.ts +5 -0
  30. package/dist/errors/CMSErrors.js +36 -0
  31. package/dist/errors/LinkedDependantsError.d.ts +21 -0
  32. package/dist/errors/LinkedDependantsError.js +31 -0
  33. package/dist/errors/LockdownError.d.ts +4 -0
  34. package/dist/errors/LockdownError.js +12 -0
  35. package/dist/errors/SlugValidationError.d.ts +21 -0
  36. package/dist/errors/SlugValidationError.js +23 -0
  37. package/dist/errors/TranslateReferencesError.d.ts +21 -0
  38. package/dist/errors/TranslateReferencesError.js +22 -0
  39. package/dist/errors/index.d.ts +4 -0
  40. package/dist/errors/index.js +25 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.js +19 -0
  43. package/dist/models/Entity.d.ts +14 -0
  44. package/dist/models/Entity.js +2 -0
  45. package/dist/models/Environment.d.ts +1 -0
  46. package/dist/models/Environment.js +2 -0
  47. package/dist/models/Pagination.d.ts +20 -0
  48. package/dist/models/Pagination.js +21 -0
  49. package/dist/models/Privilege.d.ts +57 -0
  50. package/dist/models/Privilege.js +163 -0
  51. package/dist/models/Role.d.ts +33 -0
  52. package/dist/models/Role.js +118 -0
  53. package/dist/models/SiteConfig.d.ts +14 -0
  54. package/dist/models/SiteConfig.js +2 -0
  55. package/dist/models/Upgrade.d.ts +40 -0
  56. package/dist/models/Upgrade.js +19 -0
  57. package/dist/models/User.d.ts +41 -0
  58. package/dist/models/User.js +71 -0
  59. package/dist/models/Versioned.d.ts +22 -0
  60. package/dist/models/Versioned.js +45 -0
  61. package/dist/models/index.d.ts +9 -0
  62. package/dist/models/index.js +25 -0
  63. package/dist/strapi/IStrapiContentClient.d.ts +39 -0
  64. package/dist/strapi/IStrapiContentClient.js +2 -0
  65. package/dist/strapi/Strapi.d.ts +37 -0
  66. package/dist/strapi/Strapi.js +156 -0
  67. package/dist/strapi/StrapiAssetClient.d.ts +11 -0
  68. package/dist/strapi/StrapiAssetClient.js +143 -0
  69. package/dist/strapi/StrapiAssetUploadClient.d.ts +6 -0
  70. package/dist/strapi/StrapiAssetUploadClient.js +109 -0
  71. package/dist/strapi/StrapiAuthClient.d.ts +9 -0
  72. package/dist/strapi/StrapiAuthClient.js +64 -0
  73. package/dist/strapi/StrapiChangeSetClient.d.ts +22 -0
  74. package/dist/strapi/StrapiChangeSetClient.js +218 -0
  75. package/dist/strapi/StrapiCollectionClient.d.ts +18 -0
  76. package/dist/strapi/StrapiCollectionClient.js +610 -0
  77. package/dist/strapi/StrapiContentClient.d.ts +38 -0
  78. package/dist/strapi/StrapiContentClient.js +105 -0
  79. package/dist/strapi/StrapiContentClientFactory.d.ts +13 -0
  80. package/dist/strapi/StrapiContentClientFactory.js +19 -0
  81. package/dist/strapi/StrapiPageClient.d.ts +23 -0
  82. package/dist/strapi/StrapiPageClient.js +882 -0
  83. package/dist/strapi/StrapiSiteConfigClient.d.ts +8 -0
  84. package/dist/strapi/StrapiSiteConfigClient.js +50 -0
  85. package/dist/strapi/StrapiUpgradeClient.d.ts +13 -0
  86. package/dist/strapi/StrapiUpgradeClient.js +118 -0
  87. package/dist/strapi/StrapiUserClient.d.ts +17 -0
  88. package/dist/strapi/StrapiUserClient.js +199 -0
  89. package/dist/strapi/client.d.ts +1 -0
  90. package/dist/strapi/client.js +17 -0
  91. package/dist/strapi/index.d.ts +3 -0
  92. package/dist/strapi/index.js +19 -0
  93. package/dist/strapi/models/StrapiAsset.d.ts +10 -0
  94. package/dist/strapi/models/StrapiAsset.js +16 -0
  95. package/dist/strapi/models/StrapiData.d.ts +13 -0
  96. package/dist/strapi/models/StrapiData.js +16 -0
  97. package/dist/strapi/models/StrapiFile.d.ts +18 -0
  98. package/dist/strapi/models/StrapiFile.js +2 -0
  99. package/dist/strapi/models/index.d.ts +3 -0
  100. package/dist/strapi/models/index.js +19 -0
  101. package/dist/strapi/serialization/ChangeSetData.d.ts +15 -0
  102. package/dist/strapi/serialization/ChangeSetData.js +76 -0
  103. package/dist/strapi/serialization/CollectionData.d.ts +57 -0
  104. package/dist/strapi/serialization/CollectionData.js +258 -0
  105. package/dist/strapi/serialization/CollectionSnapshotData.d.ts +16 -0
  106. package/dist/strapi/serialization/CollectionSnapshotData.js +66 -0
  107. package/dist/strapi/serialization/PageData.d.ts +126 -0
  108. package/dist/strapi/serialization/PageData.js +335 -0
  109. package/dist/strapi/serialization/PageSnapshotData.d.ts +20 -0
  110. package/dist/strapi/serialization/PageSnapshotData.js +69 -0
  111. package/dist/strapi/serialization/RoleData.d.ts +5 -0
  112. package/dist/strapi/serialization/RoleData.js +2 -0
  113. package/dist/strapi/serialization/SiteConfigData.d.ts +11 -0
  114. package/dist/strapi/serialization/SiteConfigData.js +23 -0
  115. package/dist/strapi/serialization/StrapiAssetData.d.ts +17 -0
  116. package/dist/strapi/serialization/StrapiAssetData.js +39 -0
  117. package/dist/strapi/serialization/UserData.d.ts +18 -0
  118. package/dist/strapi/serialization/UserData.js +42 -0
  119. package/dist/strapi/serialization/VersionData.d.ts +26 -0
  120. package/dist/strapi/serialization/VersionData.js +88 -0
  121. package/dist/strapi/serialization/index.d.ts +10 -0
  122. package/dist/strapi/serialization/index.js +26 -0
  123. package/dist/strapi/test.d.ts +563 -0
  124. package/dist/strapi/test.js +1131 -0
  125. package/package.json +42 -0
@@ -0,0 +1,610 @@
1
+ "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.StrapiCollectionClient = void 0;
15
+ const funnel_core_1 = require("@nascentdigital/funnel-core");
16
+ const errors_1 = require("../errors");
17
+ const serialization_1 = require("./serialization");
18
+ const Strapi_1 = require("./Strapi");
19
+ // class
20
+ class StrapiCollectionClient {
21
+ constructor(provider) {
22
+ this.provider = provider;
23
+ }
24
+ getOverview({ brand, version }) {
25
+ return this.provider.customRequest({
26
+ command: 'query/collections',
27
+ params: { brand, preview: version === 'draft' ? 'true' : 'false' }
28
+ });
29
+ }
30
+ async getItems({ brand, type, language, tags, version }) {
31
+ // create params (add tags if any)
32
+ const params = {
33
+ brand,
34
+ type,
35
+ language,
36
+ preview: version === 'draft' ? 'true' : 'false'
37
+ };
38
+ if (tags && tags.length > 0) {
39
+ params.tags = tags.join(',');
40
+ }
41
+ const itemsData = await this.provider.customRequest({
42
+ command: 'query/collection',
43
+ params
44
+ });
45
+ // convert refs and return
46
+ return itemsData.map((_a) => {
47
+ var { refs } = _a, itemData = __rest(_a, ["refs"]);
48
+ return (Object.assign(Object.assign({}, itemData), { refs: Object.values(refs).reduce((refs, ref) => {
49
+ // map ref
50
+ refs[ref.lang] = serialization_1.CollectionData.deserializeRef(ref);
51
+ // keep reducing
52
+ return refs;
53
+ }, {}) }));
54
+ });
55
+ }
56
+ async find(_a) {
57
+ var { pagination } = _a, args = __rest(_a, ["pagination"]);
58
+ // fetch all pages that match (as link data)
59
+ const client = this.provider.client;
60
+ const strapiUrl = client.baseURL;
61
+ const collection = client.collection('collections');
62
+ const resultProps = funnel_core_1.Schema.Collection.Data.Props.all;
63
+ const _b = await Strapi_1.Strapi.paginate(Object.assign({ collection,
64
+ pagination, fields: serialization_1.CollectionData.getStrapiFilter(resultProps), sort: args.version === 'published'
65
+ ? ['publishedOn:desc', 'updatedAt:desc']
66
+ : ['updatedAt:desc'], populate: serialization_1.CollectionData.populate }, getCollectionQueryParams(args))), { items } = _b, paginated = __rest(_b, ["items"]);
67
+ // transform to DTOs
68
+ return Object.assign({ items: items.map(item => serialization_1.CollectionData.deserialize(item, strapiUrl, resultProps)) }, paginated);
69
+ }
70
+ async getGroup({ version, type, brand, groupId, language }) {
71
+ var _a, _b;
72
+ // fetch all collection items in group
73
+ const client = this.provider.client;
74
+ const collection = client.collection('collections');
75
+ const { items = [] } = await Strapi_1.Strapi.paginate(Object.assign({ collection, pagination: 'all', fields: serialization_1.CollectionData.getStrapiFilter(funnel_core_1.Schema.Collection.Data.Props.id) }, getCollectionQueryParams({ version, brand, groupId })));
76
+ // return nothing if there are no instances
77
+ if (items.length === 0) {
78
+ return undefined;
79
+ }
80
+ // create group
81
+ const schema = funnel_core_1.Schema.Site.getCollection(type);
82
+ const instances = items.map(serialization_1.CollectionData.deserializeRef);
83
+ const result = {
84
+ group: {
85
+ type,
86
+ brand,
87
+ groupId,
88
+ name: (_b = (_a = funnel_core_1.ArrayUtils.first(items)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : schema.name,
89
+ instances
90
+ }
91
+ };
92
+ // add language if it exists as an instance
93
+ const target = instances.find(item => item.language === language);
94
+ if (target) {
95
+ // get collection
96
+ result.collection = await this.get({ version, id: target.id });
97
+ // sync name if collection was found
98
+ if (result.collection) {
99
+ result.group.name = result.collection.name;
100
+ }
101
+ }
102
+ // return result
103
+ return result;
104
+ }
105
+ async get({ version, id }) {
106
+ // get data
107
+ const client = this.provider.client;
108
+ const resultProps = funnel_core_1.Schema.Collection.Data.Props.all;
109
+ const { data } = await client.collection('collections').findOne(id, {
110
+ fields: serialization_1.CollectionData.getStrapiFilter(resultProps),
111
+ status: version,
112
+ populate: serialization_1.CollectionData.populate
113
+ });
114
+ // deserialize and return
115
+ return data
116
+ ? serialization_1.CollectionData.deserialize(data, client.baseURL, resultProps)
117
+ : undefined;
118
+ }
119
+ async create(args) {
120
+ // resolve current user (or throw)
121
+ const { client, users } = this.provider;
122
+ const strapiUrl = client.baseURL;
123
+ const user = await users.me();
124
+ if (!user) {
125
+ throw new funnel_core_1.NotAuthenticatedError();
126
+ }
127
+ // create a new language of an existing collection
128
+ if (funnel_core_1.Schema.Collection.Data.AsNewLanguage.filter(args)) {
129
+ // fetch all collections in group
130
+ const groupResult = await this.getGroup({
131
+ version: 'draft',
132
+ type: args.type,
133
+ groupId: args.groupId,
134
+ language: args.language
135
+ });
136
+ // throw if the group doesn't exist
137
+ if (groupResult === undefined) {
138
+ throw new funnel_core_1.ArgumentError(`Collection group "${args.groupId}" no longer exists in "${args.brand}"`);
139
+ }
140
+ // extract group and existing collection from result
141
+ const { group, collection: existingCollection } = groupResult;
142
+ // return existing collection if it's there
143
+ if (existingCollection) {
144
+ return {
145
+ group,
146
+ collection: existingCollection
147
+ };
148
+ }
149
+ // bind data + update url
150
+ const draft = funnel_core_1.Schema.CollectionModel.fromDraft(Object.assign(Object.assign({}, args), { type: group.type, name: group.name, tags: [] }));
151
+ draft.sync();
152
+ // resolve change set (rebind)
153
+ const { provider } = this;
154
+ const changeSet = await provider.changeSets.resolve();
155
+ // create collection
156
+ try {
157
+ // connect collection to changeset
158
+ draft.data.changeSetId = changeSet.id;
159
+ // create data model based on existing page
160
+ const { data } = await client.collection('collections')
161
+ .create(serialization_1.CollectionData.serialize(draft.data), {
162
+ status: 'draft',
163
+ populate: serialization_1.CollectionData.populate
164
+ });
165
+ // transform the deserialized entry
166
+ const collection = serialization_1.CollectionData.deserialize(data, strapiUrl, funnel_core_1.Schema.Collection.Data.Props.all);
167
+ // add collection to changeset
168
+ await provider.changeSets.update({
169
+ id: changeSet.id,
170
+ changes: [
171
+ ...changeSet.changes,
172
+ {
173
+ __type: 'collection',
174
+ type: 'create',
175
+ schema: collection.type,
176
+ id: collection.id,
177
+ groupId: collection.groupId,
178
+ name: collection.name,
179
+ language: collection.language,
180
+ errors: collection.errors,
181
+ attribution: [
182
+ { userId: user.id, updatedOn: Date.now() }
183
+ ]
184
+ }
185
+ ]
186
+ });
187
+ // add collection to group
188
+ group.instances.push({
189
+ id: collection.id,
190
+ language: collection.language,
191
+ version: collection.version,
192
+ tags: collection.tags
193
+ });
194
+ // return updated group
195
+ return {
196
+ group,
197
+ collection
198
+ };
199
+ }
200
+ // or remove on failure remove
201
+ catch (e) {
202
+ // discard if it had no changes
203
+ if (changeSet.changes.length === 0) {
204
+ await provider.changeSets.delete(changeSet.id);
205
+ }
206
+ // throw error
207
+ throw funnel_core_1.IsometricErrorUtils.coerceError(e);
208
+ }
209
+ }
210
+ // or create a net new collection
211
+ else {
212
+ // bind data + update url
213
+ const draft = funnel_core_1.Schema.CollectionModel.fromDraft(Object.assign(Object.assign({}, args), { groupId: funnel_core_1.Value.uuid() }));
214
+ draft.sync();
215
+ console.debug('[StrapiCollectionClient/create/new] creating new draft', serialization_1.CollectionData.serialize(draft.data));
216
+ // resolve change set (rebind)
217
+ const { provider } = this;
218
+ const changeSet = await provider.changeSets.resolve();
219
+ // or create it
220
+ try {
221
+ // connect collection to changeset
222
+ draft.data.changeSetId = changeSet.id;
223
+ // create collection
224
+ const { data } = await client.collection('collections')
225
+ .create(serialization_1.CollectionData.serialize(draft.data), {
226
+ status: 'draft',
227
+ populate: serialization_1.CollectionData.populate
228
+ });
229
+ // transform the deserialized entry
230
+ const collection = serialization_1.CollectionData.deserialize(data, strapiUrl, funnel_core_1.Schema.Collection.Data.Props.all);
231
+ // add collection to changeset
232
+ await provider.changeSets.update({
233
+ id: changeSet.id,
234
+ changes: [
235
+ ...changeSet.changes,
236
+ {
237
+ __type: 'collection',
238
+ type: 'create',
239
+ schema: collection.type,
240
+ id: collection.id,
241
+ groupId: collection.groupId,
242
+ name: collection.name,
243
+ language: collection.language,
244
+ errors: collection.errors,
245
+ attribution: [
246
+ { userId: user.id, updatedOn: Date.now() }
247
+ ]
248
+ }
249
+ ]
250
+ });
251
+ // return collection
252
+ return {
253
+ group: {
254
+ groupId: collection.groupId,
255
+ brand: collection.brand,
256
+ type: collection.type,
257
+ name: collection.name,
258
+ instances: [{
259
+ id: collection.id,
260
+ language: collection.language,
261
+ version: collection.version,
262
+ tags: collection.tags
263
+ }]
264
+ },
265
+ collection
266
+ };
267
+ }
268
+ // or remove on failure remove
269
+ catch (e) {
270
+ // discard if it had no changes
271
+ if (changeSet.changes.length === 0) {
272
+ await provider.changeSets.delete(changeSet.id);
273
+ }
274
+ // throw error
275
+ throw funnel_core_1.IsometricErrorUtils.coerceError(e);
276
+ }
277
+ }
278
+ }
279
+ async duplicate({ source: collectionId, targetCollection, targetLanguage }) {
280
+ // resolve current user (or throw)
281
+ const { client, users } = this.provider;
282
+ const strapiUrl = client.baseURL;
283
+ const user = await users.me();
284
+ if (!user) {
285
+ throw new funnel_core_1.NotAuthenticatedError();
286
+ }
287
+ // get collection by id
288
+ const collectionCollection = client.collection('collections');
289
+ const { data: sourceData } = await collectionCollection.findOne(collectionId, {
290
+ fields: serialization_1.CollectionData.getStrapiFilter(funnel_core_1.Schema.Collection.Data.Props.all),
291
+ status: 'draft',
292
+ populate: serialization_1.CollectionData.populate
293
+ });
294
+ const sourceCollection = sourceData;
295
+ // throw if there's no collection
296
+ if (!sourceCollection) {
297
+ throw new funnel_core_1.NotFoundError(`Unable to resolve collection with id "${collectionId}"`);
298
+ }
299
+ // make sure target language doesn't already exist if we are targeting the current group
300
+ if (targetCollection === 'current') {
301
+ const { data: collectionsWithTargetLanguage } = await collectionCollection.find(Object.assign({ fields: ['documentId'] }, getCollectionQueryParams({ version: 'draft', groupId: sourceCollection.groupId, language: targetLanguage })));
302
+ if (collectionsWithTargetLanguage.length > 0) {
303
+ throw new funnel_core_1.InvalidOperationError(`There is already a collection in group "${sourceCollection.groupId}" with ${targetLanguage} language`);
304
+ }
305
+ }
306
+ // get refs from source collection
307
+ const { assetRefs, collectionRefs } = sourceCollection;
308
+ // target refs and body
309
+ let targetCollectionRefIds;
310
+ let targetBody;
311
+ // if we are targeting a different language then we need to "translate" the references
312
+ if (targetLanguage !== sourceCollection.lang) {
313
+ // fetch target language refs
314
+ const { collectionIdMappings } = await Strapi_1.Strapi.translateReferences({
315
+ client,
316
+ targetLanguage,
317
+ collectionRefs
318
+ });
319
+ // set target values
320
+ targetCollectionRefIds = collectionIdMappings.map(mapping => mapping.targetId);
321
+ targetBody = {
322
+ fields: Strapi_1.Strapi.updateRefs({ value: sourceCollection.fields, collectionIdMappings })
323
+ };
324
+ }
325
+ // otherwise we can keep everything the same as the source page
326
+ else {
327
+ // set target values
328
+ targetCollectionRefIds = collectionRefs.map(ref => ref.documentId);
329
+ targetBody = {
330
+ fields: sourceCollection.fields
331
+ };
332
+ }
333
+ // resolve change set (rebind)
334
+ const { provider } = this;
335
+ const changeSet = await provider.changeSets.resolve();
336
+ // create duplicate collection
337
+ try {
338
+ // create target collection using content of source
339
+ const { data: dupData } = await collectionCollection.create(Object.assign({ groupId: targetCollection === 'current'
340
+ ? sourceCollection.groupId
341
+ : funnel_core_1.Value.uuid(), version: 1, type: sourceCollection.type, brand: sourceCollection.brand, lang: targetLanguage, name: sourceCollection.name, tags: sourceCollection.tags, state: 'draft', errors: sourceCollection.errors, assetRefs: { set: assetRefs.map(ref => ref.documentId) }, collectionRefs: { set: targetCollectionRefIds } }, targetBody), { status: 'draft', populate: serialization_1.CollectionData.populate });
342
+ const dupCollectionData = dupData;
343
+ console.debug('[StrapiCollectionClient] duplicate: created duplicate collection', { dupCollectionData });
344
+ // touch new duplicated collection
345
+ let dupCollection = serialization_1.CollectionData.deserialize(dupCollectionData, strapiUrl, funnel_core_1.Schema.Collection.Data.Props.all);
346
+ const dupCollectionModel = funnel_core_1.Schema.CollectionModel.from(dupCollection);
347
+ dupCollectionModel.sync();
348
+ // connect collection to changeset
349
+ dupCollection.changeSetId = changeSet.id;
350
+ // update duplicate collection with updated data from sync
351
+ const update = serialization_1.CollectionData.serialize(dupCollection);
352
+ const { data: updatedData } = await collectionCollection.update(dupCollection.id, update, { status: 'draft' });
353
+ dupCollection = serialization_1.CollectionData.deserialize(updatedData, strapiUrl, funnel_core_1.Schema.Collection.Data.Props.all);
354
+ console.debug('[StrapiCollectionClient] duplicate: touched duplicated collection');
355
+ // add collection to changeset
356
+ await provider.changeSets.update({
357
+ id: changeSet.id,
358
+ changes: [
359
+ ...changeSet.changes,
360
+ {
361
+ __type: 'collection',
362
+ type: 'create',
363
+ schema: dupCollection.type,
364
+ id: dupCollection.id,
365
+ groupId: dupCollection.groupId,
366
+ name: dupCollection.name,
367
+ language: dupCollection.language,
368
+ errors: dupCollection.errors,
369
+ attribution: [
370
+ { userId: user.id, updatedOn: Date.now() }
371
+ ]
372
+ }
373
+ ]
374
+ });
375
+ // return group for duplicated collection
376
+ const group = await this.getGroup({
377
+ brand: dupCollection.brand,
378
+ groupId: dupCollection.groupId,
379
+ type: dupCollection.type,
380
+ language: dupCollection.language,
381
+ version: 'draft'
382
+ });
383
+ // should not happen
384
+ if (!group) {
385
+ throw new funnel_core_1.IllegalStateError(`cannot find group that was just created`);
386
+ }
387
+ // return
388
+ return group;
389
+ }
390
+ // handle errors
391
+ catch (e) {
392
+ // discard changeset if it had no changes
393
+ if (changeSet.changes.length === 0) {
394
+ await provider.changeSets.delete(changeSet.id);
395
+ }
396
+ // throw error
397
+ throw funnel_core_1.IsometricErrorUtils.coerceError(e);
398
+ }
399
+ }
400
+ async update({ id: collectionId, errors, updates }) {
401
+ // resolve current user (or throw)
402
+ const { client, users } = this.provider;
403
+ const strapiUrl = client.baseURL;
404
+ const user = await users.me();
405
+ if (!user) {
406
+ throw new funnel_core_1.NotAuthenticatedError();
407
+ }
408
+ // get latest version of collection
409
+ const entries = client.collection('collections');
410
+ const resultProps = funnel_core_1.Schema.Collection.Data.Props.all;
411
+ const { data: currentData } = await entries.findOne(collectionId, {
412
+ status: 'draft',
413
+ populate: serialization_1.CollectionData.populate
414
+ });
415
+ // TODO: validate collection is able to be updated (e.g. not archived, etc.)
416
+ // TODO: switch to isometric error so we can catch it on client-side
417
+ // throw if collection doesn't exist
418
+ if (!currentData) {
419
+ throw new funnel_core_1.NotFoundError();
420
+ }
421
+ // deserialize collection (we'll be updating this version)
422
+ const collection = serialization_1.CollectionData.deserialize(currentData, strapiUrl, resultProps);
423
+ // set errors
424
+ collection.errors = errors;
425
+ console.debug(`[StrapiPageClient/update] applying ${updates.length} collection updates`);
426
+ // merge changes (the original collection will have changed)
427
+ const model = funnel_core_1.Schema.CollectionModel.from(collection);
428
+ model.update(updates);
429
+ console.debug(`[StrapiPageClient/update] saving updated collection`);
430
+ // resolve change set (rebind)
431
+ const { provider } = this;
432
+ const changeSet = await provider.changeSets.resolve({ id: collection.changeSetId, fallbackToGlobal: true });
433
+ collection.changeSetId = changeSet.id;
434
+ // save collection
435
+ const update = serialization_1.CollectionData.serialize(collection);
436
+ const { data: updatedData } = await entries.update(collection.id, Object.assign(Object.assign({}, update), { state: 'draft' }), {
437
+ status: 'draft',
438
+ populate: serialization_1.CollectionData.populate
439
+ });
440
+ // update changeset
441
+ changeSet.addCollectionChange(user.id, {
442
+ __type: 'collection',
443
+ id: collection.id,
444
+ groupId: collection.groupId,
445
+ name: collection.name,
446
+ schema: collection.type,
447
+ language: collection.language,
448
+ type: collection.publishedOn ? 'update' : 'create',
449
+ errors: collection.errors
450
+ });
451
+ provider.changeSets.update(changeSet.toData())
452
+ .catch(console.error);
453
+ // return collection
454
+ return serialization_1.CollectionData.deserialize(updatedData, strapiUrl, resultProps);
455
+ }
456
+ async replace({ updatedCollection, version, skipSync }) {
457
+ console.debug(`[StrapiCollectionClient/replace] replacing collection`);
458
+ // get latest version of collection
459
+ const client = this.provider.client;
460
+ const strapiUrl = client.baseURL;
461
+ const collection = client.collection('collection');
462
+ // sync changes (the original collection will have changed)
463
+ const model = funnel_core_1.Schema.CollectionModel.from(updatedCollection);
464
+ if (!skipSync) {
465
+ model.sync();
466
+ }
467
+ // save collection
468
+ const update = serialization_1.CollectionData.serialize(updatedCollection);
469
+ const { data: updatedData } = await collection.update(updatedCollection.id, update, {
470
+ status: version,
471
+ populate: serialization_1.CollectionData.populate
472
+ });
473
+ console.debug(`[StrapiCollectionClient/replace] returning final collection`);
474
+ // return collection
475
+ return serialization_1.CollectionData.deserialize(updatedData, strapiUrl);
476
+ }
477
+ async unpublish(collectionId) {
478
+ // get collection
479
+ const collection = await this.get({ id: collectionId, version: 'draft' });
480
+ // throw if there's no collection
481
+ if (!collection) {
482
+ throw new funnel_core_1.NotFoundError('Unable to resolve collection');
483
+ }
484
+ // or throw if it's already draft
485
+ else if (!collection.publishedOn) {
486
+ throw new funnel_core_1.InvalidOperationError('Collection is not published');
487
+ }
488
+ // unpublish the document
489
+ await this.provider.customRequest({
490
+ method: 'POST',
491
+ command: 'unpublish',
492
+ data: JSON.stringify({
493
+ collection: 'collection',
494
+ documentId: collection.id
495
+ }),
496
+ onError: ({ pageRefs, collectionRefs }) => {
497
+ // throw dependants error if we got any refs
498
+ if (pageRefs || collectionRefs) {
499
+ const client = this.provider.client;
500
+ const strapiUrl = client.baseURL;
501
+ throw new errors_1.LinkedDependantsError({
502
+ message: 'This collection cannot be unpublished because it would break dependencies',
503
+ pages: pageRefs.map(data => serialization_1.PageData.deserialize(data, strapiUrl, funnel_core_1.Schema.Page.Data.AsLink.props)),
504
+ collections: collectionRefs.map(data => serialization_1.CollectionData.deserialize(data, strapiUrl, funnel_core_1.Schema.Collection.Data.AsLink.props))
505
+ });
506
+ }
507
+ // or assume the page isn't published
508
+ else {
509
+ throw new funnel_core_1.NotFoundError();
510
+ }
511
+ }
512
+ });
513
+ // indicate success
514
+ return true;
515
+ }
516
+ async getDependants({ id: collectionId, version }) {
517
+ // setup strapi collections and query
518
+ const client = this.provider.client;
519
+ const strapiUrl = client.baseURL;
520
+ const pagesCollection = client.collection('pages');
521
+ const collectionsCollection = client.collection('collections');
522
+ const dependantsQuery = {
523
+ pagination: 'all',
524
+ filters: {
525
+ collectionRefs: {
526
+ documentId: collectionId
527
+ }
528
+ },
529
+ status: version
530
+ };
531
+ // fetch dependants
532
+ const [{ items: pages = [] }, { items: collections = [] }] = await Promise.all([
533
+ Strapi_1.Strapi.paginate(Object.assign({ collection: pagesCollection }, dependantsQuery)),
534
+ Strapi_1.Strapi.paginate(Object.assign({ collection: collectionsCollection }, dependantsQuery))
535
+ ]);
536
+ // return
537
+ return {
538
+ pages: pages.map(page => serialization_1.PageData.deserialize(page, strapiUrl, funnel_core_1.Schema.Page.Data.AsRef.props)),
539
+ collections: collections.map(collection => serialization_1.CollectionData.deserialize(collection, strapiUrl, funnel_core_1.Schema.Collection.Data.AsRef.props))
540
+ };
541
+ }
542
+ async getDependencies({ id: collectionId, version }) {
543
+ // get collection by id
544
+ const client = this.provider.client;
545
+ const strapiUrl = client.baseURL;
546
+ const collection = client.collection('collections');
547
+ const { data } = await collection.findOne(collectionId, {
548
+ status: version,
549
+ populate: ['collectionRefs']
550
+ });
551
+ const collectionData = data;
552
+ // throw if not found
553
+ if (!collectionData) {
554
+ throw new funnel_core_1.NotFoundError(`cannot find collection with id "${collectionId}"`);
555
+ }
556
+ // return
557
+ return {
558
+ collections: collectionData.collectionRefs.map(collectionRef => serialization_1.CollectionData.deserialize(collectionRef, strapiUrl, funnel_core_1.Schema.Collection.Data.AsRef.props))
559
+ };
560
+ }
561
+ }
562
+ exports.StrapiCollectionClient = StrapiCollectionClient;
563
+ // helper
564
+ function getCollectionQueryParams(query) {
565
+ // build filters
566
+ const { groupId, brand, type, language, name, tags = [], tagsMatch = 'any', version } = query;
567
+ const filters = [];
568
+ // filter group
569
+ if (groupId) {
570
+ filters.push({ groupId: { $eq: groupId } });
571
+ }
572
+ // filter brand
573
+ if (brand) {
574
+ filters.push({ brand: { $eq: brand } });
575
+ }
576
+ // filter type
577
+ const normalizedType = type
578
+ ? Array.isArray(type)
579
+ ? type
580
+ : [type]
581
+ : [];
582
+ if (normalizedType.length > 0) {
583
+ filters.push({ type: { $in: type } });
584
+ }
585
+ // filter language
586
+ if (language) {
587
+ filters.push({ lang: { $eq: language } });
588
+ }
589
+ // filter name
590
+ if (name) {
591
+ filters.push({ name: { $contains: name } });
592
+ }
593
+ // filter tags
594
+ if (tags.length === 1) {
595
+ filters.push({ tags: { $contains: `"${tags[0]}"` } });
596
+ }
597
+ else if (tags.length > 1) {
598
+ const operator = tagsMatch === 'any' ? '$or' : '$and';
599
+ filters.push({
600
+ [operator]: tags
601
+ .filter((tag) => !!tag)
602
+ .map((tag) => ({ tags: { $contains: `"${tag}"` } }))
603
+ });
604
+ }
605
+ // return query
606
+ return {
607
+ filters: filters.length > 0 ? { $and: filters } : undefined,
608
+ status: version
609
+ };
610
+ }
@@ -0,0 +1,38 @@
1
+ import { StrapiClient } from '@strapi/client';
2
+ import { JsonValue } from 'type-fest';
3
+ import { AuthClient, ContentClient } from '../api';
4
+ import { IStrapiContentClient } from './IStrapiContentClient';
5
+ import { StrapiAssetClient } from './StrapiAssetClient';
6
+ import { StrapiAuthClient } from './StrapiAuthClient';
7
+ import { StrapiChangeSetClient } from './StrapiChangeSetClient';
8
+ import { StrapiCollectionClient } from './StrapiCollectionClient';
9
+ import { StrapiPageClient } from './StrapiPageClient';
10
+ import { StrapiSiteConfigClient } from './StrapiSiteConfigClient';
11
+ import { StrapiUpgradeClient } from './StrapiUpgradeClient';
12
+ import { StrapiUserClient } from './StrapiUserClient';
13
+ export declare class StrapiContentClient implements ContentClient, IStrapiContentClient {
14
+ readonly auth: StrapiAuthClient;
15
+ readonly changeSets: StrapiChangeSetClient;
16
+ readonly files: StrapiAssetClient;
17
+ readonly pages: StrapiPageClient;
18
+ readonly collections: StrapiCollectionClient;
19
+ readonly upgrade: StrapiUpgradeClient;
20
+ readonly users: StrapiUserClient;
21
+ readonly siteConfig: StrapiSiteConfigClient;
22
+ private readonly _baseUrl;
23
+ private _token?;
24
+ private _client;
25
+ constructor({ baseUrl, token, slackUrl }: StrapiContentClient.ConstructorArgs);
26
+ get client(): StrapiClient;
27
+ get token(): AuthClient.AccessToken;
28
+ set token(token: AuthClient.AccessToken);
29
+ clearToken(): void;
30
+ customRequest<TResult extends JsonValue = JsonValue, TError extends JsonValue = JsonValue>({ command, method, params, data, onError }: IStrapiContentClient.CustomRequestArgs<TError>): Promise<TResult>;
31
+ }
32
+ export declare namespace StrapiContentClient {
33
+ type ConstructorArgs = {
34
+ baseUrl: string;
35
+ token?: string;
36
+ slackUrl?: string;
37
+ };
38
+ }