@cardinali-studio/adminkit 2.2.6 → 2.2.7

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.
@@ -16,6 +16,12 @@ function diagnosticId() {
16
16
  return `diag_${crypto.randomUUID().replaceAll("-", "").slice(0, 12)}`;
17
17
  }
18
18
 
19
+ function invalid(code, reason) {
20
+ const error = new Error(code);
21
+ error.reason = reason;
22
+ return error;
23
+ }
24
+
19
25
  function repository(env) {
20
26
  if (!env.CONTENT_DB) throw new Error("content_unavailable");
21
27
  return new D1ContentRepository(env.CONTENT_DB);
@@ -28,12 +34,20 @@ function safeError(error, stage) {
28
34
  const status = safeCode === "unauthenticated" ? 401
29
35
  : safeCode === "stale_revision" || safeCode === "duplicate_request" ? 409
30
36
  : safeCode === "invalid_request" || safeCode === "invalid_document" ? 400 : 503;
37
+ const invalidMessages = {
38
+ request_shape: "La richiesta di salvataggio ha una forma non valida.",
39
+ schema_validation: "Il contenuto non rispetta lo schema del sito.",
40
+ document_identity: "Il documento validato non conserva la propria identità.",
41
+ payload_checksum: "Il checksum del contenuto non coincide con il documento validato.",
42
+ request_checksum: "Il checksum del comando non coincide con il salvataggio validato.",
43
+ };
44
+ const reason = typeof error?.reason === "string" && invalidMessages[error.reason] ? error.reason : undefined;
31
45
  const message = safeCode === "unauthenticated" ? "Sessione non valida: ricarica la pagina per rientrare."
32
46
  : safeCode === "stale_revision" ? "Questo contenuto è stato modificato altrove: ricarica e risolvi il conflitto."
33
47
  : code === "duplicate_request" ? "Questo identificatore di salvataggio è già associato a dati diversi."
34
- : safeCode === "invalid_request" || safeCode === "invalid_document" ? "Il documento non è valido."
48
+ : safeCode === "invalid_request" || safeCode === "invalid_document" ? (invalidMessages[reason] || "Il documento non è valido.")
35
49
  : "La persistenza contenuti non è disponibile.";
36
- return response({ ok: false, code: safeCode, stage, error: message, diagnosticId: diagnosticId(), retryable: status >= 500 }, status);
50
+ return response({ ok: false, code: safeCode, stage, ...(reason ? { reason } : {}), error: message, diagnosticId: diagnosticId(), retryable: status >= 500 }, status);
37
51
  }
38
52
 
39
53
  function author(data) {
@@ -117,14 +131,20 @@ export async function onRequestPost({ request, env, data }) {
117
131
  }
118
132
  if (!new URL(request.url).pathname.endsWith("/save")) return response({ ok: false, code: "invalid_request", stage: "validation", error: "Metodo non ammesso.", diagnosticId: diagnosticId(), retryable: false }, 405);
119
133
  const editor = author(data);
120
- if (!id.test(body.revisionId) || !id.test(body.documentId) || (body.baseRevisionId !== null && !id.test(body.baseRevisionId)) || (body.expectedDraftRevisionId !== undefined && body.expectedDraftRevisionId !== null && !id.test(body.expectedDraftRevisionId)) || (body.translationGroupId !== null && body.translationGroupId !== undefined && !id.test(body.translationGroupId)) || !checksum.test(body.requestChecksum || "") || !Number.isInteger(body.schemaVersion) || body.schemaVersion < 1 || typeof body.kind !== "string" || body.kind.length > 120 || typeof body.locale !== "string" || body.locale.length > 35 || (body.payload !== null && (typeof body.payload !== "object" || Array.isArray(body.payload)))) throw new Error("invalid_request");
121
- const document = validateContentDocument({ documentId: body.documentId, kind: body.kind, locale: body.locale, translationGroupId: body.translationGroupId ?? null, payload: body.payload, tombstone: body.tombstone === true, schemaVersion: body.schemaVersion });
122
- if (document.documentId !== body.documentId || document.kind !== body.kind || document.locale !== body.locale || document.schemaVersion !== body.schemaVersion || document.tombstone !== (body.tombstone === true)) throw new Error("invalid_document");
134
+ if (!id.test(body.revisionId) || !id.test(body.documentId) || (body.baseRevisionId !== null && !id.test(body.baseRevisionId)) || (body.expectedDraftRevisionId !== undefined && body.expectedDraftRevisionId !== null && !id.test(body.expectedDraftRevisionId)) || (body.translationGroupId !== null && body.translationGroupId !== undefined && !id.test(body.translationGroupId)) || !checksum.test(body.requestChecksum || "") || !Number.isInteger(body.schemaVersion) || body.schemaVersion < 1 || typeof body.kind !== "string" || body.kind.length > 120 || typeof body.locale !== "string" || body.locale.length > 35 || (body.payload !== null && (typeof body.payload !== "object" || Array.isArray(body.payload)))) throw invalid("invalid_request", "request_shape");
135
+ let document;
136
+ try {
137
+ document = validateContentDocument({ documentId: body.documentId, kind: body.kind, locale: body.locale, translationGroupId: body.translationGroupId ?? null, payload: body.payload, tombstone: body.tombstone === true, schemaVersion: body.schemaVersion });
138
+ } catch (error) {
139
+ if (error?.message === "invalid_document") throw invalid("invalid_document", "schema_validation");
140
+ throw error;
141
+ }
142
+ if (document.documentId !== body.documentId || document.kind !== body.kind || document.locale !== body.locale || document.schemaVersion !== body.schemaVersion || document.tombstone !== (body.tombstone === true)) throw invalid("invalid_document", "document_identity");
123
143
  const expectedPayloadChecksum = await canonicalChecksum(document.tombstone ? null : document.payload);
124
- if (body.payloadChecksum !== expectedPayloadChecksum) throw new Error("invalid_document");
144
+ if (body.payloadChecksum !== expectedPayloadChecksum) throw invalid("invalid_document", "payload_checksum");
125
145
  const normalized = { ...body, ...document, expectedDraftRevisionId: body.expectedDraftRevisionId === undefined ? body.baseRevisionId : body.expectedDraftRevisionId, payloadChecksum: expectedPayloadChecksum };
126
146
  const expectedRequestChecksum = await contentSaveRequestChecksum(normalized);
127
- if (body.requestChecksum !== expectedRequestChecksum) throw new Error("invalid_document");
147
+ if (body.requestChecksum !== expectedRequestChecksum) throw invalid("invalid_document", "request_checksum");
128
148
  const repo = repository(env);
129
149
  try {
130
150
  const outcome = await repo.save({ ...normalized, now, authorSubject: editor.subject, authorLabel: editor.label });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardinali-studio/adminkit",
3
- "version": "2.2.6",
3
+ "version": "2.2.7",
4
4
  "type": "module",
5
5
  "description": "Motore riusabile di un pannello di amministrazione per siti Hugo su Cloudflare Pages: codec del front matter guidato dallo schema, form React, libreria media su R2. NIENTE di specifico di un sito qui dentro.",
6
6
  "license": "UNLICENSED",