@shipstatic/types 0.7.3 → 0.7.5
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.d.ts +25 -2
- package/dist/index.js +31 -2
- package/package.json +2 -1
- package/src/index.ts +34 -2
package/dist/index.d.ts
CHANGED
|
@@ -389,15 +389,38 @@ export declare const BLOCKED_EXTENSIONS: ReadonlySet<string>;
|
|
|
389
389
|
*/
|
|
390
390
|
export declare function isBlockedExtension(filename: string): boolean;
|
|
391
391
|
/**
|
|
392
|
-
*
|
|
392
|
+
* Characters that are unsafe in filenames for static hosting.
|
|
393
|
+
*
|
|
394
|
+
* Blocks only characters that genuinely break the upload→serve round-trip:
|
|
395
|
+
* - # ? % URL round-trip breakers (fragment, query, encoding ambiguity)
|
|
396
|
+
* - \ Path separator confusion (upload splits on backslash)
|
|
397
|
+
* - < > " XSS vectors with zero legitimate use in filenames
|
|
398
|
+
* - \x00-\x1f \x7f Control characters (header injection, display corruption)
|
|
399
|
+
*
|
|
400
|
+
* Everything else is allowed — browser percent-encodes, Worker decodes, R2 matches.
|
|
401
|
+
*/
|
|
402
|
+
export declare const UNSAFE_FILENAME_CHARS: RegExp;
|
|
403
|
+
/**
|
|
404
|
+
* Check if a filename contains unsafe characters.
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* hasUnsafeChars('saved_resource(1).html') // false — parentheses are safe
|
|
408
|
+
* hasUnsafeChars('page[slug].js') // false — brackets are safe
|
|
409
|
+
* hasUnsafeChars('file#anchor.html') // true — # breaks URL resolution
|
|
410
|
+
* hasUnsafeChars('file<tag>.html') // true — < is an XSS vector
|
|
411
|
+
*/
|
|
412
|
+
export declare function hasUnsafeChars(filename: string): boolean;
|
|
413
|
+
/**
|
|
414
|
+
* Path segment names that indicate an unbuilt project was uploaded instead of build output.
|
|
393
415
|
* Used for early detection in CLI, browser, and server validation.
|
|
394
416
|
*/
|
|
395
417
|
export declare const UNBUILT_PROJECT_MARKERS: ReadonlySet<string>;
|
|
396
418
|
/**
|
|
397
|
-
* Check if a file path contains an unbuilt project marker
|
|
419
|
+
* Check if a file path contains an unbuilt project marker.
|
|
398
420
|
*
|
|
399
421
|
* @example
|
|
400
422
|
* hasUnbuiltMarker('node_modules/react/index.js') // true
|
|
423
|
+
* hasUnbuiltMarker('package.json') // true
|
|
401
424
|
* hasUnbuiltMarker('dist/index.html') // false
|
|
402
425
|
*/
|
|
403
426
|
export declare function hasUnbuiltMarker(filePath: string): boolean;
|
package/dist/index.js
CHANGED
|
@@ -250,20 +250,49 @@ export function isBlockedExtension(filename) {
|
|
|
250
250
|
return BLOCKED_EXTENSIONS.has(ext);
|
|
251
251
|
}
|
|
252
252
|
// =============================================================================
|
|
253
|
+
// FILENAME CHARACTER VALIDATION
|
|
254
|
+
// =============================================================================
|
|
255
|
+
/**
|
|
256
|
+
* Characters that are unsafe in filenames for static hosting.
|
|
257
|
+
*
|
|
258
|
+
* Blocks only characters that genuinely break the upload→serve round-trip:
|
|
259
|
+
* - # ? % URL round-trip breakers (fragment, query, encoding ambiguity)
|
|
260
|
+
* - \ Path separator confusion (upload splits on backslash)
|
|
261
|
+
* - < > " XSS vectors with zero legitimate use in filenames
|
|
262
|
+
* - \x00-\x1f \x7f Control characters (header injection, display corruption)
|
|
263
|
+
*
|
|
264
|
+
* Everything else is allowed — browser percent-encodes, Worker decodes, R2 matches.
|
|
265
|
+
*/
|
|
266
|
+
export const UNSAFE_FILENAME_CHARS = /[\x00-\x1f\x7f#?%\\<>"]/;
|
|
267
|
+
/**
|
|
268
|
+
* Check if a filename contains unsafe characters.
|
|
269
|
+
*
|
|
270
|
+
* @example
|
|
271
|
+
* hasUnsafeChars('saved_resource(1).html') // false — parentheses are safe
|
|
272
|
+
* hasUnsafeChars('page[slug].js') // false — brackets are safe
|
|
273
|
+
* hasUnsafeChars('file#anchor.html') // true — # breaks URL resolution
|
|
274
|
+
* hasUnsafeChars('file<tag>.html') // true — < is an XSS vector
|
|
275
|
+
*/
|
|
276
|
+
export function hasUnsafeChars(filename) {
|
|
277
|
+
return UNSAFE_FILENAME_CHARS.test(filename);
|
|
278
|
+
}
|
|
279
|
+
// =============================================================================
|
|
253
280
|
// UNBUILT PROJECT MARKERS
|
|
254
281
|
// =============================================================================
|
|
255
282
|
/**
|
|
256
|
-
*
|
|
283
|
+
* Path segment names that indicate an unbuilt project was uploaded instead of build output.
|
|
257
284
|
* Used for early detection in CLI, browser, and server validation.
|
|
258
285
|
*/
|
|
259
286
|
export const UNBUILT_PROJECT_MARKERS = new Set([
|
|
260
287
|
'node_modules',
|
|
288
|
+
'package.json',
|
|
261
289
|
]);
|
|
262
290
|
/**
|
|
263
|
-
* Check if a file path contains an unbuilt project marker
|
|
291
|
+
* Check if a file path contains an unbuilt project marker.
|
|
264
292
|
*
|
|
265
293
|
* @example
|
|
266
294
|
* hasUnbuiltMarker('node_modules/react/index.js') // true
|
|
295
|
+
* hasUnbuiltMarker('package.json') // true
|
|
267
296
|
* hasUnbuiltMarker('dist/index.html') // false
|
|
268
297
|
*/
|
|
269
298
|
export function hasUnbuiltMarker(filePath) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipstatic/types",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"description": "Shared types for Shipstatic platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^24.10.9",
|
|
37
|
+
"husky": "^9.1.7",
|
|
37
38
|
"typescript": "^5.9.3",
|
|
38
39
|
"vitest": "^2.1.8"
|
|
39
40
|
},
|
package/src/index.ts
CHANGED
|
@@ -571,23 +571,55 @@ export function isBlockedExtension(filename: string): boolean {
|
|
|
571
571
|
return BLOCKED_EXTENSIONS.has(ext);
|
|
572
572
|
}
|
|
573
573
|
|
|
574
|
+
// =============================================================================
|
|
575
|
+
// FILENAME CHARACTER VALIDATION
|
|
576
|
+
// =============================================================================
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Characters that are unsafe in filenames for static hosting.
|
|
580
|
+
*
|
|
581
|
+
* Blocks only characters that genuinely break the upload→serve round-trip:
|
|
582
|
+
* - # ? % URL round-trip breakers (fragment, query, encoding ambiguity)
|
|
583
|
+
* - \ Path separator confusion (upload splits on backslash)
|
|
584
|
+
* - < > " XSS vectors with zero legitimate use in filenames
|
|
585
|
+
* - \x00-\x1f \x7f Control characters (header injection, display corruption)
|
|
586
|
+
*
|
|
587
|
+
* Everything else is allowed — browser percent-encodes, Worker decodes, R2 matches.
|
|
588
|
+
*/
|
|
589
|
+
export const UNSAFE_FILENAME_CHARS = /[\x00-\x1f\x7f#?%\\<>"]/;
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Check if a filename contains unsafe characters.
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* hasUnsafeChars('saved_resource(1).html') // false — parentheses are safe
|
|
596
|
+
* hasUnsafeChars('page[slug].js') // false — brackets are safe
|
|
597
|
+
* hasUnsafeChars('file#anchor.html') // true — # breaks URL resolution
|
|
598
|
+
* hasUnsafeChars('file<tag>.html') // true — < is an XSS vector
|
|
599
|
+
*/
|
|
600
|
+
export function hasUnsafeChars(filename: string): boolean {
|
|
601
|
+
return UNSAFE_FILENAME_CHARS.test(filename);
|
|
602
|
+
}
|
|
603
|
+
|
|
574
604
|
// =============================================================================
|
|
575
605
|
// UNBUILT PROJECT MARKERS
|
|
576
606
|
// =============================================================================
|
|
577
607
|
|
|
578
608
|
/**
|
|
579
|
-
*
|
|
609
|
+
* Path segment names that indicate an unbuilt project was uploaded instead of build output.
|
|
580
610
|
* Used for early detection in CLI, browser, and server validation.
|
|
581
611
|
*/
|
|
582
612
|
export const UNBUILT_PROJECT_MARKERS: ReadonlySet<string> = new Set([
|
|
583
613
|
'node_modules',
|
|
614
|
+
'package.json',
|
|
584
615
|
]);
|
|
585
616
|
|
|
586
617
|
/**
|
|
587
|
-
* Check if a file path contains an unbuilt project marker
|
|
618
|
+
* Check if a file path contains an unbuilt project marker.
|
|
588
619
|
*
|
|
589
620
|
* @example
|
|
590
621
|
* hasUnbuiltMarker('node_modules/react/index.js') // true
|
|
622
|
+
* hasUnbuiltMarker('package.json') // true
|
|
591
623
|
* hasUnbuiltMarker('dist/index.html') // false
|
|
592
624
|
*/
|
|
593
625
|
export function hasUnbuiltMarker(filePath: string): boolean {
|