@shipstatic/types 0.9.9 → 0.9.11

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
@@ -38,6 +38,8 @@ export interface Deployment {
38
38
  readonly created: number;
39
39
  /** Unix timestamp (seconds) when deployment expires, null if never */
40
40
  expires: number | null;
41
+ /** Screenshot URL for this deployment (e.g., 'https://screenshots.shipstatic.com/happy-cat-abc1234/a3f2c1b4d5e6f789') */
42
+ readonly screenshot: string;
41
43
  }
42
44
  /**
43
45
  * Response from deployment creation. Extends Deployment with one-time fields
@@ -692,7 +694,8 @@ export interface DeploymentUploadOptions {
692
694
  * Optional password that protects this deployment.
693
695
  *
694
696
  * Length: {@link PASSWORD_CONSTRAINTS.MIN_LENGTH} to
695
- * {@link PASSWORD_CONSTRAINTS.MAX_LENGTH} characters; whitespace is
697
+ * {@link PASSWORD_CONSTRAINTS.MAX_LENGTH} characters. Leading and trailing
698
+ * whitespace is trimmed before validation; internal whitespace is
696
699
  * significant. Visitors are prompted to enter the password before they can
697
700
  * view the deployment — including on any custom domains pointing at it.
698
701
  * To remove protection, redeploy without a password.
@@ -1015,10 +1018,18 @@ export declare const PASSWORD_CONSTRAINTS: {
1015
1018
  /**
1016
1019
  * Validate an optional deployment password and return it normalized.
1017
1020
  *
1018
- * Absent (`undefined` / `null`) → returns `undefined`; an unprotected
1019
- * deployment is a valid choice. Present → must be a string within
1020
- * `PASSWORD_CONSTRAINTS` length bounds. Whitespace is preserved verbatim
1021
- * significant. Throws `ShipError.validation` on breach.
1021
+ * Absent (`undefined` / `null`) → returns `undefined`. Present → trim
1022
+ * leading/trailing whitespace, then validate against `PASSWORD_CONSTRAINTS`
1023
+ * length bounds (internal whitespace is significant and counts toward
1024
+ * length). Throws `ShipError.validation` on breach; returns the trimmed
1025
+ * value.
1026
+ *
1027
+ * The trim is canonical: at upload, the API hashes the trimmed value; at
1028
+ * unlock, the router trims submissions before hashing. Submission and storage
1029
+ * agree byte-for-byte. Length validation runs on the trimmed value because
1030
+ * that's the user's actual intent — and it disarms a class of invisible
1031
+ * foot-guns (trailing newlines from copy/paste, mobile auto-spacing,
1032
+ * password-manager artifacts).
1022
1033
  *
1023
1034
  * Single source of truth shared by SDK (client-side validation, return
1024
1035
  * ignored) and API (server-side enforcement, return threaded into config).
package/dist/index.js CHANGED
@@ -664,10 +664,18 @@ export const PASSWORD_CONSTRAINTS = {
664
664
  /**
665
665
  * Validate an optional deployment password and return it normalized.
666
666
  *
667
- * Absent (`undefined` / `null`) → returns `undefined`; an unprotected
668
- * deployment is a valid choice. Present → must be a string within
669
- * `PASSWORD_CONSTRAINTS` length bounds. Whitespace is preserved verbatim
670
- * significant. Throws `ShipError.validation` on breach.
667
+ * Absent (`undefined` / `null`) → returns `undefined`. Present → trim
668
+ * leading/trailing whitespace, then validate against `PASSWORD_CONSTRAINTS`
669
+ * length bounds (internal whitespace is significant and counts toward
670
+ * length). Throws `ShipError.validation` on breach; returns the trimmed
671
+ * value.
672
+ *
673
+ * The trim is canonical: at upload, the API hashes the trimmed value; at
674
+ * unlock, the router trims submissions before hashing. Submission and storage
675
+ * agree byte-for-byte. Length validation runs on the trimmed value because
676
+ * that's the user's actual intent — and it disarms a class of invisible
677
+ * foot-guns (trailing newlines from copy/paste, mobile auto-spacing,
678
+ * password-manager artifacts).
671
679
  *
672
680
  * Single source of truth shared by SDK (client-side validation, return
673
681
  * ignored) and API (server-side enforcement, return threaded into config).
@@ -680,9 +688,10 @@ export function validatePassword(value) {
680
688
  if (typeof value !== 'string') {
681
689
  throw ShipError.validation('Password must be a string');
682
690
  }
683
- if (value.length < PASSWORD_CONSTRAINTS.MIN_LENGTH ||
684
- value.length > PASSWORD_CONSTRAINTS.MAX_LENGTH) {
691
+ const trimmed = value.trim();
692
+ if (trimmed.length < PASSWORD_CONSTRAINTS.MIN_LENGTH ||
693
+ trimmed.length > PASSWORD_CONSTRAINTS.MAX_LENGTH) {
685
694
  throw ShipError.validation(`Password must be between ${PASSWORD_CONSTRAINTS.MIN_LENGTH} and ${PASSWORD_CONSTRAINTS.MAX_LENGTH} characters`);
686
695
  }
687
- return value;
696
+ return trimmed;
688
697
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipstatic/types",
3
- "version": "0.9.9",
3
+ "version": "0.9.11",
4
4
  "description": "Shared types for ShipStatic platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -45,6 +45,8 @@ export interface Deployment {
45
45
  readonly created: number;
46
46
  /** Unix timestamp (seconds) when deployment expires, null if never */
47
47
  expires: number | null; // Mutable - can be updated
48
+ /** Screenshot URL for this deployment (e.g., 'https://screenshots.shipstatic.com/happy-cat-abc1234/a3f2c1b4d5e6f789') */
49
+ readonly screenshot: string;
48
50
  }
49
51
 
50
52
 
@@ -1065,7 +1067,8 @@ export interface DeploymentUploadOptions {
1065
1067
  * Optional password that protects this deployment.
1066
1068
  *
1067
1069
  * Length: {@link PASSWORD_CONSTRAINTS.MIN_LENGTH} to
1068
- * {@link PASSWORD_CONSTRAINTS.MAX_LENGTH} characters; whitespace is
1070
+ * {@link PASSWORD_CONSTRAINTS.MAX_LENGTH} characters. Leading and trailing
1071
+ * whitespace is trimmed before validation; internal whitespace is
1069
1072
  * significant. Visitors are prompted to enter the password before they can
1070
1073
  * view the deployment — including on any custom domains pointing at it.
1071
1074
  * To remove protection, redeploy without a password.
@@ -1529,10 +1532,18 @@ export const PASSWORD_CONSTRAINTS = {
1529
1532
  /**
1530
1533
  * Validate an optional deployment password and return it normalized.
1531
1534
  *
1532
- * Absent (`undefined` / `null`) → returns `undefined`; an unprotected
1533
- * deployment is a valid choice. Present → must be a string within
1534
- * `PASSWORD_CONSTRAINTS` length bounds. Whitespace is preserved verbatim
1535
- * significant. Throws `ShipError.validation` on breach.
1535
+ * Absent (`undefined` / `null`) → returns `undefined`. Present → trim
1536
+ * leading/trailing whitespace, then validate against `PASSWORD_CONSTRAINTS`
1537
+ * length bounds (internal whitespace is significant and counts toward
1538
+ * length). Throws `ShipError.validation` on breach; returns the trimmed
1539
+ * value.
1540
+ *
1541
+ * The trim is canonical: at upload, the API hashes the trimmed value; at
1542
+ * unlock, the router trims submissions before hashing. Submission and storage
1543
+ * agree byte-for-byte. Length validation runs on the trimmed value because
1544
+ * that's the user's actual intent — and it disarms a class of invisible
1545
+ * foot-guns (trailing newlines from copy/paste, mobile auto-spacing,
1546
+ * password-manager artifacts).
1536
1547
  *
1537
1548
  * Single source of truth shared by SDK (client-side validation, return
1538
1549
  * ignored) and API (server-side enforcement, return threaded into config).
@@ -1544,13 +1555,14 @@ export function validatePassword(value: unknown): string | undefined {
1544
1555
  if (typeof value !== 'string') {
1545
1556
  throw ShipError.validation('Password must be a string');
1546
1557
  }
1558
+ const trimmed = value.trim();
1547
1559
  if (
1548
- value.length < PASSWORD_CONSTRAINTS.MIN_LENGTH ||
1549
- value.length > PASSWORD_CONSTRAINTS.MAX_LENGTH
1560
+ trimmed.length < PASSWORD_CONSTRAINTS.MIN_LENGTH ||
1561
+ trimmed.length > PASSWORD_CONSTRAINTS.MAX_LENGTH
1550
1562
  ) {
1551
1563
  throw ShipError.validation(
1552
1564
  `Password must be between ${PASSWORD_CONSTRAINTS.MIN_LENGTH} and ${PASSWORD_CONSTRAINTS.MAX_LENGTH} characters`,
1553
1565
  );
1554
1566
  }
1555
- return value;
1567
+ return trimmed;
1556
1568
  }