openreceive 0.4.21 → 0.4.22

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dfeec42ce821ad2ab73b5140eb1959f76f4125c34f26bfd214cc0e68ef507a00
4
- data.tar.gz: '09f6e1227799a8d50cab35b0b2e69d4eb6509e55f4e6cbbff9e5067c50fb9b06'
3
+ metadata.gz: 4ab3f684223bbce9a03d09d44e0ec67529cbc2b6616d2b50fb28a42f664e1a9a
4
+ data.tar.gz: 067be079ba6ccc64c251183495e7252837f596be0f244e1eceee557b08491f38
5
5
  SHA512:
6
- metadata.gz: 0bc687a6d13e167aa2ad2a9dbfc1286058177be57a245424e8ad8e0e911631579296b1520c3fa4876baca6562570b3fdeaadc3fd49576c49752102a72f939bc6
7
- data.tar.gz: 64ab63dda22aafcac83e0b831ebc3ab17b441145eb07250516e2de2c8141eb7ebeb4cd812ac274fe1427df1c94e96fe00ec45b2b94c1aac47c89a07aa57b5d6b
6
+ metadata.gz: 913b9d2b647168a3e383199a15078eaa807496ac18fe941e25d7d1bddc0e114f654aaa9cccecdff347fd9eb578043ac397fe6cca484b0088bb7659ac5583aff0
7
+ data.tar.gz: d4a72bb5286fcaaa4c58aeef127c488fcf6921f921ea3676b9115bb3138500954a5c5bcbe5c6b369ed6e5e36f759d985c080db351a83f898edc4e67d7d2a3dd8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.22 - 2026-10-10
4
+
5
+ Release with the complete 0.4.22 package family. The bundled agent skills'
6
+ directions now end with a message that starts "Setup is finished" and sends
7
+ nothing after it. They write the codes with the file-editing tool, check the
8
+ app sees them with doctor rather than `printenv`, start the server the way
9
+ the project already does, and restart only the app's own server by pid. No
10
+ Ruby runtime changes from 0.4.21.
11
+
3
12
  ## 0.4.21 - 2026-10-09
4
13
 
5
14
  Release with the complete 0.4.21 package family. The bundled agent skills'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenReceive
4
- VERSION = "0.4.21"
4
+ VERSION = "0.4.22"
5
5
  end
@@ -17,7 +17,7 @@ curl -fsSL https://openreceive.org/agent-directions/btcpay/full.md
17
17
  - Never tick the spend-capable override to make a save succeed.
18
18
  - Do not suggest rotating or revoking a code because it was pasted here.
19
19
 
20
- These directions describe OpenReceive 0.4.21.
20
+ These directions describe OpenReceive 0.4.22.
21
21
 
22
22
  Connect a BTCPay Server store to a receive-only NWC wallet with the OpenReceive
23
23
  plugin, and optionally let payers pay BTCPay invoices with USDT, USDC, ETH or
@@ -3,7 +3,7 @@ This is the full file; follow it from Step 0.
3
3
  # OpenReceive agent directions (Django)
4
4
 
5
5
  ```sh
6
- # READ THIS FIRST: this file is 44 KB and a summary drops required steps. Download it whole:
6
+ # READ THIS FIRST: this file is 46 KB and a summary drops required steps. Download it whole:
7
7
  curl -fsSL https://openreceive.org/agent-directions/django/full.md
8
8
  # Skip the download only if you already have all of it: pasted, read from disk or fetched raw.
9
9
  ```
@@ -17,7 +17,7 @@ curl -fsSL https://openreceive.org/agent-directions/django/full.md
17
17
  - Do not suggest rotating or revoking a code because it was pasted here.
18
18
  - Start the quickstart only once the NWC code is saved, and the LSC code is saved or the user said "Bitcoin only".
19
19
 
20
- These directions describe OpenReceive 0.4.21.
20
+ These directions describe OpenReceive 0.4.22.
21
21
 
22
22
  Add OpenReceive to a Django project — the app you are already working in. You
23
23
  do not need a copy of the OpenReceive source: the Python package is on PyPI
@@ -61,11 +61,12 @@ owns orders, users, prices, or fulfillment.
61
61
 
62
62
  ## Step 0 — ask for the two codes, one question at a time
63
63
 
64
- Before anything else, look at one file: the project's `.env`, if it exists.
65
- Read it only far enough to see whether `NWC_URI` and `LSC_URI_PRIMARY` are
66
- there and non-empty, and never print the values. A code that is already
67
- set is not asked for again; if both are set, skip to step 5
68
- (making the server load the file), then the quickstart.
64
+ Before anything else, check one file: the project's `.env`, if it exists.
65
+ `grep -E '^(NWC_URI|LSC_URI_PRIMARY)=.' .env | cut -d= -f1` names the codes
66
+ it sets without printing them. Check with that, here and after each write,
67
+ not by reading the file, and never print the values. A code that is already
68
+ set is not asked for again; if both are set, skip to step 5 (making the
69
+ server load the file), then the quickstart.
69
70
 
70
71
  Otherwise your next action is a question to the user. Do not install the package,
71
72
  edit the app, write `.env.example`, or search anywhere else before asking
@@ -96,14 +97,17 @@ you store it. Ask one question per message.
96
97
  Do not mention `.env`, exports, or "tell me when it's set".
97
98
  2. **When they paste it.** If it does not start with `nostr+walletconnect://`,
98
99
  ask them to copy the receive-only code again. Otherwise write
99
- `NWC_URI=<paste>` into the project's `.env`, creating the file if needed.
100
- Make sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has
101
- one). Never echo the value, commit it, or put it in client code. Reply only
102
- that it is saved, then ask the next question.
103
- 3. **Second message — swaps.** If the user already asked for stablecoins or
104
- altcoins, skip the yes/no and go straight to the walkthrough. Otherwise ask
105
- whether payers should also be able to pay with USDT, USDC, ETH or SOL. The
106
- walkthrough:
100
+ `NWC_URI=<paste>` into the project's `.env` with your file-editing tool,
101
+ creating the file if needed. Never write it with a shell command (`echo`,
102
+ `printf`, a heredoc, `python -c`): the command line shows the code. Make
103
+ sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has one).
104
+ Never echo the value, commit it, or put it in client code. Reply only that
105
+ it is saved, then ask the next question.
106
+ 3. **Second message — swaps.** If the user asked for stablecoins, USDT, USDC,
107
+ ETH, SOL, altcoins or "crypto" (as in "Bitcoin and stablecoin payments"),
108
+ this message IS the walkthrough below: send it as it is, and do not ask yes
109
+ or no first. Otherwise ask whether payers should also be able to pay with
110
+ USDT, USDC, ETH or SOL, then give the walkthrough. The walkthrough:
107
111
 
108
112
  > Go to https://lightning-swap.com, sign in for API keys, create a key, and
109
113
  > copy the whole URI (https://openreceive.org/set_up_swap_provider). Paste
@@ -113,10 +117,10 @@ you store it. Ask one question per message.
113
117
  Mention FixedFloat only if they already use it.
114
118
  4. **When they paste it.** If it does not start with
115
119
  `lightning+swapconnect://`, ask them to copy it again. Otherwise add
116
- `LSC_URI_PRIMARY=<paste>` to the same `.env`, without echoing it. Swaps
117
- are now on, so build the refund route back (the swap non-negotiable below) as
118
- part of this integration. If they chose Bitcoin only, leave
119
- `LSC_URI_PRIMARY` unset and skip that route.
120
+ `LSC_URI_PRIMARY=<paste>` to the same `.env` with the file-editing tool,
121
+ never a shell command. Swaps are now on, so build the refund route back
122
+ (the swap non-negotiable below) as part of this integration. If they chose
123
+ Bitcoin only, leave `LSC_URI_PRIMARY` unset and skip that route.
120
124
  5. **Make the server load the file — yourself.** Django does not
121
125
  read `.env` on its own. If the app already uses `django-environ`, make sure
122
126
  it reads this file; otherwise add it and call `environ.Env.read_env()` in
@@ -160,22 +164,28 @@ failed check and exits nonzero; fix it before going on.
160
164
 
161
165
  Give the user that checkout link. The browser check in the quickstart's
162
166
  "Render the checkout" section (payment-method icons, wallet logos, a pay
163
- tutorial) is theirs: tell them what to look at, and do not run it yourself.
167
+ tutorial) is theirs: name it in one line of your closing message, and do not
168
+ run it yourself.
164
169
 
165
170
  You cannot pay the invoice: the code is receive-only. Do not pay, settle or
166
171
  mark an order paid, and do not look for a way to (a wallet control port, a
167
172
  test endpoint, another wallet). If the user wants a real settlement test, they
168
173
  pay on that link from their own wallet, and `on_paid` marks the order paid.
169
174
 
170
- Setup ends here. Say "Setup is finished" in one message of at most five
171
- lines, with the link and what to check. Do not list what changed, offer more
172
- work, or end the message on a question.
175
+ Setup ends here. Your last message starts "Setup is finished" and has at most
176
+ five short lines (about 80 characters each): the link, the methods it offers,
177
+ and one line of what to look at. Send nothing after it. Do not list what
178
+ changed, copy out the quickstart's browser checklist, offer more work, or end
179
+ the message on a question.
173
180
 
174
181
  - The link is to a real unpaid order. Keep that order; do not delete it.
182
+ - When this app's orders belong to a session or cookie, the user's browser
183
+ cannot open the order you made. Then the link is the shop's own page:
184
+ "Open <shop url> and click Buy: it opens the checkout." Do not explain order
185
+ ownership or mention your test order.
175
186
  - Name the methods it offers: Bitcoin, plus USDT, USDC, ETH and SOL when
176
- `LSC_URI_PRIMARY` is saved. Never say a coin will not work or will not be
177
- offered. Swap minimums apply per order, and a coin whose minimum is above an
178
- order's total says so on its own tile.
187
+ `LSC_URI_PRIMARY` is saved. Do not mention minimums, and never say a coin
188
+ will not work or will not be offered.
179
189
 
180
190
  ## Non-negotiables
181
191
 
@@ -192,6 +202,21 @@ itself, and they hold for every integration.
192
202
  - Work only in this application. Never read or run anything from another
193
203
  project on this machine (its `node_modules`, tools or source), for any
194
204
  reason. A browser and Playwright are not part of setup.
205
+ - Restart only this app's server, on the port it already uses: stop the
206
+ process you started, or the one listening on that port, by its pid (or
207
+ restart its Compose service). Never `pkill` or `killall` by name: that
208
+ stops other people's servers too. Start it the way this project already
209
+ does (its README, Procfile, compose file or package script), on its own
210
+ port, not a port you pick.
211
+ - Run commands where the app runs. When a compose file builds it, run its
212
+ package manager, generators, migrations and doctor inside that service
213
+ (`docker compose exec` or `run`), and rebuild the image after adding a
214
+ package. This machine's language version and database path are not the
215
+ app's.
216
+ - To check that the running app sees the codes, run doctor: it reports each
217
+ one as present or missing and never prints a value. Never print the
218
+ environment (`printenv`, `env`, `docker compose config`), even filtered to
219
+ names.
195
220
  - The host owns the price. `amount_for` reads it from your own data;
196
221
  reject payer-supplied amounts.
197
222
  - `authorize` runs on every request, and the `resource` it receives is a
@@ -200,6 +225,10 @@ itself, and they hold for every integration.
200
225
  a placeholder that allows everything (`manage.py check` warns
201
226
  `openreceive.W002` while it is set) — replace it with this app's real
202
227
  ownership check, same as `on_paid`.
228
+ - Fill in `openreceive_host.py` with your file-edit tool: replace each
229
+ placeholder in place (the `authorize = staticmethod(...)` line, the
230
+ `amount_for` body, the `on_paid = staticmethod(...)` line). Never edit it
231
+ by line number from a script.
203
232
  - `on_paid` must be idempotent. Its database fulfillment commits once per `reference` — your order
204
233
  id, one per thing you fulfill, created before checkout, kept across retries,
205
234
  never reused. A fresh id per page load lets one order be paid twice.
@@ -3,7 +3,7 @@ This is the full file; follow it from Step 0.
3
3
  # OpenReceive agent directions (FastAPI)
4
4
 
5
5
  ```sh
6
- # READ THIS FIRST: this file is 37 KB and a summary drops required steps. Download it whole:
6
+ # READ THIS FIRST: this file is 39 KB and a summary drops required steps. Download it whole:
7
7
  curl -fsSL https://openreceive.org/agent-directions/fastapi/full.md
8
8
  # Skip the download only if you already have all of it: pasted, read from disk or fetched raw.
9
9
  ```
@@ -17,7 +17,7 @@ curl -fsSL https://openreceive.org/agent-directions/fastapi/full.md
17
17
  - Do not suggest rotating or revoking a code because it was pasted here.
18
18
  - Start the quickstart only once the NWC code is saved, and the LSC code is saved or the user said "Bitcoin only".
19
19
 
20
- These directions describe OpenReceive 0.4.21.
20
+ These directions describe OpenReceive 0.4.22.
21
21
 
22
22
  Add OpenReceive to a FastAPI application — the app you are already working in.
23
23
  You do not need a copy of the OpenReceive source: the engine is on PyPI
@@ -61,11 +61,12 @@ owns orders, users, prices, or fulfillment.
61
61
 
62
62
  ## Step 0 — ask for the two codes, one question at a time
63
63
 
64
- Before anything else, look at one file: the project's `.env`, if it exists.
65
- Read it only far enough to see whether `NWC_URI` and `LSC_URI_PRIMARY` are
66
- there and non-empty, and never print the values. A code that is already
67
- set is not asked for again; if both are set, skip to step 5
68
- (making the server load the file), then the quickstart.
64
+ Before anything else, check one file: the project's `.env`, if it exists.
65
+ `grep -E '^(NWC_URI|LSC_URI_PRIMARY)=.' .env | cut -d= -f1` names the codes
66
+ it sets without printing them. Check with that, here and after each write,
67
+ not by reading the file, and never print the values. A code that is already
68
+ set is not asked for again; if both are set, skip to step 5 (making the
69
+ server load the file), then the quickstart.
69
70
 
70
71
  Otherwise your next action is a question to the user. Do not install packages,
71
72
  edit the app, write `.env.example`, or search anywhere else before asking
@@ -96,14 +97,17 @@ you store it. Ask one question per message.
96
97
  Do not mention `.env`, exports, or "tell me when it's set".
97
98
  2. **When they paste it.** If it does not start with `nostr+walletconnect://`,
98
99
  ask them to copy the receive-only code again. Otherwise write
99
- `NWC_URI=<paste>` into the project's `.env`, creating the file if needed.
100
- Make sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has
101
- one). Never echo the value, commit it, or put it in client code. Reply only
102
- that it is saved, then ask the next question.
103
- 3. **Second message — swaps.** If the user already asked for stablecoins or
104
- altcoins, skip the yes/no and go straight to the walkthrough. Otherwise ask
105
- whether payers should also be able to pay with USDT, USDC, ETH or SOL. The
106
- walkthrough:
100
+ `NWC_URI=<paste>` into the project's `.env` with your file-editing tool,
101
+ creating the file if needed. Never write it with a shell command (`echo`,
102
+ `printf`, a heredoc, `python -c`): the command line shows the code. Make
103
+ sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has one).
104
+ Never echo the value, commit it, or put it in client code. Reply only that
105
+ it is saved, then ask the next question.
106
+ 3. **Second message — swaps.** If the user asked for stablecoins, USDT, USDC,
107
+ ETH, SOL, altcoins or "crypto" (as in "Bitcoin and stablecoin payments"),
108
+ this message IS the walkthrough below: send it as it is, and do not ask yes
109
+ or no first. Otherwise ask whether payers should also be able to pay with
110
+ USDT, USDC, ETH or SOL, then give the walkthrough. The walkthrough:
107
111
 
108
112
  > Go to https://lightning-swap.com, sign in for API keys, create a key, and
109
113
  > copy the whole URI (https://openreceive.org/set_up_swap_provider). Paste
@@ -113,10 +117,10 @@ you store it. Ask one question per message.
113
117
  Mention FixedFloat only if they already use it.
114
118
  4. **When they paste it.** If it does not start with
115
119
  `lightning+swapconnect://`, ask them to copy it again. Otherwise add
116
- `LSC_URI_PRIMARY=<paste>` to the same `.env`, without echoing it. Swaps
117
- are now on, so build the refund route back (the swap non-negotiable below) as
118
- part of this integration. If they chose Bitcoin only, leave
119
- `LSC_URI_PRIMARY` unset and skip that route.
120
+ `LSC_URI_PRIMARY=<paste>` to the same `.env` with the file-editing tool,
121
+ never a shell command. Swaps are now on, so build the refund route back
122
+ (the swap non-negotiable below) as part of this integration. If they chose
123
+ Bitcoin only, leave `LSC_URI_PRIMARY` unset and skip that route.
120
124
  5. **Make the server load the file — yourself.** OpenReceive reads
121
125
  `os.environ`, and a `.env` file on disk is not in it. Start the dev server
122
126
  with `uvicorn --env-file .env` (update the app's run script or Procfile, not
@@ -153,23 +157,28 @@ serves the checkout page for one of its orders. Doctor names any failed check
153
157
  and exits nonzero; fix it before going on.
154
158
 
155
159
  Give the user that checkout link. The browser check in the quickstart's step 6
156
- (payment-method icons, wallet logos, a pay tutorial) is theirs: tell them what
157
- to look at, and do not run it yourself.
160
+ (payment-method icons, wallet logos, a pay tutorial) is theirs: name it in one
161
+ line of your closing message, and do not run it yourself.
158
162
 
159
163
  You cannot pay the invoice: the code is receive-only. Do not pay, settle or
160
164
  mark an order paid, and do not look for a way to (a wallet control port, a
161
165
  test endpoint, another wallet). If the user wants a real settlement test, they
162
166
  pay on that link from their own wallet, and `on_paid` marks the order paid.
163
167
 
164
- Setup ends here. Say "Setup is finished" in one message of at most five
165
- lines, with the link and what to check. Do not list what changed, offer more
166
- work, or end the message on a question.
168
+ Setup ends here. Your last message starts "Setup is finished" and has at most
169
+ five short lines (about 80 characters each): the link, the methods it offers,
170
+ and one line of what to look at. Send nothing after it. Do not list what
171
+ changed, copy out the quickstart's browser checklist, offer more work, or end
172
+ the message on a question.
167
173
 
168
174
  - The link is to a real unpaid order. Keep that order; do not delete it.
175
+ - When this app's orders belong to a session or cookie, the user's browser
176
+ cannot open the order you made. Then the link is the shop's own page:
177
+ "Open <shop url> and click Buy: it opens the checkout." Do not explain order
178
+ ownership or mention your test order.
169
179
  - Name the methods it offers: Bitcoin, plus USDT, USDC, ETH and SOL when
170
- `LSC_URI_PRIMARY` is saved. Never say a coin will not work or will not be
171
- offered. Swap minimums apply per order, and a coin whose minimum is above an
172
- order's total says so on its own tile.
180
+ `LSC_URI_PRIMARY` is saved. Do not mention minimums, and never say a coin
181
+ will not work or will not be offered.
173
182
 
174
183
  ## Non-negotiables
175
184
 
@@ -186,6 +195,21 @@ itself, and they hold for every integration.
186
195
  - Work only in this application. Never read or run anything from another
187
196
  project on this machine (its `node_modules`, tools or source), for any
188
197
  reason. A browser and Playwright are not part of setup.
198
+ - Restart only this app's server, on the port it already uses: stop the
199
+ process you started, or the one listening on that port, by its pid (or
200
+ restart its Compose service). Never `pkill` or `killall` by name: that
201
+ stops other people's servers too. Start it the way this project already
202
+ does (its README, Procfile, compose file or package script), on its own
203
+ port, not a port you pick.
204
+ - Run commands where the app runs. When a compose file builds it, run its
205
+ package manager, generators, migrations and doctor inside that service
206
+ (`docker compose exec` or `run`), and rebuild the image after adding a
207
+ package. This machine's language version and database path are not the
208
+ app's.
209
+ - To check that the running app sees the codes, run doctor: it reports each
210
+ one as present or missing and never prints a value. Never print the
211
+ environment (`printenv`, `env`, `docker compose config`), even filtered to
212
+ names.
189
213
  - The host owns the price. `amount_for` reads it from your own data; reject
190
214
  payer-supplied amounts.
191
215
  - `authorize` runs on every request, and the `resource` it receives is a CLAIM
@@ -519,14 +543,18 @@ host = Host(
519
543
  ),
520
544
  )
521
545
 
522
- app = FastAPI(lifespan=openreceive_lifespan(host, engine=engine))
523
- app.include_router(
546
+ # The router carries the options. Build it before the lifespan: through
547
+ # 0.4.21 the lifespan bound first and refused the router's options.
548
+ router = openreceive_router(
549
+ host,
550
+ engine=engine,
524
551
  # Recommended for public web shops: `rate_limiting=True` caps invoice
525
552
  # creation at 60 per client IP per hour. Leave it off (the default) for
526
553
  # point-of-sale deployments, where many payers share the terminal's IP.
527
- openreceive_router(host, engine=engine, rate_limiting=True),
528
- prefix="/openreceive",
554
+ rate_limiting=True,
529
555
  )
556
+ app = FastAPI(lifespan=openreceive_lifespan(host, engine=engine))
557
+ app.include_router(router, prefix="/openreceive")
530
558
  ```
531
559
 
532
560
  `authorize` receives the Starlette `Request`. Cookies, headers, and whatever
@@ -3,7 +3,7 @@ This is the full file; follow it from Step 0.
3
3
  # OpenReceive agent directions (Fastify)
4
4
 
5
5
  ```sh
6
- # READ THIS FIRST: this file is 36 KB and a summary drops required steps. Download it whole:
6
+ # READ THIS FIRST: this file is 38 KB and a summary drops required steps. Download it whole:
7
7
  curl -fsSL https://openreceive.org/agent-directions/fastify/full.md
8
8
  # Skip the download only if you already have all of it: pasted, read from disk or fetched raw.
9
9
  ```
@@ -17,7 +17,7 @@ curl -fsSL https://openreceive.org/agent-directions/fastify/full.md
17
17
  - Do not suggest rotating or revoking a code because it was pasted here.
18
18
  - Start the quickstart only once the NWC code is saved, and the LSC code is saved or the user said "Bitcoin only".
19
19
 
20
- These directions describe OpenReceive 0.4.21.
20
+ These directions describe OpenReceive 0.4.22.
21
21
 
22
22
  Add OpenReceive to a Fastify application — the app you are already working in.
23
23
  You do not need a copy of the OpenReceive source: the packages are on npm, and
@@ -58,11 +58,12 @@ owns orders, users, prices, or fulfillment.
58
58
 
59
59
  ## Step 0 — ask for the two codes, one question at a time
60
60
 
61
- Before anything else, look at one file: the project's `.env`, if it exists.
62
- Read it only far enough to see whether `NWC_URI` and `LSC_URI_PRIMARY` are
63
- there and non-empty, and never print the values. A code that is already
64
- set is not asked for again; if both are set, skip to step 5
65
- (making the server load the file), then the quickstart.
61
+ Before anything else, check one file: the project's `.env`, if it exists.
62
+ `grep -E '^(NWC_URI|LSC_URI_PRIMARY)=.' .env | cut -d= -f1` names the codes
63
+ it sets without printing them. Check with that, here and after each write,
64
+ not by reading the file, and never print the values. A code that is already
65
+ set is not asked for again; if both are set, skip to step 5 (making the
66
+ server load the file), then the quickstart.
66
67
 
67
68
  Otherwise your next action is a question to the user. Do not install packages,
68
69
  edit the app, write `.env.example`, or search anywhere else before asking
@@ -93,14 +94,17 @@ you store it. Ask one question per message.
93
94
  Do not mention `.env`, exports, or "tell me when it's set".
94
95
  2. **When they paste it.** If it does not start with `nostr+walletconnect://`,
95
96
  ask them to copy the receive-only code again. Otherwise write
96
- `NWC_URI=<paste>` into the project's `.env`, creating the file if needed.
97
- Make sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has
98
- one). Never echo the value, commit it, or put it in client code. Reply only
99
- that it is saved, then ask the next question.
100
- 3. **Second message — swaps.** If the user already asked for stablecoins or
101
- altcoins, skip the yes/no and go straight to the walkthrough. Otherwise ask
102
- whether payers should also be able to pay with USDT, USDC, ETH or SOL. The
103
- walkthrough:
97
+ `NWC_URI=<paste>` into the project's `.env` with your file-editing tool,
98
+ creating the file if needed. Never write it with a shell command (`echo`,
99
+ `printf`, a heredoc, `python -c`): the command line shows the code. Make
100
+ sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has one).
101
+ Never echo the value, commit it, or put it in client code. Reply only that
102
+ it is saved, then ask the next question.
103
+ 3. **Second message — swaps.** If the user asked for stablecoins, USDT, USDC,
104
+ ETH, SOL, altcoins or "crypto" (as in "Bitcoin and stablecoin payments"),
105
+ this message IS the walkthrough below: send it as it is, and do not ask yes
106
+ or no first. Otherwise ask whether payers should also be able to pay with
107
+ USDT, USDC, ETH or SOL, then give the walkthrough. The walkthrough:
104
108
 
105
109
  > Go to https://lightning-swap.com, sign in for API keys, create a key, and
106
110
  > copy the whole URI (https://openreceive.org/set_up_swap_provider). Paste
@@ -110,10 +114,10 @@ you store it. Ask one question per message.
110
114
  Mention FixedFloat only if they already use it.
111
115
  4. **When they paste it.** If it does not start with
112
116
  `lightning+swapconnect://`, ask them to copy it again. Otherwise add
113
- `LSC_URI_PRIMARY=<paste>` to the same `.env`, without echoing it. Swaps
114
- are now on, so build the refund route back (the swap non-negotiable below) as
115
- part of this integration. If they chose Bitcoin only, leave
116
- `LSC_URI_PRIMARY` unset and skip that route.
117
+ `LSC_URI_PRIMARY=<paste>` to the same `.env` with the file-editing tool,
118
+ never a shell command. Swaps are now on, so build the refund route back
119
+ (the swap non-negotiable below) as part of this integration. If they chose
120
+ Bitcoin only, leave `LSC_URI_PRIMARY` unset and skip that route.
117
121
  5. **Make the server load the file — yourself.** OpenReceive reads
118
122
  `process.env`, and a `.env` file on disk is not in it. Put
119
123
  `import "dotenv/config";` at the top of the server entry, as the quickstart
@@ -148,23 +152,28 @@ Doctor reads `.env` itself. Never source it into a shell: the `&` in a
148
152
  code splits the value and prints the pieces.
149
153
 
150
154
  Give the user that checkout link. The browser check in the quickstart's step 6
151
- (payment-method icons, wallet logos, a pay tutorial) is theirs: tell them what
152
- to look at, and do not run it yourself.
155
+ (payment-method icons, wallet logos, a pay tutorial) is theirs: name it in one
156
+ line of your closing message, and do not run it yourself.
153
157
 
154
158
  You cannot pay the invoice: the code is receive-only. Do not pay, settle or
155
159
  mark an order paid, and do not look for a way to (a wallet control port, a
156
160
  test endpoint, another wallet). If the user wants a real settlement test, they
157
161
  pay on that link from their own wallet, and `onPaid` marks the order paid.
158
162
 
159
- Setup ends here. Say "Setup is finished" in one message of at most five
160
- lines, with the link and what to check. Do not list what changed, offer more
161
- work, or end the message on a question.
163
+ Setup ends here. Your last message starts "Setup is finished" and has at most
164
+ five short lines (about 80 characters each): the link, the methods it offers,
165
+ and one line of what to look at. Send nothing after it. Do not list what
166
+ changed, copy out the quickstart's browser checklist, offer more work, or end
167
+ the message on a question.
162
168
 
163
169
  - The link is to a real unpaid order. Keep that order; do not delete it.
170
+ - When this app's orders belong to a session or cookie, the user's browser
171
+ cannot open the order you made. Then the link is the shop's own page:
172
+ "Open <shop url> and click Buy: it opens the checkout." Do not explain order
173
+ ownership or mention your test order.
164
174
  - Name the methods it offers: Bitcoin, plus USDT, USDC, ETH and SOL when
165
- `LSC_URI_PRIMARY` is saved. Never say a coin will not work or will not be
166
- offered. Swap minimums apply per order, and a coin whose minimum is above an
167
- order's total says so on its own tile.
175
+ `LSC_URI_PRIMARY` is saved. Do not mention minimums, and never say a coin
176
+ will not work or will not be offered.
168
177
 
169
178
  ## Non-negotiables
170
179
 
@@ -181,6 +190,21 @@ itself, and they hold for every integration.
181
190
  - Work only in this application. Never read or run anything from another
182
191
  project on this machine (its `node_modules`, tools or source), for any
183
192
  reason. A browser and Playwright are not part of setup.
193
+ - Restart only this app's server, on the port it already uses: stop the
194
+ process you started, or the one listening on that port, by its pid (or
195
+ restart its Compose service). Never `pkill` or `killall` by name: that
196
+ stops other people's servers too. Start it the way this project already
197
+ does (its README, Procfile, compose file or package script), on its own
198
+ port, not a port you pick.
199
+ - Run commands where the app runs. When a compose file builds it, run its
200
+ package manager, generators, migrations and doctor inside that service
201
+ (`docker compose exec` or `run`), and rebuild the image after adding a
202
+ package. This machine's language version and database path are not the
203
+ app's.
204
+ - To check that the running app sees the codes, run doctor: it reports each
205
+ one as present or missing and never prints a value. Never print the
206
+ environment (`printenv`, `env`, `docker compose config`), even filtered to
207
+ names.
184
208
  - The host owns the price. `amountFor` reads it from your own data; reject
185
209
  payer-supplied amounts.
186
210
  - `authorize` runs on every request, and the `resource` it receives is a CLAIM
@@ -256,7 +280,10 @@ products, and you do not join them.
256
280
  are buying.
257
281
  - **Users own the order; OpenReceive never sees them.** `authorize` uses the
258
282
  same ownership check this app already uses on the order show / pay page —
259
- `sessions.currentUser(request)`, a cookie, whatever it is.
283
+ `sessions.currentUser(native)`, a cookie, whatever it is. Pass `native` (the
284
+ Fastify request) to this app's own cookie and session helpers, never
285
+ `request`: that one is a Web Request, a helper that reads
286
+ `req.headers.cookie` finds nothing on it, and every payer gets a 403.
260
287
  `resource.reference` is a claim the payer sent, not proof.
261
288
  - **The order is unpaid or paid.** Do not copy `pending` / `expired` / `failed`
262
289
  / `attention` onto it. Those are attempt statuses on `openreceive_payments`. An
@@ -521,11 +548,14 @@ await app.register(openReceiveFastify, {
521
548
  // Your own access check: may this caller do this action to this reference?
522
549
  // `resource.reference` is your own order id, sent back by the payer's
523
550
  // browser — a claim, not proof — already validated as a non-empty string.
524
- // `native` is the untouched Fastify request, so a session decorated by
525
- // @fastify/session (or whatever this app uses) is readable here too.
526
- authorize: async ({ action, request, resource }) =>
551
+ // `native` is the untouched Fastify request: pass it to this app's own
552
+ // cookie and session helpers, and a session decorated by @fastify/session
553
+ // (or whatever this app uses) is readable on it. `request` is a Web
554
+ // Request, so a helper that reads `req.headers.cookie` finds nothing on it
555
+ // and every payer gets a 403.
556
+ authorize: async ({ action, native, resource }) =>
527
557
  orders.viewerMay(
528
- await sessions.currentUser(request),
558
+ await sessions.currentUser(native),
529
559
  resource.reference,
530
560
  action,
531
561
  ),
@@ -541,7 +571,7 @@ await app.register(openReceiveFastify, {
541
571
  ```
542
572
 
543
573
  Register the plugin after whichever plugin gives you sessions or auth
544
- decorations, because `authorize` sees the same request object. The plugin
574
+ decorations, because `native` is that same request object. The plugin
545
575
  handles shutdown for you. It registers an `onClose` hook that closes the
546
576
  wallet client together with the app, so you have no `ready`/`close` pair to
547
577
  manage. A deploy health check awaits `fastify.ready()` instead.