@peac/telemetry 0.9.31
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/.turbo/turbo-build.log +4 -0
- package/LICENSE +190 -0
- package/README.md +116 -0
- package/dist/attributes.d.ts +58 -0
- package/dist/attributes.d.ts.map +1 -0
- package/dist/attributes.js +67 -0
- package/dist/attributes.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -0
- package/dist/noop.d.ts +15 -0
- package/dist/noop.d.ts.map +1 -0
- package/dist/noop.js +21 -0
- package/dist/noop.js.map +1 -0
- package/dist/provider.d.ts +54 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +65 -0
- package/dist/provider.js.map +1 -0
- package/dist/types.d.ts +129 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +37 -0
- package/src/attributes.ts +71 -0
- package/src/index.ts +63 -0
- package/src/noop.ts +20 -0
- package/src/provider.ts +64 -0
- package/src/types.ts +163 -0
- package/tests/attributes.test.ts +126 -0
- package/tests/noop.test.ts +109 -0
- package/tests/provider.test.ts +223 -0
- package/tests/types.test.ts +218 -0
- package/tsconfig.json +12 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +8 -0
package/dist/provider.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @peac/telemetry - Provider registry
|
|
4
|
+
*
|
|
5
|
+
* Zero-throw provider ref pattern for hot-path performance.
|
|
6
|
+
* When undefined, telemetry is disabled with NO function calls.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.providerRef = void 0;
|
|
10
|
+
exports.setTelemetryProvider = setTelemetryProvider;
|
|
11
|
+
exports.getTelemetryProvider = getTelemetryProvider;
|
|
12
|
+
exports.isTelemetryEnabled = isTelemetryEnabled;
|
|
13
|
+
/**
|
|
14
|
+
* Singleton provider reference for zero-overhead hot path.
|
|
15
|
+
*
|
|
16
|
+
* When undefined, telemetry is disabled with NO function calls
|
|
17
|
+
* beyond the initial `if (!p)` check.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // In hot path (issue/verify)
|
|
22
|
+
* const p = providerRef.current;
|
|
23
|
+
* if (p) {
|
|
24
|
+
* try {
|
|
25
|
+
* p.onReceiptIssued({ receiptHash: '...' });
|
|
26
|
+
* } catch {
|
|
27
|
+
* // Telemetry MUST NOT break core flow
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
exports.providerRef = {
|
|
33
|
+
current: undefined,
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Set the telemetry provider.
|
|
37
|
+
*
|
|
38
|
+
* Idempotent, no-throw, safe to call multiple times.
|
|
39
|
+
* Pass undefined to disable telemetry.
|
|
40
|
+
*
|
|
41
|
+
* @param provider - The provider to use, or undefined to disable
|
|
42
|
+
*/
|
|
43
|
+
function setTelemetryProvider(provider) {
|
|
44
|
+
exports.providerRef.current = provider;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get the current telemetry provider.
|
|
48
|
+
*
|
|
49
|
+
* Returns undefined if no provider is set (telemetry disabled).
|
|
50
|
+
*
|
|
51
|
+
* For hot paths, prefer direct access to `providerRef.current`
|
|
52
|
+
* to avoid the function call overhead.
|
|
53
|
+
*/
|
|
54
|
+
function getTelemetryProvider() {
|
|
55
|
+
return exports.providerRef.current;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if telemetry is enabled.
|
|
59
|
+
*
|
|
60
|
+
* Convenience function for conditional logic outside hot paths.
|
|
61
|
+
*/
|
|
62
|
+
function isTelemetryEnabled() {
|
|
63
|
+
return exports.providerRef.current !== undefined;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAmCH,oDAEC;AAUD,oDAEC;AAOD,gDAEC;AAtDD;;;;;;;;;;;;;;;;;;GAkBG;AACU,QAAA,WAAW,GAAoC;IAC1D,OAAO,EAAE,SAAS;CACnB,CAAC;AAEF;;;;;;;GAOG;AACH,SAAgB,oBAAoB,CAAC,QAAuC;IAC1E,mBAAW,CAAC,OAAO,GAAG,QAAQ,CAAC;AACjC,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,oBAAoB;IAClC,OAAO,mBAAW,CAAC,OAAO,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,SAAgB,kBAAkB;IAChC,OAAO,mBAAW,CAAC,OAAO,KAAK,SAAS,CAAC;AAC3C,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @peac/telemetry - Telemetry types and interfaces
|
|
3
|
+
*
|
|
4
|
+
* This module defines the core telemetry interfaces for PEAC protocol.
|
|
5
|
+
* These are runtime-portable and have no external dependencies.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Telemetry decision outcome
|
|
9
|
+
*/
|
|
10
|
+
export type TelemetryDecision = 'allow' | 'deny' | 'unknown';
|
|
11
|
+
/**
|
|
12
|
+
* Privacy mode for telemetry emission
|
|
13
|
+
*
|
|
14
|
+
* - strict: Hash all identifiers, emit minimal data (production default)
|
|
15
|
+
* - balanced: Hash identifiers but include rail + amounts (debugging)
|
|
16
|
+
* - custom: Use allowlist-based filtering
|
|
17
|
+
*/
|
|
18
|
+
export type PrivacyMode = 'strict' | 'balanced' | 'custom';
|
|
19
|
+
/**
|
|
20
|
+
* Telemetry configuration
|
|
21
|
+
*/
|
|
22
|
+
export interface TelemetryConfig {
|
|
23
|
+
/** Service name for resource identification */
|
|
24
|
+
serviceName: string;
|
|
25
|
+
/** Privacy mode: strict (hashes only), balanced, custom */
|
|
26
|
+
privacyMode?: PrivacyMode;
|
|
27
|
+
/** Allowlist for custom mode - only these attribute keys are emitted */
|
|
28
|
+
allowAttributes?: string[];
|
|
29
|
+
/** Custom redaction hook for edge cases */
|
|
30
|
+
redact?: (attrs: Record<string, unknown>) => Record<string, unknown>;
|
|
31
|
+
/** Enable experimental GenAI semantic conventions (default: false) */
|
|
32
|
+
enableExperimentalGenAI?: boolean;
|
|
33
|
+
/** Salt for privacy-preserving hashing (should be configured per deployment) */
|
|
34
|
+
hashSalt?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Input for receipt issued telemetry event
|
|
38
|
+
*/
|
|
39
|
+
export interface ReceiptIssuedInput {
|
|
40
|
+
/** Hash of the receipt (never raw content) */
|
|
41
|
+
receiptHash: string;
|
|
42
|
+
/** Hash of the policy used */
|
|
43
|
+
policyHash?: string;
|
|
44
|
+
/** Issuer identifier (may be hashed based on privacy mode) */
|
|
45
|
+
issuer?: string;
|
|
46
|
+
/** Key ID used for signing */
|
|
47
|
+
kid?: string;
|
|
48
|
+
/** HTTP context (privacy-safe: path only, no query) */
|
|
49
|
+
http?: HttpContext;
|
|
50
|
+
/** Duration of issue operation in milliseconds */
|
|
51
|
+
durationMs?: number;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Input for receipt verified telemetry event
|
|
55
|
+
*/
|
|
56
|
+
export interface ReceiptVerifiedInput {
|
|
57
|
+
/** Hash of the receipt */
|
|
58
|
+
receiptHash: string;
|
|
59
|
+
/** Issuer identifier */
|
|
60
|
+
issuer?: string;
|
|
61
|
+
/** Key ID used */
|
|
62
|
+
kid?: string;
|
|
63
|
+
/** Whether verification succeeded */
|
|
64
|
+
valid: boolean;
|
|
65
|
+
/** Reason code if verification failed */
|
|
66
|
+
reasonCode?: string;
|
|
67
|
+
/** HTTP context */
|
|
68
|
+
http?: HttpContext;
|
|
69
|
+
/** Duration of verify operation in milliseconds */
|
|
70
|
+
durationMs?: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Input for access decision telemetry event
|
|
74
|
+
*/
|
|
75
|
+
export interface AccessDecisionInput {
|
|
76
|
+
/** Hash of the receipt (if present) */
|
|
77
|
+
receiptHash?: string;
|
|
78
|
+
/** Hash of the policy evaluated */
|
|
79
|
+
policyHash?: string;
|
|
80
|
+
/** Decision outcome */
|
|
81
|
+
decision: TelemetryDecision;
|
|
82
|
+
/** Reason code for the decision */
|
|
83
|
+
reasonCode?: string;
|
|
84
|
+
/** Payment context (balanced/custom mode only) */
|
|
85
|
+
payment?: PaymentContext;
|
|
86
|
+
/** HTTP context */
|
|
87
|
+
http?: HttpContext;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* HTTP context for telemetry (privacy-safe subset)
|
|
91
|
+
*/
|
|
92
|
+
export interface HttpContext {
|
|
93
|
+
/** HTTP method */
|
|
94
|
+
method?: string;
|
|
95
|
+
/** URL path (no query string) */
|
|
96
|
+
path?: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Payment context for telemetry (balanced/custom mode only)
|
|
100
|
+
*/
|
|
101
|
+
export interface PaymentContext {
|
|
102
|
+
/** Payment rail identifier */
|
|
103
|
+
rail?: string;
|
|
104
|
+
/** Amount in minor units */
|
|
105
|
+
amount?: number;
|
|
106
|
+
/** Currency code */
|
|
107
|
+
currency?: string;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Telemetry provider interface
|
|
111
|
+
*
|
|
112
|
+
* Implementations SHOULD be no-throw. PEAC guards all calls,
|
|
113
|
+
* but well-behaved providers should not throw.
|
|
114
|
+
*/
|
|
115
|
+
export interface TelemetryProvider {
|
|
116
|
+
/**
|
|
117
|
+
* Called when a receipt is issued
|
|
118
|
+
*/
|
|
119
|
+
onReceiptIssued(input: ReceiptIssuedInput): void;
|
|
120
|
+
/**
|
|
121
|
+
* Called when a receipt is verified
|
|
122
|
+
*/
|
|
123
|
+
onReceiptVerified(input: ReceiptVerifiedInput): void;
|
|
124
|
+
/**
|
|
125
|
+
* Called when an access decision is made
|
|
126
|
+
*/
|
|
127
|
+
onAccessDecision(input: AccessDecisionInput): void;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IAEpB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B,wEAAwE;IACxE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAE3B,2CAA2C;IAC3C,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAErE,sEAAsE;IACtE,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAElC,gFAAgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IAEpB,8BAA8B;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,uDAAuD;IACvD,IAAI,CAAC,EAAE,WAAW,CAAC;IAEnB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,0BAA0B;IAC1B,WAAW,EAAE,MAAM,CAAC;IAEpB,wBAAwB;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,kBAAkB;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb,qCAAqC;IACrC,KAAK,EAAE,OAAO,CAAC;IAEf,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,mBAAmB;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC;IAEnB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,uCAAuC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,uBAAuB;IACvB,QAAQ,EAAE,iBAAiB,CAAC;IAE5B,mCAAmC;IACnC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,kDAAkD;IAClD,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB,mBAAmB;IACnB,IAAI,CAAC,EAAE,WAAW,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,kBAAkB;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,eAAe,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAEjD;;OAEG;IACH,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAErD;;OAEG;IACH,gBAAgB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAAC;CACpD"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @peac/telemetry - Telemetry types and interfaces
|
|
4
|
+
*
|
|
5
|
+
* This module defines the core telemetry interfaces for PEAC protocol.
|
|
6
|
+
* These are runtime-portable and have no external dependencies.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;GAKG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@peac/telemetry",
|
|
3
|
+
"version": "0.9.31",
|
|
4
|
+
"description": "Telemetry interfaces and no-op implementation for PEAC protocol",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/peacprotocol/peac.git",
|
|
17
|
+
"directory": "packages/telemetry"
|
|
18
|
+
},
|
|
19
|
+
"author": "PEAC Protocol contributors",
|
|
20
|
+
"license": "Apache-2.0",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@peac/kernel": "0.9.31"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^20.10.0",
|
|
26
|
+
"typescript": "^5.3.3",
|
|
27
|
+
"vitest": "^1.6.0"
|
|
28
|
+
},
|
|
29
|
+
"sideEffects": false,
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"typecheck": "tsc --noEmit",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"test:watch": "vitest",
|
|
35
|
+
"clean": "rm -rf dist"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @peac/telemetry - Attribute constants
|
|
3
|
+
*
|
|
4
|
+
* Standard attribute names for PEAC telemetry.
|
|
5
|
+
* Uses stable OTel semantic conventions where applicable.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* PEAC-specific attribute names
|
|
10
|
+
*/
|
|
11
|
+
export const PEAC_ATTRS = {
|
|
12
|
+
// Core (always emitted)
|
|
13
|
+
VERSION: 'peac.version',
|
|
14
|
+
EVENT: 'peac.event',
|
|
15
|
+
RECEIPT_HASH: 'peac.receipt.hash',
|
|
16
|
+
POLICY_HASH: 'peac.policy.hash',
|
|
17
|
+
DECISION: 'peac.decision',
|
|
18
|
+
REASON_CODE: 'peac.reason_code',
|
|
19
|
+
ISSUER: 'peac.issuer',
|
|
20
|
+
ISSUER_HASH: 'peac.issuer_hash',
|
|
21
|
+
KID: 'peac.kid',
|
|
22
|
+
VALID: 'peac.valid',
|
|
23
|
+
|
|
24
|
+
// HTTP (privacy-safe, stable OTel semconv)
|
|
25
|
+
HTTP_METHOD: 'http.request.method',
|
|
26
|
+
HTTP_PATH: 'url.path', // No query string
|
|
27
|
+
HTTP_HOST_HASH: 'peac.http.host_hash',
|
|
28
|
+
HTTP_CLIENT_HASH: 'peac.http.client_hash',
|
|
29
|
+
|
|
30
|
+
// Payment (balanced/custom mode only)
|
|
31
|
+
PAYMENT_RAIL: 'peac.payment.rail',
|
|
32
|
+
PAYMENT_AMOUNT: 'peac.payment.amount',
|
|
33
|
+
PAYMENT_CURRENCY: 'peac.payment.currency',
|
|
34
|
+
|
|
35
|
+
// Duration
|
|
36
|
+
DURATION_MS: 'peac.duration_ms',
|
|
37
|
+
} as const;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* PEAC event names
|
|
41
|
+
*/
|
|
42
|
+
export const PEAC_EVENTS = {
|
|
43
|
+
RECEIPT_ISSUED: 'peac.receipt.issued',
|
|
44
|
+
RECEIPT_VERIFIED: 'peac.receipt.verified',
|
|
45
|
+
ACCESS_DECISION: 'peac.access.decision',
|
|
46
|
+
} as const;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* PEAC metric names
|
|
50
|
+
*/
|
|
51
|
+
export const PEAC_METRICS = {
|
|
52
|
+
// Counters
|
|
53
|
+
RECEIPTS_ISSUED: 'peac.receipts.issued',
|
|
54
|
+
RECEIPTS_VERIFIED: 'peac.receipts.verified',
|
|
55
|
+
ACCESS_DECISIONS: 'peac.access.decisions',
|
|
56
|
+
|
|
57
|
+
// Histograms
|
|
58
|
+
ISSUE_DURATION: 'peac.issue.duration',
|
|
59
|
+
VERIFY_DURATION: 'peac.verify.duration',
|
|
60
|
+
} as const;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Extension keys for trace context binding
|
|
64
|
+
*
|
|
65
|
+
* Uses w3c/ namespace for vendor neutrality.
|
|
66
|
+
* W3C owns the Trace Context spec; OTel implements it.
|
|
67
|
+
*/
|
|
68
|
+
export const TRACE_CONTEXT_EXTENSIONS = {
|
|
69
|
+
TRACEPARENT: 'w3c/traceparent',
|
|
70
|
+
TRACESTATE: 'w3c/tracestate',
|
|
71
|
+
} as const;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @peac/telemetry
|
|
3
|
+
*
|
|
4
|
+
* Telemetry interfaces and no-op implementation for PEAC protocol.
|
|
5
|
+
*
|
|
6
|
+
* This package provides:
|
|
7
|
+
* - Core telemetry interfaces (TelemetryProvider, inputs, config)
|
|
8
|
+
* - No-op provider for when telemetry is disabled
|
|
9
|
+
* - Provider registry for global telemetry configuration
|
|
10
|
+
* - Attribute constants for consistent naming
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import {
|
|
15
|
+
* setTelemetryProvider,
|
|
16
|
+
* providerRef,
|
|
17
|
+
* noopProvider,
|
|
18
|
+
* PEAC_ATTRS,
|
|
19
|
+
* } from '@peac/telemetry';
|
|
20
|
+
*
|
|
21
|
+
* // Enable telemetry with a custom provider
|
|
22
|
+
* setTelemetryProvider(myOtelProvider);
|
|
23
|
+
*
|
|
24
|
+
* // In hot path (zero overhead when disabled)
|
|
25
|
+
* const p = providerRef.current;
|
|
26
|
+
* if (p) {
|
|
27
|
+
* try {
|
|
28
|
+
* p.onReceiptIssued({ receiptHash: '...' });
|
|
29
|
+
* } catch {
|
|
30
|
+
* // Telemetry MUST NOT break core flow
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @packageDocumentation
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
// Types
|
|
39
|
+
export type {
|
|
40
|
+
TelemetryDecision,
|
|
41
|
+
PrivacyMode,
|
|
42
|
+
TelemetryConfig,
|
|
43
|
+
TelemetryProvider,
|
|
44
|
+
ReceiptIssuedInput,
|
|
45
|
+
ReceiptVerifiedInput,
|
|
46
|
+
AccessDecisionInput,
|
|
47
|
+
HttpContext,
|
|
48
|
+
PaymentContext,
|
|
49
|
+
} from './types.js';
|
|
50
|
+
|
|
51
|
+
// No-op provider
|
|
52
|
+
export { noopProvider } from './noop.js';
|
|
53
|
+
|
|
54
|
+
// Provider registry
|
|
55
|
+
export {
|
|
56
|
+
providerRef,
|
|
57
|
+
setTelemetryProvider,
|
|
58
|
+
getTelemetryProvider,
|
|
59
|
+
isTelemetryEnabled,
|
|
60
|
+
} from './provider.js';
|
|
61
|
+
|
|
62
|
+
// Attribute constants
|
|
63
|
+
export { PEAC_ATTRS, PEAC_EVENTS, PEAC_METRICS, TRACE_CONTEXT_EXTENSIONS } from './attributes.js';
|
package/src/noop.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @peac/telemetry - No-op telemetry provider
|
|
3
|
+
*
|
|
4
|
+
* This provider does nothing. Use it when telemetry is disabled
|
|
5
|
+
* or when you need a fallback provider.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { TelemetryProvider } from './types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* No-op telemetry provider
|
|
12
|
+
*
|
|
13
|
+
* All methods are empty functions that do nothing.
|
|
14
|
+
* Use this as the default when no telemetry is configured.
|
|
15
|
+
*/
|
|
16
|
+
export const noopProvider: TelemetryProvider = {
|
|
17
|
+
onReceiptIssued: () => {},
|
|
18
|
+
onReceiptVerified: () => {},
|
|
19
|
+
onAccessDecision: () => {},
|
|
20
|
+
};
|
package/src/provider.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @peac/telemetry - Provider registry
|
|
3
|
+
*
|
|
4
|
+
* Zero-throw provider ref pattern for hot-path performance.
|
|
5
|
+
* When undefined, telemetry is disabled with NO function calls.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { TelemetryProvider } from './types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Singleton provider reference for zero-overhead hot path.
|
|
12
|
+
*
|
|
13
|
+
* When undefined, telemetry is disabled with NO function calls
|
|
14
|
+
* beyond the initial `if (!p)` check.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // In hot path (issue/verify)
|
|
19
|
+
* const p = providerRef.current;
|
|
20
|
+
* if (p) {
|
|
21
|
+
* try {
|
|
22
|
+
* p.onReceiptIssued({ receiptHash: '...' });
|
|
23
|
+
* } catch {
|
|
24
|
+
* // Telemetry MUST NOT break core flow
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export const providerRef: { current?: TelemetryProvider } = {
|
|
30
|
+
current: undefined,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Set the telemetry provider.
|
|
35
|
+
*
|
|
36
|
+
* Idempotent, no-throw, safe to call multiple times.
|
|
37
|
+
* Pass undefined to disable telemetry.
|
|
38
|
+
*
|
|
39
|
+
* @param provider - The provider to use, or undefined to disable
|
|
40
|
+
*/
|
|
41
|
+
export function setTelemetryProvider(provider: TelemetryProvider | undefined): void {
|
|
42
|
+
providerRef.current = provider;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Get the current telemetry provider.
|
|
47
|
+
*
|
|
48
|
+
* Returns undefined if no provider is set (telemetry disabled).
|
|
49
|
+
*
|
|
50
|
+
* For hot paths, prefer direct access to `providerRef.current`
|
|
51
|
+
* to avoid the function call overhead.
|
|
52
|
+
*/
|
|
53
|
+
export function getTelemetryProvider(): TelemetryProvider | undefined {
|
|
54
|
+
return providerRef.current;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check if telemetry is enabled.
|
|
59
|
+
*
|
|
60
|
+
* Convenience function for conditional logic outside hot paths.
|
|
61
|
+
*/
|
|
62
|
+
export function isTelemetryEnabled(): boolean {
|
|
63
|
+
return providerRef.current !== undefined;
|
|
64
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @peac/telemetry - Telemetry types and interfaces
|
|
3
|
+
*
|
|
4
|
+
* This module defines the core telemetry interfaces for PEAC protocol.
|
|
5
|
+
* These are runtime-portable and have no external dependencies.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Telemetry decision outcome
|
|
10
|
+
*/
|
|
11
|
+
export type TelemetryDecision = 'allow' | 'deny' | 'unknown';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Privacy mode for telemetry emission
|
|
15
|
+
*
|
|
16
|
+
* - strict: Hash all identifiers, emit minimal data (production default)
|
|
17
|
+
* - balanced: Hash identifiers but include rail + amounts (debugging)
|
|
18
|
+
* - custom: Use allowlist-based filtering
|
|
19
|
+
*/
|
|
20
|
+
export type PrivacyMode = 'strict' | 'balanced' | 'custom';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Telemetry configuration
|
|
24
|
+
*/
|
|
25
|
+
export interface TelemetryConfig {
|
|
26
|
+
/** Service name for resource identification */
|
|
27
|
+
serviceName: string;
|
|
28
|
+
|
|
29
|
+
/** Privacy mode: strict (hashes only), balanced, custom */
|
|
30
|
+
privacyMode?: PrivacyMode;
|
|
31
|
+
|
|
32
|
+
/** Allowlist for custom mode - only these attribute keys are emitted */
|
|
33
|
+
allowAttributes?: string[];
|
|
34
|
+
|
|
35
|
+
/** Custom redaction hook for edge cases */
|
|
36
|
+
redact?: (attrs: Record<string, unknown>) => Record<string, unknown>;
|
|
37
|
+
|
|
38
|
+
/** Enable experimental GenAI semantic conventions (default: false) */
|
|
39
|
+
enableExperimentalGenAI?: boolean;
|
|
40
|
+
|
|
41
|
+
/** Salt for privacy-preserving hashing (should be configured per deployment) */
|
|
42
|
+
hashSalt?: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Input for receipt issued telemetry event
|
|
47
|
+
*/
|
|
48
|
+
export interface ReceiptIssuedInput {
|
|
49
|
+
/** Hash of the receipt (never raw content) */
|
|
50
|
+
receiptHash: string;
|
|
51
|
+
|
|
52
|
+
/** Hash of the policy used */
|
|
53
|
+
policyHash?: string;
|
|
54
|
+
|
|
55
|
+
/** Issuer identifier (may be hashed based on privacy mode) */
|
|
56
|
+
issuer?: string;
|
|
57
|
+
|
|
58
|
+
/** Key ID used for signing */
|
|
59
|
+
kid?: string;
|
|
60
|
+
|
|
61
|
+
/** HTTP context (privacy-safe: path only, no query) */
|
|
62
|
+
http?: HttpContext;
|
|
63
|
+
|
|
64
|
+
/** Duration of issue operation in milliseconds */
|
|
65
|
+
durationMs?: number;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Input for receipt verified telemetry event
|
|
70
|
+
*/
|
|
71
|
+
export interface ReceiptVerifiedInput {
|
|
72
|
+
/** Hash of the receipt */
|
|
73
|
+
receiptHash: string;
|
|
74
|
+
|
|
75
|
+
/** Issuer identifier */
|
|
76
|
+
issuer?: string;
|
|
77
|
+
|
|
78
|
+
/** Key ID used */
|
|
79
|
+
kid?: string;
|
|
80
|
+
|
|
81
|
+
/** Whether verification succeeded */
|
|
82
|
+
valid: boolean;
|
|
83
|
+
|
|
84
|
+
/** Reason code if verification failed */
|
|
85
|
+
reasonCode?: string;
|
|
86
|
+
|
|
87
|
+
/** HTTP context */
|
|
88
|
+
http?: HttpContext;
|
|
89
|
+
|
|
90
|
+
/** Duration of verify operation in milliseconds */
|
|
91
|
+
durationMs?: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Input for access decision telemetry event
|
|
96
|
+
*/
|
|
97
|
+
export interface AccessDecisionInput {
|
|
98
|
+
/** Hash of the receipt (if present) */
|
|
99
|
+
receiptHash?: string;
|
|
100
|
+
|
|
101
|
+
/** Hash of the policy evaluated */
|
|
102
|
+
policyHash?: string;
|
|
103
|
+
|
|
104
|
+
/** Decision outcome */
|
|
105
|
+
decision: TelemetryDecision;
|
|
106
|
+
|
|
107
|
+
/** Reason code for the decision */
|
|
108
|
+
reasonCode?: string;
|
|
109
|
+
|
|
110
|
+
/** Payment context (balanced/custom mode only) */
|
|
111
|
+
payment?: PaymentContext;
|
|
112
|
+
|
|
113
|
+
/** HTTP context */
|
|
114
|
+
http?: HttpContext;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* HTTP context for telemetry (privacy-safe subset)
|
|
119
|
+
*/
|
|
120
|
+
export interface HttpContext {
|
|
121
|
+
/** HTTP method */
|
|
122
|
+
method?: string;
|
|
123
|
+
|
|
124
|
+
/** URL path (no query string) */
|
|
125
|
+
path?: string;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Payment context for telemetry (balanced/custom mode only)
|
|
130
|
+
*/
|
|
131
|
+
export interface PaymentContext {
|
|
132
|
+
/** Payment rail identifier */
|
|
133
|
+
rail?: string;
|
|
134
|
+
|
|
135
|
+
/** Amount in minor units */
|
|
136
|
+
amount?: number;
|
|
137
|
+
|
|
138
|
+
/** Currency code */
|
|
139
|
+
currency?: string;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Telemetry provider interface
|
|
144
|
+
*
|
|
145
|
+
* Implementations SHOULD be no-throw. PEAC guards all calls,
|
|
146
|
+
* but well-behaved providers should not throw.
|
|
147
|
+
*/
|
|
148
|
+
export interface TelemetryProvider {
|
|
149
|
+
/**
|
|
150
|
+
* Called when a receipt is issued
|
|
151
|
+
*/
|
|
152
|
+
onReceiptIssued(input: ReceiptIssuedInput): void;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Called when a receipt is verified
|
|
156
|
+
*/
|
|
157
|
+
onReceiptVerified(input: ReceiptVerifiedInput): void;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Called when an access decision is made
|
|
161
|
+
*/
|
|
162
|
+
onAccessDecision(input: AccessDecisionInput): void;
|
|
163
|
+
}
|