@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 @@
1
+ {"version":3,"sources":["../../src/nextjs/getConfig.ts","../../src/platform/client.ts"],"sourcesContent":["import { ConfigClient, type ConfigClientOptions } from '../platform/client';\n\nexport interface GetConfigOptions extends ConfigClientOptions {\n /** Config keys to fetch. If omitted, fetches all values for the environment. */\n keys?: string[];\n /** Additional fetch options passed to the underlying HTTP call (e.g., Next.js `{ next: { revalidate: 60 } }`). */\n fetchOptions?: RequestInit;\n}\n\n/**\n * Server-side helper for fetching config values in Next.js Server Components or `getServerSideProps`.\n *\n * ```tsx\n * // app/layout.tsx (Server Component)\n * import { getConfig } from '@smooai/config/nextjs';\n *\n * export default async function RootLayout({ children }) {\n * const config = await getConfig({\n * environment: 'production',\n * fetchOptions: { next: { revalidate: 60 } },\n * });\n * return (\n * <SmooConfigProvider initialValues={config}>\n * {children}\n * </SmooConfigProvider>\n * );\n * }\n * ```\n */\nexport async function getConfig(options: GetConfigOptions = {}): Promise<Record<string, unknown>> {\n const { keys, fetchOptions, ...clientOptions } = options;\n const client = new ConfigClient(clientOptions);\n\n if (keys && keys.length > 0) {\n const result: Record<string, unknown> = {};\n await Promise.all(\n keys.map(async (key) => {\n result[key] = await client.getValue(key, clientOptions.environment);\n }),\n );\n return result;\n }\n\n return client.getAllValues(clientOptions.environment, fetchOptions);\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,9 @@
1
+ import {
2
+ getConfig
3
+ } from "../chunk-FAF45VZA.mjs";
4
+ import "../chunk-3B5SRHJ2.mjs";
5
+ import "../chunk-J5LGTIGS.mjs";
6
+ export {
7
+ getConfig
8
+ };
9
+ //# sourceMappingURL=getConfig.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,22 @@
1
+ interface UseConfigResult<T = unknown> {
2
+ /** The resolved config value, or undefined while loading (synchronous when pre-seeded). */
3
+ value: T | undefined;
4
+ /** True while the initial fetch is in progress. False immediately if value was pre-seeded. */
5
+ isLoading: boolean;
6
+ /** The error if the fetch failed. */
7
+ error: Error | null;
8
+ /** Re-fetch the value (bypasses cache). */
9
+ refetch: () => void;
10
+ }
11
+ /**
12
+ * SSR-aware hook for fetching a public config value.
13
+ * Returns the value synchronously when pre-seeded via `SmooConfigProvider`.
14
+ */
15
+ declare function usePublicConfig<T = unknown>(key: string, environment?: string): UseConfigResult<T>;
16
+ /**
17
+ * SSR-aware hook for fetching a feature flag value.
18
+ * Returns the value synchronously when pre-seeded via `SmooConfigProvider`.
19
+ */
20
+ declare function useFeatureFlag<T = unknown>(key: string, environment?: string): UseConfigResult<T>;
21
+
22
+ export { useFeatureFlag, usePublicConfig };
@@ -0,0 +1,22 @@
1
+ interface UseConfigResult<T = unknown> {
2
+ /** The resolved config value, or undefined while loading (synchronous when pre-seeded). */
3
+ value: T | undefined;
4
+ /** True while the initial fetch is in progress. False immediately if value was pre-seeded. */
5
+ isLoading: boolean;
6
+ /** The error if the fetch failed. */
7
+ error: Error | null;
8
+ /** Re-fetch the value (bypasses cache). */
9
+ refetch: () => void;
10
+ }
11
+ /**
12
+ * SSR-aware hook for fetching a public config value.
13
+ * Returns the value synchronously when pre-seeded via `SmooConfigProvider`.
14
+ */
15
+ declare function usePublicConfig<T = unknown>(key: string, environment?: string): UseConfigResult<T>;
16
+ /**
17
+ * SSR-aware hook for fetching a feature flag value.
18
+ * Returns the value synchronously when pre-seeded via `SmooConfigProvider`.
19
+ */
20
+ declare function useFeatureFlag<T = unknown>(key: string, environment?: string): UseConfigResult<T>;
21
+
22
+ export { useFeatureFlag, usePublicConfig };
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ "use client";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/nextjs/hooks.ts
22
+ var hooks_exports = {};
23
+ __export(hooks_exports, {
24
+ useFeatureFlag: () => useFeatureFlag,
25
+ usePublicConfig: () => usePublicConfig
26
+ });
27
+ module.exports = __toCommonJS(hooks_exports);
28
+ var import_react2 = require("react");
29
+
30
+ // src/react/ConfigProvider.tsx
31
+ var import_react = require("react");
32
+ var import_jsx_runtime = require("react/jsx-runtime");
33
+ var ConfigContext = (0, import_react.createContext)(null);
34
+ function useConfigClient() {
35
+ const client = (0, import_react.useContext)(ConfigContext);
36
+ if (!client) {
37
+ throw new Error("useConfigClient must be used within a <ConfigProvider>");
38
+ }
39
+ return client;
40
+ }
41
+
42
+ // src/nextjs/hooks.ts
43
+ function useConfigValue(key, environment) {
44
+ const client = useConfigClient();
45
+ const [value, setValue] = (0, import_react2.useState)(() => client.getCachedValue(key, environment));
46
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(value === void 0);
47
+ const [error, setError] = (0, import_react2.useState)(null);
48
+ const [fetchCount, setFetchCount] = (0, import_react2.useState)(0);
49
+ const refetch = (0, import_react2.useCallback)(() => {
50
+ client.invalidateCache();
51
+ setFetchCount((c) => c + 1);
52
+ }, [client]);
53
+ (0, import_react2.useEffect)(() => {
54
+ if (value !== void 0 && fetchCount === 0) {
55
+ setIsLoading(false);
56
+ return;
57
+ }
58
+ let cancelled = false;
59
+ setIsLoading(true);
60
+ setError(null);
61
+ client.getValue(key, environment).then((result) => {
62
+ if (!cancelled) {
63
+ setValue(result);
64
+ setIsLoading(false);
65
+ }
66
+ }).catch((err) => {
67
+ if (!cancelled) {
68
+ setError(err instanceof Error ? err : new Error(String(err)));
69
+ setIsLoading(false);
70
+ }
71
+ });
72
+ return () => {
73
+ cancelled = true;
74
+ };
75
+ }, [client, key, environment, fetchCount]);
76
+ return { value, isLoading, error, refetch };
77
+ }
78
+ function usePublicConfig(key, environment) {
79
+ return useConfigValue(key, environment);
80
+ }
81
+ function useFeatureFlag(key, environment) {
82
+ return useConfigValue(key, environment);
83
+ }
84
+ // Annotate the CommonJS export names for ESM import in node:
85
+ 0 && (module.exports = {
86
+ useFeatureFlag,
87
+ usePublicConfig
88
+ });
89
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/nextjs/hooks.ts","../../src/react/ConfigProvider.tsx"],"sourcesContent":["'use client';\n\nimport { useCallback, useEffect, useState } from 'react';\nimport { useConfigClient } from '../react/ConfigProvider';\n\ninterface UseConfigResult<T = unknown> {\n /** The resolved config value, or undefined while loading (synchronous when pre-seeded). */\n value: T | undefined;\n /** True while the initial fetch is in progress. False immediately if value was pre-seeded. */\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\n // Attempt synchronous read from pre-seeded cache (zero loading flash)\n const [value, setValue] = useState<unknown>(() => client.getCachedValue(key, environment));\n const [isLoading, setIsLoading] = useState(value === undefined);\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 // If we already have a cached value and this is the initial mount, skip fetch\n if (value !== undefined && fetchCount === 0) {\n setIsLoading(false);\n return;\n }\n\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 * SSR-aware hook for fetching a public config value.\n * Returns the value synchronously when pre-seeded via `SmooConfigProvider`.\n */\nexport function usePublicConfig<T = unknown>(key: string, environment?: string): UseConfigResult<T> {\n return useConfigValue(key, environment) as UseConfigResult<T>;\n}\n\n/**\n * SSR-aware hook for fetching a feature flag value.\n * Returns the value synchronously when pre-seeded via `SmooConfigProvider`.\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\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"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAAA,gBAAiD;;;ACAjD,mBAAmE;AAwBxD;AArBJ,IAAM,oBAAgB,4BAAmC,IAAI;AA4B7D,SAAS,kBAAgC;AAC5C,QAAM,aAAS,yBAAW,aAAa;AACvC,MAAI,CAAC,QAAQ;AACT,UAAM,IAAI,MAAM,wDAAwD;AAAA,EAC5E;AACA,SAAO;AACX;;;ADvBA,SAAS,eAAe,KAAa,aAAuC;AACxE,QAAM,SAAS,gBAAgB;AAG/B,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAkB,MAAM,OAAO,eAAe,KAAK,WAAW,CAAC;AACzF,QAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,UAAU,MAAS;AAC9D,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AACrD,QAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,CAAC;AAE9C,QAAM,cAAU,2BAAY,MAAM;AAC9B,WAAO,gBAAgB;AACvB,kBAAc,CAAC,MAAM,IAAI,CAAC;AAAA,EAC9B,GAAG,CAAC,MAAM,CAAC;AAEX,+BAAU,MAAM;AAEZ,QAAI,UAAU,UAAa,eAAe,GAAG;AACzC,mBAAa,KAAK;AAClB;AAAA,IACJ;AAEA,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;AAMO,SAAS,gBAA6B,KAAa,aAA0C;AAChG,SAAO,eAAe,KAAK,WAAW;AAC1C;AAMO,SAAS,eAA4B,KAAa,aAA0C;AAC/F,SAAO,eAAe,KAAK,WAAW;AAC1C;","names":["import_react"]}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import {
3
+ useFeatureFlag,
4
+ usePublicConfig
5
+ } from "../chunk-GP2JUWOD.mjs";
6
+ import "../chunk-N6Z4AZZA.mjs";
7
+ import "../chunk-3B5SRHJ2.mjs";
8
+ import "../chunk-J5LGTIGS.mjs";
9
+ export {
10
+ useFeatureFlag,
11
+ usePublicConfig
12
+ };
13
+ //# sourceMappingURL=hooks.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,28 @@
1
+ export { GetConfigOptions, getConfig } from './getConfig.mjs';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import { ReactNode } from 'react';
4
+ import { ConfigClientOptions } from '../platform/client.mjs';
5
+ export { useFeatureFlag, usePublicConfig } from './hooks.mjs';
6
+
7
+ interface SmooConfigProviderProps extends ConfigClientOptions {
8
+ /** Initial config values fetched on the server (from `getConfig()`). Pre-seeds the client cache. */
9
+ initialValues?: Record<string, unknown>;
10
+ children: ReactNode;
11
+ }
12
+ /**
13
+ * Client Component that provides a pre-seeded ConfigClient, eliminating loading
14
+ * flashes on first render when used with server-fetched `initialValues`.
15
+ *
16
+ * ```tsx
17
+ * // layout.tsx (Server Component)
18
+ * const config = await getConfig({ environment: 'production' });
19
+ *
20
+ * // Client boundary
21
+ * <SmooConfigProvider initialValues={config} environment="production" {...clientOptions}>
22
+ * <App />
23
+ * </SmooConfigProvider>
24
+ * ```
25
+ */
26
+ declare function SmooConfigProvider({ initialValues, children, ...options }: SmooConfigProviderProps): react_jsx_runtime.JSX.Element;
27
+
28
+ export { SmooConfigProvider, type SmooConfigProviderProps };
@@ -0,0 +1,28 @@
1
+ export { GetConfigOptions, getConfig } from './getConfig.js';
2
+ import * as react_jsx_runtime from 'react/jsx-runtime';
3
+ import { ReactNode } from 'react';
4
+ import { ConfigClientOptions } from '../platform/client.js';
5
+ export { useFeatureFlag, usePublicConfig } from './hooks.js';
6
+
7
+ interface SmooConfigProviderProps extends ConfigClientOptions {
8
+ /** Initial config values fetched on the server (from `getConfig()`). Pre-seeds the client cache. */
9
+ initialValues?: Record<string, unknown>;
10
+ children: ReactNode;
11
+ }
12
+ /**
13
+ * Client Component that provides a pre-seeded ConfigClient, eliminating loading
14
+ * flashes on first render when used with server-fetched `initialValues`.
15
+ *
16
+ * ```tsx
17
+ * // layout.tsx (Server Component)
18
+ * const config = await getConfig({ environment: 'production' });
19
+ *
20
+ * // Client boundary
21
+ * <SmooConfigProvider initialValues={config} environment="production" {...clientOptions}>
22
+ * <App />
23
+ * </SmooConfigProvider>
24
+ * ```
25
+ */
26
+ declare function SmooConfigProvider({ initialValues, children, ...options }: SmooConfigProviderProps): react_jsx_runtime.JSX.Element;
27
+
28
+ export { SmooConfigProvider, type SmooConfigProviderProps };
@@ -0,0 +1,255 @@
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/nextjs/index.ts
21
+ var nextjs_exports = {};
22
+ __export(nextjs_exports, {
23
+ SmooConfigProvider: () => SmooConfigProvider,
24
+ getConfig: () => getConfig,
25
+ useFeatureFlag: () => useFeatureFlag,
26
+ usePublicConfig: () => usePublicConfig
27
+ });
28
+ module.exports = __toCommonJS(nextjs_exports);
29
+
30
+ // src/platform/client.ts
31
+ function getEnv(key) {
32
+ if (typeof process !== "undefined" && process.env) {
33
+ return process.env[key];
34
+ }
35
+ return void 0;
36
+ }
37
+ var ConfigClient = class {
38
+ baseUrl;
39
+ orgId;
40
+ apiKey;
41
+ defaultEnvironment;
42
+ cacheTtlMs;
43
+ cache = /* @__PURE__ */ new Map();
44
+ constructor(options = {}) {
45
+ const baseUrl = options.baseUrl ?? getEnv("SMOOAI_CONFIG_API_URL");
46
+ const apiKey = options.apiKey ?? getEnv("SMOOAI_CONFIG_API_KEY");
47
+ const orgId = options.orgId ?? getEnv("SMOOAI_CONFIG_ORG_ID");
48
+ if (!baseUrl) throw new Error("@smooai/config: baseUrl is required (or set SMOOAI_CONFIG_API_URL)");
49
+ if (!apiKey) throw new Error("@smooai/config: apiKey is required (or set SMOOAI_CONFIG_API_KEY)");
50
+ if (!orgId) throw new Error("@smooai/config: orgId is required (or set SMOOAI_CONFIG_ORG_ID)");
51
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
52
+ this.apiKey = apiKey;
53
+ this.orgId = orgId;
54
+ this.defaultEnvironment = options.environment ?? getEnv("SMOOAI_CONFIG_ENV") ?? "development";
55
+ this.cacheTtlMs = options.cacheTtlMs ?? 0;
56
+ }
57
+ computeExpiresAt() {
58
+ return this.cacheTtlMs > 0 ? Date.now() + this.cacheTtlMs : 0;
59
+ }
60
+ getCached(cacheKey) {
61
+ const entry = this.cache.get(cacheKey);
62
+ if (!entry) return void 0;
63
+ if (entry.expiresAt > 0 && Date.now() > entry.expiresAt) {
64
+ this.cache.delete(cacheKey);
65
+ return void 0;
66
+ }
67
+ return entry.value;
68
+ }
69
+ async fetchJson(path, fetchOptions) {
70
+ const response = await fetch(`${this.baseUrl}${path}`, {
71
+ ...fetchOptions,
72
+ headers: { Authorization: `Bearer ${this.apiKey}`, ...fetchOptions?.headers }
73
+ });
74
+ if (!response.ok) {
75
+ throw new Error(`Config API error: HTTP ${response.status} ${response.statusText}`);
76
+ }
77
+ return response.json();
78
+ }
79
+ /**
80
+ * Get a single config value by key.
81
+ * Results are cached locally after the first fetch.
82
+ */
83
+ async getValue(key, environment) {
84
+ const env = environment ?? this.defaultEnvironment;
85
+ const cacheKey = `${env}:${key}`;
86
+ const cached = this.getCached(cacheKey);
87
+ if (cached !== void 0) {
88
+ return cached;
89
+ }
90
+ const result = await this.fetchJson(
91
+ `/organizations/${this.orgId}/config/values/${encodeURIComponent(key)}?environment=${encodeURIComponent(env)}`
92
+ );
93
+ this.cache.set(cacheKey, { value: result.value, expiresAt: this.computeExpiresAt() });
94
+ return result.value;
95
+ }
96
+ /**
97
+ * Get all config values for an environment.
98
+ * All returned values are cached locally.
99
+ * @param environment - Environment name (defaults to constructor option or SMOOAI_CONFIG_ENV)
100
+ * @param fetchOptions - Optional fetch options (e.g., Next.js `{ next: { revalidate: 60 } }`)
101
+ */
102
+ async getAllValues(environment, fetchOptions) {
103
+ const env = environment ?? this.defaultEnvironment;
104
+ const result = await this.fetchJson(
105
+ `/organizations/${this.orgId}/config/values?environment=${encodeURIComponent(env)}`,
106
+ fetchOptions
107
+ );
108
+ const expiresAt = this.computeExpiresAt();
109
+ for (const [key, value] of Object.entries(result.values)) {
110
+ this.cache.set(`${env}:${key}`, { value, expiresAt });
111
+ }
112
+ return result.values;
113
+ }
114
+ /**
115
+ * Pre-populate a single cache entry (e.g., from SSR).
116
+ * Does not make a network request.
117
+ */
118
+ seedCache(key, value, environment) {
119
+ const env = environment ?? this.defaultEnvironment;
120
+ this.cache.set(`${env}:${key}`, { value, expiresAt: this.computeExpiresAt() });
121
+ }
122
+ /**
123
+ * Pre-populate multiple cache entries from a key-value map (e.g., from SSR).
124
+ * Does not make a network request.
125
+ */
126
+ seedCacheFromMap(values, environment) {
127
+ const env = environment ?? this.defaultEnvironment;
128
+ const expiresAt = this.computeExpiresAt();
129
+ for (const [key, value] of Object.entries(values)) {
130
+ this.cache.set(`${env}:${key}`, { value, expiresAt });
131
+ }
132
+ }
133
+ /**
134
+ * Synchronously read a value from the local cache without making a network request.
135
+ * Returns `undefined` if the key is not cached or has expired.
136
+ */
137
+ getCachedValue(key, environment) {
138
+ const env = environment ?? this.defaultEnvironment;
139
+ return this.getCached(`${env}:${key}`);
140
+ }
141
+ /** Clear the entire local cache. */
142
+ invalidateCache() {
143
+ this.cache.clear();
144
+ }
145
+ /** Clear cached values for a specific environment. */
146
+ invalidateCacheForEnvironment(environment) {
147
+ const prefix = `${environment}:`;
148
+ for (const key of this.cache.keys()) {
149
+ if (key.startsWith(prefix)) {
150
+ this.cache.delete(key);
151
+ }
152
+ }
153
+ }
154
+ };
155
+
156
+ // src/nextjs/getConfig.ts
157
+ async function getConfig(options = {}) {
158
+ const { keys, fetchOptions, ...clientOptions } = options;
159
+ const client = new ConfigClient(clientOptions);
160
+ if (keys && keys.length > 0) {
161
+ const result = {};
162
+ await Promise.all(
163
+ keys.map(async (key) => {
164
+ result[key] = await client.getValue(key, clientOptions.environment);
165
+ })
166
+ );
167
+ return result;
168
+ }
169
+ return client.getAllValues(clientOptions.environment, fetchOptions);
170
+ }
171
+
172
+ // src/nextjs/SmooConfigProvider.tsx
173
+ var import_react2 = require("react");
174
+
175
+ // src/react/ConfigProvider.tsx
176
+ var import_react = require("react");
177
+ var import_jsx_runtime = require("react/jsx-runtime");
178
+ var ConfigContext = (0, import_react.createContext)(null);
179
+ function useConfigClient() {
180
+ const client = (0, import_react.useContext)(ConfigContext);
181
+ if (!client) {
182
+ throw new Error("useConfigClient must be used within a <ConfigProvider>");
183
+ }
184
+ return client;
185
+ }
186
+
187
+ // src/nextjs/SmooConfigProvider.tsx
188
+ var import_jsx_runtime2 = require("react/jsx-runtime");
189
+ function SmooConfigProvider({ initialValues, children, ...options }) {
190
+ const client = (0, import_react2.useMemo)(() => {
191
+ const c = new ConfigClient(options);
192
+ if (initialValues) {
193
+ c.seedCacheFromMap(initialValues, options.environment);
194
+ }
195
+ return c;
196
+ }, [options.baseUrl, options.apiKey, options.orgId, options.environment]);
197
+ (0, import_react2.useEffect)(() => {
198
+ if (initialValues) {
199
+ client.seedCacheFromMap(initialValues, options.environment);
200
+ }
201
+ }, [initialValues, client, options.environment]);
202
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ConfigContext.Provider, { value: client, children });
203
+ }
204
+
205
+ // src/nextjs/hooks.ts
206
+ var import_react3 = require("react");
207
+ function useConfigValue(key, environment) {
208
+ const client = useConfigClient();
209
+ const [value, setValue] = (0, import_react3.useState)(() => client.getCachedValue(key, environment));
210
+ const [isLoading, setIsLoading] = (0, import_react3.useState)(value === void 0);
211
+ const [error, setError] = (0, import_react3.useState)(null);
212
+ const [fetchCount, setFetchCount] = (0, import_react3.useState)(0);
213
+ const refetch = (0, import_react3.useCallback)(() => {
214
+ client.invalidateCache();
215
+ setFetchCount((c) => c + 1);
216
+ }, [client]);
217
+ (0, import_react3.useEffect)(() => {
218
+ if (value !== void 0 && fetchCount === 0) {
219
+ setIsLoading(false);
220
+ return;
221
+ }
222
+ let cancelled = false;
223
+ setIsLoading(true);
224
+ setError(null);
225
+ client.getValue(key, environment).then((result) => {
226
+ if (!cancelled) {
227
+ setValue(result);
228
+ setIsLoading(false);
229
+ }
230
+ }).catch((err) => {
231
+ if (!cancelled) {
232
+ setError(err instanceof Error ? err : new Error(String(err)));
233
+ setIsLoading(false);
234
+ }
235
+ });
236
+ return () => {
237
+ cancelled = true;
238
+ };
239
+ }, [client, key, environment, fetchCount]);
240
+ return { value, isLoading, error, refetch };
241
+ }
242
+ function usePublicConfig(key, environment) {
243
+ return useConfigValue(key, environment);
244
+ }
245
+ function useFeatureFlag(key, environment) {
246
+ return useConfigValue(key, environment);
247
+ }
248
+ // Annotate the CommonJS export names for ESM import in node:
249
+ 0 && (module.exports = {
250
+ SmooConfigProvider,
251
+ getConfig,
252
+ useFeatureFlag,
253
+ usePublicConfig
254
+ });
255
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/nextjs/index.ts","../../src/platform/client.ts","../../src/nextjs/getConfig.ts","../../src/nextjs/SmooConfigProvider.tsx","../../src/react/ConfigProvider.tsx","../../src/nextjs/hooks.ts"],"sourcesContent":["export { getConfig } from './getConfig';\nexport type { GetConfigOptions } from './getConfig';\nexport { SmooConfigProvider } from './SmooConfigProvider';\nexport type { SmooConfigProviderProps } from './SmooConfigProvider';\nexport { usePublicConfig, useFeatureFlag } from './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\nexport interface GetConfigOptions extends ConfigClientOptions {\n /** Config keys to fetch. If omitted, fetches all values for the environment. */\n keys?: string[];\n /** Additional fetch options passed to the underlying HTTP call (e.g., Next.js `{ next: { revalidate: 60 } }`). */\n fetchOptions?: RequestInit;\n}\n\n/**\n * Server-side helper for fetching config values in Next.js Server Components or `getServerSideProps`.\n *\n * ```tsx\n * // app/layout.tsx (Server Component)\n * import { getConfig } from '@smooai/config/nextjs';\n *\n * export default async function RootLayout({ children }) {\n * const config = await getConfig({\n * environment: 'production',\n * fetchOptions: { next: { revalidate: 60 } },\n * });\n * return (\n * <SmooConfigProvider initialValues={config}>\n * {children}\n * </SmooConfigProvider>\n * );\n * }\n * ```\n */\nexport async function getConfig(options: GetConfigOptions = {}): Promise<Record<string, unknown>> {\n const { keys, fetchOptions, ...clientOptions } = options;\n const client = new ConfigClient(clientOptions);\n\n if (keys && keys.length > 0) {\n const result: Record<string, unknown> = {};\n await Promise.all(\n keys.map(async (key) => {\n result[key] = await client.getValue(key, clientOptions.environment);\n }),\n );\n return result;\n }\n\n return client.getAllValues(clientOptions.environment, fetchOptions);\n}\n","'use client';\n\nimport { useEffect, useMemo, type ReactNode } from 'react';\nimport { ConfigClient, type ConfigClientOptions } from '../platform/client';\nimport { ConfigContext } from '../react/ConfigProvider';\n\nexport interface SmooConfigProviderProps extends ConfigClientOptions {\n /** Initial config values fetched on the server (from `getConfig()`). Pre-seeds the client cache. */\n initialValues?: Record<string, unknown>;\n children: ReactNode;\n}\n\n/**\n * Client Component that provides a pre-seeded ConfigClient, eliminating loading\n * flashes on first render when used with server-fetched `initialValues`.\n *\n * ```tsx\n * // layout.tsx (Server Component)\n * const config = await getConfig({ environment: 'production' });\n *\n * // Client boundary\n * <SmooConfigProvider initialValues={config} environment=\"production\" {...clientOptions}>\n * <App />\n * </SmooConfigProvider>\n * ```\n */\nexport function SmooConfigProvider({ initialValues, children, ...options }: SmooConfigProviderProps) {\n const client = useMemo(() => {\n const c = new ConfigClient(options);\n if (initialValues) {\n c.seedCacheFromMap(initialValues, options.environment);\n }\n return c;\n }, [options.baseUrl, options.apiKey, options.orgId, options.environment]);\n\n // Re-seed if initialValues change (e.g., after revalidation)\n useEffect(() => {\n if (initialValues) {\n client.seedCacheFromMap(initialValues, options.environment);\n }\n }, [initialValues, client, options.environment]);\n\n return <ConfigContext.Provider value={client}>{children}</ConfigContext.Provider>;\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 '../react/ConfigProvider';\n\ninterface UseConfigResult<T = unknown> {\n /** The resolved config value, or undefined while loading (synchronous when pre-seeded). */\n value: T | undefined;\n /** True while the initial fetch is in progress. False immediately if value was pre-seeded. */\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\n // Attempt synchronous read from pre-seeded cache (zero loading flash)\n const [value, setValue] = useState<unknown>(() => client.getCachedValue(key, environment));\n const [isLoading, setIsLoading] = useState(value === undefined);\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 // If we already have a cached value and this is the initial mount, skip fetch\n if (value !== undefined && fetchCount === 0) {\n setIsLoading(false);\n return;\n }\n\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 * SSR-aware hook for fetching a public config value.\n * Returns the value synchronously when pre-seeded via `SmooConfigProvider`.\n */\nexport function usePublicConfig<T = unknown>(key: string, environment?: string): UseConfigResult<T> {\n return useConfigValue(key, environment) as UseConfigResult<T>;\n}\n\n/**\n * SSR-aware hook for fetching a feature flag value.\n * Returns the value synchronously when pre-seeded via `SmooConfigProvider`.\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","import_jsx_runtime","import_react"]}
@@ -0,0 +1,40 @@
1
+ import {
2
+ getConfig
3
+ } from "../chunk-FAF45VZA.mjs";
4
+ import {
5
+ useFeatureFlag,
6
+ usePublicConfig
7
+ } from "../chunk-GP2JUWOD.mjs";
8
+ import {
9
+ ConfigContext
10
+ } from "../chunk-N6Z4AZZA.mjs";
11
+ import {
12
+ ConfigClient
13
+ } from "../chunk-3B5SRHJ2.mjs";
14
+ import "../chunk-J5LGTIGS.mjs";
15
+
16
+ // src/nextjs/SmooConfigProvider.tsx
17
+ import { useEffect, useMemo } from "react";
18
+ import { jsx } from "react/jsx-runtime";
19
+ function SmooConfigProvider({ initialValues, children, ...options }) {
20
+ const client = useMemo(() => {
21
+ const c = new ConfigClient(options);
22
+ if (initialValues) {
23
+ c.seedCacheFromMap(initialValues, options.environment);
24
+ }
25
+ return c;
26
+ }, [options.baseUrl, options.apiKey, options.orgId, options.environment]);
27
+ useEffect(() => {
28
+ if (initialValues) {
29
+ client.seedCacheFromMap(initialValues, options.environment);
30
+ }
31
+ }, [initialValues, client, options.environment]);
32
+ return /* @__PURE__ */ jsx(ConfigContext.Provider, { value: client, children });
33
+ }
34
+ export {
35
+ SmooConfigProvider,
36
+ getConfig,
37
+ useFeatureFlag,
38
+ usePublicConfig
39
+ };
40
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/nextjs/SmooConfigProvider.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useMemo, type ReactNode } from 'react';\nimport { ConfigClient, type ConfigClientOptions } from '../platform/client';\nimport { ConfigContext } from '../react/ConfigProvider';\n\nexport interface SmooConfigProviderProps extends ConfigClientOptions {\n /** Initial config values fetched on the server (from `getConfig()`). Pre-seeds the client cache. */\n initialValues?: Record<string, unknown>;\n children: ReactNode;\n}\n\n/**\n * Client Component that provides a pre-seeded ConfigClient, eliminating loading\n * flashes on first render when used with server-fetched `initialValues`.\n *\n * ```tsx\n * // layout.tsx (Server Component)\n * const config = await getConfig({ environment: 'production' });\n *\n * // Client boundary\n * <SmooConfigProvider initialValues={config} environment=\"production\" {...clientOptions}>\n * <App />\n * </SmooConfigProvider>\n * ```\n */\nexport function SmooConfigProvider({ initialValues, children, ...options }: SmooConfigProviderProps) {\n const client = useMemo(() => {\n const c = new ConfigClient(options);\n if (initialValues) {\n c.seedCacheFromMap(initialValues, options.environment);\n }\n return c;\n }, [options.baseUrl, options.apiKey, options.orgId, options.environment]);\n\n // Re-seed if initialValues change (e.g., after revalidation)\n useEffect(() => {\n if (initialValues) {\n client.seedCacheFromMap(initialValues, options.environment);\n }\n }, [initialValues, client, options.environment]);\n\n return <ConfigContext.Provider value={client}>{children}</ConfigContext.Provider>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAEA,SAAS,WAAW,eAA+B;AAwCxC;AAhBJ,SAAS,mBAAmB,EAAE,eAAe,UAAU,GAAG,QAAQ,GAA4B;AACjG,QAAM,SAAS,QAAQ,MAAM;AACzB,UAAM,IAAI,IAAI,aAAa,OAAO;AAClC,QAAI,eAAe;AACf,QAAE,iBAAiB,eAAe,QAAQ,WAAW;AAAA,IACzD;AACA,WAAO;AAAA,EACX,GAAG,CAAC,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,WAAW,CAAC;AAGxE,YAAU,MAAM;AACZ,QAAI,eAAe;AACf,aAAO,iBAAiB,eAAe,QAAQ,WAAW;AAAA,IAC9D;AAAA,EACJ,GAAG,CAAC,eAAe,QAAQ,QAAQ,WAAW,CAAC;AAE/C,SAAO,oBAAC,cAAc,UAAd,EAAuB,OAAO,QAAS,UAAS;AAC5D;","names":[]}
@@ -38,8 +38,25 @@ declare class ConfigClient {
38
38
  /**
39
39
  * Get all config values for an environment.
40
40
  * All returned values are cached locally.
41
+ * @param environment - Environment name (defaults to constructor option or SMOOAI_CONFIG_ENV)
42
+ * @param fetchOptions - Optional fetch options (e.g., Next.js `{ next: { revalidate: 60 } }`)
41
43
  */
42
- getAllValues(environment?: string): Promise<Record<string, unknown>>;
44
+ getAllValues(environment?: string, fetchOptions?: RequestInit): Promise<Record<string, unknown>>;
45
+ /**
46
+ * Pre-populate a single cache entry (e.g., from SSR).
47
+ * Does not make a network request.
48
+ */
49
+ seedCache(key: string, value: unknown, environment?: string): void;
50
+ /**
51
+ * Pre-populate multiple cache entries from a key-value map (e.g., from SSR).
52
+ * Does not make a network request.
53
+ */
54
+ seedCacheFromMap(values: Record<string, unknown>, environment?: string): void;
55
+ /**
56
+ * Synchronously read a value from the local cache without making a network request.
57
+ * Returns `undefined` if the key is not cached or has expired.
58
+ */
59
+ getCachedValue(key: string, environment?: string): unknown | undefined;
43
60
  /** Clear the entire local cache. */
44
61
  invalidateCache(): void;
45
62
  /** Clear cached values for a specific environment. */