@openreceive/http 0.4.12 → 0.4.14

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.
@@ -7,7 +7,7 @@ import {
7
7
  isServiceErrorShape,
8
8
  mapHostRouteError,
9
9
  startNotificationWorker
10
- } from "./chunk-PGZAFYN6.js";
10
+ } from "./chunk-67MZJBIF.js";
11
11
  export {
12
12
  HostError,
13
13
  HttpError,
@@ -229,7 +229,10 @@ function isUnderPrefix(pathname, prefix) {
229
229
  import { compact, unixSeconds as unixSeconds7 } from "@openreceive/core";
230
230
 
231
231
  // src/reconcile-gate.ts
232
- import { createPaymentScanWindow, unixSeconds as unixSeconds5 } from "@openreceive/core";
232
+ import {
233
+ createPaymentScanWindow,
234
+ unixSeconds as unixSeconds5
235
+ } from "@openreceive/core";
233
236
 
234
237
  // src/host-payments.ts
235
238
  import { unixSeconds as unixSeconds3 } from "@openreceive/core";
@@ -1307,10 +1310,11 @@ function abortableDelay(milliseconds, signal) {
1307
1310
  }
1308
1311
 
1309
1312
  // src/reconcile-gate.ts
1310
- var OPENRECEIVE_MIN_RECONCILE_INTERVAL_SECONDS = 2;
1313
+ var OPENRECEIVE_MIN_RECONCILE_INTERVAL_SECONDS = 3;
1311
1314
  var OPENRECEIVE_RECONCILE_SCAN_TIMEOUT_MS = 9e3;
1315
+ var SCAN_BACKSTOP_GRACE_MS = 500;
1312
1316
  var OPENRECEIVE_RECONCILE_SCAN_MAX_PAGES = 50;
1313
- var EARLY_INVOICE_INTERVAL_SECONDS = 2;
1317
+ var EARLY_INVOICE_INTERVAL_SECONDS = 3;
1314
1318
  var MID_INVOICE_INTERVAL_SECONDS = 6;
1315
1319
  var LATE_INVOICE_INTERVAL_SECONDS = 12;
1316
1320
  var EARLY_INVOICE_WINDOW_SECONDS = 2 * 60;
@@ -1345,7 +1349,10 @@ async function maybeReconcilePayments(input) {
1345
1349
  try {
1346
1350
  const clock = input.clock ?? unixSeconds5;
1347
1351
  const now = clock();
1348
- const minInterval = Math.max(2, input.minIntervalSeconds ?? 2);
1352
+ const minInterval = Math.max(
1353
+ OPENRECEIVE_MIN_RECONCILE_INTERVAL_SECONDS,
1354
+ input.minIntervalSeconds ?? OPENRECEIVE_MIN_RECONCILE_INTERVAL_SECONDS
1355
+ );
1349
1356
  const timeout = Math.min(
1350
1357
  OPENRECEIVE_RECONCILE_SCAN_TIMEOUT_MS,
1351
1358
  input.scanTimeoutMs ?? OPENRECEIVE_RECONCILE_SCAN_TIMEOUT_MS
@@ -1368,22 +1375,33 @@ async function maybeReconcilePayments(input) {
1368
1375
  let candidates = await input.host.payments.listReconcilableAttempts(scheduler.cursor);
1369
1376
  if (candidates.length === 0 && scheduler.cursor !== null)
1370
1377
  candidates = await input.host.payments.listReconcilableAttempts(null);
1371
- const last = candidates.at(-1);
1372
- scheduler.cursor = last === void 0 || candidates.length < OPENRECEIVE_RECONCILE_BATCH_SIZE ? null : { created_at: last.createdAt, payment_hash: last.paymentHash };
1373
- const fresh = candidates.filter((attempt) => !queued.has(attempt.paymentHash));
1374
- if (fresh.length > 0)
1375
- scheduler.windows.push(
1376
- createPaymentScanWindow(
1377
- fresh.map((attempt) => ({
1378
- payment_hash: attempt.paymentHash,
1379
- created_at: attempt.createdAt,
1380
- expires_at: attempt.expiresAt,
1381
- created_at_source: attempt.createdAtSource ?? "host"
1382
- })),
1383
- now,
1384
- input.overlapSeconds
1385
- )
1386
- );
1378
+ const cohorts = /* @__PURE__ */ new Map();
1379
+ let taken = 0;
1380
+ for (const attempt of candidates) {
1381
+ if (!queued.has(attempt.paymentHash)) {
1382
+ const wallet = attempt.createdAtSource === "wallet";
1383
+ let cohort = cohorts.get(wallet);
1384
+ if (cohort === void 0) {
1385
+ if (scheduler.windows.length + cohorts.size >= 2) break;
1386
+ cohort = [];
1387
+ cohorts.set(wallet, cohort);
1388
+ }
1389
+ cohort.push({
1390
+ payment_hash: attempt.paymentHash,
1391
+ created_at: attempt.createdAt,
1392
+ expires_at: attempt.expiresAt,
1393
+ created_at_source: attempt.createdAtSource ?? "host"
1394
+ });
1395
+ }
1396
+ taken += 1;
1397
+ }
1398
+ const last = candidates[taken - 1];
1399
+ scheduler.cursor = last === void 0 || taken === candidates.length && candidates.length < OPENRECEIVE_RECONCILE_BATCH_SIZE ? null : { created_at: last.createdAt, payment_hash: last.paymentHash };
1400
+ for (const wallet of [true, false]) {
1401
+ const cohort = cohorts.get(wallet);
1402
+ if (cohort !== void 0)
1403
+ scheduler.windows.push(createPaymentScanWindow(cohort, now, input.overlapSeconds));
1404
+ }
1387
1405
  }
1388
1406
  const window = scheduler.windows.shift();
1389
1407
  if (window === void 0) {
@@ -1445,7 +1463,7 @@ async function maybeReconcilePayments(input) {
1445
1463
  }
1446
1464
  }
1447
1465
  }),
1448
- timeout,
1466
+ timeout + SCAN_BACKSTOP_GRACE_MS,
1449
1467
  controller
1450
1468
  );
1451
1469
  if (slice.outcome === "continued") {
package/dist/index.d.ts CHANGED
@@ -282,15 +282,16 @@ declare function startReconciler(input: {
282
282
 
283
283
  /**
284
284
  * Floor for the durable reconcile-gate interval: at most one real wallet scan
285
- * per two seconds across EVERY worker sharing the host database. This gate is
285
+ * per three seconds across EVERY worker sharing the host database. This gate is
286
286
  * the NWC rate limit for settlement scans — open tabs polling `payments/check`
287
287
  * (~3s) all share the one global pass instead of fanning out wallet walks.
288
288
  */
289
- declare const OPENRECEIVE_MIN_RECONCILE_INTERVAL_SECONDS: 2;
289
+ declare const OPENRECEIVE_MIN_RECONCILE_INTERVAL_SECONDS: 3;
290
290
  /**
291
291
  * Wall-clock bound on an awaited request-path pass: a slow wallet must not
292
- * hang user-facing requests. A timed-out pass counts as a failed scan; the
293
- * gate stays claimed so the next interval retries without a stampede.
292
+ * hang user-facing requests. A page still in flight at the deadline is cut;
293
+ * the pass keeps the progress of its completed pages, and the next interval
294
+ * resumes there.
294
295
  */
295
296
  declare const OPENRECEIVE_RECONCILE_SCAN_TIMEOUT_MS: 9000;
296
297
  /** Page cap per wallet-history walk on the awaited request path. */
@@ -304,7 +305,7 @@ type OpportunisticReconcileResult = {
304
305
  interface MaybeReconcilePaymentsOptions {
305
306
  readonly service: OpenReceive;
306
307
  readonly host: Host;
307
- /** Gate interval floor. Default (and minimum) 2 seconds. */
308
+ /** Gate interval floor. Default (and minimum) 3 seconds. */
308
309
  readonly minIntervalSeconds?: number;
309
310
  readonly overlapSeconds?: number;
310
311
  readonly scanTimeoutMs?: number;
@@ -315,7 +316,7 @@ interface MaybeReconcilePaymentsOptions {
315
316
  }
316
317
  /**
317
318
  * The gate interval for the current pending set: the configured floor,
318
- * stretched by invoice age (2s while any pending invoice is under 2 minutes
319
+ * stretched by invoice age (3s while any pending invoice is under 2 minutes
319
320
  * old, 6s under 5 minutes, else 12s).
320
321
  */
321
322
  declare function reconcileIntervalSeconds(attempts: readonly ReconcilableAttempt[], now: number, minIntervalSeconds?: number): number;
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ import {
34
34
  startReconciler,
35
35
  typeOrmDb,
36
36
  webRequest
37
- } from "./chunk-PGZAFYN6.js";
37
+ } from "./chunk-67MZJBIF.js";
38
38
  export {
39
39
  HostError,
40
40
  HttpError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openreceive/http",
3
- "version": "0.4.12",
3
+ "version": "0.4.14",
4
4
  "description": "Node.js HTTP routes and payment storage for Bitcoin Lightning checkout, with optional USDT, USDC, SOL and ETH swaps.",
5
5
  "keywords": [
6
6
  "bitcoin",
@@ -17,8 +17,8 @@
17
17
  "main": "./dist/index.js",
18
18
  "types": "./dist/index.d.ts",
19
19
  "dependencies": {
20
- "@openreceive/core": "0.4.12",
21
- "@openreceive/node": "0.4.12"
20
+ "@openreceive/core": "0.4.14",
21
+ "@openreceive/node": "0.4.14"
22
22
  },
23
23
  "exports": {
24
24
  ".": {
@@ -49,7 +49,7 @@ same diagnostics redacted, always exit 0 — safe to share.
49
49
  ## 4. Paid but never settles
50
50
 
51
51
  - Settlement is opportunistic: any OpenReceive request runs one reconcile pass
52
- through a durable gate (min 2s between wallet scans, stretched by invoice
52
+ through a durable gate (min 3s between wallet scans, stretched by invoice
53
53
  age). A quiet server settles on the next request — or run the optional
54
54
  notification worker. No timer is missing; that is the design.
55
55
  - An unpaid attempt closes only after a successful wallet scan at/after expiry
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (BTCPay Server)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Connect a BTCPay Server store to a receive-only NWC wallet with the OpenReceive
6
6
  plugin, and optionally let payers pay BTCPay invoices with USDT, USDC, ETH or
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Django)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Add OpenReceive to a Django project — the app you are already working in. You
6
6
  do not need a copy of the OpenReceive source: the Python package is on PyPI
@@ -167,15 +167,19 @@ itself, and they hold for every integration.
167
167
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
168
168
  after leaving your page to fetch an address from another wallet. Three things
169
169
  must exist or that money is unreachable through your UI: a per-order URL your
170
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
171
- order-summary route to restore the order from, and the ATTEMPT.
170
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
171
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
172
+ restore the order from, and the ATTEMPT.
172
173
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
173
174
  reference alone opens on the method grid. Re-picking the same coin
174
175
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
175
176
  and the shadow invoice behind a swap lasts about half an hour, after which the
176
177
  same click mints a NEW deposit address and the refund is off-screen. Keep the
177
178
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
178
- such window. https://openreceive.org/guides/swap-refunds.md
179
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
180
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
181
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
182
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
179
183
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
180
184
  the price from `amount_for` and both drop-ins render it above the
181
185
  amount. Without it the checkout is a QR and "$1.00" with no sign of what the
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (FastAPI)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Add OpenReceive to a FastAPI application — the app you are already working in.
6
6
  You do not need a copy of the OpenReceive source: the engine is on PyPI
@@ -157,15 +157,19 @@ itself, and they hold for every integration.
157
157
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
158
158
  after leaving your page to fetch an address from another wallet. Three things
159
159
  must exist or that money is unreachable through your UI: a per-order URL your
160
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
161
- order-summary route to restore the order from, and the ATTEMPT.
160
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
161
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
162
+ restore the order from, and the ATTEMPT.
162
163
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
163
164
  reference alone opens on the method grid. Re-picking the same coin
164
165
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
165
166
  and the shadow invoice behind a swap lasts about half an hour, after which the
166
167
  same click mints a NEW deposit address and the refund is off-screen. Keep the
167
168
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
168
- such window. https://openreceive.org/guides/swap-refunds.md
169
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
170
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
171
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
172
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
169
173
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
170
174
  the price from `amount_for` and both drop-ins render it above the amount.
171
175
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Fastify)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Add OpenReceive to a Fastify application — the app you are already working in.
6
6
  You do not need a copy of the OpenReceive source: the packages are on npm, and
@@ -149,15 +149,19 @@ itself, and they hold for every integration.
149
149
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
150
150
  after leaving your page to fetch an address from another wallet. Three things
151
151
  must exist or that money is unreachable through your UI: a per-order URL your
152
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
153
- order-summary route to restore the order from, and the ATTEMPT.
152
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
153
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
154
+ restore the order from, and the ATTEMPT.
154
155
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
155
156
  reference alone opens on the method grid. Re-picking the same coin
156
157
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
157
158
  and the shadow invoice behind a swap lasts about half an hour, after which the
158
159
  same click mints a NEW deposit address and the refund is off-screen. Keep the
159
160
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
160
- such window. https://openreceive.org/guides/swap-refunds.md
161
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
162
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
163
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
164
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
161
165
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
162
166
  the price from `amountFor` and both drop-ins render it above the amount.
163
167
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -375,7 +379,9 @@ there is nothing else to generate. Details:
375
379
  No ORM? You can pass a bare driver handle (`pg`, `node:sqlite`,
376
380
  `better-sqlite3`) as the `db` in step 4. The scaffold has no flavor for it.
377
381
  Instead of scaffolding, run the same DDL once yourself, using
378
- `paymentsSchemaSql(dialect)` from `@openreceive/http`.
382
+ `paymentsSchemaSql(dialect)` from `@openreceive/http`. Your adapter already
383
+ pulls that package in, but this import is yours, so install it too:
384
+ `npm install @openreceive/http`.
379
385
 
380
386
  ### 3. Add wallet credentials
381
387
 
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Laravel)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Add OpenReceive to a Laravel application — the app you are already working in.
6
6
  You do not need a copy of the OpenReceive source: the package is on Packagist
@@ -158,15 +158,19 @@ itself, and they hold for every integration.
158
158
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
159
159
  after leaving your page to fetch an address from another wallet. Three things
160
160
  must exist or that money is unreachable through your UI: a per-order URL your
161
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
162
- order-summary route to restore the order from, and the ATTEMPT.
161
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
162
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
163
+ restore the order from, and the ATTEMPT.
163
164
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
164
165
  reference alone opens on the method grid. Re-picking the same coin
165
166
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
166
167
  and the shadow invoice behind a swap lasts about half an hour, after which the
167
168
  same click mints a NEW deposit address and the refund is off-screen. Keep the
168
169
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
169
- such window. https://openreceive.org/guides/swap-refunds.md
170
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
171
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
172
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
173
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
170
174
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
171
175
  the price from `amountFor` and both drop-ins render it above the
172
176
  amount. Without it the checkout is a QR and "$1.00" with no sign of what the
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Next.js)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Add OpenReceive to a Next.js App Router application — the app you are already
6
6
  working in. You do not need a copy of the OpenReceive source: the packages are
@@ -149,15 +149,19 @@ itself, and they hold for every integration.
149
149
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
150
150
  after leaving your page to fetch an address from another wallet. Three things
151
151
  must exist or that money is unreachable through your UI: a per-order URL your
152
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
153
- order-summary route to restore the order from, and the ATTEMPT.
152
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
153
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
154
+ restore the order from, and the ATTEMPT.
154
155
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
155
156
  reference alone opens on the method grid. Re-picking the same coin
156
157
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
157
158
  and the shadow invoice behind a swap lasts about half an hour, after which the
158
159
  same click mints a NEW deposit address and the refund is off-screen. Keep the
159
160
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
160
- such window. https://openreceive.org/guides/swap-refunds.md
161
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
162
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
163
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
164
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
161
165
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
162
166
  the price from `amountFor` and both drop-ins render it above the amount.
163
167
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -381,7 +385,9 @@ there is nothing else to generate. Details:
381
385
  No ORM? You can pass a bare driver handle (`pg`, `node:sqlite`,
382
386
  `better-sqlite3`) as the `db` in step 4. The scaffold has no flavor for it.
383
387
  Instead of scaffolding, run the same DDL once yourself, using
384
- `paymentsSchemaSql(dialect)` from `@openreceive/http`.
388
+ `paymentsSchemaSql(dialect)` from `@openreceive/http`. Your adapter already
389
+ pulls that package in, but this import is yours, so install it too:
390
+ `npm install @openreceive/http`.
385
391
 
386
392
  ### 3. Add wallet credentials
387
393
 
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Node.js)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Add OpenReceive to a Node application — the app you are already working in. You
6
6
  do not need a copy of the OpenReceive source: the packages are on npm, and the
@@ -146,15 +146,19 @@ itself, and they hold for every integration.
146
146
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
147
147
  after leaving your page to fetch an address from another wallet. Three things
148
148
  must exist or that money is unreachable through your UI: a per-order URL your
149
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
150
- order-summary route to restore the order from, and the ATTEMPT.
149
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
150
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
151
+ restore the order from, and the ATTEMPT.
151
152
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
152
153
  reference alone opens on the method grid. Re-picking the same coin
153
154
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
154
155
  and the shadow invoice behind a swap lasts about half an hour, after which the
155
156
  same click mints a NEW deposit address and the refund is off-screen. Keep the
156
157
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
157
- such window. https://openreceive.org/guides/swap-refunds.md
158
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
159
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
160
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
161
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
158
162
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
159
163
  the price from `amountFor` and both drop-ins render it above the amount.
160
164
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -366,7 +370,9 @@ there is nothing else to generate. Details:
366
370
  No ORM? You can pass a bare driver handle (`pg`, `node:sqlite`,
367
371
  `better-sqlite3`) as the `db` in step 4. The scaffold has no flavor for it.
368
372
  Instead of scaffolding, run the same DDL once yourself, using
369
- `paymentsSchemaSql(dialect)` from `@openreceive/http`.
373
+ `paymentsSchemaSql(dialect)` from `@openreceive/http`. Your adapter already
374
+ pulls that package in, but this import is yours, so install it too:
375
+ `npm install @openreceive/http`.
370
376
 
371
377
  ### 3. Add wallet credentials
372
378
 
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (PHP)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
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
@@ -171,7 +171,9 @@ itself, and they hold for every integration.
171
171
  and the shadow invoice behind a swap lasts about half an hour, after which the
172
172
  same click mints a NEW deposit address and the refund is off-screen. Keep the
173
173
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
174
- such window. https://openreceive.org/guides/swap-refunds.md
174
+ such window. On the element: the `resume-payment-hash` attribute, fed from
175
+ the `openreceive-state` event (`event.detail.state.payment_hash`).
176
+ https://openreceive.org/guides/swap-refunds.md
175
177
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
176
178
  the price from `amountFor` and the drop-in renders it above the amount.
177
179
  Without it the checkout is a QR and "$1.00" with no sign of what the dollar
@@ -651,7 +653,7 @@ use registry `icon_path` / tutorial `path` keys as browser URLs.
651
653
 
652
654
  Settlement runs on the request path. Every payment route first runs one bounded
653
655
  reconcile pass through the durable `openreceive_meta` gate. The gate allows at
654
- most one real wallet scan every 2 seconds, shared by every PHP process. You do
656
+ most one real wallet scan every 3 seconds, shared by every PHP process. You do
655
657
  not need a cron job. Tune or disable it with `Engine`'s
656
658
  `opportunisticReconcile` (`false`, or `['min_interval_seconds' => …]`).
657
659
 
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (Rails)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Add OpenReceive to a Rails application — the app you are already working in. You
6
6
  do not need a copy of the OpenReceive source: the gem is on RubyGems, the
@@ -153,15 +153,19 @@ itself, and they hold for every integration.
153
153
  late becomes `refund_required`, and the payer claims it on a SECOND VISIT,
154
154
  after leaving your page to fetch an address from another wallet. Three things
155
155
  must exist or that money is unreachable through your UI: a per-order URL your
156
- server serves (`/checkout/:reference` — `syncUrl` on the drop-ins), your own
157
- order-summary route to restore the order from, and the ATTEMPT.
156
+ server serves (`/checkout/:reference` — `syncUrl` on `<Checkout>`, `sync-url`
157
+ or `resumable` on `<openreceive-checkout>`), your own order-summary route to
158
+ restore the order from, and the ATTEMPT.
158
159
  `/checkouts/prepare` returns no attempts, so a checkout rebuilt from the
159
160
  reference alone opens on the method grid. Re-picking the same coin
160
161
  (`POST /swaps`) re-serves the committed attempt — but only while it is live,
161
162
  and the shadow invoice behind a swap lasts about half an hour, after which the
162
163
  same click mints a NEW deposit address and the refund is off-screen. Keep the
163
164
  `payment_hash` and reopen the attempt with `POST /swaps/status`, which has no
164
- such window. https://openreceive.org/guides/swap-refunds.md
165
+ such window. On the drop-ins: `resumePaymentHash`, fed from `onState`, on
166
+ `<Checkout>`; the `resume-payment-hash` attribute, fed from the
167
+ `openreceive-state` event (`event.detail.state.payment_hash`), on
168
+ `<openreceive-checkout>`. https://openreceive.org/guides/swap-refunds.md
165
169
  - Show the payer WHAT THEY ARE BUYING. Return an optional `description` beside
166
170
  the price from `config.amount_for` and both drop-ins render it above the
167
171
  amount. Without it the checkout is a QR and "$1.00" with no sign of what the
@@ -1,6 +1,6 @@
1
1
  # OpenReceive agent directions (WordPress + WooCommerce)
2
2
 
3
- These directions describe OpenReceive 0.4.12.
3
+ These directions describe OpenReceive 0.4.14.
4
4
 
5
5
  Install and configure the OpenReceive gateway in the existing WooCommerce
6
6
  store. Preserve its theme, checkout, customer accounts, order model and prices.