@sylphx/sdk 0.3.3 → 0.3.5

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.
@@ -694,14 +694,6 @@ interface TaskRunStatus {
694
694
  updatedAt: string;
695
695
  }
696
696
 
697
- /**
698
- * SDK Configuration
699
- *
700
- * Create a config object that can be passed to SDK functions.
701
- * This is the foundation for the function-based API.
702
- *
703
- * Uses appId or secretKey for authentication via x-app-secret header.
704
- */
705
697
  /**
706
698
  * SDK Configuration for Pure Functions
707
699
  *
@@ -725,27 +717,26 @@ interface TaskRunStatus {
725
717
  */
726
718
  interface SylphxConfig {
727
719
  /**
728
- * Your app key — identifies the app and environment.
729
- *
730
- * Accepts either:
731
- * - Secret key (sk_dev_, sk_stg_, sk_prod_) — full access, server-side only
732
- * - Publishable key (app_dev_, app_stg_, app_prod_) — limited access, safe for client
733
- *
734
- * Get this from Platform Console → Apps → Your App → Environments
720
+ * Secret key (sk_*) full access, server-side only.
721
+ * Embed project ref, env, and routing info (ADR-021).
722
+ * Get from Platform Console → Apps → Your App → Environments.
735
723
  */
736
724
  readonly secretKey?: string;
737
725
  /**
738
- * Project refshort 16-char alphanumeric nanoid (e.g. "abc123def456ghij").
739
- *
726
+ * Publishable key (pk_*) client-safe, read-only access.
727
+ * Embeds project ref, env, and routing info (ADR-021).
728
+ * Get from Platform Console → Apps → Your App → Environments.
729
+ */
730
+ readonly publicKey?: string;
731
+ /**
732
+ * Project ref — 12-char lowercase alphanumeric string.
733
+ * Extracted from the key automatically (ADR-021).
740
734
  * The SDK targets: https://{ref}.api.sylphx.com/v1
741
- *
742
- * Get this from Platform Console → Projects → Your Project → Overview.
743
735
  */
744
736
  readonly ref: string;
745
737
  /**
746
738
  * Pre-computed base URL: https://{ref}.api.sylphx.com/v1
747
- *
748
- * Used by buildApiUrl and callApi internally.
739
+ * Derived from the embedded ref in the key.
749
740
  */
750
741
  readonly baseUrl: string;
751
742
  /** Optional: Current access token for authenticated requests */
@@ -5337,7 +5328,7 @@ interface components {
5337
5328
  OrgInvitation: {
5338
5329
  /**
5339
5330
  * @description Invitation ID
5340
- * @example ivt_3Zb83qVQxkHMJPZ8VrJfQ2
5331
+ * @example inv_3Zb83qVQxkHMJPZ8VrJfQ2
5341
5332
  */
5342
5333
  id: string
5343
5334
  /**
@@ -5407,7 +5398,7 @@ interface components {
5407
5398
  /**
5408
5399
  * Format: uuid
5409
5400
  * @description Invitation token (ID)
5410
- * @example ivt_3Zb83qVQxkHMJPZ8VrJfQ2
5401
+ * @example inv_3Zb83qVQxkHMJPZ8VrJfQ2
5411
5402
  */
5412
5403
  token: string
5413
5404
  }
@@ -15399,18 +15390,20 @@ declare function sanitizeUrl$1(url: string): string | null;
15399
15390
  * 4. No silent fixes - Transparency over convenience (but warn + continue)
15400
15391
  * 5. Single Source of Truth - All key logic in one place
15401
15392
  *
15402
- * Key Formats (OAuth 2.0 Standard):
15403
- * - App ID: app_(dev|stg|prod)_[identifier]Public identifier (like OAuth client_id)
15404
- * - Secret Key: sk_(dev|stg|prod)_[identifier]Server-side only (like OAuth client_secret)
15393
+ * Key Formats (ADR-021):
15394
+ * - Publishable key: pk_(dev|stg|prod)_{ref}_{32hex}client-safe (new)
15395
+ * - Secret Key: sk_(dev|stg|prod)_{ref}_{64hex}server-side only
15405
15396
  *
15406
- * Identifier Types:
15407
- * - Customer apps: 32 hex chars
15408
- * - Platform apps: platform_{app-slug} (e.g., platform_sylphx-console)
15397
+ * Legacy Key Formats (backward-compat):
15398
+ * - App ID (old): app_(dev|stg|prod)_[identifier] Public identifier
15399
+ *
15400
+ * Special Internal Formats (NOT rotated):
15401
+ * - Console bootstrap: app_prod_platform_{slug} / sk_prod_platform_{slug}
15409
15402
  */
15410
15403
  /** Environment type derived from key prefix */
15411
15404
  type EnvironmentType = 'development' | 'staging' | 'production';
15412
- /** Key type - appId (public) or secret (server) */
15413
- type KeyType = 'appId' | 'secret';
15405
+ /** Key type - publicKey (pk_*), appId (legacy app_*), or secret (sk_*) */
15406
+ type KeyType = 'publicKey' | 'appId' | 'secret';
15414
15407
  /** Validation result with clear error information */
15415
15408
  interface KeyValidationResult {
15416
15409
  /** Whether the key is valid (possibly after sanitization) */
@@ -15429,7 +15422,9 @@ interface KeyValidationResult {
15429
15422
  issues?: string[];
15430
15423
  }
15431
15424
  /**
15432
- * Validate an App ID and return detailed results
15425
+ * Validate a legacy App ID (app_*) and return detailed results.
15426
+ *
15427
+ * @deprecated Use validatePublicKey() for new pk_* keys (ADR-021).
15433
15428
  *
15434
15429
  * @example
15435
15430
  * ```typescript
@@ -15444,8 +15439,9 @@ interface KeyValidationResult {
15444
15439
  */
15445
15440
  declare function validateAppId(key: string | undefined | null): KeyValidationResult;
15446
15441
  /**
15447
- * Validate and sanitize App ID, logging warnings
15442
+ * Validate and sanitize App ID, logging warnings.
15448
15443
  *
15444
+ * @deprecated Use validateAndSanitizePublicKey() for new pk_* keys (ADR-021).
15449
15445
  * @throws Error if the key is invalid and cannot be sanitized
15450
15446
  * @returns The sanitized App ID
15451
15447
  */
@@ -15504,17 +15500,19 @@ declare function isProductionKey(key: string): boolean;
15504
15500
  */
15505
15501
  declare function getCookieNamespace(secretKey: string): string;
15506
15502
  /**
15507
- * Detect the type of key (App ID or Secret Key)
15503
+ * Detect the type of key.
15508
15504
  *
15509
- * @returns 'appId', 'secret', or null if unknown
15505
+ * @returns 'publicKey' (pk_*), 'appId' (legacy app_*), 'secret' (sk_*), or null if unknown
15510
15506
  */
15511
15507
  declare function detectKeyType(key: string): KeyType | null;
15512
15508
  /**
15513
- * Check if a key is an App ID
15509
+ * Check if a key is an App ID (legacy app_* format)
15510
+ *
15511
+ * @deprecated Use isPublishableKey() to also accept new pk_* keys
15514
15512
  */
15515
15513
  declare function isAppId(key: string): boolean;
15516
15514
  /**
15517
- * Check if a key is a secret key
15515
+ * Check if a key is a secret key (sk_*)
15518
15516
  */
15519
15517
  declare function isSecretKey(key: string): boolean;
15520
15518
  /**
@@ -694,14 +694,6 @@ interface TaskRunStatus {
694
694
  updatedAt: string;
695
695
  }
696
696
 
697
- /**
698
- * SDK Configuration
699
- *
700
- * Create a config object that can be passed to SDK functions.
701
- * This is the foundation for the function-based API.
702
- *
703
- * Uses appId or secretKey for authentication via x-app-secret header.
704
- */
705
697
  /**
706
698
  * SDK Configuration for Pure Functions
707
699
  *
@@ -725,27 +717,26 @@ interface TaskRunStatus {
725
717
  */
726
718
  interface SylphxConfig {
727
719
  /**
728
- * Your app key — identifies the app and environment.
729
- *
730
- * Accepts either:
731
- * - Secret key (sk_dev_, sk_stg_, sk_prod_) — full access, server-side only
732
- * - Publishable key (app_dev_, app_stg_, app_prod_) — limited access, safe for client
733
- *
734
- * Get this from Platform Console → Apps → Your App → Environments
720
+ * Secret key (sk_*) full access, server-side only.
721
+ * Embed project ref, env, and routing info (ADR-021).
722
+ * Get from Platform Console → Apps → Your App → Environments.
735
723
  */
736
724
  readonly secretKey?: string;
737
725
  /**
738
- * Project refshort 16-char alphanumeric nanoid (e.g. "abc123def456ghij").
739
- *
726
+ * Publishable key (pk_*) client-safe, read-only access.
727
+ * Embeds project ref, env, and routing info (ADR-021).
728
+ * Get from Platform Console → Apps → Your App → Environments.
729
+ */
730
+ readonly publicKey?: string;
731
+ /**
732
+ * Project ref — 12-char lowercase alphanumeric string.
733
+ * Extracted from the key automatically (ADR-021).
740
734
  * The SDK targets: https://{ref}.api.sylphx.com/v1
741
- *
742
- * Get this from Platform Console → Projects → Your Project → Overview.
743
735
  */
744
736
  readonly ref: string;
745
737
  /**
746
738
  * Pre-computed base URL: https://{ref}.api.sylphx.com/v1
747
- *
748
- * Used by buildApiUrl and callApi internally.
739
+ * Derived from the embedded ref in the key.
749
740
  */
750
741
  readonly baseUrl: string;
751
742
  /** Optional: Current access token for authenticated requests */
@@ -5337,7 +5328,7 @@ interface components {
5337
5328
  OrgInvitation: {
5338
5329
  /**
5339
5330
  * @description Invitation ID
5340
- * @example ivt_3Zb83qVQxkHMJPZ8VrJfQ2
5331
+ * @example inv_3Zb83qVQxkHMJPZ8VrJfQ2
5341
5332
  */
5342
5333
  id: string
5343
5334
  /**
@@ -5407,7 +5398,7 @@ interface components {
5407
5398
  /**
5408
5399
  * Format: uuid
5409
5400
  * @description Invitation token (ID)
5410
- * @example ivt_3Zb83qVQxkHMJPZ8VrJfQ2
5401
+ * @example inv_3Zb83qVQxkHMJPZ8VrJfQ2
5411
5402
  */
5412
5403
  token: string
5413
5404
  }
@@ -15399,18 +15390,20 @@ declare function sanitizeUrl$1(url: string): string | null;
15399
15390
  * 4. No silent fixes - Transparency over convenience (but warn + continue)
15400
15391
  * 5. Single Source of Truth - All key logic in one place
15401
15392
  *
15402
- * Key Formats (OAuth 2.0 Standard):
15403
- * - App ID: app_(dev|stg|prod)_[identifier]Public identifier (like OAuth client_id)
15404
- * - Secret Key: sk_(dev|stg|prod)_[identifier]Server-side only (like OAuth client_secret)
15393
+ * Key Formats (ADR-021):
15394
+ * - Publishable key: pk_(dev|stg|prod)_{ref}_{32hex}client-safe (new)
15395
+ * - Secret Key: sk_(dev|stg|prod)_{ref}_{64hex}server-side only
15405
15396
  *
15406
- * Identifier Types:
15407
- * - Customer apps: 32 hex chars
15408
- * - Platform apps: platform_{app-slug} (e.g., platform_sylphx-console)
15397
+ * Legacy Key Formats (backward-compat):
15398
+ * - App ID (old): app_(dev|stg|prod)_[identifier] Public identifier
15399
+ *
15400
+ * Special Internal Formats (NOT rotated):
15401
+ * - Console bootstrap: app_prod_platform_{slug} / sk_prod_platform_{slug}
15409
15402
  */
15410
15403
  /** Environment type derived from key prefix */
15411
15404
  type EnvironmentType = 'development' | 'staging' | 'production';
15412
- /** Key type - appId (public) or secret (server) */
15413
- type KeyType = 'appId' | 'secret';
15405
+ /** Key type - publicKey (pk_*), appId (legacy app_*), or secret (sk_*) */
15406
+ type KeyType = 'publicKey' | 'appId' | 'secret';
15414
15407
  /** Validation result with clear error information */
15415
15408
  interface KeyValidationResult {
15416
15409
  /** Whether the key is valid (possibly after sanitization) */
@@ -15429,7 +15422,9 @@ interface KeyValidationResult {
15429
15422
  issues?: string[];
15430
15423
  }
15431
15424
  /**
15432
- * Validate an App ID and return detailed results
15425
+ * Validate a legacy App ID (app_*) and return detailed results.
15426
+ *
15427
+ * @deprecated Use validatePublicKey() for new pk_* keys (ADR-021).
15433
15428
  *
15434
15429
  * @example
15435
15430
  * ```typescript
@@ -15444,8 +15439,9 @@ interface KeyValidationResult {
15444
15439
  */
15445
15440
  declare function validateAppId(key: string | undefined | null): KeyValidationResult;
15446
15441
  /**
15447
- * Validate and sanitize App ID, logging warnings
15442
+ * Validate and sanitize App ID, logging warnings.
15448
15443
  *
15444
+ * @deprecated Use validateAndSanitizePublicKey() for new pk_* keys (ADR-021).
15449
15445
  * @throws Error if the key is invalid and cannot be sanitized
15450
15446
  * @returns The sanitized App ID
15451
15447
  */
@@ -15504,17 +15500,19 @@ declare function isProductionKey(key: string): boolean;
15504
15500
  */
15505
15501
  declare function getCookieNamespace(secretKey: string): string;
15506
15502
  /**
15507
- * Detect the type of key (App ID or Secret Key)
15503
+ * Detect the type of key.
15508
15504
  *
15509
- * @returns 'appId', 'secret', or null if unknown
15505
+ * @returns 'publicKey' (pk_*), 'appId' (legacy app_*), 'secret' (sk_*), or null if unknown
15510
15506
  */
15511
15507
  declare function detectKeyType(key: string): KeyType | null;
15512
15508
  /**
15513
- * Check if a key is an App ID
15509
+ * Check if a key is an App ID (legacy app_* format)
15510
+ *
15511
+ * @deprecated Use isPublishableKey() to also accept new pk_* keys
15514
15512
  */
15515
15513
  declare function isAppId(key: string): boolean;
15516
15514
  /**
15517
- * Check if a key is a secret key
15515
+ * Check if a key is a secret key (sk_*)
15518
15516
  */
15519
15517
  declare function isSecretKey(key: string): boolean;
15520
15518
  /**
@@ -43292,6 +43292,7 @@ var PlatformContext = (0, import_react72.createContext)(null);
43292
43292
  init_constants();
43293
43293
 
43294
43294
  // src/key-validation.ts
43295
+ var PUBLIC_KEY_PATTERN = /^pk_(dev|stg|prod)_[a-z0-9]{12}_[a-f0-9]{32}$/;
43295
43296
  var APP_ID_PATTERN = /^app_(dev|stg|prod)_[a-z0-9_-]+$/;
43296
43297
  var SECRET_KEY_PATTERN = /^sk_(dev|stg|prod)_[a-z0-9_-]+$/;
43297
43298
  var ENV_PREFIX_MAP = {
@@ -43382,6 +43383,9 @@ function validateKeyForType(key, keyType, pattern, envVarName) {
43382
43383
  issues: [...issues, "invalid-format"]
43383
43384
  };
43384
43385
  }
43386
+ function validatePublicKey(key) {
43387
+ return validateKeyForType(key, "publicKey", PUBLIC_KEY_PATTERN, "NEXT_PUBLIC_SYLPHX_KEY");
43388
+ }
43385
43389
  function validateAppId(key) {
43386
43390
  return validateKeyForType(key, "appId", APP_ID_PATTERN, "NEXT_PUBLIC_SYLPHX_APP_ID");
43387
43391
  }
@@ -43410,22 +43414,23 @@ function validateAndSanitizeSecretKey(key) {
43410
43414
  }
43411
43415
  function detectEnvironment(key) {
43412
43416
  const sanitized = key.trim().toLowerCase();
43417
+ if (sanitized.startsWith("pk_")) {
43418
+ const result = validatePublicKey(sanitized);
43419
+ if (!result.valid) throw new Error(result.error);
43420
+ return result.environment;
43421
+ }
43413
43422
  if (sanitized.startsWith("sk_")) {
43414
43423
  const result = validateSecretKey(sanitized);
43415
- if (!result.valid) {
43416
- throw new Error(result.error);
43417
- }
43424
+ if (!result.valid) throw new Error(result.error);
43418
43425
  return result.environment;
43419
43426
  }
43420
43427
  if (sanitized.startsWith("app_")) {
43421
43428
  const result = validateAppId(sanitized);
43422
- if (!result.valid) {
43423
- throw new Error(result.error);
43424
- }
43429
+ if (!result.valid) throw new Error(result.error);
43425
43430
  return result.environment;
43426
43431
  }
43427
43432
  throw new Error(
43428
- `[Sylphx] Invalid key format. Key must start with 'sk_' (secret) or 'app_' (App ID).`
43433
+ `[Sylphx] Invalid key format. Key must start with 'pk_' (publishable), 'sk_' (secret), or 'app_' (legacy App ID).`
43429
43434
  );
43430
43435
  }
43431
43436
  function isDevelopmentKey(key) {
@@ -43441,6 +43446,7 @@ function getCookieNamespace(secretKey) {
43441
43446
  }
43442
43447
  function detectKeyType(key) {
43443
43448
  const sanitized = key.trim().toLowerCase();
43449
+ if (sanitized.startsWith("pk_")) return "publicKey";
43444
43450
  if (sanitized.startsWith("app_")) return "appId";
43445
43451
  if (sanitized.startsWith("sk_")) return "secret";
43446
43452
  return null;
@@ -43453,6 +43459,9 @@ function isSecretKey(key) {
43453
43459
  }
43454
43460
  function validateKey(key) {
43455
43461
  const keyType = key ? detectKeyType(key) : null;
43462
+ if (keyType === "publicKey") {
43463
+ return validatePublicKey(key);
43464
+ }
43456
43465
  if (keyType === "appId") {
43457
43466
  return validateAppId(key);
43458
43467
  }
@@ -43462,7 +43471,7 @@ function validateKey(key) {
43462
43471
  return {
43463
43472
  valid: false,
43464
43473
  sanitizedKey: "",
43465
- 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.",
43474
+ 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.",
43466
43475
  issues: key ? ["invalid_format"] : ["missing"]
43467
43476
  };
43468
43477
  }
@@ -43487,6 +43496,57 @@ function isDevelopmentRuntime() {
43487
43496
  }
43488
43497
 
43489
43498
  // src/config.ts
43499
+ function parseKey(key) {
43500
+ const sanitized = key.trim().toLowerCase();
43501
+ if (sanitized.startsWith("app_")) {
43502
+ throw new SylphxError(
43503
+ "[Sylphx] API key format has changed (ADR-021). Keys now embed the project ref.\n\nOld format: app_prod_xxx\nNew format: pk_prod_{ref}_xxx\n\nPlease regenerate your API keys from the Sylphx Console \u2192 Your App \u2192 Environments.\nOr contact support@sylphx.com for assistance.",
43504
+ { code: "BAD_REQUEST" }
43505
+ );
43506
+ }
43507
+ const prefix = sanitized.startsWith("pk_") ? "pk" : sanitized.startsWith("sk_") ? "sk" : null;
43508
+ if (!prefix) {
43509
+ throw new SylphxError(
43510
+ `[Sylphx] Invalid key format. Keys must start with 'pk_' (publishable) or 'sk_' (secret). Got: "${sanitized.slice(0, 15)}..."`,
43511
+ { code: "BAD_REQUEST" }
43512
+ );
43513
+ }
43514
+ const parts = sanitized.split("_");
43515
+ if (parts.length !== 4) {
43516
+ throw new SylphxError(
43517
+ `[Sylphx] Invalid key structure. Expected format: ${prefix}_{env}_{ref}_{token} (4 segments separated by '_'). Got ${parts.length} segment(s).`,
43518
+ { code: "BAD_REQUEST" }
43519
+ );
43520
+ }
43521
+ const [, env, ref, token] = parts;
43522
+ if (env !== "prod" && env !== "dev" && env !== "stg") {
43523
+ throw new SylphxError(
43524
+ `[Sylphx] Invalid key environment "${env}". Must be 'prod', 'dev', or 'stg'.`,
43525
+ { code: "BAD_REQUEST" }
43526
+ );
43527
+ }
43528
+ if (!/^[a-z0-9]{12}$/.test(ref)) {
43529
+ throw new SylphxError(
43530
+ `[Sylphx] Invalid project ref in key: "${ref}". Must be a 12-character lowercase alphanumeric string.`,
43531
+ { code: "BAD_REQUEST" }
43532
+ );
43533
+ }
43534
+ const expectedTokenLen = prefix === "pk" ? 32 : 64;
43535
+ if (token.length !== expectedTokenLen || !/^[a-f0-9]+$/.test(token)) {
43536
+ throw new SylphxError(
43537
+ `[Sylphx] Invalid key token. ${prefix === "pk" ? "Publishable" : "Secret"} keys must have a ${expectedTokenLen}-char hex token.`,
43538
+ { code: "BAD_REQUEST" }
43539
+ );
43540
+ }
43541
+ return {
43542
+ type: prefix,
43543
+ env,
43544
+ ref,
43545
+ token,
43546
+ isPublic: prefix === "pk",
43547
+ baseUrl: `https://${ref}.${DEFAULT_SDK_API_HOST}${SDK_API_PATH}`
43548
+ };
43549
+ }
43490
43550
  function httpStatusToErrorCode(status) {
43491
43551
  switch (status) {
43492
43552
  case 400:
@@ -43519,33 +43579,60 @@ function httpStatusToErrorCode(status) {
43519
43579
  return status >= 500 ? "INTERNAL_SERVER_ERROR" : "BAD_REQUEST";
43520
43580
  }
43521
43581
  }
43522
- var REF_PATTERN = /^[a-z0-9]{16}$/;
43582
+ var REF_PATTERN = /^[a-z0-9]{12}$/;
43523
43583
  function createConfig(input) {
43584
+ const keyForParsing = input.secretKey || input.publicKey;
43585
+ if (!keyForParsing) {
43586
+ if (input.ref) {
43587
+ const trimmedRef = input.ref.trim();
43588
+ if (!REF_PATTERN.test(trimmedRef)) {
43589
+ throw new SylphxError(
43590
+ `[Sylphx] Invalid project ref format: "${input.ref}". Expected a 12-character lowercase alphanumeric string (e.g. "abc123def456"). Get your ref from Platform Console \u2192 Projects \u2192 Your Project \u2192 Overview.`,
43591
+ { code: "BAD_REQUEST" }
43592
+ );
43593
+ }
43594
+ const baseUrl2 = `https://${trimmedRef}.${DEFAULT_SDK_API_HOST}${SDK_API_PATH}`;
43595
+ console.warn(
43596
+ "[Sylphx] Providing only ref without a key is deprecated. Provide secretKey or publicKey \u2014 the ref is now embedded in keys (ADR-021)."
43597
+ );
43598
+ return Object.freeze({ ref: trimmedRef, baseUrl: baseUrl2, accessToken: input.accessToken });
43599
+ }
43600
+ throw new SylphxError(
43601
+ "[Sylphx] Either publicKey or secretKey must be provided to createConfig().",
43602
+ { code: "BAD_REQUEST" }
43603
+ );
43604
+ }
43605
+ const parsed = parseKey(keyForParsing);
43606
+ const ref = parsed.ref;
43607
+ const baseUrl = parsed.baseUrl;
43524
43608
  let secretKey;
43525
43609
  if (input.secretKey) {
43526
43610
  const result = validateKey(input.secretKey);
43527
43611
  if (!result.valid) {
43528
- throw new SylphxError(result.error || "Invalid API key", {
43612
+ throw new SylphxError(result.error || "Invalid secret key", {
43529
43613
  code: "BAD_REQUEST",
43530
43614
  data: { issues: result.issues }
43531
43615
  });
43532
43616
  }
43533
- if (result.warning) {
43534
- console.warn(`[Sylphx] ${result.warning}`);
43535
- }
43617
+ if (result.warning) console.warn(`[Sylphx] ${result.warning}`);
43536
43618
  secretKey = result.sanitizedKey;
43537
43619
  }
43538
- const trimmedRef = input.ref.trim();
43539
- if (!REF_PATTERN.test(trimmedRef)) {
43540
- throw new SylphxError(
43541
- `[Sylphx] Invalid project ref format: "${input.ref}". Expected a 16-character lowercase alphanumeric string (e.g. "abc123def456ghij"). Get your ref from Platform Console \u2192 Projects \u2192 Your Project \u2192 Overview.`,
43542
- { code: "BAD_REQUEST" }
43543
- );
43620
+ let publicKey;
43621
+ if (input.publicKey) {
43622
+ const result = validateKey(input.publicKey);
43623
+ if (!result.valid) {
43624
+ throw new SylphxError(result.error || "Invalid public key", {
43625
+ code: "BAD_REQUEST",
43626
+ data: { issues: result.issues }
43627
+ });
43628
+ }
43629
+ if (result.warning) console.warn(`[Sylphx] ${result.warning}`);
43630
+ publicKey = result.sanitizedKey;
43544
43631
  }
43545
- const baseUrl = `https://${trimmedRef}.${DEFAULT_SDK_API_HOST}${SDK_API_PATH}`;
43546
43632
  return Object.freeze({
43547
43633
  secretKey,
43548
- ref: trimmedRef,
43634
+ publicKey,
43635
+ ref,
43549
43636
  baseUrl,
43550
43637
  accessToken: input.accessToken
43551
43638
  });
@@ -43556,6 +43643,8 @@ function buildHeaders(config2) {
43556
43643
  };
43557
43644
  if (config2.secretKey) {
43558
43645
  headers["x-app-secret"] = config2.secretKey;
43646
+ } else if (config2.publicKey) {
43647
+ headers["x-app-secret"] = config2.publicKey;
43559
43648
  }
43560
43649
  if (config2.accessToken) {
43561
43650
  headers.Authorization = `Bearer ${config2.accessToken}`;