UNPKG

gatsby-source-prismic

Version:

Gatsby source plugin for building websites using Prismic as a data source

117 lines (112 loc) 3.84 kB
import * as RTE from "fp-ts/ReaderTaskEither"; import * as A from "fp-ts/Array"; import * as s from "fp-ts/string"; import { pipe, constVoid } from "fp-ts/function"; import { deleteNodesForDocumentIds } from "./lib/deleteNodesForDocumentIds"; import { queryDocumentsByIds } from "./lib/queryDocumentsByIds"; import { reportInfo } from "./lib/reportInfo"; import { sourceNodesForDocumentIds } from "./lib/sourceNodesForDocumentIds"; import { touchAllNodes } from "./lib/touchAllNodes"; import { Dependencies, PrismicWebhookBodyApiUpdate } from "./types"; /** * Extract all document IDs from a Prismic `api-update` webhook body. All * document IDs, including deleted documents, are returned in the same list. */ const extractApiUpdateWebhookBodyDocumentIds = ( webhookBody: PrismicWebhookBodyApiUpdate, ): RTE.ReaderTaskEither<Dependencies, never, string[]> => pipe( RTE.ask<Dependencies>(), RTE.bindW("documentIds", () => RTE.right(webhookBody.documents)), RTE.bindW("releaseDocumentIds", (scope) => pipe( [ ...(webhookBody.releases.update || []), ...(webhookBody.releases.addition || []), ...(webhookBody.releases.deletion || []), ], A.filter((payload) => payload.id === scope.pluginOptions.releaseID), A.chain((payload) => payload.documents), RTE.right, ), ), RTE.map((scope) => [ ...new Set([...scope.documentIds, ...scope.releaseDocumentIds]), ]), ); /** * To be executed in the `sourceNodes` API when a Prismic `api-update` webhook * is received. * * This handler is implemented specifically for Gatsby Preview support. * * This handler performs delta changes to documents that have been updated or deleted. * * - UPDATED documents: Nodes are updated in the Gatsby data layer. * - DELETED documents: Nodes are deleted from the Gatsby data layer. * * After the handler is complete, the Gatsby data layer should be identical to * one that just performed a fresh bootstrap. */ export const onWebhookApiUpdate = ( webhookBody: PrismicWebhookBodyApiUpdate, ): RTE.ReaderTaskEither<Dependencies, Error, void> => pipe( RTE.ask<Dependencies>(), RTE.chainFirst(() => reportInfo("Received API update webhook. Processing changes."), ), RTE.bind("documentIds", () => extractApiUpdateWebhookBodyDocumentIds(webhookBody), ), RTE.bind("documentsToUpdate", (scope) => queryDocumentsByIds(scope.documentIds), ), RTE.bind("documentIdsToUpdate", (scope) => pipe( scope.documentsToUpdate, A.map((document) => document.id), (ids) => RTE.right(ids), ), ), // Documents that have been deleted are included in the `documents` field, // but they are not marked as deleted. They appear adjacent to documents // that still exist but have only been updated. // // To check if the document was deleted, we query for all documents in the // `documents` field and compare the result to that list. Documents that // have been deleted will not be returned from the query. RTE.bind("documentIdsToDelete", (scope) => pipe( scope.documentIds, A.difference(s.Eq)(scope.documentIdsToUpdate), (ids) => RTE.right(ids), ), ), RTE.chainFirstW((scope) => reportInfo( `Adding or updating the following Prismic documents: [${scope.documentIdsToUpdate .map((id) => `"${id}"`) .join(", ")}]`, ), ), RTE.chainFirstW((scope) => reportInfo( `Deleting the following Prismic documents: [${scope.documentIdsToDelete .map((id) => `"${id}"`) .join(", ")}]`, ), ), RTE.chainFirstW((scope) => deleteNodesForDocumentIds(scope.documentIdsToDelete), ), RTE.chainFirstW((scope) => sourceNodesForDocumentIds(scope.documentIdsToUpdate), ), RTE.chainFirstW((scope) => touchAllNodes({ exceptPrismicIds: scope.documentIdsToDelete, }), ), RTE.map(constVoid), );