@shipstatic/types 2.5.0-beta.16 → 2.5.0-beta.17

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 CHANGED
@@ -775,6 +775,28 @@ export declare const BLOCKED_EXTENSIONS: ReadonlySet<string>;
775
775
  * isBlockedExtension('README') // false
776
776
  */
777
777
  export declare function isBlockedExtension(filename: string): boolean;
778
+ /**
779
+ * The `accept` attribute value for a browser file picker offering web files.
780
+ *
781
+ * **This is a hint, never a rule.** `BLOCKED_EXTENSIONS` is the platform's
782
+ * gate and the only thing that decides what may be hosted; this constant
783
+ * decides what a *file dialog* shows first. The two are not two halves of one
784
+ * policy, and this one must never be consulted to accept or reject a file.
785
+ *
786
+ * The distinction is structural, not stylistic. `accept` can express only an
787
+ * allowlist, while the platform's rule is a blocklist — so this list is
788
+ * necessarily *narrower* than what the platform hosts, and reading it as
789
+ * authority would reject files the platform serves happily. It is also not
790
+ * enforcement in the browser's own terms: every file dialog offers an
791
+ * all-files escape, and **drag-and-drop ignores `accept` entirely**. The
792
+ * dropzone and the picker must reach the same verdict on the same files, and
793
+ * they do — because the verdict is `validateFiles`, downstream of both.
794
+ *
795
+ * Kept beside `BLOCKED_EXTENSIONS` so one file holds both, which is what lets
796
+ * `tests/validation-constants.test.ts` fence the invariant that matters: the
797
+ * picker must never offer a file the platform will refuse.
798
+ */
799
+ export declare const WEB_FILE_ACCEPT: string;
778
800
  /**
779
801
  * Characters that are unsafe in filenames for static hosting.
780
802
  *
package/dist/index.js CHANGED
@@ -560,6 +560,125 @@ export function isBlockedExtension(filename) {
560
560
  return BLOCKED_EXTENSIONS.has(ext);
561
561
  }
562
562
  // =============================================================================
563
+ // PICKER ACCEPT HINT
564
+ // =============================================================================
565
+ /**
566
+ * The extensions a browser file picker offers by default, grouped by role.
567
+ *
568
+ * Private on purpose: the only published form is `WEB_FILE_ACCEPT`, the
569
+ * attribute value itself. A published set would invite a call site to ask it
570
+ * whether a file is allowed — which is the one thing this list must never
571
+ * answer. See `WEB_FILE_ACCEPT`.
572
+ *
573
+ * Extensionless files (`LICENSE`, most `.well-known` entries) are inexpressible
574
+ * in `accept`, and reach a deployment by folder pick, ZIP, or drag-and-drop.
575
+ */
576
+ const WEB_FILE_EXTENSIONS = [
577
+ // Markup & documents
578
+ 'html',
579
+ 'htm',
580
+ 'xhtml',
581
+ 'xml',
582
+ 'txt',
583
+ 'md',
584
+ 'markdown',
585
+ 'pdf',
586
+ 'csv',
587
+ // Data & config
588
+ 'json',
589
+ 'jsonc',
590
+ 'webmanifest',
591
+ 'map',
592
+ 'toml',
593
+ 'yaml',
594
+ 'yml',
595
+ 'rss',
596
+ 'atom',
597
+ // Styles
598
+ 'css',
599
+ 'scss',
600
+ 'sass',
601
+ 'less',
602
+ // Scripts & modules
603
+ 'js',
604
+ 'mjs',
605
+ 'cjs',
606
+ 'jsx',
607
+ 'ts',
608
+ 'tsx',
609
+ 'wasm',
610
+ 'vue',
611
+ 'svelte',
612
+ // Images
613
+ 'png',
614
+ 'jpg',
615
+ 'jpeg',
616
+ 'gif',
617
+ 'webp',
618
+ 'avif',
619
+ 'svg',
620
+ 'ico',
621
+ 'bmp',
622
+ 'tif',
623
+ 'tiff',
624
+ 'heic',
625
+ 'heif',
626
+ // Fonts
627
+ 'woff',
628
+ 'woff2',
629
+ 'ttf',
630
+ 'otf',
631
+ 'eot',
632
+ // Audio
633
+ 'mp3',
634
+ 'wav',
635
+ 'ogg',
636
+ 'oga',
637
+ 'opus',
638
+ 'm4a',
639
+ 'aac',
640
+ 'flac',
641
+ 'weba',
642
+ // Video
643
+ 'mp4',
644
+ 'webm',
645
+ 'ogv',
646
+ 'mov',
647
+ 'm4v',
648
+ 'avi',
649
+ // 3D models
650
+ 'glb',
651
+ 'gltf',
652
+ 'usdz',
653
+ // Text tracks
654
+ 'vtt',
655
+ 'srt',
656
+ // Archive — a whole site in one file
657
+ 'zip',
658
+ ];
659
+ /**
660
+ * The `accept` attribute value for a browser file picker offering web files.
661
+ *
662
+ * **This is a hint, never a rule.** `BLOCKED_EXTENSIONS` is the platform's
663
+ * gate and the only thing that decides what may be hosted; this constant
664
+ * decides what a *file dialog* shows first. The two are not two halves of one
665
+ * policy, and this one must never be consulted to accept or reject a file.
666
+ *
667
+ * The distinction is structural, not stylistic. `accept` can express only an
668
+ * allowlist, while the platform's rule is a blocklist — so this list is
669
+ * necessarily *narrower* than what the platform hosts, and reading it as
670
+ * authority would reject files the platform serves happily. It is also not
671
+ * enforcement in the browser's own terms: every file dialog offers an
672
+ * all-files escape, and **drag-and-drop ignores `accept` entirely**. The
673
+ * dropzone and the picker must reach the same verdict on the same files, and
674
+ * they do — because the verdict is `validateFiles`, downstream of both.
675
+ *
676
+ * Kept beside `BLOCKED_EXTENSIONS` so one file holds both, which is what lets
677
+ * `tests/validation-constants.test.ts` fence the invariant that matters: the
678
+ * picker must never offer a file the platform will refuse.
679
+ */
680
+ export const WEB_FILE_ACCEPT = WEB_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(',');
681
+ // =============================================================================
563
682
  // FILENAME CHARACTER VALIDATION
564
683
  // =============================================================================
565
684
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipstatic/types",
3
- "version": "2.5.0-beta.16",
3
+ "version": "2.5.0-beta.17",
4
4
  "description": "Shared types for ShipStatic platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -1147,6 +1147,128 @@ export function isBlockedExtension(filename: string): boolean {
1147
1147
  return BLOCKED_EXTENSIONS.has(ext);
1148
1148
  }
1149
1149
 
1150
+ // =============================================================================
1151
+ // PICKER ACCEPT HINT
1152
+ // =============================================================================
1153
+
1154
+ /**
1155
+ * The extensions a browser file picker offers by default, grouped by role.
1156
+ *
1157
+ * Private on purpose: the only published form is `WEB_FILE_ACCEPT`, the
1158
+ * attribute value itself. A published set would invite a call site to ask it
1159
+ * whether a file is allowed — which is the one thing this list must never
1160
+ * answer. See `WEB_FILE_ACCEPT`.
1161
+ *
1162
+ * Extensionless files (`LICENSE`, most `.well-known` entries) are inexpressible
1163
+ * in `accept`, and reach a deployment by folder pick, ZIP, or drag-and-drop.
1164
+ */
1165
+ const WEB_FILE_EXTENSIONS = [
1166
+ // Markup & documents
1167
+ 'html',
1168
+ 'htm',
1169
+ 'xhtml',
1170
+ 'xml',
1171
+ 'txt',
1172
+ 'md',
1173
+ 'markdown',
1174
+ 'pdf',
1175
+ 'csv',
1176
+ // Data & config
1177
+ 'json',
1178
+ 'jsonc',
1179
+ 'webmanifest',
1180
+ 'map',
1181
+ 'toml',
1182
+ 'yaml',
1183
+ 'yml',
1184
+ 'rss',
1185
+ 'atom',
1186
+ // Styles
1187
+ 'css',
1188
+ 'scss',
1189
+ 'sass',
1190
+ 'less',
1191
+ // Scripts & modules
1192
+ 'js',
1193
+ 'mjs',
1194
+ 'cjs',
1195
+ 'jsx',
1196
+ 'ts',
1197
+ 'tsx',
1198
+ 'wasm',
1199
+ 'vue',
1200
+ 'svelte',
1201
+ // Images
1202
+ 'png',
1203
+ 'jpg',
1204
+ 'jpeg',
1205
+ 'gif',
1206
+ 'webp',
1207
+ 'avif',
1208
+ 'svg',
1209
+ 'ico',
1210
+ 'bmp',
1211
+ 'tif',
1212
+ 'tiff',
1213
+ 'heic',
1214
+ 'heif',
1215
+ // Fonts
1216
+ 'woff',
1217
+ 'woff2',
1218
+ 'ttf',
1219
+ 'otf',
1220
+ 'eot',
1221
+ // Audio
1222
+ 'mp3',
1223
+ 'wav',
1224
+ 'ogg',
1225
+ 'oga',
1226
+ 'opus',
1227
+ 'm4a',
1228
+ 'aac',
1229
+ 'flac',
1230
+ 'weba',
1231
+ // Video
1232
+ 'mp4',
1233
+ 'webm',
1234
+ 'ogv',
1235
+ 'mov',
1236
+ 'm4v',
1237
+ 'avi',
1238
+ // 3D models
1239
+ 'glb',
1240
+ 'gltf',
1241
+ 'usdz',
1242
+ // Text tracks
1243
+ 'vtt',
1244
+ 'srt',
1245
+ // Archive — a whole site in one file
1246
+ 'zip',
1247
+ ] as const;
1248
+
1249
+ /**
1250
+ * The `accept` attribute value for a browser file picker offering web files.
1251
+ *
1252
+ * **This is a hint, never a rule.** `BLOCKED_EXTENSIONS` is the platform's
1253
+ * gate and the only thing that decides what may be hosted; this constant
1254
+ * decides what a *file dialog* shows first. The two are not two halves of one
1255
+ * policy, and this one must never be consulted to accept or reject a file.
1256
+ *
1257
+ * The distinction is structural, not stylistic. `accept` can express only an
1258
+ * allowlist, while the platform's rule is a blocklist — so this list is
1259
+ * necessarily *narrower* than what the platform hosts, and reading it as
1260
+ * authority would reject files the platform serves happily. It is also not
1261
+ * enforcement in the browser's own terms: every file dialog offers an
1262
+ * all-files escape, and **drag-and-drop ignores `accept` entirely**. The
1263
+ * dropzone and the picker must reach the same verdict on the same files, and
1264
+ * they do — because the verdict is `validateFiles`, downstream of both.
1265
+ *
1266
+ * Kept beside `BLOCKED_EXTENSIONS` so one file holds both, which is what lets
1267
+ * `tests/validation-constants.test.ts` fence the invariant that matters: the
1268
+ * picker must never offer a file the platform will refuse.
1269
+ */
1270
+ export const WEB_FILE_ACCEPT: string = WEB_FILE_EXTENSIONS.map((ext) => `.${ext}`).join(',');
1271
+
1150
1272
  // =============================================================================
1151
1273
  // FILENAME CHARACTER VALIDATION
1152
1274
  // =============================================================================