@zalkera/client 0.21.5 → 0.21.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +35 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -12
- package/dist/index.d.ts +0 -12
- package/dist/index.js +35 -3
- package/dist/index.js.map +1 -1
- package/llms.txt +5 -5
- package/package.json +65 -65
package/dist/index.d.cts
CHANGED
|
@@ -1158,18 +1158,6 @@ declare function asHandle(value: unknown): string | undefined;
|
|
|
1158
1158
|
* (자기 카탈로그 안의 자기 handle — 정당하다)을 배열로 들고 다닐 때 여전히 쓰이기 때문이다.
|
|
1159
1159
|
*/
|
|
1160
1160
|
declare function asHandleArray(value: unknown): string[];
|
|
1161
|
-
/**
|
|
1162
|
-
* 레포 `public/` 에이셋 경로. **루트 절대 경로만** 통과한다.
|
|
1163
|
-
*
|
|
1164
|
-
* 왜 `safeLinkUrl` 을 그대로 안 쓰는가: 링크는 외부로 나가는 것이 정당하지만(스킴 허용목록),
|
|
1165
|
-
* 이 값은 `<img src>` 로 들어가는 **레포 안 파일 참조**다. 원격 호스트를 허용하면 ⑴ 개시된 사이트가
|
|
1166
|
-
* 남의 서버에 의존해 조용히 깨지고 ⑵ 방문자 IP·리퍼러가 그 호스트로 새며 ⑶ `data:`·`javascript:`
|
|
1167
|
-
* 가 같은 구멍으로 들어온다. 원격 이미지가 필요한 레포는 계약 영역이 아니라 자유 영역에서 자기
|
|
1168
|
-
* 컴포넌트로 그린다 — 계약이 자유를 막지는 않되, 계약이 보증하는 범위는 좁게 잡는다.
|
|
1169
|
-
*
|
|
1170
|
-
* 막는 것: 스킴 있는 URL(`http:`·`data:`·`javascript:`) · 스킴 상대(`//host`) · 상대 경로 ·
|
|
1171
|
-
* 경로 탈출(`..`) · 역슬래시(윈도 경로·정규화 우회) · 널바이트. **절대 throw 하지 않는다.**
|
|
1172
|
-
*/
|
|
1173
1161
|
declare function assetPath(value: unknown): string | undefined;
|
|
1174
1162
|
|
|
1175
1163
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1158,18 +1158,6 @@ declare function asHandle(value: unknown): string | undefined;
|
|
|
1158
1158
|
* (자기 카탈로그 안의 자기 handle — 정당하다)을 배열로 들고 다닐 때 여전히 쓰이기 때문이다.
|
|
1159
1159
|
*/
|
|
1160
1160
|
declare function asHandleArray(value: unknown): string[];
|
|
1161
|
-
/**
|
|
1162
|
-
* 레포 `public/` 에이셋 경로. **루트 절대 경로만** 통과한다.
|
|
1163
|
-
*
|
|
1164
|
-
* 왜 `safeLinkUrl` 을 그대로 안 쓰는가: 링크는 외부로 나가는 것이 정당하지만(스킴 허용목록),
|
|
1165
|
-
* 이 값은 `<img src>` 로 들어가는 **레포 안 파일 참조**다. 원격 호스트를 허용하면 ⑴ 개시된 사이트가
|
|
1166
|
-
* 남의 서버에 의존해 조용히 깨지고 ⑵ 방문자 IP·리퍼러가 그 호스트로 새며 ⑶ `data:`·`javascript:`
|
|
1167
|
-
* 가 같은 구멍으로 들어온다. 원격 이미지가 필요한 레포는 계약 영역이 아니라 자유 영역에서 자기
|
|
1168
|
-
* 컴포넌트로 그린다 — 계약이 자유를 막지는 않되, 계약이 보증하는 범위는 좁게 잡는다.
|
|
1169
|
-
*
|
|
1170
|
-
* 막는 것: 스킴 있는 URL(`http:`·`data:`·`javascript:`) · 스킴 상대(`//host`) · 상대 경로 ·
|
|
1171
|
-
* 경로 탈출(`..`) · 역슬래시(윈도 경로·정규화 우회) · 널바이트. **절대 throw 하지 않는다.**
|
|
1172
|
-
*/
|
|
1173
1161
|
declare function assetPath(value: unknown): string | undefined;
|
|
1174
1162
|
|
|
1175
1163
|
/**
|
package/dist/index.js
CHANGED
|
@@ -327,15 +327,37 @@ function sectionsOfVertical(vertical) {
|
|
|
327
327
|
|
|
328
328
|
// src/safeUrl.ts
|
|
329
329
|
var ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["http:", "https:", "mailto:", "tel:"]);
|
|
330
|
+
var DUMMY_ORIGIN = "https://zalkera.invalid";
|
|
331
|
+
function internalPath(raw) {
|
|
332
|
+
let out;
|
|
333
|
+
try {
|
|
334
|
+
const parsed = new URL(raw, DUMMY_ORIGIN);
|
|
335
|
+
if (parsed.origin !== DUMMY_ORIGIN) return null;
|
|
336
|
+
out = parsed.pathname + parsed.search + parsed.hash;
|
|
337
|
+
} catch {
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
if (new URL(out, DUMMY_ORIGIN).origin !== DUMMY_ORIGIN) return null;
|
|
342
|
+
} catch {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
return out;
|
|
346
|
+
}
|
|
330
347
|
function safeLinkUrl(raw) {
|
|
331
348
|
if (!raw) return "#";
|
|
332
349
|
const url = raw.trim();
|
|
333
|
-
if (url.startsWith("
|
|
350
|
+
if (url.startsWith("#") || url.startsWith("?")) return url;
|
|
351
|
+
if (url.startsWith("/")) return internalPath(url) ?? "#";
|
|
334
352
|
try {
|
|
335
353
|
const parsed = new URL(url);
|
|
336
354
|
return ALLOWED_SCHEMES.has(parsed.protocol) ? url : "#";
|
|
337
355
|
} catch {
|
|
338
|
-
|
|
356
|
+
try {
|
|
357
|
+
return internalPath(url) ?? "#";
|
|
358
|
+
} catch {
|
|
359
|
+
return "#";
|
|
360
|
+
}
|
|
339
361
|
}
|
|
340
362
|
}
|
|
341
363
|
|
|
@@ -407,13 +429,23 @@ function asHandleArray(value) {
|
|
|
407
429
|
if (!Array.isArray(value)) return [];
|
|
408
430
|
return value.map(asHandle).filter((h) => h !== void 0);
|
|
409
431
|
}
|
|
432
|
+
var ASSET_DUMMY_ORIGIN = "https://zalkera.invalid";
|
|
410
433
|
function assetPath(value) {
|
|
411
434
|
if (typeof value !== "string") return void 0;
|
|
412
435
|
const path = value.trim();
|
|
413
436
|
if (!path.startsWith("/") || path.startsWith("//")) return void 0;
|
|
414
437
|
if (path.includes("\\") || path.includes("\0")) return void 0;
|
|
415
438
|
if (path.split("/").includes("..")) return void 0;
|
|
416
|
-
|
|
439
|
+
let parsed;
|
|
440
|
+
try {
|
|
441
|
+
parsed = new URL(path, ASSET_DUMMY_ORIGIN);
|
|
442
|
+
} catch {
|
|
443
|
+
return void 0;
|
|
444
|
+
}
|
|
445
|
+
if (parsed.origin !== ASSET_DUMMY_ORIGIN) return void 0;
|
|
446
|
+
const out = parsed.pathname + parsed.search + parsed.hash;
|
|
447
|
+
if (!out.startsWith("/") || out.startsWith("//")) return void 0;
|
|
448
|
+
return out;
|
|
417
449
|
}
|
|
418
450
|
|
|
419
451
|
// src/theme.ts
|