@aduek/ne-sy 0.1.0-alpha.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/README.md +92 -0
- package/dist/adapters.d.ts +13 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +20 -0
- package/dist/audit.d.ts +14 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +129 -0
- package/dist/capabilities.d.ts +10 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +89 -0
- package/dist/evidence.d.ts +19 -0
- package/dist/evidence.d.ts.map +1 -0
- package/dist/evidence.js +48 -0
- package/dist/hubspot.d.ts +59 -0
- package/dist/hubspot.d.ts.map +1 -0
- package/dist/hubspot.js +175 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/ir.d.ts +104 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +859 -0
- package/dist/metering.d.ts +53 -0
- package/dist/metering.d.ts.map +1 -0
- package/dist/metering.js +224 -0
- package/dist/openaiAgents.d.ts +29 -0
- package/dist/openaiAgents.d.ts.map +1 -0
- package/dist/openaiAgents.js +81 -0
- package/dist/policy.d.ts +12 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +362 -0
- package/dist/types.d.ts +112 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +71 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +51 -0
- package/dist/validation.d.ts +14 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +226 -0
- package/dist/verifier.d.ts +13 -0
- package/dist/verifier.d.ts.map +1 -0
- package/dist/verifier.js +69 -0
- package/package.json +60 -0
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Aduek TypeScript SDK
|
|
2
|
+
|
|
3
|
+
TypeScript package foundation for Aduek Ne-Sy.
|
|
4
|
+
|
|
5
|
+
The TypeScript SDK should feel native for SaaS apps, web agents, browser automation, internal tools, workflow apps, Next.js backends, and production agent applications.
|
|
6
|
+
|
|
7
|
+
## Target Ergonomics
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { verifyAction } from "@aduek/ne-sy";
|
|
11
|
+
|
|
12
|
+
const decision = await verifyAction({ agent, action, context });
|
|
13
|
+
if (decision.allowed) await tool.execute(action);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Planned Responsibilities
|
|
17
|
+
|
|
18
|
+
- Action model bindings
|
|
19
|
+
- Local verifier API
|
|
20
|
+
- Tool wrapper helpers
|
|
21
|
+
- JSONL audit event emitter
|
|
22
|
+
- Framework adapters
|
|
23
|
+
|
|
24
|
+
## Current Sprint State
|
|
25
|
+
|
|
26
|
+
The SDK now includes a local evaluator for explicit policy packs, dotted-path condition checks, decision precedence, JSON Schema-backed policy-pack validation, policy analysis, async tool wrapping, and JSONL audit writing.
|
|
27
|
+
|
|
28
|
+
Policy packs can declare a default decision for no-match actions, and audit events include policy-pack metadata for reviewer traceability.
|
|
29
|
+
|
|
30
|
+
The implementation is split into focused modules for types, policy evaluation, audit events, runtime schema validation, verifier entrypoints, and shared utilities while preserving the public `@aduek/ne-sy` export surface.
|
|
31
|
+
|
|
32
|
+
Policy packs can also be normalized into a deterministic policy IR for static analysis and future solver adapters:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { hashPolicyIr, normalizePolicyPack } from "@aduek/ne-sy";
|
|
36
|
+
|
|
37
|
+
const policyIr = normalizePolicyPack(policyPack);
|
|
38
|
+
hashPolicyIr(policyIr);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Finite-domain bounded simulation can run over the normalized IR without adding solver dependencies:
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
simulatePolicyIr(policyIr, simulationSpec);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Policy evidence can be reproduced with:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { hashPolicyPack } from "@aduek/ne-sy";
|
|
51
|
+
|
|
52
|
+
hashPolicyPack(policyPack)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Generic tool adapters can create the shared action shape with:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
createToolAction({ agent, tool, args })
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
OpenAI Agents SDK custom function-tool input guardrails can use a dependency-light boundary:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
const result = await runOpenAiToolInputGuardrail({
|
|
65
|
+
agent,
|
|
66
|
+
toolName: "loan_approve",
|
|
67
|
+
toolArguments: { amount: 150000 },
|
|
68
|
+
policies: policyPack,
|
|
69
|
+
context,
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The result maps `allow` and `log` to guardrail allow, and `deny` and `review` to `rejectContent`. The base package does not depend on the OpenAI Agents SDK.
|
|
74
|
+
|
|
75
|
+
HubSpot-shaped outcome fixtures can be classified locally for planned paid-pilot evidence:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { classifyHubSpotOutcomes, exportHubSpotCreditsRows, loadHubSpotOutcomeEvents } from "@aduek/ne-sy";
|
|
79
|
+
|
|
80
|
+
const events = loadHubSpotOutcomeEvents("examples/hubspot-outcomes/hubspot-outcome-events.json");
|
|
81
|
+
const ledger = classifyHubSpotOutcomes(events);
|
|
82
|
+
const creditsRows = exportHubSpotCreditsRows(ledger.records);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
This is local fixture/evidence tooling only. It does not add OAuth, webhook verification, HubSpot API writes, HubSpot Credits writes, hosted billing, or payment collection.
|
|
86
|
+
|
|
87
|
+
Package metadata is now set for alpha prerelease dry-run work at version `0.1.0-alpha.0`.
|
|
88
|
+
|
|
89
|
+
## Current Technical Debt
|
|
90
|
+
|
|
91
|
+
- Framework-specific adapters beyond the OpenAI Agents tool input guardrail boundary are not implemented yet.
|
|
92
|
+
- Required package content assertions, initial changelog, alpha release notes, and manual artifact inspection are implemented; publishing approval remains out of scope.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface ToolActionInput<Args extends unknown[] = unknown[]> {
|
|
2
|
+
agent: unknown;
|
|
3
|
+
tool?: (...args: Args) => unknown;
|
|
4
|
+
toolName?: string;
|
|
5
|
+
args?: Args;
|
|
6
|
+
actionType?: string;
|
|
7
|
+
target?: unknown;
|
|
8
|
+
metadata?: Record<string, unknown>;
|
|
9
|
+
actionId?: string;
|
|
10
|
+
timestamp?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function createToolAction<Args extends unknown[] = unknown[]>(input: ToolActionInput<Args>): Record<string, unknown>;
|
|
13
|
+
//# sourceMappingURL=adapters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapters.d.ts","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe,CAAC,IAAI,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE;IACjE,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,EACjE,KAAK,EAAE,eAAe,CAAC,IAAI,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB"}
|
package/dist/adapters.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { agentRef } from "./utils.js";
|
|
3
|
+
export function createToolAction(input) {
|
|
4
|
+
const toolName = input.toolName ?? input.tool?.name ?? "tool";
|
|
5
|
+
return {
|
|
6
|
+
id: input.actionId ?? randomUUID(),
|
|
7
|
+
type: input.actionType ?? "tool.call",
|
|
8
|
+
actor: agentRef(input.agent),
|
|
9
|
+
target: input.target ?? {
|
|
10
|
+
id: toolName,
|
|
11
|
+
kind: "function",
|
|
12
|
+
trustBoundary: "internal",
|
|
13
|
+
},
|
|
14
|
+
input: {
|
|
15
|
+
args: [...(input.args ?? [])],
|
|
16
|
+
},
|
|
17
|
+
metadata: input.metadata ?? {},
|
|
18
|
+
timestamp: input.timestamp ?? new Date().toISOString(),
|
|
19
|
+
};
|
|
20
|
+
}
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AuditEvent, Decision } from "./types.js";
|
|
2
|
+
export declare function createAuditEvent(input: {
|
|
3
|
+
agent: unknown;
|
|
4
|
+
action: unknown;
|
|
5
|
+
context: unknown;
|
|
6
|
+
decision: Decision;
|
|
7
|
+
policyPackId?: string;
|
|
8
|
+
policyVersion?: string;
|
|
9
|
+
policyHash?: string;
|
|
10
|
+
}): AuditEvent;
|
|
11
|
+
export declare function writeAuditEvent(path: string, event: AuditEvent): Promise<void>;
|
|
12
|
+
export declare function validateAuditEvent(event: unknown): string[];
|
|
13
|
+
export declare function assertValidAuditEvent(event: unknown): asserts event is AuditEvent;
|
|
14
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAoB,MAAM,YAAY,CAAC;AAUzE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACtC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,UAAU,CA+Cb;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAWpF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CA6C3D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAQjF"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, appendFile } from "node:fs/promises";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { DECISION_RANK, PolicyEvaluationError } from "./types.js";
|
|
5
|
+
import { VERIFIER_VERSION, hashAction, hashAuditEvidence, hashEnvelope, } from "./evidence.js";
|
|
6
|
+
import { isRecord } from "./utils.js";
|
|
7
|
+
import { validateAuditEventSchema } from "./validation.js";
|
|
8
|
+
export function createAuditEvent(input) {
|
|
9
|
+
let executionOutcome;
|
|
10
|
+
if (input.decision.decision === "review") {
|
|
11
|
+
executionOutcome = "pending_review";
|
|
12
|
+
}
|
|
13
|
+
else if (input.decision.decision === "deny") {
|
|
14
|
+
executionOutcome = "blocked";
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
executionOutcome = "executed";
|
|
18
|
+
}
|
|
19
|
+
const event = {
|
|
20
|
+
id: randomUUID(),
|
|
21
|
+
action: input.action,
|
|
22
|
+
decision: {
|
|
23
|
+
decision: input.decision.decision,
|
|
24
|
+
reason: input.decision.reason,
|
|
25
|
+
matchedPolicyIds: input.decision.matchedPolicyIds,
|
|
26
|
+
metadata: input.decision.metadata,
|
|
27
|
+
},
|
|
28
|
+
runtime: {
|
|
29
|
+
agent: input.agent,
|
|
30
|
+
context: input.context,
|
|
31
|
+
executionOutcome,
|
|
32
|
+
},
|
|
33
|
+
timestamp: new Date().toISOString(),
|
|
34
|
+
};
|
|
35
|
+
if (input.policyPackId) {
|
|
36
|
+
event.policyPackId = input.policyPackId;
|
|
37
|
+
}
|
|
38
|
+
if (input.policyVersion) {
|
|
39
|
+
event.policyVersion = input.policyVersion;
|
|
40
|
+
}
|
|
41
|
+
if (input.policyHash) {
|
|
42
|
+
event.policyHash = input.policyHash;
|
|
43
|
+
}
|
|
44
|
+
event.actionHash = hashAction(input.action);
|
|
45
|
+
event.envelopeHash = hashEnvelope({
|
|
46
|
+
agent: input.agent,
|
|
47
|
+
action: input.action,
|
|
48
|
+
context: input.context,
|
|
49
|
+
policyPackId: input.policyPackId,
|
|
50
|
+
policyVersion: input.policyVersion,
|
|
51
|
+
policyHash: input.policyHash,
|
|
52
|
+
});
|
|
53
|
+
event.verifierVersion = VERIFIER_VERSION;
|
|
54
|
+
event.evidenceHash = hashAuditEvidence(event);
|
|
55
|
+
return event;
|
|
56
|
+
}
|
|
57
|
+
export async function writeAuditEvent(path, event) {
|
|
58
|
+
try {
|
|
59
|
+
await mkdir(dirname(path), { recursive: true });
|
|
60
|
+
await appendFile(path, `${JSON.stringify(event)}\n`, "utf8");
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
64
|
+
throw new PolicyEvaluationError(`Audit write failed: ${message}`, {
|
|
65
|
+
category: "audit_write_error",
|
|
66
|
+
code: "audit_write_failed",
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export function validateAuditEvent(event) {
|
|
71
|
+
const errors = validateAuditEventSchema(event);
|
|
72
|
+
if (!isRecord(event))
|
|
73
|
+
return ["event must be an object"];
|
|
74
|
+
requireString(event, "id", errors);
|
|
75
|
+
requireObject(event, "action", errors);
|
|
76
|
+
requireObject(event, "decision", errors);
|
|
77
|
+
requireString(event, "timestamp", errors);
|
|
78
|
+
if (isRecord(event.decision)) {
|
|
79
|
+
if (!Object.prototype.hasOwnProperty.call(DECISION_RANK, String(event.decision.decision))) {
|
|
80
|
+
errors.push("decision.decision must be one of allow, deny, review, log");
|
|
81
|
+
}
|
|
82
|
+
requireString(event.decision, "reason", errors, "decision.");
|
|
83
|
+
if (event.decision.matchedPolicyIds !== undefined &&
|
|
84
|
+
(!Array.isArray(event.decision.matchedPolicyIds) ||
|
|
85
|
+
!event.decision.matchedPolicyIds.every((item) => typeof item === "string"))) {
|
|
86
|
+
errors.push("decision.matchedPolicyIds must be a list of strings");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (event.policyVersion !== undefined && typeof event.policyVersion !== "string") {
|
|
90
|
+
errors.push("policyVersion must be a string when present");
|
|
91
|
+
}
|
|
92
|
+
if (event.policyPackId !== undefined && typeof event.policyPackId !== "string") {
|
|
93
|
+
errors.push("policyPackId must be a string when present");
|
|
94
|
+
}
|
|
95
|
+
if (event.policyHash !== undefined && typeof event.policyHash !== "string") {
|
|
96
|
+
errors.push("policyHash must be a string when present");
|
|
97
|
+
}
|
|
98
|
+
for (const hashField of ["actionHash", "envelopeHash", "evidenceHash"]) {
|
|
99
|
+
if (event[hashField] !== undefined && typeof event[hashField] !== "string") {
|
|
100
|
+
errors.push(`${hashField} must be a string when present`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (event.verifierVersion !== undefined && typeof event.verifierVersion !== "string") {
|
|
104
|
+
errors.push("verifierVersion must be a string when present");
|
|
105
|
+
}
|
|
106
|
+
if (event.runtime !== undefined && !isRecord(event.runtime)) {
|
|
107
|
+
errors.push("runtime must be an object when present");
|
|
108
|
+
}
|
|
109
|
+
return errors;
|
|
110
|
+
}
|
|
111
|
+
export function assertValidAuditEvent(event) {
|
|
112
|
+
const errors = validateAuditEvent(event);
|
|
113
|
+
if (errors.length > 0) {
|
|
114
|
+
throw new PolicyEvaluationError(errors.join("; "), {
|
|
115
|
+
category: "validation_error",
|
|
116
|
+
code: "audit_event_validation_error",
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function requireString(record, key, errors, prefix = "") {
|
|
121
|
+
if (typeof record[key] !== "string") {
|
|
122
|
+
errors.push(`${prefix}${key} must be a string`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function requireObject(record, key, errors, prefix = "") {
|
|
126
|
+
if (!isRecord(record[key])) {
|
|
127
|
+
errors.push(`${prefix}${key} must be an object`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const CAPABILITY_VOCABULARY: Set<string>;
|
|
2
|
+
export declare const BOUNDED_SIMULATION_CAPABILITIES: Set<string>;
|
|
3
|
+
export interface CapabilityValidation {
|
|
4
|
+
ok: boolean;
|
|
5
|
+
reason?: string;
|
|
6
|
+
errorCode?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function validateRequiredCapabilities(capabilities: unknown, supported: Set<string>): CapabilityValidation;
|
|
9
|
+
export declare function validateCapabilityList(capabilities: unknown): CapabilityValidation;
|
|
10
|
+
//# sourceMappingURL=capabilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,qBAAqB,aAgBhC,CAAC;AAEH,eAAO,MAAM,+BAA+B,aAS1C,CAAC;AAEH,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,OAAO,EACrB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GACrB,oBAAoB,CA6CtB;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,OAAO,GAAG,oBAAoB,CAUlF"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export const CAPABILITY_VOCABULARY = new Set([
|
|
2
|
+
"policy.conditions.basic",
|
|
3
|
+
"policy.operators.equals",
|
|
4
|
+
"policy.operators.not_equals",
|
|
5
|
+
"policy.operators.greater_than",
|
|
6
|
+
"policy.operators.less_than",
|
|
7
|
+
"policy.operators.in",
|
|
8
|
+
"analysis.bounded_simulation",
|
|
9
|
+
"analysis.typed_field_registry",
|
|
10
|
+
"analysis.solver.numeric",
|
|
11
|
+
"analysis.solver.enum",
|
|
12
|
+
"analysis.explanation.facts",
|
|
13
|
+
"evidence.policy_hash",
|
|
14
|
+
"evidence.policy_ir_hash",
|
|
15
|
+
"evidence.hashes",
|
|
16
|
+
"evidence.replay_manifest",
|
|
17
|
+
]);
|
|
18
|
+
export const BOUNDED_SIMULATION_CAPABILITIES = new Set([
|
|
19
|
+
"policy.conditions.basic",
|
|
20
|
+
"policy.operators.equals",
|
|
21
|
+
"policy.operators.not_equals",
|
|
22
|
+
"policy.operators.greater_than",
|
|
23
|
+
"policy.operators.less_than",
|
|
24
|
+
"policy.operators.in",
|
|
25
|
+
"analysis.bounded_simulation",
|
|
26
|
+
"analysis.typed_field_registry",
|
|
27
|
+
]);
|
|
28
|
+
export function validateRequiredCapabilities(capabilities, supported) {
|
|
29
|
+
if (capabilities === undefined || capabilities === null)
|
|
30
|
+
return { ok: true };
|
|
31
|
+
if (!isRecord(capabilities)) {
|
|
32
|
+
return {
|
|
33
|
+
ok: false,
|
|
34
|
+
reason: "Capability declarations must be an object.",
|
|
35
|
+
errorCode: "simulation_invalid_capabilities",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const requires = capabilities.requires ?? [];
|
|
39
|
+
if (!Array.isArray(requires) || !requires.every((item) => typeof item === "string")) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
reason: "Capability `requires` must be an array of strings.",
|
|
43
|
+
errorCode: "simulation_invalid_capabilities",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const supportedBy = capabilities.supportedBy ?? {};
|
|
47
|
+
if (supportedBy !== undefined && supportedBy !== null) {
|
|
48
|
+
if (!isRecord(supportedBy)) {
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
reason: "Capability `supportedBy` must be an object.",
|
|
52
|
+
errorCode: "simulation_invalid_capabilities",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
for (const [consumer, values] of Object.entries(supportedBy)) {
|
|
56
|
+
if (typeof consumer !== "string" || !Array.isArray(values) || !values.every((item) => typeof item === "string")) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
reason: "Capability `supportedBy` entries must be arrays of strings.",
|
|
60
|
+
errorCode: "simulation_invalid_capabilities",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const unsupported = requires.filter((item) => !supported.has(item));
|
|
66
|
+
if (unsupported.length > 0) {
|
|
67
|
+
return {
|
|
68
|
+
ok: false,
|
|
69
|
+
reason: `Unsupported required capabilities: ${JSON.stringify(unsupported)}`,
|
|
70
|
+
errorCode: "simulation_unsupported_capability",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return { ok: true };
|
|
74
|
+
}
|
|
75
|
+
export function validateCapabilityList(capabilities) {
|
|
76
|
+
if (capabilities === undefined || capabilities === null)
|
|
77
|
+
return { ok: true };
|
|
78
|
+
if (!Array.isArray(capabilities) || !capabilities.every((item) => typeof item === "string")) {
|
|
79
|
+
return {
|
|
80
|
+
ok: false,
|
|
81
|
+
reason: "Capability list must be an array of strings.",
|
|
82
|
+
errorCode: "simulation_invalid_capabilities",
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return { ok: true };
|
|
86
|
+
}
|
|
87
|
+
function isRecord(value) {
|
|
88
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
89
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const EVIDENCE_HASH_ALGORITHM = "sha256";
|
|
2
|
+
export declare const VERIFIER_VERSION = "0.1.0-alpha.0";
|
|
3
|
+
export declare function canonicalEvidenceJson(value: unknown, options?: {
|
|
4
|
+
excludeSelfHashes?: boolean;
|
|
5
|
+
}): string;
|
|
6
|
+
export declare function hashEvidenceValue(value: unknown, options?: {
|
|
7
|
+
excludeSelfHashes?: boolean;
|
|
8
|
+
}): string;
|
|
9
|
+
export declare function hashAction(action: unknown): string;
|
|
10
|
+
export declare function hashEnvelope(input: {
|
|
11
|
+
agent: unknown;
|
|
12
|
+
action: unknown;
|
|
13
|
+
context: unknown;
|
|
14
|
+
policyPackId?: string;
|
|
15
|
+
policyVersion?: string;
|
|
16
|
+
policyHash?: string;
|
|
17
|
+
}): string;
|
|
18
|
+
export declare function hashAuditEvidence(event: Record<string, unknown>): string;
|
|
19
|
+
//# sourceMappingURL=evidence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.d.ts","sourceRoot":"","sources":["../src/evidence.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAChD,eAAO,MAAM,gBAAgB,kBAAkB,CAAC;AAIhD,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5C,MAAM,CAER;AAED,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,OAAO,EACd,OAAO,GAAE;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5C,MAAM,CAIR;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAElD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,MAAM,CAST;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAExE"}
|
package/dist/evidence.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { compareStrings, isRecord } from "./utils.js";
|
|
3
|
+
export const EVIDENCE_HASH_ALGORITHM = "sha256";
|
|
4
|
+
export const VERIFIER_VERSION = "0.1.0-alpha.0";
|
|
5
|
+
const SELF_REFERENTIAL_HASH_FIELDS = new Set(["evidenceHash"]);
|
|
6
|
+
export function canonicalEvidenceJson(value, options = {}) {
|
|
7
|
+
return JSON.stringify(canonicalEvidenceValue(value, options));
|
|
8
|
+
}
|
|
9
|
+
export function hashEvidenceValue(value, options = {}) {
|
|
10
|
+
return createHash(EVIDENCE_HASH_ALGORITHM)
|
|
11
|
+
.update(canonicalEvidenceJson(value, options), "utf8")
|
|
12
|
+
.digest("hex");
|
|
13
|
+
}
|
|
14
|
+
export function hashAction(action) {
|
|
15
|
+
return hashEvidenceValue(action);
|
|
16
|
+
}
|
|
17
|
+
export function hashEnvelope(input) {
|
|
18
|
+
return hashEvidenceValue({
|
|
19
|
+
agent: input.agent,
|
|
20
|
+
action: input.action,
|
|
21
|
+
context: input.context,
|
|
22
|
+
policyPackId: input.policyPackId ?? null,
|
|
23
|
+
policyVersion: input.policyVersion ?? null,
|
|
24
|
+
policyHash: input.policyHash ?? null,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
export function hashAuditEvidence(event) {
|
|
28
|
+
return hashEvidenceValue(event, { excludeSelfHashes: true });
|
|
29
|
+
}
|
|
30
|
+
function canonicalEvidenceValue(value, options) {
|
|
31
|
+
if (Array.isArray(value)) {
|
|
32
|
+
return value.map((item) => canonicalEvidenceValue(item, options));
|
|
33
|
+
}
|
|
34
|
+
if (isRecord(value)) {
|
|
35
|
+
return Object.fromEntries(Object.entries(value)
|
|
36
|
+
.filter(([key, entry]) => entry !== undefined &&
|
|
37
|
+
!(options.excludeSelfHashes && SELF_REFERENTIAL_HASH_FIELDS.has(key)))
|
|
38
|
+
.sort(([left], [right]) => compareStrings(left, right))
|
|
39
|
+
.map(([key, entry]) => [key, canonicalEvidenceValue(entry, options)]));
|
|
40
|
+
}
|
|
41
|
+
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
42
|
+
throw new Error("Evidence hash payloads must not contain NaN or Infinity.");
|
|
43
|
+
}
|
|
44
|
+
if (value === undefined || typeof value === "function" || typeof value === "symbol") {
|
|
45
|
+
throw new Error("Evidence hash payloads must contain JSON-compatible values only.");
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
export type HubSpotOutcomeType = "resolved_conversation" | "qualified_lead_recommended" | "workflow_completed";
|
|
2
|
+
export type HubSpotLifecycleState = "candidate" | "verified" | "rejected" | "reversed" | "exported";
|
|
3
|
+
export type HubSpotRejectionReason = "malformed_event" | "unsupported_outcome_type" | "duplicate_idempotency_key" | "missing_required_evidence" | "human_escalation" | "reopened_conversation" | "unknown_reversal_target";
|
|
4
|
+
export interface HubSpotOutcomeRecord {
|
|
5
|
+
eventId: string | null;
|
|
6
|
+
portalId: string | null;
|
|
7
|
+
appId: string | null;
|
|
8
|
+
agentId: string | null;
|
|
9
|
+
outcomeType: string | null;
|
|
10
|
+
idempotencyKey: string | null;
|
|
11
|
+
lifecycleState: HubSpotLifecycleState;
|
|
12
|
+
billable: boolean;
|
|
13
|
+
exportEligible: boolean;
|
|
14
|
+
adjustmentQuantity: number;
|
|
15
|
+
rejectionReason: HubSpotRejectionReason | null;
|
|
16
|
+
reversalOf: string | null;
|
|
17
|
+
occurredAt: string | null;
|
|
18
|
+
}
|
|
19
|
+
export interface HubSpotOutcomeSummary {
|
|
20
|
+
totalRecords: number;
|
|
21
|
+
billableRecords: number;
|
|
22
|
+
exportEligibleRecords: number;
|
|
23
|
+
byLifecycleState: Record<string, number>;
|
|
24
|
+
byOutcomeType: Record<string, number>;
|
|
25
|
+
byRejectionReason: Record<string, number>;
|
|
26
|
+
}
|
|
27
|
+
export interface HubSpotOutcomeLedger {
|
|
28
|
+
records: HubSpotOutcomeRecord[];
|
|
29
|
+
summary: HubSpotOutcomeSummary;
|
|
30
|
+
}
|
|
31
|
+
export interface HubSpotCreditsRow {
|
|
32
|
+
portalId: string | null;
|
|
33
|
+
appId: string | null;
|
|
34
|
+
outcomeType: string | null;
|
|
35
|
+
idempotencyKey: string | null;
|
|
36
|
+
lifecycleState: HubSpotLifecycleState;
|
|
37
|
+
quantity: number;
|
|
38
|
+
sourceEventId: string | null;
|
|
39
|
+
reversalOf: string | null;
|
|
40
|
+
occurredAt: string | null;
|
|
41
|
+
}
|
|
42
|
+
export interface HubSpotInvoiceLineRow {
|
|
43
|
+
portalId: string | null;
|
|
44
|
+
appId: string | null;
|
|
45
|
+
agentId: string | null;
|
|
46
|
+
outcomeType: string | null;
|
|
47
|
+
idempotencyKey: string | null;
|
|
48
|
+
quantity: number;
|
|
49
|
+
description: string;
|
|
50
|
+
sourceEventId: string | null;
|
|
51
|
+
reversalOf: string | null;
|
|
52
|
+
occurredAt: string | null;
|
|
53
|
+
}
|
|
54
|
+
export declare function loadHubSpotOutcomeEvents(path: string): unknown[];
|
|
55
|
+
export declare function classifyHubSpotOutcomes(events: Iterable<unknown>): HubSpotOutcomeLedger;
|
|
56
|
+
export declare function summarizeHubSpotOutcomes(records: Iterable<HubSpotOutcomeRecord>): HubSpotOutcomeSummary;
|
|
57
|
+
export declare function exportHubSpotCreditsRows(records: Iterable<HubSpotOutcomeRecord>): HubSpotCreditsRow[];
|
|
58
|
+
export declare function exportHubSpotInvoiceLineRows(records: Iterable<HubSpotOutcomeRecord>): HubSpotInvoiceLineRow[];
|
|
59
|
+
//# sourceMappingURL=hubspot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hubspot.d.ts","sourceRoot":"","sources":["../src/hubspot.ts"],"names":[],"mappings":"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"}
|