bitsnap 0.0.0-stage → 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 (5) hide show
  1. package/AGENTS.md +110 -0
  2. package/LICENSE +21 -0
  3. package/README.md +101 -2
  4. package/dist/cli.js +1685 -0
  5. package/package.json +35 -4
package/AGENTS.md ADDED
@@ -0,0 +1,110 @@
1
+ # bitsnap CLI for agents
2
+
3
+ `bitsnap` is a CLI for the Bitsnap public API (`/api/v1`). Run it with
4
+ `npx bitsnap …` or install it. Always pass `--json`.
5
+
6
+ ## Rules
7
+
8
+ - Authenticate with `BITSNAP_API_KEY` (preferred in agent sandboxes) or
9
+ `bitsnap login --key <key>`. Use a **test key** (`bs_test_…`) unless the user asked
10
+ for live. Never print, log or commit a key; the CLI masks keys as
11
+ `bs_test_…ab12`, keep it that way. Do not put the key in the project's client code.
12
+ - Check first: `bitsnap whoami --json` shows project, `environment`
13
+ (`ENVIRONMENT_TEST` / `ENVIRONMENT_LIVE`), `scopes` and `canWrite`.
14
+ - `--json`: result on stdout, errors on stderr as one line
15
+ `{"error":{"kind":"usage|api|auth|network|timeout","message","detail?","hint?","reason?","code?","status?","requestId?"}}`.
16
+ Branch on `reason` (stable), not on `message`.
17
+ - Exit codes: `0` ok · `1` API or usage error · `2` auth error (no/bad key) · `3` network error.
18
+ - No command prompts. Missing input is a usage error (exit 1).
19
+ - Money is an integer in minor units: `--price 4900` = 49.00 PLN.
20
+ - Writes send an `Idempotency-Key` (random UUID). To make a retry safe, pass the
21
+ same `--idempotency-key <key>` with the same arguments; the API returns the first
22
+ result instead of creating a second product or order. The same key with
23
+ different arguments fails with `idempotency_key_reused`.
24
+ - `--json` prints the API's response body verbatim (Connect JSON: lowerCamelCase,
25
+ enums by name such as `ORDER_STATUS_PAID`, timestamps RFC 3339). Fields may be added.
26
+ - Global options: `--json`, `--host <url>`, `--idempotency-key <key>`, `-h/--help`.
27
+
28
+ ## Commands and `--json` output
29
+
30
+ | Command | stdout with `--json` |
31
+ | --- | --- |
32
+ | `login --key K` | `GetAccount` fields + `key` (masked), `host`, `configPath` |
33
+ | `logout` | `{ok, removed, configPath}` |
34
+ | `whoami` | `{projectId, projectName, environment, credentialType, scopes[], canWrite, key (masked), keySource: "env"\|"config", host}` |
35
+ | `products list [--search t] [--limit 1-100] [--drafts] [--cursor c]` | `{products: Product[], nextCursor}` (`nextCursor` `""` = last page) |
36
+ | `products get ID` | `{product}` |
37
+ | `products create --name N --price MINOR [--currency PLN] [--status draft\|published\|unpublished] [--stock n] [--image URL]…` | `{product}` (draft unless `--status`) |
38
+ | `orders list [--status paid]… [--limit n] [--cursor c]` | `{orders: Order[], nextCursor, totalCount}` |
39
+ | `orders get ID` | `{order}` |
40
+ | `coupons list` | `{coupons: Coupon[]}` |
41
+ | `checkout create --product ID [--variant ID] [--quantity n] [--success-url U] [--cancel-url U] [--email E] [--reference R]` | `{url, orderId, environment}` (without `--json` only the URL is printed) |
42
+ | `payments settle ORDER_ID [--fail]` | `{orderId, outcome: "TEST_PAYMENT_OUTCOME_PAID"\|"TEST_PAYMENT_OUTCOME_FAILED"}`; exit 1 locally for live keys |
43
+ | `webhooks list` | `{webhooks: Webhook[]}` |
44
+ | `webhooks create --url HTTPS_URL [--name N] [--event E]…` | `{webhook, signingSecret}` (secret shown once; omit `--event` for all) |
45
+ | `webhooks delete ID` | `{}` |
46
+ | `webhooks listen [--forward URL] [--poll] [--max-events n] [--timeout s]` | NDJSON, see below |
47
+ | `webhooks trigger [EVENT]` | `{eventId, event, deliveredTo}` (default `TRANSACTION_SUCCESS`) |
48
+ | `openapi [--format yaml\|json] [--out F]` | the document on stdout (json with `--json`); with `--out`: `{ok, path, format, bytes}` |
49
+ | `stats [--from D] [--to D]` | `{from, to, orders, unitsSold, revenue: Money[], daily: [{date, units, revenue}]}`; `D` is `YYYY-MM-DD` or RFC 3339, a plain `--to` date covers that whole day |
50
+
51
+ `Product`: `{id, name, status: PRODUCT_STATUS_DRAFT|UNPUBLISHED|PUBLISHED, price?: {amount, currency}, availableQuantity?, images[], variants[{id, name, price?, availableQuantity?}], revision, createdAt, updatedAt}`.
52
+ `Order`: `{id, status: ORDER_STATUS_*, environment, createdAt, customer{email,name,phone}, items[{productId,name,quantity,unitPrice}], total, paymentGateway, couponCode, deliveryPrice?}`.
53
+ Order statuses for `--status`: `created paid unpaid canceled sent completed issue returned in_progress`.
54
+
55
+ ### `webhooks listen`
56
+
57
+ Test keys only. One JSON object per line:
58
+
59
+ ```json
60
+ {"type":"ready","secret":"whsec_…","projectId":"…","host":"https://bitsnap.pl","mode":"sse"}
61
+ {"type":"event","id":"evt_1","event":"TRANSACTION_SUCCESS","signature":"<hex hmac-sha512>","payload":"<exact JSON body string>","forward":{"url":"http://localhost:3000/api/webhooks","status":200,"ok":true,"durationMs":12}}
62
+ {"type":"status","state":"reconnecting"}
63
+ ```
64
+
65
+ `forward` is present with `--forward`; on a connection failure it is
66
+ `{"url","error","durationMs"}`; a non-2xx answer adds `body`. `payload` is the exact
67
+ string that was signed; `JSON.parse` it, never re-serialize it before verifying.
68
+ The signature is HMAC-SHA512 (hex) of `payload` with the signing secret, sent as
69
+ `X-Content-Signature` and `?sig=`. The command runs until Ctrl+C; use
70
+ `--max-events 1 --timeout 120` to wait for a single event (exit 0 when received,
71
+ exit 1 `kind: "timeout"` when not). Tip: run it in the background, trigger the
72
+ event (`bitsnap webhooks trigger` or `bitsnap payments settle`), then read the output.
73
+
74
+ ## Error reasons and what to do
75
+
76
+ | `reason` | Meaning | Do |
77
+ | --- | --- | --- |
78
+ | `missing_credentials`, `invalid_credentials` (exit 2) | No/bad key | Ask the user for a key from Settings → Developer |
79
+ | `writes_disabled` | Key has writes off | Ask the user to turn on writes for the key in Settings → Developer |
80
+ | `missing_scope` (`metadata.scope`) | Key lacks the scope | Ask the user to add the scope |
81
+ | `test_mode_only` | Command needs a test key | Use a `bs_test_…` key |
82
+ | `invalid_request` (`metadata.field`) | Bad argument | Fix the field named in `detail` |
83
+ | `*_not_found` | Wrong id or environment | List first (`products list`, `orders list`) |
84
+ | `product_not_purchasable`, `checkout_unavailable` | Product is a draft / no stock / shop has no gateway | Publish the product; set up the test gateway in the dashboard |
85
+ | `order_not_settleable` | Not an open test order of the Bitsnap test gateway (cancelled, expired, live, or another gateway). Settling twice is not an error: it returns the first outcome | Create a new checkout with a test key |
86
+ | `idempotency_key_in_progress` | Same key still running | Retry in seconds with the same key |
87
+ | `rate_limited`, `daily_write_limit`, `service_unavailable`, `internal` | Server side limits | Wait and retry (`daily_write_limit` resets 00:00 UTC) |
88
+
89
+ ## Recipes
90
+
91
+ ```sh
92
+ # 1. Is the key right?
93
+ bitsnap whoami --json
94
+
95
+ # 2. A product to sell (published so it can be bought)
96
+ bitsnap products create --name "Ebook" --price 4900 --status published --json
97
+
98
+ # 3. Buy it in test mode without a card
99
+ URL_JSON=$(bitsnap checkout create --product "$PRODUCT_ID" --success-url http://localhost:3000/thanks --json)
100
+ bitsnap payments settle "$ORDER_ID" --json
101
+
102
+ # 4. See the webhook arrive in the user's dev server
103
+ bitsnap webhooks listen --forward http://localhost:3000/api/webhooks --json --max-events 1 --timeout 120 &
104
+ bitsnap payments settle "$ORDER_ID" --json
105
+ wait
106
+ ```
107
+
108
+ Set `BITSNAP_WEBHOOK_SECRET` in the app's local env to the `secret` of the `ready`
109
+ record. The `bitsnap-js` package verifies the forwarded request unchanged
110
+ (`handleWebhook(rawBody, request.url, headers, secret)`).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Piotr Michalik
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,102 @@
1
- # Temporary Holding Version
1
+ # bitsnap
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Command-line tool for the [Bitsnap](https://bitsnap.pl) public API. Create
4
+ products, make test checkout links, settle test payments and forward test
5
+ webhooks to your local dev server, from a terminal or from an AI coding agent.
6
+
7
+ ```sh
8
+ npx bitsnap --help
9
+ npm install -g bitsnap # or: bun add -g bitsnap
10
+ ```
11
+
12
+ Needs Node.js 20 or newer. No runtime dependencies.
13
+
14
+ ## Log in
15
+
16
+ Create an API key in **Settings → Developer** of your Bitsnap dashboard. Use a
17
+ **test key** (`bs_test_…`) while you build: test orders move no money.
18
+
19
+ ```sh
20
+ bitsnap login --key bs_test_…
21
+ bitsnap whoami
22
+ ```
23
+
24
+ `login` checks the key with the API and stores it in
25
+ `~/.config/bitsnap/config.json` (or `$XDG_CONFIG_HOME/bitsnap/config.json`) with
26
+ mode `0600`. `BITSNAP_API_KEY` always wins over the stored key, which is the
27
+ better choice in CI and for agents. `--host` / `BITSNAP_HOST` change the API
28
+ host (default `https://bitsnap.pl`). A key is never printed in full
29
+ (`bs_test_…ab12`). `bitsnap logout` deletes the stored key.
30
+
31
+ Writes (create product, checkout links, webhooks) need the key's write switch
32
+ and the matching scope; if they are off the CLI says so and where to turn them
33
+ on.
34
+
35
+ ## Commands
36
+
37
+ | Command | What it does |
38
+ | --- | --- |
39
+ | `login --key <key>` / `logout` / `whoami` | Store, remove or inspect the credentials. |
40
+ | `products list [--search] [--limit] [--drafts] [--cursor]` | List products. |
41
+ | `products get <id>` | One product with its variants. |
42
+ | `products create --name --price <minor units> [--currency PLN] [--status draft\|published\|unpublished] [--stock n] [--image url]…` | Create a product. `--price 4900` is 49.00 PLN. |
43
+ | `orders list [--status paid]… [--limit] [--cursor]` / `orders get <id>` | Orders of the key's environment. |
44
+ | `coupons list` | Coupons and their codes. |
45
+ | `checkout create --product <id> [--variant] [--quantity] [--success-url] [--cancel-url] [--email]` | Prints the checkout URL. |
46
+ | `payments settle <orderId> [--fail]` | Settle a **test** order as paid (or failed). Refused locally for live keys. |
47
+ | `webhooks list` / `create --url <https>` / `delete <id>` | Manage webhook endpoints. |
48
+ | `webhooks listen [--forward <url>]` | Stream test webhook events; forward them to your local server. |
49
+ | `webhooks trigger [event]` | Send a sample event (default `TRANSACTION_SUCCESS`). |
50
+ | `openapi [--format yaml\|json] [--out file]` | Download the OpenAPI document (no key needed). |
51
+ | `stats [--from] [--to]` | Sales summary. |
52
+
53
+ `bitsnap <command> --help` shows every option.
54
+
55
+ ## Test a purchase end to end
56
+
57
+ ```sh
58
+ bitsnap products create --name "Ebook" --price 4900 --status published
59
+ bitsnap checkout create --product prodv2_… --success-url http://localhost:3000/thanks
60
+ # open the URL, or skip paying and settle the test order:
61
+ bitsnap payments settle <orderId>
62
+ ```
63
+
64
+ ## Receive webhooks on localhost
65
+
66
+ ```sh
67
+ bitsnap webhooks listen --forward http://localhost:3000/api/webhooks
68
+ ```
69
+
70
+ It prints the signing secret; set it as `BITSNAP_WEBHOOK_SECRET` in your app. Each
71
+ event is `POST`ed to your URL with the exact payload as body, the HMAC-SHA512
72
+ signature in `X-Content-Signature` and also as `?sig=`, so your normal webhook
73
+ verification (for example `handleWebhook` from `bitsnap-js`) works unchanged. The
74
+ stream reconnects by itself (with `Last-Event-ID`) and falls back to long
75
+ polling if the event stream is blocked. `bitsnap webhooks trigger` sends a
76
+ sample event so you can see it arrive.
77
+
78
+ ## For scripts and agents
79
+
80
+ - `--json` on any command: result as JSON on stdout. Errors go to stderr as
81
+ `{"error":{"kind","message","hint","reason",…}}`.
82
+ - Exit codes: `0` ok, `1` API or usage error, `2` auth error, `3` network error.
83
+ - The CLI never asks questions.
84
+ - Writes send an `Idempotency-Key` (random UUID; set it with `--idempotency-key`),
85
+ so a retry cannot create a second product or order.
86
+ - `bitsnap --help --json` lists every command and option.
87
+
88
+ See [AGENTS.md](./AGENTS.md) for the JSON shapes and recipes.
89
+
90
+ ## Develop
91
+
92
+ This package lives in the Bitsnap monorepo as `packages/cli` (workspace name
93
+ `@bitsnap/cli`; the published name is `bitsnap`).
94
+
95
+ ```sh
96
+ bun run typecheck && bun test && bun run build
97
+ node dist/cli.js --help
98
+ bun run release:prepare # assembles release/ with the public `bitsnap` manifest
99
+ npm publish ./release
100
+ ```
101
+
102
+ MIT licensed.