@shipstatic/types 0.1.8 → 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 +12 -0
- package/dist/index.js +43 -0
- package/package.json +1 -1
- package/src/index.ts +53 -1
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export interface Deployment {
|
|
|
14
14
|
size: number;
|
|
15
15
|
/** Current deployment status */
|
|
16
16
|
status: 'pending' | 'success' | 'failed';
|
|
17
|
+
/** Whether deployment has configuration */
|
|
18
|
+
config?: boolean;
|
|
17
19
|
/** The deployment URL */
|
|
18
20
|
url: string;
|
|
19
21
|
/** Unix timestamp (seconds) when deployment was created */
|
|
@@ -213,4 +215,14 @@ export interface PingResponse {
|
|
|
213
215
|
timestamp?: number;
|
|
214
216
|
}
|
|
215
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;
|
|
216
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
package/src/index.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface Deployment {
|
|
|
19
19
|
size: number;
|
|
20
20
|
/** Current deployment status */
|
|
21
21
|
status: 'pending' | 'success' | 'failed';
|
|
22
|
+
/** Whether deployment has configuration */
|
|
23
|
+
config?: boolean;
|
|
22
24
|
/** The deployment URL */
|
|
23
25
|
url: string;
|
|
24
26
|
/** Unix timestamp (seconds) when deployment was created */
|
|
@@ -355,6 +357,56 @@ export interface PingResponse {
|
|
|
355
357
|
|
|
356
358
|
// API Key Configuration
|
|
357
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
|
|
358
362
|
|
|
359
363
|
// Deployment Configuration
|
|
360
|
-
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
|
+
}
|