@next-buildr/payload 2.0.0 → 3.0.0-rc.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.
Files changed (52) hide show
  1. package/README.md +7 -0
  2. package/UPGRADING.md +322 -0
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/plugin/access.d.ts +7 -0
  5. package/dist/plugin/access.d.ts.map +1 -1
  6. package/dist/plugin/access.js +19 -0
  7. package/dist/plugin/collections/templates.d.ts.map +1 -1
  8. package/dist/plugin/collections/templates.js +9 -3
  9. package/dist/plugin/endpoints/context.d.ts +8 -0
  10. package/dist/plugin/endpoints/context.d.ts.map +1 -1
  11. package/dist/plugin/endpoints/forms-captcha.test.d.ts +2 -0
  12. package/dist/plugin/endpoints/forms-captcha.test.d.ts.map +1 -0
  13. package/dist/plugin/endpoints/forms-captcha.test.js +676 -0
  14. package/dist/plugin/endpoints/forms.d.ts.map +1 -1
  15. package/dist/plugin/endpoints/forms.js +110 -12
  16. package/dist/plugin/endpoints/publish.d.ts.map +1 -1
  17. package/dist/plugin/endpoints/publish.js +4 -0
  18. package/dist/plugin/endpoints/save.d.ts.map +1 -1
  19. package/dist/plugin/endpoints/save.js +3 -0
  20. package/dist/plugin/forms/captcha.d.ts +45 -0
  21. package/dist/plugin/forms/captcha.d.ts.map +1 -0
  22. package/dist/plugin/forms/captcha.js +195 -0
  23. package/dist/plugin/forms/captcha.test.d.ts +2 -0
  24. package/dist/plugin/forms/captcha.test.d.ts.map +1 -0
  25. package/dist/plugin/forms/captcha.test.js +262 -0
  26. package/dist/plugin/forms/client-ip.d.ts +8 -0
  27. package/dist/plugin/forms/client-ip.d.ts.map +1 -0
  28. package/dist/plugin/forms/client-ip.js +41 -0
  29. package/dist/plugin/forms/client-ip.test.d.ts +2 -0
  30. package/dist/plugin/forms/client-ip.test.d.ts.map +1 -0
  31. package/dist/plugin/forms/client-ip.test.js +45 -0
  32. package/dist/plugin/forms/rate-limit.d.ts +2 -0
  33. package/dist/plugin/forms/rate-limit.d.ts.map +1 -1
  34. package/dist/plugin/forms/rate-limit.js +10 -1
  35. package/dist/plugin/hooks/author-code.test.d.ts +2 -0
  36. package/dist/plugin/hooks/author-code.test.d.ts.map +1 -0
  37. package/dist/plugin/hooks/author-code.test.js +285 -0
  38. package/dist/plugin/hooks/layout-hook.d.ts +1 -1
  39. package/dist/plugin/hooks/layout-hook.d.ts.map +1 -1
  40. package/dist/plugin/hooks/layout-hook.js +12 -2
  41. package/dist/plugin/hooks/process-layout.d.ts +10 -0
  42. package/dist/plugin/hooks/process-layout.d.ts.map +1 -1
  43. package/dist/plugin/hooks/process-layout.js +94 -1
  44. package/dist/plugin/hooks/read-layout.d.ts +1 -1
  45. package/dist/plugin/hooks/read-layout.d.ts.map +1 -1
  46. package/dist/plugin/index.d.ts.map +1 -1
  47. package/dist/plugin/index.js +20 -1
  48. package/dist/plugin/options.d.ts +11 -0
  49. package/dist/plugin/options.d.ts.map +1 -1
  50. package/dist/plugin/options.js +49 -1
  51. package/dist/plugin/plugin.test.js +81 -2
  52. package/package.json +13 -11
@@ -1,11 +1,12 @@
1
1
  import { mkdtempSync, rmSync } from 'node:fs';
2
2
  import { tmpdir } from 'node:os';
3
3
  import { join } from 'node:path';
4
- import { createEmptyDocument } from '@next-buildr/core';
4
+ import { createEmptyDocument, createRegistryMeta } from '@next-buildr/core';
5
5
  import { sqliteAdapter } from '@payloadcms/db-sqlite';
6
6
  import { buildConfig, getPayload } from 'payload';
7
- import { afterAll, beforeAll, describe, expect, it } from 'vitest';
7
+ import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
8
8
  import { buildrPlugin } from './index.js';
9
+ import { resolveOptions } from './options.js';
9
10
  import { BUILDR_WRITE } from './write-guard.js';
10
11
  const pages = {
11
12
  slug: 'pages',
@@ -16,6 +17,84 @@ const layoutOf = (name) => ({
16
17
  ...createEmptyDocument(),
17
18
  nodes: { root: { id: 'root', type: 'buildr/page', name } },
18
19
  });
20
+ describe('captcha options', () => {
21
+ const secret = 'never-echo-this-secret';
22
+ const valid = {
23
+ collections: {},
24
+ forms: {
25
+ enabled: true,
26
+ clientIp: { header: 'trusted-ip' },
27
+ captcha: { secretKey: secret, hostnames: ['example.com'] },
28
+ },
29
+ };
30
+ it('ignores unknown forms keys as before', () => {
31
+ expect(resolveOptions({ collections: {}, forms: { legacy: true } }).forms
32
+ .enabled).toBe(false);
33
+ });
34
+ it('keeps verifier implementation out of the public entry', async () => {
35
+ const entry = await import('./index.js');
36
+ expect(entry).not.toHaveProperty('createTurnstileVerifier');
37
+ });
38
+ it('serialises no captcha secret and preserves the host onInit hook', async () => {
39
+ const onInit = vi.fn();
40
+ const config = await buildrPlugin({
41
+ ...valid,
42
+ registry: { meta: createRegistryMeta({ components: [] }) },
43
+ })({ collections: [], onInit });
44
+ expect(JSON.stringify(config)).not.toContain(secret);
45
+ const payload = { logger: { error: vi.fn(), warn: vi.fn() } };
46
+ await config.onInit?.(payload);
47
+ expect(onInit).toHaveBeenCalledExactlyOnceWith(payload);
48
+ });
49
+ it('applies provider, concurrency and trusted hop defaults; accepts a request callback', () => {
50
+ expect(resolveOptions(valid).forms).toMatchObject({
51
+ captcha: { provider: 'turnstile', maxInFlight: 16 },
52
+ clientIp: { hops: 1 },
53
+ });
54
+ const callback = () => '192.0.2.1';
55
+ expect(resolveOptions({ ...valid, forms: { ...valid.forms, clientIp: callback } }).forms.clientIp).toBe(callback);
56
+ });
57
+ it.each([
58
+ { enabled: false },
59
+ { clientIp: undefined },
60
+ { captcha: { secretKey: secret } },
61
+ { captcha: { secretKey: secret, hostnames: [] } },
62
+ ...[
63
+ '.',
64
+ '..',
65
+ '-',
66
+ 'example.com.',
67
+ '-example.com',
68
+ 'example-.com',
69
+ `${'a'.repeat(64)}.com`,
70
+ 'EXAMPLE.COM',
71
+ 'https://example.com',
72
+ 'example.com:443',
73
+ 'example.com/path',
74
+ 'a'.repeat(254),
75
+ 'example.com\n',
76
+ ].map((hostname) => ({ captcha: { secretKey: secret, hostnames: [hostname] } })),
77
+ ...[0, 1.5, 1025].map((maxInFlight) => ({ captcha: { ...valid.forms.captcha, maxInFlight } })),
78
+ { captcha: { ...valid.forms.captcha, secretKey: '' } },
79
+ { captcha: { ...valid.forms.captcha, provider: 'other' } },
80
+ { captcha: { ...valid.forms.captcha, verifier: { verify() { } } } },
81
+ { captcha: { ...valid.forms.captcha, [secret]: true } },
82
+ ...['X-Forwarded-For', '', 'a b', 'valid\n', 'x'.repeat(65)].map((header) => ({
83
+ clientIp: { header },
84
+ })),
85
+ ...[0, -1, 1.5].map((hops) => ({ clientIp: { header: 'trusted-ip', hops } })),
86
+ ])('rejects invalid captcha configuration without exposing the secret', (change) => {
87
+ let message = '';
88
+ try {
89
+ resolveOptions({ ...valid, forms: { ...valid.forms, ...change } });
90
+ }
91
+ catch (error) {
92
+ message = error.message;
93
+ }
94
+ expect(message).toContain('buildrPlugin: invalid options');
95
+ expect(message).not.toContain(secret);
96
+ });
97
+ });
19
98
  let dir;
20
99
  const configOf = (options, collections = [pages]) => buildConfig({
21
100
  secret: 'test-secret',
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@next-buildr/payload",
3
- "version": "2.0.0",
3
+ "version": "3.0.0-rc.0",
4
4
  "private": false,
5
+ "license": "MIT",
5
6
  "type": "module",
6
7
  "sideEffects": false,
7
8
  "exports": {
@@ -39,16 +40,17 @@
39
40
  "access": "public"
40
41
  },
41
42
  "files": [
42
- "dist"
43
+ "dist",
44
+ "UPGRADING.md"
43
45
  ],
44
46
  "dependencies": {
45
- "@next-buildr/core": "2.0.0",
47
+ "@next-buildr/core": "3.0.0-rc.0",
46
48
  "zod": "^4.6.5"
47
49
  },
48
50
  "peerDependencies": {
49
- "@next-buildr/editor": "2.0.0",
50
- "@next-buildr/mcp": "2.0.0",
51
- "@next-buildr/next": "2.0.0",
51
+ "@next-buildr/editor": "3.0.0-rc.0",
52
+ "@next-buildr/mcp": "3.0.0-rc.0",
53
+ "@next-buildr/next": "3.0.0-rc.0",
52
54
  "@modelcontextprotocol/sdk": "^1.30.1",
53
55
  "@payloadcms/ui": "^3.0.0",
54
56
  "next": "^15.0.0 || ^16.0.0",
@@ -78,11 +80,11 @@
78
80
  }
79
81
  },
80
82
  "devDependencies": {
81
- "@next-buildr/editor": "2.0.0",
82
- "@next-buildr/mcp": "2.0.0",
83
- "@next-buildr/next": "2.0.0",
84
- "@next-buildr/test-utils": "2.0.0",
85
- "@next-buildr/tsconfig": "2.0.0",
83
+ "@next-buildr/editor": "3.0.0-rc.0",
84
+ "@next-buildr/mcp": "3.0.0-rc.0",
85
+ "@next-buildr/next": "3.0.0-rc.0",
86
+ "@next-buildr/test-utils": "3.0.0-rc.0",
87
+ "@next-buildr/tsconfig": "3.0.0-rc.0",
86
88
  "@modelcontextprotocol/sdk": "^1.30.1",
87
89
  "@payloadcms/db-sqlite": "3.90.1",
88
90
  "@payloadcms/ui": "3.90.1",