@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.
- package/dist/__tests__/api/admin-contracts.test.js +1 -0
- package/dist/__tests__/api/admin-contracts.test.js.map +1 -1
- package/dist/__tests__/api/public-globals.test.js +8 -4
- package/dist/__tests__/api/public-globals.test.js.map +1 -1
- package/dist/__tests__/security/audit.test.d.ts +2 -0
- package/dist/__tests__/security/audit.test.d.ts.map +1 -0
- package/dist/__tests__/security/audit.test.js +50 -0
- package/dist/__tests__/security/audit.test.js.map +1 -0
- package/dist/__tests__/security/client-ip.test.d.ts +2 -0
- package/dist/__tests__/security/client-ip.test.d.ts.map +1 -0
- package/dist/__tests__/security/client-ip.test.js +37 -0
- package/dist/__tests__/security/client-ip.test.js.map +1 -0
- package/dist/__tests__/security/ip-allowlist.test.d.ts +2 -0
- package/dist/__tests__/security/ip-allowlist.test.d.ts.map +1 -0
- package/dist/__tests__/security/ip-allowlist.test.js +40 -0
- package/dist/__tests__/security/ip-allowlist.test.js.map +1 -0
- package/dist/__tests__/security/redact.test.d.ts +2 -0
- package/dist/__tests__/security/redact.test.d.ts.map +1 -0
- package/dist/__tests__/security/redact.test.js +31 -0
- package/dist/__tests__/security/redact.test.js.map +1 -0
- package/dist/__tests__/security/secret-storage.test.d.ts +2 -0
- package/dist/__tests__/security/secret-storage.test.d.ts.map +1 -0
- package/dist/__tests__/security/secret-storage.test.js +42 -0
- package/dist/__tests__/security/secret-storage.test.js.map +1 -0
- package/dist/__tests__/security/upload-magic.test.d.ts +2 -0
- package/dist/__tests__/security/upload-magic.test.d.ts.map +1 -0
- package/dist/__tests__/security/upload-magic.test.js +55 -0
- package/dist/__tests__/security/upload-magic.test.js.map +1 -0
- package/dist/__tests__/server-site.test.d.ts +2 -0
- package/dist/__tests__/server-site.test.d.ts.map +1 -0
- package/dist/__tests__/server-site.test.js +123 -0
- package/dist/__tests__/server-site.test.js.map +1 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +170 -34
- package/dist/actions.js.map +1 -1
- package/dist/api/handler-factory.d.ts.map +1 -1
- package/dist/api/handler-factory.js +64 -9
- package/dist/api/handler-factory.js.map +1 -1
- package/dist/api/handlers.d.ts.map +1 -1
- package/dist/api/handlers.js +673 -116
- package/dist/api/handlers.js.map +1 -1
- package/dist/api/openapi.d.ts.map +1 -1
- package/dist/api/openapi.js +38 -0
- package/dist/api/openapi.js.map +1 -1
- package/dist/auth/mfa-pending.d.ts +24 -0
- package/dist/auth/mfa-pending.d.ts.map +1 -0
- package/dist/auth/mfa-pending.js +38 -0
- package/dist/auth/mfa-pending.js.map +1 -0
- package/dist/auth/oauth.d.ts +25 -3
- package/dist/auth/oauth.d.ts.map +1 -1
- package/dist/auth/oauth.js +109 -20
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/reset.d.ts.map +1 -1
- package/dist/auth/reset.js +26 -2
- package/dist/auth/reset.js.map +1 -1
- package/dist/auth/session.d.ts +9 -2
- package/dist/auth/session.d.ts.map +1 -1
- package/dist/auth/session.js +20 -2
- package/dist/auth/session.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +21 -34
- package/dist/middleware.js.map +1 -1
- package/dist/page-builder/__tests__/blocks.test.js +104 -1
- package/dist/page-builder/__tests__/blocks.test.js.map +1 -1
- package/dist/page-builder/blocks.d.ts +18 -1
- package/dist/page-builder/blocks.d.ts.map +1 -1
- package/dist/page-builder/blocks.js +22 -2
- package/dist/page-builder/blocks.js.map +1 -1
- package/dist/security/audit.d.ts.map +1 -1
- package/dist/security/audit.js +8 -4
- package/dist/security/audit.js.map +1 -1
- package/dist/security/client-ip.d.ts +33 -0
- package/dist/security/client-ip.d.ts.map +1 -0
- package/dist/security/client-ip.js +39 -0
- package/dist/security/client-ip.js.map +1 -0
- package/dist/security/index.d.ts +7 -0
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +5 -0
- package/dist/security/index.js.map +1 -1
- package/dist/security/internal-keys.d.ts +15 -0
- package/dist/security/internal-keys.d.ts.map +1 -0
- package/dist/security/internal-keys.js +33 -0
- package/dist/security/internal-keys.js.map +1 -0
- package/dist/security/ip-allowlist.d.ts +13 -1
- package/dist/security/ip-allowlist.d.ts.map +1 -1
- package/dist/security/ip-allowlist.js +120 -12
- package/dist/security/ip-allowlist.js.map +1 -1
- package/dist/security/rate-limit.d.ts.map +1 -1
- package/dist/security/rate-limit.js +49 -17
- package/dist/security/rate-limit.js.map +1 -1
- package/dist/security/redact.d.ts +12 -0
- package/dist/security/redact.d.ts.map +1 -0
- package/dist/security/redact.js +41 -0
- package/dist/security/redact.js.map +1 -0
- package/dist/security/safe-fetch.d.ts +35 -0
- package/dist/security/safe-fetch.d.ts.map +1 -0
- package/dist/security/safe-fetch.js +45 -0
- package/dist/security/safe-fetch.js.map +1 -0
- package/dist/security/secret-storage.d.ts +22 -0
- package/dist/security/secret-storage.d.ts.map +1 -0
- package/dist/security/secret-storage.js +75 -0
- package/dist/security/secret-storage.js.map +1 -0
- package/dist/security/upload.d.ts +23 -4
- package/dist/security/upload.d.ts.map +1 -1
- package/dist/security/upload.js +110 -21
- package/dist/security/upload.js.map +1 -1
- package/dist/server-site.d.ts +54 -0
- package/dist/server-site.d.ts.map +1 -0
- package/dist/server-site.js +149 -0
- package/dist/server-site.js.map +1 -0
- package/dist/site.d.ts.map +1 -1
- package/dist/site.js +19 -1
- package/dist/site.js.map +1 -1
- package/dist/storage/index.d.ts +20 -10
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +6 -3
- package/dist/storage/index.js.map +1 -1
- package/dist/webhooks/index.d.ts.map +1 -1
- package/dist/webhooks/index.js +20 -9
- package/dist/webhooks/index.js.map +1 -1
- 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
|
-
/**
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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,
|
|
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"}
|
package/dist/security/upload.js
CHANGED
|
@@ -1,34 +1,123 @@
|
|
|
1
1
|
const ALLOWED_IMAGE_TYPES = new Set([
|
|
2
|
-
"image/jpeg",
|
|
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",
|
|
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
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
|
19
|
-
|
|
20
|
-
|
|
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 {
|
|
61
|
+
return {
|
|
62
|
+
valid: false,
|
|
63
|
+
error: `Declared "${declaredMimeType}" but content looks like "${detected}"`,
|
|
64
|
+
detectedMimeType: detected,
|
|
65
|
+
};
|
|
23
66
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
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,
|
|
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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"}
|
package/dist/site.d.ts.map
CHANGED
|
@@ -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+
|
|
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 =
|
|
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":"AA0DA,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAEpC,SAAS,iBAAiB,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;IAC/D,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,YAAY,CAAC,OAA2B,EAAE,OAA2B;IAC5E,MAAM,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"site.js","sourceRoot":"","sources":["../src/site.ts"],"names":[],"mappings":"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"}
|
package/dist/storage/index.d.ts
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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,
|
|
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"}
|
package/dist/storage/index.js
CHANGED
|
@@ -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":"
|
|
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"}
|