tapimo 0.0.2 → 0.1.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 (265) hide show
  1. package/README.md +11 -2
  2. package/dist/ApiKey.d.ts +12 -11
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +10 -12
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +139 -0
  7. package/dist/ApiKeys.d.ts.map +1 -0
  8. package/dist/ApiKeys.js +166 -0
  9. package/dist/ApiKeys.js.map +1 -0
  10. package/dist/App.d.ts +920 -910
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +36 -12
  13. package/dist/App.js.map +1 -1
  14. package/dist/Handler.d.ts +86 -0
  15. package/dist/Handler.d.ts.map +1 -0
  16. package/dist/Handler.js +83 -0
  17. package/dist/Handler.js.map +1 -0
  18. package/dist/Scope.d.ts +4 -1
  19. package/dist/Scope.d.ts.map +1 -1
  20. package/dist/Scope.js +5 -1
  21. package/dist/Scope.js.map +1 -1
  22. package/dist/Webhooks.d.ts +3 -5
  23. package/dist/Webhooks.d.ts.map +1 -1
  24. package/dist/Webhooks.js +9 -2
  25. package/dist/Webhooks.js.map +1 -1
  26. package/dist/admin/Access.d.ts +1 -3
  27. package/dist/admin/Access.d.ts.map +1 -1
  28. package/dist/admin/Access.js +1 -3
  29. package/dist/admin/Access.js.map +1 -1
  30. package/dist/admin/App.d.ts +98 -209
  31. package/dist/admin/App.d.ts.map +1 -1
  32. package/dist/admin/App.js +2 -4
  33. package/dist/admin/App.js.map +1 -1
  34. package/dist/admin/apps/api-keys.d.ts +7 -5
  35. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  36. package/dist/admin/apps/api-keys.js +8 -9
  37. package/dist/admin/apps/api-keys.js.map +1 -1
  38. package/dist/admin/apps/scopes.d.ts +3 -0
  39. package/dist/admin/apps/scopes.d.ts.map +1 -1
  40. package/dist/admin/apps/verified-tokens.d.ts +101 -215
  41. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  42. package/dist/admin/apps/verified-tokens.js +17 -38
  43. package/dist/admin/apps/verified-tokens.js.map +1 -1
  44. package/dist/admin/ui.generated.d.ts +1 -1
  45. package/dist/admin/ui.generated.js +1 -1
  46. package/dist/apps/balances.d.ts +2 -2
  47. package/dist/apps/receipts.d.ts +43 -43
  48. package/dist/apps/tokens.d.ts +454 -454
  49. package/dist/apps/transactions.d.ts +43 -43
  50. package/dist/apps/transfers.d.ts +29 -29
  51. package/dist/apps/webhooks.d.ts +5 -2
  52. package/dist/apps/webhooks.d.ts.map +1 -1
  53. package/dist/apps/webhooks.js +38 -34
  54. package/dist/apps/webhooks.js.map +1 -1
  55. package/dist/{Cli.d.ts → cli/Cli.d.ts} +13 -2
  56. package/dist/cli/Cli.d.ts.map +1 -0
  57. package/dist/cli/Cli.js +19 -0
  58. package/dist/cli/Cli.js.map +1 -0
  59. package/dist/cli/bin.d.ts +3 -0
  60. package/dist/cli/bin.d.ts.map +1 -0
  61. package/dist/cli/bin.js +4 -0
  62. package/dist/cli/bin.js.map +1 -0
  63. package/dist/cli/commands/admin.d.ts +15 -0
  64. package/dist/cli/commands/admin.d.ts.map +1 -0
  65. package/dist/cli/commands/admin.js +60 -0
  66. package/dist/cli/commands/admin.js.map +1 -0
  67. package/dist/cloudflare.d.ts +7 -0
  68. package/dist/cloudflare.d.ts.map +1 -1
  69. package/dist/cloudflare.js +9 -0
  70. package/dist/cloudflare.js.map +1 -1
  71. package/dist/db/Db.d.ts +103 -0
  72. package/dist/db/Db.d.ts.map +1 -0
  73. package/dist/db/Db.js +274 -0
  74. package/dist/db/Db.js.map +1 -0
  75. package/dist/db/Schema.d.ts +88 -0
  76. package/dist/db/Schema.d.ts.map +1 -0
  77. package/dist/db/Schema.js +130 -0
  78. package/dist/db/Schema.js.map +1 -0
  79. package/dist/db/tables/organizations.d.ts +79 -0
  80. package/dist/db/tables/organizations.d.ts.map +1 -0
  81. package/dist/db/tables/organizations.js +81 -0
  82. package/dist/db/tables/organizations.js.map +1 -0
  83. package/dist/db/tables/verifiedTokens.d.ts +53 -0
  84. package/dist/db/tables/verifiedTokens.d.ts.map +1 -0
  85. package/dist/db/tables/verifiedTokens.js +74 -0
  86. package/dist/db/tables/verifiedTokens.js.map +1 -0
  87. package/dist/db/tables/webhookDeliveries.d.ts +71 -0
  88. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -0
  89. package/dist/db/tables/webhookDeliveries.js +119 -0
  90. package/dist/db/tables/webhookDeliveries.js.map +1 -0
  91. package/dist/db/tables/webhookSubscriptions.d.ts +158 -0
  92. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -0
  93. package/dist/db/tables/webhookSubscriptions.js +272 -0
  94. package/dist/db/tables/webhookSubscriptions.js.map +1 -0
  95. package/dist/handlers/internal/executionError.d.ts +25 -0
  96. package/dist/handlers/internal/executionError.d.ts.map +1 -0
  97. package/dist/handlers/internal/executionError.js +184 -0
  98. package/dist/handlers/internal/executionError.js.map +1 -0
  99. package/dist/handlers/internal/multisig.d.ts +237 -0
  100. package/dist/handlers/internal/multisig.d.ts.map +1 -0
  101. package/dist/handlers/internal/multisig.js +567 -0
  102. package/dist/handlers/internal/multisig.js.map +1 -0
  103. package/dist/handlers/internal/requestListener.d.ts +124 -0
  104. package/dist/handlers/internal/requestListener.d.ts.map +1 -0
  105. package/dist/handlers/internal/requestListener.js +173 -0
  106. package/dist/handlers/internal/requestListener.js.map +1 -0
  107. package/dist/handlers/internal/sponsorship.d.ts +83 -0
  108. package/dist/handlers/internal/sponsorship.d.ts.map +1 -0
  109. package/dist/handlers/internal/sponsorship.js +103 -0
  110. package/dist/handlers/internal/sponsorship.js.map +1 -0
  111. package/dist/handlers/internal/types.d.ts +284 -0
  112. package/dist/handlers/internal/types.d.ts.map +1 -0
  113. package/dist/handlers/internal/types.js +2 -0
  114. package/dist/handlers/internal/types.js.map +1 -0
  115. package/dist/handlers/internal/utils.d.ts +34 -0
  116. package/dist/handlers/internal/utils.d.ts.map +1 -0
  117. package/dist/handlers/internal/utils.js +131 -0
  118. package/dist/handlers/internal/utils.js.map +1 -0
  119. package/dist/handlers/relay.d.ts +119 -0
  120. package/dist/handlers/relay.d.ts.map +1 -0
  121. package/dist/handlers/relay.js +1264 -0
  122. package/dist/handlers/relay.js.map +1 -0
  123. package/dist/index.d.ts +4 -2
  124. package/dist/index.d.ts.map +1 -1
  125. package/dist/index.js +4 -2
  126. package/dist/index.js.map +1 -1
  127. package/dist/internal/Auth.d.ts +16 -10
  128. package/dist/internal/Auth.d.ts.map +1 -1
  129. package/dist/internal/Auth.js +72 -12
  130. package/dist/internal/Auth.js.map +1 -1
  131. package/dist/internal/RpcSchema.d.ts +10 -0
  132. package/dist/internal/RpcSchema.d.ts.map +1 -0
  133. package/dist/internal/RpcSchema.js +2 -0
  134. package/dist/internal/RpcSchema.js.map +1 -0
  135. package/dist/internal/Store.d.ts +42 -3
  136. package/dist/internal/Store.d.ts.map +1 -1
  137. package/dist/internal/Store.js +65 -3
  138. package/dist/internal/Store.js.map +1 -1
  139. package/dist/internal/VerifiedTokens.d.ts +15 -34
  140. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  141. package/dist/internal/VerifiedTokens.js +115 -159
  142. package/dist/internal/VerifiedTokens.js.map +1 -1
  143. package/dist/internal/Webhooks.d.ts +49 -35
  144. package/dist/internal/Webhooks.d.ts.map +1 -1
  145. package/dist/internal/Webhooks.js +92 -205
  146. package/dist/internal/Webhooks.js.map +1 -1
  147. package/package.json +7 -2
  148. package/src/ApiKey.test.ts +3 -3
  149. package/src/ApiKey.ts +10 -12
  150. package/src/ApiKeys.test.ts +175 -0
  151. package/src/ApiKeys.ts +205 -0
  152. package/src/App.test-d.ts +1 -1
  153. package/src/App.test.ts +10768 -351
  154. package/src/App.ts +79 -36
  155. package/src/Client.test-d.ts +1 -1
  156. package/src/Handler.ts +154 -0
  157. package/src/Scope.ts +5 -1
  158. package/src/Webhooks.test.ts +8 -7
  159. package/src/Webhooks.ts +11 -5
  160. package/src/admin/Access.ts +1 -3
  161. package/src/admin/App.ts +19 -24
  162. package/src/admin/apps/api-keys.test.ts +19 -18
  163. package/src/admin/apps/api-keys.ts +8 -9
  164. package/src/admin/apps/scopes.test.ts +4 -0
  165. package/src/admin/apps/verified-tokens.test.ts +3 -30
  166. package/src/admin/apps/verified-tokens.ts +17 -36
  167. package/src/admin/ui.generated.ts +1 -1
  168. package/src/apps/balances.test.ts +4 -3
  169. package/src/apps/blocks.test.ts +1 -1
  170. package/src/apps/exchanges.test.ts +1 -1
  171. package/src/apps/indexer.test.ts +1 -1
  172. package/src/apps/receipts.test.ts +1 -1
  173. package/src/apps/rpc.test.ts +100 -10
  174. package/src/apps/tokenlist.test.ts +5 -7
  175. package/src/apps/tokens.test.ts +4 -3
  176. package/src/apps/transactions.test.ts +1 -1
  177. package/src/apps/transfers.test.ts +1 -1
  178. package/src/apps/verified-tokens.test.ts +24 -12
  179. package/src/apps/webhooks.test.ts +130 -143
  180. package/src/apps/webhooks.ts +45 -47
  181. package/src/{Cli.test.ts → cli/Cli.test.ts} +10 -9
  182. package/src/{Cli.ts → cli/Cli.ts} +16 -9
  183. package/src/cli/bin.ts +4 -0
  184. package/src/cli/commands/admin.test.ts +71 -0
  185. package/src/cli/commands/admin.ts +60 -0
  186. package/src/cloudflare.ts +10 -0
  187. package/src/db/Db.test.ts +84 -0
  188. package/src/db/Db.ts +383 -0
  189. package/src/db/Schema.ts +164 -0
  190. package/src/db/tables/organizations.test.ts +124 -0
  191. package/src/db/tables/organizations.ts +127 -0
  192. package/src/db/tables/verifiedTokens.ts +111 -0
  193. package/src/db/tables/webhookDeliveries.ts +159 -0
  194. package/src/db/tables/webhookSubscriptions.ts +358 -0
  195. package/src/handlers/internal/executionError.ts +205 -0
  196. package/src/handlers/internal/multisig.localnet.test.ts +146 -0
  197. package/src/handlers/internal/multisig.test.ts +744 -0
  198. package/src/handlers/internal/multisig.ts +858 -0
  199. package/src/handlers/internal/relay.localnet.test.ts +2035 -0
  200. package/src/handlers/internal/requestListener.ts +273 -0
  201. package/src/handlers/internal/sponsorship.ts +186 -0
  202. package/src/handlers/internal/types.ts +378 -0
  203. package/src/handlers/internal/utils.ts +153 -0
  204. package/src/handlers/relay.ts +1605 -0
  205. package/src/index.ts +4 -2
  206. package/src/internal/Auth.test.ts +21 -21
  207. package/src/internal/Auth.ts +92 -19
  208. package/src/internal/RateLimit.test.ts +1 -1
  209. package/src/internal/RpcSchema.ts +10 -0
  210. package/src/internal/Store.test.ts +98 -10
  211. package/src/internal/Store.ts +112 -6
  212. package/src/internal/VerifiedTokens.test.ts +99 -115
  213. package/src/internal/VerifiedTokens.ts +123 -175
  214. package/src/internal/Webhooks.test.ts +107 -107
  215. package/src/internal/Webhooks.ts +102 -220
  216. package/dist/ApiKeySource.d.ts +0 -166
  217. package/dist/ApiKeySource.d.ts.map +0 -1
  218. package/dist/ApiKeySource.js +0 -234
  219. package/dist/ApiKeySource.js.map +0 -1
  220. package/dist/Cli.d.ts.map +0 -1
  221. package/dist/Cli.js +0 -13
  222. package/dist/Cli.js.map +0 -1
  223. package/seeds/31318/icons/0x20c0000000000000000000000000000000000000.svg +0 -1
  224. package/seeds/31318/icons/0x20c0000000000000000000000000000000000001.svg +0 -1
  225. package/seeds/31318/icons/0x20c0000000000000000000000000000000000002.svg +0 -1
  226. package/seeds/31318/icons/0x20c0000000000000000000000000000000000003.svg +0 -1
  227. package/seeds/31318/verified-tokens.json +0 -30
  228. package/seeds/4217/icons/0x20c0000000000000000000000000000000000000.svg +0 -25
  229. package/seeds/4217/icons/0x20c000000000000000000000048c8f36df1c9a4a.svg +0 -1
  230. package/seeds/4217/icons/0x20c0000000000000000000000520792dcccccccc.svg +0 -1
  231. package/seeds/4217/icons/0x20c0000000000000000000000a6da882d075a4c3.svg +0 -4
  232. package/seeds/4217/icons/0x20c000000000000000000000111111111e910f0f.svg +0 -30
  233. package/seeds/4217/icons/0x20c00000000000000000000014f22ca97301eb73.svg +0 -1
  234. package/seeds/4217/icons/0x20c0000000000000000000001621e21f71cf12fb.svg +0 -1
  235. package/seeds/4217/icons/0x20c0000000000000000000002f52d5cc21a3207b.svg +0 -1
  236. package/seeds/4217/icons/0x20c0000000000000000000003158081efd85bfc2.svg +0 -11
  237. package/seeds/4217/icons/0x20c0000000000000000000003554d28269e0f3c2.svg +0 -1
  238. package/seeds/4217/icons/0x20c000000000000000000000383a23bacb546ab9.svg +0 -1
  239. package/seeds/4217/icons/0x20c00000000000000000000042109aef2f8b28e1.png +0 -0
  240. package/seeds/4217/icons/0x20c0000000000000000000005c0bac7cef389a11.svg +0 -1
  241. package/seeds/4217/icons/0x20c0000000000000000000006fd9a167923ba194.png +0 -0
  242. package/seeds/4217/icons/0x20c0000000000000000000007f7ba549dd0251b9.svg +0 -1
  243. package/seeds/4217/icons/0x20c0000000000000000000008191667423f70e67.svg +0 -5
  244. package/seeds/4217/icons/0x20c0000000000000000000008ee4fcff88888888.svg +0 -1
  245. package/seeds/4217/icons/0x20c0000000000000000000009a4a4b17e0dc6651.svg +0 -1
  246. package/seeds/4217/icons/0x20c000000000000000000000ab02d39df30bd17e.svg +0 -1
  247. package/seeds/4217/icons/0x20c000000000000000000000ae247a1130450f09.svg +0 -1
  248. package/seeds/4217/icons/0x20c000000000000000000000aeed2ec36a54d0e5.svg +0 -1
  249. package/seeds/4217/icons/0x20c000000000000000000000b9537d11c60e8b50.svg +0 -1
  250. package/seeds/4217/icons/0x20c000000000000000000000bd95bfb69fbe6ce3.svg +0 -1
  251. package/seeds/4217/icons/0x20c000000000000000000000c412ec89d0c08be5.svg +0 -1
  252. package/seeds/4217/icons/0x20c000000000000000000000f047dd7018e50367.png +0 -0
  253. package/seeds/4217/verified-tokens.json +0 -177
  254. package/seeds/42431/icons/0x20c0000000000000000000000000000000000000.svg +0 -25
  255. package/seeds/42431/icons/0x20c0000000000000000000000000000000000001.svg +0 -1
  256. package/seeds/42431/icons/0x20c0000000000000000000000000000000000002.svg +0 -1
  257. package/seeds/42431/icons/0x20c0000000000000000000000000000000000003.svg +0 -1
  258. package/seeds/42431/icons/0x20c0000000000000000000009e8d7eb59b783726.svg +0 -1
  259. package/seeds/42431/icons/0x20c000000000000000000000d72572838bbee59c.svg +0 -1
  260. package/seeds/42431/verified-tokens.json +0 -44
  261. package/seeds/openrpc/README.md +0 -27
  262. package/seeds/openrpc/execution-apis.json +0 -8989
  263. package/src/ApiKeySource.test-d.ts +0 -11
  264. package/src/ApiKeySource.test.ts +0 -295
  265. package/src/ApiKeySource.ts +0 -303
package/README.md CHANGED
@@ -33,15 +33,24 @@ Install the package:
33
33
  pnpm i tapimo
34
34
  ```
35
35
 
36
+ Stateful features (webhook subscriptions, verified tokens) live in Postgres.
37
+ Provision a database and apply migrations with the CLI:
38
+
39
+ ```sh
40
+ DATABASE_URL=postgresql://… tapimo admin migrate
41
+ ```
42
+
36
43
  Compose an app with `App.create`. It returns a handler with a Web `fetch`
37
44
  method and a Node.js `listener`, so you can serve it from any runtime or
38
45
  framework:
39
46
 
40
47
  <!-- prettier-ignore -->
41
48
  ```ts
42
- import { App } from 'tapimo'
49
+ import { App, Db } from 'tapimo'
43
50
 
44
- const handler = App.create()
51
+ const handler = App.create({
52
+ db: Db.postgres({ connectionString: process.env.DATABASE_URL }),
53
+ })
45
54
 
46
55
  createServer(handler.listener) // Node.js
47
56
  Bun.serve({ fetch: handler.fetch }) // Bun
package/dist/ApiKey.d.ts CHANGED
@@ -1,23 +1,21 @@
1
1
  /**
2
- * The resolved API-key resource and the reusable credential primitives every
3
- * source backend shares.
2
+ * The resolved API-key resource and the reusable credential primitives.
4
3
  *
5
4
  * Holds the resolved {@link ApiKey} type and its {@link schema}, the token
6
- * format/generation ({@link generateToken}/{@link generateId}), the storage-key
7
- * derivation ({@link keyFor}/{@link recordPrefix}), and log {@link redact}ion.
8
- * These live here — not in a single source — so every `ApiKeySource` backend
9
- * (the built-in store, a future D1/Postgres source) issues and parses
10
- * byte-identical credentials and cannot drift. The persisted record/mint-input
11
- * shapes and provisioning (mint/list/revoke) belong to the
12
- * `ApiKeySource.Source` contract, which composes these primitives with its own
13
- * persistence.
5
+ * format/generation ({@link generateToken}/{@link generateId}), the
6
+ * storage-key derivation ({@link keyFor}/{@link recordPrefix}), and log
7
+ * {@link redact}ion. These live here — not in the persistence module — so
8
+ * issued and parsed credentials are byte-identical and cannot drift. The
9
+ * persisted record/mint-input shapes and provisioning (mint/list/revoke) live
10
+ * in `./ApiKeys.js`, which composes these primitives with the app's KV state
11
+ * store (`App.create({ kv })`).
14
12
  */
15
13
  import * as z from 'zod/mini';
16
14
  /** Zod schemas owned by the API-key module. */
17
15
  export declare namespace schema {
18
16
  /**
19
17
  * Canonical schema for resolved API-key metadata, and the single source of
20
- * truth for the {@link ApiKey} type. `ApiKeySource` derives its persisted
18
+ * truth for the {@link ApiKey} type. `ApiKeys` derives its persisted
21
19
  * `Record` and `MintInput` schemas from this one, so the resolved and
22
20
  * persisted shapes cannot drift.
23
21
  */
@@ -36,6 +34,7 @@ export declare namespace schema {
36
34
  "*": "*";
37
35
  "data:read": "data:read";
38
36
  "indexer:query": "indexer:query";
37
+ "rpc-relay": "rpc-relay";
39
38
  "webhooks:read": "webhooks:read";
40
39
  "webhooks:write": "webhooks:write";
41
40
  }>>>;
@@ -60,6 +59,8 @@ export declare function generateToken(environment?: ApiKey['environment']): stri
60
59
  export declare function generateId(): string;
61
60
  /** Storage-key prefix under which key records are persisted, keyed by token hash. */
62
61
  export declare const recordPrefix = "apikey:";
62
+ /** Hashes a plaintext token to its at-rest lookup hash (lowercase hex, no `0x`). */
63
+ export declare function hash(token: string): string;
63
64
  /** Storage key under which the record for a plaintext token is persisted. */
64
65
  export declare function keyFor(token: string): string;
65
66
  //# sourceMappingURL=ApiKey.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ApiKey.d.ts","sourceRoot":"","sources":["../src/ApiKey.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAK7B,+CAA+C;AAC/C,yBAAiB,MAAM,CAAC;IACtB;;;;;OAKG;IACI,MAAM,MAAM;;;;;;;;;;;;;;;;;;qBAiBjB,CAAA;CACH;AAED,mDAAmD;AACnD,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAA;AAEnD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI3C;AAiCD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,WAAW,GAAE,MAAM,CAAC,aAAa,CAAgB,GAAG,MAAM,CAEvF;AAED,mDAAmD;AACnD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,qFAAqF;AACrF,eAAO,MAAM,YAAY,YAAY,CAAA;AAOrC,6EAA6E;AAC7E,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C"}
1
+ {"version":3,"file":"ApiKey.d.ts","sourceRoot":"","sources":["../src/ApiKey.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAK7B,+CAA+C;AAC/C,yBAAiB,MAAM,CAAC;IACtB;;;;;OAKG;IACI,MAAM,MAAM;;;;;;;;;;;;;;;;;;;qBAiBjB,CAAA;CACH;AAED,mDAAmD;AACnD,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAA;AAEnD;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI3C;AAiCD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,WAAW,GAAE,MAAM,CAAC,aAAa,CAAgB,GAAG,MAAM,CAEvF;AAED,mDAAmD;AACnD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,qFAAqF;AACrF,eAAO,MAAM,YAAY,YAAY,CAAA;AAErC,oFAAoF;AACpF,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED,6EAA6E;AAC7E,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE5C"}
package/dist/ApiKey.js CHANGED
@@ -1,16 +1,14 @@
1
1
  /**
2
- * The resolved API-key resource and the reusable credential primitives every
3
- * source backend shares.
2
+ * The resolved API-key resource and the reusable credential primitives.
4
3
  *
5
4
  * Holds the resolved {@link ApiKey} type and its {@link schema}, the token
6
- * format/generation ({@link generateToken}/{@link generateId}), the storage-key
7
- * derivation ({@link keyFor}/{@link recordPrefix}), and log {@link redact}ion.
8
- * These live here — not in a single source — so every `ApiKeySource` backend
9
- * (the built-in store, a future D1/Postgres source) issues and parses
10
- * byte-identical credentials and cannot drift. The persisted record/mint-input
11
- * shapes and provisioning (mint/list/revoke) belong to the
12
- * `ApiKeySource.Source` contract, which composes these primitives with its own
13
- * persistence.
5
+ * format/generation ({@link generateToken}/{@link generateId}), the
6
+ * storage-key derivation ({@link keyFor}/{@link recordPrefix}), and log
7
+ * {@link redact}ion. These live here — not in the persistence module — so
8
+ * issued and parsed credentials are byte-identical and cannot drift. The
9
+ * persisted record/mint-input shapes and provisioning (mint/list/revoke) live
10
+ * in `./ApiKeys.js`, which composes these primitives with the app's KV state
11
+ * store (`App.create({ kv })`).
14
12
  */
15
13
  import { nanoid } from 'nanoid';
16
14
  import { Hash, Hex } from 'ox';
@@ -22,7 +20,7 @@ export var schema;
22
20
  (function (schema) {
23
21
  /**
24
22
  * Canonical schema for resolved API-key metadata, and the single source of
25
- * truth for the {@link ApiKey} type. `ApiKeySource` derives its persisted
23
+ * truth for the {@link ApiKey} type. `ApiKeys` derives its persisted
26
24
  * `Record` and `MintInput` schemas from this one, so the resolved and
27
25
  * persisted shapes cannot drift.
28
26
  */
@@ -95,7 +93,7 @@ export function generateId() {
95
93
  /** Storage-key prefix under which key records are persisted, keyed by token hash. */
96
94
  export const recordPrefix = 'apikey:';
97
95
  /** Hashes a plaintext token to its at-rest lookup hash (lowercase hex, no `0x`). */
98
- function hash(token) {
96
+ export function hash(token) {
99
97
  return Hash.sha256(Hex.fromString(token)).slice(2);
100
98
  }
101
99
  /** Storage key under which the record for a plaintext token is persisted. */
@@ -1 +1 @@
1
- {"version":3,"file":"ApiKey.js","sourceRoot":"","sources":["../src/ApiKey.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ApiKey.js","sourceRoot":"","sources":["../src/ApiKey.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * API-key persistence over the app's KV state store (`App.create({ kv })`).
3
+ *
4
+ * Records are keyed by token hash (`ApiKey.keyFor`) — the plaintext token is
5
+ * never stored — and validated against the scope catalog on read; unknown,
6
+ * corrupt, expired, or invalid records resolve to `null`. An `id → recordKey`
7
+ * index makes revoke-by-id O(1). The persisted {@link Record}/{@link
8
+ * MintInput} shapes live here (derived from `ApiKey.schema` so they cannot
9
+ * drift from the resolved shape), while the shared credential primitives
10
+ * (token format/generation, storage-key derivation, redaction) live in
11
+ * `./ApiKey.js`.
12
+ */
13
+ import * as z from 'zod/mini';
14
+ import * as ApiKey from './ApiKey.js';
15
+ import type * as Store from './internal/Store.js';
16
+ /** Zod schemas owned by the API-keys module. */
17
+ export declare namespace schema {
18
+ /**
19
+ * Fields accepted when minting a key, and the single source of truth for the
20
+ * {@link MintInput} type and `mint` validation. Derived from the resolved
21
+ * `ApiKey.schema` (minus the generated `id`) so the scope vocabulary stays in
22
+ * lockstep with the resolved shape.
23
+ */
24
+ const MintInput: z.ZodMiniObject<{
25
+ environment: z.ZodMiniDefault<z.ZodMiniEnum<{
26
+ production: "production";
27
+ sandbox: "sandbox";
28
+ }>>;
29
+ name: z.ZodMiniOptional<z.ZodMiniString<string>>;
30
+ rateLimits: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniObject<{
31
+ perMinute: z.ZodMiniNumber<number>;
32
+ }, z.core.$strip>>>;
33
+ scopes: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniEnum<{
34
+ "*": "*";
35
+ "data:read": "data:read";
36
+ "indexer:query": "indexer:query";
37
+ "rpc-relay": "rpc-relay";
38
+ "webhooks:read": "webhooks:read";
39
+ "webhooks:write": "webhooks:write";
40
+ }>>>;
41
+ createdBy: z.ZodMiniOptional<z.ZodMiniString<string>>;
42
+ expiresAt: z.ZodMiniOptional<z.ZodMiniString<string>>;
43
+ orgId: z.ZodMiniOptional<z.ZodMiniString<string>>;
44
+ }, z.core.$strip>;
45
+ /**
46
+ * A persisted API-key record: the resolved `ApiKey.schema` plus
47
+ * persistence/display fields. Extending the resolved schema keeps the resolved
48
+ * and persisted shapes in lockstep.
49
+ */
50
+ const Record: z.ZodMiniObject<{
51
+ environment: z.ZodMiniDefault<z.ZodMiniEnum<{
52
+ production: "production";
53
+ sandbox: "sandbox";
54
+ }>>;
55
+ id: z.ZodMiniString<string>;
56
+ name: z.ZodMiniOptional<z.ZodMiniString<string>>;
57
+ orgId: z.ZodMiniString<string>;
58
+ rateLimits: z.ZodMiniOptional<z.ZodMiniRecord<z.ZodMiniString<string>, z.ZodMiniObject<{
59
+ perMinute: z.ZodMiniNumber<number>;
60
+ }, z.core.$strip>>>;
61
+ scopes: z.ZodMiniReadonly<z.ZodMiniArray<z.ZodMiniEnum<{
62
+ "*": "*";
63
+ "data:read": "data:read";
64
+ "indexer:query": "indexer:query";
65
+ "rpc-relay": "rpc-relay";
66
+ "webhooks:read": "webhooks:read";
67
+ "webhooks:write": "webhooks:write";
68
+ }>>>;
69
+ createdAt: z.ZodMiniString<string>;
70
+ createdBy: z.ZodMiniOptional<z.ZodMiniString<string>>;
71
+ expiresAt: z.ZodMiniOptional<z.ZodMiniString<string>>;
72
+ tokenLast4: z.ZodMiniString<string>;
73
+ }, z.core.$strip>;
74
+ }
75
+ /**
76
+ * A durable API-key record as persisted. A superset of the resolved
77
+ * `ApiKey.ApiKey` with provisioning/display metadata. The plaintext token is
78
+ * never stored — records are keyed by its hash (`ApiKey.keyFor`) and carry only
79
+ * `tokenLast4` for display.
80
+ */
81
+ export type Record = z.output<typeof schema.Record>;
82
+ /**
83
+ * Fields accepted when minting a key via {@link mint}. Uses the schema's
84
+ * *input* type so defaulted fields (e.g. `environment`) are optional for
85
+ * callers — the default is applied during `mint`'s validation.
86
+ */
87
+ export type MintInput = z.input<typeof schema.MintInput>;
88
+ /** Result of {@link mint}: the persisted record and its one-time token. */
89
+ export type MintResult = {
90
+ /** The persisted key record (metadata only — never the token). */
91
+ record: Record;
92
+ /** The plaintext token, shown once and unrecoverable afterward. */
93
+ token: string;
94
+ };
95
+ /**
96
+ * Mints a key: validates the input (e.g. rejects an unknown scope at the write
97
+ * boundary), persists its hashed record, and returns the record plus the
98
+ * one-time plaintext token (shown once, unrecoverable afterward).
99
+ *
100
+ * @param state - The KV state store holding key records.
101
+ * @param input - The key to mint.
102
+ * @returns The persisted record and its one-time token.
103
+ */
104
+ export declare function mint(state: Store.State, input: MintInput): Promise<MintResult>;
105
+ /**
106
+ * Resolves a plaintext API key token to its metadata, or `null`. Expiry is
107
+ * enforced on read — not just via the store's native TTL — so it holds on
108
+ * backends that evict lazily and regardless of TTL granularity.
109
+ *
110
+ * @param state - The KV state store holding key records.
111
+ * @param token - The presented plaintext token.
112
+ * @returns The resolved key metadata, or `null`.
113
+ */
114
+ export declare function resolve(state: Store.State, token: string): Promise<ApiKey.ApiKey | null>;
115
+ /**
116
+ * Lists key records (metadata only — never tokens), newest first. Expired or
117
+ * catalog-invalid records are skipped.
118
+ *
119
+ * @param state - The KV state store holding key records.
120
+ * @param options - Optional owner filter.
121
+ * @returns The records.
122
+ */
123
+ export declare function list(state: Store.State, options?: list.Options): Promise<readonly Record[]>;
124
+ export declare namespace list {
125
+ /** Options for {@link list}. */
126
+ type Options = {
127
+ /** Restrict results to keys owned by this organization. */
128
+ orgId?: string | undefined;
129
+ };
130
+ }
131
+ /**
132
+ * Revokes a key by id, deleting its record and index entry.
133
+ *
134
+ * @param state - The KV state store holding key records.
135
+ * @param id - The key id (`key_…`).
136
+ * @returns Whether a matching record was deleted.
137
+ */
138
+ export declare function revoke(state: Store.State, id: string): Promise<boolean>;
139
+ //# sourceMappingURL=ApiKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiKeys.d.ts","sourceRoot":"","sources":["../src/ApiKeys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AACrC,OAAO,KAAK,KAAK,KAAK,MAAM,qBAAqB,CAAA;AAEjD,gDAAgD;AAChD,yBAAiB,MAAM,CAAC;IACtB;;;;;OAKG;IACI,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;qBASpB,CAAA;IAEF;;;;OAIG;IACI,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;qBAKjB,CAAA;CACH;AAED;;;;;GAKG;AACH,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAA;AAEnD;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,SAAS,CAAC,CAAA;AAExD,2EAA2E;AAC3E,MAAM,MAAM,UAAU,GAAG;IACvB,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAsB,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAkCpF;AAED;;;;;;;;GAQG;AACH,wBAAsB,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,CAE9F;AAED;;;;;;;GAOG;AACH,wBAAsB,IAAI,CACxB,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,OAAO,GAAE,IAAI,CAAC,OAAY,GACzB,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAS5B;AAED,MAAM,CAAC,OAAO,WAAW,IAAI,CAAC;IAC5B,gCAAgC;IAChC,KAAK,OAAO,GAAG;QACb,2DAA2D;QAC3D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAC3B,CAAA;CACF;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAM7E"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * API-key persistence over the app's KV state store (`App.create({ kv })`).
3
+ *
4
+ * Records are keyed by token hash (`ApiKey.keyFor`) — the plaintext token is
5
+ * never stored — and validated against the scope catalog on read; unknown,
6
+ * corrupt, expired, or invalid records resolve to `null`. An `id → recordKey`
7
+ * index makes revoke-by-id O(1). The persisted {@link Record}/{@link
8
+ * MintInput} shapes live here (derived from `ApiKey.schema` so they cannot
9
+ * drift from the resolved shape), while the shared credential primitives
10
+ * (token format/generation, storage-key derivation, redaction) live in
11
+ * `./ApiKey.js`.
12
+ */
13
+ import * as z from 'zod/mini';
14
+ import * as ApiKey from './ApiKey.js';
15
+ /** Zod schemas owned by the API-keys module. */
16
+ export var schema;
17
+ (function (schema) {
18
+ /**
19
+ * Fields accepted when minting a key, and the single source of truth for the
20
+ * {@link MintInput} type and `mint` validation. Derived from the resolved
21
+ * `ApiKey.schema` (minus the generated `id`) so the scope vocabulary stays in
22
+ * lockstep with the resolved shape.
23
+ */
24
+ schema.MintInput = z.extend(z.omit(ApiKey.schema.ApiKey, { id: true }), {
25
+ createdBy: z
26
+ .optional(z.string())
27
+ .check(z.describe('Identity creating the key (e.g. admin email), recorded for audit.')),
28
+ expiresAt: z
29
+ .optional(z.string())
30
+ .check(z.describe('ISO 8601 expiry timestamp. Omit for a non-expiring key.')),
31
+ // TODO: make required once orgs exist.
32
+ orgId: z.optional(z.string()).check(z.describe('Owning organization id.')),
33
+ });
34
+ /**
35
+ * A persisted API-key record: the resolved `ApiKey.schema` plus
36
+ * persistence/display fields. Extending the resolved schema keeps the resolved
37
+ * and persisted shapes in lockstep.
38
+ */
39
+ schema.Record = z.extend(ApiKey.schema.ApiKey, {
40
+ createdAt: z.string().check(z.describe('ISO 8601 creation timestamp.')),
41
+ createdBy: z.optional(z.string()).check(z.describe('Identity that created the key.')),
42
+ expiresAt: z.optional(z.string()).check(z.describe('ISO 8601 expiry timestamp.')),
43
+ tokenLast4: z.string().check(z.describe('Last 4 chars of the plaintext token.')),
44
+ });
45
+ })(schema || (schema = {}));
46
+ /**
47
+ * Mints a key: validates the input (e.g. rejects an unknown scope at the write
48
+ * boundary), persists its hashed record, and returns the record plus the
49
+ * one-time plaintext token (shown once, unrecoverable afterward).
50
+ *
51
+ * @param state - The KV state store holding key records.
52
+ * @param input - The key to mint.
53
+ * @returns The persisted record and its one-time token.
54
+ */
55
+ export async function mint(state, input) {
56
+ const valid = schema.MintInput.safeParse(input);
57
+ if (!valid.success)
58
+ throw new Error(`invalid API key input: ${z.prettifyError(valid.error)}`);
59
+ const data = valid.data;
60
+ const time = new Date();
61
+ const token = ApiKey.generateToken(data.environment);
62
+ const recordKey = ApiKey.keyFor(token);
63
+ const id = ApiKey.generateId();
64
+ const record = {
65
+ createdAt: time.toISOString(),
66
+ environment: data.environment,
67
+ id,
68
+ // TODO: drop fallback once a real org concept exists.
69
+ orgId: data.orgId ?? id,
70
+ scopes: data.scopes,
71
+ tokenLast4: token.slice(-4),
72
+ ...(data.createdBy === undefined ? {} : { createdBy: data.createdBy }),
73
+ ...(data.expiresAt === undefined ? {} : { expiresAt: data.expiresAt }),
74
+ ...(data.name === undefined ? {} : { name: data.name }),
75
+ ...(data.rateLimits === undefined ? {} : { rateLimits: data.rateLimits }),
76
+ };
77
+ // Bound the stored record by its expiry so the backend evicts it natively.
78
+ const ttl = data.expiresAt === undefined
79
+ ? undefined
80
+ : Math.max(1, Date.parse(data.expiresAt) - time.getTime());
81
+ await state.put(recordKey, JSON.stringify(record), { ttl });
82
+ // Index `id → recordKey` so revoke-by-id is O(1) (records are keyed by
83
+ // token hash, unrecoverable from the id alone). Shares the record's TTL so
84
+ // both entries expire together.
85
+ await state.put(idKeyFor(record.id), recordKey, { ttl });
86
+ return { record, token };
87
+ }
88
+ /**
89
+ * Resolves a plaintext API key token to its metadata, or `null`. Expiry is
90
+ * enforced on read — not just via the store's native TTL — so it holds on
91
+ * backends that evict lazily and regardless of TTL granularity.
92
+ *
93
+ * @param state - The KV state store holding key records.
94
+ * @param token - The presented plaintext token.
95
+ * @returns The resolved key metadata, or `null`.
96
+ */
97
+ export async function resolve(state, token) {
98
+ return read(state, ApiKey.keyFor(token), Date.now());
99
+ }
100
+ /**
101
+ * Lists key records (metadata only — never tokens), newest first. Expired or
102
+ * catalog-invalid records are skipped.
103
+ *
104
+ * @param state - The KV state store holding key records.
105
+ * @param options - Optional owner filter.
106
+ * @returns The records.
107
+ */
108
+ export async function list(state, options = {}) {
109
+ const { keys } = await state.list({ prefix: ApiKey.recordPrefix });
110
+ const records = [];
111
+ for (const { name } of keys) {
112
+ const record = await read(state, name, Date.now());
113
+ if (record && (!options.orgId || record.orgId === options.orgId))
114
+ records.push(record);
115
+ }
116
+ // Newest first; ids are random, so sort by creation time.
117
+ return records.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
118
+ }
119
+ /**
120
+ * Revokes a key by id, deleting its record and index entry.
121
+ *
122
+ * @param state - The KV state store holding key records.
123
+ * @param id - The key id (`key_…`).
124
+ * @returns Whether a matching record was deleted.
125
+ */
126
+ export async function revoke(state, id) {
127
+ const recordKey = await state.get(idKeyFor(id));
128
+ if (!recordKey)
129
+ return false;
130
+ await state.delete(recordKey);
131
+ await state.delete(idKeyFor(id));
132
+ return true;
133
+ }
134
+ /**
135
+ * Reads and validates a stored record by storage key. Invalid, corrupt, or
136
+ * expired records (`expiresAt <= now`) resolve to `null`.
137
+ */
138
+ async function read(state, key, now) {
139
+ const raw = await state.get(key);
140
+ if (!raw)
141
+ return null;
142
+ const value = (() => {
143
+ try {
144
+ return JSON.parse(raw);
145
+ }
146
+ catch {
147
+ return undefined;
148
+ }
149
+ })();
150
+ if (value === undefined)
151
+ return null;
152
+ const parsed = schema.Record.safeParse(value);
153
+ if (!parsed.success)
154
+ return null;
155
+ const record = parsed.data;
156
+ if (record.expiresAt !== undefined && Date.parse(record.expiresAt) <= now)
157
+ return null;
158
+ return record;
159
+ }
160
+ /** Storage-key prefix for the `id → recordKey` index. */
161
+ const idPrefix = 'apikey_id:';
162
+ /** Storage key under which a key's `id → recordKey` index entry is persisted. */
163
+ function idKeyFor(id) {
164
+ return `${idPrefix}${id}`;
165
+ }
166
+ //# sourceMappingURL=ApiKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ApiKeys.js","sourceRoot":"","sources":["../src/ApiKeys.ts"],"names":[],"mappings":"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"}