@mohasinac/appkit 4.42.6 → 4.42.8
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/utils/media-url.js +44 -0
- package/package.json +1 -1
package/dist/utils/media-url.js
CHANGED
|
@@ -64,6 +64,33 @@ export const MEDIA_URL_MESSAGE = "Must be a stored media reference (/media/<slug
|
|
|
64
64
|
* validated before stops validating now.
|
|
65
65
|
*/
|
|
66
66
|
export function isStoredMediaRef(value) {
|
|
67
|
+
/*
|
|
68
|
+
* 🛑 Type-guard first: this predicate is reached through `.refine()` from two
|
|
69
|
+
* schemas and from several hand-written call sites, so it receives whatever
|
|
70
|
+
* the document actually holds — not whatever the signature says.
|
|
71
|
+
*
|
|
72
|
+
* Without this line a non-string reached `value.startsWith(...)` and threw
|
|
73
|
+
* `TypeError: e.startsWith is not a function`, which killed the whole render
|
|
74
|
+
* of the panel it was validating. Measured on production 2026-10-02: expanding
|
|
75
|
+
* the Branding section of /admin/site threw exactly that and the section body
|
|
76
|
+
* never appeared — so the Site Settings editor looked like it rendered no
|
|
77
|
+
* fields for ANY section, and five checklist cases were blocked behind what
|
|
78
|
+
* read as a missing feature.
|
|
79
|
+
*
|
|
80
|
+
* `!value` already caught null/undefined/"" and 0; an object or an array is
|
|
81
|
+
* truthy with `length === undefined`, so `undefined > MAX` is false and
|
|
82
|
+
* execution fell straight through to `.startsWith`.
|
|
83
|
+
*
|
|
84
|
+
* A VALIDATOR MUST REJECT, NEVER THROW. Returning false is the correct answer
|
|
85
|
+
* for a non-string, and the warn keeps the real defect findable — some caller
|
|
86
|
+
* is passing the wrong shape (a `{ url }` object where its `.url` was meant
|
|
87
|
+
* is the obvious candidate) and that is a separate fix at the call site.
|
|
88
|
+
*/
|
|
89
|
+
if (typeof value !== "string") {
|
|
90
|
+
// eslint-disable-next-line no-console -- client-side; the server path has its own recorder
|
|
91
|
+
console.warn("[isStoredMediaRef] expected a string, received", Object.prototype.toString.call(value));
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
67
94
|
if (!value || value.length > MEDIA_URL_MAX_LENGTH)
|
|
68
95
|
return false;
|
|
69
96
|
if (value.startsWith(MEDIA_PROXY_PREFIX))
|
|
@@ -102,6 +129,23 @@ const OWN_STORAGE_BUCKET = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET ?? ""
|
|
|
102
129
|
export function resolveMediaUrl(url, opts) {
|
|
103
130
|
if (!url)
|
|
104
131
|
return undefined;
|
|
132
|
+
/*
|
|
133
|
+
* 🛑 Same type-guard as `isStoredMediaRef`, and for the same reason: this is a
|
|
134
|
+
* RENDER-path helper called from `MediaImage`, every avatar, every logo and
|
|
135
|
+
* every card, with whatever the document happens to hold. `!url` catches
|
|
136
|
+
* null/undefined/""; an object or array is truthy and falls straight through
|
|
137
|
+
* to `.startsWith`, throwing `TypeError: e.startsWith is not a function` and
|
|
138
|
+
* taking out the whole subtree it was rendering.
|
|
139
|
+
*
|
|
140
|
+
* Returning undefined is the documented behaviour for a falsy input and is the
|
|
141
|
+
* right answer here too — the caller renders its placeholder instead of
|
|
142
|
+
* crashing. The warn names the shape so the real caller stays findable.
|
|
143
|
+
*/
|
|
144
|
+
if (typeof url !== "string") {
|
|
145
|
+
// eslint-disable-next-line no-console -- render path; a throw here kills the subtree
|
|
146
|
+
console.warn("[resolveMediaUrl] expected a string, received", Object.prototype.toString.call(url));
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
105
149
|
if (url.startsWith(PROXY_PREFIX))
|
|
106
150
|
return url;
|
|
107
151
|
// A blob:/data: URI is only ever valid in the tab that created it (e.g. a
|