@llm-dev-ops/agentics-cli 1.4.87 → 1.4.89
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/dist/__tests__/api_gateway.test.d.ts +1 -0
- package/dist/__tests__/api_gateway.test.js +50 -0
- package/dist/__tests__/domain_enterprise_solution.test.d.ts +1 -0
- package/dist/__tests__/domain_enterprise_solution.test.js +50 -0
- package/dist/__tests__/health.test.d.ts +1 -0
- package/dist/__tests__/health.test.js +19 -0
- package/dist/__tests__/monitoring_alerts.test.d.ts +1 -0
- package/dist/__tests__/monitoring_alerts.test.js +50 -0
- package/dist/__tests__/ongoing_regular_stakeholder.test.d.ts +1 -0
- package/dist/__tests__/ongoing_regular_stakeholder.test.js +50 -0
- package/dist/__tests__/re_evaluate_risk.test.d.ts +1 -0
- package/dist/__tests__/re_evaluate_risk.test.js +50 -0
- package/dist/__tests__/recommendation.test.d.ts +1 -0
- package/dist/__tests__/recommendation.test.js +50 -0
- package/dist/__tests__/risk_mitigation_plan.test.d.ts +1 -0
- package/dist/__tests__/risk_mitigation_plan.test.js +50 -0
- package/dist/__tests__/scoped_pilot_reduce.test.d.ts +1 -0
- package/dist/__tests__/scoped_pilot_reduce.test.js +50 -0
- package/dist/__tests__/target_enterprise_system.test.d.ts +1 -0
- package/dist/__tests__/target_enterprise_system.test.js +50 -0
- package/dist/__tests__/underwriting.test.d.ts +1 -0
- package/dist/__tests__/underwriting.test.js +50 -0
- package/dist/api-gateway/infra/api-gateway-adapter.d.ts +27 -0
- package/dist/api-gateway/infra/api-gateway-adapter.js +54 -0
- package/dist/api-gateway/ports/api-gateway.d.ts +26 -0
- package/dist/api-gateway/ports/api-gateway.js +2 -0
- package/dist/contracts/contract-validation.d.ts +11 -0
- package/dist/contracts/contract-validation.js +21 -0
- package/dist/domain-enterprise-solution/infra/api-gateway-seam-adapter.d.ts +21 -0
- package/dist/domain-enterprise-solution/infra/api-gateway-seam-adapter.js +42 -0
- package/dist/domain-enterprise-solution/infra/domain-enterprise-solution-adapter.d.ts +25 -0
- package/dist/domain-enterprise-solution/infra/domain-enterprise-solution-adapter.js +47 -0
- package/dist/domain-enterprise-solution/ports/api-gateway-seam.d.ts +20 -0
- package/dist/domain-enterprise-solution/ports/api-gateway-seam.js +2 -0
- package/dist/domain-enterprise-solution/ports/domain-enterprise-solution.d.ts +24 -0
- package/dist/domain-enterprise-solution/ports/domain-enterprise-solution.js +2 -0
- package/dist/enterprise/index.d.ts +15 -0
- package/dist/enterprise/index.js +16 -0
- package/dist/erp-client/client.d.ts +42 -0
- package/dist/erp-client/client.js +235 -0
- package/dist/erp-client/mapper.d.ts +9 -0
- package/dist/erp-client/mapper.js +116 -0
- package/dist/erp-client/retry.d.ts +17 -0
- package/dist/erp-client/retry.js +74 -0
- package/dist/erp-client/types.d.ts +155 -0
- package/dist/erp-client/types.js +2 -0
- package/dist/infra/clients.d.ts +27 -0
- package/dist/infra/clients.js +16 -0
- package/dist/infra/connection-pool.d.ts +16 -0
- package/dist/infra/connection-pool.js +13 -0
- package/dist/infra/iam-helper.d.ts +1 -0
- package/dist/infra/iam-helper.js +138 -0
- package/dist/infra/telemetry.d.ts +26 -0
- package/dist/infra/telemetry.js +39 -0
- package/dist/monitoring-alerts/infra/monitoring-alerts-adapter.d.ts +25 -0
- package/dist/monitoring-alerts/infra/monitoring-alerts-adapter.js +47 -0
- package/dist/monitoring-alerts/ports/monitoring-alerts.d.ts +24 -0
- package/dist/monitoring-alerts/ports/monitoring-alerts.js +2 -0
- package/dist/ongoing-regular-stakeholder/infra/ongoing-regular-stakeholder-adapter.d.ts +25 -0
- package/dist/ongoing-regular-stakeholder/infra/ongoing-regular-stakeholder-adapter.js +47 -0
- package/dist/ongoing-regular-stakeholder/ports/ongoing-regular-stakeholder.d.ts +24 -0
- package/dist/ongoing-regular-stakeholder/ports/ongoing-regular-stakeholder.js +2 -0
- package/dist/pipeline/phase2/phase2-coordinator.d.ts.map +1 -1
- package/dist/pipeline/phase2/phase2-coordinator.js +7 -3
- package/dist/pipeline/phase2/phase2-coordinator.js.map +1 -1
- package/dist/pipeline/ruflo-phase-executor.js +1 -1
- package/dist/pipeline/ruflo-phase-executor.js.map +1 -1
- package/dist/re-evaluate-risk/infra/re-evaluate-risk-adapter.d.ts +25 -0
- package/dist/re-evaluate-risk/infra/re-evaluate-risk-adapter.js +47 -0
- package/dist/re-evaluate-risk/ports/re-evaluate-risk.d.ts +24 -0
- package/dist/re-evaluate-risk/ports/re-evaluate-risk.js +2 -0
- package/dist/recommendation/infra/recommendation-adapter.d.ts +25 -0
- package/dist/recommendation/infra/recommendation-adapter.js +47 -0
- package/dist/recommendation/ports/recommendation.d.ts +24 -0
- package/dist/recommendation/ports/recommendation.js +2 -0
- package/dist/risk-mitigation-plan/infra/risk-mitigation-plan-adapter.d.ts +25 -0
- package/dist/risk-mitigation-plan/infra/risk-mitigation-plan-adapter.js +47 -0
- package/dist/risk-mitigation-plan/ports/risk-mitigation-plan.d.ts +24 -0
- package/dist/risk-mitigation-plan/ports/risk-mitigation-plan.js +2 -0
- package/dist/scoped-pilot-reduce/infra/scoped-pilot-reduce-adapter.d.ts +25 -0
- package/dist/scoped-pilot-reduce/infra/scoped-pilot-reduce-adapter.js +47 -0
- package/dist/scoped-pilot-reduce/ports/scoped-pilot-reduce.d.ts +24 -0
- package/dist/scoped-pilot-reduce/ports/scoped-pilot-reduce.js +2 -0
- package/dist/server/dependencies.d.ts +178 -0
- package/dist/server/dependencies.js +321 -0
- package/dist/server/health.d.ts +2 -0
- package/dist/server/health.js +9 -0
- package/dist/server/main.d.ts +1 -0
- package/dist/server/main.js +21 -0
- package/dist/server/middleware.d.ts +4 -0
- package/dist/server/middleware.js +106 -0
- package/dist/server/routes.d.ts +5 -0
- package/dist/server/routes.js +1100 -0
- package/dist/server/schemas.d.ts +217 -0
- package/dist/server/schemas.js +185 -0
- package/dist/target-enterprise-system/infra/target-enterprise-system-adapter.d.ts +25 -0
- package/dist/target-enterprise-system/infra/target-enterprise-system-adapter.js +47 -0
- package/dist/target-enterprise-system/ports/target-enterprise-system.d.ts +24 -0
- package/dist/target-enterprise-system/ports/target-enterprise-system.js +2 -0
- package/dist/underwriting/infra/underwriting-adapter.d.ts +25 -0
- package/dist/underwriting/infra/underwriting-adapter.js +47 -0
- package/dist/underwriting/ports/underwriting.d.ts +24 -0
- package/dist/underwriting/ports/underwriting.js +2 -0
- package/docs/ecosystem.graph.json +295 -214
- package/package.json +1 -1
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Generated by Phase 4 pipeline — do not edit manually
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// PII Redaction
|
|
4
|
+
// ============================================================================
|
|
5
|
+
const PII_PATTERNS = [
|
|
6
|
+
/\b\d{3}-\d{2}-\d{4}\b/g, // SSN
|
|
7
|
+
/\b[A-Z]{2}\d{6,9}\b/g, // Passport
|
|
8
|
+
/\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g, // Credit card
|
|
9
|
+
/patient[_\s]?(?:id|name|mrn)/gi, // Patient identifiers
|
|
10
|
+
];
|
|
11
|
+
function redactPii(value) {
|
|
12
|
+
let result = value;
|
|
13
|
+
for (const pattern of PII_PATTERNS) {
|
|
14
|
+
result = result.replace(pattern, '[REDACTED]');
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
function redactObject(obj, governance) {
|
|
19
|
+
if (!governance.pii_redaction)
|
|
20
|
+
return obj;
|
|
21
|
+
const result = {};
|
|
22
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
23
|
+
if (typeof value === 'string') {
|
|
24
|
+
result[key] = redactPii(value);
|
|
25
|
+
}
|
|
26
|
+
else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
27
|
+
result[key] = redactObject(value, governance);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
result[key] = value;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// InforMapper — Domain ↔ Wire Type Translation
|
|
37
|
+
// ============================================================================
|
|
38
|
+
export class InforMapper {
|
|
39
|
+
governance;
|
|
40
|
+
constructor(governance) {
|
|
41
|
+
this.governance = governance;
|
|
42
|
+
}
|
|
43
|
+
// --------------------------------------------------------------------------
|
|
44
|
+
// Domain → Infor (outbound)
|
|
45
|
+
// --------------------------------------------------------------------------
|
|
46
|
+
toTransferOrder(domain) {
|
|
47
|
+
const wire = {
|
|
48
|
+
subsidiary: { id: '1' },
|
|
49
|
+
location: { id: domain.from_facility },
|
|
50
|
+
transferLocation: { id: domain.to_facility },
|
|
51
|
+
memo: `Transfer ${domain.sku} — priority: ${domain.priority}`,
|
|
52
|
+
item: {
|
|
53
|
+
items: [{
|
|
54
|
+
item: { id: domain.sku },
|
|
55
|
+
quantity: domain.quantity,
|
|
56
|
+
units: { id: '1' },
|
|
57
|
+
}],
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
if (this.governance.pii_redaction) {
|
|
61
|
+
return redactObject(wire, this.governance);
|
|
62
|
+
{
|
|
63
|
+
wp;
|
|
64
|
+
}
|
|
65
|
+
TransferOrder;
|
|
66
|
+
}
|
|
67
|
+
return wire;
|
|
68
|
+
}
|
|
69
|
+
toPurchaseOrder(domain) {
|
|
70
|
+
const wire = {
|
|
71
|
+
entity: { id: domain.vendor_id },
|
|
72
|
+
subsidiary: { id: '1' },
|
|
73
|
+
location: { id: domain.facility_id },
|
|
74
|
+
memo: `PO for ${domain.sku} — qty: ${domain.quantity}`,
|
|
75
|
+
item: {
|
|
76
|
+
items: [{
|
|
77
|
+
item: { id: domain.sku },
|
|
78
|
+
quantity: domain.quantity,
|
|
79
|
+
}],
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
if (this.governance.pii_redaction) {
|
|
83
|
+
return redactObject(wire, this.governance);
|
|
84
|
+
{
|
|
85
|
+
wp;
|
|
86
|
+
}
|
|
87
|
+
PurchaseOrder;
|
|
88
|
+
}
|
|
89
|
+
return wire;
|
|
90
|
+
}
|
|
91
|
+
toItemReceipt(domain, transferNsId) {
|
|
92
|
+
return {
|
|
93
|
+
createdFrom: { id: transferNsId },
|
|
94
|
+
subsidiary: { id: '1' },
|
|
95
|
+
item: {
|
|
96
|
+
items: [{
|
|
97
|
+
item: { id: domain.sku },
|
|
98
|
+
quantity: domain.quantity_received,
|
|
99
|
+
location: { id: domain.facility_id },
|
|
100
|
+
}],
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
// --------------------------------------------------------------------------
|
|
105
|
+
// Infor → Domain (inbound)
|
|
106
|
+
// --------------------------------------------------------------------------
|
|
107
|
+
fromInventoryBalance(ns) {
|
|
108
|
+
return {
|
|
109
|
+
facility_id: ns.location.id,
|
|
110
|
+
sku: ns.item.id,
|
|
111
|
+
quantity: ns.quantityAvailable,
|
|
112
|
+
unit_of_measure: 'EA',
|
|
113
|
+
last_synced_at: ns.lastModifiedDate,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface RetryConfig {
|
|
2
|
+
readonly maxAttempts: number;
|
|
3
|
+
readonly initialDelayMs: number;
|
|
4
|
+
readonly multiplier: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function withRetry<T>(fn: () => Promise<T>, config?: RetryConfig): Promise<T>;
|
|
7
|
+
export declare class CircuitBreaker {
|
|
8
|
+
private readonly threshold;
|
|
9
|
+
private readonly resetTimeoutMs;
|
|
10
|
+
private failures;
|
|
11
|
+
private openedAt;
|
|
12
|
+
constructor(threshold?: number, resetTimeoutMs?: number);
|
|
13
|
+
get state(): 'closed' | 'open' | 'half-open';
|
|
14
|
+
get isOpen(): boolean;
|
|
15
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
16
|
+
reset(): void;
|
|
17
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Generated by Phase 4 pipeline — do not edit manually
|
|
2
|
+
const DEFAULT_RETRY_CONFIG = {
|
|
3
|
+
maxAttempts: 3,
|
|
4
|
+
initialDelayMs: 1_000,
|
|
5
|
+
multiplier: 2,
|
|
6
|
+
};
|
|
7
|
+
export async function withRetry(fn, config = DEFAULT_RETRY_CONFIG) {
|
|
8
|
+
let lastError;
|
|
9
|
+
let delayMs = config.initialDelayMs;
|
|
10
|
+
for (let attempt = 1; attempt <= config.maxAttempts; attempt++) {
|
|
11
|
+
try {
|
|
12
|
+
return await fn();
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
lastError = err;
|
|
16
|
+
if (attempt < config.maxAttempts) {
|
|
17
|
+
await sleep(delayMs);
|
|
18
|
+
delayMs *= config.multiplier;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
throw lastError;
|
|
23
|
+
}
|
|
24
|
+
function sleep(ms) {
|
|
25
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
26
|
+
}
|
|
27
|
+
export class CircuitBreaker {
|
|
28
|
+
threshold;
|
|
29
|
+
resetTimeoutMs;
|
|
30
|
+
failures = 0;
|
|
31
|
+
openedAt = null;
|
|
32
|
+
constructor(threshold = 5, resetTimeoutMs = 60_000) {
|
|
33
|
+
this.threshold = threshold;
|
|
34
|
+
this.resetTimeoutMs = resetTimeoutMs;
|
|
35
|
+
}
|
|
36
|
+
get state() {
|
|
37
|
+
if (this.openedAt === null)
|
|
38
|
+
return 'closed';
|
|
39
|
+
if (Date.now() - this.openedAt >= this.resetTimeoutMs)
|
|
40
|
+
return 'half-open';
|
|
41
|
+
return 'open';
|
|
42
|
+
}
|
|
43
|
+
get isOpen() {
|
|
44
|
+
if (this.openedAt === null)
|
|
45
|
+
return false;
|
|
46
|
+
if (Date.now() - this.openedAt >= this.resetTimeoutMs) {
|
|
47
|
+
this.openedAt = null;
|
|
48
|
+
this.failures = 0;
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
async execute(fn) {
|
|
54
|
+
if (this.isOpen) {
|
|
55
|
+
throw new Error('Circuit breaker is open — ERP service unavailable');
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const result = await fn();
|
|
59
|
+
this.failures = 0;
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
this.failures++;
|
|
64
|
+
if (this.failures >= this.threshold) {
|
|
65
|
+
this.openedAt = Date.now();
|
|
66
|
+
}
|
|
67
|
+
throw err;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
reset() {
|
|
71
|
+
this.failures = 0;
|
|
72
|
+
this.openedAt = null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ERP surface types for infor.
|
|
3
|
+
* Domain types and Infor wire format types for the ACL boundary.
|
|
4
|
+
*/
|
|
5
|
+
export type ErpSystemType = 'infor';
|
|
6
|
+
export interface ErpSurfaceRequest {
|
|
7
|
+
readonly erp_type: ErpSystemType;
|
|
8
|
+
readonly operation: string;
|
|
9
|
+
readonly entity_type: string;
|
|
10
|
+
readonly query?: Record<string, unknown>;
|
|
11
|
+
readonly correlation_id: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ErpSurfaceResponse {
|
|
14
|
+
readonly id: string;
|
|
15
|
+
readonly status: number;
|
|
16
|
+
readonly message: string;
|
|
17
|
+
readonly data: unknown;
|
|
18
|
+
readonly correlation_id: string;
|
|
19
|
+
readonly timestamp: string;
|
|
20
|
+
}
|
|
21
|
+
export interface DomainTransferOrder {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly from_facility: string;
|
|
24
|
+
readonly to_facility: string;
|
|
25
|
+
readonly sku: string;
|
|
26
|
+
readonly quantity: number;
|
|
27
|
+
readonly status: string;
|
|
28
|
+
readonly priority: string;
|
|
29
|
+
}
|
|
30
|
+
export interface DomainPurchaseOrder {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly facility_id: string;
|
|
33
|
+
readonly sku: string;
|
|
34
|
+
readonly quantity: number;
|
|
35
|
+
readonly vendor_id: string;
|
|
36
|
+
readonly status: string;
|
|
37
|
+
}
|
|
38
|
+
export interface DomainInventoryBalance {
|
|
39
|
+
readonly facility_id: string;
|
|
40
|
+
readonly sku: string;
|
|
41
|
+
readonly quantity: number;
|
|
42
|
+
readonly unit_of_measure: string;
|
|
43
|
+
readonly last_synced_at: string;
|
|
44
|
+
}
|
|
45
|
+
export interface DomainItemReceipt {
|
|
46
|
+
readonly transfer_id: string;
|
|
47
|
+
readonly facility_id: string;
|
|
48
|
+
readonly sku: string;
|
|
49
|
+
readonly quantity_received: number;
|
|
50
|
+
readonly received_at: string;
|
|
51
|
+
}
|
|
52
|
+
export interface InforTransferOrder {
|
|
53
|
+
readonly subsidiary: {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
};
|
|
56
|
+
readonly location: {
|
|
57
|
+
readonly id: string;
|
|
58
|
+
};
|
|
59
|
+
readonly transferLocation: {
|
|
60
|
+
readonly id: string;
|
|
61
|
+
};
|
|
62
|
+
readonly memo?: string;
|
|
63
|
+
readonly item: {
|
|
64
|
+
readonly items: ReadonlyArray<{
|
|
65
|
+
readonly item: {
|
|
66
|
+
readonly id: string;
|
|
67
|
+
};
|
|
68
|
+
readonly quantity: number;
|
|
69
|
+
readonly units?: {
|
|
70
|
+
readonly id: string;
|
|
71
|
+
};
|
|
72
|
+
}>;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export interface InforPurchaseOrder {
|
|
76
|
+
readonly entity: {
|
|
77
|
+
readonly id: string;
|
|
78
|
+
};
|
|
79
|
+
readonly subsidiary: {
|
|
80
|
+
readonly id: string;
|
|
81
|
+
};
|
|
82
|
+
readonly location: {
|
|
83
|
+
readonly id: string;
|
|
84
|
+
};
|
|
85
|
+
readonly memo?: string;
|
|
86
|
+
readonly item: {
|
|
87
|
+
readonly items: ReadonlyArray<{
|
|
88
|
+
readonly item: {
|
|
89
|
+
readonly id: string;
|
|
90
|
+
};
|
|
91
|
+
readonly quantity: number;
|
|
92
|
+
readonly rate?: number;
|
|
93
|
+
}>;
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export interface InforInventoryBalance {
|
|
97
|
+
readonly subsidiary: {
|
|
98
|
+
readonly id: string;
|
|
99
|
+
readonly refName: string;
|
|
100
|
+
};
|
|
101
|
+
readonly location: {
|
|
102
|
+
readonly id: string;
|
|
103
|
+
readonly refName: string;
|
|
104
|
+
};
|
|
105
|
+
readonly item: {
|
|
106
|
+
readonly id: string;
|
|
107
|
+
readonly refName: string;
|
|
108
|
+
};
|
|
109
|
+
readonly quantityOnHand: number;
|
|
110
|
+
readonly quantityAvailable: number;
|
|
111
|
+
readonly lastModifiedDate: string;
|
|
112
|
+
}
|
|
113
|
+
export interface InforItemReceipt {
|
|
114
|
+
readonly createdFrom: {
|
|
115
|
+
readonly id: string;
|
|
116
|
+
};
|
|
117
|
+
readonly subsidiary: {
|
|
118
|
+
readonly id: string;
|
|
119
|
+
};
|
|
120
|
+
readonly item: {
|
|
121
|
+
readonly items: ReadonlyArray<{
|
|
122
|
+
readonly item: {
|
|
123
|
+
readonly id: string;
|
|
124
|
+
};
|
|
125
|
+
readonly quantity: number;
|
|
126
|
+
readonly location: {
|
|
127
|
+
readonly id: string;
|
|
128
|
+
};
|
|
129
|
+
}>;
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
export interface GovernanceConfig {
|
|
133
|
+
readonly read_only: boolean;
|
|
134
|
+
readonly audit_enabled: boolean;
|
|
135
|
+
readonly pii_redaction: boolean;
|
|
136
|
+
readonly max_tokens_per_request: number;
|
|
137
|
+
}
|
|
138
|
+
export interface SyncQueueEntry {
|
|
139
|
+
readonly id: string;
|
|
140
|
+
readonly operation: string;
|
|
141
|
+
readonly payload: unknown;
|
|
142
|
+
readonly created_at: string;
|
|
143
|
+
readonly retry_count: number;
|
|
144
|
+
readonly last_error: string | null;
|
|
145
|
+
}
|
|
146
|
+
export interface SyncStatus {
|
|
147
|
+
readonly last_successful_sync: string | null;
|
|
148
|
+
readonly pending_queue_depth: number;
|
|
149
|
+
readonly circuit_breaker_state: 'closed' | 'open' | 'half-open';
|
|
150
|
+
readonly recent_errors: ReadonlyArray<{
|
|
151
|
+
timestamp: string;
|
|
152
|
+
operation: string;
|
|
153
|
+
error: string;
|
|
154
|
+
}>;
|
|
155
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database client interface.
|
|
3
|
+
* Adapters depend on this abstraction — implementations are injected.
|
|
4
|
+
*/
|
|
5
|
+
export interface DbClient {
|
|
6
|
+
/** Execute a parameterized query and return rows. */
|
|
7
|
+
query(sql: string, params: unknown[]): Promise<unknown[]>;
|
|
8
|
+
/** Execute a parameterized statement (INSERT/UPDATE/DELETE). */
|
|
9
|
+
execute(sql: string, params: unknown[]): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* ERP client interface.
|
|
13
|
+
* Adapters delegate domain operations to the ERP system via this contract.
|
|
14
|
+
*/
|
|
15
|
+
export interface ErpClient {
|
|
16
|
+
/** Invoke a named ERP operation with a typed payload. */
|
|
17
|
+
invoke(operation: string, data: unknown): Promise<unknown>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Domain-specific error for adapter failures.
|
|
21
|
+
*/
|
|
22
|
+
export declare class AdapterError extends Error {
|
|
23
|
+
readonly context: string;
|
|
24
|
+
readonly operation: string;
|
|
25
|
+
readonly cause?: unknown | undefined;
|
|
26
|
+
constructor(message: string, context: string, operation: string, cause?: unknown | undefined);
|
|
27
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Generated by Phase 4 pipeline — do not edit manually
|
|
2
|
+
/**
|
|
3
|
+
* Domain-specific error for adapter failures.
|
|
4
|
+
*/
|
|
5
|
+
export class AdapterError extends Error {
|
|
6
|
+
context;
|
|
7
|
+
operation;
|
|
8
|
+
cause;
|
|
9
|
+
constructor(message, context, operation, cause) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.context = context;
|
|
12
|
+
this.operation = operation;
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
this.name = 'AdapterError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Connection Pool Configuration
|
|
3
|
+
* ERP system: infor
|
|
4
|
+
* SQL dialect: oracle-sql
|
|
5
|
+
*/
|
|
6
|
+
export interface ConnectionPoolConfig {
|
|
7
|
+
readonly host: string;
|
|
8
|
+
readonly port: number;
|
|
9
|
+
readonly database: string;
|
|
10
|
+
readonly user: string;
|
|
11
|
+
readonly password: string;
|
|
12
|
+
readonly maxConnections: number;
|
|
13
|
+
readonly idleTimeoutMs: number;
|
|
14
|
+
readonly ssl: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function buildConnectionPoolConfig(): ConnectionPoolConfig;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Generated by Phase 4 pipeline — do not edit manually
|
|
2
|
+
export function buildConnectionPoolConfig() {
|
|
3
|
+
return {
|
|
4
|
+
host: process.env['DB_HOST'] ?? 'localhost',
|
|
5
|
+
port: Number(process.env['DB_PORT'] ?? 5432),
|
|
6
|
+
database: process.env['DB_NAME'] ?? 'infor',
|
|
7
|
+
user: process.env['DB_USER'] ?? '',
|
|
8
|
+
password: process.env['DB_PASSWORD'] ?? '',
|
|
9
|
+
maxConnections: Number(process.env['DB_MAX_CONNECTIONS'] ?? 10),
|
|
10
|
+
idleTimeoutMs: Number(process.env['DB_IDLE_TIMEOUT_MS'] ?? 30000),
|
|
11
|
+
ssl: process.env['DB_SSL'] !== 'false',
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Generated by Phase 4 pipeline — do not edit manually
|
|
2
|
+
function detectProvider() {
|
|
3
|
+
return (process.env['CLOUD_PROVIDER'] ?? 'gcp').toLowerCase();
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* GCP: Fetch identity token from the metadata server.
|
|
7
|
+
*/
|
|
8
|
+
async function fetchGcpToken(audience) {
|
|
9
|
+
const url = 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity'
|
|
10
|
+
+ `?audience=${encodeURIComponent(audience)}&format=full`;
|
|
11
|
+
const response = await fetch(url, {
|
|
12
|
+
headers: { 'Metadata-Flavor': 'Google' },
|
|
13
|
+
});
|
|
14
|
+
if (!response.ok) {
|
|
15
|
+
throw new Error(`GCP metadata token request failed: HTTP ${response.status}`);
|
|
16
|
+
}
|
|
17
|
+
return response.text();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* AWS: Fetch a session token via IMDSv2 (two-step: PUT for token, then GET credentials).
|
|
21
|
+
*/
|
|
22
|
+
async function fetchAwsToken(_audience) {
|
|
23
|
+
// Step 1: Get IMDSv2 session token
|
|
24
|
+
const tokenRes = await fetch('http://169.254.169.254/latest/api/token', {
|
|
25
|
+
method: 'PUT',
|
|
26
|
+
headers: { 'X-aws-ec2-metadata-token-ttl-seconds': '300' },
|
|
27
|
+
});
|
|
28
|
+
if (!tokenRes.ok) {
|
|
29
|
+
throw new Error(`AWS IMDSv2 token request failed: HTTP ${tokenRes.status}`);
|
|
30
|
+
}
|
|
31
|
+
const imdsToken = await tokenRes.text();
|
|
32
|
+
// Step 2: Use the session token to retrieve IAM role credentials
|
|
33
|
+
const credsRes = await fetch('http://169.254.169.254/latest/meta-data/iam/security-credentials/', { headers: { 'X-aws-ec2-metadata-token': imdsToken } });
|
|
34
|
+
if (!credsRes.ok) {
|
|
35
|
+
throw new Error(`AWS IMDS credentials request failed: HTTP ${credsRes.status}`);
|
|
36
|
+
}
|
|
37
|
+
const roleName = (await credsRes.text()).trim();
|
|
38
|
+
const roleRes = await fetch();
|
|
39
|
+
`http://169.254.169.254/latest/meta-data/iam/security-credentials/\${roleName}\`,
|
|
40
|
+
{ headers: { 'X-aws-ec2-metadata-token': imdsToken } },
|
|
41
|
+
);
|
|
42
|
+
if (!roleRes.ok) {
|
|
43
|
+
throw new Error(`;
|
|
44
|
+
AWS;
|
|
45
|
+
IMDS;
|
|
46
|
+
role;
|
|
47
|
+
credentials;
|
|
48
|
+
request;
|
|
49
|
+
failed: HTTP;
|
|
50
|
+
$;
|
|
51
|
+
{
|
|
52
|
+
roleRes.status;
|
|
53
|
+
}
|
|
54
|
+
`);
|
|
55
|
+
}
|
|
56
|
+
const creds = await roleRes.json() as { Token: string };
|
|
57
|
+
return creds.Token;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Azure: Fetch an access token from the Azure Instance Metadata Service (IMDS).
|
|
62
|
+
*/
|
|
63
|
+
async function fetchAzureToken(audience: string): Promise<string> {
|
|
64
|
+
const resource = audience || 'https://management.azure.com/';
|
|
65
|
+
const url =
|
|
66
|
+
'http://169.254.169.254/metadata/identity/oauth2/token'
|
|
67
|
+
+ ` ? api - version : ;
|
|
68
|
+
2018 - 2 - 1 & resource;
|
|
69
|
+
$;
|
|
70
|
+
{
|
|
71
|
+
encodeURIComponent(resource);
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
|
|
75
|
+
const response = await fetch(url, {
|
|
76
|
+
headers: { Metadata: 'true' },
|
|
77
|
+
});
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
throw new Error(`;
|
|
80
|
+
Azure;
|
|
81
|
+
IMDS;
|
|
82
|
+
token;
|
|
83
|
+
request;
|
|
84
|
+
failed: HTTP;
|
|
85
|
+
$;
|
|
86
|
+
{
|
|
87
|
+
response.status;
|
|
88
|
+
}
|
|
89
|
+
`);
|
|
90
|
+
}
|
|
91
|
+
const body = await response.json() as { access_token: string };
|
|
92
|
+
return body.access_token;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Fetch an identity/session token for service-to-service authentication.
|
|
97
|
+
* Automatically selects the correct provider based on CLOUD_PROVIDER env var.
|
|
98
|
+
*
|
|
99
|
+
* @param audience - The target audience or resource URI for the token.
|
|
100
|
+
* @returns The bearer token string.
|
|
101
|
+
*/
|
|
102
|
+
export async function fetchIdentityToken(audience: string): Promise<string> {
|
|
103
|
+
const provider = detectProvider();
|
|
104
|
+
|
|
105
|
+
switch (provider) {
|
|
106
|
+
case 'gcp':
|
|
107
|
+
return fetchGcpToken(audience);
|
|
108
|
+
case 'aws':
|
|
109
|
+
return fetchAwsToken(audience);
|
|
110
|
+
case 'azure':
|
|
111
|
+
return fetchAzureToken(audience);
|
|
112
|
+
default: {
|
|
113
|
+
// Fallback: use AUTH_TOKEN env var for on-prem or unsupported providers
|
|
114
|
+
const token = process.env['AUTH_TOKEN'];
|
|
115
|
+
if (!token) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`;
|
|
118
|
+
No;
|
|
119
|
+
identity;
|
|
120
|
+
token;
|
|
121
|
+
available: unsupported;
|
|
122
|
+
provider;
|
|
123
|
+
"${provider}" ` +
|
|
124
|
+
`;
|
|
125
|
+
and;
|
|
126
|
+
AUTH_TOKEN;
|
|
127
|
+
env;
|
|
128
|
+
var is, not, set;
|
|
129
|
+
`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
return token;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
;
|
|
137
|
+
}
|
|
138
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenTelemetry wrapper for infrastructure adapters.
|
|
3
|
+
*
|
|
4
|
+
* Provides span creation and a convenience withSpan() helper.
|
|
5
|
+
* Self-contained — no pipeline dependencies.
|
|
6
|
+
*/
|
|
7
|
+
export interface SpanAttributes {
|
|
8
|
+
readonly [key: string]: string | number | boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface Span {
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly startTime: number;
|
|
13
|
+
end(status: 'ok' | 'error', attributes?: SpanAttributes): void;
|
|
14
|
+
}
|
|
15
|
+
export interface Telemetry {
|
|
16
|
+
createSpan(service: string, operation: string, attributes?: SpanAttributes): Span;
|
|
17
|
+
withSpan<T>(service: string, operation: string, attributes: SpanAttributes, fn: () => Promise<T>): Promise<T>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Console-based telemetry implementation.
|
|
21
|
+
* Replace with OpenTelemetry SDK integration for production.
|
|
22
|
+
*/
|
|
23
|
+
export declare class ConsoleTelemetry implements Telemetry {
|
|
24
|
+
createSpan(service: string, operation: string, attributes?: SpanAttributes): Span;
|
|
25
|
+
withSpan<T>(service: string, operation: string, attributes: SpanAttributes, fn: () => Promise<T>): Promise<T>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Generated by Phase 4 pipeline — do not edit manually
|
|
2
|
+
/**
|
|
3
|
+
* Console-based telemetry implementation.
|
|
4
|
+
* Replace with OpenTelemetry SDK integration for production.
|
|
5
|
+
*/
|
|
6
|
+
export class ConsoleTelemetry {
|
|
7
|
+
createSpan(service, operation, attributes = {}) {
|
|
8
|
+
const startTime = Date.now();
|
|
9
|
+
const name = `${service}.${operation}`;
|
|
10
|
+
return {
|
|
11
|
+
name,
|
|
12
|
+
startTime,
|
|
13
|
+
end(status, endAttrs = {}) {
|
|
14
|
+
const duration = Date.now() - startTime;
|
|
15
|
+
const level = status === 'error' ? 'error' : 'info';
|
|
16
|
+
const logFn = level === 'error' ? console.error : console.info;
|
|
17
|
+
logFn(JSON.stringify({
|
|
18
|
+
span: name,
|
|
19
|
+
status,
|
|
20
|
+
durationMs: duration,
|
|
21
|
+
...attributes,
|
|
22
|
+
...endAttrs,
|
|
23
|
+
}));
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
async withSpan(service, operation, attributes, fn) {
|
|
28
|
+
const span = this.createSpan(service, operation, attributes);
|
|
29
|
+
try {
|
|
30
|
+
const result = await fn();
|
|
31
|
+
span.end('ok');
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
span.end('error', { error: err instanceof Error ? err.message : String(err) });
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { MonitoringAlertsPort, MonitoringAlertsInput, MonitoringAlerts } from '../ports/monitoring-alerts.js';
|
|
2
|
+
import type { Telemetry } from '../../infra/telemetry.js';
|
|
3
|
+
import type { DbClient, ErpClient } from '../../infra/clients.js';
|
|
4
|
+
/**
|
|
5
|
+
* Infrastructure adapter: MonitoringAlertsAdapter
|
|
6
|
+
* Bounded context: monitoring-alerts
|
|
7
|
+
* ERP system: infor
|
|
8
|
+
*
|
|
9
|
+
* Bridges the MonitoringAlertsPort port to the infor ERP system
|
|
10
|
+
* and the underlying database client.
|
|
11
|
+
*/
|
|
12
|
+
export declare class MonitoringAlertsAdapter implements MonitoringAlertsPort {
|
|
13
|
+
private readonly db;
|
|
14
|
+
private readonly erp;
|
|
15
|
+
private readonly telemetry;
|
|
16
|
+
constructor(db: DbClient, erp: ErpClient, telemetry: Telemetry);
|
|
17
|
+
/** Creates or updates monitoring-alerts record */
|
|
18
|
+
manageMonitoringAlerts(input: MonitoringAlertsInput): Promise<MonitoringAlerts>;
|
|
19
|
+
/** Creates or updates monitoring-alerts record */
|
|
20
|
+
queryMonitoringAlerts(input: MonitoringAlertsInput): Promise<MonitoringAlerts>;
|
|
21
|
+
/** Returns monitoring-alerts data */
|
|
22
|
+
listMonitoringAlerts(input: Record<string, unknown>): Promise<MonitoringAlerts[]>;
|
|
23
|
+
/** Returns monitoring-alerts data */
|
|
24
|
+
id(input: Record<string, unknown>): Promise<MonitoringAlerts[]>;
|
|
25
|
+
}
|