@tabai/sdk 0.2.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 (204) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +401 -0
  3. package/bin/tab.mjs +23 -0
  4. package/dist/_shared/abi.d.ts +150 -0
  5. package/dist/_shared/abi.d.ts.map +1 -0
  6. package/dist/_shared/abi.js +197 -0
  7. package/dist/_shared/abi.js.map +1 -0
  8. package/dist/_shared/chains.d.ts +118 -0
  9. package/dist/_shared/chains.d.ts.map +1 -0
  10. package/dist/_shared/chains.js +89 -0
  11. package/dist/_shared/chains.js.map +1 -0
  12. package/dist/_shared/hex.d.ts +35 -0
  13. package/dist/_shared/hex.d.ts.map +1 -0
  14. package/dist/_shared/hex.js +40 -0
  15. package/dist/_shared/hex.js.map +1 -0
  16. package/dist/_shared/index.d.ts +14 -0
  17. package/dist/_shared/index.d.ts.map +1 -0
  18. package/dist/_shared/index.js +14 -0
  19. package/dist/_shared/index.js.map +1 -0
  20. package/dist/_shared/keccak256.d.ts +29 -0
  21. package/dist/_shared/keccak256.d.ts.map +1 -0
  22. package/dist/_shared/keccak256.js +145 -0
  23. package/dist/_shared/keccak256.js.map +1 -0
  24. package/dist/_shared/result.d.ts +78 -0
  25. package/dist/_shared/result.d.ts.map +1 -0
  26. package/dist/_shared/result.js +61 -0
  27. package/dist/_shared/result.js.map +1 -0
  28. package/dist/cli/client-config.d.ts +155 -0
  29. package/dist/cli/client-config.d.ts.map +1 -0
  30. package/dist/cli/client-config.js +382 -0
  31. package/dist/cli/client-config.js.map +1 -0
  32. package/dist/cli/connect.d.ts +76 -0
  33. package/dist/cli/connect.d.ts.map +1 -0
  34. package/dist/cli/connect.js +158 -0
  35. package/dist/cli/connect.js.map +1 -0
  36. package/dist/cli/doctor.d.ts +57 -0
  37. package/dist/cli/doctor.d.ts.map +1 -0
  38. package/dist/cli/doctor.js +253 -0
  39. package/dist/cli/doctor.js.map +1 -0
  40. package/dist/cli/index.d.ts +13 -0
  41. package/dist/cli/index.d.ts.map +1 -0
  42. package/dist/cli/index.js +13 -0
  43. package/dist/cli/index.js.map +1 -0
  44. package/dist/cli/main.d.ts +45 -0
  45. package/dist/cli/main.d.ts.map +1 -0
  46. package/dist/cli/main.js +371 -0
  47. package/dist/cli/main.js.map +1 -0
  48. package/dist/errors.d.ts +29 -0
  49. package/dist/errors.d.ts.map +1 -0
  50. package/dist/errors.js +37 -0
  51. package/dist/errors.js.map +1 -0
  52. package/dist/http/client-402.d.ts +243 -0
  53. package/dist/http/client-402.d.ts.map +1 -0
  54. package/dist/http/client-402.js +515 -0
  55. package/dist/http/client-402.js.map +1 -0
  56. package/dist/http/headers.d.ts +173 -0
  57. package/dist/http/headers.d.ts.map +1 -0
  58. package/dist/http/headers.js +284 -0
  59. package/dist/http/headers.js.map +1 -0
  60. package/dist/http/index.d.ts +15 -0
  61. package/dist/http/index.d.ts.map +1 -0
  62. package/dist/http/index.js +15 -0
  63. package/dist/http/index.js.map +1 -0
  64. package/dist/http/metering-claim.d.ts +82 -0
  65. package/dist/http/metering-claim.d.ts.map +1 -0
  66. package/dist/http/metering-claim.js +99 -0
  67. package/dist/http/metering-claim.js.map +1 -0
  68. package/dist/index.d.ts +48 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +51 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/logger.d.ts +40 -0
  73. package/dist/logger.d.ts.map +1 -0
  74. package/dist/logger.js +50 -0
  75. package/dist/logger.js.map +1 -0
  76. package/dist/mcp/assets.d.ts +31 -0
  77. package/dist/mcp/assets.d.ts.map +1 -0
  78. package/dist/mcp/assets.js +78 -0
  79. package/dist/mcp/assets.js.map +1 -0
  80. package/dist/mcp/index.d.ts +19 -0
  81. package/dist/mcp/index.d.ts.map +1 -0
  82. package/dist/mcp/index.js +19 -0
  83. package/dist/mcp/index.js.map +1 -0
  84. package/dist/mcp/json-schema.d.ts +86 -0
  85. package/dist/mcp/json-schema.d.ts.map +1 -0
  86. package/dist/mcp/json-schema.js +215 -0
  87. package/dist/mcp/json-schema.js.map +1 -0
  88. package/dist/mcp/json.d.ts +43 -0
  89. package/dist/mcp/json.d.ts.map +1 -0
  90. package/dist/mcp/json.js +69 -0
  91. package/dist/mcp/json.js.map +1 -0
  92. package/dist/mcp/registry-client.d.ts +88 -0
  93. package/dist/mcp/registry-client.d.ts.map +1 -0
  94. package/dist/mcp/registry-client.js +158 -0
  95. package/dist/mcp/registry-client.js.map +1 -0
  96. package/dist/mcp/schemas.d.ts +82 -0
  97. package/dist/mcp/schemas.d.ts.map +1 -0
  98. package/dist/mcp/schemas.js +493 -0
  99. package/dist/mcp/schemas.js.map +1 -0
  100. package/dist/mcp/server.d.ts +97 -0
  101. package/dist/mcp/server.d.ts.map +1 -0
  102. package/dist/mcp/server.js +285 -0
  103. package/dist/mcp/server.js.map +1 -0
  104. package/dist/mcp/settings.d.ts +90 -0
  105. package/dist/mcp/settings.d.ts.map +1 -0
  106. package/dist/mcp/settings.js +160 -0
  107. package/dist/mcp/settings.js.map +1 -0
  108. package/dist/mcp/toolset.d.ts +231 -0
  109. package/dist/mcp/toolset.d.ts.map +1 -0
  110. package/dist/mcp/toolset.js +760 -0
  111. package/dist/mcp/toolset.js.map +1 -0
  112. package/dist/payments/abi.d.ts +9 -0
  113. package/dist/payments/abi.d.ts.map +1 -0
  114. package/dist/payments/abi.js +17 -0
  115. package/dist/payments/abi.js.map +1 -0
  116. package/dist/payments/config.d.ts +199 -0
  117. package/dist/payments/config.d.ts.map +1 -0
  118. package/dist/payments/config.js +259 -0
  119. package/dist/payments/config.js.map +1 -0
  120. package/dist/payments/index.d.ts +13 -0
  121. package/dist/payments/index.d.ts.map +1 -0
  122. package/dist/payments/index.js +13 -0
  123. package/dist/payments/index.js.map +1 -0
  124. package/dist/payments/kuru.d.ts +191 -0
  125. package/dist/payments/kuru.d.ts.map +1 -0
  126. package/dist/payments/kuru.js +377 -0
  127. package/dist/payments/kuru.js.map +1 -0
  128. package/dist/payments/monad.d.ts +69 -0
  129. package/dist/payments/monad.d.ts.map +1 -0
  130. package/dist/payments/monad.js +306 -0
  131. package/dist/payments/monad.js.map +1 -0
  132. package/dist/payments/permit2.d.ts +118 -0
  133. package/dist/payments/permit2.d.ts.map +1 -0
  134. package/dist/payments/permit2.js +366 -0
  135. package/dist/payments/permit2.js.map +1 -0
  136. package/dist/payments/registry.d.ts +119 -0
  137. package/dist/payments/registry.d.ts.map +1 -0
  138. package/dist/payments/registry.js +199 -0
  139. package/dist/payments/registry.js.map +1 -0
  140. package/dist/payments/strategy.d.ts +80 -0
  141. package/dist/payments/strategy.d.ts.map +1 -0
  142. package/dist/payments/strategy.js +103 -0
  143. package/dist/payments/strategy.js.map +1 -0
  144. package/dist/proxy/hooks.d.ts +90 -0
  145. package/dist/proxy/hooks.d.ts.map +1 -0
  146. package/dist/proxy/hooks.js +35 -0
  147. package/dist/proxy/hooks.js.map +1 -0
  148. package/dist/proxy/index.d.ts +9 -0
  149. package/dist/proxy/index.d.ts.map +1 -0
  150. package/dist/proxy/index.js +9 -0
  151. package/dist/proxy/index.js.map +1 -0
  152. package/dist/proxy/proxy.d.ts +156 -0
  153. package/dist/proxy/proxy.d.ts.map +1 -0
  154. package/dist/proxy/proxy.js +366 -0
  155. package/dist/proxy/proxy.js.map +1 -0
  156. package/dist/server/adapters/express.d.ts +89 -0
  157. package/dist/server/adapters/express.d.ts.map +1 -0
  158. package/dist/server/adapters/express.js +215 -0
  159. package/dist/server/adapters/express.js.map +1 -0
  160. package/dist/server/adapters/hono.d.ts +52 -0
  161. package/dist/server/adapters/hono.d.ts.map +1 -0
  162. package/dist/server/adapters/hono.js +61 -0
  163. package/dist/server/adapters/hono.js.map +1 -0
  164. package/dist/server/adapters/next.d.ts +52 -0
  165. package/dist/server/adapters/next.d.ts.map +1 -0
  166. package/dist/server/adapters/next.js +56 -0
  167. package/dist/server/adapters/next.js.map +1 -0
  168. package/dist/server/index.d.ts +30 -0
  169. package/dist/server/index.d.ts.map +1 -0
  170. package/dist/server/index.js +30 -0
  171. package/dist/server/index.js.map +1 -0
  172. package/dist/server/metering.d.ts +209 -0
  173. package/dist/server/metering.d.ts.map +1 -0
  174. package/dist/server/metering.js +365 -0
  175. package/dist/server/metering.js.map +1 -0
  176. package/dist/server/post-paid.d.ts +355 -0
  177. package/dist/server/post-paid.d.ts.map +1 -0
  178. package/dist/server/post-paid.js +512 -0
  179. package/dist/server/post-paid.js.map +1 -0
  180. package/dist/x402/client.d.ts +203 -0
  181. package/dist/x402/client.d.ts.map +1 -0
  182. package/dist/x402/client.js +337 -0
  183. package/dist/x402/client.js.map +1 -0
  184. package/dist/x402/hub.d.ts +79 -0
  185. package/dist/x402/hub.d.ts.map +1 -0
  186. package/dist/x402/hub.js +164 -0
  187. package/dist/x402/hub.js.map +1 -0
  188. package/dist/x402/index.d.ts +27 -0
  189. package/dist/x402/index.d.ts.map +1 -0
  190. package/dist/x402/index.js +27 -0
  191. package/dist/x402/index.js.map +1 -0
  192. package/dist/x402/proxy.d.ts +162 -0
  193. package/dist/x402/proxy.d.ts.map +1 -0
  194. package/dist/x402/proxy.js +198 -0
  195. package/dist/x402/proxy.js.map +1 -0
  196. package/dist/x402/server.d.ts +162 -0
  197. package/dist/x402/server.d.ts.map +1 -0
  198. package/dist/x402/server.js +306 -0
  199. package/dist/x402/server.js.map +1 -0
  200. package/dist/x402/wire.d.ts +104 -0
  201. package/dist/x402/wire.d.ts.map +1 -0
  202. package/dist/x402/wire.js +265 -0
  203. package/dist/x402/wire.js.map +1 -0
  204. package/package.json +61 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Keccak-256, written against native `bigint`.
3
+ *
4
+ * `@tabai/shared` carries zero runtime dependencies, and Keccak-256 is not
5
+ * SHA3-256, the two differ in their padding byte, so the platform hash
6
+ * primitives cannot stand in for it. The permutation below is therefore
7
+ * implemented here: 24 rounds of Keccak-f[1600] over 25 64-bit lanes, rate 136
8
+ * bytes, capacity 64 bytes, `0x01` domain padding.
9
+ *
10
+ * Correctness is pinned by published digests in `test/keccak256.test.mjs`: the
11
+ * empty-input digest, the `abc` digest, and the ERC-20 `Transfer` and `Approval`
12
+ * event topics any chain explorer shows. The permutation was additionally
13
+ * cross-checked against the platform SHA3-256, same permutation, same rate,
14
+ * different padding byte, at input lengths spanning the 136-byte block
15
+ * boundary. It is used only to derive a handful of event topic hashes at module
16
+ * load, so the `bigint` lane representation costs nothing that matters.
17
+ */
18
+ const LANE_MASK = (1n << 64n) - 1n;
19
+ /** Rate in bytes for a 256-bit digest: 200 - 2 * 32. */
20
+ const RATE_BYTES = 136;
21
+ /** Lanes of the state absorbed per block: RATE_BYTES / 8. */
22
+ const RATE_LANES = RATE_BYTES / 8;
23
+ /** Iota round constants. */
24
+ const ROUND_CONSTANTS = [
25
+ 0x0000000000000001n,
26
+ 0x0000000000008082n,
27
+ 0x800000000000808an,
28
+ 0x8000000080008000n,
29
+ 0x000000000000808bn,
30
+ 0x0000000080000001n,
31
+ 0x8000000080008081n,
32
+ 0x8000000000008009n,
33
+ 0x000000000000008an,
34
+ 0x0000000000000088n,
35
+ 0x0000000080008009n,
36
+ 0x000000008000000an,
37
+ 0x000000008000808bn,
38
+ 0x800000000000008bn,
39
+ 0x8000000000008089n,
40
+ 0x8000000000008003n,
41
+ 0x8000000000008002n,
42
+ 0x8000000000000080n,
43
+ 0x000000000000800an,
44
+ 0x800000008000000an,
45
+ 0x8000000080008081n,
46
+ 0x8000000000008080n,
47
+ 0x0000000080000001n,
48
+ 0x8000000080008008n,
49
+ ];
50
+ /**
51
+ * Rho rotation offsets, in lane-permutation order: `((t + 1)(t + 2) / 2) mod 64`
52
+ * for step `t`, which is the offset of the lane the walk sits on at that step.
53
+ */
54
+ const ROTATIONS = [
55
+ 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
56
+ ];
57
+ /** Pi lane permutation. */
58
+ const LANE_ORDER = [
59
+ 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
60
+ ];
61
+ const rotl = (lane, bits) => {
62
+ const shift = BigInt(bits);
63
+ return ((lane << shift) | (lane >> (64n - shift))) & LANE_MASK;
64
+ };
65
+ /** Applies Keccak-f[1600] to `state` in place. */
66
+ function permute(state) {
67
+ const column = new Array(5).fill(0n);
68
+ for (let round = 0; round < 24; round += 1) {
69
+ // theta
70
+ for (let x = 0; x < 5; x += 1) {
71
+ column[x] =
72
+ state[x] ^ state[x + 5] ^ state[x + 10] ^ state[x + 15] ^ state[x + 20];
73
+ }
74
+ for (let x = 0; x < 5; x += 1) {
75
+ const parity = column[(x + 4) % 5] ^ rotl(column[(x + 1) % 5], 1);
76
+ for (let y = 0; y < 25; y += 5)
77
+ state[y + x] = state[y + x] ^ parity;
78
+ }
79
+ // rho and pi
80
+ let carried = state[1];
81
+ for (let step = 0; step < 24; step += 1) {
82
+ const target = LANE_ORDER[step];
83
+ const displaced = state[target];
84
+ state[target] = rotl(carried, ROTATIONS[step]);
85
+ carried = displaced;
86
+ }
87
+ // chi
88
+ for (let y = 0; y < 25; y += 5) {
89
+ for (let x = 0; x < 5; x += 1)
90
+ column[x] = state[y + x];
91
+ for (let x = 0; x < 5; x += 1) {
92
+ state[y + x] = state[y + x] ^ ((column[(x + 1) % 5] ^ LANE_MASK) & column[(x + 2) % 5]);
93
+ }
94
+ }
95
+ // iota
96
+ state[0] = state[0] ^ ROUND_CONSTANTS[round];
97
+ }
98
+ }
99
+ /** Hashes raw bytes and renders the digest as a 32-byte word. */
100
+ export function keccak256(data) {
101
+ const state = new Array(25).fill(0n);
102
+ const blocks = Math.ceil((data.length + 1) / RATE_BYTES);
103
+ const padded = new Uint8Array(blocks * RATE_BYTES);
104
+ padded.set(data);
105
+ padded[data.length] = 0x01;
106
+ const finalByte = padded.length - 1;
107
+ padded[finalByte] = padded[finalByte] | 0x80;
108
+ for (let offset = 0; offset < padded.length; offset += RATE_BYTES) {
109
+ for (let lane = 0; lane < RATE_LANES; lane += 1) {
110
+ let word = 0n;
111
+ for (let byte = 7; byte >= 0; byte -= 1) {
112
+ word = (word << 8n) | BigInt(padded[offset + lane * 8 + byte]);
113
+ }
114
+ state[lane] = state[lane] ^ word;
115
+ }
116
+ permute(state);
117
+ }
118
+ let digest = "";
119
+ for (let lane = 0; lane < 4; lane += 1) {
120
+ const word = state[lane];
121
+ for (let byte = 0; byte < 8; byte += 1) {
122
+ digest += ((word >> BigInt(byte * 8)) & 0xffn).toString(16).padStart(2, "0");
123
+ }
124
+ }
125
+ return `0x${digest}`;
126
+ }
127
+ /**
128
+ * Hashes an ASCII string. Event and function signatures are ASCII by
129
+ * construction, so refusing anything above `0x7f` keeps encoding out of the
130
+ * picture entirely.
131
+ *
132
+ * @throws RangeError when `text` carries a non-ASCII code unit.
133
+ */
134
+ export function keccak256Ascii(text) {
135
+ const bytes = new Uint8Array(text.length);
136
+ for (let i = 0; i < text.length; i += 1) {
137
+ const code = text.charCodeAt(i);
138
+ if (code > 0x7f) {
139
+ throw new RangeError(`keccak256Ascii: expected ASCII only, found code unit ${code} at index ${i}`);
140
+ }
141
+ bytes[i] = code;
142
+ }
143
+ return keccak256(bytes);
144
+ }
145
+ //# sourceMappingURL=keccak256.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keccak256.js","sourceRoot":"","sources":["../src/keccak256.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Keccak-256, written against native `bigint`.\n *\n * `@tabai/shared` carries zero runtime dependencies, and Keccak-256 is not\n * SHA3-256, the two differ in their padding byte, so the platform hash\n * primitives cannot stand in for it. The permutation below is therefore\n * implemented here: 24 rounds of Keccak-f[1600] over 25 64-bit lanes, rate 136\n * bytes, capacity 64 bytes, `0x01` domain padding.\n *\n * Correctness is pinned by published digests in `test/keccak256.test.mjs`: the\n * empty-input digest, the `abc` digest, and the ERC-20 `Transfer` and `Approval`\n * event topics any chain explorer shows. The permutation was additionally\n * cross-checked against the platform SHA3-256, same permutation, same rate,\n * different padding byte, at input lengths spanning the 136-byte block\n * boundary. It is used only to derive a handful of event topic hashes at module\n * load, so the `bigint` lane representation costs nothing that matters.\n */\n\nimport type { Bytes32 } from \"./hex.js\";\n\nconst LANE_MASK = (1n << 64n) - 1n;\n\n/** Rate in bytes for a 256-bit digest: 200 - 2 * 32. */\nconst RATE_BYTES = 136;\n\n/** Lanes of the state absorbed per block: RATE_BYTES / 8. */\nconst RATE_LANES = RATE_BYTES / 8;\n\n/** Iota round constants. */\nconst ROUND_CONSTANTS: readonly bigint[] = [\n 0x0000000000000001n,\n 0x0000000000008082n,\n 0x800000000000808an,\n 0x8000000080008000n,\n 0x000000000000808bn,\n 0x0000000080000001n,\n 0x8000000080008081n,\n 0x8000000000008009n,\n 0x000000000000008an,\n 0x0000000000000088n,\n 0x0000000080008009n,\n 0x000000008000000an,\n 0x000000008000808bn,\n 0x800000000000008bn,\n 0x8000000000008089n,\n 0x8000000000008003n,\n 0x8000000000008002n,\n 0x8000000000000080n,\n 0x000000000000800an,\n 0x800000008000000an,\n 0x8000000080008081n,\n 0x8000000000008080n,\n 0x0000000080000001n,\n 0x8000000080008008n,\n];\n\n/**\n * Rho rotation offsets, in lane-permutation order: `((t + 1)(t + 2) / 2) mod 64`\n * for step `t`, which is the offset of the lane the walk sits on at that step.\n */\nconst ROTATIONS: readonly number[] = [\n 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,\n];\n\n/** Pi lane permutation. */\nconst LANE_ORDER: readonly number[] = [\n 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,\n];\n\nconst rotl = (lane: bigint, bits: number): bigint => {\n const shift = BigInt(bits);\n return ((lane << shift) | (lane >> (64n - shift))) & LANE_MASK;\n};\n\n/** Applies Keccak-f[1600] to `state` in place. */\nfunction permute(state: bigint[]): void {\n const column = new Array<bigint>(5).fill(0n);\n\n for (let round = 0; round < 24; round += 1) {\n // theta\n for (let x = 0; x < 5; x += 1) {\n column[x] =\n state[x]! ^ state[x + 5]! ^ state[x + 10]! ^ state[x + 15]! ^ state[x + 20]!;\n }\n for (let x = 0; x < 5; x += 1) {\n const parity = column[(x + 4) % 5]! ^ rotl(column[(x + 1) % 5]!, 1);\n for (let y = 0; y < 25; y += 5) state[y + x] = state[y + x]! ^ parity;\n }\n\n // rho and pi\n let carried = state[1]!;\n for (let step = 0; step < 24; step += 1) {\n const target = LANE_ORDER[step]!;\n const displaced = state[target]!;\n state[target] = rotl(carried, ROTATIONS[step]!);\n carried = displaced;\n }\n\n // chi\n for (let y = 0; y < 25; y += 5) {\n for (let x = 0; x < 5; x += 1) column[x] = state[y + x]!;\n for (let x = 0; x < 5; x += 1) {\n state[y + x] = state[y + x]! ^ ((column[(x + 1) % 5]! ^ LANE_MASK) & column[(x + 2) % 5]!);\n }\n }\n\n // iota\n state[0] = state[0]! ^ ROUND_CONSTANTS[round]!;\n }\n}\n\n/** Hashes raw bytes and renders the digest as a 32-byte word. */\nexport function keccak256(data: Uint8Array): Bytes32 {\n const state = new Array<bigint>(25).fill(0n);\n\n const blocks = Math.ceil((data.length + 1) / RATE_BYTES);\n const padded = new Uint8Array(blocks * RATE_BYTES);\n padded.set(data);\n padded[data.length] = 0x01;\n const finalByte = padded.length - 1;\n padded[finalByte] = padded[finalByte]! | 0x80;\n\n for (let offset = 0; offset < padded.length; offset += RATE_BYTES) {\n for (let lane = 0; lane < RATE_LANES; lane += 1) {\n let word = 0n;\n for (let byte = 7; byte >= 0; byte -= 1) {\n word = (word << 8n) | BigInt(padded[offset + lane * 8 + byte]!);\n }\n state[lane] = state[lane]! ^ word;\n }\n permute(state);\n }\n\n let digest = \"\";\n for (let lane = 0; lane < 4; lane += 1) {\n const word = state[lane]!;\n for (let byte = 0; byte < 8; byte += 1) {\n digest += ((word >> BigInt(byte * 8)) & 0xffn).toString(16).padStart(2, \"0\");\n }\n }\n return `0x${digest}`;\n}\n\n/**\n * Hashes an ASCII string. Event and function signatures are ASCII by\n * construction, so refusing anything above `0x7f` keeps encoding out of the\n * picture entirely.\n *\n * @throws RangeError when `text` carries a non-ASCII code unit.\n */\nexport function keccak256Ascii(text: string): Bytes32 {\n const bytes = new Uint8Array(text.length);\n for (let i = 0; i < text.length; i += 1) {\n const code = text.charCodeAt(i);\n if (code > 0x7f) {\n throw new RangeError(\n `keccak256Ascii: expected ASCII only, found code unit ${code} at index ${i}`,\n );\n }\n bytes[i] = code;\n }\n return keccak256(bytes);\n}\n"]}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The zero-throw result type.
3
+ *
4
+ * No exported SDK function throws. `wrap` is the single boundary at which a
5
+ * thrown value from a dependency becomes a `TabError`, so a caller only ever
6
+ * branches on `result.ok` and never writes a `try` block of its own.
7
+ *
8
+ * HTTP surfaces map `category` to a status code:
9
+ * `VALIDATION` 400, `AUTHORISATION` 403, `NOT_FOUND` 404, `LIMIT` 402,
10
+ * `CONFLICT` 409, `UPSTREAM` 502, `UNAVAILABLE` 503, and
11
+ * `CHAIN`/`INTERNAL` 500.
12
+ *
13
+ * Requirements: 21.5
14
+ */
15
+ export type ErrorCategory =
16
+ /** caller-supplied input is malformed */
17
+ "VALIDATION"
18
+ /** missing, expired, or exceeded spending authorisation */
19
+ | "AUTHORISATION"
20
+ /** unknown service, agent, asset, tab, or settlement */
21
+ | "NOT_FOUND"
22
+ /** credit limit or headroom exhausted */
23
+ | "LIMIT"
24
+ /** A Monad transaction failed or reverted */
25
+ | "CHAIN"
26
+ /** RPC endpoint, module loader, or service endpoint failure */
27
+ | "UPSTREAM"
28
+ /** duplicate registration, timelock still pending */
29
+ | "CONFLICT"
30
+ /** the write path is unavailable */
31
+ | "UNAVAILABLE"
32
+ /** invariant violated inside our own code */
33
+ | "INTERNAL";
34
+ /** The HTTP status every category maps to, so services cannot disagree. */
35
+ export declare const HTTP_STATUS_BY_CATEGORY: Readonly<Record<ErrorCategory, number>>;
36
+ export interface TabError {
37
+ category: ErrorCategory;
38
+ /** stable and machine-readable, for example `LIMIT_EXCEEDED` */
39
+ code: string;
40
+ /** human-readable, carrying no secret and no stack trace */
41
+ message: string;
42
+ retryable: boolean;
43
+ retryAfterMs?: number;
44
+ details?: Record<string, string | number | boolean>;
45
+ cause?: {
46
+ code: string;
47
+ message: string;
48
+ };
49
+ }
50
+ export type Result<T> = {
51
+ ok: true;
52
+ value: T;
53
+ } | {
54
+ ok: false;
55
+ error: TabError;
56
+ };
57
+ export declare const ok: <T>(value: T) => Result<T>;
58
+ export declare const err: (error: TabError) => Result<never>;
59
+ /**
60
+ * Runs `fn` and converts a thrown value into a `TabError` through `map`.
61
+ * This is the only place in the workspace where a `catch` belongs.
62
+ */
63
+ export declare const wrap: <T>(fn: () => Promise<T>, map: (e: unknown) => TabError) => Promise<Result<T>>;
64
+ /** The synchronous sibling of `wrap`, for pure computations that validate their input. */
65
+ export declare const wrapSync: <T>(fn: () => T, map: (e: unknown) => TabError) => Result<T>;
66
+ /** Narrows an unknown thrown value into the `cause` shape a `TabError` accepts. */
67
+ export declare const causeOf: (e: unknown) => {
68
+ code: string;
69
+ message: string;
70
+ };
71
+ /** True when the result carries a value. Present so callers can filter without a cast. */
72
+ export declare const isOk: <T>(result: Result<T>) => result is {
73
+ ok: true;
74
+ value: T;
75
+ };
76
+ /** Returns the HTTP status a failed result maps to. */
77
+ export declare const httpStatusOf: (error: TabError) => number;
78
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,aAAa;AACvB,yCAAyC;AACvC,YAAY;AACd,2DAA2D;GACzD,eAAe;AACjB,wDAAwD;GACtD,WAAW;AACb,yCAAyC;GACvC,OAAO;AACT,6CAA6C;GAC3C,OAAO;AACT,+DAA+D;GAC7D,UAAU;AACZ,qDAAqD;GACnD,UAAU;AACZ,oCAAoC;GAClC,aAAa;AACf,6CAA6C;GAC3C,UAAU,CAAC;AAEf,2EAA2E;AAC3E,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa,EAAE,MAAM,CAAC,CAU3E,CAAC;AAEF,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,aAAa,CAAC;IACxB,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACpD,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEhF,eAAO,MAAM,EAAE,GAAI,CAAC,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,CAAC,CAA0B,CAAC;AAEpE,eAAO,MAAM,GAAG,GAAI,OAAO,QAAQ,KAAG,MAAM,CAAC,KAAK,CAA2B,CAAC;AAE9E;;;GAGG;AACH,eAAO,MAAM,IAAI,GAAU,CAAC,EAC1B,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,KAAK,CAAC,CAAC,EAAE,OAAO,KAAK,QAAQ,KAC5B,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAMnB,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,IAAI,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,OAAO,KAAK,QAAQ,KAAG,MAAM,CAAC,CAAC,CAMhF,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,OAAO,GAAI,GAAG,OAAO,KAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAKnE,CAAC;AAEF,0FAA0F;AAC1F,eAAO,MAAM,IAAI,GAAI,CAAC,EAAE,QAAQ,MAAM,CAAC,CAAC,CAAC,KAAG,MAAM,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAe,CAAC;AAE1F,uDAAuD;AACvD,eAAO,MAAM,YAAY,GAAI,OAAO,QAAQ,KAAG,MAAiD,CAAC"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The zero-throw result type.
3
+ *
4
+ * No exported SDK function throws. `wrap` is the single boundary at which a
5
+ * thrown value from a dependency becomes a `TabError`, so a caller only ever
6
+ * branches on `result.ok` and never writes a `try` block of its own.
7
+ *
8
+ * HTTP surfaces map `category` to a status code:
9
+ * `VALIDATION` 400, `AUTHORISATION` 403, `NOT_FOUND` 404, `LIMIT` 402,
10
+ * `CONFLICT` 409, `UPSTREAM` 502, `UNAVAILABLE` 503, and
11
+ * `CHAIN`/`INTERNAL` 500.
12
+ *
13
+ * Requirements: 21.5
14
+ */
15
+ /** The HTTP status every category maps to, so services cannot disagree. */
16
+ export const HTTP_STATUS_BY_CATEGORY = {
17
+ VALIDATION: 400,
18
+ AUTHORISATION: 403,
19
+ NOT_FOUND: 404,
20
+ LIMIT: 402,
21
+ CHAIN: 500,
22
+ UPSTREAM: 502,
23
+ CONFLICT: 409,
24
+ UNAVAILABLE: 503,
25
+ INTERNAL: 500,
26
+ };
27
+ export const ok = (value) => ({ ok: true, value });
28
+ export const err = (error) => ({ ok: false, error });
29
+ /**
30
+ * Runs `fn` and converts a thrown value into a `TabError` through `map`.
31
+ * This is the only place in the workspace where a `catch` belongs.
32
+ */
33
+ export const wrap = async (fn, map) => {
34
+ try {
35
+ return ok(await fn());
36
+ }
37
+ catch (e) {
38
+ return err(map(e));
39
+ }
40
+ };
41
+ /** The synchronous sibling of `wrap`, for pure computations that validate their input. */
42
+ export const wrapSync = (fn, map) => {
43
+ try {
44
+ return ok(fn());
45
+ }
46
+ catch (e) {
47
+ return err(map(e));
48
+ }
49
+ };
50
+ /** Narrows an unknown thrown value into the `cause` shape a `TabError` accepts. */
51
+ export const causeOf = (e) => {
52
+ if (e instanceof Error) {
53
+ return { code: e.name, message: e.message };
54
+ }
55
+ return { code: "UNKNOWN", message: String(e) };
56
+ };
57
+ /** True when the result carries a value. Present so callers can filter without a cast. */
58
+ export const isOk = (result) => result.ok;
59
+ /** Returns the HTTP status a failed result maps to. */
60
+ export const httpStatusOf = (error) => HTTP_STATUS_BY_CATEGORY[error.category];
61
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAsBH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,uBAAuB,GAA4C;IAC9E,UAAU,EAAE,GAAG;IACf,aAAa,EAAE,GAAG;IAClB,SAAS,EAAE,GAAG;IACd,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,GAAG;IACV,QAAQ,EAAE,GAAG;IACb,QAAQ,EAAE,GAAG;IACb,WAAW,EAAE,GAAG;IAChB,QAAQ,EAAE,GAAG;CACd,CAAC;AAgBF,MAAM,CAAC,MAAM,EAAE,GAAG,CAAI,KAAQ,EAAa,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAEpE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,KAAe,EAAiB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,KAAK,EACvB,EAAoB,EACpB,GAA6B,EACT,EAAE;IACtB,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;AACH,CAAC,CAAC;AAEF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAI,EAAW,EAAE,GAA6B,EAAa,EAAE;IACnF,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;AACH,CAAC,CAAC;AAEF,mFAAmF;AACnF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAU,EAAqC,EAAE;IACvE,IAAI,CAAC,YAAY,KAAK,EAAE,CAAC;QACvB,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;IAC9C,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;AACjD,CAAC,CAAC;AAEF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,IAAI,GAAG,CAAI,MAAiB,EAAoC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC;AAE1F,uDAAuD;AACvD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,KAAe,EAAU,EAAE,CAAC,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC","sourcesContent":["/**\n * The zero-throw result type.\n *\n * No exported SDK function throws. `wrap` is the single boundary at which a\n * thrown value from a dependency becomes a `TabError`, so a caller only ever\n * branches on `result.ok` and never writes a `try` block of its own.\n *\n * HTTP surfaces map `category` to a status code:\n * `VALIDATION` 400, `AUTHORISATION` 403, `NOT_FOUND` 404, `LIMIT` 402,\n * `CONFLICT` 409, `UPSTREAM` 502, `UNAVAILABLE` 503, and\n * `CHAIN`/`INTERNAL` 500.\n *\n * Requirements: 21.5\n */\n\nexport type ErrorCategory =\n /** caller-supplied input is malformed */\n | \"VALIDATION\"\n /** missing, expired, or exceeded spending authorisation */\n | \"AUTHORISATION\"\n /** unknown service, agent, asset, tab, or settlement */\n | \"NOT_FOUND\"\n /** credit limit or headroom exhausted */\n | \"LIMIT\"\n /** A Monad transaction failed or reverted */\n | \"CHAIN\"\n /** RPC endpoint, module loader, or service endpoint failure */\n | \"UPSTREAM\"\n /** duplicate registration, timelock still pending */\n | \"CONFLICT\"\n /** the write path is unavailable */\n | \"UNAVAILABLE\"\n /** invariant violated inside our own code */\n | \"INTERNAL\";\n\n/** The HTTP status every category maps to, so services cannot disagree. */\nexport const HTTP_STATUS_BY_CATEGORY: Readonly<Record<ErrorCategory, number>> = {\n VALIDATION: 400,\n AUTHORISATION: 403,\n NOT_FOUND: 404,\n LIMIT: 402,\n CHAIN: 500,\n UPSTREAM: 502,\n CONFLICT: 409,\n UNAVAILABLE: 503,\n INTERNAL: 500,\n};\n\nexport interface TabError {\n category: ErrorCategory;\n /** stable and machine-readable, for example `LIMIT_EXCEEDED` */\n code: string;\n /** human-readable, carrying no secret and no stack trace */\n message: string;\n retryable: boolean;\n retryAfterMs?: number;\n details?: Record<string, string | number | boolean>;\n cause?: { code: string; message: string };\n}\n\nexport type Result<T> = { ok: true; value: T } | { ok: false; error: TabError };\n\nexport const ok = <T>(value: T): Result<T> => ({ ok: true, value });\n\nexport const err = (error: TabError): Result<never> => ({ ok: false, error });\n\n/**\n * Runs `fn` and converts a thrown value into a `TabError` through `map`.\n * This is the only place in the workspace where a `catch` belongs.\n */\nexport const wrap = async <T>(\n fn: () => Promise<T>,\n map: (e: unknown) => TabError,\n): Promise<Result<T>> => {\n try {\n return ok(await fn());\n } catch (e) {\n return err(map(e));\n }\n};\n\n/** The synchronous sibling of `wrap`, for pure computations that validate their input. */\nexport const wrapSync = <T>(fn: () => T, map: (e: unknown) => TabError): Result<T> => {\n try {\n return ok(fn());\n } catch (e) {\n return err(map(e));\n }\n};\n\n/** Narrows an unknown thrown value into the `cause` shape a `TabError` accepts. */\nexport const causeOf = (e: unknown): { code: string; message: string } => {\n if (e instanceof Error) {\n return { code: e.name, message: e.message };\n }\n return { code: \"UNKNOWN\", message: String(e) };\n};\n\n/** True when the result carries a value. Present so callers can filter without a cast. */\nexport const isOk = <T>(result: Result<T>): result is { ok: true; value: T } => result.ok;\n\n/** Returns the HTTP status a failed result maps to. */\nexport const httpStatusOf = (error: TabError): number => HTTP_STATUS_BY_CATEGORY[error.category];\n"]}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Where an MCP client keeps its server list, and how `tab connect` edits it.
3
+ *
4
+ * ## The claim this file has to earn
5
+ *
6
+ * Adopting Tab costs one line of configuration. That line is a `mcpServers`
7
+ * stanza in a file the client already owns, and `tab connect` writes it. The
8
+ * claim is only worth making if the write is safe to run, so three properties
9
+ * are enforced here rather than documented:
10
+ *
11
+ * - **Idempotent.** Running it twice writes once. The second run compares the
12
+ * merged document against what is on disk and, finding no change, writes
13
+ * nothing and takes no backup. A connect command that rewrote the file every
14
+ * time would churn a file the client also writes.
15
+ * - **Backed up.** Any run that does change the file copies the previous
16
+ * contents beside it first, named with the instant. This is somebody's editor
17
+ * configuration, and it may hold servers this package has never heard of.
18
+ * - **Never a key.** {@link assertNoSecret} walks the stanza before it is
19
+ * written and refuses on anything key-shaped. The settlement signing key is
20
+ * read from the environment at the moment a Settlement is signed. It does not
21
+ * belong in a JSON file that a desktop client rewrites, syncs, and quotes in
22
+ * its own logs.
23
+ *
24
+ * ## Only `mcpServers.tab` is touched
25
+ *
26
+ * The merge is by key, and every other server in the document is carried through
27
+ * untouched, as is every top-level key the client keeps beside `mcpServers`. A
28
+ * file that fails to parse is not overwritten: it is reported, because a
29
+ * half-written config file is a client that will not start and the caller is the
30
+ * only one who knows what was in it.
31
+ *
32
+ * Requirements: 25.5, 25.6
33
+ */
34
+ import type { Result } from "../_shared/index.js";
35
+ import { type JsonRecord } from "../mcp/json.js";
36
+ /** One MCP client this command knows how to find. */
37
+ export interface McpClientTarget {
38
+ /** The `--client` value, for example `claude-desktop`. */
39
+ readonly id: string;
40
+ /** What to call it in a message a person reads. */
41
+ readonly label: string;
42
+ /** Absolute path to its server list on this platform, or undefined where it has none. */
43
+ readonly configPath: string | undefined;
44
+ /** True when the file exists. A known client with no file yet is still a valid target. */
45
+ readonly present: boolean;
46
+ /**
47
+ * True when the directory the file would live in exists, which is the signal
48
+ * that the client is installed even though it has never been configured.
49
+ */
50
+ readonly installed: boolean;
51
+ }
52
+ /** Every client `connect` can target, in the order detection prefers them. */
53
+ export declare const MCP_CLIENT_IDS: readonly ["claude-code", "claude-desktop", "cursor", "windsurf", "vscode"];
54
+ export interface DetectOptions {
55
+ readonly os?: string;
56
+ readonly env?: NodeJS.ProcessEnv;
57
+ readonly cwd?: string;
58
+ }
59
+ /** Every known client on this platform, whether or not it is installed. */
60
+ export declare function detectMcpClients(options?: DetectOptions): readonly McpClientTarget[];
61
+ /**
62
+ * The client to write to when the caller named none.
63
+ *
64
+ * A client with an existing config file wins over one that is merely installed,
65
+ * because an existing file is evidence somebody uses it. Detection never picks
66
+ * between two files silently: with more than one candidate present, the caller
67
+ * is asked to name one.
68
+ */
69
+ export declare function chooseMcpClient(targets: readonly McpClientTarget[]): Result<McpClientTarget>;
70
+ /** The `env` block the stanza carries. Non-secret values only, by construction. */
71
+ export type StanzaEnv = Readonly<Record<string, string>>;
72
+ export interface TabStanza {
73
+ readonly command: string;
74
+ readonly args: readonly string[];
75
+ readonly env?: StanzaEnv;
76
+ }
77
+ /** The key the stanza is written under. One server, one name, always this one. */
78
+ export declare const TAB_SERVER_KEY = "tab";
79
+ /**
80
+ * Builds the stanza.
81
+ *
82
+ * `npx -y @tabai/sdk mcp` rather than a path: the client launches it, `npx`
83
+ * resolves the published package, and nothing has to be installed first. That is
84
+ * the one line the adoption claim rests on.
85
+ *
86
+ * The `env` block carries only what the server reads and a person could publish:
87
+ * an RPC endpoint, a chain id and a read API URL. The names are the ones in the
88
+ * tracked environment contract, `MONAD_RPC_URL`, `MONAD_CHAIN_ID` and
89
+ * `NEXT_PUBLIC_REGISTRY_API_URL`, so a stanza and a `.env` agree.
90
+ */
91
+ export declare function buildTabStanza(env?: StanzaEnv): TabStanza;
92
+ /**
93
+ * Refuses a stanza that carries a secret.
94
+ *
95
+ * Both a name check and a shape check, because either alone is defeated by the
96
+ * obvious mistake: a key under an innocuous name has the shape, and an empty
97
+ * placeholder under `PRIVATE_KEY` has the name. This runs on the merged document
98
+ * before it is written, so it also catches a secret that was already in the file
99
+ * under the `tab` key from an earlier hand edit.
100
+ */
101
+ export declare function assertNoSecret(stanza: unknown, where?: string): Result<void>;
102
+ export interface MergeOutcome {
103
+ /** The document as it should be on disk. */
104
+ readonly merged: JsonRecord;
105
+ /** The document that was on disk, or an empty object when the file did not exist. */
106
+ readonly previous: JsonRecord;
107
+ /** False when the file already said exactly this, which is the idempotent case. */
108
+ readonly changed: boolean;
109
+ /** Whether a `tab` stanza was already there, so a message can say added or updated. */
110
+ readonly hadStanza: boolean;
111
+ }
112
+ /** Two-space JSON with a trailing newline, which is what every one of these files uses. */
113
+ export declare const renderConfig: (document: unknown) => string;
114
+ /**
115
+ * Merges the stanza into a document, leaving every other key alone.
116
+ *
117
+ * `changed` compares rendered text rather than object identity, so a run that
118
+ * produces the same file is reported as no change even when the objects differ
119
+ * by key order.
120
+ */
121
+ export declare function mergeTabStanza(previous: JsonRecord, stanza: TabStanza): Result<MergeOutcome>;
122
+ export interface ReadConfigOutcome {
123
+ readonly document: JsonRecord;
124
+ readonly existed: boolean;
125
+ readonly raw: string;
126
+ }
127
+ /**
128
+ * Reads a client config.
129
+ *
130
+ * A file that does not exist is an empty document and not an error: connecting a
131
+ * client that has never been configured is the common case. A file that exists
132
+ * and does not parse *is* an error, and nothing is written over it.
133
+ */
134
+ export declare function readClientConfig(path: string): Result<ReadConfigOutcome>;
135
+ /** Where a backup of `path` goes, named with the instant so two runs never collide. */
136
+ export declare const backupPathFor: (path: string, at: Date) => string;
137
+ export interface WriteOutcome {
138
+ readonly path: string;
139
+ /** Absent when nothing was written, which is the idempotent case. */
140
+ readonly backupPath?: string;
141
+ readonly wrote: boolean;
142
+ }
143
+ /** Writes the merged document, taking a backup first when a file was already there. */
144
+ export declare function writeClientConfig(path: string, outcome: MergeOutcome, existed: boolean, at: Date): Result<WriteOutcome>;
145
+ /**
146
+ * A unified diff of two JSON documents, line by line.
147
+ *
148
+ * Written here rather than pulled in because it is a longest-common-subsequence
149
+ * over at most a few hundred lines and the alternative is a dependency for a
150
+ * command that prints one. `connect` shows this before it claims to have done
151
+ * anything, because a command that edits a file the user did not open owes them
152
+ * a look at what it changed.
153
+ */
154
+ export declare function unifiedDiff(before: string, after: string, context?: number): string;
155
+ //# sourceMappingURL=client-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-config.d.ts","sourceRoot":"","sources":["../../src/cli/client-config.ts"],"names":[],"mappings":"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"}