hive-stream 3.0.0 → 3.0.2

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 (107) hide show
  1. package/AGENTS.md +35 -0
  2. package/DOCUMENTATION.md +396 -0
  3. package/README.md +160 -39
  4. package/dist/actions.d.ts +3 -3
  5. package/dist/actions.js +7 -7
  6. package/dist/actions.js.map +1 -1
  7. package/dist/adapters/base.adapter.d.ts +19 -1
  8. package/dist/adapters/base.adapter.js +16 -0
  9. package/dist/adapters/base.adapter.js.map +1 -1
  10. package/dist/adapters/mongodb.adapter.d.ts +5 -11
  11. package/dist/adapters/mongodb.adapter.js +10 -10
  12. package/dist/adapters/mongodb.adapter.js.map +1 -1
  13. package/dist/adapters/postgresql.adapter.d.ts +17 -0
  14. package/dist/adapters/postgresql.adapter.js +99 -8
  15. package/dist/adapters/postgresql.adapter.js.map +1 -1
  16. package/dist/adapters/sqlite.adapter.d.ts +17 -0
  17. package/dist/adapters/sqlite.adapter.js +99 -8
  18. package/dist/adapters/sqlite.adapter.js.map +1 -1
  19. package/dist/api.js +86 -0
  20. package/dist/api.js.map +1 -1
  21. package/dist/config.d.ts +26 -0
  22. package/dist/config.js +76 -4
  23. package/dist/config.js.map +1 -1
  24. package/dist/contracts/coinflip.contract.d.ts +8 -26
  25. package/dist/contracts/coinflip.contract.js +123 -144
  26. package/dist/contracts/coinflip.contract.js.map +1 -1
  27. package/dist/contracts/contract.d.ts +3 -0
  28. package/dist/contracts/contract.js +26 -0
  29. package/dist/contracts/contract.js.map +1 -0
  30. package/dist/contracts/dice.contract.d.ts +9 -36
  31. package/dist/contracts/dice.contract.js +135 -200
  32. package/dist/contracts/dice.contract.js.map +1 -1
  33. package/dist/contracts/exchange.contract.d.ts +11 -0
  34. package/dist/contracts/exchange.contract.js +492 -0
  35. package/dist/contracts/exchange.contract.js.map +1 -0
  36. package/dist/contracts/lotto.contract.d.ts +15 -19
  37. package/dist/contracts/lotto.contract.js +154 -162
  38. package/dist/contracts/lotto.contract.js.map +1 -1
  39. package/dist/contracts/nft.contract.d.ts +4 -0
  40. package/dist/contracts/nft.contract.js +65 -0
  41. package/dist/contracts/nft.contract.js.map +1 -1
  42. package/dist/contracts/poll.contract.d.ts +4 -0
  43. package/dist/contracts/poll.contract.js +105 -0
  44. package/dist/contracts/poll.contract.js.map +1 -0
  45. package/dist/contracts/rps.contract.d.ts +9 -0
  46. package/dist/contracts/rps.contract.js +217 -0
  47. package/dist/contracts/rps.contract.js.map +1 -0
  48. package/dist/contracts/tipjar.contract.d.ts +4 -0
  49. package/dist/contracts/tipjar.contract.js +60 -0
  50. package/dist/contracts/tipjar.contract.js.map +1 -0
  51. package/dist/contracts/token.contract.d.ts +3 -17
  52. package/dist/contracts/token.contract.js +128 -80
  53. package/dist/contracts/token.contract.js.map +1 -1
  54. package/dist/exchanges/coingecko.d.ts +7 -1
  55. package/dist/exchanges/coingecko.js +38 -21
  56. package/dist/exchanges/coingecko.js.map +1 -1
  57. package/dist/exchanges/exchange.d.ts +15 -8
  58. package/dist/exchanges/exchange.js +65 -11
  59. package/dist/exchanges/exchange.js.map +1 -1
  60. package/dist/hive-rates.d.ts +29 -4
  61. package/dist/hive-rates.js +179 -92
  62. package/dist/hive-rates.js.map +1 -1
  63. package/dist/index.d.ts +11 -3
  64. package/dist/index.js +19 -4
  65. package/dist/index.js.map +1 -1
  66. package/dist/metadata.d.ts +63 -0
  67. package/dist/metadata.js +407 -0
  68. package/dist/metadata.js.map +1 -0
  69. package/dist/streamer.d.ts +104 -11
  70. package/dist/streamer.js +415 -143
  71. package/dist/streamer.js.map +1 -1
  72. package/dist/test.js +11 -12
  73. package/dist/test.js.map +1 -1
  74. package/dist/types/hive-stream.d.ts +85 -14
  75. package/dist/types/rates.d.ts +47 -0
  76. package/dist/types/rates.js +29 -0
  77. package/dist/types/rates.js.map +1 -0
  78. package/dist/utils.d.ts +318 -11
  79. package/dist/utils.js +804 -115
  80. package/dist/utils.js.map +1 -1
  81. package/examples/contracts/README.md +8 -0
  82. package/examples/contracts/exchange.ts +38 -0
  83. package/examples/contracts/poll.ts +21 -0
  84. package/examples/contracts/rps.ts +19 -0
  85. package/examples/contracts/tipjar.ts +19 -0
  86. package/package.json +20 -19
  87. package/test-contract-block.md +3 -3
  88. package/tests/actions.spec.ts +7 -7
  89. package/tests/adapters/actions-persistence.spec.ts +4 -4
  90. package/tests/adapters/sqlite.adapter.spec.ts +2 -2
  91. package/tests/config-input.spec.ts +90 -0
  92. package/tests/contracts/coinflip.contract.spec.ts +26 -154
  93. package/tests/contracts/dice.contract.spec.ts +24 -140
  94. package/tests/contracts/exchange.contract.spec.ts +84 -0
  95. package/tests/contracts/lotto.contract.spec.ts +30 -295
  96. package/tests/contracts/token.contract.spec.ts +72 -316
  97. package/tests/exchanges/coingecko.exchange.spec.ts +169 -0
  98. package/tests/exchanges/exchange.base.spec.ts +246 -0
  99. package/tests/helpers/mock-fetch.ts +165 -0
  100. package/tests/hive-chain-features.spec.ts +319 -0
  101. package/tests/hive-rates.spec.ts +443 -0
  102. package/tests/integration/hive-rates.integration.spec.ts +35 -0
  103. package/tests/metadata.spec.ts +63 -0
  104. package/tests/streamer-actions.spec.ts +29 -18
  105. package/tests/streamer.spec.ts +142 -49
  106. package/tests/types/rates.spec.ts +216 -0
  107. package/tests/utils.spec.ts +27 -6
package/AGENTS.md ADDED
@@ -0,0 +1,35 @@
1
+ # Repository Guidelines
2
+
3
+ ## Project Structure & Module Organization
4
+ - `src/` holds TypeScript source. Core entry points are `streamer.ts`, `api.ts`, and `index.ts`.
5
+ - `src/adapters/` contains SQLite/Mongo/Postgres adapters; `src/contracts/` has contract examples; `src/exchanges/` has rate helpers; `src/types/` centralizes shared types.
6
+ - `tests/` contains Jest specs (`**/*.spec.ts`) plus `tests/integration/` and `tests/helpers/`.
7
+ - `dist/` is generated build output; `examples/` provides usage samples; `ecosystem.config.js` is a PM2 reference.
8
+
9
+ ## Build, Test, and Development Commands
10
+ - `npm install` installs dependencies.
11
+ - `npm run build` compiles TypeScript to `dist/`.
12
+ - `npm run start` runs the local dev harness (`src/test.ts`) via ts-node.
13
+ - `npm run watch` enables TypeScript watch mode.
14
+ - `npm test` runs the Jest suite.
15
+ - `npm run clean-tests` clears Jest cache if tests act stale.
16
+
17
+ ## Coding Style & Naming Conventions
18
+ - TypeScript with CommonJS output; keep module boundaries within `src/`.
19
+ - Indent 4 spaces; prefer single quotes (see `tslint.json`).
20
+ - File naming conventions: `*.adapter.ts`, `*.contract.ts`, `*.spec.ts`; shared types live in `src/types/`.
21
+ - TSLint rules in `tslint.json` are the baseline; match existing style before introducing new tooling.
22
+
23
+ ## Testing Guidelines
24
+ - Framework: Jest + `ts-jest` (see `jest.config.js`).
25
+ - Place specs under `tests/` and name `*.spec.ts` (example: `tests/utils.spec.ts`).
26
+ - Use `tests/setup.ts` for shared mocks; integration tests live under `tests/integration/`.
27
+ - No coverage thresholds are configured; add focused tests for new adapters, contracts, or API routes.
28
+
29
+ ## Commit & Pull Request Guidelines
30
+ - Follow Conventional Commits with scopes, as in history: `feat(api): ...`, `fix(contract): ...`, `chore(deps): ...`, `docs(readme): ...`.
31
+ - PRs should include: a clear summary, testing notes (`npm test`/`npm run build`), and docs/CHANGELOG updates for user-facing changes.
32
+
33
+ ## Configuration & Security Notes
34
+ - Keys and usernames should come from env/config (see `src/config.ts`); never commit secrets.
35
+ - When adding new config, document defaults and keep backward compatibility.
@@ -0,0 +1,396 @@
1
+ # Hive-Stream Documentation
2
+
3
+ ## Introduction
4
+ Hive Stream is a Node.js library for streaming Hive blockchain activity and routing it to contracts you define. Contracts can react to:
5
+ - `custom_json` operations
6
+ - transfer memos
7
+ - time-based actions
8
+ - escrow operations
9
+
10
+ This document focuses on the contract system and how to build robust contracts using the new `defineContract`/`action` API.
11
+
12
+ By default, `new Streamer()` registers the SQLite adapter and starts the built-in Express API server on port `5001` when `NODE_ENV !== 'test'`.
13
+
14
+ ---
15
+
16
+ ## Concepts
17
+
18
+ ### Contracts
19
+ A **contract** is a definition object with:
20
+ - a **name**
21
+ - one or more **actions**
22
+ - optional **lifecycle hooks**
23
+
24
+ Contracts are registered with the `Streamer` and called when a payload matches `contract` + `action`.
25
+
26
+ ### Actions
27
+ An **action** is a handler function plus metadata such as:
28
+ - the trigger (`custom_json`, `transfer`, `time`, `escrow_transfer`, `escrow_approve`, `escrow_dispute`, `escrow_release`, or `recurrent_transfer`)
29
+ - an optional Zod schema to validate payloads
30
+ - whether it requires an active key signature
31
+
32
+ ### Payload Identifier
33
+ Hive Stream extracts payloads from:
34
+ - **custom_json**: `op[1].json`
35
+ - **transfer memo**: `op[1].memo`
36
+ - **recurrent transfer memo**: `op[1].memo`
37
+ - **escrow metadata**: `op[1].json_meta`
38
+
39
+ It expects a wrapper object that looks like:
40
+
41
+ ```
42
+ {
43
+ "hive_stream": {
44
+ "contract": "mycontract",
45
+ "action": "doSomething",
46
+ "payload": { "any": "data" },
47
+ "meta": { "optional": true }
48
+ }
49
+ }
50
+ ```
51
+
52
+ The wrapper key `hive_stream` is the default `PAYLOAD_IDENTIFIER`. You can change it in config.
53
+
54
+ Relevant configuration defaults:
55
+
56
+ - `PAYLOAD_IDENTIFIER`: `hive_stream`
57
+ - `JSON_ID`: `hivestream`
58
+ - `HIVE_ENGINE_ID`: `ssc-mainnet-hive`
59
+ - `HIVE_ENGINE_API`: `https://api.hive-engine.com/rpc`
60
+
61
+ ### Event Handlers vs Contracts
62
+ Streamer event handlers (`onTransfer`, `onCustomJson`, `onCustomJsonId`, etc.) and contract actions are different execution paths.
63
+
64
+ - Event handlers fire for matching blockchain operations.
65
+ - Contract actions only run when a valid wrapper exists under `PAYLOAD_IDENTIFIER` and the `contract` + `action` values match a registered contract action.
66
+
67
+ ---
68
+
69
+ ## Contract API
70
+
71
+ ### Define a Contract
72
+
73
+ ```ts
74
+ import { defineContract, action } from 'hive-stream';
75
+
76
+ const MyContract = defineContract({
77
+ name: 'mycontract',
78
+ actions: {
79
+ hello: action(async (payload, ctx) => {
80
+ console.log('hello', payload.name, ctx.sender);
81
+ }, {
82
+ trigger: 'custom_json'
83
+ })
84
+ }
85
+ });
86
+ ```
87
+
88
+ ### Register a Contract
89
+
90
+ ```ts
91
+ import { Streamer } from 'hive-stream';
92
+
93
+ const streamer = new Streamer();
94
+ await streamer.registerContract(MyContract);
95
+ ```
96
+
97
+ ### Unregister a Contract
98
+
99
+ ```ts
100
+ await streamer.unregisterContract('mycontract');
101
+ ```
102
+
103
+ ### Contract Lifecycle Hooks
104
+
105
+ ```ts
106
+ const MyContract = defineContract({
107
+ name: 'mycontract',
108
+ hooks: {
109
+ create: async ({ streamer, adapter, config }) => {
110
+ // initialize tables, cache config, etc
111
+ },
112
+ destroy: async ({ streamer, adapter }) => {
113
+ // cleanup resources
114
+ }
115
+ },
116
+ actions: { ... }
117
+ });
118
+ ```
119
+
120
+ ---
121
+
122
+ ## Contract Context
123
+
124
+ Every action receives a `ContractContext` with:
125
+
126
+ - `trigger`: `custom_json | transfer | time | escrow_transfer | escrow_approve | escrow_dispute | escrow_release | recurrent_transfer`
127
+ - `streamer`: access to Hive client and helpers
128
+ - `adapter`: database adapter
129
+ - `config`: resolved config values
130
+ - `block`: `{ number, id, previousId, time }`
131
+ - `transaction`: `{ id }`
132
+ - `sender`: Hive account invoking the action
133
+ - `transfer`: transfer details (only for `transfer` trigger)
134
+ - `customJson`: custom JSON details (only for `custom_json` trigger)
135
+ - `escrow`: escrow details (only for escrow triggers)
136
+ - `operation`: raw operation data and operation type for advanced use cases
137
+
138
+ ### Example
139
+
140
+ ```ts
141
+ action((payload, ctx) => {
142
+ console.log(ctx.trigger);
143
+ console.log(ctx.block.number, ctx.transaction.id);
144
+ if (ctx.transfer) {
145
+ console.log(ctx.transfer.amount, ctx.transfer.asset);
146
+ }
147
+ });
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Payload Validation (Zod)
153
+
154
+ Use Zod to validate payloads and enforce strong inputs:
155
+
156
+ ```ts
157
+ import { z } from 'zod';
158
+
159
+ const schema = z.object({
160
+ amount: z.string().min(1),
161
+ to: z.string().min(1)
162
+ });
163
+
164
+ const MyContract = defineContract({
165
+ name: 'payments',
166
+ actions: {
167
+ send: action((payload, ctx) => {
168
+ // payload is validated here
169
+ }, { schema, trigger: 'custom_json' })
170
+ }
171
+ });
172
+ ```
173
+
174
+ If validation fails, the action is not executed and the error is logged.
175
+
176
+ ---
177
+
178
+ ## Triggers
179
+
180
+ Actions can be scoped to a trigger:
181
+
182
+ - `custom_json`: called when a custom JSON payload matches
183
+ - `transfer`: called when a transfer memo matches
184
+ - `time`: called by a `TimeAction`
185
+ - `escrow_transfer`: called when escrow transfer payload in `json_meta` matches
186
+ - `escrow_approve`: available as a trigger for escrow-related contracts
187
+ - `escrow_dispute`: available as a trigger for escrow-related contracts
188
+ - `escrow_release`: available as a trigger for escrow-related contracts
189
+ - `recurrent_transfer`: called when recurrent transfer memo payload matches
190
+
191
+ ```ts
192
+ action(handler, { trigger: 'transfer' });
193
+ ```
194
+
195
+ You can also allow multiple triggers:
196
+
197
+ ```ts
198
+ action(handler, { trigger: ['custom_json', 'transfer'] });
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Active Key Enforcement
204
+
205
+ Some actions should only run when the transaction is signed with an active key. Mark them with:
206
+
207
+ ```ts
208
+ action(handler, { trigger: 'custom_json', requiresActiveKey: true });
209
+ ```
210
+
211
+ This prevents posting-key JSONs from triggering sensitive actions like withdrawals.
212
+
213
+ ---
214
+
215
+ ## Error Handling
216
+
217
+ - Errors inside contract actions are caught and logged.
218
+ - **Time actions** bubble errors back into the scheduler so the action does **not** increment execution count if it fails.
219
+
220
+ Write actions defensively and always validate inputs.
221
+
222
+ ---
223
+
224
+ ## Time-Based Actions
225
+
226
+ Time-based actions let you run contract logic on a schedule:
227
+
228
+ ```ts
229
+ import { TimeAction } from 'hive-stream';
230
+
231
+ const matchAction = new TimeAction('30s', 'exchange-matcher', 'exchange', 'matchOrders', { limit: 50 });
232
+ await streamer.registerAction(matchAction);
233
+ ```
234
+
235
+ The action must have `trigger: 'time'` in its definition.
236
+
237
+ ---
238
+
239
+ ## Adapter Requirements
240
+
241
+ Contracts can use any adapter, but some require SQL features:
242
+
243
+ - **SQL adapters** (SQLite/Postgres) support `adapter.query(...)`.
244
+ - **MongoDB adapter** does not support raw SQL.
245
+
246
+ If a contract uses `adapter.query`, it must document that it requires a SQL adapter.
247
+
248
+ ---
249
+
250
+ ## Building Contracts Step-by-Step
251
+
252
+ 1. **Define the contract** with `defineContract`.
253
+ 2. **Define actions** with `action`, specifying trigger and optional schema.
254
+ 3. **Use hooks** (`create`, `destroy`) to initialize tables or cache configuration.
255
+ 4. **Validate input** using Zod.
256
+ 5. **Use `ctx`** for block/transaction context.
257
+ 6. **Return void** (actions are fire-and-forget).
258
+ 7. **Register the contract** with the streamer.
259
+
260
+ ---
261
+
262
+ ## Example Contract
263
+
264
+ ```ts
265
+ import { defineContract, action } from 'hive-stream';
266
+ import { z } from 'zod';
267
+
268
+ const tipSchema = z.object({
269
+ message: z.string().max(280).optional()
270
+ });
271
+
272
+ export const TipJar = defineContract({
273
+ name: 'tipjar',
274
+ actions: {
275
+ tip: action(async (payload, ctx) => {
276
+ if (!ctx.transfer) {
277
+ throw new Error('Transfer context required');
278
+ }
279
+
280
+ console.log(`Tip from ${ctx.sender}: ${ctx.transfer.amount} ${ctx.transfer.asset}`);
281
+ if (payload.message) {
282
+ console.log(`Message: ${payload.message}`);
283
+ }
284
+ }, {
285
+ schema: tipSchema,
286
+ trigger: 'transfer'
287
+ })
288
+ }
289
+ });
290
+ ```
291
+
292
+ ---
293
+
294
+ ## Built-in Contract Examples
295
+
296
+ - `createDiceContract` - Dice game using transfer bets
297
+ - `createCoinflipContract` - Coin flip game using transfer bets
298
+ - `createLottoContract` - Lottery system with scheduled draws
299
+ - `createTokenContract` - SQL-backed fungible tokens
300
+ - `createNFTContract` - SQL-backed NFTs
301
+ - `createRpsContract` - Rock/Paper/Scissors
302
+ - `createPollContract` - Polls and votes
303
+ - `createTipJarContract` - Tip jar + message log
304
+ - `createExchangeContract` - Deposits/withdrawals/orders/matching (SQL)
305
+
306
+ ### Example Snippets
307
+
308
+ Quick-start snippets live in `examples/contracts/`:
309
+
310
+ - `examples/contracts/rps.ts`
311
+ - `examples/contracts/poll.ts`
312
+ - `examples/contracts/tipjar.ts`
313
+ - `examples/contracts/exchange.ts`
314
+
315
+ ---
316
+
317
+ ## Exchange Contract Guide
318
+
319
+ The exchange contract gives you a basic on-chain orderbook experience backed by a SQL adapter.
320
+
321
+ ### Features
322
+ - Deposits via transfer memo
323
+ - Internal balances (available + locked)
324
+ - Order placement and cancellation
325
+ - Order matching
326
+ - Withdrawals (active key required)
327
+ - Internal transfers between exchange users
328
+ - Maker/taker fees (basis points)
329
+ - Order book snapshots for API consumption
330
+
331
+ ### Notes
332
+ - Requires a SQL adapter (SQLite or Postgres).
333
+ - Uses `TimeAction` to run `matchOrders` periodically.
334
+ - Fees are charged on received assets (base for buyers, quote for sellers).
335
+
336
+ ### Configuration Options
337
+ ```
338
+ createExchangeContract({
339
+ name: 'exchange',
340
+ account: 'my-exchange',
341
+ feeAccount: 'my-exchange-fees',
342
+ makerFeeBps: 10,
343
+ takerFeeBps: 20
344
+ })
345
+ ```
346
+
347
+ ### Example Payloads
348
+
349
+ **Create pair**
350
+ ```
351
+ {"hive_stream": {"contract":"exchange","action":"createPair","payload":{"base":"HIVE","quote":"HBD"}}}
352
+ ```
353
+
354
+ **Deposit** (send transfer to exchange account with memo)
355
+ ```
356
+ {"hive_stream": {"contract":"exchange","action":"deposit","payload":{}}}
357
+ ```
358
+
359
+ **Place order**
360
+ ```
361
+ {"hive_stream": {"contract":"exchange","action":"placeOrder","payload":{"side":"buy","base":"HIVE","quote":"HBD","price":"2","amount":"5"}}}
362
+ ```
363
+
364
+ **Cancel order**
365
+ ```
366
+ {"hive_stream": {"contract":"exchange","action":"cancelOrder","payload":{"orderId":"..."}}}
367
+ ```
368
+
369
+ **Snapshot orderbook**
370
+ ```
371
+ {"hive_stream": {"contract":"exchange","action":"snapshotOrderBook","payload":{"base":"HIVE","quote":"HBD","depth":20}}}
372
+ ```
373
+
374
+ **Withdraw**
375
+ ```
376
+ {"hive_stream": {"contract":"exchange","action":"withdraw","payload":{"asset":"HBD","amount":"5.000"}}}
377
+ ```
378
+
379
+ ### API Endpoints
380
+
381
+ If you run the built-in API server, the following endpoints are available:
382
+
383
+ - `GET /exchange/balances` (optional query `?account=alice`)
384
+ - `GET /exchange/orders` (query `account`, `base`, `quote`, `status`)
385
+ - `GET /exchange/trades` (query `account`, `base`, `quote`)
386
+ - `GET /exchange/orderbook` (query `base`, `quote`, `limit`)
387
+
388
+ ---
389
+
390
+ ## Utilities
391
+ The library includes helpers for JSON parsing, randomness, and transfer verification. See `src/utils.ts` for details.
392
+
393
+ ---
394
+
395
+ ## Tests
396
+ Contract tests live under `tests/contracts/`. Time action tests are in `tests/streamer-actions.spec.ts`.