@nascentdigital/funnel-cms 5.0.2 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/PageClient.d.ts +1 -1
- package/dist/contentful/ContentfulCollectionClient.d.ts +1 -1
- package/dist/contentful/ContentfulCollectionClient.js +172 -4
- package/dist/contentful/ContentfulContentClient.d.ts +3 -2
- package/dist/contentful/ContentfulContentClient.js +83 -20
- package/dist/contentful/ContentfulPageClient.d.ts +1 -1
- package/dist/contentful/ContentfulPageClient.js +264 -28
- package/dist/contentful/ContentfulSiteConfigClient.js +1 -1
- package/dist/contentful/IContentfulContentClient.d.ts +15 -6
- package/dist/contentful/models/ContentfulAssetData.d.ts +3 -1
- package/dist/contentful/models/ContentfulCollectionData.d.ts +4 -2
- package/dist/contentful/models/ContentfulCollectionData.js +9 -1
- package/dist/contentful/models/ContentfulData.d.ts +1 -2
- package/dist/contentful/models/ContentfulPageData.d.ts +8 -2
- package/dist/contentful/models/ContentfulPageData.js +10 -0
- package/dist/models/Pagination.d.ts +1 -0
- package/dist/strapi/StrapiPageClient.js +21 -37
- package/dist/strapi/serialization/CollectionData.js +2 -1
- package/package.json +2 -2
package/dist/api/PageClient.d.ts
CHANGED
|
@@ -169,7 +169,7 @@ export declare namespace PageClient {
|
|
|
169
169
|
type Result = Schema.Page.Data.AsGroup;
|
|
170
170
|
}
|
|
171
171
|
namespace Get {
|
|
172
|
-
type Args =
|
|
172
|
+
type Args = Query.ById & Query.Select;
|
|
173
173
|
type Result = Schema.Page.FlattenedData | undefined;
|
|
174
174
|
}
|
|
175
175
|
namespace Create {
|
|
@@ -6,7 +6,7 @@ export declare class ContentfulCollectionClient implements CollectionClient {
|
|
|
6
6
|
readonly cms: IContentfulContentClient;
|
|
7
7
|
constructor(cms: IContentfulContentClient);
|
|
8
8
|
getOverview(args: CollectionClient.GetOverview.Args): Promise<CollectionClient.GetOverview.Result>;
|
|
9
|
-
getItems(args: CollectionClient.GetItems.Args): Promise<CollectionClient.GetItems.Result>;
|
|
9
|
+
getItems({ language, ...args }: CollectionClient.GetItems.Args): Promise<CollectionClient.GetItems.Result>;
|
|
10
10
|
find(args: CollectionClient.Find.Args): Promise<CollectionClient.Find.Result>;
|
|
11
11
|
getGroup(args: CollectionClient.GetGroup.Args): Promise<ContentfulCollectionClient.GetGroup.Result>;
|
|
12
12
|
get(args: CollectionClient.Get.Args): Promise<ContentfulCollectionClient.Get.Result>;
|
|
@@ -1,4 +1,15 @@
|
|
|
1
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
|
+
};
|
|
2
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
14
|
exports.ContentfulCollectionClient = void 0;
|
|
4
15
|
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
@@ -9,10 +20,68 @@ class ContentfulCollectionClient {
|
|
|
9
20
|
this.cms = cms;
|
|
10
21
|
}
|
|
11
22
|
async getOverview(args) {
|
|
12
|
-
|
|
23
|
+
// fetch all collections
|
|
24
|
+
const { cms } = this;
|
|
25
|
+
const { entries } = await cms.getEntries(Object.assign({ content_type: models_1.ContentfulCollectionData.contentType, version: args.version, select: getCollectionSelect(funnel_core_1.Schema.Collection.Data.AsRef.props) }, getCollectionQueryParams(args)));
|
|
26
|
+
// convert entries to collection data
|
|
27
|
+
const collectionsData = entries.map(entry => models_1.ContentfulCollectionData.deserialize(entry, funnel_core_1.Schema.Collection.Data.AsRef.props));
|
|
28
|
+
// group by type
|
|
29
|
+
const collectionsByType = new Map();
|
|
30
|
+
for (const data of collectionsData) {
|
|
31
|
+
// get group
|
|
32
|
+
let group = collectionsByType.get(data.type);
|
|
33
|
+
if (!group) {
|
|
34
|
+
collectionsByType.set(data.type, group = []);
|
|
35
|
+
}
|
|
36
|
+
// push to group
|
|
37
|
+
group.push(data);
|
|
38
|
+
}
|
|
39
|
+
// return in overview format
|
|
40
|
+
return funnel_core_1.Schema.Site.current().collections.map(({ type }) => {
|
|
41
|
+
var _a, _b;
|
|
42
|
+
return ({
|
|
43
|
+
type,
|
|
44
|
+
total: (_b = (_a = collectionsByType.get(type)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0
|
|
45
|
+
});
|
|
46
|
+
});
|
|
13
47
|
}
|
|
14
|
-
async getItems(
|
|
15
|
-
|
|
48
|
+
async getItems(_a) {
|
|
49
|
+
var { language } = _a, args = __rest(_a, ["language"]);
|
|
50
|
+
// fetch all collections
|
|
51
|
+
const { cms } = this;
|
|
52
|
+
const { entries } = await cms.getEntries(Object.assign({ content_type: models_1.ContentfulCollectionData.contentType, version: args.version, select: getCollectionSelect(funnel_core_1.Schema.Collection.Data.AsRef.props) }, getCollectionQueryParams(args)));
|
|
53
|
+
// convert entries to collection data
|
|
54
|
+
const collectionsData = entries.map(entry => models_1.ContentfulCollectionData.deserialize(entry, funnel_core_1.Schema.Collection.Data.AsRef.props));
|
|
55
|
+
// group by group id
|
|
56
|
+
const collectionsByGroupId = new Map();
|
|
57
|
+
for (const data of collectionsData) {
|
|
58
|
+
// get group
|
|
59
|
+
let group = collectionsByGroupId.get(data.groupId);
|
|
60
|
+
if (!group) {
|
|
61
|
+
collectionsByGroupId.set(data.groupId, group = []);
|
|
62
|
+
}
|
|
63
|
+
// push to group
|
|
64
|
+
group.push(data);
|
|
65
|
+
}
|
|
66
|
+
// return in correct format
|
|
67
|
+
return collectionsByGroupId.entries().map(([groupId, refs]) => {
|
|
68
|
+
var _a;
|
|
69
|
+
// find ref with specified language
|
|
70
|
+
const target = (_a = refs.find(ref => ref.language === language)) !== null && _a !== void 0 ? _a : refs[0];
|
|
71
|
+
// return item
|
|
72
|
+
return {
|
|
73
|
+
id: target.id,
|
|
74
|
+
groupId: target.groupId,
|
|
75
|
+
type: args.type,
|
|
76
|
+
name: target.name,
|
|
77
|
+
refs: refs.reduce((refs, ref) => {
|
|
78
|
+
// map ref
|
|
79
|
+
refs[ref.language] = ref;
|
|
80
|
+
// keep reducing
|
|
81
|
+
return refs;
|
|
82
|
+
}, {})
|
|
83
|
+
};
|
|
84
|
+
}).toArray();
|
|
16
85
|
}
|
|
17
86
|
async find(args) {
|
|
18
87
|
throw new funnel_core_1.NotImplementedError();
|
|
@@ -59,10 +128,109 @@ class ContentfulCollectionClient {
|
|
|
59
128
|
entryId: args.id,
|
|
60
129
|
version: args.version
|
|
61
130
|
});
|
|
131
|
+
// skip if there's no entry
|
|
132
|
+
if (!entry) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
// or return it
|
|
62
136
|
return Object.assign({ data: models_1.ContentfulCollectionData.deserialize(entry) }, models_1.ContentfulCollectionData.deserializeRefs(references));
|
|
63
137
|
}
|
|
64
138
|
async create(args) {
|
|
65
|
-
|
|
139
|
+
// create a new language of an existing collection
|
|
140
|
+
if (funnel_core_1.Schema.Collection.Data.AsNewLanguage.filter(args)) {
|
|
141
|
+
// fetch all collections in group
|
|
142
|
+
const groupResult = await this.getGroup({
|
|
143
|
+
version: 'draft',
|
|
144
|
+
type: args.type,
|
|
145
|
+
groupId: args.groupId,
|
|
146
|
+
language: args.language
|
|
147
|
+
});
|
|
148
|
+
// throw if group doesn't exist
|
|
149
|
+
if (!groupResult) {
|
|
150
|
+
throw new funnel_core_1.ArgumentError(`Collection group "${args.groupId}" no longer exists`);
|
|
151
|
+
}
|
|
152
|
+
// return existing collection if it's there
|
|
153
|
+
if (groupResult.collection) {
|
|
154
|
+
return groupResult;
|
|
155
|
+
}
|
|
156
|
+
// try to create page
|
|
157
|
+
try {
|
|
158
|
+
// create entry
|
|
159
|
+
const { group } = groupResult;
|
|
160
|
+
const collectionData = await this.cms.createEntry(models_1.ContentfulCollectionData.contentType, {
|
|
161
|
+
type: args.type,
|
|
162
|
+
brand: args.brand,
|
|
163
|
+
version: args.version,
|
|
164
|
+
groupId: args.groupId,
|
|
165
|
+
language: args.language,
|
|
166
|
+
name: group.name,
|
|
167
|
+
references: [],
|
|
168
|
+
tags: [],
|
|
169
|
+
fields: {},
|
|
170
|
+
state: 'draft',
|
|
171
|
+
errors: true
|
|
172
|
+
});
|
|
173
|
+
// return updated group
|
|
174
|
+
return {
|
|
175
|
+
group: Object.assign(Object.assign({}, group), { instances: [
|
|
176
|
+
...group.instances,
|
|
177
|
+
models_1.ContentfulCollectionData.deserialize(collectionData, funnel_core_1.Schema.Collection.Data.AsGroup.Instance.props)
|
|
178
|
+
] }),
|
|
179
|
+
collection: {
|
|
180
|
+
data: models_1.ContentfulCollectionData.deserialize(collectionData),
|
|
181
|
+
files: {},
|
|
182
|
+
collections: {},
|
|
183
|
+
pages: {}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
// or throw
|
|
188
|
+
catch (e) {
|
|
189
|
+
throw funnel_core_1.IsometricErrorUtils.coerceError(e);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// or create a net-new collection
|
|
193
|
+
else {
|
|
194
|
+
// try to create
|
|
195
|
+
try {
|
|
196
|
+
// create entry
|
|
197
|
+
const collectionData = await this.cms.createEntry(models_1.ContentfulCollectionData.contentType, {
|
|
198
|
+
type: args.type,
|
|
199
|
+
brand: args.brand,
|
|
200
|
+
version: args.version,
|
|
201
|
+
groupId: funnel_core_1.Value.uuid(),
|
|
202
|
+
language: args.language,
|
|
203
|
+
name: args.name,
|
|
204
|
+
references: [],
|
|
205
|
+
tags: [],
|
|
206
|
+
fields: {},
|
|
207
|
+
state: 'draft',
|
|
208
|
+
errors: true
|
|
209
|
+
});
|
|
210
|
+
// return updated group
|
|
211
|
+
return {
|
|
212
|
+
group: {
|
|
213
|
+
brand: collectionData.brand,
|
|
214
|
+
type: collectionData.type,
|
|
215
|
+
groupId: collectionData.groupId,
|
|
216
|
+
name: collectionData.name,
|
|
217
|
+
instances: [
|
|
218
|
+
models_1.ContentfulCollectionData.deserialize(collectionData, funnel_core_1.Schema.Collection.Data.AsGroup.Instance.props)
|
|
219
|
+
]
|
|
220
|
+
},
|
|
221
|
+
collection: {
|
|
222
|
+
data: models_1.ContentfulCollectionData.deserialize(collectionData),
|
|
223
|
+
files: {},
|
|
224
|
+
collections: {},
|
|
225
|
+
pages: {}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
// or throw
|
|
230
|
+
catch (e) {
|
|
231
|
+
throw funnel_core_1.IsometricErrorUtils.coerceError(e);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
66
234
|
}
|
|
67
235
|
async duplicate(args) {
|
|
68
236
|
throw new funnel_core_1.NotImplementedError();
|
|
@@ -33,8 +33,9 @@ export declare class ContentfulContentClient implements ContentClient, IContentf
|
|
|
33
33
|
set token(token: AuthClient.AccessToken);
|
|
34
34
|
clearToken(): void;
|
|
35
35
|
createEntry<T extends ContentfulData>(contentTypeId: string, entry: ContentfulData.Draft<T>): Promise<T>;
|
|
36
|
-
getEntry<TEntry extends ContentfulData>({ entryId, includeLinks, version }: IContentfulContentClient.GetEntry.Args<TEntry>): Promise<IContentfulContentClient.GetEntry.Result<TEntry>>;
|
|
37
|
-
getEntries<TEntry extends ContentfulData>({
|
|
36
|
+
getEntry<TEntry extends ContentfulData>({ entryId, includeLinks, version, ...query }: IContentfulContentClient.GetEntry.Args<TEntry>): Promise<IContentfulContentClient.GetEntry.Result<TEntry>>;
|
|
37
|
+
getEntries<TEntry extends ContentfulData>({ pagination, version, includeLinks, ...query }: IContentfulContentClient.GetEntries.Args<TEntry>): Promise<IContentfulContentClient.GetEntries.Result<TEntry>>;
|
|
38
|
+
uploadAsset(args: IContentfulContentClient.UploadAsset.Args): Promise<IContentfulContentClient.UploadAsset.Result>;
|
|
38
39
|
static forEditor(sdk: KnownAppSDK): Promise<ContentfulContentClient>;
|
|
39
40
|
}
|
|
40
41
|
export declare namespace ContentfulContentClient {
|
|
@@ -88,40 +88,43 @@ class ContentfulContentClient {
|
|
|
88
88
|
// transform + return new entry
|
|
89
89
|
return models_2.ContentfulData.fromCmaData(data, locale);
|
|
90
90
|
}
|
|
91
|
-
async getEntry(
|
|
92
|
-
var
|
|
91
|
+
async getEntry(_a) {
|
|
92
|
+
var _b, _c;
|
|
93
|
+
var { entryId, includeLinks = false, version = 'draft' } = _a, query = __rest(_a, ["entryId", "includeLinks", "version"]);
|
|
93
94
|
// get entry
|
|
94
95
|
const client = version === 'published' ? this.cda : this.cpa;
|
|
95
96
|
const result = await client.entry.getMany({
|
|
96
|
-
query: {
|
|
97
|
-
'sys.id': entryId,
|
|
98
|
-
include: includeLinks === true
|
|
97
|
+
query: Object.assign(Object.assign({ 'sys.id': entryId }, query), { include: includeLinks === true
|
|
99
98
|
? 10
|
|
100
|
-
: includeLinks || undefined
|
|
101
|
-
}
|
|
99
|
+
: includeLinks || undefined })
|
|
102
100
|
});
|
|
103
101
|
const { items: [item], includes } = result;
|
|
104
102
|
console.debug('[ContentfulContentClient/getEntry] fetched', result);
|
|
103
|
+
// skip
|
|
105
104
|
// bind references
|
|
106
|
-
const entry = models_2.ContentfulData.fromCdaData(item);
|
|
107
|
-
const references = (
|
|
105
|
+
const entry = item ? models_2.ContentfulData.fromCdaData(item) : undefined;
|
|
106
|
+
const references = (_c = (_b = includes === null || includes === void 0 ? void 0 : includes.Entry) === null || _b === void 0 ? void 0 : _b.map(link => models_2.ContentfulData.fromCdaData(link))) !== null && _c !== void 0 ? _c : [];
|
|
108
107
|
// return normalized item
|
|
109
108
|
return { entry, references };
|
|
110
109
|
}
|
|
111
110
|
async getEntries(_a) {
|
|
112
111
|
var _b, _c;
|
|
113
|
-
var {
|
|
112
|
+
var { pagination = 'all', version = 'draft', includeLinks = false } = _a, query = __rest(_a, ["pagination", "version", "includeLinks"]);
|
|
113
|
+
// setup pagination
|
|
114
|
+
const itemsPerRequest = pagination === 'all' ? 1000 : Math.min(pagination.pageSize, 1000);
|
|
115
|
+
const page = pagination === 'all' ? 1 : pagination.page;
|
|
116
|
+
let skip = pagination === 'all' ? 0 : (page - 1) * pagination.pageSize;
|
|
117
|
+
let totalItemFetched = 0;
|
|
118
|
+
let hasMorePages = true;
|
|
119
|
+
let totalItems = undefined;
|
|
114
120
|
// loop until no more pages
|
|
115
121
|
const client = version === 'published' ? this.cda : this.cpa;
|
|
116
|
-
let skip = 0;
|
|
117
|
-
let total = 1;
|
|
118
122
|
const entries = [];
|
|
119
123
|
const includes = [];
|
|
120
|
-
|
|
124
|
+
do {
|
|
121
125
|
// fetch next page
|
|
122
126
|
const _d = await client.entry.getMany({
|
|
123
|
-
query: Object.assign(Object.assign({}, query), { limit,
|
|
124
|
-
skip, include: includeLinks === true
|
|
127
|
+
query: Object.assign(Object.assign({}, query), { limit: itemsPerRequest, skip, include: includeLinks === true
|
|
125
128
|
? 10
|
|
126
129
|
: includeLinks || undefined })
|
|
127
130
|
}), { items } = _d, response = __rest(_d, ["items"]);
|
|
@@ -129,19 +132,79 @@ class ContentfulContentClient {
|
|
|
129
132
|
// add items
|
|
130
133
|
items.forEach(item => entries.push(models_2.ContentfulData.fromCdaData(item)));
|
|
131
134
|
includes.push(...((_c = (_b = response.includes) === null || _b === void 0 ? void 0 : _b.Entry) !== null && _c !== void 0 ? _c : []));
|
|
132
|
-
// update
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
// update paging info
|
|
136
|
+
totalItemFetched += items.length;
|
|
137
|
+
totalItems = response.total;
|
|
138
|
+
skip += items.length;
|
|
139
|
+
hasMorePages = pagination === 'all'
|
|
140
|
+
? skip < totalItems
|
|
141
|
+
: totalItemFetched < pagination.pageSize && skip < totalItems;
|
|
142
|
+
} while (hasMorePages);
|
|
136
143
|
console.debug('[ContentfulContentClient/getEntries] fetched entries', { entries, includes });
|
|
137
144
|
// normalize references
|
|
138
145
|
const references = includes.map(link => models_2.ContentfulData.fromCdaData(link));
|
|
139
146
|
// return
|
|
140
147
|
return {
|
|
141
148
|
entries,
|
|
142
|
-
references
|
|
149
|
+
references,
|
|
150
|
+
page,
|
|
151
|
+
pageCount: pagination === 'all'
|
|
152
|
+
? 1
|
|
153
|
+
: Math.floor(totalItems / pagination.pageSize),
|
|
154
|
+
totalItemCount: totalItems
|
|
143
155
|
};
|
|
144
156
|
}
|
|
157
|
+
async uploadAsset(args) {
|
|
158
|
+
var _a;
|
|
159
|
+
// upload file
|
|
160
|
+
const { cma, locale } = this;
|
|
161
|
+
const uploadResult = await this.cma.upload.create({}, {
|
|
162
|
+
file: await args.file.arrayBuffer()
|
|
163
|
+
});
|
|
164
|
+
// create contentful asset
|
|
165
|
+
const contentfulAsset = await cma.asset.create({}, {
|
|
166
|
+
fields: models_2.ContentfulData.toEntryData({
|
|
167
|
+
title: args.name,
|
|
168
|
+
description: (_a = args.description) !== null && _a !== void 0 ? _a : '',
|
|
169
|
+
file: {
|
|
170
|
+
contentType: args.file.type,
|
|
171
|
+
fileName: args.name,
|
|
172
|
+
uploadFrom: {
|
|
173
|
+
sys: {
|
|
174
|
+
type: 'Link',
|
|
175
|
+
linkType: 'Upload',
|
|
176
|
+
id: uploadResult.sys.id
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}, locale)
|
|
181
|
+
});
|
|
182
|
+
// process contentful asset (creates url etc.) and return
|
|
183
|
+
const processedAsset = await cma.asset.processForAllLocales({}, contentfulAsset);
|
|
184
|
+
// create funnel asset then return
|
|
185
|
+
const entry = await cma.entry.create({ contentTypeId: models_2.ContentfulAssetData.contentType }, {
|
|
186
|
+
fields: models_2.ContentfulData.toEntryData({
|
|
187
|
+
name: args.name,
|
|
188
|
+
description: args.description,
|
|
189
|
+
brand: args.brand,
|
|
190
|
+
type: args.type,
|
|
191
|
+
scope: args.scope,
|
|
192
|
+
tags: args.tags,
|
|
193
|
+
url: 'https:' + processedAsset.fields.file[locale].url,
|
|
194
|
+
size: args.size,
|
|
195
|
+
metadata: args.metadata,
|
|
196
|
+
media: {
|
|
197
|
+
sys: {
|
|
198
|
+
type: 'Link',
|
|
199
|
+
linkType: 'Asset',
|
|
200
|
+
id: processedAsset.sys.id
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}, locale)
|
|
204
|
+
});
|
|
205
|
+
// return asset
|
|
206
|
+
return models_2.ContentfulData.fromCmaData(entry, locale);
|
|
207
|
+
}
|
|
145
208
|
static async forEditor(sdk) {
|
|
146
209
|
var _a;
|
|
147
210
|
// get current site config (throw if we can't)
|
|
@@ -21,7 +21,7 @@ export declare class ContentfulPageClient implements PageClient {
|
|
|
21
21
|
unpublish(args: PageClient.Unpublish.Args): Promise<PageClient.Unpublish.Result>;
|
|
22
22
|
getDependants(args: PageClient.GetDependants.Args): Promise<PageClient.GetDependants.Result>;
|
|
23
23
|
getDependencies(args: PageClient.GetDependencies.Args): Promise<PageClient.GetDependencies.Result>;
|
|
24
|
-
validateSlug(
|
|
24
|
+
validateSlug({ brand, type, region, slug, groupId }: PageClient.ValidateSlug.Args): Promise<PageClient.ValidateSlug.Result>;
|
|
25
25
|
}
|
|
26
26
|
export declare namespace ContentfulPageClient {
|
|
27
27
|
type FlattedPageData = Omit<Schema.Page.FlattenedData, 'data'> & {
|
|
@@ -1,7 +1,19 @@
|
|
|
1
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
|
+
};
|
|
2
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
14
|
exports.ContentfulPageClient = void 0;
|
|
4
15
|
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
16
|
+
const errors_1 = require("../errors");
|
|
5
17
|
const models_1 = require("./models");
|
|
6
18
|
// class
|
|
7
19
|
class ContentfulPageClient {
|
|
@@ -51,7 +63,7 @@ class ContentfulPageClient {
|
|
|
51
63
|
};
|
|
52
64
|
}
|
|
53
65
|
async getSummaries(args) {
|
|
54
|
-
// fetch items (bail if there are no instances
|
|
66
|
+
// fetch items (bail if there are no instances)
|
|
55
67
|
const { cms } = this;
|
|
56
68
|
const { entries } = await cms.getEntries(Object.assign({ content_type: models_1.ContentfulPageData.contentType, version: args.version, select: getPageSelect(funnel_core_1.Schema.Page.Data.AsLink.props) }, getPageQueryParams(args)));
|
|
57
69
|
// return result
|
|
@@ -60,8 +72,15 @@ class ContentfulPageClient {
|
|
|
60
72
|
getPreviews(args) {
|
|
61
73
|
throw new funnel_core_1.NotImplementedError();
|
|
62
74
|
}
|
|
63
|
-
search(args) {
|
|
64
|
-
|
|
75
|
+
async search(args) {
|
|
76
|
+
// fetch items (bail if there are no instances)
|
|
77
|
+
const { cms } = this;
|
|
78
|
+
const { entries, page, pageCount, totalItemCount } = await cms.getEntries(Object.assign({ content_type: models_1.ContentfulPageData.contentType, version: args.version, select: getPageSelect(funnel_core_1.Schema.Page.Data.AsLink.props) }, getPageQueryParams(args)));
|
|
79
|
+
// return entries
|
|
80
|
+
return {
|
|
81
|
+
items: entries.map(entry => models_1.ContentfulPageData.deserialize(entry, funnel_core_1.Schema.Page.Data.AsLink.props)),
|
|
82
|
+
page, pageCount, totalItemCount
|
|
83
|
+
};
|
|
65
84
|
}
|
|
66
85
|
query(args) {
|
|
67
86
|
throw new funnel_core_1.NotImplementedError();
|
|
@@ -71,58 +90,257 @@ class ContentfulPageClient {
|
|
|
71
90
|
}
|
|
72
91
|
async getGroup(args) {
|
|
73
92
|
// fetch items (bail if there are no instances
|
|
93
|
+
const { language, region, version } = args, queryArgs = __rest(args, ["language", "region", "version"]);
|
|
74
94
|
const { cms } = this;
|
|
75
|
-
const { entries } = await cms.getEntries(Object.assign({ content_type: models_1.ContentfulPageData.contentType, version
|
|
95
|
+
const { entries } = await cms.getEntries(Object.assign({ content_type: models_1.ContentfulPageData.contentType, version, select: getPageSelect(funnel_core_1.Schema.Page.Data.AsGroup.Instance.props) }, getPageQueryParams(queryArgs)));
|
|
76
96
|
// bail if no items
|
|
77
97
|
if (entries.length === 0) {
|
|
78
98
|
console.debug('[ContentfulPageClient/getGroup] no items in group', args);
|
|
79
|
-
const { brand, groupId: possibleGroupId, type, slug
|
|
99
|
+
const { brand, groupId: possibleGroupId, type, slug } = queryArgs;
|
|
80
100
|
return {
|
|
81
|
-
group: { groupId: possibleGroupId !== null && possibleGroupId !== void 0 ? possibleGroupId : funnel_core_1.Schema.Page.GroupId.empty, brand, type, slug,
|
|
101
|
+
group: { groupId: possibleGroupId !== null && possibleGroupId !== void 0 ? possibleGroupId : funnel_core_1.Schema.Page.GroupId.empty, brand, type, slug, instances: [] }
|
|
82
102
|
};
|
|
83
103
|
}
|
|
84
|
-
console.debug('[ContentfulPageClient/getGroup] processing group items',
|
|
104
|
+
console.debug('[ContentfulPageClient/getGroup] processing group items', args);
|
|
85
105
|
// collate the group ids into summaries (fetches full page if region/language match exists
|
|
86
106
|
const instances = entries.map(entry => models_1.ContentfulPageData.deserialize(entry, funnel_core_1.Schema.Page.Data.AsGroup.Instance.props));
|
|
87
107
|
// bind page (if it exists)
|
|
88
|
-
const { language, version } = args;
|
|
89
108
|
const pageInstance = instances
|
|
90
|
-
.find(instance => instance.language === language);
|
|
109
|
+
.find(instance => instance.region === region && instance.language === language);
|
|
91
110
|
console.debug('[ContentfulPageClient/getGroup] getting page using this.get...', { id: pageInstance === null || pageInstance === void 0 ? void 0 : pageInstance.id, version });
|
|
92
111
|
const page = pageInstance
|
|
93
112
|
? await this.get({ id: pageInstance.id, version })
|
|
94
113
|
: undefined;
|
|
95
114
|
// return group (and optional page)
|
|
96
|
-
const { type, brand, groupId,
|
|
115
|
+
const { type, brand, groupId, slug } = entries[0];
|
|
97
116
|
return {
|
|
98
|
-
group: {
|
|
99
|
-
groupId,
|
|
100
|
-
type,
|
|
101
|
-
brand,
|
|
102
|
-
region,
|
|
103
|
-
slug,
|
|
104
|
-
instances
|
|
105
|
-
},
|
|
117
|
+
group: { groupId, type, brand, slug, instances },
|
|
106
118
|
page
|
|
107
119
|
};
|
|
108
120
|
}
|
|
109
121
|
async get(args) {
|
|
110
|
-
// create args for query
|
|
111
|
-
const queryArgs = 'id' in args
|
|
112
|
-
? { ids: [args.id], version: args.version }
|
|
113
|
-
: args;
|
|
114
122
|
// fetch entries (should be one entry)
|
|
115
123
|
const { cms } = this;
|
|
116
|
-
const { entries, references }
|
|
124
|
+
const [{ entries, references }, { entry: entrySnapshot }] = await Promise.all([
|
|
125
|
+
// query target (could be published/draft)
|
|
126
|
+
cms.getEntries(Object.assign({ content_type: models_1.ContentfulPageData.contentType, includeLinks: true, version: args.version, pagination: { page: 1, pageSize: 1 }, select: getPageSelect(args.select === 'content'
|
|
127
|
+
? funnel_core_1.Schema.Page.Data.AsContent.props
|
|
128
|
+
: funnel_core_1.Schema.Page.Data.Props.all) }, getPageQueryParams({ ids: [args.id] }))),
|
|
129
|
+
// query published (if pulling draft above)
|
|
130
|
+
args.version === 'draft'
|
|
131
|
+
? cms.getEntry(Object.assign({ content_type: models_1.ContentfulPageData.contentType, entryId: args.id, includeLinks: false, version: 'published', select: getPageSelect(funnel_core_1.Schema.PageSnapshot.props) }, getPageQueryParams({ ids: [args.id] })))
|
|
132
|
+
: Promise.resolve({ entry: undefined, references: [] })
|
|
133
|
+
]);
|
|
117
134
|
// skip if no entries
|
|
118
135
|
if (entries.length === 0) {
|
|
119
136
|
return undefined;
|
|
120
137
|
}
|
|
138
|
+
// stitch together snapshot with entry (if available
|
|
139
|
+
const data = models_1.ContentfulPageData.deserialize(entries[0]);
|
|
140
|
+
const snapshot = entrySnapshot
|
|
141
|
+
? models_1.ContentfulPageData.Snapshot.deserialize(entrySnapshot)
|
|
142
|
+
: undefined;
|
|
121
143
|
// use first entry and deserialize
|
|
122
|
-
return Object.assign({ data:
|
|
144
|
+
return Object.assign({ data: Object.assign(Object.assign({}, data), { snapshotId: snapshot === null || snapshot === void 0 ? void 0 : snapshot.id, snapshot }) }, models_1.ContentfulPageData.deserializeRefs(references));
|
|
123
145
|
}
|
|
124
|
-
create(args) {
|
|
125
|
-
|
|
146
|
+
async create(args) {
|
|
147
|
+
console.debug('[ContentfulPageClient/create] processing create page request', args);
|
|
148
|
+
// create a new language of an existing page
|
|
149
|
+
if (funnel_core_1.Schema.Page.Data.AsNewLanguage.filter(args)) {
|
|
150
|
+
// fetch all pages in group (summaries only)
|
|
151
|
+
const existingPages = await this.getSummaries({
|
|
152
|
+
version: 'draft',
|
|
153
|
+
brand: args.brand,
|
|
154
|
+
groupId: args.groupId
|
|
155
|
+
});
|
|
156
|
+
// throw if there are no pages
|
|
157
|
+
if (existingPages.length === 0) {
|
|
158
|
+
throw new funnel_core_1.ArgumentError(`Page group "${args.groupId}" no longer exists in "${args.brand}"`);
|
|
159
|
+
}
|
|
160
|
+
// return existing page if it's there
|
|
161
|
+
let existingPage = existingPages
|
|
162
|
+
.find(existing => existing.region === args.region && existing.language === args.language);
|
|
163
|
+
if (existingPage) {
|
|
164
|
+
console.debug('[ContentfulPageClient/create/lang] returning existing page', existingPage);
|
|
165
|
+
return this.getGroup(Object.assign(Object.assign({}, existingPage), { version: 'draft' }));
|
|
166
|
+
}
|
|
167
|
+
// bind data + update url
|
|
168
|
+
existingPage = existingPages[0];
|
|
169
|
+
const draft = funnel_core_1.Schema.PageModel.fromDraft(Object.assign({ type: existingPage.type, slug: existingPage.slug, url: existingPage.url, name: existingPage.name, tags: existingPage.tags }, args));
|
|
170
|
+
draft.sync();
|
|
171
|
+
console.debug('[ContentfulPageClient/create/lang] creating from', { draft, existingPages });
|
|
172
|
+
// create page
|
|
173
|
+
try {
|
|
174
|
+
// create page
|
|
175
|
+
const draftData = draft.data;
|
|
176
|
+
const references = models_1.ContentfulData.findReferences([draftData.discover, draftData.content]);
|
|
177
|
+
const pageData = await this.cms.createEntry(models_1.ContentfulPageData.contentType, {
|
|
178
|
+
groupId: draftData.groupId,
|
|
179
|
+
brand: draftData.brand,
|
|
180
|
+
type: draftData.type,
|
|
181
|
+
region: draftData.region,
|
|
182
|
+
language: draftData.language,
|
|
183
|
+
name: draftData.name,
|
|
184
|
+
tags: draftData.tags,
|
|
185
|
+
slug: draftData.slug,
|
|
186
|
+
url: draftData.url,
|
|
187
|
+
preview: draftData.preview,
|
|
188
|
+
discover: draftData.discover,
|
|
189
|
+
content: draftData.content,
|
|
190
|
+
state: 'draft',
|
|
191
|
+
errors: true,
|
|
192
|
+
references
|
|
193
|
+
});
|
|
194
|
+
// transform entry to page data
|
|
195
|
+
const flattenedPage = {
|
|
196
|
+
data: pageData,
|
|
197
|
+
files: {},
|
|
198
|
+
collections: {},
|
|
199
|
+
pages: {}
|
|
200
|
+
};
|
|
201
|
+
const page = flattenedPage.data;
|
|
202
|
+
// return new page
|
|
203
|
+
return {
|
|
204
|
+
group: {
|
|
205
|
+
groupId: page.groupId,
|
|
206
|
+
brand: page.brand,
|
|
207
|
+
type: page.type,
|
|
208
|
+
slug: page.slug,
|
|
209
|
+
instances: [
|
|
210
|
+
// map exiting entries
|
|
211
|
+
...existingPages.map(({ id, url, region, language, name, slug, tags, state, errors, createdOn, updatedOn, publishedOn }) => ({ id, url, region, language, name, slug, tags, state, errors, createdOn, updatedOn, publishedOn })),
|
|
212
|
+
// add new entry
|
|
213
|
+
{
|
|
214
|
+
id: page.id,
|
|
215
|
+
url: page.url,
|
|
216
|
+
region: page.region,
|
|
217
|
+
language: page.language,
|
|
218
|
+
name: page.name,
|
|
219
|
+
slug: page.slug,
|
|
220
|
+
tags: page.tags,
|
|
221
|
+
state: page.state,
|
|
222
|
+
errors: page.errors,
|
|
223
|
+
createdOn: page.createdOn,
|
|
224
|
+
updatedOn: page.updatedOn,
|
|
225
|
+
publishedOn: page.publishedOn
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
page: flattenedPage
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
// or throw
|
|
233
|
+
catch (e) {
|
|
234
|
+
throw funnel_core_1.IsometricErrorUtils.coerceError(e);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// or create a net-new page
|
|
238
|
+
else {
|
|
239
|
+
console.debug('[ContentfulPageClient/create/new] creating fresh');
|
|
240
|
+
// get page's template
|
|
241
|
+
const site = funnel_core_1.Schema.Site.current();
|
|
242
|
+
const schema = site.regions[args.region][args.type];
|
|
243
|
+
// check slug if dynamic page
|
|
244
|
+
if (schema.variant === 'dynamic') {
|
|
245
|
+
// make sure there is a slug for a dynamic page
|
|
246
|
+
if (args.slug === undefined) {
|
|
247
|
+
throw new funnel_core_1.ArgumentError(`A "${args.type}" Page must provide a slug when created`);
|
|
248
|
+
}
|
|
249
|
+
// validate slug
|
|
250
|
+
const validateSlugResult = await this.validateSlug(Object.assign(Object.assign({}, args), { slug: args.slug }));
|
|
251
|
+
if (validateSlugResult.status !== 'available') {
|
|
252
|
+
throw new errors_1.SlugValidationError({ slug: args.slug, reason: validateSlugResult });
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
// fetch all pages matching brand/type/region
|
|
256
|
+
const { group: existingGroup, page: existingPage } = await this.getGroup({
|
|
257
|
+
version: 'draft',
|
|
258
|
+
brand: args.brand,
|
|
259
|
+
type: args.type,
|
|
260
|
+
region: args.region,
|
|
261
|
+
language: args.language,
|
|
262
|
+
slug: args.slug
|
|
263
|
+
});
|
|
264
|
+
// return existing page if it's there
|
|
265
|
+
if (existingPage) {
|
|
266
|
+
console.debug('[ContentfulPageClient/create/new] returning existing page', existingPage);
|
|
267
|
+
return { group: existingGroup, page: existingPage };
|
|
268
|
+
}
|
|
269
|
+
else if (existingGroup.instances.length > 0) {
|
|
270
|
+
console.debug('[ContentfulPageClient/create/new] using existing group', existingGroup);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
console.debug('[ContentfulPageClient/create/new] no existing group found');
|
|
274
|
+
}
|
|
275
|
+
// bind data + update url
|
|
276
|
+
const draft = funnel_core_1.Schema.PageModel.fromDraft(Object.assign(Object.assign({}, args), { groupId: existingGroup.groupId === funnel_core_1.Schema.Page.GroupId.empty
|
|
277
|
+
? funnel_core_1.Value.uuid()
|
|
278
|
+
: existingGroup.groupId, url: '' }));
|
|
279
|
+
draft.sync();
|
|
280
|
+
// create page
|
|
281
|
+
try {
|
|
282
|
+
console.debug('[ContentfulPageClient/create/new] adding new page', draft.data);
|
|
283
|
+
// create page
|
|
284
|
+
const draftData = draft.data;
|
|
285
|
+
const references = models_1.ContentfulData.findReferences([draftData.discover, draftData.content]);
|
|
286
|
+
const pageData = await this.cms.createEntry(models_1.ContentfulPageData.contentType, {
|
|
287
|
+
groupId: draftData.groupId,
|
|
288
|
+
brand: draftData.brand,
|
|
289
|
+
type: draftData.type,
|
|
290
|
+
region: draftData.region,
|
|
291
|
+
language: draftData.language,
|
|
292
|
+
name: draftData.name,
|
|
293
|
+
tags: draftData.tags,
|
|
294
|
+
slug: draftData.slug,
|
|
295
|
+
url: draftData.url,
|
|
296
|
+
preview: draftData.preview,
|
|
297
|
+
discover: draftData.discover,
|
|
298
|
+
content: draftData.content,
|
|
299
|
+
state: 'draft',
|
|
300
|
+
errors: true,
|
|
301
|
+
references
|
|
302
|
+
});
|
|
303
|
+
// transform entry to page data
|
|
304
|
+
const flattenedPage = {
|
|
305
|
+
data: pageData,
|
|
306
|
+
files: {},
|
|
307
|
+
collections: {},
|
|
308
|
+
pages: {}
|
|
309
|
+
};
|
|
310
|
+
const page = flattenedPage.data;
|
|
311
|
+
// return page
|
|
312
|
+
return {
|
|
313
|
+
group: {
|
|
314
|
+
groupId: page.groupId,
|
|
315
|
+
brand: page.brand,
|
|
316
|
+
type: page.type,
|
|
317
|
+
slug: page.slug,
|
|
318
|
+
instances: [
|
|
319
|
+
...existingGroup.instances,
|
|
320
|
+
{
|
|
321
|
+
id: page.id,
|
|
322
|
+
url: page.url,
|
|
323
|
+
region: page.region,
|
|
324
|
+
language: page.language,
|
|
325
|
+
name: page.name,
|
|
326
|
+
slug: page.slug,
|
|
327
|
+
tags: page.tags,
|
|
328
|
+
state: page.state,
|
|
329
|
+
errors: page.errors,
|
|
330
|
+
createdOn: page.createdOn,
|
|
331
|
+
updatedOn: page.updatedOn,
|
|
332
|
+
publishedOn: page.publishedOn
|
|
333
|
+
}
|
|
334
|
+
]
|
|
335
|
+
},
|
|
336
|
+
page: flattenedPage
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
// or throw
|
|
340
|
+
catch (e) {
|
|
341
|
+
throw funnel_core_1.IsometricErrorUtils.coerceError(e);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
126
344
|
}
|
|
127
345
|
duplicate(args) {
|
|
128
346
|
throw new funnel_core_1.NotImplementedError();
|
|
@@ -145,8 +363,26 @@ class ContentfulPageClient {
|
|
|
145
363
|
getDependencies(args) {
|
|
146
364
|
throw new funnel_core_1.NotImplementedError();
|
|
147
365
|
}
|
|
148
|
-
validateSlug(
|
|
149
|
-
|
|
366
|
+
async validateSlug({ brand, type, region, slug, groupId }) {
|
|
367
|
+
// fetch items (bail if there are no instances)
|
|
368
|
+
const { cms } = this;
|
|
369
|
+
const { entries } = await cms.getEntries(Object.assign({ content_type: models_1.ContentfulPageData.contentType, version: 'draft', select: getPageSelect(funnel_core_1.Schema.Page.Data.AsLink.props) }, getPageQueryParams({ brand, type, region, slug })));
|
|
370
|
+
const links = entries.map(entry => models_1.ContentfulPageData.deserialize(entry, funnel_core_1.Schema.Page.Data.AsLink.props));
|
|
371
|
+
// ignore pages in same group (if group specified)
|
|
372
|
+
const matchedPages = groupId !== undefined
|
|
373
|
+
? links.filter(link => link.groupId !== groupId)
|
|
374
|
+
: links;
|
|
375
|
+
// available if no pages matched
|
|
376
|
+
if (matchedPages.length === 0) {
|
|
377
|
+
return { status: 'available' };
|
|
378
|
+
}
|
|
379
|
+
// otherwise not available
|
|
380
|
+
else {
|
|
381
|
+
return {
|
|
382
|
+
status: 'unavailable',
|
|
383
|
+
takenBy: links[0]
|
|
384
|
+
};
|
|
385
|
+
}
|
|
150
386
|
}
|
|
151
387
|
}
|
|
152
388
|
exports.ContentfulPageClient = ContentfulPageClient;
|
|
@@ -12,7 +12,7 @@ class ContentfulSiteConfigClient {
|
|
|
12
12
|
// fetch config model
|
|
13
13
|
let { entries: [siteConfig] } = await this.cms.getEntries({
|
|
14
14
|
content_type: models_1.ContentfulSiteConfigData.contentType,
|
|
15
|
-
|
|
15
|
+
pagination: { page: 1, pageSize: 1 },
|
|
16
16
|
'fields.brand': brand
|
|
17
17
|
});
|
|
18
18
|
// or create it if it's not there
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { CMAClient } from '@contentful/app-sdk';
|
|
2
2
|
import { PlainClientAPI, QueryOptions } from 'contentful-management';
|
|
3
|
-
import {
|
|
3
|
+
import { AssetClient } from '../api';
|
|
4
|
+
import { Environment, Pagination, User } from '../models';
|
|
4
5
|
import type { ContentfulAssetClient } from './ContentfulAssetClient';
|
|
5
6
|
import type { ContentfulAuthClient } from './ContentfulAuthClient';
|
|
6
7
|
import type { ContentfulChangeSetClient } from './ContentfulChangeSetClient';
|
|
@@ -8,7 +9,7 @@ import type { ContentfulCollectionClient } from './ContentfulCollectionClient';
|
|
|
8
9
|
import type { ContentfulPageClient } from './ContentfulPageClient';
|
|
9
10
|
import type { ContentfulSiteConfigClient } from './ContentfulSiteConfigClient';
|
|
10
11
|
import type { ContentfulUserClient } from './ContentfulUserClient';
|
|
11
|
-
import { ContentfulData } from './models';
|
|
12
|
+
import { ContentfulAssetData, ContentfulData } from './models';
|
|
12
13
|
export interface IContentfulContentClient {
|
|
13
14
|
readonly user: User;
|
|
14
15
|
readonly locale: string;
|
|
@@ -25,6 +26,7 @@ export interface IContentfulContentClient {
|
|
|
25
26
|
createEntry<TEntry extends ContentfulData>(contentType: string, entry: ContentfulData.Draft<TEntry>): Promise<TEntry>;
|
|
26
27
|
getEntry<TEntry extends ContentfulData>(args: IContentfulContentClient.GetEntry.Args<TEntry>): Promise<IContentfulContentClient.GetEntry.Result<TEntry>>;
|
|
27
28
|
getEntries<TEntry extends ContentfulData>(args: IContentfulContentClient.GetEntries.Args<TEntry>): Promise<IContentfulContentClient.GetEntries.Result<TEntry>>;
|
|
29
|
+
uploadAsset(args: IContentfulContentClient.UploadAsset.Args): Promise<IContentfulContentClient.UploadAsset.Result>;
|
|
28
30
|
}
|
|
29
31
|
export declare namespace IContentfulContentClient {
|
|
30
32
|
type EntryQueryOptions = {
|
|
@@ -32,21 +34,28 @@ export declare namespace IContentfulContentClient {
|
|
|
32
34
|
version?: Environment;
|
|
33
35
|
};
|
|
34
36
|
namespace GetEntry {
|
|
35
|
-
type Args<TEntry extends ContentfulData> = EntryQueryOptions & {
|
|
37
|
+
type Args<TEntry extends ContentfulData> = Pick<QueryOptions, 'content_type' | 'select'> & EntryQueryOptions & {
|
|
36
38
|
entryId: ContentfulData.EntryId<TEntry>;
|
|
37
39
|
};
|
|
38
40
|
type Result<TEntry extends ContentfulData> = {
|
|
39
|
-
entry: TEntry;
|
|
41
|
+
entry: TEntry | undefined;
|
|
40
42
|
references: ContentfulData[];
|
|
41
43
|
};
|
|
42
44
|
}
|
|
43
45
|
namespace GetEntries {
|
|
44
|
-
type Args<TEntry extends ContentfulData> = Omit<QueryOptions, 'content_type' | 'include'> & EntryQueryOptions & {
|
|
46
|
+
type Args<TEntry extends ContentfulData> = Omit<QueryOptions, 'content_type' | 'include' | 'limit' | 'skip'> & EntryQueryOptions & {
|
|
45
47
|
content_type: ContentfulData.ContentType<TEntry>;
|
|
48
|
+
pagination?: Pagination;
|
|
46
49
|
};
|
|
47
|
-
type Result<TEntry extends ContentfulData> = {
|
|
50
|
+
type Result<TEntry extends ContentfulData> = Pagination.Counts & {
|
|
48
51
|
entries: TEntry[];
|
|
49
52
|
references: ContentfulData[];
|
|
50
53
|
};
|
|
51
54
|
}
|
|
55
|
+
namespace UploadAsset {
|
|
56
|
+
type Args = AssetClient.CreateAsset.Args & {
|
|
57
|
+
file: Blob;
|
|
58
|
+
};
|
|
59
|
+
type Result = ContentfulAssetData;
|
|
60
|
+
}
|
|
52
61
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Schema } from '@nascentdigital/funnel-core';
|
|
2
2
|
import { ContentfulData } from './ContentfulData';
|
|
3
|
-
export type ContentfulAssetData = ContentfulData<ContentfulAssetData.ContentType, Schema.Asset.Id> & Omit<Schema.
|
|
3
|
+
export type ContentfulAssetData = ContentfulData<ContentfulAssetData.ContentType, Schema.Asset.Id> & Omit<Schema.Asset.Linked['value'], 'id'> & {
|
|
4
|
+
media: ContentfulData.Link.Asset;
|
|
5
|
+
};
|
|
4
6
|
export declare namespace ContentfulAssetData {
|
|
5
7
|
const contentType: "asset";
|
|
6
8
|
type ContentType = typeof contentType;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { RequiredBy, Schema } from '@nascentdigital/funnel-core';
|
|
2
2
|
import { ContentfulData } from './ContentfulData';
|
|
3
|
-
export type ContentfulCollectionData = ContentfulData<ContentfulCollectionData.ContentType, Schema.Collection.Id> & Omit<Schema.Collection.Data, 'id' | 'changeSetId' | 'snapshotId' | 'snapshot'
|
|
3
|
+
export type ContentfulCollectionData = ContentfulData<ContentfulCollectionData.ContentType, Schema.Collection.Id> & Omit<Schema.Collection.Data, 'id' | 'changeSetId' | 'snapshotId' | 'snapshot'> & {
|
|
4
|
+
references: ContentfulData.References;
|
|
5
|
+
};
|
|
4
6
|
export declare namespace ContentfulCollectionData {
|
|
5
7
|
const contentType: "collection";
|
|
6
8
|
type ContentType = typeof contentType;
|
|
7
|
-
type ForSchema = Schema.Collection.Data
|
|
9
|
+
type ForSchema = Schema.Collection.Data;
|
|
8
10
|
type Potential = RequiredBy<Partial<ContentfulCollectionData>, keyof ContentfulData<ContentfulCollectionData.ContentType, Schema.Collection.Id>>;
|
|
9
11
|
function deserialize(data: Potential, props?: ReadonlyArray<Schema.Collection.Data.Props.All>): ForSchema;
|
|
10
12
|
function deserializeRefs(refs: ContentfulData[]): Schema.Collection.References;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ContentfulCollectionData = void 0;
|
|
4
4
|
const funnel_core_1 = require("@nascentdigital/funnel-core");
|
|
5
5
|
const ContentfulAssetData_1 = require("./ContentfulAssetData");
|
|
6
|
+
const ContentfulPageData_1 = require("./ContentfulPageData");
|
|
6
7
|
// extension
|
|
7
8
|
var ContentfulCollectionData;
|
|
8
9
|
(function (ContentfulCollectionData) {
|
|
@@ -71,6 +72,7 @@ var ContentfulCollectionData;
|
|
|
71
72
|
// setup
|
|
72
73
|
const files = {};
|
|
73
74
|
const collections = {};
|
|
75
|
+
const pages = {};
|
|
74
76
|
// loop over references and serialize
|
|
75
77
|
for (const ref of refs) {
|
|
76
78
|
switch (ref.__type) {
|
|
@@ -86,12 +88,18 @@ var ContentfulCollectionData;
|
|
|
86
88
|
collections[collectionRef.id] = ContentfulCollectionData.deserialize(collectionRef, funnel_core_1.Schema.Collection.Data.AsLink.props);
|
|
87
89
|
break;
|
|
88
90
|
}
|
|
91
|
+
// page
|
|
92
|
+
case ContentfulPageData_1.ContentfulPageData.contentType: {
|
|
93
|
+
const pageRef = ref;
|
|
94
|
+
pages[pageRef.id] = ContentfulPageData_1.ContentfulPageData.deserialize(pageRef, funnel_core_1.Schema.Page.Data.AsLink.props);
|
|
95
|
+
}
|
|
89
96
|
}
|
|
90
97
|
}
|
|
91
98
|
// return
|
|
92
99
|
return {
|
|
93
100
|
files,
|
|
94
|
-
collections
|
|
101
|
+
collections,
|
|
102
|
+
pages
|
|
95
103
|
};
|
|
96
104
|
}
|
|
97
105
|
ContentfulCollectionData.deserializeRefs = deserializeRefs;
|
|
@@ -7,13 +7,12 @@ export type ContentfulData<TType extends string = string, TId extends string = s
|
|
|
7
7
|
id: TId;
|
|
8
8
|
createdOn: number;
|
|
9
9
|
updatedOn: number;
|
|
10
|
-
references: ContentfulData.References;
|
|
11
10
|
};
|
|
12
11
|
export declare namespace ContentfulData {
|
|
13
12
|
type ContentType<T extends ContentfulData> = T['__type'];
|
|
14
13
|
type EntryId<T extends ContentfulData> = T['id'];
|
|
15
14
|
type References = Array<Link.Entry | Link.Asset>;
|
|
16
|
-
type Draft<T extends ContentfulData> = Omit<T, keyof ContentfulData>;
|
|
15
|
+
type Draft<T extends ContentfulData> = Omit<T, keyof ContentfulData | '__root'>;
|
|
17
16
|
type Link<TType extends Link.Type = Link.Type> = {
|
|
18
17
|
sys: {
|
|
19
18
|
type: 'Link';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { RequiredBy, Schema } from '@nascentdigital/funnel-core';
|
|
2
2
|
import { ContentfulData } from './ContentfulData';
|
|
3
|
-
export type ContentfulPageData = ContentfulData<ContentfulPageData.ContentType, Schema.Page.Id> & Omit<Schema.Page.Data, 'id' | 'changeSetId' | 'snapshotId' | 'snapshot'
|
|
3
|
+
export type ContentfulPageData = ContentfulData<ContentfulPageData.ContentType, Schema.Page.Id> & Omit<Schema.Page.Data, 'id' | 'changeSetId' | 'snapshotId' | 'snapshot'> & {
|
|
4
|
+
references: ContentfulData.References;
|
|
5
|
+
};
|
|
4
6
|
export declare namespace ContentfulPageData {
|
|
5
7
|
const contentType: "page";
|
|
6
8
|
type ContentType = typeof contentType;
|
|
@@ -10,7 +12,11 @@ export declare namespace ContentfulPageData {
|
|
|
10
12
|
readonly asset: "files";
|
|
11
13
|
};
|
|
12
14
|
type ReferencesSpec = typeof referencesSpec;
|
|
13
|
-
type
|
|
15
|
+
type Snapshot = ContentfulData<ContentfulPageData.ContentType, Schema.PageSnapshot.Id> & Omit<Schema.PageSnapshot, 'id' | 'changeSetId'>;
|
|
16
|
+
namespace Snapshot {
|
|
17
|
+
function deserialize(snapshot: Snapshot): Schema.PageSnapshot;
|
|
18
|
+
}
|
|
19
|
+
type ForSchema = Schema.Page.Data;
|
|
14
20
|
type Potential = RequiredBy<Partial<ContentfulPageData>, keyof ContentfulData<ContentfulPageData.ContentType, Schema.Page.Id>>;
|
|
15
21
|
function deserialize(data: Potential, props?: ReadonlyArray<Schema.Page.Data.Props.All>): ForSchema;
|
|
16
22
|
function deserializeRefs(refs: ContentfulData[]): Schema.Page.References;
|
|
@@ -9,11 +9,21 @@ var ContentfulPageData;
|
|
|
9
9
|
(function (ContentfulPageData) {
|
|
10
10
|
// constants
|
|
11
11
|
ContentfulPageData.contentType = 'page';
|
|
12
|
+
// references
|
|
12
13
|
ContentfulPageData.referencesSpec = {
|
|
13
14
|
'page': 'pages',
|
|
14
15
|
'collection': 'collections',
|
|
15
16
|
'asset': 'files'
|
|
16
17
|
};
|
|
18
|
+
let Snapshot;
|
|
19
|
+
(function (Snapshot) {
|
|
20
|
+
function deserialize(snapshot) {
|
|
21
|
+
var _a, _b;
|
|
22
|
+
const data = ContentfulPageData.deserialize(snapshot, funnel_core_1.Schema.PageSnapshot.props);
|
|
23
|
+
return Object.assign(Object.assign({}, data), { changeSetId: ((_b = (_a = snapshot === null || snapshot === void 0 ? void 0 : snapshot.__version) === null || _a === void 0 ? void 0 : _a.toString()) !== null && _b !== void 0 ? _b : 'unknown') });
|
|
24
|
+
}
|
|
25
|
+
Snapshot.deserialize = deserialize;
|
|
26
|
+
})(Snapshot = ContentfulPageData.Snapshot || (ContentfulPageData.Snapshot = {}));
|
|
17
27
|
function deserialize(data, props = funnel_core_1.Schema.Page.Data.Props.all) {
|
|
18
28
|
var _a;
|
|
19
29
|
// create base page
|
|
@@ -150,12 +150,12 @@ class StrapiPageClient {
|
|
|
150
150
|
async getGroup({ brand, groupId, type, slug, region, language, version, select }) {
|
|
151
151
|
// create base result
|
|
152
152
|
const result = {
|
|
153
|
-
group: { groupId: groupId !== null && groupId !== void 0 ? groupId : funnel_core_1.Schema.Page.GroupId.empty, brand, type, slug,
|
|
153
|
+
group: { groupId: groupId !== null && groupId !== void 0 ? groupId : funnel_core_1.Schema.Page.GroupId.empty, brand, type, slug, instances: [] }
|
|
154
154
|
};
|
|
155
155
|
// fetch baseline page (fail if it doesn't exist)
|
|
156
156
|
const client = this.provider.client;
|
|
157
157
|
const collection = client.collection('pages');
|
|
158
|
-
const { items: baselineItems = [] } = await Strapi_1.Strapi.paginate(Object.assign({ collection, pagination: 'all', fields: serialization_1.PageData.getStrapiFilter(funnel_core_1.Schema.Page.Data.Props.id) }, getPageQueryParams({ version, brand, groupId, type, slug
|
|
158
|
+
const { items: baselineItems = [] } = await Strapi_1.Strapi.paginate(Object.assign({ collection, pagination: 'all', fields: serialization_1.PageData.getStrapiFilter(funnel_core_1.Schema.Page.Data.Props.id) }, getPageQueryParams({ version, brand, groupId, type, slug })));
|
|
159
159
|
const [baselinePage] = baselineItems;
|
|
160
160
|
if (!baselinePage) {
|
|
161
161
|
return result;
|
|
@@ -172,7 +172,7 @@ class StrapiPageClient {
|
|
|
172
172
|
const instance = serialization_1.PageData.deserializeLegacy(item, client.baseURL, funnel_core_1.Schema.Page.Data.AsGroup.Instance.props);
|
|
173
173
|
group.instances.push(instance);
|
|
174
174
|
// set page if language matches
|
|
175
|
-
if (instance.language === language) {
|
|
175
|
+
if (instance.region === region && instance.language === language) {
|
|
176
176
|
result.page = await this.get({ id: instance.id, version, select });
|
|
177
177
|
}
|
|
178
178
|
}
|
|
@@ -187,33 +187,16 @@ class StrapiPageClient {
|
|
|
187
187
|
const resultProps = args.select === 'content'
|
|
188
188
|
? funnel_core_1.Schema.Page.Data.AsContent.props
|
|
189
189
|
: funnel_core_1.Schema.Page.Data.Props.all;
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
console.debug(`[StrapiPageClient/getPage] no "${args.version}" entry found for id ${args.id}`);
|
|
201
|
-
return undefined;
|
|
202
|
-
}
|
|
203
|
-
// or capture it
|
|
204
|
-
data = rawData;
|
|
205
|
-
}
|
|
206
|
-
// or by querying type (including region, and language)
|
|
207
|
-
else {
|
|
208
|
-
// lookup entry from collection (might be a miss)
|
|
209
|
-
const { data: rawData } = await collection.find(Object.assign({ fields: serialization_1.PageData.getStrapiFilter(resultProps), sort: ['updatedAt:desc'], populate: serialization_1.PageData.Populate.full }, getPageQueryParams(args)));
|
|
210
|
-
// skip if there's no entry
|
|
211
|
-
if (rawData.length === 0) {
|
|
212
|
-
console.warn(`[StrapiPageClient/getStaticPage] no "${args.version}" entry found for type ${args.type} in region ${args.region}/${args.language}`);
|
|
213
|
-
return undefined;
|
|
214
|
-
}
|
|
215
|
-
// or capture entry
|
|
216
|
-
data = rawData[0];
|
|
190
|
+
// find entry by document id
|
|
191
|
+
const { data } = await collection.findOne(args.id, {
|
|
192
|
+
fields: serialization_1.PageData.getStrapiFilter(resultProps),
|
|
193
|
+
status: args.version,
|
|
194
|
+
populate: serialization_1.PageData.Populate.full
|
|
195
|
+
});
|
|
196
|
+
// skip if there's no entry
|
|
197
|
+
if (!data) {
|
|
198
|
+
console.debug(`[StrapiPageClient/getPage] no "${args.version}" entry found for id ${args.id}`);
|
|
199
|
+
return undefined;
|
|
217
200
|
}
|
|
218
201
|
// convert and return
|
|
219
202
|
return serialization_1.PageData.deserializeFlattened(data, strapiUrl, resultProps);
|
|
@@ -239,13 +222,14 @@ class StrapiPageClient {
|
|
|
239
222
|
throw new funnel_core_1.ArgumentError(`Page group "${args.groupId}" no longer exists in "${args.brand}"`);
|
|
240
223
|
}
|
|
241
224
|
// return existing page if it's there
|
|
242
|
-
let existingPage = existingPages
|
|
225
|
+
let existingPage = existingPages
|
|
226
|
+
.find(existing => existing.region === args.region && existing.language === args.language);
|
|
243
227
|
if (existingPage) {
|
|
244
228
|
return this.getGroup(Object.assign(Object.assign({}, existingPage), { version: 'draft' }));
|
|
245
229
|
}
|
|
246
230
|
// bind data + update url
|
|
247
231
|
existingPage = existingPages[0];
|
|
248
|
-
const draft = funnel_core_1.Schema.PageModel.fromDraft(Object.assign({ type: existingPage.type, slug: existingPage.slug, url: existingPage.url,
|
|
232
|
+
const draft = funnel_core_1.Schema.PageModel.fromDraft(Object.assign({ type: existingPage.type, slug: existingPage.slug, url: existingPage.url, name: existingPage.name, tags: existingPage.tags }, args));
|
|
249
233
|
draft.sync();
|
|
250
234
|
// resolve change set (rebind)
|
|
251
235
|
const { provider } = this;
|
|
@@ -290,13 +274,13 @@ class StrapiPageClient {
|
|
|
290
274
|
groupId: page.groupId,
|
|
291
275
|
brand: page.brand,
|
|
292
276
|
type: page.type,
|
|
293
|
-
region: page.region,
|
|
294
277
|
slug: page.slug,
|
|
295
278
|
instances: [
|
|
296
|
-
...existingPages.map(({ id, url, language, name, slug, tags, state, errors, createdOn, updatedOn, publishedOn }) => ({ id, url, language, name, slug, tags, state, errors, createdOn, updatedOn, publishedOn })),
|
|
279
|
+
...existingPages.map(({ id, url, region, language, name, slug, tags, state, errors, createdOn, updatedOn, publishedOn }) => ({ id, url, region, language, name, slug, tags, state, errors, createdOn, updatedOn, publishedOn })),
|
|
297
280
|
{
|
|
298
281
|
id: page.id,
|
|
299
282
|
url: page.url,
|
|
283
|
+
region: page.region,
|
|
300
284
|
language: page.language,
|
|
301
285
|
name: page.name,
|
|
302
286
|
slug: page.slug,
|
|
@@ -345,8 +329,8 @@ class StrapiPageClient {
|
|
|
345
329
|
brand: args.brand,
|
|
346
330
|
type: args.type,
|
|
347
331
|
region: args.region,
|
|
348
|
-
|
|
349
|
-
|
|
332
|
+
language: args.language,
|
|
333
|
+
slug: args.slug
|
|
350
334
|
});
|
|
351
335
|
// return existing page if it's there
|
|
352
336
|
if (existingPage) {
|
|
@@ -400,13 +384,13 @@ class StrapiPageClient {
|
|
|
400
384
|
groupId: page.groupId,
|
|
401
385
|
brand: page.brand,
|
|
402
386
|
type: page.type,
|
|
403
|
-
region: args.region,
|
|
404
387
|
slug: page.slug,
|
|
405
388
|
instances: [
|
|
406
389
|
...existingGroup.instances,
|
|
407
390
|
{
|
|
408
391
|
id: page.id,
|
|
409
392
|
url: page.url,
|
|
393
|
+
region: args.region,
|
|
410
394
|
language: page.language,
|
|
411
395
|
name: page.name,
|
|
412
396
|
slug: page.slug,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nascentdigital/funnel-cms",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"url": "git+https://github.com/nascentdigital/funnel.git",
|
|
6
6
|
"directory": "libs/cms"
|
|
@@ -48,5 +48,5 @@
|
|
|
48
48
|
"ts-jest": "^29",
|
|
49
49
|
"type-fest": "^4"
|
|
50
50
|
},
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "83e335312f91fb90aae73dfc31b3df1ec1895f76"
|
|
52
52
|
}
|