@smplkit/sdk 1.6.0 → 1.6.2

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.cts CHANGED
@@ -1357,13 +1357,15 @@ interface SmplClientOptions {
1357
1357
  apiKey?: string;
1358
1358
  /**
1359
1359
  * The environment to connect to (e.g. `"production"`, `"staging"`).
1360
- * When omitted, resolved from the `SMPLKIT_ENVIRONMENT` environment variable.
1360
+ * When omitted, resolved from the `SMPLKIT_ENVIRONMENT` environment variable
1361
+ * or the `~/.smplkit` configuration file.
1361
1362
  */
1362
1363
  environment?: string;
1363
1364
  /**
1364
1365
  * Service name. The SDK automatically registers the service as a
1365
1366
  * context instance and includes it in flag evaluation context.
1366
- * When omitted, resolved from the `SMPLKIT_SERVICE` environment variable.
1367
+ * When omitted, resolved from the `SMPLKIT_SERVICE` environment variable
1368
+ * or the `~/.smplkit` configuration file.
1367
1369
  */
1368
1370
  service?: string;
1369
1371
  /**
@@ -1378,17 +1380,28 @@ interface SmplClientOptions {
1378
1380
  */
1379
1381
  disableTelemetry?: boolean;
1380
1382
  /**
1381
- * Base domain for all smplkit service URLs.
1382
- * Override for local development (e.g. `"localhost"`).
1383
- * @default "smplkit.com"
1383
+ * Configuration profile to use from `~/.smplkit`.
1384
+ * When omitted, resolved from `SMPLKIT_PROFILE` env var, falling back to `"default"`.
1385
+ */
1386
+ profile?: string;
1387
+ /**
1388
+ * Base domain for all service URLs.
1389
+ * When omitted, resolved from `SMPLKIT_BASE_DOMAIN` env var or config file,
1390
+ * falling back to `"smplkit.com"`.
1384
1391
  */
1385
1392
  baseDomain?: string;
1386
1393
  /**
1387
- * URL scheme used when constructing service URLs.
1388
- * Override for local development (e.g. `"http"`).
1389
- * @default "https"
1394
+ * URL scheme for service URLs (`"https"` or `"http"`).
1395
+ * When omitted, resolved from `SMPLKIT_SCHEME` env var or config file,
1396
+ * falling back to `"https"`.
1390
1397
  */
1391
1398
  scheme?: string;
1399
+ /**
1400
+ * Enable debug logging to stderr.
1401
+ * When omitted, resolved from `SMPLKIT_DEBUG` env var or config file,
1402
+ * falling back to `false`.
1403
+ */
1404
+ debug?: boolean;
1392
1405
  }
1393
1406
  /**
1394
1407
  * Entry point for the smplkit TypeScript SDK.
package/dist/index.d.ts CHANGED
@@ -1357,13 +1357,15 @@ interface SmplClientOptions {
1357
1357
  apiKey?: string;
1358
1358
  /**
1359
1359
  * The environment to connect to (e.g. `"production"`, `"staging"`).
1360
- * When omitted, resolved from the `SMPLKIT_ENVIRONMENT` environment variable.
1360
+ * When omitted, resolved from the `SMPLKIT_ENVIRONMENT` environment variable
1361
+ * or the `~/.smplkit` configuration file.
1361
1362
  */
1362
1363
  environment?: string;
1363
1364
  /**
1364
1365
  * Service name. The SDK automatically registers the service as a
1365
1366
  * context instance and includes it in flag evaluation context.
1366
- * When omitted, resolved from the `SMPLKIT_SERVICE` environment variable.
1367
+ * When omitted, resolved from the `SMPLKIT_SERVICE` environment variable
1368
+ * or the `~/.smplkit` configuration file.
1367
1369
  */
1368
1370
  service?: string;
1369
1371
  /**
@@ -1378,17 +1380,28 @@ interface SmplClientOptions {
1378
1380
  */
1379
1381
  disableTelemetry?: boolean;
1380
1382
  /**
1381
- * Base domain for all smplkit service URLs.
1382
- * Override for local development (e.g. `"localhost"`).
1383
- * @default "smplkit.com"
1383
+ * Configuration profile to use from `~/.smplkit`.
1384
+ * When omitted, resolved from `SMPLKIT_PROFILE` env var, falling back to `"default"`.
1385
+ */
1386
+ profile?: string;
1387
+ /**
1388
+ * Base domain for all service URLs.
1389
+ * When omitted, resolved from `SMPLKIT_BASE_DOMAIN` env var or config file,
1390
+ * falling back to `"smplkit.com"`.
1384
1391
  */
1385
1392
  baseDomain?: string;
1386
1393
  /**
1387
- * URL scheme used when constructing service URLs.
1388
- * Override for local development (e.g. `"http"`).
1389
- * @default "https"
1394
+ * URL scheme for service URLs (`"https"` or `"http"`).
1395
+ * When omitted, resolved from `SMPLKIT_SCHEME` env var or config file,
1396
+ * falling back to `"https"`.
1390
1397
  */
1391
1398
  scheme?: string;
1399
+ /**
1400
+ * Enable debug logging to stderr.
1401
+ * When omitted, resolved from `SMPLKIT_DEBUG` env var or config file,
1402
+ * falling back to `false`.
1403
+ */
1404
+ debug?: boolean;
1392
1405
  }
1393
1406
  /**
1394
1407
  * Entry point for the smplkit TypeScript SDK.
package/dist/index.js CHANGED
@@ -17043,7 +17043,7 @@ var ConfigClient = class {
17043
17043
  /** @internal */
17044
17044
  _apiKey;
17045
17045
  /** @internal */
17046
- _baseUrl = BASE_URL;
17046
+ _baseUrl;
17047
17047
  /** @internal */
17048
17048
  _http;
17049
17049
  /** @internal — returns the shared WebSocket for real-time updates. */
@@ -17058,9 +17058,11 @@ var ConfigClient = class {
17058
17058
  /** @internal */
17059
17059
  constructor(apiKey, timeout, baseUrl) {
17060
17060
  this._apiKey = apiKey;
17061
+ const resolvedBaseUrl = baseUrl ?? BASE_URL;
17062
+ this._baseUrl = resolvedBaseUrl;
17061
17063
  const ms = timeout ?? 3e4;
17062
17064
  this._http = createClient({
17063
- baseUrl: baseUrl ?? BASE_URL,
17065
+ baseUrl: resolvedBaseUrl,
17064
17066
  headers: {
17065
17067
  Authorization: `Bearer ${apiKey}`,
17066
17068
  Accept: "application/json"
@@ -17750,7 +17752,7 @@ var FlagsClient = class {
17750
17752
  /** @internal */
17751
17753
  _apiKey;
17752
17754
  /** @internal */
17753
- _baseUrl = FLAGS_BASE_URL;
17755
+ _baseUrl;
17754
17756
  /** @internal */
17755
17757
  _http;
17756
17758
  /** @internal */
@@ -17778,6 +17780,9 @@ var FlagsClient = class {
17778
17780
  constructor(apiKey, ensureWs, timeout, flagsBaseUrl, appBaseUrl) {
17779
17781
  this._apiKey = apiKey;
17780
17782
  this._ensureWs = ensureWs;
17783
+ const resolvedBaseUrl = flagsBaseUrl ?? FLAGS_BASE_URL;
17784
+ const resolvedAppBaseUrl = appBaseUrl ?? APP_BASE_URL;
17785
+ this._baseUrl = resolvedBaseUrl;
17781
17786
  const ms = timeout ?? 3e4;
17782
17787
  const fetchWithTimeout = async (request) => {
17783
17788
  const controller = new AbortController();
@@ -17794,7 +17799,7 @@ var FlagsClient = class {
17794
17799
  }
17795
17800
  };
17796
17801
  this._http = createClient2({
17797
- baseUrl: flagsBaseUrl ?? FLAGS_BASE_URL,
17802
+ baseUrl: resolvedBaseUrl,
17798
17803
  headers: {
17799
17804
  Authorization: `Bearer ${apiKey}`,
17800
17805
  Accept: "application/json"
@@ -17802,7 +17807,7 @@ var FlagsClient = class {
17802
17807
  fetch: fetchWithTimeout
17803
17808
  });
17804
17809
  this._appHttp = createClient2({
17805
- baseUrl: appBaseUrl ?? APP_BASE_URL,
17810
+ baseUrl: resolvedAppBaseUrl,
17806
17811
  headers: {
17807
17812
  Authorization: `Bearer ${apiKey}`,
17808
17813
  Accept: "application/json"
@@ -18686,7 +18691,7 @@ var LoggingClient = class {
18686
18691
  /** @internal */
18687
18692
  _apiKey;
18688
18693
  /** @internal */
18689
- _baseUrl = LOGGING_BASE_URL;
18694
+ _baseUrl;
18690
18695
  /** @internal */
18691
18696
  _http;
18692
18697
  /** @internal — set by SmplClient after construction. */
@@ -18706,9 +18711,11 @@ var LoggingClient = class {
18706
18711
  constructor(apiKey, ensureWs, timeout, baseUrl) {
18707
18712
  this._apiKey = apiKey;
18708
18713
  this._ensureWs = ensureWs;
18714
+ const resolvedBaseUrl = baseUrl ?? LOGGING_BASE_URL;
18715
+ this._baseUrl = resolvedBaseUrl;
18709
18716
  const ms = timeout ?? 3e4;
18710
18717
  this._http = createClient3({
18711
- baseUrl: baseUrl ?? LOGGING_BASE_URL,
18718
+ baseUrl: resolvedBaseUrl,
18712
18719
  headers: {
18713
18720
  Authorization: `Bearer ${apiKey}`,
18714
18721
  Accept: "application/json"
@@ -19381,59 +19388,117 @@ var SharedWebSocket = class {
19381
19388
  }
19382
19389
  };
19383
19390
 
19384
- // src/resolve.ts
19391
+ // src/config.ts
19385
19392
  import { readFileSync } from "fs";
19386
19393
  import { homedir } from "os";
19387
19394
  import { join } from "path";
19388
- function noApiKeyMessage(environment) {
19389
- return `No API key provided. Set one of:
19390
- 1. Pass apiKey to the constructor
19391
- 2. Set the SMPLKIT_API_KEY environment variable
19392
- 3. Create a ~/.smplkit file with:
19393
- [${environment}]
19394
- api_key = your_key_here`;
19395
- }
19396
- function readApiKeyFromConfig(environment) {
19397
- const configPath = join(homedir(), ".smplkit");
19398
- try {
19399
- const content = readFileSync(configPath, "utf-8");
19400
- let currentSection = null;
19401
- let envKey;
19402
- let defaultKey;
19403
- for (const line of content.split("\n")) {
19404
- const trimmed = line.trim();
19405
- if (trimmed === "" || trimmed.startsWith("#")) continue;
19406
- if (trimmed.startsWith("[")) {
19407
- const sectionName = trimmed.slice(1, trimmed.indexOf("]")).toLowerCase();
19408
- currentSection = sectionName;
19409
- continue;
19410
- }
19411
- if (currentSection && trimmed.startsWith("api_key")) {
19412
- const eqIndex = trimmed.indexOf("=");
19413
- if (eqIndex !== -1) {
19414
- const value = trimmed.slice(eqIndex + 1).trim();
19415
- if (value) {
19416
- if (currentSection === environment.toLowerCase()) {
19417
- envKey = value;
19418
- } else if (currentSection === "default") {
19419
- defaultKey = value;
19420
- }
19421
- }
19422
- }
19395
+ var CONFIG_KEYS = {
19396
+ api_key: "SMPLKIT_API_KEY",
19397
+ base_domain: "SMPLKIT_BASE_DOMAIN",
19398
+ scheme: "SMPLKIT_SCHEME",
19399
+ environment: "SMPLKIT_ENVIRONMENT",
19400
+ service: "SMPLKIT_SERVICE",
19401
+ debug: "SMPLKIT_DEBUG",
19402
+ disable_telemetry: "SMPLKIT_DISABLE_TELEMETRY"
19403
+ };
19404
+ function parseIniFile(content, profile) {
19405
+ const common = {};
19406
+ const profileValues = {};
19407
+ const sections = /* @__PURE__ */ new Set();
19408
+ let currentSection = null;
19409
+ const lowerProfile = profile.toLowerCase();
19410
+ for (const line of content.split("\n")) {
19411
+ const trimmed = line.trim();
19412
+ if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith(";")) continue;
19413
+ if (trimmed.startsWith("[")) {
19414
+ const closeBracket = trimmed.indexOf("]");
19415
+ if (closeBracket === -1) continue;
19416
+ currentSection = trimmed.slice(1, closeBracket).trim().toLowerCase();
19417
+ if (currentSection !== "common") {
19418
+ sections.add(currentSection);
19423
19419
  }
19420
+ continue;
19424
19421
  }
19425
- return envKey ?? defaultKey;
19426
- } catch {
19427
- return void 0;
19422
+ if (currentSection === null) continue;
19423
+ const eqIndex = trimmed.indexOf("=");
19424
+ if (eqIndex === -1) continue;
19425
+ const key = trimmed.slice(0, eqIndex).trim();
19426
+ const value = trimmed.slice(eqIndex + 1).trim();
19427
+ if (!key || !value) continue;
19428
+ if (currentSection === "common") {
19429
+ common[key] = value;
19430
+ } else if (currentSection === lowerProfile) {
19431
+ profileValues[key] = value;
19432
+ }
19433
+ }
19434
+ if (lowerProfile !== "default" && sections.size > 0 && !sections.has(lowerProfile) && Object.keys(profileValues).length === 0) {
19435
+ const available = [...sections].sort().join(", ");
19436
+ throw new SmplError(
19437
+ `Configuration profile "${profile}" not found in ~/.smplkit. Available profiles: ${available}`
19438
+ );
19428
19439
  }
19440
+ return { ...common, ...profileValues };
19429
19441
  }
19430
- function resolveApiKey(explicit, environment) {
19431
- if (explicit) return explicit;
19432
- const envVal = process.env.SMPLKIT_API_KEY;
19433
- if (envVal) return envVal;
19434
- const fileKey = readApiKeyFromConfig(environment);
19435
- if (fileKey) return fileKey;
19436
- throw new SmplError(noApiKeyMessage(environment));
19442
+ function parseBool(value, key) {
19443
+ const lower = value.toLowerCase();
19444
+ if (lower === "true" || lower === "1" || lower === "yes") return true;
19445
+ if (lower === "false" || lower === "0" || lower === "no") return false;
19446
+ throw new SmplError(
19447
+ `Invalid boolean value "${value}" for ${key}. Expected true/false, 1/0, or yes/no.`
19448
+ );
19449
+ }
19450
+ function serviceUrl(scheme, subdomain, baseDomain) {
19451
+ return `${scheme}://${subdomain}.${baseDomain}`;
19452
+ }
19453
+ var NO_API_KEY_MESSAGE = "No API key provided. Set one of:\n 1. Pass apiKey to the constructor\n 2. Set the SMPLKIT_API_KEY environment variable\n 3. Add api_key to your ~/.smplkit config file";
19454
+ var NO_ENVIRONMENT_MESSAGE = "No environment provided. Set one of:\n 1. Pass environment to the constructor\n 2. Set the SMPLKIT_ENVIRONMENT environment variable\n 3. Add environment to your ~/.smplkit config file";
19455
+ var NO_SERVICE_MESSAGE = "No service provided. Set one of:\n 1. Pass service in options\n 2. Set the SMPLKIT_SERVICE environment variable\n 3. Add service to your ~/.smplkit config file";
19456
+ function resolveConfig(options) {
19457
+ const merged = {
19458
+ scheme: "https",
19459
+ base_domain: "smplkit.com",
19460
+ debug: "false",
19461
+ disable_telemetry: "false"
19462
+ };
19463
+ const profile = options.profile ?? process.env.SMPLKIT_PROFILE ?? "default";
19464
+ try {
19465
+ const configPath = join(homedir(), ".smplkit");
19466
+ const content = readFileSync(configPath, "utf-8");
19467
+ const fileValues = parseIniFile(content, profile);
19468
+ for (const key of Object.keys(CONFIG_KEYS)) {
19469
+ if (fileValues[key]) {
19470
+ merged[key] = fileValues[key];
19471
+ }
19472
+ }
19473
+ } catch (e) {
19474
+ if (e instanceof SmplError) throw e;
19475
+ }
19476
+ for (const [key, envVar] of Object.entries(CONFIG_KEYS)) {
19477
+ const envVal = process.env[envVar];
19478
+ if (envVal) {
19479
+ merged[key] = envVal;
19480
+ }
19481
+ }
19482
+ if (options.apiKey !== void 0) merged.api_key = options.apiKey;
19483
+ if (options.baseDomain !== void 0) merged.base_domain = options.baseDomain;
19484
+ if (options.scheme !== void 0) merged.scheme = options.scheme;
19485
+ if (options.environment !== void 0) merged.environment = options.environment;
19486
+ if (options.service !== void 0) merged.service = options.service;
19487
+ if (options.debug !== void 0) merged.debug = String(options.debug);
19488
+ if (options.disableTelemetry !== void 0)
19489
+ merged.disable_telemetry = String(options.disableTelemetry);
19490
+ if (!merged.api_key) throw new SmplError(NO_API_KEY_MESSAGE);
19491
+ if (!merged.environment) throw new SmplError(NO_ENVIRONMENT_MESSAGE);
19492
+ if (!merged.service) throw new SmplError(NO_SERVICE_MESSAGE);
19493
+ return {
19494
+ apiKey: merged.api_key,
19495
+ baseDomain: merged.base_domain,
19496
+ scheme: merged.scheme,
19497
+ environment: merged.environment,
19498
+ service: merged.service,
19499
+ debug: parseBool(merged.debug, "debug"),
19500
+ disableTelemetry: parseBool(merged.disable_telemetry, "disable_telemetry")
19501
+ };
19437
19502
  }
19438
19503
 
19439
19504
  // src/_metrics.ts
@@ -19576,8 +19641,6 @@ var MetricsReporter = class {
19576
19641
  };
19577
19642
 
19578
19643
  // src/client.ts
19579
- var NO_ENVIRONMENT_MESSAGE = "No environment provided. Set one of:\n 1. Pass environment to the constructor\n 2. Set the SMPLKIT_ENVIRONMENT environment variable";
19580
- var NO_SERVICE_MESSAGE = "No service provided. Set one of:\n 1. Pass service in options\n 2. Set the SMPLKIT_SERVICE environment variable";
19581
19644
  var SmplClient = class {
19582
19645
  /** Client for config management and runtime. */
19583
19646
  config;
@@ -19597,55 +19660,50 @@ var SmplClient = class {
19597
19660
  _appBaseUrl;
19598
19661
  _appHttp;
19599
19662
  constructor(options = {}) {
19600
- const environment = options.environment || process.env.SMPLKIT_ENVIRONMENT;
19601
- if (!environment) {
19602
- throw new SmplError(NO_ENVIRONMENT_MESSAGE);
19603
- }
19604
- this._environment = environment;
19605
- const service = options.service || process.env.SMPLKIT_SERVICE;
19606
- if (!service) {
19607
- throw new SmplError(NO_SERVICE_MESSAGE);
19608
- }
19609
- this._service = service;
19610
- const apiKey = resolveApiKey(options.apiKey, environment);
19611
- this._apiKey = apiKey;
19663
+ const cfg = resolveConfig(options);
19664
+ this._apiKey = cfg.apiKey;
19665
+ this._environment = cfg.environment;
19666
+ this._service = cfg.service;
19612
19667
  this._timeout = options.timeout ?? 3e4;
19613
- const baseDomain = options.baseDomain ?? "smplkit.com";
19614
- const scheme = options.scheme ?? "https";
19615
- const appBaseUrl = `${scheme}://app.${baseDomain}`;
19616
- const configBaseUrl = `${scheme}://config.${baseDomain}`;
19617
- const flagsBaseUrl = `${scheme}://flags.${baseDomain}`;
19618
- const loggingBaseUrl = `${scheme}://logging.${baseDomain}`;
19668
+ const appBaseUrl = serviceUrl(cfg.scheme, "app", cfg.baseDomain);
19669
+ const configBaseUrl = serviceUrl(cfg.scheme, "config", cfg.baseDomain);
19670
+ const flagsBaseUrl = serviceUrl(cfg.scheme, "flags", cfg.baseDomain);
19671
+ const loggingBaseUrl = serviceUrl(cfg.scheme, "logging", cfg.baseDomain);
19619
19672
  this._appBaseUrl = appBaseUrl;
19620
- const maskedKey = apiKey.length > 14 ? apiKey.slice(0, 10) + "..." + apiKey.slice(-4) : apiKey.slice(0, Math.min(4, apiKey.length)) + "...";
19673
+ const maskedKey = cfg.apiKey.length > 14 ? cfg.apiKey.slice(0, 10) + "..." + cfg.apiKey.slice(-4) : cfg.apiKey.slice(0, Math.min(4, cfg.apiKey.length)) + "...";
19621
19674
  debug(
19622
19675
  "lifecycle",
19623
- `SmplClient created (api_key=${maskedKey}, environment=${environment}, service=${service})`
19676
+ `SmplClient created (api_key=${maskedKey}, environment=${cfg.environment}, service=${cfg.service})`
19624
19677
  );
19625
19678
  this._appHttp = createClient4({
19626
19679
  baseUrl: appBaseUrl,
19627
19680
  headers: {
19628
- Authorization: `Bearer ${apiKey}`,
19681
+ Authorization: `Bearer ${cfg.apiKey}`,
19629
19682
  Accept: "application/json"
19630
19683
  }
19631
19684
  });
19632
- if (!options.disableTelemetry) {
19685
+ if (!cfg.disableTelemetry) {
19633
19686
  this._metrics = new MetricsReporter({
19634
- apiKey,
19687
+ apiKey: cfg.apiKey,
19635
19688
  environment: this._environment,
19636
19689
  service: this._service,
19637
19690
  appBaseUrl
19638
19691
  });
19639
19692
  }
19640
- this.config = new ConfigClient(apiKey, this._timeout, configBaseUrl);
19693
+ this.config = new ConfigClient(cfg.apiKey, this._timeout, configBaseUrl);
19641
19694
  this.flags = new FlagsClient(
19642
- apiKey,
19695
+ cfg.apiKey,
19643
19696
  () => this._ensureWs(),
19644
19697
  this._timeout,
19645
19698
  flagsBaseUrl,
19646
19699
  appBaseUrl
19647
19700
  );
19648
- this.logging = new LoggingClient(apiKey, () => this._ensureWs(), this._timeout, loggingBaseUrl);
19701
+ this.logging = new LoggingClient(
19702
+ cfg.apiKey,
19703
+ () => this._ensureWs(),
19704
+ this._timeout,
19705
+ loggingBaseUrl
19706
+ );
19649
19707
  this.config._getSharedWs = () => this._ensureWs();
19650
19708
  this.flags._parent = this;
19651
19709
  this.config._parent = this;