@geekmidas/cli 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/{Route53Provider-xrWuBXih.cjs → Route53Provider-Bs7Arms9.cjs} +3 -2
  3. package/dist/Route53Provider-Bs7Arms9.cjs.map +1 -0
  4. package/dist/{Route53Provider-DOWmFnwN.mjs → Route53Provider-C8mS0zY6.mjs} +3 -2
  5. package/dist/Route53Provider-C8mS0zY6.mjs.map +1 -0
  6. package/dist/{config-C1bidhvG.mjs → config-DfCJ29PQ.mjs} +2 -2
  7. package/dist/{config-C1bidhvG.mjs.map → config-DfCJ29PQ.mjs.map} +1 -1
  8. package/dist/{config-C1dM7aZb.cjs → config-ZQM1vBoz.cjs} +2 -2
  9. package/dist/{config-C1dM7aZb.cjs.map → config-ZQM1vBoz.cjs.map} +1 -1
  10. package/dist/config.cjs +2 -2
  11. package/dist/config.d.cts +1 -1
  12. package/dist/config.d.mts +1 -1
  13. package/dist/config.mjs +2 -2
  14. package/dist/{index-DzmZ6SUW.d.cts → index-B58qjyBd.d.cts} +27 -1
  15. package/dist/index-B58qjyBd.d.cts.map +1 -0
  16. package/dist/{index-DvpWzLD7.d.mts → index-C0SpUT9Y.d.mts} +27 -1
  17. package/dist/index-C0SpUT9Y.d.mts.map +1 -0
  18. package/dist/index.cjs +117 -49
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.mjs +117 -49
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/{openapi-9k6a6VA4.mjs → openapi-BcSjLfWq.mjs} +2 -2
  23. package/dist/{openapi-9k6a6VA4.mjs.map → openapi-BcSjLfWq.mjs.map} +1 -1
  24. package/dist/{openapi-Dcja4e1C.cjs → openapi-D6Hcfov0.cjs} +2 -2
  25. package/dist/{openapi-Dcja4e1C.cjs.map → openapi-D6Hcfov0.cjs.map} +1 -1
  26. package/dist/openapi.cjs +3 -3
  27. package/dist/openapi.mjs +3 -3
  28. package/dist/workspace/index.cjs +1 -1
  29. package/dist/workspace/index.d.cts +1 -1
  30. package/dist/workspace/index.d.mts +1 -1
  31. package/dist/workspace/index.mjs +1 -1
  32. package/dist/{workspace-CeFgIDC-.cjs → workspace-2Do2YcGZ.cjs} +5 -1
  33. package/dist/{workspace-CeFgIDC-.cjs.map → workspace-2Do2YcGZ.cjs.map} +1 -1
  34. package/dist/{workspace-Cb_I7oCJ.mjs → workspace-BW2iU37P.mjs} +5 -1
  35. package/dist/{workspace-Cb_I7oCJ.mjs.map → workspace-BW2iU37P.mjs.map} +1 -1
  36. package/package.json +2 -2
  37. package/src/deploy/__tests__/Route53Provider.spec.ts +23 -0
  38. package/src/deploy/__tests__/env-resolver.spec.ts +384 -2
  39. package/src/deploy/__tests__/index.spec.ts +393 -5
  40. package/src/deploy/__tests__/sniffer.spec.ts +104 -93
  41. package/src/deploy/dns/Route53Provider.ts +4 -1
  42. package/src/deploy/env-resolver.ts +20 -0
  43. package/src/deploy/index.ts +83 -24
  44. package/src/deploy/sniffer.ts +39 -7
  45. package/src/init/generators/monorepo.ts +7 -1
  46. package/src/init/generators/web.ts +45 -2
  47. package/src/workspace/schema.ts +8 -0
  48. package/src/workspace/types.ts +23 -0
  49. package/dist/Route53Provider-DOWmFnwN.mjs.map +0 -1
  50. package/dist/Route53Provider-xrWuBXih.cjs.map +0 -1
  51. package/dist/index-DvpWzLD7.d.mts.map +0 -1
  52. package/dist/index-DzmZ6SUW.d.cts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @geekmidas/cli
2
2
 
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ✨ [`36166de`](https://github.com/geekmidas/toolbox/commit/36166defde0a66e68cb9ac5c6a6856ea23e2da62) Thanks [@geekmidas](https://github.com/geekmidas)! - Add sniffing and config for frontend apps. Also ensure next.js apps get args at build time.
8
+
9
+ ## 1.4.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 🐛 [`bebf821`](https://github.com/geekmidas/toolbox/commit/bebf821ce4534e314d3d536e9956260c4230a183) Thanks [@geekmidas](https://github.com/geekmidas)! - Fix dependecy output injecttion for urls
14
+
3
15
  ## 1.3.0
4
16
 
5
17
  ### Minor Changes
@@ -16,8 +16,9 @@ var Route53Provider = class {
16
16
  hostedZoneId;
17
17
  hostedZoneCache = /* @__PURE__ */ new Map();
18
18
  constructor(options = {}) {
19
+ const region = options.region ?? process.env.AWS_REGION ?? "us-east-1";
19
20
  this.client = new __aws_sdk_client_route_53.Route53Client({
20
- ...options.region && { region: options.region },
21
+ region,
21
22
  ...options.endpoint && { endpoint: options.endpoint },
22
23
  ...options.profile && { credentials: (0, __aws_sdk_credential_providers.fromIni)({ profile: options.profile }) }
23
24
  });
@@ -154,4 +155,4 @@ var Route53Provider = class {
154
155
 
155
156
  //#endregion
156
157
  exports.Route53Provider = Route53Provider;
157
- //# sourceMappingURL=Route53Provider-xrWuBXih.cjs.map
158
+ //# sourceMappingURL=Route53Provider-Bs7Arms9.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Route53Provider-Bs7Arms9.cjs","names":["options: Route53ProviderOptions","Route53Client","domain: string","ListHostedZonesByNameCommand","type: string","validTypes: DnsRecordType[]","recordName: string","records: DnsRecord[]","nextRecordName: string | undefined","nextRecordType: RRType | undefined","ListResourceRecordSetsCommand","records: UpsertDnsRecord[]","results: UpsertResult[]","ChangeResourceRecordSetsCommand"],"sources":["../src/deploy/dns/Route53Provider.ts"],"sourcesContent":["/**\n * Route53 DNS Provider\n *\n * Implements DnsProvider interface using AWS Route53.\n */\n\nimport {\n\tChangeResourceRecordSetsCommand,\n\tListHostedZonesByNameCommand,\n\tListResourceRecordSetsCommand,\n\tRoute53Client,\n\ttype RRType,\n} from '@aws-sdk/client-route-53';\nimport { fromIni } from '@aws-sdk/credential-providers';\nimport type {\n\tDnsProvider,\n\tDnsRecord,\n\tDnsRecordType,\n\tUpsertDnsRecord,\n\tUpsertResult,\n} from './DnsProvider';\n\nexport interface Route53ProviderOptions {\n\t/** AWS region (optional - uses AWS_REGION env var if not provided) */\n\tregion?: string;\n\t/** AWS profile name (optional - uses default credential chain if not provided) */\n\tprofile?: string;\n\t/** Hosted zone ID (optional - auto-detected from domain if not provided) */\n\thostedZoneId?: string;\n\t/** Custom endpoint for testing with localstack */\n\tendpoint?: string;\n}\n\n/**\n * Route53 DNS provider implementation.\n *\n * Uses AWS default credential chain for authentication.\n * Region can be specified or will use AWS_REGION/AWS_DEFAULT_REGION env vars.\n * Profile can be specified to use a named profile from ~/.aws/credentials.\n */\nexport class Route53Provider implements DnsProvider {\n\treadonly name = 'route53';\n\tprivate client: Route53Client;\n\tprivate hostedZoneId?: string;\n\tprivate hostedZoneCache: Map<string, string> = new Map();\n\n\tconstructor(options: Route53ProviderOptions = {}) {\n\t\t// Route53 is a global service, default to us-east-1 if no region specified\n\t\tconst region = options.region ?? process.env.AWS_REGION ?? 'us-east-1';\n\n\t\tthis.client = new Route53Client({\n\t\t\tregion,\n\t\t\t...(options.endpoint && { endpoint: options.endpoint }),\n\t\t\t...(options.profile && {\n\t\t\t\tcredentials: fromIni({ profile: options.profile }),\n\t\t\t}),\n\t\t});\n\t\tthis.hostedZoneId = options.hostedZoneId;\n\t}\n\n\t/**\n\t * Get the hosted zone ID for a domain.\n\t * Uses cache to avoid repeated API calls.\n\t */\n\tprivate async getHostedZoneId(domain: string): Promise<string> {\n\t\t// Use configured zone ID if provided\n\t\tif (this.hostedZoneId) {\n\t\t\treturn this.hostedZoneId;\n\t\t}\n\n\t\t// Check cache\n\t\tif (this.hostedZoneCache.has(domain)) {\n\t\t\treturn this.hostedZoneCache.get(domain)!;\n\t\t}\n\n\t\t// Auto-detect from domain\n\t\tconst command = new ListHostedZonesByNameCommand({\n\t\t\tDNSName: domain,\n\t\t\tMaxItems: 1,\n\t\t});\n\n\t\tconst response = await this.client.send(command);\n\t\tconst zones = response.HostedZones ?? [];\n\n\t\t// Find exact match (domain with trailing dot)\n\t\tconst normalizedDomain = domain.endsWith('.') ? domain : `${domain}.`;\n\t\tconst zone = zones.find((z) => z.Name === normalizedDomain);\n\n\t\tif (!zone?.Id) {\n\t\t\tthrow new Error(\n\t\t\t\t`No hosted zone found for domain: ${domain}. Create one in Route53 or provide hostedZoneId in config.`,\n\t\t\t);\n\t\t}\n\n\t\t// Zone ID comes as \"/hostedzone/Z1234567890\" - extract just the ID\n\t\tconst zoneId = zone.Id.replace('/hostedzone/', '');\n\t\tthis.hostedZoneCache.set(domain, zoneId);\n\t\treturn zoneId;\n\t}\n\n\t/**\n\t * Convert Route53 record type to our DnsRecordType.\n\t * Excludes NS and SOA which are auto-managed by Route53 for the zone.\n\t */\n\tprivate toRecordType(type: string): DnsRecordType | null {\n\t\t// Exclude NS and SOA which are auto-managed zone records\n\t\tconst managedTypes = ['NS', 'SOA'];\n\t\tif (managedTypes.includes(type)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst validTypes: DnsRecordType[] = [\n\t\t\t'A',\n\t\t\t'AAAA',\n\t\t\t'CNAME',\n\t\t\t'MX',\n\t\t\t'TXT',\n\t\t\t'SRV',\n\t\t\t'CAA',\n\t\t];\n\t\treturn validTypes.includes(type as DnsRecordType)\n\t\t\t? (type as DnsRecordType)\n\t\t\t: null;\n\t}\n\n\t/**\n\t * Extract subdomain from full record name relative to domain.\n\t */\n\tprivate extractSubdomain(recordName: string, domain: string): string {\n\t\tconst normalizedDomain = domain.endsWith('.') ? domain : `${domain}.`;\n\t\tconst normalizedName = recordName.endsWith('.')\n\t\t\t? recordName\n\t\t\t: `${recordName}.`;\n\n\t\tif (normalizedName === normalizedDomain) {\n\t\t\treturn '@';\n\t\t}\n\n\t\t// Remove the domain suffix\n\t\tconst subdomain = normalizedName.replace(`.${normalizedDomain}`, '');\n\t\treturn subdomain.replace(/\\.$/, ''); // Remove trailing dot if any\n\t}\n\n\tasync getRecords(domain: string): Promise<DnsRecord[]> {\n\t\tconst zoneId = await this.getHostedZoneId(domain);\n\t\tconst records: DnsRecord[] = [];\n\n\t\tlet nextRecordName: string | undefined;\n\t\tlet nextRecordType: RRType | undefined;\n\n\t\t// Paginate through all records\n\t\tdo {\n\t\t\tconst command = new ListResourceRecordSetsCommand({\n\t\t\t\tHostedZoneId: zoneId,\n\t\t\t\tStartRecordName: nextRecordName,\n\t\t\t\tStartRecordType: nextRecordType,\n\t\t\t\tMaxItems: 100,\n\t\t\t});\n\n\t\t\tconst response = await this.client.send(command);\n\n\t\t\tfor (const recordSet of response.ResourceRecordSets ?? []) {\n\t\t\t\tconst type = this.toRecordType(recordSet.Type ?? '');\n\t\t\t\tif (!type || !recordSet.Name) continue;\n\n\t\t\t\tconst values = (recordSet.ResourceRecords ?? [])\n\t\t\t\t\t.map((r) => r.Value)\n\t\t\t\t\t.filter((v): v is string => !!v);\n\n\t\t\t\trecords.push({\n\t\t\t\t\tname: this.extractSubdomain(recordSet.Name, domain),\n\t\t\t\t\ttype,\n\t\t\t\t\tttl: recordSet.TTL ?? 300,\n\t\t\t\t\tvalues,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (response.IsTruncated) {\n\t\t\t\tnextRecordName = response.NextRecordName;\n\t\t\t\tnextRecordType = response.NextRecordType;\n\t\t\t} else {\n\t\t\t\tnextRecordName = undefined;\n\t\t\t}\n\t\t} while (nextRecordName);\n\n\t\treturn records;\n\t}\n\n\tasync upsertRecords(\n\t\tdomain: string,\n\t\trecords: UpsertDnsRecord[],\n\t): Promise<UpsertResult[]> {\n\t\tconst zoneId = await this.getHostedZoneId(domain);\n\t\tconst results: UpsertResult[] = [];\n\n\t\t// Get existing records to determine if creating or updating\n\t\tconst existingRecords = await this.getRecords(domain);\n\n\t\t// Process records in batches (Route53 allows max 1000 changes per request)\n\t\tconst batchSize = 100;\n\t\tfor (let i = 0; i < records.length; i += batchSize) {\n\t\t\tconst batch = records.slice(i, i + batchSize);\n\t\t\tconst changes = [];\n\n\t\t\tfor (const record of batch) {\n\t\t\t\tconst existing = existingRecords.find(\n\t\t\t\t\t(r) => r.name === record.name && r.type === record.type,\n\t\t\t\t);\n\n\t\t\t\tconst existingValue = existing?.values?.[0];\n\n\t\t\t\tif (existing && existingValue === record.value) {\n\t\t\t\t\t// Record exists with same value - unchanged\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\trecord,\n\t\t\t\t\t\tcreated: false,\n\t\t\t\t\t\tunchanged: true,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Build full record name\n\t\t\t\tconst recordName =\n\t\t\t\t\trecord.name === '@' ? domain : `${record.name}.${domain}`;\n\n\t\t\t\tchanges.push({\n\t\t\t\t\tAction: 'UPSERT' as const,\n\t\t\t\t\tResourceRecordSet: {\n\t\t\t\t\t\tName: recordName,\n\t\t\t\t\t\tType: record.type,\n\t\t\t\t\t\tTTL: record.ttl,\n\t\t\t\t\t\tResourceRecords: [{ Value: record.value }],\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tresults.push({\n\t\t\t\t\trecord,\n\t\t\t\t\tcreated: !existing,\n\t\t\t\t\tunchanged: false,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Execute batch if there are changes\n\t\t\tif (changes.length > 0) {\n\t\t\t\tconst command = new ChangeResourceRecordSetsCommand({\n\t\t\t\t\tHostedZoneId: zoneId,\n\t\t\t\t\tChangeBatch: {\n\t\t\t\t\t\tComment: 'Upsert by gkm deploy',\n\t\t\t\t\t\tChanges: changes,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tawait this.client.send(command);\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n}\n"],"mappings":"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"}
@@ -15,8 +15,9 @@ var Route53Provider = class {
15
15
  hostedZoneId;
16
16
  hostedZoneCache = /* @__PURE__ */ new Map();
17
17
  constructor(options = {}) {
18
+ const region = options.region ?? process.env.AWS_REGION ?? "us-east-1";
18
19
  this.client = new Route53Client({
19
- ...options.region && { region: options.region },
20
+ region,
20
21
  ...options.endpoint && { endpoint: options.endpoint },
21
22
  ...options.profile && { credentials: fromIni({ profile: options.profile }) }
22
23
  });
@@ -153,4 +154,4 @@ var Route53Provider = class {
153
154
 
154
155
  //#endregion
155
156
  export { Route53Provider };
156
- //# sourceMappingURL=Route53Provider-DOWmFnwN.mjs.map
157
+ //# sourceMappingURL=Route53Provider-C8mS0zY6.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Route53Provider-C8mS0zY6.mjs","names":["options: Route53ProviderOptions","domain: string","type: string","validTypes: DnsRecordType[]","recordName: string","records: DnsRecord[]","nextRecordName: string | undefined","nextRecordType: RRType | undefined","records: UpsertDnsRecord[]","results: UpsertResult[]"],"sources":["../src/deploy/dns/Route53Provider.ts"],"sourcesContent":["/**\n * Route53 DNS Provider\n *\n * Implements DnsProvider interface using AWS Route53.\n */\n\nimport {\n\tChangeResourceRecordSetsCommand,\n\tListHostedZonesByNameCommand,\n\tListResourceRecordSetsCommand,\n\tRoute53Client,\n\ttype RRType,\n} from '@aws-sdk/client-route-53';\nimport { fromIni } from '@aws-sdk/credential-providers';\nimport type {\n\tDnsProvider,\n\tDnsRecord,\n\tDnsRecordType,\n\tUpsertDnsRecord,\n\tUpsertResult,\n} from './DnsProvider';\n\nexport interface Route53ProviderOptions {\n\t/** AWS region (optional - uses AWS_REGION env var if not provided) */\n\tregion?: string;\n\t/** AWS profile name (optional - uses default credential chain if not provided) */\n\tprofile?: string;\n\t/** Hosted zone ID (optional - auto-detected from domain if not provided) */\n\thostedZoneId?: string;\n\t/** Custom endpoint for testing with localstack */\n\tendpoint?: string;\n}\n\n/**\n * Route53 DNS provider implementation.\n *\n * Uses AWS default credential chain for authentication.\n * Region can be specified or will use AWS_REGION/AWS_DEFAULT_REGION env vars.\n * Profile can be specified to use a named profile from ~/.aws/credentials.\n */\nexport class Route53Provider implements DnsProvider {\n\treadonly name = 'route53';\n\tprivate client: Route53Client;\n\tprivate hostedZoneId?: string;\n\tprivate hostedZoneCache: Map<string, string> = new Map();\n\n\tconstructor(options: Route53ProviderOptions = {}) {\n\t\t// Route53 is a global service, default to us-east-1 if no region specified\n\t\tconst region = options.region ?? process.env.AWS_REGION ?? 'us-east-1';\n\n\t\tthis.client = new Route53Client({\n\t\t\tregion,\n\t\t\t...(options.endpoint && { endpoint: options.endpoint }),\n\t\t\t...(options.profile && {\n\t\t\t\tcredentials: fromIni({ profile: options.profile }),\n\t\t\t}),\n\t\t});\n\t\tthis.hostedZoneId = options.hostedZoneId;\n\t}\n\n\t/**\n\t * Get the hosted zone ID for a domain.\n\t * Uses cache to avoid repeated API calls.\n\t */\n\tprivate async getHostedZoneId(domain: string): Promise<string> {\n\t\t// Use configured zone ID if provided\n\t\tif (this.hostedZoneId) {\n\t\t\treturn this.hostedZoneId;\n\t\t}\n\n\t\t// Check cache\n\t\tif (this.hostedZoneCache.has(domain)) {\n\t\t\treturn this.hostedZoneCache.get(domain)!;\n\t\t}\n\n\t\t// Auto-detect from domain\n\t\tconst command = new ListHostedZonesByNameCommand({\n\t\t\tDNSName: domain,\n\t\t\tMaxItems: 1,\n\t\t});\n\n\t\tconst response = await this.client.send(command);\n\t\tconst zones = response.HostedZones ?? [];\n\n\t\t// Find exact match (domain with trailing dot)\n\t\tconst normalizedDomain = domain.endsWith('.') ? domain : `${domain}.`;\n\t\tconst zone = zones.find((z) => z.Name === normalizedDomain);\n\n\t\tif (!zone?.Id) {\n\t\t\tthrow new Error(\n\t\t\t\t`No hosted zone found for domain: ${domain}. Create one in Route53 or provide hostedZoneId in config.`,\n\t\t\t);\n\t\t}\n\n\t\t// Zone ID comes as \"/hostedzone/Z1234567890\" - extract just the ID\n\t\tconst zoneId = zone.Id.replace('/hostedzone/', '');\n\t\tthis.hostedZoneCache.set(domain, zoneId);\n\t\treturn zoneId;\n\t}\n\n\t/**\n\t * Convert Route53 record type to our DnsRecordType.\n\t * Excludes NS and SOA which are auto-managed by Route53 for the zone.\n\t */\n\tprivate toRecordType(type: string): DnsRecordType | null {\n\t\t// Exclude NS and SOA which are auto-managed zone records\n\t\tconst managedTypes = ['NS', 'SOA'];\n\t\tif (managedTypes.includes(type)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst validTypes: DnsRecordType[] = [\n\t\t\t'A',\n\t\t\t'AAAA',\n\t\t\t'CNAME',\n\t\t\t'MX',\n\t\t\t'TXT',\n\t\t\t'SRV',\n\t\t\t'CAA',\n\t\t];\n\t\treturn validTypes.includes(type as DnsRecordType)\n\t\t\t? (type as DnsRecordType)\n\t\t\t: null;\n\t}\n\n\t/**\n\t * Extract subdomain from full record name relative to domain.\n\t */\n\tprivate extractSubdomain(recordName: string, domain: string): string {\n\t\tconst normalizedDomain = domain.endsWith('.') ? domain : `${domain}.`;\n\t\tconst normalizedName = recordName.endsWith('.')\n\t\t\t? recordName\n\t\t\t: `${recordName}.`;\n\n\t\tif (normalizedName === normalizedDomain) {\n\t\t\treturn '@';\n\t\t}\n\n\t\t// Remove the domain suffix\n\t\tconst subdomain = normalizedName.replace(`.${normalizedDomain}`, '');\n\t\treturn subdomain.replace(/\\.$/, ''); // Remove trailing dot if any\n\t}\n\n\tasync getRecords(domain: string): Promise<DnsRecord[]> {\n\t\tconst zoneId = await this.getHostedZoneId(domain);\n\t\tconst records: DnsRecord[] = [];\n\n\t\tlet nextRecordName: string | undefined;\n\t\tlet nextRecordType: RRType | undefined;\n\n\t\t// Paginate through all records\n\t\tdo {\n\t\t\tconst command = new ListResourceRecordSetsCommand({\n\t\t\t\tHostedZoneId: zoneId,\n\t\t\t\tStartRecordName: nextRecordName,\n\t\t\t\tStartRecordType: nextRecordType,\n\t\t\t\tMaxItems: 100,\n\t\t\t});\n\n\t\t\tconst response = await this.client.send(command);\n\n\t\t\tfor (const recordSet of response.ResourceRecordSets ?? []) {\n\t\t\t\tconst type = this.toRecordType(recordSet.Type ?? '');\n\t\t\t\tif (!type || !recordSet.Name) continue;\n\n\t\t\t\tconst values = (recordSet.ResourceRecords ?? [])\n\t\t\t\t\t.map((r) => r.Value)\n\t\t\t\t\t.filter((v): v is string => !!v);\n\n\t\t\t\trecords.push({\n\t\t\t\t\tname: this.extractSubdomain(recordSet.Name, domain),\n\t\t\t\t\ttype,\n\t\t\t\t\tttl: recordSet.TTL ?? 300,\n\t\t\t\t\tvalues,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (response.IsTruncated) {\n\t\t\t\tnextRecordName = response.NextRecordName;\n\t\t\t\tnextRecordType = response.NextRecordType;\n\t\t\t} else {\n\t\t\t\tnextRecordName = undefined;\n\t\t\t}\n\t\t} while (nextRecordName);\n\n\t\treturn records;\n\t}\n\n\tasync upsertRecords(\n\t\tdomain: string,\n\t\trecords: UpsertDnsRecord[],\n\t): Promise<UpsertResult[]> {\n\t\tconst zoneId = await this.getHostedZoneId(domain);\n\t\tconst results: UpsertResult[] = [];\n\n\t\t// Get existing records to determine if creating or updating\n\t\tconst existingRecords = await this.getRecords(domain);\n\n\t\t// Process records in batches (Route53 allows max 1000 changes per request)\n\t\tconst batchSize = 100;\n\t\tfor (let i = 0; i < records.length; i += batchSize) {\n\t\t\tconst batch = records.slice(i, i + batchSize);\n\t\t\tconst changes = [];\n\n\t\t\tfor (const record of batch) {\n\t\t\t\tconst existing = existingRecords.find(\n\t\t\t\t\t(r) => r.name === record.name && r.type === record.type,\n\t\t\t\t);\n\n\t\t\t\tconst existingValue = existing?.values?.[0];\n\n\t\t\t\tif (existing && existingValue === record.value) {\n\t\t\t\t\t// Record exists with same value - unchanged\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\trecord,\n\t\t\t\t\t\tcreated: false,\n\t\t\t\t\t\tunchanged: true,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Build full record name\n\t\t\t\tconst recordName =\n\t\t\t\t\trecord.name === '@' ? domain : `${record.name}.${domain}`;\n\n\t\t\t\tchanges.push({\n\t\t\t\t\tAction: 'UPSERT' as const,\n\t\t\t\t\tResourceRecordSet: {\n\t\t\t\t\t\tName: recordName,\n\t\t\t\t\t\tType: record.type,\n\t\t\t\t\t\tTTL: record.ttl,\n\t\t\t\t\t\tResourceRecords: [{ Value: record.value }],\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tresults.push({\n\t\t\t\t\trecord,\n\t\t\t\t\tcreated: !existing,\n\t\t\t\t\tunchanged: false,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Execute batch if there are changes\n\t\t\tif (changes.length > 0) {\n\t\t\t\tconst command = new ChangeResourceRecordSetsCommand({\n\t\t\t\t\tHostedZoneId: zoneId,\n\t\t\t\t\tChangeBatch: {\n\t\t\t\t\t\tComment: 'Upsert by gkm deploy',\n\t\t\t\t\t\tChanges: changes,\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tawait this.client.send(command);\n\t\t\t}\n\t\t}\n\n\t\treturn results;\n\t}\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { getAppGkmConfig, isWorkspaceConfig, processConfig } from "./workspace-Cb_I7oCJ.mjs";
1
+ import { getAppGkmConfig, isWorkspaceConfig, processConfig } from "./workspace-BW2iU37P.mjs";
2
2
  import { existsSync, readFileSync } from "node:fs";
3
3
  import { dirname, join, parse } from "node:path";
4
4
 
@@ -186,4 +186,4 @@ async function loadAppConfig(cwd = process.cwd()) {
186
186
 
187
187
  //#endregion
188
188
  export { defineConfig, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig };
189
- //# sourceMappingURL=config-C1bidhvG.mjs.map
189
+ //# sourceMappingURL=config-DfCJ29PQ.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-C1bidhvG.mjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\nimport type { GkmConfig } from './types.js';\nimport {\n\tgetAppGkmConfig,\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\nexport interface ConfigDiscoveryResult {\n\tconfigPath: string;\n\tworkspaceRoot: string;\n}\n\n/**\n * Find and return the path to the config file.\n *\n * Resolution order:\n * 1. GKM_CONFIG_PATH env var (set by workspace dev command)\n * 2. Walk up directory tree from cwd\n */\nfunction findConfigPath(cwd: string): ConfigDiscoveryResult {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\t// Check GKM_CONFIG_PATH env var first (set by workspace dev command)\n\tconst envConfigPath = process.env.GKM_CONFIG_PATH;\n\tif (envConfigPath && existsSync(envConfigPath)) {\n\t\treturn {\n\t\t\tconfigPath: envConfigPath,\n\t\t\tworkspaceRoot: dirname(envConfigPath),\n\t\t};\n\t}\n\n\t// Walk up directory tree to find config\n\tlet currentDir = cwd;\n\tconst { root } = parse(currentDir);\n\n\twhile (currentDir !== root) {\n\t\tfor (const file of files) {\n\t\t\tconst configPath = join(currentDir, file);\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\treturn {\n\t\t\t\t\tconfigPath,\n\t\t\t\t\tworkspaceRoot: currentDir,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tcurrentDir = dirname(currentDir);\n\t}\n\n\tthrow new Error(\n\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t);\n}\n\n/**\n * Get app name from package.json in the given directory.\n * Handles scoped packages by extracting the name after the scope.\n *\n * @example\n * getAppNameFromCwd('/path/to/apps/api')\n * // package.json: { \"name\": \"@myorg/api\" }\n * // Returns: 'api'\n */\nexport function getAppNameFromCwd(cwd: string = process.cwd()): string | null {\n\tconst packageJsonPath = join(cwd, 'package.json');\n\n\tif (!existsSync(packageJsonPath)) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\t\tconst name = packageJson.name as string | undefined;\n\n\t\tif (!name) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Handle scoped packages: @scope/name -> name\n\t\tif (name.startsWith('@') && name.includes('/')) {\n\t\t\treturn name.split('/')[1] ?? null;\n\t\t}\n\n\t\treturn name;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\ninterface RawConfigResult {\n\tconfig: GkmConfig | WorkspaceConfig;\n\tworkspaceRoot: string;\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(cwd: string): Promise<RawConfigResult> {\n\tconst { configPath, workspaceRoot } = findConfigPath(cwd);\n\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn {\n\t\t\tconfig: config.default,\n\t\t\tworkspaceRoot,\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(`Failed to load config: ${(error as Error).message}`);\n\t}\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst { config } = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n): Promise<LoadedConfig> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\treturn processConfig(config, workspaceRoot);\n}\n\nexport interface AppConfigResult {\n\tappName: string;\n\tapp: NormalizedAppConfig;\n\tgkmConfig: GkmConfig;\n\tworkspace: NormalizedWorkspace;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}\n\n/**\n * Load app-specific configuration from workspace.\n * Uses the app name from package.json to find the correct app config.\n *\n * @example\n * ```ts\n * // From apps/api directory with package.json: { \"name\": \"@myorg/api\" }\n * const { app, workspace, workspaceRoot } = await loadAppConfig();\n * console.log(app.routes); // './src/endpoints/**\\/*.ts'\n * ```\n */\nexport async function loadAppConfig(\n\tcwd: string = process.cwd(),\n): Promise<AppConfigResult> {\n\tconst appName = getAppNameFromCwd(cwd);\n\n\tif (!appName) {\n\t\tthrow new Error(\n\t\t\t'Could not determine app name. Ensure package.json exists with a \"name\" field.',\n\t\t);\n\t}\n\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\tconst loadedConfig = processConfig(config, workspaceRoot);\n\n\t// Find the app in workspace (apps is a Record<string, NormalizedAppConfig>)\n\tconst app = loadedConfig.workspace.apps[appName];\n\n\tif (!app) {\n\t\tconst availableApps = Object.keys(loadedConfig.workspace.apps).join(', ');\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" not found in workspace config. Available apps: ${availableApps}. ` +\n\t\t\t\t`Ensure the package.json name matches the app key in gkm.config.ts.`,\n\t\t);\n\t}\n\n\t// Get the app's GKM config using the helper\n\tconst gkmConfig = getAppGkmConfig(loadedConfig.workspace, appName);\n\n\tif (!gkmConfig) {\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" is not a backend app and cannot be run with gkm dev.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tappName,\n\t\tapp,\n\t\tgkmConfig,\n\t\tworkspace: loadedConfig.workspace,\n\t\tworkspaceRoot,\n\t\tappRoot: join(workspaceRoot, app.path),\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config-DfCJ29PQ.mjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\nimport type { GkmConfig } from './types.js';\nimport {\n\tgetAppGkmConfig,\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\nexport interface ConfigDiscoveryResult {\n\tconfigPath: string;\n\tworkspaceRoot: string;\n}\n\n/**\n * Find and return the path to the config file.\n *\n * Resolution order:\n * 1. GKM_CONFIG_PATH env var (set by workspace dev command)\n * 2. Walk up directory tree from cwd\n */\nfunction findConfigPath(cwd: string): ConfigDiscoveryResult {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\t// Check GKM_CONFIG_PATH env var first (set by workspace dev command)\n\tconst envConfigPath = process.env.GKM_CONFIG_PATH;\n\tif (envConfigPath && existsSync(envConfigPath)) {\n\t\treturn {\n\t\t\tconfigPath: envConfigPath,\n\t\t\tworkspaceRoot: dirname(envConfigPath),\n\t\t};\n\t}\n\n\t// Walk up directory tree to find config\n\tlet currentDir = cwd;\n\tconst { root } = parse(currentDir);\n\n\twhile (currentDir !== root) {\n\t\tfor (const file of files) {\n\t\t\tconst configPath = join(currentDir, file);\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\treturn {\n\t\t\t\t\tconfigPath,\n\t\t\t\t\tworkspaceRoot: currentDir,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tcurrentDir = dirname(currentDir);\n\t}\n\n\tthrow new Error(\n\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t);\n}\n\n/**\n * Get app name from package.json in the given directory.\n * Handles scoped packages by extracting the name after the scope.\n *\n * @example\n * getAppNameFromCwd('/path/to/apps/api')\n * // package.json: { \"name\": \"@myorg/api\" }\n * // Returns: 'api'\n */\nexport function getAppNameFromCwd(cwd: string = process.cwd()): string | null {\n\tconst packageJsonPath = join(cwd, 'package.json');\n\n\tif (!existsSync(packageJsonPath)) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\t\tconst name = packageJson.name as string | undefined;\n\n\t\tif (!name) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Handle scoped packages: @scope/name -> name\n\t\tif (name.startsWith('@') && name.includes('/')) {\n\t\t\treturn name.split('/')[1] ?? null;\n\t\t}\n\n\t\treturn name;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\ninterface RawConfigResult {\n\tconfig: GkmConfig | WorkspaceConfig;\n\tworkspaceRoot: string;\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(cwd: string): Promise<RawConfigResult> {\n\tconst { configPath, workspaceRoot } = findConfigPath(cwd);\n\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn {\n\t\t\tconfig: config.default,\n\t\t\tworkspaceRoot,\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(`Failed to load config: ${(error as Error).message}`);\n\t}\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst { config } = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n): Promise<LoadedConfig> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\treturn processConfig(config, workspaceRoot);\n}\n\nexport interface AppConfigResult {\n\tappName: string;\n\tapp: NormalizedAppConfig;\n\tgkmConfig: GkmConfig;\n\tworkspace: NormalizedWorkspace;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}\n\n/**\n * Load app-specific configuration from workspace.\n * Uses the app name from package.json to find the correct app config.\n *\n * @example\n * ```ts\n * // From apps/api directory with package.json: { \"name\": \"@myorg/api\" }\n * const { app, workspace, workspaceRoot } = await loadAppConfig();\n * console.log(app.routes); // './src/endpoints/**\\/*.ts'\n * ```\n */\nexport async function loadAppConfig(\n\tcwd: string = process.cwd(),\n): Promise<AppConfigResult> {\n\tconst appName = getAppNameFromCwd(cwd);\n\n\tif (!appName) {\n\t\tthrow new Error(\n\t\t\t'Could not determine app name. Ensure package.json exists with a \"name\" field.',\n\t\t);\n\t}\n\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\tconst loadedConfig = processConfig(config, workspaceRoot);\n\n\t// Find the app in workspace (apps is a Record<string, NormalizedAppConfig>)\n\tconst app = loadedConfig.workspace.apps[appName];\n\n\tif (!app) {\n\t\tconst availableApps = Object.keys(loadedConfig.workspace.apps).join(', ');\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" not found in workspace config. Available apps: ${availableApps}. ` +\n\t\t\t\t`Ensure the package.json name matches the app key in gkm.config.ts.`,\n\t\t);\n\t}\n\n\t// Get the app's GKM config using the helper\n\tconst gkmConfig = getAppGkmConfig(loadedConfig.workspace, appName);\n\n\tif (!gkmConfig) {\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" is not a backend app and cannot be run with gkm dev.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tappName,\n\t\tapp,\n\t\tgkmConfig,\n\t\tworkspace: loadedConfig.workspace,\n\t\tworkspaceRoot,\n\t\tappRoot: join(workspaceRoot, app.path),\n\t};\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  const require_chunk = require('./chunk-CUT6urMc.cjs');
2
- const require_workspace = require('./workspace-CeFgIDC-.cjs');
2
+ const require_workspace = require('./workspace-2Do2YcGZ.cjs');
3
3
  const node_fs = require_chunk.__toESM(require("node:fs"));
4
4
  const node_path = require_chunk.__toESM(require("node:path"));
5
5
 
@@ -222,4 +222,4 @@ Object.defineProperty(exports, 'parseModuleConfig', {
222
222
  return parseModuleConfig;
223
223
  }
224
224
  });
225
- //# sourceMappingURL=config-C1dM7aZb.cjs.map
225
+ //# sourceMappingURL=config-ZQM1vBoz.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-C1dM7aZb.cjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\nimport type { GkmConfig } from './types.js';\nimport {\n\tgetAppGkmConfig,\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\nexport interface ConfigDiscoveryResult {\n\tconfigPath: string;\n\tworkspaceRoot: string;\n}\n\n/**\n * Find and return the path to the config file.\n *\n * Resolution order:\n * 1. GKM_CONFIG_PATH env var (set by workspace dev command)\n * 2. Walk up directory tree from cwd\n */\nfunction findConfigPath(cwd: string): ConfigDiscoveryResult {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\t// Check GKM_CONFIG_PATH env var first (set by workspace dev command)\n\tconst envConfigPath = process.env.GKM_CONFIG_PATH;\n\tif (envConfigPath && existsSync(envConfigPath)) {\n\t\treturn {\n\t\t\tconfigPath: envConfigPath,\n\t\t\tworkspaceRoot: dirname(envConfigPath),\n\t\t};\n\t}\n\n\t// Walk up directory tree to find config\n\tlet currentDir = cwd;\n\tconst { root } = parse(currentDir);\n\n\twhile (currentDir !== root) {\n\t\tfor (const file of files) {\n\t\t\tconst configPath = join(currentDir, file);\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\treturn {\n\t\t\t\t\tconfigPath,\n\t\t\t\t\tworkspaceRoot: currentDir,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tcurrentDir = dirname(currentDir);\n\t}\n\n\tthrow new Error(\n\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t);\n}\n\n/**\n * Get app name from package.json in the given directory.\n * Handles scoped packages by extracting the name after the scope.\n *\n * @example\n * getAppNameFromCwd('/path/to/apps/api')\n * // package.json: { \"name\": \"@myorg/api\" }\n * // Returns: 'api'\n */\nexport function getAppNameFromCwd(cwd: string = process.cwd()): string | null {\n\tconst packageJsonPath = join(cwd, 'package.json');\n\n\tif (!existsSync(packageJsonPath)) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\t\tconst name = packageJson.name as string | undefined;\n\n\t\tif (!name) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Handle scoped packages: @scope/name -> name\n\t\tif (name.startsWith('@') && name.includes('/')) {\n\t\t\treturn name.split('/')[1] ?? null;\n\t\t}\n\n\t\treturn name;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\ninterface RawConfigResult {\n\tconfig: GkmConfig | WorkspaceConfig;\n\tworkspaceRoot: string;\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(cwd: string): Promise<RawConfigResult> {\n\tconst { configPath, workspaceRoot } = findConfigPath(cwd);\n\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn {\n\t\t\tconfig: config.default,\n\t\t\tworkspaceRoot,\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(`Failed to load config: ${(error as Error).message}`);\n\t}\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst { config } = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n): Promise<LoadedConfig> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\treturn processConfig(config, workspaceRoot);\n}\n\nexport interface AppConfigResult {\n\tappName: string;\n\tapp: NormalizedAppConfig;\n\tgkmConfig: GkmConfig;\n\tworkspace: NormalizedWorkspace;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}\n\n/**\n * Load app-specific configuration from workspace.\n * Uses the app name from package.json to find the correct app config.\n *\n * @example\n * ```ts\n * // From apps/api directory with package.json: { \"name\": \"@myorg/api\" }\n * const { app, workspace, workspaceRoot } = await loadAppConfig();\n * console.log(app.routes); // './src/endpoints/**\\/*.ts'\n * ```\n */\nexport async function loadAppConfig(\n\tcwd: string = process.cwd(),\n): Promise<AppConfigResult> {\n\tconst appName = getAppNameFromCwd(cwd);\n\n\tif (!appName) {\n\t\tthrow new Error(\n\t\t\t'Could not determine app name. Ensure package.json exists with a \"name\" field.',\n\t\t);\n\t}\n\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\tconst loadedConfig = processConfig(config, workspaceRoot);\n\n\t// Find the app in workspace (apps is a Record<string, NormalizedAppConfig>)\n\tconst app = loadedConfig.workspace.apps[appName];\n\n\tif (!app) {\n\t\tconst availableApps = Object.keys(loadedConfig.workspace.apps).join(', ');\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" not found in workspace config. Available apps: ${availableApps}. ` +\n\t\t\t\t`Ensure the package.json name matches the app key in gkm.config.ts.`,\n\t\t);\n\t}\n\n\t// Get the app's GKM config using the helper\n\tconst gkmConfig = getAppGkmConfig(loadedConfig.workspace, appName);\n\n\tif (!gkmConfig) {\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" is not a backend app and cannot be run with gkm dev.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tappName,\n\t\tapp,\n\t\tgkmConfig,\n\t\tworkspace: loadedConfig.workspace,\n\t\tworkspaceRoot,\n\t\tappRoot: join(workspaceRoot, app.path),\n\t};\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config-ZQM1vBoz.cjs","names":["config: GkmConfig","configString: string","defaultAlias: string","cwd: string"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, parse } from 'node:path';\nimport type { GkmConfig } from './types.js';\nimport {\n\tgetAppGkmConfig,\n\tisWorkspaceConfig,\n\ttype LoadedConfig,\n\ttype NormalizedAppConfig,\n\ttype NormalizedWorkspace,\n\tprocessConfig,\n\ttype WorkspaceConfig,\n} from './workspace/index.js';\n\nexport type { GkmConfig } from './types.js';\nexport type { LoadedConfig, WorkspaceConfig } from './workspace/index.js';\nexport { defineWorkspace } from './workspace/index.js';\n/**\n * Define GKM configuration with full TypeScript support.\n * This is an identity function that provides type safety and autocomplete.\n *\n * @example\n * ```ts\n * // gkm.config.ts\n * import { defineConfig } from '@geekmidas/cli/config';\n *\n * export default defineConfig({\n * routes: './src/endpoints/**\\/*.ts',\n * envParser: './src/config/env',\n * logger: './src/config/logger',\n * telescope: true,\n * });\n * ```\n */\nexport function defineConfig(config: GkmConfig): GkmConfig {\n\treturn config;\n}\n\nexport interface ParsedModuleConfig {\n\tpath: string;\n\timportPattern: string;\n}\n\n/**\n * Parse a module config string into path and import pattern.\n *\n * @param configString - Config string in format \"./path/to/module\" or \"./path/to/module#exportName\"\n * @param defaultAlias - The default alias name to use if no export name specified\n * @returns Object with path and import pattern\n *\n * @example\n * parseModuleConfig('./src/config/env', 'envParser')\n * // { path: './src/config/env', importPattern: 'envParser' }\n *\n * parseModuleConfig('./src/config/env#envParser', 'envParser')\n * // { path: './src/config/env', importPattern: '{ envParser }' }\n *\n * parseModuleConfig('./src/config/env#myEnv', 'envParser')\n * // { path: './src/config/env', importPattern: '{ myEnv as envParser }' }\n */\nexport function parseModuleConfig(\n\tconfigString: string,\n\tdefaultAlias: string,\n): ParsedModuleConfig {\n\tconst parts = configString.split('#');\n\tconst path = parts[0] ?? configString;\n\tconst exportName = parts[1];\n\tconst importPattern = !exportName\n\t\t? defaultAlias\n\t\t: exportName === defaultAlias\n\t\t\t? `{ ${defaultAlias} }`\n\t\t\t: `{ ${exportName} as ${defaultAlias} }`;\n\n\treturn { path, importPattern };\n}\n\nexport interface ConfigDiscoveryResult {\n\tconfigPath: string;\n\tworkspaceRoot: string;\n}\n\n/**\n * Find and return the path to the config file.\n *\n * Resolution order:\n * 1. GKM_CONFIG_PATH env var (set by workspace dev command)\n * 2. Walk up directory tree from cwd\n */\nfunction findConfigPath(cwd: string): ConfigDiscoveryResult {\n\tconst files = ['gkm.config.json', 'gkm.config.ts', 'gkm.config.js'];\n\n\t// Check GKM_CONFIG_PATH env var first (set by workspace dev command)\n\tconst envConfigPath = process.env.GKM_CONFIG_PATH;\n\tif (envConfigPath && existsSync(envConfigPath)) {\n\t\treturn {\n\t\t\tconfigPath: envConfigPath,\n\t\t\tworkspaceRoot: dirname(envConfigPath),\n\t\t};\n\t}\n\n\t// Walk up directory tree to find config\n\tlet currentDir = cwd;\n\tconst { root } = parse(currentDir);\n\n\twhile (currentDir !== root) {\n\t\tfor (const file of files) {\n\t\t\tconst configPath = join(currentDir, file);\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\treturn {\n\t\t\t\t\tconfigPath,\n\t\t\t\t\tworkspaceRoot: currentDir,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tcurrentDir = dirname(currentDir);\n\t}\n\n\tthrow new Error(\n\t\t'Configuration file not found. Please create gkm.config.json, gkm.config.ts, or gkm.config.js in the project root.',\n\t);\n}\n\n/**\n * Get app name from package.json in the given directory.\n * Handles scoped packages by extracting the name after the scope.\n *\n * @example\n * getAppNameFromCwd('/path/to/apps/api')\n * // package.json: { \"name\": \"@myorg/api\" }\n * // Returns: 'api'\n */\nexport function getAppNameFromCwd(cwd: string = process.cwd()): string | null {\n\tconst packageJsonPath = join(cwd, 'package.json');\n\n\tif (!existsSync(packageJsonPath)) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\n\t\tconst name = packageJson.name as string | undefined;\n\n\t\tif (!name) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Handle scoped packages: @scope/name -> name\n\t\tif (name.startsWith('@') && name.includes('/')) {\n\t\t\treturn name.split('/')[1] ?? null;\n\t\t}\n\n\t\treturn name;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\ninterface RawConfigResult {\n\tconfig: GkmConfig | WorkspaceConfig;\n\tworkspaceRoot: string;\n}\n\n/**\n * Load raw configuration from file.\n */\nasync function loadRawConfig(cwd: string): Promise<RawConfigResult> {\n\tconst { configPath, workspaceRoot } = findConfigPath(cwd);\n\n\ttry {\n\t\tconst config = await import(configPath);\n\t\treturn {\n\t\t\tconfig: config.default,\n\t\t\tworkspaceRoot,\n\t\t};\n\t} catch (error) {\n\t\tthrow new Error(`Failed to load config: ${(error as Error).message}`);\n\t}\n}\n\n/**\n * Load configuration file (single-app format).\n * For backwards compatibility with existing code.\n *\n * @deprecated Use loadWorkspaceConfig for new code\n */\nexport async function loadConfig(\n\tcwd: string = process.cwd(),\n): Promise<GkmConfig> {\n\tconst { config } = await loadRawConfig(cwd);\n\n\t// If it's a workspace config, throw an error\n\tif (isWorkspaceConfig(config)) {\n\t\tthrow new Error(\n\t\t\t'Workspace configuration detected. Use loadWorkspaceConfig() instead.',\n\t\t);\n\t}\n\n\treturn config;\n}\n\n/**\n * Load configuration file and process it as a workspace.\n * Works with both single-app and workspace configurations.\n *\n * Single-app configs are automatically wrapped as a workspace with one app.\n *\n * @example\n * ```ts\n * const { type, workspace } = await loadWorkspaceConfig();\n *\n * if (type === 'workspace') {\n * console.log('Multi-app workspace:', workspace.apps);\n * } else {\n * console.log('Single app wrapped as workspace');\n * }\n * ```\n */\nexport async function loadWorkspaceConfig(\n\tcwd: string = process.cwd(),\n): Promise<LoadedConfig> {\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\treturn processConfig(config, workspaceRoot);\n}\n\nexport interface AppConfigResult {\n\tappName: string;\n\tapp: NormalizedAppConfig;\n\tgkmConfig: GkmConfig;\n\tworkspace: NormalizedWorkspace;\n\tworkspaceRoot: string;\n\tappRoot: string;\n}\n\n/**\n * Load app-specific configuration from workspace.\n * Uses the app name from package.json to find the correct app config.\n *\n * @example\n * ```ts\n * // From apps/api directory with package.json: { \"name\": \"@myorg/api\" }\n * const { app, workspace, workspaceRoot } = await loadAppConfig();\n * console.log(app.routes); // './src/endpoints/**\\/*.ts'\n * ```\n */\nexport async function loadAppConfig(\n\tcwd: string = process.cwd(),\n): Promise<AppConfigResult> {\n\tconst appName = getAppNameFromCwd(cwd);\n\n\tif (!appName) {\n\t\tthrow new Error(\n\t\t\t'Could not determine app name. Ensure package.json exists with a \"name\" field.',\n\t\t);\n\t}\n\n\tconst { config, workspaceRoot } = await loadRawConfig(cwd);\n\tconst loadedConfig = processConfig(config, workspaceRoot);\n\n\t// Find the app in workspace (apps is a Record<string, NormalizedAppConfig>)\n\tconst app = loadedConfig.workspace.apps[appName];\n\n\tif (!app) {\n\t\tconst availableApps = Object.keys(loadedConfig.workspace.apps).join(', ');\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" not found in workspace config. Available apps: ${availableApps}. ` +\n\t\t\t\t`Ensure the package.json name matches the app key in gkm.config.ts.`,\n\t\t);\n\t}\n\n\t// Get the app's GKM config using the helper\n\tconst gkmConfig = getAppGkmConfig(loadedConfig.workspace, appName);\n\n\tif (!gkmConfig) {\n\t\tthrow new Error(\n\t\t\t`App \"${appName}\" is not a backend app and cannot be run with gkm dev.`,\n\t\t);\n\t}\n\n\treturn {\n\t\tappName,\n\t\tapp,\n\t\tgkmConfig,\n\t\tworkspace: loadedConfig.workspace,\n\t\tworkspaceRoot,\n\t\tappRoot: join(workspaceRoot, app.path),\n\t};\n}\n"],"mappings":"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"}
package/dist/config.cjs CHANGED
@@ -1,5 +1,5 @@
1
- const require_workspace = require('./workspace-CeFgIDC-.cjs');
2
- const require_config = require('./config-C1dM7aZb.cjs');
1
+ const require_workspace = require('./workspace-2Do2YcGZ.cjs');
2
+ const require_config = require('./config-ZQM1vBoz.cjs');
3
3
 
4
4
  exports.defineConfig = require_config.defineConfig;
5
5
  exports.defineWorkspace = require_workspace.defineWorkspace;
package/dist/config.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { GkmConfig } from "./types-l53qUmGt.cjs";
2
- import { LoadedConfig, NormalizedAppConfig, NormalizedWorkspace, WorkspaceConfig, defineWorkspace } from "./index-DzmZ6SUW.cjs";
2
+ import { LoadedConfig, NormalizedAppConfig, NormalizedWorkspace, WorkspaceConfig, defineWorkspace } from "./index-B58qjyBd.cjs";
3
3
 
4
4
  //#region src/config.d.ts
5
5
 
package/dist/config.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { GkmConfig } from "./types-B9UZ7fOG.mjs";
2
- import { LoadedConfig, NormalizedAppConfig, NormalizedWorkspace, WorkspaceConfig, defineWorkspace } from "./index-DvpWzLD7.mjs";
2
+ import { LoadedConfig, NormalizedAppConfig, NormalizedWorkspace, WorkspaceConfig, defineWorkspace } from "./index-C0SpUT9Y.mjs";
3
3
 
4
4
  //#region src/config.d.ts
5
5
 
package/dist/config.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { defineWorkspace } from "./workspace-Cb_I7oCJ.mjs";
2
- import { defineConfig, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-C1bidhvG.mjs";
1
+ import { defineWorkspace } from "./workspace-BW2iU37P.mjs";
2
+ import { defineConfig, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig } from "./config-DfCJ29PQ.mjs";
3
3
 
4
4
  export { defineConfig, defineWorkspace, getAppNameFromCwd, loadAppConfig, loadConfig, loadWorkspaceConfig, parseModuleConfig };
@@ -316,6 +316,10 @@ declare const WorkspaceConfigSchema: z.ZodObject<{
316
316
  client: z.ZodOptional<z.ZodObject<{
317
317
  output: z.ZodOptional<z.ZodString>;
318
318
  }, z.core.$strip>>;
319
+ config: z.ZodOptional<z.ZodObject<{
320
+ client: z.ZodOptional<z.ZodString>;
321
+ server: z.ZodOptional<z.ZodString>;
322
+ }, z.core.$strip>>;
319
323
  provider: z.ZodOptional<z.ZodEnum<{
320
324
  "better-auth": "better-auth";
321
325
  }>>;
@@ -1095,6 +1099,28 @@ interface AppConfigBase {
1095
1099
  * Generates typed API client from backend dependencies.
1096
1100
  */
1097
1101
  client?: ClientConfig;
1102
+ /**
1103
+ * Config file paths for frontend environment sniffing.
1104
+ *
1105
+ * Points to file(s) that call EnvironmentParser.parse() at import time.
1106
+ * The sniffer imports these files and captures all env vars accessed.
1107
+ *
1108
+ * Dependencies are auto-generated as NEXT_PUBLIC_{DEP}_URL variables.
1109
+ *
1110
+ * @example
1111
+ * ```ts
1112
+ * config: {
1113
+ * client: './src/config/client.ts', // NEXT_PUBLIC_* vars for browser
1114
+ * server: './src/config/server.ts', // Server-only vars for SSR
1115
+ * }
1116
+ * ```
1117
+ */
1118
+ config?: {
1119
+ /** Client-side config (NEXT_PUBLIC_* vars, available in browser) */
1120
+ client?: string;
1121
+ /** Server-side config (all env vars, for SSR/API routes) */
1122
+ server?: string;
1123
+ };
1098
1124
  /**
1099
1125
  * Override domain for this app.
1100
1126
  *
@@ -1517,4 +1543,4 @@ declare function getEndpointForStage(dokployConfig: {
1517
1543
 
1518
1544
  //#endregion
1519
1545
  export { AppConfig, AppConfigInput, AppInput, AppsRecord, BackendFramework, ClientConfig, ConstrainedApps, DeployConfig, DeployTarget, DokployWorkspaceConfig, FrontendFramework, InferAppNames, InferredWorkspaceConfig, LoadedConfig, MailServiceConfig, ModelsConfig, NormalizedAppConfig, NormalizedWorkspace, PHASE_2_DEPLOY_TARGETS, SUPPORTED_DEPLOY_TARGETS, SecretsConfig, ServiceImageConfig, ServicesConfig, SharedConfig, WorkspaceConfig, WorkspaceConfigSchema, WorkspaceInput, defineWorkspace, formatValidationErrors, getAppBuildOrder, getAppGkmConfig, getDependencyEnvVars, getDeployTargetError, getEndpointForStage, isDeployTargetSupported, isPhase2DeployTarget, isWorkspaceConfig, normalizeWorkspace, processConfig, safeValidateWorkspaceConfig, validateWorkspaceConfig, wrapSingleAppAsWorkspace };
1520
- //# sourceMappingURL=index-DzmZ6SUW.d.cts.map
1546
+ //# sourceMappingURL=index-B58qjyBd.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-B58qjyBd.d.cts","names":[],"sources":["../src/deploy/state.ts","../src/deploy/StateProvider.ts","../src/workspace/schema.ts","../src/workspace/types.ts","../src/workspace/index.ts"],"sourcesContent":[],"mappings":"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"}
@@ -316,6 +316,10 @@ declare const WorkspaceConfigSchema: z.ZodObject<{
316
316
  client: z.ZodOptional<z.ZodObject<{
317
317
  output: z.ZodOptional<z.ZodString>;
318
318
  }, z.core.$strip>>;
319
+ config: z.ZodOptional<z.ZodObject<{
320
+ client: z.ZodOptional<z.ZodString>;
321
+ server: z.ZodOptional<z.ZodString>;
322
+ }, z.core.$strip>>;
319
323
  provider: z.ZodOptional<z.ZodEnum<{
320
324
  "better-auth": "better-auth";
321
325
  }>>;
@@ -1095,6 +1099,28 @@ interface AppConfigBase {
1095
1099
  * Generates typed API client from backend dependencies.
1096
1100
  */
1097
1101
  client?: ClientConfig;
1102
+ /**
1103
+ * Config file paths for frontend environment sniffing.
1104
+ *
1105
+ * Points to file(s) that call EnvironmentParser.parse() at import time.
1106
+ * The sniffer imports these files and captures all env vars accessed.
1107
+ *
1108
+ * Dependencies are auto-generated as NEXT_PUBLIC_{DEP}_URL variables.
1109
+ *
1110
+ * @example
1111
+ * ```ts
1112
+ * config: {
1113
+ * client: './src/config/client.ts', // NEXT_PUBLIC_* vars for browser
1114
+ * server: './src/config/server.ts', // Server-only vars for SSR
1115
+ * }
1116
+ * ```
1117
+ */
1118
+ config?: {
1119
+ /** Client-side config (NEXT_PUBLIC_* vars, available in browser) */
1120
+ client?: string;
1121
+ /** Server-side config (all env vars, for SSR/API routes) */
1122
+ server?: string;
1123
+ };
1098
1124
  /**
1099
1125
  * Override domain for this app.
1100
1126
  *
@@ -1517,4 +1543,4 @@ declare function getEndpointForStage(dokployConfig: {
1517
1543
 
1518
1544
  //#endregion
1519
1545
  export { AppConfig, AppConfigInput, AppInput, AppsRecord, BackendFramework, ClientConfig, ConstrainedApps, DeployConfig, DeployTarget, DokployWorkspaceConfig, FrontendFramework, InferAppNames, InferredWorkspaceConfig, LoadedConfig, MailServiceConfig, ModelsConfig, NormalizedAppConfig, NormalizedWorkspace, PHASE_2_DEPLOY_TARGETS, SUPPORTED_DEPLOY_TARGETS, SecretsConfig, ServiceImageConfig, ServicesConfig, SharedConfig, WorkspaceConfig, WorkspaceConfigSchema, WorkspaceInput, defineWorkspace, formatValidationErrors, getAppBuildOrder, getAppGkmConfig, getDependencyEnvVars, getDeployTargetError, getEndpointForStage, isDeployTargetSupported, isPhase2DeployTarget, isWorkspaceConfig, normalizeWorkspace, processConfig, safeValidateWorkspaceConfig, validateWorkspaceConfig, wrapSingleAppAsWorkspace };
1520
- //# sourceMappingURL=index-DvpWzLD7.d.mts.map
1546
+ //# sourceMappingURL=index-C0SpUT9Y.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-C0SpUT9Y.d.mts","names":[],"sources":["../src/deploy/state.ts","../src/deploy/StateProvider.ts","../src/workspace/schema.ts","../src/workspace/types.ts","../src/workspace/index.ts"],"sourcesContent":[],"mappings":"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"}