@culturefy/shared 1.0.76 → 1.0.77

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 (34) hide show
  1. package/build/cjs/middlewares/withPermissionsMw.js +73 -0
  2. package/build/cjs/middlewares/withPermissionsMw.js.map +1 -0
  3. package/build/cjs/service/tokenMapping.service.js +3 -3
  4. package/build/cjs/service/tokenMapping.service.js.map +1 -1
  5. package/build/cjs/service/user.service.js +2 -2
  6. package/build/cjs/service/user.service.js.map +1 -1
  7. package/build/cjs/utils/cache.js +4 -1
  8. package/build/cjs/utils/cache.js.map +1 -1
  9. package/build/cjs/utils/secrets.js +89 -19
  10. package/build/cjs/utils/secrets.js.map +1 -1
  11. package/build/esm/middlewares/withPermissionsMw.js +68 -0
  12. package/build/esm/middlewares/withPermissionsMw.js.map +1 -0
  13. package/build/esm/service/tokenMapping.service.js +1 -1
  14. package/build/esm/service/tokenMapping.service.js.map +1 -1
  15. package/build/esm/service/user.service.js +1 -1
  16. package/build/esm/service/user.service.js.map +1 -1
  17. package/build/esm/utils/cache.js +5 -2
  18. package/build/esm/utils/cache.js.map +1 -1
  19. package/build/esm/utils/secrets.js +88 -19
  20. package/build/esm/utils/secrets.js.map +1 -1
  21. package/build/src/schema/location.model.d.ts +1 -1
  22. package/build/src/service/tokenMapping.service.d.ts +1 -1
  23. package/build/src/service/tokenMapping.service.js +9 -9
  24. package/build/src/service/tokenMapping.service.js.map +1 -1
  25. package/build/src/service/user.service.d.ts +1 -1
  26. package/build/src/service/user.service.js +2 -2
  27. package/build/src/service/user.service.js.map +1 -1
  28. package/build/src/types/location.d.ts +1 -1
  29. package/build/src/utils/cache.js +5 -1
  30. package/build/src/utils/cache.js.map +1 -1
  31. package/build/src/utils/secrets.d.ts +12 -4
  32. package/build/src/utils/secrets.js +91 -18
  33. package/build/src/utils/secrets.js.map +1 -1
  34. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSecretsRedis = registerSecretsRedis;
3
4
  exports.getAzureVaultSecretByKey = getAzureVaultSecretByKey;
4
5
  exports.getInterservicesCommunicationKey = getInterservicesCommunicationKey;
5
6
  const tslib_1 = require("tslib");
@@ -7,36 +8,108 @@ const identity_1 = require("@azure/identity");
7
8
  const keyvault_secrets_1 = require("@azure/keyvault-secrets");
8
9
  const enums_1 = require("../enums");
9
10
  const mapper_1 = require("./mapper");
11
+ // L1: in-memory cache — permanent for the lifetime of the Function host instance
12
+ const secretCache = new Map();
13
+ // Deduplicate concurrent in-flight fetches for the same key
14
+ const secretInflight = new Map();
15
+ // Singleton SecretClient per vault URL
16
+ const secretClients = new Map();
17
+ // L2: Redis cache — injected by cache.ts after Redis connects (avoids circular import)
18
+ const SECRET_REDIS_TTL = 60; // seconds
19
+ const SECRET_REDIS_NS = "kv-secret";
20
+ let _redis = null;
21
+ // These secrets are needed to bootstrap the Redis connection itself —
22
+ // they must never be looked up via Redis to prevent infinite recursion.
23
+ const BOOTSTRAP_KEYS = new Set([
24
+ enums_1.AzureSecretKeysEnum.REDIS_HOST,
25
+ enums_1.AzureSecretKeysEnum.REDIS_KEY,
26
+ enums_1.AzureSecretKeysEnum.REDIS_PORT,
27
+ ]);
28
+ /**
29
+ * Called by cache.ts after the Redis client successfully connects.
30
+ * Enables L2 Redis caching for Key Vault secrets without a circular import.
31
+ */
32
+ function registerSecretsRedis(client) {
33
+ _redis = client;
34
+ }
35
+ function getSecretClient(vaultName) {
36
+ const vaultUrl = `https://${vaultName}.vault.azure.net`;
37
+ if (!secretClients.has(vaultUrl)) {
38
+ secretClients.set(vaultUrl, new keyvault_secrets_1.SecretClient(vaultUrl, new identity_1.DefaultAzureCredential()));
39
+ }
40
+ return secretClients.get(vaultUrl);
41
+ }
10
42
  /**
11
43
  * Fetches a secret value from Azure Key Vault by key.
12
- * @param key - The key name from the AzureSecretKeysEnum enum.
13
- * @returns The secret value.
14
- * @throws Error if the key is invalid or if the secret fetch fails.
15
- */
44
+ *
45
+ * Lookup order (fastest to slowest):
46
+ * L1 in-memory L2 Redis (60s TTL) Azure Key Vault
47
+ *
48
+ * Bootstrap secrets (REDIS_HOST/KEY/PORT) skip Redis to avoid circular calls.
49
+ */
16
50
  function getAzureVaultSecretByKey(context, vaultName, key) {
17
51
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
18
52
  var _a;
19
- // Build the list of valid enum values once
20
53
  const validKeys = (0, mapper_1.enumMapper)(enums_1.AzureSecretKeysEnum);
21
- // Validate
22
54
  if (!validKeys.includes(key)) {
23
55
  const msg = `Invalid secret key requested: ${key}`;
24
56
  context.error(msg);
25
57
  throw new Error(msg);
26
58
  }
27
- // Construct the vault URL
28
- const vaultUrl = `https://${vaultName}.vault.azure.net`;
29
- // Initialize the client
30
- const credential = new identity_1.DefaultAzureCredential();
31
- const client = new keyvault_secrets_1.SecretClient(vaultUrl, credential);
32
- try {
33
- const secret = yield client.getSecret(key);
34
- return (_a = secret.value) !== null && _a !== void 0 ? _a : "";
35
- }
36
- catch (err) {
37
- context.error(`Error fetching secret "${key}" from vault "${vaultName}"`, err);
38
- throw new Error(`Failed to fetch secret "${key}": ${err.message}`);
59
+ const cacheKey = `${vaultName}:${key}`;
60
+ // L1 in-memory
61
+ const l1 = secretCache.get(cacheKey);
62
+ if (l1 !== undefined)
63
+ return l1;
64
+ // L2 — Redis (skipped for bootstrap keys)
65
+ const useRedis = _redis !== null && !BOOTSTRAP_KEYS.has(key);
66
+ if (useRedis) {
67
+ try {
68
+ const l2 = yield _redis.get(`${SECRET_REDIS_NS}:${cacheKey}`);
69
+ if (l2 !== null) {
70
+ secretCache.set(cacheKey, l2);
71
+ return l2;
72
+ }
73
+ }
74
+ catch (err) {
75
+ (_a = context.warn) === null || _a === void 0 ? void 0 : _a.call(context, `Redis L2 secret cache read failed for "${key}", falling through to Key Vault`, err);
76
+ }
39
77
  }
78
+ // Deduplicate concurrent fetches for the same key
79
+ const inflight = secretInflight.get(cacheKey);
80
+ if (inflight)
81
+ return inflight;
82
+ const fetchPromise = (() => tslib_1.__awaiter(this, void 0, void 0, function* () {
83
+ var _a, _b;
84
+ const client = getSecretClient(vaultName);
85
+ try {
86
+ const secret = yield client.getSecret(key);
87
+ const value = (_a = secret.value) !== null && _a !== void 0 ? _a : "";
88
+ // Populate L1
89
+ secretCache.set(cacheKey, value);
90
+ // Populate L2 — re-check _redis at write time in case Redis connected
91
+ // during the Key Vault round-trip (cold-start race)
92
+ const redisForWrite = !BOOTSTRAP_KEYS.has(key) ? _redis : null;
93
+ if (redisForWrite) {
94
+ try {
95
+ yield redisForWrite.set(`${SECRET_REDIS_NS}:${cacheKey}`, value, "EX", SECRET_REDIS_TTL);
96
+ }
97
+ catch (err) {
98
+ (_b = context.warn) === null || _b === void 0 ? void 0 : _b.call(context, `Redis L2 secret cache write failed for "${key}"`, err);
99
+ }
100
+ }
101
+ return value;
102
+ }
103
+ catch (err) {
104
+ context.error(`Error fetching secret "${key}" from vault "${vaultName}"`, err);
105
+ throw new Error(`Failed to fetch secret "${key}": ${err.message}`);
106
+ }
107
+ finally {
108
+ secretInflight.delete(cacheKey);
109
+ }
110
+ }))();
111
+ secretInflight.set(cacheKey, fetchPromise);
112
+ return fetchPromise;
40
113
  });
41
114
  }
42
115
  function getInterservicesCommunicationKey(context) {
@@ -1 +1 @@
1
- {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../src/utils/secrets.ts"],"names":[],"mappings":";;AAYA,4DA6BC;AAED,4EAwBC;;AAnED,8CAAyD;AACzD,8DAAuD;AAEvD,oCAA+C;AAC/C,qCAAsC;AAEtC;;;;;EAKE;AACF,SAAsB,wBAAwB,CAC5C,OAA0B,EAC1B,SAAiB,EACjB,GAAwB;;;QAExB,2CAA2C;QAC3C,MAAM,SAAS,GAAG,IAAA,mBAAU,EAAC,2BAAmB,CAAC,CAAC;QAElD,WAAW;QACX,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,iCAAiC,GAAG,EAAE,CAAC;YACnD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACnB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;QACvB,CAAC;QAED,0BAA0B;QAC1B,MAAM,QAAQ,GAAG,WAAW,SAAS,kBAAkB,CAAC;QAExD,wBAAwB;QACxB,MAAM,UAAU,GAAG,IAAI,iCAAsB,EAAE,CAAC;QAChD,MAAM,MAAM,GAAO,IAAI,+BAAY,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;QAE1D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC3C,OAAO,MAAA,MAAM,CAAC,KAAK,mCAAI,EAAE,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,0BAA0B,GAAG,iBAAiB,SAAS,GAAG,EAAE,GAAG,CAAC,CAAC;YAC/E,MAAM,IAAI,KAAK,CAAC,2BAA2B,GAAG,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;CAAA;AAED,SAAsB,gCAAgC,CACpD,OAA0B;;;QAE1B,MAAM,QAAQ,GAAG,MAAA,OAAO,CAAC,GAAG,CAAC,+BAA+B,0CAAE,IAAI,EAAE,CAAC;QACrE,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC;QACzD,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,wBAAwB,CACxC,OAAO,EACP,SAAS,EACT,2BAAmB,CAAC,+BAA+B,CACpD,CAAC;QAEF,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,OAAO,GAAG,CAAC;IACb,CAAC;CAAA"}
1
+ {"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../../src/utils/secrets.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@culturefy/shared",
3
3
  "description": "Shared utilities for culturefy serverless services",
4
- "version": "1.0.76",
4
+ "version": "1.0.77",
5
5
  "main": "build/cjs/index.js",
6
6
  "module": "build/esm/index.js",
7
7
  "types": "build/src/index.d.ts",