1
1
/* eslint-disable @typescript-eslint/no-explicit-any */
2
2
import { getContentfulClient } from "../config/client.js"
3
3
import { summarizeData } from "../utils/summarizer.js"
4
- import { CreateEntryProps , EntryProps , QueryOptions } from "contentful-management"
4
+ import {
5
+ CreateEntryProps ,
6
+ EntryProps ,
7
+ QueryOptions ,
8
+ BulkActionProps ,
9
+ Link ,
10
+ Collection ,
11
+ } from "contentful-management"
12
+
13
+ // Define the interface for bulk action responses with succeeded property
14
+ interface BulkActionResponse extends BulkActionProps < any > {
15
+ succeeded ?: Array < {
16
+ sys : {
17
+ id : string
18
+ type : string
19
+ }
20
+ } >
21
+ }
22
+
23
+ // Define the interface for versioned links
24
+ interface VersionedLink {
25
+ sys : {
26
+ type : "Link"
27
+ linkType : "Entry" | "Asset"
28
+ id : string
29
+ version : number
30
+ }
31
+ }
5
32
6
33
export const entryHandlers = {
7
34
searchEntries : async ( args : { spaceId : string ; environmentId : string ; query : QueryOptions } ) => {
@@ -19,13 +46,13 @@ export const entryHandlers = {
19
46
query : {
20
47
...args . query ,
21
48
limit : Math . min ( args . query . limit || 3 , 3 ) ,
22
- skip : args . query . skip || 0
49
+ skip : args . query . skip || 0 ,
23
50
} ,
24
51
} )
25
52
26
53
const summarized = summarizeData ( entries , {
27
54
maxItems : 3 ,
28
- remainingMessage : "To see more entries, please ask me to retrieve the next page."
55
+ remainingMessage : "To see more entries, please ask me to retrieve the next page." ,
29
56
} )
30
57
31
58
return {
@@ -121,35 +148,128 @@ export const entryHandlers = {
121
148
}
122
149
} ,
123
150
124
- publishEntry : async ( args : {
125
- spaceId : string ;
126
- environmentId : string ;
127
- entryId : string | string [ ]
151
+ publishEntry : async ( args : {
152
+ spaceId : string
153
+ environmentId : string
154
+ entryId : string | string [ ]
128
155
} ) => {
129
156
const spaceId = process . env . SPACE_ID || args . spaceId
130
157
const environmentId = process . env . ENVIRONMENT_ID || args . environmentId
131
158
132
- // If entryId is an array, use bulkPublish instead
133
- if ( Array . isArray ( args . entryId ) ) {
134
- const bulkActionHandlers = await import ( "./bulk-action-handlers.js" ) . then ( module => module . bulkActionHandlers )
135
-
136
- // Map entry IDs to the expected format for bulkPublish
137
- const entities = args . entryId . map ( id => ( {
138
- sys : { id, type : "Entry" as const }
139
- } ) )
140
-
141
- return bulkActionHandlers . bulkPublish ( {
142
- spaceId,
143
- environmentId,
144
- entities
145
- } )
146
- }
147
-
159
+ // Handle case where entryId is a JSON string representation of an array
160
+ let entryId = args . entryId
161
+ if ( typeof entryId === "string" && entryId . startsWith ( "[" ) && entryId . endsWith ( "]" ) ) {
162
+ try {
163
+ entryId = JSON . parse ( entryId )
164
+ } catch ( e ) {
165
+ // If parsing fails, keep it as string
166
+ console . error ( "Failed to parse entryId as JSON array:" , e )
167
+ }
168
+ }
169
+
170
+ // If entryId is an array, handle bulk publishing
171
+ if ( Array . isArray ( entryId ) ) {
172
+ try {
173
+ const contentfulClient = await getContentfulClient ( )
174
+
175
+ // Get the current version of each entity
176
+ const entryVersions = await Promise . all (
177
+ entryId . map ( async ( id ) => {
178
+ try {
179
+ // Get the current version of the entry
180
+ const currentEntry = await contentfulClient . entry . get ( {
181
+ spaceId,
182
+ environmentId,
183
+ entryId : id ,
184
+ } )
185
+
186
+ // Create a versioned link according to the API docs
187
+ const versionedLink : VersionedLink = {
188
+ sys : {
189
+ type : "Link" ,
190
+ linkType : "Entry" ,
191
+ id : id ,
192
+ version : currentEntry . sys . version ,
193
+ } ,
194
+ }
195
+ return versionedLink
196
+ } catch ( error ) {
197
+ console . error ( `Error fetching entry ${ id } : ${ error } ` )
198
+ throw new Error (
199
+ `Failed to get version for entry ${ id } . All entries must have a version.` ,
200
+ )
201
+ }
202
+ } ) ,
203
+ )
204
+
205
+ // Create the correct entities format according to Contentful API docs
206
+ const entities : {
207
+ sys : { type : "Array" }
208
+ items : VersionedLink [ ]
209
+ } = {
210
+ sys : {
211
+ type : "Array" ,
212
+ } ,
213
+ items : entryVersions ,
214
+ }
215
+
216
+ // Create the bulk action
217
+ const bulkAction = await contentfulClient . bulkAction . publish (
218
+ {
219
+ spaceId,
220
+ environmentId,
221
+ } ,
222
+ {
223
+ entities,
224
+ } ,
225
+ )
226
+
227
+ // Wait for the bulk action to complete
228
+ let action = ( await contentfulClient . bulkAction . get ( {
229
+ spaceId,
230
+ environmentId,
231
+ bulkActionId : bulkAction . sys . id ,
232
+ } ) ) as BulkActionResponse // Cast to our extended interface
233
+
234
+ while ( action . sys . status === "inProgress" || action . sys . status === "created" ) {
235
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) )
236
+ action = ( await contentfulClient . bulkAction . get ( {
237
+ spaceId,
238
+ environmentId,
239
+ bulkActionId : bulkAction . sys . id ,
240
+ } ) ) as BulkActionResponse // Cast to our extended interface
241
+ }
242
+
243
+ return {
244
+ content : [
245
+ {
246
+ type : "text" ,
247
+ text : `Bulk publish completed with status: ${ action . sys . status } . ${
248
+ action . sys . status === "failed"
249
+ ? `Error: ${ JSON . stringify ( action . error ) } `
250
+ : `Successfully processed items.`
251
+ } `,
252
+ } ,
253
+ ] ,
254
+ }
255
+ } catch ( error ) {
256
+ return {
257
+ content : [
258
+ {
259
+ type : "text" ,
260
+ text : `Error during bulk publish: ${ error instanceof Error ? error . message : String ( error ) } ` ,
261
+ } ,
262
+ ] ,
263
+ isError : true ,
264
+ }
265
+ }
266
+ }
267
+
148
268
// Handle single entry publishing
149
269
const params = {
150
270
spaceId,
151
271
environmentId,
152
- entryId : args . entryId ,
272
+ entryId : entryId as string ,
153
273
}
154
274
155
275
const contentfulClient = await getContentfulClient ( )
@@ -159,41 +279,134 @@ export const entryHandlers = {
159
279
sys : currentEntry . sys ,
160
280
fields : currentEntry . fields ,
161
281
} )
162
-
282
+
163
283
return {
164
284
content : [ { type : "text" , text : JSON . stringify ( entry , null , 2 ) } ] ,
165
285
}
166
286
} ,
167
287
168
- unpublishEntry : async ( args : {
169
- spaceId : string ;
170
- environmentId : string ;
171
- entryId : string | string [ ]
288
+ unpublishEntry : async ( args : {
289
+ spaceId : string
290
+ environmentId : string
291
+ entryId : string | string [ ]
172
292
} ) => {
173
293
const spaceId = process . env . SPACE_ID || args . spaceId
174
294
const environmentId = process . env . ENVIRONMENT_ID || args . environmentId
175
295
176
- // If entryId is an array, use bulkUnpublish instead
177
- if ( Array . isArray ( args . entryId ) ) {
178
- const bulkActionHandlers = await import ( "./bulk-action-handlers.js" ) . then ( module => module . bulkActionHandlers )
179
-
180
- // Map entry IDs to the expected format for bulkUnpublish
181
- const entities = args . entryId . map ( id => ( {
182
- sys : { id, type : "Entry" as const }
183
- } ) )
184
-
185
- return bulkActionHandlers . bulkUnpublish ( {
186
- spaceId,
187
- environmentId,
188
- entities
189
- } )
190
- }
191
-
296
+ // Handle case where entryId is a JSON string representation of an array
297
+ let entryId = args . entryId
298
+ if ( typeof entryId === "string" && entryId . startsWith ( "[" ) && entryId . endsWith ( "]" ) ) {
299
+ try {
300
+ entryId = JSON . parse ( entryId )
301
+ } catch ( e ) {
302
+ // If parsing fails, keep it as string
303
+ console . error ( "Failed to parse entryId as JSON array:" , e )
304
+ }
305
+ }
306
+
307
+ // If entryId is an array, handle bulk unpublishing
308
+ if ( Array . isArray ( entryId ) ) {
309
+ try {
310
+ const contentfulClient = await getContentfulClient ( )
311
+
312
+ // Get the current version of each entity
313
+ const entryVersions = await Promise . all (
314
+ entryId . map ( async ( id ) => {
315
+ try {
316
+ // Get the current version of the entry
317
+ const currentEntry = await contentfulClient . entry . get ( {
318
+ spaceId,
319
+ environmentId,
320
+ entryId : id ,
321
+ } )
322
+
323
+ // Create a versioned link according to the API docs
324
+ const versionedLink : VersionedLink = {
325
+ sys : {
326
+ type : "Link" ,
327
+ linkType : "Entry" ,
328
+ id : id ,
329
+ version : currentEntry . sys . version ,
330
+ } ,
331
+ }
332
+ return versionedLink
333
+ } catch ( error ) {
334
+ console . error ( `Error fetching entry ${ id } : ${ error } ` )
335
+ throw new Error (
336
+ `Failed to get version for entry ${ id } . All entries must have a version.` ,
337
+ )
338
+ }
339
+ } ) ,
340
+ )
341
+
342
+ // Create the correct entities format according to Contentful API docs
343
+ const entities : {
344
+ sys : { type : "Array" }
345
+ items : VersionedLink [ ]
346
+ } = {
347
+ sys : {
348
+ type : "Array" ,
349
+ } ,
350
+ items : entryVersions ,
351
+ }
352
+
353
+ // Create the bulk action
354
+ const bulkAction = await contentfulClient . bulkAction . unpublish (
355
+ {
356
+ spaceId,
357
+ environmentId,
358
+ } ,
359
+ {
360
+ entities,
361
+ } ,
362
+ )
363
+
364
+ // Wait for the bulk action to complete
365
+ let action = ( await contentfulClient . bulkAction . get ( {
366
+ spaceId,
367
+ environmentId,
368
+ bulkActionId : bulkAction . sys . id ,
369
+ } ) ) as BulkActionResponse // Cast to our extended interface
370
+
371
+ while ( action . sys . status === "inProgress" || action . sys . status === "created" ) {
372
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) )
373
+ action = ( await contentfulClient . bulkAction . get ( {
374
+ spaceId,
375
+ environmentId,
376
+ bulkActionId : bulkAction . sys . id ,
377
+ } ) ) as BulkActionResponse // Cast to our extended interface
378
+ }
379
+
380
+ return {
381
+ content : [
382
+ {
383
+ type : "text" ,
384
+ text : `Bulk unpublish completed with status: ${ action . sys . status } . ${
385
+ action . sys . status === "failed"
386
+ ? `Error: ${ JSON . stringify ( action . error ) } `
387
+ : `Successfully processed ${ action . succeeded ?. length || 0 } items.`
388
+ } `,
389
+ } ,
390
+ ] ,
391
+ }
392
+ } catch ( error ) {
393
+ return {
394
+ content : [
395
+ {
396
+ type : "text" ,
397
+ text : `Error during bulk unpublish: ${ error instanceof Error ? error . message : String ( error ) } ` ,
398
+ } ,
399
+ ] ,
400
+ isError : true ,
401
+ }
402
+ }
403
+ }
404
+
192
405
// Handle single entry unpublishing
193
406
const params = {
194
407
spaceId,
195
408
environmentId,
196
- entryId : args . entryId ,
409
+ entryId : entryId as string ,
197
410
}
198
411
199
412
const contentfulClient = await getContentfulClient ( )
0 commit comments