mixin_bot 2.0.0 → 2.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.
- checksums.yaml +4 -4
- data/AGENTS.md +2 -2
- data/API_COVERAGE.md +80 -3
- data/CHANGELOG.md +15 -11
- data/README.md +6 -6
- data/docs/agent/cli.md +5 -1
- data/lib/mixin_bot/api/app.rb +105 -0
- data/lib/mixin_bot/api/auth.rb +11 -0
- data/lib/mixin_bot/api/circle.rb +57 -0
- data/lib/mixin_bot/api/code.rb +5 -0
- data/lib/mixin_bot/api/conversation.rb +26 -9
- data/lib/mixin_bot/api/deposit.rb +9 -2
- data/lib/mixin_bot/api/external.rb +12 -0
- data/lib/mixin_bot/api/me.rb +21 -0
- data/lib/mixin_bot/api/message.rb +48 -1
- data/lib/mixin_bot/api/user.rb +12 -3
- data/lib/mixin_bot/api/withdraw.rb +5 -0
- data/lib/mixin_bot/api.rb +4 -0
- data/lib/mixin_bot/cli/call.rb +10 -0
- data/lib/mixin_bot/cli/errors.rb +3 -0
- data/lib/mixin_bot/errors.rb +20 -0
- data/lib/mixin_bot/version.rb +1 -1
- data/llms.txt +4 -3
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2bbc251caedc50e5324a90713c291cf019b2bf0fa003a7ad4df3401af5b175fa
|
|
4
|
+
data.tar.gz: cb7e858d5073bb2fc8bd5e487027fc10a684b8ff05dbc2949aa48270808e1f0a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 758781312e8be1e922eee338ed4ddfd3154c44ea25fb1d7e2b67d9e3ea8298381e4cc4d6df33904c35b831545d136da14c4af1630fdabe7789d3761a1617d6d9
|
|
7
|
+
data.tar.gz: a5350e9812115ef75e39a906e6fb48aa55189692887ee037c0dc3f29cf67b00e70b912575fbe5b9d1f44d93be29c520c2a3142804671c1bcfd3bc96dcfee6b9a
|
data/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# AGENTS.md — MixinBot
|
|
2
2
|
|
|
3
|
-
Ruby gem (v2.
|
|
3
|
+
Ruby gem (v2.2.0): Mixin Network REST SDK + `mixinbot` CLI. Parity targets: [bot-api-go-client](https://github.com/MixinNetwork/bot-api-go-client), [bot-api-nodejs-client](https://github.com/MixinNetwork/bot-api-nodejs-client).
|
|
4
4
|
|
|
5
5
|
## Commands
|
|
6
6
|
|
|
@@ -35,7 +35,7 @@ docs/agent/ # LLM-oriented CLI and cookbook docs
|
|
|
35
35
|
## CI and release
|
|
36
36
|
|
|
37
37
|
- **CI** (`.github/workflows/ci.yml`): `pull_request` and `push` to `main` — `rake test` on Ruby 3.2/3.3/4.0, `rake rubocop` (3.3), `rake mixin_bot:api_coverage`.
|
|
38
|
-
- **Release** (`.github/workflows/release.yml`): push tag `v*` (must match `MixinBot::VERSION`, e.g. tag `v2.
|
|
38
|
+
- **Release** (`.github/workflows/release.yml`): push tag `v*` (must match `MixinBot::VERSION`, e.g. tag `v2.1.0` for `VERSION = '2.1.0'`) → `rake build` → RubyGems via [trusted publishing](https://guides.rubygems.org/trusted-publishing/) (OIDC; workflow `release.yml`, no repo secret) → GitHub Release (notes from `CHANGELOG.md`, `.gem` attached).
|
|
39
39
|
- **Dependabot** (`.github/dependabot.yml`): weekly Bundler and GitHub Actions updates; Dependabot PRs use the same CI workflow.
|
|
40
40
|
|
|
41
41
|
## Conventions
|
data/API_COVERAGE.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
# Mixin
|
|
1
|
+
# Mixin SDK API Coverage
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Go reference: [bot-api-go-client](https://github.com/MixinNetwork/bot-api-go-client) (`package bot`).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Node reference: [bot-api-nodejs-client](https://github.com/MixinNetwork/bot-api-nodejs-client) (`@mixin.dev/mixin-node-sdk`).
|
|
6
|
+
|
|
7
|
+
Status values: `done` | `alias` | `n/a` (CLI-only / config / platform-specific)
|
|
6
8
|
|
|
7
9
|
| Go symbol | Ruby method | HTTP / notes | Status |
|
|
8
10
|
|-----------|-------------|--------------|--------|
|
|
@@ -140,4 +142,79 @@ Status values: `done` | `alias` | `n/a` (CLI-only / config)
|
|
|
140
142
|
| NewSafeUser | `MixinBot::Configuration` | config | n/a |
|
|
141
143
|
| cli/*, examples/*, mixin/rpc main | `mixinbot call` / `mixinbot list` | CLI dispatch to `MixinBot::API` | done |
|
|
142
144
|
|
|
145
|
+
## Node SDK
|
|
146
|
+
|
|
147
|
+
TS-only or Node-first REST surfaces. Ruby methods follow snake_case; aliases mirror TS names where helpful.
|
|
148
|
+
|
|
149
|
+
| TS symbol | Ruby method | HTTP / notes | Status |
|
|
150
|
+
|-----------|-------------|--------------|--------|
|
|
151
|
+
| **Circle** |
|
|
152
|
+
| circle.fetch | `API#circle` | GET `/circles/:id` | done |
|
|
153
|
+
| circle.fetchList | `API#circles` | GET `/circles` | done |
|
|
154
|
+
| circle.conversations | `API#circle_conversations` | GET `/circles/:id/conversations` | done |
|
|
155
|
+
| circle.create | `API#create_circle` | POST `/circles` | done |
|
|
156
|
+
| circle.update | `API#update_circle` | POST `/circles/:id` | done |
|
|
157
|
+
| circle.delete | `API#delete_circle` | POST `/circles/:id/delete` | done |
|
|
158
|
+
| circle.addUser | `API#add_user_to_circle` | POST `/users/:id/circles` | done |
|
|
159
|
+
| circle.removeUser | `API#remove_user_from_circle` | POST `/users/:id/circles` | done |
|
|
160
|
+
| circle.addConversation | `API#add_conversation_to_circle` | POST `/conversations/:id/circles` | done |
|
|
161
|
+
| circle.removeConversation | `API#remove_conversation_from_circle` | POST `/conversations/:id/circles` | done |
|
|
162
|
+
| **App** |
|
|
163
|
+
| app.fetch | `API#app` | GET `/apps/:id` | done |
|
|
164
|
+
| app.fetchList | `API#apps` | GET `/apps` | done |
|
|
165
|
+
| app.properties | `API#app_properties` | GET `/apps/property` | done |
|
|
166
|
+
| app.billing | `API#app_billing` | GET `/safe/apps/:id/billing` | done |
|
|
167
|
+
| app.create | `API#create_app` | POST `/apps` | done |
|
|
168
|
+
| app.update | `API#update_app` | POST `/apps/:id` | done |
|
|
169
|
+
| app.updateSecret | `API#rotate_app_secret` | POST `/apps/:id/secret` | done |
|
|
170
|
+
| app.updateSafeSession | `API#update_app_safe_session` | POST `/safe/apps/:id/session` | done |
|
|
171
|
+
| app.registerSafe | `API#register_app_safe` | POST `/safe/apps/:id/register` | done |
|
|
172
|
+
| app.favorite / unfavorite | `API#add_favorite_app` / `#remove_favorite_app` | POST `/apps/:id/favorite` | done |
|
|
173
|
+
| app.favorites | `API#favorite_apps` | GET `/users/:id/apps/favorite` | done |
|
|
174
|
+
| app.migrate | `API#transfer_app_ownership` | POST `/apps/:id/transfer` | done |
|
|
175
|
+
| **OAuth** |
|
|
176
|
+
| oauth.getToken | `API#oauth_token` | POST `/oauth/token` | done |
|
|
177
|
+
| oauth.authorize | `API#authorize_code` | POST `/oauth/authorize` | done |
|
|
178
|
+
| oauth.authorizations | `API#authorizations` | GET `/authorizations` | done |
|
|
179
|
+
| oauth.revokeAuthorize | `API#revoke_authorization` | POST `/oauth/cancel` | done |
|
|
180
|
+
| **User** |
|
|
181
|
+
| user.profile | `API#me` | GET `/me` | done |
|
|
182
|
+
| user.friends | `API#friends` | GET `/friends` | done |
|
|
183
|
+
| user.blockings | `API#blocking_users` | GET `/blocking_users` | done |
|
|
184
|
+
| user.rotateCode | `API#rotate_user_code` | GET `/me/code` | done |
|
|
185
|
+
| user.search | `API#search_user` | GET `/search/:q` | done |
|
|
186
|
+
| user.fetch | `API#user` | GET `/users/:id` | done |
|
|
187
|
+
| user.fetchList | `API#fetch_users` | POST `/users/fetch` | done |
|
|
188
|
+
| user.createBareUser | `API#create_user` | POST `/users` | done |
|
|
189
|
+
| user.update | `API#update_me` | POST `/me` | done |
|
|
190
|
+
| user.updatePreferences | `API#update_preferences` | POST `/me/preferences` | done |
|
|
191
|
+
| user.updateRelationships | `API#relationship` | POST `/relationships` | done |
|
|
192
|
+
| user.logs | `API#user_logs` | GET `/logs` | done |
|
|
193
|
+
| **Conversation** |
|
|
194
|
+
| conversation.mute / unmute | `API#mute_conversation` / `#unmute_conversation` | POST `/conversations/:id/mute` | done |
|
|
195
|
+
| conversation.disappearDuration | `API#set_conversation_disappear_duration` | POST `/conversations/:id/disappear` | done |
|
|
196
|
+
| conversation.updateGroupInfo | `API#update_conversation` | POST `/conversations/:id` | done |
|
|
197
|
+
| conversation.* (CRUD/participants) | `API#conversation`, `#create_*`, `#join_*`, etc. | various | done |
|
|
198
|
+
| **Message** |
|
|
199
|
+
| message.sendAcknowledgement(s) | `API#acknowledge_message` / `#acknowledge_messages` | POST `/acknowledgements` | done |
|
|
200
|
+
| message.sendSticker/Audio/Video/Live/Location/Transfer | `API#send_*_message` | POST `/messages` | done |
|
|
201
|
+
| message.sendText/Image/File/Post/Contact/AppCard/AppButton/Recall | `API#send_*_message` | POST `/messages` | done |
|
|
202
|
+
| **Code** |
|
|
203
|
+
| code.fetch | `API#read_code` | GET `/codes/:id` | done |
|
|
204
|
+
| code.schemes | `API#create_scheme` | POST `/schemes` | done |
|
|
205
|
+
| **Address** |
|
|
206
|
+
| address.fetchListOfChain | `API#safe_withdraw_addresses` | GET `/safe/addresses?chain=` | done |
|
|
207
|
+
| address.fetch/create/delete | `API#get_withdraw_address`, `#create_withdraw_address`, `#delete_withdraw_address` | `/addresses` | done |
|
|
208
|
+
| **External** |
|
|
209
|
+
| external.proxy | `API#external_proxy` | POST `/external/proxy` | done |
|
|
210
|
+
| external.deposits | `API#transactions` (legacy) | GET `/external/transactions` | done |
|
|
211
|
+
| external.checkAddress | `API#check_address` | GET `/external/addresses/check` | done |
|
|
212
|
+
| external.exchangeRates | `API#fiats` | GET `/external/fiats` | done |
|
|
213
|
+
| **Safe / UTXO / Transfer / Network / etc.** |
|
|
214
|
+
| safe.* / utxo.* / transfer.* / network.* | spread across existing `API` modules | same HTTP paths as TS | done |
|
|
215
|
+
| **Blaze** |
|
|
216
|
+
| blaze.loop | `API#blaze` | WebSocket | done |
|
|
217
|
+
| **WebView** |
|
|
218
|
+
| WebViewApi | — | browser bridge | n/a |
|
|
219
|
+
|
|
143
220
|
Update this file when adding or changing API surfaces. Run `rake mixin_bot:api_coverage` to ensure no `missing` rows remain.
|
data/CHANGELOG.md
CHANGED
|
@@ -7,26 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.2.0] - 2026-05-24
|
|
11
|
+
|
|
10
12
|
### Added
|
|
11
13
|
|
|
12
|
-
- **`
|
|
13
|
-
- **`
|
|
14
|
+
- **`MixinBot::API#create_user` billing preflight** — verifies app billing headroom (`credit > cost + next user fee`) via `app_billing` and `app_properties` before `POST /users`. Raises `InsufficientAppBillingError` by default; pass `force: true` to skip. `create_safe_user` forwards `force:` to `create_user`.
|
|
15
|
+
- **`MixinBot::InsufficientAppBillingError`** — structured fields: `app_id`, `credit`, `cost`, `increment`.
|
|
16
|
+
- **CLI** — `mixinbot call create_user ... --force` skips billing preflight; billing failures map to structured error kind `billing`.
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## [2.1.0] - 2026-05-24
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
- **`mixinbot api`** — routes through `MixinBot::Client` (supports JSON array POST bodies); keystore loading includes `spend_key` and `client_secret`.
|
|
19
|
-
- **`mixinbot updatetip`** — uses `update_tip_pin` instead of misusing `update_pin`.
|
|
20
|
-
- **`mixinbot safetransfer`** — delegates to `transfer` (no duplicated signing pipeline).
|
|
20
|
+
### Added
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
- **Node SDK REST parity** with [bot-api-nodejs-client](https://github.com/MixinNetwork/bot-api-nodejs-client): Circle API (`API::Circle`), `external_proxy`, extended App CRUD/Safe registration, OAuth `authorizations` / `revoke_authorization`, user `blocking_users` / `rotate_user_code` / `user_logs`, conversation mute/disappear, HTTP message acknowledgements and additional send helpers, `create_scheme`, `safe_withdraw_addresses`, and query params on `pending_safe_deposits`.
|
|
23
|
+
- **API_COVERAGE.md** Node SDK section mapping TS symbols to Ruby methods.
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
- **`mixinbot safetransfer`** — use `transfer` instead.
|
|
25
|
+
## [2.0.1] - 2026-05-24
|
|
26
26
|
|
|
27
27
|
### Fixed
|
|
28
28
|
|
|
29
|
-
- **`
|
|
29
|
+
- **`StringIO.new`** — use keyword `contents:` for Ruby 4 compatibility (`lib/mixin_bot/api/message.rb`).
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- Release workflow creates a GitHub Release with notes from `CHANGELOG.md` when publishing version tags.
|
|
30
34
|
|
|
31
35
|
## [2.0.0] - 2026-05-16
|
|
32
36
|
|
data/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Ruby SDK and CLI for [Mixin Network](https://developers.mixin.one/docs): authenticated REST calls, **Safe** UTXO transfers, Blaze messaging, network asset catalog, inscriptions, invoices and mix addresses, transaction encoding, and optional **MVM** (Mixin Virtual Machine) helpers.
|
|
6
6
|
|
|
7
|
-
The gem aims for **parity with the official [bot-api-go-client](https://github.com/MixinNetwork/bot-api-go-client)** Go SDK. See [API_COVERAGE.md](API_COVERAGE.md) for the full mapping; run `rake mixin_bot:api_coverage` to confirm no gaps are marked missing.
|
|
7
|
+
The gem aims for **parity with the official [bot-api-go-client](https://github.com/MixinNetwork/bot-api-go-client)** Go SDK and **[bot-api-nodejs-client](https://github.com/MixinNetwork/bot-api-nodejs-client)** Node SDK. See [API_COVERAGE.md](API_COVERAGE.md) for the full mapping; run `rake mixin_bot:api_coverage` to confirm no gaps are marked missing.
|
|
8
8
|
|
|
9
|
-
Current gem version: **2.
|
|
9
|
+
Current gem version: **2.2.0** (see [CHANGELOG.md](CHANGELOG.md) for breaking changes and deprecations).
|
|
10
10
|
|
|
11
11
|
## Requirements
|
|
12
12
|
|
|
@@ -353,14 +353,14 @@ Publishing to [RubyGems.org](https://rubygems.org/gems/mixin_bot) is automated w
|
|
|
353
353
|
|
|
354
354
|
1. Bump `MixinBot::VERSION` in `lib/mixin_bot/version.rb` and update `CHANGELOG.md`.
|
|
355
355
|
2. Commit and push to `main`.
|
|
356
|
-
3. Create and push a tag matching the gem version (e.g. `v2.0
|
|
356
|
+
3. Create and push a tag matching the gem version (e.g. `v2.1.0` for version `2.1.0`):
|
|
357
357
|
|
|
358
358
|
```bash
|
|
359
|
-
git tag v2.0
|
|
360
|
-
git push origin v2.0
|
|
359
|
+
git tag v2.1.0
|
|
360
|
+
git push origin v2.1.0
|
|
361
361
|
```
|
|
362
362
|
|
|
363
|
-
The [Release workflow](.github/workflows/release.yml) builds the gem
|
|
363
|
+
The [Release workflow](.github/workflows/release.yml) builds the gem, publishes to RubyGems.org via [trusted publishing](https://guides.rubygems.org/trusted-publishing/) (GitHub OIDC; trusted publisher for workflow `release.yml` on `an-lee/mixin_bot`), and creates a GitHub Release with notes from `CHANGELOG.md` and the `.gem` attached. To build without publishing, run the Release workflow manually with **dry run** enabled.
|
|
364
364
|
|
|
365
365
|
## References
|
|
366
366
|
|
data/docs/agent/cli.md
CHANGED
|
@@ -72,7 +72,7 @@ Error (stderr, exit 1):
|
|
|
72
72
|
}
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
Error kinds: `invalid_args`, `auth`, `not_found`, `api_error`, `unsupported`, `conflict`, `internal`.
|
|
75
|
+
Error kinds: `invalid_args`, `auth`, `not_found`, `api_error`, `billing`, `unsupported`, `conflict`, `internal`.
|
|
76
76
|
|
|
77
77
|
## Commands
|
|
78
78
|
|
|
@@ -106,8 +106,12 @@ List JSON shape:
|
|
|
106
106
|
mixinbot call me -k keystore.json -o json
|
|
107
107
|
mixinbot call safe_outputs -k keystore.json -d '{"asset":"965e5c6e-434c-3fa9-b780-c50f43cd955c","state":"unspent","limit":10}' -o json
|
|
108
108
|
mixinbot call user USER_UUID -k keystore.json --data-only -o json
|
|
109
|
+
mixinbot call create_user "Bot User" -k keystore.json -o json
|
|
110
|
+
mixinbot call create_user "Bot User" -k keystore.json --force -o json
|
|
109
111
|
```
|
|
110
112
|
|
|
113
|
+
`create_user` performs a client-side app billing preflight by default. When credit lacks headroom for the next billed user, the CLI returns `"kind": "billing"`. Use `--force` to skip the preflight (or pass `"force": true` in `-d`; `-d` wins when both are set).
|
|
114
|
+
|
|
111
115
|
### Raw HTTP
|
|
112
116
|
|
|
113
117
|
```bash
|
data/lib/mixin_bot/api/app.rb
CHANGED
|
@@ -3,17 +3,116 @@
|
|
|
3
3
|
module MixinBot
|
|
4
4
|
class API
|
|
5
5
|
module App
|
|
6
|
+
def app(app_id, access_token: nil)
|
|
7
|
+
path = format('/apps/%<id>s', id: app_id)
|
|
8
|
+
client.get path, access_token:
|
|
9
|
+
end
|
|
10
|
+
alias fetch_app app
|
|
11
|
+
|
|
12
|
+
def apps(access_token: nil)
|
|
13
|
+
client.get '/apps', access_token:
|
|
14
|
+
end
|
|
15
|
+
alias fetch_apps apps
|
|
16
|
+
|
|
17
|
+
def app_properties(access_token: nil)
|
|
18
|
+
client.get '/apps/property', access_token:
|
|
19
|
+
end
|
|
20
|
+
alias app_property app_properties
|
|
21
|
+
|
|
22
|
+
def app_billing(app_id, access_token: nil)
|
|
23
|
+
path = format('/safe/apps/%<id>s/billing', id: app_id)
|
|
24
|
+
client.get path, access_token:
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Verifies the app has billing headroom before a billed operation (e.g.
|
|
29
|
+
# creating a network user). Skipped when +force+ is true.
|
|
30
|
+
#
|
|
31
|
+
# @param force [Boolean] skip the preflight and call the API anyway
|
|
32
|
+
# @raise [InsufficientAppBillingError] when +credit+ is not greater than
|
|
33
|
+
# total cost plus the next user fee from {app_properties}
|
|
34
|
+
#
|
|
35
|
+
def ensure_app_billing_credit!(force: false, access_token: nil)
|
|
36
|
+
return if force
|
|
37
|
+
|
|
38
|
+
app_id = config.app_id
|
|
39
|
+
billing = app_billing(app_id, access_token:)['data']
|
|
40
|
+
properties = app_properties(access_token:)['data']
|
|
41
|
+
|
|
42
|
+
credit = billing_decimal billing['credit']
|
|
43
|
+
cost_users = billing_decimal billing.dig('cost', 'users')
|
|
44
|
+
cost_resources = billing_decimal billing.dig('cost', 'resources')
|
|
45
|
+
cost = cost_users + cost_resources
|
|
46
|
+
increment = billing_decimal properties['price']
|
|
47
|
+
|
|
48
|
+
return if credit > cost + increment
|
|
49
|
+
|
|
50
|
+
raise InsufficientAppBillingError.new(
|
|
51
|
+
app_id:,
|
|
52
|
+
credit: credit.to_s('F'),
|
|
53
|
+
cost: cost.to_s('F'),
|
|
54
|
+
increment: increment.to_s('F')
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create_app(**kwargs)
|
|
59
|
+
payload = {
|
|
60
|
+
redirect_uri: kwargs[:redirect_uri],
|
|
61
|
+
home_uri: kwargs[:home_uri],
|
|
62
|
+
name: kwargs[:name],
|
|
63
|
+
description: kwargs[:description],
|
|
64
|
+
icon_base64: kwargs[:icon_base64],
|
|
65
|
+
category: kwargs[:category],
|
|
66
|
+
capabilities: kwargs[:capabilities],
|
|
67
|
+
resource_patterns: kwargs[:resource_patterns]
|
|
68
|
+
}.compact
|
|
69
|
+
client.post '/apps', **payload, access_token: kwargs[:access_token]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def update_app(app_id, **kwargs)
|
|
73
|
+
path = format('/apps/%<id>s', id: app_id)
|
|
74
|
+
payload = {
|
|
75
|
+
redirect_uri: kwargs[:redirect_uri],
|
|
76
|
+
home_uri: kwargs[:home_uri],
|
|
77
|
+
name: kwargs[:name],
|
|
78
|
+
description: kwargs[:description],
|
|
79
|
+
icon_base64: kwargs[:icon_base64],
|
|
80
|
+
category: kwargs[:category],
|
|
81
|
+
capabilities: kwargs[:capabilities],
|
|
82
|
+
resource_patterns: kwargs[:resource_patterns]
|
|
83
|
+
}.compact
|
|
84
|
+
client.post path, **payload, access_token: kwargs[:access_token]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def rotate_app_secret(app_id, access_token: nil)
|
|
88
|
+
path = format('/apps/%<id>s/secret', id: app_id)
|
|
89
|
+
client.post path, access_token:
|
|
90
|
+
end
|
|
91
|
+
alias update_app_secret rotate_app_secret
|
|
92
|
+
|
|
93
|
+
def update_app_safe_session(app_id, session_public_key:, access_token: nil)
|
|
94
|
+
path = format('/safe/apps/%<id>s/session', id: app_id)
|
|
95
|
+
client.post path, session_public_key:, access_token:
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def register_app_safe(app_id, spend_public_key:, signature_base64:, access_token: nil)
|
|
99
|
+
path = format('/safe/apps/%<id>s/register', id: app_id)
|
|
100
|
+
client.post path, spend_public_key:, signature_base64:, access_token:
|
|
101
|
+
end
|
|
102
|
+
|
|
6
103
|
def add_favorite_app(app_id, access_token: nil)
|
|
7
104
|
path = format('/apps/%<id>s/favorite', id: app_id)
|
|
8
105
|
|
|
9
106
|
client.post path, access_token:
|
|
10
107
|
end
|
|
108
|
+
alias favorite_app add_favorite_app
|
|
11
109
|
|
|
12
110
|
def remove_favorite_app(app_id, access_token: nil)
|
|
13
111
|
path = format('/apps/%<id>s/unfavorite', id: app_id)
|
|
14
112
|
|
|
15
113
|
client.post path, access_token:
|
|
16
114
|
end
|
|
115
|
+
alias unfavorite_app remove_favorite_app
|
|
17
116
|
|
|
18
117
|
def favorite_apps(user_id = nil, access_token: nil)
|
|
19
118
|
path = format('/users/%<id>s/apps/favorite', id: user_id || config.app_id)
|
|
@@ -27,6 +126,12 @@ module MixinBot
|
|
|
27
126
|
client.post path, user_id: receiver_user_id, pin_base64: tip[:pin_base64] || tip[:pin], access_token:
|
|
28
127
|
end
|
|
29
128
|
alias migrate transfer_app_ownership
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def billing_decimal(value)
|
|
133
|
+
BigDecimal(value.to_s)
|
|
134
|
+
end
|
|
30
135
|
end
|
|
31
136
|
end
|
|
32
137
|
end
|
data/lib/mixin_bot/api/auth.rb
CHANGED
|
@@ -56,6 +56,17 @@ module MixinBot
|
|
|
56
56
|
client.post path, **payload, access_token: kwargs[:access_token]
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
+
def authorizations(app_id: nil, access_token: nil)
|
|
60
|
+
params = {}
|
|
61
|
+
params[:app] = app_id if app_id
|
|
62
|
+
client.get '/authorizations', **params, access_token:
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def revoke_authorization(client_id, access_token: nil)
|
|
66
|
+
client.post '/oauth/cancel', client_id:, access_token:
|
|
67
|
+
end
|
|
68
|
+
alias revoke_authorize revoke_authorization
|
|
69
|
+
|
|
59
70
|
def authorization_data(app_id, scope = ['PROFILE:READ'])
|
|
60
71
|
@_app_id = app_id
|
|
61
72
|
@_scope = scope.join(' ')
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MixinBot
|
|
4
|
+
class API
|
|
5
|
+
module Circle
|
|
6
|
+
def circle(circle_id, access_token: nil)
|
|
7
|
+
path = format('/circles/%<circle_id>s', circle_id:)
|
|
8
|
+
client.get path, access_token:
|
|
9
|
+
end
|
|
10
|
+
alias fetch_circle circle
|
|
11
|
+
|
|
12
|
+
def circles(access_token: nil)
|
|
13
|
+
client.get '/circles', access_token:
|
|
14
|
+
end
|
|
15
|
+
alias fetch_circles circles
|
|
16
|
+
|
|
17
|
+
def circle_conversations(circle_id, **params)
|
|
18
|
+
path = format('/circles/%<circle_id>s/conversations', circle_id:)
|
|
19
|
+
client.get path, **params.compact, access_token: params[:access_token]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create_circle(name:, access_token: nil)
|
|
23
|
+
client.post '/circles', name:, access_token:
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def update_circle(circle_id, name:, access_token: nil)
|
|
27
|
+
path = format('/circles/%<circle_id>s', circle_id:)
|
|
28
|
+
client.post path, name:, access_token:
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def delete_circle(circle_id, access_token: nil)
|
|
32
|
+
path = format('/circles/%<circle_id>s/delete', circle_id:)
|
|
33
|
+
client.post path, access_token:
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def add_user_to_circle(user_id:, circle_id:, access_token: nil)
|
|
37
|
+
path = format('/users/%<user_id>s/circles', user_id:)
|
|
38
|
+
client.post path, circle_id:, action: 'ADD', access_token:
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def remove_user_from_circle(user_id:, circle_id:, access_token: nil)
|
|
42
|
+
path = format('/users/%<user_id>s/circles', user_id:)
|
|
43
|
+
client.post path, circle_id:, action: 'REMOVE', access_token:
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def add_conversation_to_circle(conversation_id:, circle_id:, access_token: nil)
|
|
47
|
+
path = format('/conversations/%<conversation_id>s/circles', conversation_id:)
|
|
48
|
+
client.post path, circle_id:, action: 'ADD', access_token:
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def remove_conversation_from_circle(conversation_id:, circle_id:, access_token: nil)
|
|
52
|
+
path = format('/conversations/%<conversation_id>s/circles', conversation_id:)
|
|
53
|
+
client.post path, circle_id:, action: 'REMOVE', access_token:
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
data/lib/mixin_bot/api/code.rb
CHANGED
|
@@ -11,6 +11,11 @@ module MixinBot
|
|
|
11
11
|
def read_multisig_by_code(code_id, access_token: nil)
|
|
12
12
|
read_code(code_id, access_token:)
|
|
13
13
|
end
|
|
14
|
+
|
|
15
|
+
def create_scheme(target, access_token: nil)
|
|
16
|
+
client.post '/schemes', target:, access_token:
|
|
17
|
+
end
|
|
18
|
+
alias schemes create_scheme
|
|
14
19
|
end
|
|
15
20
|
end
|
|
16
21
|
end
|
|
@@ -55,23 +55,40 @@ module MixinBot
|
|
|
55
55
|
)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
def
|
|
58
|
+
def update_conversation(conversation_id:, **kwargs)
|
|
59
59
|
path = format('/conversations/%<id>s', id: conversation_id)
|
|
60
60
|
payload = {
|
|
61
|
-
name:
|
|
62
|
-
|
|
61
|
+
name: kwargs[:name],
|
|
62
|
+
announcement: kwargs[:announcement]
|
|
63
|
+
}.compact
|
|
64
|
+
client.post path, **payload, access_token: kwargs[:access_token]
|
|
65
|
+
end
|
|
66
|
+
alias update_group_info update_conversation
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
def update_group_conversation_name(name:, conversation_id:, access_token: nil)
|
|
69
|
+
update_conversation(conversation_id:, name:, access_token:)
|
|
65
70
|
end
|
|
66
71
|
|
|
67
72
|
def update_group_conversation_announcement(announcement:, conversation_id:, access_token: nil)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
update_conversation(conversation_id:, announcement:, access_token:)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def mute_conversation(conversation_id, duration:, access_token: nil)
|
|
77
|
+
path = format('/conversations/%<id>s/mute', id: conversation_id)
|
|
78
|
+
client.post path, duration:, access_token:
|
|
79
|
+
end
|
|
80
|
+
alias mute mute_conversation
|
|
81
|
+
|
|
82
|
+
def unmute_conversation(conversation_id, access_token: nil)
|
|
83
|
+
mute_conversation conversation_id, duration: 0, access_token:
|
|
84
|
+
end
|
|
85
|
+
alias unmute unmute_conversation
|
|
72
86
|
|
|
73
|
-
|
|
87
|
+
def set_conversation_disappear_duration(conversation_id, duration:, access_token: nil)
|
|
88
|
+
path = format('/conversations/%<id>s/disappear', id: conversation_id)
|
|
89
|
+
client.post path, duration:, access_token:
|
|
74
90
|
end
|
|
91
|
+
alias disappear_duration set_conversation_disappear_duration
|
|
75
92
|
|
|
76
93
|
# participants = [{ user_id: "" }]
|
|
77
94
|
def add_conversation_participants(conversation_id:, user_ids:, access_token: nil)
|
|
@@ -3,8 +3,15 @@
|
|
|
3
3
|
module MixinBot
|
|
4
4
|
class API
|
|
5
5
|
module Deposit
|
|
6
|
-
def pending_safe_deposits
|
|
7
|
-
|
|
6
|
+
def pending_safe_deposits(**params)
|
|
7
|
+
query = {
|
|
8
|
+
limit: params[:limit],
|
|
9
|
+
offset: params[:offset],
|
|
10
|
+
asset: params[:asset],
|
|
11
|
+
destination: params[:destination],
|
|
12
|
+
tag: params[:tag]
|
|
13
|
+
}.compact
|
|
14
|
+
client.get '/safe/deposits', **query, access_token: params[:access_token] || ''
|
|
8
15
|
end
|
|
9
16
|
alias fetch_pending_safe_deposits pending_safe_deposits
|
|
10
17
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MixinBot
|
|
4
|
+
class API
|
|
5
|
+
module External
|
|
6
|
+
def external_proxy(method:, params: [], access_token: nil)
|
|
7
|
+
client.post '/external/proxy', method:, params:, access_token:
|
|
8
|
+
end
|
|
9
|
+
alias proxy external_proxy
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
data/lib/mixin_bot/api/me.rb
CHANGED
|
@@ -126,6 +126,27 @@ module MixinBot
|
|
|
126
126
|
path = '/relationships'
|
|
127
127
|
client.post path, user_id:, action:, access_token:
|
|
128
128
|
end
|
|
129
|
+
alias update_relationship relationship
|
|
130
|
+
|
|
131
|
+
def blocking_users(access_token: nil)
|
|
132
|
+
client.get '/blocking_users', access_token:
|
|
133
|
+
end
|
|
134
|
+
alias blockings blocking_users
|
|
135
|
+
|
|
136
|
+
def rotate_user_code(access_token: nil)
|
|
137
|
+
client.get '/me/code', access_token:
|
|
138
|
+
end
|
|
139
|
+
alias rotate_code rotate_user_code
|
|
140
|
+
|
|
141
|
+
def user_logs(**params)
|
|
142
|
+
query = {
|
|
143
|
+
limit: params[:limit],
|
|
144
|
+
offset: params[:offset],
|
|
145
|
+
category: params[:category]
|
|
146
|
+
}.compact
|
|
147
|
+
client.get '/logs', **query, access_token: params[:access_token]
|
|
148
|
+
end
|
|
149
|
+
alias logs user_logs
|
|
129
150
|
end
|
|
130
151
|
end
|
|
131
152
|
end
|
|
@@ -48,6 +48,18 @@ module MixinBot
|
|
|
48
48
|
base_message_params(options.merge(category: 'PLAIN_VIDEO'))
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
def plain_live(options)
|
|
52
|
+
base_message_params(options.merge(category: 'PLAIN_LIVE'))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def plain_location(options)
|
|
56
|
+
base_message_params(options.merge(category: 'PLAIN_LOCATION'))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def transfer_message(options)
|
|
60
|
+
base_message_params(options.merge(category: 'SYSTEM_ACCOUNT_SNAPSHOT'))
|
|
61
|
+
end
|
|
62
|
+
|
|
51
63
|
def app_card(options)
|
|
52
64
|
base_message_params(options.merge(category: 'APP_CARD'))
|
|
53
65
|
end
|
|
@@ -105,7 +117,7 @@ module MixinBot
|
|
|
105
117
|
params:
|
|
106
118
|
}.to_json
|
|
107
119
|
|
|
108
|
-
io = StringIO.new
|
|
120
|
+
io = StringIO.new
|
|
109
121
|
gzip = Zlib::GzipWriter.new io
|
|
110
122
|
gzip.write msg
|
|
111
123
|
gzip.close
|
|
@@ -141,6 +153,30 @@ module MixinBot
|
|
|
141
153
|
send_message app_button_group(options)
|
|
142
154
|
end
|
|
143
155
|
|
|
156
|
+
def send_sticker_message(options)
|
|
157
|
+
send_message plain_sticker(options)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def send_audio_message(options)
|
|
161
|
+
send_message plain_audio(options)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def send_video_message(options)
|
|
165
|
+
send_message plain_video(options)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def send_live_message(options)
|
|
169
|
+
send_message plain_live(options)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def send_location_message(options)
|
|
173
|
+
send_message plain_location(options)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def send_transfer_message(options)
|
|
177
|
+
send_message transfer_message(options)
|
|
178
|
+
end
|
|
179
|
+
|
|
144
180
|
def recall_message(message_id, options)
|
|
145
181
|
send_message [recall_message_params(message_id, options)]
|
|
146
182
|
end
|
|
@@ -149,6 +185,17 @@ module MixinBot
|
|
|
149
185
|
send_message messages
|
|
150
186
|
end
|
|
151
187
|
|
|
188
|
+
def acknowledge_message(message_id, status: 'READ', access_token: nil)
|
|
189
|
+
payload = { message_id:, status: }
|
|
190
|
+
client.post '/acknowledgements', payload, access_token:
|
|
191
|
+
end
|
|
192
|
+
alias send_acknowledgement acknowledge_message
|
|
193
|
+
|
|
194
|
+
def acknowledge_messages(messages, access_token: nil)
|
|
195
|
+
client.post '/acknowledgements', *messages, access_token:
|
|
196
|
+
end
|
|
197
|
+
alias send_acknowledgements acknowledge_messages
|
|
198
|
+
|
|
152
199
|
# http post request
|
|
153
200
|
def send_message(payload)
|
|
154
201
|
path = '/messages'
|
data/lib/mixin_bot/api/user.rb
CHANGED
|
@@ -37,9 +37,14 @@ module MixinBot
|
|
|
37
37
|
#
|
|
38
38
|
# @param full_name [String] display name for the new user
|
|
39
39
|
# @param key [String, nil] optional 32-byte Ed25519 seed
|
|
40
|
+
# @param force [Boolean] when false (default), verify app billing credit
|
|
41
|
+
# headroom before calling the API; when true, skip the preflight
|
|
40
42
|
# @return [Hash] Mixin response merged with the hex-encoded private key
|
|
43
|
+
# @raise [InsufficientAppBillingError] when billing credit lacks headroom
|
|
41
44
|
#
|
|
42
|
-
def create_user(full_name, key: nil)
|
|
45
|
+
def create_user(full_name, key: nil, force: false)
|
|
46
|
+
ensure_app_billing_credit!(force:)
|
|
47
|
+
|
|
43
48
|
keypair = JOSE::JWA::Ed25519.keypair key
|
|
44
49
|
session_secret = Base64.urlsafe_encode64 keypair[0], padding: false
|
|
45
50
|
private_key = keypair[1].unpack1('H*')
|
|
@@ -85,19 +90,23 @@ module MixinBot
|
|
|
85
90
|
# @param name [String] display name for the new user
|
|
86
91
|
# @param private_key [String, nil] optional 32-byte session Ed25519 seed
|
|
87
92
|
# @param spend_key [String, nil] optional 32-byte spend Ed25519 seed
|
|
93
|
+
# @param force [Boolean] forwarded to {#create_user}; see billing preflight
|
|
94
|
+
# there
|
|
88
95
|
# @return [Hash] keystore with +:app_id+, +:session_id+,
|
|
89
96
|
# +:session_private_key+, +:server_public_key+ and +:spend_key+
|
|
90
97
|
# @raise [MixinBot::Error] when registration ultimately fails. Transient
|
|
91
98
|
# PIN/response errors are retried up to {SAFE_REGISTER_MAX_RETRIES}
|
|
92
99
|
# times; other errors bubble up immediately.
|
|
100
|
+
# @raise [InsufficientAppBillingError] when {#create_user} billing
|
|
101
|
+
# preflight fails
|
|
93
102
|
#
|
|
94
|
-
def create_safe_user(name, private_key: nil, spend_key: nil)
|
|
103
|
+
def create_safe_user(name, private_key: nil, spend_key: nil, force: false)
|
|
95
104
|
session_keypair = JOSE::JWA::Ed25519.keypair private_key
|
|
96
105
|
spend_keypair = JOSE::JWA::Ed25519.keypair spend_key
|
|
97
106
|
|
|
98
107
|
spend_key_hex = spend_keypair[1].unpack1('H*')
|
|
99
108
|
|
|
100
|
-
user = create_user name, key: session_keypair[1][...32]
|
|
109
|
+
user = create_user name, key: session_keypair[1][...32], force: force
|
|
101
110
|
data = user.fetch('data')
|
|
102
111
|
|
|
103
112
|
keystore = {
|
|
@@ -70,6 +70,11 @@ module MixinBot
|
|
|
70
70
|
end
|
|
71
71
|
alias get_addresses_by_asset_id withdraw_addresses
|
|
72
72
|
|
|
73
|
+
def safe_withdraw_addresses(chain_id, access_token: nil)
|
|
74
|
+
client.get '/safe/addresses', chain: chain_id, access_token:
|
|
75
|
+
end
|
|
76
|
+
alias fetch_list_of_chain safe_withdraw_addresses
|
|
77
|
+
|
|
73
78
|
def check_address(asset:, destination:, tag: nil)
|
|
74
79
|
client.get '/external/addresses/check', asset:, destination:, tag:, access_token: ''
|
|
75
80
|
end
|
data/lib/mixin_bot/api.rb
CHANGED
|
@@ -10,10 +10,12 @@ require_relative 'api/auth'
|
|
|
10
10
|
require_relative 'api/blaze'
|
|
11
11
|
require_relative 'api/chain'
|
|
12
12
|
require_relative 'api/code'
|
|
13
|
+
require_relative 'api/circle'
|
|
13
14
|
require_relative 'api/computer_api'
|
|
14
15
|
require_relative 'api/conversation'
|
|
15
16
|
require_relative 'api/deposit'
|
|
16
17
|
require_relative 'api/encrypted_message'
|
|
18
|
+
require_relative 'api/external'
|
|
17
19
|
require_relative 'api/fiat'
|
|
18
20
|
require_relative 'api/inscription'
|
|
19
21
|
require_relative 'api/legacy_collectible'
|
|
@@ -338,10 +340,12 @@ module MixinBot
|
|
|
338
340
|
include MixinBot::API::Blaze
|
|
339
341
|
include MixinBot::API::Chain
|
|
340
342
|
include MixinBot::API::Code
|
|
343
|
+
include MixinBot::API::Circle
|
|
341
344
|
include MixinBot::API::ComputerApi
|
|
342
345
|
include MixinBot::API::Conversation
|
|
343
346
|
include MixinBot::API::Deposit
|
|
344
347
|
include MixinBot::API::EncryptedMessage
|
|
348
|
+
include MixinBot::API::External
|
|
345
349
|
include MixinBot::API::Fiat
|
|
346
350
|
include MixinBot::API::Inscription
|
|
347
351
|
include MixinBot::API::LegacyCollectible
|
data/lib/mixin_bot/cli/call.rb
CHANGED
|
@@ -15,11 +15,13 @@ module MixinBot
|
|
|
15
15
|
LONGDESC
|
|
16
16
|
option :keystore, type: :string, aliases: '-k', desc: 'keystore JSON file path or inline JSON'
|
|
17
17
|
option :data, type: :string, aliases: '-d', default: '{}', desc: 'JSON object of keyword arguments'
|
|
18
|
+
option :force, type: :boolean, default: false, desc: 'Skip billing preflight for create_user (see -d force to override)'
|
|
18
19
|
option :data_only, type: :boolean, default: false, desc: 'Print only the data field of API responses'
|
|
19
20
|
def call(method_name, *positional)
|
|
20
21
|
with_command_name('call') do
|
|
21
22
|
setup_api_instance!
|
|
22
23
|
kwargs = parse_json_data(options[:data])
|
|
24
|
+
kwargs = merge_call_force_kwargs(method_name, kwargs)
|
|
23
25
|
result = invoke_api(method_name, kwargs:, positional:)
|
|
24
26
|
print_result(result, data_only: options[:data_only], command: 'call')
|
|
25
27
|
end
|
|
@@ -55,6 +57,14 @@ module MixinBot
|
|
|
55
57
|
|
|
56
58
|
private
|
|
57
59
|
|
|
60
|
+
def merge_call_force_kwargs(method_name, kwargs)
|
|
61
|
+
return kwargs unless method_name.to_sym == :create_user
|
|
62
|
+
return kwargs if kwargs.key?(:force)
|
|
63
|
+
return kwargs unless options[:force]
|
|
64
|
+
|
|
65
|
+
kwargs.merge(force: true)
|
|
66
|
+
end
|
|
67
|
+
|
|
58
68
|
def print_pretty_list(items, total, limit, offset)
|
|
59
69
|
grouped = items.group_by { |item| item['owner'] }
|
|
60
70
|
grouped.sort_by { |owner, _| owner }.each do |owner, names|
|
data/lib/mixin_bot/cli/errors.rb
CHANGED
|
@@ -12,6 +12,7 @@ module MixinBot
|
|
|
12
12
|
api_error: { retryable: false, description: 'Mixin API returned an error' },
|
|
13
13
|
unsupported: { retryable: false, description: 'Operation is not supported in this context' },
|
|
14
14
|
conflict: { retryable: false, description: 'Resource exists with incompatible configuration' },
|
|
15
|
+
billing: { retryable: false, description: 'App billing credit insufficient for the operation' },
|
|
15
16
|
internal: { retryable: false, description: 'Unexpected internal error' }
|
|
16
17
|
}.freeze
|
|
17
18
|
|
|
@@ -35,6 +36,8 @@ module MixinBot
|
|
|
35
36
|
:auth
|
|
36
37
|
when NotFoundError, UserNotFoundError
|
|
37
38
|
:not_found
|
|
39
|
+
when InsufficientAppBillingError
|
|
40
|
+
:billing
|
|
38
41
|
when ResponseError, RequestError, HttpError,
|
|
39
42
|
InsufficientBalanceError, UtxoInsufficientError, InsufficientPoolError
|
|
40
43
|
:api_error
|
data/lib/mixin_bot/errors.rb
CHANGED
|
@@ -51,6 +51,26 @@ module MixinBot
|
|
|
51
51
|
#
|
|
52
52
|
class InsufficientBalanceError < Error; end
|
|
53
53
|
|
|
54
|
+
##
|
|
55
|
+
# Raised when app prepaid billing credit lacks headroom for a billed operation.
|
|
56
|
+
#
|
|
57
|
+
class InsufficientAppBillingError < Error
|
|
58
|
+
attr_reader :app_id, :credit, :cost, :increment
|
|
59
|
+
|
|
60
|
+
def initialize(app_id:, credit:, cost:, increment:)
|
|
61
|
+
@app_id = app_id
|
|
62
|
+
@credit = credit
|
|
63
|
+
@cost = cost
|
|
64
|
+
@increment = increment
|
|
65
|
+
super(
|
|
66
|
+
format(
|
|
67
|
+
'app billing insufficient: credit %<credit>s <= cost %<cost>s + increment %<increment>s (app_id=%<app_id>s)',
|
|
68
|
+
credit:, cost:, increment:, app_id:
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
54
74
|
##
|
|
55
75
|
# Raised when selected UTXOs cannot cover the requested amount (mirrors Go +UtxoInsufficientError+).
|
|
56
76
|
#
|
data/lib/mixin_bot/version.rb
CHANGED
data/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MixinBot
|
|
2
2
|
|
|
3
|
-
> Ruby SDK and CLI for Mixin Network: Safe UTXO transfers, REST API, Blaze messaging, transaction crypto, optional MVM helpers. Ruby >= 3.2. Gem version 2.
|
|
3
|
+
> Ruby SDK and CLI for Mixin Network: Safe UTXO transfers, REST API, Blaze messaging, transaction crypto, optional MVM helpers. Ruby >= 3.2. Gem version 2.2.0.
|
|
4
4
|
|
|
5
5
|
Important notes:
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ Important notes:
|
|
|
11
11
|
## Docs
|
|
12
12
|
|
|
13
13
|
- [README](README.md): Install, config, API overview, CLI summary
|
|
14
|
-
- [API coverage vs Go
|
|
14
|
+
- [API coverage vs Go/Node SDKs](API_COVERAGE.md): Method parity matrix
|
|
15
15
|
- [CLI for agents](docs/agent/cli.md): Structured output, schema, examples
|
|
16
16
|
- [Agent cookbook](docs/agent/cookbook.md): Common tasks (auth, transfer, messaging)
|
|
17
17
|
- [Changelog](CHANGELOG.md): Breaking changes
|
|
@@ -25,5 +25,6 @@ Important notes:
|
|
|
25
25
|
## Optional
|
|
26
26
|
|
|
27
27
|
- [Mixin official docs](https://developers.mixin.one/docs): External API reference
|
|
28
|
-
- [bot-api-go-client](https://github.com/MixinNetwork/bot-api-go-client):
|
|
28
|
+
- [bot-api-go-client](https://github.com/MixinNetwork/bot-api-go-client): Go parity reference
|
|
29
|
+
- [bot-api-nodejs-client](https://github.com/MixinNetwork/bot-api-nodejs-client): Node parity reference
|
|
29
30
|
- [Generated RDoc](doc/index.html): Full API reference (local)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mixin_bot
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- an-lee
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -282,11 +282,13 @@ files:
|
|
|
282
282
|
- lib/mixin_bot/api/auth.rb
|
|
283
283
|
- lib/mixin_bot/api/blaze.rb
|
|
284
284
|
- lib/mixin_bot/api/chain.rb
|
|
285
|
+
- lib/mixin_bot/api/circle.rb
|
|
285
286
|
- lib/mixin_bot/api/code.rb
|
|
286
287
|
- lib/mixin_bot/api/computer_api.rb
|
|
287
288
|
- lib/mixin_bot/api/conversation.rb
|
|
288
289
|
- lib/mixin_bot/api/deposit.rb
|
|
289
290
|
- lib/mixin_bot/api/encrypted_message.rb
|
|
291
|
+
- lib/mixin_bot/api/external.rb
|
|
290
292
|
- lib/mixin_bot/api/fiat.rb
|
|
291
293
|
- lib/mixin_bot/api/inscription.rb
|
|
292
294
|
- lib/mixin_bot/api/legacy_collectible.rb
|