@cmssy/core 16.7.1 → 16.9.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/index.cjs +71 -31
- package/dist/index.d.cts +39 -24
- package/dist/index.d.ts +39 -24
- package/dist/index.js +69 -32
- package/dist/internal/locale.cjs +1 -1
- package/dist/internal/locale.js +1 -1
- package/dist/internal.cjs +1 -1
- package/dist/internal.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -74,7 +74,7 @@ Set the listed environment variables (e.g. in .env.local) and restart the dev se
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
// src/version.ts
|
|
77
|
-
var CMSSY_CORE_VERSION = "16.
|
|
77
|
+
var CMSSY_CORE_VERSION = "16.9.0" ;
|
|
78
78
|
var CMSSY_USER_AGENT = `@cmssy/core/${CMSSY_CORE_VERSION}`;
|
|
79
79
|
|
|
80
80
|
// src/data/http.ts
|
|
@@ -967,33 +967,7 @@ function applyCmssyCsp(response, options) {
|
|
|
967
967
|
return response;
|
|
968
968
|
}
|
|
969
969
|
|
|
970
|
-
// src/
|
|
971
|
-
var CmssyWebhookError = class extends Error {
|
|
972
|
-
constructor(message) {
|
|
973
|
-
super(message);
|
|
974
|
-
this.name = "CmssyWebhookError";
|
|
975
|
-
}
|
|
976
|
-
};
|
|
977
|
-
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
978
|
-
var MAX_SIGNATURES = 8;
|
|
979
|
-
function parseSignatureHeader(header) {
|
|
980
|
-
let timestamp = null;
|
|
981
|
-
const signatures = [];
|
|
982
|
-
for (const part of header.split(",")) {
|
|
983
|
-
const idx = part.indexOf("=");
|
|
984
|
-
if (idx === -1) continue;
|
|
985
|
-
const key = part.slice(0, idx).trim();
|
|
986
|
-
const value = part.slice(idx + 1).trim();
|
|
987
|
-
if (key === "t") timestamp = Number(value);
|
|
988
|
-
else if (key === "v1" && value && signatures.length < MAX_SIGNATURES) {
|
|
989
|
-
signatures.push(value);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
if (timestamp === null || !Number.isFinite(timestamp) || !signatures.length) {
|
|
993
|
-
throw new CmssyWebhookError("Malformed X-Cmssy-Signature header");
|
|
994
|
-
}
|
|
995
|
-
return { timestamp, signatures };
|
|
996
|
-
}
|
|
970
|
+
// src/internal/hmac.ts
|
|
997
971
|
function hexToBytes(hex) {
|
|
998
972
|
if (hex.length % 2 !== 0 || /[^0-9a-fA-F]/.test(hex)) return null;
|
|
999
973
|
const bytes = new Uint8Array(hex.length / 2);
|
|
@@ -1009,9 +983,7 @@ function timingSafeHexEqual(expectedHex, providedHex) {
|
|
|
1009
983
|
if (expectedHex.length !== providedHex.length) return false;
|
|
1010
984
|
const expected = hexToBytes(expectedHex);
|
|
1011
985
|
const provided = hexToBytes(providedHex);
|
|
1012
|
-
if (!expected || !provided)
|
|
1013
|
-
return false;
|
|
1014
|
-
}
|
|
986
|
+
if (!expected || !provided) return false;
|
|
1015
987
|
let diff = 0;
|
|
1016
988
|
for (let i = 0; i < expected.length; i += 1) {
|
|
1017
989
|
diff |= (expected[i] ?? 0) ^ (provided[i] ?? 0);
|
|
@@ -1034,6 +1006,71 @@ async function hmacSha256Hex(secret, message) {
|
|
|
1034
1006
|
);
|
|
1035
1007
|
return bytesToHex(new Uint8Array(signature));
|
|
1036
1008
|
}
|
|
1009
|
+
|
|
1010
|
+
// src/edit-token.ts
|
|
1011
|
+
var CMSSY_EDIT_TOKEN_HEADER = "x-cmssy-edit-token";
|
|
1012
|
+
var DEFAULT_TTL_SECONDS = 12 * 60 * 60;
|
|
1013
|
+
var MAX_TOKEN_LENGTH = 256;
|
|
1014
|
+
function payload(expiresAt, page) {
|
|
1015
|
+
return `${expiresAt}.${page}`;
|
|
1016
|
+
}
|
|
1017
|
+
async function mintCmssyEditToken(secret, options = {}) {
|
|
1018
|
+
if (!secret) {
|
|
1019
|
+
throw new Error("cmssy: minting an edit token needs a draftSecret");
|
|
1020
|
+
}
|
|
1021
|
+
const now = options.now ?? Date.now();
|
|
1022
|
+
const ttl = options.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
1023
|
+
const expiresAt = now + ttl * 1e3;
|
|
1024
|
+
const signature = await hmacSha256Hex(
|
|
1025
|
+
secret,
|
|
1026
|
+
payload(expiresAt, options.page ?? "")
|
|
1027
|
+
);
|
|
1028
|
+
return `${expiresAt}.${signature}`;
|
|
1029
|
+
}
|
|
1030
|
+
async function verifyCmssyEditToken(token, secret, options = {}) {
|
|
1031
|
+
if (!token || !secret) return false;
|
|
1032
|
+
if (token.length > MAX_TOKEN_LENGTH) return false;
|
|
1033
|
+
const separator = token.indexOf(".");
|
|
1034
|
+
if (separator === -1) return false;
|
|
1035
|
+
const expiresAt = Number(token.slice(0, separator));
|
|
1036
|
+
const provided = token.slice(separator + 1);
|
|
1037
|
+
if (!Number.isSafeInteger(expiresAt) || !provided) return false;
|
|
1038
|
+
const now = options.now ?? Date.now();
|
|
1039
|
+
if (expiresAt <= now) return false;
|
|
1040
|
+
const expected = await hmacSha256Hex(
|
|
1041
|
+
secret,
|
|
1042
|
+
payload(expiresAt, options.page ?? "")
|
|
1043
|
+
);
|
|
1044
|
+
return timingSafeHexEqual(expected, provided);
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
// src/verify-webhook.ts
|
|
1048
|
+
var CmssyWebhookError = class extends Error {
|
|
1049
|
+
constructor(message) {
|
|
1050
|
+
super(message);
|
|
1051
|
+
this.name = "CmssyWebhookError";
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
1055
|
+
var MAX_SIGNATURES = 8;
|
|
1056
|
+
function parseSignatureHeader(header) {
|
|
1057
|
+
let timestamp = null;
|
|
1058
|
+
const signatures = [];
|
|
1059
|
+
for (const part of header.split(",")) {
|
|
1060
|
+
const idx = part.indexOf("=");
|
|
1061
|
+
if (idx === -1) continue;
|
|
1062
|
+
const key = part.slice(0, idx).trim();
|
|
1063
|
+
const value = part.slice(idx + 1).trim();
|
|
1064
|
+
if (key === "t") timestamp = Number(value);
|
|
1065
|
+
else if (key === "v1" && value && signatures.length < MAX_SIGNATURES) {
|
|
1066
|
+
signatures.push(value);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
if (timestamp === null || !Number.isFinite(timestamp) || !signatures.length) {
|
|
1070
|
+
throw new CmssyWebhookError("Malformed X-Cmssy-Signature header");
|
|
1071
|
+
}
|
|
1072
|
+
return { timestamp, signatures };
|
|
1073
|
+
}
|
|
1037
1074
|
async function verifyCmssyWebhook(options) {
|
|
1038
1075
|
const { body, signatureHeader, secret } = options;
|
|
1039
1076
|
if (!signatureHeader) {
|
|
@@ -1078,6 +1115,7 @@ Object.defineProperty(exports, "evaluateFieldConditionGroup", {
|
|
|
1078
1115
|
});
|
|
1079
1116
|
exports.CMSSY_EDIT_HEADER = CMSSY_EDIT_HEADER;
|
|
1080
1117
|
exports.CMSSY_EDIT_QUERY_PARAM = CMSSY_EDIT_QUERY_PARAM;
|
|
1118
|
+
exports.CMSSY_EDIT_TOKEN_HEADER = CMSSY_EDIT_TOKEN_HEADER;
|
|
1081
1119
|
exports.CMSSY_LOCALE_HEADER = CMSSY_LOCALE_HEADER;
|
|
1082
1120
|
exports.CMSSY_RATE_LIMIT_WINDOW_MS = CMSSY_RATE_LIMIT_WINDOW_MS;
|
|
1083
1121
|
exports.CMSSY_RETRY_MODES = CMSSY_RETRY_MODES;
|
|
@@ -1104,6 +1142,7 @@ exports.localizeHref = localizeHref;
|
|
|
1104
1142
|
exports.mediaAlt = mediaAlt;
|
|
1105
1143
|
exports.mediaUrl = mediaUrl;
|
|
1106
1144
|
exports.mediaUrls = mediaUrls;
|
|
1145
|
+
exports.mintCmssyEditToken = mintCmssyEditToken;
|
|
1107
1146
|
exports.normalizeOrigin = normalizeOrigin;
|
|
1108
1147
|
exports.parseEditorMessage = parseEditorMessage;
|
|
1109
1148
|
exports.postToEditor = postToEditor;
|
|
@@ -1111,4 +1150,5 @@ exports.propsToSchema = propsToSchema;
|
|
|
1111
1150
|
exports.registryToManifestBlocks = registryToManifestBlocks;
|
|
1112
1151
|
exports.resolveCmssyLocale = resolveCmssyLocale;
|
|
1113
1152
|
exports.resolveEditorOrigin = resolveEditorOrigin;
|
|
1153
|
+
exports.verifyCmssyEditToken = verifyCmssyEditToken;
|
|
1114
1154
|
exports.verifyCmssyWebhook = verifyCmssyWebhook;
|
package/dist/index.d.cts
CHANGED
|
@@ -26,7 +26,9 @@ interface RelationFieldOptions extends BaseFieldOptions {
|
|
|
26
26
|
sort?: string;
|
|
27
27
|
limit?: number;
|
|
28
28
|
}
|
|
29
|
-
type Only<O, Shape> = Shape &
|
|
29
|
+
type Only<O, Shape, Field extends string> = Shape & {
|
|
30
|
+
[Key in Exclude<keyof O, keyof Shape>]: `fields.${Field} has no option: ${Key & string}`;
|
|
31
|
+
};
|
|
30
32
|
type OptionValue<O> = O extends {
|
|
31
33
|
options: readonly (infer Option extends string)[];
|
|
32
34
|
} ? Option : string;
|
|
@@ -50,28 +52,28 @@ type PageSelectorValue<O> = O extends {
|
|
|
50
52
|
multiple: false;
|
|
51
53
|
} ? PageRef | undefined : PageRef[];
|
|
52
54
|
declare const fields: {
|
|
53
|
-
text: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
54
|
-
textarea: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
55
|
-
richText: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
56
|
-
markdown: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
57
|
-
number: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<number, Declared<O>>;
|
|
58
|
-
date: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
59
|
-
datetime: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
60
|
-
boolean: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<boolean, Declared<O>>;
|
|
61
|
-
color: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
62
|
-
link: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
63
|
-
url: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
64
|
-
email: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
65
|
-
json: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<_cmssy_types.JsonValue, Declared<O>>;
|
|
66
|
-
form: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
67
|
-
table: <const O extends Only<O, TableFieldOptions>>(opts?: O) => TypedField<FieldTypeValueMap["table"], Declared<O>>;
|
|
68
|
-
select: <const O extends Only<O, ChoiceFieldOptions>>(opts: O) => TypedField<OptionValue<O>, Declared<O>>;
|
|
69
|
-
radio: <const O extends Only<O, ChoiceFieldOptions>>(opts: O) => TypedField<OptionValue<O>, Declared<O>>;
|
|
70
|
-
multiselect: <const O extends Only<O, ChoiceFieldOptions>>(opts: O) => TypedField<OptionValue<O>[], Declared<O>>;
|
|
71
|
-
media: <const O extends Only<O, MediaFieldOptions>>(opts?: O) => TypedField<MediaValue<O>, Declared<O>>;
|
|
72
|
-
pageSelector: <const O extends Only<O, PageSelectorFieldOptions>>(opts?: O) => TypedField<PageSelectorValue<O>, Declared<O>>;
|
|
73
|
-
repeater: <const O extends Only<O, RepeaterFieldOptions>>(opts: O) => TypedField<RepeaterValue<O>, Declared<O>>;
|
|
74
|
-
relation: <const O extends Only<O, RelationFieldOptions>>(opts: O) => TypedField<RelationValue<O>, Declared<O>>;
|
|
55
|
+
text: <const O extends Only<O, BaseFieldOptions, "text">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
56
|
+
textarea: <const O extends Only<O, BaseFieldOptions, "textarea">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
57
|
+
richText: <const O extends Only<O, BaseFieldOptions, "richText">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
58
|
+
markdown: <const O extends Only<O, BaseFieldOptions, "markdown">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
59
|
+
number: <const O extends Only<O, BaseFieldOptions, "number">>(opts?: O) => TypedField<number, Declared<O>>;
|
|
60
|
+
date: <const O extends Only<O, BaseFieldOptions, "date">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
61
|
+
datetime: <const O extends Only<O, BaseFieldOptions, "datetime">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
62
|
+
boolean: <const O extends Only<O, BaseFieldOptions, "boolean">>(opts?: O) => TypedField<boolean, Declared<O>>;
|
|
63
|
+
color: <const O extends Only<O, BaseFieldOptions, "color">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
64
|
+
link: <const O extends Only<O, BaseFieldOptions, "link">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
65
|
+
url: <const O extends Only<O, BaseFieldOptions, "url">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
66
|
+
email: <const O extends Only<O, BaseFieldOptions, "email">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
67
|
+
json: <const O extends Only<O, BaseFieldOptions, "json">>(opts?: O) => TypedField<_cmssy_types.JsonValue, Declared<O>>;
|
|
68
|
+
form: <const O extends Only<O, BaseFieldOptions, "form">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
69
|
+
table: <const O extends Only<O, TableFieldOptions, "table">>(opts?: O) => TypedField<FieldTypeValueMap["table"], Declared<O>>;
|
|
70
|
+
select: <const O extends Only<O, ChoiceFieldOptions, "select">>(opts: O) => TypedField<OptionValue<O>, Declared<O>>;
|
|
71
|
+
radio: <const O extends Only<O, ChoiceFieldOptions, "radio">>(opts: O) => TypedField<OptionValue<O>, Declared<O>>;
|
|
72
|
+
multiselect: <const O extends Only<O, ChoiceFieldOptions, "multiselect">>(opts: O) => TypedField<OptionValue<O>[], Declared<O>>;
|
|
73
|
+
media: <const O extends Only<O, MediaFieldOptions, "media">>(opts?: O) => TypedField<MediaValue<O>, Declared<O>>;
|
|
74
|
+
pageSelector: <const O extends Only<O, PageSelectorFieldOptions, "pageSelector">>(opts?: O) => TypedField<PageSelectorValue<O>, Declared<O>>;
|
|
75
|
+
repeater: <const O extends Only<O, RepeaterFieldOptions, "repeater">>(opts: O) => TypedField<RepeaterValue<O>, Declared<O>>;
|
|
76
|
+
relation: <const O extends Only<O, RelationFieldOptions, "relation">>(opts: O) => TypedField<RelationValue<O>, Declared<O>>;
|
|
75
77
|
};
|
|
76
78
|
|
|
77
79
|
/**
|
|
@@ -133,9 +135,22 @@ declare function isVerifiedEditUrl(url: {
|
|
|
133
135
|
draftSecret: string;
|
|
134
136
|
}): Promise<boolean>;
|
|
135
137
|
|
|
138
|
+
declare const CMSSY_EDIT_TOKEN_HEADER = "x-cmssy-edit-token";
|
|
139
|
+
interface MintCmssyEditTokenOptions {
|
|
140
|
+
page?: string;
|
|
141
|
+
ttlSeconds?: number;
|
|
142
|
+
now?: number;
|
|
143
|
+
}
|
|
144
|
+
declare function mintCmssyEditToken(secret: string, options?: MintCmssyEditTokenOptions): Promise<string>;
|
|
145
|
+
interface VerifyCmssyEditTokenOptions {
|
|
146
|
+
page?: string;
|
|
147
|
+
now?: number;
|
|
148
|
+
}
|
|
149
|
+
declare function verifyCmssyEditToken(token: string | null | undefined, secret: string, options?: VerifyCmssyEditTokenOptions): Promise<boolean>;
|
|
150
|
+
|
|
136
151
|
declare class CmssyWebhookError extends Error {
|
|
137
152
|
constructor(message: string);
|
|
138
153
|
}
|
|
139
154
|
declare function verifyCmssyWebhook(options: VerifyCmssyWebhookOptions): Promise<CmssyWebhookEvent>;
|
|
140
155
|
|
|
141
|
-
export { type BlockManifest, type BlockManifestBlock, type BlockManifestSource, CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM, CMSSY_SECRET_QUERY_PARAM, CmssyWebhookError, type MediaLike, blocksToMeta, blocksToSchemas, buildBlockManifest, fields, isVerifiedEditUrl, layoutRegionsToBridge, mediaAlt, mediaUrl, mediaUrls, propsToSchema, registryToManifestBlocks, verifyCmssyWebhook };
|
|
156
|
+
export { type BlockManifest, type BlockManifestBlock, type BlockManifestSource, CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM, CMSSY_EDIT_TOKEN_HEADER, CMSSY_SECRET_QUERY_PARAM, CmssyWebhookError, type MediaLike, type MintCmssyEditTokenOptions, type VerifyCmssyEditTokenOptions, blocksToMeta, blocksToSchemas, buildBlockManifest, fields, isVerifiedEditUrl, layoutRegionsToBridge, mediaAlt, mediaUrl, mediaUrls, mintCmssyEditToken, propsToSchema, registryToManifestBlocks, verifyCmssyEditToken, verifyCmssyWebhook };
|
package/dist/index.d.ts
CHANGED
|
@@ -26,7 +26,9 @@ interface RelationFieldOptions extends BaseFieldOptions {
|
|
|
26
26
|
sort?: string;
|
|
27
27
|
limit?: number;
|
|
28
28
|
}
|
|
29
|
-
type Only<O, Shape> = Shape &
|
|
29
|
+
type Only<O, Shape, Field extends string> = Shape & {
|
|
30
|
+
[Key in Exclude<keyof O, keyof Shape>]: `fields.${Field} has no option: ${Key & string}`;
|
|
31
|
+
};
|
|
30
32
|
type OptionValue<O> = O extends {
|
|
31
33
|
options: readonly (infer Option extends string)[];
|
|
32
34
|
} ? Option : string;
|
|
@@ -50,28 +52,28 @@ type PageSelectorValue<O> = O extends {
|
|
|
50
52
|
multiple: false;
|
|
51
53
|
} ? PageRef | undefined : PageRef[];
|
|
52
54
|
declare const fields: {
|
|
53
|
-
text: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
54
|
-
textarea: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
55
|
-
richText: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
56
|
-
markdown: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
57
|
-
number: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<number, Declared<O>>;
|
|
58
|
-
date: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
59
|
-
datetime: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
60
|
-
boolean: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<boolean, Declared<O>>;
|
|
61
|
-
color: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
62
|
-
link: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
63
|
-
url: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
64
|
-
email: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
65
|
-
json: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<_cmssy_types.JsonValue, Declared<O>>;
|
|
66
|
-
form: <const O extends Only<O, BaseFieldOptions>>(opts?: O) => TypedField<string, Declared<O>>;
|
|
67
|
-
table: <const O extends Only<O, TableFieldOptions>>(opts?: O) => TypedField<FieldTypeValueMap["table"], Declared<O>>;
|
|
68
|
-
select: <const O extends Only<O, ChoiceFieldOptions>>(opts: O) => TypedField<OptionValue<O>, Declared<O>>;
|
|
69
|
-
radio: <const O extends Only<O, ChoiceFieldOptions>>(opts: O) => TypedField<OptionValue<O>, Declared<O>>;
|
|
70
|
-
multiselect: <const O extends Only<O, ChoiceFieldOptions>>(opts: O) => TypedField<OptionValue<O>[], Declared<O>>;
|
|
71
|
-
media: <const O extends Only<O, MediaFieldOptions>>(opts?: O) => TypedField<MediaValue<O>, Declared<O>>;
|
|
72
|
-
pageSelector: <const O extends Only<O, PageSelectorFieldOptions>>(opts?: O) => TypedField<PageSelectorValue<O>, Declared<O>>;
|
|
73
|
-
repeater: <const O extends Only<O, RepeaterFieldOptions>>(opts: O) => TypedField<RepeaterValue<O>, Declared<O>>;
|
|
74
|
-
relation: <const O extends Only<O, RelationFieldOptions>>(opts: O) => TypedField<RelationValue<O>, Declared<O>>;
|
|
55
|
+
text: <const O extends Only<O, BaseFieldOptions, "text">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
56
|
+
textarea: <const O extends Only<O, BaseFieldOptions, "textarea">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
57
|
+
richText: <const O extends Only<O, BaseFieldOptions, "richText">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
58
|
+
markdown: <const O extends Only<O, BaseFieldOptions, "markdown">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
59
|
+
number: <const O extends Only<O, BaseFieldOptions, "number">>(opts?: O) => TypedField<number, Declared<O>>;
|
|
60
|
+
date: <const O extends Only<O, BaseFieldOptions, "date">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
61
|
+
datetime: <const O extends Only<O, BaseFieldOptions, "datetime">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
62
|
+
boolean: <const O extends Only<O, BaseFieldOptions, "boolean">>(opts?: O) => TypedField<boolean, Declared<O>>;
|
|
63
|
+
color: <const O extends Only<O, BaseFieldOptions, "color">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
64
|
+
link: <const O extends Only<O, BaseFieldOptions, "link">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
65
|
+
url: <const O extends Only<O, BaseFieldOptions, "url">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
66
|
+
email: <const O extends Only<O, BaseFieldOptions, "email">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
67
|
+
json: <const O extends Only<O, BaseFieldOptions, "json">>(opts?: O) => TypedField<_cmssy_types.JsonValue, Declared<O>>;
|
|
68
|
+
form: <const O extends Only<O, BaseFieldOptions, "form">>(opts?: O) => TypedField<string, Declared<O>>;
|
|
69
|
+
table: <const O extends Only<O, TableFieldOptions, "table">>(opts?: O) => TypedField<FieldTypeValueMap["table"], Declared<O>>;
|
|
70
|
+
select: <const O extends Only<O, ChoiceFieldOptions, "select">>(opts: O) => TypedField<OptionValue<O>, Declared<O>>;
|
|
71
|
+
radio: <const O extends Only<O, ChoiceFieldOptions, "radio">>(opts: O) => TypedField<OptionValue<O>, Declared<O>>;
|
|
72
|
+
multiselect: <const O extends Only<O, ChoiceFieldOptions, "multiselect">>(opts: O) => TypedField<OptionValue<O>[], Declared<O>>;
|
|
73
|
+
media: <const O extends Only<O, MediaFieldOptions, "media">>(opts?: O) => TypedField<MediaValue<O>, Declared<O>>;
|
|
74
|
+
pageSelector: <const O extends Only<O, PageSelectorFieldOptions, "pageSelector">>(opts?: O) => TypedField<PageSelectorValue<O>, Declared<O>>;
|
|
75
|
+
repeater: <const O extends Only<O, RepeaterFieldOptions, "repeater">>(opts: O) => TypedField<RepeaterValue<O>, Declared<O>>;
|
|
76
|
+
relation: <const O extends Only<O, RelationFieldOptions, "relation">>(opts: O) => TypedField<RelationValue<O>, Declared<O>>;
|
|
75
77
|
};
|
|
76
78
|
|
|
77
79
|
/**
|
|
@@ -133,9 +135,22 @@ declare function isVerifiedEditUrl(url: {
|
|
|
133
135
|
draftSecret: string;
|
|
134
136
|
}): Promise<boolean>;
|
|
135
137
|
|
|
138
|
+
declare const CMSSY_EDIT_TOKEN_HEADER = "x-cmssy-edit-token";
|
|
139
|
+
interface MintCmssyEditTokenOptions {
|
|
140
|
+
page?: string;
|
|
141
|
+
ttlSeconds?: number;
|
|
142
|
+
now?: number;
|
|
143
|
+
}
|
|
144
|
+
declare function mintCmssyEditToken(secret: string, options?: MintCmssyEditTokenOptions): Promise<string>;
|
|
145
|
+
interface VerifyCmssyEditTokenOptions {
|
|
146
|
+
page?: string;
|
|
147
|
+
now?: number;
|
|
148
|
+
}
|
|
149
|
+
declare function verifyCmssyEditToken(token: string | null | undefined, secret: string, options?: VerifyCmssyEditTokenOptions): Promise<boolean>;
|
|
150
|
+
|
|
136
151
|
declare class CmssyWebhookError extends Error {
|
|
137
152
|
constructor(message: string);
|
|
138
153
|
}
|
|
139
154
|
declare function verifyCmssyWebhook(options: VerifyCmssyWebhookOptions): Promise<CmssyWebhookEvent>;
|
|
140
155
|
|
|
141
|
-
export { type BlockManifest, type BlockManifestBlock, type BlockManifestSource, CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM, CMSSY_SECRET_QUERY_PARAM, CmssyWebhookError, type MediaLike, blocksToMeta, blocksToSchemas, buildBlockManifest, fields, isVerifiedEditUrl, layoutRegionsToBridge, mediaAlt, mediaUrl, mediaUrls, propsToSchema, registryToManifestBlocks, verifyCmssyWebhook };
|
|
156
|
+
export { type BlockManifest, type BlockManifestBlock, type BlockManifestSource, CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM, CMSSY_EDIT_TOKEN_HEADER, CMSSY_SECRET_QUERY_PARAM, CmssyWebhookError, type MediaLike, type MintCmssyEditTokenOptions, type VerifyCmssyEditTokenOptions, blocksToMeta, blocksToSchemas, buildBlockManifest, fields, isVerifiedEditUrl, layoutRegionsToBridge, mediaAlt, mediaUrl, mediaUrls, mintCmssyEditToken, propsToSchema, registryToManifestBlocks, verifyCmssyEditToken, verifyCmssyWebhook };
|
package/dist/index.js
CHANGED
|
@@ -73,7 +73,7 @@ Set the listed environment variables (e.g. in .env.local) and restart the dev se
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
// src/version.ts
|
|
76
|
-
var CMSSY_CORE_VERSION = "16.
|
|
76
|
+
var CMSSY_CORE_VERSION = "16.9.0" ;
|
|
77
77
|
var CMSSY_USER_AGENT = `@cmssy/core/${CMSSY_CORE_VERSION}`;
|
|
78
78
|
|
|
79
79
|
// src/data/http.ts
|
|
@@ -966,33 +966,7 @@ function applyCmssyCsp(response, options) {
|
|
|
966
966
|
return response;
|
|
967
967
|
}
|
|
968
968
|
|
|
969
|
-
// src/
|
|
970
|
-
var CmssyWebhookError = class extends Error {
|
|
971
|
-
constructor(message) {
|
|
972
|
-
super(message);
|
|
973
|
-
this.name = "CmssyWebhookError";
|
|
974
|
-
}
|
|
975
|
-
};
|
|
976
|
-
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
977
|
-
var MAX_SIGNATURES = 8;
|
|
978
|
-
function parseSignatureHeader(header) {
|
|
979
|
-
let timestamp = null;
|
|
980
|
-
const signatures = [];
|
|
981
|
-
for (const part of header.split(",")) {
|
|
982
|
-
const idx = part.indexOf("=");
|
|
983
|
-
if (idx === -1) continue;
|
|
984
|
-
const key = part.slice(0, idx).trim();
|
|
985
|
-
const value = part.slice(idx + 1).trim();
|
|
986
|
-
if (key === "t") timestamp = Number(value);
|
|
987
|
-
else if (key === "v1" && value && signatures.length < MAX_SIGNATURES) {
|
|
988
|
-
signatures.push(value);
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
if (timestamp === null || !Number.isFinite(timestamp) || !signatures.length) {
|
|
992
|
-
throw new CmssyWebhookError("Malformed X-Cmssy-Signature header");
|
|
993
|
-
}
|
|
994
|
-
return { timestamp, signatures };
|
|
995
|
-
}
|
|
969
|
+
// src/internal/hmac.ts
|
|
996
970
|
function hexToBytes(hex) {
|
|
997
971
|
if (hex.length % 2 !== 0 || /[^0-9a-fA-F]/.test(hex)) return null;
|
|
998
972
|
const bytes = new Uint8Array(hex.length / 2);
|
|
@@ -1008,9 +982,7 @@ function timingSafeHexEqual(expectedHex, providedHex) {
|
|
|
1008
982
|
if (expectedHex.length !== providedHex.length) return false;
|
|
1009
983
|
const expected = hexToBytes(expectedHex);
|
|
1010
984
|
const provided = hexToBytes(providedHex);
|
|
1011
|
-
if (!expected || !provided)
|
|
1012
|
-
return false;
|
|
1013
|
-
}
|
|
985
|
+
if (!expected || !provided) return false;
|
|
1014
986
|
let diff = 0;
|
|
1015
987
|
for (let i = 0; i < expected.length; i += 1) {
|
|
1016
988
|
diff |= (expected[i] ?? 0) ^ (provided[i] ?? 0);
|
|
@@ -1033,6 +1005,71 @@ async function hmacSha256Hex(secret, message) {
|
|
|
1033
1005
|
);
|
|
1034
1006
|
return bytesToHex(new Uint8Array(signature));
|
|
1035
1007
|
}
|
|
1008
|
+
|
|
1009
|
+
// src/edit-token.ts
|
|
1010
|
+
var CMSSY_EDIT_TOKEN_HEADER = "x-cmssy-edit-token";
|
|
1011
|
+
var DEFAULT_TTL_SECONDS = 12 * 60 * 60;
|
|
1012
|
+
var MAX_TOKEN_LENGTH = 256;
|
|
1013
|
+
function payload(expiresAt, page) {
|
|
1014
|
+
return `${expiresAt}.${page}`;
|
|
1015
|
+
}
|
|
1016
|
+
async function mintCmssyEditToken(secret, options = {}) {
|
|
1017
|
+
if (!secret) {
|
|
1018
|
+
throw new Error("cmssy: minting an edit token needs a draftSecret");
|
|
1019
|
+
}
|
|
1020
|
+
const now = options.now ?? Date.now();
|
|
1021
|
+
const ttl = options.ttlSeconds ?? DEFAULT_TTL_SECONDS;
|
|
1022
|
+
const expiresAt = now + ttl * 1e3;
|
|
1023
|
+
const signature = await hmacSha256Hex(
|
|
1024
|
+
secret,
|
|
1025
|
+
payload(expiresAt, options.page ?? "")
|
|
1026
|
+
);
|
|
1027
|
+
return `${expiresAt}.${signature}`;
|
|
1028
|
+
}
|
|
1029
|
+
async function verifyCmssyEditToken(token, secret, options = {}) {
|
|
1030
|
+
if (!token || !secret) return false;
|
|
1031
|
+
if (token.length > MAX_TOKEN_LENGTH) return false;
|
|
1032
|
+
const separator = token.indexOf(".");
|
|
1033
|
+
if (separator === -1) return false;
|
|
1034
|
+
const expiresAt = Number(token.slice(0, separator));
|
|
1035
|
+
const provided = token.slice(separator + 1);
|
|
1036
|
+
if (!Number.isSafeInteger(expiresAt) || !provided) return false;
|
|
1037
|
+
const now = options.now ?? Date.now();
|
|
1038
|
+
if (expiresAt <= now) return false;
|
|
1039
|
+
const expected = await hmacSha256Hex(
|
|
1040
|
+
secret,
|
|
1041
|
+
payload(expiresAt, options.page ?? "")
|
|
1042
|
+
);
|
|
1043
|
+
return timingSafeHexEqual(expected, provided);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
// src/verify-webhook.ts
|
|
1047
|
+
var CmssyWebhookError = class extends Error {
|
|
1048
|
+
constructor(message) {
|
|
1049
|
+
super(message);
|
|
1050
|
+
this.name = "CmssyWebhookError";
|
|
1051
|
+
}
|
|
1052
|
+
};
|
|
1053
|
+
var DEFAULT_TOLERANCE_SECONDS = 300;
|
|
1054
|
+
var MAX_SIGNATURES = 8;
|
|
1055
|
+
function parseSignatureHeader(header) {
|
|
1056
|
+
let timestamp = null;
|
|
1057
|
+
const signatures = [];
|
|
1058
|
+
for (const part of header.split(",")) {
|
|
1059
|
+
const idx = part.indexOf("=");
|
|
1060
|
+
if (idx === -1) continue;
|
|
1061
|
+
const key = part.slice(0, idx).trim();
|
|
1062
|
+
const value = part.slice(idx + 1).trim();
|
|
1063
|
+
if (key === "t") timestamp = Number(value);
|
|
1064
|
+
else if (key === "v1" && value && signatures.length < MAX_SIGNATURES) {
|
|
1065
|
+
signatures.push(value);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
if (timestamp === null || !Number.isFinite(timestamp) || !signatures.length) {
|
|
1069
|
+
throw new CmssyWebhookError("Malformed X-Cmssy-Signature header");
|
|
1070
|
+
}
|
|
1071
|
+
return { timestamp, signatures };
|
|
1072
|
+
}
|
|
1036
1073
|
async function verifyCmssyWebhook(options) {
|
|
1037
1074
|
const { body, signatureHeader, secret } = options;
|
|
1038
1075
|
if (!signatureHeader) {
|
|
@@ -1071,4 +1108,4 @@ async function verifyCmssyWebhook(options) {
|
|
|
1071
1108
|
return parsed;
|
|
1072
1109
|
}
|
|
1073
1110
|
|
|
1074
|
-
export { CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM, CMSSY_LOCALE_HEADER, CMSSY_RATE_LIMIT_WINDOW_MS, CMSSY_RETRY_MODES, CMSSY_SECRET_QUERY_PARAM, CmssyRequestError, CmssyWebhookError, DEFAULT_CMSSY_API_URL, DEFAULT_CMSSY_EDITOR_ORIGINS, PROTOCOL_VERSION, SHORTCUT_ACTIONS, applyCmssyCsp, blocksToMeta, blocksToSchemas, buildBlockManifest, createCmssyClient, defineCmssyConfig, defineCmssyLayout, fields, graphqlRequest, isProtocolCompatible, isVerifiedEditUrl, layoutRegionsToBridge, localizeHref, mediaAlt, mediaUrl, mediaUrls, normalizeOrigin, parseEditorMessage, postToEditor, propsToSchema, registryToManifestBlocks, resolveCmssyLocale, resolveEditorOrigin, verifyCmssyWebhook };
|
|
1111
|
+
export { CMSSY_EDIT_HEADER, CMSSY_EDIT_QUERY_PARAM, CMSSY_EDIT_TOKEN_HEADER, CMSSY_LOCALE_HEADER, CMSSY_RATE_LIMIT_WINDOW_MS, CMSSY_RETRY_MODES, CMSSY_SECRET_QUERY_PARAM, CmssyRequestError, CmssyWebhookError, DEFAULT_CMSSY_API_URL, DEFAULT_CMSSY_EDITOR_ORIGINS, PROTOCOL_VERSION, SHORTCUT_ACTIONS, applyCmssyCsp, blocksToMeta, blocksToSchemas, buildBlockManifest, createCmssyClient, defineCmssyConfig, defineCmssyLayout, fields, graphqlRequest, isProtocolCompatible, isVerifiedEditUrl, layoutRegionsToBridge, localizeHref, mediaAlt, mediaUrl, mediaUrls, mintCmssyEditToken, normalizeOrigin, parseEditorMessage, postToEditor, propsToSchema, registryToManifestBlocks, resolveCmssyLocale, resolveEditorOrigin, verifyCmssyEditToken, verifyCmssyWebhook };
|
package/dist/internal/locale.cjs
CHANGED
package/dist/internal/locale.js
CHANGED
package/dist/internal.cjs
CHANGED
package/dist/internal.js
CHANGED