@smooai/config 2.0.3 → 2.1.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.
Files changed (58) hide show
  1. package/README.md +77 -0
  2. package/dist/{chunk-Z3CZGNU5.mjs → chunk-3B5SRHJ2.mjs} +36 -5
  3. package/dist/chunk-3B5SRHJ2.mjs.map +1 -0
  4. package/dist/chunk-FAF45VZA.mjs +24 -0
  5. package/dist/chunk-FAF45VZA.mjs.map +1 -0
  6. package/dist/chunk-GP2JUWOD.mjs +53 -0
  7. package/dist/chunk-GP2JUWOD.mjs.map +1 -0
  8. package/dist/chunk-N6Z4AZZA.mjs +26 -0
  9. package/dist/chunk-N6Z4AZZA.mjs.map +1 -0
  10. package/dist/{chunk-SKX7CPGS.mjs → chunk-VL7AIM2X.mjs} +3 -23
  11. package/dist/chunk-VL7AIM2X.mjs.map +1 -0
  12. package/dist/chunk-VUYQFQ63.mjs +30 -0
  13. package/dist/chunk-VUYQFQ63.mjs.map +1 -0
  14. package/dist/nextjs/getConfig.d.mts +31 -0
  15. package/dist/nextjs/getConfig.d.ts +31 -0
  16. package/dist/nextjs/getConfig.js +172 -0
  17. package/dist/nextjs/getConfig.js.map +1 -0
  18. package/dist/nextjs/getConfig.mjs +9 -0
  19. package/dist/nextjs/getConfig.mjs.map +1 -0
  20. package/dist/nextjs/hooks.d.mts +22 -0
  21. package/dist/nextjs/hooks.d.ts +22 -0
  22. package/dist/nextjs/hooks.js +89 -0
  23. package/dist/nextjs/hooks.js.map +1 -0
  24. package/dist/nextjs/hooks.mjs +13 -0
  25. package/dist/nextjs/hooks.mjs.map +1 -0
  26. package/dist/nextjs/index.d.mts +28 -0
  27. package/dist/nextjs/index.d.ts +28 -0
  28. package/dist/nextjs/index.js +255 -0
  29. package/dist/nextjs/index.js.map +1 -0
  30. package/dist/nextjs/index.mjs +40 -0
  31. package/dist/nextjs/index.mjs.map +1 -0
  32. package/dist/platform/client.d.mts +18 -1
  33. package/dist/platform/client.d.ts +18 -1
  34. package/dist/platform/client.js +35 -4
  35. package/dist/platform/client.js.map +1 -1
  36. package/dist/platform/client.mjs +1 -1
  37. package/dist/react/hooks.js.map +1 -1
  38. package/dist/react/hooks.mjs +3 -2
  39. package/dist/react/index.d.mts +4 -2
  40. package/dist/react/index.d.ts +4 -2
  41. package/dist/react/index.js +37 -4
  42. package/dist/react/index.js.map +1 -1
  43. package/dist/react/index.mjs +8 -4
  44. package/dist/vite/index.d.mts +6 -0
  45. package/dist/vite/index.d.ts +6 -0
  46. package/dist/vite/index.js +249 -0
  47. package/dist/vite/index.js.map +1 -0
  48. package/dist/vite/index.mjs +27 -0
  49. package/dist/vite/index.mjs.map +1 -0
  50. package/dist/vite/preloadConfig.d.mts +30 -0
  51. package/dist/vite/preloadConfig.d.ts +30 -0
  52. package/dist/vite/preloadConfig.js +180 -0
  53. package/dist/vite/preloadConfig.js.map +1 -0
  54. package/dist/vite/preloadConfig.mjs +13 -0
  55. package/dist/vite/preloadConfig.mjs.map +1 -0
  56. package/package.json +6 -2
  57. package/dist/chunk-SKX7CPGS.mjs.map +0 -1
  58. package/dist/chunk-Z3CZGNU5.mjs.map +0 -1
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/vite/index.ts
21
+ var vite_exports = {};
22
+ __export(vite_exports, {
23
+ ConfigProvider: () => ConfigProvider,
24
+ getPreloadedConfig: () => getPreloadedConfig,
25
+ preloadConfig: () => preloadConfig,
26
+ resetPreload: () => resetPreload,
27
+ useConfigClient: () => useConfigClient,
28
+ useFeatureFlag: () => useFeatureFlag,
29
+ usePublicConfig: () => usePublicConfig,
30
+ useSecretConfig: () => useSecretConfig
31
+ });
32
+ module.exports = __toCommonJS(vite_exports);
33
+
34
+ // src/platform/client.ts
35
+ function getEnv(key) {
36
+ if (typeof process !== "undefined" && process.env) {
37
+ return process.env[key];
38
+ }
39
+ return void 0;
40
+ }
41
+ var ConfigClient = class {
42
+ baseUrl;
43
+ orgId;
44
+ apiKey;
45
+ defaultEnvironment;
46
+ cacheTtlMs;
47
+ cache = /* @__PURE__ */ new Map();
48
+ constructor(options = {}) {
49
+ const baseUrl = options.baseUrl ?? getEnv("SMOOAI_CONFIG_API_URL");
50
+ const apiKey = options.apiKey ?? getEnv("SMOOAI_CONFIG_API_KEY");
51
+ const orgId = options.orgId ?? getEnv("SMOOAI_CONFIG_ORG_ID");
52
+ if (!baseUrl) throw new Error("@smooai/config: baseUrl is required (or set SMOOAI_CONFIG_API_URL)");
53
+ if (!apiKey) throw new Error("@smooai/config: apiKey is required (or set SMOOAI_CONFIG_API_KEY)");
54
+ if (!orgId) throw new Error("@smooai/config: orgId is required (or set SMOOAI_CONFIG_ORG_ID)");
55
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
56
+ this.apiKey = apiKey;
57
+ this.orgId = orgId;
58
+ this.defaultEnvironment = options.environment ?? getEnv("SMOOAI_CONFIG_ENV") ?? "development";
59
+ this.cacheTtlMs = options.cacheTtlMs ?? 0;
60
+ }
61
+ computeExpiresAt() {
62
+ return this.cacheTtlMs > 0 ? Date.now() + this.cacheTtlMs : 0;
63
+ }
64
+ getCached(cacheKey) {
65
+ const entry = this.cache.get(cacheKey);
66
+ if (!entry) return void 0;
67
+ if (entry.expiresAt > 0 && Date.now() > entry.expiresAt) {
68
+ this.cache.delete(cacheKey);
69
+ return void 0;
70
+ }
71
+ return entry.value;
72
+ }
73
+ async fetchJson(path, fetchOptions) {
74
+ const response = await fetch(`${this.baseUrl}${path}`, {
75
+ ...fetchOptions,
76
+ headers: { Authorization: `Bearer ${this.apiKey}`, ...fetchOptions?.headers }
77
+ });
78
+ if (!response.ok) {
79
+ throw new Error(`Config API error: HTTP ${response.status} ${response.statusText}`);
80
+ }
81
+ return response.json();
82
+ }
83
+ /**
84
+ * Get a single config value by key.
85
+ * Results are cached locally after the first fetch.
86
+ */
87
+ async getValue(key, environment) {
88
+ const env = environment ?? this.defaultEnvironment;
89
+ const cacheKey = `${env}:${key}`;
90
+ const cached = this.getCached(cacheKey);
91
+ if (cached !== void 0) {
92
+ return cached;
93
+ }
94
+ const result = await this.fetchJson(
95
+ `/organizations/${this.orgId}/config/values/${encodeURIComponent(key)}?environment=${encodeURIComponent(env)}`
96
+ );
97
+ this.cache.set(cacheKey, { value: result.value, expiresAt: this.computeExpiresAt() });
98
+ return result.value;
99
+ }
100
+ /**
101
+ * Get all config values for an environment.
102
+ * All returned values are cached locally.
103
+ * @param environment - Environment name (defaults to constructor option or SMOOAI_CONFIG_ENV)
104
+ * @param fetchOptions - Optional fetch options (e.g., Next.js `{ next: { revalidate: 60 } }`)
105
+ */
106
+ async getAllValues(environment, fetchOptions) {
107
+ const env = environment ?? this.defaultEnvironment;
108
+ const result = await this.fetchJson(
109
+ `/organizations/${this.orgId}/config/values?environment=${encodeURIComponent(env)}`,
110
+ fetchOptions
111
+ );
112
+ const expiresAt = this.computeExpiresAt();
113
+ for (const [key, value] of Object.entries(result.values)) {
114
+ this.cache.set(`${env}:${key}`, { value, expiresAt });
115
+ }
116
+ return result.values;
117
+ }
118
+ /**
119
+ * Pre-populate a single cache entry (e.g., from SSR).
120
+ * Does not make a network request.
121
+ */
122
+ seedCache(key, value, environment) {
123
+ const env = environment ?? this.defaultEnvironment;
124
+ this.cache.set(`${env}:${key}`, { value, expiresAt: this.computeExpiresAt() });
125
+ }
126
+ /**
127
+ * Pre-populate multiple cache entries from a key-value map (e.g., from SSR).
128
+ * Does not make a network request.
129
+ */
130
+ seedCacheFromMap(values, environment) {
131
+ const env = environment ?? this.defaultEnvironment;
132
+ const expiresAt = this.computeExpiresAt();
133
+ for (const [key, value] of Object.entries(values)) {
134
+ this.cache.set(`${env}:${key}`, { value, expiresAt });
135
+ }
136
+ }
137
+ /**
138
+ * Synchronously read a value from the local cache without making a network request.
139
+ * Returns `undefined` if the key is not cached or has expired.
140
+ */
141
+ getCachedValue(key, environment) {
142
+ const env = environment ?? this.defaultEnvironment;
143
+ return this.getCached(`${env}:${key}`);
144
+ }
145
+ /** Clear the entire local cache. */
146
+ invalidateCache() {
147
+ this.cache.clear();
148
+ }
149
+ /** Clear cached values for a specific environment. */
150
+ invalidateCacheForEnvironment(environment) {
151
+ const prefix = `${environment}:`;
152
+ for (const key of this.cache.keys()) {
153
+ if (key.startsWith(prefix)) {
154
+ this.cache.delete(key);
155
+ }
156
+ }
157
+ }
158
+ };
159
+
160
+ // src/vite/preloadConfig.ts
161
+ var preloadPromise = null;
162
+ var preloadedValues = null;
163
+ function preloadConfig(options) {
164
+ if (preloadPromise) return preloadPromise;
165
+ const client = new ConfigClient(options);
166
+ preloadPromise = client.getAllValues(options?.environment).then((values) => {
167
+ preloadedValues = values;
168
+ return values;
169
+ });
170
+ return preloadPromise;
171
+ }
172
+ function getPreloadedConfig() {
173
+ return preloadedValues;
174
+ }
175
+ function resetPreload() {
176
+ preloadPromise = null;
177
+ preloadedValues = null;
178
+ }
179
+
180
+ // src/react/ConfigProvider.tsx
181
+ var import_react = require("react");
182
+ var import_jsx_runtime = require("react/jsx-runtime");
183
+ var ConfigContext = (0, import_react.createContext)(null);
184
+ function ConfigProvider({ children, ...options }) {
185
+ const client = (0, import_react.useMemo)(() => new ConfigClient(options), [options.baseUrl, options.apiKey, options.orgId, options.environment]);
186
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ConfigContext.Provider, { value: client, children });
187
+ }
188
+ function useConfigClient() {
189
+ const client = (0, import_react.useContext)(ConfigContext);
190
+ if (!client) {
191
+ throw new Error("useConfigClient must be used within a <ConfigProvider>");
192
+ }
193
+ return client;
194
+ }
195
+
196
+ // src/react/hooks.ts
197
+ var import_react2 = require("react");
198
+ function useConfigValue(key, environment) {
199
+ const client = useConfigClient();
200
+ const [value, setValue] = (0, import_react2.useState)(void 0);
201
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
202
+ const [error, setError] = (0, import_react2.useState)(null);
203
+ const [fetchCount, setFetchCount] = (0, import_react2.useState)(0);
204
+ const refetch = (0, import_react2.useCallback)(() => {
205
+ client.invalidateCache();
206
+ setFetchCount((c) => c + 1);
207
+ }, [client]);
208
+ (0, import_react2.useEffect)(() => {
209
+ let cancelled = false;
210
+ setIsLoading(true);
211
+ setError(null);
212
+ client.getValue(key, environment).then((result) => {
213
+ if (!cancelled) {
214
+ setValue(result);
215
+ setIsLoading(false);
216
+ }
217
+ }).catch((err) => {
218
+ if (!cancelled) {
219
+ setError(err instanceof Error ? err : new Error(String(err)));
220
+ setIsLoading(false);
221
+ }
222
+ });
223
+ return () => {
224
+ cancelled = true;
225
+ };
226
+ }, [client, key, environment, fetchCount]);
227
+ return { value, isLoading, error, refetch };
228
+ }
229
+ function usePublicConfig(key, environment) {
230
+ return useConfigValue(key, environment);
231
+ }
232
+ function useSecretConfig(key, environment) {
233
+ return useConfigValue(key, environment);
234
+ }
235
+ function useFeatureFlag(key, environment) {
236
+ return useConfigValue(key, environment);
237
+ }
238
+ // Annotate the CommonJS export names for ESM import in node:
239
+ 0 && (module.exports = {
240
+ ConfigProvider,
241
+ getPreloadedConfig,
242
+ preloadConfig,
243
+ resetPreload,
244
+ useConfigClient,
245
+ useFeatureFlag,
246
+ usePublicConfig,
247
+ useSecretConfig
248
+ });
249
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/vite/index.ts","../../src/platform/client.ts","../../src/vite/preloadConfig.ts","../../src/react/ConfigProvider.tsx","../../src/react/hooks.ts"],"sourcesContent":["export { preloadConfig, getPreloadedConfig, resetPreload } from './preloadConfig';\nexport { ConfigProvider, useConfigClient } from '../react/ConfigProvider';\nexport type { ConfigProviderProps } from '../react/ConfigProvider';\nexport { usePublicConfig, useSecretConfig, useFeatureFlag } from '../react/hooks';\n","/**\n * Browser/universal HTTP client for fetching config values from the Smoo AI config server.\n *\n * Environment variables (optional — used as defaults when constructor args are omitted):\n * SMOOAI_CONFIG_API_URL — Base URL of the config API\n * SMOOAI_CONFIG_API_KEY — Bearer token for authentication\n * SMOOAI_CONFIG_ORG_ID — Organization ID\n * SMOOAI_CONFIG_ENV — Default environment name (e.g. \"production\")\n */\n\nexport interface ConfigClientOptions {\n /** Base URL of the config API server. Falls back to SMOOAI_CONFIG_API_URL env var. */\n baseUrl?: string;\n /** API key (M2M / client credentials token). Falls back to SMOOAI_CONFIG_API_KEY env var. */\n apiKey?: string;\n /** Organization ID. Falls back to SMOOAI_CONFIG_ORG_ID env var. */\n orgId?: string;\n /** Default environment name. Falls back to SMOOAI_CONFIG_ENV env var, then \"development\". */\n environment?: string;\n /** Cache TTL in milliseconds. 0 or undefined means cache never expires (manual invalidation only). */\n cacheTtlMs?: number;\n}\n\ninterface CacheEntry {\n value: unknown;\n expiresAt: number; // 0 = never expires\n}\n\nfunction getEnv(key: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[key];\n }\n return undefined;\n}\n\nexport class ConfigClient {\n private baseUrl: string;\n private orgId: string;\n private apiKey: string;\n private defaultEnvironment: string;\n private cacheTtlMs: number;\n private cache: Map<string, CacheEntry> = new Map();\n\n constructor(options: ConfigClientOptions = {}) {\n const baseUrl = options.baseUrl ?? getEnv('SMOOAI_CONFIG_API_URL');\n const apiKey = options.apiKey ?? getEnv('SMOOAI_CONFIG_API_KEY');\n const orgId = options.orgId ?? getEnv('SMOOAI_CONFIG_ORG_ID');\n\n if (!baseUrl) throw new Error('@smooai/config: baseUrl is required (or set SMOOAI_CONFIG_API_URL)');\n if (!apiKey) throw new Error('@smooai/config: apiKey is required (or set SMOOAI_CONFIG_API_KEY)');\n if (!orgId) throw new Error('@smooai/config: orgId is required (or set SMOOAI_CONFIG_ORG_ID)');\n\n this.baseUrl = baseUrl.replace(/\\/+$/, '');\n this.apiKey = apiKey;\n this.orgId = orgId;\n this.defaultEnvironment = options.environment ?? getEnv('SMOOAI_CONFIG_ENV') ?? 'development';\n this.cacheTtlMs = options.cacheTtlMs ?? 0;\n }\n\n private computeExpiresAt(): number {\n return this.cacheTtlMs > 0 ? Date.now() + this.cacheTtlMs : 0;\n }\n\n private getCached(cacheKey: string): unknown | undefined {\n const entry = this.cache.get(cacheKey);\n if (!entry) return undefined;\n if (entry.expiresAt > 0 && Date.now() > entry.expiresAt) {\n this.cache.delete(cacheKey);\n return undefined;\n }\n return entry.value;\n }\n\n private async fetchJson<T>(path: string, fetchOptions?: RequestInit): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...fetchOptions,\n headers: { Authorization: `Bearer ${this.apiKey}`, ...fetchOptions?.headers },\n });\n if (!response.ok) {\n throw new Error(`Config API error: HTTP ${response.status} ${response.statusText}`);\n }\n return response.json() as Promise<T>;\n }\n\n /**\n * Get a single config value by key.\n * Results are cached locally after the first fetch.\n */\n async getValue(key: string, environment?: string): Promise<unknown> {\n const env = environment ?? this.defaultEnvironment;\n const cacheKey = `${env}:${key}`;\n\n const cached = this.getCached(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const result = await this.fetchJson<{ value: unknown }>(\n `/organizations/${this.orgId}/config/values/${encodeURIComponent(key)}?environment=${encodeURIComponent(env)}`,\n );\n this.cache.set(cacheKey, { value: result.value, expiresAt: this.computeExpiresAt() });\n return result.value;\n }\n\n /**\n * Get all config values for an environment.\n * All returned values are cached locally.\n * @param environment - Environment name (defaults to constructor option or SMOOAI_CONFIG_ENV)\n * @param fetchOptions - Optional fetch options (e.g., Next.js `{ next: { revalidate: 60 } }`)\n */\n async getAllValues(environment?: string, fetchOptions?: RequestInit): Promise<Record<string, unknown>> {\n const env = environment ?? this.defaultEnvironment;\n\n const result = await this.fetchJson<{ values: Record<string, unknown> }>(\n `/organizations/${this.orgId}/config/values?environment=${encodeURIComponent(env)}`,\n fetchOptions,\n );\n\n const expiresAt = this.computeExpiresAt();\n for (const [key, value] of Object.entries(result.values)) {\n this.cache.set(`${env}:${key}`, { value, expiresAt });\n }\n\n return result.values;\n }\n\n /**\n * Pre-populate a single cache entry (e.g., from SSR).\n * Does not make a network request.\n */\n seedCache(key: string, value: unknown, environment?: string): void {\n const env = environment ?? this.defaultEnvironment;\n this.cache.set(`${env}:${key}`, { value, expiresAt: this.computeExpiresAt() });\n }\n\n /**\n * Pre-populate multiple cache entries from a key-value map (e.g., from SSR).\n * Does not make a network request.\n */\n seedCacheFromMap(values: Record<string, unknown>, environment?: string): void {\n const env = environment ?? this.defaultEnvironment;\n const expiresAt = this.computeExpiresAt();\n for (const [key, value] of Object.entries(values)) {\n this.cache.set(`${env}:${key}`, { value, expiresAt });\n }\n }\n\n /**\n * Synchronously read a value from the local cache without making a network request.\n * Returns `undefined` if the key is not cached or has expired.\n */\n getCachedValue(key: string, environment?: string): unknown | undefined {\n const env = environment ?? this.defaultEnvironment;\n return this.getCached(`${env}:${key}`);\n }\n\n /** Clear the entire local cache. */\n invalidateCache(): void {\n this.cache.clear();\n }\n\n /** Clear cached values for a specific environment. */\n invalidateCacheForEnvironment(environment: string): void {\n const prefix = `${environment}:`;\n for (const key of this.cache.keys()) {\n if (key.startsWith(prefix)) {\n this.cache.delete(key);\n }\n }\n }\n}\n","import { ConfigClient, type ConfigClientOptions } from '../platform/client';\n\nlet preloadPromise: Promise<Record<string, unknown>> | null = null;\nlet preloadedValues: Record<string, unknown> | null = null;\n\n/**\n * Start fetching all config values as early as possible (before React renders).\n * Call this in your entry file before `createRoot()`:\n *\n * ```ts\n * // main.tsx\n * import { preloadConfig } from '@smooai/config/vite';\n *\n * preloadConfig({ environment: 'production' });\n *\n * // ... later, React tree mounts and hooks read from the already-populated cache\n * ```\n *\n * The returned promise resolves with the fetched config values.\n * Subsequent calls return the same promise (singleton behavior).\n */\nexport function preloadConfig(options?: ConfigClientOptions): Promise<Record<string, unknown>> {\n if (preloadPromise) return preloadPromise;\n\n const client = new ConfigClient(options);\n preloadPromise = client.getAllValues(options?.environment).then((values) => {\n preloadedValues = values;\n return values;\n });\n return preloadPromise;\n}\n\n/**\n * Get the preloaded config values synchronously.\n * Returns `null` if `preloadConfig()` hasn't completed yet.\n */\nexport function getPreloadedConfig(): Record<string, unknown> | null {\n return preloadedValues;\n}\n\n/**\n * Reset preload state (primarily for testing).\n */\nexport function resetPreload(): void {\n preloadPromise = null;\n preloadedValues = null;\n}\n","'use client';\n\nimport { createContext, useContext, useMemo, type ReactNode } from 'react';\nimport { ConfigClient, type ConfigClientOptions } from '../platform/client';\n\nexport const ConfigContext = createContext<ConfigClient | null>(null);\n\nexport interface ConfigProviderProps extends ConfigClientOptions {\n children: ReactNode;\n}\n\n/**\n * Provides a ConfigClient instance to all descendant components.\n *\n * ```tsx\n * <ConfigProvider baseUrl=\"https://api.smooai.dev\" apiKey=\"...\" orgId=\"...\" environment=\"production\">\n * <App />\n * </ConfigProvider>\n * ```\n *\n * All props are optional if the corresponding environment variables are set:\n * SMOOAI_CONFIG_API_URL, SMOOAI_CONFIG_API_KEY, SMOOAI_CONFIG_ORG_ID, SMOOAI_CONFIG_ENV\n */\nexport function ConfigProvider({ children, ...options }: ConfigProviderProps) {\n const client = useMemo(() => new ConfigClient(options), [options.baseUrl, options.apiKey, options.orgId, options.environment]);\n\n return <ConfigContext.Provider value={client}>{children}</ConfigContext.Provider>;\n}\n\n/**\n * Access the ConfigClient instance from the nearest ConfigProvider.\n * Throws if used outside a ConfigProvider.\n */\nexport function useConfigClient(): ConfigClient {\n const client = useContext(ConfigContext);\n if (!client) {\n throw new Error('useConfigClient must be used within a <ConfigProvider>');\n }\n return client;\n}\n","'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport { useConfigClient } from './ConfigProvider';\n\ninterface UseConfigResult<T = unknown> {\n /** The resolved config value, or undefined while loading. */\n value: T | undefined;\n /** True while the initial fetch is in progress. */\n isLoading: boolean;\n /** The error if the fetch failed. */\n error: Error | null;\n /** Re-fetch the value (bypasses cache). */\n refetch: () => void;\n}\n\nfunction useConfigValue(key: string, environment?: string): UseConfigResult {\n const client = useConfigClient();\n const [value, setValue] = useState<unknown>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [fetchCount, setFetchCount] = useState(0);\n\n const refetch = useCallback(() => {\n client.invalidateCache();\n setFetchCount((c) => c + 1);\n }, [client]);\n\n useEffect(() => {\n let cancelled = false;\n setIsLoading(true);\n setError(null);\n\n client\n .getValue(key, environment)\n .then((result) => {\n if (!cancelled) {\n setValue(result);\n setIsLoading(false);\n }\n })\n .catch((err: unknown) => {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsLoading(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [client, key, environment, fetchCount]);\n\n return { value, isLoading, error, refetch };\n}\n\n/**\n * Fetch a public config value by key.\n *\n * ```tsx\n * const { value, isLoading, error } = usePublicConfig('API_URL');\n * ```\n */\nexport function usePublicConfig<T = unknown>(key: string, environment?: string): UseConfigResult<T> {\n return useConfigValue(key, environment) as UseConfigResult<T>;\n}\n\n/**\n * Fetch a secret config value by key.\n *\n * ```tsx\n * const { value, isLoading } = useSecretConfig('DATABASE_URL');\n * ```\n */\nexport function useSecretConfig<T = unknown>(key: string, environment?: string): UseConfigResult<T> {\n return useConfigValue(key, environment) as UseConfigResult<T>;\n}\n\n/**\n * Fetch a feature flag value by key.\n *\n * ```tsx\n * const { value: enableNewUI } = useFeatureFlag<boolean>('ENABLE_NEW_UI');\n * ```\n */\nexport function useFeatureFlag<T = unknown>(key: string, environment?: string): UseConfigResult<T> {\n return useConfigValue(key, environment) as UseConfigResult<T>;\n}\n"],"mappings":"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","names":["import_react"]}
@@ -0,0 +1,27 @@
1
+ import {
2
+ useFeatureFlag,
3
+ usePublicConfig,
4
+ useSecretConfig
5
+ } from "../chunk-VL7AIM2X.mjs";
6
+ import {
7
+ getPreloadedConfig,
8
+ preloadConfig,
9
+ resetPreload
10
+ } from "../chunk-VUYQFQ63.mjs";
11
+ import {
12
+ ConfigProvider,
13
+ useConfigClient
14
+ } from "../chunk-N6Z4AZZA.mjs";
15
+ import "../chunk-3B5SRHJ2.mjs";
16
+ import "../chunk-J5LGTIGS.mjs";
17
+ export {
18
+ ConfigProvider,
19
+ getPreloadedConfig,
20
+ preloadConfig,
21
+ resetPreload,
22
+ useConfigClient,
23
+ useFeatureFlag,
24
+ usePublicConfig,
25
+ useSecretConfig
26
+ };
27
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,30 @@
1
+ import { ConfigClientOptions } from '../platform/client.mjs';
2
+
3
+ /**
4
+ * Start fetching all config values as early as possible (before React renders).
5
+ * Call this in your entry file before `createRoot()`:
6
+ *
7
+ * ```ts
8
+ * // main.tsx
9
+ * import { preloadConfig } from '@smooai/config/vite';
10
+ *
11
+ * preloadConfig({ environment: 'production' });
12
+ *
13
+ * // ... later, React tree mounts and hooks read from the already-populated cache
14
+ * ```
15
+ *
16
+ * The returned promise resolves with the fetched config values.
17
+ * Subsequent calls return the same promise (singleton behavior).
18
+ */
19
+ declare function preloadConfig(options?: ConfigClientOptions): Promise<Record<string, unknown>>;
20
+ /**
21
+ * Get the preloaded config values synchronously.
22
+ * Returns `null` if `preloadConfig()` hasn't completed yet.
23
+ */
24
+ declare function getPreloadedConfig(): Record<string, unknown> | null;
25
+ /**
26
+ * Reset preload state (primarily for testing).
27
+ */
28
+ declare function resetPreload(): void;
29
+
30
+ export { getPreloadedConfig, preloadConfig, resetPreload };
@@ -0,0 +1,30 @@
1
+ import { ConfigClientOptions } from '../platform/client.js';
2
+
3
+ /**
4
+ * Start fetching all config values as early as possible (before React renders).
5
+ * Call this in your entry file before `createRoot()`:
6
+ *
7
+ * ```ts
8
+ * // main.tsx
9
+ * import { preloadConfig } from '@smooai/config/vite';
10
+ *
11
+ * preloadConfig({ environment: 'production' });
12
+ *
13
+ * // ... later, React tree mounts and hooks read from the already-populated cache
14
+ * ```
15
+ *
16
+ * The returned promise resolves with the fetched config values.
17
+ * Subsequent calls return the same promise (singleton behavior).
18
+ */
19
+ declare function preloadConfig(options?: ConfigClientOptions): Promise<Record<string, unknown>>;
20
+ /**
21
+ * Get the preloaded config values synchronously.
22
+ * Returns `null` if `preloadConfig()` hasn't completed yet.
23
+ */
24
+ declare function getPreloadedConfig(): Record<string, unknown> | null;
25
+ /**
26
+ * Reset preload state (primarily for testing).
27
+ */
28
+ declare function resetPreload(): void;
29
+
30
+ export { getPreloadedConfig, preloadConfig, resetPreload };
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/vite/preloadConfig.ts
21
+ var preloadConfig_exports = {};
22
+ __export(preloadConfig_exports, {
23
+ getPreloadedConfig: () => getPreloadedConfig,
24
+ preloadConfig: () => preloadConfig,
25
+ resetPreload: () => resetPreload
26
+ });
27
+ module.exports = __toCommonJS(preloadConfig_exports);
28
+
29
+ // src/platform/client.ts
30
+ function getEnv(key) {
31
+ if (typeof process !== "undefined" && process.env) {
32
+ return process.env[key];
33
+ }
34
+ return void 0;
35
+ }
36
+ var ConfigClient = class {
37
+ baseUrl;
38
+ orgId;
39
+ apiKey;
40
+ defaultEnvironment;
41
+ cacheTtlMs;
42
+ cache = /* @__PURE__ */ new Map();
43
+ constructor(options = {}) {
44
+ const baseUrl = options.baseUrl ?? getEnv("SMOOAI_CONFIG_API_URL");
45
+ const apiKey = options.apiKey ?? getEnv("SMOOAI_CONFIG_API_KEY");
46
+ const orgId = options.orgId ?? getEnv("SMOOAI_CONFIG_ORG_ID");
47
+ if (!baseUrl) throw new Error("@smooai/config: baseUrl is required (or set SMOOAI_CONFIG_API_URL)");
48
+ if (!apiKey) throw new Error("@smooai/config: apiKey is required (or set SMOOAI_CONFIG_API_KEY)");
49
+ if (!orgId) throw new Error("@smooai/config: orgId is required (or set SMOOAI_CONFIG_ORG_ID)");
50
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
51
+ this.apiKey = apiKey;
52
+ this.orgId = orgId;
53
+ this.defaultEnvironment = options.environment ?? getEnv("SMOOAI_CONFIG_ENV") ?? "development";
54
+ this.cacheTtlMs = options.cacheTtlMs ?? 0;
55
+ }
56
+ computeExpiresAt() {
57
+ return this.cacheTtlMs > 0 ? Date.now() + this.cacheTtlMs : 0;
58
+ }
59
+ getCached(cacheKey) {
60
+ const entry = this.cache.get(cacheKey);
61
+ if (!entry) return void 0;
62
+ if (entry.expiresAt > 0 && Date.now() > entry.expiresAt) {
63
+ this.cache.delete(cacheKey);
64
+ return void 0;
65
+ }
66
+ return entry.value;
67
+ }
68
+ async fetchJson(path, fetchOptions) {
69
+ const response = await fetch(`${this.baseUrl}${path}`, {
70
+ ...fetchOptions,
71
+ headers: { Authorization: `Bearer ${this.apiKey}`, ...fetchOptions?.headers }
72
+ });
73
+ if (!response.ok) {
74
+ throw new Error(`Config API error: HTTP ${response.status} ${response.statusText}`);
75
+ }
76
+ return response.json();
77
+ }
78
+ /**
79
+ * Get a single config value by key.
80
+ * Results are cached locally after the first fetch.
81
+ */
82
+ async getValue(key, environment) {
83
+ const env = environment ?? this.defaultEnvironment;
84
+ const cacheKey = `${env}:${key}`;
85
+ const cached = this.getCached(cacheKey);
86
+ if (cached !== void 0) {
87
+ return cached;
88
+ }
89
+ const result = await this.fetchJson(
90
+ `/organizations/${this.orgId}/config/values/${encodeURIComponent(key)}?environment=${encodeURIComponent(env)}`
91
+ );
92
+ this.cache.set(cacheKey, { value: result.value, expiresAt: this.computeExpiresAt() });
93
+ return result.value;
94
+ }
95
+ /**
96
+ * Get all config values for an environment.
97
+ * All returned values are cached locally.
98
+ * @param environment - Environment name (defaults to constructor option or SMOOAI_CONFIG_ENV)
99
+ * @param fetchOptions - Optional fetch options (e.g., Next.js `{ next: { revalidate: 60 } }`)
100
+ */
101
+ async getAllValues(environment, fetchOptions) {
102
+ const env = environment ?? this.defaultEnvironment;
103
+ const result = await this.fetchJson(
104
+ `/organizations/${this.orgId}/config/values?environment=${encodeURIComponent(env)}`,
105
+ fetchOptions
106
+ );
107
+ const expiresAt = this.computeExpiresAt();
108
+ for (const [key, value] of Object.entries(result.values)) {
109
+ this.cache.set(`${env}:${key}`, { value, expiresAt });
110
+ }
111
+ return result.values;
112
+ }
113
+ /**
114
+ * Pre-populate a single cache entry (e.g., from SSR).
115
+ * Does not make a network request.
116
+ */
117
+ seedCache(key, value, environment) {
118
+ const env = environment ?? this.defaultEnvironment;
119
+ this.cache.set(`${env}:${key}`, { value, expiresAt: this.computeExpiresAt() });
120
+ }
121
+ /**
122
+ * Pre-populate multiple cache entries from a key-value map (e.g., from SSR).
123
+ * Does not make a network request.
124
+ */
125
+ seedCacheFromMap(values, environment) {
126
+ const env = environment ?? this.defaultEnvironment;
127
+ const expiresAt = this.computeExpiresAt();
128
+ for (const [key, value] of Object.entries(values)) {
129
+ this.cache.set(`${env}:${key}`, { value, expiresAt });
130
+ }
131
+ }
132
+ /**
133
+ * Synchronously read a value from the local cache without making a network request.
134
+ * Returns `undefined` if the key is not cached or has expired.
135
+ */
136
+ getCachedValue(key, environment) {
137
+ const env = environment ?? this.defaultEnvironment;
138
+ return this.getCached(`${env}:${key}`);
139
+ }
140
+ /** Clear the entire local cache. */
141
+ invalidateCache() {
142
+ this.cache.clear();
143
+ }
144
+ /** Clear cached values for a specific environment. */
145
+ invalidateCacheForEnvironment(environment) {
146
+ const prefix = `${environment}:`;
147
+ for (const key of this.cache.keys()) {
148
+ if (key.startsWith(prefix)) {
149
+ this.cache.delete(key);
150
+ }
151
+ }
152
+ }
153
+ };
154
+
155
+ // src/vite/preloadConfig.ts
156
+ var preloadPromise = null;
157
+ var preloadedValues = null;
158
+ function preloadConfig(options) {
159
+ if (preloadPromise) return preloadPromise;
160
+ const client = new ConfigClient(options);
161
+ preloadPromise = client.getAllValues(options?.environment).then((values) => {
162
+ preloadedValues = values;
163
+ return values;
164
+ });
165
+ return preloadPromise;
166
+ }
167
+ function getPreloadedConfig() {
168
+ return preloadedValues;
169
+ }
170
+ function resetPreload() {
171
+ preloadPromise = null;
172
+ preloadedValues = null;
173
+ }
174
+ // Annotate the CommonJS export names for ESM import in node:
175
+ 0 && (module.exports = {
176
+ getPreloadedConfig,
177
+ preloadConfig,
178
+ resetPreload
179
+ });
180
+ //# sourceMappingURL=preloadConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/vite/preloadConfig.ts","../../src/platform/client.ts"],"sourcesContent":["import { ConfigClient, type ConfigClientOptions } from '../platform/client';\n\nlet preloadPromise: Promise<Record<string, unknown>> | null = null;\nlet preloadedValues: Record<string, unknown> | null = null;\n\n/**\n * Start fetching all config values as early as possible (before React renders).\n * Call this in your entry file before `createRoot()`:\n *\n * ```ts\n * // main.tsx\n * import { preloadConfig } from '@smooai/config/vite';\n *\n * preloadConfig({ environment: 'production' });\n *\n * // ... later, React tree mounts and hooks read from the already-populated cache\n * ```\n *\n * The returned promise resolves with the fetched config values.\n * Subsequent calls return the same promise (singleton behavior).\n */\nexport function preloadConfig(options?: ConfigClientOptions): Promise<Record<string, unknown>> {\n if (preloadPromise) return preloadPromise;\n\n const client = new ConfigClient(options);\n preloadPromise = client.getAllValues(options?.environment).then((values) => {\n preloadedValues = values;\n return values;\n });\n return preloadPromise;\n}\n\n/**\n * Get the preloaded config values synchronously.\n * Returns `null` if `preloadConfig()` hasn't completed yet.\n */\nexport function getPreloadedConfig(): Record<string, unknown> | null {\n return preloadedValues;\n}\n\n/**\n * Reset preload state (primarily for testing).\n */\nexport function resetPreload(): void {\n preloadPromise = null;\n preloadedValues = null;\n}\n","/**\n * Browser/universal HTTP client for fetching config values from the Smoo AI config server.\n *\n * Environment variables (optional — used as defaults when constructor args are omitted):\n * SMOOAI_CONFIG_API_URL — Base URL of the config API\n * SMOOAI_CONFIG_API_KEY — Bearer token for authentication\n * SMOOAI_CONFIG_ORG_ID — Organization ID\n * SMOOAI_CONFIG_ENV — Default environment name (e.g. \"production\")\n */\n\nexport interface ConfigClientOptions {\n /** Base URL of the config API server. Falls back to SMOOAI_CONFIG_API_URL env var. */\n baseUrl?: string;\n /** API key (M2M / client credentials token). Falls back to SMOOAI_CONFIG_API_KEY env var. */\n apiKey?: string;\n /** Organization ID. Falls back to SMOOAI_CONFIG_ORG_ID env var. */\n orgId?: string;\n /** Default environment name. Falls back to SMOOAI_CONFIG_ENV env var, then \"development\". */\n environment?: string;\n /** Cache TTL in milliseconds. 0 or undefined means cache never expires (manual invalidation only). */\n cacheTtlMs?: number;\n}\n\ninterface CacheEntry {\n value: unknown;\n expiresAt: number; // 0 = never expires\n}\n\nfunction getEnv(key: string): string | undefined {\n if (typeof process !== 'undefined' && process.env) {\n return process.env[key];\n }\n return undefined;\n}\n\nexport class ConfigClient {\n private baseUrl: string;\n private orgId: string;\n private apiKey: string;\n private defaultEnvironment: string;\n private cacheTtlMs: number;\n private cache: Map<string, CacheEntry> = new Map();\n\n constructor(options: ConfigClientOptions = {}) {\n const baseUrl = options.baseUrl ?? getEnv('SMOOAI_CONFIG_API_URL');\n const apiKey = options.apiKey ?? getEnv('SMOOAI_CONFIG_API_KEY');\n const orgId = options.orgId ?? getEnv('SMOOAI_CONFIG_ORG_ID');\n\n if (!baseUrl) throw new Error('@smooai/config: baseUrl is required (or set SMOOAI_CONFIG_API_URL)');\n if (!apiKey) throw new Error('@smooai/config: apiKey is required (or set SMOOAI_CONFIG_API_KEY)');\n if (!orgId) throw new Error('@smooai/config: orgId is required (or set SMOOAI_CONFIG_ORG_ID)');\n\n this.baseUrl = baseUrl.replace(/\\/+$/, '');\n this.apiKey = apiKey;\n this.orgId = orgId;\n this.defaultEnvironment = options.environment ?? getEnv('SMOOAI_CONFIG_ENV') ?? 'development';\n this.cacheTtlMs = options.cacheTtlMs ?? 0;\n }\n\n private computeExpiresAt(): number {\n return this.cacheTtlMs > 0 ? Date.now() + this.cacheTtlMs : 0;\n }\n\n private getCached(cacheKey: string): unknown | undefined {\n const entry = this.cache.get(cacheKey);\n if (!entry) return undefined;\n if (entry.expiresAt > 0 && Date.now() > entry.expiresAt) {\n this.cache.delete(cacheKey);\n return undefined;\n }\n return entry.value;\n }\n\n private async fetchJson<T>(path: string, fetchOptions?: RequestInit): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`, {\n ...fetchOptions,\n headers: { Authorization: `Bearer ${this.apiKey}`, ...fetchOptions?.headers },\n });\n if (!response.ok) {\n throw new Error(`Config API error: HTTP ${response.status} ${response.statusText}`);\n }\n return response.json() as Promise<T>;\n }\n\n /**\n * Get a single config value by key.\n * Results are cached locally after the first fetch.\n */\n async getValue(key: string, environment?: string): Promise<unknown> {\n const env = environment ?? this.defaultEnvironment;\n const cacheKey = `${env}:${key}`;\n\n const cached = this.getCached(cacheKey);\n if (cached !== undefined) {\n return cached;\n }\n\n const result = await this.fetchJson<{ value: unknown }>(\n `/organizations/${this.orgId}/config/values/${encodeURIComponent(key)}?environment=${encodeURIComponent(env)}`,\n );\n this.cache.set(cacheKey, { value: result.value, expiresAt: this.computeExpiresAt() });\n return result.value;\n }\n\n /**\n * Get all config values for an environment.\n * All returned values are cached locally.\n * @param environment - Environment name (defaults to constructor option or SMOOAI_CONFIG_ENV)\n * @param fetchOptions - Optional fetch options (e.g., Next.js `{ next: { revalidate: 60 } }`)\n */\n async getAllValues(environment?: string, fetchOptions?: RequestInit): Promise<Record<string, unknown>> {\n const env = environment ?? this.defaultEnvironment;\n\n const result = await this.fetchJson<{ values: Record<string, unknown> }>(\n `/organizations/${this.orgId}/config/values?environment=${encodeURIComponent(env)}`,\n fetchOptions,\n );\n\n const expiresAt = this.computeExpiresAt();\n for (const [key, value] of Object.entries(result.values)) {\n this.cache.set(`${env}:${key}`, { value, expiresAt });\n }\n\n return result.values;\n }\n\n /**\n * Pre-populate a single cache entry (e.g., from SSR).\n * Does not make a network request.\n */\n seedCache(key: string, value: unknown, environment?: string): void {\n const env = environment ?? this.defaultEnvironment;\n this.cache.set(`${env}:${key}`, { value, expiresAt: this.computeExpiresAt() });\n }\n\n /**\n * Pre-populate multiple cache entries from a key-value map (e.g., from SSR).\n * Does not make a network request.\n */\n seedCacheFromMap(values: Record<string, unknown>, environment?: string): void {\n const env = environment ?? this.defaultEnvironment;\n const expiresAt = this.computeExpiresAt();\n for (const [key, value] of Object.entries(values)) {\n this.cache.set(`${env}:${key}`, { value, expiresAt });\n }\n }\n\n /**\n * Synchronously read a value from the local cache without making a network request.\n * Returns `undefined` if the key is not cached or has expired.\n */\n getCachedValue(key: string, environment?: string): unknown | undefined {\n const env = environment ?? this.defaultEnvironment;\n return this.getCached(`${env}:${key}`);\n }\n\n /** Clear the entire local cache. */\n invalidateCache(): void {\n this.cache.clear();\n }\n\n /** Clear cached values for a specific environment. */\n invalidateCacheForEnvironment(environment: string): void {\n const prefix = `${environment}:`;\n for (const key of this.cache.keys()) {\n if (key.startsWith(prefix)) {\n this.cache.delete(key);\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,13 @@
1
+ import {
2
+ getPreloadedConfig,
3
+ preloadConfig,
4
+ resetPreload
5
+ } from "../chunk-VUYQFQ63.mjs";
6
+ import "../chunk-3B5SRHJ2.mjs";
7
+ import "../chunk-J5LGTIGS.mjs";
8
+ export {
9
+ getPreloadedConfig,
10
+ preloadConfig,
11
+ resetPreload
12
+ };
13
+ //# sourceMappingURL=preloadConfig.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smooai/config",
3
- "version": "2.0.3",
3
+ "version": "2.1.0",
4
4
  "description": "Type-safe multi-language configuration management with schema validation, three-tier config (public, secret, feature flags), and runtime client support for TypeScript, Python, Rust, and Go.",
5
5
  "homepage": "https://github.com/SmooAI/config#readme",
6
6
  "bugs": {
@@ -86,9 +86,13 @@
86
86
  "zod": "^4.0.0"
87
87
  },
88
88
  "peerDependencies": {
89
+ "next": ">=14.0.0",
89
90
  "react": "^18.0.0 || ^19.0.0"
90
91
  },
91
92
  "peerDependenciesMeta": {
93
+ "next": {
94
+ "optional": true
95
+ },
92
96
  "react": {
93
97
  "optional": true
94
98
  }
@@ -98,7 +102,7 @@
98
102
  "build:lib": "pnpm create-entry-points -i \"src/**/*.ts\" -x \"src/cli/**\" && pnpm tsup",
99
103
  "build:cli": "tsup --config tsup.cli.config.ts",
100
104
  "check-all": "pnpm run typecheck && pnpm run lint && pnpm run format:check && pnpm run test && pnpm run python:typecheck && pnpm run python:lint && pnpm run python:format:check && pnpm run rust:fmt:check && pnpm run rust:lint && pnpm run rust:test && pnpm run go:fmt:check && pnpm run go:lint && pnpm run go:test && pnpm run build",
101
- "ci:publish": "pnpm build && pnpm changeset publish && pnpm run version:sync",
105
+ "ci:publish": "pnpm build && pnpm changeset publish",
102
106
  "format": "oxfmt --write . && pnpm run python:format && pnpm run rust:fmt && pnpm run go:fmt",
103
107
  "lint": "oxlint --ignore-pattern .sst --ignore-pattern .pulumi . && pnpm run python:lint && pnpm run rust:lint && pnpm run go:lint",
104
108
  "lint:fix": "oxlint --ignore-pattern .sst --ignore-pattern .pulumi --fix .",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/react/hooks.ts","../src/react/ConfigProvider.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport { useConfigClient } from './ConfigProvider';\n\ninterface UseConfigResult<T = unknown> {\n /** The resolved config value, or undefined while loading. */\n value: T | undefined;\n /** True while the initial fetch is in progress. */\n isLoading: boolean;\n /** The error if the fetch failed. */\n error: Error | null;\n /** Re-fetch the value (bypasses cache). */\n refetch: () => void;\n}\n\nfunction useConfigValue(key: string, environment?: string): UseConfigResult {\n const client = useConfigClient();\n const [value, setValue] = useState<unknown>(undefined);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [fetchCount, setFetchCount] = useState(0);\n\n const refetch = useCallback(() => {\n client.invalidateCache();\n setFetchCount((c) => c + 1);\n }, [client]);\n\n useEffect(() => {\n let cancelled = false;\n setIsLoading(true);\n setError(null);\n\n client\n .getValue(key, environment)\n .then((result) => {\n if (!cancelled) {\n setValue(result);\n setIsLoading(false);\n }\n })\n .catch((err: unknown) => {\n if (!cancelled) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsLoading(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [client, key, environment, fetchCount]);\n\n return { value, isLoading, error, refetch };\n}\n\n/**\n * Fetch a public config value by key.\n *\n * ```tsx\n * const { value, isLoading, error } = usePublicConfig('API_URL');\n * ```\n */\nexport function usePublicConfig<T = unknown>(key: string, environment?: string): UseConfigResult<T> {\n return useConfigValue(key, environment) as UseConfigResult<T>;\n}\n\n/**\n * Fetch a secret config value by key.\n *\n * ```tsx\n * const { value, isLoading } = useSecretConfig('DATABASE_URL');\n * ```\n */\nexport function useSecretConfig<T = unknown>(key: string, environment?: string): UseConfigResult<T> {\n return useConfigValue(key, environment) as UseConfigResult<T>;\n}\n\n/**\n * Fetch a feature flag value by key.\n *\n * ```tsx\n * const { value: enableNewUI } = useFeatureFlag<boolean>('ENABLE_NEW_UI');\n * ```\n */\nexport function useFeatureFlag<T = unknown>(key: string, environment?: string): UseConfigResult<T> {\n return useConfigValue(key, environment) as UseConfigResult<T>;\n}\n","'use client';\n\nimport { createContext, useContext, useMemo, type ReactNode } from 'react';\nimport { ConfigClient, type ConfigClientOptions } from '../platform/client';\n\nconst ConfigContext = createContext<ConfigClient | null>(null);\n\nexport interface ConfigProviderProps extends ConfigClientOptions {\n children: ReactNode;\n}\n\n/**\n * Provides a ConfigClient instance to all descendant components.\n *\n * ```tsx\n * <ConfigProvider baseUrl=\"https://api.smooai.dev\" apiKey=\"...\" orgId=\"...\" environment=\"production\">\n * <App />\n * </ConfigProvider>\n * ```\n *\n * All props are optional if the corresponding environment variables are set:\n * SMOOAI_CONFIG_API_URL, SMOOAI_CONFIG_API_KEY, SMOOAI_CONFIG_ORG_ID, SMOOAI_CONFIG_ENV\n */\nexport function ConfigProvider({ children, ...options }: ConfigProviderProps) {\n const client = useMemo(() => new ConfigClient(options), [options.baseUrl, options.apiKey, options.orgId, options.environment]);\n\n return <ConfigContext.Provider value={client}>{children}</ConfigContext.Provider>;\n}\n\n/**\n * Access the ConfigClient instance from the nearest ConfigProvider.\n * Throws if used outside a ConfigProvider.\n */\nexport function useConfigClient(): ConfigClient {\n const client = useContext(ConfigContext);\n if (!client) {\n throw new Error('useConfigClient must be used within a <ConfigProvider>');\n }\n return client;\n}\n"],"mappings":";;;;;AAEA,SAAS,aAAa,WAAW,gBAAgB;;;ACAjD,SAAS,eAAe,YAAY,eAA+B;AAwBxD;AArBX,IAAM,gBAAgB,cAAmC,IAAI;AAkBtD,SAAS,eAAe,EAAE,UAAU,GAAG,QAAQ,GAAwB;AAC1E,QAAM,SAAS,QAAQ,MAAM,IAAI,aAAa,OAAO,GAAG,CAAC,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,WAAW,CAAC;AAE7H,SAAO,oBAAC,cAAc,UAAd,EAAuB,OAAO,QAAS,UAAS;AAC5D;AAMO,SAAS,kBAAgC;AAC5C,QAAM,SAAS,WAAW,aAAa;AACvC,MAAI,CAAC,QAAQ;AACT,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC5E;AACA,SAAO;AACX;;;ADvBA,SAAS,eAAe,KAAa,aAAuC;AACxE,QAAM,SAAS,gBAAgB;AAC/B,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAkB,MAAS;AACrD,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,IAAI;AAC/C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAuB,IAAI;AACrD,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,CAAC;AAE9C,QAAM,UAAU,YAAY,MAAM;AAC9B,WAAO,gBAAgB;AACvB,kBAAc,CAAC,MAAM,IAAI,CAAC;AAAA,EAC9B,GAAG,CAAC,MAAM,CAAC;AAEX,YAAU,MAAM;AACZ,QAAI,YAAY;AAChB,iBAAa,IAAI;AACjB,aAAS,IAAI;AAEb,WACK,SAAS,KAAK,WAAW,EACzB,KAAK,CAAC,WAAW;AACd,UAAI,CAAC,WAAW;AACZ,iBAAS,MAAM;AACf,qBAAa,KAAK;AAAA,MACtB;AAAA,IACJ,CAAC,EACA,MAAM,CAAC,QAAiB;AACrB,UAAI,CAAC,WAAW;AACZ,iBAAS,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAC5D,qBAAa,KAAK;AAAA,MACtB;AAAA,IACJ,CAAC;AAEL,WAAO,MAAM;AACT,kBAAY;AAAA,IAChB;AAAA,EACJ,GAAG,CAAC,QAAQ,KAAK,aAAa,UAAU,CAAC;AAEzC,SAAO,EAAE,OAAO,WAAW,OAAO,QAAQ;AAC9C;AASO,SAAS,gBAA6B,KAAa,aAA0C;AAChG,SAAO,eAAe,KAAK,WAAW;AAC1C;AASO,SAAS,gBAA6B,KAAa,aAA0C;AAChG,SAAO,eAAe,KAAK,WAAW;AAC1C;AASO,SAAS,eAA4B,KAAa,aAA0C;AAC/F,SAAO,eAAe,KAAK,WAAW;AAC1C;","names":[]}