@shipstatic/types 0.5.4 → 0.6.1
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 +27 -82
- package/dist/index.js +41 -201
- package/package.json +1 -1
- package/src/index.ts +58 -248
package/dist/index.d.ts
CHANGED
|
@@ -224,6 +224,13 @@ export declare const AccountPlan: {
|
|
|
224
224
|
readonly TERMINATED: "terminated";
|
|
225
225
|
};
|
|
226
226
|
export type AccountPlanType = typeof AccountPlan[keyof typeof AccountPlan];
|
|
227
|
+
/**
|
|
228
|
+
* Account usage metrics — always available regardless of billing provider.
|
|
229
|
+
*/
|
|
230
|
+
export interface AccountUsage {
|
|
231
|
+
/** Number of active custom domains (excludes paused) */
|
|
232
|
+
customDomains: number;
|
|
233
|
+
}
|
|
227
234
|
/**
|
|
228
235
|
* Core account object - used in both API responses and SDK
|
|
229
236
|
* All fields are readonly to prevent accidental mutations
|
|
@@ -237,6 +244,8 @@ export interface Account {
|
|
|
237
244
|
readonly picture: string | null;
|
|
238
245
|
/** Account plan status */
|
|
239
246
|
readonly plan: AccountPlanType;
|
|
247
|
+
/** Account usage metrics (custom domains, etc.) */
|
|
248
|
+
readonly usage: AccountUsage;
|
|
240
249
|
/** Unix timestamp (seconds) when account was created */
|
|
241
250
|
readonly created: number;
|
|
242
251
|
/** Unix timestamp (seconds) when account was activated (first deployment), null if not yet activated */
|
|
@@ -345,99 +354,38 @@ export declare class ShipError extends Error {
|
|
|
345
354
|
*/
|
|
346
355
|
export declare function isShipError(error: unknown): error is ShipError;
|
|
347
356
|
/**
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
* Contains ONLY dynamic, runtime-specific values (plan-based limits).
|
|
351
|
-
* Static constants (MIME types, validation rules) live as exported constants.
|
|
357
|
+
* Dynamic platform configuration returned by the /config endpoint.
|
|
358
|
+
* Contains plan-based limits that vary by account.
|
|
352
359
|
*/
|
|
353
360
|
export interface ConfigResponse {
|
|
354
|
-
/** Maximum individual file size in bytes */
|
|
355
361
|
maxFileSize: number;
|
|
356
|
-
/** Maximum number of files per deployment */
|
|
357
362
|
maxFilesCount: number;
|
|
358
|
-
/** Maximum total deployment size in bytes */
|
|
359
363
|
maxTotalSize: number;
|
|
360
364
|
}
|
|
361
365
|
/**
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
* This is a static platform constant, not per-user configuration.
|
|
365
|
-
* Safe to share across frontend/backend due to atomic deploys.
|
|
366
|
-
*
|
|
367
|
-
* Validation rules:
|
|
368
|
-
* - Exact match: 'application/json' allows only 'application/json'
|
|
369
|
-
* - Prefix match: 'image/' allows all image types (png, jpeg, webp, etc.)
|
|
370
|
-
*
|
|
371
|
-
* Coverage: 100% of browser-renderable web content
|
|
372
|
-
* - Core web (HTML, CSS, JS, WASM)
|
|
373
|
-
* - Media (images, audio, video, fonts)
|
|
374
|
-
* - Documents (PDF, Markdown, data formats)
|
|
375
|
-
* - Modern web (PWA, 3D, structured data)
|
|
376
|
-
*
|
|
377
|
-
* ============================================================================
|
|
378
|
-
* INTENTIONALLY EXCLUDED (Security & Platform Integrity)
|
|
379
|
-
* ============================================================================
|
|
366
|
+
* Blocked file extensions — files that cannot be uploaded.
|
|
380
367
|
*
|
|
381
|
-
* We
|
|
382
|
-
*
|
|
368
|
+
* We accept any file type by default and derive Content-Type from the
|
|
369
|
+
* extension at serve time (via mime-db in the API worker). Unknown extensions
|
|
370
|
+
* are served as `application/octet-stream` with `X-Content-Type-Options: nosniff`.
|
|
383
371
|
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
* → Reason: Direct malware delivery vector
|
|
387
|
-
* → Alternative: Use GitHub Releases or dedicated software distribution CDN
|
|
388
|
-
*
|
|
389
|
-
* 2. ARCHIVES (Piracy & Abuse)
|
|
390
|
-
* → .zip, .rar, .tar, .gz, .7z, .bz2
|
|
391
|
-
* → Reason: File sharing abuse, can contain executables, no web rendering
|
|
392
|
-
* → Alternative: Use file hosting service (Dropbox, Google Drive) or GitHub Releases
|
|
393
|
-
*
|
|
394
|
-
* 3. SERVER-SIDE SCRIPTS (Credential Leakage)
|
|
395
|
-
* → .php, .asp, .jsp, .cgi
|
|
396
|
-
* → Reason: Source code exposure (database passwords, API keys, secrets)
|
|
397
|
-
* → Alternative: Static hosting only - use serverless functions for backends
|
|
398
|
-
*
|
|
399
|
-
* 4. SHELL SCRIPTS (OS Execution)
|
|
400
|
-
* → .sh, .bash, .bat, .cmd, .ps1, .vbs
|
|
401
|
-
* → Reason: Execute on user's OS outside browser sandbox, social engineering risk
|
|
402
|
-
* → Alternative: Embed code examples in HTML <pre><code> or link to GitHub repo
|
|
403
|
-
*
|
|
404
|
-
* 5. PROGRAMMING LANGUAGE SOURCE (Platform Scope)
|
|
405
|
-
* → .py, .rb, .pl, .java, .c, .cpp, .cs, .go, .rs
|
|
406
|
-
* → Reason: Not web-renderable, better served by GitHub/GitLab/Bitbucket
|
|
407
|
-
* → Alternative: Use GitHub for code hosting, link to repository
|
|
408
|
-
*
|
|
409
|
-
* 6. OFFICE DOCUMENTS (Macro Malware)
|
|
410
|
-
* → .doc, .docx, .xls, .xlsx, .ppt, .pptx
|
|
411
|
-
* → Reason: Can contain VBA macros, active exploits in the wild
|
|
412
|
-
* → Alternative: Use PDF for documents (fully supported)
|
|
413
|
-
*
|
|
414
|
-
* 7. GENERIC BINARIES (Unvalidatable)
|
|
415
|
-
* → application/octet-stream
|
|
416
|
-
* → Reason: Too broad - allows any binary format, cannot moderate effectively
|
|
417
|
-
* → Alternative: Use specific MIME types for known formats
|
|
418
|
-
*
|
|
419
|
-
* ============================================================================
|
|
420
|
-
* Security Model:
|
|
421
|
-
* - Browser sandbox (JS/WASM execute safely in controlled environment)
|
|
422
|
-
* - AI content moderation (scans text/image content for abuse)
|
|
423
|
-
* - No server-side execution (static files only)
|
|
424
|
-
* - Explicit allowlist (only approved formats, reject unknown)
|
|
425
|
-
* ============================================================================
|
|
372
|
+
* The blocklist targets file types that pose direct security risks when hosted:
|
|
373
|
+
* executables, disk images, malware vectors, dangerous scripts, and shortcuts.
|
|
426
374
|
*/
|
|
427
|
-
export declare const
|
|
375
|
+
export declare const BLOCKED_EXTENSIONS: ReadonlySet<string>;
|
|
428
376
|
/**
|
|
429
|
-
* Check if a
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
* - 'application/json' matches 'application/json' exactly
|
|
433
|
-
* - 'text/' matches 'text/plain', 'text/html', etc.
|
|
377
|
+
* Check if a filename has a blocked extension.
|
|
378
|
+
* Extracts the extension from the filename and checks against the blocklist.
|
|
379
|
+
* Case-insensitive. Returns false for files without extensions.
|
|
434
380
|
*
|
|
435
381
|
* @example
|
|
436
|
-
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
382
|
+
* isBlockedExtension('virus.exe') // true
|
|
383
|
+
* isBlockedExtension('app.dmg') // true
|
|
384
|
+
* isBlockedExtension('style.css') // false
|
|
385
|
+
* isBlockedExtension('data.custom') // false
|
|
386
|
+
* isBlockedExtension('README') // false
|
|
439
387
|
*/
|
|
440
|
-
export declare function
|
|
388
|
+
export declare function isBlockedExtension(filename: string): boolean;
|
|
441
389
|
/**
|
|
442
390
|
* Simple ping response for health checks
|
|
443
391
|
*/
|
|
@@ -651,8 +599,6 @@ export interface BillingStatus {
|
|
|
651
599
|
billing: string | null;
|
|
652
600
|
/** Number of billing units (1 unit = 1 custom domain), null if no billing */
|
|
653
601
|
units: number | null;
|
|
654
|
-
/** Number of custom domains currently in use, null if no billing */
|
|
655
|
-
usage: number | null;
|
|
656
602
|
/** Billing status from Creem (active, trialing, canceled, etc.), null if no billing */
|
|
657
603
|
status: string | null;
|
|
658
604
|
/** Link to Creem customer portal for billing management, null if unavailable */
|
|
@@ -788,7 +734,6 @@ export interface ValidationIssue {
|
|
|
788
734
|
export interface ValidatableFile {
|
|
789
735
|
name: string;
|
|
790
736
|
size: number;
|
|
791
|
-
type: string;
|
|
792
737
|
status?: FileValidationStatusType;
|
|
793
738
|
statusMessage?: string;
|
|
794
739
|
}
|
package/dist/index.js
CHANGED
|
@@ -199,215 +199,55 @@ export function isShipError(error) {
|
|
|
199
199
|
error.name === 'ShipError' &&
|
|
200
200
|
'status' in error);
|
|
201
201
|
}
|
|
202
|
+
// =============================================================================
|
|
203
|
+
// EXTENSION BLOCKLIST
|
|
204
|
+
// =============================================================================
|
|
202
205
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
* This is a static platform constant, not per-user configuration.
|
|
206
|
-
* Safe to share across frontend/backend due to atomic deploys.
|
|
207
|
-
*
|
|
208
|
-
* Validation rules:
|
|
209
|
-
* - Exact match: 'application/json' allows only 'application/json'
|
|
210
|
-
* - Prefix match: 'image/' allows all image types (png, jpeg, webp, etc.)
|
|
211
|
-
*
|
|
212
|
-
* Coverage: 100% of browser-renderable web content
|
|
213
|
-
* - Core web (HTML, CSS, JS, WASM)
|
|
214
|
-
* - Media (images, audio, video, fonts)
|
|
215
|
-
* - Documents (PDF, Markdown, data formats)
|
|
216
|
-
* - Modern web (PWA, 3D, structured data)
|
|
217
|
-
*
|
|
218
|
-
* ============================================================================
|
|
219
|
-
* INTENTIONALLY EXCLUDED (Security & Platform Integrity)
|
|
220
|
-
* ============================================================================
|
|
221
|
-
*
|
|
222
|
-
* We are a WEB HOSTING platform, not a file distribution service.
|
|
223
|
-
* GitHub Pages-style parity for renderable content, more restrictive for downloads.
|
|
206
|
+
* Blocked file extensions — files that cannot be uploaded.
|
|
224
207
|
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
* → Alternative: Use GitHub Releases or dedicated software distribution CDN
|
|
208
|
+
* We accept any file type by default and derive Content-Type from the
|
|
209
|
+
* extension at serve time (via mime-db in the API worker). Unknown extensions
|
|
210
|
+
* are served as `application/octet-stream` with `X-Content-Type-Options: nosniff`.
|
|
229
211
|
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
* → Reason: File sharing abuse, can contain executables, no web rendering
|
|
233
|
-
* → Alternative: Use file hosting service (Dropbox, Google Drive) or GitHub Releases
|
|
234
|
-
*
|
|
235
|
-
* 3. SERVER-SIDE SCRIPTS (Credential Leakage)
|
|
236
|
-
* → .php, .asp, .jsp, .cgi
|
|
237
|
-
* → Reason: Source code exposure (database passwords, API keys, secrets)
|
|
238
|
-
* → Alternative: Static hosting only - use serverless functions for backends
|
|
239
|
-
*
|
|
240
|
-
* 4. SHELL SCRIPTS (OS Execution)
|
|
241
|
-
* → .sh, .bash, .bat, .cmd, .ps1, .vbs
|
|
242
|
-
* → Reason: Execute on user's OS outside browser sandbox, social engineering risk
|
|
243
|
-
* → Alternative: Embed code examples in HTML <pre><code> or link to GitHub repo
|
|
244
|
-
*
|
|
245
|
-
* 5. PROGRAMMING LANGUAGE SOURCE (Platform Scope)
|
|
246
|
-
* → .py, .rb, .pl, .java, .c, .cpp, .cs, .go, .rs
|
|
247
|
-
* → Reason: Not web-renderable, better served by GitHub/GitLab/Bitbucket
|
|
248
|
-
* → Alternative: Use GitHub for code hosting, link to repository
|
|
249
|
-
*
|
|
250
|
-
* 6. OFFICE DOCUMENTS (Macro Malware)
|
|
251
|
-
* → .doc, .docx, .xls, .xlsx, .ppt, .pptx
|
|
252
|
-
* → Reason: Can contain VBA macros, active exploits in the wild
|
|
253
|
-
* → Alternative: Use PDF for documents (fully supported)
|
|
254
|
-
*
|
|
255
|
-
* 7. GENERIC BINARIES (Unvalidatable)
|
|
256
|
-
* → application/octet-stream
|
|
257
|
-
* → Reason: Too broad - allows any binary format, cannot moderate effectively
|
|
258
|
-
* → Alternative: Use specific MIME types for known formats
|
|
259
|
-
*
|
|
260
|
-
* ============================================================================
|
|
261
|
-
* Security Model:
|
|
262
|
-
* - Browser sandbox (JS/WASM execute safely in controlled environment)
|
|
263
|
-
* - AI content moderation (scans text/image content for abuse)
|
|
264
|
-
* - No server-side execution (static files only)
|
|
265
|
-
* - Explicit allowlist (only approved formats, reject unknown)
|
|
266
|
-
* ============================================================================
|
|
212
|
+
* The blocklist targets file types that pose direct security risks when hosted:
|
|
213
|
+
* executables, disk images, malware vectors, dangerous scripts, and shortcuts.
|
|
267
214
|
*/
|
|
268
|
-
export const
|
|
269
|
-
//
|
|
270
|
-
|
|
271
|
-
//
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
'
|
|
275
|
-
|
|
276
|
-
'
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
'
|
|
281
|
-
|
|
282
|
-
'
|
|
283
|
-
//
|
|
284
|
-
'
|
|
285
|
-
|
|
286
|
-
// Web-specific formats
|
|
287
|
-
'text/vtt', // WebVTT video subtitles/captions (accessibility)
|
|
288
|
-
'text/srt', // SRT subtitles (SubRip format, legacy video captions)
|
|
289
|
-
'text/calendar', // iCalendar (.ics) event files
|
|
290
|
-
// JavaScript (legacy MIME type, still widely used by ~50% of servers)
|
|
291
|
-
'text/javascript',
|
|
292
|
-
// Modern web development formats (uncompiled source)
|
|
293
|
-
'text/typescript', // TypeScript source (.ts)
|
|
294
|
-
'application/x-typescript', // TypeScript (alternative MIME type, .d.ts declarations)
|
|
295
|
-
'text/tsx', // TypeScript JSX (.tsx)
|
|
296
|
-
'text/jsx', // React JSX (.jsx)
|
|
297
|
-
'text/x-scss', // SCSS preprocessor
|
|
298
|
-
'text/x-sass', // Sass preprocessor
|
|
299
|
-
'text/less', // Less preprocessor
|
|
300
|
-
'text/x-less', // Less preprocessor (alternative)
|
|
301
|
-
'text/stylus', // Stylus preprocessor
|
|
302
|
-
'text/x-vue', // Vue single-file components (.vue)
|
|
303
|
-
'text/x-svelte', // Svelte components (.svelte)
|
|
304
|
-
// Developer documentation formats
|
|
305
|
-
'text/x-sql', // SQL files (database schemas, migrations)
|
|
306
|
-
'text/x-diff', // Diff files (code comparisons, patches)
|
|
307
|
-
'text/x-patch', // Patch files (version upgrades, migrations)
|
|
308
|
-
'text/x-protobuf', // Protocol Buffers text format (gRPC schemas)
|
|
309
|
-
'text/x-ini', // INI configuration files
|
|
310
|
-
// Academic/research formats
|
|
311
|
-
'text/x-tex', // LaTeX documents
|
|
312
|
-
'text/x-latex', // LaTeX documents (alternative)
|
|
313
|
-
'text/x-bibtex', // BibTeX citations
|
|
314
|
-
'text/x-r-markdown', // R Markdown (statistical documentation)
|
|
315
|
-
// =========================================================================
|
|
316
|
-
// MEDIA (prefix matching - covers all common subtypes)
|
|
317
|
-
// =========================================================================
|
|
318
|
-
// Images: PNG, JPEG, GIF, SVG, WebP, AVIF, HEIC, BMP, TIFF, ICO, etc.
|
|
319
|
-
'image/',
|
|
320
|
-
// Audio: MP3, OGG, WAV, WebM, AAC, FLAC, Opus, etc.
|
|
321
|
-
'audio/',
|
|
322
|
-
// Video: MP4, WebM, OGG, QuickTime, etc.
|
|
323
|
-
'video/',
|
|
324
|
-
// Modern fonts: WOFF2, WOFF, TTF, OTF
|
|
325
|
-
'font/',
|
|
326
|
-
// =========================================================================
|
|
327
|
-
// CORE WEB APPLICATION TYPES
|
|
328
|
-
// =========================================================================
|
|
329
|
-
// JavaScript (multiple MIME types for compatibility)
|
|
330
|
-
'application/javascript', // Modern standard (RFC 9239)
|
|
331
|
-
'application/ecmascript', // ECMAScript (legacy but still used)
|
|
332
|
-
'application/x-javascript', // Legacy variant (old CDNs, Apache configs)
|
|
333
|
-
// WebAssembly (modern web apps, games, compute-heavy workloads)
|
|
334
|
-
'application/wasm',
|
|
335
|
-
// JSON and structured data
|
|
336
|
-
'application/json',
|
|
337
|
-
'application/ld+json', // JSON-LD for structured data / SEO (Schema.org, Open Graph)
|
|
338
|
-
'application/geo+json', // GeoJSON for mapping (Leaflet, Mapbox)
|
|
339
|
-
'application/manifest+json', // PWA web app manifests
|
|
340
|
-
'application/x-ipynb+json', // Jupyter Notebooks (data science, ML tutorials)
|
|
341
|
-
// JSON variants (AI/ML, streaming data, configs)
|
|
342
|
-
'application/x-ndjson', // Newline-Delimited JSON (training datasets, logs)
|
|
343
|
-
'application/ndjson', // NDJSON (alternative MIME type)
|
|
344
|
-
'text/x-ndjson', // NDJSON (text variant)
|
|
345
|
-
'application/jsonl', // JSON Lines (Hugging Face, OpenAI fine-tuning)
|
|
346
|
-
'text/jsonl', // JSON Lines (text variant)
|
|
347
|
-
'application/json5', // JSON5 (JSON with comments, trailing commas)
|
|
348
|
-
'text/json5', // JSON5 (text variant)
|
|
349
|
-
'application/schema+json', // JSON Schema (API specs, model definitions)
|
|
350
|
-
// Development tools
|
|
351
|
-
'application/source-map', // Source maps (.js.map, .css.map) for debugging
|
|
352
|
-
// XML and feeds
|
|
353
|
-
'application/xml',
|
|
354
|
-
'application/xhtml+xml', // XHTML - XML-compliant HTML (legacy sites)
|
|
355
|
-
'application/rss+xml', // RSS feeds (blogs, podcasts)
|
|
356
|
-
'application/atom+xml', // Atom feeds
|
|
357
|
-
'application/feed+json', // JSON Feed (modern RSS alternative)
|
|
358
|
-
'application/vnd.google-earth.kml+xml', // KML for mapping (Google Earth, GIS)
|
|
359
|
-
// Configuration formats
|
|
360
|
-
'application/yaml', // YAML configs (static site generators)
|
|
361
|
-
'application/toml', // TOML configs (Cargo, Netlify, Rust projects)
|
|
362
|
-
// Documents
|
|
363
|
-
'application/pdf', // PDF documents
|
|
364
|
-
// Media metadata
|
|
365
|
-
'application/x-subrip', // SRT subtitles (SubRip format)
|
|
366
|
-
// Developer tools and schemas
|
|
367
|
-
'application/sql', // SQL files (database schemas, queries)
|
|
368
|
-
'application/graphql', // GraphQL schemas (API documentation)
|
|
369
|
-
'application/graphql+json', // GraphQL with JSON encoding
|
|
370
|
-
'application/x-protobuf', // Protocol Buffers binary (gRPC)
|
|
371
|
-
'application/x-ini', // INI configuration files
|
|
372
|
-
// Academic formats
|
|
373
|
-
'application/x-tex', // LaTeX documents
|
|
374
|
-
'application/x-bibtex', // BibTeX citations
|
|
375
|
-
// =========================================================================
|
|
376
|
-
// 3D FORMATS (industry standard only)
|
|
377
|
-
// =========================================================================
|
|
378
|
-
// glTF - Khronos standard for 3D web content
|
|
379
|
-
'model/gltf+json', // glTF JSON format
|
|
380
|
-
'model/gltf-binary', // GLB binary format
|
|
381
|
-
// =========================================================================
|
|
382
|
-
// LEGACY COMPATIBILITY
|
|
383
|
-
// =========================================================================
|
|
384
|
-
// Video (some tools detect MP4 as application/mp4)
|
|
385
|
-
'application/mp4',
|
|
386
|
-
// Legacy font MIME types (Bootstrap, Font Awesome, IE compatibility)
|
|
387
|
-
'application/font-woff',
|
|
388
|
-
'application/font-woff2',
|
|
389
|
-
'application/x-font-woff',
|
|
390
|
-
'application/x-woff',
|
|
391
|
-
'application/vnd.ms-fontobject', // EOT files (Internet Explorer)
|
|
392
|
-
'application/x-font-ttf',
|
|
393
|
-
'application/x-font-truetype',
|
|
394
|
-
'application/x-font-otf',
|
|
395
|
-
'application/x-font-opentype',
|
|
396
|
-
];
|
|
215
|
+
export const BLOCKED_EXTENSIONS = new Set([
|
|
216
|
+
// Executables
|
|
217
|
+
'exe', 'msi', 'dll', 'scr', 'bat', 'cmd', 'com', 'pif', 'app', 'deb', 'rpm',
|
|
218
|
+
// Installers
|
|
219
|
+
'pkg', 'mpkg',
|
|
220
|
+
// Disk images
|
|
221
|
+
'dmg', 'iso', 'img',
|
|
222
|
+
// Malware vectors
|
|
223
|
+
'cab', 'cpl', 'chm',
|
|
224
|
+
// Dangerous scripts
|
|
225
|
+
'ps1', 'vbs', 'vbe', 'ws', 'wsf', 'wsc', 'wsh', 'reg',
|
|
226
|
+
// Java
|
|
227
|
+
'jar', 'jnlp',
|
|
228
|
+
// Mobile/browser packages
|
|
229
|
+
'apk', 'crx',
|
|
230
|
+
// Shortcut/link
|
|
231
|
+
'lnk', 'inf', 'hta',
|
|
232
|
+
]);
|
|
397
233
|
/**
|
|
398
|
-
* Check if a
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
* - 'application/json' matches 'application/json' exactly
|
|
402
|
-
* - 'text/' matches 'text/plain', 'text/html', etc.
|
|
234
|
+
* Check if a filename has a blocked extension.
|
|
235
|
+
* Extracts the extension from the filename and checks against the blocklist.
|
|
236
|
+
* Case-insensitive. Returns false for files without extensions.
|
|
403
237
|
*
|
|
404
238
|
* @example
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
239
|
+
* isBlockedExtension('virus.exe') // true
|
|
240
|
+
* isBlockedExtension('app.dmg') // true
|
|
241
|
+
* isBlockedExtension('style.css') // false
|
|
242
|
+
* isBlockedExtension('data.custom') // false
|
|
243
|
+
* isBlockedExtension('README') // false
|
|
408
244
|
*/
|
|
409
|
-
export function
|
|
410
|
-
|
|
245
|
+
export function isBlockedExtension(filename) {
|
|
246
|
+
const dotIndex = filename.lastIndexOf('.');
|
|
247
|
+
if (dotIndex === -1 || dotIndex === filename.length - 1)
|
|
248
|
+
return false;
|
|
249
|
+
const ext = filename.slice(dotIndex + 1).toLowerCase();
|
|
250
|
+
return BLOCKED_EXTENSIONS.has(ext);
|
|
411
251
|
}
|
|
412
252
|
// API Key Configuration
|
|
413
253
|
export const API_KEY_PREFIX = 'ship-';
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -260,6 +260,14 @@ export const AccountPlan = {
|
|
|
260
260
|
|
|
261
261
|
export type AccountPlanType = typeof AccountPlan[keyof typeof AccountPlan];
|
|
262
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Account usage metrics — always available regardless of billing provider.
|
|
265
|
+
*/
|
|
266
|
+
export interface AccountUsage {
|
|
267
|
+
/** Number of active custom domains (excludes paused) */
|
|
268
|
+
customDomains: number;
|
|
269
|
+
}
|
|
270
|
+
|
|
263
271
|
/**
|
|
264
272
|
* Core account object - used in both API responses and SDK
|
|
265
273
|
* All fields are readonly to prevent accidental mutations
|
|
@@ -273,6 +281,8 @@ export interface Account {
|
|
|
273
281
|
readonly picture: string | null;
|
|
274
282
|
/** Account plan status */
|
|
275
283
|
readonly plan: AccountPlanType;
|
|
284
|
+
/** Account usage metrics (custom domains, etc.) */
|
|
285
|
+
readonly usage: AccountUsage;
|
|
276
286
|
/** Unix timestamp (seconds) when account was created */
|
|
277
287
|
readonly created: number;
|
|
278
288
|
/** Unix timestamp (seconds) when account was activated (first deployment), null if not yet activated */
|
|
@@ -498,266 +508,69 @@ export function isShipError(error: unknown): error is ShipError {
|
|
|
498
508
|
// =============================================================================
|
|
499
509
|
|
|
500
510
|
/**
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
* Contains ONLY dynamic, runtime-specific values (plan-based limits).
|
|
504
|
-
* Static constants (MIME types, validation rules) live as exported constants.
|
|
511
|
+
* Dynamic platform configuration returned by the /config endpoint.
|
|
512
|
+
* Contains plan-based limits that vary by account.
|
|
505
513
|
*/
|
|
506
514
|
export interface ConfigResponse {
|
|
507
|
-
/** Maximum individual file size in bytes */
|
|
508
515
|
maxFileSize: number;
|
|
509
|
-
/** Maximum number of files per deployment */
|
|
510
516
|
maxFilesCount: number;
|
|
511
|
-
/** Maximum total deployment size in bytes */
|
|
512
517
|
maxTotalSize: number;
|
|
513
518
|
}
|
|
514
519
|
|
|
520
|
+
// =============================================================================
|
|
521
|
+
// EXTENSION BLOCKLIST
|
|
522
|
+
// =============================================================================
|
|
523
|
+
|
|
515
524
|
/**
|
|
516
|
-
*
|
|
517
|
-
*
|
|
518
|
-
* This is a static platform constant, not per-user configuration.
|
|
519
|
-
* Safe to share across frontend/backend due to atomic deploys.
|
|
520
|
-
*
|
|
521
|
-
* Validation rules:
|
|
522
|
-
* - Exact match: 'application/json' allows only 'application/json'
|
|
523
|
-
* - Prefix match: 'image/' allows all image types (png, jpeg, webp, etc.)
|
|
524
|
-
*
|
|
525
|
-
* Coverage: 100% of browser-renderable web content
|
|
526
|
-
* - Core web (HTML, CSS, JS, WASM)
|
|
527
|
-
* - Media (images, audio, video, fonts)
|
|
528
|
-
* - Documents (PDF, Markdown, data formats)
|
|
529
|
-
* - Modern web (PWA, 3D, structured data)
|
|
525
|
+
* Blocked file extensions — files that cannot be uploaded.
|
|
530
526
|
*
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
*
|
|
527
|
+
* We accept any file type by default and derive Content-Type from the
|
|
528
|
+
* extension at serve time (via mime-db in the API worker). Unknown extensions
|
|
529
|
+
* are served as `application/octet-stream` with `X-Content-Type-Options: nosniff`.
|
|
534
530
|
*
|
|
535
|
-
*
|
|
536
|
-
*
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
* → Alternative: Use GitHub for code hosting, link to repository
|
|
562
|
-
*
|
|
563
|
-
* 6. OFFICE DOCUMENTS (Macro Malware)
|
|
564
|
-
* → .doc, .docx, .xls, .xlsx, .ppt, .pptx
|
|
565
|
-
* → Reason: Can contain VBA macros, active exploits in the wild
|
|
566
|
-
* → Alternative: Use PDF for documents (fully supported)
|
|
567
|
-
*
|
|
568
|
-
* 7. GENERIC BINARIES (Unvalidatable)
|
|
569
|
-
* → application/octet-stream
|
|
570
|
-
* → Reason: Too broad - allows any binary format, cannot moderate effectively
|
|
571
|
-
* → Alternative: Use specific MIME types for known formats
|
|
572
|
-
*
|
|
573
|
-
* ============================================================================
|
|
574
|
-
* Security Model:
|
|
575
|
-
* - Browser sandbox (JS/WASM execute safely in controlled environment)
|
|
576
|
-
* - AI content moderation (scans text/image content for abuse)
|
|
577
|
-
* - No server-side execution (static files only)
|
|
578
|
-
* - Explicit allowlist (only approved formats, reject unknown)
|
|
579
|
-
* ============================================================================
|
|
580
|
-
*/
|
|
581
|
-
export const ALLOWED_MIME_TYPES = [
|
|
582
|
-
// =========================================================================
|
|
583
|
-
// TEXT CONTENT (explicit list - no prefix matching for security)
|
|
584
|
-
// =========================================================================
|
|
585
|
-
|
|
586
|
-
// Core web documents
|
|
587
|
-
'text/html', // HTML pages
|
|
588
|
-
'text/css', // Stylesheets
|
|
589
|
-
'text/plain', // Plain text (robots.txt, .well-known/*, LICENSE, README.txt)
|
|
590
|
-
'text/markdown', // Markdown files (.md)
|
|
591
|
-
'text/xml', // XML files
|
|
592
|
-
|
|
593
|
-
// Data formats
|
|
594
|
-
'text/csv', // CSV data files
|
|
595
|
-
'text/tab-separated-values', // TSV data files
|
|
596
|
-
'text/yaml', // YAML config files
|
|
597
|
-
'text/vcard', // VCard contact files (.vcf)
|
|
598
|
-
|
|
599
|
-
// Modern documentation formats
|
|
600
|
-
'text/mdx', // MDX (Markdown with JSX) - Next.js, Docusaurus, Nextra
|
|
601
|
-
'text/x-mdx', // MDX (alternative MIME type)
|
|
602
|
-
|
|
603
|
-
// Web-specific formats
|
|
604
|
-
'text/vtt', // WebVTT video subtitles/captions (accessibility)
|
|
605
|
-
'text/srt', // SRT subtitles (SubRip format, legacy video captions)
|
|
606
|
-
'text/calendar', // iCalendar (.ics) event files
|
|
607
|
-
|
|
608
|
-
// JavaScript (legacy MIME type, still widely used by ~50% of servers)
|
|
609
|
-
'text/javascript',
|
|
610
|
-
|
|
611
|
-
// Modern web development formats (uncompiled source)
|
|
612
|
-
'text/typescript', // TypeScript source (.ts)
|
|
613
|
-
'application/x-typescript', // TypeScript (alternative MIME type, .d.ts declarations)
|
|
614
|
-
'text/tsx', // TypeScript JSX (.tsx)
|
|
615
|
-
'text/jsx', // React JSX (.jsx)
|
|
616
|
-
'text/x-scss', // SCSS preprocessor
|
|
617
|
-
'text/x-sass', // Sass preprocessor
|
|
618
|
-
'text/less', // Less preprocessor
|
|
619
|
-
'text/x-less', // Less preprocessor (alternative)
|
|
620
|
-
'text/stylus', // Stylus preprocessor
|
|
621
|
-
'text/x-vue', // Vue single-file components (.vue)
|
|
622
|
-
'text/x-svelte', // Svelte components (.svelte)
|
|
623
|
-
|
|
624
|
-
// Developer documentation formats
|
|
625
|
-
'text/x-sql', // SQL files (database schemas, migrations)
|
|
626
|
-
'text/x-diff', // Diff files (code comparisons, patches)
|
|
627
|
-
'text/x-patch', // Patch files (version upgrades, migrations)
|
|
628
|
-
'text/x-protobuf', // Protocol Buffers text format (gRPC schemas)
|
|
629
|
-
'text/x-ini', // INI configuration files
|
|
630
|
-
|
|
631
|
-
// Academic/research formats
|
|
632
|
-
'text/x-tex', // LaTeX documents
|
|
633
|
-
'text/x-latex', // LaTeX documents (alternative)
|
|
634
|
-
'text/x-bibtex', // BibTeX citations
|
|
635
|
-
'text/x-r-markdown', // R Markdown (statistical documentation)
|
|
636
|
-
|
|
637
|
-
// =========================================================================
|
|
638
|
-
// MEDIA (prefix matching - covers all common subtypes)
|
|
639
|
-
// =========================================================================
|
|
640
|
-
|
|
641
|
-
// Images: PNG, JPEG, GIF, SVG, WebP, AVIF, HEIC, BMP, TIFF, ICO, etc.
|
|
642
|
-
'image/',
|
|
643
|
-
|
|
644
|
-
// Audio: MP3, OGG, WAV, WebM, AAC, FLAC, Opus, etc.
|
|
645
|
-
'audio/',
|
|
646
|
-
|
|
647
|
-
// Video: MP4, WebM, OGG, QuickTime, etc.
|
|
648
|
-
'video/',
|
|
649
|
-
|
|
650
|
-
// Modern fonts: WOFF2, WOFF, TTF, OTF
|
|
651
|
-
'font/',
|
|
652
|
-
|
|
653
|
-
// =========================================================================
|
|
654
|
-
// CORE WEB APPLICATION TYPES
|
|
655
|
-
// =========================================================================
|
|
656
|
-
|
|
657
|
-
// JavaScript (multiple MIME types for compatibility)
|
|
658
|
-
'application/javascript', // Modern standard (RFC 9239)
|
|
659
|
-
'application/ecmascript', // ECMAScript (legacy but still used)
|
|
660
|
-
'application/x-javascript', // Legacy variant (old CDNs, Apache configs)
|
|
661
|
-
|
|
662
|
-
// WebAssembly (modern web apps, games, compute-heavy workloads)
|
|
663
|
-
'application/wasm',
|
|
664
|
-
|
|
665
|
-
// JSON and structured data
|
|
666
|
-
'application/json',
|
|
667
|
-
'application/ld+json', // JSON-LD for structured data / SEO (Schema.org, Open Graph)
|
|
668
|
-
'application/geo+json', // GeoJSON for mapping (Leaflet, Mapbox)
|
|
669
|
-
'application/manifest+json', // PWA web app manifests
|
|
670
|
-
'application/x-ipynb+json', // Jupyter Notebooks (data science, ML tutorials)
|
|
671
|
-
|
|
672
|
-
// JSON variants (AI/ML, streaming data, configs)
|
|
673
|
-
'application/x-ndjson', // Newline-Delimited JSON (training datasets, logs)
|
|
674
|
-
'application/ndjson', // NDJSON (alternative MIME type)
|
|
675
|
-
'text/x-ndjson', // NDJSON (text variant)
|
|
676
|
-
'application/jsonl', // JSON Lines (Hugging Face, OpenAI fine-tuning)
|
|
677
|
-
'text/jsonl', // JSON Lines (text variant)
|
|
678
|
-
'application/json5', // JSON5 (JSON with comments, trailing commas)
|
|
679
|
-
'text/json5', // JSON5 (text variant)
|
|
680
|
-
'application/schema+json', // JSON Schema (API specs, model definitions)
|
|
681
|
-
|
|
682
|
-
// Development tools
|
|
683
|
-
'application/source-map', // Source maps (.js.map, .css.map) for debugging
|
|
684
|
-
|
|
685
|
-
// XML and feeds
|
|
686
|
-
'application/xml',
|
|
687
|
-
'application/xhtml+xml', // XHTML - XML-compliant HTML (legacy sites)
|
|
688
|
-
'application/rss+xml', // RSS feeds (blogs, podcasts)
|
|
689
|
-
'application/atom+xml', // Atom feeds
|
|
690
|
-
'application/feed+json', // JSON Feed (modern RSS alternative)
|
|
691
|
-
'application/vnd.google-earth.kml+xml', // KML for mapping (Google Earth, GIS)
|
|
692
|
-
|
|
693
|
-
// Configuration formats
|
|
694
|
-
'application/yaml', // YAML configs (static site generators)
|
|
695
|
-
'application/toml', // TOML configs (Cargo, Netlify, Rust projects)
|
|
696
|
-
|
|
697
|
-
// Documents
|
|
698
|
-
'application/pdf', // PDF documents
|
|
699
|
-
|
|
700
|
-
// Media metadata
|
|
701
|
-
'application/x-subrip', // SRT subtitles (SubRip format)
|
|
702
|
-
|
|
703
|
-
// Developer tools and schemas
|
|
704
|
-
'application/sql', // SQL files (database schemas, queries)
|
|
705
|
-
'application/graphql', // GraphQL schemas (API documentation)
|
|
706
|
-
'application/graphql+json', // GraphQL with JSON encoding
|
|
707
|
-
'application/x-protobuf', // Protocol Buffers binary (gRPC)
|
|
708
|
-
'application/x-ini', // INI configuration files
|
|
709
|
-
|
|
710
|
-
// Academic formats
|
|
711
|
-
'application/x-tex', // LaTeX documents
|
|
712
|
-
'application/x-bibtex', // BibTeX citations
|
|
713
|
-
|
|
714
|
-
// =========================================================================
|
|
715
|
-
// 3D FORMATS (industry standard only)
|
|
716
|
-
// =========================================================================
|
|
717
|
-
|
|
718
|
-
// glTF - Khronos standard for 3D web content
|
|
719
|
-
'model/gltf+json', // glTF JSON format
|
|
720
|
-
'model/gltf-binary', // GLB binary format
|
|
721
|
-
|
|
722
|
-
// =========================================================================
|
|
723
|
-
// LEGACY COMPATIBILITY
|
|
724
|
-
// =========================================================================
|
|
725
|
-
|
|
726
|
-
// Video (some tools detect MP4 as application/mp4)
|
|
727
|
-
'application/mp4',
|
|
728
|
-
|
|
729
|
-
// Legacy font MIME types (Bootstrap, Font Awesome, IE compatibility)
|
|
730
|
-
'application/font-woff',
|
|
731
|
-
'application/font-woff2',
|
|
732
|
-
'application/x-font-woff',
|
|
733
|
-
'application/x-woff',
|
|
734
|
-
'application/vnd.ms-fontobject', // EOT files (Internet Explorer)
|
|
735
|
-
'application/x-font-ttf',
|
|
736
|
-
'application/x-font-truetype',
|
|
737
|
-
'application/x-font-otf',
|
|
738
|
-
'application/x-font-opentype',
|
|
739
|
-
] as const;
|
|
740
|
-
|
|
741
|
-
/**
|
|
742
|
-
* Check if a MIME type is allowed for upload.
|
|
743
|
-
*
|
|
744
|
-
* Supports both exact matches and prefix matches:
|
|
745
|
-
* - 'application/json' matches 'application/json' exactly
|
|
746
|
-
* - 'text/' matches 'text/plain', 'text/html', etc.
|
|
531
|
+
* The blocklist targets file types that pose direct security risks when hosted:
|
|
532
|
+
* executables, disk images, malware vectors, dangerous scripts, and shortcuts.
|
|
533
|
+
*/
|
|
534
|
+
export const BLOCKED_EXTENSIONS: ReadonlySet<string> = new Set([
|
|
535
|
+
// Executables
|
|
536
|
+
'exe', 'msi', 'dll', 'scr', 'bat', 'cmd', 'com', 'pif', 'app', 'deb', 'rpm',
|
|
537
|
+
// Installers
|
|
538
|
+
'pkg', 'mpkg',
|
|
539
|
+
// Disk images
|
|
540
|
+
'dmg', 'iso', 'img',
|
|
541
|
+
// Malware vectors
|
|
542
|
+
'cab', 'cpl', 'chm',
|
|
543
|
+
// Dangerous scripts
|
|
544
|
+
'ps1', 'vbs', 'vbe', 'ws', 'wsf', 'wsc', 'wsh', 'reg',
|
|
545
|
+
// Java
|
|
546
|
+
'jar', 'jnlp',
|
|
547
|
+
// Mobile/browser packages
|
|
548
|
+
'apk', 'crx',
|
|
549
|
+
// Shortcut/link
|
|
550
|
+
'lnk', 'inf', 'hta',
|
|
551
|
+
]);
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Check if a filename has a blocked extension.
|
|
555
|
+
* Extracts the extension from the filename and checks against the blocklist.
|
|
556
|
+
* Case-insensitive. Returns false for files without extensions.
|
|
747
557
|
*
|
|
748
558
|
* @example
|
|
749
|
-
*
|
|
750
|
-
*
|
|
751
|
-
*
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
);
|
|
559
|
+
* isBlockedExtension('virus.exe') // true
|
|
560
|
+
* isBlockedExtension('app.dmg') // true
|
|
561
|
+
* isBlockedExtension('style.css') // false
|
|
562
|
+
* isBlockedExtension('data.custom') // false
|
|
563
|
+
* isBlockedExtension('README') // false
|
|
564
|
+
*/
|
|
565
|
+
export function isBlockedExtension(filename: string): boolean {
|
|
566
|
+
const dotIndex = filename.lastIndexOf('.');
|
|
567
|
+
if (dotIndex === -1 || dotIndex === filename.length - 1) return false;
|
|
568
|
+
const ext = filename.slice(dotIndex + 1).toLowerCase();
|
|
569
|
+
return BLOCKED_EXTENSIONS.has(ext);
|
|
757
570
|
}
|
|
758
571
|
|
|
759
572
|
// =============================================================================
|
|
760
|
-
// COMMON RESPONSE PATTERNS
|
|
573
|
+
// COMMON RESPONSE PATTERNS
|
|
761
574
|
// =============================================================================
|
|
762
575
|
|
|
763
576
|
/**
|
|
@@ -1068,8 +881,6 @@ export interface BillingStatus {
|
|
|
1068
881
|
billing: string | null;
|
|
1069
882
|
/** Number of billing units (1 unit = 1 custom domain), null if no billing */
|
|
1070
883
|
units: number | null;
|
|
1071
|
-
/** Number of custom domains currently in use, null if no billing */
|
|
1072
|
-
usage: number | null;
|
|
1073
884
|
/** Billing status from Creem (active, trialing, canceled, etc.), null if no billing */
|
|
1074
885
|
status: string | null;
|
|
1075
886
|
/** Link to Creem customer portal for billing management, null if unavailable */
|
|
@@ -1294,7 +1105,6 @@ export interface ValidationIssue {
|
|
|
1294
1105
|
export interface ValidatableFile {
|
|
1295
1106
|
name: string;
|
|
1296
1107
|
size: number;
|
|
1297
|
-
type: string;
|
|
1298
1108
|
status?: FileValidationStatusType;
|
|
1299
1109
|
statusMessage?: string;
|
|
1300
1110
|
}
|