@smplkit/sdk 1.8.4 → 1.9.1

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.cjs CHANGED
@@ -16621,11 +16621,20 @@ var require_pino = __commonJS({
16621
16621
  // src/index.ts
16622
16622
  var index_exports = {};
16623
16623
  __export(index_exports, {
16624
+ AccountSettings: () => AccountSettings,
16625
+ AccountSettingsClient: () => AccountSettingsClient,
16624
16626
  BooleanFlag: () => BooleanFlag,
16625
16627
  Config: () => Config,
16626
16628
  ConfigClient: () => ConfigClient,
16627
16629
  ConfigManagement: () => ConfigManagement,
16628
16630
  Context: () => Context,
16631
+ ContextEntity: () => ContextEntity,
16632
+ ContextType: () => ContextType,
16633
+ ContextTypesClient: () => ContextTypesClient,
16634
+ ContextsClient: () => ContextsClient,
16635
+ Environment: () => Environment,
16636
+ EnvironmentClassification: () => EnvironmentClassification,
16637
+ EnvironmentsClient: () => EnvironmentsClient,
16629
16638
  Flag: () => Flag,
16630
16639
  FlagChangeEvent: () => FlagChangeEvent,
16631
16640
  FlagStats: () => FlagStats,
@@ -16636,8 +16645,10 @@ __export(index_exports, {
16636
16645
  LogGroup: () => LogGroup,
16637
16646
  LogLevel: () => LogLevel,
16638
16647
  Logger: () => Logger,
16648
+ LoggerSource: () => LoggerSource,
16639
16649
  LoggingClient: () => LoggingClient,
16640
16650
  LoggingManagement: () => LoggingManagement,
16651
+ ManagementClient: () => ManagementClient,
16641
16652
  NumberFlag: () => NumberFlag,
16642
16653
  PinoAdapter: () => PinoAdapter,
16643
16654
  Rule: () => Rule,
@@ -16655,7 +16666,7 @@ __export(index_exports, {
16655
16666
  module.exports = __toCommonJS(index_exports);
16656
16667
 
16657
16668
  // src/client.ts
16658
- var import_openapi_fetch4 = __toESM(require("openapi-fetch"), 1);
16669
+ var import_openapi_fetch5 = __toESM(require("openapi-fetch"), 1);
16659
16670
 
16660
16671
  // src/config/client.ts
16661
16672
  var import_openapi_fetch = __toESM(require("openapi-fetch"), 1);
@@ -17887,7 +17898,7 @@ var FlagsClient = class {
17887
17898
  /** Management API — CRUD operations on Flag models. */
17888
17899
  management;
17889
17900
  /** @internal */
17890
- constructor(apiKey, ensureWs, timeout, flagsBaseUrl, appBaseUrl) {
17901
+ constructor(apiKey, ensureWs, timeout, flagsBaseUrl, appBaseUrl, contextBuffer) {
17891
17902
  this._apiKey = apiKey;
17892
17903
  this._ensureWs = ensureWs;
17893
17904
  const resolvedBaseUrl = flagsBaseUrl ?? FLAGS_BASE_URL;
@@ -17924,6 +17935,9 @@ var FlagsClient = class {
17924
17935
  },
17925
17936
  fetch: fetchWithTimeout
17926
17937
  });
17938
+ if (contextBuffer !== void 0) {
17939
+ this._contextBuffer = contextBuffer;
17940
+ }
17927
17941
  this.management = new FlagsManagement(this);
17928
17942
  }
17929
17943
  // ------------------------------------------------------------------
@@ -18298,25 +18312,6 @@ var FlagsClient = class {
18298
18312
  }
18299
18313
  }
18300
18314
  // ------------------------------------------------------------------
18301
- // Runtime: context registration
18302
- // ------------------------------------------------------------------
18303
- /**
18304
- * Register context(s) with the server.
18305
- *
18306
- * Accepts a single Context or an array. Works before `initialize()` is called.
18307
- */
18308
- register(context) {
18309
- if (Array.isArray(context)) {
18310
- this._contextBuffer.observe(context);
18311
- } else {
18312
- this._contextBuffer.observe([context]);
18313
- }
18314
- }
18315
- /** Flush pending context registrations to the server. */
18316
- async flushContexts() {
18317
- await this._flushContexts();
18318
- }
18319
- // ------------------------------------------------------------------
18320
18315
  // Runtime: Tier 1 evaluate
18321
18316
  // ------------------------------------------------------------------
18322
18317
  /**
@@ -18885,6 +18880,16 @@ var LoggingManagement = class {
18885
18880
  async deleteGroup(id) {
18886
18881
  return this._client._mgDeleteGroup(id);
18887
18882
  }
18883
+ /**
18884
+ * Bulk-register explicit logger sources with the logging service.
18885
+ *
18886
+ * Unlike `start()`, which auto-discovers loggers from the current
18887
+ * process, this method accepts explicit `service` and `environment`
18888
+ * overrides — useful for sample-data seeding and test fixtures.
18889
+ */
18890
+ async registerSources(sources) {
18891
+ return this._client._mgRegisterSources(sources);
18892
+ }
18888
18893
  };
18889
18894
  var LoggingClient = class {
18890
18895
  /** @internal */
@@ -19063,6 +19068,26 @@ var LoggingClient = class {
19063
19068
  return data.data.map((r) => this._groupToModel(r));
19064
19069
  }
19065
19070
  /** @internal */
19071
+ async _mgRegisterSources(sources) {
19072
+ if (sources.length === 0) return;
19073
+ const loggers = sources.map((src) => ({
19074
+ id: src.name,
19075
+ level: src.level ?? void 0,
19076
+ resolved_level: src.resolvedLevel,
19077
+ service: src.service,
19078
+ environment: src.environment
19079
+ }));
19080
+ try {
19081
+ const result = await this._http.POST("/api/v1/loggers/bulk", {
19082
+ body: { loggers }
19083
+ });
19084
+ if (result.error !== void 0)
19085
+ await checkError3(result.response, "Failed to register sources");
19086
+ } catch (err) {
19087
+ wrapFetchError3(err);
19088
+ }
19089
+ }
19090
+ /** @internal */
19066
19091
  async _mgDeleteGroup(id) {
19067
19092
  const group = await this.management.getGroup(id);
19068
19093
  try {
@@ -19590,10 +19615,11 @@ var LoggingClient = class {
19590
19615
  // ------------------------------------------------------------------
19591
19616
  _loggerToModel(resource) {
19592
19617
  const attrs = resource.attributes;
19618
+ const rawLevel = attrs.level ?? null;
19593
19619
  return new Logger(this, {
19594
19620
  id: resource.id ?? null,
19595
19621
  name: attrs.name,
19596
- level: attrs.level ?? null,
19622
+ level: rawLevel,
19597
19623
  group: attrs.group ?? null,
19598
19624
  managed: attrs.managed ?? false,
19599
19625
  sources: [],
@@ -19604,11 +19630,12 @@ var LoggingClient = class {
19604
19630
  }
19605
19631
  _groupToModel(resource) {
19606
19632
  const attrs = resource.attributes;
19633
+ const rawLevel = attrs.level ?? null;
19607
19634
  return new LogGroup(this, {
19608
19635
  id: resource.id ?? null,
19609
19636
  key: attrs.key ?? null,
19610
19637
  name: attrs.name,
19611
- level: attrs.level ?? null,
19638
+ level: rawLevel,
19612
19639
  group: attrs.parent_id ?? null,
19613
19640
  environments: attrs.environments ?? {},
19614
19641
  createdAt: attrs.created_at ?? null,
@@ -19617,6 +19644,664 @@ var LoggingClient = class {
19617
19644
  }
19618
19645
  };
19619
19646
 
19647
+ // src/management/client.ts
19648
+ var import_openapi_fetch4 = __toESM(require("openapi-fetch"), 1);
19649
+
19650
+ // src/management/types.ts
19651
+ var EnvironmentClassification = /* @__PURE__ */ ((EnvironmentClassification2) => {
19652
+ EnvironmentClassification2["STANDARD"] = "STANDARD";
19653
+ EnvironmentClassification2["AD_HOC"] = "AD_HOC";
19654
+ return EnvironmentClassification2;
19655
+ })(EnvironmentClassification || {});
19656
+
19657
+ // src/management/models.ts
19658
+ var Environment = class {
19659
+ /** Unique slug identifier (e.g. `"production"`). */
19660
+ id;
19661
+ /** Human-readable display name. */
19662
+ name;
19663
+ /** Hex color code, or null. */
19664
+ color;
19665
+ /** Whether this is a STANDARD or AD_HOC environment. */
19666
+ classification;
19667
+ /** When the environment was created. */
19668
+ createdAt;
19669
+ /** When the environment was last updated. */
19670
+ updatedAt;
19671
+ /** @internal */
19672
+ _client;
19673
+ /** @internal */
19674
+ constructor(client, fields) {
19675
+ this._client = client;
19676
+ this.id = fields.id;
19677
+ this.name = fields.name;
19678
+ this.color = fields.color;
19679
+ this.classification = fields.classification;
19680
+ this.createdAt = fields.createdAt;
19681
+ this.updatedAt = fields.updatedAt;
19682
+ }
19683
+ /** Persist this environment to the server (creates if new, updates if existing). */
19684
+ async save() {
19685
+ if (this._client === null) {
19686
+ throw new Error("Environment was constructed without a client; cannot save");
19687
+ }
19688
+ if (this.createdAt === null) {
19689
+ const saved = await this._client._create(this);
19690
+ this._apply(saved);
19691
+ } else {
19692
+ const saved = await this._client._update(this);
19693
+ this._apply(saved);
19694
+ }
19695
+ }
19696
+ /** @internal */
19697
+ _apply(other) {
19698
+ this.id = other.id;
19699
+ this.name = other.name;
19700
+ this.color = other.color;
19701
+ this.classification = other.classification;
19702
+ this.createdAt = other.createdAt;
19703
+ this.updatedAt = other.updatedAt;
19704
+ }
19705
+ toString() {
19706
+ return `Environment(id=${this.id}, name=${this.name}, classification=${this.classification})`;
19707
+ }
19708
+ };
19709
+ var ContextType = class {
19710
+ /** Unique slug identifier (e.g. `"user"`). */
19711
+ id;
19712
+ /** Human-readable display name. */
19713
+ name;
19714
+ /** Known attribute keys with metadata objects. */
19715
+ attributes;
19716
+ /** When the context type was created. */
19717
+ createdAt;
19718
+ /** When the context type was last updated. */
19719
+ updatedAt;
19720
+ /** @internal */
19721
+ _client;
19722
+ /** @internal */
19723
+ constructor(client, fields) {
19724
+ this._client = client;
19725
+ this.id = fields.id;
19726
+ this.name = fields.name;
19727
+ this.attributes = { ...fields.attributes };
19728
+ this.createdAt = fields.createdAt;
19729
+ this.updatedAt = fields.updatedAt;
19730
+ }
19731
+ /** Add a known-attribute slot. Local; call `save()` to persist. */
19732
+ addAttribute(name, metadata = {}) {
19733
+ this.attributes = { ...this.attributes, [name]: metadata };
19734
+ }
19735
+ /** Remove a known-attribute slot. Local; call `save()` to persist. */
19736
+ removeAttribute(name) {
19737
+ const attrs = { ...this.attributes };
19738
+ delete attrs[name];
19739
+ this.attributes = attrs;
19740
+ }
19741
+ /** Replace a known-attribute slot's metadata. Local; call `save()` to persist. */
19742
+ updateAttribute(name, metadata) {
19743
+ this.attributes = { ...this.attributes, [name]: metadata };
19744
+ }
19745
+ /** Persist this context type to the server (creates if new, updates if existing). */
19746
+ async save() {
19747
+ if (this._client === null) {
19748
+ throw new Error("ContextType was constructed without a client; cannot save");
19749
+ }
19750
+ if (this.createdAt === null) {
19751
+ const saved = await this._client._create(this);
19752
+ this._apply(saved);
19753
+ } else {
19754
+ const saved = await this._client._update(this);
19755
+ this._apply(saved);
19756
+ }
19757
+ }
19758
+ /** @internal */
19759
+ _apply(other) {
19760
+ this.id = other.id;
19761
+ this.name = other.name;
19762
+ this.attributes = { ...other.attributes };
19763
+ this.createdAt = other.createdAt;
19764
+ this.updatedAt = other.updatedAt;
19765
+ }
19766
+ toString() {
19767
+ return `ContextType(id=${this.id}, name=${this.name})`;
19768
+ }
19769
+ };
19770
+ var ContextEntity = class {
19771
+ /** Context type key (e.g. `"user"`). */
19772
+ type;
19773
+ /** Entity key (e.g. `"user-123"`). */
19774
+ key;
19775
+ /** Human-readable display name, or null. */
19776
+ name;
19777
+ /** Observed attributes. */
19778
+ attributes;
19779
+ /** When the context was created. */
19780
+ createdAt;
19781
+ /** When the context was last updated. */
19782
+ updatedAt;
19783
+ /** @internal */
19784
+ constructor(fields) {
19785
+ this.type = fields.type;
19786
+ this.key = fields.key;
19787
+ this.name = fields.name;
19788
+ this.attributes = { ...fields.attributes };
19789
+ this.createdAt = fields.createdAt;
19790
+ this.updatedAt = fields.updatedAt;
19791
+ }
19792
+ /** Composite `"type:key"` identifier. */
19793
+ get id() {
19794
+ return `${this.type}:${this.key}`;
19795
+ }
19796
+ toString() {
19797
+ return `ContextEntity(type=${this.type}, key=${this.key})`;
19798
+ }
19799
+ };
19800
+ var AccountSettings = class {
19801
+ /** @internal */
19802
+ _data;
19803
+ /** @internal */
19804
+ _client;
19805
+ /** @internal */
19806
+ constructor(client, data) {
19807
+ this._client = client;
19808
+ this._data = { ...data };
19809
+ }
19810
+ /** The full settings dict. Direct mutations are reflected in `save()`. */
19811
+ get raw() {
19812
+ return this._data;
19813
+ }
19814
+ set raw(value) {
19815
+ this._data = { ...value };
19816
+ }
19817
+ /** Canonical ordering of STANDARD environments. Empty array if unset. */
19818
+ get environmentOrder() {
19819
+ const val = this._data["environment_order"];
19820
+ return Array.isArray(val) ? [...val] : [];
19821
+ }
19822
+ set environmentOrder(value) {
19823
+ this._data["environment_order"] = [...value];
19824
+ }
19825
+ /** Persist the settings to the server. */
19826
+ async save() {
19827
+ if (this._client === null) {
19828
+ throw new Error("AccountSettings was constructed without a client; cannot save");
19829
+ }
19830
+ const saved = await this._client._save(this._data);
19831
+ this._apply(saved);
19832
+ }
19833
+ /** @internal */
19834
+ _apply(other) {
19835
+ this._data = { ...other._data };
19836
+ }
19837
+ /** @internal — expose raw data for _save(). */
19838
+ get _rawData() {
19839
+ return this._data;
19840
+ }
19841
+ toString() {
19842
+ return `AccountSettings(${JSON.stringify(this._data)})`;
19843
+ }
19844
+ };
19845
+
19846
+ // src/management/client.ts
19847
+ function splitContextId(idOrType, key) {
19848
+ if (key === void 0) {
19849
+ if (!idOrType.includes(":")) {
19850
+ throw new Error(
19851
+ `context id must be 'type:key' (got ${JSON.stringify(idOrType)}); alternatively pass type and key as separate args`
19852
+ );
19853
+ }
19854
+ const colonIdx = idOrType.indexOf(":");
19855
+ return [idOrType.slice(0, colonIdx), idOrType.slice(colonIdx + 1)];
19856
+ }
19857
+ return [idOrType, key];
19858
+ }
19859
+ async function checkError4(response, _context) {
19860
+ const body = await response.text().catch(() => "");
19861
+ throwForStatus(response.status, body);
19862
+ }
19863
+ function wrapFetchError4(err) {
19864
+ if (err instanceof SmplError) {
19865
+ throw err;
19866
+ }
19867
+ if (err instanceof TypeError) {
19868
+ throw new SmplConnectionError(`Network error: ${err.message}`);
19869
+ }
19870
+ throw new SmplConnectionError(
19871
+ `Request failed: ${err instanceof Error ? err.message : String(err)}`
19872
+ );
19873
+ }
19874
+ function envFromResource(resource, client) {
19875
+ const attrs = resource.attributes ?? {};
19876
+ return new Environment(client, {
19877
+ id: resource.id ?? null,
19878
+ name: attrs.name ?? "",
19879
+ color: attrs.color ?? null,
19880
+ classification: attrs.classification === "AD_HOC" ? "AD_HOC" /* AD_HOC */ : "STANDARD" /* STANDARD */,
19881
+ createdAt: attrs.created_at ?? null,
19882
+ updatedAt: attrs.updated_at ?? null
19883
+ });
19884
+ }
19885
+ function ctFromResource(resource, client) {
19886
+ const attrs = resource.attributes ?? {};
19887
+ const rawMeta = attrs.attributes;
19888
+ const attributeMetadata = {};
19889
+ if (rawMeta && typeof rawMeta === "object") {
19890
+ for (const [k, v] of Object.entries(rawMeta)) {
19891
+ attributeMetadata[k] = typeof v === "object" && v !== null ? v : {};
19892
+ }
19893
+ }
19894
+ return new ContextType(client, {
19895
+ id: resource.id ?? null,
19896
+ name: attrs.name ?? "",
19897
+ attributes: attributeMetadata,
19898
+ createdAt: attrs.created_at ?? null,
19899
+ updatedAt: attrs.updated_at ?? null
19900
+ });
19901
+ }
19902
+ function ctxEntityFromResource(resource) {
19903
+ const compositeId = resource.id ?? "";
19904
+ const colonIdx = compositeId.indexOf(":");
19905
+ const ctxType = colonIdx >= 0 ? compositeId.slice(0, colonIdx) : compositeId;
19906
+ const ctxKey = colonIdx >= 0 ? compositeId.slice(colonIdx + 1) : "";
19907
+ const attrs = resource.attributes ?? {};
19908
+ const rawAttrs = attrs.attributes;
19909
+ const attrDict = rawAttrs && typeof rawAttrs === "object" ? { ...rawAttrs } : {};
19910
+ return new ContextEntity({
19911
+ type: ctxType,
19912
+ key: ctxKey,
19913
+ name: attrs.name ?? null,
19914
+ attributes: attrDict,
19915
+ createdAt: attrs.created_at ?? null,
19916
+ updatedAt: attrs.updated_at ?? null
19917
+ });
19918
+ }
19919
+ var EnvironmentsClient = class {
19920
+ /** @internal */
19921
+ constructor(_http) {
19922
+ this._http = _http;
19923
+ }
19924
+ /**
19925
+ * Return an unsaved `Environment`. Call `.save()` to persist.
19926
+ */
19927
+ new(id, options) {
19928
+ return new Environment(this, {
19929
+ id,
19930
+ name: options.name,
19931
+ color: options.color ?? null,
19932
+ classification: options.classification ?? "STANDARD" /* STANDARD */,
19933
+ createdAt: null,
19934
+ updatedAt: null
19935
+ });
19936
+ }
19937
+ /** List all environments. */
19938
+ async list() {
19939
+ let data;
19940
+ try {
19941
+ const result = await this._http.GET("/api/v1/environments", {});
19942
+ if (!result.response.ok) await checkError4(result.response, "Failed to list environments");
19943
+ data = result.data;
19944
+ } catch (err) {
19945
+ wrapFetchError4(err);
19946
+ }
19947
+ const items = data?.data ?? [];
19948
+ return items.map((r) => envFromResource(r, this));
19949
+ }
19950
+ /** Fetch an environment by id. */
19951
+ async get(id) {
19952
+ let data;
19953
+ try {
19954
+ const result = await this._http.GET("/api/v1/environments/{id}", {
19955
+ params: { path: { id } }
19956
+ });
19957
+ if (!result.response.ok) await checkError4(result.response, `Environment '${id}' not found`);
19958
+ data = result.data;
19959
+ } catch (err) {
19960
+ wrapFetchError4(err);
19961
+ }
19962
+ if (!data?.data) throw new SmplNotFoundError(`Environment with id '${id}' not found`);
19963
+ return envFromResource(data.data, this);
19964
+ }
19965
+ /** Delete an environment by id. */
19966
+ async delete(id) {
19967
+ try {
19968
+ const result = await this._http.DELETE("/api/v1/environments/{id}", {
19969
+ params: { path: { id } }
19970
+ });
19971
+ if (!result.response.ok && result.response.status !== 204)
19972
+ await checkError4(result.response, `Failed to delete environment '${id}'`);
19973
+ } catch (err) {
19974
+ wrapFetchError4(err);
19975
+ }
19976
+ }
19977
+ /** @internal — called by Environment.save() for new resources. */
19978
+ async _create(env) {
19979
+ const body = {
19980
+ data: {
19981
+ id: env.id,
19982
+ type: "environment",
19983
+ attributes: {
19984
+ name: env.name,
19985
+ color: env.color,
19986
+ classification: env.classification
19987
+ }
19988
+ }
19989
+ };
19990
+ let data;
19991
+ try {
19992
+ const result = await this._http.POST("/api/v1/environments", { body });
19993
+ if (!result.response.ok) await checkError4(result.response, "Failed to create environment");
19994
+ data = result.data;
19995
+ } catch (err) {
19996
+ wrapFetchError4(err);
19997
+ }
19998
+ if (!data?.data) throw new SmplValidationError("Failed to create environment");
19999
+ return envFromResource(data.data, this);
20000
+ }
20001
+ /** @internal — called by Environment.save() for existing resources. */
20002
+ async _update(env) {
20003
+ if (!env.id) throw new Error("Cannot update an Environment with no id");
20004
+ const body = {
20005
+ data: {
20006
+ id: env.id,
20007
+ type: "environment",
20008
+ attributes: {
20009
+ name: env.name,
20010
+ color: env.color,
20011
+ classification: env.classification
20012
+ }
20013
+ }
20014
+ };
20015
+ let data;
20016
+ try {
20017
+ const result = await this._http.PUT("/api/v1/environments/{id}", {
20018
+ params: { path: { id: env.id } },
20019
+ body
20020
+ });
20021
+ if (!result.response.ok)
20022
+ await checkError4(result.response, `Failed to update environment ${env.id}`);
20023
+ data = result.data;
20024
+ } catch (err) {
20025
+ wrapFetchError4(err);
20026
+ }
20027
+ if (!data?.data) throw new SmplValidationError(`Failed to update environment ${env.id}`);
20028
+ return envFromResource(data.data, this);
20029
+ }
20030
+ };
20031
+ var ContextTypesClient = class {
20032
+ /** @internal */
20033
+ constructor(_http) {
20034
+ this._http = _http;
20035
+ }
20036
+ /**
20037
+ * Return an unsaved `ContextType`. Call `.save()` to persist.
20038
+ */
20039
+ new(id, options = {}) {
20040
+ return new ContextType(this, {
20041
+ id,
20042
+ name: options.name ?? id,
20043
+ attributes: options.attributes ?? {},
20044
+ createdAt: null,
20045
+ updatedAt: null
20046
+ });
20047
+ }
20048
+ /** List all context types. */
20049
+ async list() {
20050
+ let data;
20051
+ try {
20052
+ const result = await this._http.GET("/api/v1/context_types", {});
20053
+ if (!result.response.ok) await checkError4(result.response, "Failed to list context types");
20054
+ data = result.data;
20055
+ } catch (err) {
20056
+ wrapFetchError4(err);
20057
+ }
20058
+ const items = data?.data ?? [];
20059
+ return items.map((r) => ctFromResource(r, this));
20060
+ }
20061
+ /** Fetch a context type by id. */
20062
+ async get(id) {
20063
+ let data;
20064
+ try {
20065
+ const result = await this._http.GET("/api/v1/context_types/{id}", {
20066
+ params: { path: { id } }
20067
+ });
20068
+ if (!result.response.ok) await checkError4(result.response, `ContextType '${id}' not found`);
20069
+ data = result.data;
20070
+ } catch (err) {
20071
+ wrapFetchError4(err);
20072
+ }
20073
+ if (!data?.data) throw new SmplNotFoundError(`ContextType with id '${id}' not found`);
20074
+ return ctFromResource(data.data, this);
20075
+ }
20076
+ /** Delete a context type by id. */
20077
+ async delete(id) {
20078
+ try {
20079
+ const result = await this._http.DELETE("/api/v1/context_types/{id}", {
20080
+ params: { path: { id } }
20081
+ });
20082
+ if (!result.response.ok && result.response.status !== 204)
20083
+ await checkError4(result.response, `Failed to delete context type '${id}'`);
20084
+ } catch (err) {
20085
+ wrapFetchError4(err);
20086
+ }
20087
+ }
20088
+ /** @internal — called by ContextType.save() for new resources. */
20089
+ async _create(ct) {
20090
+ const body = {
20091
+ data: {
20092
+ id: ct.id,
20093
+ type: "context_type",
20094
+ attributes: {
20095
+ name: ct.name,
20096
+ attributes: ct.attributes
20097
+ }
20098
+ }
20099
+ };
20100
+ let data;
20101
+ try {
20102
+ const result = await this._http.POST("/api/v1/context_types", { body });
20103
+ if (!result.response.ok) await checkError4(result.response, "Failed to create context type");
20104
+ data = result.data;
20105
+ } catch (err) {
20106
+ wrapFetchError4(err);
20107
+ }
20108
+ if (!data?.data) throw new SmplValidationError("Failed to create context type");
20109
+ return ctFromResource(data.data, this);
20110
+ }
20111
+ /** @internal — called by ContextType.save() for existing resources. */
20112
+ async _update(ct) {
20113
+ if (!ct.id) throw new Error("Cannot update a ContextType with no id");
20114
+ const body = {
20115
+ data: {
20116
+ id: ct.id,
20117
+ type: "context_type",
20118
+ attributes: {
20119
+ name: ct.name,
20120
+ attributes: ct.attributes
20121
+ }
20122
+ }
20123
+ };
20124
+ let data;
20125
+ try {
20126
+ const result = await this._http.PUT("/api/v1/context_types/{id}", {
20127
+ params: { path: { id: ct.id } },
20128
+ body
20129
+ });
20130
+ if (!result.response.ok)
20131
+ await checkError4(result.response, `Failed to update context type ${ct.id}`);
20132
+ data = result.data;
20133
+ } catch (err) {
20134
+ wrapFetchError4(err);
20135
+ }
20136
+ if (!data?.data) throw new SmplValidationError(`Failed to update context type ${ct.id}`);
20137
+ return ctFromResource(data.data, this);
20138
+ }
20139
+ };
20140
+ var ContextsClient = class {
20141
+ /** @internal */
20142
+ constructor(_http, _buffer) {
20143
+ this._http = _http;
20144
+ this._buffer = _buffer;
20145
+ }
20146
+ /**
20147
+ * Buffer context(s) for registration; optionally flush immediately.
20148
+ *
20149
+ * When `flush` is false (default), contexts are queued for the SDK's
20150
+ * background flush — right for high-frequency observation from a live
20151
+ * request handler. When `flush` is true the call awaits the round-trip
20152
+ * — right for IaC scripts.
20153
+ */
20154
+ async register(items, options = {}) {
20155
+ const batch = Array.isArray(items) ? items : [items];
20156
+ this._buffer.observe(batch);
20157
+ if (options.flush) {
20158
+ await this.flush();
20159
+ }
20160
+ }
20161
+ /** Send any pending context observations to the server. */
20162
+ async flush() {
20163
+ const batch = this._buffer.drain();
20164
+ if (batch.length === 0) return;
20165
+ try {
20166
+ const result = await this._http.POST("/api/v1/contexts/bulk", {
20167
+ body: {
20168
+ contexts: batch.map((ctx) => ({
20169
+ type: ctx.type,
20170
+ key: ctx.key,
20171
+ attributes: ctx.attributes
20172
+ }))
20173
+ }
20174
+ });
20175
+ if (!result.response.ok) await checkError4(result.response, "Failed to flush contexts");
20176
+ } catch (err) {
20177
+ wrapFetchError4(err);
20178
+ }
20179
+ }
20180
+ /** List all contexts of a given type. */
20181
+ async list(type) {
20182
+ let data;
20183
+ try {
20184
+ const result = await this._http.GET("/api/v1/contexts", {
20185
+ params: { query: { "filter[context_type]": type } }
20186
+ });
20187
+ if (!result.response.ok) await checkError4(result.response, "Failed to list contexts");
20188
+ data = result.data;
20189
+ } catch (err) {
20190
+ wrapFetchError4(err);
20191
+ }
20192
+ const items = data?.data ?? [];
20193
+ return items.map(ctxEntityFromResource);
20194
+ }
20195
+ /** Fetch a context by composite id (`"type:key"`) or by separate type and key. */
20196
+ async get(idOrType, key) {
20197
+ const [ctxType, ctxKey] = splitContextId(idOrType, key);
20198
+ const composite = `${ctxType}:${ctxKey}`;
20199
+ let data;
20200
+ try {
20201
+ const result = await this._http.GET("/api/v1/contexts/{id}", {
20202
+ params: { path: { id: composite } }
20203
+ });
20204
+ if (!result.response.ok)
20205
+ await checkError4(result.response, `Context '${composite}' not found`);
20206
+ data = result.data;
20207
+ } catch (err) {
20208
+ wrapFetchError4(err);
20209
+ }
20210
+ if (!data?.data) throw new SmplNotFoundError(`Context with id '${composite}' not found`);
20211
+ return ctxEntityFromResource(data.data);
20212
+ }
20213
+ /** Delete a context by composite id (`"type:key"`) or by separate type and key. */
20214
+ async delete(idOrType, key) {
20215
+ const [ctxType, ctxKey] = splitContextId(idOrType, key);
20216
+ const composite = `${ctxType}:${ctxKey}`;
20217
+ try {
20218
+ const result = await this._http.DELETE("/api/v1/contexts/{id}", {
20219
+ params: { path: { id: composite } }
20220
+ });
20221
+ if (!result.response.ok && result.response.status !== 204)
20222
+ await checkError4(result.response, `Failed to delete context '${composite}'`);
20223
+ } catch (err) {
20224
+ wrapFetchError4(err);
20225
+ }
20226
+ }
20227
+ };
20228
+ var AccountSettingsClient = class {
20229
+ /** @internal */
20230
+ constructor(_appBaseUrl, apiKey) {
20231
+ this._appBaseUrl = _appBaseUrl;
20232
+ this._headers = {
20233
+ Authorization: `Bearer ${apiKey}`,
20234
+ "Content-Type": "application/json",
20235
+ Accept: "application/json"
20236
+ };
20237
+ }
20238
+ _headers;
20239
+ /** Fetch the current account settings. */
20240
+ async get() {
20241
+ const url = `${this._appBaseUrl}/api/v1/accounts/current/settings`;
20242
+ let resp;
20243
+ try {
20244
+ resp = await fetch(url, { headers: this._headers });
20245
+ } catch (err) {
20246
+ throw new SmplConnectionError(
20247
+ `Network error: ${err instanceof Error ? err.message : String(err)}`
20248
+ );
20249
+ }
20250
+ if (!resp.ok) {
20251
+ const body = await resp.text().catch(() => "");
20252
+ throwForStatus(resp.status, body);
20253
+ }
20254
+ const data = await resp.json();
20255
+ return new AccountSettings(this, data ?? {});
20256
+ }
20257
+ /** @internal — called by AccountSettings.save(). */
20258
+ async _save(data) {
20259
+ const url = `${this._appBaseUrl}/api/v1/accounts/current/settings`;
20260
+ let resp;
20261
+ try {
20262
+ resp = await fetch(url, {
20263
+ method: "PUT",
20264
+ headers: this._headers,
20265
+ body: JSON.stringify(data)
20266
+ });
20267
+ } catch (err) {
20268
+ throw new SmplConnectionError(
20269
+ `Network error: ${err instanceof Error ? err.message : String(err)}`
20270
+ );
20271
+ }
20272
+ if (!resp.ok) {
20273
+ const body = await resp.text().catch(() => "");
20274
+ throwForStatus(resp.status, body);
20275
+ }
20276
+ const saved = await resp.json();
20277
+ return new AccountSettings(this, saved ?? {});
20278
+ }
20279
+ };
20280
+ var ManagementClient = class {
20281
+ /** CRUD for environments. */
20282
+ environments;
20283
+ /** Registration, list, get, and delete for context instances. */
20284
+ contexts;
20285
+ /** CRUD for context types (entity schemas). */
20286
+ context_types;
20287
+ /** Get/save for account-level settings. */
20288
+ account_settings;
20289
+ /** @internal */
20290
+ constructor(options) {
20291
+ const http = (0, import_openapi_fetch4.default)({
20292
+ baseUrl: options.appBaseUrl,
20293
+ headers: {
20294
+ Authorization: `Bearer ${options.apiKey}`,
20295
+ Accept: "application/json"
20296
+ }
20297
+ });
20298
+ this.environments = new EnvironmentsClient(http);
20299
+ this.contexts = new ContextsClient(http, options.buffer);
20300
+ this.context_types = new ContextTypesClient(http);
20301
+ this.account_settings = new AccountSettingsClient(options.appBaseUrl, options.apiKey);
20302
+ }
20303
+ };
20304
+
19620
20305
  // src/ws.ts
19621
20306
  var import_ws = __toESM(require("ws"), 1);
19622
20307
  var BACKOFF_MS = [1e3, 2e3, 4e3, 8e3, 16e3, 32e3, 6e4];
@@ -20054,6 +20739,8 @@ var SmplClient = class {
20054
20739
  flags;
20055
20740
  /** Client for logging management and runtime. */
20056
20741
  logging;
20742
+ /** Client for app-plane management (environments, contexts, context types, account settings). */
20743
+ management;
20057
20744
  _wsManager = null;
20058
20745
  _apiKey;
20059
20746
  /** @internal */
@@ -20084,7 +20771,7 @@ var SmplClient = class {
20084
20771
  "lifecycle",
20085
20772
  `SmplClient created (api_key=${maskedKey}, environment=${cfg.environment}, service=${cfg.service})`
20086
20773
  );
20087
- this._appHttp = (0, import_openapi_fetch4.default)({
20774
+ this._appHttp = (0, import_openapi_fetch5.default)({
20088
20775
  baseUrl: appBaseUrl,
20089
20776
  headers: {
20090
20777
  Authorization: `Bearer ${cfg.apiKey}`,
@@ -20099,13 +20786,15 @@ var SmplClient = class {
20099
20786
  appBaseUrl
20100
20787
  });
20101
20788
  }
20789
+ const sharedContextBuffer = new ContextRegistrationBuffer();
20102
20790
  this.config = new ConfigClient(cfg.apiKey, this._timeout, configBaseUrl);
20103
20791
  this.flags = new FlagsClient(
20104
20792
  cfg.apiKey,
20105
20793
  () => this._ensureWs(),
20106
20794
  this._timeout,
20107
20795
  flagsBaseUrl,
20108
- appBaseUrl
20796
+ appBaseUrl,
20797
+ sharedContextBuffer
20109
20798
  );
20110
20799
  this.logging = new LoggingClient(
20111
20800
  cfg.apiKey,
@@ -20113,6 +20802,11 @@ var SmplClient = class {
20113
20802
  this._timeout,
20114
20803
  loggingBaseUrl
20115
20804
  );
20805
+ this.management = new ManagementClient({
20806
+ appBaseUrl,
20807
+ apiKey: cfg.apiKey,
20808
+ buffer: sharedContextBuffer
20809
+ });
20116
20810
  this.config._getSharedWs = () => this._ensureWs();
20117
20811
  this.flags._parent = this;
20118
20812
  this.config._parent = this;
@@ -20238,6 +20932,25 @@ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
20238
20932
  LogLevel2["SILENT"] = "SILENT";
20239
20933
  return LogLevel2;
20240
20934
  })(LogLevel || {});
20935
+ var LoggerSource = class {
20936
+ /** Logger name (e.g. `"sqlalchemy.engine"`). */
20937
+ name;
20938
+ /** Service name this source belongs to. */
20939
+ service;
20940
+ /** Environment name this source belongs to. */
20941
+ environment;
20942
+ /** Effective log level for this source. */
20943
+ resolvedLevel;
20944
+ /** Explicit (configured) log level, if different from `resolvedLevel`. */
20945
+ level;
20946
+ constructor(name, options) {
20947
+ this.name = name;
20948
+ this.service = options.service;
20949
+ this.environment = options.environment;
20950
+ this.resolvedLevel = options.resolved_level;
20951
+ this.level = options.level ?? null;
20952
+ }
20953
+ };
20241
20954
 
20242
20955
  // src/logging/adapters/winston.ts
20243
20956
  var SMPLKIT_TO_WINSTON = {
@@ -20464,11 +21177,20 @@ var PinoAdapter = class {
20464
21177
  };
20465
21178
  // Annotate the CommonJS export names for ESM import in node:
20466
21179
  0 && (module.exports = {
21180
+ AccountSettings,
21181
+ AccountSettingsClient,
20467
21182
  BooleanFlag,
20468
21183
  Config,
20469
21184
  ConfigClient,
20470
21185
  ConfigManagement,
20471
21186
  Context,
21187
+ ContextEntity,
21188
+ ContextType,
21189
+ ContextTypesClient,
21190
+ ContextsClient,
21191
+ Environment,
21192
+ EnvironmentClassification,
21193
+ EnvironmentsClient,
20472
21194
  Flag,
20473
21195
  FlagChangeEvent,
20474
21196
  FlagStats,
@@ -20479,8 +21201,10 @@ var PinoAdapter = class {
20479
21201
  LogGroup,
20480
21202
  LogLevel,
20481
21203
  Logger,
21204
+ LoggerSource,
20482
21205
  LoggingClient,
20483
21206
  LoggingManagement,
21207
+ ManagementClient,
20484
21208
  NumberFlag,
20485
21209
  PinoAdapter,
20486
21210
  Rule,