@sylphx/sdk 0.3.4 → 0.3.6

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.
@@ -19782,18 +19782,20 @@ interface AccessTokenPayload {
19782
19782
  * 4. No silent fixes - Transparency over convenience (but warn + continue)
19783
19783
  * 5. Single Source of Truth - All key logic in one place
19784
19784
  *
19785
- * Key Formats (OAuth 2.0 Standard):
19786
- * - App ID: app_(dev|stg|prod)_[identifier]Public identifier (like OAuth client_id)
19787
- * - Secret Key: sk_(dev|stg|prod)_[identifier]Server-side only (like OAuth client_secret)
19785
+ * Key Formats (ADR-021):
19786
+ * - Publishable key: pk_(dev|stg|prod)_{ref}_{32hex}client-safe (new)
19787
+ * - Secret Key: sk_(dev|stg|prod)_{ref}_{64hex}server-side only
19788
19788
  *
19789
- * Identifier Types:
19790
- * - Customer apps: 32 hex chars
19791
- * - Platform apps: platform_{app-slug} (e.g., platform_sylphx-console)
19789
+ * Legacy Key Formats (backward-compat):
19790
+ * - App ID (old): app_(dev|stg|prod)_[identifier] Public identifier
19791
+ *
19792
+ * Special Internal Formats (NOT rotated):
19793
+ * - Console bootstrap: app_prod_platform_{slug} / sk_prod_platform_{slug}
19792
19794
  */
19793
19795
  /** Environment type derived from key prefix */
19794
19796
  type EnvironmentType = 'development' | 'staging' | 'production';
19795
- /** Key type - appId (public) or secret (server) */
19796
- type KeyType = 'appId' | 'secret';
19797
+ /** Key type - publicKey (pk_*), appId (legacy app_*), or secret (sk_*) */
19798
+ type KeyType = 'publicKey' | 'appId' | 'secret';
19797
19799
  /** Validation result with clear error information */
19798
19800
  interface KeyValidationResult {
19799
19801
  /** Whether the key is valid (possibly after sanitization) */
@@ -19812,7 +19814,9 @@ interface KeyValidationResult {
19812
19814
  issues?: string[];
19813
19815
  }
19814
19816
  /**
19815
- * Validate an App ID and return detailed results
19817
+ * Validate a legacy App ID (app_*) and return detailed results.
19818
+ *
19819
+ * @deprecated Use validatePublicKey() for new pk_* keys (ADR-021).
19816
19820
  *
19817
19821
  * @example
19818
19822
  * ```typescript
@@ -19827,8 +19831,9 @@ interface KeyValidationResult {
19827
19831
  */
19828
19832
  declare function validateAppId(key: string | undefined | null): KeyValidationResult;
19829
19833
  /**
19830
- * Validate and sanitize App ID, logging warnings
19834
+ * Validate and sanitize App ID, logging warnings.
19831
19835
  *
19836
+ * @deprecated Use validateAndSanitizePublicKey() for new pk_* keys (ADR-021).
19832
19837
  * @throws Error if the key is invalid and cannot be sanitized
19833
19838
  * @returns The sanitized App ID
19834
19839
  */
@@ -19887,17 +19892,19 @@ declare function isProductionKey(key: string): boolean;
19887
19892
  */
19888
19893
  declare function getCookieNamespace(secretKey: string): string;
19889
19894
  /**
19890
- * Detect the type of key (App ID or Secret Key)
19895
+ * Detect the type of key.
19891
19896
  *
19892
- * @returns 'appId', 'secret', or null if unknown
19897
+ * @returns 'publicKey' (pk_*), 'appId' (legacy app_*), 'secret' (sk_*), or null if unknown
19893
19898
  */
19894
19899
  declare function detectKeyType(key: string): KeyType | null;
19895
19900
  /**
19896
- * Check if a key is an App ID
19901
+ * Check if a key is an App ID (legacy app_* format)
19902
+ *
19903
+ * @deprecated Use isPublishableKey() to also accept new pk_* keys
19897
19904
  */
19898
19905
  declare function isAppId(key: string): boolean;
19899
19906
  /**
19900
- * Check if a key is a secret key
19907
+ * Check if a key is a secret key (sk_*)
19901
19908
  */
19902
19909
  declare function isSecretKey(key: string): boolean;
19903
19910
  /**
@@ -19782,18 +19782,20 @@ interface AccessTokenPayload {
19782
19782
  * 4. No silent fixes - Transparency over convenience (but warn + continue)
19783
19783
  * 5. Single Source of Truth - All key logic in one place
19784
19784
  *
19785
- * Key Formats (OAuth 2.0 Standard):
19786
- * - App ID: app_(dev|stg|prod)_[identifier]Public identifier (like OAuth client_id)
19787
- * - Secret Key: sk_(dev|stg|prod)_[identifier]Server-side only (like OAuth client_secret)
19785
+ * Key Formats (ADR-021):
19786
+ * - Publishable key: pk_(dev|stg|prod)_{ref}_{32hex}client-safe (new)
19787
+ * - Secret Key: sk_(dev|stg|prod)_{ref}_{64hex}server-side only
19788
19788
  *
19789
- * Identifier Types:
19790
- * - Customer apps: 32 hex chars
19791
- * - Platform apps: platform_{app-slug} (e.g., platform_sylphx-console)
19789
+ * Legacy Key Formats (backward-compat):
19790
+ * - App ID (old): app_(dev|stg|prod)_[identifier] Public identifier
19791
+ *
19792
+ * Special Internal Formats (NOT rotated):
19793
+ * - Console bootstrap: app_prod_platform_{slug} / sk_prod_platform_{slug}
19792
19794
  */
19793
19795
  /** Environment type derived from key prefix */
19794
19796
  type EnvironmentType = 'development' | 'staging' | 'production';
19795
- /** Key type - appId (public) or secret (server) */
19796
- type KeyType = 'appId' | 'secret';
19797
+ /** Key type - publicKey (pk_*), appId (legacy app_*), or secret (sk_*) */
19798
+ type KeyType = 'publicKey' | 'appId' | 'secret';
19797
19799
  /** Validation result with clear error information */
19798
19800
  interface KeyValidationResult {
19799
19801
  /** Whether the key is valid (possibly after sanitization) */
@@ -19812,7 +19814,9 @@ interface KeyValidationResult {
19812
19814
  issues?: string[];
19813
19815
  }
19814
19816
  /**
19815
- * Validate an App ID and return detailed results
19817
+ * Validate a legacy App ID (app_*) and return detailed results.
19818
+ *
19819
+ * @deprecated Use validatePublicKey() for new pk_* keys (ADR-021).
19816
19820
  *
19817
19821
  * @example
19818
19822
  * ```typescript
@@ -19827,8 +19831,9 @@ interface KeyValidationResult {
19827
19831
  */
19828
19832
  declare function validateAppId(key: string | undefined | null): KeyValidationResult;
19829
19833
  /**
19830
- * Validate and sanitize App ID, logging warnings
19834
+ * Validate and sanitize App ID, logging warnings.
19831
19835
  *
19836
+ * @deprecated Use validateAndSanitizePublicKey() for new pk_* keys (ADR-021).
19832
19837
  * @throws Error if the key is invalid and cannot be sanitized
19833
19838
  * @returns The sanitized App ID
19834
19839
  */
@@ -19887,17 +19892,19 @@ declare function isProductionKey(key: string): boolean;
19887
19892
  */
19888
19893
  declare function getCookieNamespace(secretKey: string): string;
19889
19894
  /**
19890
- * Detect the type of key (App ID or Secret Key)
19895
+ * Detect the type of key.
19891
19896
  *
19892
- * @returns 'appId', 'secret', or null if unknown
19897
+ * @returns 'publicKey' (pk_*), 'appId' (legacy app_*), 'secret' (sk_*), or null if unknown
19893
19898
  */
19894
19899
  declare function detectKeyType(key: string): KeyType | null;
19895
19900
  /**
19896
- * Check if a key is an App ID
19901
+ * Check if a key is an App ID (legacy app_* format)
19902
+ *
19903
+ * @deprecated Use isPublishableKey() to also accept new pk_* keys
19897
19904
  */
19898
19905
  declare function isAppId(key: string): boolean;
19899
19906
  /**
19900
- * Check if a key is a secret key
19907
+ * Check if a key is a secret key (sk_*)
19901
19908
  */
19902
19909
  declare function isSecretKey(key: string): boolean;
19903
19910
  /**
@@ -1413,6 +1413,7 @@ function exponentialBackoff(attempt, baseDelay = BASE_RETRY_DELAY_MS, maxDelay =
1413
1413
  }
1414
1414
 
1415
1415
  // src/key-validation.ts
1416
+ var PUBLIC_KEY_PATTERN = /^pk_(dev|stg|prod)_[a-z0-9]{12}_[a-f0-9]{32}$/;
1416
1417
  var APP_ID_PATTERN = /^app_(dev|stg|prod)_[a-z0-9_-]+$/;
1417
1418
  var SECRET_KEY_PATTERN = /^sk_(dev|stg|prod)_[a-z0-9_-]+$/;
1418
1419
  var ENV_PREFIX_MAP = {
@@ -1503,6 +1504,9 @@ function validateKeyForType(key, keyType, pattern, envVarName) {
1503
1504
  issues: [...issues, "invalid-format"]
1504
1505
  };
1505
1506
  }
1507
+ function validatePublicKey(key) {
1508
+ return validateKeyForType(key, "publicKey", PUBLIC_KEY_PATTERN, "NEXT_PUBLIC_SYLPHX_KEY");
1509
+ }
1506
1510
  function validateAppId(key) {
1507
1511
  return validateKeyForType(key, "appId", APP_ID_PATTERN, "NEXT_PUBLIC_SYLPHX_APP_ID");
1508
1512
  }
@@ -1531,22 +1535,23 @@ function validateAndSanitizeSecretKey(key) {
1531
1535
  }
1532
1536
  function detectEnvironment(key) {
1533
1537
  const sanitized = key.trim().toLowerCase();
1538
+ if (sanitized.startsWith("pk_")) {
1539
+ const result = validatePublicKey(sanitized);
1540
+ if (!result.valid) throw new Error(result.error);
1541
+ return result.environment;
1542
+ }
1534
1543
  if (sanitized.startsWith("sk_")) {
1535
1544
  const result = validateSecretKey(sanitized);
1536
- if (!result.valid) {
1537
- throw new Error(result.error);
1538
- }
1545
+ if (!result.valid) throw new Error(result.error);
1539
1546
  return result.environment;
1540
1547
  }
1541
1548
  if (sanitized.startsWith("app_")) {
1542
1549
  const result = validateAppId(sanitized);
1543
- if (!result.valid) {
1544
- throw new Error(result.error);
1545
- }
1550
+ if (!result.valid) throw new Error(result.error);
1546
1551
  return result.environment;
1547
1552
  }
1548
1553
  throw new Error(
1549
- `[Sylphx] Invalid key format. Key must start with 'sk_' (secret) or 'app_' (App ID).`
1554
+ `[Sylphx] Invalid key format. Key must start with 'pk_' (publishable), 'sk_' (secret), or 'app_' (legacy App ID).`
1550
1555
  );
1551
1556
  }
1552
1557
  function isDevelopmentKey(key) {
@@ -1562,6 +1567,7 @@ function getCookieNamespace(secretKey) {
1562
1567
  }
1563
1568
  function detectKeyType(key) {
1564
1569
  const sanitized = key.trim().toLowerCase();
1570
+ if (sanitized.startsWith("pk_")) return "publicKey";
1565
1571
  if (sanitized.startsWith("app_")) return "appId";
1566
1572
  if (sanitized.startsWith("sk_")) return "secret";
1567
1573
  return null;
@@ -1574,6 +1580,9 @@ function isSecretKey(key) {
1574
1580
  }
1575
1581
  function validateKey(key) {
1576
1582
  const keyType = key ? detectKeyType(key) : null;
1583
+ if (keyType === "publicKey") {
1584
+ return validatePublicKey(key);
1585
+ }
1577
1586
  if (keyType === "appId") {
1578
1587
  return validateAppId(key);
1579
1588
  }
@@ -1583,7 +1592,7 @@ function validateKey(key) {
1583
1592
  return {
1584
1593
  valid: false,
1585
1594
  sanitizedKey: "",
1586
- error: key ? `Invalid key format. Keys must start with 'app_' (App ID) or 'sk_' (Secret Key), followed by environment (dev/stg/prod) and identifier. Got: ${key.slice(0, 20)}...` : "API key is required but was not provided.",
1595
+ error: key ? `Invalid key format. Keys must start with 'pk_' (publishable), 'app_' (legacy), or 'sk_' (secret), followed by environment (dev/stg/prod). Got: ${key.slice(0, 20)}...` : "API key is required but was not provided.",
1587
1596
  issues: key ? ["invalid_format"] : ["missing"]
1588
1597
  };
1589
1598
  }
@@ -2582,14 +2591,18 @@ function createWebhookHandler(config) {
2582
2591
  };
2583
2592
  }
2584
2593
  async function cachedFetch(params) {
2585
- const { url, headers, fallback, label, revalidate = 60 } = params;
2594
+ const { url, headers, fallback, label, revalidate = 60, timeout = 3e3 } = params;
2586
2595
  try {
2596
+ const controller = new AbortController();
2597
+ const timer = setTimeout(() => controller.abort(), timeout);
2587
2598
  const response = await fetch(url, {
2588
2599
  headers,
2600
+ signal: controller.signal,
2589
2601
  // @ts-expect-error - Next.js extended fetch option
2590
2602
  next: { revalidate }
2591
2603
  // Next.js Data Cache with TTL
2592
2604
  });
2605
+ clearTimeout(timer);
2593
2606
  if (!response.ok) {
2594
2607
  console.warn(`[Sylphx] Failed to fetch ${label}:`, response.status);
2595
2608
  return fallback;
@@ -2597,7 +2610,11 @@ async function cachedFetch(params) {
2597
2610
  const data = await response.json();
2598
2611
  return data ?? fallback;
2599
2612
  } catch (error) {
2600
- console.warn(`[Sylphx] Failed to fetch ${label}:`, error);
2613
+ if (error instanceof DOMException && error.name === "AbortError") {
2614
+ console.warn(`[Sylphx] Timeout fetching ${label} (${timeout}ms)`);
2615
+ } else {
2616
+ console.warn(`[Sylphx] Failed to fetch ${label}:`, error);
2617
+ }
2601
2618
  return fallback;
2602
2619
  }
2603
2620
  }