@actuate-media/cms-core 0.10.4 → 0.11.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 (125) hide show
  1. package/dist/__tests__/api/admin-contracts.test.js +1 -0
  2. package/dist/__tests__/api/admin-contracts.test.js.map +1 -1
  3. package/dist/__tests__/api/public-globals.test.js +8 -4
  4. package/dist/__tests__/api/public-globals.test.js.map +1 -1
  5. package/dist/__tests__/security/audit.test.d.ts +2 -0
  6. package/dist/__tests__/security/audit.test.d.ts.map +1 -0
  7. package/dist/__tests__/security/audit.test.js +50 -0
  8. package/dist/__tests__/security/audit.test.js.map +1 -0
  9. package/dist/__tests__/security/client-ip.test.d.ts +2 -0
  10. package/dist/__tests__/security/client-ip.test.d.ts.map +1 -0
  11. package/dist/__tests__/security/client-ip.test.js +37 -0
  12. package/dist/__tests__/security/client-ip.test.js.map +1 -0
  13. package/dist/__tests__/security/ip-allowlist.test.d.ts +2 -0
  14. package/dist/__tests__/security/ip-allowlist.test.d.ts.map +1 -0
  15. package/dist/__tests__/security/ip-allowlist.test.js +40 -0
  16. package/dist/__tests__/security/ip-allowlist.test.js.map +1 -0
  17. package/dist/__tests__/security/redact.test.d.ts +2 -0
  18. package/dist/__tests__/security/redact.test.d.ts.map +1 -0
  19. package/dist/__tests__/security/redact.test.js +31 -0
  20. package/dist/__tests__/security/redact.test.js.map +1 -0
  21. package/dist/__tests__/security/secret-storage.test.d.ts +2 -0
  22. package/dist/__tests__/security/secret-storage.test.d.ts.map +1 -0
  23. package/dist/__tests__/security/secret-storage.test.js +42 -0
  24. package/dist/__tests__/security/secret-storage.test.js.map +1 -0
  25. package/dist/__tests__/security/upload-magic.test.d.ts +2 -0
  26. package/dist/__tests__/security/upload-magic.test.d.ts.map +1 -0
  27. package/dist/__tests__/security/upload-magic.test.js +55 -0
  28. package/dist/__tests__/security/upload-magic.test.js.map +1 -0
  29. package/dist/__tests__/server-site.test.d.ts +2 -0
  30. package/dist/__tests__/server-site.test.d.ts.map +1 -0
  31. package/dist/__tests__/server-site.test.js +123 -0
  32. package/dist/__tests__/server-site.test.js.map +1 -0
  33. package/dist/actions.d.ts.map +1 -1
  34. package/dist/actions.js +170 -34
  35. package/dist/actions.js.map +1 -1
  36. package/dist/api/handler-factory.d.ts.map +1 -1
  37. package/dist/api/handler-factory.js +64 -9
  38. package/dist/api/handler-factory.js.map +1 -1
  39. package/dist/api/handlers.d.ts.map +1 -1
  40. package/dist/api/handlers.js +673 -116
  41. package/dist/api/handlers.js.map +1 -1
  42. package/dist/api/openapi.d.ts.map +1 -1
  43. package/dist/api/openapi.js +38 -0
  44. package/dist/api/openapi.js.map +1 -1
  45. package/dist/auth/mfa-pending.d.ts +24 -0
  46. package/dist/auth/mfa-pending.d.ts.map +1 -0
  47. package/dist/auth/mfa-pending.js +38 -0
  48. package/dist/auth/mfa-pending.js.map +1 -0
  49. package/dist/auth/oauth.d.ts +25 -3
  50. package/dist/auth/oauth.d.ts.map +1 -1
  51. package/dist/auth/oauth.js +109 -20
  52. package/dist/auth/oauth.js.map +1 -1
  53. package/dist/auth/reset.d.ts.map +1 -1
  54. package/dist/auth/reset.js +26 -2
  55. package/dist/auth/reset.js.map +1 -1
  56. package/dist/auth/session.d.ts +9 -2
  57. package/dist/auth/session.d.ts.map +1 -1
  58. package/dist/auth/session.js +20 -2
  59. package/dist/auth/session.js.map +1 -1
  60. package/dist/index.d.ts +2 -0
  61. package/dist/index.d.ts.map +1 -1
  62. package/dist/index.js +2 -0
  63. package/dist/index.js.map +1 -1
  64. package/dist/middleware.d.ts.map +1 -1
  65. package/dist/middleware.js +21 -34
  66. package/dist/middleware.js.map +1 -1
  67. package/dist/page-builder/__tests__/blocks.test.js +104 -1
  68. package/dist/page-builder/__tests__/blocks.test.js.map +1 -1
  69. package/dist/page-builder/blocks.d.ts +18 -1
  70. package/dist/page-builder/blocks.d.ts.map +1 -1
  71. package/dist/page-builder/blocks.js +22 -2
  72. package/dist/page-builder/blocks.js.map +1 -1
  73. package/dist/security/audit.d.ts.map +1 -1
  74. package/dist/security/audit.js +8 -4
  75. package/dist/security/audit.js.map +1 -1
  76. package/dist/security/client-ip.d.ts +33 -0
  77. package/dist/security/client-ip.d.ts.map +1 -0
  78. package/dist/security/client-ip.js +39 -0
  79. package/dist/security/client-ip.js.map +1 -0
  80. package/dist/security/index.d.ts +7 -0
  81. package/dist/security/index.d.ts.map +1 -1
  82. package/dist/security/index.js +5 -0
  83. package/dist/security/index.js.map +1 -1
  84. package/dist/security/internal-keys.d.ts +15 -0
  85. package/dist/security/internal-keys.d.ts.map +1 -0
  86. package/dist/security/internal-keys.js +33 -0
  87. package/dist/security/internal-keys.js.map +1 -0
  88. package/dist/security/ip-allowlist.d.ts +13 -1
  89. package/dist/security/ip-allowlist.d.ts.map +1 -1
  90. package/dist/security/ip-allowlist.js +120 -12
  91. package/dist/security/ip-allowlist.js.map +1 -1
  92. package/dist/security/rate-limit.d.ts.map +1 -1
  93. package/dist/security/rate-limit.js +49 -17
  94. package/dist/security/rate-limit.js.map +1 -1
  95. package/dist/security/redact.d.ts +12 -0
  96. package/dist/security/redact.d.ts.map +1 -0
  97. package/dist/security/redact.js +41 -0
  98. package/dist/security/redact.js.map +1 -0
  99. package/dist/security/safe-fetch.d.ts +35 -0
  100. package/dist/security/safe-fetch.d.ts.map +1 -0
  101. package/dist/security/safe-fetch.js +45 -0
  102. package/dist/security/safe-fetch.js.map +1 -0
  103. package/dist/security/secret-storage.d.ts +22 -0
  104. package/dist/security/secret-storage.d.ts.map +1 -0
  105. package/dist/security/secret-storage.js +75 -0
  106. package/dist/security/secret-storage.js.map +1 -0
  107. package/dist/security/upload.d.ts +23 -4
  108. package/dist/security/upload.d.ts.map +1 -1
  109. package/dist/security/upload.js +110 -21
  110. package/dist/security/upload.js.map +1 -1
  111. package/dist/server-site.d.ts +54 -0
  112. package/dist/server-site.d.ts.map +1 -0
  113. package/dist/server-site.js +149 -0
  114. package/dist/server-site.js.map +1 -0
  115. package/dist/site.d.ts.map +1 -1
  116. package/dist/site.js +19 -1
  117. package/dist/site.js.map +1 -1
  118. package/dist/storage/index.d.ts +20 -10
  119. package/dist/storage/index.d.ts.map +1 -1
  120. package/dist/storage/index.js +6 -3
  121. package/dist/storage/index.js.map +1 -1
  122. package/dist/webhooks/index.d.ts.map +1 -1
  123. package/dist/webhooks/index.js +20 -9
  124. package/dist/webhooks/index.js.map +1 -1
  125. package/package.json +1 -1
@@ -0,0 +1,75 @@
1
+ import { encryptField, decryptField } from './encrypted-fields.js';
2
+ /**
3
+ * High-level helpers for storing per-user secrets (TOTP secret, OAuth tokens,
4
+ * webhook signing keys) at rest. Wraps the raw `encryptField`/`decryptField`
5
+ * primitives so callers don't have to plumb `CMS_ENCRYPTION_KEY` through every
6
+ * code path.
7
+ *
8
+ * Encrypted values are tagged with a version prefix so we can rotate keys or
9
+ * change the encoding without breaking existing rows. Plaintext values written
10
+ * before encryption was enabled are passed through unchanged on read so
11
+ * upgrades don't break existing data — call `migrateSecret()` when you want
12
+ * to opportunistically re-encrypt them on next access.
13
+ */
14
+ const PREFIX = 'enc:v1:';
15
+ function getKey() {
16
+ const key = process.env.CMS_ENCRYPTION_KEY;
17
+ if (!key)
18
+ return null;
19
+ // 32 bytes = 64 hex chars
20
+ if (key.length !== 64) {
21
+ console.warn('[actuate][crypto] CMS_ENCRYPTION_KEY must be 64 hex characters (32 bytes); got '
22
+ + key.length
23
+ + '. Falling back to plaintext storage. Generate with: '
24
+ + 'node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'hex\'))"');
25
+ return null;
26
+ }
27
+ return key;
28
+ }
29
+ /**
30
+ * Encrypt a value for storage. Returns the original value unchanged when no
31
+ * encryption key is configured (development convenience). Production deployments
32
+ * MUST set `CMS_ENCRYPTION_KEY` — see `security.mdc`.
33
+ */
34
+ export async function encryptSecret(plaintext) {
35
+ if (!plaintext)
36
+ return plaintext;
37
+ const key = getKey();
38
+ if (!key)
39
+ return plaintext;
40
+ const ciphertext = await encryptField(plaintext, key);
41
+ return PREFIX + ciphertext;
42
+ }
43
+ /**
44
+ * Decrypt a value that was stored via `encryptSecret`. Plaintext values
45
+ * (written before encryption was enabled, or written by a deployment without
46
+ * the key) are returned unchanged.
47
+ */
48
+ export async function decryptSecret(stored) {
49
+ if (!stored)
50
+ return stored;
51
+ if (!stored.startsWith(PREFIX))
52
+ return stored;
53
+ const key = getKey();
54
+ if (!key) {
55
+ throw new Error('CMS_ENCRYPTION_KEY is required to decrypt this value but is not set. '
56
+ + 'Configure the same key used at write time.');
57
+ }
58
+ return decryptField(stored.slice(PREFIX.length), key);
59
+ }
60
+ /** True when the value is stored encrypted (and therefore needs decryption). */
61
+ export function isEncrypted(value) {
62
+ return typeof value === 'string' && value.startsWith(PREFIX);
63
+ }
64
+ /**
65
+ * Encrypt each string element in an array. Returns the array unchanged when
66
+ * encryption is disabled. Used for things like TOTP backup codes.
67
+ */
68
+ export async function encryptStringArray(values) {
69
+ return Promise.all(values.map((v) => encryptSecret(v)));
70
+ }
71
+ /** Decrypt each element in an array stored via `encryptStringArray`. */
72
+ export async function decryptStringArray(values) {
73
+ return Promise.all(values.map((v) => decryptSecret(v)));
74
+ }
75
+ //# sourceMappingURL=secret-storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secret-storage.js","sourceRoot":"","sources":["../../src/security/secret-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEnE;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,GAAG,SAAS,CAAC;AAEzB,SAAS,MAAM;IACb,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC3C,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,0BAA0B;IAC1B,IAAI,GAAG,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CACV,iFAAiF;cAC7E,GAAG,CAAC,MAAM;cACV,sDAAsD;cACtD,8EAA8E,CACnF,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,SAAiB;IACnD,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACtD,OAAO,MAAM,GAAG,UAAU,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,IAAI,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9C,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC;IACrB,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,uEAAuE;cACnE,4CAA4C,CACjD,CAAC;IACJ,CAAC;IACD,OAAO,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;AACxD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAC/D,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAgB;IACvD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,wEAAwE;AACxE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAgB;IACvD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -5,9 +5,28 @@ export interface FileValidationResult {
5
5
  }
6
6
  declare const ALLOWED_IMAGE_TYPES: Set<string>;
7
7
  declare const ALLOWED_DOCUMENT_TYPES: Set<string>;
8
- /** Validate a file's MIME type against an allowlist. */
9
- export declare function validateMimeType(mimeType: string, allowedTypes?: Set<string>): FileValidationResult;
10
- /** Check a file's magic bytes to detect its true MIME type. */
11
- export declare function checkMagicBytes(buffer: Uint8Array): string | undefined;
8
+ /**
9
+ * Validate a file's declared MIME type against an allowlist.
10
+ *
11
+ * Accepts either an array (typical caller form) or a Set (legacy form).
12
+ * Returns a plain boolean to make call-sites read naturally:
13
+ *
14
+ * if (!validateMimeType(file.type, ALLOWED)) return badRequest(...)
15
+ */
16
+ export declare function validateMimeType(mimeType: string, allowedTypes?: ReadonlyArray<string> | ReadonlySet<string>): boolean;
17
+ /**
18
+ * Check a file's magic bytes against the declared mime type. Returns
19
+ * `{ valid: true, detectedMimeType }` when the bytes match the declared type
20
+ * (or when we have no signature to check), and `{ valid: false, error }`
21
+ * otherwise.
22
+ *
23
+ * For container formats (WebP, AVIF) we additionally inspect the inner
24
+ * sub-type — a generic RIFF header would otherwise let `.wav` files masquerade
25
+ * as `.webp` and bypass image-only checks.
26
+ *
27
+ * For SVG (which is XML, not a binary signature) we look for `<svg` near the
28
+ * start of the file. A leading XML declaration or BOM is allowed.
29
+ */
30
+ export declare function checkMagicBytes(input: ArrayBuffer | Uint8Array | Buffer, declaredMimeType: string): FileValidationResult;
12
31
  export { ALLOWED_IMAGE_TYPES, ALLOWED_DOCUMENT_TYPES };
13
32
  //# sourceMappingURL=upload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/security/upload.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,QAAA,MAAM,mBAAmB,aAEvB,CAAC;AAEH,QAAA,MAAM,sBAAsB,aAI1B,CAAC;AAUH,wDAAwD;AACxD,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GACzB,oBAAoB,CAMtB;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAC7B,MAAM,EAAE,UAAU,GACjB,MAAM,GAAG,SAAS,CAMpB;AAED,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/security/upload.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,QAAA,MAAM,mBAAmB,aAOvB,CAAC;AAEH,QAAA,MAAM,sBAAsB,aAM1B,CAAC;AAEH;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,GACzD,OAAO,CAKT;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,MAAM,EACxC,gBAAgB,EAAE,MAAM,GACvB,oBAAoB,CA6BtB;AA2DD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC"}
@@ -1,34 +1,123 @@
1
1
  const ALLOWED_IMAGE_TYPES = new Set([
2
- "image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml", "image/avif",
2
+ "image/jpeg",
3
+ "image/png",
4
+ "image/gif",
5
+ "image/webp",
6
+ "image/svg+xml",
7
+ "image/avif",
3
8
  ]);
4
9
  const ALLOWED_DOCUMENT_TYPES = new Set([
5
- "application/pdf", "text/plain", "text/csv",
10
+ "application/pdf",
11
+ "text/plain",
12
+ "text/csv",
6
13
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
7
14
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
8
15
  ]);
9
- const MAGIC_BYTES = [
10
- { mime: "image/jpeg", bytes: [0xFF, 0xD8, 0xFF] },
11
- { mime: "image/png", bytes: [0x89, 0x50, 0x4E, 0x47] },
12
- { mime: "image/gif", bytes: [0x47, 0x49, 0x46] },
13
- { mime: "image/webp", bytes: [0x52, 0x49, 0x46, 0x46] },
14
- { mime: "application/pdf", bytes: [0x25, 0x50, 0x44, 0x46] },
15
- ];
16
- /** Validate a file's MIME type against an allowlist. */
16
+ /**
17
+ * Validate a file's declared MIME type against an allowlist.
18
+ *
19
+ * Accepts either an array (typical caller form) or a Set (legacy form).
20
+ * Returns a plain boolean to make call-sites read naturally:
21
+ *
22
+ * if (!validateMimeType(file.type, ALLOWED)) return badRequest(...)
23
+ */
17
24
  export function validateMimeType(mimeType, allowedTypes) {
18
- const allowed = allowedTypes ?? new Set([...ALLOWED_IMAGE_TYPES, ...ALLOWED_DOCUMENT_TYPES]);
19
- if (!allowed.has(mimeType)) {
20
- return { valid: false, error: `MIME type "${mimeType}" is not allowed` };
25
+ const allowed = allowedTypes
26
+ ? (allowedTypes instanceof Set ? allowedTypes : new Set(allowedTypes))
27
+ : new Set([...ALLOWED_IMAGE_TYPES, ...ALLOWED_DOCUMENT_TYPES]);
28
+ return allowed.has(mimeType);
29
+ }
30
+ /**
31
+ * Check a file's magic bytes against the declared mime type. Returns
32
+ * `{ valid: true, detectedMimeType }` when the bytes match the declared type
33
+ * (or when we have no signature to check), and `{ valid: false, error }`
34
+ * otherwise.
35
+ *
36
+ * For container formats (WebP, AVIF) we additionally inspect the inner
37
+ * sub-type — a generic RIFF header would otherwise let `.wav` files masquerade
38
+ * as `.webp` and bypass image-only checks.
39
+ *
40
+ * For SVG (which is XML, not a binary signature) we look for `<svg` near the
41
+ * start of the file. A leading XML declaration or BOM is allowed.
42
+ */
43
+ export function checkMagicBytes(input, declaredMimeType) {
44
+ const bytes = toUint8(input);
45
+ const detected = detectMimeType(bytes);
46
+ // No signature for the declared type — accept (caller is expected to have
47
+ // already checked the allowlist).
48
+ if (detected === null) {
49
+ return { valid: true };
50
+ }
51
+ if (detected === declaredMimeType) {
52
+ return { valid: true, detectedMimeType: detected };
53
+ }
54
+ // Some legitimate aliases:
55
+ // image/jpg ↔ image/jpeg
56
+ // image/x-png ↔ image/png
57
+ if ((detected === 'image/jpeg' && declaredMimeType === 'image/jpg') ||
58
+ (detected === 'image/png' && declaredMimeType === 'image/x-png')) {
59
+ return { valid: true, detectedMimeType: detected };
21
60
  }
22
- return { valid: true };
61
+ return {
62
+ valid: false,
63
+ error: `Declared "${declaredMimeType}" but content looks like "${detected}"`,
64
+ detectedMimeType: detected,
65
+ };
23
66
  }
24
- /** Check a file's magic bytes to detect its true MIME type. */
25
- export function checkMagicBytes(buffer) {
26
- for (const entry of MAGIC_BYTES) {
27
- const matches = entry.bytes.every((byte, i) => buffer[i] === byte);
28
- if (matches)
29
- return entry.mime;
67
+ function toUint8(input) {
68
+ if (input instanceof Uint8Array)
69
+ return input;
70
+ return new Uint8Array(input);
71
+ }
72
+ /** Returns the detected mime type, or null when the bytes don't match a known signature. */
73
+ function detectMimeType(b) {
74
+ if (b.length < 4)
75
+ return null;
76
+ if (b[0] === 0xFF && b[1] === 0xD8 && b[2] === 0xFF)
77
+ return 'image/jpeg';
78
+ if (b[0] === 0x89 && b[1] === 0x50 && b[2] === 0x4E && b[3] === 0x47)
79
+ return 'image/png';
80
+ // GIF: full 6-byte signature ("GIF87a" or "GIF89a"), not just "GIF".
81
+ if (b[0] === 0x47 && b[1] === 0x49 && b[2] === 0x46 && b[3] === 0x38 &&
82
+ (b[4] === 0x37 || b[4] === 0x39) && b[5] === 0x61)
83
+ return 'image/gif';
84
+ // RIFF + 4-byte size + format identifier ("WEBP" / "WAVE" / "AVI ").
85
+ if (b.length >= 12 && b[0] === 0x52 && b[1] === 0x49 && b[2] === 0x46 && b[3] === 0x46) {
86
+ if (b[8] === 0x57 && b[9] === 0x45 && b[10] === 0x42 && b[11] === 0x50)
87
+ return 'image/webp';
88
+ if (b[8] === 0x57 && b[9] === 0x41 && b[10] === 0x56 && b[11] === 0x45)
89
+ return 'audio/wav';
90
+ }
91
+ // AVIF / HEIC: ISO BMFF "ftyp" box at offset 4 with brand at offset 8.
92
+ if (b.length >= 12 && b[4] === 0x66 && b[5] === 0x74 && b[6] === 0x79 && b[7] === 0x70) {
93
+ const brand = String.fromCharCode(b[8] ?? 0, b[9] ?? 0, b[10] ?? 0, b[11] ?? 0);
94
+ if (brand === 'avif' || brand === 'avis')
95
+ return 'image/avif';
96
+ if (brand === 'mp42' || brand === 'isom' || brand === 'iso2')
97
+ return 'video/mp4';
98
+ }
99
+ // PDF
100
+ if (b[0] === 0x25 && b[1] === 0x50 && b[2] === 0x44 && b[3] === 0x46)
101
+ return 'application/pdf';
102
+ // OGG
103
+ if (b[0] === 0x4F && b[1] === 0x67 && b[2] === 0x67 && b[3] === 0x53)
104
+ return 'audio/ogg';
105
+ // MP3 — either "ID3" tag or a frame sync (0xFFE).
106
+ if (b[0] === 0x49 && b[1] === 0x44 && b[2] === 0x33)
107
+ return 'audio/mpeg';
108
+ if (b[0] === 0xFF && (b[1] & 0xE0) === 0xE0)
109
+ return 'audio/mpeg';
110
+ // WebM / Matroska EBML header
111
+ if (b[0] === 0x1A && b[1] === 0x45 && b[2] === 0xDF && b[3] === 0xA3)
112
+ return 'video/webm';
113
+ // SVG: scan the first 1024 bytes for a "<svg" tag. Accept optional XML
114
+ // declaration / BOM / whitespace / comments.
115
+ const head = new TextDecoder('utf-8', { fatal: false }).decode(b.slice(0, 1024)).trimStart();
116
+ if (head.toLowerCase().includes('<svg') ||
117
+ head.startsWith('<?xml') && head.toLowerCase().includes('<svg')) {
118
+ return 'image/svg+xml';
30
119
  }
31
- return undefined;
120
+ return null;
32
121
  }
33
122
  export { ALLOWED_IMAGE_TYPES, ALLOWED_DOCUMENT_TYPES };
34
123
  //# sourceMappingURL=upload.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/security/upload.ts"],"names":[],"mappings":"AAMA,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY;CACpF,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG,IAAI,GAAG,CAAC;IACrC,iBAAiB,EAAE,YAAY,EAAE,UAAU;IAC3C,yEAAyE;IACzE,mEAAmE;CACpE,CAAC,CAAC;AAEH,MAAM,WAAW,GAA6C;IAC5D,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;IACjD,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;IACtD,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;IAChD,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;IACvD,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE;CAC7D,CAAC;AAEF,wDAAwD;AACxD,MAAM,UAAU,gBAAgB,CAC9B,QAAgB,EAChB,YAA0B;IAE1B,MAAM,OAAO,GAAG,YAAY,IAAI,IAAI,GAAG,CAAC,CAAC,GAAG,mBAAmB,EAAE,GAAG,sBAAsB,CAAC,CAAC,CAAC;IAC7F,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,QAAQ,kBAAkB,EAAE,CAAC;IAC3E,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,eAAe,CAC7B,MAAkB;IAElB,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QACnE,IAAI,OAAO;YAAE,OAAO,KAAK,CAAC,IAAI,CAAC;IACjC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/security/upload.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import type { SiteClient, ResolvedMedia, MediaInput } from './site.js';
2
+ /**
3
+ * Server-only Site client that reads from the database directly.
4
+ *
5
+ * Use this in Server Components, `generateMetadata`, route loaders, and
6
+ * anywhere else you would otherwise be tempted to call `createSiteClient()`
7
+ * with a relative URL (which throws under bare Node `fetch`).
8
+ *
9
+ * import { PrismaClient } from '@/generated/prisma'
10
+ * import { createServerSiteClient } from '@actuate-media/cms-core'
11
+ * import config from '@/actuate.config'
12
+ *
13
+ * const prisma = new PrismaClient()
14
+ * const cms = createServerSiteClient(prisma, config)
15
+ *
16
+ * const settings = await cms.getGlobal('settings')
17
+ *
18
+ * Benefits over the fetch-based client in Server Components:
19
+ * - Zero self-fetch overhead (one DB roundtrip instead of HTTP).
20
+ * - No `NEXT_PUBLIC_SITE_URL` plumbing required.
21
+ * - Works under bare Node, Edge runtime with Prisma Accelerate, or any
22
+ * Prisma-compatible client.
23
+ * - Bypasses Next.js fetch caching pitfalls on Server Components.
24
+ */
25
+ export interface CmsConfigLike {
26
+ /** Map of global slug → global definition. `access.read` is consulted before returning data. */
27
+ globals?: Record<string, {
28
+ access?: {
29
+ read?: (ctx: {
30
+ user: null;
31
+ doc: any;
32
+ }) => boolean | Promise<boolean>;
33
+ };
34
+ }>;
35
+ /** Map of collection slug → collection definition (used by `resolveDocument`). */
36
+ collections?: Record<string, {
37
+ slug?: string;
38
+ type?: string;
39
+ urlPrefix?: string;
40
+ }>;
41
+ }
42
+ export interface ServerSiteClient extends SiteClient {
43
+ /** Resolve any media-like value into a normalized shape, looking up by id from the DB when needed. */
44
+ resolveMedia(value: MediaInput): Promise<ResolvedMedia | null>;
45
+ }
46
+ /**
47
+ * Build the server-side Site client. The supplied `db` only needs a tiny
48
+ * subset of the Prisma surface (`document`, `media`) — that lets us accept
49
+ * generated PrismaClient instances from any consumer schema without forcing
50
+ * a hard type dependency.
51
+ */
52
+ export declare function createServerSiteClient(db: any, config?: CmsConfigLike): ServerSiteClient;
53
+ export { normalizeMedia, resolveMedia } from './site.js';
54
+ //# sourceMappingURL=server-site.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-site.d.ts","sourceRoot":"","sources":["../src/server-site.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAEV,aAAa,EACb,UAAU,EAEX,MAAM,WAAW,CAAC;AAGnB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,WAAW,aAAa;IAC5B,gGAAgG;IAChG,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE;gBAAE,IAAI,EAAE,IAAI,CAAC;gBAAC,GAAG,EAAE,GAAG,CAAA;aAAE,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;IAChH,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpF;AAED,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,sGAAsG;IACtG,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;CAChE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,EAAE,EAAE,GAAG,EACP,MAAM,GAAE,aAAkB,GACzB,gBAAgB,CA+IlB;AAID,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,149 @@
1
+ import { resolveMedia } from './site.js';
2
+ /**
3
+ * Build the server-side Site client. The supplied `db` only needs a tiny
4
+ * subset of the Prisma surface (`document`, `media`) — that lets us accept
5
+ * generated PrismaClient instances from any consumer schema without forcing
6
+ * a hard type dependency.
7
+ */
8
+ export function createServerSiteClient(db, config = {}) {
9
+ if (!db || typeof db !== 'object') {
10
+ throw new Error('createServerSiteClient: `db` must be a Prisma-compatible client');
11
+ }
12
+ async function getGlobal(slug) {
13
+ const globalConfig = config.globals?.[slug];
14
+ if (!db.document?.findFirst)
15
+ return null;
16
+ const doc = await db.document.findFirst({
17
+ where: { collection: slug, deletedAt: null },
18
+ });
19
+ if (!doc)
20
+ return null;
21
+ // Honor the same access policy the public REST endpoint enforces. When
22
+ // no policy is configured we default to "public" — globals routed through
23
+ // `getGlobal()` are by definition public site data; integrators that want
24
+ // gating should set `access.read` explicitly.
25
+ if (globalConfig?.access?.read) {
26
+ const allowed = await globalConfig.access.read({ user: null, doc });
27
+ if (!allowed)
28
+ return null;
29
+ }
30
+ return (doc.data && typeof doc.data === 'object'
31
+ ? doc.data
32
+ : {});
33
+ }
34
+ async function resolveDocument(path) {
35
+ const segments = path.replace(/^\/|\/$/g, '').split('/').filter(Boolean);
36
+ const collectionDefs = Object.values(config.collections ?? {});
37
+ let matchedCollection = null;
38
+ let docSlug = null;
39
+ if (segments.length === 0) {
40
+ const pageCol = collectionDefs.find((c) => c.type === 'page' && !((c.urlPrefix ?? '').replace(/^\/|\/$/g, '')));
41
+ matchedCollection = pageCol?.slug ?? 'pages';
42
+ docSlug = 'home';
43
+ }
44
+ else {
45
+ for (const col of collectionDefs) {
46
+ const prefix = (col.urlPrefix ?? col.slug ?? '').replace(/^\/|\/$/g, '');
47
+ if (prefix && segments.length >= 2) {
48
+ const prefixParts = prefix.split('/');
49
+ const pathPrefix = segments.slice(0, prefixParts.length).join('/');
50
+ if (pathPrefix === prefix) {
51
+ matchedCollection = col.slug ?? null;
52
+ docSlug = segments.slice(prefixParts.length).join('/');
53
+ break;
54
+ }
55
+ }
56
+ else if (!prefix && col.type === 'page') {
57
+ matchedCollection = col.slug ?? null;
58
+ docSlug = segments.join('/');
59
+ }
60
+ }
61
+ if (!matchedCollection && segments.length === 1) {
62
+ matchedCollection = 'pages';
63
+ docSlug = segments[0];
64
+ }
65
+ if (!matchedCollection && segments.length >= 2) {
66
+ matchedCollection = segments[0];
67
+ docSlug = segments.slice(1).join('/');
68
+ }
69
+ }
70
+ if (!matchedCollection || !docSlug)
71
+ return null;
72
+ const isRootPath = segments.length === 0;
73
+ const doc = await db.document.findFirst({
74
+ where: {
75
+ collection: matchedCollection,
76
+ deletedAt: null,
77
+ status: 'PUBLISHED',
78
+ OR: isRootPath
79
+ ? [
80
+ { data: { path: ['slug'], equals: 'home' } },
81
+ { data: { path: ['slug'], equals: 'index' } },
82
+ { slug: 'home' },
83
+ { slug: 'index' },
84
+ ]
85
+ : [
86
+ { data: { path: ['slug'], equals: docSlug } },
87
+ { slug: docSlug },
88
+ ],
89
+ },
90
+ });
91
+ if (!doc)
92
+ return null;
93
+ const docData = (doc.data && typeof doc.data === 'object')
94
+ ? doc.data
95
+ : {};
96
+ // Strip CMS-internal keys (mirrors handler behavior for /resolve).
97
+ const layout = (docData._layout && typeof docData._layout === 'object')
98
+ ? docData._layout
99
+ : undefined;
100
+ const { _layout: _omit, ...cleanData } = docData;
101
+ return {
102
+ data: {
103
+ id: doc.id,
104
+ collection: doc.collection,
105
+ data: cleanData,
106
+ status: doc.status,
107
+ publishedAt: doc.publishedAt
108
+ ? (doc.publishedAt instanceof Date ? doc.publishedAt.toISOString() : String(doc.publishedAt))
109
+ : null,
110
+ structuredData: doc.structuredData,
111
+ },
112
+ ...(layout && Object.keys(layout).length > 0 ? { layout } : {}),
113
+ };
114
+ }
115
+ return {
116
+ getGlobal,
117
+ resolveDocument,
118
+ async resolveMedia(value) {
119
+ const options = {
120
+ resolveById: async (id) => {
121
+ if (!db.media?.findUnique)
122
+ return null;
123
+ try {
124
+ const row = await db.media.findUnique({ where: { id } });
125
+ if (!row)
126
+ return null;
127
+ return {
128
+ id: row.id,
129
+ url: row.storageKey,
130
+ alt: row.altText ?? null,
131
+ title: row.title ?? null,
132
+ width: row.width ?? null,
133
+ height: row.height ?? null,
134
+ storageKey: row.storageKey ?? null,
135
+ };
136
+ }
137
+ catch {
138
+ return null;
139
+ }
140
+ },
141
+ };
142
+ return resolveMedia(value, options);
143
+ },
144
+ };
145
+ }
146
+ // Re-export the same helpers consumers were using before so a single import
147
+ // site covers both the fetch and Prisma flavours.
148
+ export { normalizeMedia, resolveMedia } from './site.js';
149
+ //# sourceMappingURL=server-site.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-site.js","sourceRoot":"","sources":["../src/server-site.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,CAAC,CAAC;QACR,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,MAAM,UAAU,GAClB,MAAM,GACN;IACE,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GACD,IAAI,GACJ,SAAS,CAAC;AAEd,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACxE,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CAC9F;AA+BD,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU,CA0B5E;AAkBD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,IAAI,CA4BtE;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAU/B"}
1
+ {"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,CAAC;CACT;AAED,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxD,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,CAAC,CAAC;QACR,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,cAAc,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACxC;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,MAAM,UAAU,GAClB,MAAM,GACN;IACE,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GACD,IAAI,GACJ,SAAS,CAAC;AAEd,MAAM,WAAW,mBAAmB;IAClC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACxE,eAAe,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CAC9F;AA+CD,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,UAAU,CA0B5E;AAkBD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,IAAI,CA4BtE;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAU/B"}
package/dist/site.js CHANGED
@@ -6,8 +6,26 @@ function normalizeApiPath(apiPath) {
6
6
  const path = apiPath.startsWith('/') ? apiPath : `/${apiPath}`;
7
7
  return trimTrailingSlash(path);
8
8
  }
9
+ /**
10
+ * Resolve a base URL, in order of preference:
11
+ * 1. explicit `baseUrl` option
12
+ * 2. `NEXT_PUBLIC_SITE_URL`
13
+ * 3. `VERCEL_URL` (with `https://` prefix; Vercel only sets the host)
14
+ * 4. empty string (relative URL — only safe in browsers and Next.js
15
+ * route handlers; will throw under bare Node `fetch`)
16
+ */
17
+ function resolveBaseUrl(baseUrl) {
18
+ if (baseUrl)
19
+ return trimTrailingSlash(baseUrl);
20
+ const env = process.env;
21
+ if (env.NEXT_PUBLIC_SITE_URL)
22
+ return trimTrailingSlash(env.NEXT_PUBLIC_SITE_URL);
23
+ if (env.VERCEL_URL)
24
+ return `https://${env.VERCEL_URL}`;
25
+ return '';
26
+ }
9
27
  function buildBaseUrl(baseUrl, apiPath) {
10
- const origin = trimTrailingSlash(baseUrl ?? '');
28
+ const origin = resolveBaseUrl(baseUrl);
11
29
  return `${origin}${normalizeApiPath(apiPath ?? DEFAULT_API_PATH)}`;
12
30
  }
13
31
  async function readApiData(response) {
package/dist/site.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,21 @@
1
- export interface StorageAdapter {
2
- generateUploadUrl(filename: string, contentType: string): Promise<{
3
- uploadUrl: string;
4
- publicUrl: string;
5
- storageKey: string;
6
- }>;
7
- deleteFile(storageKey: string): Promise<void>;
8
- }
9
- export declare function setStorageAdapter(adapter: StorageAdapter): void;
10
- export declare function getStorageAdapter(): StorageAdapter;
1
+ import type { StorageAdapter as ConfigStorageAdapter } from '../config/types.js';
2
+ /**
3
+ * Re-exports the canonical {@link StorageAdapter} shape used by platform
4
+ * adapters (see `packages/platform-vercel/src/storage.ts`,
5
+ * `packages/platform-aws/src/storage.ts`).
6
+ *
7
+ * Historically there were two divergent `StorageAdapter` interfaces in the
8
+ * codebase — a presign-style one here and an upload/download one in
9
+ * `config/types.ts`. Platform packages implemented the latter, so nothing
10
+ * actually wired the storage adapter into the API. This re-export
11
+ * unifies them so the registry and the platform packages speak the same
12
+ * contract.
13
+ */
14
+ export type StorageAdapter = ConfigStorageAdapter;
15
+ /** Register a storage adapter for the running CMS instance. Idempotent. */
16
+ export declare function setStorageAdapter(adapter: StorageAdapter | null): void;
17
+ /** Returns the registered storage adapter, or `null` if none is configured. */
18
+ export declare function getStorageAdapter(): StorageAdapter | null;
19
+ /** True when a storage adapter has been registered. */
20
+ export declare function hasStorageAdapter(): boolean;
11
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QAChE,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC,CAAC;IACH,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAID,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAE/D;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAOlD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,IAAI,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAEjF;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAIlD,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,GAAG,IAAI,CAEtE;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAEzD;AAED,uDAAuD;AACvD,wBAAgB,iBAAiB,IAAI,OAAO,CAE3C"}
@@ -1,11 +1,14 @@
1
1
  let _adapter = null;
2
+ /** Register a storage adapter for the running CMS instance. Idempotent. */
2
3
  export function setStorageAdapter(adapter) {
3
4
  _adapter = adapter;
4
5
  }
6
+ /** Returns the registered storage adapter, or `null` if none is configured. */
5
7
  export function getStorageAdapter() {
6
- if (!_adapter) {
7
- throw new Error('No storage adapter configured. Call setStorageAdapter() with a Vercel Blob or S3 adapter.');
8
- }
9
8
  return _adapter;
10
9
  }
10
+ /** True when a storage adapter has been registered. */
11
+ export function hasStorageAdapter() {
12
+ return _adapter !== null;
13
+ }
11
14
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AASA,IAAI,QAAQ,GAA0B,IAAI,CAAC;AAE3C,MAAM,UAAU,iBAAiB,CAAC,OAAuB;IACvD,QAAQ,GAAG,OAAO,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,2FAA2F,CAC5F,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/storage/index.ts"],"names":[],"mappings":"AAgBA,IAAI,QAAQ,GAA0B,IAAI,CAAC;AAE3C,2EAA2E;AAC3E,MAAM,UAAU,iBAAiB,CAAC,OAA8B;IAC9D,QAAQ,GAAG,OAAO,CAAC;AACrB,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,iBAAiB;IAC/B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,iBAAiB;IAC/B,OAAO,QAAQ,KAAK,IAAI,CAAC;AAC3B,CAAC"}