payid 1.1.0 → 2.0.3

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 CHANGED
@@ -1,15 +1,478 @@
1
- # sdk-core
2
-
3
- To install dependencies:
4
-
5
- ```bash
6
- bun install
7
- ```
8
-
9
- To run:
10
-
11
- ```bash
12
- bun run src/index.ts
13
- ```
14
-
15
- This project was created using `bun init` in bun v1.2.21. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
1
+ # PayID SDK — `payid`
2
+
3
+ Policy-driven payment engine for EVM chains. Define **rules** that evaluate payment context off-chain, then submit a cryptographic **Decision Proof** on-chain for verification.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bun add payid ethers
9
+ # or
10
+ npm install payid ethers
11
+ ```
12
+
13
+ ---
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { PayIDClient } from "payid/client";
19
+ import { ethers } from "ethers";
20
+
21
+ const client = new PayIDClient();
22
+
23
+ const result = await client.evaluateAndProve({
24
+ context: {
25
+ tx: {
26
+ sender: "0xSender...",
27
+ receiver: "0xReceiver...",
28
+ asset: "0x0000000000000000000000000000000000000000", // native token
29
+ amount: "1000000000000000000", // 1 ETH in wei
30
+ chainId: 42161, // Arbitrum
31
+ },
32
+ },
33
+ authorityRule: myRuleConfig,
34
+ payId: "user@pay.id",
35
+ payer: "0xSender...",
36
+ receiver: "0xReceiver...",
37
+ asset: "0x0000000000000000000000000000000000000000",
38
+ amount: 1_000_000_000_000_000_000n,
39
+ signer: wallet,
40
+ verifyingContract: "0xPayWithPayID...",
41
+ ruleAuthority: "0xRuleAuthority...",
42
+ chainId: 42161,
43
+ blockTimestamp: Math.floor(Date.now() / 1000),
44
+ });
45
+
46
+ if (result.result.decision === "ALLOW") {
47
+ // submit result.proof to PayWithPayID.payNative() on-chain
48
+ }
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Rule Language
54
+
55
+ Rules define **what conditions must be true** for a payment to be allowed. They are evaluated off-chain, and the outcome is signed into a Decision Proof that the smart contract verifies.
56
+
57
+ ### Rule Config
58
+
59
+ Every rule set starts with a `RuleConfig`:
60
+
61
+ ```typescript
62
+ interface RuleConfig {
63
+ logic: "AND" | "OR"; // how top-level rules are combined
64
+ rules: AnyRule[]; // list of rules
65
+ requires?: string[]; // required context namespaces (e.g. ["state", "risk"])
66
+ message?: string; // custom message on root rejection
67
+ }
68
+ ```
69
+
70
+ - **`AND`** — all rules must pass
71
+ - **`OR`** — at least one rule must pass
72
+ - Max nesting depth: **10 levels**
73
+
74
+ ---
75
+
76
+ ### Rule Formats
77
+
78
+ There are three rule formats that can be mixed freely.
79
+
80
+ #### Format A — Simple Rule
81
+
82
+ One condition, one rule.
83
+
84
+ ```typescript
85
+ {
86
+ id: "min-amount",
87
+ if: { field: "tx.amount", op: ">=", value: "100000000000000000" },
88
+ message: "Minimum transfer is 0.1 ETH"
89
+ }
90
+ ```
91
+
92
+ #### Format B — Multi-Condition Rule
93
+
94
+ Multiple conditions combined with `AND` / `OR`.
95
+
96
+ ```typescript
97
+ {
98
+ id: "business-hours",
99
+ logic: "AND",
100
+ conditions: [
101
+ { field: "env.timestamp|hour", op: ">=", value: "9" },
102
+ { field: "env.timestamp|hour", op: "<", value: "17" },
103
+ ],
104
+ message: "Transfers only allowed during business hours (9–17 UTC)"
105
+ }
106
+ ```
107
+
108
+ #### Format C — Nested Rule
109
+
110
+ Groups of rules combined with `AND` / `OR`. Can be nested up to 10 levels deep.
111
+
112
+ ```typescript
113
+ {
114
+ id: "whitelist-or-small",
115
+ logic: "OR",
116
+ rules: [
117
+ { id: "in-whitelist", if: { field: "tx.sender", op: "in", value: ["0xAlice", "0xBob"] } },
118
+ { id: "small-amount", if: { field: "tx.amount", op: "<=", value: "50000000000000000" } }
119
+ ]
120
+ }
121
+ ```
122
+
123
+ ---
124
+
125
+ ### Conditions
126
+
127
+ ```typescript
128
+ interface RuleCondition {
129
+ field: string; // dot-notation path into the context
130
+ op: string; // operator
131
+ value: any; // literal value or "$field.reference"
132
+ }
133
+ ```
134
+
135
+ ---
136
+
137
+ ### Fields (Context Paths)
138
+
139
+ Fields use dot-notation to navigate the payment context.
140
+
141
+ #### Core Context (`tx`)
142
+
143
+ | Field | Type | Description |
144
+ |---|---|---|
145
+ | `tx.amount` | `string` (wei) | Transfer amount in smallest unit |
146
+ | `tx.amountUsd` | `string` | USD equivalent (if oracle provided) |
147
+ | `tx.asset` | `string` | Token contract address; `0x000...000` for native |
148
+ | `tx.sender` | `string` | Sender address |
149
+ | `tx.receiver` | `string` | Receiver address |
150
+ | `tx.chainId` | `number` | EVM chain ID |
151
+
152
+ #### Pay.ID Context (`payId`)
153
+
154
+ | Field | Type | Description |
155
+ |---|---|---|
156
+ | `payId.id` | `string` | The Pay.ID handle (e.g. `user@pay.id`) |
157
+ | `payId.owner` | `string` | Address that owns this Pay.ID |
158
+
159
+ #### Intent Context (`intent`)
160
+
161
+ | Field | Type | Description |
162
+ |---|---|---|
163
+ | `intent.type` | `"QR" \| "DIRECT" \| "API"` | How payment was initiated |
164
+ | `intent.expiresAt` | `number` | Unix timestamp when intent expires |
165
+ | `intent.issuer` | `string` | Who issued the intent |
166
+
167
+ #### Environment Context (`env`) — V2
168
+
169
+ | Field | Type | Description |
170
+ |---|---|---|
171
+ | `env.timestamp` | `number` | Current block timestamp (Unix seconds) |
172
+
173
+ #### State Context (`state`) — V2
174
+
175
+ | Field | Type | Description |
176
+ |---|---|---|
177
+ | `state.spentToday` | `string` | Total amount spent today (wei) |
178
+ | `state.period` | `string` | Current period identifier |
179
+
180
+ #### Oracle Context (`oracle`) — V2
181
+
182
+ Custom key-value data from an off-chain oracle. Example: `oracle.ethPrice`, `oracle.gasPrice`.
183
+
184
+ #### Risk Context (`risk`) — V2
185
+
186
+ | Field | Type | Description |
187
+ |---|---|---|
188
+ | `risk.score` | `number` | Risk score 0–1000 |
189
+ | `risk.category` | `string` | Risk category label |
190
+
191
+ ---
192
+
193
+ ### Field Transforms
194
+
195
+ Append `|transform` to a field to transform its value before comparison.
196
+
197
+ ```
198
+ "env.timestamp|hour" → hour of day (0–23)
199
+ "tx.amount|div:1e18" → amount divided by 1e18
200
+ ```
201
+
202
+ | Transform | Syntax | Description |
203
+ |---|---|---|
204
+ | `div` | `field\|div:N` | Divide by N (integer) |
205
+ | `mod` | `field\|mod:N` | Modulo N |
206
+ | `abs` | `field\|abs` | Absolute value |
207
+ | `hour` | `field\|hour` | Hour of day from Unix timestamp (0–23) |
208
+ | `day` | `field\|day` | Day of week from Unix timestamp (0=Mon, 6=Sun) |
209
+ | `date` | `field\|date` | Day of month (1–31) |
210
+ | `month` | `field\|month` | Month of year (1–12) |
211
+ | `len` | `field\|len` | String length |
212
+ | `lower` | `field\|lower` | Lowercase string |
213
+ | `upper` | `field\|upper` | Uppercase string |
214
+
215
+ ---
216
+
217
+ ### Operators
218
+
219
+ #### Numeric
220
+
221
+ | Operator | Description | Example |
222
+ |---|---|---|
223
+ | `>=` | Greater than or equal | `amount >= 1000` |
224
+ | `<=` | Less than or equal | `amount <= 50000` |
225
+ | `>` | Greater than | `amount > 0` |
226
+ | `<` | Less than | `risk.score < 700` |
227
+ | `between` | Inclusive range `[min, max]` | `value: ["100", "5000"]` |
228
+ | `not_between` | Outside range | `value: ["100", "5000"]` |
229
+ | `mod_eq` | `field % divisor == remainder` | `value: ["7", "0"]` (divisible by 7) |
230
+ | `mod_ne` | `field % divisor != remainder` | |
231
+
232
+ #### Equality
233
+
234
+ | Operator | Description |
235
+ |---|---|
236
+ | `==` | Loose equality (string + numeric coercion) |
237
+ | `!=` | Not equal |
238
+ | `in` | Value is in array |
239
+ | `not_in` | Value is not in array |
240
+
241
+ #### String
242
+
243
+ | Operator | Description |
244
+ |---|---|
245
+ | `contains` | String contains substring |
246
+ | `not_contains` | String does not contain substring |
247
+ | `starts_with` | String starts with prefix |
248
+ | `ends_with` | String ends with suffix |
249
+ | `regex` | Matches regex pattern (ReDoS-safe, max 200 chars) |
250
+ | `not_regex` | Does not match regex |
251
+
252
+ #### Existence
253
+
254
+ | Operator | Description |
255
+ |---|---|
256
+ | `exists` | Field is present and not null |
257
+ | `not_exists` | Field is absent or null |
258
+
259
+ ---
260
+
261
+ ### Cross-Field References
262
+
263
+ Prefix a value with `$` to compare against another field in the context.
264
+
265
+ ```typescript
266
+ // Reject if spending more than today's limit
267
+ { field: "tx.amount", op: "<=", value: "$state.dailyLimit" }
268
+
269
+ // Only allow if sender equals the Pay.ID owner
270
+ { field: "tx.sender", op: "==", value: "$payId.owner" }
271
+ ```
272
+
273
+ ---
274
+
275
+ ### Message Interpolation
276
+
277
+ Rule messages support `{field}` interpolation using the same dot-notation and transforms.
278
+
279
+ ```typescript
280
+ {
281
+ id: "amount-cap",
282
+ if: { field: "tx.amount", op: "<=", value: "1000000000000000000" },
283
+ message: "Rejected: amount {tx.amount} exceeds 1 ETH cap"
284
+ }
285
+ ```
286
+
287
+ ---
288
+
289
+ ## Complete Examples
290
+
291
+ ### 1. Simple Amount Cap
292
+
293
+ ```typescript
294
+ const rule: RuleConfig = {
295
+ logic: "AND",
296
+ rules: [
297
+ {
298
+ id: "max-per-tx",
299
+ if: { field: "tx.amount", op: "<=", value: "5000000000000000000" },
300
+ message: "Max 5 ETH per transaction"
301
+ }
302
+ ]
303
+ };
304
+ ```
305
+
306
+ ### 2. Daily Spending Limit
307
+
308
+ ```typescript
309
+ const rule: RuleConfig = {
310
+ logic: "AND",
311
+ requires: ["state"],
312
+ rules: [
313
+ {
314
+ id: "daily-limit",
315
+ if: { field: "state.spentToday", op: "<=", value: "10000000000000000000" },
316
+ message: "Daily limit of 10 ETH exceeded"
317
+ }
318
+ ]
319
+ };
320
+ ```
321
+
322
+ ### 3. Business Hours Only
323
+
324
+ ```typescript
325
+ const rule: RuleConfig = {
326
+ logic: "AND",
327
+ requires: ["env"],
328
+ rules: [
329
+ {
330
+ id: "business-hours",
331
+ logic: "AND",
332
+ conditions: [
333
+ { field: "env.timestamp|hour", op: ">=", value: "9" },
334
+ { field: "env.timestamp|hour", op: "<", value: "17" }
335
+ ],
336
+ message: "Transfers only allowed 09:00–17:00 UTC"
337
+ }
338
+ ]
339
+ };
340
+ ```
341
+
342
+ ### 4. Whitelist OR Small Amount
343
+
344
+ ```typescript
345
+ const rule: RuleConfig = {
346
+ logic: "AND",
347
+ rules: [
348
+ {
349
+ id: "whitelist-or-small",
350
+ logic: "OR",
351
+ rules: [
352
+ {
353
+ id: "is-whitelisted",
354
+ if: {
355
+ field: "tx.sender",
356
+ op: "in",
357
+ value: ["0xAlice...", "0xBob...", "0xCharlie..."]
358
+ }
359
+ },
360
+ {
361
+ id: "small-amount",
362
+ if: { field: "tx.amount", op: "<=", value: "100000000000000000" }
363
+ }
364
+ ],
365
+ message: "Sender not whitelisted and amount exceeds 0.1 ETH"
366
+ }
367
+ ]
368
+ };
369
+ ```
370
+
371
+ ### 5. Multi-Condition Risk Gate
372
+
373
+ ```typescript
374
+ const rule: RuleConfig = {
375
+ logic: "AND",
376
+ requires: ["risk"],
377
+ rules: [
378
+ {
379
+ id: "risk-gate",
380
+ logic: "AND",
381
+ conditions: [
382
+ { field: "risk.score", op: "<", value: "700" },
383
+ { field: "risk.category", op: "!=", value: "SANCTIONED" }
384
+ ],
385
+ message: "Payment blocked: risk score too high or sender sanctioned"
386
+ }
387
+ ]
388
+ };
389
+ ```
390
+
391
+ ### 6. Recurring Payment (Weekdays Only)
392
+
393
+ ```typescript
394
+ const rule: RuleConfig = {
395
+ logic: "AND",
396
+ requires: ["env"],
397
+ rules: [
398
+ {
399
+ id: "weekday-only",
400
+ // day transform: 0=Mon, 4=Fri, 5=Sat, 6=Sun
401
+ logic: "AND",
402
+ conditions: [
403
+ { field: "env.timestamp|day", op: ">=", value: "0" },
404
+ { field: "env.timestamp|day", op: "<=", value: "4" }
405
+ ],
406
+ message: "Only weekday payments allowed"
407
+ }
408
+ ]
409
+ };
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Evaluate Only (No Proof)
415
+
416
+ ```typescript
417
+ import { evaluate } from "payid";
418
+
419
+ const result = await evaluate(context, ruleConfig);
420
+ // result.decision === "ALLOW" | "REJECT"
421
+ // result.code — rule ID that triggered the decision
422
+ // result.reason — human-readable message
423
+ ```
424
+
425
+ ---
426
+
427
+ ## Server-Side Usage
428
+
429
+ ```typescript
430
+ import { PayIDServer } from "payid/server";
431
+ import { ethers } from "ethers";
432
+
433
+ const server = new PayIDServer(
434
+ new ethers.Wallet(process.env.SIGNER_KEY!),
435
+ new Set(["0xTrustedIssuer..."]) // trusted attestation issuers
436
+ );
437
+
438
+ const { result, proof } = await server.evaluateAndProve({
439
+ context,
440
+ authorityRule: ruleConfig,
441
+ payId: "merchant@pay.id",
442
+ payer: "0xPayer...",
443
+ receiver: "0xMerchant...",
444
+ asset: "0x0000000000000000000000000000000000000000",
445
+ amount: 1_000_000_000_000_000_000n,
446
+ verifyingContract: "0xPayWithPayID...",
447
+ ruleAuthority: "0xRuleAuthority...",
448
+ chainId: 42161,
449
+ blockTimestamp: Math.floor(Date.now() / 1000),
450
+ });
451
+ ```
452
+
453
+ ---
454
+
455
+ ## Exports
456
+
457
+ | Import path | Contents |
458
+ |---|---|
459
+ | `payid` | `evaluate()` |
460
+ | `payid/client` | `PayIDClient` |
461
+ | `payid/server` | `PayIDServer` |
462
+ | `payid/decision-proof` | `generateDecisionProof()` |
463
+ | `payid/rule` | `combineRules()`, `canonicalizeRuleSet()` |
464
+ | `payid/issuer` | `signAttestation()` |
465
+ | `payid/context` | Context types |
466
+ | `payid/sessionPolicy` | `decodeSessionPolicy()`, `decodeSessionPolicyV2()` |
467
+
468
+ ---
469
+
470
+ ## Limits
471
+
472
+ | Constraint | Value |
473
+ |---|---|
474
+ | Max rule nesting depth | 10 levels |
475
+ | Max regex pattern length | 200 chars |
476
+ | Nested quantifiers in regex | Rejected (ReDoS protection) |
477
+ | Decision Proof TTL (default) | 300 seconds |
478
+ | Decision Proof TTL (max recommended) | 3600 seconds |
@@ -10,17 +10,32 @@ import {
10
10
  import { ethers, ZeroAddress } from "ethers";
11
11
  var hash = (v) => ethers.keccak256(ethers.toUtf8Bytes(v));
12
12
  async function generateDecisionProof(params) {
13
+ if (!params.payId || typeof params.payId !== "string" || params.payId.trim() === "") {
14
+ throw new Error("payId must not be empty");
15
+ }
13
16
  if (!ethers.isAddress(params.payer) || params.payer === ethers.ZeroAddress) {
14
- throw new Error("GENERATE_PROOF: payer address tidak valid atau zero");
17
+ throw new Error("GENERATE_PROOF: payer address is invalid or zero");
15
18
  }
16
19
  if (!ethers.isAddress(params.receiver) || params.receiver === ethers.ZeroAddress) {
17
- throw new Error("GENERATE_PROOF: receiver address tidak valid atau zero");
20
+ throw new Error("GENERATE_PROOF: receiver address is invalid or zero");
18
21
  }
19
22
  if (!ethers.isAddress(params.verifyingContract) || params.verifyingContract === ethers.ZeroAddress) {
20
- throw new Error("GENERATE_PROOF: verifyingContract tidak valid atau zero");
23
+ throw new Error("GENERATE_PROOF: verifyingContract is invalid or zero");
24
+ }
25
+ if (!ethers.isAddress(params.ruleAuthority)) {
26
+ throw new Error("GENERATE_PROOF: ruleAuthority is not a valid address");
27
+ }
28
+ if (params.asset !== void 0 && !ethers.isAddress(params.asset)) {
29
+ throw new Error("GENERATE_PROOF: asset is not a valid address");
21
30
  }
22
31
  if (params.amount <= 0n) {
23
- throw new Error("GENERATE_PROOF: amount harus > 0");
32
+ throw new Error("amount must be > 0");
33
+ }
34
+ if (params.ttlSeconds !== void 0 && (params.ttlSeconds <= 0 || !Number.isInteger(params.ttlSeconds))) {
35
+ throw new Error("GENERATE_PROOF: ttlSeconds must be a positive integer");
36
+ }
37
+ if (params.blockTimestamp !== void 0 && params.blockTimestamp <= 0) {
38
+ throw new Error("GENERATE_PROOF: blockTimestamp is invalid");
24
39
  }
25
40
  const now = params.blockTimestamp ?? Math.floor(Date.now() / 1e3);
26
41
  const issuedAt = now - 30;
@@ -31,7 +46,7 @@ async function generateDecisionProof(params) {
31
46
  chainId = Number(network.chainId);
32
47
  }
33
48
  if (!chainId || chainId <= 0 || !Number.isInteger(chainId)) {
34
- throw new Error(`GENERATE_PROOF: chainId tidak valid: ${chainId}`);
49
+ throw new Error(`GENERATE_PROOF: chainId is invalid: ${chainId}`);
35
50
  }
36
51
  const requiresAttestation = Array.isArray(params.ruleConfig?.requires) && params.ruleConfig.requires.length > 0;
37
52
  const attestationUIDsHash = params.attestationUIDs ? ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(["bytes32[]"], [params.attestationUIDs])) : ethers.ZeroHash;
@@ -129,29 +129,33 @@ async function runWasmRule(context, config, wasmBinary) {
129
129
  async function runWasmRule2(context, config, _wasmBinary) {
130
130
  return evaluateRule(context, config);
131
131
  }
132
+ var MAX_RULE_DEPTH = 10;
132
133
  function evaluateRule(context, config) {
133
134
  const rules = config?.rules;
134
135
  if (!Array.isArray(rules) || rules.length === 0) {
135
136
  return { decision: "ALLOW", code: "NO_RULES", reason: "no rules defined" };
136
137
  }
137
138
  const logic = config?.logic ?? "AND";
138
- return evalRules(context, rules, logic);
139
+ return evalRules(context, rules, logic, 0);
139
140
  }
140
- function evalRules(context, rules, logic) {
141
+ function evalRules(context, rules, logic, depth) {
142
+ if (depth > MAX_RULE_DEPTH) {
143
+ return { decision: "REJECT", code: "MAX_DEPTH_EXCEEDED", reason: `rule nesting exceeds the limit of ${MAX_RULE_DEPTH}` };
144
+ }
141
145
  for (const rule of rules) {
142
- const res = evalOneRule(context, rule);
146
+ const res = evalOneRule(context, rule, depth);
143
147
  if (res.decision === "REJECT" && logic === "AND") return res;
144
148
  if (res.decision === "ALLOW" && logic === "OR") return res;
145
149
  }
146
150
  if (logic === "AND") return { decision: "ALLOW", code: "OK", reason: "all rules passed" };
147
151
  return { decision: "REJECT", code: "NO_RULE_MATCH", reason: "no rule matched in OR group" };
148
152
  }
149
- function evalOneRule(context, rule) {
153
+ function evalOneRule(context, rule, depth) {
150
154
  const ruleId = rule?.id ?? "UNKNOWN_RULE";
151
155
  const message = rule?.message ?? "";
152
156
  if (Array.isArray(rule?.rules)) {
153
157
  const subLogic = rule?.logic ?? "AND";
154
- const res = evalRules(context, rule.rules, subLogic);
158
+ const res = evalRules(context, rule.rules, subLogic, depth + 1);
155
159
  if (res.decision === "REJECT" && message) {
156
160
  return { decision: "REJECT", code: ruleId, reason: message };
157
161
  }
@@ -564,9 +568,22 @@ async function evaluate(context, ruleConfig, options, wasmBinary) {
564
568
  if (!context.tx) {
565
569
  throw new Error("evaluate(): context.tx is required");
566
570
  }
571
+ if (context.tx.chainId !== void 0 && (!Number.isInteger(context.tx.chainId) || context.tx.chainId <= 0)) {
572
+ throw new Error(`chainId is invalid: ${context.tx.chainId}`);
573
+ }
574
+ if (context.tx.amount !== void 0) {
575
+ const amt = BigInt(context.tx.amount);
576
+ if (amt <= 0n) throw new Error("amount must be > 0");
577
+ }
567
578
  if (!ruleConfig || typeof ruleConfig !== "object") {
568
579
  throw new Error("evaluate(): ruleConfig is required");
569
580
  }
581
+ if (ruleConfig.logic !== "AND" && ruleConfig.logic !== "OR") {
582
+ throw new Error(`ruleConfig.logic must be "AND" or "OR", got: ${ruleConfig.logic}`);
583
+ }
584
+ if (!Array.isArray(ruleConfig.rules) || ruleConfig.rules.length === 0) {
585
+ throw new Error("ruleConfig.rules must be a non-empty array");
586
+ }
570
587
  let result;
571
588
  try {
572
589
  const preparedContext = options?.trustedIssuers ? preprocessContextV2(context, ruleConfig, options.trustedIssuers) : context;
@@ -9,10 +9,10 @@ import {
9
9
  evaluate,
10
10
  loadWasm,
11
11
  resolveRule
12
- } from "./chunk-GQJAHRA7.js";
12
+ } from "./chunk-F2KQGW76.js";
13
13
  import {
14
14
  generateDecisionProof
15
- } from "./chunk-X43JAJPI.js";
15
+ } from "./chunk-AXLZUAYL.js";
16
16
  import {
17
17
  __export
18
18
  } from "./chunk-MLKGABMK.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  evaluate,
3
3
  resolveRule
4
- } from "./chunk-GQJAHRA7.js";
4
+ } from "./chunk-F2KQGW76.js";
5
5
  import {
6
6
  generateDecisionProof
7
- } from "./chunk-X43JAJPI.js";
7
+ } from "./chunk-AXLZUAYL.js";
8
8
  import {
9
9
  __export
10
10
  } from "./chunk-MLKGABMK.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  PayIDClient,
3
3
  createPayIDClient
4
- } from "../../chunk-XLQGSYE6.js";
4
+ } from "../../chunk-K2B5UHYA.js";
5
5
  import "../../chunk-GG34PNTF.js";
6
6
  import "../../chunk-BC77BLFK.js";
7
7
  import "../../chunk-6VPSJFO4.js";
8
- import "../../chunk-GQJAHRA7.js";
9
- import "../../chunk-X43JAJPI.js";
8
+ import "../../chunk-F2KQGW76.js";
9
+ import "../../chunk-AXLZUAYL.js";
10
10
  import "../../chunk-X7NYQ47Y.js";
11
11
  import "../../chunk-KDC67LIN.js";
12
12
  import "../../chunk-MLKGABMK.js";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  PayIDServer,
3
3
  createPayIDServer
4
- } from "../../chunk-J5C4O242.js";
5
- import "../../chunk-GQJAHRA7.js";
6
- import "../../chunk-X43JAJPI.js";
4
+ } from "../../chunk-WQEZYX4X.js";
5
+ import "../../chunk-F2KQGW76.js";
6
+ import "../../chunk-AXLZUAYL.js";
7
7
  import "../../chunk-X7NYQ47Y.js";
8
8
  import "../../chunk-KDC67LIN.js";
9
9
  import "../../chunk-MLKGABMK.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  generateDecisionProof
3
- } from "../chunk-X43JAJPI.js";
3
+ } from "../chunk-AXLZUAYL.js";
4
4
  import "../chunk-X7NYQ47Y.js";
5
5
  import "../chunk-KDC67LIN.js";
6
6
  import "../chunk-MLKGABMK.js";
package/dist/index.js CHANGED
@@ -1,33 +1,33 @@
1
1
  import {
2
2
  context_exports
3
3
  } from "./chunk-BFCPKJ46.js";
4
- import {
5
- issuer_exports
6
- } from "./chunk-E6VQETBC.js";
7
- import "./chunk-YKCMGGYB.js";
8
4
  import {
9
5
  rule_exports
10
6
  } from "./chunk-FZNMDGVK.js";
11
- import {
12
- sessionPolicy_exports
13
- } from "./chunk-R674DZJS.js";
14
7
  import {
15
8
  PayIDClient,
16
9
  client_exports
17
- } from "./chunk-XLQGSYE6.js";
10
+ } from "./chunk-K2B5UHYA.js";
18
11
  import "./chunk-GG34PNTF.js";
12
+ import {
13
+ sessionPolicy_exports
14
+ } from "./chunk-R674DZJS.js";
19
15
  import "./chunk-BC77BLFK.js";
20
16
  import "./chunk-6VPSJFO4.js";
17
+ import {
18
+ issuer_exports
19
+ } from "./chunk-E6VQETBC.js";
20
+ import "./chunk-YKCMGGYB.js";
21
21
  import {
22
22
  PayIDServer,
23
23
  server_exports
24
- } from "./chunk-J5C4O242.js";
24
+ } from "./chunk-WQEZYX4X.js";
25
25
  import {
26
26
  verifyAttestation
27
- } from "./chunk-GQJAHRA7.js";
27
+ } from "./chunk-F2KQGW76.js";
28
28
  import {
29
29
  generateDecisionProof
30
- } from "./chunk-X43JAJPI.js";
30
+ } from "./chunk-AXLZUAYL.js";
31
31
  import "./chunk-X7NYQ47Y.js";
32
32
  import "./chunk-KDC67LIN.js";
33
33
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "payid",
3
- "version": "1.1.0",
3
+ "version": "2.0.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -62,7 +62,7 @@
62
62
  "scripts": {
63
63
  "build": "tsup",
64
64
  "type-check": "tsc --noEmit",
65
- "test": "echo 'No unit tests — add test files to run with bun test'",
65
+ "test": "bun test",
66
66
  "prepublishOnly": "bun run type-check && bun run test && bun run build",
67
67
  "release": "release-it",
68
68
  "release:dry": "release-it --dry-run",
@@ -80,8 +80,12 @@
80
80
  },
81
81
  "devDependencies": {
82
82
  "@types/bun": "latest",
83
+ "@wagmi/core": "^3.4.12",
84
+ "react": "^19.2.6",
83
85
  "release-it": "^20.0.1",
84
- "tsup": "^8.5.1"
86
+ "tsup": "^8.5.1",
87
+ "viem": "^2.49.3",
88
+ "wagmi": "^3.6.15"
85
89
  },
86
90
  "description": "PAY.ID policy engine — evaluate payment rules and generate EIP-712 Decision Proofs",
87
91
  "repository": {