@vard-app/sdk 0.1.7 → 0.1.8
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/README.md +4 -4
- package/dist/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +32 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +32 -5
- package/dist/index.mjs.map +1 -1
- package/dist/next.d.mts +5 -0
- package/dist/next.d.ts +5 -0
- package/dist/next.js +34 -5
- package/dist/next.js.map +1 -1
- package/dist/next.mjs +34 -5
- package/dist/next.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ export default async function Page() {
|
|
|
88
88
|
|
|
89
89
|
## Environment Variables
|
|
90
90
|
|
|
91
|
-
| Variable | Description
|
|
92
|
-
| --------------- |
|
|
93
|
-
| `VARD_API_KEY` | Your workspace API Key (Required for production)
|
|
94
|
-
| `VARD_API_BASE` | Optional custom API base (Defaults to vard.app)
|
|
91
|
+
| Variable | Description |
|
|
92
|
+
| --------------- | ------------------------------------------------ |
|
|
93
|
+
| `VARD_API_KEY` | Your workspace API Key (Required for production) |
|
|
94
|
+
| `VARD_API_BASE` | Optional custom API base (Defaults to vard.app) |
|
package/dist/index.d.mts
CHANGED
|
@@ -222,6 +222,11 @@ interface VardFetchStoreOptions {
|
|
|
222
222
|
* Enable verbose logging for requests and responses.
|
|
223
223
|
*/
|
|
224
224
|
debug?: boolean;
|
|
225
|
+
/**
|
|
226
|
+
* Time in seconds to cache the fetched variables in memory.
|
|
227
|
+
* Defaults to 60 (1 minute).
|
|
228
|
+
*/
|
|
229
|
+
ttl?: number;
|
|
225
230
|
}
|
|
226
231
|
/**
|
|
227
232
|
* Creates a universal VardStore that fetches variable values from the Vard API.
|
package/dist/index.d.ts
CHANGED
|
@@ -222,6 +222,11 @@ interface VardFetchStoreOptions {
|
|
|
222
222
|
* Enable verbose logging for requests and responses.
|
|
223
223
|
*/
|
|
224
224
|
debug?: boolean;
|
|
225
|
+
/**
|
|
226
|
+
* Time in seconds to cache the fetched variables in memory.
|
|
227
|
+
* Defaults to 60 (1 minute).
|
|
228
|
+
*/
|
|
229
|
+
ttl?: number;
|
|
225
230
|
}
|
|
226
231
|
/**
|
|
227
232
|
* Creates a universal VardStore that fetches variable values from the Vard API.
|
package/dist/index.js
CHANGED
|
@@ -35,11 +35,14 @@ function createVardFetchStore(options = {}) {
|
|
|
35
35
|
apiBase = options.apiBase ?? VARD_API_HOST,
|
|
36
36
|
apiKey = options.apiKey ?? process.env.VARD_API_KEY,
|
|
37
37
|
fetchOptions = {},
|
|
38
|
-
debug = options.debug ?? false
|
|
38
|
+
debug = options.debug ?? false,
|
|
39
|
+
ttl = options.ttl ?? 60
|
|
39
40
|
} = options;
|
|
40
41
|
let resolvedValues = null;
|
|
41
42
|
let structuredContent = null;
|
|
42
43
|
let fetchPromise = null;
|
|
44
|
+
let lastFetchTime = 0;
|
|
45
|
+
let lastLogTime = 0;
|
|
43
46
|
async function fetchValues() {
|
|
44
47
|
const isDevelopment = process.env.NODE_ENV === "development";
|
|
45
48
|
if (!apiKey) {
|
|
@@ -112,13 +115,37 @@ function createVardFetchStore(options = {}) {
|
|
|
112
115
|
return structuredContent;
|
|
113
116
|
},
|
|
114
117
|
async prefetch() {
|
|
115
|
-
|
|
118
|
+
const now = Date.now();
|
|
119
|
+
if (resolvedValues) {
|
|
120
|
+
const elapsed = Math.floor((now - lastFetchTime) / 1e3);
|
|
121
|
+
if (elapsed < ttl) {
|
|
122
|
+
if (now - lastLogTime > 2e3) {
|
|
123
|
+
if (debug) {
|
|
124
|
+
console.log(`[vard] Cache HIT. Next fresh check in ${ttl - elapsed}s.`);
|
|
125
|
+
}
|
|
126
|
+
lastLogTime = now;
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
116
131
|
if (!fetchPromise) {
|
|
132
|
+
if (debug) {
|
|
133
|
+
if (resolvedValues) {
|
|
134
|
+
console.log(`[vard] Cache STALE (${ttl}s TTL expired). Fetching fresh data...`);
|
|
135
|
+
} else {
|
|
136
|
+
console.log(`[vard] Cache COLD. Initializing fresh fetch...`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
117
139
|
fetchPromise = fetchValues();
|
|
118
140
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
141
|
+
try {
|
|
142
|
+
const result = await fetchPromise;
|
|
143
|
+
resolvedValues = result.variables;
|
|
144
|
+
structuredContent = result.structured;
|
|
145
|
+
lastFetchTime = Date.now();
|
|
146
|
+
} finally {
|
|
147
|
+
fetchPromise = null;
|
|
148
|
+
}
|
|
122
149
|
}
|
|
123
150
|
};
|
|
124
151
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/fetch-store.ts","../src/client.ts","../src/schema.ts"],"sourcesContent":["// Public entrypoint for @vard/sdk\nexport { createVard } from \"./client\";\nexport { createVardFetchStore } from \"./fetch-store\";\nexport { v } from \"./schema\";\nexport type { VardSchema, InferSchema, VardSchemaFragment, MergeSchema } from \"./schema\";\nexport type {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableType,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n} from \"./types\";\n","/**\n * The base URL for the Vard API.\n * Reads from VARD_API_HOST env var; falls back to https://vard.app.\n */\nexport const VARD_API_HOST: string =\n process.env.VARD_API_HOST ?? \"https://vard.app\";\n","import type { VardStore } from \"./types\";\nimport { VARD_API_HOST } from \"./constants\";\n\nexport interface VardFetchStoreOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Defaults to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Custom fetch options (headers, etc.)\n */\n fetchOptions?: RequestInit;\n\n /**\n * Enable verbose logging for requests and responses.\n */\n debug?: boolean;\n}\n\n/**\n * Creates a universal VardStore that fetches variable values from the Vard API.\n * Works in any environment with a global `fetch` (Browsers, Node 18+, Bun, Deno).\n */\nexport function createVardFetchStore(\n options: VardFetchStoreOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const {\n apiBase = options.apiBase ?? VARD_API_HOST,\n apiKey = options.apiKey ?? process.env.VARD_API_KEY,\n fetchOptions = {},\n debug = options.debug ?? false,\n } = options;\n\n let resolvedValues: Map<string, unknown> | null = null;\n let structuredContent: any = null;\n let fetchPromise: Promise<{ variables: Map<string, unknown>; structured: any }> | null = null;\n\n async function fetchValues(): Promise<{ variables: Map<string, unknown>; structured: any }> {\n const isDevelopment = process.env.NODE_ENV === \"development\";\n\n if (!apiKey) {\n if (!isDevelopment) {\n console.error(\n \"\\x1b[31m[vard] Missing configuration! VARD_API_KEY is not set.\\x1b[0m\\n\" +\n \"Please set this environment variable in your production environment.\"\n );\n } else {\n console.warn(\n \"[vard] No API Key found. Running in local fallback mode (using default values).\"\n );\n }\n return { variables: new Map(), structured: {} };\n }\n\n const url = `${apiBase}/api/content/variables`;\n\n if (debug) {\n console.log(`[vard] Request: GET ${url}`);\n console.log(`[vard] Headers:`, {\n \"X-Vard-API-Key\": apiKey.substring(0, 10) + \"...\",\n ...fetchOptions.headers,\n });\n }\n\n try {\n const res = await fetch(url, {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n \"X-Vard-API-Key\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errorMsg = `[vard] Failed to fetch variables from ${url} (Status: ${res.status} ${res.statusText})`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`);\n return { variables: new Map(), structured: {} };\n }\n\n const data = (await res.json()) as Record<string, unknown>;\n\n if (debug) {\n console.log(`[vard] Response (${res.status}):`, data);\n }\n\n // Flatten the nested structure into the internal Map for key-based lookups\n const variablesMap = new Map<string, unknown>();\n flattenObject(data, \"\", variablesMap);\n\n return {\n variables: variablesMap,\n structured: data,\n };\n } catch (err) {\n const errorMsg = `[vard] Network error fetching variables from ${url}`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`, err);\n return { variables: new Map(), structured: {} };\n }\n }\n\n function flattenObject(obj: any, prefix: string, map: Map<string, unknown>) {\n if (typeof obj !== \"object\" || obj === null) return;\n\n for (const [key, value] of Object.entries(obj)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n // If it's an array, we treat it as a single value (e.g. a collection)\n if (Array.isArray(value)) {\n map.set(fullKey, value);\n } else if (typeof value === \"object\" && value !== null) {\n flattenObject(value, fullKey, map);\n } else {\n map.set(fullKey, value);\n }\n }\n }\n\n return {\n get(key: string): unknown {\n return resolvedValues?.get(key);\n },\n\n getStructured(): any {\n return structuredContent;\n },\n\n async prefetch(): Promise<void> {\n if (resolvedValues) return;\n if (!fetchPromise) {\n fetchPromise = fetchValues();\n }\n const result = await fetchPromise;\n resolvedValues = result.variables;\n structuredContent = result.structured;\n },\n };\n}\n","import {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n VardVariableType,\n} from \"./types\";\nimport {\n VardSchema,\n InferSchema,\n VardField,\n VardCollection,\n VardSchemaFragment,\n MergeSchema,\n} from \"./schema\";\nimport { createVardFetchStore } from \"./fetch-store\";\nimport { VARD_API_HOST } from \"./constants\";\n\n// ─────────────────────────────────────────────\n// No-op store (used in local dev when no apiKey is set)\n// ─────────────────────────────────────────────\n\nlet hasLoggedNoop = false;\nconst noopStore: VardStore = {\n get: () => {\n if (!hasLoggedNoop && process.env.NODE_ENV !== \"test\") {\n console.warn(\n \"[vard] Using default values for all variables because no Store was provided to createVard().\"\n );\n hasLoggedNoop = true;\n }\n return undefined;\n },\n};\n\n// ─────────────────────────────────────────────\n// createVard — the main SDK factory\n// ─────────────────────────────────────────────\n\n/**\n * Creates a Vard client instance. Call this once at the top of your site\n * (e.g. in `lib/vard.ts`) and export the result.\n */\nexport function createVard<S extends VardSchema = any>(\n options: VardOptions<S> = {}\n): VardClient<S> {\n const store: VardStore =\n options.store ?? (options.apiKey ? createVardFetchStore(options) : noopStore);\n\n // Registry of all declared variables — used by CLI + build pipeline\n const registry: VardVariableDefinition[] = [];\n\n function register<T>(def: VardVariableDefinition<T>): T {\n if (!registry.find((d) => d.key === def.key)) {\n registry.push(def as VardVariableDefinition);\n }\n\n const stored = store.get(def.key);\n if (stored !== undefined && stored !== null) {\n return stored as T;\n }\n\n return def.defaultValue;\n }\n\n // ─────────────────────────────────────────────\n // Schema Traversal\n // ─────────────────────────────────────────────\n\n function flattenSchema(schema: VardSchema, prefix = \"\"): any {\n const result: any = {};\n\n for (const [key, value] of Object.entries(schema)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === \"object\" && value !== null && \"type\" in value) {\n // It's a field or collection\n const field = value as VardField | VardCollection;\n\n if (field.type === \"collection\") {\n // Flatten collection schema but keep it as a 'list' type for the registry\n const collection = field as VardCollection;\n const listItemSchema: Record<string, string> = {};\n for (const [fKey, fVal] of Object.entries(collection.schema)) {\n listItemSchema[fKey] = (fVal as VardField).type;\n }\n\n register({\n key: fullKey,\n label: labelFromKey(key),\n type: \"list\",\n defaultValue: [],\n editableBy: \"member\",\n listItemSchema: listItemSchema as VardListItemSchema,\n isCollection: true,\n });\n\n // In the returned object, this remains a placeholder or is proxied to the store\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? [],\n enumerable: true,\n });\n } else {\n // It's a plain field\n const vardField = field as VardField;\n register({\n key: fullKey,\n label: vardField.label ?? labelFromKey(key),\n description: vardField.description,\n type: vardField.type,\n defaultValue: vardField.default,\n editableBy: vardField.editableBy ?? \"member\",\n group: vardField.group,\n });\n\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? vardField.default,\n enumerable: true,\n });\n }\n } else if (typeof value === \"object\" && value !== null) {\n // It's a nested object\n result[key] = flattenSchema(value as VardSchema, fullKey);\n }\n }\n\n return result;\n }\n\n // Auto-sync schema in development\n if (options.schema && process.env.NODE_ENV === \"development\" && options.apiKey) {\n flattenSchema(options.schema);\n const definitions = [...registry];\n const apiBase = VARD_API_HOST;\n\n fetch(`${apiBase}/api/content/variables/sync`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Vard-API-Key\": options.apiKey,\n },\n body: JSON.stringify({\n definitions,\n schema: options.schema,\n }),\n }).catch((err) => console.warn(\"[vard] Auto-sync failed:\", err));\n }\n\n const client: VardClient<S> = {\n define<NS extends VardSchema>(schema: NS): InferSchema<NS> {\n return flattenSchema(schema) as InferSchema<NS>;\n },\n\n async get(): Promise<InferSchema<S>> {\n if (store.prefetch) {\n await store.prefetch();\n }\n if (store.getStructured) {\n const structured = store.getStructured();\n if (structured && Object.keys(structured).length > 0) {\n return structured as InferSchema<S>;\n }\n }\n return flattenSchema(options.schema ?? {}) as InferSchema<S>;\n },\n\n string(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"string\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n richtext(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"richtext\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n color(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"color\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n image(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"image\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n boolean(key, fallback, opts: VardVariableOptions = {}) {\n return register<boolean>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"boolean\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n group: opts.group,\n });\n },\n\n list<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: VardVariableOptions = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n });\n },\n\n collection<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: Omit<VardVariableOptions, \"type\"> = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n isCollection: true,\n });\n },\n\n global: {\n string(key, fallback, opts = {}) {\n return client.string(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n richtext(key, fallback, opts = {}) {\n return client.richtext(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n color(key, fallback, opts = {}) {\n return client.color(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n image(key, fallback, opts = {}) {\n return client.image(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n boolean(key, fallback, opts = {}) {\n return client.boolean(key, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n list(key, schema, fallback, opts = {}) {\n return client.list(key, schema, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n },\n\n extend<E extends VardSchema>(fragment: VardSchemaFragment<E>): VardClient<MergeSchema<S, E>> {\n // Merge the base schema with the fragment — the fragment keys win on collision\n const mergedSchema = { ...(options.schema ?? {}), ...fragment } as unknown as MergeSchema<\n S,\n E\n >;\n // Return a new client with the merged schema, sharing the same store & registry.\n // We pass the in-memory store directly so there is no second fetch.\n return createVard<MergeSchema<S, E>>({\n ...options,\n schema: mergedSchema,\n store,\n });\n },\n\n getDefinitions() {\n return [...registry];\n },\n store,\n };\n\n return client;\n}\n\n// ─────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────\n\nfunction labelFromKey(key: string): string {\n const lastSegment = key.split(\".\").pop() ?? key;\n return lastSegment\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (c) => c.toUpperCase())\n .trim();\n}\n","import { VardVariableType, VardRole } from \"./types\";\n\nexport interface VardFieldOptions<T = any> {\n label?: string;\n description?: string;\n editableBy?: VardRole;\n group?: string;\n default?: T;\n}\n\nexport interface VardField<T = any> extends VardFieldOptions<T> {\n type: VardVariableType;\n}\n\nexport interface VardCollection<S extends Record<string, VardField | any> = any> {\n type: \"collection\";\n schema: S;\n}\n\nexport type VardSchemaValue =\n | VardField\n | VardCollection\n | boolean\n | { [key: string]: VardSchemaValue };\n\nexport type VardSchema = Record<string, VardSchemaValue>;\n\n/**\n * A branded schema fragment created with `v.schema()`. Use with `vard.extend()`\n * to compose schemas defined across multiple files.\n */\nexport type VardSchemaFragment<S extends VardSchema> = S & {\n readonly __fragment: true;\n};\n\n/**\n * Merges two VardSchema types, with B's keys overriding A on collision.\n */\nexport type MergeSchema<A extends VardSchema, B extends VardSchema> = Omit<A, keyof B> & B;\n\n// ─────────────────────────────────────────────\n// The `v` helper object for schema definition\n// ─────────────────────────────────────────────\n\nexport const v = {\n string: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"string\",\n default: defaultValue,\n ...opts,\n }),\n\n richtext: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"richtext\",\n default: defaultValue,\n ...opts,\n }),\n\n color: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"color\",\n default: defaultValue,\n ...opts,\n }),\n\n image: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"image\",\n default: defaultValue,\n ...opts,\n }),\n\n boolean: (\n defaultValue?: boolean,\n opts: Omit<VardFieldOptions<boolean>, \"default\"> = {}\n ): VardField<boolean> => ({\n type: \"boolean\",\n default: defaultValue,\n ...opts,\n }),\n\n collection: <S extends Record<string, VardField | any>>(schema: S): VardCollection<S> => ({\n type: \"collection\",\n schema,\n }),\n\n /**\n * Creates a reusable schema fragment that can be merged into a Vard client\n * via `vard.extend(fragment)`. Co-locate this with your page/component.\n *\n * @example\n * // app/therapists/schema.ts\n * export const therapistSchema = v.schema({\n * therapists: v.collection({ name: v.string(), photo: v.image() }),\n * });\n *\n * // app/therapists/page.tsx\n * const { therapists } = await vard.extend(therapistSchema).get();\n */\n schema: <S extends VardSchema>(schema: S): VardSchemaFragment<S> =>\n schema as VardSchemaFragment<S>,\n};\n\n// ─────────────────────────────────────────────\n// Type inference for schema objects\n// ─────────────────────────────────────────────\n\nexport type InferSchema<T> = 0 extends 1 & T\n ? any\n : T extends VardField<infer U>\n ? U\n : T extends VardCollection<infer S>\n ? InferSchema<S>[]\n : T extends VardSchemaFragment<infer S>\n ? InferSchema<S>\n : T extends Record<string, any>\n ? { [K in keyof T as K extends \"__fragment\" ? never : K]: InferSchema<T[K]> }\n : T;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/fetch-store.ts","../src/client.ts","../src/schema.ts"],"sourcesContent":["// Public entrypoint for @vard/sdk\nexport { createVard } from \"./client\";\nexport { createVardFetchStore } from \"./fetch-store\";\nexport { v } from \"./schema\";\nexport type { VardSchema, InferSchema, VardSchemaFragment, MergeSchema } from \"./schema\";\nexport type {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableType,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n} from \"./types\";\n","/**\n * The base URL for the Vard API.\n * Reads from VARD_API_HOST env var; falls back to https://vard.app.\n */\nexport const VARD_API_HOST: string = process.env.VARD_API_HOST ?? \"https://vard.app\";\n","import type { VardStore } from \"./types\";\nimport { VARD_API_HOST } from \"./constants\";\n\nexport interface VardFetchStoreOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Defaults to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Custom fetch options (headers, etc.)\n */\n fetchOptions?: RequestInit;\n\n /**\n * Enable verbose logging for requests and responses.\n */\n debug?: boolean;\n\n /**\n * Time in seconds to cache the fetched variables in memory.\n * Defaults to 60 (1 minute).\n */\n ttl?: number;\n}\n\n/**\n * Creates a universal VardStore that fetches variable values from the Vard API.\n * Works in any environment with a global `fetch` (Browsers, Node 18+, Bun, Deno).\n */\nexport function createVardFetchStore(\n options: VardFetchStoreOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const {\n apiBase = options.apiBase ?? VARD_API_HOST,\n apiKey = options.apiKey ?? process.env.VARD_API_KEY,\n fetchOptions = {},\n debug = options.debug ?? false,\n ttl = options.ttl ?? 60,\n } = options;\n\n let resolvedValues: Map<string, unknown> | null = null;\n let structuredContent: any = null;\n let fetchPromise: Promise<{ variables: Map<string, unknown>; structured: any }> | null = null;\n let lastFetchTime = 0;\n let lastLogTime = 0;\n\n async function fetchValues(): Promise<{ variables: Map<string, unknown>; structured: any }> {\n const isDevelopment = process.env.NODE_ENV === \"development\";\n\n if (!apiKey) {\n if (!isDevelopment) {\n console.error(\n \"\\x1b[31m[vard] Missing configuration! VARD_API_KEY is not set.\\x1b[0m\\n\" +\n \"Please set this environment variable in your production environment.\"\n );\n } else {\n console.warn(\n \"[vard] No API Key found. Running in local fallback mode (using default values).\"\n );\n }\n return { variables: new Map(), structured: {} };\n }\n\n const url = `${apiBase}/api/content/variables`;\n\n if (debug) {\n console.log(`[vard] Request: GET ${url}`);\n console.log(`[vard] Headers:`, {\n \"X-Vard-API-Key\": apiKey.substring(0, 10) + \"...\",\n ...fetchOptions.headers,\n });\n }\n\n try {\n const res = await fetch(url, {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n \"X-Vard-API-Key\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errorMsg = `[vard] Failed to fetch variables from ${url} (Status: ${res.status} ${res.statusText})`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`);\n return { variables: new Map(), structured: {} };\n }\n\n const data = (await res.json()) as Record<string, unknown>;\n\n if (debug) {\n console.log(`[vard] Response (${res.status}):`, data);\n }\n\n // Flatten the nested structure into the internal Map for key-based lookups\n const variablesMap = new Map<string, unknown>();\n flattenObject(data, \"\", variablesMap);\n\n return {\n variables: variablesMap,\n structured: data,\n };\n } catch (err) {\n const errorMsg = `[vard] Network error fetching variables from ${url}`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`, err);\n return { variables: new Map(), structured: {} };\n }\n }\n\n function flattenObject(obj: any, prefix: string, map: Map<string, unknown>) {\n if (typeof obj !== \"object\" || obj === null) return;\n\n for (const [key, value] of Object.entries(obj)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n // If it's an array, we treat it as a single value (e.g. a collection)\n if (Array.isArray(value)) {\n map.set(fullKey, value);\n } else if (typeof value === \"object\" && value !== null) {\n flattenObject(value, fullKey, map);\n } else {\n map.set(fullKey, value);\n }\n }\n }\n\n return {\n get(key: string): unknown {\n return resolvedValues?.get(key);\n },\n\n getStructured(): any {\n return structuredContent;\n },\n\n async prefetch(): Promise<void> {\n const now = Date.now();\n\n if (resolvedValues) {\n const elapsed = Math.floor((now - lastFetchTime) / 1000);\n if (elapsed < ttl) {\n if (now - lastLogTime > 2000) {\n if (debug) {\n console.log(`[vard] Cache HIT. Next fresh check in ${ttl - elapsed}s.`);\n }\n lastLogTime = now;\n }\n return;\n }\n }\n\n if (!fetchPromise) {\n if (debug) {\n if (resolvedValues) {\n console.log(`[vard] Cache STALE (${ttl}s TTL expired). Fetching fresh data...`);\n } else {\n console.log(`[vard] Cache COLD. Initializing fresh fetch...`);\n }\n }\n fetchPromise = fetchValues();\n }\n\n try {\n const result = await fetchPromise;\n resolvedValues = result.variables;\n structuredContent = result.structured;\n lastFetchTime = Date.now();\n } finally {\n fetchPromise = null;\n }\n },\n };\n}\n","import {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n VardVariableType,\n} from \"./types\";\nimport {\n VardSchema,\n InferSchema,\n VardField,\n VardCollection,\n VardSchemaFragment,\n MergeSchema,\n} from \"./schema\";\nimport { createVardFetchStore } from \"./fetch-store\";\nimport { VARD_API_HOST } from \"./constants\";\n\n// ─────────────────────────────────────────────\n// No-op store (used in local dev when no apiKey is set)\n// ─────────────────────────────────────────────\n\nlet hasLoggedNoop = false;\nconst noopStore: VardStore = {\n get: () => {\n if (!hasLoggedNoop && process.env.NODE_ENV !== \"test\") {\n console.warn(\n \"[vard] Using default values for all variables because no Store was provided to createVard().\"\n );\n hasLoggedNoop = true;\n }\n return undefined;\n },\n};\n\n// ─────────────────────────────────────────────\n// createVard — the main SDK factory\n// ─────────────────────────────────────────────\n\n/**\n * Creates a Vard client instance. Call this once at the top of your site\n * (e.g. in `lib/vard.ts`) and export the result.\n */\nexport function createVard<S extends VardSchema = any>(\n options: VardOptions<S> = {}\n): VardClient<S> {\n const store: VardStore =\n options.store ?? (options.apiKey ? createVardFetchStore(options) : noopStore);\n\n // Registry of all declared variables — used by CLI + build pipeline\n const registry: VardVariableDefinition[] = [];\n\n function register<T>(def: VardVariableDefinition<T>): T {\n if (!registry.find((d) => d.key === def.key)) {\n registry.push(def as VardVariableDefinition);\n }\n\n const stored = store.get(def.key);\n if (stored !== undefined && stored !== null) {\n return stored as T;\n }\n\n return def.defaultValue;\n }\n\n // ─────────────────────────────────────────────\n // Schema Traversal\n // ─────────────────────────────────────────────\n\n function flattenSchema(schema: VardSchema, prefix = \"\"): any {\n const result: any = {};\n\n for (const [key, value] of Object.entries(schema)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === \"object\" && value !== null && \"type\" in value) {\n // It's a field or collection\n const field = value as VardField | VardCollection;\n\n if (field.type === \"collection\") {\n // Flatten collection schema but keep it as a 'list' type for the registry\n const collection = field as VardCollection;\n const listItemSchema: Record<string, string> = {};\n for (const [fKey, fVal] of Object.entries(collection.schema)) {\n listItemSchema[fKey] = (fVal as VardField).type;\n }\n\n register({\n key: fullKey,\n label: labelFromKey(key),\n type: \"list\",\n defaultValue: [],\n editableBy: \"member\",\n listItemSchema: listItemSchema as VardListItemSchema,\n isCollection: true,\n });\n\n // In the returned object, this remains a placeholder or is proxied to the store\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? [],\n enumerable: true,\n });\n } else {\n // It's a plain field\n const vardField = field as VardField;\n register({\n key: fullKey,\n label: vardField.label ?? labelFromKey(key),\n description: vardField.description,\n type: vardField.type,\n defaultValue: vardField.default,\n editableBy: vardField.editableBy ?? \"member\",\n group: vardField.group,\n });\n\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? vardField.default,\n enumerable: true,\n });\n }\n } else if (typeof value === \"object\" && value !== null) {\n // It's a nested object\n result[key] = flattenSchema(value as VardSchema, fullKey);\n }\n }\n\n return result;\n }\n\n // Auto-sync schema in development\n if (options.schema && process.env.NODE_ENV === \"development\" && options.apiKey) {\n flattenSchema(options.schema);\n const definitions = [...registry];\n const apiBase = VARD_API_HOST;\n\n fetch(`${apiBase}/api/content/variables/sync`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Vard-API-Key\": options.apiKey,\n },\n body: JSON.stringify({\n definitions,\n schema: options.schema,\n }),\n }).catch((err) => console.warn(\"[vard] Auto-sync failed:\", err));\n }\n\n const client: VardClient<S> = {\n define<NS extends VardSchema>(schema: NS): InferSchema<NS> {\n return flattenSchema(schema) as InferSchema<NS>;\n },\n\n async get(): Promise<InferSchema<S>> {\n if (store.prefetch) {\n await store.prefetch();\n }\n if (store.getStructured) {\n const structured = store.getStructured();\n if (structured && Object.keys(structured).length > 0) {\n return structured as InferSchema<S>;\n }\n }\n return flattenSchema(options.schema ?? {}) as InferSchema<S>;\n },\n\n string(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"string\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n richtext(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"richtext\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n color(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"color\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n image(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"image\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n boolean(key, fallback, opts: VardVariableOptions = {}) {\n return register<boolean>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"boolean\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n group: opts.group,\n });\n },\n\n list<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: VardVariableOptions = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n });\n },\n\n collection<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: Omit<VardVariableOptions, \"type\"> = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n isCollection: true,\n });\n },\n\n global: {\n string(key, fallback, opts = {}) {\n return client.string(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n richtext(key, fallback, opts = {}) {\n return client.richtext(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n color(key, fallback, opts = {}) {\n return client.color(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n image(key, fallback, opts = {}) {\n return client.image(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n boolean(key, fallback, opts = {}) {\n return client.boolean(key, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n list(key, schema, fallback, opts = {}) {\n return client.list(key, schema, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n },\n\n extend<E extends VardSchema>(fragment: VardSchemaFragment<E>): VardClient<MergeSchema<S, E>> {\n // Merge the base schema with the fragment — the fragment keys win on collision\n const mergedSchema = { ...(options.schema ?? {}), ...fragment } as unknown as MergeSchema<\n S,\n E\n >;\n // Return a new client with the merged schema, sharing the same store & registry.\n // We pass the in-memory store directly so there is no second fetch.\n return createVard<MergeSchema<S, E>>({\n ...options,\n schema: mergedSchema,\n store,\n });\n },\n\n getDefinitions() {\n return [...registry];\n },\n store,\n };\n\n return client;\n}\n\n// ─────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────\n\nfunction labelFromKey(key: string): string {\n const lastSegment = key.split(\".\").pop() ?? key;\n return lastSegment\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (c) => c.toUpperCase())\n .trim();\n}\n","import { VardVariableType, VardRole } from \"./types\";\n\nexport interface VardFieldOptions<T = any> {\n label?: string;\n description?: string;\n editableBy?: VardRole;\n group?: string;\n default?: T;\n}\n\nexport interface VardField<T = any> extends VardFieldOptions<T> {\n type: VardVariableType;\n}\n\nexport interface VardCollection<S extends Record<string, VardField | any> = any> {\n type: \"collection\";\n schema: S;\n}\n\nexport type VardSchemaValue =\n | VardField\n | VardCollection\n | boolean\n | { [key: string]: VardSchemaValue };\n\nexport type VardSchema = Record<string, VardSchemaValue>;\n\n/**\n * A branded schema fragment created with `v.schema()`. Use with `vard.extend()`\n * to compose schemas defined across multiple files.\n */\nexport type VardSchemaFragment<S extends VardSchema> = S & {\n readonly __fragment: true;\n};\n\n/**\n * Merges two VardSchema types, with B's keys overriding A on collision.\n */\nexport type MergeSchema<A extends VardSchema, B extends VardSchema> = Omit<A, keyof B> & B;\n\n// ─────────────────────────────────────────────\n// The `v` helper object for schema definition\n// ─────────────────────────────────────────────\n\nexport const v = {\n string: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"string\",\n default: defaultValue,\n ...opts,\n }),\n\n richtext: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"richtext\",\n default: defaultValue,\n ...opts,\n }),\n\n color: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"color\",\n default: defaultValue,\n ...opts,\n }),\n\n image: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"image\",\n default: defaultValue,\n ...opts,\n }),\n\n boolean: (\n defaultValue?: boolean,\n opts: Omit<VardFieldOptions<boolean>, \"default\"> = {}\n ): VardField<boolean> => ({\n type: \"boolean\",\n default: defaultValue,\n ...opts,\n }),\n\n collection: <S extends Record<string, VardField | any>>(schema: S): VardCollection<S> => ({\n type: \"collection\",\n schema,\n }),\n\n /**\n * Creates a reusable schema fragment that can be merged into a Vard client\n * via `vard.extend(fragment)`. Co-locate this with your page/component.\n *\n * @example\n * // app/therapists/schema.ts\n * export const therapistSchema = v.schema({\n * therapists: v.collection({ name: v.string(), photo: v.image() }),\n * });\n *\n * // app/therapists/page.tsx\n * const { therapists } = await vard.extend(therapistSchema).get();\n */\n schema: <S extends VardSchema>(schema: S): VardSchemaFragment<S> =>\n schema as VardSchemaFragment<S>,\n};\n\n// ─────────────────────────────────────────────\n// Type inference for schema objects\n// ─────────────────────────────────────────────\n\nexport type InferSchema<T> = 0 extends 1 & T\n ? any\n : T extends VardField<infer U>\n ? U\n : T extends VardCollection<infer S>\n ? InferSchema<S>[]\n : T extends VardSchemaFragment<infer S>\n ? InferSchema<S>\n : T extends Record<string, any>\n ? { [K in keyof T as K extends \"__fragment\" ? never : K]: InferSchema<T[K]> }\n : T;\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -7,11 +7,14 @@ function createVardFetchStore(options = {}) {
|
|
|
7
7
|
apiBase = options.apiBase ?? VARD_API_HOST,
|
|
8
8
|
apiKey = options.apiKey ?? process.env.VARD_API_KEY,
|
|
9
9
|
fetchOptions = {},
|
|
10
|
-
debug = options.debug ?? false
|
|
10
|
+
debug = options.debug ?? false,
|
|
11
|
+
ttl = options.ttl ?? 60
|
|
11
12
|
} = options;
|
|
12
13
|
let resolvedValues = null;
|
|
13
14
|
let structuredContent = null;
|
|
14
15
|
let fetchPromise = null;
|
|
16
|
+
let lastFetchTime = 0;
|
|
17
|
+
let lastLogTime = 0;
|
|
15
18
|
async function fetchValues() {
|
|
16
19
|
const isDevelopment = process.env.NODE_ENV === "development";
|
|
17
20
|
if (!apiKey) {
|
|
@@ -84,13 +87,37 @@ function createVardFetchStore(options = {}) {
|
|
|
84
87
|
return structuredContent;
|
|
85
88
|
},
|
|
86
89
|
async prefetch() {
|
|
87
|
-
|
|
90
|
+
const now = Date.now();
|
|
91
|
+
if (resolvedValues) {
|
|
92
|
+
const elapsed = Math.floor((now - lastFetchTime) / 1e3);
|
|
93
|
+
if (elapsed < ttl) {
|
|
94
|
+
if (now - lastLogTime > 2e3) {
|
|
95
|
+
if (debug) {
|
|
96
|
+
console.log(`[vard] Cache HIT. Next fresh check in ${ttl - elapsed}s.`);
|
|
97
|
+
}
|
|
98
|
+
lastLogTime = now;
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
88
103
|
if (!fetchPromise) {
|
|
104
|
+
if (debug) {
|
|
105
|
+
if (resolvedValues) {
|
|
106
|
+
console.log(`[vard] Cache STALE (${ttl}s TTL expired). Fetching fresh data...`);
|
|
107
|
+
} else {
|
|
108
|
+
console.log(`[vard] Cache COLD. Initializing fresh fetch...`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
89
111
|
fetchPromise = fetchValues();
|
|
90
112
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
113
|
+
try {
|
|
114
|
+
const result = await fetchPromise;
|
|
115
|
+
resolvedValues = result.variables;
|
|
116
|
+
structuredContent = result.structured;
|
|
117
|
+
lastFetchTime = Date.now();
|
|
118
|
+
} finally {
|
|
119
|
+
fetchPromise = null;
|
|
120
|
+
}
|
|
94
121
|
}
|
|
95
122
|
};
|
|
96
123
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/fetch-store.ts","../src/client.ts","../src/schema.ts"],"sourcesContent":["/**\n * The base URL for the Vard API.\n * Reads from VARD_API_HOST env var; falls back to https://vard.app.\n */\nexport const VARD_API_HOST: string =\n process.env.VARD_API_HOST ?? \"https://vard.app\";\n","import type { VardStore } from \"./types\";\nimport { VARD_API_HOST } from \"./constants\";\n\nexport interface VardFetchStoreOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Defaults to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Custom fetch options (headers, etc.)\n */\n fetchOptions?: RequestInit;\n\n /**\n * Enable verbose logging for requests and responses.\n */\n debug?: boolean;\n}\n\n/**\n * Creates a universal VardStore that fetches variable values from the Vard API.\n * Works in any environment with a global `fetch` (Browsers, Node 18+, Bun, Deno).\n */\nexport function createVardFetchStore(\n options: VardFetchStoreOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const {\n apiBase = options.apiBase ?? VARD_API_HOST,\n apiKey = options.apiKey ?? process.env.VARD_API_KEY,\n fetchOptions = {},\n debug = options.debug ?? false,\n } = options;\n\n let resolvedValues: Map<string, unknown> | null = null;\n let structuredContent: any = null;\n let fetchPromise: Promise<{ variables: Map<string, unknown>; structured: any }> | null = null;\n\n async function fetchValues(): Promise<{ variables: Map<string, unknown>; structured: any }> {\n const isDevelopment = process.env.NODE_ENV === \"development\";\n\n if (!apiKey) {\n if (!isDevelopment) {\n console.error(\n \"\\x1b[31m[vard] Missing configuration! VARD_API_KEY is not set.\\x1b[0m\\n\" +\n \"Please set this environment variable in your production environment.\"\n );\n } else {\n console.warn(\n \"[vard] No API Key found. Running in local fallback mode (using default values).\"\n );\n }\n return { variables: new Map(), structured: {} };\n }\n\n const url = `${apiBase}/api/content/variables`;\n\n if (debug) {\n console.log(`[vard] Request: GET ${url}`);\n console.log(`[vard] Headers:`, {\n \"X-Vard-API-Key\": apiKey.substring(0, 10) + \"...\",\n ...fetchOptions.headers,\n });\n }\n\n try {\n const res = await fetch(url, {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n \"X-Vard-API-Key\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errorMsg = `[vard] Failed to fetch variables from ${url} (Status: ${res.status} ${res.statusText})`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`);\n return { variables: new Map(), structured: {} };\n }\n\n const data = (await res.json()) as Record<string, unknown>;\n\n if (debug) {\n console.log(`[vard] Response (${res.status}):`, data);\n }\n\n // Flatten the nested structure into the internal Map for key-based lookups\n const variablesMap = new Map<string, unknown>();\n flattenObject(data, \"\", variablesMap);\n\n return {\n variables: variablesMap,\n structured: data,\n };\n } catch (err) {\n const errorMsg = `[vard] Network error fetching variables from ${url}`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`, err);\n return { variables: new Map(), structured: {} };\n }\n }\n\n function flattenObject(obj: any, prefix: string, map: Map<string, unknown>) {\n if (typeof obj !== \"object\" || obj === null) return;\n\n for (const [key, value] of Object.entries(obj)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n // If it's an array, we treat it as a single value (e.g. a collection)\n if (Array.isArray(value)) {\n map.set(fullKey, value);\n } else if (typeof value === \"object\" && value !== null) {\n flattenObject(value, fullKey, map);\n } else {\n map.set(fullKey, value);\n }\n }\n }\n\n return {\n get(key: string): unknown {\n return resolvedValues?.get(key);\n },\n\n getStructured(): any {\n return structuredContent;\n },\n\n async prefetch(): Promise<void> {\n if (resolvedValues) return;\n if (!fetchPromise) {\n fetchPromise = fetchValues();\n }\n const result = await fetchPromise;\n resolvedValues = result.variables;\n structuredContent = result.structured;\n },\n };\n}\n","import {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n VardVariableType,\n} from \"./types\";\nimport {\n VardSchema,\n InferSchema,\n VardField,\n VardCollection,\n VardSchemaFragment,\n MergeSchema,\n} from \"./schema\";\nimport { createVardFetchStore } from \"./fetch-store\";\nimport { VARD_API_HOST } from \"./constants\";\n\n// ─────────────────────────────────────────────\n// No-op store (used in local dev when no apiKey is set)\n// ─────────────────────────────────────────────\n\nlet hasLoggedNoop = false;\nconst noopStore: VardStore = {\n get: () => {\n if (!hasLoggedNoop && process.env.NODE_ENV !== \"test\") {\n console.warn(\n \"[vard] Using default values for all variables because no Store was provided to createVard().\"\n );\n hasLoggedNoop = true;\n }\n return undefined;\n },\n};\n\n// ─────────────────────────────────────────────\n// createVard — the main SDK factory\n// ─────────────────────────────────────────────\n\n/**\n * Creates a Vard client instance. Call this once at the top of your site\n * (e.g. in `lib/vard.ts`) and export the result.\n */\nexport function createVard<S extends VardSchema = any>(\n options: VardOptions<S> = {}\n): VardClient<S> {\n const store: VardStore =\n options.store ?? (options.apiKey ? createVardFetchStore(options) : noopStore);\n\n // Registry of all declared variables — used by CLI + build pipeline\n const registry: VardVariableDefinition[] = [];\n\n function register<T>(def: VardVariableDefinition<T>): T {\n if (!registry.find((d) => d.key === def.key)) {\n registry.push(def as VardVariableDefinition);\n }\n\n const stored = store.get(def.key);\n if (stored !== undefined && stored !== null) {\n return stored as T;\n }\n\n return def.defaultValue;\n }\n\n // ─────────────────────────────────────────────\n // Schema Traversal\n // ─────────────────────────────────────────────\n\n function flattenSchema(schema: VardSchema, prefix = \"\"): any {\n const result: any = {};\n\n for (const [key, value] of Object.entries(schema)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === \"object\" && value !== null && \"type\" in value) {\n // It's a field or collection\n const field = value as VardField | VardCollection;\n\n if (field.type === \"collection\") {\n // Flatten collection schema but keep it as a 'list' type for the registry\n const collection = field as VardCollection;\n const listItemSchema: Record<string, string> = {};\n for (const [fKey, fVal] of Object.entries(collection.schema)) {\n listItemSchema[fKey] = (fVal as VardField).type;\n }\n\n register({\n key: fullKey,\n label: labelFromKey(key),\n type: \"list\",\n defaultValue: [],\n editableBy: \"member\",\n listItemSchema: listItemSchema as VardListItemSchema,\n isCollection: true,\n });\n\n // In the returned object, this remains a placeholder or is proxied to the store\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? [],\n enumerable: true,\n });\n } else {\n // It's a plain field\n const vardField = field as VardField;\n register({\n key: fullKey,\n label: vardField.label ?? labelFromKey(key),\n description: vardField.description,\n type: vardField.type,\n defaultValue: vardField.default,\n editableBy: vardField.editableBy ?? \"member\",\n group: vardField.group,\n });\n\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? vardField.default,\n enumerable: true,\n });\n }\n } else if (typeof value === \"object\" && value !== null) {\n // It's a nested object\n result[key] = flattenSchema(value as VardSchema, fullKey);\n }\n }\n\n return result;\n }\n\n // Auto-sync schema in development\n if (options.schema && process.env.NODE_ENV === \"development\" && options.apiKey) {\n flattenSchema(options.schema);\n const definitions = [...registry];\n const apiBase = VARD_API_HOST;\n\n fetch(`${apiBase}/api/content/variables/sync`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Vard-API-Key\": options.apiKey,\n },\n body: JSON.stringify({\n definitions,\n schema: options.schema,\n }),\n }).catch((err) => console.warn(\"[vard] Auto-sync failed:\", err));\n }\n\n const client: VardClient<S> = {\n define<NS extends VardSchema>(schema: NS): InferSchema<NS> {\n return flattenSchema(schema) as InferSchema<NS>;\n },\n\n async get(): Promise<InferSchema<S>> {\n if (store.prefetch) {\n await store.prefetch();\n }\n if (store.getStructured) {\n const structured = store.getStructured();\n if (structured && Object.keys(structured).length > 0) {\n return structured as InferSchema<S>;\n }\n }\n return flattenSchema(options.schema ?? {}) as InferSchema<S>;\n },\n\n string(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"string\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n richtext(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"richtext\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n color(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"color\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n image(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"image\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n boolean(key, fallback, opts: VardVariableOptions = {}) {\n return register<boolean>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"boolean\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n group: opts.group,\n });\n },\n\n list<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: VardVariableOptions = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n });\n },\n\n collection<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: Omit<VardVariableOptions, \"type\"> = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n isCollection: true,\n });\n },\n\n global: {\n string(key, fallback, opts = {}) {\n return client.string(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n richtext(key, fallback, opts = {}) {\n return client.richtext(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n color(key, fallback, opts = {}) {\n return client.color(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n image(key, fallback, opts = {}) {\n return client.image(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n boolean(key, fallback, opts = {}) {\n return client.boolean(key, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n list(key, schema, fallback, opts = {}) {\n return client.list(key, schema, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n },\n\n extend<E extends VardSchema>(fragment: VardSchemaFragment<E>): VardClient<MergeSchema<S, E>> {\n // Merge the base schema with the fragment — the fragment keys win on collision\n const mergedSchema = { ...(options.schema ?? {}), ...fragment } as unknown as MergeSchema<\n S,\n E\n >;\n // Return a new client with the merged schema, sharing the same store & registry.\n // We pass the in-memory store directly so there is no second fetch.\n return createVard<MergeSchema<S, E>>({\n ...options,\n schema: mergedSchema,\n store,\n });\n },\n\n getDefinitions() {\n return [...registry];\n },\n store,\n };\n\n return client;\n}\n\n// ─────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────\n\nfunction labelFromKey(key: string): string {\n const lastSegment = key.split(\".\").pop() ?? key;\n return lastSegment\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (c) => c.toUpperCase())\n .trim();\n}\n","import { VardVariableType, VardRole } from \"./types\";\n\nexport interface VardFieldOptions<T = any> {\n label?: string;\n description?: string;\n editableBy?: VardRole;\n group?: string;\n default?: T;\n}\n\nexport interface VardField<T = any> extends VardFieldOptions<T> {\n type: VardVariableType;\n}\n\nexport interface VardCollection<S extends Record<string, VardField | any> = any> {\n type: \"collection\";\n schema: S;\n}\n\nexport type VardSchemaValue =\n | VardField\n | VardCollection\n | boolean\n | { [key: string]: VardSchemaValue };\n\nexport type VardSchema = Record<string, VardSchemaValue>;\n\n/**\n * A branded schema fragment created with `v.schema()`. Use with `vard.extend()`\n * to compose schemas defined across multiple files.\n */\nexport type VardSchemaFragment<S extends VardSchema> = S & {\n readonly __fragment: true;\n};\n\n/**\n * Merges two VardSchema types, with B's keys overriding A on collision.\n */\nexport type MergeSchema<A extends VardSchema, B extends VardSchema> = Omit<A, keyof B> & B;\n\n// ─────────────────────────────────────────────\n// The `v` helper object for schema definition\n// ─────────────────────────────────────────────\n\nexport const v = {\n string: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"string\",\n default: defaultValue,\n ...opts,\n }),\n\n richtext: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"richtext\",\n default: defaultValue,\n ...opts,\n }),\n\n color: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"color\",\n default: defaultValue,\n ...opts,\n }),\n\n image: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"image\",\n default: defaultValue,\n ...opts,\n }),\n\n boolean: (\n defaultValue?: boolean,\n opts: Omit<VardFieldOptions<boolean>, \"default\"> = {}\n ): VardField<boolean> => ({\n type: \"boolean\",\n default: defaultValue,\n ...opts,\n }),\n\n collection: <S extends Record<string, VardField | any>>(schema: S): VardCollection<S> => ({\n type: \"collection\",\n schema,\n }),\n\n /**\n * Creates a reusable schema fragment that can be merged into a Vard client\n * via `vard.extend(fragment)`. Co-locate this with your page/component.\n *\n * @example\n * // app/therapists/schema.ts\n * export const therapistSchema = v.schema({\n * therapists: v.collection({ name: v.string(), photo: v.image() }),\n * });\n *\n * // app/therapists/page.tsx\n * const { therapists } = await vard.extend(therapistSchema).get();\n */\n schema: <S extends VardSchema>(schema: S): VardSchemaFragment<S> =>\n schema as VardSchemaFragment<S>,\n};\n\n// ─────────────────────────────────────────────\n// Type inference for schema objects\n// ─────────────────────────────────────────────\n\nexport type InferSchema<T> = 0 extends 1 & T\n ? any\n : T extends VardField<infer U>\n ? U\n : T extends VardCollection<infer S>\n ? InferSchema<S>[]\n : T extends VardSchemaFragment<infer S>\n ? InferSchema<S>\n : T extends Record<string, any>\n ? { [K in keyof T as K extends \"__fragment\" ? never : K]: InferSchema<T[K]> }\n : T;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/fetch-store.ts","../src/client.ts","../src/schema.ts"],"sourcesContent":["/**\n * The base URL for the Vard API.\n * Reads from VARD_API_HOST env var; falls back to https://vard.app.\n */\nexport const VARD_API_HOST: string = process.env.VARD_API_HOST ?? \"https://vard.app\";\n","import type { VardStore } from \"./types\";\nimport { VARD_API_HOST } from \"./constants\";\n\nexport interface VardFetchStoreOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Defaults to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Custom fetch options (headers, etc.)\n */\n fetchOptions?: RequestInit;\n\n /**\n * Enable verbose logging for requests and responses.\n */\n debug?: boolean;\n\n /**\n * Time in seconds to cache the fetched variables in memory.\n * Defaults to 60 (1 minute).\n */\n ttl?: number;\n}\n\n/**\n * Creates a universal VardStore that fetches variable values from the Vard API.\n * Works in any environment with a global `fetch` (Browsers, Node 18+, Bun, Deno).\n */\nexport function createVardFetchStore(\n options: VardFetchStoreOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const {\n apiBase = options.apiBase ?? VARD_API_HOST,\n apiKey = options.apiKey ?? process.env.VARD_API_KEY,\n fetchOptions = {},\n debug = options.debug ?? false,\n ttl = options.ttl ?? 60,\n } = options;\n\n let resolvedValues: Map<string, unknown> | null = null;\n let structuredContent: any = null;\n let fetchPromise: Promise<{ variables: Map<string, unknown>; structured: any }> | null = null;\n let lastFetchTime = 0;\n let lastLogTime = 0;\n\n async function fetchValues(): Promise<{ variables: Map<string, unknown>; structured: any }> {\n const isDevelopment = process.env.NODE_ENV === \"development\";\n\n if (!apiKey) {\n if (!isDevelopment) {\n console.error(\n \"\\x1b[31m[vard] Missing configuration! VARD_API_KEY is not set.\\x1b[0m\\n\" +\n \"Please set this environment variable in your production environment.\"\n );\n } else {\n console.warn(\n \"[vard] No API Key found. Running in local fallback mode (using default values).\"\n );\n }\n return { variables: new Map(), structured: {} };\n }\n\n const url = `${apiBase}/api/content/variables`;\n\n if (debug) {\n console.log(`[vard] Request: GET ${url}`);\n console.log(`[vard] Headers:`, {\n \"X-Vard-API-Key\": apiKey.substring(0, 10) + \"...\",\n ...fetchOptions.headers,\n });\n }\n\n try {\n const res = await fetch(url, {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n \"X-Vard-API-Key\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errorMsg = `[vard] Failed to fetch variables from ${url} (Status: ${res.status} ${res.statusText})`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`);\n return { variables: new Map(), structured: {} };\n }\n\n const data = (await res.json()) as Record<string, unknown>;\n\n if (debug) {\n console.log(`[vard] Response (${res.status}):`, data);\n }\n\n // Flatten the nested structure into the internal Map for key-based lookups\n const variablesMap = new Map<string, unknown>();\n flattenObject(data, \"\", variablesMap);\n\n return {\n variables: variablesMap,\n structured: data,\n };\n } catch (err) {\n const errorMsg = `[vard] Network error fetching variables from ${url}`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`, err);\n return { variables: new Map(), structured: {} };\n }\n }\n\n function flattenObject(obj: any, prefix: string, map: Map<string, unknown>) {\n if (typeof obj !== \"object\" || obj === null) return;\n\n for (const [key, value] of Object.entries(obj)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n // If it's an array, we treat it as a single value (e.g. a collection)\n if (Array.isArray(value)) {\n map.set(fullKey, value);\n } else if (typeof value === \"object\" && value !== null) {\n flattenObject(value, fullKey, map);\n } else {\n map.set(fullKey, value);\n }\n }\n }\n\n return {\n get(key: string): unknown {\n return resolvedValues?.get(key);\n },\n\n getStructured(): any {\n return structuredContent;\n },\n\n async prefetch(): Promise<void> {\n const now = Date.now();\n\n if (resolvedValues) {\n const elapsed = Math.floor((now - lastFetchTime) / 1000);\n if (elapsed < ttl) {\n if (now - lastLogTime > 2000) {\n if (debug) {\n console.log(`[vard] Cache HIT. Next fresh check in ${ttl - elapsed}s.`);\n }\n lastLogTime = now;\n }\n return;\n }\n }\n\n if (!fetchPromise) {\n if (debug) {\n if (resolvedValues) {\n console.log(`[vard] Cache STALE (${ttl}s TTL expired). Fetching fresh data...`);\n } else {\n console.log(`[vard] Cache COLD. Initializing fresh fetch...`);\n }\n }\n fetchPromise = fetchValues();\n }\n\n try {\n const result = await fetchPromise;\n resolvedValues = result.variables;\n structuredContent = result.structured;\n lastFetchTime = Date.now();\n } finally {\n fetchPromise = null;\n }\n },\n };\n}\n","import {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n VardVariableType,\n} from \"./types\";\nimport {\n VardSchema,\n InferSchema,\n VardField,\n VardCollection,\n VardSchemaFragment,\n MergeSchema,\n} from \"./schema\";\nimport { createVardFetchStore } from \"./fetch-store\";\nimport { VARD_API_HOST } from \"./constants\";\n\n// ─────────────────────────────────────────────\n// No-op store (used in local dev when no apiKey is set)\n// ─────────────────────────────────────────────\n\nlet hasLoggedNoop = false;\nconst noopStore: VardStore = {\n get: () => {\n if (!hasLoggedNoop && process.env.NODE_ENV !== \"test\") {\n console.warn(\n \"[vard] Using default values for all variables because no Store was provided to createVard().\"\n );\n hasLoggedNoop = true;\n }\n return undefined;\n },\n};\n\n// ─────────────────────────────────────────────\n// createVard — the main SDK factory\n// ─────────────────────────────────────────────\n\n/**\n * Creates a Vard client instance. Call this once at the top of your site\n * (e.g. in `lib/vard.ts`) and export the result.\n */\nexport function createVard<S extends VardSchema = any>(\n options: VardOptions<S> = {}\n): VardClient<S> {\n const store: VardStore =\n options.store ?? (options.apiKey ? createVardFetchStore(options) : noopStore);\n\n // Registry of all declared variables — used by CLI + build pipeline\n const registry: VardVariableDefinition[] = [];\n\n function register<T>(def: VardVariableDefinition<T>): T {\n if (!registry.find((d) => d.key === def.key)) {\n registry.push(def as VardVariableDefinition);\n }\n\n const stored = store.get(def.key);\n if (stored !== undefined && stored !== null) {\n return stored as T;\n }\n\n return def.defaultValue;\n }\n\n // ─────────────────────────────────────────────\n // Schema Traversal\n // ─────────────────────────────────────────────\n\n function flattenSchema(schema: VardSchema, prefix = \"\"): any {\n const result: any = {};\n\n for (const [key, value] of Object.entries(schema)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === \"object\" && value !== null && \"type\" in value) {\n // It's a field or collection\n const field = value as VardField | VardCollection;\n\n if (field.type === \"collection\") {\n // Flatten collection schema but keep it as a 'list' type for the registry\n const collection = field as VardCollection;\n const listItemSchema: Record<string, string> = {};\n for (const [fKey, fVal] of Object.entries(collection.schema)) {\n listItemSchema[fKey] = (fVal as VardField).type;\n }\n\n register({\n key: fullKey,\n label: labelFromKey(key),\n type: \"list\",\n defaultValue: [],\n editableBy: \"member\",\n listItemSchema: listItemSchema as VardListItemSchema,\n isCollection: true,\n });\n\n // In the returned object, this remains a placeholder or is proxied to the store\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? [],\n enumerable: true,\n });\n } else {\n // It's a plain field\n const vardField = field as VardField;\n register({\n key: fullKey,\n label: vardField.label ?? labelFromKey(key),\n description: vardField.description,\n type: vardField.type,\n defaultValue: vardField.default,\n editableBy: vardField.editableBy ?? \"member\",\n group: vardField.group,\n });\n\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? vardField.default,\n enumerable: true,\n });\n }\n } else if (typeof value === \"object\" && value !== null) {\n // It's a nested object\n result[key] = flattenSchema(value as VardSchema, fullKey);\n }\n }\n\n return result;\n }\n\n // Auto-sync schema in development\n if (options.schema && process.env.NODE_ENV === \"development\" && options.apiKey) {\n flattenSchema(options.schema);\n const definitions = [...registry];\n const apiBase = VARD_API_HOST;\n\n fetch(`${apiBase}/api/content/variables/sync`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Vard-API-Key\": options.apiKey,\n },\n body: JSON.stringify({\n definitions,\n schema: options.schema,\n }),\n }).catch((err) => console.warn(\"[vard] Auto-sync failed:\", err));\n }\n\n const client: VardClient<S> = {\n define<NS extends VardSchema>(schema: NS): InferSchema<NS> {\n return flattenSchema(schema) as InferSchema<NS>;\n },\n\n async get(): Promise<InferSchema<S>> {\n if (store.prefetch) {\n await store.prefetch();\n }\n if (store.getStructured) {\n const structured = store.getStructured();\n if (structured && Object.keys(structured).length > 0) {\n return structured as InferSchema<S>;\n }\n }\n return flattenSchema(options.schema ?? {}) as InferSchema<S>;\n },\n\n string(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"string\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n richtext(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"richtext\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n color(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"color\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n image(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"image\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n boolean(key, fallback, opts: VardVariableOptions = {}) {\n return register<boolean>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"boolean\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n group: opts.group,\n });\n },\n\n list<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: VardVariableOptions = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n });\n },\n\n collection<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: Omit<VardVariableOptions, \"type\"> = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n isCollection: true,\n });\n },\n\n global: {\n string(key, fallback, opts = {}) {\n return client.string(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n richtext(key, fallback, opts = {}) {\n return client.richtext(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n color(key, fallback, opts = {}) {\n return client.color(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n image(key, fallback, opts = {}) {\n return client.image(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n boolean(key, fallback, opts = {}) {\n return client.boolean(key, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n list(key, schema, fallback, opts = {}) {\n return client.list(key, schema, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n },\n\n extend<E extends VardSchema>(fragment: VardSchemaFragment<E>): VardClient<MergeSchema<S, E>> {\n // Merge the base schema with the fragment — the fragment keys win on collision\n const mergedSchema = { ...(options.schema ?? {}), ...fragment } as unknown as MergeSchema<\n S,\n E\n >;\n // Return a new client with the merged schema, sharing the same store & registry.\n // We pass the in-memory store directly so there is no second fetch.\n return createVard<MergeSchema<S, E>>({\n ...options,\n schema: mergedSchema,\n store,\n });\n },\n\n getDefinitions() {\n return [...registry];\n },\n store,\n };\n\n return client;\n}\n\n// ─────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────\n\nfunction labelFromKey(key: string): string {\n const lastSegment = key.split(\".\").pop() ?? key;\n return lastSegment\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (c) => c.toUpperCase())\n .trim();\n}\n","import { VardVariableType, VardRole } from \"./types\";\n\nexport interface VardFieldOptions<T = any> {\n label?: string;\n description?: string;\n editableBy?: VardRole;\n group?: string;\n default?: T;\n}\n\nexport interface VardField<T = any> extends VardFieldOptions<T> {\n type: VardVariableType;\n}\n\nexport interface VardCollection<S extends Record<string, VardField | any> = any> {\n type: \"collection\";\n schema: S;\n}\n\nexport type VardSchemaValue =\n | VardField\n | VardCollection\n | boolean\n | { [key: string]: VardSchemaValue };\n\nexport type VardSchema = Record<string, VardSchemaValue>;\n\n/**\n * A branded schema fragment created with `v.schema()`. Use with `vard.extend()`\n * to compose schemas defined across multiple files.\n */\nexport type VardSchemaFragment<S extends VardSchema> = S & {\n readonly __fragment: true;\n};\n\n/**\n * Merges two VardSchema types, with B's keys overriding A on collision.\n */\nexport type MergeSchema<A extends VardSchema, B extends VardSchema> = Omit<A, keyof B> & B;\n\n// ─────────────────────────────────────────────\n// The `v` helper object for schema definition\n// ─────────────────────────────────────────────\n\nexport const v = {\n string: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"string\",\n default: defaultValue,\n ...opts,\n }),\n\n richtext: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"richtext\",\n default: defaultValue,\n ...opts,\n }),\n\n color: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"color\",\n default: defaultValue,\n ...opts,\n }),\n\n image: (\n defaultValue?: string,\n opts: Omit<VardFieldOptions<string>, \"default\"> = {}\n ): VardField<string> => ({\n type: \"image\",\n default: defaultValue,\n ...opts,\n }),\n\n boolean: (\n defaultValue?: boolean,\n opts: Omit<VardFieldOptions<boolean>, \"default\"> = {}\n ): VardField<boolean> => ({\n type: \"boolean\",\n default: defaultValue,\n ...opts,\n }),\n\n collection: <S extends Record<string, VardField | any>>(schema: S): VardCollection<S> => ({\n type: \"collection\",\n schema,\n }),\n\n /**\n * Creates a reusable schema fragment that can be merged into a Vard client\n * via `vard.extend(fragment)`. Co-locate this with your page/component.\n *\n * @example\n * // app/therapists/schema.ts\n * export const therapistSchema = v.schema({\n * therapists: v.collection({ name: v.string(), photo: v.image() }),\n * });\n *\n * // app/therapists/page.tsx\n * const { therapists } = await vard.extend(therapistSchema).get();\n */\n schema: <S extends VardSchema>(schema: S): VardSchemaFragment<S> =>\n schema as VardSchemaFragment<S>,\n};\n\n// ─────────────────────────────────────────────\n// Type inference for schema objects\n// ─────────────────────────────────────────────\n\nexport type InferSchema<T> = 0 extends 1 & T\n ? any\n : T extends VardField<infer U>\n ? U\n : T extends VardCollection<infer S>\n ? InferSchema<S>[]\n : T extends VardSchemaFragment<infer S>\n ? InferSchema<S>\n : T extends Record<string, any>\n ? { [K in keyof T as K extends \"__fragment\" ? never : K]: InferSchema<T[K]> }\n : T;\n"],"mappings":"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","names":[]}
|
package/dist/next.d.mts
CHANGED
|
@@ -214,6 +214,11 @@ interface VardNextAdapterOptions {
|
|
|
214
214
|
* Only applies when cache is "force-cache".
|
|
215
215
|
*/
|
|
216
216
|
revalidate?: number;
|
|
217
|
+
/**
|
|
218
|
+
* Enable verbose logging (e.g. cache hits, misses, TTL triggers).
|
|
219
|
+
* Defaults to false.
|
|
220
|
+
*/
|
|
221
|
+
debug?: boolean;
|
|
217
222
|
}
|
|
218
223
|
/**
|
|
219
224
|
* Creates a VardStore that fetches live variable values from the Vard API.
|
package/dist/next.d.ts
CHANGED
|
@@ -214,6 +214,11 @@ interface VardNextAdapterOptions {
|
|
|
214
214
|
* Only applies when cache is "force-cache".
|
|
215
215
|
*/
|
|
216
216
|
revalidate?: number;
|
|
217
|
+
/**
|
|
218
|
+
* Enable verbose logging (e.g. cache hits, misses, TTL triggers).
|
|
219
|
+
* Defaults to false.
|
|
220
|
+
*/
|
|
221
|
+
debug?: boolean;
|
|
217
222
|
}
|
|
218
223
|
/**
|
|
219
224
|
* Creates a VardStore that fetches live variable values from the Vard API.
|
package/dist/next.js
CHANGED
|
@@ -35,11 +35,14 @@ function createVardFetchStore(options = {}) {
|
|
|
35
35
|
apiBase = options.apiBase ?? VARD_API_HOST,
|
|
36
36
|
apiKey = options.apiKey ?? process.env.VARD_API_KEY,
|
|
37
37
|
fetchOptions = {},
|
|
38
|
-
debug = options.debug ?? false
|
|
38
|
+
debug = options.debug ?? false,
|
|
39
|
+
ttl = options.ttl ?? 60
|
|
39
40
|
} = options;
|
|
40
41
|
let resolvedValues = null;
|
|
41
42
|
let structuredContent = null;
|
|
42
43
|
let fetchPromise = null;
|
|
44
|
+
let lastFetchTime = 0;
|
|
45
|
+
let lastLogTime = 0;
|
|
43
46
|
async function fetchValues() {
|
|
44
47
|
const isDevelopment = process.env.NODE_ENV === "development";
|
|
45
48
|
if (!apiKey) {
|
|
@@ -112,13 +115,37 @@ function createVardFetchStore(options = {}) {
|
|
|
112
115
|
return structuredContent;
|
|
113
116
|
},
|
|
114
117
|
async prefetch() {
|
|
115
|
-
|
|
118
|
+
const now = Date.now();
|
|
119
|
+
if (resolvedValues) {
|
|
120
|
+
const elapsed = Math.floor((now - lastFetchTime) / 1e3);
|
|
121
|
+
if (elapsed < ttl) {
|
|
122
|
+
if (now - lastLogTime > 2e3) {
|
|
123
|
+
if (debug) {
|
|
124
|
+
console.log(`[vard] Cache HIT. Next fresh check in ${ttl - elapsed}s.`);
|
|
125
|
+
}
|
|
126
|
+
lastLogTime = now;
|
|
127
|
+
}
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
116
131
|
if (!fetchPromise) {
|
|
132
|
+
if (debug) {
|
|
133
|
+
if (resolvedValues) {
|
|
134
|
+
console.log(`[vard] Cache STALE (${ttl}s TTL expired). Fetching fresh data...`);
|
|
135
|
+
} else {
|
|
136
|
+
console.log(`[vard] Cache COLD. Initializing fresh fetch...`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
117
139
|
fetchPromise = fetchValues();
|
|
118
140
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
141
|
+
try {
|
|
142
|
+
const result = await fetchPromise;
|
|
143
|
+
resolvedValues = result.variables;
|
|
144
|
+
structuredContent = result.structured;
|
|
145
|
+
lastFetchTime = Date.now();
|
|
146
|
+
} finally {
|
|
147
|
+
fetchPromise = null;
|
|
148
|
+
}
|
|
122
149
|
}
|
|
123
150
|
};
|
|
124
151
|
}
|
|
@@ -353,6 +380,8 @@ function createVardNextAdapter(options = {}) {
|
|
|
353
380
|
const { cache = "force-cache", revalidate, ...rest } = options;
|
|
354
381
|
return createVardFetchStore({
|
|
355
382
|
...rest,
|
|
383
|
+
// Sync the Next.js revalidation time (seconds) to the internal store TTL (seconds)
|
|
384
|
+
ttl: revalidate !== void 0 ? revalidate : 60,
|
|
356
385
|
fetchOptions: {
|
|
357
386
|
cache,
|
|
358
387
|
...revalidate !== void 0 && cache === "force-cache" ? { next: { revalidate, tags: ["variables"] } } : {}
|
package/dist/next.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/next.ts","../src/constants.ts","../src/fetch-store.ts","../src/client.ts"],"sourcesContent":["/**\n * @vard/sdk — Next.js adapter\n *\n * This module provides a VardStore implementation that reads variable values\n * from the Vard API at request time (App Router) or build time (static export).\n *\n * Usage in your Next.js site:\n *\n * // lib/vard.ts\n * import { createVardNextAdapter } from \"@vard/sdk/next\"\n * import { createVard } from \"@vard/sdk\"\n *\n * export const vard = createVard({\n * apiKey: process.env.VARD_API_KEY,\n * store: createVardNextAdapter(),\n * })\n */\n\nimport type { VardStore } from \"./types\";\n\nexport interface VardNextAdapterOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Falls back to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Next.js fetch cache strategy. Defaults to \"force-cache\" (SSG-friendly).\n * Use \"no-store\" for fully dynamic pages.\n */\n cache?: RequestCache;\n\n /**\n * Next.js ISR revalidation interval in seconds.\n * Only applies when cache is \"force-cache\".\n */\n revalidate?: number;\n}\n\nimport { createVardFetchStore, VardFetchStoreOptions } from \"./fetch-store\";\n\n/**\n * Creates a VardStore that fetches live variable values from the Vard API.\n * Designed for use inside Next.js App Router (server components, server actions).\n */\nexport function createVardNextAdapter(\n options: VardNextAdapterOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const { cache = \"force-cache\", revalidate, ...rest } = options;\n\n return createVardFetchStore({\n ...rest,\n fetchOptions: {\n cache,\n ...(revalidate !== undefined && cache === \"force-cache\"\n ? ({ next: { revalidate, tags: [\"variables\"] } } as any)\n : {}),\n },\n });\n}\n\n/**\n * A convenience wrapper that creates a Vard client pre-loaded with live values.\n * Call this once in your Next.js layout before rendering any server component\n * that uses vard variables.\n *\n * @example\n * // app/layout.tsx\n * import { prefetchVardValues } from \"@vard/sdk/next\"\n * import { vard } from \"@/lib/vard\"\n *\n * export default async function RootLayout({ children }) {\n * await prefetchVardValues(vard)\n * return <html>...</html>\n * }\n */\nimport { createVard } from \"./client\";\nimport type { VardClient, VardOptions } from \"./types\";\n\nimport { VardSchema } from \"./schema\";\n\n/**\n * A convenience wrapper for createVard that automatically uses the Next.js adapter.\n *\n * @example\n * // lib/vard.ts\n * import { createVardNext } from \"@vard/sdk/next\"\n * export const vard = createVardNext({ revalidate: 60 })\n */\nexport function createVardNext<S extends VardSchema = any>(\n options: VardNextAdapterOptions & VardOptions<S> = {}\n): VardClient<S> {\n const adapter = createVardNextAdapter(options);\n return createVard<S>({\n ...options,\n store: adapter,\n });\n}\n\nexport async function prefetchVardValues(\n target: { prefetch(): Promise<void> } | VardClient\n): Promise<void> {\n const adapter = (target as any).prefetch ? target : (target as VardClient).store;\n if (adapter && typeof (adapter as any).prefetch === \"function\") {\n await (adapter as any).prefetch();\n }\n}\n","/**\n * The base URL for the Vard API.\n * Reads from VARD_API_HOST env var; falls back to https://vard.app.\n */\nexport const VARD_API_HOST: string =\n process.env.VARD_API_HOST ?? \"https://vard.app\";\n","import type { VardStore } from \"./types\";\nimport { VARD_API_HOST } from \"./constants\";\n\nexport interface VardFetchStoreOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Defaults to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Custom fetch options (headers, etc.)\n */\n fetchOptions?: RequestInit;\n\n /**\n * Enable verbose logging for requests and responses.\n */\n debug?: boolean;\n}\n\n/**\n * Creates a universal VardStore that fetches variable values from the Vard API.\n * Works in any environment with a global `fetch` (Browsers, Node 18+, Bun, Deno).\n */\nexport function createVardFetchStore(\n options: VardFetchStoreOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const {\n apiBase = options.apiBase ?? VARD_API_HOST,\n apiKey = options.apiKey ?? process.env.VARD_API_KEY,\n fetchOptions = {},\n debug = options.debug ?? false,\n } = options;\n\n let resolvedValues: Map<string, unknown> | null = null;\n let structuredContent: any = null;\n let fetchPromise: Promise<{ variables: Map<string, unknown>; structured: any }> | null = null;\n\n async function fetchValues(): Promise<{ variables: Map<string, unknown>; structured: any }> {\n const isDevelopment = process.env.NODE_ENV === \"development\";\n\n if (!apiKey) {\n if (!isDevelopment) {\n console.error(\n \"\\x1b[31m[vard] Missing configuration! VARD_API_KEY is not set.\\x1b[0m\\n\" +\n \"Please set this environment variable in your production environment.\"\n );\n } else {\n console.warn(\n \"[vard] No API Key found. Running in local fallback mode (using default values).\"\n );\n }\n return { variables: new Map(), structured: {} };\n }\n\n const url = `${apiBase}/api/content/variables`;\n\n if (debug) {\n console.log(`[vard] Request: GET ${url}`);\n console.log(`[vard] Headers:`, {\n \"X-Vard-API-Key\": apiKey.substring(0, 10) + \"...\",\n ...fetchOptions.headers,\n });\n }\n\n try {\n const res = await fetch(url, {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n \"X-Vard-API-Key\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errorMsg = `[vard] Failed to fetch variables from ${url} (Status: ${res.status} ${res.statusText})`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`);\n return { variables: new Map(), structured: {} };\n }\n\n const data = (await res.json()) as Record<string, unknown>;\n\n if (debug) {\n console.log(`[vard] Response (${res.status}):`, data);\n }\n\n // Flatten the nested structure into the internal Map for key-based lookups\n const variablesMap = new Map<string, unknown>();\n flattenObject(data, \"\", variablesMap);\n\n return {\n variables: variablesMap,\n structured: data,\n };\n } catch (err) {\n const errorMsg = `[vard] Network error fetching variables from ${url}`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`, err);\n return { variables: new Map(), structured: {} };\n }\n }\n\n function flattenObject(obj: any, prefix: string, map: Map<string, unknown>) {\n if (typeof obj !== \"object\" || obj === null) return;\n\n for (const [key, value] of Object.entries(obj)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n // If it's an array, we treat it as a single value (e.g. a collection)\n if (Array.isArray(value)) {\n map.set(fullKey, value);\n } else if (typeof value === \"object\" && value !== null) {\n flattenObject(value, fullKey, map);\n } else {\n map.set(fullKey, value);\n }\n }\n }\n\n return {\n get(key: string): unknown {\n return resolvedValues?.get(key);\n },\n\n getStructured(): any {\n return structuredContent;\n },\n\n async prefetch(): Promise<void> {\n if (resolvedValues) return;\n if (!fetchPromise) {\n fetchPromise = fetchValues();\n }\n const result = await fetchPromise;\n resolvedValues = result.variables;\n structuredContent = result.structured;\n },\n };\n}\n","import {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n VardVariableType,\n} from \"./types\";\nimport {\n VardSchema,\n InferSchema,\n VardField,\n VardCollection,\n VardSchemaFragment,\n MergeSchema,\n} from \"./schema\";\nimport { createVardFetchStore } from \"./fetch-store\";\nimport { VARD_API_HOST } from \"./constants\";\n\n// ─────────────────────────────────────────────\n// No-op store (used in local dev when no apiKey is set)\n// ─────────────────────────────────────────────\n\nlet hasLoggedNoop = false;\nconst noopStore: VardStore = {\n get: () => {\n if (!hasLoggedNoop && process.env.NODE_ENV !== \"test\") {\n console.warn(\n \"[vard] Using default values for all variables because no Store was provided to createVard().\"\n );\n hasLoggedNoop = true;\n }\n return undefined;\n },\n};\n\n// ─────────────────────────────────────────────\n// createVard — the main SDK factory\n// ─────────────────────────────────────────────\n\n/**\n * Creates a Vard client instance. Call this once at the top of your site\n * (e.g. in `lib/vard.ts`) and export the result.\n */\nexport function createVard<S extends VardSchema = any>(\n options: VardOptions<S> = {}\n): VardClient<S> {\n const store: VardStore =\n options.store ?? (options.apiKey ? createVardFetchStore(options) : noopStore);\n\n // Registry of all declared variables — used by CLI + build pipeline\n const registry: VardVariableDefinition[] = [];\n\n function register<T>(def: VardVariableDefinition<T>): T {\n if (!registry.find((d) => d.key === def.key)) {\n registry.push(def as VardVariableDefinition);\n }\n\n const stored = store.get(def.key);\n if (stored !== undefined && stored !== null) {\n return stored as T;\n }\n\n return def.defaultValue;\n }\n\n // ─────────────────────────────────────────────\n // Schema Traversal\n // ─────────────────────────────────────────────\n\n function flattenSchema(schema: VardSchema, prefix = \"\"): any {\n const result: any = {};\n\n for (const [key, value] of Object.entries(schema)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === \"object\" && value !== null && \"type\" in value) {\n // It's a field or collection\n const field = value as VardField | VardCollection;\n\n if (field.type === \"collection\") {\n // Flatten collection schema but keep it as a 'list' type for the registry\n const collection = field as VardCollection;\n const listItemSchema: Record<string, string> = {};\n for (const [fKey, fVal] of Object.entries(collection.schema)) {\n listItemSchema[fKey] = (fVal as VardField).type;\n }\n\n register({\n key: fullKey,\n label: labelFromKey(key),\n type: \"list\",\n defaultValue: [],\n editableBy: \"member\",\n listItemSchema: listItemSchema as VardListItemSchema,\n isCollection: true,\n });\n\n // In the returned object, this remains a placeholder or is proxied to the store\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? [],\n enumerable: true,\n });\n } else {\n // It's a plain field\n const vardField = field as VardField;\n register({\n key: fullKey,\n label: vardField.label ?? labelFromKey(key),\n description: vardField.description,\n type: vardField.type,\n defaultValue: vardField.default,\n editableBy: vardField.editableBy ?? \"member\",\n group: vardField.group,\n });\n\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? vardField.default,\n enumerable: true,\n });\n }\n } else if (typeof value === \"object\" && value !== null) {\n // It's a nested object\n result[key] = flattenSchema(value as VardSchema, fullKey);\n }\n }\n\n return result;\n }\n\n // Auto-sync schema in development\n if (options.schema && process.env.NODE_ENV === \"development\" && options.apiKey) {\n flattenSchema(options.schema);\n const definitions = [...registry];\n const apiBase = VARD_API_HOST;\n\n fetch(`${apiBase}/api/content/variables/sync`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Vard-API-Key\": options.apiKey,\n },\n body: JSON.stringify({\n definitions,\n schema: options.schema,\n }),\n }).catch((err) => console.warn(\"[vard] Auto-sync failed:\", err));\n }\n\n const client: VardClient<S> = {\n define<NS extends VardSchema>(schema: NS): InferSchema<NS> {\n return flattenSchema(schema) as InferSchema<NS>;\n },\n\n async get(): Promise<InferSchema<S>> {\n if (store.prefetch) {\n await store.prefetch();\n }\n if (store.getStructured) {\n const structured = store.getStructured();\n if (structured && Object.keys(structured).length > 0) {\n return structured as InferSchema<S>;\n }\n }\n return flattenSchema(options.schema ?? {}) as InferSchema<S>;\n },\n\n string(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"string\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n richtext(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"richtext\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n color(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"color\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n image(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"image\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n boolean(key, fallback, opts: VardVariableOptions = {}) {\n return register<boolean>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"boolean\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n group: opts.group,\n });\n },\n\n list<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: VardVariableOptions = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n });\n },\n\n collection<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: Omit<VardVariableOptions, \"type\"> = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n isCollection: true,\n });\n },\n\n global: {\n string(key, fallback, opts = {}) {\n return client.string(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n richtext(key, fallback, opts = {}) {\n return client.richtext(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n color(key, fallback, opts = {}) {\n return client.color(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n image(key, fallback, opts = {}) {\n return client.image(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n boolean(key, fallback, opts = {}) {\n return client.boolean(key, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n list(key, schema, fallback, opts = {}) {\n return client.list(key, schema, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n },\n\n extend<E extends VardSchema>(fragment: VardSchemaFragment<E>): VardClient<MergeSchema<S, E>> {\n // Merge the base schema with the fragment — the fragment keys win on collision\n const mergedSchema = { ...(options.schema ?? {}), ...fragment } as unknown as MergeSchema<\n S,\n E\n >;\n // Return a new client with the merged schema, sharing the same store & registry.\n // We pass the in-memory store directly so there is no second fetch.\n return createVard<MergeSchema<S, E>>({\n ...options,\n schema: mergedSchema,\n store,\n });\n },\n\n getDefinitions() {\n return [...registry];\n },\n store,\n };\n\n return client;\n}\n\n// ─────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────\n\nfunction labelFromKey(key: string): string {\n const lastSegment = key.split(\".\").pop() ?? key;\n return lastSegment\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (c) => c.toUpperCase())\n .trim();\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACIO,IAAM,gBACX,QAAQ,IAAI,iBAAiB;;;ACwBxB,SAAS,qBACd,UAAiC,CAAC,GACS;AAC3C,QAAM;AAAA,IACJ,UAAU,QAAQ,WAAW;AAAA,IAC7B,SAAS,QAAQ,UAAU,QAAQ,IAAI;AAAA,IACvC,eAAe,CAAC;AAAA,IAChB,QAAQ,QAAQ,SAAS;AAAA,EAC3B,IAAI;AAEJ,MAAI,iBAA8C;AAClD,MAAI,oBAAyB;AAC7B,MAAI,eAAqF;AAEzF,iBAAe,cAA6E;AAC1F,UAAM,gBAAgB,QAAQ,IAAI,aAAa;AAE/C,QAAI,CAAC,QAAQ;AACX,UAAI,CAAC,eAAe;AAClB,gBAAQ;AAAA,UACN;AAAA,QAEF;AAAA,MACF,OAAO;AACL,gBAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AACA,aAAO,EAAE,WAAW,oBAAI,IAAI,GAAG,YAAY,CAAC,EAAE;AAAA,IAChD;AAEA,UAAM,MAAM,GAAG,OAAO;AAEtB,QAAI,OAAO;AACT,cAAQ,IAAI,uBAAuB,GAAG,EAAE;AACxC,cAAQ,IAAI,mBAAmB;AAAA,QAC7B,kBAAkB,OAAO,UAAU,GAAG,EAAE,IAAI;AAAA,QAC5C,GAAG,aAAa;AAAA,MAClB,CAAC;AAAA,IACH;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,KAAK;AAAA,QAC3B,GAAG;AAAA,QACH,SAAS;AAAA,UACP,GAAG,aAAa;AAAA,UAChB,kBAAkB;AAAA,QACpB;AAAA,MACF,CAAC;AAED,UAAI,CAAC,IAAI,IAAI;AACX,cAAM,WAAW,yCAAyC,GAAG,aAAa,IAAI,MAAM,IAAI,IAAI,UAAU;AACtG,gBAAQ,MAAM,WAAW,QAAQ,SAAS;AAC1C,eAAO,EAAE,WAAW,oBAAI,IAAI,GAAG,YAAY,CAAC,EAAE;AAAA,MAChD;AAEA,YAAM,OAAQ,MAAM,IAAI,KAAK;AAE7B,UAAI,OAAO;AACT,gBAAQ,IAAI,oBAAoB,IAAI,MAAM,MAAM,IAAI;AAAA,MACtD;AAGA,YAAM,eAAe,oBAAI,IAAqB;AAC9C,oBAAc,MAAM,IAAI,YAAY;AAEpC,aAAO;AAAA,QACL,WAAW;AAAA,QACX,YAAY;AAAA,MACd;AAAA,IACF,SAAS,KAAK;AACZ,YAAM,WAAW,gDAAgD,GAAG;AACpE,cAAQ,MAAM,WAAW,QAAQ,WAAW,GAAG;AAC/C,aAAO,EAAE,WAAW,oBAAI,IAAI,GAAG,YAAY,CAAC,EAAE;AAAA,IAChD;AAAA,EACF;AAEA,WAAS,cAAc,KAAU,QAAgB,KAA2B;AAC1E,QAAI,OAAO,QAAQ,YAAY,QAAQ,KAAM;AAE7C,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC9C,YAAM,UAAU,SAAS,GAAG,MAAM,IAAI,GAAG,KAAK;AAG9C,UAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,YAAI,IAAI,SAAS,KAAK;AAAA,MACxB,WAAW,OAAO,UAAU,YAAY,UAAU,MAAM;AACtD,sBAAc,OAAO,SAAS,GAAG;AAAA,MACnC,OAAO;AACL,YAAI,IAAI,SAAS,KAAK;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,IAAI,KAAsB;AACxB,aAAO,gBAAgB,IAAI,GAAG;AAAA,IAChC;AAAA,IAEA,gBAAqB;AACnB,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,WAA0B;AAC9B,UAAI,eAAgB;AACpB,UAAI,CAAC,cAAc;AACjB,uBAAe,YAAY;AAAA,MAC7B;AACA,YAAM,SAAS,MAAM;AACrB,uBAAiB,OAAO;AACxB,0BAAoB,OAAO;AAAA,IAC7B;AAAA,EACF;AACF;;;ACpHA,IAAI,gBAAgB;AACpB,IAAM,YAAuB;AAAA,EAC3B,KAAK,MAAM;AACT,QAAI,CAAC,iBAAiB,QAAQ,IAAI,aAAa,QAAQ;AACrD,cAAQ;AAAA,QACN;AAAA,MACF;AACA,sBAAgB;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AACF;AAUO,SAAS,WACd,UAA0B,CAAC,GACZ;AACf,QAAM,QACJ,QAAQ,UAAU,QAAQ,SAAS,qBAAqB,OAAO,IAAI;AAGrE,QAAM,WAAqC,CAAC;AAE5C,WAAS,SAAY,KAAmC;AACtD,QAAI,CAAC,SAAS,KAAK,CAAC,MAAM,EAAE,QAAQ,IAAI,GAAG,GAAG;AAC5C,eAAS,KAAK,GAA6B;AAAA,IAC7C;AAEA,UAAM,SAAS,MAAM,IAAI,IAAI,GAAG;AAChC,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,aAAO;AAAA,IACT;AAEA,WAAO,IAAI;AAAA,EACb;AAMA,WAAS,cAAc,QAAoB,SAAS,IAAS;AAC3D,UAAM,SAAc,CAAC;AAErB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,YAAM,UAAU,SAAS,GAAG,MAAM,IAAI,GAAG,KAAK;AAE9C,UAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,OAAO;AAElE,cAAM,QAAQ;AAEd,YAAI,MAAM,SAAS,cAAc;AAE/B,gBAAM,aAAa;AACnB,gBAAM,iBAAyC,CAAC;AAChD,qBAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,WAAW,MAAM,GAAG;AAC5D,2BAAe,IAAI,IAAK,KAAmB;AAAA,UAC7C;AAEA,mBAAS;AAAA,YACP,KAAK;AAAA,YACL,OAAO,aAAa,GAAG;AAAA,YACvB,MAAM;AAAA,YACN,cAAc,CAAC;AAAA,YACf,YAAY;AAAA,YACZ;AAAA,YACA,cAAc;AAAA,UAChB,CAAC;AAGD,iBAAO,eAAe,QAAQ,KAAK;AAAA,YACjC,KAAK,MAAM,MAAM,IAAI,OAAO,KAAK,CAAC;AAAA,YAClC,YAAY;AAAA,UACd,CAAC;AAAA,QACH,OAAO;AAEL,gBAAM,YAAY;AAClB,mBAAS;AAAA,YACP,KAAK;AAAA,YACL,OAAO,UAAU,SAAS,aAAa,GAAG;AAAA,YAC1C,aAAa,UAAU;AAAA,YACvB,MAAM,UAAU;AAAA,YAChB,cAAc,UAAU;AAAA,YACxB,YAAY,UAAU,cAAc;AAAA,YACpC,OAAO,UAAU;AAAA,UACnB,CAAC;AAED,iBAAO,eAAe,QAAQ,KAAK;AAAA,YACjC,KAAK,MAAM,MAAM,IAAI,OAAO,KAAK,UAAU;AAAA,YAC3C,YAAY;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF,WAAW,OAAO,UAAU,YAAY,UAAU,MAAM;AAEtD,eAAO,GAAG,IAAI,cAAc,OAAqB,OAAO;AAAA,MAC1D;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,UAAU,QAAQ,IAAI,aAAa,iBAAiB,QAAQ,QAAQ;AAC9E,kBAAc,QAAQ,MAAM;AAC5B,UAAM,cAAc,CAAC,GAAG,QAAQ;AAChC,UAAM,UAAU;AAEhB,UAAM,GAAG,OAAO,+BAA+B;AAAA,MAC7C,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,kBAAkB,QAAQ;AAAA,MAC5B;AAAA,MACA,MAAM,KAAK,UAAU;AAAA,QACnB;AAAA,QACA,QAAQ,QAAQ;AAAA,MAClB,CAAC;AAAA,IACH,CAAC,EAAE,MAAM,CAAC,QAAQ,QAAQ,KAAK,4BAA4B,GAAG,CAAC;AAAA,EACjE;AAEA,QAAM,SAAwB;AAAA,IAC5B,OAA8B,QAA6B;AACzD,aAAO,cAAc,MAAM;AAAA,IAC7B;AAAA,IAEA,MAAM,MAA+B;AACnC,UAAI,MAAM,UAAU;AAClB,cAAM,MAAM,SAAS;AAAA,MACvB;AACA,UAAI,MAAM,eAAe;AACvB,cAAM,aAAa,MAAM,cAAc;AACvC,YAAI,cAAc,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACpD,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO,cAAc,QAAQ,UAAU,CAAC,CAAC;AAAA,IAC3C;AAAA,IAEA,OAAO,KAAK,UAAU,OAA4B,CAAC,GAAG;AACpD,aAAO,SAAiB;AAAA,QACtB;AAAA,QACA,OAAO,KAAK,SAAS,aAAa,GAAG;AAAA,QACrC,aAAa,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAY,KAAK,cAAc;AAAA,QAC/B,OAAO,KAAK;AAAA,MACd,CAAC;AAAA,IACH;AAAA,IAEA,SAAS,KAAK,UAAU,OAA4B,CAAC,GAAG;AACtD,aAAO,SAAiB;AAAA,QACtB;AAAA,QACA,OAAO,KAAK,SAAS,aAAa,GAAG;AAAA,QACrC,aAAa,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAY,KAAK,cAAc;AAAA,QAC/B,OAAO,KAAK;AAAA,MACd,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,KAAK,UAAU,OAA4B,CAAC,GAAG;AACnD,aAAO,SAAiB;AAAA,QACtB;AAAA,QACA,OAAO,KAAK,SAAS,aAAa,GAAG;AAAA,QACrC,aAAa,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAY,KAAK,cAAc;AAAA,QAC/B,OAAO,KAAK;AAAA,MACd,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,KAAK,UAAU,OAA4B,CAAC,GAAG;AACnD,aAAO,SAAiB;AAAA,QACtB;AAAA,QACA,OAAO,KAAK,SAAS,aAAa,GAAG;AAAA,QACrC,aAAa,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAY,KAAK,cAAc;AAAA,QAC/B,OAAO,KAAK;AAAA,MACd,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ,KAAK,UAAU,OAA4B,CAAC,GAAG;AACrD,aAAO,SAAkB;AAAA,QACvB;AAAA,QACA,OAAO,KAAK,SAAS,aAAa,GAAG;AAAA,QACrC,aAAa,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAa,KAAK,cAA2B;AAAA,QAC7C,OAAO,KAAK;AAAA,MACd,CAAC;AAAA,IACH;AAAA,IAEA,KACE,KACA,QACA,UACA,OAA4B,CAAC,GACR;AACrB,aAAO,SAA8B;AAAA,QACnC;AAAA,QACA,OAAO,KAAK,SAAS,aAAa,GAAG;AAAA,QACrC,aAAa,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAa,KAAK,cAA2B;AAAA,QAC7C,gBAAgB;AAAA,QAChB,OAAO,KAAK;AAAA,MACd,CAAC;AAAA,IACH;AAAA,IAEA,WACE,KACA,QACA,UACA,OAA0C,CAAC,GACtB;AACrB,aAAO,SAA8B;AAAA,QACnC;AAAA,QACA,OAAO,KAAK,SAAS,aAAa,GAAG;AAAA,QACrC,aAAa,KAAK;AAAA,QAClB,MAAM;AAAA,QACN,cAAc;AAAA,QACd,YAAa,KAAK,cAA2B;AAAA,QAC7C,gBAAgB;AAAA,QAChB,OAAO,KAAK;AAAA,QACZ,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ;AAAA,MACN,OAAO,KAAK,UAAU,OAAO,CAAC,GAAG;AAC/B,eAAO,OAAO,OAAO,KAAK,UAAU,EAAE,GAAG,MAAM,OAAO,SAAS,CAAwB;AAAA,MACzF;AAAA,MACA,SAAS,KAAK,UAAU,OAAO,CAAC,GAAG;AACjC,eAAO,OAAO,SAAS,KAAK,UAAU,EAAE,GAAG,MAAM,OAAO,SAAS,CAAwB;AAAA,MAC3F;AAAA,MACA,MAAM,KAAK,UAAU,OAAO,CAAC,GAAG;AAC9B,eAAO,OAAO,MAAM,KAAK,UAAU,EAAE,GAAG,MAAM,OAAO,SAAS,CAAwB;AAAA,MACxF;AAAA,MACA,MAAM,KAAK,UAAU,OAAO,CAAC,GAAG;AAC9B,eAAO,OAAO,MAAM,KAAK,UAAU,EAAE,GAAG,MAAM,OAAO,SAAS,CAAwB;AAAA,MACxF;AAAA,MACA,QAAQ,KAAK,UAAU,OAAO,CAAC,GAAG;AAChC,eAAO,OAAO,QAAQ,KAAK,UAAU,EAAE,GAAG,MAAM,OAAO,SAAS,CAG/D;AAAA,MACH;AAAA,MACA,KAAK,KAAK,QAAQ,UAAU,OAAO,CAAC,GAAG;AACrC,eAAO,OAAO,KAAK,KAAK,QAAQ,UAAU,EAAE,GAAG,MAAM,OAAO,SAAS,CAGpE;AAAA,MACH;AAAA,IACF;AAAA,IAEA,OAA6B,UAAgE;AAE3F,YAAM,eAAe,EAAE,GAAI,QAAQ,UAAU,CAAC,GAAI,GAAG,SAAS;AAM9D,aAAO,WAA8B;AAAA,QACnC,GAAG;AAAA,QACH,QAAQ;AAAA,QACR;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,iBAAiB;AACf,aAAO,CAAC,GAAG,QAAQ;AAAA,IACrB;AAAA,IACA;AAAA,EACF;AAEA,SAAO;AACT;AAMA,SAAS,aAAa,KAAqB;AACzC,QAAM,cAAc,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK;AAC5C,SAAO,YACJ,QAAQ,YAAY,KAAK,EACzB,QAAQ,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EACpC,KAAK;AACV;;;AHtRO,SAAS,sBACd,UAAkC,CAAC,GACQ;AAC3C,QAAM,EAAE,QAAQ,eAAe,YAAY,GAAG,KAAK,IAAI;AAEvD,SAAO,qBAAqB;AAAA,IAC1B,GAAG;AAAA,IACH,cAAc;AAAA,MACZ;AAAA,MACA,GAAI,eAAe,UAAa,UAAU,gBACrC,EAAE,MAAM,EAAE,YAAY,MAAM,CAAC,WAAW,EAAE,EAAE,IAC7C,CAAC;AAAA,IACP;AAAA,EACF,CAAC;AACH;AA8BO,SAAS,eACd,UAAmD,CAAC,GACrC;AACf,QAAM,UAAU,sBAAsB,OAAO;AAC7C,SAAO,WAAc;AAAA,IACnB,GAAG;AAAA,IACH,OAAO;AAAA,EACT,CAAC;AACH;AAEA,eAAsB,mBACpB,QACe;AACf,QAAM,UAAW,OAAe,WAAW,SAAU,OAAsB;AAC3E,MAAI,WAAW,OAAQ,QAAgB,aAAa,YAAY;AAC9D,UAAO,QAAgB,SAAS;AAAA,EAClC;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/next.ts","../src/constants.ts","../src/fetch-store.ts","../src/client.ts"],"sourcesContent":["/**\n * @vard/sdk — Next.js adapter\n *\n * This module provides a VardStore implementation that reads variable values\n * from the Vard API at request time (App Router) or build time (static export).\n *\n * Usage in your Next.js site:\n *\n * // lib/vard.ts\n * import { createVardNextAdapter } from \"@vard/sdk/next\"\n * import { createVard } from \"@vard/sdk\"\n *\n * export const vard = createVard({\n * apiKey: process.env.VARD_API_KEY,\n * store: createVardNextAdapter(),\n * })\n */\n\nimport type { VardStore } from \"./types\";\n\nexport interface VardNextAdapterOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Falls back to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Next.js fetch cache strategy. Defaults to \"force-cache\" (SSG-friendly).\n * Use \"no-store\" for fully dynamic pages.\n */\n cache?: RequestCache;\n\n /**\n * Next.js ISR revalidation interval in seconds.\n * Only applies when cache is \"force-cache\".\n */\n revalidate?: number;\n\n /**\n * Enable verbose logging (e.g. cache hits, misses, TTL triggers).\n * Defaults to false.\n */\n debug?: boolean;\n}\n\nimport { createVardFetchStore, VardFetchStoreOptions } from \"./fetch-store\";\n\n/**\n * Creates a VardStore that fetches live variable values from the Vard API.\n * Designed for use inside Next.js App Router (server components, server actions).\n */\nexport function createVardNextAdapter(\n options: VardNextAdapterOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const { cache = \"force-cache\", revalidate, ...rest } = options;\n\n return createVardFetchStore({\n ...rest,\n // Sync the Next.js revalidation time (seconds) to the internal store TTL (seconds)\n ttl: revalidate !== undefined ? revalidate : 60,\n fetchOptions: {\n cache,\n ...(revalidate !== undefined && cache === \"force-cache\"\n ? ({ next: { revalidate, tags: [\"variables\"] } } as any)\n : {}),\n },\n });\n}\n\n/**\n * A convenience wrapper that creates a Vard client pre-loaded with live values.\n * Call this once in your Next.js layout before rendering any server component\n * that uses vard variables.\n *\n * @example\n * // app/layout.tsx\n * import { prefetchVardValues } from \"@vard/sdk/next\"\n * import { vard } from \"@/lib/vard\"\n *\n * export default async function RootLayout({ children }) {\n * await prefetchVardValues(vard)\n * return <html>...</html>\n * }\n */\nimport { createVard } from \"./client\";\nimport type { VardClient, VardOptions } from \"./types\";\n\nimport { VardSchema } from \"./schema\";\n\n/**\n * A convenience wrapper for createVard that automatically uses the Next.js adapter.\n *\n * @example\n * // lib/vard.ts\n * import { createVardNext } from \"@vard/sdk/next\"\n * export const vard = createVardNext({ revalidate: 60 })\n */\nexport function createVardNext<S extends VardSchema = any>(\n options: VardNextAdapterOptions & VardOptions<S> = {}\n): VardClient<S> {\n const adapter = createVardNextAdapter(options);\n return createVard<S>({\n ...options,\n store: adapter,\n });\n}\n\nexport async function prefetchVardValues(\n target: { prefetch(): Promise<void> } | VardClient\n): Promise<void> {\n const adapter = (target as any).prefetch ? target : (target as VardClient).store;\n if (adapter && typeof (adapter as any).prefetch === \"function\") {\n await (adapter as any).prefetch();\n }\n}\n","/**\n * The base URL for the Vard API.\n * Reads from VARD_API_HOST env var; falls back to https://vard.app.\n */\nexport const VARD_API_HOST: string = process.env.VARD_API_HOST ?? \"https://vard.app\";\n","import type { VardStore } from \"./types\";\nimport { VARD_API_HOST } from \"./constants\";\n\nexport interface VardFetchStoreOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Defaults to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Custom fetch options (headers, etc.)\n */\n fetchOptions?: RequestInit;\n\n /**\n * Enable verbose logging for requests and responses.\n */\n debug?: boolean;\n\n /**\n * Time in seconds to cache the fetched variables in memory.\n * Defaults to 60 (1 minute).\n */\n ttl?: number;\n}\n\n/**\n * Creates a universal VardStore that fetches variable values from the Vard API.\n * Works in any environment with a global `fetch` (Browsers, Node 18+, Bun, Deno).\n */\nexport function createVardFetchStore(\n options: VardFetchStoreOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const {\n apiBase = options.apiBase ?? VARD_API_HOST,\n apiKey = options.apiKey ?? process.env.VARD_API_KEY,\n fetchOptions = {},\n debug = options.debug ?? false,\n ttl = options.ttl ?? 60,\n } = options;\n\n let resolvedValues: Map<string, unknown> | null = null;\n let structuredContent: any = null;\n let fetchPromise: Promise<{ variables: Map<string, unknown>; structured: any }> | null = null;\n let lastFetchTime = 0;\n let lastLogTime = 0;\n\n async function fetchValues(): Promise<{ variables: Map<string, unknown>; structured: any }> {\n const isDevelopment = process.env.NODE_ENV === \"development\";\n\n if (!apiKey) {\n if (!isDevelopment) {\n console.error(\n \"\\x1b[31m[vard] Missing configuration! VARD_API_KEY is not set.\\x1b[0m\\n\" +\n \"Please set this environment variable in your production environment.\"\n );\n } else {\n console.warn(\n \"[vard] No API Key found. Running in local fallback mode (using default values).\"\n );\n }\n return { variables: new Map(), structured: {} };\n }\n\n const url = `${apiBase}/api/content/variables`;\n\n if (debug) {\n console.log(`[vard] Request: GET ${url}`);\n console.log(`[vard] Headers:`, {\n \"X-Vard-API-Key\": apiKey.substring(0, 10) + \"...\",\n ...fetchOptions.headers,\n });\n }\n\n try {\n const res = await fetch(url, {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n \"X-Vard-API-Key\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errorMsg = `[vard] Failed to fetch variables from ${url} (Status: ${res.status} ${res.statusText})`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`);\n return { variables: new Map(), structured: {} };\n }\n\n const data = (await res.json()) as Record<string, unknown>;\n\n if (debug) {\n console.log(`[vard] Response (${res.status}):`, data);\n }\n\n // Flatten the nested structure into the internal Map for key-based lookups\n const variablesMap = new Map<string, unknown>();\n flattenObject(data, \"\", variablesMap);\n\n return {\n variables: variablesMap,\n structured: data,\n };\n } catch (err) {\n const errorMsg = `[vard] Network error fetching variables from ${url}`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`, err);\n return { variables: new Map(), structured: {} };\n }\n }\n\n function flattenObject(obj: any, prefix: string, map: Map<string, unknown>) {\n if (typeof obj !== \"object\" || obj === null) return;\n\n for (const [key, value] of Object.entries(obj)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n // If it's an array, we treat it as a single value (e.g. a collection)\n if (Array.isArray(value)) {\n map.set(fullKey, value);\n } else if (typeof value === \"object\" && value !== null) {\n flattenObject(value, fullKey, map);\n } else {\n map.set(fullKey, value);\n }\n }\n }\n\n return {\n get(key: string): unknown {\n return resolvedValues?.get(key);\n },\n\n getStructured(): any {\n return structuredContent;\n },\n\n async prefetch(): Promise<void> {\n const now = Date.now();\n\n if (resolvedValues) {\n const elapsed = Math.floor((now - lastFetchTime) / 1000);\n if (elapsed < ttl) {\n if (now - lastLogTime > 2000) {\n if (debug) {\n console.log(`[vard] Cache HIT. Next fresh check in ${ttl - elapsed}s.`);\n }\n lastLogTime = now;\n }\n return;\n }\n }\n\n if (!fetchPromise) {\n if (debug) {\n if (resolvedValues) {\n console.log(`[vard] Cache STALE (${ttl}s TTL expired). Fetching fresh data...`);\n } else {\n console.log(`[vard] Cache COLD. Initializing fresh fetch...`);\n }\n }\n fetchPromise = fetchValues();\n }\n\n try {\n const result = await fetchPromise;\n resolvedValues = result.variables;\n structuredContent = result.structured;\n lastFetchTime = Date.now();\n } finally {\n fetchPromise = null;\n }\n },\n };\n}\n","import {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n VardVariableType,\n} from \"./types\";\nimport {\n VardSchema,\n InferSchema,\n VardField,\n VardCollection,\n VardSchemaFragment,\n MergeSchema,\n} from \"./schema\";\nimport { createVardFetchStore } from \"./fetch-store\";\nimport { VARD_API_HOST } from \"./constants\";\n\n// ─────────────────────────────────────────────\n// No-op store (used in local dev when no apiKey is set)\n// ─────────────────────────────────────────────\n\nlet hasLoggedNoop = false;\nconst noopStore: VardStore = {\n get: () => {\n if (!hasLoggedNoop && process.env.NODE_ENV !== \"test\") {\n console.warn(\n \"[vard] Using default values for all variables because no Store was provided to createVard().\"\n );\n hasLoggedNoop = true;\n }\n return undefined;\n },\n};\n\n// ─────────────────────────────────────────────\n// createVard — the main SDK factory\n// ─────────────────────────────────────────────\n\n/**\n * Creates a Vard client instance. Call this once at the top of your site\n * (e.g. in `lib/vard.ts`) and export the result.\n */\nexport function createVard<S extends VardSchema = any>(\n options: VardOptions<S> = {}\n): VardClient<S> {\n const store: VardStore =\n options.store ?? (options.apiKey ? createVardFetchStore(options) : noopStore);\n\n // Registry of all declared variables — used by CLI + build pipeline\n const registry: VardVariableDefinition[] = [];\n\n function register<T>(def: VardVariableDefinition<T>): T {\n if (!registry.find((d) => d.key === def.key)) {\n registry.push(def as VardVariableDefinition);\n }\n\n const stored = store.get(def.key);\n if (stored !== undefined && stored !== null) {\n return stored as T;\n }\n\n return def.defaultValue;\n }\n\n // ─────────────────────────────────────────────\n // Schema Traversal\n // ─────────────────────────────────────────────\n\n function flattenSchema(schema: VardSchema, prefix = \"\"): any {\n const result: any = {};\n\n for (const [key, value] of Object.entries(schema)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === \"object\" && value !== null && \"type\" in value) {\n // It's a field or collection\n const field = value as VardField | VardCollection;\n\n if (field.type === \"collection\") {\n // Flatten collection schema but keep it as a 'list' type for the registry\n const collection = field as VardCollection;\n const listItemSchema: Record<string, string> = {};\n for (const [fKey, fVal] of Object.entries(collection.schema)) {\n listItemSchema[fKey] = (fVal as VardField).type;\n }\n\n register({\n key: fullKey,\n label: labelFromKey(key),\n type: \"list\",\n defaultValue: [],\n editableBy: \"member\",\n listItemSchema: listItemSchema as VardListItemSchema,\n isCollection: true,\n });\n\n // In the returned object, this remains a placeholder or is proxied to the store\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? [],\n enumerable: true,\n });\n } else {\n // It's a plain field\n const vardField = field as VardField;\n register({\n key: fullKey,\n label: vardField.label ?? labelFromKey(key),\n description: vardField.description,\n type: vardField.type,\n defaultValue: vardField.default,\n editableBy: vardField.editableBy ?? \"member\",\n group: vardField.group,\n });\n\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? vardField.default,\n enumerable: true,\n });\n }\n } else if (typeof value === \"object\" && value !== null) {\n // It's a nested object\n result[key] = flattenSchema(value as VardSchema, fullKey);\n }\n }\n\n return result;\n }\n\n // Auto-sync schema in development\n if (options.schema && process.env.NODE_ENV === \"development\" && options.apiKey) {\n flattenSchema(options.schema);\n const definitions = [...registry];\n const apiBase = VARD_API_HOST;\n\n fetch(`${apiBase}/api/content/variables/sync`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Vard-API-Key\": options.apiKey,\n },\n body: JSON.stringify({\n definitions,\n schema: options.schema,\n }),\n }).catch((err) => console.warn(\"[vard] Auto-sync failed:\", err));\n }\n\n const client: VardClient<S> = {\n define<NS extends VardSchema>(schema: NS): InferSchema<NS> {\n return flattenSchema(schema) as InferSchema<NS>;\n },\n\n async get(): Promise<InferSchema<S>> {\n if (store.prefetch) {\n await store.prefetch();\n }\n if (store.getStructured) {\n const structured = store.getStructured();\n if (structured && Object.keys(structured).length > 0) {\n return structured as InferSchema<S>;\n }\n }\n return flattenSchema(options.schema ?? {}) as InferSchema<S>;\n },\n\n string(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"string\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n richtext(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"richtext\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n color(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"color\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n image(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"image\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n boolean(key, fallback, opts: VardVariableOptions = {}) {\n return register<boolean>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"boolean\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n group: opts.group,\n });\n },\n\n list<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: VardVariableOptions = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n });\n },\n\n collection<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: Omit<VardVariableOptions, \"type\"> = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n isCollection: true,\n });\n },\n\n global: {\n string(key, fallback, opts = {}) {\n return client.string(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n richtext(key, fallback, opts = {}) {\n return client.richtext(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n color(key, fallback, opts = {}) {\n return client.color(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n image(key, fallback, opts = {}) {\n return client.image(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n boolean(key, fallback, opts = {}) {\n return client.boolean(key, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n list(key, schema, fallback, opts = {}) {\n return client.list(key, schema, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n },\n\n extend<E extends VardSchema>(fragment: VardSchemaFragment<E>): VardClient<MergeSchema<S, E>> {\n // Merge the base schema with the fragment — the fragment keys win on collision\n const mergedSchema = { ...(options.schema ?? {}), ...fragment } as unknown as MergeSchema<\n S,\n E\n >;\n // Return a new client with the merged schema, sharing the same store & registry.\n // We pass the in-memory store directly so there is no second fetch.\n return createVard<MergeSchema<S, E>>({\n ...options,\n schema: mergedSchema,\n store,\n });\n },\n\n getDefinitions() {\n return [...registry];\n },\n store,\n };\n\n return client;\n}\n\n// ─────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────\n\nfunction labelFromKey(key: string): string {\n const lastSegment = key.split(\".\").pop() ?? key;\n return lastSegment\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (c) => c.toUpperCase())\n .trim();\n}\n"],"mappings":"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","names":[]}
|
package/dist/next.mjs
CHANGED
|
@@ -7,11 +7,14 @@ function createVardFetchStore(options = {}) {
|
|
|
7
7
|
apiBase = options.apiBase ?? VARD_API_HOST,
|
|
8
8
|
apiKey = options.apiKey ?? process.env.VARD_API_KEY,
|
|
9
9
|
fetchOptions = {},
|
|
10
|
-
debug = options.debug ?? false
|
|
10
|
+
debug = options.debug ?? false,
|
|
11
|
+
ttl = options.ttl ?? 60
|
|
11
12
|
} = options;
|
|
12
13
|
let resolvedValues = null;
|
|
13
14
|
let structuredContent = null;
|
|
14
15
|
let fetchPromise = null;
|
|
16
|
+
let lastFetchTime = 0;
|
|
17
|
+
let lastLogTime = 0;
|
|
15
18
|
async function fetchValues() {
|
|
16
19
|
const isDevelopment = process.env.NODE_ENV === "development";
|
|
17
20
|
if (!apiKey) {
|
|
@@ -84,13 +87,37 @@ function createVardFetchStore(options = {}) {
|
|
|
84
87
|
return structuredContent;
|
|
85
88
|
},
|
|
86
89
|
async prefetch() {
|
|
87
|
-
|
|
90
|
+
const now = Date.now();
|
|
91
|
+
if (resolvedValues) {
|
|
92
|
+
const elapsed = Math.floor((now - lastFetchTime) / 1e3);
|
|
93
|
+
if (elapsed < ttl) {
|
|
94
|
+
if (now - lastLogTime > 2e3) {
|
|
95
|
+
if (debug) {
|
|
96
|
+
console.log(`[vard] Cache HIT. Next fresh check in ${ttl - elapsed}s.`);
|
|
97
|
+
}
|
|
98
|
+
lastLogTime = now;
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
88
103
|
if (!fetchPromise) {
|
|
104
|
+
if (debug) {
|
|
105
|
+
if (resolvedValues) {
|
|
106
|
+
console.log(`[vard] Cache STALE (${ttl}s TTL expired). Fetching fresh data...`);
|
|
107
|
+
} else {
|
|
108
|
+
console.log(`[vard] Cache COLD. Initializing fresh fetch...`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
89
111
|
fetchPromise = fetchValues();
|
|
90
112
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
113
|
+
try {
|
|
114
|
+
const result = await fetchPromise;
|
|
115
|
+
resolvedValues = result.variables;
|
|
116
|
+
structuredContent = result.structured;
|
|
117
|
+
lastFetchTime = Date.now();
|
|
118
|
+
} finally {
|
|
119
|
+
fetchPromise = null;
|
|
120
|
+
}
|
|
94
121
|
}
|
|
95
122
|
};
|
|
96
123
|
}
|
|
@@ -325,6 +352,8 @@ function createVardNextAdapter(options = {}) {
|
|
|
325
352
|
const { cache = "force-cache", revalidate, ...rest } = options;
|
|
326
353
|
return createVardFetchStore({
|
|
327
354
|
...rest,
|
|
355
|
+
// Sync the Next.js revalidation time (seconds) to the internal store TTL (seconds)
|
|
356
|
+
ttl: revalidate !== void 0 ? revalidate : 60,
|
|
328
357
|
fetchOptions: {
|
|
329
358
|
cache,
|
|
330
359
|
...revalidate !== void 0 && cache === "force-cache" ? { next: { revalidate, tags: ["variables"] } } : {}
|
package/dist/next.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/fetch-store.ts","../src/client.ts","../src/next.ts"],"sourcesContent":["/**\n * The base URL for the Vard API.\n * Reads from VARD_API_HOST env var; falls back to https://vard.app.\n */\nexport const VARD_API_HOST: string =\n process.env.VARD_API_HOST ?? \"https://vard.app\";\n","import type { VardStore } from \"./types\";\nimport { VARD_API_HOST } from \"./constants\";\n\nexport interface VardFetchStoreOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Defaults to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Custom fetch options (headers, etc.)\n */\n fetchOptions?: RequestInit;\n\n /**\n * Enable verbose logging for requests and responses.\n */\n debug?: boolean;\n}\n\n/**\n * Creates a universal VardStore that fetches variable values from the Vard API.\n * Works in any environment with a global `fetch` (Browsers, Node 18+, Bun, Deno).\n */\nexport function createVardFetchStore(\n options: VardFetchStoreOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const {\n apiBase = options.apiBase ?? VARD_API_HOST,\n apiKey = options.apiKey ?? process.env.VARD_API_KEY,\n fetchOptions = {},\n debug = options.debug ?? false,\n } = options;\n\n let resolvedValues: Map<string, unknown> | null = null;\n let structuredContent: any = null;\n let fetchPromise: Promise<{ variables: Map<string, unknown>; structured: any }> | null = null;\n\n async function fetchValues(): Promise<{ variables: Map<string, unknown>; structured: any }> {\n const isDevelopment = process.env.NODE_ENV === \"development\";\n\n if (!apiKey) {\n if (!isDevelopment) {\n console.error(\n \"\\x1b[31m[vard] Missing configuration! VARD_API_KEY is not set.\\x1b[0m\\n\" +\n \"Please set this environment variable in your production environment.\"\n );\n } else {\n console.warn(\n \"[vard] No API Key found. Running in local fallback mode (using default values).\"\n );\n }\n return { variables: new Map(), structured: {} };\n }\n\n const url = `${apiBase}/api/content/variables`;\n\n if (debug) {\n console.log(`[vard] Request: GET ${url}`);\n console.log(`[vard] Headers:`, {\n \"X-Vard-API-Key\": apiKey.substring(0, 10) + \"...\",\n ...fetchOptions.headers,\n });\n }\n\n try {\n const res = await fetch(url, {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n \"X-Vard-API-Key\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errorMsg = `[vard] Failed to fetch variables from ${url} (Status: ${res.status} ${res.statusText})`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`);\n return { variables: new Map(), structured: {} };\n }\n\n const data = (await res.json()) as Record<string, unknown>;\n\n if (debug) {\n console.log(`[vard] Response (${res.status}):`, data);\n }\n\n // Flatten the nested structure into the internal Map for key-based lookups\n const variablesMap = new Map<string, unknown>();\n flattenObject(data, \"\", variablesMap);\n\n return {\n variables: variablesMap,\n structured: data,\n };\n } catch (err) {\n const errorMsg = `[vard] Network error fetching variables from ${url}`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`, err);\n return { variables: new Map(), structured: {} };\n }\n }\n\n function flattenObject(obj: any, prefix: string, map: Map<string, unknown>) {\n if (typeof obj !== \"object\" || obj === null) return;\n\n for (const [key, value] of Object.entries(obj)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n // If it's an array, we treat it as a single value (e.g. a collection)\n if (Array.isArray(value)) {\n map.set(fullKey, value);\n } else if (typeof value === \"object\" && value !== null) {\n flattenObject(value, fullKey, map);\n } else {\n map.set(fullKey, value);\n }\n }\n }\n\n return {\n get(key: string): unknown {\n return resolvedValues?.get(key);\n },\n\n getStructured(): any {\n return structuredContent;\n },\n\n async prefetch(): Promise<void> {\n if (resolvedValues) return;\n if (!fetchPromise) {\n fetchPromise = fetchValues();\n }\n const result = await fetchPromise;\n resolvedValues = result.variables;\n structuredContent = result.structured;\n },\n };\n}\n","import {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n VardVariableType,\n} from \"./types\";\nimport {\n VardSchema,\n InferSchema,\n VardField,\n VardCollection,\n VardSchemaFragment,\n MergeSchema,\n} from \"./schema\";\nimport { createVardFetchStore } from \"./fetch-store\";\nimport { VARD_API_HOST } from \"./constants\";\n\n// ─────────────────────────────────────────────\n// No-op store (used in local dev when no apiKey is set)\n// ─────────────────────────────────────────────\n\nlet hasLoggedNoop = false;\nconst noopStore: VardStore = {\n get: () => {\n if (!hasLoggedNoop && process.env.NODE_ENV !== \"test\") {\n console.warn(\n \"[vard] Using default values for all variables because no Store was provided to createVard().\"\n );\n hasLoggedNoop = true;\n }\n return undefined;\n },\n};\n\n// ─────────────────────────────────────────────\n// createVard — the main SDK factory\n// ─────────────────────────────────────────────\n\n/**\n * Creates a Vard client instance. Call this once at the top of your site\n * (e.g. in `lib/vard.ts`) and export the result.\n */\nexport function createVard<S extends VardSchema = any>(\n options: VardOptions<S> = {}\n): VardClient<S> {\n const store: VardStore =\n options.store ?? (options.apiKey ? createVardFetchStore(options) : noopStore);\n\n // Registry of all declared variables — used by CLI + build pipeline\n const registry: VardVariableDefinition[] = [];\n\n function register<T>(def: VardVariableDefinition<T>): T {\n if (!registry.find((d) => d.key === def.key)) {\n registry.push(def as VardVariableDefinition);\n }\n\n const stored = store.get(def.key);\n if (stored !== undefined && stored !== null) {\n return stored as T;\n }\n\n return def.defaultValue;\n }\n\n // ─────────────────────────────────────────────\n // Schema Traversal\n // ─────────────────────────────────────────────\n\n function flattenSchema(schema: VardSchema, prefix = \"\"): any {\n const result: any = {};\n\n for (const [key, value] of Object.entries(schema)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === \"object\" && value !== null && \"type\" in value) {\n // It's a field or collection\n const field = value as VardField | VardCollection;\n\n if (field.type === \"collection\") {\n // Flatten collection schema but keep it as a 'list' type for the registry\n const collection = field as VardCollection;\n const listItemSchema: Record<string, string> = {};\n for (const [fKey, fVal] of Object.entries(collection.schema)) {\n listItemSchema[fKey] = (fVal as VardField).type;\n }\n\n register({\n key: fullKey,\n label: labelFromKey(key),\n type: \"list\",\n defaultValue: [],\n editableBy: \"member\",\n listItemSchema: listItemSchema as VardListItemSchema,\n isCollection: true,\n });\n\n // In the returned object, this remains a placeholder or is proxied to the store\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? [],\n enumerable: true,\n });\n } else {\n // It's a plain field\n const vardField = field as VardField;\n register({\n key: fullKey,\n label: vardField.label ?? labelFromKey(key),\n description: vardField.description,\n type: vardField.type,\n defaultValue: vardField.default,\n editableBy: vardField.editableBy ?? \"member\",\n group: vardField.group,\n });\n\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? vardField.default,\n enumerable: true,\n });\n }\n } else if (typeof value === \"object\" && value !== null) {\n // It's a nested object\n result[key] = flattenSchema(value as VardSchema, fullKey);\n }\n }\n\n return result;\n }\n\n // Auto-sync schema in development\n if (options.schema && process.env.NODE_ENV === \"development\" && options.apiKey) {\n flattenSchema(options.schema);\n const definitions = [...registry];\n const apiBase = VARD_API_HOST;\n\n fetch(`${apiBase}/api/content/variables/sync`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Vard-API-Key\": options.apiKey,\n },\n body: JSON.stringify({\n definitions,\n schema: options.schema,\n }),\n }).catch((err) => console.warn(\"[vard] Auto-sync failed:\", err));\n }\n\n const client: VardClient<S> = {\n define<NS extends VardSchema>(schema: NS): InferSchema<NS> {\n return flattenSchema(schema) as InferSchema<NS>;\n },\n\n async get(): Promise<InferSchema<S>> {\n if (store.prefetch) {\n await store.prefetch();\n }\n if (store.getStructured) {\n const structured = store.getStructured();\n if (structured && Object.keys(structured).length > 0) {\n return structured as InferSchema<S>;\n }\n }\n return flattenSchema(options.schema ?? {}) as InferSchema<S>;\n },\n\n string(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"string\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n richtext(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"richtext\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n color(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"color\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n image(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"image\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n boolean(key, fallback, opts: VardVariableOptions = {}) {\n return register<boolean>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"boolean\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n group: opts.group,\n });\n },\n\n list<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: VardVariableOptions = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n });\n },\n\n collection<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: Omit<VardVariableOptions, \"type\"> = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n isCollection: true,\n });\n },\n\n global: {\n string(key, fallback, opts = {}) {\n return client.string(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n richtext(key, fallback, opts = {}) {\n return client.richtext(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n color(key, fallback, opts = {}) {\n return client.color(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n image(key, fallback, opts = {}) {\n return client.image(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n boolean(key, fallback, opts = {}) {\n return client.boolean(key, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n list(key, schema, fallback, opts = {}) {\n return client.list(key, schema, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n },\n\n extend<E extends VardSchema>(fragment: VardSchemaFragment<E>): VardClient<MergeSchema<S, E>> {\n // Merge the base schema with the fragment — the fragment keys win on collision\n const mergedSchema = { ...(options.schema ?? {}), ...fragment } as unknown as MergeSchema<\n S,\n E\n >;\n // Return a new client with the merged schema, sharing the same store & registry.\n // We pass the in-memory store directly so there is no second fetch.\n return createVard<MergeSchema<S, E>>({\n ...options,\n schema: mergedSchema,\n store,\n });\n },\n\n getDefinitions() {\n return [...registry];\n },\n store,\n };\n\n return client;\n}\n\n// ─────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────\n\nfunction labelFromKey(key: string): string {\n const lastSegment = key.split(\".\").pop() ?? key;\n return lastSegment\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (c) => c.toUpperCase())\n .trim();\n}\n","/**\n * @vard/sdk — Next.js adapter\n *\n * This module provides a VardStore implementation that reads variable values\n * from the Vard API at request time (App Router) or build time (static export).\n *\n * Usage in your Next.js site:\n *\n * // lib/vard.ts\n * import { createVardNextAdapter } from \"@vard/sdk/next\"\n * import { createVard } from \"@vard/sdk\"\n *\n * export const vard = createVard({\n * apiKey: process.env.VARD_API_KEY,\n * store: createVardNextAdapter(),\n * })\n */\n\nimport type { VardStore } from \"./types\";\n\nexport interface VardNextAdapterOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Falls back to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Next.js fetch cache strategy. Defaults to \"force-cache\" (SSG-friendly).\n * Use \"no-store\" for fully dynamic pages.\n */\n cache?: RequestCache;\n\n /**\n * Next.js ISR revalidation interval in seconds.\n * Only applies when cache is \"force-cache\".\n */\n revalidate?: number;\n}\n\nimport { createVardFetchStore, VardFetchStoreOptions } from \"./fetch-store\";\n\n/**\n * Creates a VardStore that fetches live variable values from the Vard API.\n * Designed for use inside Next.js App Router (server components, server actions).\n */\nexport function createVardNextAdapter(\n options: VardNextAdapterOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const { cache = \"force-cache\", revalidate, ...rest } = options;\n\n return createVardFetchStore({\n ...rest,\n fetchOptions: {\n cache,\n ...(revalidate !== undefined && cache === \"force-cache\"\n ? ({ next: { revalidate, tags: [\"variables\"] } } as any)\n : {}),\n },\n });\n}\n\n/**\n * A convenience wrapper that creates a Vard client pre-loaded with live values.\n * Call this once in your Next.js layout before rendering any server component\n * that uses vard variables.\n *\n * @example\n * // app/layout.tsx\n * import { prefetchVardValues } from \"@vard/sdk/next\"\n * import { vard } from \"@/lib/vard\"\n *\n * export default async function RootLayout({ children }) {\n * await prefetchVardValues(vard)\n * return <html>...</html>\n * }\n */\nimport { createVard } from \"./client\";\nimport type { VardClient, VardOptions } from \"./types\";\n\nimport { VardSchema } from \"./schema\";\n\n/**\n * A convenience wrapper for createVard that automatically uses the Next.js adapter.\n *\n * @example\n * // lib/vard.ts\n * import { createVardNext } from \"@vard/sdk/next\"\n * export const vard = createVardNext({ revalidate: 60 })\n */\nexport function createVardNext<S extends VardSchema = any>(\n options: VardNextAdapterOptions & VardOptions<S> = {}\n): VardClient<S> {\n const adapter = createVardNextAdapter(options);\n return createVard<S>({\n ...options,\n store: adapter,\n });\n}\n\nexport async function prefetchVardValues(\n target: { prefetch(): Promise<void> } | VardClient\n): Promise<void> {\n const adapter = (target as any).prefetch ? target : (target as VardClient).store;\n if (adapter && typeof (adapter as any).prefetch === \"function\") {\n await (adapter as any).prefetch();\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/fetch-store.ts","../src/client.ts","../src/next.ts"],"sourcesContent":["/**\n * The base URL for the Vard API.\n * Reads from VARD_API_HOST env var; falls back to https://vard.app.\n */\nexport const VARD_API_HOST: string = process.env.VARD_API_HOST ?? \"https://vard.app\";\n","import type { VardStore } from \"./types\";\nimport { VARD_API_HOST } from \"./constants\";\n\nexport interface VardFetchStoreOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Defaults to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Custom fetch options (headers, etc.)\n */\n fetchOptions?: RequestInit;\n\n /**\n * Enable verbose logging for requests and responses.\n */\n debug?: boolean;\n\n /**\n * Time in seconds to cache the fetched variables in memory.\n * Defaults to 60 (1 minute).\n */\n ttl?: number;\n}\n\n/**\n * Creates a universal VardStore that fetches variable values from the Vard API.\n * Works in any environment with a global `fetch` (Browsers, Node 18+, Bun, Deno).\n */\nexport function createVardFetchStore(\n options: VardFetchStoreOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const {\n apiBase = options.apiBase ?? VARD_API_HOST,\n apiKey = options.apiKey ?? process.env.VARD_API_KEY,\n fetchOptions = {},\n debug = options.debug ?? false,\n ttl = options.ttl ?? 60,\n } = options;\n\n let resolvedValues: Map<string, unknown> | null = null;\n let structuredContent: any = null;\n let fetchPromise: Promise<{ variables: Map<string, unknown>; structured: any }> | null = null;\n let lastFetchTime = 0;\n let lastLogTime = 0;\n\n async function fetchValues(): Promise<{ variables: Map<string, unknown>; structured: any }> {\n const isDevelopment = process.env.NODE_ENV === \"development\";\n\n if (!apiKey) {\n if (!isDevelopment) {\n console.error(\n \"\\x1b[31m[vard] Missing configuration! VARD_API_KEY is not set.\\x1b[0m\\n\" +\n \"Please set this environment variable in your production environment.\"\n );\n } else {\n console.warn(\n \"[vard] No API Key found. Running in local fallback mode (using default values).\"\n );\n }\n return { variables: new Map(), structured: {} };\n }\n\n const url = `${apiBase}/api/content/variables`;\n\n if (debug) {\n console.log(`[vard] Request: GET ${url}`);\n console.log(`[vard] Headers:`, {\n \"X-Vard-API-Key\": apiKey.substring(0, 10) + \"...\",\n ...fetchOptions.headers,\n });\n }\n\n try {\n const res = await fetch(url, {\n ...fetchOptions,\n headers: {\n ...fetchOptions.headers,\n \"X-Vard-API-Key\": apiKey,\n },\n });\n\n if (!res.ok) {\n const errorMsg = `[vard] Failed to fetch variables from ${url} (Status: ${res.status} ${res.statusText})`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`);\n return { variables: new Map(), structured: {} };\n }\n\n const data = (await res.json()) as Record<string, unknown>;\n\n if (debug) {\n console.log(`[vard] Response (${res.status}):`, data);\n }\n\n // Flatten the nested structure into the internal Map for key-based lookups\n const variablesMap = new Map<string, unknown>();\n flattenObject(data, \"\", variablesMap);\n\n return {\n variables: variablesMap,\n structured: data,\n };\n } catch (err) {\n const errorMsg = `[vard] Network error fetching variables from ${url}`;\n console.error(`\\x1b[31m${errorMsg}\\x1b[0m`, err);\n return { variables: new Map(), structured: {} };\n }\n }\n\n function flattenObject(obj: any, prefix: string, map: Map<string, unknown>) {\n if (typeof obj !== \"object\" || obj === null) return;\n\n for (const [key, value] of Object.entries(obj)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n // If it's an array, we treat it as a single value (e.g. a collection)\n if (Array.isArray(value)) {\n map.set(fullKey, value);\n } else if (typeof value === \"object\" && value !== null) {\n flattenObject(value, fullKey, map);\n } else {\n map.set(fullKey, value);\n }\n }\n }\n\n return {\n get(key: string): unknown {\n return resolvedValues?.get(key);\n },\n\n getStructured(): any {\n return structuredContent;\n },\n\n async prefetch(): Promise<void> {\n const now = Date.now();\n\n if (resolvedValues) {\n const elapsed = Math.floor((now - lastFetchTime) / 1000);\n if (elapsed < ttl) {\n if (now - lastLogTime > 2000) {\n if (debug) {\n console.log(`[vard] Cache HIT. Next fresh check in ${ttl - elapsed}s.`);\n }\n lastLogTime = now;\n }\n return;\n }\n }\n\n if (!fetchPromise) {\n if (debug) {\n if (resolvedValues) {\n console.log(`[vard] Cache STALE (${ttl}s TTL expired). Fetching fresh data...`);\n } else {\n console.log(`[vard] Cache COLD. Initializing fresh fetch...`);\n }\n }\n fetchPromise = fetchValues();\n }\n\n try {\n const result = await fetchPromise;\n resolvedValues = result.variables;\n structuredContent = result.structured;\n lastFetchTime = Date.now();\n } finally {\n fetchPromise = null;\n }\n },\n };\n}\n","import {\n VardClient,\n VardOptions,\n VardStore,\n VardVariableDefinition,\n VardVariableOptions,\n VardListItemSchema,\n InferListItem,\n VardRole,\n VardVariableType,\n} from \"./types\";\nimport {\n VardSchema,\n InferSchema,\n VardField,\n VardCollection,\n VardSchemaFragment,\n MergeSchema,\n} from \"./schema\";\nimport { createVardFetchStore } from \"./fetch-store\";\nimport { VARD_API_HOST } from \"./constants\";\n\n// ─────────────────────────────────────────────\n// No-op store (used in local dev when no apiKey is set)\n// ─────────────────────────────────────────────\n\nlet hasLoggedNoop = false;\nconst noopStore: VardStore = {\n get: () => {\n if (!hasLoggedNoop && process.env.NODE_ENV !== \"test\") {\n console.warn(\n \"[vard] Using default values for all variables because no Store was provided to createVard().\"\n );\n hasLoggedNoop = true;\n }\n return undefined;\n },\n};\n\n// ─────────────────────────────────────────────\n// createVard — the main SDK factory\n// ─────────────────────────────────────────────\n\n/**\n * Creates a Vard client instance. Call this once at the top of your site\n * (e.g. in `lib/vard.ts`) and export the result.\n */\nexport function createVard<S extends VardSchema = any>(\n options: VardOptions<S> = {}\n): VardClient<S> {\n const store: VardStore =\n options.store ?? (options.apiKey ? createVardFetchStore(options) : noopStore);\n\n // Registry of all declared variables — used by CLI + build pipeline\n const registry: VardVariableDefinition[] = [];\n\n function register<T>(def: VardVariableDefinition<T>): T {\n if (!registry.find((d) => d.key === def.key)) {\n registry.push(def as VardVariableDefinition);\n }\n\n const stored = store.get(def.key);\n if (stored !== undefined && stored !== null) {\n return stored as T;\n }\n\n return def.defaultValue;\n }\n\n // ─────────────────────────────────────────────\n // Schema Traversal\n // ─────────────────────────────────────────────\n\n function flattenSchema(schema: VardSchema, prefix = \"\"): any {\n const result: any = {};\n\n for (const [key, value] of Object.entries(schema)) {\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === \"object\" && value !== null && \"type\" in value) {\n // It's a field or collection\n const field = value as VardField | VardCollection;\n\n if (field.type === \"collection\") {\n // Flatten collection schema but keep it as a 'list' type for the registry\n const collection = field as VardCollection;\n const listItemSchema: Record<string, string> = {};\n for (const [fKey, fVal] of Object.entries(collection.schema)) {\n listItemSchema[fKey] = (fVal as VardField).type;\n }\n\n register({\n key: fullKey,\n label: labelFromKey(key),\n type: \"list\",\n defaultValue: [],\n editableBy: \"member\",\n listItemSchema: listItemSchema as VardListItemSchema,\n isCollection: true,\n });\n\n // In the returned object, this remains a placeholder or is proxied to the store\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? [],\n enumerable: true,\n });\n } else {\n // It's a plain field\n const vardField = field as VardField;\n register({\n key: fullKey,\n label: vardField.label ?? labelFromKey(key),\n description: vardField.description,\n type: vardField.type,\n defaultValue: vardField.default,\n editableBy: vardField.editableBy ?? \"member\",\n group: vardField.group,\n });\n\n Object.defineProperty(result, key, {\n get: () => store.get(fullKey) ?? vardField.default,\n enumerable: true,\n });\n }\n } else if (typeof value === \"object\" && value !== null) {\n // It's a nested object\n result[key] = flattenSchema(value as VardSchema, fullKey);\n }\n }\n\n return result;\n }\n\n // Auto-sync schema in development\n if (options.schema && process.env.NODE_ENV === \"development\" && options.apiKey) {\n flattenSchema(options.schema);\n const definitions = [...registry];\n const apiBase = VARD_API_HOST;\n\n fetch(`${apiBase}/api/content/variables/sync`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"X-Vard-API-Key\": options.apiKey,\n },\n body: JSON.stringify({\n definitions,\n schema: options.schema,\n }),\n }).catch((err) => console.warn(\"[vard] Auto-sync failed:\", err));\n }\n\n const client: VardClient<S> = {\n define<NS extends VardSchema>(schema: NS): InferSchema<NS> {\n return flattenSchema(schema) as InferSchema<NS>;\n },\n\n async get(): Promise<InferSchema<S>> {\n if (store.prefetch) {\n await store.prefetch();\n }\n if (store.getStructured) {\n const structured = store.getStructured();\n if (structured && Object.keys(structured).length > 0) {\n return structured as InferSchema<S>;\n }\n }\n return flattenSchema(options.schema ?? {}) as InferSchema<S>;\n },\n\n string(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"string\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n richtext(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"richtext\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n color(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"color\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n image(key, fallback, opts: VardVariableOptions = {}) {\n return register<string>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"image\",\n defaultValue: fallback,\n editableBy: opts.editableBy ?? \"member\",\n group: opts.group,\n });\n },\n\n boolean(key, fallback, opts: VardVariableOptions = {}) {\n return register<boolean>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"boolean\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n group: opts.group,\n });\n },\n\n list<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: VardVariableOptions = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n });\n },\n\n collection<LS extends VardListItemSchema>(\n key: string,\n schema: LS,\n fallback: InferListItem<LS>[],\n opts: Omit<VardVariableOptions, \"type\"> = {}\n ): InferListItem<LS>[] {\n return register<InferListItem<LS>[]>({\n key,\n label: opts.label ?? labelFromKey(key),\n description: opts.description,\n type: \"list\",\n defaultValue: fallback,\n editableBy: (opts.editableBy as VardRole) ?? \"member\",\n listItemSchema: schema,\n group: opts.group,\n isCollection: true,\n });\n },\n\n global: {\n string(key, fallback, opts = {}) {\n return client.string(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n richtext(key, fallback, opts = {}) {\n return client.richtext(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n color(key, fallback, opts = {}) {\n return client.color(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n image(key, fallback, opts = {}) {\n return client.image(key, fallback, { ...opts, group: \"Global\" } as VardVariableOptions);\n },\n boolean(key, fallback, opts = {}) {\n return client.boolean(key, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n list(key, schema, fallback, opts = {}) {\n return client.list(key, schema, fallback, { ...opts, group: \"Global\" } as Omit<\n VardVariableOptions,\n \"type\"\n >);\n },\n },\n\n extend<E extends VardSchema>(fragment: VardSchemaFragment<E>): VardClient<MergeSchema<S, E>> {\n // Merge the base schema with the fragment — the fragment keys win on collision\n const mergedSchema = { ...(options.schema ?? {}), ...fragment } as unknown as MergeSchema<\n S,\n E\n >;\n // Return a new client with the merged schema, sharing the same store & registry.\n // We pass the in-memory store directly so there is no second fetch.\n return createVard<MergeSchema<S, E>>({\n ...options,\n schema: mergedSchema,\n store,\n });\n },\n\n getDefinitions() {\n return [...registry];\n },\n store,\n };\n\n return client;\n}\n\n// ─────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────\n\nfunction labelFromKey(key: string): string {\n const lastSegment = key.split(\".\").pop() ?? key;\n return lastSegment\n .replace(/([A-Z])/g, \" $1\")\n .replace(/^./, (c) => c.toUpperCase())\n .trim();\n}\n","/**\n * @vard/sdk — Next.js adapter\n *\n * This module provides a VardStore implementation that reads variable values\n * from the Vard API at request time (App Router) or build time (static export).\n *\n * Usage in your Next.js site:\n *\n * // lib/vard.ts\n * import { createVardNextAdapter } from \"@vard/sdk/next\"\n * import { createVard } from \"@vard/sdk\"\n *\n * export const vard = createVard({\n * apiKey: process.env.VARD_API_KEY,\n * store: createVardNextAdapter(),\n * })\n */\n\nimport type { VardStore } from \"./types\";\n\nexport interface VardNextAdapterOptions {\n /**\n * Base URL of the Vard API. Defaults to https://vard.app\n */\n apiBase?: string;\n\n /**\n * API Key for authentication. Falls back to process.env.VARD_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Next.js fetch cache strategy. Defaults to \"force-cache\" (SSG-friendly).\n * Use \"no-store\" for fully dynamic pages.\n */\n cache?: RequestCache;\n\n /**\n * Next.js ISR revalidation interval in seconds.\n * Only applies when cache is \"force-cache\".\n */\n revalidate?: number;\n\n /**\n * Enable verbose logging (e.g. cache hits, misses, TTL triggers).\n * Defaults to false.\n */\n debug?: boolean;\n}\n\nimport { createVardFetchStore, VardFetchStoreOptions } from \"./fetch-store\";\n\n/**\n * Creates a VardStore that fetches live variable values from the Vard API.\n * Designed for use inside Next.js App Router (server components, server actions).\n */\nexport function createVardNextAdapter(\n options: VardNextAdapterOptions = {}\n): VardStore & { prefetch(): Promise<void> } {\n const { cache = \"force-cache\", revalidate, ...rest } = options;\n\n return createVardFetchStore({\n ...rest,\n // Sync the Next.js revalidation time (seconds) to the internal store TTL (seconds)\n ttl: revalidate !== undefined ? revalidate : 60,\n fetchOptions: {\n cache,\n ...(revalidate !== undefined && cache === \"force-cache\"\n ? ({ next: { revalidate, tags: [\"variables\"] } } as any)\n : {}),\n },\n });\n}\n\n/**\n * A convenience wrapper that creates a Vard client pre-loaded with live values.\n * Call this once in your Next.js layout before rendering any server component\n * that uses vard variables.\n *\n * @example\n * // app/layout.tsx\n * import { prefetchVardValues } from \"@vard/sdk/next\"\n * import { vard } from \"@/lib/vard\"\n *\n * export default async function RootLayout({ children }) {\n * await prefetchVardValues(vard)\n * return <html>...</html>\n * }\n */\nimport { createVard } from \"./client\";\nimport type { VardClient, VardOptions } from \"./types\";\n\nimport { VardSchema } from \"./schema\";\n\n/**\n * A convenience wrapper for createVard that automatically uses the Next.js adapter.\n *\n * @example\n * // lib/vard.ts\n * import { createVardNext } from \"@vard/sdk/next\"\n * export const vard = createVardNext({ revalidate: 60 })\n */\nexport function createVardNext<S extends VardSchema = any>(\n options: VardNextAdapterOptions & VardOptions<S> = {}\n): VardClient<S> {\n const adapter = createVardNextAdapter(options);\n return createVard<S>({\n ...options,\n store: adapter,\n });\n}\n\nexport async function prefetchVardValues(\n target: { prefetch(): Promise<void> } | VardClient\n): Promise<void> {\n const adapter = (target as any).prefetch ? target : (target as VardClient).store;\n if (adapter && typeof (adapter as any).prefetch === \"function\") {\n await (adapter as any).prefetch();\n }\n}\n"],"mappings":"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","names":[]}
|