@voyantjs/plugin-payload-cms 0.1.1 → 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oEAAoE;IACpE,KAAK,CAAC,EAAE,YAAY,CAAA;CACrB;AAUD,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,gBAAgB,CACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAC5C;;;OAGG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACxE,+EAA+E;IAC/E,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;CACrF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA+FhF"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACjD,YAAY,EACV,uBAAuB,EACvB,aAAa,EACb,YAAY,EACZ,qBAAqB,GACtB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,gBAAgB,CAAA;AAExD,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,iBAAiB,KAAK,cAAc,CAAA;AAEvE;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IAChD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CACjD;AAED,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACnE;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,qBAAqB,CAAA;IAC9B;;;OAGG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,aAAa,CAAA;CACvB;AAcD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CA+DzE"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEpD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACJ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,KACE,OAAO,CAAC;IACX,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAC5B,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/plugin-payload-cms",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "license": "FSL-1.1-Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -22,7 +22,7 @@
22
22
  }
23
23
  },
24
24
  "dependencies": {
25
- "@voyantjs/core": "0.1.1"
25
+ "@voyantjs/core": "0.2.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "typescript": "^6.0.2",
@@ -44,7 +44,7 @@
44
44
  "typecheck": "tsc --noEmit",
45
45
  "lint": "biome check src/",
46
46
  "test": "vitest run",
47
- "build": "tsc -p tsconfig.json",
47
+ "build": "pnpm run clean && tsc -p tsconfig.json",
48
48
  "clean": "rm -rf dist"
49
49
  },
50
50
  "main": "./dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,oEAAoE;IACpE,KAAK,CAAC,EAAE,YAAY,CAAA;CACrB;AAUD,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,gBAAgB,CACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAC5C;;;OAGG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACxE,+EAA+E;IAC/E,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;CACrF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CA+FhF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AACjD,YAAY,EACV,uBAAuB,EACvB,aAAa,EACb,YAAY,EACZ,qBAAqB,GACtB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,gBAAgB,CAAA;AAExD,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,iBAAiB,KAAK,cAAc,CAAA;AAEvE;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IAChD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CACjD;AAED,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB;IACnE;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,MAAM,CAAC,EAAE,qBAAqB,CAAA;IAC9B;;;OAGG;IACH,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,aAAa,CAAA;CACvB;AAcD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CA+DzE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEpD;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IACJ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,KACE,OAAO,CAAC;IACX,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5B,IAAI,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CAC5B,CAAC,CAAA"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=client.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../../tests/unit/client.test.ts"],"names":[],"mappings":""}
@@ -1,192 +0,0 @@
1
- import { describe, expect, it, vi } from "vitest";
2
- import { createPayloadClient } from "../../src/client.js";
3
- function jsonResponse(status, body) {
4
- const text = JSON.stringify(body);
5
- return {
6
- ok: status >= 200 && status < 300,
7
- status,
8
- json: async () => JSON.parse(text),
9
- text: async () => text,
10
- };
11
- }
12
- function textResponse(status, text) {
13
- return {
14
- ok: status >= 200 && status < 300,
15
- status,
16
- json: async () => {
17
- throw new Error("not json");
18
- },
19
- text: async () => text,
20
- };
21
- }
22
- const baseOptions = {
23
- apiUrl: "https://cms.example.com/api",
24
- apiKey: "test-key",
25
- };
26
- describe("createPayloadClient.findByVoyantId", () => {
27
- it("returns the first matching doc", async () => {
28
- const fetchMock = vi.fn(async () => jsonResponse(200, { docs: [{ id: "pl_1", name: "a" }], totalDocs: 1 }));
29
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
30
- const result = await client.findByVoyantId("products", "prod_xyz");
31
- expect(result).toEqual({ id: "pl_1" });
32
- const [url, init] = fetchMock.mock.calls[0];
33
- expect(url).toContain("https://cms.example.com/api/products?");
34
- expect(url).toContain("where[voyantId][equals]=prod_xyz");
35
- expect(url).toContain("limit=1");
36
- expect(init.method).toBe("GET");
37
- expect(init.headers.Authorization).toBe("users API-Key test-key");
38
- });
39
- it("returns null when no docs match", async () => {
40
- const fetchMock = vi.fn(async () => jsonResponse(200, { docs: [], totalDocs: 0 }));
41
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
42
- expect(await client.findByVoyantId("products", "missing")).toBeNull();
43
- });
44
- it("respects a custom voyantIdField", async () => {
45
- const fetchMock = vi.fn(async () => jsonResponse(200, { docs: [] }));
46
- const client = createPayloadClient({
47
- ...baseOptions,
48
- voyantIdField: "externalId",
49
- fetch: fetchMock,
50
- });
51
- await client.findByVoyantId("products", "prod_1");
52
- const [url] = fetchMock.mock.calls[0];
53
- expect(url).toContain("where[externalId][equals]=prod_1");
54
- });
55
- it("respects a custom apiKeyAuthScheme", async () => {
56
- const fetchMock = vi.fn(async () => jsonResponse(200, { docs: [] }));
57
- const client = createPayloadClient({
58
- ...baseOptions,
59
- apiKeyAuthScheme: "admins API-Key",
60
- fetch: fetchMock,
61
- });
62
- await client.findByVoyantId("products", "prod_1");
63
- const [, init] = fetchMock.mock.calls[0];
64
- expect(init.headers.Authorization).toBe("admins API-Key test-key");
65
- });
66
- it("strips trailing slash from apiUrl", async () => {
67
- const fetchMock = vi.fn(async () => jsonResponse(200, { docs: [] }));
68
- const client = createPayloadClient({
69
- ...baseOptions,
70
- apiUrl: "https://cms.example.com/api/",
71
- fetch: fetchMock,
72
- });
73
- await client.findByVoyantId("products", "x");
74
- const [url] = fetchMock.mock.calls[0];
75
- expect(url.startsWith("https://cms.example.com/api/products?")).toBe(true);
76
- });
77
- it("throws on non-2xx response", async () => {
78
- const fetchMock = vi.fn(async () => textResponse(500, "boom"));
79
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
80
- await expect(client.findByVoyantId("products", "x")).rejects.toThrow(/Payload findByVoyantId\(products\) failed \(500\)/);
81
- });
82
- });
83
- describe("createPayloadClient.upsertByVoyantId", () => {
84
- it("creates a new doc when none exists", async () => {
85
- const fetchMock = vi
86
- .fn()
87
- .mockResolvedValueOnce(jsonResponse(200, { docs: [] }))
88
- .mockResolvedValueOnce(jsonResponse(201, { doc: { id: "pl_new", name: "X" } }));
89
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
90
- const result = await client.upsertByVoyantId("products", "prod_1", { name: "X" });
91
- expect(result).toEqual({ id: "pl_new", created: true });
92
- const createCall = fetchMock.mock.calls[1];
93
- expect(createCall[0]).toBe("https://cms.example.com/api/products");
94
- expect(createCall[1].method).toBe("POST");
95
- const body = JSON.parse(createCall[1].body ?? "{}");
96
- expect(body).toEqual({ name: "X", voyantId: "prod_1" });
97
- });
98
- it("updates an existing doc when found", async () => {
99
- const fetchMock = vi
100
- .fn()
101
- .mockResolvedValueOnce(jsonResponse(200, { docs: [{ id: "pl_existing" }] }))
102
- .mockResolvedValueOnce(jsonResponse(200, { doc: { id: "pl_existing", name: "Y" } }));
103
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
104
- const result = await client.upsertByVoyantId("products", "prod_1", { name: "Y" });
105
- expect(result).toEqual({ id: "pl_existing", created: false });
106
- const patchCall = fetchMock.mock.calls[1];
107
- expect(patchCall[0]).toBe("https://cms.example.com/api/products/pl_existing");
108
- expect(patchCall[1].method).toBe("PATCH");
109
- });
110
- it("accepts a top-level id in create response", async () => {
111
- const fetchMock = vi
112
- .fn()
113
- .mockResolvedValueOnce(jsonResponse(200, { docs: [] }))
114
- .mockResolvedValueOnce(jsonResponse(201, { id: "pl_top" }));
115
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
116
- const result = await client.upsertByVoyantId("products", "prod_1", {});
117
- expect(result.id).toBe("pl_top");
118
- });
119
- it("throws if create response has no id", async () => {
120
- const fetchMock = vi
121
- .fn()
122
- .mockResolvedValueOnce(jsonResponse(200, { docs: [] }))
123
- .mockResolvedValueOnce(jsonResponse(201, {}));
124
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
125
- await expect(client.upsertByVoyantId("products", "p", {})).rejects.toThrow(/response missing id/);
126
- });
127
- it("throws on create error", async () => {
128
- const fetchMock = vi
129
- .fn()
130
- .mockResolvedValueOnce(jsonResponse(200, { docs: [] }))
131
- .mockResolvedValueOnce(textResponse(400, "bad request"));
132
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
133
- await expect(client.upsertByVoyantId("products", "p", {})).rejects.toThrow(/Payload create\(products\) failed \(400\)/);
134
- });
135
- it("throws on update error", async () => {
136
- const fetchMock = vi
137
- .fn()
138
- .mockResolvedValueOnce(jsonResponse(200, { docs: [{ id: "pl_1" }] }))
139
- .mockResolvedValueOnce(textResponse(409, "conflict"));
140
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
141
- await expect(client.upsertByVoyantId("products", "p", {})).rejects.toThrow(/Payload update\(products\/pl_1\) failed \(409\)/);
142
- });
143
- });
144
- describe("createPayloadClient.deleteByVoyantId", () => {
145
- it("deletes when doc exists", async () => {
146
- const fetchMock = vi
147
- .fn()
148
- .mockResolvedValueOnce(jsonResponse(200, { docs: [{ id: "pl_1" }] }))
149
- .mockResolvedValueOnce(jsonResponse(200, {}));
150
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
151
- expect(await client.deleteByVoyantId("products", "p")).toBe(true);
152
- const deleteCall = fetchMock.mock.calls[1];
153
- expect(deleteCall[0]).toBe("https://cms.example.com/api/products/pl_1");
154
- expect(deleteCall[1].method).toBe("DELETE");
155
- });
156
- it("returns false when doc does not exist", async () => {
157
- const fetchMock = vi.fn().mockResolvedValueOnce(jsonResponse(200, { docs: [] }));
158
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
159
- expect(await client.deleteByVoyantId("products", "p")).toBe(false);
160
- expect(fetchMock).toHaveBeenCalledOnce();
161
- });
162
- it("treats 404 on delete as success", async () => {
163
- const fetchMock = vi
164
- .fn()
165
- .mockResolvedValueOnce(jsonResponse(200, { docs: [{ id: "pl_1" }] }))
166
- .mockResolvedValueOnce(textResponse(404, "gone"));
167
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
168
- expect(await client.deleteByVoyantId("products", "p")).toBe(true);
169
- });
170
- it("throws on non-2xx, non-404 delete response", async () => {
171
- const fetchMock = vi
172
- .fn()
173
- .mockResolvedValueOnce(jsonResponse(200, { docs: [{ id: "pl_1" }] }))
174
- .mockResolvedValueOnce(textResponse(500, "boom"));
175
- const client = createPayloadClient({ ...baseOptions, fetch: fetchMock });
176
- await expect(client.deleteByVoyantId("products", "p")).rejects.toThrow(/Payload delete\(products\/pl_1\) failed \(500\)/);
177
- });
178
- });
179
- describe("createPayloadClient — fetch handling", () => {
180
- it("throws when no fetch implementation is available", async () => {
181
- const originalFetch = globalThis.fetch;
182
- globalThis.fetch = undefined;
183
- try {
184
- // biome-ignore lint/suspicious/noExplicitAny: simulating missing fetch
185
- const client = createPayloadClient({ ...baseOptions, fetch: undefined });
186
- await expect(client.findByVoyantId("products", "x")).rejects.toThrow(/requires a fetch implementation/);
187
- }
188
- finally {
189
- globalThis.fetch = originalFetch;
190
- }
191
- });
192
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=plugin.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"plugin.test.d.ts","sourceRoot":"","sources":["../../../tests/unit/plugin.test.ts"],"names":[],"mappings":""}
@@ -1,164 +0,0 @@
1
- import { createEventBus, registerPlugins } from "@voyantjs/core";
2
- import { describe, expect, it, vi } from "vitest";
3
- import { payloadCmsPlugin } from "../../src/plugin.js";
4
- function jsonResponse(status, body) {
5
- const text = JSON.stringify(body);
6
- return {
7
- ok: status >= 200 && status < 300,
8
- status,
9
- json: async () => JSON.parse(text),
10
- text: async () => text,
11
- };
12
- }
13
- const baseOptions = {
14
- apiUrl: "https://cms.example.com/api",
15
- apiKey: "test-key",
16
- collection: "products",
17
- };
18
- describe("payloadCmsPlugin", () => {
19
- it("exposes a stable identity", () => {
20
- const plugin = payloadCmsPlugin({ ...baseOptions });
21
- expect(plugin.name).toBe("payload-cms");
22
- expect(plugin.version).toBeDefined();
23
- expect(plugin.subscribers).toHaveLength(3);
24
- });
25
- it("subscribes to default product.* events", () => {
26
- const plugin = payloadCmsPlugin({ ...baseOptions });
27
- const names = plugin.subscribers?.map((s) => s.event);
28
- expect(names).toEqual(["product.created", "product.updated", "product.deleted"]);
29
- });
30
- it("honors custom event names", () => {
31
- const plugin = payloadCmsPlugin({
32
- ...baseOptions,
33
- events: {
34
- created: "departure.created",
35
- updated: "departure.updated",
36
- deleted: "departure.deleted",
37
- },
38
- });
39
- const names = plugin.subscribers?.map((s) => s.event);
40
- expect(names).toEqual(["departure.created", "departure.updated", "departure.deleted"]);
41
- });
42
- it("pushes product.created to Payload as an upsert", async () => {
43
- const fetchMock = vi
44
- .fn()
45
- .mockResolvedValueOnce(jsonResponse(200, { docs: [] }))
46
- .mockResolvedValueOnce(jsonResponse(201, { doc: { id: "pl_1" } }));
47
- const bus = createEventBus();
48
- const plugin = payloadCmsPlugin({ ...baseOptions, fetch: fetchMock });
49
- registerPlugins([plugin], { eventBus: bus });
50
- await bus.emit("product.created", { id: "prod_1", name: "Tour A" });
51
- expect(fetchMock).toHaveBeenCalledTimes(2);
52
- const [, createInit] = fetchMock.mock.calls[1];
53
- expect(createInit.method).toBe("POST");
54
- const body = JSON.parse(createInit.body ?? "{}");
55
- expect(body).toEqual({ name: "Tour A", voyantId: "prod_1" });
56
- });
57
- it("pushes product.updated to Payload as an upsert", async () => {
58
- const fetchMock = vi
59
- .fn()
60
- .mockResolvedValueOnce(jsonResponse(200, { docs: [{ id: "pl_99" }] }))
61
- .mockResolvedValueOnce(jsonResponse(200, { doc: { id: "pl_99" } }));
62
- const bus = createEventBus();
63
- const plugin = payloadCmsPlugin({ ...baseOptions, fetch: fetchMock });
64
- registerPlugins([plugin], { eventBus: bus });
65
- await bus.emit("product.updated", { id: "prod_1", name: "Tour B" });
66
- const [url, init] = fetchMock.mock.calls[1];
67
- expect(url).toBe("https://cms.example.com/api/products/pl_99");
68
- expect(init.method).toBe("PATCH");
69
- });
70
- it("deletes from Payload on product.deleted", async () => {
71
- const fetchMock = vi
72
- .fn()
73
- .mockResolvedValueOnce(jsonResponse(200, { docs: [{ id: "pl_50" }] }))
74
- .mockResolvedValueOnce(jsonResponse(200, {}));
75
- const bus = createEventBus();
76
- const plugin = payloadCmsPlugin({ ...baseOptions, fetch: fetchMock });
77
- registerPlugins([plugin], { eventBus: bus });
78
- await bus.emit("product.deleted", { id: "prod_1" });
79
- const [url, init] = fetchMock.mock.calls[1];
80
- expect(url).toBe("https://cms.example.com/api/products/pl_50");
81
- expect(init.method).toBe("DELETE");
82
- });
83
- it("applies a custom mapEvent function", async () => {
84
- const fetchMock = vi
85
- .fn()
86
- .mockResolvedValueOnce(jsonResponse(200, { docs: [] }))
87
- .mockResolvedValueOnce(jsonResponse(201, { doc: { id: "pl_1" } }));
88
- const bus = createEventBus();
89
- const plugin = payloadCmsPlugin({
90
- ...baseOptions,
91
- fetch: fetchMock,
92
- mapEvent: (event) => ({
93
- title: String(event.name ?? ""),
94
- _syncedAt: "2024-01-01",
95
- }),
96
- });
97
- registerPlugins([plugin], { eventBus: bus });
98
- await bus.emit("product.created", { id: "prod_x", name: "Cool Tour" });
99
- const [, init] = fetchMock.mock.calls[1];
100
- const body = JSON.parse(init.body ?? "{}");
101
- expect(body).toEqual({
102
- title: "Cool Tour",
103
- _syncedAt: "2024-01-01",
104
- voyantId: "prod_x",
105
- });
106
- });
107
- it("ignores events with no string id", async () => {
108
- const fetchMock = vi.fn();
109
- const bus = createEventBus();
110
- const plugin = payloadCmsPlugin({ ...baseOptions, fetch: fetchMock });
111
- registerPlugins([plugin], { eventBus: bus });
112
- await bus.emit("product.created", { name: "no id here" });
113
- await bus.emit("product.created", null);
114
- await bus.emit("product.created", { id: 42 });
115
- expect(fetchMock).not.toHaveBeenCalled();
116
- });
117
- it("logs and swallows Payload errors (fire-and-forget)", async () => {
118
- const fetchMock = vi.fn().mockResolvedValue({
119
- ok: false,
120
- status: 500,
121
- json: async () => ({}),
122
- text: async () => "server down",
123
- });
124
- const errorFn = vi.fn();
125
- const bus = createEventBus();
126
- const plugin = payloadCmsPlugin({
127
- ...baseOptions,
128
- fetch: fetchMock,
129
- logger: { error: errorFn },
130
- });
131
- registerPlugins([plugin], { eventBus: bus });
132
- await bus.emit("product.created", { id: "prod_1", name: "X" });
133
- expect(errorFn).toHaveBeenCalledOnce();
134
- const [msg] = errorFn.mock.calls[0];
135
- expect(msg).toContain('[payload-cms] upsert on "product.created" failed for prod_1');
136
- });
137
- it("uses a custom collection name for the Payload path", async () => {
138
- const fetchMock = vi
139
- .fn()
140
- .mockResolvedValueOnce(jsonResponse(200, { docs: [] }))
141
- .mockResolvedValueOnce(jsonResponse(201, { doc: { id: "pl_1" } }));
142
- const bus = createEventBus();
143
- const plugin = payloadCmsPlugin({
144
- ...baseOptions,
145
- collection: "tours",
146
- fetch: fetchMock,
147
- });
148
- registerPlugins([plugin], { eventBus: bus });
149
- await bus.emit("product.created", { id: "prod_1", name: "X" });
150
- const [findUrl] = fetchMock.mock.calls[0];
151
- expect(findUrl).toContain("https://cms.example.com/api/tours?");
152
- const [createUrl] = fetchMock.mock.calls[1];
153
- expect(createUrl).toBe("https://cms.example.com/api/tours");
154
- });
155
- it("does not delete if the doc is missing on product.deleted", async () => {
156
- const fetchMock = vi.fn().mockResolvedValueOnce(jsonResponse(200, { docs: [] }));
157
- const bus = createEventBus();
158
- const plugin = payloadCmsPlugin({ ...baseOptions, fetch: fetchMock });
159
- registerPlugins([plugin], { eventBus: bus });
160
- await bus.emit("product.deleted", { id: "prod_missing" });
161
- // Only the find call should have been made.
162
- expect(fetchMock).toHaveBeenCalledOnce();
163
- });
164
- });
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes