@stackbit/cms-contentstack 0.1.1-staging.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/README.md +1 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/contentstack-api-client.d.ts +63 -0
- package/dist/contentstack-api-client.d.ts.map +1 -0
- package/dist/contentstack-api-client.js +295 -0
- package/dist/contentstack-api-client.js.map +1 -0
- package/dist/contentstack-content-poller.d.ts +46 -0
- package/dist/contentstack-content-poller.d.ts.map +1 -0
- package/dist/contentstack-content-poller.js +111 -0
- package/dist/contentstack-content-poller.js.map +1 -0
- package/dist/contentstack-content-source.d.ts +138 -0
- package/dist/contentstack-content-source.d.ts.map +1 -0
- package/dist/contentstack-content-source.js +544 -0
- package/dist/contentstack-content-source.js.map +1 -0
- package/dist/contentstack-conversion-utils.d.ts +41 -0
- package/dist/contentstack-conversion-utils.d.ts.map +1 -0
- package/dist/contentstack-conversion-utils.js +504 -0
- package/dist/contentstack-conversion-utils.js.map +1 -0
- package/dist/contentstack-entries-converter.d.ts +39 -0
- package/dist/contentstack-entries-converter.d.ts.map +1 -0
- package/dist/contentstack-entries-converter.js +333 -0
- package/dist/contentstack-entries-converter.js.map +1 -0
- package/dist/contentstack-operation-converter.d.ts +42 -0
- package/dist/contentstack-operation-converter.d.ts.map +1 -0
- package/dist/contentstack-operation-converter.js +535 -0
- package/dist/contentstack-operation-converter.js.map +1 -0
- package/dist/contentstack-schema-converter.d.ts +26 -0
- package/dist/contentstack-schema-converter.d.ts.map +1 -0
- package/dist/contentstack-schema-converter.js +379 -0
- package/dist/contentstack-schema-converter.js.map +1 -0
- package/dist/contentstack-types.d.ts +429 -0
- package/dist/contentstack-types.d.ts.map +1 -0
- package/dist/contentstack-types.js +3 -0
- package/dist/contentstack-types.js.map +1 -0
- package/dist/contentstack-utils.d.ts +31 -0
- package/dist/contentstack-utils.d.ts.map +1 -0
- package/dist/contentstack-utils.js +144 -0
- package/dist/contentstack-utils.js.map +1 -0
- package/dist/entries-converter.d.ts +10 -0
- package/dist/entries-converter.d.ts.map +1 -0
- package/dist/entries-converter.js +245 -0
- package/dist/entries-converter.js.map +1 -0
- package/dist/file-download.d.ts +2 -0
- package/dist/file-download.d.ts.map +1 -0
- package/dist/file-download.js +33 -0
- package/dist/file-download.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/schema-converter.d.ts +3 -0
- package/dist/schema-converter.d.ts.map +1 -0
- package/dist/schema-converter.js +169 -0
- package/dist/schema-converter.js.map +1 -0
- package/dist/transformation-utils.d.ts +41 -0
- package/dist/transformation-utils.d.ts.map +1 -0
- package/dist/transformation-utils.js +730 -0
- package/dist/transformation-utils.js.map +1 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
- package/src/contentstack-api-client.ts +330 -0
- package/src/contentstack-content-poller.ts +157 -0
- package/src/contentstack-content-source.ts +687 -0
- package/src/contentstack-entries-converter.ts +438 -0
- package/src/contentstack-operation-converter.ts +703 -0
- package/src/contentstack-schema-converter.ts +486 -0
- package/src/contentstack-types.ts +527 -0
- package/src/contentstack-utils.ts +174 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import type { Logger } from '@stackbit/types';
|
|
3
|
+
import type { ContentStackClient } from './contentstack-api-client';
|
|
4
|
+
import type { ContentType, GlobalField, Entry, Asset } from './contentstack-types';
|
|
5
|
+
|
|
6
|
+
export type SyncContext = {
|
|
7
|
+
lastUpdatedEntryDate?: string;
|
|
8
|
+
lastUpdatedAssetDate?: string;
|
|
9
|
+
lastUpdatedContentTypeDate?: string;
|
|
10
|
+
lastUpdatedGlobalFieldDate?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export interface SyncResult {
|
|
14
|
+
entries: Entry[];
|
|
15
|
+
assets: Asset[];
|
|
16
|
+
contentTypes: ContentType[];
|
|
17
|
+
globalFields: GlobalField[];
|
|
18
|
+
deletedEntries: Entry[];
|
|
19
|
+
deletedAssets: Asset[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type SyncCallback = (result: SyncResult) => void;
|
|
23
|
+
|
|
24
|
+
export class ContentPoller {
|
|
25
|
+
private readonly logger: Logger;
|
|
26
|
+
private readonly contentStackClient: ContentStackClient;
|
|
27
|
+
private readonly notificationCallback: SyncCallback;
|
|
28
|
+
private readonly pollingIntervalMs: number;
|
|
29
|
+
private readonly modelNames: string[];
|
|
30
|
+
private running: boolean;
|
|
31
|
+
private pollTimeout: NodeJS.Timeout | null;
|
|
32
|
+
private syncContext!: Required<SyncContext>;
|
|
33
|
+
|
|
34
|
+
constructor({
|
|
35
|
+
modelNames,
|
|
36
|
+
contentStackClient,
|
|
37
|
+
syncContext,
|
|
38
|
+
pollingIntervalMs = 2000,
|
|
39
|
+
notificationCallback,
|
|
40
|
+
logger
|
|
41
|
+
}: {
|
|
42
|
+
modelNames: string[];
|
|
43
|
+
contentStackClient: ContentStackClient;
|
|
44
|
+
syncContext?: SyncContext;
|
|
45
|
+
pollingIntervalMs?: number;
|
|
46
|
+
notificationCallback: SyncCallback;
|
|
47
|
+
logger: Logger;
|
|
48
|
+
}) {
|
|
49
|
+
this.logger = logger;
|
|
50
|
+
this.modelNames = modelNames;
|
|
51
|
+
this.running = false;
|
|
52
|
+
this.pollTimeout = null;
|
|
53
|
+
this.pollingIntervalMs = pollingIntervalMs;
|
|
54
|
+
this.contentStackClient = contentStackClient;
|
|
55
|
+
this.notificationCallback = notificationCallback;
|
|
56
|
+
this.setSyncContext(syncContext);
|
|
57
|
+
this.handleTimeout = this.handleTimeout.bind(this);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
start() {
|
|
61
|
+
this.logger.debug(`start polling Contentstack for content changes`);
|
|
62
|
+
if (!this.running) {
|
|
63
|
+
this.running = true;
|
|
64
|
+
this.setPollTimeout();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
stop() {
|
|
69
|
+
this.logger.debug(`stop polling Contentstack for content changes`);
|
|
70
|
+
if (this.pollTimeout) {
|
|
71
|
+
clearTimeout(this.pollTimeout);
|
|
72
|
+
this.pollTimeout = null;
|
|
73
|
+
}
|
|
74
|
+
this.running = false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
setSyncContext(syncContext?: SyncContext) {
|
|
78
|
+
const now = new Date().toISOString();
|
|
79
|
+
this.syncContext = {
|
|
80
|
+
lastUpdatedEntryDate: syncContext?.lastUpdatedEntryDate ?? now,
|
|
81
|
+
lastUpdatedAssetDate: syncContext?.lastUpdatedAssetDate ?? now,
|
|
82
|
+
lastUpdatedContentTypeDate: syncContext?.lastUpdatedContentTypeDate ?? now,
|
|
83
|
+
lastUpdatedGlobalFieldDate: syncContext?.lastUpdatedGlobalFieldDate ?? now
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private setPollTimeout() {
|
|
88
|
+
if (this.pollTimeout) {
|
|
89
|
+
clearTimeout(this.pollTimeout);
|
|
90
|
+
}
|
|
91
|
+
this.pollTimeout = setTimeout(this.handleTimeout, this.pollingIntervalMs);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async handleTimeout() {
|
|
95
|
+
this.pollTimeout = null;
|
|
96
|
+
try {
|
|
97
|
+
await this.pollContent();
|
|
98
|
+
} catch (error: any) {
|
|
99
|
+
this.logger.warn('error polling', { error: error.message });
|
|
100
|
+
}
|
|
101
|
+
if (this.running) {
|
|
102
|
+
this.setPollTimeout();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async pollContent(): Promise<any> {
|
|
107
|
+
const prevSyncContext = this.syncContext;
|
|
108
|
+
const [entries, assets, contentTypes, globalFields] = await Promise.all([
|
|
109
|
+
this.contentStackClient.getAllEntriesUpdatedAfter(this.modelNames, this.syncContext.lastUpdatedEntryDate),
|
|
110
|
+
this.contentStackClient.getAssetsUpdatedAfter(this.syncContext.lastUpdatedAssetDate),
|
|
111
|
+
this.contentStackClient.getContentTypesUpdatedAfter(this.syncContext.lastUpdatedContentTypeDate),
|
|
112
|
+
this.contentStackClient.getGlobalFieldsUpdatedAfter(this.syncContext.lastUpdatedGlobalFieldDate)
|
|
113
|
+
]);
|
|
114
|
+
// Check that syncContext wasn't updated externally by calling
|
|
115
|
+
// setLastUpdatedAt() while the content is being fetched. If it was
|
|
116
|
+
// updated, then ignore the dates from the fetched content and use the
|
|
117
|
+
// syncContext that was set externally in the next poll.
|
|
118
|
+
if (_.isEqual(prevSyncContext, this.syncContext)) {
|
|
119
|
+
this.syncContext = _.defaults(
|
|
120
|
+
{
|
|
121
|
+
lastUpdatedEntryDate: getLastUpdatedEntityDate(entries),
|
|
122
|
+
lastUpdatedAssetDate: getLastUpdatedEntityDate(assets),
|
|
123
|
+
lastUpdatedContentTypeDate: getLastUpdatedEntityDate(contentTypes),
|
|
124
|
+
lastUpdatedGlobalFieldDate: getLastUpdatedEntityDate(globalFields)
|
|
125
|
+
},
|
|
126
|
+
this.syncContext
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
if (contentTypes.length || globalFields.length || entries.length || assets.length) {
|
|
130
|
+
this.logger.info(
|
|
131
|
+
`poll date response: got ` +
|
|
132
|
+
`${entries.length} changed entries, ` +
|
|
133
|
+
`${assets.length} changed assets, ` +
|
|
134
|
+
`${contentTypes.length} changed content types` +
|
|
135
|
+
`${globalFields.length} changed global fields`
|
|
136
|
+
);
|
|
137
|
+
this.notificationCallback({
|
|
138
|
+
contentTypes,
|
|
139
|
+
globalFields,
|
|
140
|
+
entries,
|
|
141
|
+
assets,
|
|
142
|
+
deletedEntries: [],
|
|
143
|
+
deletedAssets: []
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function getLastUpdatedEntityDate(entities: { updated_at?: string }[]): string | undefined {
|
|
150
|
+
let lastUpdatedDate: string = '';
|
|
151
|
+
for (const entity of entities) {
|
|
152
|
+
if (entity.updated_at! > lastUpdatedDate) {
|
|
153
|
+
lastUpdatedDate = entity.updated_at!;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return lastUpdatedDate || undefined;
|
|
157
|
+
}
|