@shipstatic/types 0.7.4 → 0.7.6
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 +1 -1
- package/dist/index.d.ts +32 -10
- package/dist/index.js +37 -10
- package/package.json +2 -2
- package/src/index.ts +40 -10
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file Shared TypeScript types, constants, and utilities for the
|
|
2
|
+
* @file Shared TypeScript types, constants, and utilities for the ShipStatic platform.
|
|
3
3
|
* This package is the single source of truth for all shared data structures.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
@@ -272,7 +272,7 @@ export interface AccountOverrides {
|
|
|
272
272
|
totalSize?: number;
|
|
273
273
|
}
|
|
274
274
|
/**
|
|
275
|
-
* All possible error types in the
|
|
275
|
+
* All possible error types in the ShipStatic platform
|
|
276
276
|
* Names are developer-friendly while wire format stays consistent
|
|
277
277
|
*/
|
|
278
278
|
export declare enum ErrorType {
|
|
@@ -389,12 +389,34 @@ 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
|
|
@@ -802,24 +824,24 @@ export interface UploadedFile {
|
|
|
802
824
|
* Check if a domain is a platform domain (subdomain of our platform).
|
|
803
825
|
* Platform domains are free and don't require DNS verification.
|
|
804
826
|
*
|
|
805
|
-
* @example isPlatformDomain("www.shipstatic.
|
|
806
|
-
* @example isPlatformDomain("example.com", "shipstatic.
|
|
827
|
+
* @example isPlatformDomain("www.shipstatic.com", "shipstatic.com") → true
|
|
828
|
+
* @example isPlatformDomain("example.com", "shipstatic.com") → false
|
|
807
829
|
*/
|
|
808
830
|
export declare function isPlatformDomain(domain: string, platformDomain: string): boolean;
|
|
809
831
|
/**
|
|
810
832
|
* Check if a domain is a custom domain (not a platform subdomain).
|
|
811
833
|
* Custom domains are billable and require DNS verification.
|
|
812
834
|
*
|
|
813
|
-
* @example isCustomDomain("example.com", "shipstatic.
|
|
814
|
-
* @example isCustomDomain("www.shipstatic.
|
|
835
|
+
* @example isCustomDomain("example.com", "shipstatic.com") → true
|
|
836
|
+
* @example isCustomDomain("www.shipstatic.com", "shipstatic.com") → false
|
|
815
837
|
*/
|
|
816
838
|
export declare function isCustomDomain(domain: string, platformDomain: string): boolean;
|
|
817
839
|
/**
|
|
818
840
|
* Extract subdomain from a platform domain.
|
|
819
841
|
* Returns null if not a platform domain.
|
|
820
842
|
*
|
|
821
|
-
* @example extractSubdomain("www.shipstatic.
|
|
822
|
-
* @example extractSubdomain("example.com", "shipstatic.
|
|
843
|
+
* @example extractSubdomain("www.shipstatic.com", "shipstatic.com") → "www"
|
|
844
|
+
* @example extractSubdomain("example.com", "shipstatic.com") → null
|
|
823
845
|
*/
|
|
824
846
|
export declare function extractSubdomain(domain: string, platformDomain: string): string | null;
|
|
825
847
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file Shared TypeScript types, constants, and utilities for the
|
|
2
|
+
* @file Shared TypeScript types, constants, and utilities for the ShipStatic platform.
|
|
3
3
|
* This package is the single source of truth for all shared data structures.
|
|
4
4
|
*/
|
|
5
5
|
// =============================================================================
|
|
@@ -50,7 +50,7 @@ export const AccountPlan = {
|
|
|
50
50
|
// ERROR SYSTEM
|
|
51
51
|
// =============================================================================
|
|
52
52
|
/**
|
|
53
|
-
* All possible error types in the
|
|
53
|
+
* All possible error types in the ShipStatic platform
|
|
54
54
|
* Names are developer-friendly while wire format stays consistent
|
|
55
55
|
*/
|
|
56
56
|
export var ErrorType;
|
|
@@ -250,10 +250,37 @@ 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([
|
|
@@ -261,7 +288,7 @@ export const UNBUILT_PROJECT_MARKERS = new Set([
|
|
|
261
288
|
'package.json',
|
|
262
289
|
]);
|
|
263
290
|
/**
|
|
264
|
-
* Check if a file path contains an unbuilt project marker
|
|
291
|
+
* Check if a file path contains an unbuilt project marker.
|
|
265
292
|
*
|
|
266
293
|
* @example
|
|
267
294
|
* hasUnbuiltMarker('node_modules/react/index.js') // true
|
|
@@ -384,8 +411,8 @@ export const FileValidationStatus = {
|
|
|
384
411
|
* Check if a domain is a platform domain (subdomain of our platform).
|
|
385
412
|
* Platform domains are free and don't require DNS verification.
|
|
386
413
|
*
|
|
387
|
-
* @example isPlatformDomain("www.shipstatic.
|
|
388
|
-
* @example isPlatformDomain("example.com", "shipstatic.
|
|
414
|
+
* @example isPlatformDomain("www.shipstatic.com", "shipstatic.com") → true
|
|
415
|
+
* @example isPlatformDomain("example.com", "shipstatic.com") → false
|
|
389
416
|
*/
|
|
390
417
|
export function isPlatformDomain(domain, platformDomain) {
|
|
391
418
|
return domain.endsWith(`.${platformDomain}`);
|
|
@@ -394,8 +421,8 @@ export function isPlatformDomain(domain, platformDomain) {
|
|
|
394
421
|
* Check if a domain is a custom domain (not a platform subdomain).
|
|
395
422
|
* Custom domains are billable and require DNS verification.
|
|
396
423
|
*
|
|
397
|
-
* @example isCustomDomain("example.com", "shipstatic.
|
|
398
|
-
* @example isCustomDomain("www.shipstatic.
|
|
424
|
+
* @example isCustomDomain("example.com", "shipstatic.com") → true
|
|
425
|
+
* @example isCustomDomain("www.shipstatic.com", "shipstatic.com") → false
|
|
399
426
|
*/
|
|
400
427
|
export function isCustomDomain(domain, platformDomain) {
|
|
401
428
|
return !isPlatformDomain(domain, platformDomain);
|
|
@@ -404,8 +431,8 @@ export function isCustomDomain(domain, platformDomain) {
|
|
|
404
431
|
* Extract subdomain from a platform domain.
|
|
405
432
|
* Returns null if not a platform domain.
|
|
406
433
|
*
|
|
407
|
-
* @example extractSubdomain("www.shipstatic.
|
|
408
|
-
* @example extractSubdomain("example.com", "shipstatic.
|
|
434
|
+
* @example extractSubdomain("www.shipstatic.com", "shipstatic.com") → "www"
|
|
435
|
+
* @example extractSubdomain("example.com", "shipstatic.com") → null
|
|
409
436
|
*/
|
|
410
437
|
export function extractSubdomain(domain, platformDomain) {
|
|
411
438
|
if (!isPlatformDomain(domain, platformDomain)) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shipstatic/types",
|
|
3
|
-
"version": "0.7.
|
|
4
|
-
"description": "Shared types for
|
|
3
|
+
"version": "0.7.6",
|
|
4
|
+
"description": "Shared types for ShipStatic platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file Shared TypeScript types, constants, and utilities for the
|
|
2
|
+
* @file Shared TypeScript types, constants, and utilities for the ShipStatic platform.
|
|
3
3
|
* This package is the single source of truth for all shared data structures.
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -315,7 +315,7 @@ export interface AccountOverrides {
|
|
|
315
315
|
// =============================================================================
|
|
316
316
|
|
|
317
317
|
/**
|
|
318
|
-
* All possible error types in the
|
|
318
|
+
* All possible error types in the ShipStatic platform
|
|
319
319
|
* Names are developer-friendly while wire format stays consistent
|
|
320
320
|
*/
|
|
321
321
|
export enum ErrorType {
|
|
@@ -571,12 +571,42 @@ 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([
|
|
@@ -585,7 +615,7 @@ export const UNBUILT_PROJECT_MARKERS: ReadonlySet<string> = new Set([
|
|
|
585
615
|
]);
|
|
586
616
|
|
|
587
617
|
/**
|
|
588
|
-
* Check if a file path contains an unbuilt project marker
|
|
618
|
+
* Check if a file path contains an unbuilt project marker.
|
|
589
619
|
*
|
|
590
620
|
* @example
|
|
591
621
|
* hasUnbuiltMarker('node_modules/react/index.js') // true
|
|
@@ -1201,8 +1231,8 @@ export interface UploadedFile {
|
|
|
1201
1231
|
* Check if a domain is a platform domain (subdomain of our platform).
|
|
1202
1232
|
* Platform domains are free and don't require DNS verification.
|
|
1203
1233
|
*
|
|
1204
|
-
* @example isPlatformDomain("www.shipstatic.
|
|
1205
|
-
* @example isPlatformDomain("example.com", "shipstatic.
|
|
1234
|
+
* @example isPlatformDomain("www.shipstatic.com", "shipstatic.com") → true
|
|
1235
|
+
* @example isPlatformDomain("example.com", "shipstatic.com") → false
|
|
1206
1236
|
*/
|
|
1207
1237
|
export function isPlatformDomain(domain: string, platformDomain: string): boolean {
|
|
1208
1238
|
return domain.endsWith(`.${platformDomain}`);
|
|
@@ -1212,8 +1242,8 @@ export function isPlatformDomain(domain: string, platformDomain: string): boolea
|
|
|
1212
1242
|
* Check if a domain is a custom domain (not a platform subdomain).
|
|
1213
1243
|
* Custom domains are billable and require DNS verification.
|
|
1214
1244
|
*
|
|
1215
|
-
* @example isCustomDomain("example.com", "shipstatic.
|
|
1216
|
-
* @example isCustomDomain("www.shipstatic.
|
|
1245
|
+
* @example isCustomDomain("example.com", "shipstatic.com") → true
|
|
1246
|
+
* @example isCustomDomain("www.shipstatic.com", "shipstatic.com") → false
|
|
1217
1247
|
*/
|
|
1218
1248
|
export function isCustomDomain(domain: string, platformDomain: string): boolean {
|
|
1219
1249
|
return !isPlatformDomain(domain, platformDomain);
|
|
@@ -1223,8 +1253,8 @@ export function isCustomDomain(domain: string, platformDomain: string): boolean
|
|
|
1223
1253
|
* Extract subdomain from a platform domain.
|
|
1224
1254
|
* Returns null if not a platform domain.
|
|
1225
1255
|
*
|
|
1226
|
-
* @example extractSubdomain("www.shipstatic.
|
|
1227
|
-
* @example extractSubdomain("example.com", "shipstatic.
|
|
1256
|
+
* @example extractSubdomain("www.shipstatic.com", "shipstatic.com") → "www"
|
|
1257
|
+
* @example extractSubdomain("example.com", "shipstatic.com") → null
|
|
1228
1258
|
*/
|
|
1229
1259
|
export function extractSubdomain(domain: string, platformDomain: string): string | null {
|
|
1230
1260
|
if (!isPlatformDomain(domain, platformDomain)) {
|