@opendatalabs/vana-sdk 3.5.1 → 3.6.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.
Files changed (116) hide show
  1. package/README.md +116 -0
  2. package/dist/direct/access-request-client.cjs +104 -0
  3. package/dist/direct/access-request-client.cjs.map +1 -0
  4. package/dist/direct/access-request-client.d.ts +51 -0
  5. package/dist/direct/access-request-client.js +79 -0
  6. package/dist/direct/access-request-client.js.map +1 -0
  7. package/dist/direct/access-request-client.test.d.ts +1 -0
  8. package/dist/direct/connect-flow.cjs +152 -0
  9. package/dist/direct/connect-flow.cjs.map +1 -0
  10. package/dist/direct/connect-flow.d.ts +85 -0
  11. package/dist/direct/connect-flow.js +128 -0
  12. package/dist/direct/connect-flow.js.map +1 -0
  13. package/dist/direct/connect-flow.test.d.ts +1 -0
  14. package/dist/direct/controller.cjs +129 -0
  15. package/dist/direct/controller.cjs.map +1 -0
  16. package/dist/direct/controller.d.ts +152 -0
  17. package/dist/direct/controller.js +109 -0
  18. package/dist/direct/controller.js.map +1 -0
  19. package/dist/direct/controller.test.d.ts +1 -0
  20. package/dist/direct/endpoints.cjs +45 -0
  21. package/dist/direct/endpoints.cjs.map +1 -0
  22. package/dist/direct/endpoints.d.ts +22 -0
  23. package/dist/direct/endpoints.js +19 -0
  24. package/dist/direct/endpoints.js.map +1 -0
  25. package/dist/direct/errors.cjs +65 -0
  26. package/dist/direct/errors.cjs.map +1 -0
  27. package/dist/direct/errors.d.ts +44 -0
  28. package/dist/direct/errors.js +38 -0
  29. package/dist/direct/errors.js.map +1 -0
  30. package/dist/direct/escrow-payment.cjs +96 -0
  31. package/dist/direct/escrow-payment.cjs.map +1 -0
  32. package/dist/direct/escrow-payment.d.ts +81 -0
  33. package/dist/direct/escrow-payment.js +72 -0
  34. package/dist/direct/escrow-payment.js.map +1 -0
  35. package/dist/direct/escrow-payment.test.d.ts +1 -0
  36. package/dist/direct/personal-server-read.cjs +149 -0
  37. package/dist/direct/personal-server-read.cjs.map +1 -0
  38. package/dist/direct/personal-server-read.d.ts +103 -0
  39. package/dist/direct/personal-server-read.js +124 -0
  40. package/dist/direct/personal-server-read.js.map +1 -0
  41. package/dist/direct/personal-server-read.test.d.ts +1 -0
  42. package/dist/direct/types.cjs +35 -0
  43. package/dist/direct/types.cjs.map +1 -0
  44. package/dist/direct/types.d.ts +205 -0
  45. package/dist/direct/types.js +11 -0
  46. package/dist/direct/types.js.map +1 -0
  47. package/dist/direct/use-direct-vana-connect.cjs +68 -0
  48. package/dist/direct/use-direct-vana-connect.cjs.map +1 -0
  49. package/dist/direct/use-direct-vana-connect.d.ts +45 -0
  50. package/dist/direct/use-direct-vana-connect.js +46 -0
  51. package/dist/direct/use-direct-vana-connect.js.map +1 -0
  52. package/dist/index.browser.d.ts +7 -3
  53. package/dist/index.browser.js +438 -157
  54. package/dist/index.browser.js.map +4 -4
  55. package/dist/index.node.cjs +461 -162
  56. package/dist/index.node.cjs.map +4 -4
  57. package/dist/index.node.d.ts +7 -3
  58. package/dist/index.node.js +438 -157
  59. package/dist/index.node.js.map +4 -4
  60. package/dist/protocol/data-point-status.cjs +80 -0
  61. package/dist/protocol/data-point-status.cjs.map +1 -0
  62. package/dist/protocol/data-point-status.d.ts +34 -0
  63. package/dist/protocol/data-point-status.js +51 -0
  64. package/dist/protocol/data-point-status.js.map +1 -0
  65. package/dist/protocol/data-point-status.test.d.ts +1 -0
  66. package/dist/protocol/eip712.cjs +53 -31
  67. package/dist/protocol/eip712.cjs.map +1 -1
  68. package/dist/protocol/eip712.d.ts +98 -43
  69. package/dist/protocol/eip712.js +47 -27
  70. package/dist/protocol/eip712.js.map +1 -1
  71. package/dist/protocol/escrow-deposit.cjs +89 -0
  72. package/dist/protocol/escrow-deposit.cjs.map +1 -0
  73. package/dist/protocol/escrow-deposit.d.ts +47 -0
  74. package/dist/protocol/escrow-deposit.js +60 -0
  75. package/dist/protocol/escrow-deposit.js.map +1 -0
  76. package/dist/protocol/escrow-deposit.test.d.ts +1 -0
  77. package/dist/protocol/escrow-flow.test.d.ts +21 -0
  78. package/dist/protocol/fee-registry.cjs +116 -0
  79. package/dist/protocol/fee-registry.cjs.map +1 -0
  80. package/dist/protocol/fee-registry.d.ts +151 -0
  81. package/dist/protocol/fee-registry.js +89 -0
  82. package/dist/protocol/fee-registry.js.map +1 -0
  83. package/dist/protocol/fee-registry.test.d.ts +1 -0
  84. package/dist/protocol/gateway.cjs +107 -37
  85. package/dist/protocol/gateway.cjs.map +1 -1
  86. package/dist/protocol/gateway.d.ts +223 -57
  87. package/dist/protocol/gateway.js +107 -37
  88. package/dist/protocol/gateway.js.map +1 -1
  89. package/dist/protocol/grants.cjs +27 -64
  90. package/dist/protocol/grants.cjs.map +1 -1
  91. package/dist/protocol/grants.d.ts +6 -13
  92. package/dist/protocol/grants.js +27 -63
  93. package/dist/protocol/grants.js.map +1 -1
  94. package/dist/protocol/personal-server-data.cjs +71 -0
  95. package/dist/protocol/personal-server-data.cjs.map +1 -0
  96. package/dist/protocol/personal-server-data.d.ts +16 -0
  97. package/dist/protocol/personal-server-data.js +47 -0
  98. package/dist/protocol/personal-server-data.js.map +1 -0
  99. package/dist/protocol/personal-server-data.test.d.ts +1 -0
  100. package/dist/protocol/personal-server-lite-owner-binding.cjs +93 -0
  101. package/dist/protocol/personal-server-lite-owner-binding.cjs.map +1 -0
  102. package/dist/protocol/personal-server-lite-owner-binding.d.ts +44 -0
  103. package/dist/protocol/personal-server-lite-owner-binding.js +65 -0
  104. package/dist/protocol/personal-server-lite-owner-binding.js.map +1 -0
  105. package/dist/protocol/personal-server-lite-owner-binding.test.d.ts +1 -0
  106. package/dist/react.cjs +32 -0
  107. package/dist/react.cjs.map +1 -0
  108. package/dist/react.d.ts +33 -0
  109. package/dist/react.js +11 -0
  110. package/dist/react.js.map +1 -0
  111. package/dist/server.cjs +73 -0
  112. package/dist/server.cjs.map +1 -0
  113. package/dist/server.d.ts +32 -0
  114. package/dist/server.js +55 -0
  115. package/dist/server.js.map +1 -0
  116. package/package.json +20 -1
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Adapter for the on-chain FeeRegistry contract — the source of truth the
3
+ * gateway re-reads on every /v1/escrow/pay to size the payment amount.
4
+ *
5
+ * The registry stores per-operation `{amount, asset, payee, enabled}`
6
+ * records keyed on `keccak256(name)`. SDK consumers (builders sizing
7
+ * payments) MUST read fees from this contract rather than hardcoding
8
+ * them, or the signed `amount` won't match the gateway's expected total
9
+ * and /v1/escrow/pay returns 400.
10
+ *
11
+ * Five operation kinds are wired up; each kind's name matches the
12
+ * corresponding `payments.kind` column value on the gateway:
13
+ *
14
+ * - 'grant_registration' — one-time fee when a grant is first registered
15
+ * (POST /v1/grants).
16
+ * - 'data_access' — per-access surcharge on grant payments
17
+ * (every accessRecord posted against a grant).
18
+ * - 'data_registration' — one-time fee for registering a data point
19
+ * (POST /v1/data → addDataWithSignature).
20
+ * - 'server_registration' — one-time fee for registering a personal server
21
+ * (POST /v1/servers).
22
+ * - 'builder_registration' — one-time fee for registering a builder
23
+ * (POST /v1/builders; gateway-only, no on-chain
24
+ * submission).
25
+ *
26
+ * Disabled or unregistered fees skip enforcement: the corresponding
27
+ * operation settles WITHOUT requiring a payment from escrow. `getFee`
28
+ * surfaces this via `enabled: false` rather than throwing — the gateway
29
+ * itself treats a disabled fee as a steady state, not a misconfig.
30
+ *
31
+ * Deployers can override the on-chain operation strings via
32
+ * `FEE_REGISTRY_<KIND>_OP` env vars on the gateway side; the matching
33
+ * SDK escape hatch is the `opts.<kind>OpName` arguments.
34
+ *
35
+ * This module is signer/transport-agnostic — callers pass in their own
36
+ * `PublicClient` for the contract reads. No caching here; long-running
37
+ * service consumers should wrap with their own TTL. Mirrors
38
+ * data-gateway/lib/fee-registry.ts byte-for-byte.
39
+ *
40
+ * @category Protocol
41
+ */
42
+ import { type Address, type PublicClient } from "viem";
43
+ import type { DataPortabilityGatewayConfig } from "./eip712";
44
+ export declare const FEE_REGISTRY_ABI: readonly [{
45
+ readonly name: "fees";
46
+ readonly type: "function";
47
+ readonly stateMutability: "view";
48
+ readonly inputs: readonly [{
49
+ readonly type: "bytes32";
50
+ readonly name: "operation";
51
+ }];
52
+ readonly outputs: readonly [{
53
+ readonly type: "tuple";
54
+ readonly components: readonly [{
55
+ readonly type: "uint256";
56
+ readonly name: "amount";
57
+ }, {
58
+ readonly type: "address";
59
+ readonly name: "asset";
60
+ }, {
61
+ readonly type: "address";
62
+ readonly name: "payee";
63
+ }, {
64
+ readonly type: "bool";
65
+ readonly name: "enabled";
66
+ }];
67
+ }];
68
+ }, {
69
+ readonly name: "operationKey";
70
+ readonly type: "function";
71
+ readonly stateMutability: "pure";
72
+ readonly inputs: readonly [{
73
+ readonly type: "string";
74
+ readonly name: "name";
75
+ }];
76
+ readonly outputs: readonly [{
77
+ readonly type: "bytes32";
78
+ }];
79
+ }];
80
+ export type FeeKind = "grant_registration" | "data_access" | "data_registration" | "server_registration" | "builder_registration";
81
+ /**
82
+ * Map from a user-facing opType (POST /v1/escrow/pay body field, matches
83
+ * the gateway's `payments.op_type` column) to the FeeKind that gates its
84
+ * one-time registration fee.
85
+ *
86
+ * Data access is a per-call surcharge on grants only — it's not a
87
+ * registration fee for any op, so it lives outside this map.
88
+ */
89
+ export declare const REGISTRATION_KIND_FOR_OP: Record<string, FeeKind>;
90
+ export interface FeeEntry {
91
+ amount: bigint;
92
+ asset: Address;
93
+ payee: Address;
94
+ enabled: boolean;
95
+ }
96
+ /**
97
+ * Compound fee schedule for one op type, mirroring the gateway's
98
+ * lib/op-fees.ts `OpFee`. For ANY op type, `registrationFee` is the
99
+ * one-time fee charged at registration. For `'grant'` only, `dataAccessFee`
100
+ * is the per-access surcharge — for any other op type it's always 0n with
101
+ * `dataAccessEnabled: false`.
102
+ *
103
+ * `xxxEnabled` reflects the on-chain `Fee.enabled` flag. When OFF, the
104
+ * corresponding amount is 0 and the pay handler should NOT require
105
+ * payment for that kind. When both are off (for a grant) or registration
106
+ * is off (for any other op type), the entire payment flow is skipped —
107
+ * the op settles directly via the no-payment path.
108
+ */
109
+ export interface OpFee {
110
+ asset: Address;
111
+ registrationFee: bigint;
112
+ dataAccessFee: bigint;
113
+ registrationEnabled: boolean;
114
+ dataAccessEnabled: boolean;
115
+ registrationPayee: Address;
116
+ dataAccessPayee: Address;
117
+ }
118
+ export interface FeeRegistryOptions {
119
+ grantRegistrationOpName?: string;
120
+ dataAccessOpName?: string;
121
+ dataRegistrationOpName?: string;
122
+ serverRegistrationOpName?: string;
123
+ builderRegistrationOpName?: string;
124
+ }
125
+ /**
126
+ * Reads one fee kind from the FeeRegistry. Calls the contract's
127
+ * `operationKey(name)` first to derive the bytes32 key — matches the
128
+ * gateway's approach exactly (could compute locally via keccak256, but
129
+ * going through the contract eliminates any chance of encoding drift).
130
+ *
131
+ * Returns `{enabled: false}` entries WITHOUT throwing — disabled is a
132
+ * valid steady state on the gateway. The only validation is the
133
+ * zero-payee check, and that only fires when the fee is enabled
134
+ * (a disabled fee never lands as a SettleOp `to`).
135
+ */
136
+ export declare function getFee(client: PublicClient, config: DataPortabilityGatewayConfig, kind: FeeKind, opts?: FeeRegistryOptions): Promise<FeeEntry>;
137
+ /**
138
+ * Convenience: combine the FeeRegistry reads for one op type into the
139
+ * compound shape the pay handler validates against.
140
+ *
141
+ * For 'grant' opType the result includes both registration + data_access
142
+ * components; for other op types data_access is always disabled with
143
+ * amount=0. Disabled components contribute 0 to the signed total —
144
+ * callers compute `amount = registrationFee + dataAccessFee` and the pay
145
+ * handler accepts (or short-circuits with 'Payment not required' when
146
+ * both are 0).
147
+ *
148
+ * Throws on asset mismatch ONLY when both components are enabled — a
149
+ * disabled fee never lands as a SettleOp, so its asset is moot.
150
+ */
151
+ export declare function getOpFee(client: PublicClient, config: DataPortabilityGatewayConfig, opType: string, opts?: FeeRegistryOptions): Promise<OpFee>;
@@ -0,0 +1,89 @@
1
+ import { parseAbi } from "viem";
2
+ const FEE_REGISTRY_ABI = parseAbi([
3
+ "struct Fee { uint256 amount; address asset; address payee; bool enabled; }",
4
+ "function fees(bytes32 operation) view returns (Fee)",
5
+ "function operationKey(string name) pure returns (bytes32)"
6
+ ]);
7
+ const REGISTRATION_KIND_FOR_OP = {
8
+ grant: "grant_registration",
9
+ data: "data_registration",
10
+ server: "server_registration",
11
+ builder: "builder_registration"
12
+ };
13
+ function operationNameFor(kind, opts) {
14
+ switch (kind) {
15
+ case "grant_registration":
16
+ return opts?.grantRegistrationOpName ?? "grant_registration";
17
+ case "data_access":
18
+ return opts?.dataAccessOpName ?? "data_access";
19
+ case "data_registration":
20
+ return opts?.dataRegistrationOpName ?? "data_registration";
21
+ case "server_registration":
22
+ return opts?.serverRegistrationOpName ?? "server_registration";
23
+ case "builder_registration":
24
+ return opts?.builderRegistrationOpName ?? "builder_registration";
25
+ }
26
+ }
27
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
28
+ async function getFee(client, config, kind, opts) {
29
+ const address = config.contracts.feeRegistry;
30
+ const opName = operationNameFor(kind, opts);
31
+ const opKey = await client.readContract({
32
+ address,
33
+ abi: FEE_REGISTRY_ABI,
34
+ functionName: "operationKey",
35
+ args: [opName]
36
+ });
37
+ const fee = await client.readContract({
38
+ address,
39
+ abi: FEE_REGISTRY_ABI,
40
+ functionName: "fees",
41
+ args: [opKey]
42
+ });
43
+ if (fee.enabled && fee.payee === ZERO_ADDRESS) {
44
+ throw new Error(
45
+ `FeeRegistry: enabled operation "${opName}" has zero-address payee \u2014 contract pre-flight rejects payouts to 0x0`
46
+ );
47
+ }
48
+ return fee;
49
+ }
50
+ async function getOpFee(client, config, opType, opts) {
51
+ const registrationKind = REGISTRATION_KIND_FOR_OP[opType];
52
+ if (!registrationKind) {
53
+ throw new Error(
54
+ `getOpFee: unknown opType "${opType}" \u2014 supported types are ${Object.keys(REGISTRATION_KIND_FOR_OP).join(", ")}`
55
+ );
56
+ }
57
+ const includeDataAccess = opType === "grant";
58
+ const [registration, dataAccess] = await Promise.all([
59
+ getFee(client, config, registrationKind, opts),
60
+ includeDataAccess ? getFee(client, config, "data_access", opts) : Promise.resolve({
61
+ amount: 0n,
62
+ asset: ZERO_ADDRESS,
63
+ payee: ZERO_ADDRESS,
64
+ enabled: false
65
+ })
66
+ ]);
67
+ if (registration.enabled && dataAccess.enabled && registration.asset.toLowerCase() !== dataAccess.asset.toLowerCase()) {
68
+ throw new Error(
69
+ `FeeRegistry asset mismatch for "${opType}": registration=${registration.asset} vs data_access=${dataAccess.asset}. The gateway requires both kinds to settle in the same asset when both are enabled.`
70
+ );
71
+ }
72
+ const asset = registration.enabled ? registration.asset : dataAccess.enabled ? dataAccess.asset : ZERO_ADDRESS;
73
+ return {
74
+ asset,
75
+ registrationFee: registration.enabled ? registration.amount : 0n,
76
+ dataAccessFee: dataAccess.enabled ? dataAccess.amount : 0n,
77
+ registrationEnabled: registration.enabled,
78
+ dataAccessEnabled: dataAccess.enabled,
79
+ registrationPayee: registration.enabled ? registration.payee : ZERO_ADDRESS,
80
+ dataAccessPayee: dataAccess.enabled ? dataAccess.payee : ZERO_ADDRESS
81
+ };
82
+ }
83
+ export {
84
+ FEE_REGISTRY_ABI,
85
+ REGISTRATION_KIND_FOR_OP,
86
+ getFee,
87
+ getOpFee
88
+ };
89
+ //# sourceMappingURL=fee-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/protocol/fee-registry.ts"],"sourcesContent":["/**\n * Adapter for the on-chain FeeRegistry contract — the source of truth the\n * gateway re-reads on every /v1/escrow/pay to size the payment amount.\n *\n * The registry stores per-operation `{amount, asset, payee, enabled}`\n * records keyed on `keccak256(name)`. SDK consumers (builders sizing\n * payments) MUST read fees from this contract rather than hardcoding\n * them, or the signed `amount` won't match the gateway's expected total\n * and /v1/escrow/pay returns 400.\n *\n * Five operation kinds are wired up; each kind's name matches the\n * corresponding `payments.kind` column value on the gateway:\n *\n * - 'grant_registration' — one-time fee when a grant is first registered\n * (POST /v1/grants).\n * - 'data_access' — per-access surcharge on grant payments\n * (every accessRecord posted against a grant).\n * - 'data_registration' — one-time fee for registering a data point\n * (POST /v1/data → addDataWithSignature).\n * - 'server_registration' — one-time fee for registering a personal server\n * (POST /v1/servers).\n * - 'builder_registration' — one-time fee for registering a builder\n * (POST /v1/builders; gateway-only, no on-chain\n * submission).\n *\n * Disabled or unregistered fees skip enforcement: the corresponding\n * operation settles WITHOUT requiring a payment from escrow. `getFee`\n * surfaces this via `enabled: false` rather than throwing — the gateway\n * itself treats a disabled fee as a steady state, not a misconfig.\n *\n * Deployers can override the on-chain operation strings via\n * `FEE_REGISTRY_<KIND>_OP` env vars on the gateway side; the matching\n * SDK escape hatch is the `opts.<kind>OpName` arguments.\n *\n * This module is signer/transport-agnostic — callers pass in their own\n * `PublicClient` for the contract reads. No caching here; long-running\n * service consumers should wrap with their own TTL. Mirrors\n * data-gateway/lib/fee-registry.ts byte-for-byte.\n *\n * @category Protocol\n */\nimport { parseAbi, type Address, type Hex, type PublicClient } from \"viem\";\nimport type { DataPortabilityGatewayConfig } from \"./eip712\";\n\nexport const FEE_REGISTRY_ABI = parseAbi([\n \"struct Fee { uint256 amount; address asset; address payee; bool enabled; }\",\n \"function fees(bytes32 operation) view returns (Fee)\",\n \"function operationKey(string name) pure returns (bytes32)\",\n]);\n\nexport type FeeKind =\n | \"grant_registration\"\n | \"data_access\"\n | \"data_registration\"\n | \"server_registration\"\n | \"builder_registration\";\n\n/**\n * Map from a user-facing opType (POST /v1/escrow/pay body field, matches\n * the gateway's `payments.op_type` column) to the FeeKind that gates its\n * one-time registration fee.\n *\n * Data access is a per-call surcharge on grants only — it's not a\n * registration fee for any op, so it lives outside this map.\n */\nexport const REGISTRATION_KIND_FOR_OP: Record<string, FeeKind> = {\n grant: \"grant_registration\",\n data: \"data_registration\",\n server: \"server_registration\",\n builder: \"builder_registration\",\n};\n\nexport interface FeeEntry {\n amount: bigint;\n // Asset the fee is denominated in. 0x0000…0000 = native VANA; anything\n // else is an ERC-20 contract address.\n asset: Address;\n // The recipient the on-chain settle pass routes the fee to. Only\n // meaningful when `enabled` — disabled fees never land as a SettleOp `to`.\n payee: Address;\n enabled: boolean;\n}\n\n/**\n * Compound fee schedule for one op type, mirroring the gateway's\n * lib/op-fees.ts `OpFee`. For ANY op type, `registrationFee` is the\n * one-time fee charged at registration. For `'grant'` only, `dataAccessFee`\n * is the per-access surcharge — for any other op type it's always 0n with\n * `dataAccessEnabled: false`.\n *\n * `xxxEnabled` reflects the on-chain `Fee.enabled` flag. When OFF, the\n * corresponding amount is 0 and the pay handler should NOT require\n * payment for that kind. When both are off (for a grant) or registration\n * is off (for any other op type), the entire payment flow is skipped —\n * the op settles directly via the no-payment path.\n */\nexport interface OpFee {\n // Asset for whichever components are enabled. Falls back to native VANA\n // (0x0) when both components are disabled. The pay handler enforces that\n // the payer's `asset` matches.\n asset: Address;\n registrationFee: bigint;\n dataAccessFee: bigint;\n registrationEnabled: boolean;\n dataAccessEnabled: boolean;\n // Surfaced for the SDK's on-chain log-filter use case; the gateway's\n // OpFee type doesn't include these but the SDK keeps them since callers\n // sizing on-chain assertions need to know where the fee lands. Equal to\n // the zero address when the corresponding kind is disabled.\n registrationPayee: Address;\n dataAccessPayee: Address;\n}\n\nexport interface FeeRegistryOptions {\n grantRegistrationOpName?: string;\n dataAccessOpName?: string;\n dataRegistrationOpName?: string;\n serverRegistrationOpName?: string;\n builderRegistrationOpName?: string;\n}\n\nfunction operationNameFor(\n kind: FeeKind,\n opts: FeeRegistryOptions | undefined,\n): string {\n switch (kind) {\n case \"grant_registration\":\n return opts?.grantRegistrationOpName ?? \"grant_registration\";\n case \"data_access\":\n return opts?.dataAccessOpName ?? \"data_access\";\n case \"data_registration\":\n return opts?.dataRegistrationOpName ?? \"data_registration\";\n case \"server_registration\":\n return opts?.serverRegistrationOpName ?? \"server_registration\";\n case \"builder_registration\":\n return opts?.builderRegistrationOpName ?? \"builder_registration\";\n }\n}\n\nconst ZERO_ADDRESS = \"0x0000000000000000000000000000000000000000\" as Address;\n\n/**\n * Reads one fee kind from the FeeRegistry. Calls the contract's\n * `operationKey(name)` first to derive the bytes32 key — matches the\n * gateway's approach exactly (could compute locally via keccak256, but\n * going through the contract eliminates any chance of encoding drift).\n *\n * Returns `{enabled: false}` entries WITHOUT throwing — disabled is a\n * valid steady state on the gateway. The only validation is the\n * zero-payee check, and that only fires when the fee is enabled\n * (a disabled fee never lands as a SettleOp `to`).\n */\nexport async function getFee(\n client: PublicClient,\n config: DataPortabilityGatewayConfig,\n kind: FeeKind,\n opts?: FeeRegistryOptions,\n): Promise<FeeEntry> {\n const address = config.contracts.feeRegistry as Address;\n const opName = operationNameFor(kind, opts);\n\n const opKey = (await client.readContract({\n address,\n abi: FEE_REGISTRY_ABI,\n functionName: \"operationKey\",\n args: [opName],\n })) as Hex;\n\n const fee = (await client.readContract({\n address,\n abi: FEE_REGISTRY_ABI,\n functionName: \"fees\",\n args: [opKey],\n })) as FeeEntry;\n\n if (fee.enabled && fee.payee === ZERO_ADDRESS) {\n throw new Error(\n `FeeRegistry: enabled operation \"${opName}\" has zero-address payee — contract pre-flight rejects payouts to 0x0`,\n );\n }\n\n return fee;\n}\n\n/**\n * Convenience: combine the FeeRegistry reads for one op type into the\n * compound shape the pay handler validates against.\n *\n * For 'grant' opType the result includes both registration + data_access\n * components; for other op types data_access is always disabled with\n * amount=0. Disabled components contribute 0 to the signed total —\n * callers compute `amount = registrationFee + dataAccessFee` and the pay\n * handler accepts (or short-circuits with 'Payment not required' when\n * both are 0).\n *\n * Throws on asset mismatch ONLY when both components are enabled — a\n * disabled fee never lands as a SettleOp, so its asset is moot.\n */\nexport async function getOpFee(\n client: PublicClient,\n config: DataPortabilityGatewayConfig,\n opType: string,\n opts?: FeeRegistryOptions,\n): Promise<OpFee> {\n const registrationKind = REGISTRATION_KIND_FOR_OP[opType];\n if (!registrationKind) {\n throw new Error(\n `getOpFee: unknown opType \"${opType}\" — supported types are ${Object.keys(REGISTRATION_KIND_FOR_OP).join(\", \")}`,\n );\n }\n\n const includeDataAccess = opType === \"grant\";\n const [registration, dataAccess] = await Promise.all([\n getFee(client, config, registrationKind, opts),\n includeDataAccess\n ? getFee(client, config, \"data_access\", opts)\n : Promise.resolve<FeeEntry>({\n amount: 0n,\n asset: ZERO_ADDRESS,\n payee: ZERO_ADDRESS,\n enabled: false,\n }),\n ]);\n\n if (\n registration.enabled &&\n dataAccess.enabled &&\n registration.asset.toLowerCase() !== dataAccess.asset.toLowerCase()\n ) {\n throw new Error(\n `FeeRegistry asset mismatch for \"${opType}\": registration=${registration.asset} vs data_access=${dataAccess.asset}. The gateway requires both kinds to settle in the same asset when both are enabled.`,\n );\n }\n\n const asset = registration.enabled\n ? registration.asset\n : dataAccess.enabled\n ? dataAccess.asset\n : ZERO_ADDRESS;\n\n return {\n asset,\n registrationFee: registration.enabled ? registration.amount : 0n,\n dataAccessFee: dataAccess.enabled ? dataAccess.amount : 0n,\n registrationEnabled: registration.enabled,\n dataAccessEnabled: dataAccess.enabled,\n registrationPayee: registration.enabled ? registration.payee : ZERO_ADDRESS,\n dataAccessPayee: dataAccess.enabled ? dataAccess.payee : ZERO_ADDRESS,\n };\n}\n"],"mappings":"AAyCA,SAAS,gBAA2D;AAG7D,MAAM,mBAAmB,SAAS;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAiBM,MAAM,2BAAoD;AAAA,EAC/D,OAAO;AAAA,EACP,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AACX;AAmDA,SAAS,iBACP,MACA,MACQ;AACR,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,MAAM,2BAA2B;AAAA,IAC1C,KAAK;AACH,aAAO,MAAM,oBAAoB;AAAA,IACnC,KAAK;AACH,aAAO,MAAM,0BAA0B;AAAA,IACzC,KAAK;AACH,aAAO,MAAM,4BAA4B;AAAA,IAC3C,KAAK;AACH,aAAO,MAAM,6BAA6B;AAAA,EAC9C;AACF;AAEA,MAAM,eAAe;AAarB,eAAsB,OACpB,QACA,QACA,MACA,MACmB;AACnB,QAAM,UAAU,OAAO,UAAU;AACjC,QAAM,SAAS,iBAAiB,MAAM,IAAI;AAE1C,QAAM,QAAS,MAAM,OAAO,aAAa;AAAA,IACvC;AAAA,IACA,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,MAAM;AAAA,EACf,CAAC;AAED,QAAM,MAAO,MAAM,OAAO,aAAa;AAAA,IACrC;AAAA,IACA,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,KAAK;AAAA,EACd,CAAC;AAED,MAAI,IAAI,WAAW,IAAI,UAAU,cAAc;AAC7C,UAAM,IAAI;AAAA,MACR,mCAAmC,MAAM;AAAA,IAC3C;AAAA,EACF;AAEA,SAAO;AACT;AAgBA,eAAsB,SACpB,QACA,QACA,QACA,MACgB;AAChB,QAAM,mBAAmB,yBAAyB,MAAM;AACxD,MAAI,CAAC,kBAAkB;AACrB,UAAM,IAAI;AAAA,MACR,6BAA6B,MAAM,gCAA2B,OAAO,KAAK,wBAAwB,EAAE,KAAK,IAAI,CAAC;AAAA,IAChH;AAAA,EACF;AAEA,QAAM,oBAAoB,WAAW;AACrC,QAAM,CAAC,cAAc,UAAU,IAAI,MAAM,QAAQ,IAAI;AAAA,IACnD,OAAO,QAAQ,QAAQ,kBAAkB,IAAI;AAAA,IAC7C,oBACI,OAAO,QAAQ,QAAQ,eAAe,IAAI,IAC1C,QAAQ,QAAkB;AAAA,MACxB,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,IACX,CAAC;AAAA,EACP,CAAC;AAED,MACE,aAAa,WACb,WAAW,WACX,aAAa,MAAM,YAAY,MAAM,WAAW,MAAM,YAAY,GAClE;AACA,UAAM,IAAI;AAAA,MACR,mCAAmC,MAAM,mBAAmB,aAAa,KAAK,mBAAmB,WAAW,KAAK;AAAA,IACnH;AAAA,EACF;AAEA,QAAM,QAAQ,aAAa,UACvB,aAAa,QACb,WAAW,UACT,WAAW,QACX;AAEN,SAAO;AAAA,IACL;AAAA,IACA,iBAAiB,aAAa,UAAU,aAAa,SAAS;AAAA,IAC9D,eAAe,WAAW,UAAU,WAAW,SAAS;AAAA,IACxD,qBAAqB,aAAa;AAAA,IAClC,mBAAmB,WAAW;AAAA,IAC9B,mBAAmB,aAAa,UAAU,aAAa,QAAQ;AAAA,IAC/D,iBAAiB,WAAW,UAAU,WAAW,QAAQ;AAAA,EAC3D;AACF;","names":[]}
@@ -0,0 +1 @@
1
+ export {};
@@ -27,16 +27,6 @@ function createGatewayClient(baseUrl) {
27
27
  const envelope = await res.json();
28
28
  return envelope.data;
29
29
  }
30
- function normalizeFileRecord(record) {
31
- return {
32
- fileId: record.fileId ?? record.id ?? "",
33
- owner: record.owner ?? record.ownerAddress ?? "",
34
- url: record.url,
35
- schemaId: record.schemaId,
36
- createdAt: record.createdAt ?? record.addedAt ?? "",
37
- deletedAt: record.deletedAt ?? null
38
- };
39
- }
40
30
  function getMutationId(body, key) {
41
31
  const value = body[key] ?? body["id"];
42
32
  return typeof value === "string" ? value : void 0;
@@ -86,31 +76,33 @@ function createGatewayClient(baseUrl) {
86
76
  }
87
77
  return unwrapEnvelope(res);
88
78
  },
89
- async getFile(fileId) {
90
- const res = await fetch(`${base}/v1/files/${fileId}`);
79
+ async getDataPoint(dataPointId) {
80
+ const res = await fetch(`${base}/v1/data/${dataPointId}`);
91
81
  if (res.status === 404) return null;
92
82
  if (!res.ok) {
93
83
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
94
84
  }
95
- return normalizeFileRecord(await unwrapEnvelope(res));
85
+ return unwrapEnvelope(res);
96
86
  },
97
- async listFilesSince(owner, cursor, options) {
87
+ async listDataPointsByOwner(owner, cursor, options) {
98
88
  const params = new URLSearchParams({ user: owner });
99
89
  if (cursor !== null) {
100
90
  params.set("cursor", cursor);
101
91
  }
102
- if (options?.includeDeleted) {
103
- params.set("includeDeleted", "true");
92
+ if (options?.since) {
93
+ params.set("since", options.since);
94
+ }
95
+ if (options?.limit !== void 0) {
96
+ params.set("limit", String(options.limit));
104
97
  }
105
- const res = await fetch(`${base}/v1/files?${params.toString()}`);
98
+ const res = await fetch(`${base}/v1/data?${params.toString()}`);
106
99
  if (!res.ok) {
107
100
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
108
101
  }
109
102
  const envelope = await res.json();
110
- const { pagination } = envelope;
111
- const nextCursor = pagination?.hasMore === false ? null : pagination?.nextCursor ?? envelope.data.cursor ?? null;
103
+ const nextCursor = envelope.pagination?.hasMore === false ? null : envelope.pagination?.nextCursor ?? null;
112
104
  return {
113
- files: envelope.data.files.map(normalizeFileRecord),
105
+ dataPoints: envelope.data.dataPoints,
114
106
  cursor: nextCursor
115
107
  };
116
108
  },
@@ -152,8 +144,8 @@ function createGatewayClient(baseUrl) {
152
144
  alreadyRegistered: false
153
145
  };
154
146
  },
155
- async registerFile(params) {
156
- const res = await fetch(`${base}/v1/files`, {
147
+ async registerBuilder(params) {
148
+ const res = await fetch(`${base}/v1/builders`, {
157
149
  method: "POST",
158
150
  headers: {
159
151
  "Content-Type": "application/json",
@@ -161,22 +153,57 @@ function createGatewayClient(baseUrl) {
161
153
  },
162
154
  body: JSON.stringify({
163
155
  ownerAddress: params.ownerAddress,
164
- url: params.url,
165
- schemaId: params.schemaId
156
+ granteeAddress: params.granteeAddress,
157
+ publicKey: params.publicKey,
158
+ appUrl: params.appUrl
166
159
  })
167
160
  });
168
161
  if (res.status === 409) {
169
162
  const body2 = await res.json().catch(() => ({}));
170
163
  return {
171
- fileId: getMutationId(body2, "fileId")
164
+ builderId: getMutationId(
165
+ body2,
166
+ "builderId"
167
+ ),
168
+ alreadyRegistered: true
172
169
  };
173
170
  }
174
171
  if (!res.ok) {
175
172
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
176
173
  }
177
- const body = await res.json();
174
+ const body = await res.json().catch(() => ({}));
175
+ return {
176
+ builderId: getMutationId(body, "builderId"),
177
+ alreadyRegistered: false
178
+ };
179
+ },
180
+ async registerDataPoint(params) {
181
+ const res = await fetch(`${base}/v1/data`, {
182
+ method: "POST",
183
+ headers: {
184
+ "Content-Type": "application/json",
185
+ Authorization: `Web3Signed ${params.signature}`
186
+ },
187
+ body: JSON.stringify({
188
+ ownerAddress: params.ownerAddress,
189
+ scope: params.scope,
190
+ dataHash: params.dataHash,
191
+ metadataHash: params.metadataHash,
192
+ expectedVersion: params.expectedVersion
193
+ })
194
+ });
195
+ if (!res.ok) {
196
+ const body2 = await res.json().catch(() => ({}));
197
+ const detail = body2.error ?? res.statusText;
198
+ throw new Error(`Gateway error: ${res.status} ${detail}`);
199
+ }
200
+ const body = await res.json().catch(() => ({}));
178
201
  return {
179
- fileId: getMutationId(body, "fileId")
202
+ dataPointId: getMutationId(
203
+ body,
204
+ "dataPointId"
205
+ ),
206
+ expectedVersion: body.expectedVersion
180
207
  };
181
208
  },
182
209
  async createGrant(params) {
@@ -189,8 +216,9 @@ function createGatewayClient(baseUrl) {
189
216
  body: JSON.stringify({
190
217
  grantorAddress: params.grantorAddress,
191
218
  granteeId: params.granteeId,
192
- grant: params.grant,
193
- fileIds: params.fileIds
219
+ scopes: params.scopes,
220
+ grantVersion: params.grantVersion,
221
+ expiresAt: params.expiresAt
194
222
  })
195
223
  });
196
224
  if (res.status === 409) {
@@ -215,7 +243,8 @@ function createGatewayClient(baseUrl) {
215
243
  Authorization: `Web3Signed ${params.signature}`
216
244
  },
217
245
  body: JSON.stringify({
218
- grantorAddress: params.grantorAddress
246
+ grantorAddress: params.grantorAddress,
247
+ grantVersion: params.grantVersion
219
248
  })
220
249
  });
221
250
  if (res.status === 409) return;
@@ -223,21 +252,62 @@ function createGatewayClient(baseUrl) {
223
252
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
224
253
  }
225
254
  },
226
- async deleteFile(params) {
227
- const res = await fetch(`${base}/v1/files/${params.fileId}`, {
228
- method: "DELETE",
255
+ async getEscrowBalance(account) {
256
+ const res = await fetch(`${base}/v1/escrow/balance?account=${account}`);
257
+ if (!res.ok) {
258
+ throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
259
+ }
260
+ return await res.json();
261
+ },
262
+ async submitEscrowDeposit(params) {
263
+ const res = await fetch(`${base}/v1/escrow/deposit`, {
264
+ method: "POST",
265
+ headers: { "Content-Type": "application/json" },
266
+ body: JSON.stringify({ txHash: params.txHash })
267
+ });
268
+ if (res.status !== 200 && res.status !== 202) {
269
+ throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
270
+ }
271
+ return await res.json();
272
+ },
273
+ async payForOperation(params) {
274
+ const body = {
275
+ payerAddress: params.payerAddress,
276
+ opType: params.opType,
277
+ opId: params.opId,
278
+ asset: params.asset,
279
+ amount: params.amount,
280
+ paymentNonce: params.paymentNonce
281
+ };
282
+ if (params.accessRecord) {
283
+ body["accessRecord"] = params.accessRecord;
284
+ }
285
+ const res = await fetch(`${base}/v1/escrow/pay`, {
286
+ method: "POST",
229
287
  headers: {
230
288
  "Content-Type": "application/json",
231
289
  Authorization: `Web3Signed ${params.signature}`
232
290
  },
233
- body: JSON.stringify({
234
- ownerAddress: params.ownerAddress
235
- })
291
+ body: JSON.stringify(body)
292
+ });
293
+ if (!res.ok) {
294
+ throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
295
+ }
296
+ return await res.json();
297
+ },
298
+ async settle(params) {
299
+ const res = await fetch(`${base}/v1/settle`, {
300
+ method: "POST",
301
+ headers: { "Content-Type": "application/json" },
302
+ // The gateway accepts an empty body; only `limit` is recognised.
303
+ // Always send a JSON body so the gateway's req.body shape parse
304
+ // doesn't have to deal with an undefined.
305
+ body: JSON.stringify(params ?? {})
236
306
  });
237
- if (res.status === 409) return;
238
307
  if (!res.ok) {
239
308
  throw new Error(`Gateway error: ${res.status} ${res.statusText}`);
240
309
  }
310
+ return await res.json();
241
311
  }
242
312
  };
243
313
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/protocol/gateway.ts"],"sourcesContent":["export interface GatewayEnvelope<T> {\n data: T;\n proof: GatewayProof;\n /**\n * Cursor-based pagination metadata, present on list endpoints (e.g.\n * `GET /v1/files`). A sibling of `data`, not nested inside it — so callers\n * that need it must read the full envelope rather than going through\n * `unwrapEnvelope`, which intentionally returns only `data`.\n */\n pagination?: GatewayPagination;\n}\n\nexport interface GatewayPagination {\n limit: number;\n hasMore: boolean;\n /**\n * Opaque cursor for the NEXT page; pass back as the `cursor` query param.\n * Null when there are no further pages.\n */\n nextCursor: string | null;\n}\n\nexport interface GatewayProof {\n signature: string;\n timestamp: string;\n gatewayAddress: string;\n requestHash: string;\n responseHash: string;\n userSignature: string;\n status: string;\n chainBlockHeight: number;\n}\n\nexport interface Builder {\n id: string;\n ownerAddress: string;\n granteeAddress: string;\n publicKey: string;\n appUrl: string;\n addedAt: string;\n}\n\nexport interface Schema {\n id: string;\n ownerAddress: string;\n name: string;\n definitionUrl: string;\n scope: string;\n addedAt: string;\n}\n\nexport interface ServerInfo {\n id: string;\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n addedAt: string;\n}\n\nexport interface GatewayGrantResponse {\n id: string;\n grantorAddress: string;\n granteeId: string;\n grant: string;\n fileIds: string[];\n status: \"pending\" | \"confirmed\";\n addedAt: string;\n revokedAt: string | null;\n revocationSignature: string | null;\n}\n\nexport interface GrantListItem {\n id: string;\n grantorAddress: string;\n granteeId: string;\n grant: string;\n fileIds: string[];\n status: \"pending\" | \"confirmed\";\n addedAt: string;\n revokedAt: string | null;\n revocationSignature: string | null;\n}\n\nexport interface FileRecord {\n fileId: string;\n owner: string;\n url: string;\n schemaId: string;\n createdAt: string;\n /**\n * Soft-deletion timestamp (ISO 8601), or null if the file is active. Always present\n * (`normalizeFileRecord` populates it); non-null only when the gateway returns deletion state\n * (e.g. listed with `includeDeleted`). Drives the PS sync delete-reconciliation.\n */\n deletedAt: string | null;\n}\n\nexport interface FileListResult {\n files: FileRecord[];\n cursor: string | null;\n}\n\nexport interface ListFilesOptions {\n /**\n * Include soft-deleted files in the result (each carries a non-null `deletedAt`). Default false.\n * Used by the PS sync download worker to reconcile deletions of files it already holds locally.\n */\n includeDeleted?: boolean;\n}\n\ninterface GatewayFileRecord {\n id?: string;\n fileId?: string;\n ownerAddress?: string;\n owner?: string;\n url: string;\n schemaId: string;\n addedAt?: string;\n createdAt?: string;\n deletedAt?: string | null;\n}\n\nexport interface RegisterFileParams {\n ownerAddress: string;\n url: string;\n schemaId: string;\n signature: string;\n}\n\nexport interface CreateGrantParams {\n grantorAddress: string;\n granteeId: string;\n grant: string;\n fileIds: string[];\n signature: string;\n}\n\nexport interface RevokeGrantParams {\n grantId: string;\n grantorAddress: string;\n signature: string;\n}\n\nexport interface DeleteFileParams {\n fileId: string;\n ownerAddress: string;\n /** EIP-712 FileDeletion signature, signed by the owner or the owner's registered server. */\n signature: string;\n}\n\nexport interface RegisterServerParams {\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n signature: string;\n}\n\nexport interface RegisterServerResult {\n serverId?: string;\n alreadyRegistered: boolean;\n}\n\nexport interface GatewayClient {\n isRegisteredBuilder(address: string): Promise<boolean>;\n getBuilder(address: string): Promise<Builder | null>;\n getGrant(grantId: string): Promise<GatewayGrantResponse | null>;\n listGrantsByUser(userAddress: string): Promise<GrantListItem[]>;\n getSchemaForScope(scope: string): Promise<Schema | null>;\n getServer(address: string): Promise<ServerInfo | null>;\n getFile(fileId: string): Promise<FileRecord | null>;\n listFilesSince(\n owner: string,\n cursor: string | null,\n options?: ListFilesOptions,\n ): Promise<FileListResult>;\n getSchema(schemaId: string): Promise<Schema | null>;\n registerServer(params: RegisterServerParams): Promise<RegisterServerResult>;\n registerFile(params: RegisterFileParams): Promise<{ fileId?: string }>;\n createGrant(params: CreateGrantParams): Promise<{ grantId?: string }>;\n revokeGrant(params: RevokeGrantParams): Promise<void>;\n /**\n * Soft-deletes (de-registers) a file at the gateway. Resolves on 200 and on 409\n * (already deleted) — 409 is treated as idempotent success. Other non-2xx, including\n * 404 (file not registered), throw; the PS delete cascade decides whether a 404 is\n * benign (blob already gone) or a hard failure.\n */\n deleteFile(params: DeleteFileParams): Promise<void>;\n}\n\nexport function createGatewayClient(baseUrl: string): GatewayClient {\n const base = baseUrl.replace(/\\/+$/, \"\");\n\n async function unwrapEnvelope<T>(res: Response): Promise<T> {\n const envelope = (await res.json()) as GatewayEnvelope<T>;\n return envelope.data;\n }\n\n function normalizeFileRecord(record: GatewayFileRecord): FileRecord {\n return {\n fileId: record.fileId ?? record.id ?? \"\",\n owner: record.owner ?? record.ownerAddress ?? \"\",\n url: record.url,\n schemaId: record.schemaId,\n createdAt: record.createdAt ?? record.addedAt ?? \"\",\n deletedAt: record.deletedAt ?? null,\n };\n }\n\n function getMutationId(\n body: Record<string, unknown>,\n key: string,\n ): string | undefined {\n const value = body[key] ?? body[\"id\"];\n return typeof value === \"string\" ? value : undefined;\n }\n\n return {\n async isRegisteredBuilder(address: string): Promise<boolean> {\n const builder = await this.getBuilder(address);\n return builder !== null;\n },\n\n async getBuilder(address: string): Promise<Builder | null> {\n const res = await fetch(`${base}/v1/builders/${address}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Builder>(res);\n },\n\n async getGrant(grantId: string): Promise<GatewayGrantResponse | null> {\n const res = await fetch(`${base}/v1/grants/${grantId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<GatewayGrantResponse>(res);\n },\n\n async listGrantsByUser(userAddress: string): Promise<GrantListItem[]> {\n const res = await fetch(`${base}/v1/grants?user=${userAddress}`);\n if (res.status === 404) return [];\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<GrantListItem[]>(res);\n },\n\n async getSchemaForScope(scope: string): Promise<Schema | null> {\n const res = await fetch(`${base}/v1/schemas?scope=${scope}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Schema>(res);\n },\n\n async getServer(address: string): Promise<ServerInfo | null> {\n const res = await fetch(`${base}/v1/servers/${address}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<ServerInfo>(res);\n },\n\n async getFile(fileId: string): Promise<FileRecord | null> {\n const res = await fetch(`${base}/v1/files/${fileId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return normalizeFileRecord(await unwrapEnvelope<GatewayFileRecord>(res));\n },\n\n async listFilesSince(\n owner: string,\n cursor: string | null,\n options?: ListFilesOptions,\n ): Promise<FileListResult> {\n const params = new URLSearchParams({ user: owner });\n if (cursor !== null) {\n params.set(\"cursor\", cursor);\n }\n if (options?.includeDeleted) {\n params.set(\"includeDeleted\", \"true\");\n }\n const res = await fetch(`${base}/v1/files?${params.toString()}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // The next-page cursor lives in the envelope's `pagination.nextCursor`\n // (a sibling of `data`), so read the full envelope rather than going\n // through `unwrapEnvelope`, which returns only `data`. Fall back to a\n // legacy `data.cursor` for older gateways that nested it there.\n const envelope = (await res.json()) as GatewayEnvelope<{\n files: GatewayFileRecord[];\n cursor?: string | null;\n }>;\n const { pagination } = envelope;\n const nextCursor =\n pagination?.hasMore === false\n ? null\n : (pagination?.nextCursor ?? envelope.data.cursor ?? null);\n return {\n files: envelope.data.files.map(normalizeFileRecord),\n cursor: nextCursor,\n };\n },\n\n async getSchema(schemaId: string): Promise<Schema | null> {\n const res = await fetch(`${base}/v1/schemas/${schemaId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Schema>(res);\n },\n\n async registerServer(\n params: RegisterServerParams,\n ): Promise<RegisterServerResult> {\n const res = await fetch(`${base}/v1/servers`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n serverAddress: params.serverAddress,\n publicKey: params.publicKey,\n serverUrl: params.serverUrl,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n serverId: getMutationId(body as Record<string, unknown>, \"serverId\"),\n alreadyRegistered: true,\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json().catch(() => ({}));\n return {\n serverId: getMutationId(body as Record<string, unknown>, \"serverId\"),\n alreadyRegistered: false,\n };\n },\n\n async registerFile(\n params: RegisterFileParams,\n ): Promise<{ fileId?: string }> {\n const res = await fetch(`${base}/v1/files`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n url: params.url,\n schemaId: params.schemaId,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n fileId: getMutationId(body as Record<string, unknown>, \"fileId\"),\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json();\n return {\n fileId: getMutationId(body as Record<string, unknown>, \"fileId\"),\n };\n },\n\n async createGrant(\n params: CreateGrantParams,\n ): Promise<{ grantId?: string }> {\n const res = await fetch(`${base}/v1/grants`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n grantorAddress: params.grantorAddress,\n granteeId: params.granteeId,\n grant: params.grant,\n fileIds: params.fileIds,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n grantId: getMutationId(body as Record<string, unknown>, \"grantId\"),\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json();\n return {\n grantId: getMutationId(body as Record<string, unknown>, \"grantId\"),\n };\n },\n\n async revokeGrant(params: RevokeGrantParams): Promise<void> {\n const res = await fetch(`${base}/v1/grants/${params.grantId}`, {\n method: \"DELETE\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n grantorAddress: params.grantorAddress,\n }),\n });\n if (res.status === 409) return;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n },\n\n async deleteFile(params: DeleteFileParams): Promise<void> {\n const res = await fetch(`${base}/v1/files/${params.fileId}`, {\n method: \"DELETE\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n }),\n });\n // 409 = already deleted; treat as success (idempotent), same as revokeGrant.\n if (res.status === 409) return;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n },\n };\n}\n"],"mappings":"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","names":["body"]}
1
+ {"version":3,"sources":["../../src/protocol/gateway.ts"],"sourcesContent":["export interface GatewayEnvelope<T> {\n data: T;\n proof: GatewayProof;\n /**\n * Cursor-based pagination metadata, present on list endpoints (e.g.\n * `GET /v1/data`). A sibling of `data`, not nested inside it — so callers\n * that need it must read the full envelope rather than going through\n * `unwrapEnvelope`, which intentionally returns only `data`.\n */\n pagination?: GatewayPagination;\n}\n\nexport interface GatewayPagination {\n limit: number;\n hasMore: boolean;\n /**\n * Opaque cursor for the NEXT page; pass back as the `cursor` query param.\n * Null when there are no further pages.\n */\n nextCursor: string | null;\n}\n\nexport interface GatewayProof {\n signature: string;\n timestamp: string;\n gatewayAddress: string;\n requestHash: string;\n responseHash: string;\n userSignature: string;\n status: string;\n chainBlockHeight: number;\n}\n\nexport interface Builder {\n id: string;\n ownerAddress: string;\n granteeAddress: string;\n publicKey: string;\n appUrl: string;\n addedAt: string;\n}\n\nexport interface Schema {\n id: string;\n ownerAddress: string;\n name: string;\n definitionUrl: string;\n scope: string;\n addedAt: string;\n}\n\nexport interface ServerInfo {\n id: string;\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n addedAt: string;\n // ISO timestamp when the grantor deregistered this server, null while\n // active. The gateway returns this on /v1/servers/:address GETs since\n // covering revocation in the response keeps the attestation hash\n // authoritative for both states.\n revokedAt: string | null;\n}\n\n// Fee annotation surfaced on every GET grant response. Amounts are decimal\n// uint256 strings to match `/v1/escrow/pay`'s wire format. totalDue is a\n// snapshot — the gateway re-resolves fees at pay time, so clients shouldn't\n// cache this across requests.\nexport interface GatewayGrantFee {\n asset: string;\n registrationFee: string;\n dataAccessFee: string;\n totalDue: string;\n}\n\n// Lifecycle of a grant's on-chain settlement, tracked separately from the\n// fee-payment lifecycle (paymentStatus). Driven by POST /v1/settle:\n// pending — nothing on-chain yet\n// submitting — settle tx broadcast but receipt not yet observed\n// confirmed — settle tx mined successfully\n// finalized — finalized tip past the settle block, reorg-safe\n// reorged — finalized observation reverted; back to 'pending' on next settle\nexport type GatewayGrantStatus =\n | \"pending\"\n | \"submitting\"\n | \"confirmed\"\n | \"finalized\"\n | \"reorged\";\n\nexport interface GatewayGrantResponse {\n id: string;\n grantorAddress: string;\n granteeId: string;\n scopes: string[];\n status: GatewayGrantStatus;\n addedAt: string;\n // Grantor-signed deadline. null = perpetual grant (signed value was 0).\n expiresAt: string | null;\n // Derived at read time from expiresAt vs the gateway's clock — a snapshot,\n // not a cached truth. Re-check against expiresAt locally if you care.\n expired: boolean;\n revokedAt: string | null;\n revocationSignature: string | null;\n // 'pending' until the grant registration fee is settled via /v1/escrow/pay.\n paymentStatus: \"pending\" | \"paid\";\n paidAt: string | null;\n paidBy: string | null;\n // Decimal-string uint256 monotonic nonce; advances on every state change.\n grantVersion: string;\n // Settle metadata — populated as the grant progresses through the chain\n // lifecycle. Null while `status === 'pending'`.\n settleTxHash: string | null;\n settleSubmittedAt: string | null;\n // Revocation metadata — populated independently when the grantor signs\n // and the gateway pushes a deregister tx.\n revocationTxHash: string | null;\n revocationSubmittedAt: string | null;\n fee: GatewayGrantFee;\n}\n\nexport type GrantListItem = GatewayGrantResponse;\n\n// Mirror of a DataRegistryV2 row as the gateway exposes it. `id` is the\n// deterministic `keccak256(abi.encode(owner, scope))` dataPointId — the same\n// value the contract uses as its primary key. `expectedVersion` is the latest\n// version the gateway has accepted; the on-chain row may be one version behind\n// while a settle is still pending. The gateway response intentionally drops\n// `status` from the body — read it from the on-chain contract when you need\n// the canonical lifecycle state.\nexport interface DataPointRecord {\n id: string;\n ownerAddress: string;\n scope: string;\n dataHash: string;\n metadataHash: string;\n // Decimal-string uint256.\n expectedVersion: string;\n // ISO 8601 timestamp of the most recent gateway-side upsert.\n addedAt: string;\n}\n\nexport interface DataPointListResult {\n dataPoints: DataPointRecord[];\n cursor: string | null;\n}\n\nexport interface ListDataPointsOptions {\n /**\n * Only return rows added at or after this ISO 8601 timestamp. Used by sync\n * loops that want incremental tails — pass the last seen `addedAt`.\n */\n since?: string;\n /** Page size. Capped at 1000 by the gateway. */\n limit?: number;\n}\n\n// grantVersion and expiresAt are decimal-string uint256s — same wire format\n// the gateway expects. The caller is responsible for converting their bigint\n// to a decimal string and for signing GRANT_REGISTRATION_TYPES with matching\n// bigint values.\nexport interface CreateGrantParams {\n grantorAddress: string;\n granteeId: string;\n scopes: string[];\n grantVersion: string;\n expiresAt: string;\n signature: string;\n}\n\nexport interface RevokeGrantParams {\n grantId: string;\n grantorAddress: string;\n grantVersion: string;\n signature: string;\n}\n\nexport interface RegisterServerParams {\n ownerAddress: string;\n serverAddress: string;\n publicKey: string;\n serverUrl: string;\n signature: string;\n}\n\nexport interface RegisterServerResult {\n serverId?: string;\n alreadyRegistered: boolean;\n}\n\nexport interface RegisterBuilderParams {\n ownerAddress: string;\n // Wallet the builder authenticates to the Personal Server with. The\n // builderId is deterministically derived from (owner, grantee, publicKey,\n // appUrl) so this triple pins the on-chain identity.\n granteeAddress: string;\n publicKey: string;\n appUrl: string;\n signature: string;\n}\n\nexport interface RegisterBuilderResult {\n builderId?: string;\n alreadyRegistered: boolean;\n}\n\n// AddData on DataRegistryV2. dataHash + metadataHash are bytes32 commitments\n// to the off-chain payload + its metadata. expectedVersion is a CAS knob —\n// the gateway/contract rejects on 409 if a higher version is already stored,\n// and the error body surfaces `currentExpectedVersion` so callers can re-sign.\nexport interface RegisterDataPointParams {\n ownerAddress: string;\n scope: string;\n dataHash: string;\n metadataHash: string;\n expectedVersion: string;\n signature: string;\n}\n\nexport interface RegisterDataPointResult {\n dataPointId?: string;\n expectedVersion?: string;\n}\n\n// ── Escrow / data-access payment path ───────────────────────────────────────\n// /v1/escrow/pay debits the payer's escrow balance for a payable op. For a\n// grant: opType = 'grant', opId = the bytes32 grantId. amount, paymentNonce,\n// and asset are decimal-uint256 strings on the wire. The signature is the\n// raw EIP-712 hex of GENERIC_PAYMENT_TYPES against escrowPaymentDomain.\n\n// A server-signed delivery receipt attached to a data-access payment. The\n// signature is over RECORD_DATA_ACCESS_TYPES against dataRegistryDomain; the\n// signer must be a personal server the data point's owner has registered as\n// trusted. The gateway re-uses this signature verbatim on-chain in the next\n// /v1/settle pass via DataRegistryV2.recordDataAccess, where `recordId`\n// dedupes via `_usedRecordIds`.\nexport interface AccessRecord {\n dataPointId: string;\n // Decimal-string uint256 — the data point version being attested to.\n version: string;\n // Must equal the enclosing payment's payerAddress (the gateway enforces).\n accessor: string;\n recordId: string;\n signature: string;\n}\n\nexport interface PayForOperationParams {\n payerAddress: string;\n opType: string;\n opId: string;\n asset: string;\n amount: string;\n // Per-payer monotonic; (payer, nonce, kind) must be unique. The gateway\n // returns 409 if reused — bump and re-sign.\n paymentNonce: string;\n signature: string;\n // Optional: attach a server-signed access record so the next /v1/settle\n // pass submits a recordDataAccess tx alongside the payment settlement.\n // Required for data-access payments (the second-and-onward payments per\n // grant) that want their on-chain `totalAccesses` counter to advance.\n accessRecord?: AccessRecord;\n}\n\nexport interface PayForOperationResult {\n opType: string;\n opId: string;\n payerAddress: string;\n asset: string;\n amount: string;\n // Echoes how the gateway split this payment. `registrationPaid` is true on\n // the first payment for a grant (which bundles both fees) and false on\n // subsequent data-access-only payments. Off-chain ledger state only — the\n // on-chain settlement of the registration is tracked by the grant's\n // `status` field, not this flag.\n breakdown: {\n registrationFee: string;\n dataAccessFee: string;\n registrationPaid: boolean;\n };\n paymentNonce: string;\n paidAt: string;\n}\n\n// ── Settle / reconcile ──────────────────────────────────────────────────────\n// POST /v1/settle drains pending-on-chain rows (grants, servers, builders,\n// data points, data-point statuses, access records) to the relayer, then\n// promotes 'submitting' → 'confirmed' and 'confirmed' → 'finalized' for\n// previously-submitted rows. One call does all three; the response surfaces\n// each phase's outcomes.\n\n// The op-types the settle endpoint emits in `items[]`. Kept as a union so\n// callers can narrow inside the discriminated SettleItem shape. Mirrors the\n// gateway's drain phases (drainGrants/drainServers/drainBuilders/\n// drainDataPoints/drainDataPointStatuses/drainAccessRecords) — keep in sync\n// when the gateway adds a drain.\nexport type SettleOpType =\n | \"grant\"\n | \"server\"\n | \"data\"\n | \"access\"\n | \"builder\"\n | \"data-status\";\n\nexport type SettleItem =\n | {\n opType: SettleOpType;\n opId: string;\n // 'confirmed' when the submit function waited for the receipt and it\n // mined (registerAndSettle path); 'submitting' when only the tx was\n // sent (no receipt wait).\n status: \"submitting\" | \"confirmed\";\n settleTxHash: string | null;\n settleSubmittedAt: string | null;\n // Block height the tx mined in; only set when status === 'confirmed'.\n chainBlockHeight: string | null;\n revocationTxHash: string | null;\n revocationSubmittedAt: string | null;\n // True while lib/settle.ts is in placeholder mode for this row's pass.\n placeholder: boolean;\n }\n | {\n opType: SettleOpType;\n opId: string;\n status: \"skipped\";\n reason: string;\n }\n | {\n opType: SettleOpType;\n opId: string;\n status: \"failed\";\n error: string;\n };\n\n// Outcome of the housekeeping pass that retries earlier `submitting` rows\n// whose receipt arrived after the prior /v1/settle's wait budget elapsed.\nexport interface SettlePromoteResult {\n opType: SettleOpType;\n opId: string;\n status: \"confirmed\" | \"failed\" | \"pending\" | \"skipped\";\n txHash: string;\n chainBlockHeight: string | null;\n reason?: string;\n}\n\n// Outcome of the reconcile pass that advances 'confirmed' → 'finalized' once\n// the chain's finalized tip catches up past the tx's block (or reverts to\n// 'pending' on reorg detection).\nexport interface SettleReconcileItem {\n opId: string;\n status: \"finalized\" | \"reorged\" | \"unchanged\";\n chainBlockHeight: string | null;\n settleTxHash: string | null;\n reason?: string;\n}\n\nexport interface SettleParams {\n // Per-phase cap. Bounded by MAX_LIMIT on the gateway side; omit to use\n // the gateway's default BATCH_LIMIT.\n limit?: number;\n}\n\nexport interface SettleResult {\n scanned: number;\n submitted: number;\n confirmed: number;\n skipped: number;\n failed: number;\n items: SettleItem[];\n promoted: { count: number; items: SettlePromoteResult[] };\n reconciled: {\n scanned: number;\n finalized: number;\n reorged: number;\n unchanged: number;\n items: SettleReconcileItem[];\n };\n // Present only when the gateway is configured for paced submission —\n // spreads work across several blocks within one /v1/settle invocation.\n paced?: { iterations: number };\n}\n\n// /v1/escrow/balance?account=... — pure read. Returns finalized balances by\n// asset, plus the lifecycle breakdown of deposits.\nexport interface EscrowBalanceEntry {\n asset: string;\n // Gross credited deposits for (account, asset). Decremented only when the\n // reconcile pass marks a payment finalized — NOT on /v1/escrow/pay.\n balance: string;\n // Sum of claimedAmount for deposits still in 'submitted' status — surfaced\n // separately so clients don't conflate \"credited\" with \"deposit announced\n // but not yet confirmed.\"\n pendingAmount: string;\n // Sum of payments.amount for (account, asset) regardless of settled status —\n // mirrors the /v1/escrow/pay handler's soft-lock counter. Subtract from\n // `balance` to see how much the payer can still authorise.\n authorizedAmount: string;\n // `max(balance − authorizedAmount, 0)`. The headroom a payer has against\n // the soft-lock before /v1/escrow/pay starts returning 402.\n availableAmount: string;\n updatedAt: string | null;\n}\n\nexport interface EscrowDepositSubmitted {\n txHash: string;\n submittedAt: string;\n claimedAsset: string;\n claimedAmount: string;\n}\n\nexport interface EscrowDepositFinalized {\n txHash: string;\n finalizedAt: string | null;\n blockNumber: string | null;\n claimedAsset: string;\n claimedAmount: string;\n}\n\nexport interface EscrowDepositFailed {\n txHash: string;\n submittedAt: string;\n claimedAsset: string;\n claimedAmount: string;\n lastError: string | null;\n}\n\nexport interface EscrowBalance {\n account: string;\n balances: EscrowBalanceEntry[];\n deposits: {\n submitted: EscrowDepositSubmitted[];\n finalized: EscrowDepositFinalized[];\n failed: EscrowDepositFailed[];\n };\n}\n\n// /v1/escrow/deposit announces an on-chain deposit tx so the gateway can\n// reconcile it into the payer's balance. The gateway extracts the credited\n// account from calldata — no off-chain claim about who paid.\nexport interface SubmitDepositParams {\n txHash: string;\n}\n\nexport interface DepositState {\n txHash: string;\n account: string;\n // 'submitted' | 'finalized' | 'failed' — kept open since the gateway adds\n // states (e.g. 'orphaned') as the deposit flow evolves.\n status: string;\n blockNumber: string | null;\n submittedAt: string;\n finalizedAt: string | null;\n lastError: string | null;\n}\n\nexport interface GatewayClient {\n isRegisteredBuilder(address: string): Promise<boolean>;\n getBuilder(address: string): Promise<Builder | null>;\n getGrant(grantId: string): Promise<GatewayGrantResponse | null>;\n listGrantsByUser(userAddress: string): Promise<GrantListItem[]>;\n getSchemaForScope(scope: string): Promise<Schema | null>;\n getServer(address: string): Promise<ServerInfo | null>;\n /**\n * Fetch a single data point by its deterministic id (keccak256 of (owner, scope)).\n * Returns null on 404. The gateway omits `status` from the response body — read it\n * from the on-chain DataRegistryV2 contract when you need the canonical lifecycle state.\n */\n getDataPoint(dataPointId: string): Promise<DataPointRecord | null>;\n /**\n * Page through an owner's data points. Cursor is opaque; pass `null` for the first\n * page and feed back `result.cursor` until it returns null.\n */\n listDataPointsByOwner(\n owner: string,\n cursor: string | null,\n options?: ListDataPointsOptions,\n ): Promise<DataPointListResult>;\n getSchema(schemaId: string): Promise<Schema | null>;\n registerServer(params: RegisterServerParams): Promise<RegisterServerResult>;\n registerBuilder(\n params: RegisterBuilderParams,\n ): Promise<RegisterBuilderResult>;\n registerDataPoint(\n params: RegisterDataPointParams,\n ): Promise<RegisterDataPointResult>;\n createGrant(params: CreateGrantParams): Promise<{ grantId?: string }>;\n revokeGrant(params: RevokeGrantParams): Promise<void>;\n getEscrowBalance(account: string): Promise<EscrowBalance>;\n submitEscrowDeposit(params: SubmitDepositParams): Promise<DepositState>;\n payForOperation(\n params: PayForOperationParams,\n ): Promise<PayForOperationResult>;\n settle(params?: SettleParams): Promise<SettleResult>;\n}\n\nexport function createGatewayClient(baseUrl: string): GatewayClient {\n const base = baseUrl.replace(/\\/+$/, \"\");\n\n async function unwrapEnvelope<T>(res: Response): Promise<T> {\n const envelope = (await res.json()) as GatewayEnvelope<T>;\n return envelope.data;\n }\n\n function getMutationId(\n body: Record<string, unknown>,\n key: string,\n ): string | undefined {\n const value = body[key] ?? body[\"id\"];\n return typeof value === \"string\" ? value : undefined;\n }\n\n return {\n async isRegisteredBuilder(address: string): Promise<boolean> {\n const builder = await this.getBuilder(address);\n return builder !== null;\n },\n\n async getBuilder(address: string): Promise<Builder | null> {\n const res = await fetch(`${base}/v1/builders/${address}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Builder>(res);\n },\n\n async getGrant(grantId: string): Promise<GatewayGrantResponse | null> {\n const res = await fetch(`${base}/v1/grants/${grantId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<GatewayGrantResponse>(res);\n },\n\n async listGrantsByUser(userAddress: string): Promise<GrantListItem[]> {\n const res = await fetch(`${base}/v1/grants?user=${userAddress}`);\n if (res.status === 404) return [];\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<GrantListItem[]>(res);\n },\n\n async getSchemaForScope(scope: string): Promise<Schema | null> {\n const res = await fetch(`${base}/v1/schemas?scope=${scope}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Schema>(res);\n },\n\n async getServer(address: string): Promise<ServerInfo | null> {\n const res = await fetch(`${base}/v1/servers/${address}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<ServerInfo>(res);\n },\n\n async getDataPoint(dataPointId: string): Promise<DataPointRecord | null> {\n const res = await fetch(`${base}/v1/data/${dataPointId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<DataPointRecord>(res);\n },\n\n async listDataPointsByOwner(\n owner: string,\n cursor: string | null,\n options?: ListDataPointsOptions,\n ): Promise<DataPointListResult> {\n const params = new URLSearchParams({ user: owner });\n if (cursor !== null) {\n params.set(\"cursor\", cursor);\n }\n if (options?.since) {\n params.set(\"since\", options.since);\n }\n if (options?.limit !== undefined) {\n params.set(\"limit\", String(options.limit));\n }\n const res = await fetch(`${base}/v1/data?${params.toString()}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // Next-page cursor lives in the envelope's `pagination.nextCursor`\n // (a sibling of `data`), so read the full envelope rather than going\n // through `unwrapEnvelope`, which returns only `data`.\n const envelope = (await res.json()) as GatewayEnvelope<{\n dataPoints: DataPointRecord[];\n }>;\n const nextCursor =\n envelope.pagination?.hasMore === false\n ? null\n : (envelope.pagination?.nextCursor ?? null);\n return {\n dataPoints: envelope.data.dataPoints,\n cursor: nextCursor,\n };\n },\n\n async getSchema(schemaId: string): Promise<Schema | null> {\n const res = await fetch(`${base}/v1/schemas/${schemaId}`);\n if (res.status === 404) return null;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return unwrapEnvelope<Schema>(res);\n },\n\n async registerServer(\n params: RegisterServerParams,\n ): Promise<RegisterServerResult> {\n const res = await fetch(`${base}/v1/servers`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n serverAddress: params.serverAddress,\n publicKey: params.publicKey,\n serverUrl: params.serverUrl,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n serverId: getMutationId(body as Record<string, unknown>, \"serverId\"),\n alreadyRegistered: true,\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json().catch(() => ({}));\n return {\n serverId: getMutationId(body as Record<string, unknown>, \"serverId\"),\n alreadyRegistered: false,\n };\n },\n\n async registerBuilder(\n params: RegisterBuilderParams,\n ): Promise<RegisterBuilderResult> {\n const res = await fetch(`${base}/v1/builders`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n granteeAddress: params.granteeAddress,\n publicKey: params.publicKey,\n appUrl: params.appUrl,\n }),\n });\n // 409 is idempotent — the gateway's current 409 body doesn't include\n // the builderId, but we tolerate it in case that changes (mirrors the\n // registerServer / createGrant shape).\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n builderId: getMutationId(\n body as Record<string, unknown>,\n \"builderId\",\n ),\n alreadyRegistered: true,\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json().catch(() => ({}));\n return {\n builderId: getMutationId(body as Record<string, unknown>, \"builderId\"),\n alreadyRegistered: false,\n };\n },\n\n async registerDataPoint(\n params: RegisterDataPointParams,\n ): Promise<RegisterDataPointResult> {\n const res = await fetch(`${base}/v1/data`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n ownerAddress: params.ownerAddress,\n scope: params.scope,\n dataHash: params.dataHash,\n metadataHash: params.metadataHash,\n expectedVersion: params.expectedVersion,\n }),\n });\n // 409 is a real failure here (stale CAS), not an idempotent replay —\n // surface the gateway's error message verbatim so the caller knows\n // what `currentExpectedVersion` to re-sign against.\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as {\n error?: string;\n };\n const detail = body.error ?? res.statusText;\n throw new Error(`Gateway error: ${res.status} ${detail}`);\n }\n const body = (await res.json().catch(() => ({}))) as {\n dataPointId?: string;\n expectedVersion?: string;\n };\n return {\n dataPointId: getMutationId(\n body as Record<string, unknown>,\n \"dataPointId\",\n ),\n expectedVersion: body.expectedVersion,\n };\n },\n\n async createGrant(\n params: CreateGrantParams,\n ): Promise<{ grantId?: string }> {\n const res = await fetch(`${base}/v1/grants`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n grantorAddress: params.grantorAddress,\n granteeId: params.granteeId,\n scopes: params.scopes,\n grantVersion: params.grantVersion,\n expiresAt: params.expiresAt,\n }),\n });\n if (res.status === 409) {\n const body = await res.json().catch(() => ({}));\n return {\n grantId: getMutationId(body as Record<string, unknown>, \"grantId\"),\n };\n }\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n const body = await res.json();\n return {\n grantId: getMutationId(body as Record<string, unknown>, \"grantId\"),\n };\n },\n\n async revokeGrant(params: RevokeGrantParams): Promise<void> {\n const res = await fetch(`${base}/v1/grants/${params.grantId}`, {\n method: \"DELETE\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify({\n grantorAddress: params.grantorAddress,\n grantVersion: params.grantVersion,\n }),\n });\n if (res.status === 409) return;\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n },\n\n async getEscrowBalance(account: string): Promise<EscrowBalance> {\n const res = await fetch(`${base}/v1/escrow/balance?account=${account}`);\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n // Unlike the rest of /v1, the balance endpoint returns the body\n // directly (no GatewayEnvelope wrap) — it's a pure read with no\n // gateway-signed attestation. See data-gateway api/v1/escrow/balance.ts.\n return (await res.json()) as EscrowBalance;\n },\n\n async submitEscrowDeposit(\n params: SubmitDepositParams,\n ): Promise<DepositState> {\n const res = await fetch(`${base}/v1/escrow/deposit`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ txHash: params.txHash }),\n });\n // The gateway returns 202 for \"accepted (still confirming)\" and 200 for\n // duplicate idempotent replays. Both carry the deposit's current state.\n if (res.status !== 200 && res.status !== 202) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as DepositState;\n },\n\n async payForOperation(\n params: PayForOperationParams,\n ): Promise<PayForOperationResult> {\n // Build the body without the accessRecord key when absent so the\n // gateway's \"missing optional\" branch matches the no-receipt case\n // exactly (an explicit `accessRecord: undefined` would JSON-serialize\n // to nothing — same result — but keeping it conditional makes wire\n // traces easier to read).\n const body: Record<string, unknown> = {\n payerAddress: params.payerAddress,\n opType: params.opType,\n opId: params.opId,\n asset: params.asset,\n amount: params.amount,\n paymentNonce: params.paymentNonce,\n };\n if (params.accessRecord) {\n body[\"accessRecord\"] = params.accessRecord;\n }\n const res = await fetch(`${base}/v1/escrow/pay`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Web3Signed ${params.signature}`,\n },\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as PayForOperationResult;\n },\n\n async settle(params?: SettleParams): Promise<SettleResult> {\n const res = await fetch(`${base}/v1/settle`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n // The gateway accepts an empty body; only `limit` is recognised.\n // Always send a JSON body so the gateway's req.body shape parse\n // doesn't have to deal with an undefined.\n body: JSON.stringify(params ?? {}),\n });\n if (!res.ok) {\n throw new Error(`Gateway error: ${res.status} ${res.statusText}`);\n }\n return (await res.json()) as SettleResult;\n },\n };\n}\n"],"mappings":"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","names":["body"]}