@eventuras/app-config 0.1.4

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 ADDED
@@ -0,0 +1,423 @@
1
+ # @eventuras/app-config
2
+
3
+ Declarative environment configuration for Eventuras applications.
4
+
5
+ ## Overview
6
+
7
+ `@eventuras/app-config` provides a centralized, type-safe way to manage environment variables across all Eventuras applications. Instead of manually validating env vars in code, you declare them in an `app.config.json` file.
8
+
9
+
10
+ ## Development
11
+
12
+ ```bash
13
+ # Build the library
14
+ pnpm build
15
+
16
+ # Type check
17
+ pnpm typecheck
18
+
19
+ # Lint
20
+ pnpm lint
21
+ ```
22
+
23
+ ## TypeScript Type Generation
24
+
25
+ The library includes a tool to generate TypeScript type definitions from your `app.config.json` file. This ensures your client-side environment variables are properly typed.
26
+
27
+ ### Using the generator programmatically
28
+
29
+ Create a script in your app's `scripts/` directory:
30
+
31
+ ```typescript
32
+ #!/usr/bin/env tsx
33
+ import path from 'path';
34
+ import { fileURLToPath } from 'url';
35
+ import { generateTypes } from '@eventuras/app-config/generator';
36
+
37
+ const __filename = fileURLToPath(import.meta.url);
38
+ const __dirname = path.dirname(__filename);
39
+
40
+ generateTypes({
41
+ configPath: path.join(__dirname, '..', 'app.config.json'),
42
+ outputPath: path.join(__dirname, '..', 'src', 'config.client.generated.d.ts'),
43
+ interfaceName: 'WebPublicEnv', // Optional, defaults to 'PublicEnv'
44
+ }).catch((error: unknown) => {
45
+ console.error('❌ Failed to generate types:', error);
46
+ process.exit(1);
47
+ });
48
+ ```
49
+
50
+ Add a script to your `package.json`:
51
+
52
+ ```json
53
+ {
54
+ "scripts": {
55
+ "generate:config-types": "tsx scripts/generate-config-types.ts"
56
+ }
57
+ }
58
+ ```
59
+
60
+ ### Generated output
61
+
62
+ For example, given this config:
63
+
64
+ ```json
65
+ {
66
+ "env": {
67
+ "NEXT_PUBLIC_API_BASE_URL": {
68
+ "required": true,
69
+ "client": true,
70
+ "type": "url",
71
+ "description": "API base URL"
72
+ },
73
+ "NEXT_PUBLIC_ORGANIZATION_ID": {
74
+ "required": false,
75
+ "client": true,
76
+ "type": "int",
77
+ "description": "Organization ID"
78
+ }
79
+ }
80
+ }
81
+ ```
82
+
83
+ The generated `config.client.generated.d.ts` will be:
84
+
85
+ ```typescript
86
+ /**
87
+ * AUTO-GENERATED FILE - DO NOT EDIT
88
+ * Generated from app.config.json
89
+ *
90
+ * To regenerate, run: pnpm generate:config-types
91
+ */
92
+
93
+ export interface WebPublicEnv {
94
+ NEXT_PUBLIC_API_BASE_URL: string;
95
+ NEXT_PUBLIC_ORGANIZATION_ID?: number;
96
+ }
97
+ ```
98
+
99
+ You can then use this interface to type your client-side environment:
100
+
101
+ ```typescript
102
+ import type { WebPublicEnv } from './config.client.generated';
103
+
104
+ declare global {
105
+ namespace NodeJS {
106
+ interface ProcessEnv extends WebPublicEnv {}
107
+ }
108
+ }
109
+ ```
110
+
111
+
112
+ ## Installation
113
+
114
+ ```bash
115
+ pnpm add @eventuras/app-config
116
+ ```
117
+
118
+ ## Usage
119
+
120
+ ### 1. Create `app.config.json`
121
+
122
+ Create an `app.config.json` file in your app's root directory:
123
+
124
+ ```json
125
+ {
126
+ "$schema": "https://eventuras.dev/schema/app-config.schema.json",
127
+ "name": "@eventuras/web",
128
+ "type": "app",
129
+ "description": "Main web frontend for Eventuras",
130
+ "env": {
131
+ "NEXT_PUBLIC_API_BASE_URL": {
132
+ "required": true,
133
+ "client": true,
134
+ "type": "url",
135
+ "description": "Base URL for the Eventuras API"
136
+ },
137
+ "NEXT_PUBLIC_ORGANIZATION_ID": {
138
+ "required": false,
139
+ "client": true,
140
+ "type": "string",
141
+ "description": "Organization ID for scoping configuration",
142
+ "default": "1"
143
+ },
144
+ "AUTH0_CLIENT_SECRET": {
145
+ "required": true,
146
+ "client": false,
147
+ "type": "string",
148
+ "description": "Auth0 client secret (server-side only)"
149
+ },
150
+ "PORT": {
151
+ "required": false,
152
+ "client": false,
153
+ "type": "int",
154
+ "description": "Port to run the server on",
155
+ "default": 3000
156
+ }
157
+ }
158
+ }
159
+ ```
160
+
161
+ ### 2. Load and validate configuration
162
+
163
+ #### Server-Side Usage (Recommended)
164
+
165
+ ```typescript
166
+ import { createConfig } from '@eventuras/app-config';
167
+
168
+ const config = createConfig('./app.config.json');
169
+
170
+ // Method 1: Direct property access (cleanest for server-side)
171
+ const clientId = config.env.AUTH0_CLIENT_ID;
172
+ const clientSecret = config.env.AUTH0_CLIENT_SECRET;
173
+ const sessionSecret = config.env.SESSION_SECRET;
174
+
175
+ // Method 2: Using get() with type parameter
176
+ const apiUrl = config.get<string>('NEXT_PUBLIC_API_BASE_URL');
177
+ const orgId = config.get<string>('NEXT_PUBLIC_ORGANIZATION_ID');
178
+ ```
179
+
180
+ #### Next.js Usage (Client + Server)
181
+
182
+ For Next.js apps, use the `createEnvironment()` helper for automatic compatibility:
183
+
184
+ ```typescript
185
+ // config.ts
186
+ import { createConfig, createEnvironment } from '@eventuras/app-config';
187
+ import { resolve } from 'path';
188
+
189
+ // Server-side configuration
190
+ export const appConfig = createConfig(
191
+ resolve(process.cwd(), 'app.config.json')
192
+ );
193
+
194
+ // Client-side public environment variables
195
+ export const publicEnv = createEnvironment(
196
+ resolve(process.cwd(), 'app.config.json')
197
+ );
198
+ ```
199
+
200
+ ```typescript
201
+ // In client components - use publicEnv
202
+ 'use client';
203
+
204
+ export default function MyComponent() {
205
+ const apiUrl = publicEnv.NEXT_PUBLIC_API_BASE_URL; // ✅ Works in client
206
+ const domain = publicEnv.NEXT_PUBLIC_AUTH0_DOMAIN; // ✅ Works in client
207
+
208
+ return <div>API: {apiUrl}</div>;
209
+ }
210
+ ```
211
+
212
+ ```typescript
213
+ // In server components / API routes - use appConfig.env
214
+ export async function getServerSideProps() {
215
+ // Recommended: Use appConfig.env for server-side variables
216
+ const clientSecret = appConfig.env.AUTH0_CLIENT_SECRET;
217
+ const sessionSecret = appConfig.env.SESSION_SECRET;
218
+
219
+ // Alternative: Use publicEnv.get() (also works server-side)
220
+ const altSecret = publicEnv.get('AUTH0_CLIENT_SECRET');
221
+
222
+ return { props: {} };
223
+ }
224
+ ```
225
+
226
+ **Why explicit getters for NEXT_PUBLIC_*?**
227
+ Next.js performs build-time replacement of `process.env.NEXT_PUBLIC_*`. The `createEnvironment()` helper automatically generates getters that access `process.env` directly, ensuring client-side compatibility while still validating all variables server-side.
228
+
229
+ ### 3. Validation happens automatically
230
+
231
+ When you create a config, all environment variables are validated:
232
+
233
+ ```typescript
234
+ // This will throw if any required env vars are missing or invalid
235
+ const config = createConfig('./app.config.json');
236
+ ```
237
+
238
+ You can also validate explicitly during app initialization:
239
+
240
+ ```typescript
241
+ import { validate } from '@eventuras/app-config';
242
+
243
+ // In your app initialization (e.g., layout.tsx or main.ts)
244
+ validate('./app.config.json');
245
+ console.log('✓ Environment validated successfully');
246
+ ```
247
+
248
+ Error messages are helpful:
249
+
250
+ ```
251
+ Environment validation failed:
252
+
253
+ ❌ Required environment variable "NEXT_PUBLIC_API_BASE_URL" is not set.
254
+ Description: Base URL for the Eventuras API
255
+
256
+ ❌ Environment variable "PORT" must be a valid integer.
257
+ Got: "not-a-number"
258
+ ```
259
+
260
+ ## Environment Variable Types
261
+
262
+ | Type | Description | Example |
263
+ |------|-------------|---------|
264
+ | `string` | Any string value | `"hello"` |
265
+ | `url` | Valid URL | `"https://api.example.com"` |
266
+ | `int` | Integer number | `3000` |
267
+ | `bool` | Boolean (true/false, 1/0) | `true`, `"1"` |
268
+ | `json` | Valid JSON | `{"key": "value"}` |
269
+
270
+ ## Configuration Schema
271
+
272
+ ### `app.config.json` Structure
273
+
274
+ ```typescript
275
+ interface AppConfig {
276
+ $schema?: string; // JSON Schema reference
277
+ name: string; // Package name (e.g., "@eventuras/web")
278
+ type: 'app'; // Always "app"
279
+ description?: string; // Human-readable description
280
+ env: { // Environment variable definitions
281
+ [varName: string]: {
282
+ required: boolean; // Is this var required?
283
+ client: boolean; // Exposed to client? (NEXT_PUBLIC_*)
284
+ type: EnvVarType; // 'string' | 'url' | 'int' | 'bool' | 'json'
285
+ description: string; // What is this var for?
286
+ default?: any; // Default value
287
+ pattern?: string; // Regex pattern
288
+ enum?: string[]; // Allowed values
289
+ }
290
+ };
291
+ build?: { // Build configuration (optional)
292
+ outDir?: string;
293
+ target?: string;
294
+ };
295
+ runtime?: { // Runtime configuration (optional)
296
+ port?: number;
297
+ };
298
+ }
299
+ ```
300
+
301
+ ### Environment Variable Definition
302
+
303
+ ```typescript
304
+ interface EnvVarDefinition {
305
+ required: boolean; // Throw error if missing?
306
+ client: boolean; // Client-side accessible?
307
+ type: EnvVarType; // Expected type
308
+ description: string; // Documentation
309
+ default?: any; // Fallback value
310
+ pattern?: string; // Validation regex
311
+ enum?: string[]; // Allowed values
312
+ }
313
+ ```
314
+
315
+ ## Migration from `Environment.ts`
316
+
317
+ ### Before (apps/web/src/utils/Environment.ts)
318
+
319
+ ```typescript
320
+ export enum EnvironmentVariables {
321
+ NEXT_PUBLIC_API_BASE_URL = 'NEXT_PUBLIC_API_BASE_URL',
322
+ AUTH0_CLIENT_SECRET = 'AUTH0_CLIENT_SECRET',
323
+ }
324
+
325
+ class Environment {
326
+ static validate() { /* ... */ }
327
+
328
+ static get NEXT_PUBLIC_API_BASE_URL() {
329
+ return process.env.NEXT_PUBLIC_API_BASE_URL!;
330
+ }
331
+
332
+ static get(identifier: string): string {
333
+ return process.env[identifier]!;
334
+ }
335
+ }
336
+ ```
337
+
338
+ ### After (apps/web/app.config.json + config.ts)
339
+
340
+ **app.config.json:**
341
+ ```json
342
+ {
343
+ "name": "@eventuras/web",
344
+ "type": "app",
345
+ "env": {
346
+ "NEXT_PUBLIC_API_BASE_URL": {
347
+ "required": true,
348
+ "client": true,
349
+ "type": "url",
350
+ "description": "API base URL"
351
+ },
352
+ "AUTH0_CLIENT_SECRET": {
353
+ "required": true,
354
+ "client": false,
355
+ "type": "string",
356
+ "description": "Auth0 secret"
357
+ }
358
+ }
359
+ }
360
+ ```
361
+
362
+ **src/config.ts:**
363
+ ```typescript
364
+ import { createConfig } from '@eventuras/app-config';
365
+
366
+ export const config = createConfig('./app.config.json');
367
+
368
+ // Usage:
369
+ const apiUrl = config.get<string>('NEXT_PUBLIC_API_BASE_URL');
370
+ const secret = config.get<string>('AUTH0_CLIENT_SECRET');
371
+ ```
372
+
373
+ ## Next.js Integration
374
+
375
+ For Next.js apps, you can validate the config in your root layout:
376
+
377
+ ```typescript
378
+ // app/layout.tsx
379
+ import { validate } from '@eventuras/app-config';
380
+
381
+ // Validate on server startup
382
+ validate('./app.config.json');
383
+
384
+ export default function RootLayout({ children }) {
385
+ return <html><body>{children}</body></html>;
386
+ }
387
+ ```
388
+
389
+ Or use the config instance directly:
390
+
391
+ ```typescript
392
+ // app/layout.tsx
393
+ import { createConfig } from '@eventuras/app-config';
394
+
395
+ // Validate on startup
396
+ const config = createConfig('./app.config.json');
397
+
398
+ export default function RootLayout({ children }) {
399
+ return <html><body>{children}</body></html>;
400
+ }
401
+ ```
402
+
403
+ Access client-side variables (NEXT_PUBLIC_*):
404
+ ```typescript
405
+ // Client component
406
+ 'use client';
407
+
408
+ import { config } from '@/config';
409
+
410
+ export function MyComponent() {
411
+ // ⚠️ IMPORTANT: For Next.js, NEXT_PUBLIC_* vars MUST access process.env directly
412
+ // Next.js replaces process.env.NEXT_PUBLIC_* at build time
413
+ const apiUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
414
+
415
+ // Or use the Environment wrapper which does this for you:
416
+ import { Environment } from '@/config';
417
+ const apiUrl = Environment.NEXT_PUBLIC_API_BASE_URL;
418
+
419
+ return <div>API: {apiUrl}</div>;
420
+ }
421
+ ```
422
+
423
+ **Why the limitation?** Next.js performs build-time replacement of `process.env.NEXT_PUBLIC_*` variables. The `appConfig.get()` method reads from a runtime object, so it won't work for client-side code. Server-side code can use either approach.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI tool to generate TypeScript types from app.config.json
4
+ * Usage: node cli.js <configPath> <outputPath> [interfaceName]
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;GAGG"}
package/dist/cli.js ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ import { generateTypes } from "./generator.js";
3
+ //#region src/cli.ts
4
+ /**
5
+ * CLI tool to generate TypeScript types from app.config.json
6
+ * Usage: node cli.js <configPath> <outputPath> [interfaceName]
7
+ */
8
+ async function main() {
9
+ const [, , configPath, outputPath, interfaceName] = process.argv;
10
+ if (!configPath || !outputPath) {
11
+ console.error("Usage: generate-config-types <configPath> <outputPath> [interfaceName]");
12
+ console.error("Example: generate-config-types ./app.config.json ./src/config.generated.d.ts PublicEnv");
13
+ process.exit(1);
14
+ }
15
+ try {
16
+ await generateTypes({
17
+ configPath,
18
+ outputPath,
19
+ interfaceName
20
+ });
21
+ } catch (error) {
22
+ console.error("❌ Failed to generate types:", error);
23
+ process.exit(1);
24
+ }
25
+ }
26
+ main();
27
+ //#endregion
28
+
29
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * CLI tool to generate TypeScript types from app.config.json\n * Usage: node cli.js <configPath> <outputPath> [interfaceName]\n */\n\nimport { generateTypes } from './generator.js';\n\nasync function main() {\n const [, , configPath, outputPath, interfaceName] = process.argv;\n\n if (!configPath || !outputPath) {\n console.error('Usage: generate-config-types <configPath> <outputPath> [interfaceName]');\n console.error('Example: generate-config-types ./app.config.json ./src/config.generated.d.ts PublicEnv');\n process.exit(1);\n }\n\n try {\n await generateTypes({\n configPath,\n outputPath,\n interfaceName,\n });\n } catch (error) {\n console.error('❌ Failed to generate types:', error);\n process.exit(1);\n }\n}\n\nmain();\n"],"mappings":";;;;;;;AAQA,eAAe,OAAO;CACpB,MAAM,KAAK,YAAY,YAAY,iBAAiB,QAAQ;CAE5D,IAAI,CAAC,cAAc,CAAC,YAAY;EAC9B,QAAQ,MAAM,wEAAwE;EACtF,QAAQ,MAAM,wFAAwF;EACtG,QAAQ,KAAK,CAAC;CAChB;CAEA,IAAI;EACF,MAAM,cAAc;GAClB;GACA;GACA;EACF,CAAC;CACH,SAAS,OAAO;EACd,QAAQ,MAAM,+BAA+B,KAAK;EAClD,QAAQ,KAAK,CAAC;CAChB;AACF;AAEA,KAAK"}
@@ -0,0 +1,97 @@
1
+ import { AppConfig } from './types.js';
2
+ export type { AppConfig } from './types.js';
3
+ /**
4
+ * Map environment variable type string to TypeScript type
5
+ */
6
+ type EnvVarTypeMap = {
7
+ string: string;
8
+ url: string;
9
+ int: number;
10
+ bool: boolean;
11
+ json: unknown;
12
+ };
13
+ /**
14
+ * Infer the TypeScript type from an environment variable definition with literal type support
15
+ */
16
+ type InferEnvVarType<T> = T extends {
17
+ type: infer Type;
18
+ required: infer Req;
19
+ } ? Type extends keyof EnvVarTypeMap ? Req extends true ? EnvVarTypeMap[Type] : EnvVarTypeMap[Type] | undefined : unknown : unknown;
20
+ /**
21
+ * Extract public environment variable types from AppConfig
22
+ */
23
+ export type PublicEnvObject<T> = T extends {
24
+ env: infer Env;
25
+ } ? {
26
+ [K in keyof Env as Env[K] extends {
27
+ client: true;
28
+ } ? K : never]: InferEnvVarType<Env[K]>;
29
+ } : never;
30
+ /**
31
+ * Helper to parse integer value
32
+ */
33
+ export declare function parseIntValue(value: string | undefined): number | undefined;
34
+ /**
35
+ * Helper to parse boolean value
36
+ */
37
+ export declare function parseBoolValue(value: string | undefined): boolean | undefined;
38
+ /**
39
+ * Helper to parse JSON value
40
+ */
41
+ export declare function parseJsonValue(value: string | undefined): unknown;
42
+ /**
43
+ * Helper to define a getter property on an object.
44
+ *
45
+ * This is useful for creating explicit getters that Next.js can statically analyze.
46
+ * Instead of dynamic property access like process.env[varName], you should use
47
+ * direct property access like process.env.NEXT_PUBLIC_MY_VAR in the getter function.
48
+ *
49
+ * @param target - The target object to add the getter to
50
+ * @param propName - The property name
51
+ * @param getter - The getter function that returns the value
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const env = {};
56
+ * defineGetter(env, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);
57
+ * defineGetter(env, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));
58
+ * ```
59
+ */
60
+ export declare function defineGetter<T>(target: Record<string, unknown>, propName: string, getter: () => T): void;
61
+ /**
62
+ * Create an empty object for public environment variables.
63
+ *
64
+ * Use this with defineGetter to create explicit getters for NEXT_PUBLIC_* variables.
65
+ * This approach allows Next.js to perform static analysis and replace environment
66
+ * variables at build time.
67
+ *
68
+ * @returns An empty object to add getters to
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const publicEnv = createPublicEnvGetters();
73
+ * defineGetter(publicEnv, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);
74
+ * defineGetter(publicEnv, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));
75
+ * ```
76
+ */
77
+ export declare function createPublicEnvGetters(): Record<string, unknown>;
78
+ /**
79
+ * Create a public environment object with the correct TypeScript type.
80
+ *
81
+ * This is a type-safe wrapper that returns an empty object you can add getters to.
82
+ * Use this with defineGetter to create explicit NEXT_PUBLIC_* getters.
83
+ *
84
+ * @param _config - Plain app configuration object (used only for type inference)
85
+ * @returns An empty object with the correct TypeScript type for your config
86
+ *
87
+ * @example
88
+ * ```ts
89
+ * import appConfig from '../app.config.json';
90
+ *
91
+ * export const publicEnv = createPublicEnv(appConfig as AppConfig);
92
+ * defineGetter(publicEnv, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);
93
+ * defineGetter(publicEnv, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));
94
+ * ```
95
+ */
96
+ export declare function createPublicEnv<const T extends AppConfig>(_config: T): PublicEnvObject<T>;
97
+ //# sourceMappingURL=clientside.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientside.d.ts","sourceRoot":"","sources":["../src/clientside.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;GAEG;AACH,KAAK,aAAa,GAAG;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF;;GAEG;AACH,KAAK,eAAe,CAAC,CAAC,IACpB,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,CAAA;CAAE,GAC/C,IAAI,SAAS,MAAM,aAAa,GAC9B,GAAG,SAAS,IAAI,GACd,aAAa,CAAC,IAAI,CAAC,GACnB,aAAa,CAAC,IAAI,CAAC,GAAG,SAAS,GACjC,OAAO,GACT,OAAO,CAAC;AAEd;;GAEG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAAC,SAAS;IAAE,GAAG,EAAE,MAAM,GAAG,CAAA;CAAE,GACzD;KACG,CAAC,IAAI,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,SAAS;QAAE,MAAM,EAAE,IAAI,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACzF,GACD,KAAK,CAAC;AAEV;;GAEG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAG7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAOjE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,GACd,IAAI,CAKN;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEhE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,eAAe,CAAC,KAAK,CAAC,CAAC,SAAS,SAAS,EAAE,OAAO,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAEzF"}
@@ -0,0 +1,94 @@
1
+ //#region src/clientside.ts
2
+ /**
3
+ * Helper to parse integer value
4
+ */
5
+ function parseIntValue(value) {
6
+ if (value === void 0) return void 0;
7
+ return Number.parseInt(value, 10);
8
+ }
9
+ /**
10
+ * Helper to parse boolean value
11
+ */
12
+ function parseBoolValue(value) {
13
+ if (value === void 0) return void 0;
14
+ return value === "true" || value === "1";
15
+ }
16
+ /**
17
+ * Helper to parse JSON value
18
+ */
19
+ function parseJsonValue(value) {
20
+ if (value === void 0) return void 0;
21
+ try {
22
+ return JSON.parse(value);
23
+ } catch {
24
+ return value;
25
+ }
26
+ }
27
+ /**
28
+ * Helper to define a getter property on an object.
29
+ *
30
+ * This is useful for creating explicit getters that Next.js can statically analyze.
31
+ * Instead of dynamic property access like process.env[varName], you should use
32
+ * direct property access like process.env.NEXT_PUBLIC_MY_VAR in the getter function.
33
+ *
34
+ * @param target - The target object to add the getter to
35
+ * @param propName - The property name
36
+ * @param getter - The getter function that returns the value
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * const env = {};
41
+ * defineGetter(env, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);
42
+ * defineGetter(env, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));
43
+ * ```
44
+ */
45
+ function defineGetter(target, propName, getter) {
46
+ Object.defineProperty(target, propName, {
47
+ get: getter,
48
+ enumerable: true
49
+ });
50
+ }
51
+ /**
52
+ * Create an empty object for public environment variables.
53
+ *
54
+ * Use this with defineGetter to create explicit getters for NEXT_PUBLIC_* variables.
55
+ * This approach allows Next.js to perform static analysis and replace environment
56
+ * variables at build time.
57
+ *
58
+ * @returns An empty object to add getters to
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * const publicEnv = createPublicEnvGetters();
63
+ * defineGetter(publicEnv, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);
64
+ * defineGetter(publicEnv, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));
65
+ * ```
66
+ */
67
+ function createPublicEnvGetters() {
68
+ return {};
69
+ }
70
+ /**
71
+ * Create a public environment object with the correct TypeScript type.
72
+ *
73
+ * This is a type-safe wrapper that returns an empty object you can add getters to.
74
+ * Use this with defineGetter to create explicit NEXT_PUBLIC_* getters.
75
+ *
76
+ * @param _config - Plain app configuration object (used only for type inference)
77
+ * @returns An empty object with the correct TypeScript type for your config
78
+ *
79
+ * @example
80
+ * ```ts
81
+ * import appConfig from '../app.config.json';
82
+ *
83
+ * export const publicEnv = createPublicEnv(appConfig as AppConfig);
84
+ * defineGetter(publicEnv, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);
85
+ * defineGetter(publicEnv, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));
86
+ * ```
87
+ */
88
+ function createPublicEnv(_config) {
89
+ return createPublicEnvGetters();
90
+ }
91
+ //#endregion
92
+ export { createPublicEnv, createPublicEnvGetters, defineGetter, parseBoolValue, parseIntValue, parseJsonValue };
93
+
94
+ //# sourceMappingURL=clientside.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clientside.js","names":[],"sources":["../src/clientside.ts"],"sourcesContent":["import { AppConfig } from './types.js';\n\n// Re-export types for client usage\nexport type { AppConfig } from './types.js';\n\n/**\n * Map environment variable type string to TypeScript type\n */\ntype EnvVarTypeMap = {\n string: string;\n url: string;\n int: number;\n bool: boolean;\n json: unknown;\n};\n\n/**\n * Infer the TypeScript type from an environment variable definition with literal type support\n */\ntype InferEnvVarType<T> =\n T extends { type: infer Type; required: infer Req }\n ? Type extends keyof EnvVarTypeMap\n ? Req extends true\n ? EnvVarTypeMap[Type]\n : EnvVarTypeMap[Type] | undefined\n : unknown\n : unknown;\n\n/**\n * Extract public environment variable types from AppConfig\n */\nexport type PublicEnvObject<T> = T extends { env: infer Env }\n ? {\n [K in keyof Env as Env[K] extends { client: true } ? K : never]: InferEnvVarType<Env[K]>;\n }\n : never;\n\n/**\n * Helper to parse integer value\n */\nexport function parseIntValue(value: string | undefined): number | undefined {\n if (value === undefined) return undefined;\n return Number.parseInt(value, 10);\n}\n\n/**\n * Helper to parse boolean value\n */\nexport function parseBoolValue(value: string | undefined): boolean | undefined {\n if (value === undefined) return undefined;\n return value === 'true' || value === '1';\n}\n\n/**\n * Helper to parse JSON value\n */\nexport function parseJsonValue(value: string | undefined): unknown {\n if (value === undefined) return undefined;\n try {\n return JSON.parse(value);\n } catch {\n return value;\n }\n}\n\n/**\n * Helper to define a getter property on an object.\n *\n * This is useful for creating explicit getters that Next.js can statically analyze.\n * Instead of dynamic property access like process.env[varName], you should use\n * direct property access like process.env.NEXT_PUBLIC_MY_VAR in the getter function.\n *\n * @param target - The target object to add the getter to\n * @param propName - The property name\n * @param getter - The getter function that returns the value\n *\n * @example\n * ```ts\n * const env = {};\n * defineGetter(env, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);\n * defineGetter(env, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));\n * ```\n */\nexport function defineGetter<T>(\n target: Record<string, unknown>,\n propName: string,\n getter: () => T\n): void {\n Object.defineProperty(target, propName, {\n get: getter,\n enumerable: true,\n });\n}\n\n/**\n * Create an empty object for public environment variables.\n *\n * Use this with defineGetter to create explicit getters for NEXT_PUBLIC_* variables.\n * This approach allows Next.js to perform static analysis and replace environment\n * variables at build time.\n *\n * @returns An empty object to add getters to\n *\n * @example\n * ```ts\n * const publicEnv = createPublicEnvGetters();\n * defineGetter(publicEnv, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);\n * defineGetter(publicEnv, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));\n * ```\n */\nexport function createPublicEnvGetters(): Record<string, unknown> {\n return {};\n}\n\n/**\n * Create a public environment object with the correct TypeScript type.\n *\n * This is a type-safe wrapper that returns an empty object you can add getters to.\n * Use this with defineGetter to create explicit NEXT_PUBLIC_* getters.\n *\n * @param _config - Plain app configuration object (used only for type inference)\n * @returns An empty object with the correct TypeScript type for your config\n *\n * @example\n * ```ts\n * import appConfig from '../app.config.json';\n *\n * export const publicEnv = createPublicEnv(appConfig as AppConfig);\n * defineGetter(publicEnv, 'NEXT_PUBLIC_API_URL', () => process.env.NEXT_PUBLIC_API_URL);\n * defineGetter(publicEnv, 'NEXT_PUBLIC_ORG_ID', () => parseIntValue(process.env.NEXT_PUBLIC_ORG_ID));\n * ```\n */\nexport function createPublicEnv<const T extends AppConfig>(_config: T): PublicEnvObject<T> {\n return createPublicEnvGetters() as PublicEnvObject<T>;\n}\n"],"mappings":";;;;AAwCA,SAAgB,cAAc,OAA+C;CAC3E,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;CAChC,OAAO,OAAO,SAAS,OAAO,EAAE;AAClC;;;;AAKA,SAAgB,eAAe,OAAgD;CAC7E,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;CAChC,OAAO,UAAU,UAAU,UAAU;AACvC;;;;AAKA,SAAgB,eAAe,OAAoC;CACjE,IAAI,UAAU,KAAA,GAAW,OAAO,KAAA;CAChC,IAAI;EACF,OAAO,KAAK,MAAM,KAAK;CACzB,QAAQ;EACN,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,aACd,QACA,UACA,QACM;CACN,OAAO,eAAe,QAAQ,UAAU;EACtC,KAAK;EACL,YAAY;CACd,CAAC;AACH;;;;;;;;;;;;;;;;;AAkBA,SAAgB,yBAAkD;CAChE,OAAO,CAAC;AACV;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,gBAA2C,SAAgC;CACzF,OAAO,uBAAuB;AAChC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Generate TypeScript types from app.config.json
3
+ * This module provides functions to generate type definitions from configuration files
4
+ */
5
+ export interface GenerateTypesOptions {
6
+ /** Path to app.config.json file */
7
+ configPath: string;
8
+ /** Path where the generated .d.ts file should be written */
9
+ outputPath: string;
10
+ /** Name of the interface to generate (default: 'PublicEnv') */
11
+ interfaceName?: string;
12
+ }
13
+ /**
14
+ * Generate TypeScript type definitions from an app.config.json file
15
+ * @param options - Configuration options for type generation
16
+ */
17
+ export declare function generateTypes(options: GenerateTypesOptions): Promise<void>;
18
+ //# sourceMappingURL=generator.d.ts.map