openreceive-rails 0.4.11 → 0.4.13
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/CHANGELOG.md +19 -0
- data/lib/generators/openreceive/install/templates/initializer.rb +1 -1
- data/lib/openreceive/configuration.rb +1 -1
- data/lib/openreceive/rails/version.rb +1 -1
- data/lib/openreceive/reconcile.rb +11 -6
- data/lib/openreceive/reconcile_scan.rb +15 -2
- data/skills/debug-openreceive-payment/SKILL.md +1 -1
- data/skills/integrate-openreceive/SKILL.md +4 -3
- data/skills/integrate-openreceive/references/btcpay.md +65 -36
- data/skills/integrate-openreceive/references/django.md +288 -243
- data/skills/integrate-openreceive/references/fastapi.md +203 -154
- data/skills/integrate-openreceive/references/fastify.md +197 -146
- data/skills/integrate-openreceive/references/laravel.md +291 -233
- data/skills/integrate-openreceive/references/next.md +207 -161
- data/skills/integrate-openreceive/references/node.md +185 -137
- data/skills/integrate-openreceive/references/php.md +245 -192
- data/skills/integrate-openreceive/references/rails.md +259 -217
- data/skills/integrate-openreceive/references/woocommerce.md +66 -51
- metadata +5 -5
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OpenReceive agent directions (PHP)
|
|
2
2
|
|
|
3
|
-
These directions describe OpenReceive 0.4.
|
|
3
|
+
These directions describe OpenReceive 0.4.13.
|
|
4
4
|
|
|
5
5
|
Add OpenReceive to a PHP application — the app you are already working in. You
|
|
6
6
|
do not need a copy of the OpenReceive source: the engine is on Packagist
|
|
@@ -35,75 +35,99 @@ The one required credential is a receive-only NWC code (Nostr Wallet Connect):
|
|
|
35
35
|
a string from the merchant's wallet that can create invoices and read their
|
|
36
36
|
status, and cannot spend. A swap provider (an "LSC" code) optionally lets the
|
|
37
37
|
payer send USDT, USDC, ETH or SOL instead, converted into that same
|
|
38
|
-
Lightning payment.
|
|
38
|
+
Lightning payment. Step 0 collects those credentials from the user; you write three hooks — `authorize`,
|
|
39
39
|
`amountFor`, `onPaid` on one `OpenReceive\Host`;
|
|
40
40
|
OpenReceive supplies invoices, polling, settlement and the checkout UI. It never
|
|
41
41
|
owns orders, users, prices, or fulfillment.
|
|
42
42
|
|
|
43
|
-
## Step 0 —
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
>
|
|
72
|
-
>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
`
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
43
|
+
## Step 0 — ask for the two codes, one question at a time
|
|
44
|
+
|
|
45
|
+
Before anything else, look at one file: the project's `.env`, if it exists.
|
|
46
|
+
Read it only far enough to see whether `NWC_URI` and `LSC_URI_PRIMARY` are
|
|
47
|
+
there and non-empty, and never print the values. A code that is already
|
|
48
|
+
set is not asked for again; if both are set, skip to step 5
|
|
49
|
+
(making the server load the file), then the quickstart.
|
|
50
|
+
|
|
51
|
+
Otherwise your next action is a question to the user. Do not run `composer require`,
|
|
52
|
+
edit the app, write `.env.example`, or search anywhere else before asking
|
|
53
|
+
it. Do not read deploy config (compose files, `SetEnv`/`fastcgi_param` blocks, platform secrets), Docker containers, or process environments, and never run
|
|
54
|
+
`printenv`. A new shop has neither code yet: hunting for one burns the turn and
|
|
55
|
+
can leak other secrets into the transcript.
|
|
56
|
+
|
|
57
|
+
Two server-only URIs are needed before the quickstart:
|
|
58
|
+
|
|
59
|
+
- `NWC_URI` — a receive-only Nostr Wallet Connect code,
|
|
60
|
+
`nostr+walletconnect://…`. Required for Bitcoin.
|
|
61
|
+
- `LSC_URI_PRIMARY` — a Lightning Swap Connect URI,
|
|
62
|
+
`lightning+swapconnect://…`. Required for USDT, USDC, ETH and SOL. Skip it
|
|
63
|
+
only when the user says they want Bitcoin alone.
|
|
64
|
+
|
|
65
|
+
The user never edits an environment file. They paste each code into the chat;
|
|
66
|
+
you store it. Ask one question per message.
|
|
67
|
+
|
|
68
|
+
1. **First message — the NWC code, and nothing else.** Ask for it and walk them
|
|
69
|
+
through getting it:
|
|
70
|
+
|
|
71
|
+
> To receive payments I need a receive-only wallet code. In Rizful: open
|
|
72
|
+
> the menu, tap NWC, choose Receive-only NWC code, and tap Copy
|
|
73
|
+
> (https://openreceive.org/get_a_nwc_code_to_receive_payments). If you would
|
|
74
|
+
> rather run your own wallet, Alby Hub works too: Connections → Add
|
|
75
|
+
> Connection → Read Only. Paste the code here and I will store it.
|
|
76
|
+
|
|
77
|
+
Do not mention `.env`, exports, or "tell me when it's set".
|
|
78
|
+
2. **When they paste it.** If it does not start with `nostr+walletconnect://`,
|
|
79
|
+
ask them to copy the receive-only code again. Otherwise write
|
|
80
|
+
`NWC_URI=<paste>` into the project's `.env`, creating the file if needed.
|
|
81
|
+
Make sure `.gitignore` covers `.env` (and `.dockerignore`, if the app has
|
|
82
|
+
one). Never echo the value, commit it, or put it in client code. Reply only
|
|
83
|
+
that it is saved, then ask the next question.
|
|
84
|
+
3. **Second message — swaps.** If the user already asked for stablecoins or
|
|
85
|
+
altcoins, skip the yes/no and go straight to the walkthrough. Otherwise ask
|
|
86
|
+
whether payers should also be able to pay with USDT, USDC, ETH or SOL. The
|
|
87
|
+
walkthrough:
|
|
88
|
+
|
|
89
|
+
> Go to https://lightning-swap.com, sign in for API keys, create a key, and
|
|
90
|
+
> copy the whole URI (https://openreceive.org/set_up_swap_provider). Paste
|
|
91
|
+
> it here and I will store it — or say "Bitcoin only" and I will continue
|
|
92
|
+
> without it.
|
|
93
|
+
|
|
94
|
+
Mention FixedFloat only if they already use it.
|
|
95
|
+
4. **When they paste it.** If it does not start with
|
|
96
|
+
`lightning+swapconnect://`, ask them to copy it again. Otherwise add
|
|
97
|
+
`LSC_URI_PRIMARY=<paste>` to the same `.env`, without echoing it. Swaps
|
|
98
|
+
are now on, so build the refund route back (the swap non-negotiable below) as
|
|
99
|
+
part of this integration. If they chose Bitcoin only, leave
|
|
100
|
+
`LSC_URI_PRIMARY` unset and skip that route.
|
|
101
|
+
5. **Make the server load the file — yourself.** Nothing in PHP
|
|
102
|
+
reads `.env` on its own. Add `vlucas/phpdotenv` and load the file in the
|
|
103
|
+
front controller before `Service::fromEnvironment()`. When the app is started
|
|
104
|
+
with Docker Compose, give the service `env_file: .env`. Restart PHP-FPM or
|
|
105
|
+
the server after writing the file.
|
|
106
|
+
|
|
107
|
+
Do not invent placeholder URIs. Start the quickstart only once `NWC_URI` is
|
|
108
|
+
saved and `LSC_URI_PRIMARY` is saved or explicitly declined. The first boot
|
|
109
|
+
runs the receive-only preflight: if it reports spend methods such as
|
|
110
|
+
`pay_invoice`, remove `NWC_URI` from `.env` and ask for a receive-only code
|
|
111
|
+
again. Never set the spend-capable override to get past it.
|
|
112
|
+
|
|
113
|
+
Then check the PHP runtime: `php -m` must list `gmp`, `sodium`, `mbstring`,
|
|
114
|
+
`json`, `pdo` and one PDO driver. `ext-gmp` is REQUIRED — the NWC transport
|
|
115
|
+
signs every request with it — and `php:*-cli`/`-fpm` images do not ship it
|
|
116
|
+
(`docker-php-ext-install gmp`). PHP must be ≥ 8.2 and 64-bit.
|
|
117
|
+
|
|
118
|
+
### Upgrading an existing install
|
|
119
|
+
|
|
120
|
+
This is not the opening move of a new integration. When OpenReceive is ALREADY
|
|
121
|
+
installed here, `OpenReceive\Server\Doctor::report()` (a plain host runs it
|
|
122
|
+
from the quickstart's `bin/doctor` script) reports every credential as
|
|
123
|
+
set/unset (never the value), the host class and any placeholder hooks, the
|
|
124
|
+
mount, and the wallet preflight. Check the installed `openreceive/openreceive`
|
|
125
|
+
(`composer show openreceive/openreceive`) and the unpacked checkout's
|
|
126
|
+
`MANIFEST.json` against the release named at the top of this file. The two
|
|
127
|
+
must match: the browser build and the engine are one release. Upgrade first —
|
|
128
|
+
and if this app runs in containers, rebuild the images: `vendor/` is baked into
|
|
129
|
+
the image, so an in-place `composer update` is undone by the next
|
|
130
|
+
`compose up`.
|
|
107
131
|
|
|
108
132
|
Only then start the quickstart.
|
|
109
133
|
|
|
@@ -312,13 +336,14 @@ passes. The page it comes from is https://openreceive.org/guides/quickstart-php.
|
|
|
312
336
|
|
|
313
337
|
## PHP quickstart (plain PHP)
|
|
314
338
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
339
|
+
This page is for plain PHP, with no framework: a front controller, a PDO handle
|
|
340
|
+
and three methods. Laravel has its own quickstart (`openreceive/laravel`, the
|
|
341
|
+
thin adapter over this engine).
|
|
342
|
+
|
|
343
|
+
Requires PHP ≥ 8.2 (64-bit) with `ext-gmp`, `ext-sodium`, `ext-mbstring`,
|
|
344
|
+
`ext-json`, `ext-pdo` and one PDO driver (`pdo_pgsql`, `pdo_sqlite` or
|
|
345
|
+
`pdo_mysql`). `ext-gmp` is **required**, not optional. The NWC transport signs
|
|
346
|
+
every wallet request with it.
|
|
322
347
|
|
|
323
348
|
### 1. Install
|
|
324
349
|
|
|
@@ -326,26 +351,27 @@ three methods.
|
|
|
326
351
|
composer require openreceive/openreceive nyholm/psr7 nyholm/psr7-server
|
|
327
352
|
```
|
|
328
353
|
|
|
329
|
-
`openreceive/openreceive` is the whole engine
|
|
330
|
-
exact money, settlement, the `openreceive_payments` repository
|
|
331
|
-
rates and a PSR-15 handler. It depends on the PSR
|
|
332
|
-
PSR-7/PSR-17 implementation your app already has
|
|
333
|
-
`nyholm/psr7-server` is the smallest pair and
|
|
354
|
+
`openreceive/openreceive` is the whole engine. It includes the receive-only
|
|
355
|
+
wallet client, exact money, settlement, the `openreceive_payments` repository
|
|
356
|
+
over PDO, swaps, rates and a PSR-15 handler. It depends only on the PSR
|
|
357
|
+
interfaces, so bring the PSR-7/PSR-17 implementation your app already has.
|
|
358
|
+
`nyholm/psr7` + `nyholm/psr7-server` is the smallest pair, and this page uses
|
|
359
|
+
it.
|
|
334
360
|
|
|
335
361
|
The **checkout UI is not in the Composer package.** Packagist installs from git
|
|
336
|
-
and cannot run a JS build
|
|
362
|
+
and cannot run a JS build. So the browser side ships separately, as
|
|
337
363
|
`standalone-checkout-<version>.tar.gz` on every
|
|
338
|
-
[GitHub release](https://github.com/openreceive/openreceive/releases)
|
|
339
|
-
self-contained ES module, its stylesheet, a source map and a
|
|
340
|
-
`MANIFEST.json`. Unpack it somewhere your web server serves
|
|
341
|
-
(step 5).
|
|
342
|
-
instead
|
|
364
|
+
[GitHub release](https://github.com/openreceive/openreceive/releases). It holds
|
|
365
|
+
one self-contained ES module, its stylesheet, a source map and a
|
|
366
|
+
`MANIFEST.json`. Unpack it somewhere your web server serves static files
|
|
367
|
+
(step 5). If your app has a JS bundler, you can `npm install @openreceive/elements`
|
|
368
|
+
instead. The tarball is the same build.
|
|
343
369
|
|
|
344
370
|
### 2. Migrate the payment tables
|
|
345
371
|
|
|
346
|
-
The engine owns two tables in **your** database and renders their DDL
|
|
347
|
-
dialect. Run
|
|
348
|
-
Phinx, Doctrine Migrations, a plain SQL file, a `bin/migrate` script
|
|
372
|
+
The engine owns two tables in **your** database and renders their DDL for each
|
|
373
|
+
SQL dialect. Run that DDL through whatever your app uses for schema changes:
|
|
374
|
+
Phinx, Doctrine Migrations, a plain SQL file, or a `bin/migrate` script.
|
|
349
375
|
|
|
350
376
|
```php
|
|
351
377
|
use OpenReceive\Storage\PaymentsSchema;
|
|
@@ -357,16 +383,18 @@ foreach (PaymentsSchema::statements($dialect) as $sql) {
|
|
|
357
383
|
// down(): PaymentsSchema::dropStatements()
|
|
358
384
|
```
|
|
359
385
|
|
|
360
|
-
`PaymentsSchema::migrate(new PdoConnection($pdo))`
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
386
|
+
If your script has no migration tool, `PaymentsSchema::migrate(new PdoConnection($pdo))`
|
|
387
|
+
does the same in one call. It creates two tables. Leave both to the library:
|
|
388
|
+
|
|
389
|
+
- `openreceive_payments`: one row per payment attempt.
|
|
390
|
+
- `openreceive_meta`: the reconcile gate and the schema version.
|
|
391
|
+
|
|
392
|
+
Details: [Payment storage](https://openreceive.org/guides/storage.md).
|
|
365
393
|
|
|
366
394
|
### 3. Add wallet credentials
|
|
367
395
|
|
|
368
|
-
Create a server-only `.env
|
|
369
|
-
|
|
396
|
+
Create a server-only `.env`, or export the variables from your process manager.
|
|
397
|
+
The engine reads `getenv()` and `$_ENV`.
|
|
370
398
|
|
|
371
399
|
```dotenv
|
|
372
400
|
NWC_URI=
|
|
@@ -375,27 +403,28 @@ LSC_URI_BACKUP=
|
|
|
375
403
|
```
|
|
376
404
|
|
|
377
405
|
1. Get a receive-only NWC code from a compatible wallet
|
|
378
|
-
([get one here](https://openreceive.org/get_a_nwc_code_to_receive_payments))
|
|
379
|
-
|
|
380
|
-
2.
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
406
|
+
([get one here](https://openreceive.org/get_a_nwc_code_to_receive_payments)).
|
|
407
|
+
Put it in `NWC_URI`.
|
|
408
|
+
2. Optional: set up a [swap provider](https://openreceive.org/set_up_swap_provider).
|
|
409
|
+
Put its connection string in `LSC_URI_PRIMARY`, and a second one in
|
|
410
|
+
`LSC_URI_BACKUP` if you have one.
|
|
411
|
+
|
|
412
|
+
Never put these values in browser code. Your app refuses to start if the NWC
|
|
413
|
+
code also advertises spend methods such as `pay_invoice`. Create a
|
|
414
|
+
receive-only code instead ([Security](https://openreceive.org/guides/security.md)).
|
|
415
|
+
|
|
416
|
+
Nothing in PHP loads a `.env` file on its own. Something has to put the values
|
|
417
|
+
in the process environment first: `vlucas/phpdotenv`, your web server's
|
|
418
|
+
`SetEnv`/`fastcgi_param`, or the container runtime
|
|
390
419
|
([Environment variables](https://openreceive.org/guides/environment-variables.md)).
|
|
391
420
|
|
|
392
421
|
### 4. Wire OpenReceive
|
|
393
422
|
|
|
394
423
|
Three methods on one object are the entire bridge between the engine and your
|
|
395
|
-
data
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
424
|
+
data. The engine never sees an order, a user or a price except through them.
|
|
425
|
+
`Engine` combines the wallet, the repository over your PDO, and that object
|
|
426
|
+
into a PSR-15 handler. Your front controller sends requests under one path
|
|
427
|
+
prefix to that handler:
|
|
399
428
|
|
|
400
429
|
```php
|
|
401
430
|
<?php
|
|
@@ -481,57 +510,73 @@ if (str_starts_with($path, '/openreceive')) {
|
|
|
481
510
|
```
|
|
482
511
|
|
|
483
512
|
`Service::fromEnvironment()` builds the wallet client from `NWC_URI` and runs
|
|
484
|
-
the receive-only preflight
|
|
513
|
+
the receive-only preflight. A missing, invalid or spend-capable code throws
|
|
485
514
|
before any route is served. PHP starts every request from nothing, so that
|
|
486
|
-
check runs
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
515
|
+
check runs on every request that reaches the engine.
|
|
516
|
+
|
|
517
|
+
The settlement gate the engine relies on lives in `openreceive_meta`, not in
|
|
518
|
+
memory. That is why a fleet of PHP-FPM workers shares one wallet-scan budget,
|
|
519
|
+
with no worker process of its own. Later OpenReceive requests also settle
|
|
520
|
+
pending invoices, so a payer who closes the tab is still covered. `authorize`
|
|
521
|
+
runs on every request.
|
|
491
522
|
→ [Engine](https://openreceive.org/guides/api-reference.md#openreceiveserverengine) ·
|
|
492
523
|
[Host](https://openreceive.org/guides/api-reference.md#openreceivehost) ·
|
|
493
524
|
[the authorize context](https://openreceive.org/guides/api-reference.md#the-authorize-context-php)
|
|
494
525
|
|
|
495
|
-
**Cross-site requests.** Plain PHP has no CSRF layer,
|
|
496
|
-
|
|
497
|
-
`Sec-Fetch-Site` header says `cross-site
|
|
498
|
-
origin cannot
|
|
499
|
-
|
|
500
|
-
`X-CSRF-Token` (or the header named by `csrf-header`) for your own layer
|
|
501
|
-
check.
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
526
|
+
**Cross-site requests.** Plain PHP has no CSRF layer, just like Express, and the
|
|
527
|
+
engine does not need one. Every mounted route refuses a request whose
|
|
528
|
+
`Sec-Fetch-Site` header says `cross-site`. So a form or script on another
|
|
529
|
+
origin cannot create invoices using a payer's cookie. That makes
|
|
530
|
+
`<meta name="csrf-token">` optional. If you set it, the checkout sends the value
|
|
531
|
+
back as `X-CSRF-Token` (or the header named by `csrf-header`) for your own layer
|
|
532
|
+
to check.
|
|
533
|
+
|
|
534
|
+
The engine's check does NOT cover two cases:
|
|
535
|
+
|
|
536
|
+
- A browser too old to send `Sec-Fetch-Site`. The header is absent, and an
|
|
537
|
+
absent header passes.
|
|
538
|
+
- Anything that is not a browser at all. A script holding a stolen cookie is a
|
|
539
|
+
session problem, not a forgery problem.
|
|
540
|
+
|
|
541
|
+
`authorize` is still the boundary that decides whether *this caller* may act on
|
|
542
|
+
*this order* ([Security](https://openreceive.org/guides/security.md)).
|
|
543
|
+
|
|
544
|
+
For public web shops, turn on the per-IP invoice cap with `rateLimiting: true`
|
|
545
|
+
on `Engine`. Leave it off (the default) when many payers share one IP. Behind a
|
|
546
|
+
proxy, pass `clientIp: fn ($request) => …` so the cap counts the payer, not the
|
|
547
|
+
proxy. → [Rate limiting](https://openreceive.org/guides/rate-limiting.md)
|
|
548
|
+
|
|
549
|
+
Your app also needs an ordinary order-creation route. It validates the cart,
|
|
550
|
+
prices with exact decimal math, and returns the order id. The page then passes
|
|
551
|
+
that id as the `reference`. OpenReceive never prices from payer input.
|
|
552
|
+
|
|
553
|
+
The `reference` is a string you choose, and it is the fulfillment identity. Use
|
|
554
|
+
your order id:
|
|
555
|
+
|
|
556
|
+
- one per thing you fulfill,
|
|
557
|
+
- created before checkout,
|
|
558
|
+
- kept across retries,
|
|
559
|
+
- never reused.
|
|
560
|
+
|
|
561
|
+
`onPaid` commits fulfillment once per reference, and a new checkout under a
|
|
562
|
+
reference that already settled is refused with 409. A fresh id per page load
|
|
563
|
+
would let one order be paid twice.
|
|
564
|
+
|
|
565
|
+
Naming: PHP APIs use camelCase methods and snake_case array keys
|
|
566
|
+
(`amount_msats`, `payment_hash`). The keys match the wire format. The mounted
|
|
567
|
+
HTTP routes and the browser snapshots are snake_case throughout.
|
|
524
568
|
|
|
525
569
|
### 5. Render checkout
|
|
526
570
|
|
|
527
|
-
Serve the compiled `styles.css` without Tailwind processing
|
|
528
|
-
JavaScript (with a CSS-capable bundler) or use a plain
|
|
529
|
-
Do not `@import` it into
|
|
530
|
-
|
|
571
|
+
Serve the compiled `styles.css` without Tailwind processing. Either import it
|
|
572
|
+
from JavaScript (with a CSS-capable bundler) or use a plain
|
|
573
|
+
`<link rel="stylesheet">`. Do not `@import` it into your Tailwind entry. Its
|
|
574
|
+
rules have zero specificity, so your own styles can override checkout styles.
|
|
575
|
+
Scoping does not prevent that.
|
|
531
576
|
|
|
532
577
|
Unpack the release's `standalone-checkout-<version>.tar.gz` into a directory
|
|
533
|
-
your web server serves
|
|
534
|
-
the element:
|
|
578
|
+
your web server serves. This page uses `public/openreceive/`. Then add two tags
|
|
579
|
+
and the element:
|
|
535
580
|
|
|
536
581
|
```html
|
|
537
582
|
<link rel="stylesheet" href="/openreceive/openreceive-checkout.css" />
|
|
@@ -543,32 +588,33 @@ the element:
|
|
|
543
588
|
></openreceive-checkout>
|
|
544
589
|
```
|
|
545
590
|
|
|
546
|
-
The module registers `<openreceive-checkout>` as it loads
|
|
591
|
+
The module registers `<openreceive-checkout>` as it loads. The element creates
|
|
547
592
|
the checkout for `reference`, then renders, polls and settles itself. The
|
|
548
|
-
stylesheet is scoped to what OpenReceive renders. The checkout follows the
|
|
549
|
-
always one theme, lock it with
|
|
550
|
-
|
|
551
|
-
|
|
593
|
+
stylesheet is scoped to what OpenReceive renders. The checkout follows the
|
|
594
|
+
payer's theme. On a page that always uses one theme, lock it with
|
|
595
|
+
`theme="dark"`. React, Vue, Svelte, and Angular apps use the matching wrapper
|
|
596
|
+
package instead, with the same attributes
|
|
597
|
+
([Frontend checkout](https://openreceive.org/guides/frontend-checkout.md)). A custom UI builds on
|
|
552
598
|
`@openreceive/browser/headless` ([Headless checkout](https://openreceive.org/guides/headless-checkout.md)).
|
|
553
599
|
|
|
554
600
|
Everything the checkout draws ships inside the JavaScript: the payment-method
|
|
555
601
|
icons, the wallet logos and the pay tutorials. There is no image file to copy
|
|
556
602
|
or serve and no asset option to set. Deploy your normal JavaScript and CSS
|
|
557
603
|
build output, including any generated JavaScript chunks. Bundlers with code
|
|
558
|
-
splitting can
|
|
559
|
-
|
|
560
|
-
Content-Security-Policy has a strict `img-src`, allow `data:`
|
|
604
|
+
splitting can load tutorial screenshots only when a tutorial is first opened.
|
|
605
|
+
Single-file builds, including the standalone checkout, include them upfront. If
|
|
606
|
+
your Content-Security-Policy has a strict `img-src`, allow `data:`
|
|
561
607
|
([Provider registry](https://openreceive.org/guides/provider-registry.md#assets)).
|
|
562
608
|
|
|
563
|
-
`MANIFEST.json` in the tarball carries the version and a SHA-256 per file
|
|
564
|
-
|
|
565
|
-
version in step with the Composer package.
|
|
609
|
+
`MANIFEST.json` in the tarball carries the version and a SHA-256 per file. You
|
|
610
|
+
can use it to check a copied tree against the release it came from. Keep the
|
|
611
|
+
tarball version in step with the Composer package.
|
|
566
612
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
It has products, visitors, and orders,
|
|
571
|
-
Map that shape onto the models in THIS app.
|
|
613
|
+
Buy a Button
|
|
614
|
+
(`examples/buttons/server/php-plain`)
|
|
615
|
+
is a runnable illustration of this boundary. It is not a template to copy
|
|
616
|
+
models from. It has products, visitors, and orders, and the three hooks are the
|
|
617
|
+
only bridge. Map that shape onto the models in THIS app.
|
|
572
618
|
|
|
573
619
|
### 6. Verify
|
|
574
620
|
|
|
@@ -581,28 +627,33 @@ foreach (\OpenReceive\Server\Doctor::report(
|
|
|
581
627
|
) as $line) echo $line, PHP_EOL;
|
|
582
628
|
```
|
|
583
629
|
|
|
584
|
-
`Doctor::report()` prints
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
630
|
+
`Doctor::report()` prints:
|
|
631
|
+
|
|
632
|
+
- every credential as set or unset, never its value;
|
|
633
|
+
- the host class, and which of the three methods are still the scaffolded
|
|
634
|
+
placeholders (`Hosts\AllowAllAuthorize`, `Hosts\LoggingOnPaid`). The engine
|
|
635
|
+
also warns at boot while either is in use;
|
|
636
|
+
- where the handler is mounted;
|
|
637
|
+
- the receive-only wallet preflight.
|
|
638
|
+
|
|
639
|
+
`$engine->doctor()` is the same report for an engine you already built. Put it
|
|
640
|
+
behind a `bin/doctor` script. The demo's is twelve lines.
|
|
641
|
+
→ [Doctor](https://openreceive.org/guides/api-reference.md#openreceiveserverdoctor)
|
|
591
642
|
|
|
592
|
-
Then open the checkout in a browser
|
|
643
|
+
Then open the checkout in a browser. Confirm the payment-method icons and
|
|
593
644
|
wallet logos render, and open a wallet's pay tutorial to check its screenshots.
|
|
594
|
-
If an image is missing,
|
|
645
|
+
If an image is missing, check the console for CSP violations and the Network
|
|
595
646
|
panel for failed JavaScript chunks. Allow `data:` in `img-src` and deploy the
|
|
596
647
|
complete build output. Do not add image routes, copy package source images, or
|
|
597
648
|
use registry `icon_path` / tutorial `path` keys as browser URLs.
|
|
598
649
|
|
|
599
650
|
### Reconciliation
|
|
600
651
|
|
|
601
|
-
Settlement runs on the request path
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
need a cron job. Tune or disable it with `Engine`'s
|
|
605
|
-
(`false`, or `['min_interval_seconds' => …]`).
|
|
652
|
+
Settlement runs on the request path. Every payment route first runs one bounded
|
|
653
|
+
reconcile pass through the durable `openreceive_meta` gate. The gate allows at
|
|
654
|
+
most one real wallet scan every 3 seconds, shared by every PHP process. You do
|
|
655
|
+
not need a cron job. Tune or disable it with `Engine`'s
|
|
656
|
+
`opportunisticReconcile` (`false`, or `['min_interval_seconds' => …]`).
|
|
606
657
|
|
|
607
658
|
Optionally, run one worker so settlement does not wait for the next page load:
|
|
608
659
|
|
|
@@ -610,18 +661,20 @@ Optionally, run one worker so settlement does not wait for the next page load:
|
|
|
610
661
|
$engine->notificationsWorker()->run(); // blocks: an NWC-02 listener plus a periodic pass
|
|
611
662
|
```
|
|
612
663
|
|
|
613
|
-
as its own long-lived process (`php bin/notifications`).
|
|
614
|
-
|
|
664
|
+
Run it as its own long-lived process (`php bin/notifications`). To run a pass
|
|
665
|
+
yourself, use the one-shot `$engine->reconcile()`.
|
|
615
666
|
→ [Engine notificationsWorker](https://openreceive.org/guides/api-reference.md#engine-notificationsworker)
|
|
616
667
|
|
|
617
668
|
### Swap secrets
|
|
618
669
|
|
|
619
|
-
Setting `LSC_URI_PRIMARY` (and `LSC_URI_BACKUP`) auto-builds the matching
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
670
|
+
Setting `LSC_URI_PRIMARY` (and `LSC_URI_BACKUP`) auto-builds the matching swap
|
|
671
|
+
providers. Nothing in your code changes. One `openreceive_payments` row holds
|
|
672
|
+
at most one provider order, in its server-only `swap_data`. The repository
|
|
673
|
+
never selects it into public arrays. Do not log it or return it from your own
|
|
674
|
+
API.
|
|
675
|
+
|
|
676
|
+
**Setting either connection string commits you to refunds.** A deposit that
|
|
677
|
+
arrives short or late is claimed on a second visit. That needs a per-order URL
|
|
678
|
+
your app serves, and the attempt's `payment_hash` kept.
|
|
679
|
+
[Swap refunds](https://openreceive.org/guides/swap-refunds.md) covers all of it. Read it before you set
|
|
680
|
+
`LSC_URI_PRIMARY`.
|