@smplkit/sdk 1.9.6 → 1.10.0

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.ts CHANGED
@@ -73,86 +73,39 @@ declare class SharedWebSocket {
73
73
  }
74
74
 
75
75
  /**
76
- * Config resource active-record model with save() pattern.
76
+ * LiveConfigProxylive, dict-like, read-only configuration access.
77
77
  */
78
78
 
79
79
  /**
80
- * A configuration resource managed by the smplkit platform.
80
+ * A live, dict-like, read-only view of resolved config values.
81
81
  *
82
- * Management: mutate properties directly and call `save()` to persist.
83
- * Creates if new, updates if existing.
84
- */
85
- declare class Config {
86
- /** Unique identifier (slug, e.g. `"user-service"`). */
87
- id: string | null;
88
- /** Display name. */
89
- name: string;
90
- /** Optional description. */
91
- description: string | null;
92
- /** Parent config id (slug), or null if this is a root config. */
93
- parent: string | null;
94
- /** Base key-value pairs. */
95
- items: Record<string, unknown>;
96
- /**
97
- * Per-environment overrides.
98
- * Structured as `{ env_name: { values: { key: value } } }`.
99
- */
100
- environments: Record<string, unknown>;
101
- /** When the config was created, or null if unavailable. */
102
- createdAt: string | null;
103
- /** When the config was last updated, or null if unavailable. */
104
- updatedAt: string | null;
105
- /** @internal */
106
- readonly _client: ConfigClient;
107
- /** @internal */
108
- constructor(client: ConfigClient, fields: {
109
- id: string | null;
110
- name: string;
111
- description: string | null;
112
- parent: string | null;
113
- items: Record<string, unknown>;
114
- environments: Record<string, unknown>;
115
- createdAt: string | null;
116
- updatedAt: string | null;
117
- });
118
- /**
119
- * Persist this config to the server.
120
- *
121
- * Creates if new, updates if existing.
122
- * Updates this instance in-place with the server response.
123
- */
124
- save(): Promise<void>;
125
- /**
126
- * Walk the parent chain and return config data objects, child-to-root.
127
- *
128
- * @param configs - Optional pre-fetched list of configs to look up parents
129
- * by ID, avoiding extra network calls and the key-vs-UUID mismatch with
130
- * {@link ConfigClient.get}.
131
- * @internal
132
- */
133
- _buildChain(configs?: Config[]): Promise<Array<{
134
- id: string;
135
- items: Record<string, unknown>;
136
- environments: Record<string, unknown>;
137
- }>>;
138
- /** @internal — copy all fields from another Config instance. */
139
- _apply(other: Config): void;
140
- toString(): string;
141
- }
142
-
143
- /**
144
- * LiveConfigProxy — live configuration access.
145
- */
146
-
147
- /**
148
- * A live proxy whose properties always reflect the latest config values.
82
+ * Returned by {@link ConfigClient.get}. Always reflects the latest
83
+ * server-pushed state every read sees current values.
84
+ *
85
+ * Attribute access returns the current resolved value for the given item
86
+ * key. If a *model* class was provided, the model is reconstructed from
87
+ * the latest values on each access (so attribute access type-checks
88
+ * against the model).
89
+ *
90
+ * Dict-like API: `proxy["key"]`, `key in proxy`, `Object.keys(proxy)`,
91
+ * `proxy.values()`, `proxy.items()`, `proxy.get(key, default)`,
92
+ * iteration via `for (const k in proxy)`.
93
+ *
94
+ * Read-only: `proxy.x = ...`, `delete proxy.x`, `proxy["k"] = ...` all throw.
95
+ *
96
+ * Note: customer config items whose names collide with proxy method names
97
+ * (`keys`, `values`, `items`, `get`, `onChange`) are shadowed for attribute
98
+ * access use subscript (`proxy["values"]`) for those.
149
99
  *
150
100
  * @example
151
101
  * ```typescript
152
- * const proxy = await client.config.subscribe("user-service");
153
- * console.log(proxy.timeout); // current value
154
- * // ... later, after a config change ...
155
- * console.log(proxy.timeout); // updated value
102
+ * const cfg = await client.config.get("user-service");
103
+ * console.log(cfg.database.host); // resolved value
104
+ * console.log(cfg["max_retries"]); // subscript also works
105
+ * for (const key of Object.keys(cfg)) console.log(key);
106
+ *
107
+ * cfg.onChange((event) => console.log(event));
108
+ * cfg.onChange("max_retries", (event) => console.log("retries changed"));
156
109
  * ```
157
110
  */
158
111
  declare class LiveConfigProxy<T = Record<string, unknown>> {
@@ -165,127 +118,432 @@ declare class LiveConfigProxy<T = Record<string, unknown>> {
165
118
  constructor(client: ConfigClient, key: string, model?: new (data: any) => T);
166
119
  /** @internal */
167
120
  _currentValues(): Record<string, unknown>;
168
- }
169
-
170
- /** Describes a single config value change detected on refresh. */
171
- interface ConfigChangeEvent {
172
- /** The config id that changed. */
173
- configId: string;
174
- /** The item key within the config that changed. */
175
- itemKey: string;
176
- /** The previous value (null if the key was absent). */
177
- oldValue: unknown;
178
- /** The updated value (null if the key was removed). */
179
- newValue: unknown;
180
- /** How the change was delivered. */
181
- source: "websocket" | "manual";
182
- }
183
- /**
184
- * Management API for smplkit Config — CRUD operations on Config models.
185
- *
186
- * Access via `SmplClient.config.management`.
187
- */
188
- declare class ConfigManagement {
189
- private readonly _client;
190
- constructor(_client: ConfigClient);
191
- /** Create an unsaved config. Call `.save()` to persist. */
192
- new(id: string, options?: {
193
- name?: string;
194
- description?: string;
195
- parent?: string;
196
- }): Config;
197
- /** Fetch a config by id. */
198
- get(id: string): Promise<Config>;
199
- /** List all configs. */
200
- list(): Promise<Config[]>;
201
- /** Delete a config by id. */
202
- delete(id: string): Promise<void>;
203
- }
204
- /**
205
- * Client for the smplkit Config API.
206
- *
207
- * Obtained via `SmplClient.config`.
208
- */
209
- declare class ConfigClient {
210
- /** @internal */
211
- readonly _apiKey: string;
212
- /** @internal */
213
- readonly _baseUrl: string;
214
- /** @internal */
215
- private readonly _http;
216
- /** @internal — returns the shared WebSocket for real-time updates. */
217
- _getSharedWs?: () => SharedWebSocket;
218
- /** @internal — set by SmplClient after construction. */
219
- _parent: {
220
- readonly _environment: string;
221
- readonly _service: string | null;
222
- readonly _metrics: MetricsReporter | null;
223
- } | null;
224
- /** Management API — CRUD operations on Config models. */
225
- readonly management: ConfigManagement;
226
- private _configCache;
227
- private _initialized;
228
- private _listeners;
229
- /** @internal */
230
- constructor(apiKey: string, timeout?: number, baseUrl?: string);
231
- /** @internal */
232
- _mgNew(id: string, options?: {
233
- name?: string;
234
- description?: string;
235
- parent?: string;
236
- }): Config;
237
- /** @internal */
238
- _mgList(): Promise<Config[]>;
239
- /** @internal */
240
- _mgDelete(id: string): Promise<void>;
241
- /** @internal — POST a new config. */
242
- _createConfig(config: Config): Promise<Config>;
243
- /** @internal — PUT a config update. */
244
- _updateConfig(config: Config): Promise<Config>;
245
- /** @internal — fetch a config by id. */
246
- _getById(id: string): Promise<Config>;
121
+ /** Dict method: list of resolved item keys. */
122
+ keys(): string[];
123
+ /** Dict method: list of resolved item values. */
124
+ values(): unknown[];
125
+ /** Dict method: list of `[key, value]` pairs. */
126
+ items(): Array<[string, unknown]>;
127
+ /** Dict method: get a value by key, returning `defaultValue` if absent. */
128
+ get<V = unknown>(key: string, defaultValue?: V): V | unknown;
247
129
  /**
248
- * Get a config's resolved values for the current environment.
130
+ * Register a change listener scoped to this config.
249
131
  *
250
- * Returns the resolved key-value pairs for the given config.
251
- * Optionally pass a model class to map the resolved values.
252
- */
253
- get<T = Record<string, unknown>>(id: string, model?: new (data: any) => T): Promise<T>;
254
- /**
255
- * Subscribe to a config's values. Returns a proxy whose properties
256
- * always reflect the latest resolved values.
132
+ * Three forms:
133
+ * - `proxy.onChange(callback)` fires on any change to this config.
134
+ * - `proxy.onChange("itemKey", callback)` — fires only when `itemKey` changes.
257
135
  *
258
- * Optionally pass a model class to map the resolved values.
136
+ * Equivalent to `client.config.onChange(this._key, ...)`; offered as
137
+ * sugar so callers who already have a live proxy can register listeners
138
+ * without re-stating the config id.
259
139
  */
260
- subscribe<T = Record<string, unknown>>(id: string, model?: new (data: any) => T): Promise<LiveConfigProxy<T>>;
261
- /**
262
- * Register a change listener.
263
- *
264
- * - `onChange(callback)` — fires for any config change (global).
265
- * - `onChange(configId, callback)` — fires for changes to a specific config.
266
- * - `onChange(configId, itemKey, callback)` — fires for a specific item.
267
- */
268
- onChange(callbackOrConfigId: string | ((event: ConfigChangeEvent) => void), callbackOrItemKey?: string | ((event: ConfigChangeEvent) => void), callback?: (event: ConfigChangeEvent) => void): void;
269
- /**
270
- * Refresh all config values from the server.
271
- * Fires change listeners for any values that changed.
272
- */
273
- refresh(): Promise<void>;
274
- /** @internal */
275
- private _ensureInitialized;
276
- /** @internal called by SmplClient for backward compat. */
277
- _connectInternal(environment: string): Promise<void>;
278
- /** @internal — get resolved config from cache. Used by LiveConfigProxy. */
279
- _getCachedConfig(key: string): Record<string, unknown> | undefined;
280
- private _handleConfigChanged;
281
- private _handleConfigDeleted;
282
- private _handleConfigsChanged;
283
- /** Fetch a single config by key. Returns null if not found. @internal */
284
- private _fetchSingleConfig;
285
- /** Resolve a config's values for an environment (no parent chain). @internal */
286
- private _resolveConfigValues;
287
- /** @internal */
288
- private _diffAndFire;
140
+ onChange(callback: (event: ConfigChangeEvent) => void): void;
141
+ onChange(itemKey: string, callback: (event: ConfigChangeEvent) => void): void;
142
+ }
143
+
144
+ interface components$1 {
145
+ schemas: {
146
+ /**
147
+ * Error
148
+ * @description Single JSON:API error object.
149
+ */
150
+ Error: {
151
+ /** Status */
152
+ status: string;
153
+ /** Title */
154
+ title: string;
155
+ /** Detail */
156
+ detail?: string | null;
157
+ /** Source */
158
+ source?: {
159
+ [key: string]: unknown;
160
+ } | null;
161
+ };
162
+ /**
163
+ * ErrorResponse
164
+ * @description JSON:API error response envelope.
165
+ */
166
+ ErrorResponse: {
167
+ /** Errors */
168
+ errors: components$1["schemas"]["Error"][];
169
+ };
170
+ /**
171
+ * LogGroup
172
+ * @example {
173
+ * "created_at": "2026-04-01T10:00:00Z",
174
+ * "environments": {
175
+ * "production": {
176
+ * "level": "ERROR"
177
+ * }
178
+ * },
179
+ * "level": "WARN",
180
+ * "name": "Database Loggers",
181
+ * "updated_at": "2026-04-01T10:00:00Z"
182
+ * }
183
+ */
184
+ LogGroup: {
185
+ /** Name */
186
+ name: string;
187
+ /** Level */
188
+ level?: string | null;
189
+ /** Parent Id */
190
+ parent_id?: string | null;
191
+ /** Environments */
192
+ environments?: {
193
+ [key: string]: unknown;
194
+ } | null;
195
+ /** Created At */
196
+ readonly created_at?: string | null;
197
+ /** Updated At */
198
+ readonly updated_at?: string | null;
199
+ };
200
+ /** LogGroupListResponse */
201
+ LogGroupListResponse: {
202
+ /** Data */
203
+ data: components$1["schemas"]["LogGroupResource"][];
204
+ };
205
+ /**
206
+ * LogGroupResource
207
+ * @example {
208
+ * "attributes": {
209
+ * "created_at": "2026-04-01T10:00:00Z",
210
+ * "environments": {
211
+ * "production": {
212
+ * "level": "ERROR"
213
+ * }
214
+ * },
215
+ * "level": "WARN",
216
+ * "name": "Database Loggers",
217
+ * "updated_at": "2026-04-01T10:00:00Z"
218
+ * },
219
+ * "id": "database-loggers",
220
+ * "type": "log_group"
221
+ * }
222
+ */
223
+ LogGroupResource: {
224
+ /** Id */
225
+ id?: string | null;
226
+ /**
227
+ * Type
228
+ * @constant
229
+ */
230
+ type: "log_group";
231
+ attributes: components$1["schemas"]["LogGroup"];
232
+ };
233
+ /** LogGroupResponse */
234
+ LogGroupResponse: {
235
+ data: components$1["schemas"]["LogGroupResource"];
236
+ };
237
+ /**
238
+ * Logger
239
+ * @example {
240
+ * "created_at": "2026-04-01T10:00:00Z",
241
+ * "environments": {
242
+ * "production": {
243
+ * "level": "WARN"
244
+ * },
245
+ * "staging": {
246
+ * "level": "DEBUG"
247
+ * }
248
+ * },
249
+ * "group": "database-loggers",
250
+ * "level": "DEBUG",
251
+ * "managed": true,
252
+ * "name": "SQL Logger",
253
+ * "updated_at": "2026-04-01T10:00:00Z"
254
+ * }
255
+ */
256
+ Logger: {
257
+ /** Name */
258
+ name: string;
259
+ /** Level */
260
+ level?: string | null;
261
+ /** Group */
262
+ group?: string | null;
263
+ /** Managed */
264
+ managed?: boolean | null;
265
+ /** Sources */
266
+ readonly sources?: {
267
+ [key: string]: unknown;
268
+ }[] | null;
269
+ /** Environments */
270
+ environments?: {
271
+ [key: string]: unknown;
272
+ } | null;
273
+ /** Effective Levels */
274
+ readonly effective_levels?: {
275
+ [key: string]: unknown;
276
+ } | null;
277
+ /** Created At */
278
+ readonly created_at?: string | null;
279
+ /** Updated At */
280
+ readonly updated_at?: string | null;
281
+ };
282
+ /**
283
+ * LoggerBulkItem
284
+ * @example {
285
+ * "environment": "production",
286
+ * "id": "sqlalchemy.engine",
287
+ * "level": "WARN",
288
+ * "resolved_level": "WARN",
289
+ * "service": "api-gateway"
290
+ * }
291
+ */
292
+ LoggerBulkItem: {
293
+ /**
294
+ * Id
295
+ * @description Normalized logger name
296
+ */
297
+ id: string;
298
+ /**
299
+ * Level
300
+ * @description The explicitly-set level on this logger. Null if inherited.
301
+ */
302
+ level?: string | null;
303
+ /**
304
+ * Resolved Level
305
+ * @description The effective level after framework inheritance. Never null in compliant SDKs.
306
+ */
307
+ resolved_level?: string | null;
308
+ /**
309
+ * Service
310
+ * @description Service name that discovered this logger
311
+ */
312
+ service?: string | null;
313
+ /**
314
+ * Environment
315
+ * @description Environment where this logger was observed
316
+ */
317
+ environment?: string | null;
318
+ };
319
+ /**
320
+ * LoggerBulkRequest
321
+ * @example {
322
+ * "loggers": [
323
+ * {
324
+ * "environment": "production",
325
+ * "id": "sqlalchemy.engine",
326
+ * "level": "WARN",
327
+ * "service": "api-gateway"
328
+ * },
329
+ * {
330
+ * "environment": "production",
331
+ * "id": "stripe",
332
+ * "level": "INFO",
333
+ * "service": "api-gateway"
334
+ * }
335
+ * ]
336
+ * }
337
+ */
338
+ LoggerBulkRequest: {
339
+ /** Loggers */
340
+ loggers: components$1["schemas"]["LoggerBulkItem"][];
341
+ };
342
+ /**
343
+ * LoggerBulkResponse
344
+ * @example {
345
+ * "registered": 5
346
+ * }
347
+ */
348
+ LoggerBulkResponse: {
349
+ /** Registered */
350
+ registered: number;
351
+ };
352
+ /** LoggerListResponse */
353
+ LoggerListResponse: {
354
+ /** Data */
355
+ data: components$1["schemas"]["LoggerResource"][];
356
+ };
357
+ /**
358
+ * LoggerResource
359
+ * @example {
360
+ * "attributes": {
361
+ * "created_at": "2026-04-01T10:00:00Z",
362
+ * "environments": {
363
+ * "production": {
364
+ * "level": "WARN"
365
+ * },
366
+ * "staging": {
367
+ * "level": "DEBUG"
368
+ * }
369
+ * },
370
+ * "group": "database-loggers",
371
+ * "level": "DEBUG",
372
+ * "managed": true,
373
+ * "name": "SQL Logger",
374
+ * "updated_at": "2026-04-01T10:00:00Z"
375
+ * },
376
+ * "id": "com.example.sql",
377
+ * "type": "logger"
378
+ * }
379
+ */
380
+ LoggerResource: {
381
+ /** Id */
382
+ id?: string | null;
383
+ /**
384
+ * Type
385
+ * @constant
386
+ */
387
+ type: "logger";
388
+ attributes: components$1["schemas"]["Logger"];
389
+ };
390
+ /** LoggerResponse */
391
+ LoggerResponse: {
392
+ data: components$1["schemas"]["LoggerResource"];
393
+ };
394
+ /**
395
+ * LoggerSource
396
+ * @example {
397
+ * "created_at": "2026-04-01T10:00:00Z",
398
+ * "environment": "production",
399
+ * "first_observed": "2026-04-01T10:00:00Z",
400
+ * "last_seen": "2026-04-11T15:30:00Z",
401
+ * "resolved_level": "WARN",
402
+ * "service": "api-gateway",
403
+ * "updated_at": "2026-04-11T15:30:00Z"
404
+ * }
405
+ */
406
+ LoggerSource: {
407
+ /** Service */
408
+ readonly service?: string;
409
+ /** Environment */
410
+ readonly environment?: string;
411
+ /** Level */
412
+ readonly level?: string | null;
413
+ /** Resolved Level */
414
+ readonly resolved_level?: string;
415
+ /** First Observed */
416
+ readonly first_observed?: string | null;
417
+ /** Last Seen */
418
+ readonly last_seen?: string | null;
419
+ /** Created At */
420
+ readonly created_at?: string | null;
421
+ /** Updated At */
422
+ readonly updated_at?: string | null;
423
+ };
424
+ /** LoggerSourceListResponse */
425
+ LoggerSourceListResponse: {
426
+ /** Data */
427
+ data: components$1["schemas"]["LoggerSourceResource"][];
428
+ };
429
+ /**
430
+ * LoggerSourceResource
431
+ * @example {
432
+ * "attributes": {
433
+ * "created_at": "2026-04-01T10:00:00Z",
434
+ * "environment": "production",
435
+ * "first_observed": "2026-04-01T10:00:00Z",
436
+ * "last_seen": "2026-04-11T15:30:00Z",
437
+ * "resolved_level": "WARN",
438
+ * "service": "api-gateway",
439
+ * "updated_at": "2026-04-11T15:30:00Z"
440
+ * },
441
+ * "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
442
+ * "type": "logger_source"
443
+ * }
444
+ */
445
+ LoggerSourceResource: {
446
+ /** Id */
447
+ id?: string | null;
448
+ /**
449
+ * Type
450
+ * @constant
451
+ */
452
+ type: "logger_source";
453
+ attributes: components$1["schemas"]["LoggerSource"];
454
+ };
455
+ /** ServiceAttributes */
456
+ ServiceAttributes: Record<string, never>;
457
+ /** ServiceListResponse */
458
+ ServiceListResponse: {
459
+ /** Data */
460
+ data: components$1["schemas"]["ServiceResource"][];
461
+ };
462
+ /**
463
+ * ServiceResource
464
+ * @example {
465
+ * "attributes": {},
466
+ * "id": "api-gateway",
467
+ * "type": "service"
468
+ * }
469
+ */
470
+ ServiceResource: {
471
+ /** Id */
472
+ id: string;
473
+ /**
474
+ * Type
475
+ * @constant
476
+ */
477
+ type: "service";
478
+ /** @default {} */
479
+ attributes: components$1["schemas"]["ServiceAttributes"];
480
+ };
481
+ /** UsageAttributes */
482
+ UsageAttributes: {
483
+ /** Limit Key */
484
+ limit_key: string;
485
+ /** Period */
486
+ period: string;
487
+ /** Value */
488
+ value: number;
489
+ };
490
+ /**
491
+ * UsageListResponse
492
+ * @example {
493
+ * "data": [
494
+ * {
495
+ * "attributes": {
496
+ * "limit_key": "logging.managed_loggers",
497
+ * "period": "current",
498
+ * "value": 8
499
+ * },
500
+ * "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
501
+ * "type": "usage"
502
+ * },
503
+ * {
504
+ * "attributes": {
505
+ * "limit_key": "logging.groups",
506
+ * "period": "current",
507
+ * "value": 2
508
+ * },
509
+ * "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
510
+ * "type": "usage"
511
+ * }
512
+ * ]
513
+ * }
514
+ */
515
+ UsageListResponse: {
516
+ /** Data */
517
+ data: components$1["schemas"]["UsageResource"][];
518
+ };
519
+ /**
520
+ * UsageResource
521
+ * @example {
522
+ * "attributes": {
523
+ * "limit_key": "logging.managed_loggers",
524
+ * "period": "current",
525
+ * "value": 8
526
+ * },
527
+ * "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
528
+ * "type": "usage"
529
+ * }
530
+ */
531
+ UsageResource: {
532
+ /** Id */
533
+ id: string;
534
+ /**
535
+ * Type
536
+ * @constant
537
+ */
538
+ type: "usage";
539
+ attributes: components$1["schemas"]["UsageAttributes"];
540
+ };
541
+ };
542
+ responses: never;
543
+ parameters: never;
544
+ requestBodies: never;
545
+ headers: never;
546
+ pathItems: never;
289
547
  }
290
548
 
291
549
  interface components {
@@ -727,173 +985,493 @@ interface components {
727
985
  }
728
986
 
729
987
  /**
730
- * Public types for the Flags SDK: Context, Rule.
988
+ * Shared types for the management namespace.
989
+ */
990
+ /** Whether an environment participates in the canonical ordering.
991
+ *
992
+ * STANDARD environments are the customer's deploy targets (production,
993
+ * staging, development, etc.) and appear in the environment_order list.
994
+ * AD_HOC environments are transient targets (preview branches,
995
+ * developer sandboxes) that are excluded from the standard ordering.
996
+ */
997
+ declare enum EnvironmentClassification {
998
+ STANDARD = "STANDARD",
999
+ AD_HOC = "AD_HOC"
1000
+ }
1001
+ /**
1002
+ * A color, expressed as a CSS hex string.
1003
+ *
1004
+ * Frozen — construct a fresh `Color` to change a value.
1005
+ *
1006
+ * @example
1007
+ * ```typescript
1008
+ * new Color("#ef4444") // 6-digit hex
1009
+ * new Color("#fff") // 3-digit shorthand
1010
+ * new Color("#ef4444aa") // 8-digit with alpha
1011
+ * Color.rgb(239, 68, 68) // RGB components
1012
+ * ```
1013
+ */
1014
+ declare class Color {
1015
+ /** The normalized lowercase hex string. */
1016
+ readonly hex: string;
1017
+ constructor(hex: string);
1018
+ /** Construct a `Color` from 0–255 RGB components. */
1019
+ static rgb(r: number, g: number, b: number): Color;
1020
+ toString(): string;
1021
+ /** Equality by hex value. */
1022
+ equals(other: unknown): boolean;
1023
+ }
1024
+
1025
+ /**
1026
+ * Active-record models for management resources.
1027
+ */
1028
+
1029
+ /** @internal */
1030
+ interface EnvironmentModelClient {
1031
+ _create(env: Environment): Promise<Environment>;
1032
+ _update(env: Environment): Promise<Environment>;
1033
+ delete(id: string): Promise<void>;
1034
+ }
1035
+ /** @internal */
1036
+ interface ContextTypeModelClient {
1037
+ _create(ct: ContextType): Promise<ContextType>;
1038
+ _update(ct: ContextType): Promise<ContextType>;
1039
+ delete(id: string): Promise<void>;
1040
+ }
1041
+ /** @internal */
1042
+ interface AccountSettingsModelClient {
1043
+ _save(data: Record<string, any>): Promise<AccountSettings>;
1044
+ }
1045
+ /**
1046
+ * An environment resource managed by the smplkit platform.
1047
+ *
1048
+ * Mutate fields, then call {@link save} to create or update.
1049
+ */
1050
+ declare class Environment {
1051
+ /** Unique slug identifier (e.g. `"production"`). */
1052
+ id: string | null;
1053
+ /** Human-readable display name. */
1054
+ name: string;
1055
+ /** Whether this is a STANDARD or AD_HOC environment. */
1056
+ classification: EnvironmentClassification;
1057
+ /** When the environment was created. */
1058
+ createdAt: string | null;
1059
+ /** When the environment was last updated. */
1060
+ updatedAt: string | null;
1061
+ /** @internal */
1062
+ private _color;
1063
+ /** @internal */
1064
+ readonly _client: EnvironmentModelClient | null;
1065
+ /** @internal */
1066
+ constructor(client: EnvironmentModelClient | null, fields: {
1067
+ id: string | null;
1068
+ name: string;
1069
+ color?: Color | string | null;
1070
+ classification: EnvironmentClassification;
1071
+ createdAt?: string | null;
1072
+ updatedAt?: string | null;
1073
+ });
1074
+ /** The environment color, or `null`. Accepts `Color | string | null` on assignment. */
1075
+ get color(): Color | null;
1076
+ set color(value: Color | string | null);
1077
+ /** Persist this environment to the server (creates if new, updates if existing). */
1078
+ save(): Promise<void>;
1079
+ /** Delete this environment from the server. */
1080
+ delete(): Promise<void>;
1081
+ /** @internal */
1082
+ _apply(other: Environment): void;
1083
+ toString(): string;
1084
+ }
1085
+ /**
1086
+ * A context-type resource managed by the smplkit platform.
1087
+ *
1088
+ * Mutate fields or use {@link addAttribute} / {@link removeAttribute} /
1089
+ * {@link updateAttribute}, then call {@link save} to persist.
1090
+ */
1091
+ declare class ContextType {
1092
+ /** Unique slug identifier (e.g. `"user"`). */
1093
+ id: string | null;
1094
+ /** Human-readable display name. */
1095
+ name: string;
1096
+ /** Known attribute keys with metadata objects. */
1097
+ attributes: Record<string, Record<string, any>>;
1098
+ createdAt: string | null;
1099
+ updatedAt: string | null;
1100
+ /** @internal */
1101
+ readonly _client: ContextTypeModelClient | null;
1102
+ /** @internal */
1103
+ constructor(client: ContextTypeModelClient | null, fields: {
1104
+ id: string | null;
1105
+ name: string;
1106
+ attributes?: Record<string, Record<string, any>>;
1107
+ createdAt?: string | null;
1108
+ updatedAt?: string | null;
1109
+ });
1110
+ /** Add a known-attribute slot. Local; call {@link save} to persist. */
1111
+ addAttribute(name: string, metadata?: Record<string, any>): void;
1112
+ /** Remove a known-attribute slot. Local; call {@link save} to persist. */
1113
+ removeAttribute(name: string): void;
1114
+ /** Replace a known-attribute slot's metadata. Local; call {@link save} to persist. */
1115
+ updateAttribute(name: string, metadata: Record<string, any>): void;
1116
+ save(): Promise<void>;
1117
+ delete(): Promise<void>;
1118
+ /** @internal */
1119
+ _apply(other: ContextType): void;
1120
+ toString(): string;
1121
+ }
1122
+ /**
1123
+ * Active-record account-settings model.
1124
+ *
1125
+ * The wire format is opaque JSON. Documented keys are exposed as typed
1126
+ * properties; unknown keys live in `raw`. Call {@link save} to write back.
1127
+ */
1128
+ declare class AccountSettings {
1129
+ /** @internal */
1130
+ private _data;
1131
+ /** @internal */
1132
+ readonly _client: AccountSettingsModelClient | null;
1133
+ /** @internal */
1134
+ constructor(client: AccountSettingsModelClient | null, data: Record<string, any>);
1135
+ /** The full settings dict. */
1136
+ get raw(): Record<string, any>;
1137
+ set raw(value: Record<string, any>);
1138
+ /** Canonical ordering of STANDARD environments. Empty array if unset. */
1139
+ get environmentOrder(): string[];
1140
+ set environmentOrder(value: string[]);
1141
+ save(): Promise<void>;
1142
+ /** @internal */
1143
+ _apply(other: AccountSettings): void;
1144
+ /** @internal — expose raw data for `_save()`. */
1145
+ get _rawData(): Record<string, any>;
1146
+ toString(): string;
1147
+ }
1148
+
1149
+ /**
1150
+ * Public types for the Flags SDK: Op, Context, FlagDeclaration, Rule.
1151
+ */
1152
+ /**
1153
+ * Operators supported by `Rule.when`.
1154
+ *
1155
+ * Customers should prefer `Op.EQ` etc. over raw strings so the IDE
1156
+ * can validate calls. Raw strings are still accepted for flexibility.
731
1157
  */
1158
+ declare enum Op {
1159
+ EQ = "==",
1160
+ NEQ = "!=",
1161
+ LT = "<",
1162
+ LTE = "<=",
1163
+ GT = ">",
1164
+ GTE = ">=",
1165
+ IN = "in",
1166
+ CONTAINS = "contains"
1167
+ }
1168
+ /** @internal */
1169
+ interface ContextClient {
1170
+ _saveContext(ctx: Context): Promise<Context>;
1171
+ delete(id: string): Promise<void>;
1172
+ }
732
1173
  /**
733
- * A typed evaluation context entity.
1174
+ * A typed evaluation-context entity.
734
1175
  *
735
- * Represents a single entity (user, account, device, etc.) in the
736
- * evaluation context. The *type* and *key* identify the entity;
737
- * *attributes* carry the data that JSON Logic rules target.
1176
+ * Represents a single entity (user, account, device, etc.). The *type*
1177
+ * and *key* identify the entity; *attributes* carry the data that
1178
+ * targeting rules evaluate against.
1179
+ *
1180
+ * Used for both authoring (`flag.get({ context: [...] })`,
1181
+ * `client.setContext([...])`, `mgmt.contexts.register([...])`) and
1182
+ * reading (`mgmt.contexts.list/get` return populated `Context`
1183
+ * instances with `save()` / `delete()` ready to call).
1184
+ *
1185
+ * Validation happens at construction:
1186
+ * - `type` and `key` must be strings (numeric IDs rejected — stringify
1187
+ * them at the SDK boundary).
1188
+ * - Unknown property assignment via dotted notation is blocked. Use
1189
+ * `ctx.attributes["plan"] = ...` instead.
1190
+ * - Once persisted (`createdAt` is set), `type` and `key` become
1191
+ * immutable.
738
1192
  *
739
1193
  * @example
740
1194
  * ```typescript
741
- * new Context("user", "user-123", { plan: "enterprise", firstName: "Alice" })
742
- * new Context("user", "user-123", { plan: "enterprise" }, { name: "Alice Smith" })
1195
+ * new Context("user", "user-123", { plan: "enterprise" });
1196
+ * new Context("account", "acme", { region: "us" }, { name: "Acme" });
743
1197
  * ```
744
1198
  */
745
1199
  declare class Context {
746
- readonly type: string;
747
- readonly key: string;
748
- readonly name: string | null;
749
- readonly attributes: Record<string, unknown>;
1200
+ type: string;
1201
+ key: string;
1202
+ name: string | null;
1203
+ attributes: Record<string, unknown>;
1204
+ createdAt: string | null;
1205
+ updatedAt: string | null;
1206
+ /** @internal */
1207
+ _client: ContextClient | null;
750
1208
  constructor(type: string, key: string, attributes?: Record<string, unknown>, options?: {
751
1209
  name?: string;
1210
+ createdAt?: string | null;
1211
+ updatedAt?: string | null;
752
1212
  });
1213
+ /** Composite `"{type}:{key}"` identifier. */
1214
+ get id(): string;
1215
+ /** Persist this context to the server (create or update). */
1216
+ save(): Promise<void>;
1217
+ /** Delete this context from the server. */
1218
+ delete(): Promise<void>;
1219
+ /** @internal */
1220
+ _apply(other: Context): void;
753
1221
  toString(): string;
754
1222
  }
1223
+ /**
1224
+ * Describes a flag declaration for buffered registration.
1225
+ *
1226
+ * Used by `mgmt.flags.register` to queue declarations for bulk
1227
+ * registration. `service` and `environment` default to `null`; the
1228
+ * runtime client fills them from the active `SmplClient` when it
1229
+ * forwards declarations.
1230
+ */
1231
+ declare class FlagDeclaration {
1232
+ readonly id: string;
1233
+ readonly type: string;
1234
+ readonly default: unknown;
1235
+ readonly service: string | null;
1236
+ readonly environment: string | null;
1237
+ constructor(fields: {
1238
+ id: string;
1239
+ type: string;
1240
+ default: unknown;
1241
+ service?: string | null;
1242
+ environment?: string | null;
1243
+ });
1244
+ }
755
1245
  /**
756
1246
  * Fluent builder for flag targeting rules.
757
1247
  *
758
1248
  * @example
759
1249
  * ```typescript
760
- * new Rule("Enable for enterprise users")
761
- * .when("user.plan", "==", "enterprise")
762
- * .when("account.region", "==", "us")
763
- * .serve(true)
764
- * .build()
1250
+ * new Rule("Enable for enterprise users", { environment: "staging" })
1251
+ * .when("user.plan", Op.EQ, "enterprise")
1252
+ * .when("account.region", Op.EQ, "us")
1253
+ * .serve(true);
765
1254
  * ```
766
1255
  *
767
- * Multiple `.when()` calls are combined with AND logic.
1256
+ * Multiple `.when()` calls are AND'd. `environment` is required so the
1257
+ * target environment is unambiguous when the rule is passed to
1258
+ * `Flag.addRule`. `.serve()` finalizes the rule and returns a built
1259
+ * dict ready to pass to `addRule`.
768
1260
  */
769
1261
  declare class Rule {
770
- private _description;
771
- private _conditions;
772
- private _value;
773
- private _environment;
774
- constructor(description: string);
775
- /** Tag this rule with an environment key (used by `addRule`). */
776
- environment(envKey: string): Rule;
777
- /** Add a condition. Multiple calls are AND'd. */
778
- when(variable: string, op: string, value: any): Rule;
779
- /** Set the value returned when this rule matches. */
780
- serve(value: any): Rule;
781
- /** Finalize and return the rule as a plain object. */
782
- build(): Record<string, any>;
1262
+ private readonly _description;
1263
+ private readonly _conditions;
1264
+ private readonly _environment;
1265
+ constructor(description: string, options: {
1266
+ environment: string;
1267
+ });
1268
+ /**
1269
+ * Add a condition. Multiple calls are AND'd at the top level.
1270
+ *
1271
+ * Two forms:
1272
+ * - `when(var, op, value)` — convenience for simple comparisons.
1273
+ * - `when(expr)` escape hatch accepting an arbitrary JSON Logic
1274
+ * expression (use this for OR, nested AND/OR, `if`, etc.).
1275
+ */
1276
+ when(expr: Record<string, any>): Rule;
1277
+ when(variable: string, op: Op | string, value: any): Rule;
1278
+ /** Finalize the rule with `value` served on match and return the built dict. */
1279
+ serve(value: any): Record<string, any>;
783
1280
  }
784
1281
 
785
1282
  /**
786
- * Flag model hierarchy with typed subclasses for type-safe evaluation.
1283
+ * Config model + ConfigItem + ConfigEnvironment.
787
1284
  */
788
-
1285
+ /** Type of a {@link ConfigItem} value. */
1286
+ declare enum ItemType {
1287
+ STRING = "STRING",
1288
+ NUMBER = "NUMBER",
1289
+ BOOLEAN = "BOOLEAN",
1290
+ JSON = "JSON"
1291
+ }
1292
+ /** @internal Config client surface used by the active-record `Config.save`/`delete`. */
1293
+ interface ConfigModelClient {
1294
+ _createConfig?: (config: Config) => Promise<Config>;
1295
+ _updateConfig?: (config: Config) => Promise<Config>;
1296
+ _deleteConfig?: (id: string) => Promise<void>;
1297
+ _fetchConfig?: (id: string) => Promise<Config>;
1298
+ }
1299
+ /** A single typed item in a {@link Config}. */
1300
+ declare class ConfigItem {
1301
+ readonly name: string;
1302
+ readonly value: unknown;
1303
+ readonly type: ItemType;
1304
+ readonly description: string | null;
1305
+ constructor(name: string, value: unknown, type: ItemType | string, options?: {
1306
+ description?: string;
1307
+ });
1308
+ toString(): string;
1309
+ }
789
1310
  /**
790
- * A flag resource.
1311
+ * Per-environment value overrides for a {@link Config}.
791
1312
  *
792
- * Call `save()` to persist changes. Call `get()` to evaluate the flag.
1313
+ * Read-only inspection container. Mutation is performed via {@link Config}'s
1314
+ * setters with `environment` option (e.g. `cfg.setString("k", "v",
1315
+ * { environment: "production" })`).
793
1316
  */
794
- declare class Flag {
795
- /** Unique identifier (slug) within the account. */
1317
+ declare class ConfigEnvironment {
1318
+ /** @internal */
1319
+ readonly _valuesRaw: Record<string, Record<string, unknown>>;
1320
+ constructor(values?: Record<string, unknown>);
1321
+ /** Return overrides as a plain dict `{key: rawValue}`. */
1322
+ get values(): Record<string, unknown>;
1323
+ /** Return the full typed overrides `{key: {value, type, description}}` (deep copy). */
1324
+ get valuesRaw(): Record<string, Record<string, unknown>>;
1325
+ toString(): string;
1326
+ }
1327
+ /**
1328
+ * A configuration resource fetched from the Smpl Config service.
1329
+ *
1330
+ * Mutate base values via `set` / `setString` / `setNumber` /
1331
+ * `setBoolean` / `setJson` / `remove` (pass `{ environment: "..." }` to
1332
+ * scope mutations to a specific environment). Call {@link save} to persist.
1333
+ */
1334
+ declare class Config {
796
1335
  id: string | null;
797
- /** Human-readable display name. */
798
1336
  name: string;
799
- /** Value type: BOOLEAN, STRING, NUMERIC, or JSON. */
800
- type: string;
801
- /** Flag-level default value. */
802
- default: unknown;
803
- /** Closed set of possible values (constrained), or null (unconstrained). */
804
- values: Array<{
805
- name: string;
806
- value: unknown;
807
- }> | null;
808
- /** Optional description. */
809
1337
  description: string | null;
810
- /** Per-environment configuration. */
811
- environments: Record<string, any>;
812
- /** When the flag was created. */
1338
+ parent: string | null;
813
1339
  createdAt: string | null;
814
- /** When the flag was last updated. */
815
1340
  updatedAt: string | null;
816
1341
  /** @internal */
817
- readonly _client: FlagsClient;
1342
+ protected _itemsRaw: Record<string, Record<string, unknown>>;
818
1343
  /** @internal */
819
- constructor(client: FlagsClient, fields: {
1344
+ protected _environments: Record<string, ConfigEnvironment>;
1345
+ /** @internal */
1346
+ readonly _client: ConfigModelClient | null;
1347
+ /** @internal */
1348
+ constructor(client: ConfigModelClient | null, fields: {
820
1349
  id: string | null;
821
1350
  name: string;
822
- type: string;
823
- default: unknown;
824
- values: Array<{
825
- name: string;
826
- value: unknown;
827
- }> | null;
828
- description: string | null;
829
- environments: Record<string, any>;
830
- createdAt: string | null;
831
- updatedAt: string | null;
1351
+ description?: string | null;
1352
+ parent?: string | null;
1353
+ items?: Record<string, unknown> | null;
1354
+ environments?: Record<string, unknown> | null;
1355
+ createdAt?: string | null;
1356
+ updatedAt?: string | null;
832
1357
  });
833
1358
  /**
834
- * Persist this flag to the server.
1359
+ * Read-only `{key: rawValue}` view of base items.
835
1360
  *
836
- * Creates if new, updates if existing.
837
- * Updates this instance in-place with the server response.
1361
+ * Mutate via {@link set} / {@link setString} / {@link setNumber} /
1362
+ * {@link setBoolean} / {@link setJson} / {@link remove}.
838
1363
  */
839
- save(): Promise<void>;
1364
+ get items(): Record<string, unknown>;
1365
+ /** Return the full typed items `{key: {value, type, description}}` (deep copy). */
1366
+ get itemsRaw(): Record<string, Record<string, unknown>>;
1367
+ /**
1368
+ * Read-only view of per-environment overrides keyed by environment id.
1369
+ *
1370
+ * Mutate via the `environment` option on {@link set} / {@link setString} /
1371
+ * {@link setNumber} / {@link setBoolean} / {@link setJson} / {@link remove}.
1372
+ */
1373
+ get environments(): Record<string, ConfigEnvironment>;
1374
+ /** @internal — return the wire-shaped raw items for serialization. */
1375
+ get _itemsRawDirect(): Record<string, Record<string, unknown>>;
1376
+ /** @internal — return the typed environments dict for serialization. */
1377
+ get _environmentsDirect(): Record<string, ConfigEnvironment>;
1378
+ /** @internal — return the dict that `set()` / `remove()` should mutate. */
1379
+ private _itemsTarget;
1380
+ /**
1381
+ * Set (or replace) an item. With `environment`, sets an override on
1382
+ * that environment.
1383
+ */
1384
+ set(item: ConfigItem, options?: {
1385
+ environment?: string;
1386
+ }): void;
1387
+ /** Remove an item by name. With `environment`, removes only that env's override. */
1388
+ remove(name: string, options?: {
1389
+ environment?: string;
1390
+ }): void;
1391
+ /** Convenience: set a STRING item (or environment override). */
1392
+ setString(name: string, value: string, options?: {
1393
+ description?: string;
1394
+ environment?: string;
1395
+ }): void;
1396
+ /** Convenience: set a NUMBER item (or environment override). */
1397
+ setNumber(name: string, value: number, options?: {
1398
+ description?: string;
1399
+ environment?: string;
1400
+ }): void;
1401
+ /** Convenience: set a BOOLEAN item (or environment override). */
1402
+ setBoolean(name: string, value: boolean, options?: {
1403
+ description?: string;
1404
+ environment?: string;
1405
+ }): void;
1406
+ /** Convenience: set a JSON item (or environment override). */
1407
+ setJson(name: string, value: unknown, options?: {
1408
+ description?: string;
1409
+ environment?: string;
1410
+ }): void;
840
1411
  /**
841
- * Add a rule to a specific environment.
1412
+ * Persist this config to the server.
842
1413
  *
843
- * The built rule must include an `environment` key (set via
844
- * `Rule(...).environment("env_key")`). Call `save()` to persist.
1414
+ * Creates a new config if unsaved, or updates the existing one.
845
1415
  *
846
- * @returns `this` for chaining.
1416
+ * @throws SmplkitNotFoundError if the config no longer exists (update).
1417
+ * @throws SmplkitValidationError if the server rejects the request.
1418
+ * @throws Error if the model was constructed without a management client.
847
1419
  */
848
- addRule(builtRule: Record<string, any>): Flag;
849
- /** Enable or disable a flag in a specific environment. Call `save()` to persist. */
850
- setEnvironmentEnabled(envKey: string, enabled: boolean): void;
851
- /** Set the default value for a specific environment. Call `save()` to persist. */
852
- setEnvironmentDefault(envKey: string, defaultValue: unknown): void;
853
- /** Clear all rules for a specific environment. Call `save()` to persist. */
854
- clearRules(envKey: string): void;
1420
+ save(): Promise<void>;
1421
+ /** Delete this config from the server. */
1422
+ delete(): Promise<void>;
1423
+ /** @internal */
1424
+ _apply(other: Config): void;
855
1425
  /**
856
- * Evaluate the flag and return its current value.
1426
+ * Walk the parent chain and return config data dicts child-to-root.
857
1427
  *
858
- * Requires `initialize()` to have been called on the flags client.
1428
+ * @internal
859
1429
  */
860
- get(options?: {
861
- context?: Context[];
862
- }): unknown;
863
- /** @internal — copy all fields from another Flag instance. */
864
- _apply(other: Flag): void;
865
- toString(): string;
866
- }
867
- /** Typed flag that returns `boolean` from `get()`. */
868
- declare class BooleanFlag extends Flag {
869
- get(options?: {
870
- context?: Context[];
871
- }): boolean;
872
- }
873
- /** Typed flag that returns `string` from `get()`. */
874
- declare class StringFlag extends Flag {
875
- get(options?: {
876
- context?: Context[];
877
- }): string;
878
- }
879
- /** Typed flag that returns `number` from `get()`. */
880
- declare class NumberFlag extends Flag {
881
- get(options?: {
882
- context?: Context[];
883
- }): number;
1430
+ _buildChain(configs?: Config[]): Promise<Array<{
1431
+ id: string | null;
1432
+ items: Record<string, Record<string, unknown>>;
1433
+ environments: Record<string, {
1434
+ values: Record<string, Record<string, unknown>>;
1435
+ }>;
1436
+ }>>;
1437
+ toString(): string;
884
1438
  }
885
- /** Typed flag that returns `Record<string, any>` from `get()`. */
886
- declare class JsonFlag extends Flag {
887
- get(options?: {
888
- context?: Context[];
889
- }): Record<string, any>;
1439
+
1440
+ type ConfigHttp$1 = ReturnType<typeof createClient<___generated_config_d_ts.paths>>;
1441
+ /**
1442
+ * `mgmt.config.*` — CRUD client for configs.
1443
+ */
1444
+ declare class ManagementConfigClient {
1445
+ private readonly _http;
1446
+ /** @internal */
1447
+ constructor(_http: ConfigHttp$1);
1448
+ /** Construct an unsaved {@link Config}. Call `.save()` to persist. */
1449
+ new(id: string, options?: {
1450
+ name?: string;
1451
+ description?: string;
1452
+ parent?: string | Config | null;
1453
+ }): Config;
1454
+ /** List all configs. */
1455
+ list(): Promise<Config[]>;
1456
+ /** Fetch a config by id. */
1457
+ get(id: string): Promise<Config>;
1458
+ /** Delete a config by id. */
1459
+ delete(id: string): Promise<void>;
1460
+ /** @internal — called by `Config.delete()`. */
1461
+ _deleteConfig(id: string): Promise<void>;
1462
+ /** @internal — called by `Config._buildChain` to resolve parents. */
1463
+ _fetchConfig(id: string): Promise<Config>;
1464
+ /** @internal — called by `Config.save()` for new resources. */
1465
+ _createConfig(config: Config): Promise<Config>;
1466
+ /** @internal — called by `Config.save()` for existing resources. */
1467
+ _updateConfig(config: Config): Promise<Config>;
890
1468
  }
891
1469
 
892
1470
  /**
893
- * FlagsClient — management and runtime for Smpl Flags.
1471
+ * FlagsClient — runtime client for Smpl Flags (handle declaration, evaluation,
1472
+ * live updates). Management/CRUD lives on `mgmt.flags.*`.
894
1473
  */
895
1474
 
896
- type FlagResource = components["schemas"]["FlagResource"];
897
1475
  /** Describes a flag definition change. */
898
1476
  declare class FlagChangeEvent {
899
1477
  readonly id: string;
@@ -908,69 +1486,13 @@ declare class FlagStats {
908
1486
  readonly cacheMisses: number;
909
1487
  constructor(cacheHits: number, cacheMisses: number);
910
1488
  }
911
- /** @internal — exported so ManagementClient.contexts can share the same buffer. */
912
- declare class ContextRegistrationBuffer {
913
- private _seen;
914
- private _pending;
915
- observe(contexts: Context[]): void;
916
- drain(): Array<Record<string, any>>;
917
- get pendingCount(): number;
918
- }
919
- /**
920
- * Management API for smplkit Flags — CRUD operations on Flag models.
921
- *
922
- * Access via `SmplClient.flags.management`.
923
- */
924
- declare class FlagsManagement {
925
- private readonly _client;
926
- constructor(_client: FlagsClient);
927
- /** Create an unsaved boolean flag. Call `.save()` to persist. */
928
- newBooleanFlag(id: string, options: {
929
- default: boolean;
930
- name?: string;
931
- description?: string;
932
- }): BooleanFlag;
933
- /** Create an unsaved string flag. Call `.save()` to persist. */
934
- newStringFlag(id: string, options: {
935
- default: string;
936
- name?: string;
937
- description?: string;
938
- values?: Array<{
939
- name: string;
940
- value: unknown;
941
- }>;
942
- }): StringFlag;
943
- /** Create an unsaved number flag. Call `.save()` to persist. */
944
- newNumberFlag(id: string, options: {
945
- default: number;
946
- name?: string;
947
- description?: string;
948
- values?: Array<{
949
- name: string;
950
- value: unknown;
951
- }>;
952
- }): NumberFlag;
953
- /** Create an unsaved JSON flag. Call `.save()` to persist. */
954
- newJsonFlag(id: string, options: {
955
- default: Record<string, any>;
956
- name?: string;
957
- description?: string;
958
- values?: Array<{
959
- name: string;
960
- value: unknown;
961
- }>;
962
- }): JsonFlag;
963
- /** Fetch a flag by id. */
964
- get(id: string): Promise<Flag>;
965
- /** List all flags. */
966
- list(): Promise<Flag[]>;
967
- /** Delete a flag by id. */
968
- delete(id: string): Promise<void>;
969
- }
1489
+
970
1490
  /**
971
- * Client for the smplkit Flags API.
1491
+ * Runtime client for the smplkit Flags service.
972
1492
  *
973
- * Obtained via `SmplClient.flags`.
1493
+ * Obtained via `SmplClient.flags`. Provides flag handle declaration,
1494
+ * evaluation, and live-updates. Management/CRUD lives on
1495
+ * `SmplClient.manage.flags` (or use a standalone {@link SmplManagementClient}).
974
1496
  */
975
1497
  declare class FlagsClient {
976
1498
  /** @internal */
@@ -1000,56 +1522,8 @@ declare class FlagsClient {
1000
1522
  readonly _service: string | null;
1001
1523
  readonly _metrics: MetricsReporter | null;
1002
1524
  } | null;
1003
- /** Management API — CRUD operations on Flag models. */
1004
- readonly management: FlagsManagement;
1005
1525
  /** @internal */
1006
1526
  constructor(apiKey: string, ensureWs: () => SharedWebSocket, timeout?: number, flagsBaseUrl?: string, appBaseUrl?: string, contextBuffer?: ContextRegistrationBuffer);
1007
- /** @internal */
1008
- _mgNewBooleanFlag(id: string, options: {
1009
- default: boolean;
1010
- name?: string;
1011
- description?: string;
1012
- }): BooleanFlag;
1013
- /** @internal */
1014
- _mgNewStringFlag(id: string, options: {
1015
- default: string;
1016
- name?: string;
1017
- description?: string;
1018
- values?: Array<{
1019
- name: string;
1020
- value: unknown;
1021
- }>;
1022
- }): StringFlag;
1023
- /** @internal */
1024
- _mgNewNumberFlag(id: string, options: {
1025
- default: number;
1026
- name?: string;
1027
- description?: string;
1028
- values?: Array<{
1029
- name: string;
1030
- value: unknown;
1031
- }>;
1032
- }): NumberFlag;
1033
- /** @internal */
1034
- _mgNewJsonFlag(id: string, options: {
1035
- default: Record<string, any>;
1036
- name?: string;
1037
- description?: string;
1038
- values?: Array<{
1039
- name: string;
1040
- value: unknown;
1041
- }>;
1042
- }): JsonFlag;
1043
- /** @internal */
1044
- _mgGet(id: string): Promise<Flag>;
1045
- /** @internal */
1046
- _mgList(): Promise<Flag[]>;
1047
- /** @internal */
1048
- _mgDelete(id: string): Promise<void>;
1049
- /** @internal — POST a new flag. */
1050
- _createFlag(flag: Flag): Promise<Flag>;
1051
- /** @internal — PUT a flag update. */
1052
- _updateFlag(flag: Flag): Promise<Flag>;
1053
1527
  /** Declare a boolean flag handle for runtime evaluation. */
1054
1528
  booleanFlag(id: string, defaultValue: boolean): BooleanFlag;
1055
1529
  /** Declare a string flag handle for runtime evaluation. */
@@ -1112,11 +1586,320 @@ declare class FlagsClient {
1112
1586
  private _fireChangeListenersAll;
1113
1587
  private _flushFlags;
1114
1588
  private _flushContexts;
1115
- /** @internal */
1116
- _resourceToModel(resource: FlagResource): Flag;
1117
1589
  private _resourceToPlainDict;
1118
1590
  }
1119
1591
 
1592
+ /**
1593
+ * Flag, FlagValue, FlagRule, FlagEnvironment — flag model + frozen wrappers.
1594
+ */
1595
+
1596
+ /** @internal Flag client surface needed by the model (covers both runtime + management). */
1597
+ interface FlagModelClient {
1598
+ _createFlag?: (flag: Flag) => Promise<Flag>;
1599
+ _updateFlag?: (flag: Flag) => Promise<Flag>;
1600
+ _deleteFlag?: (id: string) => Promise<void>;
1601
+ _evaluateHandle(id: string, defaultValue: unknown, context: Context[] | null): unknown;
1602
+ }
1603
+ /**
1604
+ * A constrained value entry on a {@link Flag}.
1605
+ *
1606
+ * Lives in {@link Flag.values}. Frozen — author values via
1607
+ * {@link Flag.addValue} / {@link Flag.removeValue} / {@link Flag.clearValues}.
1608
+ */
1609
+ declare class FlagValue {
1610
+ readonly name: string;
1611
+ readonly value: unknown;
1612
+ constructor(fields: {
1613
+ name: string;
1614
+ value: unknown;
1615
+ });
1616
+ }
1617
+ /**
1618
+ * A single targeting rule on a {@link Flag}.
1619
+ *
1620
+ * Lives in {@link FlagEnvironment.rules}. Frozen — author rules via the
1621
+ * {@link Rule} fluent builder and pass through {@link Flag.addRule}.
1622
+ */
1623
+ declare class FlagRule {
1624
+ /** JSON Logic predicate. Empty object means "always match". */
1625
+ readonly logic: Readonly<Record<string, unknown>>;
1626
+ /** Value to serve when `logic` evaluates truthy. */
1627
+ readonly value: unknown;
1628
+ /** Human-readable label (optional). */
1629
+ readonly description: string | null;
1630
+ constructor(fields: {
1631
+ logic: Record<string, unknown>;
1632
+ value: unknown;
1633
+ description?: string | null;
1634
+ });
1635
+ }
1636
+ /**
1637
+ * Per-environment configuration on a {@link Flag}.
1638
+ *
1639
+ * Lives at `flag.environments[envName]`. Frozen — mutate via
1640
+ * {@link Flag.addRule} / {@link Flag.enableRules} / {@link Flag.disableRules} /
1641
+ * {@link Flag.setDefault} / {@link Flag.clearRules} (with `environment` option).
1642
+ */
1643
+ declare class FlagEnvironment {
1644
+ /** Whether the flag is active in this environment. */
1645
+ readonly enabled: boolean;
1646
+ /** Environment-specific default override (`null` means no override). */
1647
+ readonly default: unknown;
1648
+ /** Targeting rules to evaluate, in order. Frozen tuple. */
1649
+ readonly rules: ReadonlyArray<FlagRule>;
1650
+ constructor(fields?: {
1651
+ enabled?: boolean;
1652
+ default?: unknown;
1653
+ rules?: ReadonlyArray<FlagRule>;
1654
+ });
1655
+ /** Return a new `FlagEnvironment` with the given fields replaced. @internal */
1656
+ _replace(fields: {
1657
+ enabled?: boolean;
1658
+ default?: unknown;
1659
+ rules?: ReadonlyArray<FlagRule>;
1660
+ }): FlagEnvironment;
1661
+ }
1662
+ /**
1663
+ * A flag resource.
1664
+ *
1665
+ * Provides management operations (save, addRule, environment settings)
1666
+ * and runtime evaluation via {@link Flag.get}.
1667
+ *
1668
+ * Use typed variants ({@link BooleanFlag}, {@link StringFlag},
1669
+ * {@link NumberFlag}, {@link JsonFlag}) for type-safe `get()` returns.
1670
+ */
1671
+ declare class Flag {
1672
+ id: string | null;
1673
+ name: string;
1674
+ type: string;
1675
+ default: unknown;
1676
+ description: string | null;
1677
+ createdAt: string | null;
1678
+ updatedAt: string | null;
1679
+ /** @internal */
1680
+ protected _values: FlagValue[] | null;
1681
+ /** @internal */
1682
+ protected _environments: Record<string, FlagEnvironment>;
1683
+ /** @internal */
1684
+ readonly _client: FlagModelClient | null;
1685
+ /** @internal */
1686
+ constructor(client: FlagModelClient | null, fields: {
1687
+ id: string | null;
1688
+ name: string;
1689
+ type: string;
1690
+ default: unknown;
1691
+ values: FlagValue[] | null;
1692
+ description: string | null;
1693
+ environments: Record<string, FlagEnvironment>;
1694
+ createdAt: string | null;
1695
+ updatedAt: string | null;
1696
+ });
1697
+ /**
1698
+ * Read-only view of constrained values.
1699
+ *
1700
+ * `null` means unconstrained. Mutate via {@link addValue} /
1701
+ * {@link removeValue} / {@link clearValues}.
1702
+ */
1703
+ get values(): FlagValue[] | null;
1704
+ /**
1705
+ * Read-only view of per-environment configuration.
1706
+ *
1707
+ * Mutate via {@link addRule} / {@link enableRules} / {@link disableRules} /
1708
+ * {@link setDefault} (with `environment` option) / {@link clearRules}.
1709
+ */
1710
+ get environments(): Record<string, FlagEnvironment>;
1711
+ /**
1712
+ * Persist this flag to the server.
1713
+ *
1714
+ * Creates a new flag if unsaved, or updates the existing one.
1715
+ */
1716
+ save(): Promise<void>;
1717
+ /** Delete this flag from the server. */
1718
+ delete(): Promise<void>;
1719
+ /**
1720
+ * Append a rule to a specific environment.
1721
+ *
1722
+ * The *builtRule* dict must include an `environment` key. Call
1723
+ * {@link save} to persist. Returns `this` for chaining.
1724
+ */
1725
+ addRule(builtRule: Record<string, any>): this;
1726
+ /**
1727
+ * Enable rule evaluation. Call {@link save} to persist.
1728
+ *
1729
+ * With `environment` set scopes to that single environment; without,
1730
+ * enables rules in every environment configured on this flag.
1731
+ */
1732
+ enableRules(options?: {
1733
+ environment?: string;
1734
+ }): void;
1735
+ /**
1736
+ * Disable rule evaluation (kill switch). Call {@link save} to persist.
1737
+ *
1738
+ * With `environment` set scopes to that single environment; without,
1739
+ * disables rules in every environment configured on this flag. When
1740
+ * disabled, {@link Flag.get} skips rules and returns the env-specific
1741
+ * default (or the flag's base default).
1742
+ */
1743
+ disableRules(options?: {
1744
+ environment?: string;
1745
+ }): void;
1746
+ /**
1747
+ * Set the flag's default served value.
1748
+ *
1749
+ * With `environment` undefined (the default), updates the flag-level
1750
+ * default used when no environment-specific override applies. With
1751
+ * `environment` set, sets the per-environment default served when no
1752
+ * rule matches.
1753
+ *
1754
+ * Call {@link save} to persist.
1755
+ */
1756
+ setDefault(value: unknown, options?: {
1757
+ environment?: string;
1758
+ }): void;
1759
+ /**
1760
+ * Clear the per-environment default override on `environment`.
1761
+ *
1762
+ * After clearing, the environment falls back to the flag's base default
1763
+ * when no rule matches. Call {@link save} to persist.
1764
+ */
1765
+ clearDefault(options: {
1766
+ environment: string;
1767
+ }): void;
1768
+ /**
1769
+ * Remove rules. Call {@link save} to persist.
1770
+ *
1771
+ * With `environment` set scopes to that single environment; without,
1772
+ * removes rules from every environment configured on this flag.
1773
+ */
1774
+ clearRules(options?: {
1775
+ environment?: string;
1776
+ }): void;
1777
+ /** Append a constrained value. Returns `this` for chaining. */
1778
+ addValue(name: string, value: unknown): this;
1779
+ /** Remove the first values entry whose `value` field matches. Returns `this`. */
1780
+ removeValue(value: unknown): this;
1781
+ /** Set values to `null` (unconstrained). Call {@link save} to persist. */
1782
+ clearValues(): void;
1783
+ /** Evaluate this flag and return its current value. */
1784
+ get(options?: {
1785
+ context?: Context[];
1786
+ }): unknown;
1787
+ /** @internal */
1788
+ _apply(other: Flag): void;
1789
+ /** @internal — raw access for serialization. */
1790
+ _envsRaw(): Record<string, FlagEnvironment>;
1791
+ toString(): string;
1792
+ }
1793
+ /** Typed flag that returns `boolean` from {@link Flag.get}. */
1794
+ declare class BooleanFlag extends Flag {
1795
+ get(options?: {
1796
+ context?: Context[];
1797
+ }): boolean;
1798
+ }
1799
+ /** Typed flag that returns `string` from {@link Flag.get}. */
1800
+ declare class StringFlag extends Flag {
1801
+ get(options?: {
1802
+ context?: Context[];
1803
+ }): string;
1804
+ }
1805
+ /** Typed flag that returns `number` from {@link Flag.get}. */
1806
+ declare class NumberFlag extends Flag {
1807
+ get(options?: {
1808
+ context?: Context[];
1809
+ }): number;
1810
+ }
1811
+ /** Typed flag that returns `Record<string, unknown>` from {@link Flag.get}. */
1812
+ declare class JsonFlag extends Flag {
1813
+ get(options?: {
1814
+ context?: Context[];
1815
+ }): Record<string, unknown>;
1816
+ }
1817
+
1818
+ type FlagsHttp$1 = ReturnType<typeof createClient<___generated_flags_d_ts.paths>>;
1819
+ /**
1820
+ * Buffer pending flag declarations for bulk registration. @internal
1821
+ */
1822
+ declare class FlagRegistrationBuffer {
1823
+ private _seen;
1824
+ private _pending;
1825
+ add(decl: FlagDeclaration): void;
1826
+ drain(): Array<components["schemas"]["FlagBulkItem"]>;
1827
+ get pendingCount(): number;
1828
+ }
1829
+ /**
1830
+ * `mgmt.flags.*` — CRUD client for flags + bulk registration buffer.
1831
+ */
1832
+ declare class ManagementFlagsClient {
1833
+ private readonly _http;
1834
+ /** @internal */
1835
+ readonly _buffer: FlagRegistrationBuffer;
1836
+ /** @internal */
1837
+ constructor(_http: FlagsHttp$1);
1838
+ /** Construct an unsaved {@link BooleanFlag}. Call `.save()` to persist. */
1839
+ newBooleanFlag(id: string, options: {
1840
+ default: boolean;
1841
+ name?: string;
1842
+ description?: string;
1843
+ }): BooleanFlag;
1844
+ /** Construct an unsaved {@link StringFlag}. Call `.save()` to persist. */
1845
+ newStringFlag(id: string, options: {
1846
+ default: string;
1847
+ name?: string;
1848
+ description?: string;
1849
+ values?: Array<FlagValue | {
1850
+ name: string;
1851
+ value: unknown;
1852
+ }>;
1853
+ }): StringFlag;
1854
+ /** Construct an unsaved {@link NumberFlag}. Call `.save()` to persist. */
1855
+ newNumberFlag(id: string, options: {
1856
+ default: number;
1857
+ name?: string;
1858
+ description?: string;
1859
+ values?: Array<FlagValue | {
1860
+ name: string;
1861
+ value: unknown;
1862
+ }>;
1863
+ }): NumberFlag;
1864
+ /** Construct an unsaved {@link JsonFlag}. Call `.save()` to persist. */
1865
+ newJsonFlag(id: string, options: {
1866
+ default: Record<string, unknown>;
1867
+ name?: string;
1868
+ description?: string;
1869
+ values?: Array<FlagValue | {
1870
+ name: string;
1871
+ value: unknown;
1872
+ }>;
1873
+ }): JsonFlag;
1874
+ /** Fetch a flag by id. */
1875
+ get(id: string): Promise<Flag>;
1876
+ /** List all flags. */
1877
+ list(): Promise<Flag[]>;
1878
+ /** Delete a flag by id. */
1879
+ delete(id: string): Promise<void>;
1880
+ /** @internal — called by `Flag.delete()`. */
1881
+ _deleteFlag(id: string): Promise<void>;
1882
+ /**
1883
+ * Queue flag declaration(s) for bulk registration; optionally flush.
1884
+ *
1885
+ * Threshold-based flushing fires when 50+ pending; the periodic
1886
+ * timer on {@link SmplClient} also drains it every 60s.
1887
+ */
1888
+ register(items: FlagDeclaration | FlagDeclaration[], options?: {
1889
+ flush?: boolean;
1890
+ }): Promise<void>;
1891
+ /** Send any pending flag declarations to the server. */
1892
+ flush(): Promise<void>;
1893
+ /** Number of declarations awaiting flush. */
1894
+ get pendingCount(): number;
1895
+ /** @internal — called by `Flag.save()` for new resources. */
1896
+ _createFlag(flag: Flag): Promise<Flag>;
1897
+ /** @internal — called by `Flag.save()` for existing resources. */
1898
+ _updateFlag(flag: Flag): Promise<Flag>;
1899
+ /** @internal — flag models constructed via `mgmt.flags.*` cannot evaluate. */
1900
+ _evaluateHandle(_id: string, _defaultValue: unknown, _context: Context[] | null): unknown;
1901
+ }
1902
+
1120
1903
  /**
1121
1904
  * Public types for the Logging SDK.
1122
1905
  */
@@ -1130,39 +1913,63 @@ declare enum LogLevel {
1130
1913
  FATAL = "FATAL",
1131
1914
  SILENT = "SILENT"
1132
1915
  }
1133
- /** Describes a logger configuration change. */
1134
- interface LoggerChangeEvent {
1135
- /** The logger id that changed. */
1136
- id: string;
1137
- /** The new effective log level, or null if removed. */
1138
- level: LogLevel | null;
1139
- /** How the change was delivered. */
1140
- source: string;
1141
- /** True when the logger or group was deleted. */
1142
- deleted?: true;
1916
+ /**
1917
+ * Describes a logger configuration change. Frozen — fields cannot be
1918
+ * mutated after construction so a listener cannot affect later listeners.
1919
+ *
1920
+ * The `level` field is a TypeScript-SDK-only convenience for callers that
1921
+ * want to act on the new effective level without re-fetching the logger.
1922
+ */
1923
+ declare class LoggerChangeEvent {
1924
+ readonly id: string;
1925
+ readonly source: string;
1926
+ readonly level?: LogLevel | null;
1927
+ readonly deleted?: true;
1928
+ constructor(fields: {
1929
+ id: string;
1930
+ source: string;
1931
+ level?: LogLevel | null;
1932
+ deleted?: true;
1933
+ });
1143
1934
  }
1144
1935
  /**
1145
- * Describes a logger to register via `client.logging.management.registerSources()`.
1936
+ * Describes a logger to register via `mgmt.loggers.register([source, ...])`.
1146
1937
  *
1147
- * Unlike auto-discovery (which reads the current process's logging framework),
1148
- * `registerSources` accepts explicit `service` and `environment` overrides —
1149
- * useful for sample-data seeding, cross-tenant migration, and test fixtures.
1938
+ * Unlike runtime auto-discovery (which reads the current process's logging
1939
+ * framework), `mgmt.loggers.register` accepts explicit `service` and
1940
+ * `environment` overrides — useful for sample-data seeding, cross-tenant
1941
+ * migration, and test fixtures.
1942
+ *
1943
+ * Frozen.
1150
1944
  */
1151
1945
  declare class LoggerSource {
1152
1946
  /** Logger name (e.g. `"sqlalchemy.engine"`). */
1153
1947
  readonly name: string;
1154
1948
  /** Service name this source belongs to. */
1155
- readonly service: string;
1949
+ readonly service: string | null;
1156
1950
  /** Environment name this source belongs to. */
1157
- readonly environment: string;
1951
+ readonly environment: string | null;
1158
1952
  /** Effective log level for this source. */
1159
1953
  readonly resolvedLevel: LogLevel;
1160
1954
  /** Explicit (configured) log level, if different from `resolvedLevel`. */
1161
1955
  readonly level: LogLevel | null;
1162
1956
  constructor(name: string, options: {
1163
- service: string;
1164
- environment: string;
1165
- resolved_level: LogLevel;
1957
+ service?: string | null;
1958
+ environment?: string | null;
1959
+ resolvedLevel: LogLevel;
1960
+ level?: LogLevel | null;
1961
+ });
1962
+ }
1963
+ /**
1964
+ * Per-environment configuration on a logger or log group.
1965
+ *
1966
+ * Frozen — mutate via `logger.setLevel(level, { environment: "..." })`
1967
+ * or remove with `logger.clearLevel({ environment: "..." })`.
1968
+ */
1969
+ declare class LoggerEnvironment {
1970
+ /** Per-environment level override (`null` means no override). */
1971
+ readonly level: LogLevel | null;
1972
+ constructor(fields?: {
1166
1973
  level?: LogLevel | null;
1167
1974
  });
1168
1975
  }
@@ -1171,10 +1978,22 @@ declare class LoggerSource {
1171
1978
  * Logger and LogGroup active-record models for the Logging SDK.
1172
1979
  */
1173
1980
 
1981
+ /** @internal */
1982
+ interface LoggerModelClient {
1983
+ _saveLogger?: (logger: Logger) => Promise<Logger>;
1984
+ _deleteLogger?: (id: string) => Promise<void>;
1985
+ }
1986
+ /** @internal */
1987
+ interface LogGroupModelClient {
1988
+ _saveGroup?: (group: LogGroup) => Promise<LogGroup>;
1989
+ _deleteGroup?: (id: string) => Promise<void>;
1990
+ }
1174
1991
  /**
1175
1992
  * A logger resource managed by the smplkit platform.
1176
1993
  *
1177
- * Mutate properties or use convenience methods, then call `save()` to persist.
1994
+ * Mutate via {@link setLevel} / {@link clearLevel} /
1995
+ * {@link clearAllEnvironmentLevels} (with `environment` option for per-env
1996
+ * overrides), then call {@link save} to persist.
1178
1997
  */
1179
1998
  declare class Logger {
1180
1999
  /** Unique identifier (dot-separated hierarchy, e.g. `"sqlalchemy.engine"`). */
@@ -1186,105 +2005,475 @@ declare class Logger {
1186
2005
  /** Id of the parent log group, or null. */
1187
2006
  group: string | null;
1188
2007
  /** Whether this logger is managed by the platform. */
1189
- managed: boolean;
2008
+ managed: boolean | null;
1190
2009
  /** Observed sources (services that report this logger). */
1191
2010
  sources: Array<Record<string, any>>;
1192
- /** Per-environment level overrides. */
1193
- environments: Record<string, any>;
1194
2011
  /** When the logger was created. */
1195
2012
  createdAt: string | null;
1196
2013
  /** When the logger was last updated. */
1197
2014
  updatedAt: string | null;
1198
2015
  /** @internal */
1199
- readonly _client: LoggingClient;
2016
+ protected _environments: Record<string, LoggerEnvironment>;
1200
2017
  /** @internal */
1201
- constructor(client: LoggingClient, fields: {
2018
+ readonly _client: LoggerModelClient | null;
2019
+ /** @internal */
2020
+ constructor(client: LoggerModelClient | null, fields: {
1202
2021
  id: string | null;
1203
2022
  name: string;
1204
- level: LogLevel | null;
1205
- group: string | null;
1206
- managed: boolean;
1207
- sources: Array<Record<string, any>>;
1208
- environments: Record<string, any>;
1209
- createdAt: string | null;
1210
- updatedAt: string | null;
2023
+ level?: LogLevel | null;
2024
+ group?: string | null;
2025
+ managed?: boolean | null;
2026
+ sources?: Array<Record<string, any>>;
2027
+ environments?: Record<string, unknown> | null;
2028
+ createdAt?: string | null;
2029
+ updatedAt?: string | null;
1211
2030
  });
1212
2031
  /**
1213
- * Persist this logger to the server.
2032
+ * Read-only view of per-environment level overrides.
1214
2033
  *
1215
- * Creates if new, updates if existing.
2034
+ * Mutate via {@link setLevel} / {@link clearLevel} /
2035
+ * {@link clearAllEnvironmentLevels} (with `environment` option).
1216
2036
  */
2037
+ get environments(): Record<string, LoggerEnvironment>;
2038
+ /** @internal — direct typed environments dict for serialization. */
2039
+ get _environmentsDirect(): Record<string, LoggerEnvironment>;
2040
+ /** Persist this logger to the server (create or update). */
1217
2041
  save(): Promise<void>;
1218
- /** Set the base log level. Call `save()` to persist. */
1219
- setLevel(level: LogLevel): void;
1220
- /** Clear the base log level. Call `save()` to persist. */
1221
- clearLevel(): void;
1222
- /** Set an environment-specific log level. Call `save()` to persist. */
1223
- setEnvironmentLevel(env: string, level: LogLevel): void;
1224
- /** Clear an environment-specific log level. Call `save()` to persist. */
1225
- clearEnvironmentLevel(env: string): void;
1226
- /** Clear all environment-specific log levels. Call `save()` to persist. */
2042
+ /** Delete this logger from the server. */
2043
+ delete(): Promise<void>;
2044
+ /**
2045
+ * Set the log level.
2046
+ *
2047
+ * With `environment` undefined (the default), sets the base log level
2048
+ * used when no environment-specific override applies. With `environment`,
2049
+ * sets the per-environment override.
2050
+ */
2051
+ setLevel(level: LogLevel, options?: {
2052
+ environment?: string;
2053
+ }): void;
2054
+ /**
2055
+ * Remove a log level.
2056
+ *
2057
+ * With `environment` undefined (the default), removes the base log level
2058
+ * (the logger then inherits from its group / dot-notation ancestor /
2059
+ * system default). With `environment`, removes only that env's override.
2060
+ */
2061
+ clearLevel(options?: {
2062
+ environment?: string;
2063
+ }): void;
2064
+ /** Remove all per-environment level overrides. */
1227
2065
  clearAllEnvironmentLevels(): void;
1228
- /** @internal — copy all fields from another Logger instance. */
2066
+ /** @internal */
1229
2067
  _apply(other: Logger): void;
1230
2068
  toString(): string;
1231
2069
  }
1232
2070
  /**
1233
2071
  * A log group resource for organizing loggers.
1234
2072
  *
1235
- * Management: mutate properties and call `save()` to persist.
2073
+ * Mutate via {@link setLevel} / {@link clearLevel} /
2074
+ * {@link clearAllEnvironmentLevels} (with `environment` option), then
2075
+ * call {@link save} to persist.
1236
2076
  */
1237
2077
  declare class LogGroup {
1238
- /** Unique identifier (slug), or `null` if unsaved. */
1239
2078
  id: string | null;
1240
- /** Human-readable key (slug), or `null` if not set. */
1241
- key: string | null;
1242
- /** Human-readable display name. */
1243
2079
  name: string;
1244
- /** Base log level, or null if inherited. */
1245
2080
  level: LogLevel | null;
1246
- /** Id of the parent log group, or null. */
1247
2081
  group: string | null;
1248
- /** Per-environment level overrides. */
1249
- environments: Record<string, any>;
1250
- /** When the log group was created. */
1251
2082
  createdAt: string | null;
1252
- /** When the log group was last updated. */
1253
2083
  updatedAt: string | null;
1254
2084
  /** @internal */
1255
- readonly _client: LoggingClient;
2085
+ protected _environments: Record<string, LoggerEnvironment>;
1256
2086
  /** @internal */
1257
- constructor(client: LoggingClient, fields: {
2087
+ readonly _client: LogGroupModelClient | null;
2088
+ /** @internal */
2089
+ constructor(client: LogGroupModelClient | null, fields: {
1258
2090
  id: string | null;
1259
- key: string | null;
1260
2091
  name: string;
1261
- level: LogLevel | null;
1262
- group: string | null;
1263
- environments: Record<string, any>;
1264
- createdAt: string | null;
1265
- updatedAt: string | null;
2092
+ level?: LogLevel | null;
2093
+ group?: string | null;
2094
+ environments?: Record<string, unknown> | null;
2095
+ createdAt?: string | null;
2096
+ updatedAt?: string | null;
1266
2097
  });
1267
- /**
1268
- * Persist this log group to the server.
1269
- *
1270
- * Creates if new, updates if existing.
1271
- */
2098
+ /** Read-only view of per-environment level overrides. */
2099
+ get environments(): Record<string, LoggerEnvironment>;
2100
+ /** @internal */
2101
+ get _environmentsDirect(): Record<string, LoggerEnvironment>;
1272
2102
  save(): Promise<void>;
1273
- /** Set the base log level. Call `save()` to persist. */
1274
- setLevel(level: LogLevel): void;
1275
- /** Clear the base log level. Call `save()` to persist. */
1276
- clearLevel(): void;
1277
- /** Set an environment-specific log level. Call `save()` to persist. */
1278
- setEnvironmentLevel(env: string, level: LogLevel): void;
1279
- /** Clear an environment-specific log level. Call `save()` to persist. */
1280
- clearEnvironmentLevel(env: string): void;
1281
- /** Clear all environment-specific log levels. Call `save()` to persist. */
2103
+ delete(): Promise<void>;
2104
+ setLevel(level: LogLevel, options?: {
2105
+ environment?: string;
2106
+ }): void;
2107
+ clearLevel(options?: {
2108
+ environment?: string;
2109
+ }): void;
1282
2110
  clearAllEnvironmentLevels(): void;
1283
- /** @internal — copy all fields from another LogGroup instance. */
2111
+ /** @internal */
1284
2112
  _apply(other: LogGroup): void;
1285
2113
  toString(): string;
1286
2114
  }
1287
2115
 
2116
+ type LoggingHttp$1 = ReturnType<typeof createClient<___generated_logging_d_ts.paths>>;
2117
+ /** Buffer pending logger sources for bulk registration. @internal */
2118
+ declare class LoggerRegistrationBuffer {
2119
+ private _seen;
2120
+ private _pending;
2121
+ add(source: LoggerSource): void;
2122
+ drain(): Array<components$1["schemas"]["LoggerBulkItem"]>;
2123
+ get pendingCount(): number;
2124
+ }
2125
+ /**
2126
+ * `mgmt.loggers.*` — CRUD client for individual loggers + bulk registration.
2127
+ */
2128
+ declare class LoggersClient {
2129
+ private readonly _http;
2130
+ /** @internal */
2131
+ readonly _buffer: LoggerRegistrationBuffer;
2132
+ /** @internal */
2133
+ constructor(_http: LoggingHttp$1);
2134
+ /**
2135
+ * Construct an unsaved {@link Logger}. Call `.save()` to persist.
2136
+ *
2137
+ * The id doubles as the display name. `managed` defaults to `true`
2138
+ * (every customer using the management API is doing so to manage it).
2139
+ */
2140
+ new(id: string, options?: {
2141
+ managed?: boolean;
2142
+ }): Logger;
2143
+ list(): Promise<Logger[]>;
2144
+ get(id: string): Promise<Logger>;
2145
+ delete(id: string): Promise<void>;
2146
+ /** @internal — called by `Logger.delete()`. */
2147
+ _deleteLogger(id: string): Promise<void>;
2148
+ /**
2149
+ * Queue logger source(s) for bulk registration; optionally flush.
2150
+ */
2151
+ register(items: LoggerSource | LoggerSource[], options?: {
2152
+ flush?: boolean;
2153
+ }): Promise<void>;
2154
+ flush(): Promise<void>;
2155
+ get pendingCount(): number;
2156
+ /** @internal — called by `Logger.save()`. PUT /loggers/{id} is upsert. */
2157
+ _saveLogger(logger: Logger): Promise<Logger>;
2158
+ }
2159
+ /**
2160
+ * `mgmt.logGroups.*` — CRUD client for log groups.
2161
+ */
2162
+ declare class LogGroupsClient {
2163
+ private readonly _http;
2164
+ /** @internal */
2165
+ constructor(_http: LoggingHttp$1);
2166
+ /** Construct an unsaved {@link LogGroup}. Call `.save()` to persist. */
2167
+ new(id: string, options?: {
2168
+ name?: string;
2169
+ group?: string;
2170
+ }): LogGroup;
2171
+ list(): Promise<LogGroup[]>;
2172
+ get(id: string): Promise<LogGroup>;
2173
+ delete(id: string): Promise<void>;
2174
+ /** @internal — called by `LogGroup.delete()`. */
2175
+ _deleteGroup(id: string): Promise<void>;
2176
+ /** @internal — called by `LogGroup.save()`. PUT /log_groups/{id} is upsert. */
2177
+ _saveGroup(group: LogGroup): Promise<LogGroup>;
2178
+ }
2179
+
2180
+ type AppHttp = ReturnType<typeof createClient<___generated_app_d_ts.paths>>;
2181
+ type ConfigHttp = ReturnType<typeof createClient<___generated_config_d_ts.paths>>;
2182
+ type FlagsHttp = ReturnType<typeof createClient<___generated_flags_d_ts.paths>>;
2183
+ type LoggingHttp = ReturnType<typeof createClient<___generated_logging_d_ts.paths>>;
2184
+ /** `mgmt.environments.*` — CRUD for environments. */
2185
+ declare class EnvironmentsClient {
2186
+ private readonly _http;
2187
+ /** @internal */
2188
+ constructor(_http: AppHttp);
2189
+ /**
2190
+ * Construct an unsaved {@link Environment}. Call `.save()` to persist.
2191
+ */
2192
+ new(id: string, options: {
2193
+ name: string;
2194
+ color?: Color | string | null;
2195
+ classification?: EnvironmentClassification;
2196
+ }): Environment;
2197
+ list(): Promise<Environment[]>;
2198
+ get(id: string): Promise<Environment>;
2199
+ delete(id: string): Promise<void>;
2200
+ /** @internal */
2201
+ _create(env: Environment): Promise<Environment>;
2202
+ /** @internal */
2203
+ _update(env: Environment): Promise<Environment>;
2204
+ }
2205
+ /** `mgmt.contextTypes.*` — CRUD for context types. */
2206
+ declare class ContextTypesClient {
2207
+ private readonly _http;
2208
+ /** @internal */
2209
+ constructor(_http: AppHttp);
2210
+ /**
2211
+ * Construct an unsaved {@link ContextType}. Call `.save()` to persist.
2212
+ *
2213
+ * `name` defaults to the id when omitted.
2214
+ */
2215
+ new(id: string, options?: {
2216
+ name?: string;
2217
+ attributes?: Record<string, Record<string, any>>;
2218
+ }): ContextType;
2219
+ list(): Promise<ContextType[]>;
2220
+ get(id: string): Promise<ContextType>;
2221
+ delete(id: string): Promise<void>;
2222
+ /** @internal */
2223
+ _create(ct: ContextType): Promise<ContextType>;
2224
+ /** @internal */
2225
+ _update(ct: ContextType): Promise<ContextType>;
2226
+ }
2227
+ /**
2228
+ * Buffer pending context observations for bulk registration.
2229
+ *
2230
+ * Backed by an LRU of size {@link CONTEXT_REGISTRATION_LRU_SIZE} so the
2231
+ * dedup window doesn't grow unbounded for long-lived processes.
2232
+ * @internal
2233
+ */
2234
+ declare class ContextRegistrationBuffer {
2235
+ private _seen;
2236
+ private _pending;
2237
+ observe(contexts: Context[]): void;
2238
+ drain(): Array<{
2239
+ type: string;
2240
+ key: string;
2241
+ attributes: Record<string, unknown>;
2242
+ }>;
2243
+ get pendingCount(): number;
2244
+ }
2245
+ /** `mgmt.contexts.*` — register/list/get/delete for context instances. */
2246
+ declare class ContextsClient {
2247
+ private readonly _http;
2248
+ /** @internal */
2249
+ readonly _buffer: ContextRegistrationBuffer;
2250
+ /** @internal */
2251
+ constructor(_http: AppHttp, buffer?: ContextRegistrationBuffer);
2252
+ /**
2253
+ * Buffer context(s) for registration; optionally flush immediately.
2254
+ *
2255
+ * When `flush` is false (default), contexts are queued for the SDK's
2256
+ * background flush. When `flush` is true the call awaits the round-trip.
2257
+ */
2258
+ register(items: Context | Context[], options?: {
2259
+ flush?: boolean;
2260
+ }): Promise<void>;
2261
+ /** Send any pending context observations to the server. */
2262
+ flush(): Promise<void>;
2263
+ /** Number of contexts awaiting flush. */
2264
+ get pendingCount(): number;
2265
+ /** List all contexts of a given type. */
2266
+ list(type: string): Promise<Context[]>;
2267
+ /** Fetch a context by composite id (`"type:key"`) or by separate type and key. */
2268
+ get(idOrType: string, key?: string): Promise<Context>;
2269
+ /** Delete a context by composite id (`"type:key"`) or by separate type and key. */
2270
+ delete(idOrType: string, key?: string): Promise<void>;
2271
+ /** @internal — called by `Context.save()`. */
2272
+ _saveContext(ctx: Context): Promise<Context>;
2273
+ }
2274
+ /** `mgmt.accountSettings.*` — get/save for account-level settings. */
2275
+ declare class AccountSettingsClient {
2276
+ private readonly _appBaseUrl;
2277
+ private readonly _headers;
2278
+ /** @internal */
2279
+ constructor(_appBaseUrl: string, apiKey: string);
2280
+ get(): Promise<AccountSettings>;
2281
+ /** @internal */
2282
+ _save(data: Record<string, any>): Promise<AccountSettings>;
2283
+ }
2284
+ /** Configuration options for the {@link SmplManagementClient}. */
2285
+ interface SmplManagementClientOptions {
2286
+ /** API key. Resolves from `SMPLKIT_API_KEY` / `~/.smplkit` if omitted. */
2287
+ apiKey?: string;
2288
+ /** Configuration profile to use from `~/.smplkit`. Default `"default"`. */
2289
+ profile?: string;
2290
+ /** Base domain for service URLs. Default `"smplkit.com"`. */
2291
+ baseDomain?: string;
2292
+ /** URL scheme. Default `"https"`. */
2293
+ scheme?: string;
2294
+ /** Enable debug logging to stderr. */
2295
+ debug?: boolean;
2296
+ }
2297
+ /**
2298
+ * Standalone management/CRUD entry point — zero construction side effects.
2299
+ *
2300
+ * Construction does **not**:
2301
+ * - register the service or environment as context instances
2302
+ * - start a metrics thread
2303
+ * - open the WebSocket
2304
+ * - install logger discovery
2305
+ *
2306
+ * Use this for setup scripts, CI, admin tooling, and one-off CRUD.
2307
+ *
2308
+ * @example
2309
+ * ```typescript
2310
+ * import { SmplManagementClient } from "@smplkit/sdk";
2311
+ *
2312
+ * const mgmt = new SmplManagementClient();
2313
+ * const env = mgmt.environments.new("production", { name: "Production" });
2314
+ * await env.save();
2315
+ * await mgmt.close();
2316
+ * ```
2317
+ */
2318
+ declare class SmplManagementClient {
2319
+ /** Context entity CRUD. */
2320
+ readonly contexts: ContextsClient;
2321
+ /** Context-type schemas. */
2322
+ readonly contextTypes: ContextTypesClient;
2323
+ /** Environment CRUD. */
2324
+ readonly environments: EnvironmentsClient;
2325
+ /** Account-level settings. */
2326
+ readonly accountSettings: AccountSettingsClient;
2327
+ /** Config CRUD (singular — matches runtime `client.config`). */
2328
+ readonly config: ManagementConfigClient;
2329
+ /** Flag CRUD + bulk registration. */
2330
+ readonly flags: ManagementFlagsClient;
2331
+ /** Logger CRUD + bulk registration. */
2332
+ readonly loggers: LoggersClient;
2333
+ /** Log group CRUD. */
2334
+ readonly logGroups: LogGroupsClient;
2335
+ /** @internal — shared HTTP transports (so SmplClient can alias them). */
2336
+ readonly _appHttp: AppHttp;
2337
+ /** @internal */
2338
+ readonly _configHttp: ConfigHttp;
2339
+ /** @internal */
2340
+ readonly _flagsHttp: FlagsHttp;
2341
+ /** @internal */
2342
+ readonly _loggingHttp: LoggingHttp;
2343
+ constructor(options?: SmplManagementClientOptions);
2344
+ private _contextsRef;
2345
+ private _contextTypesRef;
2346
+ private _environmentsRef;
2347
+ private _accountSettingsRef;
2348
+ private _configRef;
2349
+ private _flagsRef;
2350
+ private _loggersRef;
2351
+ private _logGroupsRef;
2352
+ private _appHttpRef;
2353
+ private _configHttpRef;
2354
+ private _flagsHttpRef;
2355
+ private _loggingHttpRef;
2356
+ private _sharedContextBuffer;
2357
+ private _init;
2358
+ /** @internal — used by SmplClient to share the buffer. */
2359
+ get _contextBuffer(): ContextRegistrationBuffer;
2360
+ /** Release resources. Drains pending bulk registrations one last time. */
2361
+ close(): Promise<void>;
2362
+ }
2363
+
2364
+ /**
2365
+ * Describes a single config value change detected on refresh. Frozen —
2366
+ * fields are set at construction and cannot be mutated afterward.
2367
+ */
2368
+ declare class ConfigChangeEvent {
2369
+ /** The config id that changed. */
2370
+ readonly configId: string;
2371
+ /** The item key within the config that changed. */
2372
+ readonly itemKey: string;
2373
+ /** The previous value (null if the key was absent). */
2374
+ readonly oldValue: unknown;
2375
+ /** The updated value (null if the key was removed). */
2376
+ readonly newValue: unknown;
2377
+ /** How the change was delivered. */
2378
+ readonly source: "websocket" | "manual";
2379
+ constructor(fields: {
2380
+ configId: string;
2381
+ itemKey: string;
2382
+ oldValue: unknown;
2383
+ newValue: unknown;
2384
+ source: "websocket" | "manual";
2385
+ });
2386
+ }
2387
+ /**
2388
+ * Runtime client for the smplkit Config service.
2389
+ *
2390
+ * Obtained via `SmplClient.config`. Provides live config values, change
2391
+ * listeners, and lazy initialization. Management/CRUD lives on
2392
+ * `SmplClient.manage.config` (or use a standalone {@link SmplManagementClient}).
2393
+ */
2394
+ declare class ConfigClient {
2395
+ /** @internal */
2396
+ readonly _apiKey: string;
2397
+ /** @internal */
2398
+ readonly _baseUrl: string;
2399
+ /** @internal */
2400
+ private readonly _http;
2401
+ /** @internal — returns the shared WebSocket for real-time updates. */
2402
+ _getSharedWs?: () => SharedWebSocket;
2403
+ /** @internal — set by SmplClient after construction. */
2404
+ _parent: {
2405
+ readonly _environment: string;
2406
+ readonly _service: string | null;
2407
+ readonly _metrics: MetricsReporter | null;
2408
+ } | null;
2409
+ /** @internal — resolves the management config sub-client used by lazy-init/refresh. */
2410
+ _resolveManagement?: () => SmplManagementClient;
2411
+ private _configCache;
2412
+ private _initialized;
2413
+ private _listeners;
2414
+ /** @internal */
2415
+ constructor(apiKey: string, timeout?: number, baseUrl?: string);
2416
+ /**
2417
+ * Return a live, dict-like view of the resolved values for *id*.
2418
+ *
2419
+ * Without `model`, returns a {@link LiveConfigProxy} that behaves like a
2420
+ * `Record<string, unknown>` (`proxy["key"]`, iteration, `proxy.items()`,
2421
+ * `Object.keys(proxy)`) and updates automatically as the server pushes
2422
+ * changes.
2423
+ *
2424
+ * With `model`, the return value type-checks as `model` — attribute
2425
+ * access (`cfg.database.host`) walks a model rebuilt from the current
2426
+ * values on each read, so the customer sees the model's type signature
2427
+ * in their IDE while still tracking live data.
2428
+ *
2429
+ * Mirrors Python's `client.config.get(id)` / `client.config.get(id, ModelCls)`.
2430
+ * There is no `subscribe()` — it was unified into `get()`.
2431
+ */
2432
+ get<T = Record<string, unknown>>(id: string, model?: new (data: any) => T): Promise<LiveConfigProxy<T>>;
2433
+ /**
2434
+ * Register a change listener.
2435
+ *
2436
+ * - `onChange(callback)` — fires for any config change (global).
2437
+ * - `onChange(configId, callback)` — fires for changes to a specific config.
2438
+ * - `onChange(configId, itemKey, callback)` — fires for a specific item.
2439
+ */
2440
+ onChange(callbackOrConfigId: string | ((event: ConfigChangeEvent) => void), callbackOrItemKey?: string | ((event: ConfigChangeEvent) => void), callback?: (event: ConfigChangeEvent) => void): void;
2441
+ /**
2442
+ * Refresh all config values from the server.
2443
+ * Fires change listeners for any values that changed.
2444
+ */
2445
+ refresh(): Promise<void>;
2446
+ /**
2447
+ * @internal — fetch the full config list. Prefers the management plane
2448
+ * (set via `_resolveManagement`) so runtime + management share one HTTP
2449
+ * client; falls back to a direct GET when running without `SmplClient`
2450
+ * bootstrap (e.g. unit tests that construct `ConfigClient` directly).
2451
+ */
2452
+ private _listConfigs;
2453
+ /**
2454
+ * Eagerly initialize the config subclient — fetch all configs, resolve
2455
+ * environment-scoped values into the local cache, and subscribe to the
2456
+ * shared WebSocket for live updates. Idempotent. Called automatically
2457
+ * on first `client.config.get(...)` if not invoked manually.
2458
+ */
2459
+ start(): Promise<void>;
2460
+ /** @internal */
2461
+ private _ensureInitialized;
2462
+ /** @internal — called by SmplClient for backward compat. */
2463
+ _connectInternal(environment: string): Promise<void>;
2464
+ /** @internal — get resolved config from cache. Used by LiveConfigProxy. */
2465
+ _getCachedConfig(key: string): Record<string, unknown> | undefined;
2466
+ private _handleConfigChanged;
2467
+ private _handleConfigDeleted;
2468
+ private _handleConfigsChanged;
2469
+ /** Fetch a single config by key. Returns null if not found. @internal */
2470
+ private _fetchSingleConfig;
2471
+ /** Resolve a config's values for an environment (no parent chain). @internal */
2472
+ private _resolveConfigValues;
2473
+ /** @internal */
2474
+ private _diffAndFire;
2475
+ }
2476
+
1288
2477
  /**
1289
2478
  * Contract for logging framework adapters.
1290
2479
  */
@@ -1315,52 +2504,12 @@ interface LoggingAdapter {
1315
2504
  }
1316
2505
 
1317
2506
  /**
1318
- * LoggingClient management and runtime for Smpl Logging.
1319
- */
1320
-
1321
- /**
1322
- * Management API for smplkit Logging — CRUD operations on Logger and LogGroup models.
1323
- *
1324
- * Access via `SmplClient.logging.management`.
1325
- */
1326
- declare class LoggingManagement {
1327
- private readonly _client;
1328
- constructor(_client: LoggingClient);
1329
- /** Create an unsaved logger. Call `.save()` to persist. */
1330
- new(id: string, options?: {
1331
- name?: string;
1332
- managed?: boolean;
1333
- }): Logger;
1334
- /** Fetch a logger by id. */
1335
- get(id: string): Promise<Logger>;
1336
- /** List all loggers. */
1337
- list(): Promise<Logger[]>;
1338
- /** Delete a logger by id. */
1339
- delete(id: string): Promise<void>;
1340
- /** Create an unsaved log group. Call `.save()` to persist. */
1341
- newGroup(id: string, options?: {
1342
- name?: string;
1343
- group?: string;
1344
- }): LogGroup;
1345
- /** Fetch a log group by id. */
1346
- getGroup(id: string): Promise<LogGroup>;
1347
- /** List all log groups. */
1348
- listGroups(): Promise<LogGroup[]>;
1349
- /** Delete a log group by id. */
1350
- deleteGroup(id: string): Promise<void>;
1351
- /**
1352
- * Bulk-register explicit logger sources with the logging service.
1353
- *
1354
- * Unlike `start()`, which auto-discovers loggers from the current
1355
- * process, this method accepts explicit `service` and `environment`
1356
- * overrides — useful for sample-data seeding and test fixtures.
1357
- */
1358
- registerSources(sources: LoggerSource[]): Promise<void>;
1359
- }
1360
- /**
1361
- * Client for the smplkit Logging API.
2507
+ * Runtime client for the smplkit Logging service.
1362
2508
  *
1363
- * Obtained via `SmplClient.logging`.
2509
+ * Obtained via `SmplClient.logging`. Provides adapter integration, level
2510
+ * resolution, and live-updates for logger/group changes. Management/CRUD
2511
+ * lives on `SmplClient.manage.loggers` / `SmplClient.manage.logGroups` (or
2512
+ * use a standalone {@link SmplManagementClient}).
1364
2513
  */
1365
2514
  declare class LoggingClient {
1366
2515
  /** @internal */
@@ -1375,8 +2524,8 @@ declare class LoggingClient {
1375
2524
  readonly _service: string | null;
1376
2525
  readonly _metrics: MetricsReporter | null;
1377
2526
  } | null;
1378
- /** Management API CRUD operations on Logger and LogGroup models. */
1379
- readonly management: LoggingManagement;
2527
+ /** @internalresolves the management plane sub-clients used by install/refresh. */
2528
+ _resolveManagement?: () => SmplManagementClient;
1380
2529
  private readonly _ensureWs;
1381
2530
  private _wsManager;
1382
2531
  private _started;
@@ -1397,42 +2546,34 @@ declare class LoggingClient {
1397
2546
  * registered adapters will be used.
1398
2547
  */
1399
2548
  registerAdapter(adapter: LoggingAdapter): void;
1400
- /** @internal */
1401
- _mgNew(id: string, options?: {
1402
- name?: string;
1403
- managed?: boolean;
1404
- }): Logger;
1405
- /** @internal */
1406
- _mgGet(id: string): Promise<Logger>;
1407
- /** @internal */
1408
- _mgList(): Promise<Logger[]>;
1409
- /** @internal */
1410
- _mgDelete(id: string): Promise<void>;
1411
- /** @internal */
1412
- _mgNewGroup(id: string, options?: {
1413
- name?: string;
1414
- group?: string;
1415
- }): LogGroup;
1416
- /** @internal */
1417
- _mgGetGroup(id: string): Promise<LogGroup>;
1418
- /** @internal */
1419
- _mgListGroups(): Promise<LogGroup[]>;
1420
- /** @internal */
1421
- _mgRegisterSources(sources: LoggerSource[]): Promise<void>;
1422
- /** @internal */
1423
- _mgDeleteGroup(id: string): Promise<void>;
1424
- /** @internal — PUT a logger (upsert: server creates if not found). */
1425
- _saveLogger(logger: Logger): Promise<Logger>;
1426
- /** @internal — POST or PUT a log group. */
1427
- _saveLogGroup(group: LogGroup): Promise<LogGroup>;
1428
2549
  /**
1429
- * Start the logging runtime.
2550
+ * @internal — fetch the full logger list. Prefers the management plane
2551
+ * (set via `_resolveManagement`); falls back to a direct GET when running
2552
+ * without `SmplClient` bootstrap (e.g. unit tests that construct
2553
+ * `LoggingClient` directly).
2554
+ */
2555
+ private _listLoggers;
2556
+ /** @internal — see {@link _listLoggers}. */
2557
+ private _listLogGroups;
2558
+ /**
2559
+ * Install the smplkit logging integration into the running process.
1430
2560
  *
1431
- * Synchronizes loggers with the server and subscribes to live level
1432
- * updates. Idempotent safe to call multiple times.
1433
- * Management methods work without calling `start()`.
2561
+ * Loads any adapters that haven't been registered explicitly, discovers
2562
+ * existing loggers from each adapter, hooks new-logger creation, and
2563
+ * subscribes to live level updates over the shared WebSocket. Idempotent —
2564
+ * safe to call multiple times. Management methods work without calling
2565
+ * `install()`.
2566
+ *
2567
+ * Mirrors Python's `client.logging.install()`. There is no `stop()`.
2568
+ */
2569
+ install(): Promise<void>;
2570
+ /**
2571
+ * @deprecated Use {@link LoggingClient.install}. Retained as a backwards-
2572
+ * compatible alias.
1434
2573
  */
1435
2574
  start(): Promise<void>;
2575
+ /** @internal — shared body of install()/start(). */
2576
+ _installInternal(): Promise<void>;
1436
2577
  /**
1437
2578
  * Register a change listener.
1438
2579
  *
@@ -1459,289 +2600,12 @@ declare class LoggingClient {
1459
2600
  private _fetchSingleLogger;
1460
2601
  /** Fetch a single log group by key. Returns null if not found. @internal */
1461
2602
  private _fetchSingleGroup;
2603
+ /** @internal — runtime models are read-only (no save/delete). */
1462
2604
  private _loggerToModel;
2605
+ /** @internal — runtime models are read-only (no save/delete). */
1463
2606
  private _groupToModel;
1464
2607
  }
1465
2608
 
1466
- /**
1467
- * Shared types for the management namespace.
1468
- */
1469
- /** Whether an environment participates in the canonical ordering.
1470
- *
1471
- * STANDARD environments are the customer's deploy targets (production,
1472
- * staging, development, etc.) and appear in the environment_order list.
1473
- * AD_HOC environments are transient targets (preview branches,
1474
- * developer sandboxes) that are excluded from the standard ordering.
1475
- */
1476
- declare enum EnvironmentClassification {
1477
- STANDARD = "STANDARD",
1478
- AD_HOC = "AD_HOC"
1479
- }
1480
-
1481
- /**
1482
- * Active-record models for client.management.* resources.
1483
- */
1484
-
1485
- /**
1486
- * An environment resource managed by the smplkit platform.
1487
- *
1488
- * Mutate fields, then call `save()` to create or update.
1489
- */
1490
- declare class Environment {
1491
- /** Unique slug identifier (e.g. `"production"`). */
1492
- id: string | null;
1493
- /** Human-readable display name. */
1494
- name: string;
1495
- /** Hex color code, or null. */
1496
- color: string | null;
1497
- /** Whether this is a STANDARD or AD_HOC environment. */
1498
- classification: EnvironmentClassification;
1499
- /** When the environment was created. */
1500
- createdAt: string | null;
1501
- /** When the environment was last updated. */
1502
- updatedAt: string | null;
1503
- /** @internal */
1504
- readonly _client: EnvironmentsClient | null;
1505
- /** @internal */
1506
- constructor(client: EnvironmentsClient | null, fields: {
1507
- id: string | null;
1508
- name: string;
1509
- color: string | null;
1510
- classification: EnvironmentClassification;
1511
- createdAt: string | null;
1512
- updatedAt: string | null;
1513
- });
1514
- /** Persist this environment to the server (creates if new, updates if existing). */
1515
- save(): Promise<void>;
1516
- /** @internal */
1517
- _apply(other: Environment): void;
1518
- toString(): string;
1519
- }
1520
- /**
1521
- * A context-type resource managed by the smplkit platform.
1522
- *
1523
- * Mutate fields or use `addAttribute`/`removeAttribute`/`updateAttribute`,
1524
- * then call `save()` to persist.
1525
- */
1526
- declare class ContextType {
1527
- /** Unique slug identifier (e.g. `"user"`). */
1528
- id: string | null;
1529
- /** Human-readable display name. */
1530
- name: string;
1531
- /** Known attribute keys with metadata objects. */
1532
- attributes: Record<string, Record<string, any>>;
1533
- /** When the context type was created. */
1534
- createdAt: string | null;
1535
- /** When the context type was last updated. */
1536
- updatedAt: string | null;
1537
- /** @internal */
1538
- readonly _client: ContextTypesClient | null;
1539
- /** @internal */
1540
- constructor(client: ContextTypesClient | null, fields: {
1541
- id: string | null;
1542
- name: string;
1543
- attributes: Record<string, Record<string, any>>;
1544
- createdAt: string | null;
1545
- updatedAt: string | null;
1546
- });
1547
- /** Add a known-attribute slot. Local; call `save()` to persist. */
1548
- addAttribute(name: string, metadata?: Record<string, any>): void;
1549
- /** Remove a known-attribute slot. Local; call `save()` to persist. */
1550
- removeAttribute(name: string): void;
1551
- /** Replace a known-attribute slot's metadata. Local; call `save()` to persist. */
1552
- updateAttribute(name: string, metadata: Record<string, any>): void;
1553
- /** Persist this context type to the server (creates if new, updates if existing). */
1554
- save(): Promise<void>;
1555
- /** @internal */
1556
- _apply(other: ContextType): void;
1557
- toString(): string;
1558
- }
1559
- /**
1560
- * A context instance as returned by the management API.
1561
- *
1562
- * The write path is `client.management.contexts.register([...])`.
1563
- * This model is what comes back from `list`/`get`.
1564
- */
1565
- declare class ContextEntity {
1566
- /** Context type key (e.g. `"user"`). */
1567
- type: string;
1568
- /** Entity key (e.g. `"user-123"`). */
1569
- key: string;
1570
- /** Human-readable display name, or null. */
1571
- name: string | null;
1572
- /** Observed attributes. */
1573
- attributes: Record<string, any>;
1574
- /** When the context was created. */
1575
- createdAt: string | null;
1576
- /** When the context was last updated. */
1577
- updatedAt: string | null;
1578
- /** @internal */
1579
- constructor(fields: {
1580
- type: string;
1581
- key: string;
1582
- name: string | null;
1583
- attributes: Record<string, any>;
1584
- createdAt: string | null;
1585
- updatedAt: string | null;
1586
- });
1587
- /** Composite `"type:key"` identifier. */
1588
- get id(): string;
1589
- toString(): string;
1590
- }
1591
- /**
1592
- * Active-record account-settings model.
1593
- *
1594
- * The wire format is opaque JSON. Documented keys are exposed as typed
1595
- * properties; unknown keys live in `raw`. Call `save()` to write back.
1596
- */
1597
- declare class AccountSettings {
1598
- /** @internal */
1599
- private _data;
1600
- /** @internal */
1601
- readonly _client: AccountSettingsClient | null;
1602
- /** @internal */
1603
- constructor(client: AccountSettingsClient | null, data: Record<string, any>);
1604
- /** The full settings dict. Direct mutations are reflected in `save()`. */
1605
- get raw(): Record<string, any>;
1606
- set raw(value: Record<string, any>);
1607
- /** Canonical ordering of STANDARD environments. Empty array if unset. */
1608
- get environmentOrder(): string[];
1609
- set environmentOrder(value: string[]);
1610
- /** Persist the settings to the server. */
1611
- save(): Promise<void>;
1612
- /** @internal */
1613
- _apply(other: AccountSettings): void;
1614
- /** @internal — expose raw data for _save(). */
1615
- get _rawData(): Record<string, any>;
1616
- toString(): string;
1617
- }
1618
-
1619
- type AppClient = ReturnType<typeof createClient<___generated_app_d_ts.paths>>;
1620
- /**
1621
- * CRUD client for environments.
1622
- *
1623
- * Accessed via `client.management.environments`.
1624
- */
1625
- declare class EnvironmentsClient {
1626
- private readonly _http;
1627
- /** @internal */
1628
- constructor(_http: AppClient);
1629
- /**
1630
- * Return an unsaved `Environment`. Call `.save()` to persist.
1631
- */
1632
- new(id: string, options: {
1633
- name: string;
1634
- color?: string | null;
1635
- classification?: EnvironmentClassification;
1636
- }): Environment;
1637
- /** List all environments. */
1638
- list(): Promise<Environment[]>;
1639
- /** Fetch an environment by id. */
1640
- get(id: string): Promise<Environment>;
1641
- /** Delete an environment by id. */
1642
- delete(id: string): Promise<void>;
1643
- /** @internal — called by Environment.save() for new resources. */
1644
- _create(env: Environment): Promise<Environment>;
1645
- /** @internal — called by Environment.save() for existing resources. */
1646
- _update(env: Environment): Promise<Environment>;
1647
- }
1648
- /**
1649
- * CRUD client for context types.
1650
- *
1651
- * Accessed via `client.management.context_types`.
1652
- */
1653
- declare class ContextTypesClient {
1654
- private readonly _http;
1655
- /** @internal */
1656
- constructor(_http: AppClient);
1657
- /**
1658
- * Return an unsaved `ContextType`. Call `.save()` to persist.
1659
- */
1660
- new(id: string, options?: {
1661
- name?: string;
1662
- attributes?: Record<string, Record<string, any>>;
1663
- }): ContextType;
1664
- /** List all context types. */
1665
- list(): Promise<ContextType[]>;
1666
- /** Fetch a context type by id. */
1667
- get(id: string): Promise<ContextType>;
1668
- /** Delete a context type by id. */
1669
- delete(id: string): Promise<void>;
1670
- /** @internal — called by ContextType.save() for new resources. */
1671
- _create(ct: ContextType): Promise<ContextType>;
1672
- /** @internal — called by ContextType.save() for existing resources. */
1673
- _update(ct: ContextType): Promise<ContextType>;
1674
- }
1675
- /**
1676
- * Context registration + read/delete client.
1677
- *
1678
- * Accessed via `client.management.contexts`.
1679
- */
1680
- declare class ContextsClient {
1681
- private readonly _http;
1682
- private readonly _buffer;
1683
- /** @internal */
1684
- constructor(_http: AppClient, _buffer: ContextRegistrationBuffer);
1685
- /**
1686
- * Buffer context(s) for registration; optionally flush immediately.
1687
- *
1688
- * When `flush` is false (default), contexts are queued for the SDK's
1689
- * background flush — right for high-frequency observation from a live
1690
- * request handler. When `flush` is true the call awaits the round-trip
1691
- * — right for IaC scripts.
1692
- */
1693
- register(items: Context | Context[], options?: {
1694
- flush?: boolean;
1695
- }): Promise<void>;
1696
- /** Send any pending context observations to the server. */
1697
- flush(): Promise<void>;
1698
- /** List all contexts of a given type. */
1699
- list(type: string): Promise<ContextEntity[]>;
1700
- /** Fetch a context by composite id (`"type:key"`) or by separate type and key. */
1701
- get(idOrType: string, key?: string): Promise<ContextEntity>;
1702
- /** Delete a context by composite id (`"type:key"`) or by separate type and key. */
1703
- delete(idOrType: string, key?: string): Promise<void>;
1704
- }
1705
- /**
1706
- * Account-settings get/save client.
1707
- *
1708
- * The settings endpoint is not JSON:API — body is a raw JSON object — so
1709
- * we use fetch directly rather than the typed openapi-fetch client.
1710
- *
1711
- * Accessed via `client.management.account_settings`.
1712
- */
1713
- declare class AccountSettingsClient {
1714
- private readonly _appBaseUrl;
1715
- private readonly _headers;
1716
- /** @internal */
1717
- constructor(_appBaseUrl: string, apiKey: string);
1718
- /** Fetch the current account settings. */
1719
- get(): Promise<AccountSettings>;
1720
- /** @internal — called by AccountSettings.save(). */
1721
- _save(data: Record<string, any>): Promise<AccountSettings>;
1722
- }
1723
- /**
1724
- * Top-level management namespace.
1725
- *
1726
- * Accessed via `client.management`.
1727
- */
1728
- declare class ManagementClient {
1729
- /** CRUD for environments. */
1730
- readonly environments: EnvironmentsClient;
1731
- /** Registration, list, get, and delete for context instances. */
1732
- readonly contexts: ContextsClient;
1733
- /** CRUD for context types (entity schemas). */
1734
- readonly context_types: ContextTypesClient;
1735
- /** Get/save for account-level settings. */
1736
- readonly account_settings: AccountSettingsClient;
1737
- /** @internal */
1738
- constructor(options: {
1739
- appBaseUrl: string;
1740
- apiKey: string;
1741
- buffer: ContextRegistrationBuffer;
1742
- });
1743
- }
1744
-
1745
2609
  /**
1746
2610
  * Top-level SDK client — SmplClient.
1747
2611
  *
@@ -1834,8 +2698,12 @@ declare class SmplClient {
1834
2698
  readonly flags: FlagsClient;
1835
2699
  /** Client for logging management and runtime. */
1836
2700
  readonly logging: LoggingClient;
1837
- /** Client for app-plane management (environments, contexts, context types, account settings). */
1838
- readonly management: ManagementClient;
2701
+ /**
2702
+ * Standalone management/CRUD entry point — mirrors Python's
2703
+ * `client.manage`. Construction is side-effect-free; safe to use even
2704
+ * when the runtime plane is dormant.
2705
+ */
2706
+ readonly manage: SmplManagementClient;
1839
2707
  private _wsManager;
1840
2708
  private readonly _apiKey;
1841
2709
  /** @internal */
@@ -1852,6 +2720,28 @@ declare class SmplClient {
1852
2720
  private _registerServiceContext;
1853
2721
  /** Lazily create and start the shared WebSocket. @internal */
1854
2722
  private _ensureWs;
2723
+ /**
2724
+ * Eagerly initialize the SDK and wait until it is fully ready.
2725
+ *
2726
+ * Pre-fetches all flags and configs into the local cache, opens the
2727
+ * live-updates WebSocket, and waits for the handshake to complete.
2728
+ * After this returns, `flag.get()` / `client.config.get()` hit cache
2729
+ * (no first-request connect tax) and any `onChange` listeners receive
2730
+ * every server event from this point forward.
2731
+ *
2732
+ * Logging integration is _not_ installed here — call
2733
+ * `client.logging.install()` separately if you want it (it installs
2734
+ * adapters and hooks into your application's logger, which should be
2735
+ * opt-in).
2736
+ *
2737
+ * Mirrors Python's `await client.wait_until_ready()`.
2738
+ *
2739
+ * @throws SmplTimeoutError If the WebSocket fails to connect within
2740
+ * `timeoutMs` milliseconds.
2741
+ */
2742
+ waitUntilReady(options?: {
2743
+ timeoutMs?: number;
2744
+ }): Promise<void>;
1855
2745
  /** Close the shared WebSocket and release resources. */
1856
2746
  close(): void;
1857
2747
  }
@@ -1911,12 +2801,16 @@ declare class PinoAdapter implements LoggingAdapter {
1911
2801
  /**
1912
2802
  * Structured SDK error types.
1913
2803
  *
1914
- * All smplkit errors extend {@link SmplError}, allowing callers to catch
1915
- * the base class for generic handling or specific subclasses for
1916
- * fine-grained control.
2804
+ * All smplkit errors extend {@link SmplError}. The TypeScript SDK keeps
2805
+ * the `Smpl` prefix on its public error names because TypeScript's
2806
+ * built-in `Error`/`TypeError`/etc. preclude bare names. The Python
2807
+ * canonical names (`Error`, `NotFoundError`, ...) line up via
2808
+ * `Smpl{X}Error` ↔ Python `{X}Error`. The `Smplkit{X}Error` names are
2809
+ * exported as aliases (introduced in PR #103) for callers that prefer
2810
+ * the longer prefix.
1917
2811
  */
1918
2812
  /** A single error object from a JSON:API error response. */
1919
- interface ApiErrorObject {
2813
+ interface ApiErrorDetail {
1920
2814
  status?: string;
1921
2815
  title?: string;
1922
2816
  detail?: string;
@@ -1929,29 +2823,32 @@ declare class SmplError extends Error {
1929
2823
  /** The raw response body, if available. */
1930
2824
  readonly responseBody?: string;
1931
2825
  /** Structured JSON:API error objects from the server response, if available. */
1932
- readonly errors: ReadonlyArray<ApiErrorObject>;
1933
- constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorObject[]);
2826
+ readonly errors: ReadonlyArray<ApiErrorDetail>;
2827
+ constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorDetail[]);
1934
2828
  toString(): string;
1935
2829
  }
1936
2830
  /** Raised when a network request fails (e.g., DNS resolution, connection refused). */
1937
2831
  declare class SmplConnectionError extends SmplError {
1938
- constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorObject[]);
2832
+ constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorDetail[]);
1939
2833
  }
1940
2834
  /** Raised when an operation exceeds its timeout. */
1941
2835
  declare class SmplTimeoutError extends SmplError {
1942
- constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorObject[]);
2836
+ constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorDetail[]);
1943
2837
  }
1944
2838
  /** Raised when a requested resource does not exist (HTTP 404). */
1945
2839
  declare class SmplNotFoundError extends SmplError {
1946
- constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorObject[]);
2840
+ constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorDetail[]);
1947
2841
  }
1948
2842
  /** Raised when an operation conflicts with current state (HTTP 409). */
1949
2843
  declare class SmplConflictError extends SmplError {
1950
- constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorObject[]);
2844
+ constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorDetail[]);
1951
2845
  }
1952
- /** Raised when the server rejects a request due to validation errors (HTTP 422). */
2846
+ /** Raised when the server rejects a request due to validation errors (HTTP 400/422). */
1953
2847
  declare class SmplValidationError extends SmplError {
1954
- constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorObject[]);
2848
+ constructor(message: string, statusCode?: number, responseBody?: string, errors?: ApiErrorDetail[]);
1955
2849
  }
1956
2850
 
1957
- export { AccountSettings, AccountSettingsClient, type ApiErrorObject, BooleanFlag, Config, type ConfigChangeEvent, ConfigClient, ConfigManagement, Context, ContextEntity, ContextType, ContextTypesClient, ContextsClient, Environment, EnvironmentClassification, EnvironmentsClient, Flag, FlagChangeEvent, FlagStats, FlagsClient, FlagsManagement, JsonFlag, LiveConfigProxy, LogGroup, LogLevel, Logger, type LoggerChangeEvent, LoggerSource, type LoggingAdapter, LoggingClient, LoggingManagement, ManagementClient, NumberFlag, PinoAdapter, type PinoAdapterConfig, Rule, SharedWebSocket, SmplClient, type SmplClientOptions, SmplConflictError, SmplConnectionError, SmplError, SmplNotFoundError, SmplTimeoutError, SmplValidationError, StringFlag, WinstonAdapter, type WinstonAdapterConfig };
2851
+ /** @deprecated Use {@link ApiErrorDetail}. */
2852
+ type ApiErrorObject = ApiErrorDetail;
2853
+
2854
+ export { AccountSettings, AccountSettingsClient, type ApiErrorDetail, type ApiErrorObject, BooleanFlag, Color, Config, ConfigChangeEvent, ConfigClient, ConfigEnvironment, ConfigItem, Context, ContextType, ContextTypesClient, ContextsClient, Environment, EnvironmentClassification, EnvironmentsClient, Flag, FlagChangeEvent, FlagDeclaration, FlagEnvironment, FlagRule, FlagStats, FlagValue, FlagsClient, ItemType, JsonFlag, LiveConfigProxy, LogGroup, LogLevel, Logger, LoggerChangeEvent, LoggerEnvironment, LoggerSource, type LoggingAdapter, LoggingClient, NumberFlag, Op, PinoAdapter, type PinoAdapterConfig, Rule, SharedWebSocket, SmplClient, type SmplClientOptions, SmplConflictError, SmplConnectionError, SmplError, SmplManagementClient, type SmplManagementClientOptions, SmplNotFoundError, SmplTimeoutError, SmplValidationError, SmplConflictError as SmplkitConflictError, SmplConnectionError as SmplkitConnectionError, SmplError as SmplkitError, SmplNotFoundError as SmplkitNotFoundError, SmplTimeoutError as SmplkitTimeoutError, SmplValidationError as SmplkitValidationError, StringFlag, WinstonAdapter, type WinstonAdapterConfig };