@edge-protocol/sdk 0.7.0 → 0.9.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/CHANGELOG.md +110 -0
- package/dist/core/EdgePass.d.ts +88 -28
- package/dist/core/EdgePass.d.ts.map +1 -1
- package/dist/core/EdgePass.js +118 -63
- package/dist/core/EdgePass.js.map +1 -1
- package/dist/core/ExecutionEngine.d.ts +4 -4
- package/dist/core/ExecutionEngine.d.ts.map +1 -1
- package/dist/core/ExecutionEngine.js +18 -42
- package/dist/core/ExecutionEngine.js.map +1 -1
- package/dist/core/PolicyEngine.d.ts +57 -1
- package/dist/core/PolicyEngine.d.ts.map +1 -1
- package/dist/core/PolicyEngine.js +138 -35
- package/dist/core/PolicyEngine.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +29 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +74 -0
- package/dist/react/index.js.map +1 -0
- package/dist/utils/types.d.ts +40 -5
- package/dist/utils/types.d.ts.map +1 -1
- package/package.json +23 -41
|
@@ -12,7 +12,6 @@ exports.EDGE_ERROR_CODES = {
|
|
|
12
12
|
INVALID_OBJECT_ID: 'INVALID_OBJECT_ID',
|
|
13
13
|
OBJECT_NOT_FOUND: 'OBJECT_NOT_FOUND',
|
|
14
14
|
INVALID_PASS_STATE: 'INVALID_PASS_STATE',
|
|
15
|
-
VERSION_CONFLICT: 'VERSION_CONFLICT',
|
|
16
15
|
UNKNOWN: 'UNKNOWN',
|
|
17
16
|
};
|
|
18
17
|
function classifyError(error) {
|
|
@@ -36,15 +35,6 @@ function classifyError(error) {
|
|
|
36
35
|
code: exports.EDGE_ERROR_CODES.SIGNING_FAILURE,
|
|
37
36
|
};
|
|
38
37
|
}
|
|
39
|
-
// Object version conflict — caller should refetch and retry
|
|
40
|
-
if (msg.includes('version') ||
|
|
41
|
-
msg.includes('unavailable for consumption') ||
|
|
42
|
-
msg.includes('Transaction needs to be rebuilt')) {
|
|
43
|
-
return {
|
|
44
|
-
reason: `Object version conflict — transaction was NOT submitted. Refetch the pass and retry. (${msg})`,
|
|
45
|
-
code: exports.EDGE_ERROR_CODES.VERSION_CONFLICT,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
38
|
if (msg.includes('not found') || msg.includes('does not exist')) {
|
|
49
39
|
return {
|
|
50
40
|
reason: `EdgePass object not found on chain — it may have been deleted or the ID is incorrect. (${msg})`,
|
|
@@ -62,7 +52,7 @@ class ExecutionEngine {
|
|
|
62
52
|
this.client = new client_1.SuiClient({ url: constants_1.NETWORK_URLS[network] });
|
|
63
53
|
}
|
|
64
54
|
async execute(pass, request, signer) {
|
|
65
|
-
// ── Step 1: Policy validation (pure TS,
|
|
55
|
+
// ── Step 1: Policy validation (pure TS, no network) ───────────────────
|
|
66
56
|
const validation = PolicyEngine_1.PolicyEngine.validate(pass, request);
|
|
67
57
|
if (!validation.allowed) {
|
|
68
58
|
return { status: 'blocked', reason: validation.reason, auto: false };
|
|
@@ -70,21 +60,17 @@ class ExecutionEngine {
|
|
|
70
60
|
if (validation.requiresEscalation) {
|
|
71
61
|
return { status: 'escalated', reason: validation.reason, auto: false };
|
|
72
62
|
}
|
|
73
|
-
// ── Step 2: On-chain execution
|
|
74
|
-
// Uses objectRef if available (populated by fetchPass) to skip RPC
|
|
75
|
-
// version resolution — saves ~300-400ms per approved transaction.
|
|
76
|
-
// Falls back to tx.object() for passes created locally via sdk.create().
|
|
63
|
+
// ── Step 2: On-chain execution ─────────────────────────────────────────
|
|
77
64
|
try {
|
|
78
65
|
const tx = this.buildPTB(pass, request);
|
|
79
66
|
const result = await signer.signAndExecute(tx);
|
|
80
67
|
return { status: 'approved', digest: result.digest, auto: true };
|
|
81
68
|
}
|
|
82
69
|
catch (error) {
|
|
70
|
+
// Distinguish infrastructure failures from policy rejections
|
|
71
|
+
// 'error' status means the transaction was NEVER submitted to chain
|
|
72
|
+
// 'blocked' status means the policy rejected it
|
|
83
73
|
const { reason, code } = classifyError(error);
|
|
84
|
-
// Version conflict — surface it so caller can refetch and retry
|
|
85
|
-
if (code === exports.EDGE_ERROR_CODES.VERSION_CONFLICT) {
|
|
86
|
-
return { status: 'error', reason, code, auto: false };
|
|
87
|
-
}
|
|
88
74
|
return { status: 'error', reason, code, auto: false };
|
|
89
75
|
}
|
|
90
76
|
}
|
|
@@ -96,16 +82,10 @@ class ExecutionEngine {
|
|
|
96
82
|
throw new Error(`EdgePass: no package ID configured for network "${this.network}". ` +
|
|
97
83
|
`Update EDGE_PACKAGE_ID in constants.ts after deploying the Move contract.`);
|
|
98
84
|
}
|
|
99
|
-
// Use objectRef when available — skips RPC round trip to resolve version.
|
|
100
|
-
// objectRef is populated by fetchPass() and contains the exact version + digest
|
|
101
|
-
// from the last on-chain state, making the PTB construction deterministic.
|
|
102
|
-
const passArg = pass.objectRef
|
|
103
|
-
? tx.objectRef(pass.objectRef)
|
|
104
|
-
: tx.object(pass.id);
|
|
105
85
|
tx.moveCall({
|
|
106
86
|
target: `${packageId}::edge_pass::execute_transaction`,
|
|
107
87
|
arguments: [
|
|
108
|
-
|
|
88
|
+
tx.object(pass.id),
|
|
109
89
|
tx.pure.u64(request.amount),
|
|
110
90
|
tx.pure.string(request.merchant),
|
|
111
91
|
tx.object('0x6'), // Sui shared Clock object
|
|
@@ -115,11 +95,13 @@ class ExecutionEngine {
|
|
|
115
95
|
}
|
|
116
96
|
/**
|
|
117
97
|
* Fetch a live EdgePass from Sui.
|
|
118
|
-
*
|
|
119
|
-
* Returns null if
|
|
120
|
-
* Throws if objectId is invalid or a network error occurs
|
|
98
|
+
*
|
|
99
|
+
* Returns null if the object doesn't exist.
|
|
100
|
+
* Throws EdgePassError if the objectId is invalid or a network error occurs —
|
|
101
|
+
* so callers can distinguish "not found" from "broken".
|
|
121
102
|
*/
|
|
122
103
|
async fetchPass(objectId) {
|
|
104
|
+
// Validate objectId format before hitting the network
|
|
123
105
|
if (!objectId || objectId.length < 10) {
|
|
124
106
|
throw new Error(`EdgePass.fetch: invalid objectId "${objectId}". ` +
|
|
125
107
|
`Expected a Sui object ID starting with 0x.`);
|
|
@@ -132,18 +114,17 @@ class ExecutionEngine {
|
|
|
132
114
|
id: objectId,
|
|
133
115
|
options: { showContent: true },
|
|
134
116
|
});
|
|
135
|
-
|
|
117
|
+
// Object exists but has no content — deleted or wrong type
|
|
118
|
+
if (!obj.data?.content) {
|
|
136
119
|
return null;
|
|
120
|
+
}
|
|
137
121
|
if (obj.data.content.dataType !== 'moveObject') {
|
|
138
122
|
throw new Error(`EdgePass.fetch: object ${objectId} is not a Move object. ` +
|
|
139
123
|
`Make sure you're passing an EdgePass object ID, not a transaction digest.`);
|
|
140
124
|
}
|
|
141
125
|
const fields = obj.data.content.fields;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
'approved_merchants', 'owner', 'spent', 'active',
|
|
145
|
-
'created_at', 'expires_at',
|
|
146
|
-
];
|
|
126
|
+
// Validate required fields exist before accessing
|
|
127
|
+
const requiredFields = ['budget', 'auto_threshold', 'escalate_threshold', 'approved_merchants', 'owner', 'spent', 'active', 'created_at', 'expires_at'];
|
|
147
128
|
for (const field of requiredFields) {
|
|
148
129
|
if (fields[field] === undefined) {
|
|
149
130
|
throw new Error(`EdgePass.fetch: object ${objectId} is missing field "${field}". ` +
|
|
@@ -164,19 +145,14 @@ class ExecutionEngine {
|
|
|
164
145
|
active: fields.active,
|
|
165
146
|
createdAt: Number(fields.created_at),
|
|
166
147
|
expiresAt: Number(fields.expires_at),
|
|
167
|
-
// Populate objectRef for optimized PTB construction
|
|
168
|
-
// This allows execute() to skip the RPC version resolution call
|
|
169
|
-
objectRef: obj.data.version && obj.data.digest ? {
|
|
170
|
-
objectId: objectId,
|
|
171
|
-
version: obj.data.version,
|
|
172
|
-
digest: obj.data.digest,
|
|
173
|
-
} : undefined,
|
|
174
148
|
};
|
|
175
149
|
}
|
|
176
150
|
catch (error) {
|
|
151
|
+
// Re-throw our own errors as-is
|
|
177
152
|
if (error instanceof Error && error.message.startsWith('EdgePass')) {
|
|
178
153
|
throw error;
|
|
179
154
|
}
|
|
155
|
+
// Wrap network/RPC errors with context
|
|
180
156
|
const msg = error instanceof Error ? error.message : String(error);
|
|
181
157
|
throw new Error(`EdgePass.fetch: network error fetching object ${objectId}. ` +
|
|
182
158
|
`Check your Sui RPC connection. (${msg})`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExecutionEngine.js","sourceRoot":"","sources":["../../src/core/ExecutionEngine.ts"],"names":[],"mappings":";;;AAAA,+CAA+C;AAC/C,2DAAuD;AAOvD,iDAA8C;AAC9C,kDAAuF;AAEvF,wCAAwC;AAC3B,QAAA,gBAAgB,GAAG;IAC9B,eAAe,EAAK,iBAAiB;IACrC,eAAe,EAAK,iBAAiB;IACrC,iBAAiB,EAAG,mBAAmB;IACvC,gBAAgB,EAAI,kBAAkB;IACtC,kBAAkB,EAAE,oBAAoB;IACxC,
|
|
1
|
+
{"version":3,"file":"ExecutionEngine.js","sourceRoot":"","sources":["../../src/core/ExecutionEngine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EdgePassObject, TransactionRequest, PolicyValidation } from '../utils/types';
|
|
1
|
+
import { EdgePassObject, TransactionRequest, PolicyValidation, SimulationResult, BudgetStatus } from '../utils/types';
|
|
2
2
|
export declare class PolicyEngine {
|
|
3
3
|
/**
|
|
4
4
|
* Validates a transaction request against an EdgePass policy.
|
|
@@ -13,6 +13,23 @@ export declare class PolicyEngine {
|
|
|
13
13
|
* 7. If amount ≤ autoThreshold → auto-approve
|
|
14
14
|
*/
|
|
15
15
|
static validate(pass: EdgePassObject, request: TransactionRequest): PolicyValidation;
|
|
16
|
+
/**
|
|
17
|
+
* Simulate a sequence of transactions against an EdgePass.
|
|
18
|
+
* Zero network calls. Returns predicted outcomes for all decisions
|
|
19
|
+
* including projected budget state after each step.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const plan = sdk.simulate(pass, claudeDecisions);
|
|
23
|
+
* console.log(plan.approved.length); // decisions that will execute
|
|
24
|
+
* console.log(plan.blocked.length); // decisions that will be rejected
|
|
25
|
+
* console.log(plan.utilizationPct); // projected budget usage
|
|
26
|
+
*
|
|
27
|
+
* // Show plan to user, then execute approved decisions
|
|
28
|
+
* for (const decision of plan.approved) {
|
|
29
|
+
* await sdk.execute(pass, decision.request, signer);
|
|
30
|
+
* }
|
|
31
|
+
*/
|
|
32
|
+
static simulate(pass: EdgePassObject, requests: TransactionRequest[]): SimulationResult;
|
|
16
33
|
/**
|
|
17
34
|
* Returns true if the pass is active and not expired.
|
|
18
35
|
*/
|
|
@@ -21,5 +38,44 @@ export declare class PolicyEngine {
|
|
|
21
38
|
* Returns the remaining budget in MIST.
|
|
22
39
|
*/
|
|
23
40
|
static remainingBudget(pass: EdgePassObject): bigint;
|
|
41
|
+
/**
|
|
42
|
+
* Returns budget utilization as a percentage (0-100).
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const pct = sdk.utilizationPct(pass);
|
|
46
|
+
* if (pct > 80) warnUser('Running low on budget');
|
|
47
|
+
*/
|
|
48
|
+
static utilizationPct(pass: EdgePassObject): number;
|
|
49
|
+
/**
|
|
50
|
+
* Returns true if budget utilization exceeds the given threshold.
|
|
51
|
+
* Default threshold is 80%.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* if (sdk.isNearLimit(pass)) notifyUser('Budget nearly exhausted');
|
|
55
|
+
* if (sdk.isNearLimit(pass, 0.5)) notifyUser('Halfway through budget');
|
|
56
|
+
*/
|
|
57
|
+
static isNearLimit(pass: EdgePassObject, threshold?: number): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Returns a complete budget status snapshot.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* const status = sdk.budgetStatus(pass);
|
|
63
|
+
* if (status.isExhausted) stopAgent();
|
|
64
|
+
* if (status.isNearLimit) notifyUser(`${status.utilizationPct}% spent`);
|
|
65
|
+
*/
|
|
66
|
+
static budgetStatus(pass: EdgePassObject, nearLimitThreshold?: number): BudgetStatus;
|
|
67
|
+
/**
|
|
68
|
+
* Returns the time remaining on the pass in milliseconds.
|
|
69
|
+
* Returns 0 if expired.
|
|
70
|
+
*/
|
|
71
|
+
static timeRemaining(pass: EdgePassObject): number;
|
|
72
|
+
/**
|
|
73
|
+
* Returns true if the pass will expire within the given window.
|
|
74
|
+
* Default window is 1 hour.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* if (sdk.isExpiringSoon(pass)) notifyUser('Pass expires in less than 1 hour');
|
|
78
|
+
*/
|
|
79
|
+
static isExpiringSoon(pass: EdgePassObject, withinMs?: number): boolean;
|
|
24
80
|
}
|
|
25
81
|
//# sourceMappingURL=PolicyEngine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PolicyEngine.d.ts","sourceRoot":"","sources":["../../src/core/PolicyEngine.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"PolicyEngine.d.ts","sourceRoot":"","sources":["../../src/core/PolicyEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAEhB,gBAAgB,EAChB,YAAY,EACb,MAAM,gBAAgB,CAAC;AAExB,qBAAa,YAAY;IAEvB;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,kBAAkB,GAC1B,gBAAgB;IAqCnB;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,QAAQ,CACb,IAAI,EAAE,cAAc,EACpB,QAAQ,EAAE,kBAAkB,EAAE,GAC7B,gBAAgB;IA8DnB;;OAEG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO;IAI7C;;OAEG;IACH,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM;IAIpD;;;;;;OAMG;IACH,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM;IAKnD;;;;;;;OAOG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,SAAM,GAAG,OAAO;IAIlE;;;;;;;OAOG;IACH,MAAM,CAAC,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,kBAAkB,SAAM,GAAG,YAAY;IAajF;;;OAGG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM;IAIlD;;;;;;OAMG;IACH,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,SAAiB,GAAG,OAAO;CAIhF"}
|
|
@@ -17,59 +17,101 @@ class PolicyEngine {
|
|
|
17
17
|
static validate(pass, request) {
|
|
18
18
|
// Rule 1 — pass must be active
|
|
19
19
|
if (!pass.active) {
|
|
20
|
-
return {
|
|
21
|
-
allowed: false,
|
|
22
|
-
requiresEscalation: false,
|
|
23
|
-
reason: 'EdgePass is inactive',
|
|
24
|
-
};
|
|
20
|
+
return { allowed: false, requiresEscalation: false, reason: 'EdgePass is inactive' };
|
|
25
21
|
}
|
|
26
22
|
// Rule 2 — pass must not be expired
|
|
27
23
|
if (Date.now() > pass.expiresAt) {
|
|
28
|
-
return {
|
|
29
|
-
allowed: false,
|
|
30
|
-
requiresEscalation: false,
|
|
31
|
-
reason: 'EdgePass has expired',
|
|
32
|
-
};
|
|
24
|
+
return { allowed: false, requiresEscalation: false, reason: 'EdgePass has expired' };
|
|
33
25
|
}
|
|
34
26
|
// Rule 3 — merchant must be approved
|
|
35
27
|
if (!pass.config.approvedMerchants.includes(request.merchant)) {
|
|
36
|
-
return {
|
|
37
|
-
allowed: false,
|
|
38
|
-
requiresEscalation: false,
|
|
39
|
-
reason: `Merchant "${request.merchant}" is not approved`,
|
|
40
|
-
};
|
|
28
|
+
return { allowed: false, requiresEscalation: false, reason: `Merchant "${request.merchant}" is not approved` };
|
|
41
29
|
}
|
|
42
30
|
// Rule 4 — must not exceed remaining budget
|
|
43
31
|
const remaining = pass.config.budget - pass.spent;
|
|
44
32
|
if (request.amount > remaining) {
|
|
45
|
-
return {
|
|
46
|
-
allowed: false,
|
|
47
|
-
requiresEscalation: false,
|
|
48
|
-
reason: `Insufficient budget. Remaining: ${remaining} MIST`,
|
|
49
|
-
};
|
|
33
|
+
return { allowed: false, requiresEscalation: false, reason: `Insufficient budget. Remaining: ${remaining} MIST` };
|
|
50
34
|
}
|
|
51
35
|
// Rule 5 — must not exceed per-transaction limit (if set)
|
|
52
|
-
if (pass.config.maxPerTransaction !== undefined &&
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
allowed: false,
|
|
56
|
-
requiresEscalation: false,
|
|
57
|
-
reason: `Amount exceeds per-transaction limit of ${pass.config.maxPerTransaction} MIST`,
|
|
58
|
-
};
|
|
36
|
+
if (pass.config.maxPerTransaction !== undefined && request.amount > pass.config.maxPerTransaction) {
|
|
37
|
+
return { allowed: false, requiresEscalation: false, reason: `Amount exceeds per-transaction limit of ${pass.config.maxPerTransaction} MIST` };
|
|
59
38
|
}
|
|
60
39
|
// Rule 6 — escalate if above escalation threshold
|
|
61
40
|
if (request.amount > pass.config.escalateThreshold) {
|
|
62
|
-
return {
|
|
63
|
-
allowed: true,
|
|
64
|
-
requiresEscalation: true,
|
|
65
|
-
reason: `Amount exceeds escalation threshold of ${pass.config.escalateThreshold} MIST`,
|
|
66
|
-
};
|
|
41
|
+
return { allowed: true, requiresEscalation: true, reason: `Amount exceeds escalation threshold of ${pass.config.escalateThreshold} MIST` };
|
|
67
42
|
}
|
|
68
43
|
// Rule 7 — auto-approve
|
|
44
|
+
return { allowed: true, requiresEscalation: false, reason: 'Auto-approved' };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Simulate a sequence of transactions against an EdgePass.
|
|
48
|
+
* Zero network calls. Returns predicted outcomes for all decisions
|
|
49
|
+
* including projected budget state after each step.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* const plan = sdk.simulate(pass, claudeDecisions);
|
|
53
|
+
* console.log(plan.approved.length); // decisions that will execute
|
|
54
|
+
* console.log(plan.blocked.length); // decisions that will be rejected
|
|
55
|
+
* console.log(plan.utilizationPct); // projected budget usage
|
|
56
|
+
*
|
|
57
|
+
* // Show plan to user, then execute approved decisions
|
|
58
|
+
* for (const decision of plan.approved) {
|
|
59
|
+
* await sdk.execute(pass, decision.request, signer);
|
|
60
|
+
* }
|
|
61
|
+
*/
|
|
62
|
+
static simulate(pass, requests) {
|
|
63
|
+
const decisions = [];
|
|
64
|
+
let projectedSpent = pass.spent;
|
|
65
|
+
for (const request of requests) {
|
|
66
|
+
// Create a projected pass with current projected spent for validation
|
|
67
|
+
const projectedPass = {
|
|
68
|
+
...pass,
|
|
69
|
+
spent: projectedSpent,
|
|
70
|
+
};
|
|
71
|
+
const validation = PolicyEngine.validate(projectedPass, request);
|
|
72
|
+
let outcome;
|
|
73
|
+
let nextSpent = projectedSpent;
|
|
74
|
+
if (!validation.allowed) {
|
|
75
|
+
outcome = 'blocked';
|
|
76
|
+
}
|
|
77
|
+
else if (validation.requiresEscalation) {
|
|
78
|
+
outcome = 'escalated';
|
|
79
|
+
// Escalated decisions don't spend budget until approved
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
outcome = 'approved';
|
|
83
|
+
nextSpent = projectedSpent + request.amount;
|
|
84
|
+
}
|
|
85
|
+
const decision = {
|
|
86
|
+
request,
|
|
87
|
+
outcome,
|
|
88
|
+
reason: validation.reason,
|
|
89
|
+
projectedSpent: nextSpent,
|
|
90
|
+
projectedRemaining: pass.config.budget - nextSpent,
|
|
91
|
+
};
|
|
92
|
+
decisions.push(decision);
|
|
93
|
+
projectedSpent = nextSpent;
|
|
94
|
+
}
|
|
95
|
+
const approved = decisions.filter(d => d.outcome === 'approved');
|
|
96
|
+
const blocked = decisions.filter(d => d.outcome === 'blocked');
|
|
97
|
+
const escalated = decisions.filter(d => d.outcome === 'escalated');
|
|
98
|
+
const totalSpend = approved.reduce((sum, d) => sum + d.request.amount, 0n);
|
|
99
|
+
const remainingBudget = pass.config.budget - pass.spent - totalSpend;
|
|
100
|
+
const utilizationPct = Number((pass.spent + totalSpend) * 100n / pass.config.budget);
|
|
69
101
|
return {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
102
|
+
decisions,
|
|
103
|
+
approved,
|
|
104
|
+
blocked,
|
|
105
|
+
escalated,
|
|
106
|
+
totalSpend,
|
|
107
|
+
remainingBudget,
|
|
108
|
+
utilizationPct,
|
|
109
|
+
summary: {
|
|
110
|
+
approvedCount: approved.length,
|
|
111
|
+
blockedCount: blocked.length,
|
|
112
|
+
escalatedCount: escalated.length,
|
|
113
|
+
totalDecisions: decisions.length,
|
|
114
|
+
},
|
|
73
115
|
};
|
|
74
116
|
}
|
|
75
117
|
/**
|
|
@@ -84,6 +126,67 @@ class PolicyEngine {
|
|
|
84
126
|
static remainingBudget(pass) {
|
|
85
127
|
return pass.config.budget - pass.spent;
|
|
86
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Returns budget utilization as a percentage (0-100).
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* const pct = sdk.utilizationPct(pass);
|
|
134
|
+
* if (pct > 80) warnUser('Running low on budget');
|
|
135
|
+
*/
|
|
136
|
+
static utilizationPct(pass) {
|
|
137
|
+
if (pass.config.budget === 0n)
|
|
138
|
+
return 0;
|
|
139
|
+
return Number(pass.spent * 100n / pass.config.budget);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Returns true if budget utilization exceeds the given threshold.
|
|
143
|
+
* Default threshold is 80%.
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* if (sdk.isNearLimit(pass)) notifyUser('Budget nearly exhausted');
|
|
147
|
+
* if (sdk.isNearLimit(pass, 0.5)) notifyUser('Halfway through budget');
|
|
148
|
+
*/
|
|
149
|
+
static isNearLimit(pass, threshold = 0.8) {
|
|
150
|
+
return PolicyEngine.utilizationPct(pass) >= threshold * 100;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Returns a complete budget status snapshot.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* const status = sdk.budgetStatus(pass);
|
|
157
|
+
* if (status.isExhausted) stopAgent();
|
|
158
|
+
* if (status.isNearLimit) notifyUser(`${status.utilizationPct}% spent`);
|
|
159
|
+
*/
|
|
160
|
+
static budgetStatus(pass, nearLimitThreshold = 0.8) {
|
|
161
|
+
const remaining = pass.config.budget - pass.spent;
|
|
162
|
+
const utilizationPct = PolicyEngine.utilizationPct(pass);
|
|
163
|
+
return {
|
|
164
|
+
budget: pass.config.budget,
|
|
165
|
+
spent: pass.spent,
|
|
166
|
+
remaining,
|
|
167
|
+
utilizationPct,
|
|
168
|
+
isNearLimit: utilizationPct >= nearLimitThreshold * 100,
|
|
169
|
+
isExhausted: remaining === 0n,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Returns the time remaining on the pass in milliseconds.
|
|
174
|
+
* Returns 0 if expired.
|
|
175
|
+
*/
|
|
176
|
+
static timeRemaining(pass) {
|
|
177
|
+
return Math.max(0, pass.expiresAt - Date.now());
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Returns true if the pass will expire within the given window.
|
|
181
|
+
* Default window is 1 hour.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* if (sdk.isExpiringSoon(pass)) notifyUser('Pass expires in less than 1 hour');
|
|
185
|
+
*/
|
|
186
|
+
static isExpiringSoon(pass, withinMs = 60 * 60 * 1000) {
|
|
187
|
+
const remaining = PolicyEngine.timeRemaining(pass);
|
|
188
|
+
return remaining > 0 && remaining <= withinMs;
|
|
189
|
+
}
|
|
87
190
|
}
|
|
88
191
|
exports.PolicyEngine = PolicyEngine;
|
|
89
192
|
//# sourceMappingURL=PolicyEngine.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PolicyEngine.js","sourceRoot":"","sources":["../../src/core/PolicyEngine.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"PolicyEngine.js","sourceRoot":"","sources":["../../src/core/PolicyEngine.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { EdgePass } from './core/EdgePass';
|
|
2
2
|
export { PolicyEngine } from './core/PolicyEngine';
|
|
3
3
|
export { ExecutionEngine } from './core/ExecutionEngine';
|
|
4
|
-
export type { EdgePassConfig, EdgePassObject, TransactionRequest, TransactionOutcome, PolicyValidation, Network, EdgeSDKConfig, } from './utils/types';
|
|
4
|
+
export type { EdgePassConfig, EdgePassObject, TransactionRequest, TransactionOutcome, PolicyValidation, SimulatedDecision, SimulationResult, BudgetStatus, Network, EdgeSDKConfig, } from './utils/types';
|
|
5
5
|
export { MIST_PER_SUI, NETWORK_URLS, EDGE_PACKAGE_ID, EDGE_TEMPLATES, DEFAULT_GAS_BUDGET, } from './utils/constants';
|
|
6
6
|
export type { EdgePassTemplate } from './utils/constants';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EACV,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,OAAO,EACP,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,cAAc,EACd,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EACV,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACP,aAAa,GACd,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,cAAc,EACd,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,4CAA2C;AAAlC,oGAAA,QAAQ,OAAA;AACjB,oDAAmD;AAA1C,4GAAA,YAAY,OAAA;AACrB,0DAAyD;AAAhD,kHAAA,eAAe,OAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,4CAA2C;AAAlC,oGAAA,QAAQ,OAAA;AACjB,oDAAmD;AAA1C,4GAAA,YAAY,OAAA;AACrB,0DAAyD;AAAhD,kHAAA,eAAe,OAAA;AAaxB,+CAM2B;AALzB,yGAAA,YAAY,OAAA;AACZ,yGAAA,YAAY,OAAA;AACZ,4GAAA,eAAe,OAAA;AACf,2GAAA,cAAc,OAAA;AACd,+GAAA,kBAAkB,OAAA"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Transaction } from '@mysten/sui/transactions';
|
|
2
|
+
import { EdgePass } from '../core/EdgePass';
|
|
3
|
+
import { EdgePassObject, TransactionRequest, TransactionOutcome, SimulationResult, BudgetStatus, Network } from '../utils/types';
|
|
4
|
+
export interface UseEdgePassConfig {
|
|
5
|
+
passId: string;
|
|
6
|
+
network: Network;
|
|
7
|
+
enokiApiKey: string;
|
|
8
|
+
signer?: {
|
|
9
|
+
signAndExecute: (tx: Transaction) => Promise<{
|
|
10
|
+
digest: string;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
autoRefresh?: boolean;
|
|
14
|
+
pollInterval?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface UseEdgePassResult {
|
|
17
|
+
pass: EdgePassObject | null;
|
|
18
|
+
loading: boolean;
|
|
19
|
+
error: Error | null;
|
|
20
|
+
execute: (request: TransactionRequest) => Promise<TransactionOutcome>;
|
|
21
|
+
simulate: (requests: TransactionRequest[]) => SimulationResult | null;
|
|
22
|
+
budgetStatus: BudgetStatus | null;
|
|
23
|
+
refresh: () => Promise<void>;
|
|
24
|
+
sdk: EdgePass;
|
|
25
|
+
}
|
|
26
|
+
export declare function useEdgePass({ passId, network, enokiApiKey, signer, autoRefresh, pollInterval, }: UseEdgePassConfig): UseEdgePassResult;
|
|
27
|
+
export declare function useBudgetStatus(config: UseEdgePassConfig): BudgetStatus | null;
|
|
28
|
+
export declare function useSimulate(config: UseEdgePassConfig, requests: TransactionRequest[]): SimulationResult | null;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,YAAY,EACZ,OAAO,EACR,MAAM,gBAAgB,CAAC;AAExB,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAS,MAAM,CAAC;IACtB,OAAO,EAAQ,OAAO,CAAC;IACvB,WAAW,EAAI,MAAM,CAAC;IACtB,MAAM,CAAC,EAAQ;QAAE,cAAc,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC;YAAE,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IACpF,WAAW,CAAC,EAAG,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAU,cAAc,GAAG,IAAI,CAAC;IACpC,OAAO,EAAO,OAAO,CAAC;IACtB,KAAK,EAAS,KAAK,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAO,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC3E,QAAQ,EAAM,CAAC,QAAQ,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,GAAG,IAAI,CAAC;IAC1E,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,OAAO,EAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,GAAG,EAAW,QAAQ,CAAC;CACxB;AAED,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,OAAO,EACP,WAAW,EACX,MAAM,EACN,WAAkB,EAClB,YAAgB,GACjB,EAAE,iBAAiB,GAAG,iBAAiB,CAsDvC;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG,YAAY,GAAG,IAAI,CAG9E;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,kBAAkB,EAAE,GAC7B,gBAAgB,GAAG,IAAI,CAGzB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useEdgePass = useEdgePass;
|
|
4
|
+
exports.useBudgetStatus = useBudgetStatus;
|
|
5
|
+
exports.useSimulate = useSimulate;
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const EdgePass_1 = require("../core/EdgePass");
|
|
8
|
+
function useEdgePass({ passId, network, enokiApiKey, signer, autoRefresh = true, pollInterval = 0, }) {
|
|
9
|
+
const [pass, setPass] = (0, react_1.useState)(null);
|
|
10
|
+
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
11
|
+
const [error, setError] = (0, react_1.useState)(null);
|
|
12
|
+
const sdkRef = (0, react_1.useRef)(new EdgePass_1.EdgePass({ network, enokiApiKey }));
|
|
13
|
+
(0, react_1.useEffect)(() => {
|
|
14
|
+
sdkRef.current = new EdgePass_1.EdgePass({ network, enokiApiKey });
|
|
15
|
+
}, [network, enokiApiKey]);
|
|
16
|
+
const refresh = (0, react_1.useCallback)(async () => {
|
|
17
|
+
if (!passId)
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
setError(null);
|
|
21
|
+
const fetched = await sdkRef.current.fetch(passId);
|
|
22
|
+
setPass(fetched);
|
|
23
|
+
}
|
|
24
|
+
catch (e) {
|
|
25
|
+
setError(e instanceof Error ? e : new Error(String(e)));
|
|
26
|
+
}
|
|
27
|
+
}, [passId]);
|
|
28
|
+
(0, react_1.useEffect)(() => {
|
|
29
|
+
let cancelled = false;
|
|
30
|
+
setLoading(true);
|
|
31
|
+
sdkRef.current.fetch(passId)
|
|
32
|
+
.then(fetched => { if (!cancelled) {
|
|
33
|
+
setPass(fetched);
|
|
34
|
+
setError(null);
|
|
35
|
+
} })
|
|
36
|
+
.catch(e => { if (!cancelled)
|
|
37
|
+
setError(e instanceof Error ? e : new Error(String(e))); })
|
|
38
|
+
.finally(() => { if (!cancelled)
|
|
39
|
+
setLoading(false); });
|
|
40
|
+
return () => { cancelled = true; };
|
|
41
|
+
}, [passId]);
|
|
42
|
+
(0, react_1.useEffect)(() => {
|
|
43
|
+
if (!pollInterval || pollInterval <= 0)
|
|
44
|
+
return;
|
|
45
|
+
const interval = setInterval(refresh, pollInterval);
|
|
46
|
+
return () => clearInterval(interval);
|
|
47
|
+
}, [refresh, pollInterval]);
|
|
48
|
+
const execute = (0, react_1.useCallback)(async (request) => {
|
|
49
|
+
if (!pass)
|
|
50
|
+
throw new Error('EdgePass not loaded');
|
|
51
|
+
if (!signer)
|
|
52
|
+
throw new Error('No signer provided');
|
|
53
|
+
const outcome = await sdkRef.current.execute(pass, request, signer);
|
|
54
|
+
if (outcome.status === 'approved' && autoRefresh)
|
|
55
|
+
await refresh();
|
|
56
|
+
return outcome;
|
|
57
|
+
}, [pass, signer, autoRefresh, refresh]);
|
|
58
|
+
const simulate = (0, react_1.useCallback)((requests) => {
|
|
59
|
+
if (!pass)
|
|
60
|
+
return null;
|
|
61
|
+
return sdkRef.current.simulate(pass, requests);
|
|
62
|
+
}, [pass]);
|
|
63
|
+
const budgetStatus = pass ? sdkRef.current.budgetStatus(pass) : null;
|
|
64
|
+
return { pass, loading, error, execute, simulate, budgetStatus, refresh, sdk: sdkRef.current };
|
|
65
|
+
}
|
|
66
|
+
function useBudgetStatus(config) {
|
|
67
|
+
const { budgetStatus } = useEdgePass(config);
|
|
68
|
+
return budgetStatus;
|
|
69
|
+
}
|
|
70
|
+
function useSimulate(config, requests) {
|
|
71
|
+
const { simulate } = useEdgePass(config);
|
|
72
|
+
return simulate(requests);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
|