@jaypie/constructs 1.2.0-rc.0 → 1.2.0-rc.10

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.
@@ -316,6 +316,23 @@ function addDatadogLayers(lambdaFunction, options = {}) {
316
316
  return true;
317
317
  }
318
318
 
319
+ /**
320
+ * Conditional logging for CDK constructs.
321
+ * Only logs when CDK_ENV_LOG=true is set.
322
+ */
323
+ /* eslint-disable no-console */
324
+ function cdkLog(message, data) {
325
+ if (process.env.CDK_ENV_LOG === "true") {
326
+ if (data !== undefined) {
327
+ console.log(`[CDK] ${message}`, JSON.stringify(data, null, 2));
328
+ }
329
+ else {
330
+ console.log(`[CDK] ${message}`);
331
+ }
332
+ }
333
+ }
334
+ /* eslint-enable no-console */
335
+
319
336
  function constructEnvName(name, opts) {
320
337
  const env = opts?.env ?? process.env.PROJECT_ENV ?? "build";
321
338
  const key = opts?.key ?? process.env.PROJECT_KEY ?? "project";
@@ -385,6 +402,15 @@ function constructTagger(construct, { name } = {}) {
385
402
  }
386
403
 
387
404
  function envHostname({ component, domain, env, subdomain, } = {}) {
405
+ cdkLog("envHostname called", {
406
+ params: { component, domain, env, subdomain },
407
+ envVars: {
408
+ CDK_ENV_DOMAIN: process.env.CDK_ENV_DOMAIN,
409
+ CDK_ENV_HOSTED_ZONE: process.env.CDK_ENV_HOSTED_ZONE,
410
+ CDK_ENV_SUBDOMAIN: process.env.CDK_ENV_SUBDOMAIN,
411
+ PROJECT_ENV: process.env.PROJECT_ENV,
412
+ },
413
+ });
388
414
  const resolvedDomain = domain || process.env.CDK_ENV_DOMAIN || process.env.CDK_ENV_HOSTED_ZONE;
389
415
  if (!resolvedDomain) {
390
416
  throw new errors.ConfigurationError("No hostname `domain` provided. Set CDK_ENV_DOMAIN or CDK_ENV_HOSTED_ZONE to use environment domain");
@@ -399,7 +425,9 @@ function envHostname({ component, domain, env, subdomain, } = {}) {
399
425
  filteredEnv,
400
426
  resolvedDomain,
401
427
  ].filter((part) => part);
402
- return parts.join(".");
428
+ const hostname = parts.join(".");
429
+ cdkLog("envHostname resolved", { hostname });
430
+ return hostname;
403
431
  }
404
432
 
405
433
  /**
@@ -687,15 +715,84 @@ function resolveDatadogLoggingDestination(scope, options) {
687
715
  return datadogLoggingDestination;
688
716
  }
689
717
 
718
+ /**
719
+ * Resolves environment input to a plain object.
720
+ *
721
+ * When environment is an object (legacy syntax), returns it as-is.
722
+ * When environment is an array:
723
+ * - Strings are treated as keys to lookup in process.env
724
+ * - Objects have their key-value pairs merged in
725
+ *
726
+ * @example
727
+ * // Legacy object syntax
728
+ * resolveEnvironment({ FOO: "bar" })
729
+ * // => { FOO: "bar" }
730
+ *
731
+ * @example
732
+ * // Array syntax with process.env lookup
733
+ * // Given process.env.MY_VAR = "hello"
734
+ * resolveEnvironment(["MY_VAR"])
735
+ * // => { MY_VAR: "hello" }
736
+ *
737
+ * @example
738
+ * // Array syntax with objects
739
+ * resolveEnvironment([{ FOO: "bar", BAZ: "qux" }])
740
+ * // => { FOO: "bar", BAZ: "qux" }
741
+ *
742
+ * @example
743
+ * // Mixed array syntax
744
+ * // Given process.env.MY_VAR = "hello"
745
+ * resolveEnvironment(["MY_VAR", { FOO: "bar" }])
746
+ * // => { MY_VAR: "hello", FOO: "bar" }
747
+ */
748
+ function resolveEnvironment(environment, env = process.env) {
749
+ if (!environment) {
750
+ return {};
751
+ }
752
+ // Legacy object syntax - return as-is
753
+ if (!Array.isArray(environment)) {
754
+ return environment;
755
+ }
756
+ // Array syntax - process each item
757
+ return environment.reduce((acc, item) => {
758
+ if (typeof item === "string") {
759
+ // String: lookup in process.env
760
+ const value = env[item];
761
+ if (value !== undefined) {
762
+ return {
763
+ ...acc,
764
+ [item]: value,
765
+ };
766
+ }
767
+ // Skip if not found in process.env
768
+ return acc;
769
+ }
770
+ // Object: merge key-value pairs
771
+ return {
772
+ ...acc,
773
+ ...item,
774
+ };
775
+ }, {});
776
+ }
777
+
690
778
  function resolveHostedZone(scope, { name = "HostedZone", zone = process.env.CDK_ENV_HOSTED_ZONE, } = {}) {
779
+ cdkLog("resolveHostedZone called", {
780
+ name,
781
+ zone: typeof zone === "string" ? zone : "(IHostedZone object)",
782
+ CDK_ENV_HOSTED_ZONE: process.env.CDK_ENV_HOSTED_ZONE,
783
+ });
691
784
  if (!zone) {
692
785
  throw new errors.ConfigurationError("No `zone` provided. Set CDK_ENV_HOSTED_ZONE to use environment zone");
693
786
  }
694
787
  if (typeof zone === "string") {
788
+ cdkLog("resolveHostedZone: looking up zone by domain name", {
789
+ domainName: zone,
790
+ });
695
791
  return route53__namespace.HostedZone.fromLookup(scope, name, {
696
792
  domainName: zone,
697
793
  });
698
794
  }
795
+ cdkLog("resolveHostedZone: using provided IHostedZone object");
699
796
  return zone;
700
797
  }
701
798
 
@@ -719,6 +816,246 @@ const resolveParamsAndSecrets = ({ paramsAndSecrets, options, } = {}) => {
719
816
  return resolvedParamsAndSecrets;
720
817
  };
721
818
 
819
+ // It is a consumer if the environment is ephemeral
820
+ function checkEnvIsConsumer(env = process.env) {
821
+ return (env.PROJECT_ENV === CDK$2.ENV.PERSONAL ||
822
+ !!env.CDK_ENV_PERSONAL ||
823
+ /** @deprecated */ env.PROJECT_ENV === "ephemeral" ||
824
+ /** @deprecated */ !!env.CDK_ENV_EPHEMERAL);
825
+ }
826
+ function checkEnvIsProvider(env = process.env) {
827
+ return env.PROJECT_ENV === CDK$2.ENV.SANDBOX;
828
+ }
829
+ function cleanName(name) {
830
+ return name.replace(/[^a-zA-Z0-9:-]/g, "");
831
+ }
832
+ function exportEnvName(name, env = process.env) {
833
+ let rawName;
834
+ if (checkEnvIsProvider(env)) {
835
+ rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
836
+ // Clean the entire name to only allow alphanumeric, colons, and hyphens
837
+ return cleanName(rawName);
838
+ }
839
+ else {
840
+ if (checkEnvIsConsumer(env)) {
841
+ rawName = `env-${CDK$2.ENV.SANDBOX}-${env.PROJECT_KEY}-${name}`;
842
+ }
843
+ else {
844
+ rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
845
+ }
846
+ }
847
+ return cleanName(rawName);
848
+ }
849
+ class JaypieEnvSecret extends constructs.Construct {
850
+ constructor(scope, idOrEnvKey, props) {
851
+ // Check if idOrEnvKey should be treated as envKey:
852
+ // - No props provided OR props.envKey is not set
853
+ // - AND idOrEnvKey exists as a non-empty string in process.env
854
+ const treatAsEnvKey = (!props || props.envKey === undefined) &&
855
+ typeof process.env[idOrEnvKey] === "string" &&
856
+ process.env[idOrEnvKey] !== "";
857
+ const id = treatAsEnvKey ? `EnvSecret_${idOrEnvKey}` : idOrEnvKey;
858
+ super(scope, id);
859
+ const { consumer = checkEnvIsConsumer(), envKey: envKeyProp, export: exportParam, generateSecretString, provider = checkEnvIsProvider(), roleTag, vendorTag, value, } = props || {};
860
+ const envKey = treatAsEnvKey ? idOrEnvKey : envKeyProp;
861
+ this._envKey = envKey;
862
+ let exportName;
863
+ if (!exportParam) {
864
+ exportName = exportEnvName(id);
865
+ }
866
+ else {
867
+ exportName = cleanName(exportParam);
868
+ }
869
+ if (consumer) {
870
+ const secretName = cdk.Fn.importValue(exportName);
871
+ this._secret = secretsmanager__namespace.Secret.fromSecretNameV2(this, id, secretName);
872
+ // Add CfnOutput for consumer secrets
873
+ new cdk.CfnOutput(this, `ConsumedName`, {
874
+ value: this._secret.secretName,
875
+ });
876
+ }
877
+ else {
878
+ const secretValue = envKey && process.env[envKey] ? process.env[envKey] : value;
879
+ const secretProps = {
880
+ generateSecretString,
881
+ secretStringValue: !generateSecretString && secretValue
882
+ ? cdk.SecretValue.unsafePlainText(secretValue)
883
+ : undefined,
884
+ };
885
+ this._secret = new secretsmanager__namespace.Secret(this, id, secretProps);
886
+ if (roleTag) {
887
+ cdk.Tags.of(this._secret).add(CDK$2.TAG.ROLE, roleTag);
888
+ }
889
+ if (vendorTag) {
890
+ cdk.Tags.of(this._secret).add(CDK$2.TAG.VENDOR, vendorTag);
891
+ }
892
+ if (provider) {
893
+ new cdk.CfnOutput(this, `ProvidedName`, {
894
+ value: this._secret.secretName,
895
+ exportName,
896
+ });
897
+ }
898
+ else {
899
+ new cdk.CfnOutput(this, `CreatedName`, {
900
+ value: this._secret.secretName,
901
+ });
902
+ }
903
+ }
904
+ }
905
+ // IResource implementation
906
+ get stack() {
907
+ return cdk.Stack.of(this);
908
+ }
909
+ get env() {
910
+ return {
911
+ account: cdk.Stack.of(this).account,
912
+ region: cdk.Stack.of(this).region,
913
+ };
914
+ }
915
+ applyRemovalPolicy(policy) {
916
+ this._secret.applyRemovalPolicy(policy);
917
+ }
918
+ // ISecret implementation
919
+ get secretArn() {
920
+ return this._secret.secretArn;
921
+ }
922
+ get secretName() {
923
+ return this._secret.secretName;
924
+ }
925
+ get secretFullArn() {
926
+ return this._secret.secretFullArn;
927
+ }
928
+ get encryptionKey() {
929
+ return this._secret.encryptionKey;
930
+ }
931
+ get secretValue() {
932
+ return this._secret.secretValue;
933
+ }
934
+ secretValueFromJson(key) {
935
+ return this._secret.secretValueFromJson(key);
936
+ }
937
+ grantRead(grantee, versionStages) {
938
+ return this._secret.grantRead(grantee, versionStages);
939
+ }
940
+ grantWrite(grantee) {
941
+ return this._secret.grantWrite(grantee);
942
+ }
943
+ addRotationSchedule(id, options) {
944
+ return this._secret.addRotationSchedule(id, options);
945
+ }
946
+ addToResourcePolicy(statement) {
947
+ return this._secret.addToResourcePolicy(statement);
948
+ }
949
+ denyAccountRootDelete() {
950
+ this._secret.denyAccountRootDelete();
951
+ }
952
+ attach(target) {
953
+ return this._secret.attach(target);
954
+ }
955
+ cfnDynamicReferenceKey(options) {
956
+ return this._secret.cfnDynamicReferenceKey(options);
957
+ }
958
+ get envKey() {
959
+ return this._envKey;
960
+ }
961
+ }
962
+
963
+ /**
964
+ * Cache for secrets by scope to avoid creating duplicates.
965
+ * Uses WeakMap to allow garbage collection when scopes are no longer referenced.
966
+ */
967
+ const secretsByScope = new WeakMap();
968
+ /**
969
+ * Gets or creates the secrets cache for a given scope.
970
+ */
971
+ function getSecretsCache(scope) {
972
+ let cache = secretsByScope.get(scope);
973
+ if (!cache) {
974
+ cache = new Map();
975
+ secretsByScope.set(scope, cache);
976
+ }
977
+ return cache;
978
+ }
979
+ /**
980
+ * Gets an existing secret from the cache or creates a new one.
981
+ * This ensures that multiple constructs within the same scope share secrets.
982
+ */
983
+ function getOrCreateSecret(scope, envKey, props) {
984
+ const cache = getSecretsCache(scope);
985
+ const existingSecret = cache.get(envKey);
986
+ if (existingSecret) {
987
+ return existingSecret;
988
+ }
989
+ // Create new secret - JaypieEnvSecret's smart constructor handles envKey detection
990
+ const secret = new JaypieEnvSecret(scope, envKey, {
991
+ ...props,
992
+ envKey,
993
+ });
994
+ cache.set(envKey, secret);
995
+ return secret;
996
+ }
997
+ /**
998
+ * Resolves secrets input to an array of JaypieEnvSecret instances.
999
+ *
1000
+ * When an item is already a JaypieEnvSecret, it's passed through as-is.
1001
+ * When an item is a string, a JaypieEnvSecret is created (or reused from cache)
1002
+ * with the string as the envKey.
1003
+ *
1004
+ * Secrets are cached per scope to avoid creating duplicate secrets when
1005
+ * multiple constructs in the same scope reference the same secret.
1006
+ *
1007
+ * @example
1008
+ * // JaypieEnvSecret instances pass through
1009
+ * const secret = new JaypieEnvSecret(scope, "MySecret", { envKey: "MY_KEY" });
1010
+ * resolveSecrets(scope, [secret])
1011
+ * // => [secret]
1012
+ *
1013
+ * @example
1014
+ * // Strings create JaypieEnvSecret instances
1015
+ * resolveSecrets(scope, ["AUTH0_SECRET", "MONGODB_URI"])
1016
+ * // => [JaypieEnvSecret(envKey: "AUTH0_SECRET"), JaypieEnvSecret(envKey: "MONGODB_URI")]
1017
+ *
1018
+ * @example
1019
+ * // Mixed input
1020
+ * const existingSecret = new JaypieEnvSecret(scope, "Existing", { envKey: "EXISTING" });
1021
+ * resolveSecrets(scope, [existingSecret, "NEW_SECRET"])
1022
+ * // => [existingSecret, JaypieEnvSecret(envKey: "NEW_SECRET")]
1023
+ *
1024
+ * @example
1025
+ * // Secrets are shared across calls with the same scope
1026
+ * const secrets1 = resolveSecrets(scope, ["SHARED_SECRET"]);
1027
+ * const secrets2 = resolveSecrets(scope, ["SHARED_SECRET"]);
1028
+ * // secrets1[0] === secrets2[0] (same instance)
1029
+ */
1030
+ function resolveSecrets(scope, secrets) {
1031
+ if (!secrets || secrets.length === 0) {
1032
+ return [];
1033
+ }
1034
+ return secrets.map((item) => {
1035
+ if (typeof item === "string") {
1036
+ return getOrCreateSecret(scope, item);
1037
+ }
1038
+ // Already a JaypieEnvSecret instance
1039
+ return item;
1040
+ });
1041
+ }
1042
+ /**
1043
+ * Clears the secrets cache for a given scope.
1044
+ * Primarily useful for testing.
1045
+ */
1046
+ function clearSecretsCache(scope) {
1047
+ secretsByScope.delete(scope);
1048
+ }
1049
+ /**
1050
+ * Clears all secrets caches.
1051
+ * Primarily useful for testing.
1052
+ */
1053
+ function clearAllSecretsCaches() {
1054
+ // WeakMap doesn't have a clear() method, so we create a new one
1055
+ // This relies on the module being reloaded or the function being called
1056
+ // between test runs. For testing, use clearSecretsCache(scope) instead.
1057
+ }
1058
+
722
1059
  class JaypieApiGateway extends constructs.Construct {
723
1060
  constructor(scope, id, props) {
724
1061
  super(scope, id);
@@ -900,11 +1237,15 @@ class JaypieAppStack extends JaypieStack {
900
1237
  class JaypieLambda extends constructs.Construct {
901
1238
  constructor(scope, id, props) {
902
1239
  super(scope, id);
903
- const { allowAllOutbound, allowPublicSubnet, architecture = lambda__namespace.Architecture.X86_64, code, datadogApiKeyArn, deadLetterQueue, deadLetterQueueEnabled, deadLetterTopic, description, environment: initialEnvironment = {}, envSecrets = {}, ephemeralStorageSize, filesystem, handler = "index.handler", initialPolicy, layers = [], logGroup, logRetention = CDK$2.LAMBDA.LOG_RETENTION, maxEventAge, memorySize = CDK$2.LAMBDA.MEMORY_SIZE, paramsAndSecrets, paramsAndSecretsOptions, profiling, profilingGroup, provisionedConcurrentExecutions, reservedConcurrentExecutions, retryAttempts, roleTag = CDK$2.ROLE.PROCESSING, runtime = new lambda__namespace.Runtime("nodejs24.x", lambda__namespace.RuntimeFamily.NODEJS, {
1240
+ const { allowAllOutbound, allowPublicSubnet, architecture = lambda__namespace.Architecture.X86_64, code, datadogApiKeyArn, deadLetterQueue, deadLetterQueueEnabled, deadLetterTopic, description, environment: environmentInput, envSecrets = {}, ephemeralStorageSize, filesystem, handler = "index.handler", initialPolicy, layers = [], logGroup, logRetention = CDK$2.LAMBDA.LOG_RETENTION, maxEventAge, memorySize = CDK$2.LAMBDA.MEMORY_SIZE, paramsAndSecrets, paramsAndSecretsOptions, profiling, profilingGroup, provisionedConcurrentExecutions, reservedConcurrentExecutions, retryAttempts, roleTag = CDK$2.ROLE.PROCESSING, runtime = new lambda__namespace.Runtime("nodejs24.x", lambda__namespace.RuntimeFamily.NODEJS, {
904
1241
  supportsInlineCode: true,
905
- }), runtimeManagementMode, secrets = [], securityGroups, timeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, vpc, vpcSubnets, } = props;
1242
+ }), runtimeManagementMode, secrets: secretsInput = [], securityGroups, timeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, vpc, vpcSubnets, } = props;
1243
+ // Resolve environment from array or object syntax
1244
+ const initialEnvironment = resolveEnvironment(environmentInput);
906
1245
  // Get base environment with defaults
907
1246
  const environment = jaypieLambdaEnv({ initialEnvironment });
1247
+ // Resolve secrets from mixed array (strings and JaypieEnvSecret instances)
1248
+ const secrets = resolveSecrets(scope, secretsInput);
908
1249
  const codeAsset = typeof code === "string" ? lambda__namespace.Code.fromAsset(code) : code;
909
1250
  // Create a working copy of layers
910
1251
  const resolvedLayers = [...layers];
@@ -1885,150 +2226,6 @@ class JaypieDistribution extends constructs.Construct {
1885
2226
  }
1886
2227
  }
1887
2228
 
1888
- // It is a consumer if the environment is ephemeral
1889
- function checkEnvIsConsumer(env = process.env) {
1890
- return (env.PROJECT_ENV === CDK$2.ENV.PERSONAL ||
1891
- !!env.CDK_ENV_PERSONAL ||
1892
- /** @deprecated */ env.PROJECT_ENV === "ephemeral" ||
1893
- /** @deprecated */ !!env.CDK_ENV_EPHEMERAL);
1894
- }
1895
- function checkEnvIsProvider(env = process.env) {
1896
- return env.PROJECT_ENV === CDK$2.ENV.SANDBOX;
1897
- }
1898
- function cleanName(name) {
1899
- return name.replace(/[^a-zA-Z0-9:-]/g, "");
1900
- }
1901
- function exportEnvName(name, env = process.env) {
1902
- let rawName;
1903
- if (checkEnvIsProvider(env)) {
1904
- rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
1905
- // Clean the entire name to only allow alphanumeric, colons, and hyphens
1906
- return cleanName(rawName);
1907
- }
1908
- else {
1909
- if (checkEnvIsConsumer(env)) {
1910
- rawName = `env-${CDK$2.ENV.SANDBOX}-${env.PROJECT_KEY}-${name}`;
1911
- }
1912
- else {
1913
- rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
1914
- }
1915
- }
1916
- return cleanName(rawName);
1917
- }
1918
- class JaypieEnvSecret extends constructs.Construct {
1919
- constructor(scope, idOrEnvKey, props) {
1920
- // Check if idOrEnvKey should be treated as envKey:
1921
- // - No props provided OR props.envKey is not set
1922
- // - AND idOrEnvKey exists as a non-empty string in process.env
1923
- const treatAsEnvKey = (!props || props.envKey === undefined) &&
1924
- typeof process.env[idOrEnvKey] === "string" &&
1925
- process.env[idOrEnvKey] !== "";
1926
- const id = treatAsEnvKey ? `EnvSecret_${idOrEnvKey}` : idOrEnvKey;
1927
- super(scope, id);
1928
- const { consumer = checkEnvIsConsumer(), envKey: envKeyProp, export: exportParam, generateSecretString, provider = checkEnvIsProvider(), roleTag, vendorTag, value, } = props || {};
1929
- const envKey = treatAsEnvKey ? idOrEnvKey : envKeyProp;
1930
- this._envKey = envKey;
1931
- let exportName;
1932
- if (!exportParam) {
1933
- exportName = exportEnvName(id);
1934
- }
1935
- else {
1936
- exportName = cleanName(exportParam);
1937
- }
1938
- if (consumer) {
1939
- const secretName = cdk.Fn.importValue(exportName);
1940
- this._secret = secretsmanager__namespace.Secret.fromSecretNameV2(this, id, secretName);
1941
- // Add CfnOutput for consumer secrets
1942
- new cdk.CfnOutput(this, `ConsumedName`, {
1943
- value: this._secret.secretName,
1944
- });
1945
- }
1946
- else {
1947
- const secretValue = envKey && process.env[envKey] ? process.env[envKey] : value;
1948
- const secretProps = {
1949
- generateSecretString,
1950
- secretStringValue: !generateSecretString && secretValue
1951
- ? cdk.SecretValue.unsafePlainText(secretValue)
1952
- : undefined,
1953
- };
1954
- this._secret = new secretsmanager__namespace.Secret(this, id, secretProps);
1955
- if (roleTag) {
1956
- cdk.Tags.of(this._secret).add(CDK$2.TAG.ROLE, roleTag);
1957
- }
1958
- if (vendorTag) {
1959
- cdk.Tags.of(this._secret).add(CDK$2.TAG.VENDOR, vendorTag);
1960
- }
1961
- if (provider) {
1962
- new cdk.CfnOutput(this, `ProvidedName`, {
1963
- value: this._secret.secretName,
1964
- exportName,
1965
- });
1966
- }
1967
- else {
1968
- new cdk.CfnOutput(this, `CreatedName`, {
1969
- value: this._secret.secretName,
1970
- });
1971
- }
1972
- }
1973
- }
1974
- // IResource implementation
1975
- get stack() {
1976
- return cdk.Stack.of(this);
1977
- }
1978
- get env() {
1979
- return {
1980
- account: cdk.Stack.of(this).account,
1981
- region: cdk.Stack.of(this).region,
1982
- };
1983
- }
1984
- applyRemovalPolicy(policy) {
1985
- this._secret.applyRemovalPolicy(policy);
1986
- }
1987
- // ISecret implementation
1988
- get secretArn() {
1989
- return this._secret.secretArn;
1990
- }
1991
- get secretName() {
1992
- return this._secret.secretName;
1993
- }
1994
- get secretFullArn() {
1995
- return this._secret.secretFullArn;
1996
- }
1997
- get encryptionKey() {
1998
- return this._secret.encryptionKey;
1999
- }
2000
- get secretValue() {
2001
- return this._secret.secretValue;
2002
- }
2003
- secretValueFromJson(key) {
2004
- return this._secret.secretValueFromJson(key);
2005
- }
2006
- grantRead(grantee, versionStages) {
2007
- return this._secret.grantRead(grantee, versionStages);
2008
- }
2009
- grantWrite(grantee) {
2010
- return this._secret.grantWrite(grantee);
2011
- }
2012
- addRotationSchedule(id, options) {
2013
- return this._secret.addRotationSchedule(id, options);
2014
- }
2015
- addToResourcePolicy(statement) {
2016
- return this._secret.addToResourcePolicy(statement);
2017
- }
2018
- denyAccountRootDelete() {
2019
- this._secret.denyAccountRootDelete();
2020
- }
2021
- attach(target) {
2022
- return this._secret.attach(target);
2023
- }
2024
- cfnDynamicReferenceKey(options) {
2025
- return this._secret.cfnDynamicReferenceKey(options);
2026
- }
2027
- get envKey() {
2028
- return this._envKey;
2029
- }
2030
- }
2031
-
2032
2229
  class JaypieDatadogSecret extends JaypieEnvSecret {
2033
2230
  constructor(scope, id = "MongoConnectionString", props) {
2034
2231
  const defaultProps = {
@@ -2435,17 +2632,45 @@ class JaypieMongoDbSecret extends JaypieEnvSecret {
2435
2632
  class JaypieNextJs extends constructs.Construct {
2436
2633
  constructor(scope, id, props) {
2437
2634
  super(scope, id);
2635
+ cdkLog("JaypieNextJs constructor called", {
2636
+ id,
2637
+ props: {
2638
+ domainName: props?.domainName,
2639
+ hostedZone: typeof props?.hostedZone === "string"
2640
+ ? props.hostedZone
2641
+ : props?.hostedZone
2642
+ ? "(IHostedZone object)"
2643
+ : undefined,
2644
+ nextjsPath: props?.nextjsPath,
2645
+ hasEnvironment: !!props?.environment,
2646
+ hasEnvSecrets: !!props?.envSecrets,
2647
+ hasSecrets: !!props?.secrets,
2648
+ },
2649
+ cwd: process.cwd(),
2650
+ });
2438
2651
  const domainName = props?.domainName || envHostname();
2439
2652
  this.domainName = domainName;
2440
2653
  const domainNameSanitized = domainName
2441
2654
  .replace(/\./g, "-")
2442
2655
  .replace(/[^a-zA-Z0-9]/g, "_");
2656
+ cdkLog("JaypieNextJs domain resolved", {
2657
+ domainName,
2658
+ domainNameSanitized,
2659
+ });
2660
+ // Resolve environment from array or object syntax
2661
+ const environment = resolveEnvironment(props?.environment);
2443
2662
  const envSecrets = props?.envSecrets || {};
2444
2663
  const nextjsPath = props?.nextjsPath?.startsWith("..")
2445
2664
  ? path__namespace.join(process.cwd(), props.nextjsPath)
2446
2665
  : props?.nextjsPath || path__namespace.join(process.cwd(), "..", "nextjs");
2447
2666
  const paramsAndSecrets = resolveParamsAndSecrets();
2448
- const secrets = props?.secrets || [];
2667
+ cdkLog("JaypieNextJs paths resolved", {
2668
+ nextjsPath,
2669
+ propsNextjsPath: props?.nextjsPath,
2670
+ cwd: process.cwd(),
2671
+ });
2672
+ // Resolve secrets from mixed array (strings and JaypieEnvSecret instances)
2673
+ const secrets = resolveSecrets(scope, props?.secrets);
2449
2674
  // Process secrets environment variables
2450
2675
  const secretsEnvironment = Object.entries(envSecrets).reduce((acc, [key, secret]) => ({
2451
2676
  ...acc,
@@ -2471,6 +2696,17 @@ class JaypieNextJs extends constructs.Construct {
2471
2696
  }
2472
2697
  return acc;
2473
2698
  }, {});
2699
+ cdkLog("JaypieNextJs creating Nextjs construct", {
2700
+ nextjsPath,
2701
+ domainName,
2702
+ environmentKeys: Object.keys({
2703
+ ...jaypieLambdaEnv(),
2704
+ ...environment,
2705
+ ...secretsEnvironment,
2706
+ ...jaypieSecretsEnvironment,
2707
+ ...nextPublicEnv,
2708
+ }),
2709
+ });
2474
2710
  const nextjs = new cdkNextjsStandalone.Nextjs(this, "NextJsApp", {
2475
2711
  nextjsPath,
2476
2712
  domainProps: {
@@ -2481,6 +2717,7 @@ class JaypieNextJs extends constructs.Construct {
2481
2717
  },
2482
2718
  environment: {
2483
2719
  ...jaypieLambdaEnv(),
2720
+ ...environment,
2484
2721
  ...secretsEnvironment,
2485
2722
  ...jaypieSecretsEnvironment,
2486
2723
  ...nextPublicEnv,
@@ -2507,8 +2744,10 @@ class JaypieNextJs extends constructs.Construct {
2507
2744
  },
2508
2745
  },
2509
2746
  });
2747
+ cdkLog("JaypieNextJs Nextjs construct created successfully");
2510
2748
  addDatadogLayers(nextjs.imageOptimizationFunction);
2511
2749
  addDatadogLayers(nextjs.serverFunction.lambdaFunction);
2750
+ cdkLog("JaypieNextJs Datadog layers added");
2512
2751
  // Grant secret read permissions
2513
2752
  Object.values(envSecrets).forEach((secret) => {
2514
2753
  secret.grantRead(nextjs.serverFunction.lambdaFunction);
@@ -3314,6 +3553,9 @@ exports.JaypieStaticWebBucket = JaypieStaticWebBucket;
3314
3553
  exports.JaypieTraceSigningKeySecret = JaypieTraceSigningKeySecret;
3315
3554
  exports.JaypieWebDeploymentBucket = JaypieWebDeploymentBucket;
3316
3555
  exports.addDatadogLayers = addDatadogLayers;
3556
+ exports.cdkLog = cdkLog;
3557
+ exports.clearAllSecretsCaches = clearAllSecretsCaches;
3558
+ exports.clearSecretsCache = clearSecretsCache;
3317
3559
  exports.constructEnvName = constructEnvName;
3318
3560
  exports.constructStackName = constructStackName;
3319
3561
  exports.constructTagger = constructTagger;
@@ -3329,6 +3571,8 @@ exports.mergeDomain = mergeDomain;
3329
3571
  exports.resolveDatadogForwarderFunction = resolveDatadogForwarderFunction;
3330
3572
  exports.resolveDatadogLayers = resolveDatadogLayers;
3331
3573
  exports.resolveDatadogLoggingDestination = resolveDatadogLoggingDestination;
3574
+ exports.resolveEnvironment = resolveEnvironment;
3332
3575
  exports.resolveHostedZone = resolveHostedZone;
3333
3576
  exports.resolveParamsAndSecrets = resolveParamsAndSecrets;
3577
+ exports.resolveSecrets = resolveSecrets;
3334
3578
  //# sourceMappingURL=index.cjs.map