From abfcd13b672d6bef7f119af2435db49373886741 Mon Sep 17 00:00:00 2001 From: Xavier Rutayisire Date: Wed, 29 May 2024 16:16:07 +0200 Subject: [PATCH 1/7] feat(bulk-update): replace bulk by bulk-update endpoint BREAKING CHANGE: drop support for bulk endpoint --- src/{bulk.ts => bulkUpdate.ts} | 61 ++++--- src/client.ts | 65 +++---- src/errors.ts | 38 ++-- src/index.ts | 15 +- test/client-bulk.test.ts | 170 ------------------ test/client-bulkUpdate.test.ts | 111 ++++++++++++ ...ateBulkUpdateTransaction-fromDiff.test.ts} | 50 +++--- ...ts => createBulkUpdateTransaction.test.ts} | 56 +++--- 8 files changed, 248 insertions(+), 318 deletions(-) rename src/{bulk.ts => bulkUpdate.ts} (65%) delete mode 100644 test/client-bulk.test.ts create mode 100644 test/client-bulkUpdate.test.ts rename test/{createBulkTransaction-fromDiff.test.ts => createBulkUpdateTransaction-fromDiff.test.ts} (66%) rename test/{createBulkTransaction.test.ts => createBulkUpdateTransaction.test.ts} (57%) diff --git a/src/bulk.ts b/src/bulkUpdate.ts similarity index 65% rename from src/bulk.ts rename to src/bulkUpdate.ts index 9167d96..efe9140 100644 --- a/src/bulk.ts +++ b/src/bulkUpdate.ts @@ -3,7 +3,7 @@ import * as prismic from "@prismicio/client"; /** * The type of a bulk operation. */ -export const BulkOperationType = { +export const BulkUpdateOperationType = { CustomTypeInsert: "CUSTOM_TYPE_INSERT", CustomTypeUpdate: "CUSTOM_TYPE_UPDATE", CustomTypeDelete: "CUSTOM_TYPE_DELETE", @@ -11,45 +11,45 @@ export const BulkOperationType = { SliceUpdate: "SLICE_UPDATE", SliceDelete: "SLICE_DELETE", } as const; -export type BulkOperationType = - (typeof BulkOperationType)[keyof typeof BulkOperationType]; +export type BulkUpdateOperationType = + (typeof BulkUpdateOperationType)[keyof typeof BulkUpdateOperationType]; /** - * An object describing a bulk operation. + * An object describing a bulk update operation. */ -export type BulkOperation = +export type BulkUpdateOperation = | { - type: typeof BulkOperationType.CustomTypeInsert; + type: typeof BulkUpdateOperationType.CustomTypeInsert; id: string; payload: prismic.CustomTypeModel; } | { - type: typeof BulkOperationType.CustomTypeUpdate; + type: typeof BulkUpdateOperationType.CustomTypeUpdate; id: string; payload: prismic.CustomTypeModel; } | { - type: typeof BulkOperationType.CustomTypeDelete; + type: typeof BulkUpdateOperationType.CustomTypeDelete; id: string; payload: Pick; } | { - type: typeof BulkOperationType.SliceInsert; + type: typeof BulkUpdateOperationType.SliceInsert; id: string; payload: prismic.SharedSliceModel; } | { - type: typeof BulkOperationType.SliceUpdate; + type: typeof BulkUpdateOperationType.SliceUpdate; id: string; payload: prismic.SharedSliceModel; } | { - type: typeof BulkOperationType.SliceDelete; + type: typeof BulkUpdateOperationType.SliceDelete; id: string; payload: Pick; }; -export type BulkTransactionModels = { +export type BulkUpdateTransactionModels = { customTypes?: prismic.CustomTypeModel[]; slices?: prismic.SharedSliceModel[]; }; @@ -85,24 +85,29 @@ const processDiff = < }; /** - * Create a bulk transaction instance to pass to a Custom Types Client `bulk()` - * method. + * Create a bulk update transaction instance to pass to a Custom Types Client + * `bulkUpdate()` method. */ -export const createBulkTransaction = ( - ...args: ConstructorParameters -): BulkTransaction => new BulkTransaction(...args); +export const createBulkUpdateTransaction = ( + ...args: ConstructorParameters +): BulkUpdateTransaction => new BulkUpdateTransaction(...args); -export class BulkTransaction { - operations: BulkOperation[]; +export class BulkUpdateTransaction { + operations: BulkUpdateOperation[]; - constructor(initialOperations: BulkTransaction | BulkOperation[] = []) { + constructor( + initialOperations: BulkUpdateTransaction | BulkUpdateOperation[] = [], + ) { this.operations = - initialOperations instanceof BulkTransaction + initialOperations instanceof BulkUpdateTransaction ? initialOperations.operations : initialOperations; } - fromDiff(before: BulkTransactionModels, after: BulkTransactionModels): void { + fromDiff( + before: BulkUpdateTransactionModels, + after: BulkUpdateTransactionModels, + ): void { processDiff(before.customTypes ?? [], after.customTypes ?? [], { onInsert: (model) => this.insertCustomType(model), onUpdate: (model) => this.updateCustomType(model), @@ -117,7 +122,7 @@ export class BulkTransaction { insertCustomType(customType: prismic.CustomTypeModel): void { this.operations.push({ - type: BulkOperationType.CustomTypeInsert, + type: BulkUpdateOperationType.CustomTypeInsert, id: customType.id, payload: customType, }); @@ -125,7 +130,7 @@ export class BulkTransaction { updateCustomType(customType: prismic.CustomTypeModel): void { this.operations.push({ - type: BulkOperationType.CustomTypeUpdate, + type: BulkUpdateOperationType.CustomTypeUpdate, id: customType.id, payload: customType, }); @@ -133,7 +138,7 @@ export class BulkTransaction { deleteCustomType(customType: prismic.CustomTypeModel): void { this.operations.push({ - type: BulkOperationType.CustomTypeDelete, + type: BulkUpdateOperationType.CustomTypeDelete, id: customType.id, payload: { id: customType.id }, }); @@ -141,7 +146,7 @@ export class BulkTransaction { insertSlice(slice: prismic.SharedSliceModel): void { this.operations.push({ - type: BulkOperationType.SliceInsert, + type: BulkUpdateOperationType.SliceInsert, id: slice.id, payload: slice, }); @@ -149,7 +154,7 @@ export class BulkTransaction { updateSlice(slice: prismic.SharedSliceModel): void { this.operations.push({ - type: BulkOperationType.SliceUpdate, + type: BulkUpdateOperationType.SliceUpdate, id: slice.id, payload: slice, }); @@ -157,7 +162,7 @@ export class BulkTransaction { deleteSlice(slice: prismic.SharedSliceModel): void { this.operations.push({ - type: BulkOperationType.SliceDelete, + type: BulkUpdateOperationType.SliceDelete, id: slice.id, payload: { id: slice.id }, }); diff --git a/src/client.ts b/src/client.ts index e91b0c6..5ba5b0e 100644 --- a/src/client.ts +++ b/src/client.ts @@ -3,8 +3,7 @@ import type * as prismic from "@prismicio/client"; import type { AbortSignalLike, FetchLike, RequestInitLike } from "./types"; import { - BulkTransactionConfirmationError, - BulkTransactionLimitError, + BulkUpdateHasExistingDocumentsError, ConflictError, ForbiddenError, InvalidPayloadError, @@ -14,7 +13,7 @@ import { UnauthorizedError, } from "./errors"; -import { BulkOperation, BulkTransaction } from "./bulk"; +import { BulkUpdateOperation, BulkUpdateTransaction } from "./bulkUpdate"; /** * The default endpoint for the Prismic Custom Types API. @@ -52,7 +51,8 @@ export type CustomTypesClientConfig = { /** * Options provided to the client's `fetch()` on all network requests. These * options will be merged with internally required options. They can also be - * overriden on a per-query basis using the query's `fetchOptions` parameter. + * overridden on a per-query basis using the query's `fetchOptions` + * parameter. */ fetchOptions?: RequestInitLike; }; @@ -85,19 +85,6 @@ type FetchParams = { signal?: AbortSignalLike; }; -/** - * Parameters for the `bulk()` client method. - */ -type BulkParams = { - /** - * Determines if the method stops a bulk request if the changes require - * deleting Prismic documents. - * - * @defaultValue false - */ - deleteDocuments?: boolean; -}; - /** * Create a `RequestInit` object for a POST `fetch` request. The provided body * will be run through `JSON.stringify`. @@ -454,34 +441,33 @@ export class CustomTypesClient { * @example * * ```ts - * const bulkTransaction = createBulkTransaction(); - * bulkTransaction.insertCustomType(myCustomType); - * bulkTransaction.deleteSlice(mySlice); + * const bulkUpdateTransaction = createBulkUpdateTransaction(); + * bulkUpdateTransaction.insertCustomType(myCustomType); + * bulkUpdateTransaction.deleteSlice(mySlice); * - * await client.bulk(bulkTransaction); + * await client.bulkUpdate(bulkUpdateTransaction); * ``` * - * @param operations - A `BulkTransaction` containing all operations or an - * array of objects describing an operation. + * @param operations - A `BulkUpdateTransaction` containing all operations or + * an array of objects describing an operation. * @param params - Parameters that determine how the method behaves and for * overriding the client's default configuration. * * @returns An array of objects describing the operations. */ - async bulk( - operations: BulkTransaction | BulkOperation[], - params?: BulkParams & CustomTypesClientMethodParams & FetchParams, - ): Promise { + async bulkUpdate( + operations: BulkUpdateTransaction | BulkUpdateOperation[], + params?: CustomTypesClientMethodParams & FetchParams, + ): Promise { const resolvedOperations = - operations instanceof BulkTransaction + operations instanceof BulkUpdateTransaction ? operations.operations : operations; await this.fetch( - "./bulk", + "./bulk-update", params, createPostFetchRequestInit({ - confirmDeleteDocuments: params?.deleteDocuments ?? false, changes: resolvedOperations, }), ); @@ -564,17 +550,6 @@ export class CustomTypesClient { return undefined as any; } - // Accepted - // - Soft limit reached for bulk request (requires confirmation) - case 202: { - const json = await res.json(); - - throw new BulkTransactionConfirmationError( - "The bulk transaction will delete documents. Confirm before trying again.", - { url, response: json }, - ); - } - // Bad Request // - Invalid body sent case 400: { @@ -594,13 +569,13 @@ export class CustomTypesClient { // Forbidden // - Missing token // - Incorrect token - // - Hard limit reached for bulk request (cannot process) + // - Has existing documents (cannot process) case 403: { const json = await res.json(); - if ("details" in json) { - throw new BulkTransactionLimitError( - "The bulk transaction reached or surpassed the limit of allowed commands.", + if ("hasExistingDocuments" in json && json.hasExistingDocuments) { + throw new BulkUpdateHasExistingDocumentsError( + "The bulk update changes contain deletion operations for custom types with existing documents.", { url, response: json }, ); } diff --git a/src/errors.ts b/src/errors.ts index 5705352..92180b2 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -45,7 +45,7 @@ export class PrismicError extends Error { } /** - * The response returned by the Prismic Custom Types API when unauthorized. + * The response returned by the Prismic Custom Types API when forbidden. */ export interface ForbiddenErrorAPIResponse { /** @@ -55,17 +55,21 @@ export interface ForbiddenErrorAPIResponse { } /** - * The response returned by the Prismic Custom Types API bulk transaction - * endpoint when a soft or hard limit is reached. + * The response returned by the Prismic Custom Types API bulk update transaction + * endpoint when changes contain a deletion operation of custom type(s) with + * existing document(s). */ -type BulkTransactionErrorAPIResponse = { - details: { - customTypes: { - id: string; - numberOfDocuments: number; - url: string; - }[]; - }; +type BulkUpdateTransactionErrorAPIResponse = { + /** + * Description of the error. + */ + message: string; + + /** + * Identify if the changes contain a deletion operation of custom type(s) with + * existing document(s). + */ + hasExistingDocuments: true; }; /** @@ -95,16 +99,10 @@ export class NotFoundError extends PrismicError {} export class InvalidPayloadError extends PrismicError {} /** - * Represents an error when a bulk transaction requires confirmation to delete - * documents. - */ -export class BulkTransactionConfirmationError extends PrismicError {} - -/** - * Represents an error when a bulk transaction reached the limit of operations - * allowed by the API. + * Represents an error when a bulk update changes contain a deletion operation + * of custom type(s) with existing document(s). */ -export class BulkTransactionLimitError extends PrismicError {} +export class BulkUpdateHasExistingDocumentsError extends PrismicError {} /** * Represents an error when a valid `fetch` function is not available to the diff --git a/src/index.ts b/src/index.ts index afc18b4..ef97810 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,11 +5,14 @@ export type { } from "./client"; export { - createBulkTransaction, - BulkTransaction, - BulkOperationType, -} from "./bulk"; -export type { BulkOperation, BulkTransactionModels } from "./bulk"; + createBulkUpdateTransaction, + BulkUpdateTransaction, + BulkUpdateOperationType, +} from "./bulkUpdate"; +export type { + BulkUpdateOperation, + BulkUpdateTransactionModels, +} from "./bulkUpdate"; export { PrismicError, @@ -19,8 +22,6 @@ export { InvalidPayloadError, MissingFetchError, NotFoundError, - BulkTransactionLimitError, - BulkTransactionConfirmationError, } from "./errors"; export type { FetchLike, ResponseLike, RequestInitLike } from "./types"; diff --git a/test/client-bulk.test.ts b/test/client-bulk.test.ts deleted file mode 100644 index 46b2666..0000000 --- a/test/client-bulk.test.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { expect } from "vitest"; - -import { it } from "./__testutils__/it"; -import { testFetchOptions } from "./__testutils__/testFetchOptions"; - -import * as prismicCustomTypes from "../src"; - -it("performs a bulk transaction", async ({ client, mock, api }) => { - const insertedCustomType = mock.model.customType(); - const updatedCustomType = mock.model.customType(); - const deletedCustomType = mock.model.customType(); - - const insertedSlice = mock.model.sharedSlice(); - const updatedSlice = mock.model.sharedSlice(); - const deletedSlice = mock.model.sharedSlice(); - - const operations = [ - { - type: prismicCustomTypes.BulkOperationType.CustomTypeInsert, - id: insertedCustomType.id, - payload: insertedCustomType, - }, - { - type: prismicCustomTypes.BulkOperationType.CustomTypeUpdate, - id: updatedCustomType.id, - payload: updatedCustomType, - }, - { - type: prismicCustomTypes.BulkOperationType.CustomTypeDelete, - id: deletedCustomType.id, - payload: { id: deletedCustomType.id }, - }, - { - type: prismicCustomTypes.BulkOperationType.SliceInsert, - id: insertedSlice.id, - payload: insertedSlice, - }, - { - type: prismicCustomTypes.BulkOperationType.SliceUpdate, - id: updatedSlice.id, - payload: updatedSlice, - }, - { - type: prismicCustomTypes.BulkOperationType.SliceDelete, - id: deletedSlice.id, - payload: { id: deletedSlice.id }, - }, - ]; - - api.mock("./bulk", undefined, { - method: "post", - statusCode: 204, - requiredBody: { - confirmDeleteDocuments: false, - changes: operations, - }, - }); - - const res = await client.bulk(operations); - - expect(res).toStrictEqual(operations); -}); - -it("supports BulkTransation instance", async ({ client, mock, api }) => { - const bulkTransaction = prismicCustomTypes.createBulkTransaction(); - - const insertedCustomType = mock.model.customType(); - const updatedCustomType = mock.model.customType(); - const deletedCustomType = mock.model.customType(); - - bulkTransaction.insertCustomType(insertedCustomType); - bulkTransaction.updateCustomType(updatedCustomType); - bulkTransaction.deleteCustomType(deletedCustomType); - - const insertedSlice = mock.model.sharedSlice(); - const updatedSlice = mock.model.sharedSlice(); - const deletedSlice = mock.model.sharedSlice(); - - bulkTransaction.insertSlice(insertedSlice); - bulkTransaction.updateSlice(updatedSlice); - bulkTransaction.deleteSlice(deletedSlice); - - api.mock("./bulk", undefined, { - method: "post", - statusCode: 204, - requiredBody: { - confirmDeleteDocuments: false, - changes: bulkTransaction.operations, - }, - }); - - const res = await client.bulk(bulkTransaction); - - expect(res).toStrictEqual(bulkTransaction.operations); -}); - -it("does not delete documents by default", async ({ client, api }) => { - api.mock("./bulk", undefined, { - method: "post", - statusCode: 204, - requiredBody: { - confirmDeleteDocuments: false, - changes: [], - }, - }); - - await expect(client.bulk([])).resolves.not.toThrow(); -}); - -it("allows confirming document deletion", async ({ client, api }) => { - api.mock("./bulk", undefined, { - method: "post", - statusCode: 204, - requiredBody: { - confirmDeleteDocuments: true, - changes: [], - }, - }); - - await expect( - client.bulk([], { deleteDocuments: true }), - ).resolves.not.toThrow(); -}); - -it("throws BulkTransactionConfirmationError if confirmation is needed", async ({ - client, - api, -}) => { - api.mock( - "./bulk", - { details: { customTypes: [] } }, - { method: "post", statusCode: 202 }, - ); - - await expect(async () => { - await client.bulk([]); - }).rejects.toThrow(prismicCustomTypes.BulkTransactionConfirmationError); -}); - -it("throws BulkTransactionLimitError if the command limit is reached", async ({ - client, - api, -}) => { - api.mock( - "./bulk", - { details: { customTypes: [] } }, - { method: "post", statusCode: 403 }, - ); - - await expect(async () => { - await client.bulk([]); - }).rejects.toThrow(prismicCustomTypes.BulkTransactionLimitError); -}); - -it("is abortable", async ({ client, api }) => { - api.mock("./bulk", undefined, { method: "post" }); - - const controller = new AbortController(); - controller.abort(); - - await expect(async () => { - await client.bulk([], { signal: controller.signal }); - }).rejects.toThrow(/aborted/i); -}); - -testFetchOptions("supports fetch options", { - mockURL: (client) => new URL("./bulk", client.endpoint), - mockURLMethod: "post", - run: (client, params) => client.bulk([], params), -}); diff --git a/test/client-bulkUpdate.test.ts b/test/client-bulkUpdate.test.ts new file mode 100644 index 0000000..f26c0ad --- /dev/null +++ b/test/client-bulkUpdate.test.ts @@ -0,0 +1,111 @@ +import { expect } from "vitest"; + +import { it } from "./__testutils__/it"; +import { testFetchOptions } from "./__testutils__/testFetchOptions"; + +import * as prismicCustomTypes from "../src"; + +it("performs a bulk update transaction", async ({ client, mock, api }) => { + const insertedCustomType = mock.model.customType(); + const updatedCustomType = mock.model.customType(); + const deletedCustomType = mock.model.customType(); + + const insertedSlice = mock.model.sharedSlice(); + const updatedSlice = mock.model.sharedSlice(); + const deletedSlice = mock.model.sharedSlice(); + + const operations = [ + { + type: prismicCustomTypes.BulkUpdateOperationType.CustomTypeInsert, + id: insertedCustomType.id, + payload: insertedCustomType, + }, + { + type: prismicCustomTypes.BulkUpdateOperationType.CustomTypeUpdate, + id: updatedCustomType.id, + payload: updatedCustomType, + }, + { + type: prismicCustomTypes.BulkUpdateOperationType.CustomTypeDelete, + id: deletedCustomType.id, + payload: { id: deletedCustomType.id }, + }, + { + type: prismicCustomTypes.BulkUpdateOperationType.SliceInsert, + id: insertedSlice.id, + payload: insertedSlice, + }, + { + type: prismicCustomTypes.BulkUpdateOperationType.SliceUpdate, + id: updatedSlice.id, + payload: updatedSlice, + }, + { + type: prismicCustomTypes.BulkUpdateOperationType.SliceDelete, + id: deletedSlice.id, + payload: { id: deletedSlice.id }, + }, + ]; + + api.mock("./bulk-update", undefined, { + method: "post", + statusCode: 204, + requiredBody: { + changes: operations, + }, + }); + + const res = await client.bulkUpdate(operations); + + expect(res).toStrictEqual(operations); +}); + +it("supports BulkUpdateTransaction instance", async ({ client, mock, api }) => { + const bulkUpdateTransaction = + prismicCustomTypes.createBulkUpdateTransaction(); + + const insertedCustomType = mock.model.customType(); + const updatedCustomType = mock.model.customType(); + const deletedCustomType = mock.model.customType(); + + bulkUpdateTransaction.insertCustomType(insertedCustomType); + bulkUpdateTransaction.updateCustomType(updatedCustomType); + bulkUpdateTransaction.deleteCustomType(deletedCustomType); + + const insertedSlice = mock.model.sharedSlice(); + const updatedSlice = mock.model.sharedSlice(); + const deletedSlice = mock.model.sharedSlice(); + + bulkUpdateTransaction.insertSlice(insertedSlice); + bulkUpdateTransaction.updateSlice(updatedSlice); + bulkUpdateTransaction.deleteSlice(deletedSlice); + + api.mock("./bulk-update", undefined, { + method: "post", + statusCode: 204, + requiredBody: { + changes: bulkUpdateTransaction.operations, + }, + }); + + const res = await client.bulkUpdate(bulkUpdateTransaction); + + expect(res).toStrictEqual(bulkUpdateTransaction.operations); +}); + +it("is abortable", async ({ client, api }) => { + api.mock("./bulk-update", undefined, { method: "post" }); + + const controller = new AbortController(); + controller.abort(); + + await expect(async () => { + await client.bulkUpdate([], { signal: controller.signal }); + }).rejects.toThrow(/aborted/i); +}); + +testFetchOptions("supports fetch options", { + mockURL: (client) => new URL("./bulk-update", client.endpoint), + mockURLMethod: "post", + run: (client, params) => client.bulkUpdate([], params), +}); diff --git a/test/createBulkTransaction-fromDiff.test.ts b/test/createBulkUpdateTransaction-fromDiff.test.ts similarity index 66% rename from test/createBulkTransaction-fromDiff.test.ts rename to test/createBulkUpdateTransaction-fromDiff.test.ts index 3d2ca6e..d1fd25c 100644 --- a/test/createBulkTransaction-fromDiff.test.ts +++ b/test/createBulkUpdateTransaction-fromDiff.test.ts @@ -2,7 +2,7 @@ import { describe, expect } from "vitest"; import { it } from "./__testutils__/it"; -import { createBulkTransaction } from "../src"; +import { createBulkUpdateTransaction } from "../src"; it("adds operations using the difference between two sets of models", ({ mock, @@ -32,10 +32,10 @@ it("adds operations using the difference between two sets of models", ({ ], }; - const bulkTransaction = createBulkTransaction(); - bulkTransaction.fromDiff(before, after); + const bulkUpdateTransaction = createBulkUpdateTransaction(); + bulkUpdateTransaction.fromDiff(before, after); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "CUSTOM_TYPE_UPDATE", id: after.customTypes[1].id, @@ -73,10 +73,13 @@ describe("custom type", () => { it("detects creation", ({ mock }) => { const after = mock.model.customType({ label: "after" }); - const bulkTransaction = createBulkTransaction(); - bulkTransaction.fromDiff({ customTypes: [] }, { customTypes: [after] }); + const bulkUpdateTransaction = createBulkUpdateTransaction(); + bulkUpdateTransaction.fromDiff( + { customTypes: [] }, + { customTypes: [after] }, + ); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "CUSTOM_TYPE_INSERT", id: after.id, @@ -89,13 +92,13 @@ describe("custom type", () => { const before = mock.model.customType({ label: "before" }); const after = { ...before, label: "after" }; - const bulkTransaction = createBulkTransaction(); - bulkTransaction.fromDiff( + const bulkUpdateTransaction = createBulkUpdateTransaction(); + bulkUpdateTransaction.fromDiff( { customTypes: [before] }, { customTypes: [after] }, ); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "CUSTOM_TYPE_UPDATE", id: before.id, @@ -107,10 +110,13 @@ describe("custom type", () => { it("detects deletion", ({ mock }) => { const before = mock.model.customType({ label: "before" }); - const bulkTransaction = createBulkTransaction(); - bulkTransaction.fromDiff({ customTypes: [before] }, { customTypes: [] }); + const bulkUpdateTransaction = createBulkUpdateTransaction(); + bulkUpdateTransaction.fromDiff( + { customTypes: [before] }, + { customTypes: [] }, + ); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "CUSTOM_TYPE_DELETE", id: before.id, @@ -124,10 +130,10 @@ describe("slice", () => { it("detects creation", ({ mock }) => { const after = mock.model.sharedSlice({ name: "after" }); - const bulkTransaction = createBulkTransaction(); - bulkTransaction.fromDiff({ slices: [] }, { slices: [after] }); + const bulkUpdateTransaction = createBulkUpdateTransaction(); + bulkUpdateTransaction.fromDiff({ slices: [] }, { slices: [after] }); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "SLICE_INSERT", id: after.id, @@ -140,10 +146,10 @@ describe("slice", () => { const before = mock.model.sharedSlice({ name: "before" }); const after = { ...before, name: "after" }; - const bulkTransaction = createBulkTransaction(); - bulkTransaction.fromDiff({ slices: [before] }, { slices: [after] }); + const bulkUpdateTransaction = createBulkUpdateTransaction(); + bulkUpdateTransaction.fromDiff({ slices: [before] }, { slices: [after] }); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "SLICE_UPDATE", id: before.id, @@ -155,10 +161,10 @@ describe("slice", () => { it("detects deletion", ({ mock }) => { const before = mock.model.sharedSlice({ name: "before" }); - const bulkTransaction = createBulkTransaction(); - bulkTransaction.fromDiff({ slices: [before] }, { slices: [] }); + const bulkUpdateTransaction = createBulkUpdateTransaction(); + bulkUpdateTransaction.fromDiff({ slices: [before] }, { slices: [] }); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "SLICE_DELETE", id: before.id, diff --git a/test/createBulkTransaction.test.ts b/test/createBulkUpdateTransaction.test.ts similarity index 57% rename from test/createBulkTransaction.test.ts rename to test/createBulkUpdateTransaction.test.ts index 3f26a51..854fb91 100644 --- a/test/createBulkTransaction.test.ts +++ b/test/createBulkUpdateTransaction.test.ts @@ -2,26 +2,26 @@ import { expect } from "vitest"; import { it } from "./__testutils__/it"; -import { createBulkTransaction } from "../src"; +import { createBulkUpdateTransaction } from "../src"; it("starts with an empty array of operations", () => { - const bulkTransaction = createBulkTransaction(); + const bulkUpdateTransaction = createBulkUpdateTransaction(); - expect(bulkTransaction.operations).toStrictEqual([]); + expect(bulkUpdateTransaction.operations).toStrictEqual([]); }); it("supports custom type operations", ({ mock }) => { - const bulkTransaction = createBulkTransaction(); + const bulkUpdateTransaction = createBulkUpdateTransaction(); const insertedCustomType = mock.model.customType(); const updatedCustomType = mock.model.customType(); const deletedCustomType = mock.model.customType(); - bulkTransaction.insertCustomType(insertedCustomType); - bulkTransaction.updateCustomType(updatedCustomType); - bulkTransaction.deleteCustomType(deletedCustomType); + bulkUpdateTransaction.insertCustomType(insertedCustomType); + bulkUpdateTransaction.updateCustomType(updatedCustomType); + bulkUpdateTransaction.deleteCustomType(deletedCustomType); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "CUSTOM_TYPE_INSERT", id: insertedCustomType.id, @@ -41,17 +41,17 @@ it("supports custom type operations", ({ mock }) => { }); it("supports slice operations", ({ mock }) => { - const bulkTransaction = createBulkTransaction(); + const bulkUpdateTransaction = createBulkUpdateTransaction(); const insertedSlice = mock.model.sharedSlice(); const updatedSlice = mock.model.sharedSlice(); const deletedSlice = mock.model.sharedSlice(); - bulkTransaction.insertSlice(insertedSlice); - bulkTransaction.updateSlice(updatedSlice); - bulkTransaction.deleteSlice(deletedSlice); + bulkUpdateTransaction.insertSlice(insertedSlice); + bulkUpdateTransaction.updateSlice(updatedSlice); + bulkUpdateTransaction.deleteSlice(deletedSlice); - expect(bulkTransaction.operations).toStrictEqual([ + expect(bulkUpdateTransaction.operations).toStrictEqual([ { type: "SLICE_INSERT", id: insertedSlice.id, @@ -75,14 +75,16 @@ it("supports initial operations", ({ mock }) => { const updatedCustomType = mock.model.customType(); const deletedCustomType = mock.model.customType(); - const bulkTransaction1 = createBulkTransaction(); - bulkTransaction1.insertCustomType(insertedCustomType); + const bulkUpdateTransaction1 = createBulkUpdateTransaction(); + bulkUpdateTransaction1.insertCustomType(insertedCustomType); - const bulkTransaction2 = createBulkTransaction(bulkTransaction1.operations); - bulkTransaction2.updateCustomType(updatedCustomType); - bulkTransaction2.deleteCustomType(deletedCustomType); + const bulkUpdateTransaction2 = createBulkUpdateTransaction( + bulkUpdateTransaction1.operations, + ); + bulkUpdateTransaction2.updateCustomType(updatedCustomType); + bulkUpdateTransaction2.deleteCustomType(deletedCustomType); - expect(bulkTransaction2.operations).toStrictEqual([ + expect(bulkUpdateTransaction2.operations).toStrictEqual([ { type: "CUSTOM_TYPE_INSERT", id: insertedCustomType.id, @@ -101,19 +103,21 @@ it("supports initial operations", ({ mock }) => { ]); }); -it("supports initial BulkTransaction", ({ mock }) => { +it("supports initial BulkUpdateTransaction", ({ mock }) => { const insertedCustomType = mock.model.customType(); const updatedCustomType = mock.model.customType(); const deletedCustomType = mock.model.customType(); - const bulkTransaction1 = createBulkTransaction(); - bulkTransaction1.insertCustomType(insertedCustomType); + const bulkUpdateTransaction1 = createBulkUpdateTransaction(); + bulkUpdateTransaction1.insertCustomType(insertedCustomType); - const bulkTransaction2 = createBulkTransaction(bulkTransaction1); - bulkTransaction2.updateCustomType(updatedCustomType); - bulkTransaction2.deleteCustomType(deletedCustomType); + const bulkUpdateTransaction2 = createBulkUpdateTransaction( + bulkUpdateTransaction1, + ); + bulkUpdateTransaction2.updateCustomType(updatedCustomType); + bulkUpdateTransaction2.deleteCustomType(deletedCustomType); - expect(bulkTransaction2.operations).toStrictEqual([ + expect(bulkUpdateTransaction2.operations).toStrictEqual([ { type: "CUSTOM_TYPE_INSERT", id: insertedCustomType.id, From 82948fbc887e246244718b37f0d0e230ca5db827 Mon Sep 17 00:00:00 2001 From: Xavier Rutayisire Date: Wed, 29 May 2024 16:33:35 +0200 Subject: [PATCH 2/7] chore(releases): release alpha as major --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 597417d..4ab6251 100644 --- a/package.json +++ b/package.json @@ -34,8 +34,8 @@ "lint": "eslint --ext .js,.ts .", "prepare": "npm run build", "release": "npm run test && standard-version && git push --follow-tags && npm run build && npm publish", - "release:alpha": "npm run test && standard-version --release-as minor --prerelease alpha && git push --follow-tags && npm run build && npm publish --tag alpha", - "release:alpha:dry": "standard-version --release-as minor --prerelease alpha --dry-run", + "release:alpha": "npm run test && standard-version --release-as major --prerelease alpha && git push --follow-tags && npm run build && npm publish --tag alpha", + "release:alpha:dry": "standard-version --release-as major --prerelease alpha --dry-run", "release:dry": "standard-version --dry-run", "size": "size-limit", "test": "npm run lint && npm run types && npm run unit && npm run build && npm run size", From 223a5f91cbea3d2d11c90ff0afab1d134de3e3b1 Mon Sep 17 00:00:00 2001 From: Xavier Rutayisire Date: Wed, 29 May 2024 16:34:45 +0200 Subject: [PATCH 3/7] chore(release): 2.0.0-alpha.0 --- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4927fd..7073fd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,34 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.0.0-alpha.0](https://github.com/prismicio/prismic-custom-types-client/compare/v1.1.0...v2.0.0-alpha.0) (2024-05-29) + + +### ⚠ BREAKING CHANGES + +* **bulk-update:** drop support for bulk endpoint + +### Features + +* **bulk-update:** replace bulk by bulk-update endpoint ([abfcd13](https://github.com/prismicio/prismic-custom-types-client/commit/abfcd13b672d6bef7f119af2435db49373886741)) +* pass arbitrary options to `fetch()` with the `fetchOptions` parameter ([#9](https://github.com/prismicio/prismic-custom-types-client/issues/9)) ([ae76fe8](https://github.com/prismicio/prismic-custom-types-client/commit/ae76fe8e6fcd84f2e79745e57f687625325d0a94)) +* support bulk transactions ([#10](https://github.com/prismicio/prismic-custom-types-client/issues/10)) ([38968f7](https://github.com/prismicio/prismic-custom-types-client/commit/38968f779b00ce8d62495438c14b87b2fe3c8f13)) + + +### Bug Fixes + +* make `@prismicio/client` a peer dependency ([#14](https://github.com/prismicio/prismic-custom-types-client/issues/14)) ([99d2b67](https://github.com/prismicio/prismic-custom-types-client/commit/99d2b675f7e974cff7ad1ea74f8f4f3c37884e98)) +* replace `@prismicio/types` with `@prismicio/client` ([#11](https://github.com/prismicio/prismic-custom-types-client/issues/11)) ([77474e6](https://github.com/prismicio/prismic-custom-types-client/commit/77474e63f6907639f3f3ed8c7a9cee80116e8692)) + + +### Chore + +* **deps:** update all dependencies ([#12](https://github.com/prismicio/prismic-custom-types-client/issues/12)) ([2c5330e](https://github.com/prismicio/prismic-custom-types-client/commit/2c5330e41c921f7d536db4a84c021ffd4776ed74)) +* **release:** 1.2.0 ([c662c3f](https://github.com/prismicio/prismic-custom-types-client/commit/c662c3f57464653e654ae4e48d6506b6c44ba6c0)) +* **release:** 1.3.0 ([bd7f977](https://github.com/prismicio/prismic-custom-types-client/commit/bd7f9774e505e39262ab030e66213d88341f19cd)) +* **release:** 1.3.1 ([1fff28f](https://github.com/prismicio/prismic-custom-types-client/commit/1fff28fc39e40c672f8002fbcb00af8792f331b3)) +* **releases:** release alpha as major ([82948fb](https://github.com/prismicio/prismic-custom-types-client/commit/82948fbc887e246244718b37f0d0e230ca5db827)) + ### [1.3.1](https://github.com/prismicio/prismic-custom-types-client/compare/v1.3.0...v1.3.1) (2024-04-17) diff --git a/package-lock.json b/package-lock.json index e93d00a..8a6ff6d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@prismicio/custom-types-client", - "version": "1.3.1", + "version": "2.0.0-alpha.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@prismicio/custom-types-client", - "version": "1.3.1", + "version": "2.0.0-alpha.0", "license": "Apache-2.0", "devDependencies": { "@prismicio/mock": "^0.3.1", diff --git a/package.json b/package.json index 4ab6251..213fdb8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@prismicio/custom-types-client", - "version": "1.3.1", + "version": "2.0.0-alpha.0", "description": "JavaScript client to interact with the Prismic Custom Types API", "keywords": [ "typescript", From 826669ab395a658ec45c0dd9a5ed727153e91ff7 Mon Sep 17 00:00:00 2001 From: Xavier Rutayisire Date: Wed, 29 May 2024 21:26:25 +0200 Subject: [PATCH 4/7] improve errors --- src/client.ts | 6 ++++-- src/errors.ts | 5 +++++ src/index.ts | 6 ++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/client.ts b/src/client.ts index 5ba5b0e..589f704 100644 --- a/src/client.ts +++ b/src/client.ts @@ -6,10 +6,10 @@ import { BulkUpdateHasExistingDocumentsError, ConflictError, ForbiddenError, + InvalidAPIResponse, InvalidPayloadError, MissingFetchError, NotFoundError, - PrismicError, UnauthorizedError, } from "./errors"; @@ -608,6 +608,8 @@ export class CustomTypesClient { } } - throw new PrismicError("An invalid API response was returned", { url }); + throw new InvalidAPIResponse("An invalid API response was returned", { + url, + }); } } diff --git a/src/errors.ts b/src/errors.ts index 92180b2..6851af8 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -72,6 +72,11 @@ type BulkUpdateTransactionErrorAPIResponse = { hasExistingDocuments: true; }; +/** + * Represents an error when the Prismic Custom Types API response is invalid. + */ +export class InvalidAPIResponse extends PrismicError {} + /** * Represents an error when making an unauthorized Prismic Custom Types API * request. diff --git a/src/index.ts b/src/index.ts index ef97810..8a22030 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,13 +15,15 @@ export type { } from "./bulkUpdate"; export { - PrismicError, + BulkUpdateHasExistingDocumentsError, ConflictError, ForbiddenError, - UnauthorizedError, + InvalidAPIResponse, InvalidPayloadError, MissingFetchError, NotFoundError, + PrismicError, + UnauthorizedError, } from "./errors"; export type { FetchLike, ResponseLike, RequestInitLike } from "./types"; From 10ddb88203e3a8576735750561f691da52d48d36 Mon Sep 17 00:00:00 2001 From: Xavier Rutayisire Date: Wed, 29 May 2024 21:27:28 +0200 Subject: [PATCH 5/7] chore(release): 2.0.0-alpha.1 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7073fd3..f923d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.0.0-alpha.1](https://github.com/prismicio/prismic-custom-types-client/compare/v2.0.0-alpha.0...v2.0.0-alpha.1) (2024-05-29) + ## [2.0.0-alpha.0](https://github.com/prismicio/prismic-custom-types-client/compare/v1.1.0...v2.0.0-alpha.0) (2024-05-29) diff --git a/package-lock.json b/package-lock.json index 8a6ff6d..e2d729d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@prismicio/custom-types-client", - "version": "2.0.0-alpha.0", + "version": "2.0.0-alpha.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@prismicio/custom-types-client", - "version": "2.0.0-alpha.0", + "version": "2.0.0-alpha.1", "license": "Apache-2.0", "devDependencies": { "@prismicio/mock": "^0.3.1", diff --git a/package.json b/package.json index 213fdb8..ad16b03 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@prismicio/custom-types-client", - "version": "2.0.0-alpha.0", + "version": "2.0.0-alpha.1", "description": "JavaScript client to interact with the Prismic Custom Types API", "keywords": [ "typescript", From 12c5593e8f8ce118f79a7580d887f2c49de9e9ec Mon Sep 17 00:00:00 2001 From: Xavier Rutayisire Date: Thu, 30 May 2024 12:08:07 +0200 Subject: [PATCH 6/7] review --- src/errors.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/errors.ts b/src/errors.ts index 6851af8..25bd2a1 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -59,7 +59,7 @@ export interface ForbiddenErrorAPIResponse { * endpoint when changes contain a deletion operation of custom type(s) with * existing document(s). */ -type BulkUpdateTransactionErrorAPIResponse = { +type BulkUpdateHasExistingDocumentsErrorAPIResponse = { /** * Description of the error. */ @@ -107,7 +107,7 @@ export class InvalidPayloadError extends PrismicError {} * Represents an error when a bulk update changes contain a deletion operation * of custom type(s) with existing document(s). */ -export class BulkUpdateHasExistingDocumentsError extends PrismicError {} +export class BulkUpdateHasExistingDocumentsError extends PrismicError {} /** * Represents an error when a valid `fetch` function is not available to the From dccbb8fc71a0faec4f5d2c06a137cbf49a88c647 Mon Sep 17 00:00:00 2001 From: Xavier Rutayisire Date: Tue, 4 Jun 2024 10:40:36 +0200 Subject: [PATCH 7/7] Rename error message --- src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index 589f704..6a6f0f5 100644 --- a/src/client.ts +++ b/src/client.ts @@ -575,7 +575,7 @@ export class CustomTypesClient { if ("hasExistingDocuments" in json && json.hasExistingDocuments) { throw new BulkUpdateHasExistingDocumentsError( - "The bulk update changes contain deletion operations for custom types with existing documents.", + "A custom type with published documents cannot be deleted. Delete all of the custom type's documents or remove the delete operation from the request before trying again.", { url, response: json }, ); }