@openrails/contentkit-ui 0.87.0-rc.1 → 0.87.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/README.md +18 -11
- package/dist/client/beacons.js +5 -1
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/contents.d.ts +8 -6
- package/dist/client/contents.js +10 -7
- package/dist/client/contents.js.map +1 -1
- package/dist/client/errors.d.ts +15 -3
- package/dist/client/errors.js +40 -14
- package/dist/client/errors.js.map +1 -1
- package/dist/client/generated/routes.d.ts +1 -1
- package/dist/client/generated/routes.js +1 -1
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +11 -3
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/http.js +27 -27
- package/dist/client/http.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/media/client.d.ts +10 -4
- package/dist/client/media/client.js +33 -7
- package/dist/client/media/client.js.map +1 -1
- package/dist/client/media/rules.d.ts +1 -1
- package/dist/client/media/rules.js +6 -6
- package/dist/client/media/rules.js.map +1 -1
- package/dist/client/media/transport.d.ts +1 -1
- package/dist/client/media/transport.js +16 -16
- package/dist/client/media/transport.js.map +1 -1
- package/dist/client/public.d.ts +2 -2
- package/dist/client/public.js +2 -2
- package/dist/client/public.js.map +1 -1
- package/dist/client.js +25 -25
- package/dist/components/admin/content-manager.js +233 -232
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/content/editors.d.ts +8 -0
- package/dist/components/content/editors.js +299 -229
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/index.d.ts +1 -1
- package/dist/components/content/paywall.js +61 -61
- package/dist/components/content/paywall.js.map +1 -1
- package/dist/i18n/messages.js +49 -46
- package/dist/i18n/messages.js.map +1 -1
- package/dist/index.js +11 -11
- package/dist/locales/de.js +2 -1
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/en.d.ts +1 -0
- package/dist/locales/en.js +2 -1
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +2 -1
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/ja.js +2 -1
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +2 -1
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/zh.js +2 -1
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/contents.d.ts +13 -5
- package/dist/react/contents.js +163 -149
- package/dist/react/contents.js.map +1 -1
- package/dist/react/detail.d.ts +7 -1
- package/dist/react/detail.js +9 -6
- package/dist/react/detail.js.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/public.js +17 -16
- package/dist/react/public.js.map +1 -1
- package/dist/react.js +8 -8
- package/package.json +1 -1
|
@@ -121,21 +121,21 @@ function v(e, t, n, r) {
|
|
|
121
121
|
let i = e.filter((e) => e.kind === t && u([{ path: e.from }], n));
|
|
122
122
|
return (r ? i.find((e) => e.name === r) : void 0) ?? i.find((e) => e.aspect) ?? i[0];
|
|
123
123
|
}
|
|
124
|
-
function y(e, t) {
|
|
125
|
-
return !e.default || e.first || e.to.includes(s) ? null : x(e, t);
|
|
124
|
+
function y(e, t, n) {
|
|
125
|
+
return !e.default || e.first || e.to.includes(s) ? null : x(e, t, n);
|
|
126
126
|
}
|
|
127
127
|
function b(e, t) {
|
|
128
128
|
return e.stable ? x(e, t) : null;
|
|
129
129
|
}
|
|
130
|
-
function x(e, i) {
|
|
131
|
-
let
|
|
130
|
+
function x(e, i, a) {
|
|
131
|
+
let o = r(e.aspect);
|
|
132
132
|
return {
|
|
133
133
|
preset: e.name,
|
|
134
134
|
aspect: e.aspect,
|
|
135
135
|
renditions: e.widths.map((r) => ({
|
|
136
|
-
url: n(e.base, e.namespace, e.kind, i, t(e.to, { w: r })),
|
|
136
|
+
url: n(e.base, e.namespace, e.kind, i, t(e.to, { w: r }), a),
|
|
137
137
|
w: r,
|
|
138
|
-
...
|
|
138
|
+
...o ? { h: Math.round(r / o) } : {}
|
|
139
139
|
}))
|
|
140
140
|
};
|
|
141
141
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","names":[],"sources":["../../../src/client/media/rules.ts"],"sourcesContent":["import { ContentKitError } from \"../errors.js\";\nimport type { ErrorDetails, PresetRule, ReadResult, UploadRule } from \"../generated/wire.js\";\nimport { fill, publicURL, type PublicPreset } from \"../public.js\";\nimport { ratio } from \"../aspect.js\";\nimport { stem } from \"./client.js\";\n\nconst NO_RULES: UploadRule[] = [];\n\n/** An editor read's upload rules (a viewer read has none): one empty list, so memos keyed on them hold. */\nexport const uploadRules = (read: ReadResult | null | undefined): UploadRule[] => read?.uploads ?? NO_RULES;\n\nconst NAME = \"{name}\";\n\n/** A pattern path (\"originals/{name}\") holds many files; a literal (\"cover\") one. */\nexport const isPattern = (path: string) => path.endsWith(NAME);\n\n/** The directory of a pattern (\"originals/\"), or the literal itself. */\nexport const ruleDir = (path: string) => (isPattern(path) ? path.slice(0, -NAME.length) : path);\n\n/** The rule an upload path (with or without its extension) falls under: a literal wins over a pattern. */\nexport function ruleFor<R extends { path: string }>(rules: readonly R[], path: string): R | undefined {\n const s = stem(path);\n return (\n rules.find((r) => !isPattern(r.path) && r.path === s) ??\n rules.find((r) => {\n if (!isPattern(r.path)) return false;\n const dir = ruleDir(r.path);\n return s.startsWith(dir) && s.length > dir.length && !s.slice(dir.length).includes(\"/\");\n })\n );\n}\n\n/** Uploads of the read under rule (attached, in manifest order). */\nexport function filesFor(read: ReadResult | null | undefined, rule: { path: string }, rules: readonly { path: string }[] = [rule]) {\n return (read?.files ?? []).filter((f) => f.upload && !f.unattached && ruleFor(rules, f.path)?.path === rule.path);\n}\n\nconst BY_EXTENSION: Record<string, string> = {\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n webp: \"image/webp\",\n gif: \"image/gif\",\n avif: \"image/avif\",\n mp4: \"video/mp4\",\n m4v: \"video/mp4\",\n mov: \"video/quicktime\",\n mkv: \"video/x-matroska\",\n webm: \"video/webm\",\n m4a: \"audio/mp4\",\n mp3: \"audio/mpeg\",\n vtt: \"text/vtt\",\n srt: \"application/x-subrip\",\n ass: \"text/x-ass\",\n ssa: \"text/x-ssa\",\n zip: \"application/zip\",\n};\n\n/** The file with a content type from its extension when the browser left it empty or nonstandard (.mkv, .mov, .srt). */\nexport function withMediaType(file: File, allowed?: readonly string[]): File {\n if (file.type && (!allowed || allowed.includes(file.type))) return file;\n const type = BY_EXTENSION[file.name.split(\".\").pop()?.toLowerCase() ?? \"\"];\n return type && type !== file.type ? new File([file], file.name, { type, lastModified: file.lastModified }) : file;\n}\n\n/** `accept` for a file input from the rules' types (plus the extensions browsers leave untyped). */\nexport function acceptOf(rules: readonly UploadRule[]): string | undefined {\n const types = [...new Set(rules.flatMap((r) => r.types))];\n if (!types.length) return undefined;\n const exts = Object.entries(BY_EXTENSION).filter(([, t]) => types.includes(t)).map(([e]) => `.${e}`);\n return [...types, ...exts].join(\",\");\n}\n\nexport interface Screened {\n /** Files to upload, each with its rule (typed by extension when needed). */\n accepted: { file: File; rule: UploadRule }[];\n /** Files the server would refuse, with the refusal it would answer. */\n refused: { file: File; error: ContentKitError }[];\n}\n\n/**\n * Checks files against the rules before any upload: a type some rule takes\n * (the first that does), its size, and the rule's file cap counting\n * have(rule) files already there. A rule without types, size or cap lets\n * that check through; the server decides.\n */\nexport function screenFiles(files: Iterable<File>, rules: readonly UploadRule[], have: (rule: UploadRule) => number = () => 0): Screened {\n const out: Screened = { accepted: [], refused: [] };\n const counts = new Map<UploadRule, number>();\n const allowed = [...new Set(rules.flatMap((r) => r.types))];\n for (const picked of files) {\n const file = withMediaType(picked, allowed);\n const rule = rules.find((r) => !r.types.length || r.types.includes(file.type));\n if (!rule) {\n const details: ErrorDetails = { type: file.type || undefined, allowed };\n out.refused.push({ file, error: new ContentKitError(\"type_not_allowed\", `${file.name}: type not allowed`, { status: 415, details }) });\n continue;\n }\n if (rule.max_bytes > 0 && file.size > rule.max_bytes) {\n const details: ErrorDetails = { type: file.type, size: file.size, max_bytes: rule.max_bytes };\n out.refused.push({ file, error: new ContentKitError(\"too_large\", `${file.name}: too large`, { status: 413, details }) });\n continue;\n }\n const n = counts.get(rule) ?? have(rule);\n if (rule.max && n >= rule.max) {\n const details: ErrorDetails = { max: rule.max };\n out.refused.push({ file, error: new ContentKitError(\"too_many_files\", `${file.name}: at most ${rule.max} files`, { status: 409, details }) });\n continue;\n }\n counts.set(rule, n + 1);\n out.accepted.push({ file, rule });\n }\n return out;\n}\n\n/** name, or name-2, name-3… so its stem is not among taken (names or paths without the directory). */\nexport function uniqueName(name: string, taken: Iterable<string>): string {\n const stems = new Set([...taken].map(stem));\n if (!stems.has(stem(name))) return name;\n const dot = name.lastIndexOf(\".\");\n const base = dot > 0 ? name.slice(0, dot) : name;\n const ext = dot > 0 ? name.slice(dot) : \"\";\n for (let n = 2; ; n++) {\n const candidate = `${base}-${n}${ext}`;\n if (!stems.has(stem(candidate))) return candidate;\n }\n}\n\n/** \"16:9\" style label of a width/height ratio: 2.4 → \"2.4:1\", 0.4167 → \"1:2.4\". */\nexport function ratioLabel(r: number): string {\n const round = (v: number) => String(Math.round(v * 100) / 100);\n return r >= 1 ? `${round(r)}:1` : `1:${round(1 / r)}`;\n}\n\n/** The kind's public preset for an upload path: the one named name, else the first with an aspect, else the first. */\nexport function presetFor(presets: readonly PresetRule[], kind: string, path: string, name?: string): PresetRule | undefined {\n const at = presets.filter((p) => p.kind === kind && ruleFor([{ path: p.from }], path));\n return (name ? at.find((p) => p.name === name) : undefined) ?? at.find((p) => p.aspect) ?? at[0];\n}\n\n/**\n * The kind's default image for a preset, at every width: what the gateway\n * serves for an item without its own (a URL from the template never names a\n * current file). null when the preset has no default (`rule.default`).\n */\nexport function defaultImage(rule: PresetRule, id: string): PublicPreset | null {\n if (!rule.default || rule.first || rule.to.includes(NAME)) return null;\n return logicalImage(rule, id);\n}\n\n/**\n * A Stable preset's image of an item (`rule.stable`, e.g. the content\n * model's `avatars`): URLs built from the id that show its current image,\n * else the default. null for any other preset.\n */\nexport function stableImage(rule: PresetRule, id: string): PublicPreset | null {\n return rule.stable ? logicalImage(rule, id) : null;\n}\n\nfunction logicalImage(rule: PresetRule, id: string): PublicPreset {\n const r = ratio(rule.aspect);\n return {\n preset: rule.name,\n aspect: rule.aspect,\n renditions: rule.widths.map((w) => ({ url: publicURL(rule.base, rule.namespace, rule.kind, id, fill(rule.to, { w })), w, ...(r ? { h: Math.round(w / r) } : {}) })),\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rules.js","names":[],"sources":["../../../src/client/media/rules.ts"],"sourcesContent":["import { ContentKitError } from \"../errors.js\";\nimport type { ErrorDetails, PresetRule, ReadResult, UploadRule } from \"../generated/wire.js\";\nimport { fill, publicURL, type PublicPreset } from \"../public.js\";\nimport { ratio } from \"../aspect.js\";\nimport { stem } from \"./client.js\";\n\nconst NO_RULES: UploadRule[] = [];\n\n/** An editor read's upload rules (a viewer read has none): one empty list, so memos keyed on them hold. */\nexport const uploadRules = (read: ReadResult | null | undefined): UploadRule[] => read?.uploads ?? NO_RULES;\n\nconst NAME = \"{name}\";\n\n/** A pattern path (\"originals/{name}\") holds many files; a literal (\"cover\") one. */\nexport const isPattern = (path: string) => path.endsWith(NAME);\n\n/** The directory of a pattern (\"originals/\"), or the literal itself. */\nexport const ruleDir = (path: string) => (isPattern(path) ? path.slice(0, -NAME.length) : path);\n\n/** The rule an upload path (with or without its extension) falls under: a literal wins over a pattern. */\nexport function ruleFor<R extends { path: string }>(rules: readonly R[], path: string): R | undefined {\n const s = stem(path);\n return (\n rules.find((r) => !isPattern(r.path) && r.path === s) ??\n rules.find((r) => {\n if (!isPattern(r.path)) return false;\n const dir = ruleDir(r.path);\n return s.startsWith(dir) && s.length > dir.length && !s.slice(dir.length).includes(\"/\");\n })\n );\n}\n\n/** Uploads of the read under rule (attached, in manifest order). */\nexport function filesFor(read: ReadResult | null | undefined, rule: { path: string }, rules: readonly { path: string }[] = [rule]) {\n return (read?.files ?? []).filter((f) => f.upload && !f.unattached && ruleFor(rules, f.path)?.path === rule.path);\n}\n\nconst BY_EXTENSION: Record<string, string> = {\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n webp: \"image/webp\",\n gif: \"image/gif\",\n avif: \"image/avif\",\n mp4: \"video/mp4\",\n m4v: \"video/mp4\",\n mov: \"video/quicktime\",\n mkv: \"video/x-matroska\",\n webm: \"video/webm\",\n m4a: \"audio/mp4\",\n mp3: \"audio/mpeg\",\n vtt: \"text/vtt\",\n srt: \"application/x-subrip\",\n ass: \"text/x-ass\",\n ssa: \"text/x-ssa\",\n zip: \"application/zip\",\n};\n\n/** The file with a content type from its extension when the browser left it empty or nonstandard (.mkv, .mov, .srt). */\nexport function withMediaType(file: File, allowed?: readonly string[]): File {\n if (file.type && (!allowed || allowed.includes(file.type))) return file;\n const type = BY_EXTENSION[file.name.split(\".\").pop()?.toLowerCase() ?? \"\"];\n return type && type !== file.type ? new File([file], file.name, { type, lastModified: file.lastModified }) : file;\n}\n\n/** `accept` for a file input from the rules' types (plus the extensions browsers leave untyped). */\nexport function acceptOf(rules: readonly UploadRule[]): string | undefined {\n const types = [...new Set(rules.flatMap((r) => r.types))];\n if (!types.length) return undefined;\n const exts = Object.entries(BY_EXTENSION).filter(([, t]) => types.includes(t)).map(([e]) => `.${e}`);\n return [...types, ...exts].join(\",\");\n}\n\nexport interface Screened {\n /** Files to upload, each with its rule (typed by extension when needed). */\n accepted: { file: File; rule: UploadRule }[];\n /** Files the server would refuse, with the refusal it would answer. */\n refused: { file: File; error: ContentKitError }[];\n}\n\n/**\n * Checks files against the rules before any upload: a type some rule takes\n * (the first that does), its size, and the rule's file cap counting\n * have(rule) files already there. A rule without types, size or cap lets\n * that check through; the server decides.\n */\nexport function screenFiles(files: Iterable<File>, rules: readonly UploadRule[], have: (rule: UploadRule) => number = () => 0): Screened {\n const out: Screened = { accepted: [], refused: [] };\n const counts = new Map<UploadRule, number>();\n const allowed = [...new Set(rules.flatMap((r) => r.types))];\n for (const picked of files) {\n const file = withMediaType(picked, allowed);\n const rule = rules.find((r) => !r.types.length || r.types.includes(file.type));\n if (!rule) {\n const details: ErrorDetails = { type: file.type || undefined, allowed };\n out.refused.push({ file, error: new ContentKitError(\"type_not_allowed\", `${file.name}: type not allowed`, { status: 415, details }) });\n continue;\n }\n if (rule.max_bytes > 0 && file.size > rule.max_bytes) {\n const details: ErrorDetails = { type: file.type, size: file.size, max_bytes: rule.max_bytes };\n out.refused.push({ file, error: new ContentKitError(\"too_large\", `${file.name}: too large`, { status: 413, details }) });\n continue;\n }\n const n = counts.get(rule) ?? have(rule);\n if (rule.max && n >= rule.max) {\n const details: ErrorDetails = { max: rule.max };\n out.refused.push({ file, error: new ContentKitError(\"too_many_files\", `${file.name}: at most ${rule.max} files`, { status: 409, details }) });\n continue;\n }\n counts.set(rule, n + 1);\n out.accepted.push({ file, rule });\n }\n return out;\n}\n\n/** name, or name-2, name-3… so its stem is not among taken (names or paths without the directory). */\nexport function uniqueName(name: string, taken: Iterable<string>): string {\n const stems = new Set([...taken].map(stem));\n if (!stems.has(stem(name))) return name;\n const dot = name.lastIndexOf(\".\");\n const base = dot > 0 ? name.slice(0, dot) : name;\n const ext = dot > 0 ? name.slice(dot) : \"\";\n for (let n = 2; ; n++) {\n const candidate = `${base}-${n}${ext}`;\n if (!stems.has(stem(candidate))) return candidate;\n }\n}\n\n/** \"16:9\" style label of a width/height ratio: 2.4 → \"2.4:1\", 0.4167 → \"1:2.4\". */\nexport function ratioLabel(r: number): string {\n const round = (v: number) => String(Math.round(v * 100) / 100);\n return r >= 1 ? `${round(r)}:1` : `1:${round(1 / r)}`;\n}\n\n/** The kind's public preset for an upload path: the one named name, else the first with an aspect, else the first. */\nexport function presetFor(presets: readonly PresetRule[], kind: string, path: string, name?: string): PresetRule | undefined {\n const at = presets.filter((p) => p.kind === kind && ruleFor([{ path: p.from }], path));\n return (name ? at.find((p) => p.name === name) : undefined) ?? at.find((p) => p.aspect) ?? at[0];\n}\n\n/**\n * The kind's default image for a preset, at every width: what the gateway\n * serves for an item without its own (a URL from the template never names a\n * current file). null when the preset has no default (`rule.default`).\n */\nexport function defaultImage(rule: PresetRule, id: string, version?: string): PublicPreset | null {\n if (!rule.default || rule.first || rule.to.includes(NAME)) return null;\n return logicalImage(rule, id, version);\n}\n\n/**\n * A Stable preset's image of an item (`rule.stable`, e.g. the content\n * model's `avatars`): URLs built from the id that show its current image,\n * else the default. null for any other preset.\n */\nexport function stableImage(rule: PresetRule, id: string): PublicPreset | null {\n return rule.stable ? logicalImage(rule, id) : null;\n}\n\nfunction logicalImage(rule: PresetRule, id: string, version?: string): PublicPreset {\n const r = ratio(rule.aspect);\n return {\n preset: rule.name,\n aspect: rule.aspect,\n renditions: rule.widths.map((w) => ({ url: publicURL(rule.base, rule.namespace, rule.kind, id, fill(rule.to, { w }), version), w, ...(r ? { h: Math.round(w / r) } : {}) })),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RequestReply } from '../generated/wire.js';
|
|
2
2
|
/**
|
|
3
3
|
* Sends a presigned request with its body. Resolves on 2xx; rejects with an
|
|
4
|
-
* ContentKitError (storage, network or aborted). onProgress reports bytes sent.
|
|
4
|
+
* ContentKitError (storage, network, server_unavailable or aborted). onProgress reports bytes sent.
|
|
5
5
|
*/
|
|
6
6
|
export type Transport = (req: RequestReply, body: Blob, opts: {
|
|
7
7
|
signal?: AbortSignal;
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { ContentKitError as e, aborted as t } from "../errors.js";
|
|
1
|
+
import { ContentKitError as e, aborted as t, requestFailure as n } from "../errors.js";
|
|
2
2
|
//#region src/client/media/transport.ts
|
|
3
|
-
var
|
|
3
|
+
var r = (e, t, n) => typeof XMLHttpRequest > "u" ? a(e, t, n) : i(e, t, n), i = (n, r, { signal: i, onProgress: a }) => new Promise((s, c) => {
|
|
4
4
|
if (i?.aborted) return c(t(i));
|
|
5
5
|
let l = new XMLHttpRequest(), u = () => l.abort(), d = (e) => {
|
|
6
6
|
i?.removeEventListener("abort", u), e ? c(e) : s();
|
|
7
7
|
};
|
|
8
8
|
l.open(n.method, n.url);
|
|
9
9
|
for (let [e, t] of Object.entries(n.headers)) l.setRequestHeader(e, t);
|
|
10
|
-
l.upload.onprogress = (e) =>
|
|
11
|
-
}),
|
|
12
|
-
let
|
|
10
|
+
l.upload.onprogress = (e) => a?.(e.loaded), l.onload = () => d(l.status >= 200 && l.status < 300 ? void 0 : o(l.status, l.responseText)), l.onerror = () => d(new e("network", "connection to storage failed")), l.ontimeout = () => d(new e("server_unavailable", "storage did not respond")), l.onabort = () => d(t(i)), i?.addEventListener("abort", u, { once: !0 }), l.send(r);
|
|
11
|
+
}), a = async (e, t, { signal: r, onProgress: i }) => {
|
|
12
|
+
let a;
|
|
13
13
|
try {
|
|
14
|
-
|
|
15
|
-
method:
|
|
16
|
-
headers:
|
|
17
|
-
body:
|
|
18
|
-
signal:
|
|
14
|
+
a = await fetch(e.url, {
|
|
15
|
+
method: e.method,
|
|
16
|
+
headers: e.headers,
|
|
17
|
+
body: t,
|
|
18
|
+
signal: r ?? null
|
|
19
19
|
});
|
|
20
|
-
} catch (
|
|
21
|
-
throw
|
|
20
|
+
} catch (e) {
|
|
21
|
+
throw n(e, r, "storage");
|
|
22
22
|
}
|
|
23
|
-
if (!
|
|
24
|
-
await
|
|
23
|
+
if (!a.ok) throw o(a.status, await a.text().catch(() => ""));
|
|
24
|
+
await a.body?.cancel(), i?.(t.size);
|
|
25
25
|
};
|
|
26
|
-
function
|
|
26
|
+
function o(t, n) {
|
|
27
27
|
let r = /<Code>([^<]+)<\/Code>/.exec(n)?.[1];
|
|
28
28
|
return new e("storage", `storage refused the upload (${t}${r ? " " + r : ""})`, { status: t });
|
|
29
29
|
}
|
|
30
30
|
//#endregion
|
|
31
|
-
export {
|
|
31
|
+
export { r as defaultTransport, a as fetchTransport, i as xhrTransport };
|
|
32
32
|
|
|
33
33
|
//# sourceMappingURL=transport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","names":[],"sources":["../../../src/client/media/transport.ts"],"sourcesContent":["import { ContentKitError, aborted } from \"../errors.js\";\nimport type { RequestReply } from \"../generated/wire.js\";\n\n/**\n * Sends a presigned request with its body. Resolves on 2xx; rejects with an\n * ContentKitError (storage, network or aborted). onProgress reports bytes sent.\n */\nexport type Transport = (\n req: RequestReply,\n body: Blob,\n opts: { signal?: AbortSignal; onProgress?: (sent: number) => void },\n) => Promise<void>;\n\n/** XMLHttpRequest when available (upload progress), otherwise fetch. */\nexport const defaultTransport: Transport = (req, body, opts) =>\n typeof XMLHttpRequest === \"undefined\" ? fetchTransport(req, body, opts) : xhrTransport(req, body, opts);\n\nexport const xhrTransport: Transport = (req, body, { signal, onProgress }) =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(aborted(signal));\n const xhr = new XMLHttpRequest();\n const onAbort = () => xhr.abort();\n const done = (err?: ContentKitError) => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (err) reject(err);\n else resolve();\n };\n xhr.open(req.method, req.url);\n for (const [k, v] of Object.entries(req.headers)) xhr.setRequestHeader(k, v);\n xhr.upload.onprogress = (e) => onProgress?.(e.loaded);\n xhr.onload = () =>\n done(xhr.status >= 200 && xhr.status < 300 ? undefined : storageError(xhr.status, xhr.responseText));\n xhr.onerror = () => done(new ContentKitError(\"network\", \"connection to storage failed\"));\n xhr.ontimeout =
|
|
1
|
+
{"version":3,"file":"transport.js","names":[],"sources":["../../../src/client/media/transport.ts"],"sourcesContent":["import { ContentKitError, aborted, requestFailure } from \"../errors.js\";\nimport type { RequestReply } from \"../generated/wire.js\";\n\n/**\n * Sends a presigned request with its body. Resolves on 2xx; rejects with an\n * ContentKitError (storage, network, server_unavailable or aborted). onProgress reports bytes sent.\n */\nexport type Transport = (\n req: RequestReply,\n body: Blob,\n opts: { signal?: AbortSignal; onProgress?: (sent: number) => void },\n) => Promise<void>;\n\n/** XMLHttpRequest when available (upload progress), otherwise fetch. */\nexport const defaultTransport: Transport = (req, body, opts) =>\n typeof XMLHttpRequest === \"undefined\" ? fetchTransport(req, body, opts) : xhrTransport(req, body, opts);\n\nexport const xhrTransport: Transport = (req, body, { signal, onProgress }) =>\n new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(aborted(signal));\n const xhr = new XMLHttpRequest();\n const onAbort = () => xhr.abort();\n const done = (err?: ContentKitError) => {\n signal?.removeEventListener(\"abort\", onAbort);\n if (err) reject(err);\n else resolve();\n };\n xhr.open(req.method, req.url);\n for (const [k, v] of Object.entries(req.headers)) xhr.setRequestHeader(k, v);\n xhr.upload.onprogress = (e) => onProgress?.(e.loaded);\n xhr.onload = () =>\n done(xhr.status >= 200 && xhr.status < 300 ? undefined : storageError(xhr.status, xhr.responseText));\n xhr.onerror = () => done(new ContentKitError(\"network\", \"connection to storage failed\"));\n xhr.ontimeout = () => done(new ContentKitError(\"server_unavailable\", \"storage did not respond\"));\n xhr.onabort = () => done(aborted(signal));\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n xhr.send(body);\n });\n\nexport const fetchTransport: Transport = async (req, body, { signal, onProgress }) => {\n let res: Response;\n try {\n res = await fetch(req.url, { method: req.method, headers: req.headers, body, signal: signal ?? null });\n } catch (err) {\n throw requestFailure(err, signal, \"storage\");\n }\n if (!res.ok) throw storageError(res.status, await res.text().catch(() => \"\"));\n await res.body?.cancel();\n onProgress?.(body.size);\n};\n\nfunction storageError(status: number, body: string): ContentKitError {\n const code = /<Code>([^<]+)<\\/Code>/.exec(body)?.[1];\n return new ContentKitError(\"storage\", `storage refused the upload (${status}${code ? \" \" + code : \"\"})`, { status });\n}\n"],"mappings":";;AAcA,IAAa,KAA+B,GAAK,GAAM,MACrD,OAAO,iBAAmB,MAAc,EAAe,GAAK,GAAM,CAAI,IAAI,EAAa,GAAK,GAAM,CAAI,GAE3F,KAA2B,GAAK,GAAM,EAAE,WAAQ,oBAC3D,IAAI,SAAS,GAAS,MAAW;CAC/B,IAAI,GAAQ,SAAS,OAAO,EAAO,EAAQ,CAAM,CAAC;CAClD,IAAM,IAAM,IAAI,eAAe,GACzB,UAAgB,EAAI,MAAM,GAC1B,KAAQ,MAA0B;EAEtC,AADA,GAAQ,oBAAoB,SAAS,CAAO,GACxC,IAAK,EAAO,CAAG,IACd,EAAQ;CACf;CACA,EAAI,KAAK,EAAI,QAAQ,EAAI,GAAG;CAC5B,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,EAAI,OAAO,GAAG,EAAI,iBAAiB,GAAG,CAAC;CAQ3E,AAPA,EAAI,OAAO,cAAc,MAAM,IAAa,EAAE,MAAM,GACpD,EAAI,eACF,EAAK,EAAI,UAAU,OAAO,EAAI,SAAS,MAAM,KAAA,IAAY,EAAa,EAAI,QAAQ,EAAI,YAAY,CAAC,GACrG,EAAI,gBAAgB,EAAK,IAAI,EAAgB,WAAW,8BAA8B,CAAC,GACvF,EAAI,kBAAkB,EAAK,IAAI,EAAgB,sBAAsB,yBAAyB,CAAC,GAC/F,EAAI,gBAAgB,EAAK,EAAQ,CAAM,CAAC,GACxC,GAAQ,iBAAiB,SAAS,GAAS,EAAE,MAAM,GAAK,CAAC,GACzD,EAAI,KAAK,CAAI;AACf,CAAC,GAEU,IAA4B,OAAO,GAAK,GAAM,EAAE,WAAQ,oBAAiB;CACpF,IAAI;CACJ,IAAI;EACF,IAAM,MAAM,MAAM,EAAI,KAAK;GAAE,QAAQ,EAAI;GAAQ,SAAS,EAAI;GAAS;GAAM,QAAQ,KAAU;EAAK,CAAC;CACvG,SAAS,GAAK;EACZ,MAAM,EAAe,GAAK,GAAQ,SAAS;CAC7C;CACA,IAAI,CAAC,EAAI,IAAI,MAAM,EAAa,EAAI,QAAQ,MAAM,EAAI,KAAK,CAAC,CAAC,YAAY,EAAE,CAAC;CAE5E,AADA,MAAM,EAAI,MAAM,OAAO,GACvB,IAAa,EAAK,IAAI;AACxB;AAEA,SAAS,EAAa,GAAgB,GAA+B;CACnE,IAAM,IAAO,wBAAwB,KAAK,CAAI,CAAC,GAAG;CAClD,OAAO,IAAI,EAAgB,WAAW,+BAA+B,IAAS,IAAO,MAAM,IAAO,GAAG,IAAI,EAAE,UAAO,CAAC;AACrH"}
|
package/dist/client/public.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { AspectRatio } from './aspect.js';
|
|
2
2
|
import { Rendition } from './rendition.js';
|
|
3
3
|
/**
|
|
4
|
-
* A public file's URL, as media.PublicURL: `{base}/v1/{namespace}/{kind}/{id}/public/{name}`.
|
|
4
|
+
* A public file's URL, as media.PublicURL: `{base}/v1/{namespace}/{kind}/{id}[/{version}]/public/{name}`.
|
|
5
5
|
* Pass an actual published name, not a preset template for a current image.
|
|
6
6
|
*/
|
|
7
|
-
export declare function publicURL(base: string, namespace: string, kind: string, id: string, name: string): string;
|
|
7
|
+
export declare function publicURL(base: string, namespace: string, kind: string, id: string, name: string, version?: string): string;
|
|
8
8
|
/** Each `{key}` of template replaced by vars[key] ("" when missing), as the registry's templates fill. */
|
|
9
9
|
export declare function fill(template: string, vars: Record<string, string | number>): string;
|
|
10
10
|
/** A srcset from published URLs and their actual encoded widths. */
|
package/dist/client/public.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { sortRenditions as e } from "./rendition.js";
|
|
2
2
|
//#region src/client/public.ts
|
|
3
|
-
function t(e, t, n, r, i) {
|
|
4
|
-
return `${e.replace(/\/+$/, "")}/v1/${t}/${n}/${r}/public/${i}`;
|
|
3
|
+
function t(e, t, n, r, i, a) {
|
|
4
|
+
return `${e.replace(/\/+$/, "")}/v1/${t}/${n}/${r}${a ? `/${a}` : ""}/public/${i}`;
|
|
5
5
|
}
|
|
6
6
|
function n(e, t) {
|
|
7
7
|
return e.replace(/\{([^}]*)\}/g, (e, n) => n in t ? String(t[n]) : "");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public.js","names":[],"sources":["../../src/client/public.ts"],"sourcesContent":["import type { AspectRatio } from \"./aspect.js\";\nimport { sortRenditions, type Rendition } from \"./rendition.js\";\n\n/**\n * A public file's URL, as media.PublicURL: `{base}/v1/{namespace}/{kind}/{id}/public/{name}`.\n * Pass an actual published name, not a preset template for a current image.\n */\nexport function publicURL(base: string, namespace: string, kind: string, id: string, name: string): string {\n return `${base.replace(/\\/+$/, \"\")}/v1/${namespace}/${kind}/${id}/public/${name}`;\n}\n\n/** Each `{key}` of template replaced by vars[key] (\"\" when missing), as the registry's templates fill. */\nexport function fill(template: string, vars: Record<string, string | number>): string {\n return template.replace(/\\{([^}]*)\\}/g, (_, k: string) => (k in vars ? String(vars[k]) : \"\"));\n}\n\n/** A srcset from published URLs and their actual encoded widths. */\nexport function srcSet(renditions: readonly Rendition[]): string {\n return sortRenditions(renditions)\n .filter((r, i, all) => i === 0 || r.w !== all[i - 1]!.w)\n .map((r) => `${r.url} ${r.w}w`).join(\", \");\n}\n\n/**\n * A public preset at an item: what a slot or poster shows, with its current\n * renditions (from a read's `public`, or a host's authorized listing).\n */\nexport interface PublicPreset {\n preset: string;\n renditions: readonly Rendition[];\n /** The preset's \"W:H\"; \"\" or omitted is the source's own. */\n aspect?: AspectRatio;\n}\n\n/** Published files, narrowest first; sizes and filenames are never inferred. */\nexport function publicRenditions(p: PublicPreset | { renditions: readonly Rendition[] } | null | undefined): Rendition[] {\n if (!p) return [];\n return sortRenditions(p.renditions);\n}\n"],"mappings":";;AAOA,SAAgB,EAAU,GAAc,GAAmB,GAAc,GAAY,
|
|
1
|
+
{"version":3,"file":"public.js","names":[],"sources":["../../src/client/public.ts"],"sourcesContent":["import type { AspectRatio } from \"./aspect.js\";\nimport { sortRenditions, type Rendition } from \"./rendition.js\";\n\n/**\n * A public file's URL, as media.PublicURL: `{base}/v1/{namespace}/{kind}/{id}[/{version}]/public/{name}`.\n * Pass an actual published name, not a preset template for a current image.\n */\nexport function publicURL(base: string, namespace: string, kind: string, id: string, name: string, version?: string): string {\n return `${base.replace(/\\/+$/, \"\")}/v1/${namespace}/${kind}/${id}${version ? `/${version}` : \"\"}/public/${name}`;\n}\n\n/** Each `{key}` of template replaced by vars[key] (\"\" when missing), as the registry's templates fill. */\nexport function fill(template: string, vars: Record<string, string | number>): string {\n return template.replace(/\\{([^}]*)\\}/g, (_, k: string) => (k in vars ? String(vars[k]) : \"\"));\n}\n\n/** A srcset from published URLs and their actual encoded widths. */\nexport function srcSet(renditions: readonly Rendition[]): string {\n return sortRenditions(renditions)\n .filter((r, i, all) => i === 0 || r.w !== all[i - 1]!.w)\n .map((r) => `${r.url} ${r.w}w`).join(\", \");\n}\n\n/**\n * A public preset at an item: what a slot or poster shows, with its current\n * renditions (from a read's `public`, or a host's authorized listing).\n */\nexport interface PublicPreset {\n preset: string;\n renditions: readonly Rendition[];\n /** The preset's \"W:H\"; \"\" or omitted is the source's own. */\n aspect?: AspectRatio;\n}\n\n/** Published files, narrowest first; sizes and filenames are never inferred. */\nexport function publicRenditions(p: PublicPreset | { renditions: readonly Rendition[] } | null | undefined): Rendition[] {\n if (!p) return [];\n return sortRenditions(p.renditions);\n}\n"],"mappings":";;AAOA,SAAgB,EAAU,GAAc,GAAmB,GAAc,GAAY,GAAc,GAA0B;CAC3H,OAAO,GAAG,EAAK,QAAQ,QAAQ,EAAE,EAAE,MAAM,EAAU,GAAG,EAAK,GAAG,IAAK,IAAU,IAAI,MAAY,GAAG,UAAU;AAC5G;AAGA,SAAgB,EAAK,GAAkB,GAA+C;CACpF,OAAO,EAAS,QAAQ,iBAAiB,GAAG,MAAe,KAAK,IAAO,OAAO,EAAK,EAAE,IAAI,EAAG;AAC9F;AAGA,SAAgB,EAAO,GAA0C;CAC/D,OAAO,EAAe,CAAU,CAAC,CAC9B,QAAQ,GAAG,GAAG,MAAQ,MAAM,KAAK,EAAE,MAAM,EAAI,IAAI,EAAE,CAAE,CAAC,CAAC,CACvD,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI;AAC7C;AAcA,SAAgB,EAAiB,GAAwF;CAEvH,OADK,IACE,EAAe,EAAE,UAAU,IADnB,CAAC;AAElB"}
|
package/dist/client.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
import { DEFAULT_DENSITY as e, densityFor as t, pickRendition as n, sortRenditions as r } from "./client/rendition.js";
|
|
2
|
-
import { CLIENT_ERROR_CODES as i, ContentKitError as a, ERROR_CODES as o, failureError as s, isContentKitError as c, readContentKitError as l, toContentKitError as u } from "./client/errors.js";
|
|
3
|
-
import { fill as
|
|
4
|
-
import { aspectOf as
|
|
5
|
-
import { call as
|
|
6
|
-
import { checkRef as
|
|
7
|
-
import { MediaApi as
|
|
8
|
-
import { MAX_PART_SIZE as
|
|
9
|
-
import { sha256Hex as
|
|
10
|
-
import { Pacer as
|
|
11
|
-
import { defaultTransport as
|
|
12
|
-
import { MediaClient as
|
|
13
|
-
import { acceptOf as
|
|
14
|
-
import { centeredCrop as
|
|
15
|
-
import { encodeRemaining as
|
|
16
|
-
import { ItemUploadQueue as
|
|
17
|
-
import { decodeImage as
|
|
18
|
-
import { reactionVerb as
|
|
19
|
-
import { READ_CHUNK as
|
|
20
|
-
import { ABR_DEFAULTS as
|
|
21
|
-
import { formatDuration as
|
|
22
|
-
import { PLAYBACK_SPEEDS as
|
|
23
|
-
import { CatalogClient as
|
|
24
|
-
import { CodesClient as
|
|
25
|
-
import {
|
|
2
|
+
import { CLIENT_ERROR_CODES as i, ContentKitError as a, ERROR_CODES as o, failureError as s, isContentKitError as c, readContentKitError as l, toContentKitError as u, transportFailure as d } from "./client/errors.js";
|
|
3
|
+
import { fill as f, publicRenditions as p, publicURL as m, srcSet as h } from "./client/public.js";
|
|
4
|
+
import { aspectOf as g, ratio as _ } from "./client/aspect.js";
|
|
5
|
+
import { call as v, routeURL as y } from "./client/route.js";
|
|
6
|
+
import { checkRef as b, isContentId as x, itemKey as S, sameItem as C } from "./client/media/ref.js";
|
|
7
|
+
import { MediaApi as w } from "./client/media/api.js";
|
|
8
|
+
import { MAX_PART_SIZE as T, MAX_SINGLE_PUT as E, MIN_PART_SIZE as D } from "./client/generated/wire.js";
|
|
9
|
+
import { sha256Hex as O } from "./client/media/hash.js";
|
|
10
|
+
import { Pacer as k } from "./client/media/pacer.js";
|
|
11
|
+
import { defaultTransport as A, fetchTransport as j, xhrTransport as M } from "./client/media/transport.js";
|
|
12
|
+
import { MediaClient as N, backoff as P, samePath as F, stem as I } from "./client/media/client.js";
|
|
13
|
+
import { acceptOf as L, defaultImage as R, filesFor as z, isPattern as B, ratioLabel as V, ruleDir as H, ruleFor as U, screenFiles as W, stableImage as G, uniqueName as K, uploadRules as q, withMediaType as J } from "./client/media/rules.js";
|
|
14
|
+
import { centeredCrop as Y, constrainCrop as X, editOf as Z, editedSize as Q, fromRotated as $, rotation as ee, sameEdit as te, toOriginal as ne, toRotated as re } from "./client/crop.js";
|
|
15
|
+
import { encodeRemaining as ie } from "./client/media/encode.js";
|
|
16
|
+
import { ItemUploadQueue as ae } from "./client/media/queue.js";
|
|
17
|
+
import { decodeImage as oe, isAnimatedImage as se } from "./client/image.js";
|
|
18
|
+
import { reactionVerb as ce, sameTarget as le } from "./client/content/types.js";
|
|
19
|
+
import { READ_CHUNK as ue, chunkOffsets as de, isProcessing as fe, mergeReads as pe, processing as me } from "./client/media/windows.js";
|
|
20
|
+
import { ABR_DEFAULTS as he, NETWORK_FAILURES_BEFORE_ERROR as ge, REFRESH_BEFORE_EXPIRY as _e, abrHlsConfig as ve, capRung as ye, classifyHlsError as be, classifyMediaError as xe, expiryDelay as Se, hlsConfig as Ce, initialEstimate as we, refreshable as Te, startRung as Ee, statusKind as De } from "./client/playback.js";
|
|
21
|
+
import { formatDuration as Oe, galleryItems as ke, isAudioType as Ae, isImageType as je, isSubtitleType as Me, isVideoType as Ne, stageAspect as Pe } from "./client/gallery.js";
|
|
22
|
+
import { PLAYBACK_SPEEDS as Fe, PLAYER_TRACKS_KEY as Ie, PLAYER_VOLUME_KEY as Le, parseSpriteVtt as Re, playerKeyAction as ze, resumeAt as Be } from "./client/player.js";
|
|
23
|
+
import { CatalogClient as Ve } from "./client/catalog.js";
|
|
24
|
+
import { CodesClient as He } from "./client/codes.js";
|
|
25
|
+
import { ContentsClient as Ue, IMAGE_SCHEME as We, imageRef as Ge, imageRefs as Ke } from "./client/contents.js";
|
|
26
26
|
import { BansClient as qe } from "./client/content/bans.js";
|
|
27
27
|
import { CommentsClient as Je } from "./client/content/comments.js";
|
|
28
28
|
import { Beacons as Ye, eventId as Xe, readerSession as Ze } from "./client/beacons.js";
|
|
@@ -39,4 +39,4 @@ import { NotificationsClient as ct } from "./client/notifications.js";
|
|
|
39
39
|
import { createContentKitClient as lt } from "./client/client.js";
|
|
40
40
|
import { LETTERS as ut, attributeInput as dt, fold as ft, fromLocalInput as pt, humanize as mt, letterOf as ht, parseAttribute as gt, parseAttributes as _t, slugify as vt, toLocalInput as yt } from "./client/group-fields.js";
|
|
41
41
|
import { emptyReaderMeta as bt, matchAudio as xt, readerMetaProblems as St, readerNames as Ct } from "./client/reader-meta.js";
|
|
42
|
-
export {
|
|
42
|
+
export { he as ABR_DEFAULTS, qe as BansClient, Ye as Beacons, i as CLIENT_ERROR_CODES, Ve as CatalogClient, He as CodesClient, Je as CommentsClient, a as ContentKitError, Ue as ContentsClient, e as DEFAULT_DENSITY, Qe as DiscoveryClient, o as ERROR_CODES, $e as FavoritesClient, rt as GroupsClient, We as IMAGE_SCHEME, ae as ItemUploadQueue, ut as LETTERS, T as MAX_PART_SIZE, E as MAX_SINGLE_PUT, D as MIN_PART_SIZE, w as MediaApi, N as MediaClient, et as ModerationClient, ge as NETWORK_FAILURES_BEFORE_ERROR, ct as NotificationsClient, it as OffersClient, Fe as PLAYBACK_SPEEDS, Ie as PLAYER_TRACKS_KEY, Le as PLAYER_VOLUME_KEY, k as Pacer, tt as PollsClient, ue as READ_CHUNK, _e as REFRESH_BEFORE_EXPIRY, nt as ReactionsClient, at as StatsClient, ot as VersionsClient, ve as abrHlsConfig, L as acceptOf, g as aspectOf, dt as attributeInput, P as backoff, v as call, ye as capRung, Y as centeredCrop, b as checkRef, de as chunkOffsets, be as classifyHlsError, xe as classifyMediaError, X as constrainCrop, lt as createContentKitClient, oe as decodeImage, R as defaultImage, A as defaultTransport, t as densityFor, Z as editOf, Q as editedSize, bt as emptyReaderMeta, ie as encodeRemaining, Xe as eventId, Se as expiryDelay, s as failureError, j as fetchTransport, z as filesFor, f as fill, ft as fold, Oe as formatDuration, pt as fromLocalInput, $ as fromRotated, ke as galleryItems, Ce as hlsConfig, mt as humanize, Ge as imageRef, Ke as imageRefs, we as initialEstimate, se as isAnimatedImage, Ae as isAudioType, x as isContentId, c as isContentKitError, je as isImageType, B as isPattern, st as isPending, fe as isProcessing, Me as isSubtitleType, Ne as isVideoType, S as itemKey, ht as letterOf, xt as matchAudio, pe as mergeReads, gt as parseAttribute, _t as parseAttributes, Re as parseSpriteVtt, n as pickRendition, ze as playerKeyAction, me as processing, p as publicRenditions, m as publicURL, _ as ratio, V as ratioLabel, ce as reactionVerb, l as readContentKitError, St as readerMetaProblems, Ct as readerNames, Ze as readerSession, Te as refreshable, Be as resumeAt, ee as rotation, y as routeURL, H as ruleDir, U as ruleFor, te as sameEdit, C as sameItem, F as samePath, le as sameTarget, W as screenFiles, O as sha256Hex, vt as slugify, r as sortRenditions, h as srcSet, G as stableImage, Pe as stageAspect, Ee as startRung, De as statusKind, I as stem, u as toContentKitError, yt as toLocalInput, ne as toOriginal, re as toRotated, d as transportFailure, K as uniqueName, q as uploadRules, J as withMediaType, M as xhrTransport };
|