@realiizlabs/admin 0.13.0 → 0.13.2
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/events/index.cjs +1 -1
- package/dist/events/index.cjs.map +1 -1
- package/dist/events/index.d.cts +2 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.js +1 -1
- package/dist/events/index.js.map +1 -1
- package/dist/forms/index.cjs +1 -1
- package/dist/forms/index.cjs.map +1 -1
- package/dist/forms/index.d.cts +2 -2
- package/dist/forms/index.d.ts +2 -2
- package/dist/forms/index.js +1 -1
- package/dist/forms/index.js.map +1 -1
- package/dist/forms-ui/index.d.cts +1 -1
- package/dist/forms-ui/index.d.ts +1 -1
- package/dist/media/index.cjs +33 -0
- package/dist/media/index.cjs.map +1 -1
- package/dist/media/index.d.cts +2 -0
- package/dist/media/index.d.ts +2 -0
- package/dist/media/index.js +30 -1
- package/dist/media/index.js.map +1 -1
- package/dist/shell/index.cjs +7 -1
- package/dist/shell/index.cjs.map +1 -1
- package/dist/shell/index.d.cts +2 -2
- package/dist/shell/index.d.ts +2 -2
- package/dist/shell/index.js +7 -1
- package/dist/shell/index.js.map +1 -1
- package/dist/studio/index.cjs +1 -1
- package/dist/studio/index.cjs.map +1 -1
- package/dist/studio/index.d.cts +4 -42
- package/dist/studio/index.d.ts +4 -42
- package/dist/studio/index.js +1 -1
- package/dist/studio/index.js.map +1 -1
- package/dist/studio-ui/index.cjs +7 -1
- package/dist/studio-ui/index.cjs.map +1 -1
- package/dist/studio-ui/index.d.cts +1 -1
- package/dist/studio-ui/index.d.ts +1 -1
- package/dist/studio-ui/index.js +7 -1
- package/dist/studio-ui/index.js.map +1 -1
- package/dist/{types-D46UjOfv.d.cts → types-DeHdasdP.d.cts} +2 -0
- package/dist/{types-D46UjOfv.d.ts → types-DeHdasdP.d.ts} +2 -0
- package/dist/validate-C84Ll1cD.d.cts +41 -0
- package/dist/validate-C84Ll1cD.d.ts +41 -0
- package/package.json +1 -1
package/dist/forms/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/forms/internals.ts","../../src/forms/checks.ts","../../src/forms/unwrap.ts","../../src/forms/inputs.ts","../../src/forms/labels.ts","../../src/forms/walk.ts","../../src/forms/registry.ts","../../src/forms/nav.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The slice of zod 4's `_zod.def` surface this module reads, typed loosely.\n *\n * Tested against zod 4.5.4. These are semi-public internals (the v4 \"core\"\n * shape), stable across 4.x so far but not covered by semver promises — hence\n * the peer-dep range and the fixture tests. No zod value is imported here.\n */\n\nexport interface ZodCheckDef {\n check?: string;\n format?: string;\n minimum?: number;\n maximum?: number;\n length?: number;\n value?: number;\n inclusive?: boolean;\n pattern?: RegExp;\n error?: string | ((issue: unknown) => string | { message?: string } | undefined);\n}\n\nexport interface ZodDef {\n type: string;\n shape?: Record<string, ZodNode>;\n innerType?: ZodNode;\n in?: ZodNode;\n out?: ZodNode;\n element?: ZodNode;\n entries?: Record<string, string | number>;\n checks?: Array<{ _zod: { def: ZodCheckDef } }>;\n coerce?: boolean;\n}\n\nexport interface ZodNode {\n _zod: { def: ZodDef };\n description?: string;\n}\n\n/** Narrow an unknown schema to the internal node shape, or throw a clear error. */\nexport function asNode(schema: unknown, what = \"schema\"): ZodNode {\n const n = schema as Partial<ZodNode> | null;\n if (!n || typeof n !== \"object\" || !n._zod?.def?.type) {\n throw new TypeError(`walkSchema: ${what} is not a zod 4 schema`);\n }\n return n as ZodNode;\n}\n\n/** Resolve a check's error to a plain string, if it has one. */\nexport function checkMessage(def: ZodCheckDef): string | undefined {\n const e = def.error;\n if (!e) return undefined;\n if (typeof e === \"string\") return e;\n const out = e({});\n if (typeof out === \"string\") return out;\n return out?.message;\n}\n","/**\n * checks[] → constraints + messages.\n *\n * Messages are keyed PER CHECK. The spike's walker wrote `out.message = …` on\n * every check, so a field with min and max kept only the max message and\n * showed the wrong error for a too-short value. Here each check kind gets its\n * own key; a renderer maps a failed issue to its message by that key.\n *\n * Unknown check kinds (e.g. a per-field `.refine`, which is `custom`) are kept\n * as a message when they carry one and otherwise skipped — never fatal.\n */\n\nimport type { Constraints, Messages } from \"./types\";\nimport type { ZodNode } from \"./internals\";\nimport { checkMessage } from \"./internals\";\n\nexport function readChecks(node: ZodNode): { constraints: Constraints; messages: Messages } {\n const constraints: Constraints = {};\n const messages: Messages = {};\n\n for (const c of node._zod.def.checks ?? []) {\n const d = c._zod.def;\n const msg = checkMessage(d);\n let key: string | undefined;\n\n switch (d.check) {\n case \"min_length\":\n constraints.min = d.minimum;\n key = \"min_length\";\n break;\n case \"max_length\":\n constraints.max = d.maximum;\n key = \"max_length\";\n break;\n case \"length_equals\":\n constraints.exact = d.length;\n key = \"length_equals\";\n break;\n case \"greater_than\":\n constraints.min = d.inclusive ? d.value : (d.value ?? 0) + 1;\n key = \"greater_than\";\n break;\n case \"less_than\":\n constraints.max = d.inclusive ? d.value : (d.value ?? 0) - 1;\n key = \"less_than\";\n break;\n case \"string_format\":\n if (d.format === \"regex\" && d.pattern) {\n constraints.pattern = d.pattern.source;\n constraints.format = \"regex\";\n key = \"regex\";\n } else if (d.format === \"url\" || d.format === \"email\") {\n constraints.format = d.format;\n key = d.format;\n } else {\n key = d.format;\n }\n break;\n case \"number_format\":\n if (d.format === \"safeint\" || d.format === \"int32\") {\n constraints.format = \"int\";\n key = \"int\";\n }\n break;\n case \"custom\":\n key = \"custom\";\n break;\n default:\n key = d.check;\n }\n\n if (key && msg) messages[key] = msg;\n }\n\n return { constraints, messages };\n}\n","/**\n * Peel wrapper types off a field until the real type is reached.\n *\n * optional / nullable / default → the field is not required.\n * pipe → follow `out` (older 4.x wrapped z.coerce.date in a pipe; 4.5 marks\n * the date itself with `coerce: true` — both land on the same node here).\n */\n\nimport type { ZodNode } from \"./internals\";\n\nexport interface Unwrapped {\n node: ZodNode;\n type: string;\n required: boolean;\n}\n\nexport function unwrap(start: ZodNode): Unwrapped {\n let node = start;\n let required = true;\n // Bounded so a malformed schema can't loop forever.\n for (let i = 0; i < 16; i++) {\n const def = node._zod.def;\n if (def.type === \"optional\" || def.type === \"nullable\" || def.type === \"default\") {\n required = false;\n if (!def.innerType) break;\n node = def.innerType;\n } else if (def.type === \"pipe\") {\n const next = def.out ?? def.in;\n if (!next) break;\n node = next;\n } else {\n break;\n }\n }\n return { node, type: node._zod.def.type, required };\n}\n","/**\n * zod type → InputKind, plus the extras some kinds carry (enum options, the\n * array item's constraints).\n *\n * Long strings become textareas by a simple rule: a max over 120 chars. That\n * is a heuristic, and the registry can't override it today — if a site needs\n * to, that is a one-line change here, not a per-site branch.\n */\n\nimport type { Constraints, InputKind, Messages } from \"./types\";\nimport type { ZodNode } from \"./internals\";\nimport { readChecks } from \"./checks\";\nimport { unwrap } from \"./unwrap\";\n\nconst TEXTAREA_MIN_MAX = 120;\n\nexport interface InputInfo {\n input: InputKind;\n constraints: Constraints;\n messages: Messages;\n options?: string[];\n}\n\nexport function inputFor(node: ZodNode): InputInfo {\n const def = node._zod.def;\n const { constraints, messages } = readChecks(node);\n\n switch (def.type) {\n case \"string\": {\n if (constraints.format === \"url\") return { input: \"url\", constraints, messages };\n const long = (constraints.max ?? 0) > TEXTAREA_MIN_MAX;\n return { input: long ? \"textarea\" : \"text\", constraints, messages };\n }\n case \"date\":\n return { input: \"date\", constraints, messages };\n case \"number\":\n case \"int\":\n return { input: \"number\", constraints, messages };\n case \"boolean\":\n return { input: \"boolean\", constraints, messages };\n case \"enum\":\n case \"literal\": {\n const options = Object.values(def.entries ?? {}).map(String);\n return { input: \"select\", constraints, messages, options };\n }\n case \"array\": {\n if (def.element) {\n const item = unwrap(def.element);\n const inner = readChecks(item.node);\n constraints.item = inner;\n }\n return { input: \"tags\", constraints, messages };\n }\n default:\n // Anything unrecognised (object, union, …) is presented as text so the\n // value can at least be carried; a renderer may choose to treat it as hidden.\n return { input: \"text\", constraints, messages };\n }\n}\n","/**\n * Labels and placeholders.\n *\n * Precedence (decided 2026-09-08):\n * label: registry.labels[name] → .meta({ label }) → .describe() → titlecase(name)\n * placeholder: registry.placeholders[name] → .meta({ placeholder }) → undefined\n *\n * The registry tier exists for schemas that can't be edited yet (5degrees\n * until its repo transfer). The meta tier is the intended home — one source of\n * truth beside the validation rules. Titlecase is the floor, and it is naive on\n * purpose: an acronym coming out as \"Rsvp url\" is the signal that a real label\n * is missing.\n *\n * Meta is read from zod's global registry via the schema's own `meta()` /\n * `description` accessors, so no zod value is imported here.\n */\n\nimport type { ContentTypeEntry, InputKind } from \"./types\";\n\ninterface MetaBearing {\n meta?: () => Record<string, unknown> | undefined;\n description?: string;\n}\n\ninterface FieldMeta {\n label?: string;\n placeholder?: string;\n description?: string;\n recommended?: [number, number];\n suffix?: string;\n help?: string;\n input?: InputKind;\n}\n\nexport function readMeta(schema: unknown): FieldMeta {\n const s = schema as MetaBearing;\n const raw = typeof s.meta === \"function\" ? (s.meta() ?? {}) : {};\n const pick = (k: keyof FieldMeta) => (typeof raw[k] === \"string\" ? (raw[k] as string) : undefined);\n const rec = raw.recommended;\n const recommended =\n Array.isArray(rec) && rec.length === 2 && rec.every((n) => typeof n === \"number\") ? ([rec[0], rec[1]] as [number, number]) : undefined;\n const INPUTS: InputKind[] = [\"text\", \"textarea\", \"date\", \"number\", \"boolean\", \"select\", \"tags\", \"image\", \"url\", \"time\"];\n const input = typeof raw.input === \"string\" && (INPUTS as string[]).includes(raw.input) ? (raw.input as InputKind) : undefined;\n return {\n label: pick(\"label\"),\n placeholder: pick(\"placeholder\"),\n description: pick(\"description\") ?? (typeof s.description === \"string\" ? s.description : undefined),\n recommended,\n suffix: pick(\"suffix\"),\n help: pick(\"help\"),\n input,\n };\n}\n\nexport function inputOverrideFor(\n name: string,\n schema: unknown,\n entry?: Pick<ContentTypeEntry, \"inputs\">,\n): InputKind | undefined {\n return entry?.inputs?.[name] ?? readMeta(schema).input;\n}\n\nexport function recommendedFor(\n name: string,\n schema: unknown,\n entry?: Pick<ContentTypeEntry, \"recommended\">,\n): [number, number] | undefined {\n return entry?.recommended?.[name] ?? readMeta(schema).recommended;\n}\n\nexport function titlecase(name: string): string {\n const words = name\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .replace(/[_-]+/g, \" \")\n .toLowerCase()\n .trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\nexport function labelFor(name: string, schema: unknown, entry?: Pick<ContentTypeEntry, \"labels\">): string {\n const fromRegistry = entry?.labels?.[name];\n if (fromRegistry) return fromRegistry;\n const meta = readMeta(schema);\n return meta.label ?? meta.description ?? titlecase(name);\n}\n\nexport function placeholderFor(\n name: string,\n schema: unknown,\n entry?: Pick<ContentTypeEntry, \"placeholders\">,\n): string | undefined {\n return entry?.placeholders?.[name] ?? readMeta(schema).placeholder;\n}\n\nexport function helpFor(name: string, schema: unknown, entry?: Pick<ContentTypeEntry, \"help\">): string | undefined {\n return entry?.help?.[name] ?? readMeta(schema).help;\n}\n","/**\n * walkSchema — a zod object schema (+ optional registry entry) → FieldSpec[].\n *\n * Synchronous and pure. Reads the schema's shape and checks; never parses a\n * value, never calls an options resolver, never imports zod at runtime.\n *\n * Roles from the registry override the schema-derived input kind: a field the\n * entry names as an image is `role: \"image\"` even though zod sees a string.\n * Hidden fields are still emitted so a renderer can carry their values through.\n */\n\nimport type { ContentTypeEntry, FieldRole, FieldSpec } from \"./types\";\nimport type { ZodNode } from \"./internals\";\nimport { asNode } from \"./internals\";\nimport { inputFor } from \"./inputs\";\nimport { helpFor, inputOverrideFor, labelFor, placeholderFor, readMeta, recommendedFor } from \"./labels\";\nimport { unwrap } from \"./unwrap\";\n\ntype Entry = Partial<Omit<ContentTypeEntry, \"schema\" | \"filename\" | \"id\" | \"label\" | \"folder\">>;\n\nexport function walkSchema(schema: unknown, entry: Entry = {}): FieldSpec[] {\n const root = asNode(schema);\n const shape = shapeOf(root);\n const names = Object.keys(shape);\n\n const specs = names.map((name): FieldSpec => {\n const raw = shape[name];\n const { node, required } = unwrap(raw);\n const info = inputFor(node);\n const role = roleFor(name, entry);\n\n return {\n name,\n label: labelFor(name, raw, entry),\n input: role === \"image\" ? \"image\" : (inputOverrideFor(name, raw, entry) ?? info.input),\n required,\n constraints: info.constraints,\n messages: info.messages,\n placeholder: placeholderFor(name, raw, entry),\n recommended: recommendedFor(name, raw, entry),\n suffix: readMeta(raw).suffix,\n help: helpFor(name, raw, entry),\n order: 0,\n role,\n options: entry.options?.[name] ?? info.options,\n };\n });\n\n return applyOrder(specs, entry.order ?? []);\n}\n\n/** `.strict()` and object-level `.refine()` both leave `shape` on the object def. */\nfunction shapeOf(root: ZodNode): Record<string, ZodNode> {\n let node = root;\n for (let i = 0; i < 8 && !node._zod.def.shape; i++) {\n const def = node._zod.def;\n const next = def.innerType ?? def.in;\n if (!next) break;\n node = next;\n }\n const shape = node._zod.def.shape;\n if (!shape) throw new TypeError(`walkSchema: expected an object schema, got \"${root._zod.def.type}\"`);\n return shape;\n}\n\nfunction roleFor(name: string, entry: Entry): FieldRole {\n if (entry.hidden?.includes(name)) return \"hidden\";\n if (entry.body === name) return \"body\";\n if (entry.images?.includes(name)) return \"image\";\n return \"field\";\n}\n\n/** Named fields first in the given order; the rest keep schema key order. */\nfunction applyOrder(specs: FieldSpec[], order: string[]): FieldSpec[] {\n const rank = new Map(order.map((n, i) => [n, i]));\n const named = specs.filter((s) => rank.has(s.name)).sort((a, b) => rank.get(a.name)! - rank.get(b.name)!);\n const rest = specs.filter((s) => !rank.has(s.name));\n return [...named, ...rest].map((s, i) => ({ ...s, order: i }));\n}\n","/**\n * defineContentType — validate a registry entry against the schema it describes.\n *\n * Validation is hand-rolled rather than a zod schema on purpose: this module\n * must not import zod at runtime (the host's instance is the only one that\n * should exist). The checks are small and the errors name the bad key.\n */\n\nimport type { ZodType } from \"zod\";\nimport type { ContentTypeEntry } from \"./types\";\nimport { asNode } from \"./internals\";\n\nexport function defineContentType<S extends ZodType>(entry: ContentTypeEntry<S>): ContentTypeEntry<S> {\n const where = `defineContentType(\"${entry.id}\")`;\n\n for (const key of [\"id\", \"label\", \"folder\"] as const) {\n if (typeof entry[key] !== \"string\" || entry[key].length === 0) {\n throw new TypeError(`${where}: \"${key}\" must be a non-empty string`);\n }\n }\n if (typeof entry.filename !== \"function\") {\n throw new TypeError(`${where}: \"filename\" must be a function (frontmatter) => string`);\n }\n if (entry.slugFromFilename !== undefined && typeof entry.slugFromFilename !== \"function\") {\n throw new TypeError(`${where}: \"slugFromFilename\" must be a function (fileName) => string | null`);\n }\n if (entry.body !== null && typeof entry.body !== \"string\") {\n throw new TypeError(`${where}: \"body\" must be a field name or null`);\n }\n\n const root = asNode(entry.schema, `${where}: schema`);\n const shape = findShape(root);\n const known = new Set(Object.keys(shape));\n\n const check = (list: string[] | undefined, key: string) => {\n for (const name of list ?? []) {\n if (!known.has(name)) throw new TypeError(`${where}: ${key} names \"${name}\", which is not a field of the schema`);\n }\n };\n\n if (entry.body !== null) check([entry.body], \"body\");\n check(entry.images, \"images\");\n check(entry.order, \"order\");\n check(entry.hidden, \"hidden\");\n check(Object.keys(entry.labels ?? {}), \"labels\");\n check(Object.keys(entry.placeholders ?? {}), \"placeholders\");\n check(Object.keys(entry.recommended ?? {}), \"recommended\");\n check(Object.keys(entry.inputs ?? {}), \"inputs\");\n check(Object.keys(entry.help ?? {}), \"help\");\n check(Object.keys(entry.options ?? {}), \"options\");\n for (const g of entry.groups ?? []) {\n if (typeof g.label !== \"string\" || g.label.length === 0) throw new TypeError(`${where}: every group needs a label`);\n check(g.fields, `groups[\"${g.label}\"]`);\n }\n\n return entry;\n}\n\nfunction findShape(root: ReturnType<typeof asNode>): Record<string, unknown> {\n let node = root;\n for (let i = 0; i < 8 && !node._zod.def.shape; i++) {\n const next = node._zod.def.innerType ?? node._zod.def.in;\n if (!next) break;\n node = next;\n }\n if (!node._zod.def.shape) throw new TypeError(\"defineContentType: schema must be a zod object\");\n return node._zod.def.shape;\n}\n","/**\n * navFromContentTypes — the sidebar derives from the registry.\n *\n * Adding a content type to a site (one defineContentType entry) puts it in\n * the nav with no shell change. Pure; lives in /forms so the server layout\n * can compute it without importing the client bundle.\n */\n\nimport type { ContentTypeEntry } from \"./types\";\n\nexport interface NavEntry {\n id: string;\n label: string;\n href: string;\n icon: string;\n}\n\nexport function navFromContentTypes(\n entries: Record<string, ContentTypeEntry> | ContentTypeEntry[],\n opts: { basePath?: string } = {},\n): NavEntry[] {\n const base = (opts.basePath ?? \"/admin\").replace(/\\/+$/, \"\");\n const list = Array.isArray(entries) ? entries : Object.values(entries);\n return list.map((e) => ({ id: e.id, label: e.label, href: `${base}/${e.id}`, icon: e.id }));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/forms/internals.ts","../../src/forms/checks.ts","../../src/forms/unwrap.ts","../../src/forms/inputs.ts","../../src/forms/labels.ts","../../src/forms/walk.ts","../../src/forms/registry.ts","../../src/forms/nav.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * The slice of zod 4's `_zod.def` surface this module reads, typed loosely.\n *\n * Tested against zod 4.5.4. These are semi-public internals (the v4 \"core\"\n * shape), stable across 4.x so far but not covered by semver promises — hence\n * the peer-dep range and the fixture tests. No zod value is imported here.\n */\n\nexport interface ZodCheckDef {\n check?: string;\n format?: string;\n minimum?: number;\n maximum?: number;\n length?: number;\n value?: number;\n inclusive?: boolean;\n pattern?: RegExp;\n error?: string | ((issue: unknown) => string | { message?: string } | undefined);\n}\n\nexport interface ZodDef {\n type: string;\n shape?: Record<string, ZodNode>;\n innerType?: ZodNode;\n in?: ZodNode;\n out?: ZodNode;\n element?: ZodNode;\n entries?: Record<string, string | number>;\n checks?: Array<{ _zod: { def: ZodCheckDef } }>;\n coerce?: boolean;\n}\n\nexport interface ZodNode {\n _zod: { def: ZodDef };\n description?: string;\n}\n\n/** Narrow an unknown schema to the internal node shape, or throw a clear error. */\nexport function asNode(schema: unknown, what = \"schema\"): ZodNode {\n const n = schema as Partial<ZodNode> | null;\n if (!n || typeof n !== \"object\" || !n._zod?.def?.type) {\n throw new TypeError(`walkSchema: ${what} is not a zod 4 schema`);\n }\n return n as ZodNode;\n}\n\n/** Resolve a check's error to a plain string, if it has one. */\nexport function checkMessage(def: ZodCheckDef): string | undefined {\n const e = def.error;\n if (!e) return undefined;\n if (typeof e === \"string\") return e;\n const out = e({});\n if (typeof out === \"string\") return out;\n return out?.message;\n}\n","/**\n * checks[] → constraints + messages.\n *\n * Messages are keyed PER CHECK. The spike's walker wrote `out.message = …` on\n * every check, so a field with min and max kept only the max message and\n * showed the wrong error for a too-short value. Here each check kind gets its\n * own key; a renderer maps a failed issue to its message by that key.\n *\n * Unknown check kinds (e.g. a per-field `.refine`, which is `custom`) are kept\n * as a message when they carry one and otherwise skipped — never fatal.\n */\n\nimport type { Constraints, Messages } from \"./types\";\nimport type { ZodNode } from \"./internals\";\nimport { checkMessage } from \"./internals\";\n\nexport function readChecks(node: ZodNode): { constraints: Constraints; messages: Messages } {\n const constraints: Constraints = {};\n const messages: Messages = {};\n\n for (const c of node._zod.def.checks ?? []) {\n const d = c._zod.def;\n const msg = checkMessage(d);\n let key: string | undefined;\n\n switch (d.check) {\n case \"min_length\":\n constraints.min = d.minimum;\n key = \"min_length\";\n break;\n case \"max_length\":\n constraints.max = d.maximum;\n key = \"max_length\";\n break;\n case \"length_equals\":\n constraints.exact = d.length;\n key = \"length_equals\";\n break;\n case \"greater_than\":\n constraints.min = d.inclusive ? d.value : (d.value ?? 0) + 1;\n key = \"greater_than\";\n break;\n case \"less_than\":\n constraints.max = d.inclusive ? d.value : (d.value ?? 0) - 1;\n key = \"less_than\";\n break;\n case \"string_format\":\n if (d.format === \"regex\" && d.pattern) {\n constraints.pattern = d.pattern.source;\n constraints.format = \"regex\";\n key = \"regex\";\n } else if (d.format === \"url\" || d.format === \"email\") {\n constraints.format = d.format;\n key = d.format;\n } else {\n key = d.format;\n }\n break;\n case \"number_format\":\n if (d.format === \"safeint\" || d.format === \"int32\") {\n constraints.format = \"int\";\n key = \"int\";\n }\n break;\n case \"custom\":\n key = \"custom\";\n break;\n default:\n key = d.check;\n }\n\n if (key && msg) messages[key] = msg;\n }\n\n return { constraints, messages };\n}\n","/**\n * Peel wrapper types off a field until the real type is reached.\n *\n * optional / nullable / default → the field is not required.\n * pipe → follow `out` (older 4.x wrapped z.coerce.date in a pipe; 4.5 marks\n * the date itself with `coerce: true` — both land on the same node here).\n */\n\nimport type { ZodNode } from \"./internals\";\n\nexport interface Unwrapped {\n node: ZodNode;\n type: string;\n required: boolean;\n}\n\nexport function unwrap(start: ZodNode): Unwrapped {\n let node = start;\n let required = true;\n // Bounded so a malformed schema can't loop forever.\n for (let i = 0; i < 16; i++) {\n const def = node._zod.def;\n if (def.type === \"optional\" || def.type === \"nullable\" || def.type === \"default\") {\n required = false;\n if (!def.innerType) break;\n node = def.innerType;\n } else if (def.type === \"pipe\") {\n const next = def.out ?? def.in;\n if (!next) break;\n node = next;\n } else {\n break;\n }\n }\n return { node, type: node._zod.def.type, required };\n}\n","/**\n * zod type → InputKind, plus the extras some kinds carry (enum options, the\n * array item's constraints).\n *\n * Long strings become textareas by a simple rule: a max over 120 chars. That\n * is a heuristic, and the registry can't override it today — if a site needs\n * to, that is a one-line change here, not a per-site branch.\n */\n\nimport type { Constraints, InputKind, Messages } from \"./types\";\nimport type { ZodNode } from \"./internals\";\nimport { readChecks } from \"./checks\";\nimport { unwrap } from \"./unwrap\";\n\nconst TEXTAREA_MIN_MAX = 120;\n\nexport interface InputInfo {\n input: InputKind;\n constraints: Constraints;\n messages: Messages;\n options?: string[];\n}\n\nexport function inputFor(node: ZodNode): InputInfo {\n const def = node._zod.def;\n const { constraints, messages } = readChecks(node);\n\n switch (def.type) {\n case \"string\": {\n if (constraints.format === \"url\") return { input: \"url\", constraints, messages };\n const long = (constraints.max ?? 0) > TEXTAREA_MIN_MAX;\n return { input: long ? \"textarea\" : \"text\", constraints, messages };\n }\n case \"date\":\n return { input: \"date\", constraints, messages };\n case \"number\":\n case \"int\":\n return { input: \"number\", constraints, messages };\n case \"boolean\":\n return { input: \"boolean\", constraints, messages };\n case \"enum\":\n case \"literal\": {\n const options = Object.values(def.entries ?? {}).map(String);\n return { input: \"select\", constraints, messages, options };\n }\n case \"array\": {\n if (def.element) {\n const item = unwrap(def.element);\n const inner = readChecks(item.node);\n constraints.item = inner;\n }\n return { input: \"tags\", constraints, messages };\n }\n default:\n // Anything unrecognised (object, union, …) is presented as text so the\n // value can at least be carried; a renderer may choose to treat it as hidden.\n return { input: \"text\", constraints, messages };\n }\n}\n","/**\n * Labels and placeholders.\n *\n * Precedence (decided 2026-09-08):\n * label: registry.labels[name] → .meta({ label }) → .describe() → titlecase(name)\n * placeholder: registry.placeholders[name] → .meta({ placeholder }) → undefined\n *\n * The registry tier exists for schemas that can't be edited yet (5degrees\n * until its repo transfer). The meta tier is the intended home — one source of\n * truth beside the validation rules. Titlecase is the floor, and it is naive on\n * purpose: an acronym coming out as \"Rsvp url\" is the signal that a real label\n * is missing.\n *\n * Meta is read from zod's global registry via the schema's own `meta()` /\n * `description` accessors, so no zod value is imported here.\n */\n\nimport type { ContentTypeEntry, InputKind } from \"./types\";\n\ninterface MetaBearing {\n meta?: () => Record<string, unknown> | undefined;\n description?: string;\n}\n\ninterface FieldMeta {\n label?: string;\n placeholder?: string;\n description?: string;\n recommended?: [number, number];\n suffix?: string;\n help?: string;\n input?: InputKind;\n}\n\nexport function readMeta(schema: unknown): FieldMeta {\n const s = schema as MetaBearing;\n const raw = typeof s.meta === \"function\" ? (s.meta() ?? {}) : {};\n const pick = (k: keyof FieldMeta) => (typeof raw[k] === \"string\" ? (raw[k] as string) : undefined);\n const rec = raw.recommended;\n const recommended =\n Array.isArray(rec) && rec.length === 2 && rec.every((n) => typeof n === \"number\") ? ([rec[0], rec[1]] as [number, number]) : undefined;\n const INPUTS: InputKind[] = [\"text\", \"textarea\", \"date\", \"number\", \"boolean\", \"select\", \"tags\", \"image\", \"url\", \"time\"];\n const input = typeof raw.input === \"string\" && (INPUTS as string[]).includes(raw.input) ? (raw.input as InputKind) : undefined;\n return {\n label: pick(\"label\"),\n placeholder: pick(\"placeholder\"),\n description: pick(\"description\") ?? (typeof s.description === \"string\" ? s.description : undefined),\n recommended,\n suffix: pick(\"suffix\"),\n help: pick(\"help\"),\n input,\n };\n}\n\nexport function inputOverrideFor(\n name: string,\n schema: unknown,\n entry?: Pick<ContentTypeEntry, \"inputs\">,\n): InputKind | undefined {\n return entry?.inputs?.[name] ?? readMeta(schema).input;\n}\n\nexport function recommendedFor(\n name: string,\n schema: unknown,\n entry?: Pick<ContentTypeEntry, \"recommended\">,\n): [number, number] | undefined {\n return entry?.recommended?.[name] ?? readMeta(schema).recommended;\n}\n\nexport function titlecase(name: string): string {\n const words = name\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .replace(/[_-]+/g, \" \")\n .toLowerCase()\n .trim();\n return words.charAt(0).toUpperCase() + words.slice(1);\n}\n\nexport function labelFor(name: string, schema: unknown, entry?: Pick<ContentTypeEntry, \"labels\">): string {\n const fromRegistry = entry?.labels?.[name];\n if (fromRegistry) return fromRegistry;\n const meta = readMeta(schema);\n return meta.label ?? meta.description ?? titlecase(name);\n}\n\nexport function placeholderFor(\n name: string,\n schema: unknown,\n entry?: Pick<ContentTypeEntry, \"placeholders\">,\n): string | undefined {\n return entry?.placeholders?.[name] ?? readMeta(schema).placeholder;\n}\n\nexport function helpFor(name: string, schema: unknown, entry?: Pick<ContentTypeEntry, \"help\">): string | undefined {\n return entry?.help?.[name] ?? readMeta(schema).help;\n}\n","/**\n * walkSchema — a zod object schema (+ optional registry entry) → FieldSpec[].\n *\n * Synchronous and pure. Reads the schema's shape and checks; never parses a\n * value, never calls an options resolver, never imports zod at runtime.\n *\n * Roles from the registry override the schema-derived input kind: a field the\n * entry names as an image is `role: \"image\"` even though zod sees a string.\n * Hidden fields are still emitted so a renderer can carry their values through.\n */\n\nimport type { ContentTypeEntry, FieldRole, FieldSpec } from \"./types\";\nimport type { ZodNode } from \"./internals\";\nimport { asNode } from \"./internals\";\nimport { inputFor } from \"./inputs\";\nimport { helpFor, inputOverrideFor, labelFor, placeholderFor, readMeta, recommendedFor } from \"./labels\";\nimport { unwrap } from \"./unwrap\";\n\ntype Entry = Partial<Omit<ContentTypeEntry, \"schema\" | \"filename\" | \"id\" | \"label\" | \"folder\">>;\n\nexport function walkSchema(schema: unknown, entry: Entry = {}): FieldSpec[] {\n const root = asNode(schema);\n const shape = shapeOf(root);\n const names = Object.keys(shape);\n\n const specs = names.map((name): FieldSpec => {\n const raw = shape[name];\n const { node, required } = unwrap(raw);\n const info = inputFor(node);\n const role = roleFor(name, entry);\n\n return {\n name,\n label: labelFor(name, raw, entry),\n input: role === \"image\" ? \"image\" : (inputOverrideFor(name, raw, entry) ?? info.input),\n required,\n constraints: info.constraints,\n messages: info.messages,\n placeholder: placeholderFor(name, raw, entry),\n recommended: recommendedFor(name, raw, entry),\n suffix: readMeta(raw).suffix,\n help: helpFor(name, raw, entry),\n order: 0,\n role,\n options: entry.options?.[name] ?? info.options,\n };\n });\n\n return applyOrder(specs, entry.order ?? []);\n}\n\n/** `.strict()` and object-level `.refine()` both leave `shape` on the object def. */\nfunction shapeOf(root: ZodNode): Record<string, ZodNode> {\n let node = root;\n for (let i = 0; i < 8 && !node._zod.def.shape; i++) {\n const def = node._zod.def;\n const next = def.innerType ?? def.in;\n if (!next) break;\n node = next;\n }\n const shape = node._zod.def.shape;\n if (!shape) throw new TypeError(`walkSchema: expected an object schema, got \"${root._zod.def.type}\"`);\n return shape;\n}\n\nfunction roleFor(name: string, entry: Entry): FieldRole {\n if (entry.hidden?.includes(name)) return \"hidden\";\n if (entry.body === name) return \"body\";\n if (entry.images?.includes(name)) return \"image\";\n return \"field\";\n}\n\n/** Named fields first in the given order; the rest keep schema key order. */\nfunction applyOrder(specs: FieldSpec[], order: string[]): FieldSpec[] {\n const rank = new Map(order.map((n, i) => [n, i]));\n const named = specs.filter((s) => rank.has(s.name)).sort((a, b) => rank.get(a.name)! - rank.get(b.name)!);\n const rest = specs.filter((s) => !rank.has(s.name));\n return [...named, ...rest].map((s, i) => ({ ...s, order: i }));\n}\n","/**\n * defineContentType — validate a registry entry against the schema it describes.\n *\n * Validation is hand-rolled rather than a zod schema on purpose: this module\n * must not import zod at runtime (the host's instance is the only one that\n * should exist). The checks are small and the errors name the bad key.\n */\n\nimport type { ZodType } from \"zod\";\nimport type { ContentTypeEntry } from \"./types\";\nimport { asNode } from \"./internals\";\n\nexport function defineContentType<S extends ZodType>(entry: ContentTypeEntry<S>): ContentTypeEntry<S> {\n const where = `defineContentType(\"${entry.id}\")`;\n\n for (const key of [\"id\", \"label\", \"folder\"] as const) {\n if (typeof entry[key] !== \"string\" || entry[key].length === 0) {\n throw new TypeError(`${where}: \"${key}\" must be a non-empty string`);\n }\n }\n if (typeof entry.filename !== \"function\") {\n throw new TypeError(`${where}: \"filename\" must be a function (frontmatter) => string`);\n }\n if (entry.slugFromFilename !== undefined && typeof entry.slugFromFilename !== \"function\") {\n throw new TypeError(`${where}: \"slugFromFilename\" must be a function (fileName) => string | null`);\n }\n if (entry.body !== null && typeof entry.body !== \"string\") {\n throw new TypeError(`${where}: \"body\" must be a field name or null`);\n }\n\n const root = asNode(entry.schema, `${where}: schema`);\n const shape = findShape(root);\n const known = new Set(Object.keys(shape));\n\n const check = (list: string[] | undefined, key: string) => {\n for (const name of list ?? []) {\n if (!known.has(name)) throw new TypeError(`${where}: ${key} names \"${name}\", which is not a field of the schema`);\n }\n };\n\n if (entry.body !== null) check([entry.body], \"body\");\n check(entry.images, \"images\");\n check(entry.order, \"order\");\n check(entry.hidden, \"hidden\");\n check(Object.keys(entry.labels ?? {}), \"labels\");\n check(Object.keys(entry.placeholders ?? {}), \"placeholders\");\n check(Object.keys(entry.recommended ?? {}), \"recommended\");\n check(Object.keys(entry.inputs ?? {}), \"inputs\");\n check(Object.keys(entry.help ?? {}), \"help\");\n check(Object.keys(entry.options ?? {}), \"options\");\n for (const g of entry.groups ?? []) {\n if (typeof g.label !== \"string\" || g.label.length === 0) throw new TypeError(`${where}: every group needs a label`);\n check(g.fields, `groups[\"${g.label}\"]`);\n }\n\n return entry;\n}\n\nfunction findShape(root: ReturnType<typeof asNode>): Record<string, unknown> {\n let node = root;\n for (let i = 0; i < 8 && !node._zod.def.shape; i++) {\n const next = node._zod.def.innerType ?? node._zod.def.in;\n if (!next) break;\n node = next;\n }\n if (!node._zod.def.shape) throw new TypeError(\"defineContentType: schema must be a zod object\");\n return node._zod.def.shape;\n}\n","/**\n * navFromContentTypes — the sidebar derives from the registry.\n *\n * Adding a content type to a site (one defineContentType entry) puts it in\n * the nav with no shell change. Pure; lives in /forms so the server layout\n * can compute it without importing the client bundle.\n */\n\nimport type { ContentTypeEntry } from \"./types\";\n\nexport interface NavEntry {\n id: string;\n label: string;\n href: string;\n icon: string;\n}\n\nexport function navFromContentTypes(\n entries: Record<string, ContentTypeEntry> | ContentTypeEntry[],\n opts: { basePath?: string } = {},\n): NavEntry[] {\n const base = (opts.basePath ?? \"/admin\").replace(/\\/+$/, \"\");\n const list = Array.isArray(entries) ? entries : Object.values(entries);\n return list.map((e) => ({ id: e.id, label: e.label, href: `${base}/${e.id}`, icon: e.icon ?? e.id }));\n}\n"]}
|
package/dist/forms-ui/index.d.ts
CHANGED
package/dist/media/index.cjs
CHANGED
|
@@ -82,14 +82,47 @@ function imagePathFor(kind, slug, originalName = "", opts = {}) {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
+
// src/media/validate.ts
|
|
86
|
+
var IMAGE_LIMITS = { maxEach: 800 * 1024, maxTotal: 3.5 * 1024 * 1024, prefix: "/blog/" };
|
|
87
|
+
var IMAGE_ERRORS = {
|
|
88
|
+
path: "That image path isn\u2019t allowed.",
|
|
89
|
+
size: "That picture is too large to send \u2014 try a smaller one."
|
|
90
|
+
};
|
|
91
|
+
var SAFE_PATH = /^[a-z0-9][a-z0-9/_-]*\.webp$/;
|
|
92
|
+
function decodedSize(b64) {
|
|
93
|
+
const clean = b64.replace(/\s+/g, "");
|
|
94
|
+
const pad = clean.endsWith("==") ? 2 : clean.endsWith("=") ? 1 : 0;
|
|
95
|
+
return Math.floor(clean.length * 3 / 4) - pad;
|
|
96
|
+
}
|
|
97
|
+
function validateImages(images, limits = IMAGE_LIMITS) {
|
|
98
|
+
let total = 0;
|
|
99
|
+
const files = [];
|
|
100
|
+
for (const img of images) {
|
|
101
|
+
if (typeof img?.path !== "string" || typeof img?.base64 !== "string") return { ok: false, error: IMAGE_ERRORS.path };
|
|
102
|
+
if (!img.path.startsWith(limits.prefix) || img.path.includes("..")) return { ok: false, error: IMAGE_ERRORS.path };
|
|
103
|
+
const rel = img.path.slice(1);
|
|
104
|
+
if (!SAFE_PATH.test(rel)) return { ok: false, error: IMAGE_ERRORS.path };
|
|
105
|
+
const size = decodedSize(img.base64);
|
|
106
|
+
if (size === 0 || size > limits.maxEach) return { ok: false, error: IMAGE_ERRORS.size };
|
|
107
|
+
total += size;
|
|
108
|
+
if (total > limits.maxTotal) return { ok: false, error: IMAGE_ERRORS.size };
|
|
109
|
+
files.push({ path: `public/${rel}`, content: img.base64.replace(/\s+/g, ""), encoding: "base64" });
|
|
110
|
+
}
|
|
111
|
+
return { ok: true, files };
|
|
112
|
+
}
|
|
113
|
+
|
|
85
114
|
exports.ACCEPTED_TYPES = ACCEPTED_TYPES;
|
|
115
|
+
exports.IMAGE_ERRORS = IMAGE_ERRORS;
|
|
116
|
+
exports.IMAGE_LIMITS = IMAGE_LIMITS;
|
|
86
117
|
exports.MAX_INPUT_BYTES = MAX_INPUT_BYTES;
|
|
87
118
|
exports.MEDIA_MESSAGES = MESSAGES;
|
|
88
119
|
exports.MediaError = MediaError;
|
|
89
120
|
exports.checkInput = checkInput;
|
|
121
|
+
exports.decodedSize = decodedSize;
|
|
90
122
|
exports.fitWithin = fitWithin;
|
|
91
123
|
exports.imagePathFor = imagePathFor;
|
|
92
124
|
exports.resizeImage = resizeImage;
|
|
93
125
|
exports.slugifyName = slugifyName;
|
|
126
|
+
exports.validateImages = validateImages;
|
|
94
127
|
//# sourceMappingURL=index.cjs.map
|
|
95
128
|
//# sourceMappingURL=index.cjs.map
|
package/dist/media/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/media/errors.ts","../../src/media/resize.ts","../../src/media/paths.ts"],"names":[],"mappings":";;;AACO,IAAM,UAAA,GAAN,cAAyB,KAAA,CAAM;AAAA,EACpC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,YAAA;AAAA,EACd;AACF;AAEO,IAAM,QAAA,GAAW;AAAA,EACtB,IAAA,EAAM,oEAAA;AAAA,EACN,IAAA,EAAM,6DAAA;AAAA,EACN,MAAA,EAAQ;AACV;;;ACIO,IAAM,cAAA,GAAiB,CAAC,YAAA,EAAc,WAAA,EAAa,cAAc,WAAW;AAC5E,IAAM,eAAA,GAAkB,KAAK,IAAA,GAAO;AAkBpC,SAAS,SAAA,CAAU,KAAA,EAAe,MAAA,EAAgB,QAAA,EAAqD;AAC5G,EAAA,IAAI,KAAA,IAAS,QAAA,EAAU,OAAO,EAAE,OAAO,MAAA,EAAO;AAC9C,EAAA,MAAM,QAAQ,QAAA,GAAW,KAAA;AACzB,EAAA,OAAO,EAAE,KAAA,EAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,KAAK,CAAA,EAAG,MAAA,EAAQ,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,KAAK,CAAC,CAAA,EAAE;AAC7F;AAGO,SAAS,WAAW,IAAA,EAA4C;AACrE,EAAA,IAAI,CAAE,cAAA,CAAqC,QAAA,CAAS,IAAA,CAAK,IAAI,GAAG,MAAM,IAAI,UAAA,CAAW,QAAA,CAAS,IAAI,CAAA;AAClG,EAAA,IAAI,KAAK,IAAA,GAAO,eAAA,QAAuB,IAAI,UAAA,CAAW,SAAS,IAAI,CAAA;AACrE;AAEA,eAAsB,WAAA,CAAY,IAAA,EAAY,IAAA,GAAsB,EAAC,EAA0B;AAC7F,EAAA,UAAA,CAAW,IAAI,CAAA;AACf,EAAA,MAAM,EAAE,WAAW,IAAA,EAAM,OAAA,GAAU,MAAM,QAAA,GAAW,GAAA,GAAM,MAAK,GAAI,IAAA;AAEnE,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,IAAI,CAAA;AAChC,EAAA,MAAM,EAAE,OAAO,MAAA,EAAO,GAAI,UAAU,MAAA,CAAO,KAAA,EAAO,MAAA,CAAO,MAAA,EAAQ,QAAQ,CAAA;AACzE,EAAA,MAAM,MAAA,GAAS,UAAA,CAAW,KAAA,EAAO,MAAM,CAAA;AACvC,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,EAAA,IAAI,CAAC,GAAA,EAAK,MAAM,IAAI,UAAA,CAAW,SAAS,MAAM,CAAA;AAC9C,EAAA,GAAA,CAAI,SAAA,CAAU,MAAA,EAAQ,CAAA,EAAG,CAAA,EAAG,OAAO,MAAM,CAAA;AACzC,EAAA,MAAA,CAAO,KAAA,IAAQ;AAEf,EAAA,IAAI,CAAA,GAAI,OAAA;AACR,EAAA,IAAI,IAAA,GAAO,MAAM,MAAA,CAAO,MAAA,EAAQ,CAAC,CAAA;AACjC,EAAA,OAAO,IAAA,CAAK,IAAA,GAAO,QAAA,IAAY,CAAA,GAAI,QAAQ,GAAA,EAAK;AAC9C,IAAA,CAAA,IAAK,IAAA;AACL,IAAA,IAAA,GAAO,MAAM,MAAA,CAAO,MAAA,EAAQ,CAAC,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,MAAA,EAAO;AAC/B;AAEA,eAAe,OAAO,IAAA,EAAkC;AACtD,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,kBAAkB,IAAI,CAAA;AAAA,EACrC,CAAA,CAAA,MAAQ;AACN,IAAA,MAAM,IAAI,UAAA,CAAW,QAAA,CAAS,MAAM,CAAA;AAAA,EACtC;AACF;AAIA,SAAS,UAAA,CAAW,OAAe,MAAA,EAA2B;AAC5D,EAAA,IAAI,OAAO,eAAA,KAAoB,WAAA,SAAoB,IAAI,eAAA,CAAgB,OAAO,MAAM,CAAA;AACpF,EAAA,MAAM,CAAA,GAAI,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AACzC,EAAA,CAAA,CAAE,KAAA,GAAQ,KAAA;AACV,EAAA,CAAA,CAAE,MAAA,GAAS,MAAA;AACX,EAAA,OAAO,CAAA;AACT;AAEA,eAAe,MAAA,CAAO,QAAmB,OAAA,EAAgC;AACvE,EAAA,MAAM,IAAA,GACJ,eAAA,IAAmB,MAAA,GACf,MAAM,MAAA,CAAO,aAAA,CAAc,EAAE,IAAA,EAAM,YAAA,EAAc,OAAA,EAAS,CAAA,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA,GAC5E,MAAM,IAAI,OAAA,CAAqB,CAAC,OAAA,KAAY,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,YAAA,EAAc,OAAO,CAAC,CAAA;AAC/F,EAAA,IAAI,CAAC,QAAQ,IAAA,CAAK,IAAA,KAAS,cAAc,MAAM,IAAI,UAAA,CAAW,QAAA,CAAS,MAAM,CAAA;AAC7E,EAAA,OAAO,IAAA;AACT;;;AC/EO,SAAS,YAAY,IAAA,EAAsB;AAChD,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,OAAA,CAAQ,eAAA,EAAiB,EAAE,CAAA;AAC7C,EAAA,MAAM,IAAI,IAAA,CACP,SAAA,CAAU,MAAM,CAAA,CAChB,QAAQ,QAAA,EAAU,EAAE,CAAA,CACpB,WAAA,GACA,OAAA,CAAQ,aAAA,EAAe,GAAG,CAAA,CAC1B,OAAA,CAAQ,YAAY,EAAE,CAAA;AACzB,EAAA,OAAO,CAAA,IAAK,OAAA;AACd;AAEO,SAAS,aAAa,IAAA,EAAiB,IAAA,EAAc,eAAe,EAAA,EAAI,IAAA,GAAoB,EAAC,EAAW;AAC7G,EAAA,MAAM,OAAO,IAAA,CAAK,SAAA,IAAa,OAAA,EAAS,OAAA,CAAQ,OAAO,EAAE,CAAA;AACzD,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,MAAA;AACH,MAAA,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,KAAA,CAAA;AAAA,IACvB,KAAK,QAAA;AACH,MAAA,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,YAAA,CAAA;AAAA,IACvB,KAAK,MAAA;AACH,MAAA,OAAO,GAAG,GAAG,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,EAAI,WAAA,CAAY,YAAY,CAAC,CAAA,KAAA,CAAA;AAAA;AAExD","file":"index.cjs","sourcesContent":["/** A picture problem the person can act on. The message is the sentence shown under the control. */\nexport class MediaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MediaError\";\n }\n}\n\nexport const MESSAGES = {\n type: \"That file type isn’t supported — use a JPG, PNG or WebP.\",\n size: \"That picture is too big to send — pick one under 10MB.\",\n encode: \"This browser can’t prepare pictures — try Chrome, Edge or Safari 16+.\",\n} as const;\n","/**\n * resizeImage — shrink a picture in the browser to web size, as WebP.\n *\n * Phone photos are 3–8MB; a Vercel server action body is capped at 4.5MB and the\n * GitHub API wants base64. So the shrink happens here, before anything leaves the\n * browser: decode → fit inside maxWidth → draw to a canvas → encode WebP, lowering\n * quality in steps until the result is under maxBytes. GIFs lose their animation\n * (a still frame is encoded) — acceptable for a blog.\n *\n * No network, no dependencies. Throws MediaError with a plain sentence for the\n * three things that can go wrong: wrong type, too big to even try, or a browser\n * that cannot encode WebP (toBlob returns null or a non-WebP type).\n */\n\nimport { MediaError, MESSAGES } from \"./errors\";\n\nexport const ACCEPTED_TYPES = [\"image/jpeg\", \"image/png\", \"image/webp\", \"image/gif\"] as const;\nexport const MAX_INPUT_BYTES = 10 * 1024 * 1024;\n\nexport interface ResizeOptions {\n /** Longest allowed width in pixels. Default 1600. */\n maxWidth?: number;\n /** Starting WebP quality 0–1. Default 0.82. */\n quality?: number;\n /** Target ceiling for the encoded size. Default 600KB. */\n maxBytes?: number;\n}\n\nexport interface ResizedImage {\n blob: Blob;\n width: number;\n height: number;\n}\n\n/** Pure: fit (width × height) inside maxWidth, never scaling up, whole pixels. */\nexport function fitWithin(width: number, height: number, maxWidth: number): { width: number; height: number } {\n if (width <= maxWidth) return { width, height };\n const ratio = maxWidth / width;\n return { width: Math.round(width * ratio), height: Math.max(1, Math.round(height * ratio)) };\n}\n\n/** The type/size guards, separated so they can run (and be tested) without a canvas. */\nexport function checkInput(file: { type: string; size: number }): void {\n if (!(ACCEPTED_TYPES as readonly string[]).includes(file.type)) throw new MediaError(MESSAGES.type);\n if (file.size > MAX_INPUT_BYTES) throw new MediaError(MESSAGES.size);\n}\n\nexport async function resizeImage(file: File, opts: ResizeOptions = {}): Promise<ResizedImage> {\n checkInput(file);\n const { maxWidth = 1600, quality = 0.82, maxBytes = 600 * 1024 } = opts;\n\n const bitmap = await decode(file);\n const { width, height } = fitWithin(bitmap.width, bitmap.height, maxWidth);\n const canvas = makeCanvas(width, height);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new MediaError(MESSAGES.encode);\n ctx.drawImage(bitmap, 0, 0, width, height);\n bitmap.close?.();\n\n let q = quality;\n let blob = await encode(canvas, q);\n while (blob.size > maxBytes && q - 0.08 >= 0.5) {\n q -= 0.08;\n blob = await encode(canvas, q);\n }\n return { blob, width, height };\n}\n\nasync function decode(file: File): Promise<ImageBitmap> {\n try {\n return await createImageBitmap(file);\n } catch {\n throw new MediaError(MESSAGES.encode);\n }\n}\n\ntype AnyCanvas = HTMLCanvasElement | OffscreenCanvas;\n\nfunction makeCanvas(width: number, height: number): AnyCanvas {\n if (typeof OffscreenCanvas !== \"undefined\") return new OffscreenCanvas(width, height);\n const c = document.createElement(\"canvas\");\n c.width = width;\n c.height = height;\n return c;\n}\n\nasync function encode(canvas: AnyCanvas, quality: number): Promise<Blob> {\n const blob =\n \"convertToBlob\" in canvas\n ? await canvas.convertToBlob({ type: \"image/webp\", quality }).catch(() => null)\n : await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, \"image/webp\", quality));\n if (!blob || blob.type !== \"image/webp\") throw new MediaError(MESSAGES.encode);\n return blob;\n}\n","/**\n * Where a picture lives, decided from the post's slug so the path is known before\n * anything is committed: hero → /blog/{slug}.webp, social → /blog/{slug}-social.webp,\n * body → /blog/{slug}/{name}.webp. The host commits the file under public/ + path.\n */\n\nexport type ImageKind = \"hero\" | \"social\" | \"body\";\n\nexport interface PathOptions {\n /** URL prefix the pictures are served from. Default \"/blog\". */\n publicDir?: string;\n}\n\n/** Lower-case letters, digits and single hyphens; empty in → \"image\". */\nexport function slugifyName(name: string): string {\n const base = name.replace(/\\.[a-z0-9]+$/i, \"\");\n const s = base\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return s || \"image\";\n}\n\nexport function imagePathFor(kind: ImageKind, slug: string, originalName = \"\", opts: PathOptions = {}): string {\n const dir = (opts.publicDir ?? \"/blog\").replace(/\\/$/, \"\");\n switch (kind) {\n case \"hero\":\n return `${dir}/${slug}.webp`;\n case \"social\":\n return `${dir}/${slug}-social.webp`;\n case \"body\":\n return `${dir}/${slug}/${slugifyName(originalName)}.webp`;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/media/errors.ts","../../src/media/resize.ts","../../src/media/paths.ts","../../src/media/validate.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/** A picture problem the person can act on. The message is the sentence shown under the control. */\nexport class MediaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MediaError\";\n }\n}\n\nexport const MESSAGES = {\n type: \"That file type isn’t supported — use a JPG, PNG or WebP.\",\n size: \"That picture is too big to send — pick one under 10MB.\",\n encode: \"This browser can’t prepare pictures — try Chrome, Edge or Safari 16+.\",\n} as const;\n","/**\n * resizeImage — shrink a picture in the browser to web size, as WebP.\n *\n * Phone photos are 3–8MB; a Vercel server action body is capped at 4.5MB and the\n * GitHub API wants base64. So the shrink happens here, before anything leaves the\n * browser: decode → fit inside maxWidth → draw to a canvas → encode WebP, lowering\n * quality in steps until the result is under maxBytes. GIFs lose their animation\n * (a still frame is encoded) — acceptable for a blog.\n *\n * No network, no dependencies. Throws MediaError with a plain sentence for the\n * three things that can go wrong: wrong type, too big to even try, or a browser\n * that cannot encode WebP (toBlob returns null or a non-WebP type).\n */\n\nimport { MediaError, MESSAGES } from \"./errors\";\n\nexport const ACCEPTED_TYPES = [\"image/jpeg\", \"image/png\", \"image/webp\", \"image/gif\"] as const;\nexport const MAX_INPUT_BYTES = 10 * 1024 * 1024;\n\nexport interface ResizeOptions {\n /** Longest allowed width in pixels. Default 1600. */\n maxWidth?: number;\n /** Starting WebP quality 0–1. Default 0.82. */\n quality?: number;\n /** Target ceiling for the encoded size. Default 600KB. */\n maxBytes?: number;\n}\n\nexport interface ResizedImage {\n blob: Blob;\n width: number;\n height: number;\n}\n\n/** Pure: fit (width × height) inside maxWidth, never scaling up, whole pixels. */\nexport function fitWithin(width: number, height: number, maxWidth: number): { width: number; height: number } {\n if (width <= maxWidth) return { width, height };\n const ratio = maxWidth / width;\n return { width: Math.round(width * ratio), height: Math.max(1, Math.round(height * ratio)) };\n}\n\n/** The type/size guards, separated so they can run (and be tested) without a canvas. */\nexport function checkInput(file: { type: string; size: number }): void {\n if (!(ACCEPTED_TYPES as readonly string[]).includes(file.type)) throw new MediaError(MESSAGES.type);\n if (file.size > MAX_INPUT_BYTES) throw new MediaError(MESSAGES.size);\n}\n\nexport async function resizeImage(file: File, opts: ResizeOptions = {}): Promise<ResizedImage> {\n checkInput(file);\n const { maxWidth = 1600, quality = 0.82, maxBytes = 600 * 1024 } = opts;\n\n const bitmap = await decode(file);\n const { width, height } = fitWithin(bitmap.width, bitmap.height, maxWidth);\n const canvas = makeCanvas(width, height);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new MediaError(MESSAGES.encode);\n ctx.drawImage(bitmap, 0, 0, width, height);\n bitmap.close?.();\n\n let q = quality;\n let blob = await encode(canvas, q);\n while (blob.size > maxBytes && q - 0.08 >= 0.5) {\n q -= 0.08;\n blob = await encode(canvas, q);\n }\n return { blob, width, height };\n}\n\nasync function decode(file: File): Promise<ImageBitmap> {\n try {\n return await createImageBitmap(file);\n } catch {\n throw new MediaError(MESSAGES.encode);\n }\n}\n\ntype AnyCanvas = HTMLCanvasElement | OffscreenCanvas;\n\nfunction makeCanvas(width: number, height: number): AnyCanvas {\n if (typeof OffscreenCanvas !== \"undefined\") return new OffscreenCanvas(width, height);\n const c = document.createElement(\"canvas\");\n c.width = width;\n c.height = height;\n return c;\n}\n\nasync function encode(canvas: AnyCanvas, quality: number): Promise<Blob> {\n const blob =\n \"convertToBlob\" in canvas\n ? await canvas.convertToBlob({ type: \"image/webp\", quality }).catch(() => null)\n : await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, \"image/webp\", quality));\n if (!blob || blob.type !== \"image/webp\") throw new MediaError(MESSAGES.encode);\n return blob;\n}\n","/**\n * Where a picture lives, decided from the post's slug so the path is known before\n * anything is committed: hero → /blog/{slug}.webp, social → /blog/{slug}-social.webp,\n * body → /blog/{slug}/{name}.webp. The host commits the file under public/ + path.\n */\n\nexport type ImageKind = \"hero\" | \"social\" | \"body\";\n\nexport interface PathOptions {\n /** URL prefix the pictures are served from. Default \"/blog\". */\n publicDir?: string;\n}\n\n/** Lower-case letters, digits and single hyphens; empty in → \"image\". */\nexport function slugifyName(name: string): string {\n const base = name.replace(/\\.[a-z0-9]+$/i, \"\");\n const s = base\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return s || \"image\";\n}\n\nexport function imagePathFor(kind: ImageKind, slug: string, originalName = \"\", opts: PathOptions = {}): string {\n const dir = (opts.publicDir ?? \"/blog\").replace(/\\/$/, \"\");\n switch (kind) {\n case \"hero\":\n return `${dir}/${slug}.webp`;\n case \"social\":\n return `${dir}/${slug}-social.webp`;\n case \"body\":\n return `${dir}/${slug}/${slugifyName(originalName)}.webp`;\n }\n}\n","/**\n * Server-side checks on the pictures a save carries. Pure.\n *\n * The browser already shrank them, but anyone can POST to a server action, so\n * the path, type and size are re-checked before anything is committed: only\n * WebP under the type's public folder, ≤ 800 KB each, ≤ 3.5 MB per save.\n * Frontmatter paths are URL paths (/blog/x.webp); the repo file lives under public/.\n */\n\nexport interface ImagePayload {\n /** URL path as written in the frontmatter or body, e.g. /blog/my-post.webp. */\n path: string;\n /** Base64 of the WebP bytes. */\n base64: string;\n}\n\nexport interface ImageLimits {\n maxEach: number;\n maxTotal: number;\n /** URL prefix pictures must live under. */\n prefix: string;\n}\n\nexport const IMAGE_LIMITS: ImageLimits = { maxEach: 800 * 1024, maxTotal: 3.5 * 1024 * 1024, prefix: \"/blog/\" };\n\nexport const IMAGE_ERRORS = {\n path: \"That image path isn’t allowed.\",\n size: \"That picture is too large to send — try a smaller one.\",\n} as const;\n\nexport type ValidatedImages =\n | { ok: true; files: { path: string; content: string; encoding: \"base64\" }[] }\n | { ok: false; error: string };\n\nconst SAFE_PATH = /^[a-z0-9][a-z0-9/_-]*\\.webp$/;\n\n/** Bytes a base64 string decodes to, without decoding it. */\nexport function decodedSize(b64: string): number {\n const clean = b64.replace(/\\s+/g, \"\");\n const pad = clean.endsWith(\"==\") ? 2 : clean.endsWith(\"=\") ? 1 : 0;\n return Math.floor((clean.length * 3) / 4) - pad;\n}\n\nexport function validateImages(images: ImagePayload[], limits: ImageLimits = IMAGE_LIMITS): ValidatedImages {\n let total = 0;\n const files: { path: string; content: string; encoding: \"base64\" }[] = [];\n for (const img of images) {\n if (typeof img?.path !== \"string\" || typeof img?.base64 !== \"string\") return { ok: false, error: IMAGE_ERRORS.path };\n if (!img.path.startsWith(limits.prefix) || img.path.includes(\"..\")) return { ok: false, error: IMAGE_ERRORS.path };\n const rel = img.path.slice(1);\n if (!SAFE_PATH.test(rel)) return { ok: false, error: IMAGE_ERRORS.path };\n const size = decodedSize(img.base64);\n if (size === 0 || size > limits.maxEach) return { ok: false, error: IMAGE_ERRORS.size };\n total += size;\n if (total > limits.maxTotal) return { ok: false, error: IMAGE_ERRORS.size };\n files.push({ path: `public/${rel}`, content: img.base64.replace(/\\s+/g, \"\"), encoding: \"base64\" });\n }\n return { ok: true, files };\n}\n"]}
|
package/dist/media/index.d.cts
CHANGED
package/dist/media/index.d.ts
CHANGED
package/dist/media/index.js
CHANGED
|
@@ -80,6 +80,35 @@ function imagePathFor(kind, slug, originalName = "", opts = {}) {
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
// src/media/validate.ts
|
|
84
|
+
var IMAGE_LIMITS = { maxEach: 800 * 1024, maxTotal: 3.5 * 1024 * 1024, prefix: "/blog/" };
|
|
85
|
+
var IMAGE_ERRORS = {
|
|
86
|
+
path: "That image path isn\u2019t allowed.",
|
|
87
|
+
size: "That picture is too large to send \u2014 try a smaller one."
|
|
88
|
+
};
|
|
89
|
+
var SAFE_PATH = /^[a-z0-9][a-z0-9/_-]*\.webp$/;
|
|
90
|
+
function decodedSize(b64) {
|
|
91
|
+
const clean = b64.replace(/\s+/g, "");
|
|
92
|
+
const pad = clean.endsWith("==") ? 2 : clean.endsWith("=") ? 1 : 0;
|
|
93
|
+
return Math.floor(clean.length * 3 / 4) - pad;
|
|
94
|
+
}
|
|
95
|
+
function validateImages(images, limits = IMAGE_LIMITS) {
|
|
96
|
+
let total = 0;
|
|
97
|
+
const files = [];
|
|
98
|
+
for (const img of images) {
|
|
99
|
+
if (typeof img?.path !== "string" || typeof img?.base64 !== "string") return { ok: false, error: IMAGE_ERRORS.path };
|
|
100
|
+
if (!img.path.startsWith(limits.prefix) || img.path.includes("..")) return { ok: false, error: IMAGE_ERRORS.path };
|
|
101
|
+
const rel = img.path.slice(1);
|
|
102
|
+
if (!SAFE_PATH.test(rel)) return { ok: false, error: IMAGE_ERRORS.path };
|
|
103
|
+
const size = decodedSize(img.base64);
|
|
104
|
+
if (size === 0 || size > limits.maxEach) return { ok: false, error: IMAGE_ERRORS.size };
|
|
105
|
+
total += size;
|
|
106
|
+
if (total > limits.maxTotal) return { ok: false, error: IMAGE_ERRORS.size };
|
|
107
|
+
files.push({ path: `public/${rel}`, content: img.base64.replace(/\s+/g, ""), encoding: "base64" });
|
|
108
|
+
}
|
|
109
|
+
return { ok: true, files };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { ACCEPTED_TYPES, IMAGE_ERRORS, IMAGE_LIMITS, MAX_INPUT_BYTES, MESSAGES as MEDIA_MESSAGES, MediaError, checkInput, decodedSize, fitWithin, imagePathFor, resizeImage, slugifyName, validateImages };
|
|
84
113
|
//# sourceMappingURL=index.js.map
|
|
85
114
|
//# sourceMappingURL=index.js.map
|
package/dist/media/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/media/errors.ts","../../src/media/resize.ts","../../src/media/paths.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** A picture problem the person can act on. The message is the sentence shown under the control. */\nexport class MediaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MediaError\";\n }\n}\n\nexport const MESSAGES = {\n type: \"That file type isn’t supported — use a JPG, PNG or WebP.\",\n size: \"That picture is too big to send — pick one under 10MB.\",\n encode: \"This browser can’t prepare pictures — try Chrome, Edge or Safari 16+.\",\n} as const;\n","/**\n * resizeImage — shrink a picture in the browser to web size, as WebP.\n *\n * Phone photos are 3–8MB; a Vercel server action body is capped at 4.5MB and the\n * GitHub API wants base64. So the shrink happens here, before anything leaves the\n * browser: decode → fit inside maxWidth → draw to a canvas → encode WebP, lowering\n * quality in steps until the result is under maxBytes. GIFs lose their animation\n * (a still frame is encoded) — acceptable for a blog.\n *\n * No network, no dependencies. Throws MediaError with a plain sentence for the\n * three things that can go wrong: wrong type, too big to even try, or a browser\n * that cannot encode WebP (toBlob returns null or a non-WebP type).\n */\n\nimport { MediaError, MESSAGES } from \"./errors\";\n\nexport const ACCEPTED_TYPES = [\"image/jpeg\", \"image/png\", \"image/webp\", \"image/gif\"] as const;\nexport const MAX_INPUT_BYTES = 10 * 1024 * 1024;\n\nexport interface ResizeOptions {\n /** Longest allowed width in pixels. Default 1600. */\n maxWidth?: number;\n /** Starting WebP quality 0–1. Default 0.82. */\n quality?: number;\n /** Target ceiling for the encoded size. Default 600KB. */\n maxBytes?: number;\n}\n\nexport interface ResizedImage {\n blob: Blob;\n width: number;\n height: number;\n}\n\n/** Pure: fit (width × height) inside maxWidth, never scaling up, whole pixels. */\nexport function fitWithin(width: number, height: number, maxWidth: number): { width: number; height: number } {\n if (width <= maxWidth) return { width, height };\n const ratio = maxWidth / width;\n return { width: Math.round(width * ratio), height: Math.max(1, Math.round(height * ratio)) };\n}\n\n/** The type/size guards, separated so they can run (and be tested) without a canvas. */\nexport function checkInput(file: { type: string; size: number }): void {\n if (!(ACCEPTED_TYPES as readonly string[]).includes(file.type)) throw new MediaError(MESSAGES.type);\n if (file.size > MAX_INPUT_BYTES) throw new MediaError(MESSAGES.size);\n}\n\nexport async function resizeImage(file: File, opts: ResizeOptions = {}): Promise<ResizedImage> {\n checkInput(file);\n const { maxWidth = 1600, quality = 0.82, maxBytes = 600 * 1024 } = opts;\n\n const bitmap = await decode(file);\n const { width, height } = fitWithin(bitmap.width, bitmap.height, maxWidth);\n const canvas = makeCanvas(width, height);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new MediaError(MESSAGES.encode);\n ctx.drawImage(bitmap, 0, 0, width, height);\n bitmap.close?.();\n\n let q = quality;\n let blob = await encode(canvas, q);\n while (blob.size > maxBytes && q - 0.08 >= 0.5) {\n q -= 0.08;\n blob = await encode(canvas, q);\n }\n return { blob, width, height };\n}\n\nasync function decode(file: File): Promise<ImageBitmap> {\n try {\n return await createImageBitmap(file);\n } catch {\n throw new MediaError(MESSAGES.encode);\n }\n}\n\ntype AnyCanvas = HTMLCanvasElement | OffscreenCanvas;\n\nfunction makeCanvas(width: number, height: number): AnyCanvas {\n if (typeof OffscreenCanvas !== \"undefined\") return new OffscreenCanvas(width, height);\n const c = document.createElement(\"canvas\");\n c.width = width;\n c.height = height;\n return c;\n}\n\nasync function encode(canvas: AnyCanvas, quality: number): Promise<Blob> {\n const blob =\n \"convertToBlob\" in canvas\n ? await canvas.convertToBlob({ type: \"image/webp\", quality }).catch(() => null)\n : await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, \"image/webp\", quality));\n if (!blob || blob.type !== \"image/webp\") throw new MediaError(MESSAGES.encode);\n return blob;\n}\n","/**\n * Where a picture lives, decided from the post's slug so the path is known before\n * anything is committed: hero → /blog/{slug}.webp, social → /blog/{slug}-social.webp,\n * body → /blog/{slug}/{name}.webp. The host commits the file under public/ + path.\n */\n\nexport type ImageKind = \"hero\" | \"social\" | \"body\";\n\nexport interface PathOptions {\n /** URL prefix the pictures are served from. Default \"/blog\". */\n publicDir?: string;\n}\n\n/** Lower-case letters, digits and single hyphens; empty in → \"image\". */\nexport function slugifyName(name: string): string {\n const base = name.replace(/\\.[a-z0-9]+$/i, \"\");\n const s = base\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return s || \"image\";\n}\n\nexport function imagePathFor(kind: ImageKind, slug: string, originalName = \"\", opts: PathOptions = {}): string {\n const dir = (opts.publicDir ?? \"/blog\").replace(/\\/$/, \"\");\n switch (kind) {\n case \"hero\":\n return `${dir}/${slug}.webp`;\n case \"social\":\n return `${dir}/${slug}-social.webp`;\n case \"body\":\n return `${dir}/${slug}/${slugifyName(originalName)}.webp`;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/media/errors.ts","../../src/media/resize.ts","../../src/media/paths.ts","../../src/media/validate.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** A picture problem the person can act on. The message is the sentence shown under the control. */\nexport class MediaError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"MediaError\";\n }\n}\n\nexport const MESSAGES = {\n type: \"That file type isn’t supported — use a JPG, PNG or WebP.\",\n size: \"That picture is too big to send — pick one under 10MB.\",\n encode: \"This browser can’t prepare pictures — try Chrome, Edge or Safari 16+.\",\n} as const;\n","/**\n * resizeImage — shrink a picture in the browser to web size, as WebP.\n *\n * Phone photos are 3–8MB; a Vercel server action body is capped at 4.5MB and the\n * GitHub API wants base64. So the shrink happens here, before anything leaves the\n * browser: decode → fit inside maxWidth → draw to a canvas → encode WebP, lowering\n * quality in steps until the result is under maxBytes. GIFs lose their animation\n * (a still frame is encoded) — acceptable for a blog.\n *\n * No network, no dependencies. Throws MediaError with a plain sentence for the\n * three things that can go wrong: wrong type, too big to even try, or a browser\n * that cannot encode WebP (toBlob returns null or a non-WebP type).\n */\n\nimport { MediaError, MESSAGES } from \"./errors\";\n\nexport const ACCEPTED_TYPES = [\"image/jpeg\", \"image/png\", \"image/webp\", \"image/gif\"] as const;\nexport const MAX_INPUT_BYTES = 10 * 1024 * 1024;\n\nexport interface ResizeOptions {\n /** Longest allowed width in pixels. Default 1600. */\n maxWidth?: number;\n /** Starting WebP quality 0–1. Default 0.82. */\n quality?: number;\n /** Target ceiling for the encoded size. Default 600KB. */\n maxBytes?: number;\n}\n\nexport interface ResizedImage {\n blob: Blob;\n width: number;\n height: number;\n}\n\n/** Pure: fit (width × height) inside maxWidth, never scaling up, whole pixels. */\nexport function fitWithin(width: number, height: number, maxWidth: number): { width: number; height: number } {\n if (width <= maxWidth) return { width, height };\n const ratio = maxWidth / width;\n return { width: Math.round(width * ratio), height: Math.max(1, Math.round(height * ratio)) };\n}\n\n/** The type/size guards, separated so they can run (and be tested) without a canvas. */\nexport function checkInput(file: { type: string; size: number }): void {\n if (!(ACCEPTED_TYPES as readonly string[]).includes(file.type)) throw new MediaError(MESSAGES.type);\n if (file.size > MAX_INPUT_BYTES) throw new MediaError(MESSAGES.size);\n}\n\nexport async function resizeImage(file: File, opts: ResizeOptions = {}): Promise<ResizedImage> {\n checkInput(file);\n const { maxWidth = 1600, quality = 0.82, maxBytes = 600 * 1024 } = opts;\n\n const bitmap = await decode(file);\n const { width, height } = fitWithin(bitmap.width, bitmap.height, maxWidth);\n const canvas = makeCanvas(width, height);\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) throw new MediaError(MESSAGES.encode);\n ctx.drawImage(bitmap, 0, 0, width, height);\n bitmap.close?.();\n\n let q = quality;\n let blob = await encode(canvas, q);\n while (blob.size > maxBytes && q - 0.08 >= 0.5) {\n q -= 0.08;\n blob = await encode(canvas, q);\n }\n return { blob, width, height };\n}\n\nasync function decode(file: File): Promise<ImageBitmap> {\n try {\n return await createImageBitmap(file);\n } catch {\n throw new MediaError(MESSAGES.encode);\n }\n}\n\ntype AnyCanvas = HTMLCanvasElement | OffscreenCanvas;\n\nfunction makeCanvas(width: number, height: number): AnyCanvas {\n if (typeof OffscreenCanvas !== \"undefined\") return new OffscreenCanvas(width, height);\n const c = document.createElement(\"canvas\");\n c.width = width;\n c.height = height;\n return c;\n}\n\nasync function encode(canvas: AnyCanvas, quality: number): Promise<Blob> {\n const blob =\n \"convertToBlob\" in canvas\n ? await canvas.convertToBlob({ type: \"image/webp\", quality }).catch(() => null)\n : await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, \"image/webp\", quality));\n if (!blob || blob.type !== \"image/webp\") throw new MediaError(MESSAGES.encode);\n return blob;\n}\n","/**\n * Where a picture lives, decided from the post's slug so the path is known before\n * anything is committed: hero → /blog/{slug}.webp, social → /blog/{slug}-social.webp,\n * body → /blog/{slug}/{name}.webp. The host commits the file under public/ + path.\n */\n\nexport type ImageKind = \"hero\" | \"social\" | \"body\";\n\nexport interface PathOptions {\n /** URL prefix the pictures are served from. Default \"/blog\". */\n publicDir?: string;\n}\n\n/** Lower-case letters, digits and single hyphens; empty in → \"image\". */\nexport function slugifyName(name: string): string {\n const base = name.replace(/\\.[a-z0-9]+$/i, \"\");\n const s = base\n .normalize(\"NFKD\")\n .replace(/[̀-ͯ]/g, \"\")\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n return s || \"image\";\n}\n\nexport function imagePathFor(kind: ImageKind, slug: string, originalName = \"\", opts: PathOptions = {}): string {\n const dir = (opts.publicDir ?? \"/blog\").replace(/\\/$/, \"\");\n switch (kind) {\n case \"hero\":\n return `${dir}/${slug}.webp`;\n case \"social\":\n return `${dir}/${slug}-social.webp`;\n case \"body\":\n return `${dir}/${slug}/${slugifyName(originalName)}.webp`;\n }\n}\n","/**\n * Server-side checks on the pictures a save carries. Pure.\n *\n * The browser already shrank them, but anyone can POST to a server action, so\n * the path, type and size are re-checked before anything is committed: only\n * WebP under the type's public folder, ≤ 800 KB each, ≤ 3.5 MB per save.\n * Frontmatter paths are URL paths (/blog/x.webp); the repo file lives under public/.\n */\n\nexport interface ImagePayload {\n /** URL path as written in the frontmatter or body, e.g. /blog/my-post.webp. */\n path: string;\n /** Base64 of the WebP bytes. */\n base64: string;\n}\n\nexport interface ImageLimits {\n maxEach: number;\n maxTotal: number;\n /** URL prefix pictures must live under. */\n prefix: string;\n}\n\nexport const IMAGE_LIMITS: ImageLimits = { maxEach: 800 * 1024, maxTotal: 3.5 * 1024 * 1024, prefix: \"/blog/\" };\n\nexport const IMAGE_ERRORS = {\n path: \"That image path isn’t allowed.\",\n size: \"That picture is too large to send — try a smaller one.\",\n} as const;\n\nexport type ValidatedImages =\n | { ok: true; files: { path: string; content: string; encoding: \"base64\" }[] }\n | { ok: false; error: string };\n\nconst SAFE_PATH = /^[a-z0-9][a-z0-9/_-]*\\.webp$/;\n\n/** Bytes a base64 string decodes to, without decoding it. */\nexport function decodedSize(b64: string): number {\n const clean = b64.replace(/\\s+/g, \"\");\n const pad = clean.endsWith(\"==\") ? 2 : clean.endsWith(\"=\") ? 1 : 0;\n return Math.floor((clean.length * 3) / 4) - pad;\n}\n\nexport function validateImages(images: ImagePayload[], limits: ImageLimits = IMAGE_LIMITS): ValidatedImages {\n let total = 0;\n const files: { path: string; content: string; encoding: \"base64\" }[] = [];\n for (const img of images) {\n if (typeof img?.path !== \"string\" || typeof img?.base64 !== \"string\") return { ok: false, error: IMAGE_ERRORS.path };\n if (!img.path.startsWith(limits.prefix) || img.path.includes(\"..\")) return { ok: false, error: IMAGE_ERRORS.path };\n const rel = img.path.slice(1);\n if (!SAFE_PATH.test(rel)) return { ok: false, error: IMAGE_ERRORS.path };\n const size = decodedSize(img.base64);\n if (size === 0 || size > limits.maxEach) return { ok: false, error: IMAGE_ERRORS.size };\n total += size;\n if (total > limits.maxTotal) return { ok: false, error: IMAGE_ERRORS.size };\n files.push({ path: `public/${rel}`, content: img.base64.replace(/\\s+/g, \"\"), encoding: \"base64\" });\n }\n return { ok: true, files };\n}\n"]}
|
package/dist/shell/index.cjs
CHANGED
|
@@ -37,6 +37,12 @@ function Icon({ name }) {
|
|
|
37
37
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "5", width: "18", height: "16", rx: "2" }),
|
|
38
38
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 3v4M16 3v4M3 10h18" })
|
|
39
39
|
] });
|
|
40
|
+
case "mic":
|
|
41
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...base, children: [
|
|
42
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "9", y: "3", width: "6", height: "11", rx: "3" }),
|
|
43
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 11a7 7 0 0 0 14 0" }),
|
|
44
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 18v3M9 21h6" })
|
|
45
|
+
] });
|
|
40
46
|
case "venues":
|
|
41
47
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...base, children: [
|
|
42
48
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 21s7-6.2 7-11.5A7 7 0 0 0 5 9.5C5 14.8 12 21 12 21z" }),
|
|
@@ -66,7 +72,7 @@ function Icon({ name }) {
|
|
|
66
72
|
}
|
|
67
73
|
}
|
|
68
74
|
function iconFor(id) {
|
|
69
|
-
const known = ["home", "posts", "events", "venues", "users", "settings"];
|
|
75
|
+
const known = ["home", "posts", "events", "mic", "venues", "users", "settings"];
|
|
70
76
|
return known.includes(id) ? id : "doc";
|
|
71
77
|
}
|
|
72
78
|
var SIDEBAR_KEY = "rz-admin-sidebar";
|