@configdirector/nextjs-sdk 1.9.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.cjs +1 -1
- package/dist/client/index.d.cts +1 -1
- package/dist/client/index.d.mts +1 -1
- package/dist/client/index.mjs +1 -1
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/installedTestClient-CW29YuQC.cjs +6 -0
- package/dist/client/installedTestClient-CpjJvHZD.mjs +7 -0
- package/dist/client/installedTestClient-CpjJvHZD.mjs.map +1 -0
- package/dist/client/testing.cjs +1 -1
- package/dist/client/testing.d.cts +3 -2
- package/dist/client/testing.d.cts.map +1 -1
- package/dist/client/testing.d.mts +3 -2
- package/dist/client/testing.d.mts.map +1 -1
- package/dist/client/testing.mjs +1 -1
- package/dist/client/testing.mjs.map +1 -1
- package/dist/client/{types-fL7X5zwg.d.cts → types-Cz68hQ6f.d.cts} +35 -14
- package/dist/client/types-Cz68hQ6f.d.cts.map +1 -0
- package/dist/client/{types-DA2VZKNX.d.mts → types-De4z0tu4.d.mts} +35 -14
- package/dist/client/types-De4z0tu4.d.mts.map +1 -0
- package/dist/server/{DefaultConfigDirectorClient-ied5Boyk.mjs → DefaultConfigDirectorClient-BTTja_j3.mjs} +2 -2
- package/dist/server/DefaultConfigDirectorClient-BTTja_j3.mjs.map +1 -0
- package/dist/server/{DefaultConfigDirectorClient-Cf73kJBQ.cjs → DefaultConfigDirectorClient-CqXqwNpW.cjs} +1 -1
- package/dist/server/index.cjs +1 -1
- package/dist/server/index.d.cts +1 -1
- package/dist/server/index.d.cts.map +1 -1
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.mts.map +1 -1
- package/dist/server/index.mjs +1 -1
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/testing.cjs +1 -1
- package/dist/server/testing.d.cts +4 -2
- package/dist/server/testing.d.cts.map +1 -1
- package/dist/server/testing.d.mts +4 -2
- package/dist/server/testing.d.mts.map +1 -1
- package/dist/server/testing.mjs +1 -1
- package/dist/server/testing.mjs.map +1 -1
- package/dist/server/{types-DnzM2ukj.d.cts → types-BBEEMV5Y.d.cts} +23 -10
- package/dist/server/types-BBEEMV5Y.d.cts.map +1 -0
- package/dist/server/{types-qIeNbtNf.d.mts → types-B_mGbQaa.d.mts} +23 -10
- package/dist/server/types-B_mGbQaa.d.mts.map +1 -0
- package/package.json +1 -1
- package/dist/client/installedTestClient-CDdDsfVQ.mjs +0 -7
- package/dist/client/installedTestClient-CDdDsfVQ.mjs.map +0 -1
- package/dist/client/installedTestClient-DH7rRR-J.cjs +0 -6
- package/dist/client/types-DA2VZKNX.d.mts.map +0 -1
- package/dist/client/types-fL7X5zwg.d.cts.map +0 -1
- package/dist/server/DefaultConfigDirectorClient-ied5Boyk.mjs.map +0 -1
- package/dist/server/types-DnzM2ukj.d.cts.map +0 -1
- package/dist/server/types-qIeNbtNf.d.mts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["ClientProvider"],"sources":["../../src/server/logger.ts","../../src/server/singleton.ts","../../src/server/ssr.ts","../../src/server/ConfigDirectorProvider.tsx"],"sourcesContent":["import { DefaultConsoleLogger } from \"@shared/logger\";\nimport type { ConfigDirectorLoggingLevel, ConfigDirectorLogMessageDecorator } from \"@shared/types\";\n\nclass LogMessageDecorator implements ConfigDirectorLogMessageDecorator {\n decorateMessage(message: string): string {\n return `[ConfigDirector:nextjs-sdk] ${message}`;\n }\n}\n\nexport const createDefaultLogger = (\n level?: ConfigDirectorLoggingLevel,\n messageDecorator?: ConfigDirectorLogMessageDecorator,\n) => {\n return new DefaultConsoleLogger(level ?? \"warn\", messageDecorator ?? new LogMessageDecorator());\n};\n\nexport const createConsoleLogger = (\n level: ConfigDirectorLoggingLevel,\n messageDecorator?: ConfigDirectorLogMessageDecorator,\n) => {\n return new DefaultConsoleLogger(level, messageDecorator ?? new LogMessageDecorator());\n};\n","import type { ConfigDirectorClient, ConfigDirectorClientOptions } from \"@js-server-sdk/types\";\nimport { createDefaultLogger } from \"./logger\";\nimport { ConfigDirectorInitializationError } from \"@shared/errors\";\n\ndeclare global {\n var __configDirectorServerClient: ConfigDirectorClient | undefined;\n var __configDirectorAppMeta: { appName?: string; appVersion?: string } | undefined;\n}\n\nexport type RegisterOptions = {\n /**\n * Your ConfigDirector Server SDK key. This is a secret value — do not commit it to source\n * control. Provide it via an environment variable (e.g. process.env.CONFIGDIRECTOR_SERVER_KEY).\n */\n serverSdkKey: string;\n} & ConfigDirectorClientOptions;\n\n/**\n * Initializes the ConfigDirector server SDK singleton. Call this from your Next.js\n * `instrumentation.ts` file so it runs once when the server starts:\n *\n * ```ts\n * // instrumentation.ts\n * export async function register() {\n * const { register } = await import(\"@configdirector/nextjs-sdk/server\");\n * await register({ serverSdkKey: process.env.CONFIGDIRECTOR_SERVER_KEY! });\n * }\n * ```\n */\nexport async function register(options: RegisterOptions): Promise<void> {\n if (process.env[\"NEXT_RUNTIME\"] !== \"nodejs\") {\n return;\n }\n\n if (!options.serverSdkKey) {\n const message =\n \"The ConfigDirector serverSdkKey must be provided to register(). You can pass it via process.env.CONFIGDIRECTOR_SERVER_KEY.\";\n createDefaultLogger().error(message);\n throw new ConfigDirectorInitializationError(message);\n }\n\n if (!globalThis.__configDirectorServerClient) {\n const { DefaultConfigDirectorClient } = await import(\"@js-server-sdk/DefaultConfigDirectorClient\");\n const { serverSdkKey, ...clientOptions } = options;\n globalThis.__configDirectorAppMeta = {\n appName: options.metadata?.appName,\n appVersion: options.metadata?.appVersion,\n };\n const client = new DefaultConfigDirectorClient(\n serverSdkKey,\n { sdkName: \"nextjs-sdk\", sdkVersion: \"__VERSION__\" },\n clientOptions,\n );\n globalThis.__configDirectorServerClient = client;\n await client.initialize();\n }\n}\n\nexport function getAppMeta(): { appName?: string; appVersion?: string } {\n return globalThis.__configDirectorAppMeta ?? {};\n}\n\nexport function getConfigClient(): ConfigDirectorClient {\n if (!globalThis.__configDirectorServerClient) {\n throw new ConfigDirectorInitializationError(\n \"[ConfigDirector] Server client not initialized. Make sure to call register() in your instrumentation.ts file before using the SDK.\",\n );\n }\n return globalThis.__configDirectorServerClient;\n}\n","import type { ConfigDirectorContext, ConfigState } from \"@js-server-sdk/types\";\nimport { getConfigClient } from \"./singleton\";\nimport { createDefaultLogger } from \"./logger\";\n\nconst logger = createDefaultLogger();\n\nexport type GenerateSsrConfigSetOptions = {\n /** User context for targeting rule evaluation. */\n context?: ConfigDirectorContext;\n /**\n * Restrict the returned config set to these keys. When omitted, all known configs are\n * returned. Useful when you want to pre-evaluate only a specific subset of flags.\n */\n configKeys?: string[];\n};\n\n/**\n * Evaluates configs server-side and returns a map of {@link ConfigState} objects keyed by\n * config key, suitable for passing as `initialConfigs` to `ConfigDirectorProvider`.\n *\n * Returns an empty object when the server SDK isn't initialized yet (e.g. during\n * `next build` static analysis without a live connection).\n *\n * In most cases you don't need this directly — use the `ConfigDirectorProvider` exported\n * from `@configdirector/nextjs-sdk/server`, which calls this automatically.\n */\nexport function generateSsrConfigSet(options?: GenerateSsrConfigSetOptions): Record<string, ConfigState> {\n try {\n return getConfigClient().getAllConfigs(options);\n } catch (error) {\n logger.error(\"Error retrieving SSR config set:\", error);\n return {};\n }\n}\n","import type { PropsWithChildren } from \"react\";\nimport { ConfigDirectorProvider as ClientProvider } from \"@configdirector/nextjs-sdk/client\";\nimport type { ConfigDirectorProviderOptions } from \"../client/types\";\nimport { generateSsrConfigSet } from \"./ssr\";\nimport { getAppMeta } from \"./singleton\";\n\n/**\n * Props for {@link ConfigDirectorProvider}. Identical to the client provider options\n * except `initialConfigs` is omitted — SSR-evaluated values are injected automatically.\n */\nexport type ConfigDirectorProviderProps = Omit<ConfigDirectorProviderOptions, \"initialConfigs\"> & {\n /**\n * Restrict SSR pre-evaluation to these config keys. When omitted, all known configs are\n * pre-evaluated. Useful when you have a large config set and only need a subset hydrated\n * on this layout.\n */\n configKeys?: string[];\n};\n\n/**\n * React Server Component wrapper around the ConfigDirector client provider.\n *\n * Place this in your root layout. It pre-evaluates all configs on the server using the\n * provided context and passes them to the client provider, preventing any flash of wrong\n * content on hydration.\n *\n * Requires Next.js 13+ (App Router) and React 18+.\n *\n * Read `sdkKey` from a plain environment variable (e.g. `CONFIGDIRECTOR_CLIENT_KEY`), NOT one\n * prefixed with `NEXT_PUBLIC_` — even here, inside a Server Component. Next.js substitutes\n * `NEXT_PUBLIC_*` references with a literal string at compile time wherever they appear in\n * code it bundles, with no exemption for Server Components; that permanently freezes the\n * value into the build artifact the moment you reference it here, regardless of the two\n * deployment strategies below. A plain variable, by contrast, is read live from `process.env`\n * — its resolved value (not the variable lookup itself) is what gets passed as a prop to the\n * client provider below, which is how it safely reaches the browser without ever being baked\n * into the bundle as source.\n *\n * **Deploying one build artifact to multiple environments (e.g. one Docker image promoted\n * from staging to prod):** a plain variable is only read fresh per request if this component's\n * render actually re-runs on each request — otherwise Next.js still statically prerenders the\n * route once at build time and caches the output to a static HTML file, silently freezing\n * whichever value was set at build time. Make sure your root layout either reads a per-request\n * API like `cookies()` (as below, which forces dynamic rendering as a side effect) or adds\n * `export const dynamic = \"force-dynamic\";` if it doesn't otherwise need one. The trade-off is\n * that the route loses static generation/ISR caching, since it now renders on every request.\n *\n * **Building a separate artifact per environment:** if you'd rather keep static generation\n * (and are fine building once per environment, e.g. as a distinct step per env in CI), no\n * layout changes are needed — a plain environment variable set at build time is read once and\n * baked into the static output for that build, same as `NEXT_PUBLIC_` would be, just without\n * also exposing it to arbitrary client-side code that isn't a descendant of this provider.\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { ConfigDirectorProvider } from \"@configdirector/nextjs-sdk/server\";\n * import { cookies } from \"next/headers\";\n *\n * export default async function RootLayout({ children }) {\n * const userId = (await cookies()).get(\"userId\")?.value;\n * return (\n * <html>\n * <body>\n * <ConfigDirectorProvider\n * sdkKey={process.env.CONFIGDIRECTOR_CLIENT_KEY!}\n * context={{ userId }}\n * >\n * {children}\n * </ConfigDirectorProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport async function ConfigDirectorProvider({\n children,\n configKeys,\n ...props\n}: PropsWithChildren<ConfigDirectorProviderProps>) {\n const initialConfigs = generateSsrConfigSet({ context: props.context, configKeys });\n const appMeta = getAppMeta();\n return (\n <ClientProvider\n {...props}\n appName={props.appName ?? appMeta.appName}\n appVersion={props.appVersion ?? appMeta.appVersion}\n initialConfigs={initialConfigs}>\n {children}\n </ClientProvider>\n );\n}\n"],"mappings":"oKAGA,IAAM,EAAN,KAAuE,CACrE,gBAAgB,EAAyB,CACvC,MAAO,+BAA+B,MAI1C,MAAa,GACX,EACA,IAEO,IAAI,EAAqB,GAAS,OAAQ,GAAoB,IAAI,EAAsB,CAGpF,GACX,EACA,IAEO,IAAI,EAAqB,EAAO,GAAoB,IAAI,EAAsB,CCSvF,eAAsB,EAAS,EAAyC,CAClE,WAAQ,IAAI,eAAoB,SAIpC,IAAI,CAAC,EAAQ,aAAc,CACzB,IAAM,EACJ,6HAEF,MADA,GAAqB,CAAC,MAAM,EAAQ,CAC9B,IAAI,EAAkC,EAAQ,CAGtD,GAAI,CAAC,WAAW,6BAA8B,CAC5C,GAAM,CAAE,+BAAgC,MAAM,OAAO,8CAAA,KAAA,GAAA,EAAA,EAAA,CAC/C,CAAE,eAAc,GAAG,GAAkB,EAC3C,WAAW,wBAA0B,CACnC,QAAS,EAAQ,UAAU,QAC3B,WAAY,EAAQ,UAAU,WAC/B,CACD,IAAM,EAAS,IAAI,EACjB,EACA,CAAE,QAAS,aAAc,WAAY,QAAe,CACpD,EACD,CACD,WAAW,6BAA+B,EAC1C,MAAM,EAAO,YAAY,GAI7B,SAAgB,GAAwD,CACtE,OAAO,WAAW,yBAA2B,EAAE,CAGjD,SAAgB,GAAwC,CACtD,GAAI,CAAC,WAAW,6BACd,MAAM,IAAI,EACR,qIACD,CAEH,OAAO,WAAW,6BChEpB,MAAM,EAAS,GAAqB,CAsBpC,SAAgB,EAAqB,EAAoE,CACvG,GAAI,CACF,OAAO,GAAiB,CAAC,cAAc,EAAQ,OACxC,EAAO,CAEd,OADA,EAAO,MAAM,mCAAoC,EAAM,CAChD,EAAE,EC6Cb,eAAsB,EAAuB,CAC3C,WACA,aACA,GAAG,GAC8C,CACjD,IAAM,EAAiB,EAAqB,CAAE,QAAS,EAAM,QAAS,aAAY,CAAC,CAC7E,EAAU,GAAY,CAC5B,OACE,EAACA,EAAD,CACE,GAAI,EACJ,QAAS,EAAM,SAAW,EAAQ,QAClC,WAAY,EAAM,YAAc,EAAQ,WACxB,iBACf,WACc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["ClientProvider"],"sources":["../../src/server/logger.ts","../../src/server/singleton.ts","../../src/server/ssr.ts","../../src/server/ConfigDirectorProvider.tsx"],"sourcesContent":["import { DefaultConsoleLogger } from \"@shared/logger\";\nimport type { ConfigDirectorLoggingLevel, ConfigDirectorLogMessageDecorator } from \"@shared/types\";\n\nclass LogMessageDecorator implements ConfigDirectorLogMessageDecorator {\n decorateMessage(message: string): string {\n return `[ConfigDirector:nextjs-sdk] ${message}`;\n }\n}\n\nexport const createDefaultLogger = (\n level?: ConfigDirectorLoggingLevel,\n messageDecorator?: ConfigDirectorLogMessageDecorator,\n) => {\n return new DefaultConsoleLogger(level ?? \"warn\", messageDecorator ?? new LogMessageDecorator());\n};\n\nexport const createConsoleLogger = (\n level: ConfigDirectorLoggingLevel,\n messageDecorator?: ConfigDirectorLogMessageDecorator,\n) => {\n return new DefaultConsoleLogger(level, messageDecorator ?? new LogMessageDecorator());\n};\n","import type { ConfigDirectorClient, ConfigDirectorClientOptions } from \"@js-server-sdk/types\";\nimport { createDefaultLogger } from \"./logger\";\nimport { ConfigDirectorInitializationError } from \"@shared/errors\";\n\ndeclare global {\n var __configDirectorServerClient: ConfigDirectorClient | undefined;\n var __configDirectorAppMeta: { appName?: string; appVersion?: string } | undefined;\n}\n\nexport type RegisterOptions = {\n /**\n * Your ConfigDirector Server SDK key. This is a secret value — do not commit it to source\n * control. Provide it via an environment variable (e.g. process.env.CONFIGDIRECTOR_SERVER_KEY).\n */\n serverSdkKey: string;\n} & ConfigDirectorClientOptions;\n\n/**\n * Initializes the ConfigDirector server SDK singleton. Call this from your Next.js\n * `instrumentation.ts` file so it runs once when the server starts:\n *\n * ```ts\n * // instrumentation.ts\n * export async function register() {\n * const { register } = await import(\"@configdirector/nextjs-sdk/server\");\n * await register({ serverSdkKey: process.env.CONFIGDIRECTOR_SERVER_KEY! });\n * }\n * ```\n */\nexport async function register(options: RegisterOptions): Promise<void> {\n if (process.env[\"NEXT_RUNTIME\"] !== \"nodejs\") {\n return;\n }\n\n if (!options.serverSdkKey) {\n const message =\n \"The ConfigDirector serverSdkKey must be provided to register(). You can pass it via process.env.CONFIGDIRECTOR_SERVER_KEY.\";\n createDefaultLogger().error(message);\n throw new ConfigDirectorInitializationError(message);\n }\n\n if (!globalThis.__configDirectorServerClient) {\n const { DefaultConfigDirectorClient } = await import(\"@js-server-sdk/DefaultConfigDirectorClient\");\n const { serverSdkKey, ...clientOptions } = options;\n globalThis.__configDirectorAppMeta = {\n appName: options.metadata?.appName,\n appVersion: options.metadata?.appVersion,\n };\n const client = new DefaultConfigDirectorClient(\n serverSdkKey,\n { sdkName: \"nextjs-sdk\", sdkVersion: \"__VERSION__\" },\n clientOptions,\n );\n globalThis.__configDirectorServerClient = client;\n await client.initialize();\n }\n}\n\nexport function getAppMeta(): { appName?: string; appVersion?: string } {\n return globalThis.__configDirectorAppMeta ?? {};\n}\n\nexport function getConfigClient(): ConfigDirectorClient {\n if (!globalThis.__configDirectorServerClient) {\n throw new ConfigDirectorInitializationError(\n \"[ConfigDirector] Server client not initialized. Make sure to call register() in your instrumentation.ts file before using the SDK.\",\n );\n }\n return globalThis.__configDirectorServerClient;\n}\n","import type { ConfigDirectorContext, ConfigState } from \"@js-server-sdk/types\";\nimport { getConfigClient } from \"./singleton\";\nimport { createDefaultLogger } from \"./logger\";\n\nconst logger = createDefaultLogger();\n\nexport type GenerateSsrConfigSetOptions = {\n /** User context for targeting rule evaluation. */\n context?: ConfigDirectorContext;\n /**\n * Restrict the returned config set to these keys. When omitted, all known configs are\n * returned. Useful when you want to pre-evaluate only a specific subset of flags.\n */\n configKeys?: string[];\n};\n\n/**\n * Evaluates configs server-side and returns a map of {@link ConfigState} objects keyed by\n * config key, suitable for passing as `initialConfigs` to `ConfigDirectorProvider`.\n *\n * Returns an empty object when the server SDK isn't initialized yet (e.g. during\n * `next build` static analysis without a live connection).\n *\n * In most cases you don't need this directly — use the `ConfigDirectorProvider` exported\n * from `@configdirector/nextjs-sdk/server`, which calls this automatically.\n */\nexport function generateSsrConfigSet(options?: GenerateSsrConfigSetOptions): Record<string, ConfigState> {\n try {\n return getConfigClient().getAllConfigs(options);\n } catch (error) {\n logger.error(\"Error retrieving SSR config set:\", error);\n return {};\n }\n}\n","import type { PropsWithChildren } from \"react\";\nimport { ConfigDirectorProvider as ClientProvider } from \"@configdirector/nextjs-sdk/client\";\nimport type { ConfigDirectorProviderOptions } from \"../client/types\";\nimport { generateSsrConfigSet } from \"./ssr\";\nimport { getAppMeta } from \"./singleton\";\n\n/**\n * Props for {@link ConfigDirectorProvider}. Identical to the client provider options\n * except `initialConfigs` is omitted — SSR-evaluated values are injected automatically.\n */\nexport type ConfigDirectorProviderProps = Omit<ConfigDirectorProviderOptions, \"initialConfigs\"> & {\n /**\n * Restrict SSR pre-evaluation to these config keys. When omitted, all known configs are\n * pre-evaluated. Useful when you have a large config set and only need a subset hydrated\n * on this layout.\n */\n configKeys?: string[];\n};\n\n/**\n * React Server Component wrapper around the ConfigDirector client provider.\n *\n * Place this in your root layout. It pre-evaluates all configs on the server using the\n * provided context and passes them to the client provider, preventing any flash of wrong\n * content on hydration.\n *\n * Requires Next.js 13+ (App Router) and React 18+.\n *\n * Read `sdkKey` from a plain environment variable (e.g. `CONFIGDIRECTOR_CLIENT_KEY`), NOT one\n * prefixed with `NEXT_PUBLIC_` — even here, inside a Server Component. Next.js substitutes\n * `NEXT_PUBLIC_*` references with a literal string at compile time wherever they appear in\n * code it bundles, with no exemption for Server Components; that permanently freezes the\n * value into the build artifact the moment you reference it here, regardless of the two\n * deployment strategies below. A plain variable, by contrast, is read live from `process.env`\n * — its resolved value (not the variable lookup itself) is what gets passed as a prop to the\n * client provider below, which is how it safely reaches the browser without ever being baked\n * into the bundle as source.\n *\n * **Deploying one build artifact to multiple environments (e.g. one Docker image promoted\n * from staging to prod):** a plain variable is only read fresh per request if this component's\n * render actually re-runs on each request — otherwise Next.js still statically prerenders the\n * route once at build time and caches the output to a static HTML file, silently freezing\n * whichever value was set at build time. Make sure your root layout either reads a per-request\n * API like `cookies()` (as below, which forces dynamic rendering as a side effect) or adds\n * `export const dynamic = \"force-dynamic\";` if it doesn't otherwise need one. The trade-off is\n * that the route loses static generation/ISR caching, since it now renders on every request.\n *\n * **Building a separate artifact per environment:** if you'd rather keep static generation\n * (and are fine building once per environment, e.g. as a distinct step per env in CI), no\n * layout changes are needed — a plain environment variable set at build time is read once and\n * baked into the static output for that build, same as `NEXT_PUBLIC_` would be, just without\n * also exposing it to arbitrary client-side code that isn't a descendant of this provider.\n *\n * @example\n * ```tsx\n * // app/layout.tsx\n * import { ConfigDirectorProvider } from \"@configdirector/nextjs-sdk/server\";\n * import { cookies } from \"next/headers\";\n *\n * export default async function RootLayout({ children }) {\n * const userId = (await cookies()).get(\"userId\")?.value;\n * return (\n * <html>\n * <body>\n * <ConfigDirectorProvider\n * sdkKey={process.env.CONFIGDIRECTOR_CLIENT_KEY!}\n * context={{ userId }}\n * >\n * {children}\n * </ConfigDirectorProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport async function ConfigDirectorProvider({\n children,\n configKeys,\n ...props\n}: PropsWithChildren<ConfigDirectorProviderProps>) {\n const initialConfigs = generateSsrConfigSet({ context: props.context, configKeys });\n const appMeta = getAppMeta();\n return (\n <ClientProvider\n {...props}\n appName={props.appName ?? appMeta.appName}\n appVersion={props.appVersion ?? appMeta.appVersion}\n initialConfigs={initialConfigs}>\n {children}\n </ClientProvider>\n );\n}\n"],"mappings":"oKAGA,IAAM,EAAN,KAAuE,CACrE,gBAAgB,EAAyB,CACvC,MAAO,+BAA+B,MAI1C,MAAa,GACX,EACA,IAEO,IAAI,EAAqB,GAAS,OAAQ,GAAoB,IAAI,EAAsB,CAGpF,GACX,EACA,IAEO,IAAI,EAAqB,EAAO,GAAoB,IAAI,EAAsB,CCSvF,eAAsB,EAAS,EAAyC,CAClE,WAAQ,IAAI,eAAoB,SAIpC,IAAI,CAAC,EAAQ,aAAc,CACzB,IAAM,EACJ,6HAEF,MADA,GAAqB,CAAC,MAAM,EAAQ,CAC9B,IAAI,EAAkC,EAAQ,CAGtD,GAAI,CAAC,WAAW,6BAA8B,CAC5C,GAAM,CAAE,+BAAgC,MAAM,OAAO,8CAAA,KAAA,GAAA,EAAA,EAAA,CAC/C,CAAE,eAAc,GAAG,GAAkB,EAC3C,WAAW,wBAA0B,CACnC,QAAS,EAAQ,UAAU,QAC3B,WAAY,EAAQ,UAAU,WAC/B,CACD,IAAM,EAAS,IAAI,EACjB,EACA,CAAE,QAAS,aAAc,WAAY,SAAe,CACpD,EACD,CACD,WAAW,6BAA+B,EAC1C,MAAM,EAAO,YAAY,GAI7B,SAAgB,GAAwD,CACtE,OAAO,WAAW,yBAA2B,EAAE,CAGjD,SAAgB,GAAwC,CACtD,GAAI,CAAC,WAAW,6BACd,MAAM,IAAI,EACR,qIACD,CAEH,OAAO,WAAW,6BChEpB,MAAM,EAAS,GAAqB,CAsBpC,SAAgB,EAAqB,EAAoE,CACvG,GAAI,CACF,OAAO,GAAiB,CAAC,cAAc,EAAQ,OACxC,EAAO,CAEd,OADA,EAAO,MAAM,mCAAoC,EAAM,CAChD,EAAE,EC6Cb,eAAsB,EAAuB,CAC3C,WACA,aACA,GAAG,GAC8C,CACjD,IAAM,EAAiB,EAAqB,CAAE,QAAS,EAAM,QAAS,aAAY,CAAC,CAC7E,EAAU,GAAY,CAC5B,OACE,EAACA,EAAD,CACE,GAAI,EACJ,QAAS,EAAM,SAAW,EAAQ,QAClC,WAAY,EAAM,YAAc,EAAQ,WACxB,iBACf,WACc,CAAA"}
|
package/dist/server/testing.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./DefaultConfigDirectorClient-
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./DefaultConfigDirectorClient-CqXqwNpW.cjs`),t=require(`./errors-CCbuIqT8.cjs`);let n=require(`node:events`);n=e.i(n);const r=(e,n)=>{if(e.trim().length==0)throw new t.r(`Invalid config key. The key of a test value cannot be empty.`);return i(e,n)},i=(e,n)=>{switch(typeof n){case`boolean`:return{type:`boolean`,value:n?`true`:`false`};case`number`:return a(e,n);case`string`:return{type:`string`,value:n};case`object`:if(n!==null)return s(e,n,``),{type:`json`,value:JSON.stringify(n)}}throw new t.r(`Invalid test value for '${e}': ${u(n)}. Use a boolean, a number, a string, a plain object, or an array.`)},a=(e,n)=>{if(!Number.isFinite(n))throw new t.r(`Invalid test value for '${e}': ${u(n)} is not a finite number.`);if(Number.isInteger(n)){if(!Number.isSafeInteger(n))throw new t.r(`Invalid test value for '${e}': ${n} is not a safe integer, so the SDK could not read it back exactly.`);return{type:`integer`,value:String(n)}}return{type:`float`,value:o(n)}},o=e=>{let t=String(e),n=t.indexOf(`e-`);if(n<0)return t;let r=t.startsWith(`-`)?`-`:``,[i=``,a=``]=t.slice(r.length,n).split(`.`),o=Number(t.slice(n+2))-i.length;return`${r}0.${`0`.repeat(o)}${i}${a}`},s=(e,t,n)=>{if(!(t===null||typeof t==`boolean`||typeof t==`string`)){if(typeof t==`number`){if(!Number.isFinite(t))throw c(e,n,`${u(t)} is not a finite number`);return}if(Array.isArray(t)){t.forEach((t,r)=>s(e,t,`${n}[${r}]`));return}if(l(t)){for(let[r,i]of Object.entries(t))s(e,i,n?`${n}.${r}`:r);return}throw c(e,n,`${u(t)} cannot be encoded as JSON`)}},c=(e,n,r)=>new t.r(`Invalid test value for '${e}'${n?` at '${n}'`:``}: ${r}. JSON contents can hold booleans, finite numbers, strings, null, arrays, and plain objects.`),l=e=>{if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},u=e=>e===null?`null`:typeof e==`function`?`a function`:typeof e==`object`?`a ${e.constructor?.name??`object`} instance`:typeof e==`symbol`?`a symbol`:String(e),d=(e,t)=>{let n=r(e,t);return{id:`test-config:${e}`,key:e,type:n.type,variations:[{name:null,value:n.value}],target:{defaultValue:n.value,rules:[]}}},f={environmentId:`test-environment`,projectId:`test-project`};var p=class{constructor(e,t){this.logger=e,this.emitter=new n.default,this.configs=new Map,this.pendingDeliveries=[],this.armed=`nothing`,this.connected=!1,this.delivering=!1,this.encodeAll(t).forEach((e,t)=>this.configs.set(t,e))}setValue(e,t){let n=d(e,t);this.configs.set(e,n),this.deliverIfConnected({...f,kind:`delta`,configs:{[e]:n}})}removeValue(e){this.configs.delete(e),this.deliverIfConnected(this.fullUpdate())}replaceValues(e){let t=this.encodeAll(e);this.configs.clear(),t.forEach((e,t)=>this.configs.set(t,e)),this.armed=`nothing`,this.deliverIfConnected(this.fullUpdate())}hold(){this.armed=`hold`}complete(){this.pendingHold?this.pendingHold.complete():this.armed===`hold`&&(this.armed=`nothing`)}fail(){this.pendingHold?this.pendingHold.fail():this.armed=`failure`}connect(e){this.endAttempt();let t=this.armed;switch(this.armed=`nothing`,t){case`failure`:return this.failNow();case`hold`:return this.holdNow(e);default:return this.connectNow(),Promise.resolve(this)}}get isConnected(){return this.connected}on(e,t){this.emitter.on(e,t)}off(e,t){t?this.emitter.off(e,t):this.emitter.removeAllListeners(e)}close(){this.endAttempt()}dispose(){this.close(),this.emitter.removeAllListeners()}endAttempt(){this.connected=!1,this.pendingHold?.end()}connectNow(){this.connected=!0,this.deliver(this.fullUpdate())}holdNow(e){return new Promise((t,n)=>{let r=setTimeout(()=>this.pendingHold?.end(),e),i=()=>{clearTimeout(r),this.pendingHold=void 0};this.pendingHold={end:()=>{i(),t(this)},complete:()=>{i(),this.connectNow(),t(this)},fail:()=>{i();let e=this.fatalError();this.emitter.emit(`connectionError`,e),n(e)}}})}failNow(){let e=this.fatalError();return this.emitter.emit(`connectionError`,e),Promise.reject(e)}fatalError(){return new t.t(`Connection failed with status: 401. Error: the test client failed this initialization. This is an unrecoverable error, will not attempt to reconnect.`,401)}deliverIfConnected(e){this.connected&&this.deliver(e)}deliver(e){if(this.pendingDeliveries.push(e),!this.delivering){this.delivering=!0;try{let e=this.pendingDeliveries.shift();for(;e;)this.emitCaught(e),e=this.pendingDeliveries.shift()}finally{this.delivering=!1}}}emitCaught(e){try{this.emitter.emit(`configBundleReceived`,e)}catch(e){this.logger.error(`[InMemoryConnection] Error dispatching a config update from the test client: `,e)}}fullUpdate(){return{...f,kind:`full`,configs:Object.fromEntries(this.configs)}}encodeAll(e){let t=new Map;for(let[n,r]of Object.entries(e))t.set(n,d(n,r));return t}};const m={start:()=>{},evaluatedConfig:()=>{},recordInvalidContext:()=>`new-kind-sample`,close:async()=>{}};var h=class{constructor(e,t){this.client=e,this.connection=t}setValue(e,t){this.connection.setValue(e,t)}removeValue(e){this.connection.removeValue(e)}replaceValues(e){this.connection.replaceValues(e)}holdInitialization(){this.connection.hold()}completeInitialization(){this.connection.complete()}failInitialization(){this.connection.fail()}};const g=(t,n)=>{let r=n?.logger??e.r(),i=new p(r,n?.values??{});return new h(new e.t(`test-client`,t,{logger:r,connection:{timeout:n?.timeout}},{transport:i,telemetry:m}),i)},_=e=>g({sdkName:`nextjs-sdk`,sdkVersion:`1.10.0`},e),v=e=>{let t=globalThis.__configDirectorServerClient;return globalThis.__configDirectorServerClient=e.client,()=>{globalThis.__configDirectorServerClient=t}};exports.ConfigDirectorConnectionError=t.t,exports.ConfigDirectorValidationError=t.r,exports.createTestClient=_,exports.installServerTestClient=v;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ConfigDirectorLogger, t as ConfigDirectorClient } from "./types-
|
|
1
|
+
import { a as ConfigDirectorLogger, t as ConfigDirectorClient } from "./types-BBEEMV5Y.cjs";
|
|
2
2
|
|
|
3
3
|
//#region ../shared/src/errors.d.ts
|
|
4
4
|
declare class ConfigDirectorConnectionError extends Error {
|
|
@@ -38,7 +38,9 @@ type TestClientOptions = {
|
|
|
38
38
|
*/
|
|
39
39
|
timeout?: number;
|
|
40
40
|
/**
|
|
41
|
-
* The logger the SDK client uses. Defaults to the SDK's console logger at `warn` level.
|
|
41
|
+
* The logger the SDK client uses. Defaults to the SDK's console logger at `warn` level. Since
|
|
42
|
+
* the test client sends no telemetry, every read that supplies a context with an invalid kind
|
|
43
|
+
* logs an error, rather than each invalid kind once per telemetry interval.
|
|
42
44
|
*/
|
|
43
45
|
logger?: ConfigDirectorLogger;
|
|
44
46
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.cts","names":[],"sources":["../../../shared/src/errors.ts","../../../shared/src/testing/values.ts","../../../js-server-sdk/src/testing/TestClient.ts","../../src/server/testing.ts"],"mappings":";;;cAAa,6BAAA,SAAsC,KAAA;EAAA,SACxB,IAAA;EAAA,SACT,MAAA;cAEJ,OAAA,UAAiB,MAAA;AAAA;AAAA,cAQlB,6BAAA,SAAsC,KAAA;EAAA,SACxB,IAAA;cAEb,OAAA;AAAA;;;KCZF,aAAA,sCAAmD,aAAA;EAAA,CAAqB,GAAA,WAAc,aAAA;AAAA;AAAA,KAEtF,SAAA,+BAAwC,aAAA;EAAA,CAAqB,GAAA,WAAc,aAAA;AAAA;AAAA,KAE3E,UAAA,GAAa,MAAA,SAAe,SAAA;;;;ADPxC;;KEYY,iBAAA;EFZ4C;;;;;;EEmBtD,MAAA,GAAS,UAAA;EFfmC;;AAQ9C;;EEYE,OAAA;EFZsD
|
|
1
|
+
{"version":3,"file":"testing.d.cts","names":[],"sources":["../../../shared/src/errors.ts","../../../shared/src/testing/values.ts","../../../js-server-sdk/src/testing/TestClient.ts","../../src/server/testing.ts"],"mappings":";;;cAAa,6BAAA,SAAsC,KAAA;EAAA,SACxB,IAAA;EAAA,SACT,MAAA;cAEJ,OAAA,UAAiB,MAAA;AAAA;AAAA,cAQlB,6BAAA,SAAsC,KAAA;EAAA,SACxB,IAAA;cAEb,OAAA;AAAA;;;KCZF,aAAA,sCAAmD,aAAA;EAAA,CAAqB,GAAA,WAAc,aAAA;AAAA;AAAA,KAEtF,SAAA,+BAAwC,aAAA;EAAA,CAAqB,GAAA,WAAc,aAAA;AAAA;AAAA,KAE3E,UAAA,GAAa,MAAA,SAAe,SAAA;;;;ADPxC;;KEYY,iBAAA;EFZ4C;;;;;;EEmBtD,MAAA,GAAS,UAAA;EFfmC;;AAQ9C;;EEYE,OAAA;EFZsD;;;;;EEkBtD,MAAA,GAAS,oBAAA;AAAA;;;;AD3BX;;;;;UCsCiB,UAAA;EDtCiF;;;AAElG;EAFkG,SC2CvF,MAAA,EAAQ,oBAAA;;;;;EAMjB,QAAA,CAAS,GAAA,UAAa,KAAA,EAAO,SAAA;ED/CqE;;AAEpG;;ECmDE,WAAA,CAAY,GAAA;EDnDW;;;;ECyDvB,aAAA,CAAc,MAAA,EAAQ,UAAA;EApDZ;;;;EA0DV,kBAAA;EAnDS;;;;EAyDT,sBAAA;EA9C6B;AAW/B;;;EAyCE,kBAAA;AAAA;;;;;;;;;;;;;;AFtEF;;;;cGUa,gBAAA,GAAoB,OAAA,GAAU,iBAAA,KAAoB,UAAA;;;;;;;;;cAYlD,uBAAA,GAA2B,UAAA,EAAY,UAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ConfigDirectorLogger, t as ConfigDirectorClient } from "./types-
|
|
1
|
+
import { a as ConfigDirectorLogger, t as ConfigDirectorClient } from "./types-B_mGbQaa.mjs";
|
|
2
2
|
|
|
3
3
|
//#region ../shared/src/errors.d.ts
|
|
4
4
|
declare class ConfigDirectorConnectionError extends Error {
|
|
@@ -38,7 +38,9 @@ type TestClientOptions = {
|
|
|
38
38
|
*/
|
|
39
39
|
timeout?: number;
|
|
40
40
|
/**
|
|
41
|
-
* The logger the SDK client uses. Defaults to the SDK's console logger at `warn` level.
|
|
41
|
+
* The logger the SDK client uses. Defaults to the SDK's console logger at `warn` level. Since
|
|
42
|
+
* the test client sends no telemetry, every read that supplies a context with an invalid kind
|
|
43
|
+
* logs an error, rather than each invalid kind once per telemetry interval.
|
|
42
44
|
*/
|
|
43
45
|
logger?: ConfigDirectorLogger;
|
|
44
46
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.mts","names":[],"sources":["../../../shared/src/errors.ts","../../../shared/src/testing/values.ts","../../../js-server-sdk/src/testing/TestClient.ts","../../src/server/testing.ts"],"mappings":";;;cAAa,6BAAA,SAAsC,KAAA;EAAA,SACxB,IAAA;EAAA,SACT,MAAA;cAEJ,OAAA,UAAiB,MAAA;AAAA;AAAA,cAQlB,6BAAA,SAAsC,KAAA;EAAA,SACxB,IAAA;cAEb,OAAA;AAAA;;;KCZF,aAAA,sCAAmD,aAAA;EAAA,CAAqB,GAAA,WAAc,aAAA;AAAA;AAAA,KAEtF,SAAA,+BAAwC,aAAA;EAAA,CAAqB,GAAA,WAAc,aAAA;AAAA;AAAA,KAE3E,UAAA,GAAa,MAAA,SAAe,SAAA;;;;ADPxC;;KEYY,iBAAA;EFZ4C;;;;;;EEmBtD,MAAA,GAAS,UAAA;EFfmC;;AAQ9C;;EEYE,OAAA;EFZsD
|
|
1
|
+
{"version":3,"file":"testing.d.mts","names":[],"sources":["../../../shared/src/errors.ts","../../../shared/src/testing/values.ts","../../../js-server-sdk/src/testing/TestClient.ts","../../src/server/testing.ts"],"mappings":";;;cAAa,6BAAA,SAAsC,KAAA;EAAA,SACxB,IAAA;EAAA,SACT,MAAA;cAEJ,OAAA,UAAiB,MAAA;AAAA;AAAA,cAQlB,6BAAA,SAAsC,KAAA;EAAA,SACxB,IAAA;cAEb,OAAA;AAAA;;;KCZF,aAAA,sCAAmD,aAAA;EAAA,CAAqB,GAAA,WAAc,aAAA;AAAA;AAAA,KAEtF,SAAA,+BAAwC,aAAA;EAAA,CAAqB,GAAA,WAAc,aAAA;AAAA;AAAA,KAE3E,UAAA,GAAa,MAAA,SAAe,SAAA;;;;ADPxC;;KEYY,iBAAA;EFZ4C;;;;;;EEmBtD,MAAA,GAAS,UAAA;EFfmC;;AAQ9C;;EEYE,OAAA;EFZsD;;;;;EEkBtD,MAAA,GAAS,oBAAA;AAAA;;;;AD3BX;;;;;UCsCiB,UAAA;EDtCiF;;;AAElG;EAFkG,SC2CvF,MAAA,EAAQ,oBAAA;;;;;EAMjB,QAAA,CAAS,GAAA,UAAa,KAAA,EAAO,SAAA;ED/CqE;;AAEpG;;ECmDE,WAAA,CAAY,GAAA;EDnDW;;;;ECyDvB,aAAA,CAAc,MAAA,EAAQ,UAAA;EApDZ;;;;EA0DV,kBAAA;EAnDS;;;;EAyDT,sBAAA;EA9C6B;AAW/B;;;EAyCE,kBAAA;AAAA;;;;;;;;;;;;;;AFtEF;;;;cGUa,gBAAA,GAAoB,OAAA,GAAU,iBAAA,KAAoB,UAAA;;;;;;;;;cAYlD,uBAAA,GAA2B,UAAA,EAAY,UAAA"}
|
package/dist/server/testing.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{r as e,t}from"./DefaultConfigDirectorClient-
|
|
1
|
+
import{r as e,t}from"./DefaultConfigDirectorClient-BTTja_j3.mjs";import{r as n,t as r}from"./errors-BGpFuqOO.mjs";import i from"node:events";const a=(e,t)=>{if(e.trim().length==0)throw new n(`Invalid config key. The key of a test value cannot be empty.`);return o(e,t)},o=(e,t)=>{switch(typeof t){case`boolean`:return{type:`boolean`,value:t?`true`:`false`};case`number`:return s(e,t);case`string`:return{type:`string`,value:t};case`object`:if(t!==null)return l(e,t,``),{type:`json`,value:JSON.stringify(t)}}throw new n(`Invalid test value for '${e}': ${f(t)}. Use a boolean, a number, a string, a plain object, or an array.`)},s=(e,t)=>{if(!Number.isFinite(t))throw new n(`Invalid test value for '${e}': ${f(t)} is not a finite number.`);if(Number.isInteger(t)){if(!Number.isSafeInteger(t))throw new n(`Invalid test value for '${e}': ${t} is not a safe integer, so the SDK could not read it back exactly.`);return{type:`integer`,value:String(t)}}return{type:`float`,value:c(t)}},c=e=>{let t=String(e),n=t.indexOf(`e-`);if(n<0)return t;let r=t.startsWith(`-`)?`-`:``,[i=``,a=``]=t.slice(r.length,n).split(`.`),o=Number(t.slice(n+2))-i.length;return`${r}0.${`0`.repeat(o)}${i}${a}`},l=(e,t,n)=>{if(!(t===null||typeof t==`boolean`||typeof t==`string`)){if(typeof t==`number`){if(!Number.isFinite(t))throw u(e,n,`${f(t)} is not a finite number`);return}if(Array.isArray(t)){t.forEach((t,r)=>l(e,t,`${n}[${r}]`));return}if(d(t)){for(let[r,i]of Object.entries(t))l(e,i,n?`${n}.${r}`:r);return}throw u(e,n,`${f(t)} cannot be encoded as JSON`)}},u=(e,t,r)=>new n(`Invalid test value for '${e}'${t?` at '${t}'`:``}: ${r}. JSON contents can hold booleans, finite numbers, strings, null, arrays, and plain objects.`),d=e=>{if(typeof e!=`object`||!e)return!1;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null},f=e=>e===null?`null`:typeof e==`function`?`a function`:typeof e==`object`?`a ${e.constructor?.name??`object`} instance`:typeof e==`symbol`?`a symbol`:String(e),p=(e,t)=>{let n=a(e,t);return{id:`test-config:${e}`,key:e,type:n.type,variations:[{name:null,value:n.value}],target:{defaultValue:n.value,rules:[]}}},m={environmentId:`test-environment`,projectId:`test-project`};var h=class{constructor(e,t){this.logger=e,this.emitter=new i,this.configs=new Map,this.pendingDeliveries=[],this.armed=`nothing`,this.connected=!1,this.delivering=!1,this.encodeAll(t).forEach((e,t)=>this.configs.set(t,e))}setValue(e,t){let n=p(e,t);this.configs.set(e,n),this.deliverIfConnected({...m,kind:`delta`,configs:{[e]:n}})}removeValue(e){this.configs.delete(e),this.deliverIfConnected(this.fullUpdate())}replaceValues(e){let t=this.encodeAll(e);this.configs.clear(),t.forEach((e,t)=>this.configs.set(t,e)),this.armed=`nothing`,this.deliverIfConnected(this.fullUpdate())}hold(){this.armed=`hold`}complete(){this.pendingHold?this.pendingHold.complete():this.armed===`hold`&&(this.armed=`nothing`)}fail(){this.pendingHold?this.pendingHold.fail():this.armed=`failure`}connect(e){this.endAttempt();let t=this.armed;switch(this.armed=`nothing`,t){case`failure`:return this.failNow();case`hold`:return this.holdNow(e);default:return this.connectNow(),Promise.resolve(this)}}get isConnected(){return this.connected}on(e,t){this.emitter.on(e,t)}off(e,t){t?this.emitter.off(e,t):this.emitter.removeAllListeners(e)}close(){this.endAttempt()}dispose(){this.close(),this.emitter.removeAllListeners()}endAttempt(){this.connected=!1,this.pendingHold?.end()}connectNow(){this.connected=!0,this.deliver(this.fullUpdate())}holdNow(e){return new Promise((t,n)=>{let r=setTimeout(()=>this.pendingHold?.end(),e),i=()=>{clearTimeout(r),this.pendingHold=void 0};this.pendingHold={end:()=>{i(),t(this)},complete:()=>{i(),this.connectNow(),t(this)},fail:()=>{i();let e=this.fatalError();this.emitter.emit(`connectionError`,e),n(e)}}})}failNow(){let e=this.fatalError();return this.emitter.emit(`connectionError`,e),Promise.reject(e)}fatalError(){return new r(`Connection failed with status: 401. Error: the test client failed this initialization. This is an unrecoverable error, will not attempt to reconnect.`,401)}deliverIfConnected(e){this.connected&&this.deliver(e)}deliver(e){if(this.pendingDeliveries.push(e),!this.delivering){this.delivering=!0;try{let e=this.pendingDeliveries.shift();for(;e;)this.emitCaught(e),e=this.pendingDeliveries.shift()}finally{this.delivering=!1}}}emitCaught(e){try{this.emitter.emit(`configBundleReceived`,e)}catch(e){this.logger.error(`[InMemoryConnection] Error dispatching a config update from the test client: `,e)}}fullUpdate(){return{...m,kind:`full`,configs:Object.fromEntries(this.configs)}}encodeAll(e){let t=new Map;for(let[n,r]of Object.entries(e))t.set(n,p(n,r));return t}};const g={start:()=>{},evaluatedConfig:()=>{},recordInvalidContext:()=>`new-kind-sample`,close:async()=>{}};var _=class{constructor(e,t){this.client=e,this.connection=t}setValue(e,t){this.connection.setValue(e,t)}removeValue(e){this.connection.removeValue(e)}replaceValues(e){this.connection.replaceValues(e)}holdInitialization(){this.connection.hold()}completeInitialization(){this.connection.complete()}failInitialization(){this.connection.fail()}};const v=(n,r)=>{let i=r?.logger??e(),a=new h(i,r?.values??{});return new _(new t(`test-client`,n,{logger:i,connection:{timeout:r?.timeout}},{transport:a,telemetry:g}),a)},y=e=>v({sdkName:`nextjs-sdk`,sdkVersion:`1.10.0`},e),b=e=>{let t=globalThis.__configDirectorServerClient;return globalThis.__configDirectorServerClient=e.client,()=>{globalThis.__configDirectorServerClient=t}};export{r as ConfigDirectorConnectionError,n as ConfigDirectorValidationError,y as createTestClient,b as installServerTestClient};
|
|
2
2
|
//# sourceMappingURL=testing.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.mjs","names":["encodeTestValue","encodeShared","createTestClient"],"sources":["../../../shared/src/testing/values.ts","../../../js-server-sdk/src/testing/values.ts","../../../js-server-sdk/src/testing/InMemoryConnection.ts","../../../js-server-sdk/src/testing/TestClient.ts","../../src/server/testing.ts"],"sourcesContent":["import type { ConfigType } from \"../types\";\nimport { ConfigDirectorValidationError } from \"../errors\";\n\nexport type TestJsonValue = boolean | number | string | null | TestJsonValue[] | { [key: string]: TestJsonValue };\n\nexport type TestValue = boolean | number | string | TestJsonValue[] | { [key: string]: TestJsonValue };\n\nexport type TestValues = Record<string, TestValue>;\n\nexport type EncodedTestValue = { type: ConfigType; value: string };\n\nexport const encodeTestValue = (key: string, value: TestValue): EncodedTestValue => {\n if (key.trim().length == 0) {\n throw new ConfigDirectorValidationError(\"Invalid config key. The key of a test value cannot be empty.\");\n }\n return encode(key, value);\n};\n\nconst encode = (key: string, value: TestValue): EncodedTestValue => {\n switch (typeof value) {\n case \"boolean\":\n return { type: \"boolean\", value: value ? \"true\" : \"false\" };\n case \"number\":\n return encodeNumber(key, value);\n case \"string\":\n return { type: \"string\", value };\n case \"object\":\n if (value !== null) {\n assertJsonContents(key, value, \"\");\n return { type: \"json\", value: JSON.stringify(value) };\n }\n }\n throw new ConfigDirectorValidationError(\n `Invalid test value for '${key}': ${describe(value)}. Use a boolean, a number, a string, a plain object, or an array.`,\n );\n};\n\nconst encodeNumber = (key: string, value: number): EncodedTestValue => {\n if (!Number.isFinite(value)) {\n throw new ConfigDirectorValidationError(`Invalid test value for '${key}': ${describe(value)} is not a finite number.`);\n }\n if (Number.isInteger(value)) {\n if (!Number.isSafeInteger(value)) {\n throw new ConfigDirectorValidationError(\n `Invalid test value for '${key}': ${value} is not a safe integer, so the SDK could not read it back exactly.`,\n );\n }\n return { type: \"integer\", value: String(value) };\n }\n return { type: \"float\", value: toPlainDecimal(value) };\n};\n\nconst toPlainDecimal = (value: number): string => {\n const text = String(value);\n const exponentIndex = text.indexOf(\"e-\");\n if (exponentIndex < 0) {\n return text;\n }\n const sign = text.startsWith(\"-\") ? \"-\" : \"\";\n const [integerDigits = \"\", fractionDigits = \"\"] = text.slice(sign.length, exponentIndex).split(\".\");\n const leadingZeros = Number(text.slice(exponentIndex + 2)) - integerDigits.length;\n return `${sign}0.${\"0\".repeat(leadingZeros)}${integerDigits}${fractionDigits}`;\n};\n\nconst assertJsonContents = (key: string, value: unknown, path: string): void => {\n if (value === null || typeof value === \"boolean\" || typeof value === \"string\") {\n return;\n }\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) {\n throw invalidJsonContents(key, path, `${describe(value)} is not a finite number`);\n }\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => assertJsonContents(key, item, `${path}[${index}]`));\n return;\n }\n if (isPlainObject(value)) {\n for (const [property, item] of Object.entries(value)) {\n assertJsonContents(key, item, path ? `${path}.${property}` : property);\n }\n return;\n }\n throw invalidJsonContents(key, path, `${describe(value)} cannot be encoded as JSON`);\n};\n\nconst invalidJsonContents = (key: string, path: string, problem: string) =>\n new ConfigDirectorValidationError(\n `Invalid test value for '${key}'${path ? ` at '${path}'` : \"\"}: ${problem}. JSON contents can hold booleans, finite numbers, strings, null, arrays, and plain objects.`,\n );\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n\nconst describe = (value: unknown): string => {\n if (value === null) {\n return \"null\";\n }\n if (typeof value === \"function\") {\n return \"a function\";\n }\n if (typeof value === \"object\") {\n return `a ${value.constructor?.name ?? \"object\"} instance`;\n }\n if (typeof value === \"symbol\") {\n return \"a symbol\";\n }\n return String(value);\n};\n","import type { ConfigDefinition } from \"../types\";\nimport { encodeTestValue as encodeShared } from \"@shared/testing/values\";\nimport type { TestValue } from \"@shared/testing/values\";\n\nexport type { TestJsonValue, TestValue, TestValues } from \"@shared/testing/values\";\n\nexport const encodeTestValue = (key: string, value: TestValue): ConfigDefinition => {\n const encoded = encodeShared(key, value);\n return {\n id: `test-config:${key}`,\n key,\n type: encoded.type,\n variations: [{ name: null, value: encoded.value }],\n target: { defaultValue: encoded.value, rules: [] },\n };\n};\n","import EventEmitter from \"node:events\";\nimport type { ConfigBundle, ConfigDefinition, ConfigDirectorLogger, Transport, TransportEvents } from \"../types\";\nimport { ConfigDirectorConnectionError } from \"@shared/errors\";\nimport { encodeTestValue, type TestValue, type TestValues } from \"./values\";\n\ntype Armed = \"nothing\" | \"hold\" | \"failure\";\n\ntype PendingHold = {\n end: () => void;\n complete: () => void;\n fail: () => void;\n};\n\nconst TEST_ENVIRONMENT = { environmentId: \"test-environment\", projectId: \"test-project\" };\n\nexport class InMemoryConnection implements Transport {\n private readonly emitter = new EventEmitter();\n private readonly configs = new Map<string, ConfigDefinition>();\n private readonly pendingDeliveries: ConfigBundle[] = [];\n private armed: Armed = \"nothing\";\n private pendingHold: PendingHold | undefined;\n private connected = false;\n private delivering = false;\n\n constructor(\n private readonly logger: ConfigDirectorLogger,\n values: TestValues,\n ) {\n this.encodeAll(values).forEach((definition, key) => this.configs.set(key, definition));\n }\n\n public setValue(key: string, value: TestValue) {\n const definition = encodeTestValue(key, value);\n this.configs.set(key, definition);\n this.deliverIfConnected({ ...TEST_ENVIRONMENT, kind: \"delta\", configs: { [key]: definition } });\n }\n\n public removeValue(key: string) {\n this.configs.delete(key);\n this.deliverIfConnected(this.fullUpdate());\n }\n\n public replaceValues(values: TestValues) {\n const encoded = this.encodeAll(values);\n this.configs.clear();\n encoded.forEach((definition, key) => this.configs.set(key, definition));\n this.armed = \"nothing\";\n this.deliverIfConnected(this.fullUpdate());\n }\n\n public hold() {\n this.armed = \"hold\";\n }\n\n public complete() {\n if (this.pendingHold) {\n this.pendingHold.complete();\n } else if (this.armed === \"hold\") {\n this.armed = \"nothing\";\n }\n }\n\n public fail() {\n if (this.pendingHold) {\n this.pendingHold.fail();\n } else {\n this.armed = \"failure\";\n }\n }\n\n public connect(timeout: number): Promise<this> {\n this.endAttempt();\n const armed = this.armed;\n this.armed = \"nothing\";\n switch (armed) {\n case \"failure\":\n return this.failNow();\n case \"hold\":\n return this.holdNow(timeout);\n default:\n this.connectNow();\n return Promise.resolve(this);\n }\n }\n\n public get isConnected(): boolean {\n return this.connected;\n }\n\n public on<TName extends keyof TransportEvents>(name: TName, handler: (payload: TransportEvents[TName]) => void) {\n this.emitter.on(name, handler);\n }\n\n public off<TName extends keyof TransportEvents>(name: TName, handler?: (payload: TransportEvents[TName]) => void) {\n if (handler) {\n this.emitter.off(name, handler);\n } else {\n this.emitter.removeAllListeners(name);\n }\n }\n\n public close() {\n this.endAttempt();\n }\n\n public dispose() {\n this.close();\n this.emitter.removeAllListeners();\n }\n\n private endAttempt() {\n this.connected = false;\n this.pendingHold?.end();\n }\n\n private connectNow() {\n this.connected = true;\n this.deliver(this.fullUpdate());\n }\n\n private holdNow(timeout: number): Promise<this> {\n return new Promise<this>((resolve, reject) => {\n const timer = setTimeout(() => this.pendingHold?.end(), timeout);\n const release = () => {\n clearTimeout(timer);\n this.pendingHold = undefined;\n };\n this.pendingHold = {\n end: () => {\n release();\n resolve(this);\n },\n complete: () => {\n release();\n this.connectNow();\n resolve(this);\n },\n fail: () => {\n release();\n const error = this.fatalError();\n this.emitter.emit(\"connectionError\", error);\n reject(error);\n },\n };\n });\n }\n\n private failNow(): Promise<this> {\n const error = this.fatalError();\n this.emitter.emit(\"connectionError\", error);\n return Promise.reject(error);\n }\n\n private fatalError() {\n return new ConfigDirectorConnectionError(\n \"Connection failed with status: 401. Error: the test client failed this initialization. This is an unrecoverable error, will not attempt to reconnect.\",\n 401,\n );\n }\n\n private deliverIfConnected(configBundle: ConfigBundle) {\n if (this.connected) {\n this.deliver(configBundle);\n }\n }\n\n private deliver(configBundle: ConfigBundle) {\n this.pendingDeliveries.push(configBundle);\n if (this.delivering) {\n return;\n }\n this.delivering = true;\n try {\n let next = this.pendingDeliveries.shift();\n while (next) {\n this.emitCaught(next);\n next = this.pendingDeliveries.shift();\n }\n } finally {\n this.delivering = false;\n }\n }\n\n private emitCaught(configBundle: ConfigBundle) {\n try {\n this.emitter.emit(\"configBundleReceived\", configBundle);\n } catch (error) {\n this.logger.error(\"[InMemoryConnection] Error dispatching a config update from the test client: \", error);\n }\n }\n\n private fullUpdate(): ConfigBundle {\n return { ...TEST_ENVIRONMENT, kind: \"full\", configs: Object.fromEntries(this.configs) };\n }\n\n private encodeAll(values: TestValues): Map<string, ConfigDefinition> {\n const encoded = new Map<string, ConfigDefinition>();\n for (const [key, value] of Object.entries(values)) {\n encoded.set(key, encodeTestValue(key, value));\n }\n return encoded;\n }\n}\n","import { DefaultConfigDirectorClient } from \"../DefaultConfigDirectorClient\";\nimport { createDefaultLogger } from \"../logger\";\nimport type { ConfigDirectorClient, ConfigDirectorLogger, IdentifyingSdkOptions } from \"../types\";\nimport type { ServerTelemetryClient } from \"../telemetry\";\nimport { InMemoryConnection } from \"./InMemoryConnection\";\nimport type { TestValue, TestValues } from \"./values\";\n\nconst TEST_CLIENT_SDK_KEY = \"test-client\";\n\n/**\n * Options for {@link createTestClient}. Every option is optional.\n */\nexport type TestClientOptions = {\n /**\n * The config values the test client serves once its client connects, keyed by config key. The\n * config type follows from each value: a boolean, an integral number (`integer`), any other\n * number (`float`), a string, or a plain object or array (`json`). Every context receives the\n * same value.\n */\n values?: TestValues;\n /**\n * The connection timeout of the SDK client, in milliseconds. It bounds how long a held\n * `initialize` waits. Defaults to the SDK's production timeout.\n */\n timeout?: number;\n /**\n * The logger the SDK client uses. Defaults to the SDK's console logger at `warn` level.\n */\n logger?: ConfigDirectorLogger;\n};\n\n/**\n * A real ConfigDirector client connected to an in-memory server that the test controls.\n *\n * The client under {@link TestClient.client} is the SDK's production client: value parsing,\n * targeting evaluation, watchers, events, and readiness behave as they do against ConfigDirector.\n * Only the network connection and telemetry are replaced, so no request is ever made and nothing\n * is left running after the client is disposed.\n */\nexport interface TestClient {\n /**\n * The SDK client to hand to the code under test. It starts uninitialized, like a production\n * client; `initialize` completes at once with the seeded values unless initialization is held.\n */\n readonly client: ConfigDirectorClient;\n\n /**\n * Stores `value` under `key` and, when the client is connected, delivers it as an update, so\n * reads, watchers, and `configsUpdated` handlers see it.\n */\n setValue(key: string, value: TestValue): void;\n\n /**\n * Removes `key` and, when the client is connected, delivers a full update without it, so reads\n * fall back to the in-code default value and watchers of `key` receive that default.\n */\n removeValue(key: string): void;\n\n /**\n * Replaces every stored value with `values`, disarms any armed hold or failure, and, when the\n * client is connected, delivers the new values as a full update.\n */\n replaceValues(values: TestValues): void;\n\n /**\n * Makes the next `initialize` wait until {@link completeInitialization} or\n * {@link failInitialization} is called, or until the client's timeout elapses.\n */\n holdInitialization(): void;\n\n /**\n * Delivers the stored values to a held `initialize`, so it completes with the client ready. When\n * a hold is armed but no `initialize` has started, it disarms the hold instead.\n */\n completeInitialization(): void;\n\n /**\n * Fails a held `initialize` with an unrecoverable connection error, or arms the next `initialize`\n * to fail. `initialize` completes promptly with the client not ready and `connectionError` fires.\n */\n failInitialization(): void;\n}\n\nconst noopTelemetryClient: ServerTelemetryClient = {\n start: () => {},\n evaluatedConfig: () => {},\n close: async () => {},\n};\n\nclass InMemoryTestClient implements TestClient {\n constructor(\n public readonly client: ConfigDirectorClient,\n private readonly connection: InMemoryConnection,\n ) {}\n\n public setValue(key: string, value: TestValue) {\n this.connection.setValue(key, value);\n }\n\n public removeValue(key: string) {\n this.connection.removeValue(key);\n }\n\n public replaceValues(values: TestValues) {\n this.connection.replaceValues(values);\n }\n\n public holdInitialization() {\n this.connection.hold();\n }\n\n public completeInitialization() {\n this.connection.complete();\n }\n\n public failInitialization() {\n this.connection.fail();\n }\n}\n\nexport const createTestClient = (sdkOptions: IdentifyingSdkOptions, options?: TestClientOptions): TestClient => {\n const logger = options?.logger ?? createDefaultLogger();\n const connection = new InMemoryConnection(logger, options?.values ?? {});\n const client = new DefaultConfigDirectorClient(\n TEST_CLIENT_SDK_KEY,\n sdkOptions,\n { logger, connection: { timeout: options?.timeout } },\n { transport: connection, telemetry: noopTelemetryClient },\n );\n return new InMemoryTestClient(client, connection);\n};\n","import { createTestClient as createServerTestClient } from \"@js-server-sdk/testing/TestClient\";\nimport type { TestClient, TestClientOptions } from \"@js-server-sdk/testing/TestClient\";\n\nexport type { TestClient, TestClientOptions } from \"@js-server-sdk/testing/TestClient\";\nexport type { TestValue, TestValues, TestJsonValue } from \"@js-server-sdk/testing/values\";\nexport { ConfigDirectorConnectionError, ConfigDirectorValidationError } from \"@shared/errors\";\n\n/**\n * Creates a {@link TestClient}: a real server `ConfigDirectorClient` connected to an in-memory\n * server that the test controls. No network connection is opened and no telemetry is sent. Put it\n * where `register()` would put the server singleton with {@link installServerTestClient}.\n *\n * @param options {@link TestClientOptions}: the initial values, the client's timeout, and its logger\n * @returns A {@link TestClient} whose `client` is passed to the code under test\n *\n * @example\n * import { createTestClient, installServerTestClient } from \"@configdirector/nextjs-sdk/server/testing\";\n *\n * const testClient = createTestClient({ values: { \"new-checkout\": true } });\n * const uninstall = installServerTestClient(testClient);\n * await testClient.client.initialize();\n */\nexport const createTestClient = (options?: TestClientOptions): TestClient => {\n return createServerTestClient({ sdkName: \"nextjs-sdk\", sdkVersion: \"__VERSION__\" }, options);\n};\n\n/**\n * Puts `testClient.client` where `register()` puts the server singleton, so `getConfigClient()`,\n * `generateSsrConfigSet()`, and the server `ConfigDirectorProvider` serve its values. It does not\n * initialize the client: call `await testClient.client.initialize()`, as `register()` would.\n *\n * @param testClient The server test client whose `client` to install\n * @returns A function that restores the client installed before\n */\nexport const installServerTestClient = (testClient: TestClient): (() => void) => {\n const previous = globalThis.__configDirectorServerClient;\n globalThis.__configDirectorServerClient = testClient.client;\n return () => {\n globalThis.__configDirectorServerClient = previous;\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"testing.mjs","names":["encodeTestValue","encodeShared","createTestClient"],"sources":["../../../shared/src/testing/values.ts","../../../js-server-sdk/src/testing/values.ts","../../../js-server-sdk/src/testing/InMemoryConnection.ts","../../../js-server-sdk/src/testing/TestClient.ts","../../src/server/testing.ts"],"sourcesContent":["import type { ConfigType } from \"../types\";\nimport { ConfigDirectorValidationError } from \"../errors\";\n\nexport type TestJsonValue = boolean | number | string | null | TestJsonValue[] | { [key: string]: TestJsonValue };\n\nexport type TestValue = boolean | number | string | TestJsonValue[] | { [key: string]: TestJsonValue };\n\nexport type TestValues = Record<string, TestValue>;\n\nexport type EncodedTestValue = { type: ConfigType; value: string };\n\nexport const encodeTestValue = (key: string, value: TestValue): EncodedTestValue => {\n if (key.trim().length == 0) {\n throw new ConfigDirectorValidationError(\"Invalid config key. The key of a test value cannot be empty.\");\n }\n return encode(key, value);\n};\n\nconst encode = (key: string, value: TestValue): EncodedTestValue => {\n switch (typeof value) {\n case \"boolean\":\n return { type: \"boolean\", value: value ? \"true\" : \"false\" };\n case \"number\":\n return encodeNumber(key, value);\n case \"string\":\n return { type: \"string\", value };\n case \"object\":\n if (value !== null) {\n assertJsonContents(key, value, \"\");\n return { type: \"json\", value: JSON.stringify(value) };\n }\n }\n throw new ConfigDirectorValidationError(\n `Invalid test value for '${key}': ${describe(value)}. Use a boolean, a number, a string, a plain object, or an array.`,\n );\n};\n\nconst encodeNumber = (key: string, value: number): EncodedTestValue => {\n if (!Number.isFinite(value)) {\n throw new ConfigDirectorValidationError(`Invalid test value for '${key}': ${describe(value)} is not a finite number.`);\n }\n if (Number.isInteger(value)) {\n if (!Number.isSafeInteger(value)) {\n throw new ConfigDirectorValidationError(\n `Invalid test value for '${key}': ${value} is not a safe integer, so the SDK could not read it back exactly.`,\n );\n }\n return { type: \"integer\", value: String(value) };\n }\n return { type: \"float\", value: toPlainDecimal(value) };\n};\n\nconst toPlainDecimal = (value: number): string => {\n const text = String(value);\n const exponentIndex = text.indexOf(\"e-\");\n if (exponentIndex < 0) {\n return text;\n }\n const sign = text.startsWith(\"-\") ? \"-\" : \"\";\n const [integerDigits = \"\", fractionDigits = \"\"] = text.slice(sign.length, exponentIndex).split(\".\");\n const leadingZeros = Number(text.slice(exponentIndex + 2)) - integerDigits.length;\n return `${sign}0.${\"0\".repeat(leadingZeros)}${integerDigits}${fractionDigits}`;\n};\n\nconst assertJsonContents = (key: string, value: unknown, path: string): void => {\n if (value === null || typeof value === \"boolean\" || typeof value === \"string\") {\n return;\n }\n if (typeof value === \"number\") {\n if (!Number.isFinite(value)) {\n throw invalidJsonContents(key, path, `${describe(value)} is not a finite number`);\n }\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => assertJsonContents(key, item, `${path}[${index}]`));\n return;\n }\n if (isPlainObject(value)) {\n for (const [property, item] of Object.entries(value)) {\n assertJsonContents(key, item, path ? `${path}.${property}` : property);\n }\n return;\n }\n throw invalidJsonContents(key, path, `${describe(value)} cannot be encoded as JSON`);\n};\n\nconst invalidJsonContents = (key: string, path: string, problem: string) =>\n new ConfigDirectorValidationError(\n `Invalid test value for '${key}'${path ? ` at '${path}'` : \"\"}: ${problem}. JSON contents can hold booleans, finite numbers, strings, null, arrays, and plain objects.`,\n );\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== \"object\" || value === null) {\n return false;\n }\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n\nconst describe = (value: unknown): string => {\n if (value === null) {\n return \"null\";\n }\n if (typeof value === \"function\") {\n return \"a function\";\n }\n if (typeof value === \"object\") {\n return `a ${value.constructor?.name ?? \"object\"} instance`;\n }\n if (typeof value === \"symbol\") {\n return \"a symbol\";\n }\n return String(value);\n};\n","import type { ConfigDefinition } from \"../types\";\nimport { encodeTestValue as encodeShared } from \"@shared/testing/values\";\nimport type { TestValue } from \"@shared/testing/values\";\n\nexport type { TestJsonValue, TestValue, TestValues } from \"@shared/testing/values\";\n\nexport const encodeTestValue = (key: string, value: TestValue): ConfigDefinition => {\n const encoded = encodeShared(key, value);\n return {\n id: `test-config:${key}`,\n key,\n type: encoded.type,\n variations: [{ name: null, value: encoded.value }],\n target: { defaultValue: encoded.value, rules: [] },\n };\n};\n","import EventEmitter from \"node:events\";\nimport type { ConfigBundle, ConfigDefinition, ConfigDirectorLogger, Transport, TransportEvents } from \"../types\";\nimport { ConfigDirectorConnectionError } from \"@shared/errors\";\nimport { encodeTestValue, type TestValue, type TestValues } from \"./values\";\n\ntype Armed = \"nothing\" | \"hold\" | \"failure\";\n\ntype PendingHold = {\n end: () => void;\n complete: () => void;\n fail: () => void;\n};\n\nconst TEST_ENVIRONMENT = { environmentId: \"test-environment\", projectId: \"test-project\" };\n\nexport class InMemoryConnection implements Transport {\n private readonly emitter = new EventEmitter();\n private readonly configs = new Map<string, ConfigDefinition>();\n private readonly pendingDeliveries: ConfigBundle[] = [];\n private armed: Armed = \"nothing\";\n private pendingHold: PendingHold | undefined;\n private connected = false;\n private delivering = false;\n\n constructor(\n private readonly logger: ConfigDirectorLogger,\n values: TestValues,\n ) {\n this.encodeAll(values).forEach((definition, key) => this.configs.set(key, definition));\n }\n\n public setValue(key: string, value: TestValue) {\n const definition = encodeTestValue(key, value);\n this.configs.set(key, definition);\n this.deliverIfConnected({ ...TEST_ENVIRONMENT, kind: \"delta\", configs: { [key]: definition } });\n }\n\n public removeValue(key: string) {\n this.configs.delete(key);\n this.deliverIfConnected(this.fullUpdate());\n }\n\n public replaceValues(values: TestValues) {\n const encoded = this.encodeAll(values);\n this.configs.clear();\n encoded.forEach((definition, key) => this.configs.set(key, definition));\n this.armed = \"nothing\";\n this.deliverIfConnected(this.fullUpdate());\n }\n\n public hold() {\n this.armed = \"hold\";\n }\n\n public complete() {\n if (this.pendingHold) {\n this.pendingHold.complete();\n } else if (this.armed === \"hold\") {\n this.armed = \"nothing\";\n }\n }\n\n public fail() {\n if (this.pendingHold) {\n this.pendingHold.fail();\n } else {\n this.armed = \"failure\";\n }\n }\n\n public connect(timeout: number): Promise<this> {\n this.endAttempt();\n const armed = this.armed;\n this.armed = \"nothing\";\n switch (armed) {\n case \"failure\":\n return this.failNow();\n case \"hold\":\n return this.holdNow(timeout);\n default:\n this.connectNow();\n return Promise.resolve(this);\n }\n }\n\n public get isConnected(): boolean {\n return this.connected;\n }\n\n public on<TName extends keyof TransportEvents>(name: TName, handler: (payload: TransportEvents[TName]) => void) {\n this.emitter.on(name, handler);\n }\n\n public off<TName extends keyof TransportEvents>(name: TName, handler?: (payload: TransportEvents[TName]) => void) {\n if (handler) {\n this.emitter.off(name, handler);\n } else {\n this.emitter.removeAllListeners(name);\n }\n }\n\n public close() {\n this.endAttempt();\n }\n\n public dispose() {\n this.close();\n this.emitter.removeAllListeners();\n }\n\n private endAttempt() {\n this.connected = false;\n this.pendingHold?.end();\n }\n\n private connectNow() {\n this.connected = true;\n this.deliver(this.fullUpdate());\n }\n\n private holdNow(timeout: number): Promise<this> {\n return new Promise<this>((resolve, reject) => {\n const timer = setTimeout(() => this.pendingHold?.end(), timeout);\n const release = () => {\n clearTimeout(timer);\n this.pendingHold = undefined;\n };\n this.pendingHold = {\n end: () => {\n release();\n resolve(this);\n },\n complete: () => {\n release();\n this.connectNow();\n resolve(this);\n },\n fail: () => {\n release();\n const error = this.fatalError();\n this.emitter.emit(\"connectionError\", error);\n reject(error);\n },\n };\n });\n }\n\n private failNow(): Promise<this> {\n const error = this.fatalError();\n this.emitter.emit(\"connectionError\", error);\n return Promise.reject(error);\n }\n\n private fatalError() {\n return new ConfigDirectorConnectionError(\n \"Connection failed with status: 401. Error: the test client failed this initialization. This is an unrecoverable error, will not attempt to reconnect.\",\n 401,\n );\n }\n\n private deliverIfConnected(configBundle: ConfigBundle) {\n if (this.connected) {\n this.deliver(configBundle);\n }\n }\n\n private deliver(configBundle: ConfigBundle) {\n this.pendingDeliveries.push(configBundle);\n if (this.delivering) {\n return;\n }\n this.delivering = true;\n try {\n let next = this.pendingDeliveries.shift();\n while (next) {\n this.emitCaught(next);\n next = this.pendingDeliveries.shift();\n }\n } finally {\n this.delivering = false;\n }\n }\n\n private emitCaught(configBundle: ConfigBundle) {\n try {\n this.emitter.emit(\"configBundleReceived\", configBundle);\n } catch (error) {\n this.logger.error(\"[InMemoryConnection] Error dispatching a config update from the test client: \", error);\n }\n }\n\n private fullUpdate(): ConfigBundle {\n return { ...TEST_ENVIRONMENT, kind: \"full\", configs: Object.fromEntries(this.configs) };\n }\n\n private encodeAll(values: TestValues): Map<string, ConfigDefinition> {\n const encoded = new Map<string, ConfigDefinition>();\n for (const [key, value] of Object.entries(values)) {\n encoded.set(key, encodeTestValue(key, value));\n }\n return encoded;\n }\n}\n","import { DefaultConfigDirectorClient } from \"../DefaultConfigDirectorClient\";\nimport { createDefaultLogger } from \"../logger\";\nimport type { ConfigDirectorClient, ConfigDirectorLogger, IdentifyingSdkOptions } from \"../types\";\nimport type { ServerTelemetryClient } from \"../telemetry\";\nimport { InMemoryConnection } from \"./InMemoryConnection\";\nimport type { TestValue, TestValues } from \"./values\";\n\nconst TEST_CLIENT_SDK_KEY = \"test-client\";\n\n/**\n * Options for {@link createTestClient}. Every option is optional.\n */\nexport type TestClientOptions = {\n /**\n * The config values the test client serves once its client connects, keyed by config key. The\n * config type follows from each value: a boolean, an integral number (`integer`), any other\n * number (`float`), a string, or a plain object or array (`json`). Every context receives the\n * same value.\n */\n values?: TestValues;\n /**\n * The connection timeout of the SDK client, in milliseconds. It bounds how long a held\n * `initialize` waits. Defaults to the SDK's production timeout.\n */\n timeout?: number;\n /**\n * The logger the SDK client uses. Defaults to the SDK's console logger at `warn` level. Since\n * the test client sends no telemetry, every read that supplies a context with an invalid kind\n * logs an error, rather than each invalid kind once per telemetry interval.\n */\n logger?: ConfigDirectorLogger;\n};\n\n/**\n * A real ConfigDirector client connected to an in-memory server that the test controls.\n *\n * The client under {@link TestClient.client} is the SDK's production client: value parsing,\n * targeting evaluation, watchers, events, and readiness behave as they do against ConfigDirector.\n * Only the network connection and telemetry are replaced, so no request is ever made and nothing\n * is left running after the client is disposed.\n */\nexport interface TestClient {\n /**\n * The SDK client to hand to the code under test. It starts uninitialized, like a production\n * client; `initialize` completes at once with the seeded values unless initialization is held.\n */\n readonly client: ConfigDirectorClient;\n\n /**\n * Stores `value` under `key` and, when the client is connected, delivers it as an update, so\n * reads, watchers, and `configsUpdated` handlers see it.\n */\n setValue(key: string, value: TestValue): void;\n\n /**\n * Removes `key` and, when the client is connected, delivers a full update without it, so reads\n * fall back to the in-code default value and watchers of `key` receive that default.\n */\n removeValue(key: string): void;\n\n /**\n * Replaces every stored value with `values`, disarms any armed hold or failure, and, when the\n * client is connected, delivers the new values as a full update.\n */\n replaceValues(values: TestValues): void;\n\n /**\n * Makes the next `initialize` wait until {@link completeInitialization} or\n * {@link failInitialization} is called, or until the client's timeout elapses.\n */\n holdInitialization(): void;\n\n /**\n * Delivers the stored values to a held `initialize`, so it completes with the client ready. When\n * a hold is armed but no `initialize` has started, it disarms the hold instead.\n */\n completeInitialization(): void;\n\n /**\n * Fails a held `initialize` with an unrecoverable connection error, or arms the next `initialize`\n * to fail. `initialize` completes promptly with the client not ready and `connectionError` fires.\n */\n failInitialization(): void;\n}\n\nconst noopTelemetryClient: ServerTelemetryClient = {\n start: () => {},\n evaluatedConfig: () => {},\n recordInvalidContext: () => \"new-kind-sample\",\n close: async () => {},\n};\n\nclass InMemoryTestClient implements TestClient {\n constructor(\n public readonly client: ConfigDirectorClient,\n private readonly connection: InMemoryConnection,\n ) {}\n\n public setValue(key: string, value: TestValue) {\n this.connection.setValue(key, value);\n }\n\n public removeValue(key: string) {\n this.connection.removeValue(key);\n }\n\n public replaceValues(values: TestValues) {\n this.connection.replaceValues(values);\n }\n\n public holdInitialization() {\n this.connection.hold();\n }\n\n public completeInitialization() {\n this.connection.complete();\n }\n\n public failInitialization() {\n this.connection.fail();\n }\n}\n\nexport const createTestClient = (sdkOptions: IdentifyingSdkOptions, options?: TestClientOptions): TestClient => {\n const logger = options?.logger ?? createDefaultLogger();\n const connection = new InMemoryConnection(logger, options?.values ?? {});\n const client = new DefaultConfigDirectorClient(\n TEST_CLIENT_SDK_KEY,\n sdkOptions,\n { logger, connection: { timeout: options?.timeout } },\n { transport: connection, telemetry: noopTelemetryClient },\n );\n return new InMemoryTestClient(client, connection);\n};\n","import { createTestClient as createServerTestClient } from \"@js-server-sdk/testing/TestClient\";\nimport type { TestClient, TestClientOptions } from \"@js-server-sdk/testing/TestClient\";\n\nexport type { TestClient, TestClientOptions } from \"@js-server-sdk/testing/TestClient\";\nexport type { TestValue, TestValues, TestJsonValue } from \"@js-server-sdk/testing/values\";\nexport { ConfigDirectorConnectionError, ConfigDirectorValidationError } from \"@shared/errors\";\n\n/**\n * Creates a {@link TestClient}: a real server `ConfigDirectorClient` connected to an in-memory\n * server that the test controls. No network connection is opened and no telemetry is sent. Put it\n * where `register()` would put the server singleton with {@link installServerTestClient}.\n *\n * @param options {@link TestClientOptions}: the initial values, the client's timeout, and its logger\n * @returns A {@link TestClient} whose `client` is passed to the code under test\n *\n * @example\n * import { createTestClient, installServerTestClient } from \"@configdirector/nextjs-sdk/server/testing\";\n *\n * const testClient = createTestClient({ values: { \"new-checkout\": true } });\n * const uninstall = installServerTestClient(testClient);\n * await testClient.client.initialize();\n */\nexport const createTestClient = (options?: TestClientOptions): TestClient => {\n return createServerTestClient({ sdkName: \"nextjs-sdk\", sdkVersion: \"__VERSION__\" }, options);\n};\n\n/**\n * Puts `testClient.client` where `register()` puts the server singleton, so `getConfigClient()`,\n * `generateSsrConfigSet()`, and the server `ConfigDirectorProvider` serve its values. It does not\n * initialize the client: call `await testClient.client.initialize()`, as `register()` would.\n *\n * @param testClient The server test client whose `client` to install\n * @returns A function that restores the client installed before\n */\nexport const installServerTestClient = (testClient: TestClient): (() => void) => {\n const previous = globalThis.__configDirectorServerClient;\n globalThis.__configDirectorServerClient = testClient.client;\n return () => {\n globalThis.__configDirectorServerClient = previous;\n };\n};\n"],"mappings":"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"}
|
|
@@ -32,27 +32,40 @@ type ConfigEvaluation = {
|
|
|
32
32
|
context?: ConfigDirectorContext;
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
|
-
* The
|
|
36
|
-
*
|
|
35
|
+
* The context to be sent to ConfigDirector: the user or other entity, such as a device or an
|
|
36
|
+
* organization, that configs are evaluated for. This context will be used for targeting rules
|
|
37
|
+
* evaluation.
|
|
37
38
|
*/
|
|
38
39
|
type ConfigDirectorContext = {
|
|
39
40
|
/**
|
|
40
|
-
* The
|
|
41
|
-
*
|
|
41
|
+
* The context's identifier. This should be a value that uniquely identifies the user or other
|
|
42
|
+
* entity among contexts of the same {@link kind}.
|
|
42
43
|
* In the case of anonymous users, you could generate a UUID or alternatively not provide
|
|
43
44
|
* the {@link id} and the SDK will generate a random UUID. However, keep in mind that this
|
|
44
|
-
* value is used for segmenting
|
|
45
|
-
* could result in the
|
|
45
|
+
* value is used for segmenting contexts in percentage rollouts, and changes to the {@link id}
|
|
46
|
+
* could result in the context being assigned to a different percentile.
|
|
46
47
|
*/
|
|
47
48
|
id?: string;
|
|
48
49
|
/**
|
|
49
|
-
* The
|
|
50
|
+
* The kind of entity this context represents, such as `user`, `device`, `organization`,
|
|
51
|
+
* `tenant` or `listing`. You can use any other kind that fits your application. A kind has 1
|
|
52
|
+
* to 64 characters, using only lowercase letters (`a`-`z`), digits, `-` and `_`. It is used
|
|
53
|
+
* exactly as given, without trimming or changing its case.
|
|
54
|
+
*
|
|
55
|
+
* A context with an invalid kind is ignored as a whole: the SDK logs an error and evaluates
|
|
56
|
+
* as if no context had been provided.
|
|
57
|
+
*
|
|
58
|
+
* @default "user"
|
|
59
|
+
*/
|
|
60
|
+
kind?: string;
|
|
61
|
+
/**
|
|
62
|
+
* The context's display name. This will be shown in the ConfigDirector dashboard and may be
|
|
50
63
|
* used for targeting rules.
|
|
51
64
|
*/
|
|
52
65
|
name?: string;
|
|
53
66
|
/**
|
|
54
|
-
* Any arbitrary traits for the
|
|
55
|
-
*
|
|
67
|
+
* Any arbitrary traits for the context. They will be shown in the ConfigDirector dashboard
|
|
68
|
+
* and may be used for targeting rules.
|
|
56
69
|
*/
|
|
57
70
|
traits?: {
|
|
58
71
|
[key: string]: unknown;
|
|
@@ -289,4 +302,4 @@ interface ConfigDirectorClient {
|
|
|
289
302
|
}
|
|
290
303
|
//#endregion
|
|
291
304
|
export { ConfigDirectorLogger as a, ConfigEvaluation as c, ConnectionMode as d, ConfigDirectorLogMessageDecorator as i, ConfigState as l, ConfigDirectorClientOptions as n, ConfigDirectorLoggingLevel as o, ConfigDirectorContext as r, ConfigDirectorMetaContext as s, ConfigDirectorClient as t, ConfigValueType as u };
|
|
292
|
-
//# sourceMappingURL=types-
|
|
305
|
+
//# sourceMappingURL=types-BBEEMV5Y.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-BBEEMV5Y.d.cts","names":[],"sources":["../../../shared/src/types.ts","../../../js-server-sdk/src/types.ts"],"mappings":"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"}
|
|
@@ -32,27 +32,40 @@ type ConfigEvaluation = {
|
|
|
32
32
|
context?: ConfigDirectorContext;
|
|
33
33
|
};
|
|
34
34
|
/**
|
|
35
|
-
* The
|
|
36
|
-
*
|
|
35
|
+
* The context to be sent to ConfigDirector: the user or other entity, such as a device or an
|
|
36
|
+
* organization, that configs are evaluated for. This context will be used for targeting rules
|
|
37
|
+
* evaluation.
|
|
37
38
|
*/
|
|
38
39
|
type ConfigDirectorContext = {
|
|
39
40
|
/**
|
|
40
|
-
* The
|
|
41
|
-
*
|
|
41
|
+
* The context's identifier. This should be a value that uniquely identifies the user or other
|
|
42
|
+
* entity among contexts of the same {@link kind}.
|
|
42
43
|
* In the case of anonymous users, you could generate a UUID or alternatively not provide
|
|
43
44
|
* the {@link id} and the SDK will generate a random UUID. However, keep in mind that this
|
|
44
|
-
* value is used for segmenting
|
|
45
|
-
* could result in the
|
|
45
|
+
* value is used for segmenting contexts in percentage rollouts, and changes to the {@link id}
|
|
46
|
+
* could result in the context being assigned to a different percentile.
|
|
46
47
|
*/
|
|
47
48
|
id?: string;
|
|
48
49
|
/**
|
|
49
|
-
* The
|
|
50
|
+
* The kind of entity this context represents, such as `user`, `device`, `organization`,
|
|
51
|
+
* `tenant` or `listing`. You can use any other kind that fits your application. A kind has 1
|
|
52
|
+
* to 64 characters, using only lowercase letters (`a`-`z`), digits, `-` and `_`. It is used
|
|
53
|
+
* exactly as given, without trimming or changing its case.
|
|
54
|
+
*
|
|
55
|
+
* A context with an invalid kind is ignored as a whole: the SDK logs an error and evaluates
|
|
56
|
+
* as if no context had been provided.
|
|
57
|
+
*
|
|
58
|
+
* @default "user"
|
|
59
|
+
*/
|
|
60
|
+
kind?: string;
|
|
61
|
+
/**
|
|
62
|
+
* The context's display name. This will be shown in the ConfigDirector dashboard and may be
|
|
50
63
|
* used for targeting rules.
|
|
51
64
|
*/
|
|
52
65
|
name?: string;
|
|
53
66
|
/**
|
|
54
|
-
* Any arbitrary traits for the
|
|
55
|
-
*
|
|
67
|
+
* Any arbitrary traits for the context. They will be shown in the ConfigDirector dashboard
|
|
68
|
+
* and may be used for targeting rules.
|
|
56
69
|
*/
|
|
57
70
|
traits?: {
|
|
58
71
|
[key: string]: unknown;
|
|
@@ -289,4 +302,4 @@ interface ConfigDirectorClient {
|
|
|
289
302
|
}
|
|
290
303
|
//#endregion
|
|
291
304
|
export { ConfigDirectorLogger as a, ConfigEvaluation as c, ConnectionMode as d, ConfigDirectorLogMessageDecorator as i, ConfigState as l, ConfigDirectorClientOptions as n, ConfigDirectorLoggingLevel as o, ConfigDirectorContext as r, ConfigDirectorMetaContext as s, ConfigDirectorClient as t, ConfigValueType as u };
|
|
292
|
-
//# sourceMappingURL=types-
|
|
305
|
+
//# sourceMappingURL=types-B_mGbQaa.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-B_mGbQaa.d.mts","names":[],"sources":["../../../shared/src/types.ts","../../../js-server-sdk/src/types.ts"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
"use client";
|
|
2
|
-
var e=class{constructor(){this.handlerMap=new Map}on(e,t){let n=this.handlerMap.get(e);n?n.push(t):this.handlerMap.set(e,[t])}once(e,t){let n=this;function r(i){n.off(e,r),t.apply(n,i)}this.on(e,r)}off(e,t){let n=this.handlerMap.get(e);if(n)if(t){let e=n.indexOf(t);e>=0&&n.splice(e,1)}else this.handlerMap.set(e,[])}clear(){this.handlerMap.clear()}emit(e,t){let n=this.handlerMap.get(e);n&&n.slice().map(e=>e(t))}},t=class e extends Error{constructor(t,n){super(t),this.name=`ConfigDirectorConnectionError`,this.status=n,Object.setPrototypeOf(this,e.prototype)}},n=class e extends Error{constructor(t){super(t),this.name=`ConfigDirectorValidationError`,Object.setPrototypeOf(this,e.prototype)}},r=class e extends Error{constructor(t){super(t),this.name=`StreamClosedError`,Object.setPrototypeOf(this,e.prototype)}},i=class e extends Error{constructor(t){super(t),this.name=`MissingResponseBodyError`,Object.setPrototypeOf(this,e.prototype)}},a=class e extends Error{constructor(t){super(t),this.name=`InvalidOptionError`,Object.setPrototypeOf(this,e.prototype)}},o=class e extends Error{constructor(t){super(t),this.name=`ValueOutOfRangeError`,Object.setPrototypeOf(this,e.prototype)}};function s(e){"@babel/helpers - typeof";return s=typeof Symbol==`function`&&typeof Symbol.iterator==`symbol`?function(e){return typeof e}:function(e){return e&&typeof Symbol==`function`&&e.constructor===Symbol&&e!==Symbol.prototype?`symbol`:typeof e},s(e)}function c(e,t){if(s(e)!=`object`||!e)return e;var n=e[Symbol.toPrimitive];if(n!==void 0){var r=n.call(e,t||`default`);if(s(r)!=`object`)return r;throw TypeError(`@@toPrimitive must return a primitive value.`)}return(t===`string`?String:Number)(e)}function l(e){var t=c(e,`string`);return s(t)==`symbol`?t:t+``}function u(e,t,n){return(t=l(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function d(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function f(e){for(var t=1;t<arguments.length;t++){var n=arguments[t]==null?{}:arguments[t];t%2?d(Object(n),!0).forEach(function(t){u(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):d(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}var p=class{constructor(e){var t;this.isFirstChunk=!0,this.bufferedInput=``,this.currentEvent={data:``},this.currentEvent={data:``},this.onEvent=(t=e.onEvent)==null?(()=>{}):t,this.onRetry=e.onRetry,this.onComment=e.onComment}parse(e){let t=e;this.isFirstChunk&&(this.isFirstChunk=!1,t.startsWith(``)?t=t.slice(1):t.startsWith(``)&&(t=t.slice(3)));let n=this.scanLines(this.bufferedInput+t);for(let e of n)this.dispatchLine(e)}finish(){this.bufferedInput=``}scanLines(e){let t=[],n=0,r=0;for(;r<e.length;){let i=e[r];i===`\r`||i===`
|
|
3
|
-
`?(t.push(e.slice(n,r)),i===`\r`&&e[r+1]===`
|
|
4
|
-
`&&r++,r++,n=r):r++}return this.bufferedInput=e.slice(n),t}dispatchLine(e){if(e.startsWith(`:`)){var t;(t=this.onComment)==null||t.call(this,this.extractValue(e,1));return}if(e===``){this.emitEvent();return}this.applyField(this.parseField(e))}emitEvent(){let e=this.currentEvent.data.endsWith(`
|
|
5
|
-
`)?this.currentEvent.data.slice(0,-1):this.currentEvent.data;e!==``&&this.onEvent(f(f({},this.currentEvent),{},{id:this.lastEventId,data:e})),this.currentEvent={data:``}}applyField(e){switch(e.field){case`event`:this.currentEvent.type=e.value;break;case`data`:this.currentEvent.data+=e.value+`
|
|
6
|
-
`;break;case`id`:e.value.includes(`\0`)||(this.lastEventId=e.value);break;case`retry`:if(/^\d+$/.test(e.value)){var t;(t=this.onRetry)==null||t.call(this,Number.parseInt(e.value,10))}break;default:break}}parseField(e){let t=e.indexOf(`:`);return t===-1?{field:e,value:``}:{field:e.slice(0,t),value:this.extractValue(e,t+1)}}extractValue(e,t){return e[t]===` `?e.slice(t+1):e.slice(t)}};let m=function(e){return e.OPEN=`open`,e.CLOSED=`closed`,e.CONNECTING=`connecting`,e}({});var h=class{constructor(e){var t,n;this.DEFAULT_SHOULD_RECONNECT=()=>!0,this.DEFAULT_CALCULATE_RECONNECT_DELAY=()=>this.serverReconnectionTime,this.reconnectAttempt=0,this.abortController=new AbortController,this._readyState=m.CLOSED,this.serverReconnectionTime=2e3,this.url=e.url.toString(),this.lastEventId=e.lastEventId,this.headers=f({Accept:`text/event-stream`},e.headers);let r=e.body;this.body=typeof r==`function`?r:()=>r,this.requestOptions={method:(t=e.method)==null?`GET`:t,mode:e.mode,credentials:e.credentials,redirect:e.redirect,referrer:e.referrer,referrerPolicy:e.referrerPolicy},this._fetch=(n=e.fetch)==null?((e,t)=>fetch(e,t)):n,this._onError=this.resolveCallback(e.onError,()=>{},`onError`),this._onConnect=this.resolveCallback(e.onConnect,()=>{},`onConnect`),this._onDisconnect=this.resolveCallback(e.onDisconnect,()=>{},`onDisconnect`),this._onMessage=this.resolveCallback(e.onMessage,()=>{},`onMessage`),this._onComment=this.resolveCallback(e.onComment,()=>{},`onComment`),this._shouldReconnect=this.resolveCallback(e.shouldReconnect,this.DEFAULT_SHOULD_RECONNECT,`shouldReconnect`),this._calculateReconnectDelay=this.resolveCallback(e.calculateReconnectDelay,this.DEFAULT_CALCULATE_RECONNECT_DELAY,`calculateReconnectDelay`)}set onError(e){this._onError=this.resolveCallback(e,()=>{},`onError`)}set onMessage(e){this._onMessage=this.resolveCallback(e,()=>{},`onMessage`)}set onComment(e){this._onComment=this.resolveCallback(e,()=>{},`onComment`)}set onConnect(e){this._onConnect=this.resolveCallback(e,()=>{},`onConnect`)}set onDisconnect(e){this._onDisconnect=this.resolveCallback(e,()=>{},`onDisconnect`)}set shouldReconnect(e){this._shouldReconnect=this.resolveCallback(e,this.DEFAULT_SHOULD_RECONNECT,`shouldReconnect`)}set calculateReconnectDelay(e){this._calculateReconnectDelay=this.resolveCallback(e,this.DEFAULT_CALCULATE_RECONNECT_DELAY,`shouldReconnect`)}get readyState(){return this._readyState}connect(){this._readyState===m.CLOSED&&(this.reconnectAttempt=0,this.initiateConnection())}close(){clearTimeout(this.reconnectTimeout),this._readyState=m.CLOSED,this.abortController.abort()}initiateConnection(){this.abortController=new AbortController,this._readyState=m.CONNECTING,this._fetch(this.url,f(f({},this.requestOptions),{},{body:this.body(),headers:this.buildRequestHeaders(),signal:this.abortController.signal,cache:`no-store`})).then(e=>this.handleFetchResponse(e)).catch(e=>{if(e.name===`AbortError`||this.abortController.signal.aborted){this.close();return}this._onError(e),this.scheduleReconnect({error:e})})}async handleFetchResponse(e){var t=this;let{body:n,status:a}=e;if(a===204){t.disconnected();return}if(a>=400){t.scheduleReconnect({status:a});return}if(!n)throw new i(`The server response did not have a body`);t._readyState=m.OPEN,t._onConnect(),t.reconnectAttempt=0;let o=new p({onEvent:e=>{typeof e.id==`string`&&(t.lastEventId=e.id),t._onMessage(e)},onComment:e=>t._onComment(e),onRetry:e=>t.serverReconnectionTime=e});await t.readResponseStream(n,o),t.scheduleReconnect({status:a,error:new r(`The server response stream was closed`)})}async readResponseStream(e,t){let n=e.getReader(),r=new TextDecoder,i=!1;for(;!i;){let e=await n.read();e.value&&t.parse(r.decode(e.value,{stream:!0})),i=e.done}t.finish()}disconnected(){clearTimeout(this.reconnectTimeout),this._readyState=m.CLOSED,this._onDisconnect()}buildRequestHeaders(){let e=this.lastEventId?{"Last-Event-ID":this.lastEventId}:void 0;return f(f({},this.headers),e)}scheduleReconnect(e){if(this.abortController.signal.aborted)return;clearTimeout(this.reconnectTimeout),this.reconnectAttempt+=1;let t={attempt:this.reconnectAttempt,status:e.status,error:e.error,serverReconnectionTime:this.serverReconnectionTime};if(!this._shouldReconnect(t)){this.disconnected();return}this._readyState=m.CONNECTING;let n=this._calculateReconnectDelay(t);(!Number.isFinite(n)||n<1||n>1e3*60*60)&&(this._onError(new o(`The calculated reconnect delay is out of range: ${n}. Defaulting to ${this.serverReconnectionTime}`)),n=this.serverReconnectionTime),this.reconnectTimeout=setTimeout(()=>this.initiateConnection(),n)}resolveCallback(e,t,n){if(e==null)return t;if(typeof e!=`function`)throw new a(`${n} must be a function`);return e}};const g=e=>new h(e);var _=class{constructor(t){this.options=t,this.eventEmitter=new e,this.options=t,this.logger=t.logger,this.url=t.resolveUrl(`client/sse/v1`,t.baseUrl)}async connect(e,t){var n=this;n.eventSource&&n.close();let r=new Promise((t,r)=>{n.eventSource=g({url:n.url,method:`POST`,headers:{"Content-Type":`application/json`},fetch:n.options.fetch,body:JSON.stringify({givenContext:e,metaContext:n.options.metaContext,clientSdkKey:n.options.clientSdkKey,instanceId:n.options.instanceId}),onMessage:({data:e})=>{n.dispatchMessage(e)},onConnect:()=>{n.logger.debug(`[StreamingTransport] Connected`),t(n)},shouldReconnect:e=>{let t=!n.isStatusFatal(e.status);if(!t){let t=n.prepareFatalError(e.status,e.error);n.eventEmitter.emit(`connectionError`,t),r(t)}return t},calculateReconnectDelay:e=>{let t=n.options.connectionRetryDelay(e.attempt),r=`[StreamingTransport] Scheduling reconnect attempt #${e.attempt} in ${t}ms.`;return e.attempt<=5?n.logger.info(r):n.logger.warn(r),t},onError:e=>{n.logger.debug(`[StreamingTransport] Error: `,e)},onDisconnect:()=>{n.logger.debug(`[StreamingTransport] Disconnected`)}}),n.eventSource.connect()});return clearTimeout(n.timeoutTimer),n.timeoutTimer=void 0,Promise.race([r,new Promise(e=>{n.timeoutTimer=setTimeout(()=>e(n),t)})]).finally(()=>clearTimeout(n.timeoutTimer))}dispatchMessage(e){try{let t=JSON.parse(e);this.eventEmitter.emit(`configSetReceived`,t)}catch(e){this.logger.error(`[StreamingTransport] Error parsing and dispatching config data update: `,e)}}prepareFatalError(e,n){let r=e==null?0:e;return new t(`${`Connection failed with status: ${e==null?`unknown`:e}.`}${n?` Error: ${n}`:``}. This is an unrecoverable error, will not attempt to reconnect.`,r)}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.eventEmitter.clear()}close(){var e;(e=this.eventSource)==null||e.close(),clearTimeout(this.timeoutTimer)}dispose(){this.close(),this.clear()}};const v=e=>{let t=typeof e;if(t===`object`)try{var n,r;return(n=(r=e.constructor)==null?void 0:r.name)==null?t:n}catch(e){return t}else if(t===`function`)try{let n=e.name;return n?`function: ${n}`:t}catch(e){return t}return t},y=e=>e===`number`||e===`bigint`,b=new Set([`boolean`,`integer`,`float`]),x=(e,t)=>{let n=e.value,r=v(t);if(n==null||n===``)return{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`value-missing`};if(e.type===`json`)return E(n,t,r,e.valueId);if(typeof t==`string`)return b.has(e.type)?{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`type-mismatch`}:{parsedValue:n,parsedValueId:e.valueId,requestedType:r,usedDefault:!1,reason:`found-match`};if(typeof t==`boolean`&&(e.type===`boolean`||e.type===`string`||e.type===`enum`)){let i=S(n),a=typeof i==`boolean`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-boolean`}}if(y(typeof t)&&e.type===`integer`){let i=C(n),a=typeof i==`number`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-number`}}if(y(typeof t)&&(e.type===`float`||e.type===`enum`||e.type===`string`)){let i=w(n),a=typeof i==`number`;return{parsedValue:a?i:t,parsedValueId:a?e.valueId:void 0,requestedType:r,usedDefault:!a,reason:a?`found-match`:`invalid-number`}}return{parsedValue:t,parsedValueId:void 0,requestedType:r,usedDefault:!0,reason:`type-mismatch`}},S=e=>{if(!e)return;let t=e.toLowerCase();if(!(t!=`true`&&t!=`false`))return t===`true`},C=e=>{let t=T(e);return t==null?void 0:Math.trunc(t)},w=e=>T(e),T=e=>{if(!e||!ee(e))return;let t=Number(e);if(!(isNaN(t)||!isFinite(t)))return t},ee=e=>{for(let t of e)if(!(t>=`0`&&t<=`9`)&&!`+-.eE`.includes(t))return!1;return!0},E=(e,t,n,r)=>{if(typeof t==`string`)return{parsedValue:e,parsedValueId:r,requestedType:n,usedDefault:!1,reason:`found-match`};try{let i=JSON.parse(e);return D(i,t)?{parsedValue:i,parsedValueId:r,requestedType:n,usedDefault:!1,reason:`found-match`}:{parsedValue:t,parsedValueId:void 0,requestedType:n,usedDefault:!0,reason:`type-mismatch`}}catch(e){return{parsedValue:t,parsedValueId:void 0,requestedType:n,usedDefault:!0,reason:`invalid-json`}}},D=(e,t)=>{if(e===null)return!1;let n=typeof t;return n===`bigint`?typeof e==`number`:typeof e===n},O={off:-1,error:0,warn:1,info:2,debug:3},k=()=>{let e={year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,timeZoneName:`short`};try{return new Intl.DateTimeFormat(void 0,f(f({},e),{},{fractionalSecondDigits:3}))}catch(t){return new Intl.DateTimeFormat(void 0,e)}};var A=class{constructor(e,t){this.level=e,this.decorator=t,this.level=e,this.decorator=t,this.dateFormatter=k()}debug(e,...t){this.log(console.debug,`debug`,e,...t)}info(e,...t){this.log(console.info,`info`,e,...t)}warn(e,...t){this.log(console.warn,`warn`,e,...t)}error(e,...t){this.log(console.error,`error`,e,...t)}log(e,t,n,...r){if(O[this.level]>=O[t]){var i;e(`[${this.dateFormatter.format(new Date)}] ${(i=this.decorator)==null?void 0:i.decorateMessage(n)}`,...r)}}},j=class{decorateMessage(e){return`[ConfigDirector:js-client-sdk] ${e}`}};const M=(e,t)=>new A(e==null?`warn`:e,t==null?new j:t),N=(e,t)=>new URL(e,t==null?void 0:t.toString()),P=e=>{if(e)try{return new URL(e)}catch(t){throw new n(`Invalid URL '${e}'. Parsing failed: ${t}`)}},F=`https://client-sdk-api.configdirector.com`,I=(e,t)=>e===void 0?{seconds:t.defaultSeconds,warning:void 0}:e>=t.minimumSeconds?{seconds:e,warning:void 0}:{seconds:t.minimumSeconds,warning:`pollingInterval of ${e} seconds is below the minimum of ${t.minimumSeconds} seconds. Using ${t.minimumSeconds} seconds.`},L=()=>typeof crypto<`u`&&typeof crypto.randomUUID==`function`?crypto.randomUUID():`xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`.replace(/[xy]/g,e=>{let t=Math.random()*16|0;return(e===`x`?t:t&3|8).toString(16)}),R=`configdirector-sdk:instance-id`,z=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/,B=(e,t)=>{let n=t;for(let t=0;t<e.length;t++)n^=e.charCodeAt(t),n=Math.imul(n,16777619);return n>>>0},V=(e,t)=>{let n=`configdirector.instanceId.v1|${e}|${t}`,r=B(n,2166136261);return B(`${r}|${n}`,16777619).toString(16).padStart(8,`0`)+r.toString(16).padStart(8,`0`)},H=()=>{try{var e;return(e=globalThis.localStorage)==null?void 0:e}catch(e){return}},U=e=>{if(!e||typeof e!=`object`)return!1;let{v:t,id:n,createdAt:r,checksum:i}=e;return t!==1||typeof n!=`string`||typeof i!=`string`||typeof r!=`number`||!Number.isInteger(r)||r<=0||!z.test(n)?!1:i===V(n,r)},W=(e,t)=>{let n;try{n=e.getItem(R)}catch(e){t==null||t.debug(`[ConfigDirectorClient] Could not read the stored instance id, generating a new one`,e);return}if(!n)return;let r;try{r=JSON.parse(n)}catch(e){t==null||t.debug(`[ConfigDirectorClient] The stored instance id is not valid JSON, generating a new one`);return}if(!U(r)){t==null||t.debug(`[ConfigDirectorClient] The stored instance id failed validation, generating a new one`);return}let i=Date.now()-r.createdAt;if(i<0||i>=216e5){t==null||t.debug(`[ConfigDirectorClient] The stored instance id has expired, generating a new one`);return}return r.id},G=(e,t,n)=>{let r=Date.now(),i={v:1,id:t,createdAt:r,checksum:V(t,r)};try{e.setItem(R,JSON.stringify(i))}catch(e){n==null||n.debug(`[ConfigDirectorClient] Could not persist the instance id`,e)}},K=e=>{let t=H();if(!t)return L();let n=W(t,e);if(n)return n;let r=L();return G(t,r,e),r};var q=class{constructor(){this.fatalError=!1}clearPollingInterval(){clearInterval(this.pollingInterval)}schedulePollingInterval(e){clearInterval(this.pollingInterval),!(this.pollingIntervalSeconds<=0)&&(this.pollingInterval=setInterval(e,this.pollingIntervalSeconds*1e3))}async handleNonOkResponse(e){var n=this;if(!e.ok)throw n.isStatusFatal(e.status)?(n.fatalError=!0,n.close(),n.prepareFatalResponseStatusError(e.status,await e.text())):new t(`Connection failed with status: ${e.status}`,e.status)}handleFetchError(e){throw this.isFetchErrorFatal(e)?(this.fatalError=!0,this.close(),new t(`Connection failed with fatal error: ${e}. This is an unrecoverable error, retry attempts will be ignored.`)):e instanceof SyntaxError?new t(`Failed to parse the response from the server: ${e}`):new t(`Connection failed with error: ${e}.`)}prepareFatalResponseStatusError(e,n){var r,i;let a=e==null?0:e;return new t(`${`Connection failed with status: ${e==null?`unknown`:e}`}${((r=n==null||(i=n.trim())==null?void 0:i.length)==null?0:r)>0?` (${n})`:``}. This is an unrecoverable error, retry attempts will be ignored.`,a)}isStatusFatal(e){return!!e&&e>=400&&e<500&&e!=429}isFetchErrorFatal(e){return(e==null?void 0:e.name)===`NotAllowedError`}get isConnected(){return this.pollingInterval!==void 0}close(){clearInterval(this.pollingInterval),this.pollingInterval=void 0}dispose(){this.close(),this.clear()}};const J=async(e,t,n,r)=>{let i=new AbortController,a=setTimeout(()=>{r.debug(`[fetchWithTimeout] Reached timeout, aborting request`),i.abort()},e);try{let e=await fetch(typeof t==`string`||t instanceof Request?t:t.toString(),f(f({},n),{},{signal:i.signal}));return clearTimeout(a),e}catch(e){throw r.warn(`[fetchWithTimeout] Fetch error: `,e),clearTimeout(a),e}};var Y=class extends q{constructor(t){var n;super(),this.options=t,this.eventEmitter=new e,this.options=t,this.logger=t.logger,this.url=t.resolveUrl(`client/polling/v1`,t.baseUrl),this.pollingIntervalSeconds=(n=t.pollingInterval)==null?60:n}async connect(e,t){var n=this;n.clearPollingInterval();try{await n.fetchConfigs(e,t)}finally{n.fatalError||n.schedulePollingInterval(()=>{n.fetchConfigs(e,t).catch(e=>{n.logger.error(`[PollingTransport] Error during polling:`,e)})})}return n}async fetchConfigs(e,t){var n=this;if(n.fatalError){n.logger.warn(`[PollingTransport] There was a prior unrecoverable error. Ignoring attempt to reconnect.`);return}try{let r=await J(t,n.url,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({givenContext:e,metaContext:n.options.metaContext,clientSdkKey:n.options.clientSdkKey,instanceId:n.options.instanceId,lastUpdateTimestamp:n.lastUpdateTimestamp})},n.logger);if(await n.handleNonOkResponse(r),r.status==200){let e=JSON.parse(await r.text());n.lastUpdateTimestamp=e.timestamp,n.eventEmitter.emit(`configSetReceived`,e)}}catch(e){try{n.handleFetchError(e)}catch(e){throw n.fatalError&&n.eventEmitter.emit(`connectionError`,e),e}}}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.eventEmitter.clear()}};const X=e=>{try{return e(globalThis)}catch(e){return}},Z=()=>X(e=>{var t;return(t=e.navigator)==null?void 0:t.userAgent}),Q=()=>X(e=>{var t;return(t=e.location)==null?void 0:t.host});var te=class{constructor(t,n,r,i,a){var o,s,c,l,u,d,p,m,h,g,_,v,y,b;this.handlersMap=new Map,this.eventEmitter=new e,this.ready=!1,this.initializing=!1,this.hasReceivedConfigSet=!1,this.logger=(o=i==null?void 0:i.logger)==null?M():o,this.instanceId=K(this.logger),this.timeout=(s=i==null||(c=i.connection)==null?void 0:c.timeout)==null?3e3:s,this.validateSdkKeyPresence(n);let x=(l=a==null?void 0:a.urlFactory)==null?N:l,S=(u=this.parseUrl(i==null||(d=i.connection)==null?void 0:d.url,x))==null?F:u;this.connectionMode=(p=i==null||(m=i.connection)==null?void 0:m.mode)==null?`streaming`:p,this.telemetryClient=t,this.transport=(h=a==null?void 0:a.transport)==null?this.buildTransport(n,r,S,x,i,a):h,this.transport.on(`configSetReceived`,e=>{var t;this.hasReceivedConfigSet=!0,(t=this.readyResolve)==null||t.call(this);let n=this.findKeysRemovedBy(e);!this.configSet||e.kind==`full`?this.configSet=e:this.configSet.configs=f(f({},this.configSet.configs),e.configs);let r=Object.keys(e.configs);this.emit(`configsUpdated`,{keys:r,removedKeys:n}),this.updateWatchers([...r,...n]),this.logger.debug(`[ConfigDirectorClient] ConfigSet updated from server:`,{keys:r,removedKeys:n})}),this.transport.on(`connectionError`,e=>{this.initializing=!1,this.logger.error(`[ConfigDirectorClient] The connection encountered an unrecoverable error and will not be retried. Configs will no longer receive updates.`,e),this.emit(`connectionError`,{error:e})}),this.registerHandler(`clientReady`,i==null||(g=i.hooks)==null?void 0:g.clientReady),this.registerHandler(`configEvaluated`,i==null||(_=i.hooks)==null?void 0:_.configEvaluated),this.registerHandler(`configsUpdated`,i==null||(v=i.hooks)==null?void 0:v.configsUpdated),this.registerHandler(`contextUpdated`,i==null||(y=i.hooks)==null?void 0:y.contextUpdated),this.registerHandler(`connectionError`,i==null||(b=i.hooks)==null?void 0:b.connectionError)}registerHandler(e,t){if(!t)return;let n=Array.isArray(t)?t:[t];for(let t of n)typeof t==`function`&&this.on(e,t)}resolvePollingIntervalForMode(e){if(this.connectionMode!==`polling`)return;let t=I(e,{defaultSeconds:60,minimumSeconds:30});return t.warning&&this.logger.warn(`[ConfigDirectorClient] ${t.warning}`),t.seconds}buildTransport(e,t,n,r,i,a){var o,s;return new(this.getTransportConstructor(this.connectionMode))({instanceId:this.instanceId,clientSdkKey:e,baseUrl:n,resolveUrl:r,metaContext:f(f({},i==null?void 0:i.metadata),{},{sdkName:t.sdkName,sdkVersion:t.sdkVersion,userAgent:Z(),host:Q()}),logger:this.logger,fetch:a==null?void 0:a.fetch,connectionRetryDelay:(o=a==null?void 0:a.connectionRetryDelay)==null?(e=>2**Math.min(e,9)*1e3):o,pollingInterval:this.resolvePollingIntervalForMode(i==null||(s=i.connection)==null?void 0:s.pollingInterval)})}getTransportConstructor(e){switch(e){case`polling`:return Y;default:return _}}async initialize(e){var t=this;t.hasReceivedConfigSet||(t.initializing=!0),await t.connectToTransport(e,`initialization`)}async updateContext(e){await this.connectToTransport(e,`context update`)}get context(){return this.currentContext}async connectToTransport(e,t){var n=this;try{n.ready=!1,n.readyPromise=new Promise(e=>{n.readyResolve=e}).then(e=>{e||(n.ready=!0,n.initializing=!1,n.emit(`clientReady`,{action:t}),n.logger.debug(`[ConfigDirectorClient] Received initial payload from the server, client is ready`))});let r=new Date().getTime();await n.transport.connect(e==null?{}:e,n.timeout,t),n.currentContext=e,n.telemetryClient.updateContext(e).catch(e=>n.logger.warn(`[ConfigDirectorClient] Telemetry could not update the context: `,e)),n.emit(`contextUpdated`,{context:e});let i=new Date().getTime()-r,a=n.timeout-i;clearTimeout(n.timeoutTimer),n.timeoutTimer=void 0,a>0&&await Promise.race([n.readyPromise,new Promise(e=>{n.timeoutTimer=setTimeout(()=>e(),a)})]).finally(()=>clearTimeout(n.timeoutTimer)),n.ready||n.logger.warn(`[ConfigDirectorClient] Timed out waiting for ${t} after ${n.timeout}ms. The client will continue to retry since there were no fatal errors detected. Configs will return the default value until the connection succeeds.`)}catch(e){n.logger.error(`[ConfigDirectorClient] An error occurred during ${t}: `,e)}}findKeysRemovedBy(e){return!this.configSet||e.kind!=`full`?[]:Object.keys(this.configSet.configs).filter(t=>!Object.prototype.hasOwnProperty.call(e.configs,t))}updateWatchers(e){e.forEach(e=>this.updateWatchersForConfig(e))}updateWatchersForConfig(e){var t,n;let r=(t=this.configSet)==null?void 0:t.configs[e];(n=this.handlersMap.get(e))==null||n.forEach(t=>{let n=this.getValueFromConfigState(e,r,t.defaultValue);t.handler(n)})}watch(e,t,n){this.validateDefaultValue(t);let r=this.handlersMap.get(e),i={handler:n,defaultValue:t,requestedType:typeof t};return r?r.push(i):this.handlersMap.set(e,[i]),()=>this.unwatch(e,n)}unwatch(e,t){let n=this.handlersMap.get(e);if(n)if(t){let e=n.findIndex(e=>e.handler==t);e>=0&&(n==null||n.splice(e,1))}else n.splice(0)}getValue(e,t){var n;this.validateDefaultValue(t);let r=(n=this.configSet)==null?void 0:n.configs[e];return this.getValueFromConfigState(e,r,t)}getValueFromConfigState(e,t,n){var r,i;if(!t){var a;this.logger.debug(`[ConfigDirectorClient] No config state found for '${e}', returning default value '${n}'`);let t=this.isReady?`config-state-missing`:`client-not-ready`;return this.telemetryClient.evaluatedConfig({contextId:(a=this.currentContext)==null?void 0:a.id,key:e,defaultValue:n,requestedType:v(n),evaluatedValue:n,usedDefault:!0,evaluationReason:t}),this.dispatchEvaluationEvent({key:e,value:n,isDefaultValue:!0,reason:t,context:this.context}),n}let o=x(t,n);return this.telemetryClient.evaluatedConfig({contextId:(r=this.currentContext)==null?void 0:r.id,type:t.type,key:e,defaultValue:n,requestedType:o.requestedType,evaluatedValue:o.parsedValue,evaluatedValueId:o.parsedValueId,usedDefault:o.usedDefault,evaluationReason:o.reason}),this.dispatchEvaluationEvent({key:e,value:o.parsedValue,valueId:(i=o.parsedValueId)==null?void 0:i,isDefaultValue:o.usedDefault,reason:o.reason,context:this.context}),this.logger.debug(`[ConfigDirectorClient] Evaluated '${e}' to '${o.parsedValue}'`),o.parsedValue}dispatchEvaluationEvent(e){setTimeout(()=>this.emit(`configEvaluated`,{evaluation:e}),0)}emit(e,t){try{this.eventEmitter.emit(e,t)}catch(t){this.logger.error(`[ConfigDirectorClient] Error executing event handlers for '${e}'`,t)}}parseUrl(e,t){if(e)try{return t(e)}catch(t){throw new n(`Invalid base URL '${e}'. Parsing failed: ${t}`)}}validateSdkKeyPresence(e){if(!e||e.trim().length==0)throw new n(`No client SDK key was provided, the client cannot be instantiated without a valid client SDK key`)}validateDefaultValue(e){if(e==null)throw new n(`Invalid default value. The default value for a config must be defined and non-null.`);if(typeof e==`function`)throw new n(`Invalid default value. The default value for a config cannot be a function.`)}get isReady(){return this.ready}get isInitializing(){return this.initializing}on(e,t){this.eventEmitter.on(e,t)}off(e,t){this.eventEmitter.off(e,t)}clear(){this.logger.debug(`[ConfigDirectorClient] clear() has been called, removing all observers`),this.eventEmitter.clear(),this.handlersMap.clear()}unwatchAll(){this.handlersMap.clear()}pauseNetwork(){this.logger.debug(`[ConfigDirectorClient] pauseNetwork() called, pausing transport connection`),clearTimeout(this.timeoutTimer),this.timeoutTimer=void 0,this.transport.close(),this.ready=!1}async resumeNetwork(){var e=this;await e.connectToTransport(e.currentContext,`network resume`)}async close(){var e=this,t;e.logger.debug(`[ConfigDirectorClient] close() has been called, closing connection to server`),clearTimeout(e.timeoutTimer),(t=e.readyResolve)==null||t.call(e,!0),e.telemetryClient.close().catch(t=>e.logger.warn(`[ConfigDirectorClient] Telemetry could not close: `,t)),e.transport.close(),e.ready=!1,e.initializing=!1}dispose(){this.clear(),this.close()}};const $=Symbol.for(`@configdirector/installed-test-client`),ne=()=>globalThis[$];export{N as a,x as c,n as d,e as f,F as i,f as l,ne as n,P as o,te as r,M as s,$ as t,t as u};
|
|
7
|
-
//# sourceMappingURL=installedTestClient-CDdDsfVQ.mjs.map
|