@pipeline-builder/api-core 3.1.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.
- package/LICENSE +202 -0
- package/README.md +51 -0
- package/lib/constants/ai-providers.d.ts +41 -0
- package/lib/constants/ai-providers.js +88 -0
- package/lib/constants/http-status.d.ts +24 -0
- package/lib/constants/http-status.js +29 -0
- package/lib/constants/index.d.ts +3 -0
- package/lib/constants/index.js +22 -0
- package/lib/constants/time.d.ts +10 -0
- package/lib/constants/time.js +16 -0
- package/lib/errors/app-errors.d.ts +30 -0
- package/lib/errors/app-errors.js +62 -0
- package/lib/errors/index.d.ts +1 -0
- package/lib/errors/index.js +20 -0
- package/lib/helpers/access-helpers.d.ts +40 -0
- package/lib/helpers/access-helpers.js +56 -0
- package/lib/helpers/crud-helpers.d.ts +16 -0
- package/lib/helpers/crud-helpers.js +34 -0
- package/lib/helpers/index.d.ts +4 -0
- package/lib/helpers/index.js +23 -0
- package/lib/helpers/mask-helpers.d.ts +33 -0
- package/lib/helpers/mask-helpers.js +54 -0
- package/lib/helpers/sse-helpers.d.ts +13 -0
- package/lib/helpers/sse-helpers.js +40 -0
- package/lib/index.d.ts +57 -0
- package/lib/index.js +86 -0
- package/lib/middleware/auth.d.ts +50 -0
- package/lib/middleware/auth.js +171 -0
- package/lib/middleware/index.d.ts +1 -0
- package/lib/middleware/index.js +20 -0
- package/lib/openapi/extend-zod.d.ts +1 -0
- package/lib/openapi/extend-zod.js +8 -0
- package/lib/openapi/index.d.ts +2 -0
- package/lib/openapi/index.js +10 -0
- package/lib/openapi/registry.d.ts +17 -0
- package/lib/openapi/registry.js +42 -0
- package/lib/openapi/routes/billing-routes.d.ts +1 -0
- package/lib/openapi/routes/billing-routes.js +69 -0
- package/lib/openapi/routes/index.d.ts +5 -0
- package/lib/openapi/routes/index.js +22 -0
- package/lib/openapi/routes/message-routes.d.ts +1 -0
- package/lib/openapi/routes/message-routes.js +108 -0
- package/lib/openapi/routes/pipeline-routes.d.ts +1 -0
- package/lib/openapi/routes/pipeline-routes.js +90 -0
- package/lib/openapi/routes/plugin-routes.d.ts +1 -0
- package/lib/openapi/routes/plugin-routes.js +99 -0
- package/lib/openapi/routes/quota-routes.d.ts +1 -0
- package/lib/openapi/routes/quota-routes.js +65 -0
- package/lib/openapi/schema-registry.d.ts +25 -0
- package/lib/openapi/schema-registry.js +95 -0
- package/lib/routes/health.d.ts +47 -0
- package/lib/routes/health.js +81 -0
- package/lib/routes/index.d.ts +1 -0
- package/lib/routes/index.js +20 -0
- package/lib/services/admin-audit.d.ts +13 -0
- package/lib/services/admin-audit.js +31 -0
- package/lib/services/cache-service.d.ts +108 -0
- package/lib/services/cache-service.js +212 -0
- package/lib/services/compliance-client.d.ts +46 -0
- package/lib/services/compliance-client.js +102 -0
- package/lib/services/compliance-event-subscriber.d.ts +11 -0
- package/lib/services/compliance-event-subscriber.js +60 -0
- package/lib/services/compliance-queue.d.ts +11 -0
- package/lib/services/compliance-queue.js +38 -0
- package/lib/services/entity-events.d.ts +44 -0
- package/lib/services/entity-events.js +63 -0
- package/lib/services/http-client.d.ts +108 -0
- package/lib/services/http-client.js +285 -0
- package/lib/services/index.d.ts +10 -0
- package/lib/services/index.js +40 -0
- package/lib/services/quota.d.ts +59 -0
- package/lib/services/quota.js +137 -0
- package/lib/services/retry-strategy.d.ts +74 -0
- package/lib/services/retry-strategy.js +127 -0
- package/lib/types/billing.d.ts +47 -0
- package/lib/types/billing.js +5 -0
- package/lib/types/common.d.ts +161 -0
- package/lib/types/common.js +53 -0
- package/lib/types/error-codes.d.ts +38 -0
- package/lib/types/error-codes.js +77 -0
- package/lib/types/feature-flags.d.ts +38 -0
- package/lib/types/feature-flags.js +107 -0
- package/lib/types/http.d.ts +37 -0
- package/lib/types/http.js +5 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/index.js +26 -0
- package/lib/types/pipeline.d.ts +70 -0
- package/lib/types/pipeline.js +44 -0
- package/lib/types/quota-tiers.d.ts +23 -0
- package/lib/types/quota-tiers.js +26 -0
- package/lib/utils/alias-resolver.d.ts +16 -0
- package/lib/utils/alias-resolver.js +49 -0
- package/lib/utils/headers.d.ts +18 -0
- package/lib/utils/headers.js +24 -0
- package/lib/utils/identity.d.ts +61 -0
- package/lib/utils/identity.js +75 -0
- package/lib/utils/index.d.ts +7 -0
- package/lib/utils/index.js +26 -0
- package/lib/utils/logger.d.ts +28 -0
- package/lib/utils/logger.js +77 -0
- package/lib/utils/object.d.ts +13 -0
- package/lib/utils/object.js +21 -0
- package/lib/utils/params.d.ts +89 -0
- package/lib/utils/params.js +148 -0
- package/lib/utils/response.d.ts +142 -0
- package/lib/utils/response.js +237 -0
- package/lib/validation/ai-schemas.d.ts +61 -0
- package/lib/validation/ai-schemas.js +81 -0
- package/lib/validation/common-schemas.d.ts +72 -0
- package/lib/validation/common-schemas.js +58 -0
- package/lib/validation/index.d.ts +6 -0
- package/lib/validation/index.js +25 -0
- package/lib/validation/message-schemas.d.ts +79 -0
- package/lib/validation/message-schemas.js +42 -0
- package/lib/validation/middleware.d.ts +60 -0
- package/lib/validation/middleware.js +77 -0
- package/lib/validation/pipeline-schemas.d.ts +135 -0
- package/lib/validation/pipeline-schemas.js +85 -0
- package/lib/validation/plugin-schemas.d.ts +127 -0
- package/lib/validation/plugin-schemas.js +84 -0
- package/openapi.yaml +292 -0
- package/package.json +127 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.logAdminAction = logAdminAction;
|
|
6
|
+
exports.getAuditQueue = getAuditQueue;
|
|
7
|
+
const logger_1 = require("../utils/logger");
|
|
8
|
+
const logger = (0, logger_1.createLogger)('admin-audit');
|
|
9
|
+
const auditQueue = [];
|
|
10
|
+
let flushTimer = null;
|
|
11
|
+
function logAdminAction(entry) {
|
|
12
|
+
logger.info('Admin action', entry);
|
|
13
|
+
auditQueue.push(entry);
|
|
14
|
+
if (!flushTimer) {
|
|
15
|
+
flushTimer = setTimeout(flushAuditQueue, 5000);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function flushAuditQueue() {
|
|
19
|
+
flushTimer = null;
|
|
20
|
+
const batch = auditQueue.splice(0, auditQueue.length);
|
|
21
|
+
if (batch.length === 0)
|
|
22
|
+
return;
|
|
23
|
+
// Batch will be persisted when a DB writer is registered
|
|
24
|
+
for (const entry of batch) {
|
|
25
|
+
logger.debug('Audit entry queued', { action: entry.action, target: entry.targetType });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function getAuditQueue() {
|
|
29
|
+
return [...auditQueue];
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRtaW4tYXVkaXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvYWRtaW4tYXVkaXQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBcUJ0Qyx3Q0FNQztBQVlELHNDQUVDO0FBdkNELDRDQUErQztBQUUvQyxNQUFNLE1BQU0sR0FBRyxJQUFBLHFCQUFZLEVBQUMsYUFBYSxDQUFDLENBQUM7QUFjM0MsTUFBTSxVQUFVLEdBQWlCLEVBQUUsQ0FBQztBQUNwQyxJQUFJLFVBQVUsR0FBeUMsSUFBSSxDQUFDO0FBRTVELFNBQWdCLGNBQWMsQ0FBQyxLQUFpQjtJQUM5QyxNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxLQUFLLENBQUMsQ0FBQztJQUNuQyxVQUFVLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3ZCLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUNoQixVQUFVLEdBQUcsVUFBVSxDQUFDLGVBQWUsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUNqRCxDQUFDO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxlQUFlO0lBQzVCLFVBQVUsR0FBRyxJQUFJLENBQUM7SUFDbEIsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3RELElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQUUsT0FBTztJQUMvQix5REFBeUQ7SUFDekQsS0FBSyxNQUFNLEtBQUssSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUMxQixNQUFNLENBQUMsS0FBSyxDQUFDLG9CQUFvQixFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBQ3pGLENBQUM7QUFDSCxDQUFDO0FBRUQsU0FBZ0IsYUFBYTtJQUMzQixPQUFPLENBQUMsR0FBRyxVQUFVLENBQUMsQ0FBQztBQUN6QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IGNyZWF0ZUxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2xvZ2dlcic7XG5cbmNvbnN0IGxvZ2dlciA9IGNyZWF0ZUxvZ2dlcignYWRtaW4tYXVkaXQnKTtcblxuZXhwb3J0IGludGVyZmFjZSBBdWRpdEVudHJ5IHtcbiAgdXNlcklkOiBzdHJpbmc7XG4gIHVzZXJFbWFpbD86IHN0cmluZztcbiAgb3JnSWQ/OiBzdHJpbmc7XG4gIGFjdGlvbjogc3RyaW5nO1xuICB0YXJnZXRUeXBlOiBzdHJpbmc7XG4gIHRhcmdldElkPzogc3RyaW5nO1xuICB0YXJnZXROYW1lPzogc3RyaW5nO1xuICBkZXRhaWw/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgaXBBZGRyZXNzPzogc3RyaW5nO1xufVxuXG5jb25zdCBhdWRpdFF1ZXVlOiBBdWRpdEVudHJ5W10gPSBbXTtcbmxldCBmbHVzaFRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiB8IG51bGwgPSBudWxsO1xuXG5leHBvcnQgZnVuY3Rpb24gbG9nQWRtaW5BY3Rpb24oZW50cnk6IEF1ZGl0RW50cnkpOiB2b2lkIHtcbiAgbG9nZ2VyLmluZm8oJ0FkbWluIGFjdGlvbicsIGVudHJ5KTtcbiAgYXVkaXRRdWV1ZS5wdXNoKGVudHJ5KTtcbiAgaWYgKCFmbHVzaFRpbWVyKSB7XG4gICAgZmx1c2hUaW1lciA9IHNldFRpbWVvdXQoZmx1c2hBdWRpdFF1ZXVlLCA1MDAwKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBmbHVzaEF1ZGl0UXVldWUoKTogUHJvbWlzZTx2b2lkPiB7XG4gIGZsdXNoVGltZXIgPSBudWxsO1xuICBjb25zdCBiYXRjaCA9IGF1ZGl0UXVldWUuc3BsaWNlKDAsIGF1ZGl0UXVldWUubGVuZ3RoKTtcbiAgaWYgKGJhdGNoLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAvLyBCYXRjaCB3aWxsIGJlIHBlcnNpc3RlZCB3aGVuIGEgREIgd3JpdGVyIGlzIHJlZ2lzdGVyZWRcbiAgZm9yIChjb25zdCBlbnRyeSBvZiBiYXRjaCkge1xuICAgIGxvZ2dlci5kZWJ1ZygnQXVkaXQgZW50cnkgcXVldWVkJywgeyBhY3Rpb246IGVudHJ5LmFjdGlvbiwgdGFyZ2V0OiBlbnRyeS50YXJnZXRUeXBlIH0pO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRBdWRpdFF1ZXVlKCk6IEF1ZGl0RW50cnlbXSB7XG4gIHJldHVybiBbLi4uYXVkaXRRdWV1ZV07XG59XG4iXX0=
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal Redis-like client interface (subset of ioredis).
|
|
3
|
+
* Services pass their own Redis client instance.
|
|
4
|
+
*/
|
|
5
|
+
export interface RedisCacheClient {
|
|
6
|
+
get(key: string): Promise<string | null>;
|
|
7
|
+
set(key: string, value: string, ...args: unknown[]): Promise<unknown>;
|
|
8
|
+
del(...keys: string[]): Promise<number>;
|
|
9
|
+
keys(pattern: string): Promise<string[]>;
|
|
10
|
+
/** SCAN-based iteration (preferred over KEYS for production). */
|
|
11
|
+
scanStream?(options: {
|
|
12
|
+
match: string;
|
|
13
|
+
count?: number;
|
|
14
|
+
}): NodeJS.ReadableStream;
|
|
15
|
+
}
|
|
16
|
+
export interface CacheConfig {
|
|
17
|
+
/** Key prefix for namespace isolation (e.g., 'plugin:', 'compliance:') */
|
|
18
|
+
prefix: string;
|
|
19
|
+
/** Default TTL in seconds */
|
|
20
|
+
defaultTtlSeconds: number;
|
|
21
|
+
/** Max entries for in-memory cache (default 1000) */
|
|
22
|
+
maxEntries?: number;
|
|
23
|
+
/** Optional Redis client — uses in-memory cache if not provided */
|
|
24
|
+
redis?: RedisCacheClient;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Cache service with get/set/del operations and automatic TTL expiry.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const cache = new CacheService({ prefix: 'plugin:', defaultTtlSeconds: 300 });
|
|
32
|
+
*
|
|
33
|
+
* // Set with default TTL
|
|
34
|
+
* await cache.set('org123:list', plugins);
|
|
35
|
+
*
|
|
36
|
+
* // Get (returns null on miss)
|
|
37
|
+
* const cached = await cache.get<Plugin[]>('org123:list');
|
|
38
|
+
*
|
|
39
|
+
* // Invalidate
|
|
40
|
+
* await cache.del('org123:list');
|
|
41
|
+
*
|
|
42
|
+
* // Invalidate by pattern
|
|
43
|
+
* await cache.invalidatePattern('org123:*');
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare class CacheService {
|
|
47
|
+
private memory;
|
|
48
|
+
private readonly prefix;
|
|
49
|
+
private readonly defaultTtlMs;
|
|
50
|
+
private readonly maxEntries;
|
|
51
|
+
private readonly redis?;
|
|
52
|
+
/** Cache metrics — tracks hits, misses, and invalidations. */
|
|
53
|
+
readonly metrics: {
|
|
54
|
+
hits: number;
|
|
55
|
+
misses: number;
|
|
56
|
+
sets: number;
|
|
57
|
+
invalidations: number;
|
|
58
|
+
};
|
|
59
|
+
constructor(config: CacheConfig);
|
|
60
|
+
private fullKey;
|
|
61
|
+
/**
|
|
62
|
+
* Get a cached value. Returns null on miss or error.
|
|
63
|
+
*/
|
|
64
|
+
get<T>(key: string): Promise<T | null>;
|
|
65
|
+
/**
|
|
66
|
+
* Set a cached value with optional TTL override.
|
|
67
|
+
*
|
|
68
|
+
* @param key - Cache key (prefix is added automatically)
|
|
69
|
+
* @param value - Value to cache (must be JSON-serializable for Redis)
|
|
70
|
+
* @param ttlSeconds - TTL override (uses default if not provided)
|
|
71
|
+
*/
|
|
72
|
+
set<T>(key: string, value: T, ttlSeconds?: number): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Delete a cached value.
|
|
75
|
+
*/
|
|
76
|
+
del(key: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Invalidate all keys matching a pattern (e.g., 'org123:*').
|
|
79
|
+
* Uses SCAN for Redis (non-blocking) with KEYS fallback, or regex for in-memory.
|
|
80
|
+
*/
|
|
81
|
+
invalidatePattern(pattern: string): Promise<number>;
|
|
82
|
+
/** Collect keys via Redis SCAN (non-blocking alternative to KEYS). */
|
|
83
|
+
private scanKeys;
|
|
84
|
+
/**
|
|
85
|
+
* Get or compute: returns cached value if available, otherwise calls the
|
|
86
|
+
* factory function, caches the result, and returns it.
|
|
87
|
+
*
|
|
88
|
+
* @param key - Cache key
|
|
89
|
+
* @param factory - Async function to compute the value on cache miss
|
|
90
|
+
* @param ttlSeconds - Optional TTL override
|
|
91
|
+
* @returns The cached or computed value
|
|
92
|
+
*/
|
|
93
|
+
getOrSet<T>(key: string, factory: () => Promise<T>, ttlSeconds?: number): Promise<T>;
|
|
94
|
+
/**
|
|
95
|
+
* Clear all entries (useful for testing).
|
|
96
|
+
*/
|
|
97
|
+
clear(): Promise<void>;
|
|
98
|
+
/** Current in-memory cache size (for diagnostics). */
|
|
99
|
+
get size(): number;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Create a cache service instance.
|
|
103
|
+
*
|
|
104
|
+
* @param prefix - Namespace prefix (e.g., 'compliance:', 'plugin:')
|
|
105
|
+
* @param defaultTtlSeconds - Default TTL in seconds (default 300 = 5 min)
|
|
106
|
+
* @param redis - Optional Redis client for cross-process caching
|
|
107
|
+
*/
|
|
108
|
+
export declare function createCacheService(prefix: string, defaultTtlSeconds?: number, redis?: RedisCacheClient): CacheService;
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.CacheService = void 0;
|
|
6
|
+
exports.createCacheService = createCacheService;
|
|
7
|
+
/**
|
|
8
|
+
* Cache service with get/set/del operations and automatic TTL expiry.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const cache = new CacheService({ prefix: 'plugin:', defaultTtlSeconds: 300 });
|
|
13
|
+
*
|
|
14
|
+
* // Set with default TTL
|
|
15
|
+
* await cache.set('org123:list', plugins);
|
|
16
|
+
*
|
|
17
|
+
* // Get (returns null on miss)
|
|
18
|
+
* const cached = await cache.get<Plugin[]>('org123:list');
|
|
19
|
+
*
|
|
20
|
+
* // Invalidate
|
|
21
|
+
* await cache.del('org123:list');
|
|
22
|
+
*
|
|
23
|
+
* // Invalidate by pattern
|
|
24
|
+
* await cache.invalidatePattern('org123:*');
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
class CacheService {
|
|
28
|
+
memory = new Map();
|
|
29
|
+
prefix;
|
|
30
|
+
defaultTtlMs;
|
|
31
|
+
maxEntries;
|
|
32
|
+
redis;
|
|
33
|
+
/** Cache metrics — tracks hits, misses, and invalidations. */
|
|
34
|
+
metrics = { hits: 0, misses: 0, sets: 0, invalidations: 0 };
|
|
35
|
+
constructor(config) {
|
|
36
|
+
this.prefix = config.prefix;
|
|
37
|
+
this.defaultTtlMs = config.defaultTtlSeconds * 1000;
|
|
38
|
+
this.maxEntries = config.maxEntries ?? 1000;
|
|
39
|
+
this.redis = config.redis;
|
|
40
|
+
}
|
|
41
|
+
fullKey(key) {
|
|
42
|
+
return `${this.prefix}${key}`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get a cached value. Returns null on miss or error.
|
|
46
|
+
*/
|
|
47
|
+
async get(key) {
|
|
48
|
+
const fk = this.fullKey(key);
|
|
49
|
+
try {
|
|
50
|
+
if (this.redis) {
|
|
51
|
+
const raw = await this.redis.get(fk);
|
|
52
|
+
if (!raw) {
|
|
53
|
+
this.metrics.misses++;
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
this.metrics.hits++;
|
|
57
|
+
return JSON.parse(raw);
|
|
58
|
+
}
|
|
59
|
+
// In-memory
|
|
60
|
+
const entry = this.memory.get(fk);
|
|
61
|
+
if (!entry) {
|
|
62
|
+
this.metrics.misses++;
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (Date.now() > entry.expiresAt) {
|
|
66
|
+
this.memory.delete(fk);
|
|
67
|
+
this.metrics.misses++;
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
this.metrics.hits++;
|
|
71
|
+
return entry.value;
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
this.metrics.misses++;
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Set a cached value with optional TTL override.
|
|
80
|
+
*
|
|
81
|
+
* @param key - Cache key (prefix is added automatically)
|
|
82
|
+
* @param value - Value to cache (must be JSON-serializable for Redis)
|
|
83
|
+
* @param ttlSeconds - TTL override (uses default if not provided)
|
|
84
|
+
*/
|
|
85
|
+
async set(key, value, ttlSeconds) {
|
|
86
|
+
const fk = this.fullKey(key);
|
|
87
|
+
const ttl = ttlSeconds ?? this.defaultTtlMs / 1000;
|
|
88
|
+
try {
|
|
89
|
+
this.metrics.sets++;
|
|
90
|
+
if (this.redis) {
|
|
91
|
+
await this.redis.set(fk, JSON.stringify(value), 'EX', ttl);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
// In-memory — evict oldest if at capacity
|
|
95
|
+
if (this.memory.size >= this.maxEntries) {
|
|
96
|
+
const firstKey = this.memory.keys().next().value;
|
|
97
|
+
if (firstKey)
|
|
98
|
+
this.memory.delete(firstKey);
|
|
99
|
+
}
|
|
100
|
+
this.memory.set(fk, {
|
|
101
|
+
value,
|
|
102
|
+
expiresAt: Date.now() + ttl * 1000,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
// Cache set failure is non-fatal
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Delete a cached value.
|
|
111
|
+
*/
|
|
112
|
+
async del(key) {
|
|
113
|
+
const fk = this.fullKey(key);
|
|
114
|
+
try {
|
|
115
|
+
if (this.redis) {
|
|
116
|
+
await this.redis.del(fk);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
this.memory.delete(fk);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Cache delete failure is non-fatal
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Invalidate all keys matching a pattern (e.g., 'org123:*').
|
|
127
|
+
* Uses SCAN for Redis (non-blocking) with KEYS fallback, or regex for in-memory.
|
|
128
|
+
*/
|
|
129
|
+
async invalidatePattern(pattern) {
|
|
130
|
+
const fp = this.fullKey(pattern);
|
|
131
|
+
try {
|
|
132
|
+
if (this.redis) {
|
|
133
|
+
const keys = this.redis.scanStream
|
|
134
|
+
? await this.scanKeys(fp)
|
|
135
|
+
: await this.redis.keys(fp);
|
|
136
|
+
if (keys.length > 0) {
|
|
137
|
+
await this.redis.del(...keys);
|
|
138
|
+
this.metrics.invalidations += keys.length;
|
|
139
|
+
}
|
|
140
|
+
return keys.length;
|
|
141
|
+
}
|
|
142
|
+
// In-memory — match glob-style pattern
|
|
143
|
+
const regex = new RegExp('^' + fp.replace(/\*/g, '.*') + '$');
|
|
144
|
+
let deleted = 0;
|
|
145
|
+
for (const key of this.memory.keys()) {
|
|
146
|
+
if (regex.test(key)) {
|
|
147
|
+
this.memory.delete(key);
|
|
148
|
+
deleted++;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
this.metrics.invalidations += deleted;
|
|
152
|
+
return deleted;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/** Collect keys via Redis SCAN (non-blocking alternative to KEYS). */
|
|
159
|
+
scanKeys(pattern) {
|
|
160
|
+
return new Promise((resolve, reject) => {
|
|
161
|
+
const stream = this.redis.scanStream({ match: pattern, count: 100 });
|
|
162
|
+
const keys = [];
|
|
163
|
+
stream.on('data', (batch) => keys.push(...batch));
|
|
164
|
+
stream.once('end', () => resolve(keys));
|
|
165
|
+
stream.once('error', reject);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get or compute: returns cached value if available, otherwise calls the
|
|
170
|
+
* factory function, caches the result, and returns it.
|
|
171
|
+
*
|
|
172
|
+
* @param key - Cache key
|
|
173
|
+
* @param factory - Async function to compute the value on cache miss
|
|
174
|
+
* @param ttlSeconds - Optional TTL override
|
|
175
|
+
* @returns The cached or computed value
|
|
176
|
+
*/
|
|
177
|
+
async getOrSet(key, factory, ttlSeconds) {
|
|
178
|
+
const cached = await this.get(key);
|
|
179
|
+
if (cached !== null)
|
|
180
|
+
return cached;
|
|
181
|
+
const value = await factory();
|
|
182
|
+
await this.set(key, value, ttlSeconds);
|
|
183
|
+
return value;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Clear all entries (useful for testing).
|
|
187
|
+
*/
|
|
188
|
+
async clear() {
|
|
189
|
+
if (this.redis) {
|
|
190
|
+
await this.invalidatePattern('*');
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
this.memory.clear();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/** Current in-memory cache size (for diagnostics). */
|
|
197
|
+
get size() {
|
|
198
|
+
return this.memory.size;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
exports.CacheService = CacheService;
|
|
202
|
+
/**
|
|
203
|
+
* Create a cache service instance.
|
|
204
|
+
*
|
|
205
|
+
* @param prefix - Namespace prefix (e.g., 'compliance:', 'plugin:')
|
|
206
|
+
* @param defaultTtlSeconds - Default TTL in seconds (default 300 = 5 min)
|
|
207
|
+
* @param redis - Optional Redis client for cross-process caching
|
|
208
|
+
*/
|
|
209
|
+
function createCacheService(prefix, defaultTtlSeconds = 300, redis) {
|
|
210
|
+
return new CacheService({ prefix, defaultTtlSeconds, redis });
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUtc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zZXJ2aWNlcy9jYWNoZS1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSwrQ0FBK0M7QUFDL0Msc0NBQXNDOzs7QUFpUXRDLGdEQU1DO0FBdk5EOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBbUJHO0FBQ0gsTUFBYSxZQUFZO0lBQ2YsTUFBTSxHQUFHLElBQUksR0FBRyxFQUErQixDQUFDO0lBQ3ZDLE1BQU0sQ0FBUztJQUNmLFlBQVksQ0FBUztJQUNyQixVQUFVLENBQVM7SUFDbkIsS0FBSyxDQUFvQjtJQUUxQyw4REFBOEQ7SUFDckQsT0FBTyxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLEVBQUUsYUFBYSxFQUFFLENBQUMsRUFBRSxDQUFDO0lBRXJFLFlBQVksTUFBbUI7UUFDN0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzVCLElBQUksQ0FBQyxZQUFZLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixHQUFHLElBQUksQ0FBQztRQUNwRCxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDO1FBQzVDLElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQztJQUM1QixDQUFDO0lBRU8sT0FBTyxDQUFDLEdBQVc7UUFDekIsT0FBTyxHQUFHLElBQUksQ0FBQyxNQUFNLEdBQUcsR0FBRyxFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLEdBQUcsQ0FBSSxHQUFXO1FBQ3RCLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFN0IsSUFBSSxDQUFDO1lBQ0gsSUFBSSxJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7Z0JB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TUFBTSxJQUFJLENBQUMsR0FBRyxDQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQ3RDLElBQUksTUFBTSxLQUFLLElBQUk7WUFBRSxPQUFPLE1BQU0sQ0FBQztRQUVuQyxNQUFNLEtBQUssR0FBRyxNQUFNLE9BQU8sRUFBRSxDQUFDO1FBQzlCLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ3ZDLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLEtBQUs7UUFDVCxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNmLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3BDLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUN0QixDQUFDO0lBQ0gsQ0FBQztJQUVELHNEQUFzRDtJQUN0RCxJQUFJLElBQUk7UUFDTixPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO0lBQzFCLENBQUM7Q0FDRjtBQXBMRCxvQ0FvTEM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFnQixrQkFBa0IsQ0FDaEMsTUFBYyxFQUNkLGlCQUFpQixHQUFHLEdBQUcsRUFDdkIsS0FBd0I7SUFFeEIsT0FBTyxJQUFJLFlBQVksQ0FBQyxFQUFFLE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxLQUFLLEVBQUUsQ0FBQyxDQUFDO0FBQ2hFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgMjAyNiBQaXBlbGluZSBCdWlsZGVyIENvbnRyaWJ1dG9yc1xuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBMaWdodHdlaWdodCBjYWNoaW5nIHNlcnZpY2Ugd2l0aCBUVEwgc3VwcG9ydC5cbiAqXG4gKiBUd28gaW1wbGVtZW50YXRpb25zOlxuICogLSBJbi1tZW1vcnkgKGRlZmF1bHQpOiBMUlUtc3R5bGUgTWFwIGNhY2hlLCBubyBleHRlcm5hbCBkZXBlbmRlbmNpZXNcbiAqIC0gUmVkaXM6IFdoZW4gYSBSZWRpcyBjbGllbnQgaXMgcHJvdmlkZWQsIHVzZXMgUmVkaXMgZm9yIGNyb3NzLXByb2Nlc3MgY2FjaGluZ1xuICpcbiAqIERlc2lnbjpcbiAqIC0gQWxsIG9wZXJhdGlvbnMgYXJlIGZhaWwtc2FmZTogY2FjaGUgbWlzc2VzL2Vycm9ycyByZXR1cm4gbnVsbCwgbmV2ZXIgdGhyb3dcbiAqIC0gSlNPTiBzZXJpYWxpemF0aW9uIGZvciBSZWRpczsgZGlyZWN0IHJlZmVyZW5jZSBmb3IgaW4tbWVtb3J5XG4gKiAtIEtleSBuYW1lc3BhY2UgcHJlZml4aW5nIHRvIGF2b2lkIGNvbGxpc2lvbnMgYmV0d2VlbiBzZXJ2aWNlc1xuICovXG5cblxuLyoqXG4gKiBDYWNoZSBlbnRyeSB3aXRoIHZhbHVlIGFuZCBleHBpcmF0aW9uIHRpbWUuXG4gKi9cbmludGVyZmFjZSBDYWNoZUVudHJ5PFQ+IHtcbiAgdmFsdWU6IFQ7XG4gIGV4cGlyZXNBdDogbnVtYmVyOyAvLyBVbml4IHRpbWVzdGFtcCBpbiBtc1xufVxuXG4vKipcbiAqIE1pbmltYWwgUmVkaXMtbGlrZSBjbGllbnQgaW50ZXJmYWNlIChzdWJzZXQgb2YgaW9yZWRpcykuXG4gKiBTZXJ2aWNlcyBwYXNzIHRoZWlyIG93biBSZWRpcyBjbGllbnQgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVkaXNDYWNoZUNsaWVudCB7XG4gIGdldChrZXk6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD47XG4gIHNldChrZXk6IHN0cmluZywgdmFsdWU6IHN0cmluZywgLi4uYXJnczogdW5rbm93bltdKTogUHJvbWlzZTx1bmtub3duPjtcbiAgZGVsKC4uLmtleXM6IHN0cmluZ1tdKTogUHJvbWlzZTxudW1iZXI+O1xuICBrZXlzKHBhdHRlcm46IHN0cmluZyk6IFByb21pc2U8c3RyaW5nW10+O1xuICAvKiogU0NBTi1iYXNlZCBpdGVyYXRpb24gKHByZWZlcnJlZCBvdmVyIEtFWVMgZm9yIHByb2R1Y3Rpb24pLiAqL1xuICBzY2FuU3RyZWFtPyhvcHRpb25zOiB7IG1hdGNoOiBzdHJpbmc7IGNvdW50PzogbnVtYmVyIH0pOiBOb2RlSlMuUmVhZGFibGVTdHJlYW07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2FjaGVDb25maWcge1xuICAvKiogS2V5IHByZWZpeCBmb3IgbmFtZXNwYWNlIGlzb2xhdGlvbiAoZS5nLiwgJ3BsdWdpbjonLCAnY29tcGxpYW5jZTonKSAqL1xuICBwcmVmaXg6IHN0cmluZztcbiAgLyoqIERlZmF1bHQgVFRMIGluIHNlY29uZHMgKi9cbiAgZGVmYXVsdFR0bFNlY29uZHM6IG51bWJlcjtcbiAgLyoqIE1heCBlbnRyaWVzIGZvciBpbi1tZW1vcnkgY2FjaGUgKGRlZmF1bHQgMTAwMCkgKi9cbiAgbWF4RW50cmllcz86IG51bWJlcjtcbiAgLyoqIE9wdGlvbmFsIFJlZGlzIGNsaWVudCDigJQgdXNlcyBpbi1tZW1vcnkgY2FjaGUgaWYgbm90IHByb3ZpZGVkICovXG4gIHJlZGlzPzogUmVkaXNDYWNoZUNsaWVudDtcbn1cblxuLyoqXG4gKiBDYWNoZSBzZXJ2aWNlIHdpdGggZ2V0L3NldC9kZWwgb3BlcmF0aW9ucyBhbmQgYXV0b21hdGljIFRUTCBleHBpcnkuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIGNvbnN0IGNhY2hlID0gbmV3IENhY2hlU2VydmljZSh7IHByZWZpeDogJ3BsdWdpbjonLCBkZWZhdWx0VHRsU2Vjb25kczogMzAwIH0pO1xuICpcbiAqIC8vIFNldCB3aXRoIGRlZmF1bHQgVFRMXG4gKiBhd2FpdCBjYWNoZS5zZXQoJ29yZzEyMzpsaXN0JywgcGx1Z2lucyk7XG4gKlxuICogLy8gR2V0IChyZXR1cm5zIG51bGwgb24gbWlzcylcbiAqIGNvbnN0IGNhY2hlZCA9IGF3YWl0IGNhY2hlLmdldDxQbHVnaW5bXT4oJ29yZzEyMzpsaXN0Jyk7XG4gKlxuICogLy8gSW52YWxpZGF0ZVxuICogYXdhaXQgY2FjaGUuZGVsKCdvcmcxMjM6bGlzdCcpO1xuICpcbiAqIC8vIEludmFsaWRhdGUgYnkgcGF0dGVyblxuICogYXdhaXQgY2FjaGUuaW52YWxpZGF0ZVBhdHRlcm4oJ29yZzEyMzoqJyk7XG4gKiBgYGBcbiAqL1xuZXhwb3J0IGNsYXNzIENhY2hlU2VydmljZSB7XG4gIHByaXZhdGUgbWVtb3J5ID0gbmV3IE1hcDxzdHJpbmcsIENhY2hlRW50cnk8dW5rbm93bj4+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgcHJlZml4OiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVmYXVsdFR0bE1zOiBudW1iZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgbWF4RW50cmllczogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZGlzPzogUmVkaXNDYWNoZUNsaWVudDtcblxuICAvKiogQ2FjaGUgbWV0cmljcyDigJQgdHJhY2tzIGhpdHMsIG1pc3NlcywgYW5kIGludmFsaWRhdGlvbnMuICovXG4gIHJlYWRvbmx5IG1ldHJpY3MgPSB7IGhpdHM6IDAsIG1pc3NlczogMCwgc2V0czogMCwgaW52YWxpZGF0aW9uczogMCB9O1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZzogQ2FjaGVDb25maWcpIHtcbiAgICB0aGlzLnByZWZpeCA9IGNvbmZpZy5wcmVmaXg7XG4gICAgdGhpcy5kZWZhdWx0VHRsTXMgPSBjb25maWcuZGVmYXVsdFR0bFNlY29uZHMgKiAxMDAwO1xuICAgIHRoaXMubWF4RW50cmllcyA9IGNvbmZpZy5tYXhFbnRyaWVzID8/IDEwMDA7XG4gICAgdGhpcy5yZWRpcyA9IGNvbmZpZy5yZWRpcztcbiAgfVxuXG4gIHByaXZhdGUgZnVsbEtleShrZXk6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke3RoaXMucHJlZml4fSR7a2V5fWA7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgY2FjaGVkIHZhbHVlLiBSZXR1cm5zIG51bGwgb24gbWlzcyBvciBlcnJvci5cbiAgICovXG4gIGFzeW5jIGdldDxUPihrZXk6IHN0cmluZyk6IFByb21pc2U8VCB8IG51bGw+IHtcbiAgICBjb25zdCBmayA9IHRoaXMuZnVsbEtleShrZXkpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGlmICh0aGlzLnJlZGlzKSB7XG4gICAgICAgIGNvbnN0IHJhdyA9IGF3YWl0IHRoaXMucmVkaXMuZ2V0KGZrKTtcbiAgICAgICAgaWYgKCFyYXcpIHsgdGhpcy5tZXRyaWNzLm1pc3NlcysrOyByZXR1cm4gbnVsbDsgfVxuICAgICAgICB0aGlzLm1ldHJpY3MuaGl0cysrO1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyYXcpIGFzIFQ7XG4gICAgICB9XG5cbiAgICAgIC8vIEluLW1lbW9yeVxuICAgICAgY29uc3QgZW50cnkgPSB0aGlzLm1lbW9yeS5nZXQoZmspO1xuICAgICAgaWYgKCFlbnRyeSkgeyB0aGlzLm1ldHJpY3MubWlzc2VzKys7IHJldHVybiBudWxsOyB9XG4gICAgICBpZiAoRGF0ZS5ub3coKSA+IGVudHJ5LmV4cGlyZXNBdCkge1xuICAgICAgICB0aGlzLm1lbW9yeS5kZWxldGUoZmspO1xuICAgICAgICB0aGlzLm1ldHJpY3MubWlzc2VzKys7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuICAgICAgdGhpcy5tZXRyaWNzLmhpdHMrKztcbiAgICAgIHJldHVybiBlbnRyeS52YWx1ZSBhcyBUO1xuICAgIH0gY2F0Y2gge1xuICAgICAgdGhpcy5tZXRyaWNzLm1pc3NlcysrO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNldCBhIGNhY2hlZCB2YWx1ZSB3aXRoIG9wdGlvbmFsIFRUTCBvdmVycmlkZS5cbiAgICpcbiAgICogQHBhcmFtIGtleSAtIENhY2hlIGtleSAocHJlZml4IGlzIGFkZGVkIGF1dG9tYXRpY2FsbHkpXG4gICAqIEBwYXJhbSB2YWx1ZSAtIFZhbHVlIHRvIGNhY2hlIChtdXN0IGJlIEpTT04tc2VyaWFsaXphYmxlIGZvciBSZWRpcylcbiAgICogQHBhcmFtIHR0bFNlY29uZHMgLSBUVEwgb3ZlcnJpZGUgKHVzZXMgZGVmYXVsdCBpZiBub3QgcHJvdmlkZWQpXG4gICAqL1xuICBhc3luYyBzZXQ8VD4oa2V5OiBzdHJpbmcsIHZhbHVlOiBULCB0dGxTZWNvbmRzPzogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZmsgPSB0aGlzLmZ1bGxLZXkoa2V5KTtcbiAgICBjb25zdCB0dGwgPSB0dGxTZWNvbmRzID8/IHRoaXMuZGVmYXVsdFR0bE1zIC8gMTAwMDtcblxuICAgIHRyeSB7XG4gICAgICB0aGlzLm1ldHJpY3Muc2V0cysrO1xuICAgICAgaWYgKHRoaXMucmVkaXMpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5yZWRpcy5zZXQoZmssIEpTT04uc3RyaW5naWZ5KHZhbHVlKSwgJ0VYJywgdHRsKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyBJbi1tZW1vcnkg4oCUIGV2aWN0IG9sZGVzdCBpZiBhdCBjYXBhY2l0eVxuICAgICAgaWYgKHRoaXMubWVtb3J5LnNpemUgPj0gdGhpcy5tYXhFbnRyaWVzKSB7XG4gICAgICAgIGNvbnN0IGZpcnN0S2V5ID0gdGhpcy5tZW1vcnkua2V5cygpLm5leHQoKS52YWx1ZTtcbiAgICAgICAgaWYgKGZpcnN0S2V5KSB0aGlzLm1lbW9yeS5kZWxldGUoZmlyc3RLZXkpO1xuICAgICAgfVxuXG4gICAgICB0aGlzLm1lbW9yeS5zZXQoZmssIHtcbiAgICAgICAgdmFsdWUsXG4gICAgICAgIGV4cGlyZXNBdDogRGF0ZS5ub3coKSArIHR0bCAqIDEwMDAsXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIENhY2hlIHNldCBmYWlsdXJlIGlzIG5vbi1mYXRhbFxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgYSBjYWNoZWQgdmFsdWUuXG4gICAqL1xuICBhc3luYyBkZWwoa2V5OiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBmayA9IHRoaXMuZnVsbEtleShrZXkpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGlmICh0aGlzLnJlZGlzKSB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVkaXMuZGVsKGZrKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgdGhpcy5tZW1vcnkuZGVsZXRlKGZrKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIENhY2hlIGRlbGV0ZSBmYWlsdXJlIGlzIG5vbi1mYXRhbFxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZhbGlkYXRlIGFsbCBrZXlzIG1hdGNoaW5nIGEgcGF0dGVybiAoZS5nLiwgJ29yZzEyMzoqJykuXG4gICAqIFVzZXMgU0NBTiBmb3IgUmVkaXMgKG5vbi1ibG9ja2luZykgd2l0aCBLRVlTIGZhbGxiYWNrLCBvciByZWdleCBmb3IgaW4tbWVtb3J5LlxuICAgKi9cbiAgYXN5bmMgaW52YWxpZGF0ZVBhdHRlcm4ocGF0dGVybjogc3RyaW5nKTogUHJvbWlzZTxudW1iZXI+IHtcbiAgICBjb25zdCBmcCA9IHRoaXMuZnVsbEtleShwYXR0ZXJuKTtcblxuICAgIHRyeSB7XG4gICAgICBpZiAodGhpcy5yZWRpcykge1xuICAgICAgICBjb25zdCBrZXlzID0gdGhpcy5yZWRpcy5zY2FuU3RyZWFtXG4gICAgICAgICAgPyBhd2FpdCB0aGlzLnNjYW5LZXlzKGZwKVxuICAgICAgICAgIDogYXdhaXQgdGhpcy5yZWRpcy5rZXlzKGZwKTtcbiAgICAgICAgaWYgKGtleXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGF3YWl0IHRoaXMucmVkaXMuZGVsKC4uLmtleXMpO1xuICAgICAgICAgIHRoaXMubWV0cmljcy5pbnZhbGlkYXRpb25zICs9IGtleXMubGVuZ3RoO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBrZXlzLmxlbmd0aDtcbiAgICAgIH1cblxuICAgICAgLy8gSW4tbWVtb3J5IOKAlCBtYXRjaCBnbG9iLXN0eWxlIHBhdHRlcm5cbiAgICAgIGNvbnN0IHJlZ2V4ID0gbmV3IFJlZ0V4cCgnXicgKyBmcC5yZXBsYWNlKC9cXCovZywgJy4qJykgKyAnJCcpO1xuICAgICAgbGV0IGRlbGV0ZWQgPSAwO1xuICAgICAgZm9yIChjb25zdCBrZXkgb2YgdGhpcy5tZW1vcnkua2V5cygpKSB7XG4gICAgICAgIGlmIChyZWdleC50ZXN0KGtleSkpIHtcbiAgICAgICAgICB0aGlzLm1lbW9yeS5kZWxldGUoa2V5KTtcbiAgICAgICAgICBkZWxldGVkKys7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRoaXMubWV0cmljcy5pbnZhbGlkYXRpb25zICs9IGRlbGV0ZWQ7XG4gICAgICByZXR1cm4gZGVsZXRlZDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBDb2xsZWN0IGtleXMgdmlhIFJlZGlzIFNDQU4gKG5vbi1ibG9ja2luZyBhbHRlcm5hdGl2ZSB0byBLRVlTKS4gKi9cbiAgcHJpdmF0ZSBzY2FuS2V5cyhwYXR0ZXJuOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IHN0cmVhbSA9IHRoaXMucmVkaXMhLnNjYW5TdHJlYW0hKHsgbWF0Y2g6IHBhdHRlcm4sIGNvdW50OiAxMDAgfSk7XG4gICAgICBjb25zdCBrZXlzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgc3RyZWFtLm9uKCdkYXRhJywgKGJhdGNoOiBzdHJpbmdbXSkgPT4ga2V5cy5wdXNoKC4uLmJhdGNoKSk7XG4gICAgICBzdHJlYW0ub25jZSgnZW5kJywgKCkgPT4gcmVzb2x2ZShrZXlzKSk7XG4gICAgICBzdHJlYW0ub25jZSgnZXJyb3InLCByZWplY3QpO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBvciBjb21wdXRlOiByZXR1cm5zIGNhY2hlZCB2YWx1ZSBpZiBhdmFpbGFibGUsIG90aGVyd2lzZSBjYWxscyB0aGVcbiAgICogZmFjdG9yeSBmdW5jdGlvbiwgY2FjaGVzIHRoZSByZXN1bHQsIGFuZCByZXR1cm5zIGl0LlxuICAgKlxuICAgKiBAcGFyYW0ga2V5IC0gQ2FjaGUga2V5XG4gICAqIEBwYXJhbSBmYWN0b3J5IC0gQXN5bmMgZnVuY3Rpb24gdG8gY29tcHV0ZSB0aGUgdmFsdWUgb24gY2FjaGUgbWlzc1xuICAgKiBAcGFyYW0gdHRsU2Vjb25kcyAtIE9wdGlvbmFsIFRUTCBvdmVycmlkZVxuICAgKiBAcmV0dXJucyBUaGUgY2FjaGVkIG9yIGNvbXB1dGVkIHZhbHVlXG4gICAqL1xuICBhc3luYyBnZXRPclNldDxUPihrZXk6IHN0cmluZywgZmFjdG9yeTogKCkgPT4gUHJvbWlzZTxUPiwgdHRsU2Vjb25kcz86IG51bWJlcik6IFByb21pc2U8VD4ge1xuICAgIGNvbnN0IGNhY2hlZCA9IGF3YWl0IHRoaXMuZ2V0PFQ+KGtleSk7XG4gICAgaWYgKGNhY2hlZCAhPT0gbnVsbCkgcmV0dXJuIGNhY2hlZDtcblxuICAgIGNvbnN0IHZhbHVlID0gYXdhaXQgZmFjdG9yeSgpO1xuICAgIGF3YWl0IHRoaXMuc2V0KGtleSwgdmFsdWUsIHR0bFNlY29uZHMpO1xuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhciBhbGwgZW50cmllcyAodXNlZnVsIGZvciB0ZXN0aW5nKS5cbiAgICovXG4gIGFzeW5jIGNsZWFyKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLnJlZGlzKSB7XG4gICAgICBhd2FpdCB0aGlzLmludmFsaWRhdGVQYXR0ZXJuKCcqJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubWVtb3J5LmNsZWFyKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqIEN1cnJlbnQgaW4tbWVtb3J5IGNhY2hlIHNpemUgKGZvciBkaWFnbm9zdGljcykuICovXG4gIGdldCBzaXplKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMubWVtb3J5LnNpemU7XG4gIH1cbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBjYWNoZSBzZXJ2aWNlIGluc3RhbmNlLlxuICpcbiAqIEBwYXJhbSBwcmVmaXggLSBOYW1lc3BhY2UgcHJlZml4IChlLmcuLCAnY29tcGxpYW5jZTonLCAncGx1Z2luOicpXG4gKiBAcGFyYW0gZGVmYXVsdFR0bFNlY29uZHMgLSBEZWZhdWx0IFRUTCBpbiBzZWNvbmRzIChkZWZhdWx0IDMwMCA9IDUgbWluKVxuICogQHBhcmFtIHJlZGlzIC0gT3B0aW9uYWwgUmVkaXMgY2xpZW50IGZvciBjcm9zcy1wcm9jZXNzIGNhY2hpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNhY2hlU2VydmljZShcbiAgcHJlZml4OiBzdHJpbmcsXG4gIGRlZmF1bHRUdGxTZWNvbmRzID0gMzAwLFxuICByZWRpcz86IFJlZGlzQ2FjaGVDbGllbnQsXG4pOiBDYWNoZVNlcnZpY2Uge1xuICByZXR1cm4gbmV3IENhY2hlU2VydmljZSh7IHByZWZpeCwgZGVmYXVsdFR0bFNlY29uZHMsIHJlZGlzIH0pO1xufVxuIl19
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ServiceConfig } from '../types/common';
|
|
2
|
+
/**
|
|
3
|
+
* Result of a compliance validation check.
|
|
4
|
+
*/
|
|
5
|
+
export interface ComplianceCheckResult {
|
|
6
|
+
passed: boolean;
|
|
7
|
+
violations: ComplianceViolation[];
|
|
8
|
+
warnings: ComplianceViolation[];
|
|
9
|
+
blocked: boolean;
|
|
10
|
+
rulesEvaluated: number;
|
|
11
|
+
rulesSkipped: number;
|
|
12
|
+
exemptionsApplied: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface ComplianceViolation {
|
|
15
|
+
ruleId: string;
|
|
16
|
+
ruleName: string;
|
|
17
|
+
policyId?: string | null;
|
|
18
|
+
field: string;
|
|
19
|
+
operator: string;
|
|
20
|
+
expectedValue: unknown;
|
|
21
|
+
actualValue: unknown;
|
|
22
|
+
severity: string;
|
|
23
|
+
message: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Compliance service client interface.
|
|
27
|
+
* Uses fail-closed design: errors propagate to block the operation.
|
|
28
|
+
*/
|
|
29
|
+
export interface ComplianceClient {
|
|
30
|
+
/** Validate plugin attributes against org rules. Throws on service error (fail-closed). */
|
|
31
|
+
validatePlugin(orgId: string, attributes: Record<string, unknown>, authHeader: string, entityId?: string, entityName?: string, action?: string): Promise<ComplianceCheckResult>;
|
|
32
|
+
/** Validate pipeline attributes against org rules. Throws on service error (fail-closed). */
|
|
33
|
+
validatePipeline(orgId: string, attributes: Record<string, unknown>, authHeader: string, entityId?: string, entityName?: string, action?: string): Promise<ComplianceCheckResult>;
|
|
34
|
+
/** Pre-flight check for plugin (no audit, no notification). */
|
|
35
|
+
dryRunPlugin(orgId: string, attributes: Record<string, unknown>, authHeader: string): Promise<ComplianceCheckResult>;
|
|
36
|
+
/** Pre-flight check for pipeline (no audit, no notification). */
|
|
37
|
+
dryRunPipeline(orgId: string, attributes: Record<string, unknown>, authHeader: string): Promise<ComplianceCheckResult>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Create a compliance client.
|
|
41
|
+
*
|
|
42
|
+
* IMPORTANT: This client is fail-closed — if the compliance service is
|
|
43
|
+
* unreachable or returns an error, the error propagates and the calling
|
|
44
|
+
* operation (plugin upload, pipeline create) is rejected.
|
|
45
|
+
*/
|
|
46
|
+
export declare function createComplianceClient(config?: Partial<ServiceConfig>): ComplianceClient;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.createComplianceClient = createComplianceClient;
|
|
6
|
+
const http_client_1 = require("./http-client");
|
|
7
|
+
const logger_1 = require("../utils/logger");
|
|
8
|
+
const logger = (0, logger_1.createLogger)('compliance-client');
|
|
9
|
+
/**
|
|
10
|
+
* When true, compliance checks are bypassed if the service is unavailable
|
|
11
|
+
* (fail-open). Default is fail-closed (errors propagate and block the operation).
|
|
12
|
+
*/
|
|
13
|
+
const COMPLIANCE_BYPASS = process.env.COMPLIANCE_BYPASS === 'true';
|
|
14
|
+
/**
|
|
15
|
+
* Return a pass-through result when COMPLIANCE_BYPASS is enabled and the
|
|
16
|
+
* compliance service is unreachable.
|
|
17
|
+
*/
|
|
18
|
+
function bypassResult(context) {
|
|
19
|
+
logger.warn('COMPLIANCE_BYPASS: Service unavailable, allowing request', context);
|
|
20
|
+
return {
|
|
21
|
+
passed: true,
|
|
22
|
+
blocked: false,
|
|
23
|
+
violations: [],
|
|
24
|
+
warnings: [{ ruleId: '', ruleName: '', field: '', operator: '', expectedValue: null, actualValue: null, severity: 'warning', message: 'Compliance check skipped (service unavailable)' }],
|
|
25
|
+
rulesEvaluated: 0,
|
|
26
|
+
rulesSkipped: 0,
|
|
27
|
+
exemptionsApplied: [],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Build common request headers for compliance calls.
|
|
32
|
+
*/
|
|
33
|
+
function buildHeaders(orgId, authHeader) {
|
|
34
|
+
const headers = {
|
|
35
|
+
'x-org-id': orgId,
|
|
36
|
+
'x-internal-service': 'true',
|
|
37
|
+
};
|
|
38
|
+
if (authHeader)
|
|
39
|
+
headers.Authorization = authHeader;
|
|
40
|
+
return headers;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Create a compliance client.
|
|
44
|
+
*
|
|
45
|
+
* IMPORTANT: This client is fail-closed — if the compliance service is
|
|
46
|
+
* unreachable or returns an error, the error propagates and the calling
|
|
47
|
+
* operation (plugin upload, pipeline create) is rejected.
|
|
48
|
+
*/
|
|
49
|
+
function createComplianceClient(config) {
|
|
50
|
+
const serviceConfig = {
|
|
51
|
+
host: config?.host ?? process.env.COMPLIANCE_SERVICE_HOST ?? 'compliance',
|
|
52
|
+
port: config?.port ?? parseInt(process.env.COMPLIANCE_SERVICE_PORT ?? '3000', 10),
|
|
53
|
+
};
|
|
54
|
+
const client = new http_client_1.InternalHttpClient(serviceConfig);
|
|
55
|
+
return {
|
|
56
|
+
async validatePlugin(orgId, attributes, authHeader, entityId, entityName, action) {
|
|
57
|
+
try {
|
|
58
|
+
const response = await client.post('/compliance/validate/plugin', { attributes, entityId, entityName, action: action ?? 'upload' }, { headers: buildHeaders(orgId, authHeader) });
|
|
59
|
+
return response.body.data;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
if (COMPLIANCE_BYPASS)
|
|
63
|
+
return bypassResult({ orgId, entityType: 'plugin', entityId, entityName });
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
async validatePipeline(orgId, attributes, authHeader, entityId, entityName, action) {
|
|
68
|
+
try {
|
|
69
|
+
const response = await client.post('/compliance/validate/pipeline', { attributes, entityId, entityName, action: action ?? 'create' }, { headers: buildHeaders(orgId, authHeader) });
|
|
70
|
+
return response.body.data;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (COMPLIANCE_BYPASS)
|
|
74
|
+
return bypassResult({ orgId, entityType: 'pipeline', entityId, entityName });
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
async dryRunPlugin(orgId, attributes, authHeader) {
|
|
79
|
+
try {
|
|
80
|
+
const response = await client.post('/compliance/validate/plugin/dry-run', { attributes }, { headers: buildHeaders(orgId, authHeader) });
|
|
81
|
+
return response.body.data;
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (COMPLIANCE_BYPASS)
|
|
85
|
+
return bypassResult({ orgId, entityType: 'plugin', dryRun: true });
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
async dryRunPipeline(orgId, attributes, authHeader) {
|
|
90
|
+
try {
|
|
91
|
+
const response = await client.post('/compliance/validate/pipeline/dry-run', { attributes }, { headers: buildHeaders(orgId, authHeader) });
|
|
92
|
+
return response.body.data;
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (COMPLIANCE_BYPASS)
|
|
96
|
+
return bypassResult({ orgId, entityType: 'pipeline', dryRun: true });
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxpYW5jZS1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmljZXMvY29tcGxpYW5jZS1jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtDQUErQztBQUMvQyxzQ0FBc0M7O0FBbUh0Qyx3REFpRUM7QUFsTEQsK0NBQW1EO0FBRW5ELDRDQUErQztBQUUvQyxNQUFNLE1BQU0sR0FBRyxJQUFBLHFCQUFZLEVBQUMsbUJBQW1CLENBQUMsQ0FBQztBQUVqRDs7O0dBR0c7QUFDSCxNQUFNLGlCQUFpQixHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLEtBQUssTUFBTSxDQUFDO0FBbUVuRTs7O0dBR0c7QUFDSCxTQUFTLFlBQVksQ0FBQyxPQUFnQztJQUNwRCxNQUFNLENBQUMsSUFBSSxDQUFDLDBEQUEwRCxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ2pGLE9BQU87UUFDTCxNQUFNLEVBQUUsSUFBSTtRQUNaLE9BQU8sRUFBRSxLQUFLO1FBQ2QsVUFBVSxFQUFFLEVBQUU7UUFDZCxRQUFRLEVBQUUsQ0FBQyxFQUFFLE1BQU0sRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsYUFBYSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLGdEQUFnRCxFQUFFLENBQUM7UUFDekwsY0FBYyxFQUFFLENBQUM7UUFDakIsWUFBWSxFQUFFLENBQUM7UUFDZixpQkFBaUIsRUFBRSxFQUFFO0tBQ3RCLENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxLQUFhLEVBQUUsVUFBa0I7SUFDckQsTUFBTSxPQUFPLEdBQTJCO1FBQ3RDLFVBQVUsRUFBRSxLQUFLO1FBQ2pCLG9CQUFvQixFQUFFLE1BQU07S0FDN0IsQ0FBQztJ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QUFDO2dCQUMxRixNQUFNLEtBQUssQ0FBQztZQUNkLENBQUM7UUFDSCxDQUFDO1FBRUQsS0FBSyxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsVUFBVSxFQUFFLFVBQVU7WUFDaEQsSUFBSSxDQUFDO2dCQUNILE1BQU0sUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDLElBQUksQ0FDaEMsdUNBQXVDLEVBQ3ZDLEVBQUUsVUFBVSxFQUFFLEVBQ2QsRUFBRSxPQUFPLEVBQUUsWUFBWSxDQUFDLEtBQUssRUFBRSxVQUFVLENBQUMsRUFBRSxDQUM3QyxDQUFDO2dCQUNGLE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFDNUIsQ0FBQztZQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7Z0JBQ2YsSUFBSSxpQkFBaUI7b0JBQUUsT0FBTyxZQUFZLENBQUMsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztnQkFDNUYsTUFBTSxLQUFLLENBQUM7WUFDZCxDQUFDO1FBQ0gsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IEludGVybmFsSHR0cENsaWVudCB9IGZyb20gJy4vaHR0cC1jbGllbnQnO1xuaW1wb3J0IHsgU2VydmljZUNvbmZpZyB9IGZyb20gJy4uL3R5cGVzL2NvbW1vbic7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXInO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2NvbXBsaWFuY2UtY2xpZW50Jyk7XG5cbi8qKlxuICogV2hlbiB0cnVlLCBjb21wbGlhbmNlIGNoZWNrcyBhcmUgYnlwYXNzZWQgaWYgdGhlIHNlcnZpY2UgaXMgdW5hdmFpbGFibGVcbiAqIChmYWlsLW9wZW4pLiBEZWZhdWx0IGlzIGZhaWwtY2xvc2VkIChlcnJvcnMgcHJvcGFnYXRlIGFuZCBibG9jayB0aGUgb3BlcmF0aW9uKS5cbiAqL1xuY29uc3QgQ09NUExJQU5DRV9CWVBBU1MgPSBwcm9jZXNzLmVudi5DT01QTElBTkNFX0JZUEFTUyA9PT0gJ3RydWUnO1xuXG4vKipcbiAqIFJlc3VsdCBvZiBhIGNvbXBsaWFuY2UgdmFsaWRhdGlvbiBjaGVjay5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBDb21wbGlhbmNlQ2hlY2tSZXN1bHQge1xuICBwYXNzZWQ6IGJvb2xlYW47XG4gIHZpb2xhdGlvbnM6IENvbXBsaWFuY2VWaW9sYXRpb25bXTtcbiAgd2FybmluZ3M6IENvbXBsaWFuY2VWaW9sYXRpb25bXTtcbiAgYmxvY2tlZDogYm9vbGVhbjtcbiAgcnVsZXNFdmFsdWF0ZWQ6IG51bWJlcjtcbiAgcnVsZXNTa2lwcGVkOiBudW1iZXI7XG4gIGV4ZW1wdGlvbnNBcHBsaWVkOiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb21wbGlhbmNlVmlvbGF0aW9uIHtcbiAgcnVsZUlkOiBzdHJpbmc7XG4gIHJ1bGVOYW1lOiBzdHJpbmc7XG4gIHBvbGljeUlkPzogc3RyaW5nIHwgbnVsbDtcbiAgZmllbGQ6IHN0cmluZztcbiAgb3BlcmF0b3I6IHN0cmluZztcbiAgZXhwZWN0ZWRWYWx1ZTogdW5rbm93bjtcbiAgYWN0dWFsVmFsdWU6IHVua25vd247XG4gIHNldmVyaXR5OiBzdHJpbmc7XG4gIG1lc3NhZ2U6IHN0cmluZztcbn1cblxuLyoqXG4gKiBDb21wbGlhbmNlIHNlcnZpY2UgY2xpZW50IGludGVyZmFjZS5cbiAqIFVzZXMgZmFpbC1jbG9zZWQgZGVzaWduOiBlcnJvcnMgcHJvcGFnYXRlIHRvIGJsb2NrIHRoZSBvcGVyYXRpb24uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tcGxpYW5jZUNsaWVudCB7XG4gIC8qKiBWYWxpZGF0ZSBwbHVnaW4gYXR0cmlidXRlcyBhZ2FpbnN0IG9yZyBydWxlcy4gVGhyb3dzIG9uIHNlcnZpY2UgZXJyb3IgKGZhaWwtY2xvc2VkKS4gKi9cbiAgdmFsaWRhdGVQbHVnaW4oXG4gICAgb3JnSWQ6IHN0cmluZyxcbiAgICBhdHRyaWJ1dGVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBhdXRoSGVhZGVyOiBzdHJpbmcsXG4gICAgZW50aXR5SWQ/OiBzdHJpbmcsXG4gICAgZW50aXR5TmFtZT86IHN0cmluZyxcbiAgICBhY3Rpb24/OiBzdHJpbmcsXG4gICk6IFByb21pc2U8Q29tcGxpYW5jZUNoZWNrUmVzdWx0PjtcblxuICAvKiogVmFsaWRhdGUgcGlwZWxpbmUgYXR0cmlidXRlcyBhZ2FpbnN0IG9yZyBydWxlcy4gVGhyb3dzIG9uIHNlcnZpY2UgZXJyb3IgKGZhaWwtY2xvc2VkKS4gKi9cbiAgdmFsaWRhdGVQaXBlbGluZShcbiAgICBvcmdJZDogc3RyaW5nLFxuICAgIGF0dHJpYnV0ZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgIGF1dGhIZWFkZXI6IHN0cmluZyxcbiAgICBlbnRpdHlJZD86IHN0cmluZyxcbiAgICBlbnRpdHlOYW1lPzogc3RyaW5nLFxuICAgIGFjdGlvbj86IHN0cmluZyxcbiAgKTogUHJvbWlzZTxDb21wbGlhbmNlQ2hlY2tSZXN1bHQ+O1xuXG4gIC8qKiBQcmUtZmxpZ2h0IGNoZWNrIGZvciBwbHVnaW4gKG5vIGF1ZGl0LCBubyBub3RpZmljYXRpb24pLiAqL1xuICBkcnlSdW5QbHVnaW4oXG4gICAgb3JnSWQ6IHN0cmluZyxcbiAgICBhdHRyaWJ1dGVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBhdXRoSGVhZGVyOiBzdHJpbmcsXG4gICk6IFByb21pc2U8Q29tcGxpYW5jZUNoZWNrUmVzdWx0PjtcblxuICAvKiogUHJlLWZsaWdodCBjaGVjayBmb3IgcGlwZWxpbmUgKG5vIGF1ZGl0LCBubyBub3RpZmljYXRpb24pLiAqL1xuICBkcnlSdW5QaXBlbGluZShcbiAgICBvcmdJZDogc3RyaW5nLFxuICAgIGF0dHJpYnV0ZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgIGF1dGhIZWFkZXI6IHN0cmluZyxcbiAgKTogUHJvbWlzZTxDb21wbGlhbmNlQ2hlY2tSZXN1bHQ+O1xufVxuXG4vKipcbiAqIFJldHVybiBhIHBhc3MtdGhyb3VnaCByZXN1bHQgd2hlbiBDT01QTElBTkNFX0JZUEFTUyBpcyBlbmFibGVkIGFuZCB0aGVcbiAqIGNvbXBsaWFuY2Ugc2VydmljZSBpcyB1bnJlYWNoYWJsZS5cbiAqL1xuZnVuY3Rpb24gYnlwYXNzUmVzdWx0KGNvbnRleHQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KTogQ29tcGxpYW5jZUNoZWNrUmVzdWx0IHtcbiAgbG9nZ2VyLndhcm4oJ0NPTVBMSUFOQ0VfQllQQVNTOiBTZXJ2aWNlIHVuYXZhaWxhYmxlLCBhbGxvd2luZyByZXF1ZXN0JywgY29udGV4dCk7XG4gIHJldHVybiB7XG4gICAgcGFzc2VkOiB0cnVlLFxuICAgIGJsb2NrZWQ6IGZhbHNlLFxuICAgIHZpb2xhdGlvbnM6IFtdLFxuICAgIHdhcm5pbmdzOiBbeyBydWxlSWQ6ICcnLCBydWxlTmFtZTogJycsIGZpZWxkOiAnJywgb3BlcmF0b3I6ICcnLCBleHBlY3RlZFZhbHVlOiBudWxsLCBhY3R1YWxWYWx1ZTogbnVsbCwgc2V2ZXJpdHk6ICd3YXJuaW5nJywgbWVzc2FnZTogJ0NvbXBsaWFuY2UgY2hlY2sgc2tpcHBlZCAoc2VydmljZSB1bmF2YWlsYWJsZSknIH1dLFxuICAgIHJ1bGVzRXZhbHVhdGVkOiAwLFxuICAgIHJ1bGVzU2tpcHBlZDogMCxcbiAgICBleGVtcHRpb25zQXBwbGllZDogW10sXG4gIH07XG59XG5cbi8qKlxuICogQnVpbGQgY29tbW9uIHJlcXVlc3QgaGVhZGVycyBmb3IgY29tcGxpYW5jZSBjYWxscy5cbiAqL1xuZnVuY3Rpb24gYnVpbGRIZWFkZXJzKG9yZ0lkOiBzdHJpbmcsIGF1dGhIZWFkZXI6IHN0cmluZyk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCBoZWFkZXJzOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge1xuICAgICd4LW9yZy1pZCc6IG9yZ0lkLFxuICAgICd4LWludGVybmFsLXNlcnZpY2UnOiAndHJ1ZScsXG4gIH07XG4gIGlmIChhdXRoSGVhZGVyKSBoZWFkZXJzLkF1dGhvcml6YXRpb24gPSBhdXRoSGVhZGVyO1xuICByZXR1cm4gaGVhZGVycztcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBjb21wbGlhbmNlIGNsaWVudC5cbiAqXG4gKiBJTVBPUlRBTlQ6IFRoaXMgY2xpZW50IGlzIGZhaWwtY2xvc2VkIOKAlCBpZiB0aGUgY29tcGxpYW5jZSBzZXJ2aWNlIGlzXG4gKiB1bnJlYWNoYWJsZSBvciByZXR1cm5zIGFuIGVycm9yLCB0aGUgZXJyb3IgcHJvcGFnYXRlcyBhbmQgdGhlIGNhbGxpbmdcbiAqIG9wZXJhdGlvbiAocGx1Z2luIHVwbG9hZCwgcGlwZWxpbmUgY3JlYXRlKSBpcyByZWplY3RlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUNvbXBsaWFuY2VDbGllbnQoY29uZmlnPzogUGFydGlhbDxTZXJ2aWNlQ29uZmlnPik6IENvbXBsaWFuY2VDbGllbnQge1xuICBjb25zdCBzZXJ2aWNlQ29uZmlnOiBTZXJ2aWNlQ29uZmlnID0ge1xuICAgIGhvc3Q6IGNvbmZpZz8uaG9zdCA/PyBwcm9jZXNzLmVudi5DT01QTElBTkNFX1NFUlZJQ0VfSE9TVCA/PyAnY29tcGxpYW5jZScsXG4gICAgcG9ydDogY29uZmlnPy5wb3J0ID8/IHBhcnNlSW50KHByb2Nlc3MuZW52LkNPTVBMSUFOQ0VfU0VSVklDRV9QT1JUID8/ICczMDAwJywgMTApLFxuICB9O1xuXG4gIGNvbnN0IGNsaWVudCA9IG5ldyBJbnRlcm5hbEh0dHBDbGllbnQoc2VydmljZUNvbmZpZyk7XG5cbiAgcmV0dXJuIHtcbiAgICBhc3luYyB2YWxpZGF0ZVBsdWdpbihvcmdJZCwgYXR0cmlidXRlcywgYXV0aEhlYWRlciwgZW50aXR5SWQsIGVudGl0eU5hbWUsIGFjdGlvbikge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnQucG9zdDx7IHN1Y2Nlc3M6IGJvb2xlYW47IGRhdGE6IENvbXBsaWFuY2VDaGVja1Jlc3VsdCB9PihcbiAgICAgICAgICAnL2NvbXBsaWFuY2UvdmFsaWRhdGUvcGx1Z2luJyxcbiAgICAgICAgICB7IGF0dHJpYnV0ZXMsIGVudGl0eUlkLCBlbnRpdHlOYW1lLCBhY3Rpb246IGFjdGlvbiA/PyAndXBsb2FkJyB9LFxuICAgICAgICAgIHsgaGVhZGVyczogYnVpbGRIZWFkZXJzKG9yZ0lkLCBhdXRoSGVhZGVyKSB9LFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gcmVzcG9uc2UuYm9keS5kYXRhO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKENPTVBMSUFOQ0VfQllQQVNTKSByZXR1cm4gYnlwYXNzUmVzdWx0KHsgb3JnSWQsIGVudGl0eVR5cGU6ICdwbHVnaW4nLCBlbnRpdHlJZCwgZW50aXR5TmFtZSB9KTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfSxcblxuICAgIGFzeW5jIHZhbGlkYXRlUGlwZWxpbmUob3JnSWQsIGF0dHJpYnV0ZXMsIGF1dGhIZWFkZXIsIGVudGl0eUlkLCBlbnRpdHlOYW1lLCBhY3Rpb24pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LnBvc3Q8eyBzdWNjZXNzOiBib29sZWFuOyBkYXRhOiBDb21wbGlhbmNlQ2hlY2tSZXN1bHQgfT4oXG4gICAgICAgICAgJy9jb21wbGlhbmNlL3ZhbGlkYXRlL3BpcGVsaW5lJyxcbiAgICAgICAgICB7IGF0dHJpYnV0ZXMsIGVudGl0eUlkLCBlbnRpdHlOYW1lLCBhY3Rpb246IGFjdGlvbiA/PyAnY3JlYXRlJyB9LFxuICAgICAgICAgIHsgaGVhZGVyczogYnVpbGRIZWFkZXJzKG9yZ0lkLCBhdXRoSGVhZGVyKSB9LFxuICAgICAgICApO1xuICAgICAgICByZXR1cm4gcmVzcG9uc2UuYm9keS5kYXRhO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKENPTVBMSUFOQ0VfQllQQVNTKSByZXR1cm4gYnlwYXNzUmVzdWx0KHsgb3JnSWQsIGVudGl0eVR5cGU6ICdwaXBlbGluZScsIGVudGl0eUlkLCBlbnRpdHlOYW1lIH0pO1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgYXN5bmMgZHJ5UnVuUGx1Z2luKG9yZ0lkLCBhdHRyaWJ1dGVzLCBhdXRoSGVhZGVyKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5wb3N0PHsgc3VjY2VzczogYm9vbGVhbjsgZGF0YTogQ29tcGxpYW5jZUNoZWNrUmVzdWx0IH0+KFxuICAgICAgICAgICcvY29tcGxpYW5jZS92YWxpZGF0ZS9wbHVnaW4vZHJ5LXJ1bicsXG4gICAgICAgICAgeyBhdHRyaWJ1dGVzIH0sXG4gICAgICAgICAgeyBoZWFkZXJzOiBidWlsZEhlYWRlcnMob3JnSWQsIGF1dGhIZWFkZXIpIH0sXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiByZXNwb25zZS5ib2R5LmRhdGE7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoQ09NUExJQU5DRV9CWVBBU1MpIHJldHVybiBieXBhc3NSZXN1bHQoeyBvcmdJZCwgZW50aXR5VHlwZTogJ3BsdWdpbicsIGRyeVJ1bjogdHJ1ZSB9KTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfSxcblxuICAgIGFzeW5jIGRyeVJ1blBpcGVsaW5lKG9yZ0lkLCBhdHRyaWJ1dGVzLCBhdXRoSGVhZGVyKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5wb3N0PHsgc3VjY2VzczogYm9vbGVhbjsgZGF0YTogQ29tcGxpYW5jZUNoZWNrUmVzdWx0IH0+KFxuICAgICAgICAgICcvY29tcGxpYW5jZS92YWxpZGF0ZS9waXBlbGluZS9kcnktcnVuJyxcbiAgICAgICAgICB7IGF0dHJpYnV0ZXMgfSxcbiAgICAgICAgICB7IGhlYWRlcnM6IGJ1aWxkSGVhZGVycyhvcmdJZCwgYXV0aEhlYWRlcikgfSxcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlLmJvZHkuZGF0YTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGlmIChDT01QTElBTkNFX0JZUEFTUykgcmV0dXJuIGJ5cGFzc1Jlc3VsdCh7IG9yZ0lkLCBlbnRpdHlUeXBlOiAncGlwZWxpbmUnLCBkcnlSdW46IHRydWUgfSk7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuICAgIH0sXG4gIH07XG59XG4iXX0=
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ServiceConfig } from '../types/common';
|
|
2
|
+
/**
|
|
3
|
+
* Registers an entity event subscriber that forwards events to the compliance service.
|
|
4
|
+
*
|
|
5
|
+
* Call this at service startup (in index.ts) to enable automatic compliance
|
|
6
|
+
* notification on entity mutations. Events are fire-and-forget — failures
|
|
7
|
+
* are logged but never block the original request.
|
|
8
|
+
*
|
|
9
|
+
* @param config - Optional service config override (defaults to COMPLIANCE_SERVICE_HOST/PORT env vars)
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerComplianceEventSubscriber(config?: Partial<ServiceConfig>): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Copyright 2026 Pipeline Builder Contributors
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.registerComplianceEventSubscriber = registerComplianceEventSubscriber;
|
|
6
|
+
const compliance_queue_1 = require("./compliance-queue");
|
|
7
|
+
const entity_events_1 = require("./entity-events");
|
|
8
|
+
const http_client_1 = require("./http-client");
|
|
9
|
+
const logger_1 = require("../utils/logger");
|
|
10
|
+
const logger = (0, logger_1.createLogger)('compliance-events');
|
|
11
|
+
/**
|
|
12
|
+
* Registers an entity event subscriber that forwards events to the compliance service.
|
|
13
|
+
*
|
|
14
|
+
* Call this at service startup (in index.ts) to enable automatic compliance
|
|
15
|
+
* notification on entity mutations. Events are fire-and-forget — failures
|
|
16
|
+
* are logged but never block the original request.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Optional service config override (defaults to COMPLIANCE_SERVICE_HOST/PORT env vars)
|
|
19
|
+
*/
|
|
20
|
+
function registerComplianceEventSubscriber(config) {
|
|
21
|
+
const serviceConfig = {
|
|
22
|
+
host: config?.host ?? process.env.COMPLIANCE_SERVICE_HOST ?? 'compliance',
|
|
23
|
+
port: config?.port ?? parseInt(process.env.COMPLIANCE_SERVICE_PORT ?? '3000', 10),
|
|
24
|
+
};
|
|
25
|
+
const client = new http_client_1.InternalHttpClient(serviceConfig);
|
|
26
|
+
const subscriber = {
|
|
27
|
+
async onEntityEvent(event) {
|
|
28
|
+
try {
|
|
29
|
+
await client.post('/compliance/events/entity', event, {
|
|
30
|
+
headers: { 'x-internal-service': 'true' },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
// Fire-and-forget: log and swallow. Compliance notification is non-fatal.
|
|
35
|
+
logger.warn('Failed to notify compliance service of entity event', {
|
|
36
|
+
target: event.target,
|
|
37
|
+
eventType: event.eventType,
|
|
38
|
+
entityId: event.entityId,
|
|
39
|
+
error: err instanceof Error ? err.message : String(err),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// Also enqueue for async re-validation (catches rule changes after creation)
|
|
43
|
+
void (0, compliance_queue_1.enqueueComplianceEvent)({
|
|
44
|
+
eventType: 'validate',
|
|
45
|
+
target: event.target,
|
|
46
|
+
entityId: event.entityId,
|
|
47
|
+
orgId: event.orgId,
|
|
48
|
+
userId: event.userId,
|
|
49
|
+
attributes: event.attributes,
|
|
50
|
+
timestamp: event.timestamp.toISOString(),
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
entity_events_1.entityEvents.subscribe(subscriber);
|
|
55
|
+
logger.info('Compliance event subscriber registered', {
|
|
56
|
+
host: serviceConfig.host,
|
|
57
|
+
port: serviceConfig.port,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGxpYW5jZS1ldmVudC1zdWJzY3JpYmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NlcnZpY2VzL2NvbXBsaWFuY2UtZXZlbnQtc3Vic2NyaWJlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQStDO0FBQy9DLHNDQUFzQzs7QUFtQnRDLDhFQTBDQztBQTNERCx5REFBNEQ7QUFDNUQsbURBQTZGO0FBQzdGLCtDQUFtRDtBQUVuRCw0Q0FBK0M7QUFFL0MsTUFBTSxNQUFNLEdBQUcsSUFBQSxxQkFBWSxFQUFDLG1CQUFtQixDQUFDLENBQUM7QUFFakQ7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFnQixpQ0FBaUMsQ0FBQyxNQUErQjtJQUMvRSxNQUFNLGFBQWEsR0FBa0I7UUFDbkMsSUFBSSxFQUFFLE1BQU0sRUFBRSxJQUFJLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsSUFBSSxZQUFZO1FBQ3pFLElBQUksRUFBRSxNQUFNLEVBQUUsSUFBSSxJQUFJLFFBQVEsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHVCQUF1QixJQUFJLE1BQU0sRUFBRSxFQUFFLENBQUM7S0FDbEYsQ0FBQztJQUVGLE1BQU0sTUFBTSxHQUFHLElBQUksZ0NBQWtCLENBQUMsYUFBYSxDQUFDLENBQUM7SUFFckQsTUFBTSxVQUFVLEdBQTBCO1FBQ3hDLEtBQUssQ0FBQyxhQUFhLENBQUMsS0FBa0I7WUFDcEMsSUFBSSxDQUFDO2dCQUNILE1BQU0sTUFBTSxDQUFDLElBQUksQ0FBQywyQkFBMkIsRUFBRSxLQUFLLEVBQUU7b0JBQ3BELE9BQU8sRUFBRSxFQUFFLG9CQUFvQixFQUFFLE1BQU0sRUFBRTtpQkFDMUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7Z0JBQ2IsMEVBQTBFO2dCQUMxRSxNQUFNLENBQUMsSUFBSSxDQUFDLHFEQUFxRCxFQUFFO29CQUNqRSxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU07b0JBQ3BCLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUztvQkFDMUIsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRO29CQUN4QixLQUFLLEVBQUUsR0FBRyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztpQkFDeEQsQ0FBQyxDQUFDO1lBQ0wsQ0FBQztZQUVELDZFQUE2RTtZQUM3RSxLQUFLLElBQUEseUNBQXNCLEVBQUM7Z0JBQzFCLFNBQVMsRUFBRSxVQUFVO2dCQUNyQixNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQStCO2dCQUM3QyxRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVE7Z0JBQ3hCLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSztnQkFDbEIsTUFBTSxFQUFFLEtBQUssQ0FBQyxNQUFNO2dCQUNwQixVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVU7Z0JBQzVCLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRTthQUN6QyxDQUFDLENBQUM7UUFDTCxDQUFDO0tBQ0YsQ0FBQztJQUVGLDRCQUFZLENBQUMsU0FBUyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ25DLE1BQU0sQ0FBQyxJQUFJLENBQUMsd0NBQXdDLEVBQUU7UUFDcEQsSUFBSSxFQUFFLGFBQWEsQ0FBQyxJQUFJO1FBQ3hCLElBQUksRUFBRSxhQUFhLENBQUMsSUFBSTtLQUN6QixDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IDIwMjYgUGlwZWxpbmUgQnVpbGRlciBDb250cmlidXRvcnNcbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IGVucXVldWVDb21wbGlhbmNlRXZlbnQgfSBmcm9tICcuL2NvbXBsaWFuY2UtcXVldWUnO1xuaW1wb3J0IHsgZW50aXR5RXZlbnRzLCB0eXBlIEVudGl0eUV2ZW50LCB0eXBlIEVudGl0eUV2ZW50U3Vic2NyaWJlciB9IGZyb20gJy4vZW50aXR5LWV2ZW50cyc7XG5pbXBvcnQgeyBJbnRlcm5hbEh0dHBDbGllbnQgfSBmcm9tICcuL2h0dHAtY2xpZW50JztcbmltcG9ydCB7IHR5cGUgU2VydmljZUNvbmZpZyB9IGZyb20gJy4uL3R5cGVzL2NvbW1vbic7XG5pbXBvcnQgeyBjcmVhdGVMb2dnZXIgfSBmcm9tICcuLi91dGlscy9sb2dnZXInO1xuXG5jb25zdCBsb2dnZXIgPSBjcmVhdGVMb2dnZXIoJ2NvbXBsaWFuY2UtZXZlbnRzJyk7XG5cbi8qKlxuICogUmVnaXN0ZXJzIGFuIGVudGl0eSBldmVudCBzdWJzY3JpYmVyIHRoYXQgZm9yd2FyZHMgZXZlbnRzIHRvIHRoZSBjb21wbGlhbmNlIHNlcnZpY2UuXG4gKlxuICogQ2FsbCB0aGlzIGF0IHNlcnZpY2Ugc3RhcnR1cCAoaW4gaW5kZXgudHMpIHRvIGVuYWJsZSBhdXRvbWF0aWMgY29tcGxpYW5jZVxuICogbm90aWZpY2F0aW9uIG9uIGVudGl0eSBtdXRhdGlvbnMuIEV2ZW50cyBhcmUgZmlyZS1hbmQtZm9yZ2V0IOKAlCBmYWlsdXJlc1xuICogYXJlIGxvZ2dlZCBidXQgbmV2ZXIgYmxvY2sgdGhlIG9yaWdpbmFsIHJlcXVlc3QuXG4gKlxuICogQHBhcmFtIGNvbmZpZyAtIE9wdGlvbmFsIHNlcnZpY2UgY29uZmlnIG92ZXJyaWRlIChkZWZhdWx0cyB0byBDT01QTElBTkNFX1NFUlZJQ0VfSE9TVC9QT1JUIGVudiB2YXJzKVxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJDb21wbGlhbmNlRXZlbnRTdWJzY3JpYmVyKGNvbmZpZz86IFBhcnRpYWw8U2VydmljZUNvbmZpZz4pOiB2b2lkIHtcbiAgY29uc3Qgc2VydmljZUNvbmZpZzogU2VydmljZUNvbmZpZyA9IHtcbiAgICBob3N0OiBjb25maWc/Lmhvc3QgPz8gcHJvY2Vzcy5lbnYuQ09NUExJQU5DRV9TRVJWSUNFX0hPU1QgPz8gJ2NvbXBsaWFuY2UnLFxuICAgIHBvcnQ6IGNvbmZpZz8ucG9ydCA/PyBwYXJzZUludChwcm9jZXNzLmVudi5DT01QTElBTkNFX1NFUlZJQ0VfUE9SVCA/PyAnMzAwMCcsIDEwKSxcbiAgfTtcblxuICBjb25zdCBjbGllbnQgPSBuZXcgSW50ZXJuYWxIdHRwQ2xpZW50KHNlcnZpY2VDb25maWcpO1xuXG4gIGNvbnN0IHN1YnNjcmliZXI6IEVudGl0eUV2ZW50U3Vic2NyaWJlciA9IHtcbiAgICBhc3luYyBvbkVudGl0eUV2ZW50KGV2ZW50OiBFbnRpdHlFdmVudCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgY2xpZW50LnBvc3QoJy9jb21wbGlhbmNlL2V2ZW50cy9lbnRpdHknLCBldmVudCwge1xuICAgICAgICAgIGhlYWRlcnM6IHsgJ3gtaW50ZXJuYWwtc2VydmljZSc6ICd0cnVlJyB9LFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICAvLyBGaXJlLWFuZC1mb3JnZXQ6IGxvZyBhbmQgc3dhbGxvdy4gQ29tcGxpYW5jZSBub3RpZmljYXRpb24gaXMgbm9uLWZhdGFsLlxuICAgICAgICBsb2dnZXIud2FybignRmFpbGVkIHRvIG5vdGlmeSBjb21wbGlhbmNlIHNlcnZpY2Ugb2YgZW50aXR5IGV2ZW50Jywge1xuICAgICAgICAgIHRhcmdldDogZXZlbnQudGFyZ2V0LFxuICAgICAgICAgIGV2ZW50VHlwZTogZXZlbnQuZXZlbnRUeXBlLFxuICAgICAgICAgIGVudGl0eUlkOiBldmVudC5lbnRpdHlJZCxcbiAgICAgICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6IFN0cmluZyhlcnIpLFxuICAgICAgICB9KTtcbiAgICAgIH1cblxuICAgICAgLy8gQWxzbyBlbnF1ZXVlIGZvciBhc3luYyByZS12YWxpZGF0aW9uIChjYXRjaGVzIHJ1bGUgY2hhbmdlcyBhZnRlciBjcmVhdGlvbilcbiAgICAgIHZvaWQgZW5xdWV1ZUNvbXBsaWFuY2VFdmVudCh7XG4gICAgICAgIGV2ZW50VHlwZTogJ3ZhbGlkYXRlJyxcbiAgICAgICAgdGFyZ2V0OiBldmVudC50YXJnZXQgYXMgJ3BsdWdpbicgfCAncGlwZWxpbmUnLFxuICAgICAgICBlbnRpdHlJZDogZXZlbnQuZW50aXR5SWQsXG4gICAgICAgIG9yZ0lkOiBldmVudC5vcmdJZCxcbiAgICAgICAgdXNlcklkOiBldmVudC51c2VySWQsXG4gICAgICAgIGF0dHJpYnV0ZXM6IGV2ZW50LmF0dHJpYnV0ZXMsXG4gICAgICAgIHRpbWVzdGFtcDogZXZlbnQudGltZXN0YW1wLnRvSVNPU3RyaW5nKCksXG4gICAgICB9KTtcbiAgICB9LFxuICB9O1xuXG4gIGVudGl0eUV2ZW50cy5zdWJzY3JpYmUoc3Vic2NyaWJlcik7XG4gIGxvZ2dlci5pbmZvKCdDb21wbGlhbmNlIGV2ZW50IHN1YnNjcmliZXIgcmVnaXN0ZXJlZCcsIHtcbiAgICBob3N0OiBzZXJ2aWNlQ29uZmlnLmhvc3QsXG4gICAgcG9ydDogc2VydmljZUNvbmZpZy5wb3J0LFxuICB9KTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ComplianceEvent {
|
|
2
|
+
eventType: 'validate' | 'scan' | 'notify';
|
|
3
|
+
target: 'plugin' | 'pipeline';
|
|
4
|
+
entityId: string;
|
|
5
|
+
orgId: string;
|
|
6
|
+
userId: string;
|
|
7
|
+
attributes: Record<string, unknown>;
|
|
8
|
+
timestamp: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function registerComplianceQueueBackend(fn: (event: ComplianceEvent) => Promise<void>): void;
|
|
11
|
+
export declare function enqueueComplianceEvent(event: ComplianceEvent): Promise<void>;
|