@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.
package/dist/index.mjs CHANGED
@@ -330,6 +330,7 @@ function exponentialBackoff(attempt, baseDelay = BASE_RETRY_DELAY_MS, maxDelay =
330
330
  }
331
331
 
332
332
  // src/key-validation.ts
333
+ var PUBLIC_KEY_PATTERN = /^pk_(dev|stg|prod)_[a-z0-9]{12}_[a-f0-9]{32}$/;
333
334
  var APP_ID_PATTERN = /^app_(dev|stg|prod)_[a-z0-9_-]+$/;
334
335
  var SECRET_KEY_PATTERN = /^sk_(dev|stg|prod)_[a-z0-9_-]+$/;
335
336
  var ENV_PREFIX_MAP = {
@@ -420,6 +421,9 @@ function validateKeyForType(key, keyType, pattern, envVarName) {
420
421
  issues: [...issues, "invalid-format"]
421
422
  };
422
423
  }
424
+ function validatePublicKey(key) {
425
+ return validateKeyForType(key, "publicKey", PUBLIC_KEY_PATTERN, "NEXT_PUBLIC_SYLPHX_KEY");
426
+ }
423
427
  function validateAppId(key) {
424
428
  return validateKeyForType(key, "appId", APP_ID_PATTERN, "NEXT_PUBLIC_SYLPHX_APP_ID");
425
429
  }
@@ -438,12 +442,16 @@ function validateAndSanitizeSecretKey(key) {
438
442
  }
439
443
  function detectKeyType(key) {
440
444
  const sanitized = key.trim().toLowerCase();
445
+ if (sanitized.startsWith("pk_")) return "publicKey";
441
446
  if (sanitized.startsWith("app_")) return "appId";
442
447
  if (sanitized.startsWith("sk_")) return "secret";
443
448
  return null;
444
449
  }
445
450
  function validateKey(key) {
446
451
  const keyType = key ? detectKeyType(key) : null;
452
+ if (keyType === "publicKey") {
453
+ return validatePublicKey(key);
454
+ }
447
455
  if (keyType === "appId") {
448
456
  return validateAppId(key);
449
457
  }
@@ -453,12 +461,63 @@ function validateKey(key) {
453
461
  return {
454
462
  valid: false,
455
463
  sanitizedKey: "",
456
- 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.",
464
+ 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.",
457
465
  issues: key ? ["invalid_format"] : ["missing"]
458
466
  };
459
467
  }
460
468
 
461
469
  // src/config.ts
470
+ function parseKey(key) {
471
+ const sanitized = key.trim().toLowerCase();
472
+ if (sanitized.startsWith("app_")) {
473
+ throw new SylphxError(
474
+ "[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.",
475
+ { code: "BAD_REQUEST" }
476
+ );
477
+ }
478
+ const prefix = sanitized.startsWith("pk_") ? "pk" : sanitized.startsWith("sk_") ? "sk" : null;
479
+ if (!prefix) {
480
+ throw new SylphxError(
481
+ `[Sylphx] Invalid key format. Keys must start with 'pk_' (publishable) or 'sk_' (secret). Got: "${sanitized.slice(0, 15)}..."`,
482
+ { code: "BAD_REQUEST" }
483
+ );
484
+ }
485
+ const parts = sanitized.split("_");
486
+ if (parts.length !== 4) {
487
+ throw new SylphxError(
488
+ `[Sylphx] Invalid key structure. Expected format: ${prefix}_{env}_{ref}_{token} (4 segments separated by '_'). Got ${parts.length} segment(s).`,
489
+ { code: "BAD_REQUEST" }
490
+ );
491
+ }
492
+ const [, env, ref, token] = parts;
493
+ if (env !== "prod" && env !== "dev" && env !== "stg") {
494
+ throw new SylphxError(
495
+ `[Sylphx] Invalid key environment "${env}". Must be 'prod', 'dev', or 'stg'.`,
496
+ { code: "BAD_REQUEST" }
497
+ );
498
+ }
499
+ if (!/^[a-z0-9]{12}$/.test(ref)) {
500
+ throw new SylphxError(
501
+ `[Sylphx] Invalid project ref in key: "${ref}". Must be a 12-character lowercase alphanumeric string.`,
502
+ { code: "BAD_REQUEST" }
503
+ );
504
+ }
505
+ const expectedTokenLen = prefix === "pk" ? 32 : 64;
506
+ if (token.length !== expectedTokenLen || !/^[a-f0-9]+$/.test(token)) {
507
+ throw new SylphxError(
508
+ `[Sylphx] Invalid key token. ${prefix === "pk" ? "Publishable" : "Secret"} keys must have a ${expectedTokenLen}-char hex token.`,
509
+ { code: "BAD_REQUEST" }
510
+ );
511
+ }
512
+ return {
513
+ type: prefix,
514
+ env,
515
+ ref,
516
+ token,
517
+ isPublic: prefix === "pk",
518
+ baseUrl: `https://${ref}.${DEFAULT_SDK_API_HOST}${SDK_API_PATH}`
519
+ };
520
+ }
462
521
  function httpStatusToErrorCode(status) {
463
522
  switch (status) {
464
523
  case 400:
@@ -491,33 +550,60 @@ function httpStatusToErrorCode(status) {
491
550
  return status >= 500 ? "INTERNAL_SERVER_ERROR" : "BAD_REQUEST";
492
551
  }
493
552
  }
494
- var REF_PATTERN = /^[a-z0-9]{16}$/;
553
+ var REF_PATTERN = /^[a-z0-9]{12}$/;
495
554
  function createConfig(input) {
555
+ const keyForParsing = input.secretKey || input.publicKey;
556
+ if (!keyForParsing) {
557
+ if (input.ref) {
558
+ const trimmedRef = input.ref.trim();
559
+ if (!REF_PATTERN.test(trimmedRef)) {
560
+ throw new SylphxError(
561
+ `[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.`,
562
+ { code: "BAD_REQUEST" }
563
+ );
564
+ }
565
+ const baseUrl2 = `https://${trimmedRef}.${DEFAULT_SDK_API_HOST}${SDK_API_PATH}`;
566
+ console.warn(
567
+ "[Sylphx] Providing only ref without a key is deprecated. Provide secretKey or publicKey \u2014 the ref is now embedded in keys (ADR-021)."
568
+ );
569
+ return Object.freeze({ ref: trimmedRef, baseUrl: baseUrl2, accessToken: input.accessToken });
570
+ }
571
+ throw new SylphxError(
572
+ "[Sylphx] Either publicKey or secretKey must be provided to createConfig().",
573
+ { code: "BAD_REQUEST" }
574
+ );
575
+ }
576
+ const parsed = parseKey(keyForParsing);
577
+ const ref = parsed.ref;
578
+ const baseUrl = parsed.baseUrl;
496
579
  let secretKey;
497
580
  if (input.secretKey) {
498
581
  const result = validateKey(input.secretKey);
499
582
  if (!result.valid) {
500
- throw new SylphxError(result.error || "Invalid API key", {
583
+ throw new SylphxError(result.error || "Invalid secret key", {
501
584
  code: "BAD_REQUEST",
502
585
  data: { issues: result.issues }
503
586
  });
504
587
  }
505
- if (result.warning) {
506
- console.warn(`[Sylphx] ${result.warning}`);
507
- }
588
+ if (result.warning) console.warn(`[Sylphx] ${result.warning}`);
508
589
  secretKey = result.sanitizedKey;
509
590
  }
510
- const trimmedRef = input.ref.trim();
511
- if (!REF_PATTERN.test(trimmedRef)) {
512
- throw new SylphxError(
513
- `[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.`,
514
- { code: "BAD_REQUEST" }
515
- );
591
+ let publicKey;
592
+ if (input.publicKey) {
593
+ const result = validateKey(input.publicKey);
594
+ if (!result.valid) {
595
+ throw new SylphxError(result.error || "Invalid public key", {
596
+ code: "BAD_REQUEST",
597
+ data: { issues: result.issues }
598
+ });
599
+ }
600
+ if (result.warning) console.warn(`[Sylphx] ${result.warning}`);
601
+ publicKey = result.sanitizedKey;
516
602
  }
517
- const baseUrl = `https://${trimmedRef}.${DEFAULT_SDK_API_HOST}${SDK_API_PATH}`;
518
603
  return Object.freeze({
519
604
  secretKey,
520
- ref: trimmedRef,
605
+ publicKey,
606
+ ref,
521
607
  baseUrl,
522
608
  accessToken: input.accessToken
523
609
  });
@@ -535,6 +621,8 @@ function buildHeaders(config) {
535
621
  };
536
622
  if (config.secretKey) {
537
623
  headers["x-app-secret"] = config.secretKey;
624
+ } else if (config.publicKey) {
625
+ headers["x-app-secret"] = config.publicKey;
538
626
  }
539
627
  if (config.accessToken) {
540
628
  headers.Authorization = `Bearer ${config.accessToken}`;
@@ -3575,6 +3663,7 @@ export {
3575
3663
  listTasks,
3576
3664
  listUsers,
3577
3665
  page,
3666
+ parseKey,
3578
3667
  pauseCron,
3579
3668
  realtimeEmit,
3580
3669
  recordStreakActivity,