@gradientedge/cdk-utils 9.63.0 → 9.65.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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CommonAzureConstruct = void 0;
4
4
  const provider_1 = require("@cdktf/provider-azurerm/lib/provider");
5
5
  const provider_2 = require("../.gen/providers/azapi/provider");
6
+ const cdktf_local_exec_1 = require("cdktf-local-exec");
6
7
  const data_azurerm_client_config_1 = require("@cdktf/provider-azurerm/lib/data-azurerm-client-config");
7
8
  const cdktf_1 = require("cdktf");
8
9
  const common_1 = require("../../common");
@@ -52,6 +53,7 @@ class CommonAzureConstruct extends cdktf_1.TerraformStack {
52
53
  this.determineTenantId();
53
54
  new provider_2.AzapiProvider(this, `${this.id}-azapi-provider`, this.props);
54
55
  new provider_1.AzurermProvider(this, `${this.id}-provider`, this.props);
56
+ new cdktf_local_exec_1.Provider(this, `${this.id}-local-exec-provider`);
55
57
  }
56
58
  /**
57
59
  * @summary Determine the fully qualified domain name based on domainName & subDomain
@@ -216,10 +216,107 @@ class AzureApiManagementManager {
216
216
  (0, utils_1.createAzureTfOutput)(`${id}-${operation.displayName}-${operation.method}-apimOperationOperationId`, scope, apimOperation.operationId);
217
217
  (0, utils_1.createAzureTfOutput)(`${id}-${operation.displayName}-${operation.method}-apimOperationFriendlyUniqueId`, scope, apimOperation.friendlyUniqueId);
218
218
  (0, utils_1.createAzureTfOutput)(`${id}-${operation.displayName}-${operation.method}-apimOperationId`, scope, apimOperation.id);
219
+ // Define Caching Policy if enabled
220
+ let cacheInboundPolicy = '';
221
+ let cacheOutboundPolicy = '';
222
+ if (props.caching?.enabled === true) {
223
+ if (operation.method === 'get') {
224
+ cacheInboundPolicy = `<!-- Generate a comprehensive custom cache key (without query params or Accept header) -->
225
+ <set-variable name="customCacheKey" value="@{
226
+ // Instance identification
227
+
228
+ // API identification
229
+ string apiName = context.Api.Name.Replace(" ", "").ToLower();
230
+ string apiVersion = context.Api.Version ?? "v1";
231
+
232
+ // Full path construction (without query parameters)
233
+ string fullPath = context.Request.Url.Path.ToLower();
234
+
235
+ // Construct final cache key (no Accept header needed for JSON-only APIs)
236
+ return $"{apiName}:{apiVersion}:{fullPath}";
237
+ }" />
238
+ <set-variable name="bypassCache" value="@(context.Request.Headers.GetValueOrDefault("X-Bypass-Cache", "false").ToLower())" />
239
+
240
+ <choose>
241
+ <when condition="@((string)context.Variables["bypassCache"] != "true")">
242
+ <!-- Attempt to retrieve cached response -->
243
+ <cache-lookup-value key="@((string)context.Variables["customCacheKey"])" variable-name="cachedResponse" />
244
+
245
+ <!-- If cache hit, return cached response -->
246
+ <choose>
247
+ <when condition="@(context.Variables.ContainsKey("cachedResponse"))">
248
+ <return-response>
249
+ <set-status code="200" reason="OK" />
250
+ <set-header name="Content-Type" exists-action="override">
251
+ <value>application/json</value>
252
+ </set-header>
253
+ <set-header name="X-Apim-Cache-Status" exists-action="override">
254
+ <value>HIT</value>
255
+ </set-header>
256
+ <set-header name="X-Apim-Cache-Key" exists-action="override">
257
+ <value>@((string)context.Variables["customCacheKey"])</value>
258
+ </set-header>
259
+ <set-body>@((string)context.Variables["cachedResponse"])</set-body>
260
+ </return-response>
261
+ </when>
262
+ </choose>
263
+ </when>
264
+ </choose>`;
265
+ cacheOutboundPolicy = `<choose>
266
+ <when condition="@((string)context.Variables["bypassCache"] != "true")">
267
+ <!-- Store the response body in cache -->
268
+ <choose>
269
+ <when condition="@(context.Response.StatusCode == 200)">
270
+ <cache-store-value key="@((string)context.Variables["customCacheKey"])" value="@(context.Response.Body.As<string>(preserveContent: true))" duration="${props.caching.ttl ?? 900}" />
271
+ <!-- Add cache status header -->
272
+ <set-header name="X-Apim-Cache-Status" exists-action="override">
273
+ <value>MISS</value>
274
+ </set-header>
275
+ </when>
276
+ </choose>
277
+ <!-- Add debug headers -->
278
+ <set-header name="X-Apim-Cache-Key" exists-action="override">
279
+ <value>@((string)context.Variables["customCacheKey"])</value>
280
+ </set-header>
281
+ <set-header name="X-Apim-API-Name" exists-action="override">
282
+ <value>@(context.Api.Name)</value>
283
+ </set-header>
284
+ </when>
285
+ </choose>`;
286
+ }
287
+ if (operation.method === 'post') {
288
+ cacheInboundPolicy = `<!-- Generate a comprehensive custom cache key (without query params or Accept header) -->
289
+ <set-variable name="customCacheKey" value="@{
290
+ // Instance identification
291
+
292
+ // API identification
293
+ string apiName = context.Api.Name.Replace(" ", "").ToLower();
294
+ string apiVersion = context.Api.Version ?? "v1";
295
+
296
+ // Full path construction (without query parameters)
297
+ string fullPath = context.Request.Url.Path.ToLower();
298
+
299
+ // Construct final cache key (no Accept header needed for JSON-only APIs)
300
+ return $"{apiName}:{apiVersion}:{fullPath}";
301
+ }" />
302
+ <set-variable name="clearCache" value="@(context.Request.Headers.GetValueOrDefault("X-Apim-Clear-Cache", "false").ToLower())" />
303
+
304
+ <!-- Allow admin to clear specific cache entries -->
305
+ <choose>
306
+ <when condition="@((string)context.Variables["clearCache"] == "true")">
307
+ <cache-remove-value key="@((string)context.Variables["customCacheKey"])" />
308
+ <return-response>
309
+ <set-status code="200" reason="OK" />
310
+ <set-body>Cache entry removed successfully</set-body>
311
+ </return-response>
312
+ </when>
313
+ </choose>`;
314
+ }
315
+ }
219
316
  const policyXmlContent = `<policies>
220
317
  <inbound>
221
318
  <base />
222
- ${operation.cacheInboundPolicy ?? ''}
319
+ ${cacheInboundPolicy}
223
320
  ${props.commonInboundPolicyXml ?? ''}
224
321
  </inbound>
225
322
  <backend>
@@ -227,7 +324,7 @@ class AzureApiManagementManager {
227
324
  </backend>
228
325
  <outbound>
229
326
  <base />
230
- ${operation.cacheOutboundPolicy ?? ''}
327
+ ${cacheOutboundPolicy ?? ''}
231
328
  ${props.commonOutboundPolicyXml ?? ''}
232
329
  </outbound>
233
330
  <on-error>
@@ -14,11 +14,14 @@ export interface ApiManagementApiProps extends ApiManagementApiConfig {
14
14
  operations: ApiManagementApiOperationProps[];
15
15
  commonInboundPolicyXml: string;
16
16
  commonOutboundPolicyXml: string;
17
+ caching?: ApiManagementApiCaching;
17
18
  }
18
19
  export interface ApiManagementV2Props extends ApiManagementConfig {
19
20
  body: any;
20
21
  }
21
22
  export interface ApiManagementApiOperationProps extends ApiManagementApiOperationConfig {
22
- cacheInboundPolicy: string;
23
- cacheOutboundPolicy: string;
23
+ }
24
+ export interface ApiManagementApiCaching {
25
+ enabled: boolean;
26
+ ttl?: number;
24
27
  }
@@ -5,7 +5,6 @@ const data_azurerm_resource_group_1 = require("@cdktf/provider-azurerm/lib/data-
5
5
  const linux_function_app_1 = require("@cdktf/provider-azurerm/lib/linux-function-app");
6
6
  const function_app_function_1 = require("@cdktf/provider-azurerm/lib/function-app-function");
7
7
  const function_app_flex_consumption_1 = require("@cdktf/provider-azurerm/lib/function-app-flex-consumption");
8
- const cdktf_local_exec_1 = require("cdktf-local-exec");
9
8
  const utils_1 = require("../../utils");
10
9
  /**
11
10
  * @classdesc Provides operations on Azure Functions
@@ -113,29 +112,6 @@ class AzureFunctionManager {
113
112
  environment: scope.props.stage,
114
113
  },
115
114
  });
116
- new cdktf_local_exec_1.Provider(scope, `${id}-local-exec-provider`);
117
- // Deploy function app zip package with up to 3 retry attempts.
118
- // This handles transient issues like HTTP 503s returned from the Azure Kudu deployment endpoint.
119
- new cdktf_local_exec_1.LocalExec(scope, `${id}-function-app-deploy`, {
120
- triggers: {
121
- hash: props.sourceCodeHash,
122
- },
123
- command: `
124
- set -e
125
- MAX_RETRIES=3
126
- RETRY_COUNT=0
127
- until az functionapp deployment source config-zip --resource-group "${resourceGroup.name}" --name "${functionApp.name}" --src "${props.deploySource}"; do
128
- RETRY_COUNT=$((RETRY_COUNT+1))
129
- echo "Deployment attempt $RETRY_COUNT failed. Retrying in 10 seconds..."
130
- if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
131
- echo "Deployment failed after $MAX_RETRIES attempts."
132
- exit 1
133
- fi
134
- sleep 10
135
- done
136
- echo "Deployment succeeded."
137
- `,
138
- });
139
115
  return functionApp;
140
116
  }
141
117
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradientedge/cdk-utils",
3
- "version": "9.63.0",
3
+ "version": "9.65.0",
4
4
  "description": "Utilities for AWS CDK provisioning",
5
5
  "main": "dist/index.js",
6
6
  "engines": {
@@ -1,5 +1,6 @@
1
1
  import { AzurermProvider } from '@cdktf/provider-azurerm/lib/provider'
2
2
  import { AzapiProvider } from '../.gen/providers/azapi/provider'
3
+ import { Provider } from 'cdktf-local-exec'
3
4
  import { DataAzurermClientConfig } from '@cdktf/provider-azurerm/lib/data-azurerm-client-config'
4
5
  import { AzurermBackend, TerraformStack } from 'cdktf'
5
6
  import { Construct } from 'constructs'
@@ -72,6 +73,7 @@ export class CommonAzureConstruct extends TerraformStack {
72
73
 
73
74
  new AzapiProvider(this, `${this.id}-azapi-provider`, this.props)
74
75
  new AzurermProvider(this, `${this.id}-provider`, this.props)
76
+ new Provider(this, `${this.id}-local-exec-provider`)
75
77
  }
76
78
 
77
79
  /**
@@ -272,10 +272,110 @@ export class AzureApiManagementManager {
272
272
  )
273
273
  createAzureTfOutput(`${id}-${operation.displayName}-${operation.method}-apimOperationId`, scope, apimOperation.id)
274
274
 
275
+ // Define Caching Policy if enabled
276
+ let cacheInboundPolicy = ''
277
+ let cacheOutboundPolicy = ''
278
+
279
+ if (props.caching?.enabled === true) {
280
+ if (operation.method === 'get') {
281
+ cacheInboundPolicy = `<!-- Generate a comprehensive custom cache key (without query params or Accept header) -->
282
+ <set-variable name="customCacheKey" value="@{
283
+ // Instance identification
284
+
285
+ // API identification
286
+ string apiName = context.Api.Name.Replace(" ", "").ToLower();
287
+ string apiVersion = context.Api.Version ?? "v1";
288
+
289
+ // Full path construction (without query parameters)
290
+ string fullPath = context.Request.Url.Path.ToLower();
291
+
292
+ // Construct final cache key (no Accept header needed for JSON-only APIs)
293
+ return $"{apiName}:{apiVersion}:{fullPath}";
294
+ }" />
295
+ <set-variable name="bypassCache" value="@(context.Request.Headers.GetValueOrDefault("X-Bypass-Cache", "false").ToLower())" />
296
+
297
+ <choose>
298
+ <when condition="@((string)context.Variables["bypassCache"] != "true")">
299
+ <!-- Attempt to retrieve cached response -->
300
+ <cache-lookup-value key="@((string)context.Variables["customCacheKey"])" variable-name="cachedResponse" />
301
+
302
+ <!-- If cache hit, return cached response -->
303
+ <choose>
304
+ <when condition="@(context.Variables.ContainsKey("cachedResponse"))">
305
+ <return-response>
306
+ <set-status code="200" reason="OK" />
307
+ <set-header name="Content-Type" exists-action="override">
308
+ <value>application/json</value>
309
+ </set-header>
310
+ <set-header name="X-Apim-Cache-Status" exists-action="override">
311
+ <value>HIT</value>
312
+ </set-header>
313
+ <set-header name="X-Apim-Cache-Key" exists-action="override">
314
+ <value>@((string)context.Variables["customCacheKey"])</value>
315
+ </set-header>
316
+ <set-body>@((string)context.Variables["cachedResponse"])</set-body>
317
+ </return-response>
318
+ </when>
319
+ </choose>
320
+ </when>
321
+ </choose>`
322
+ cacheOutboundPolicy = `<choose>
323
+ <when condition="@((string)context.Variables["bypassCache"] != "true")">
324
+ <!-- Store the response body in cache -->
325
+ <choose>
326
+ <when condition="@(context.Response.StatusCode == 200)">
327
+ <cache-store-value key="@((string)context.Variables["customCacheKey"])" value="@(context.Response.Body.As<string>(preserveContent: true))" duration="${props.caching.ttl ?? 900}" />
328
+ <!-- Add cache status header -->
329
+ <set-header name="X-Apim-Cache-Status" exists-action="override">
330
+ <value>MISS</value>
331
+ </set-header>
332
+ </when>
333
+ </choose>
334
+ <!-- Add debug headers -->
335
+ <set-header name="X-Apim-Cache-Key" exists-action="override">
336
+ <value>@((string)context.Variables["customCacheKey"])</value>
337
+ </set-header>
338
+ <set-header name="X-Apim-API-Name" exists-action="override">
339
+ <value>@(context.Api.Name)</value>
340
+ </set-header>
341
+ </when>
342
+ </choose>`
343
+ }
344
+
345
+ if (operation.method === 'post') {
346
+ cacheInboundPolicy = `<!-- Generate a comprehensive custom cache key (without query params or Accept header) -->
347
+ <set-variable name="customCacheKey" value="@{
348
+ // Instance identification
349
+
350
+ // API identification
351
+ string apiName = context.Api.Name.Replace(" ", "").ToLower();
352
+ string apiVersion = context.Api.Version ?? "v1";
353
+
354
+ // Full path construction (without query parameters)
355
+ string fullPath = context.Request.Url.Path.ToLower();
356
+
357
+ // Construct final cache key (no Accept header needed for JSON-only APIs)
358
+ return $"{apiName}:{apiVersion}:{fullPath}";
359
+ }" />
360
+ <set-variable name="clearCache" value="@(context.Request.Headers.GetValueOrDefault("X-Apim-Clear-Cache", "false").ToLower())" />
361
+
362
+ <!-- Allow admin to clear specific cache entries -->
363
+ <choose>
364
+ <when condition="@((string)context.Variables["clearCache"] == "true")">
365
+ <cache-remove-value key="@((string)context.Variables["customCacheKey"])" />
366
+ <return-response>
367
+ <set-status code="200" reason="OK" />
368
+ <set-body>Cache entry removed successfully</set-body>
369
+ </return-response>
370
+ </when>
371
+ </choose>`
372
+ }
373
+ }
374
+
275
375
  const policyXmlContent = `<policies>
276
376
  <inbound>
277
377
  <base />
278
- ${operation.cacheInboundPolicy ?? ''}
378
+ ${cacheInboundPolicy}
279
379
  ${props.commonInboundPolicyXml ?? ''}
280
380
  </inbound>
281
381
  <backend>
@@ -283,7 +383,7 @@ export class AzureApiManagementManager {
283
383
  </backend>
284
384
  <outbound>
285
385
  <base />
286
- ${operation.cacheOutboundPolicy ?? ''}
386
+ ${cacheOutboundPolicy ?? ''}
287
387
  ${props.commonOutboundPolicyXml ?? ''}
288
388
  </outbound>
289
389
  <on-error>
@@ -16,13 +16,16 @@ export interface ApiManagementApiProps extends ApiManagementApiConfig {
16
16
  operations: ApiManagementApiOperationProps[]
17
17
  commonInboundPolicyXml: string
18
18
  commonOutboundPolicyXml: string
19
+ caching?: ApiManagementApiCaching
19
20
  }
20
21
 
21
22
  export interface ApiManagementV2Props extends ApiManagementConfig {
22
23
  body: any
23
24
  }
24
25
 
25
- export interface ApiManagementApiOperationProps extends ApiManagementApiOperationConfig {
26
- cacheInboundPolicy: string
27
- cacheOutboundPolicy: string
26
+ export interface ApiManagementApiOperationProps extends ApiManagementApiOperationConfig {}
27
+
28
+ export interface ApiManagementApiCaching {
29
+ enabled: boolean
30
+ ttl?: number
28
31
  }
@@ -2,7 +2,6 @@ import { DataAzurermResourceGroup } from '@cdktf/provider-azurerm/lib/data-azure
2
2
  import { LinuxFunctionApp } from '@cdktf/provider-azurerm/lib/linux-function-app'
3
3
  import { FunctionAppFunction } from '@cdktf/provider-azurerm/lib/function-app-function'
4
4
  import { FunctionAppFlexConsumption } from '@cdktf/provider-azurerm/lib/function-app-flex-consumption'
5
- import { LocalExec, Provider } from 'cdktf-local-exec'
6
5
  import { CommonAzureConstruct } from '../../common'
7
6
  import { createAzureTfOutput } from '../../utils'
8
7
  import { FunctionAppProps, FunctionProps, FunctionAppFlexConsumptionProps } from './types'
@@ -126,30 +125,6 @@ export class AzureFunctionManager {
126
125
  },
127
126
  })
128
127
 
129
- new Provider(scope, `${id}-local-exec-provider`)
130
- // Deploy function app zip package with up to 3 retry attempts.
131
- // This handles transient issues like HTTP 503s returned from the Azure Kudu deployment endpoint.
132
- new LocalExec(scope, `${id}-function-app-deploy`, {
133
- triggers: {
134
- hash: props.sourceCodeHash,
135
- },
136
- command: `
137
- set -e
138
- MAX_RETRIES=3
139
- RETRY_COUNT=0
140
- until az functionapp deployment source config-zip --resource-group "${resourceGroup.name}" --name "${functionApp.name}" --src "${props.deploySource}"; do
141
- RETRY_COUNT=$((RETRY_COUNT+1))
142
- echo "Deployment attempt $RETRY_COUNT failed. Retrying in 10 seconds..."
143
- if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
144
- echo "Deployment failed after $MAX_RETRIES attempts."
145
- exit 1
146
- fi
147
- sleep 10
148
- done
149
- echo "Deployment succeeded."
150
- `,
151
- })
152
-
153
128
  return functionApp
154
129
  }
155
130
  }