@shipstatic/types 0.1.9 → 0.1.10

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
@@ -215,4 +215,14 @@ export interface PingResponse {
215
215
  timestamp?: number;
216
216
  }
217
217
  export declare const API_KEY_PREFIX = "ship-";
218
+ export declare const API_KEY_HEX_LENGTH = 64;
219
+ export declare const API_KEY_TOTAL_LENGTH: number;
218
220
  export declare const DEPLOYMENT_CONFIG_FILENAME = "ship.json";
221
+ /**
222
+ * Validate API key format
223
+ */
224
+ export declare function validateApiKey(apiKey: string): void;
225
+ /**
226
+ * Validate API URL format
227
+ */
228
+ export declare function validateApiUrl(apiUrl: string): void;
package/dist/index.js CHANGED
@@ -159,5 +159,48 @@ export const serverConfig = {
159
159
  };
160
160
  // API Key Configuration
161
161
  export const API_KEY_PREFIX = 'ship-';
162
+ export const API_KEY_HEX_LENGTH = 64;
163
+ export const API_KEY_TOTAL_LENGTH = API_KEY_PREFIX.length + API_KEY_HEX_LENGTH; // 69
162
164
  // Deployment Configuration
163
165
  export const DEPLOYMENT_CONFIG_FILENAME = 'ship.json';
166
+ // =============================================================================
167
+ // VALIDATION UTILITIES
168
+ // =============================================================================
169
+ /**
170
+ * Validate API key format
171
+ */
172
+ export function validateApiKey(apiKey) {
173
+ if (!apiKey.startsWith(API_KEY_PREFIX)) {
174
+ throw ShipError.validation(`API key must start with "${API_KEY_PREFIX}"`);
175
+ }
176
+ if (apiKey.length !== API_KEY_TOTAL_LENGTH) {
177
+ throw ShipError.validation(`API key must be ${API_KEY_TOTAL_LENGTH} characters total (${API_KEY_PREFIX} + ${API_KEY_HEX_LENGTH} hex chars)`);
178
+ }
179
+ const hexPart = apiKey.slice(API_KEY_PREFIX.length);
180
+ if (!/^[a-f0-9]{64}$/i.test(hexPart)) {
181
+ throw ShipError.validation(`API key must contain ${API_KEY_HEX_LENGTH} hexadecimal characters after "${API_KEY_PREFIX}" prefix`);
182
+ }
183
+ }
184
+ /**
185
+ * Validate API URL format
186
+ */
187
+ export function validateApiUrl(apiUrl) {
188
+ try {
189
+ const url = new URL(apiUrl);
190
+ if (!['http:', 'https:'].includes(url.protocol)) {
191
+ throw ShipError.validation('API URL must use http:// or https:// protocol');
192
+ }
193
+ if (url.pathname !== '/' && url.pathname !== '') {
194
+ throw ShipError.validation('API URL must not contain a path');
195
+ }
196
+ if (url.search || url.hash) {
197
+ throw ShipError.validation('API URL must not contain query parameters or fragments');
198
+ }
199
+ }
200
+ catch (error) {
201
+ if (error instanceof ShipError) {
202
+ throw error;
203
+ }
204
+ throw ShipError.validation('API URL must be a valid URL');
205
+ }
206
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shipstatic/types",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Shared types for Shipstatic platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -357,6 +357,56 @@ export interface PingResponse {
357
357
 
358
358
  // API Key Configuration
359
359
  export const API_KEY_PREFIX = 'ship-';
360
+ export const API_KEY_HEX_LENGTH = 64;
361
+ export const API_KEY_TOTAL_LENGTH = API_KEY_PREFIX.length + API_KEY_HEX_LENGTH; // 69
360
362
 
361
363
  // Deployment Configuration
362
- export const DEPLOYMENT_CONFIG_FILENAME = 'ship.json';
364
+ export const DEPLOYMENT_CONFIG_FILENAME = 'ship.json';
365
+
366
+ // =============================================================================
367
+ // VALIDATION UTILITIES
368
+ // =============================================================================
369
+
370
+ /**
371
+ * Validate API key format
372
+ */
373
+ export function validateApiKey(apiKey: string): void {
374
+ if (!apiKey.startsWith(API_KEY_PREFIX)) {
375
+ throw ShipError.validation(`API key must start with "${API_KEY_PREFIX}"`);
376
+ }
377
+
378
+ if (apiKey.length !== API_KEY_TOTAL_LENGTH) {
379
+ throw ShipError.validation(`API key must be ${API_KEY_TOTAL_LENGTH} characters total (${API_KEY_PREFIX} + ${API_KEY_HEX_LENGTH} hex chars)`);
380
+ }
381
+
382
+ const hexPart = apiKey.slice(API_KEY_PREFIX.length);
383
+ if (!/^[a-f0-9]{64}$/i.test(hexPart)) {
384
+ throw ShipError.validation(`API key must contain ${API_KEY_HEX_LENGTH} hexadecimal characters after "${API_KEY_PREFIX}" prefix`);
385
+ }
386
+ }
387
+
388
+ /**
389
+ * Validate API URL format
390
+ */
391
+ export function validateApiUrl(apiUrl: string): void {
392
+ try {
393
+ const url = new URL(apiUrl);
394
+
395
+ if (!['http:', 'https:'].includes(url.protocol)) {
396
+ throw ShipError.validation('API URL must use http:// or https:// protocol');
397
+ }
398
+
399
+ if (url.pathname !== '/' && url.pathname !== '') {
400
+ throw ShipError.validation('API URL must not contain a path');
401
+ }
402
+
403
+ if (url.search || url.hash) {
404
+ throw ShipError.validation('API URL must not contain query parameters or fragments');
405
+ }
406
+ } catch (error) {
407
+ if (error instanceof ShipError) {
408
+ throw error;
409
+ }
410
+ throw ShipError.validation('API URL must be a valid URL');
411
+ }
412
+ }