@402flow/sdk 0.1.0-alpha.23 → 0.1.0-alpha.25
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.
- package/README.md +151 -3
- package/dist/contracts.d.ts +1167 -130
- package/dist/contracts.js +67 -0
- package/dist/contracts.js.map +1 -1
- package/dist/executors.d.ts +27 -0
- package/dist/executors.js +2 -0
- package/dist/executors.js.map +1 -0
- package/dist/harness-instructions.d.ts +8 -0
- package/dist/harness-instructions.js.map +1 -1
- package/dist/http-utils.d.ts +1 -0
- package/dist/http-utils.js +12 -0
- package/dist/http-utils.js.map +1 -0
- package/dist/index.d.ts +14 -3
- package/dist/index.js +119 -28
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -324,6 +324,152 @@ if (prepared.kind === 'ready') {
|
|
|
324
324
|
|
|
325
325
|
If preparation does not return `kind === 'ready'`, that is not necessarily an error. It means this exact request did not currently resolve to a payable executable path. The caller can accept that result, run a normal non-paid path, or revise and prepare again.
|
|
326
326
|
|
|
327
|
+
### Delegated Execution With Custom Executors
|
|
328
|
+
|
|
329
|
+
`executePreparedRequest()` now supports governed delegated execution through a caller-supplied executor interface.
|
|
330
|
+
|
|
331
|
+
This lets the SDK keep authorization, policy, receipts, and final outcome normalization in the 402flow control plane while handing the final paid merchant call to a provider-specific executor owned by the host app or a separate integration package.
|
|
332
|
+
|
|
333
|
+
The core SDK stays provider-neutral. That means third-party payment clients such as Dexter or pay.sh should live in the host app's own dependency graph, not inside `@402flow/sdk` itself.
|
|
334
|
+
|
|
335
|
+
The flow is:
|
|
336
|
+
|
|
337
|
+
1. prepare the exact request locally with `preparePaidRequest()`
|
|
338
|
+
2. ask the control plane to authorize delegated execution
|
|
339
|
+
3. if authorized, let the supplied executor perform the actual paid merchant request
|
|
340
|
+
4. finalize the normalized executor result back through the control plane
|
|
341
|
+
5. return the same stable SDK result or `FetchPaidError` contract the caller already uses elsewhere
|
|
342
|
+
|
|
343
|
+
If the control plane denies authorization, the delegated executor is never invoked.
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
import {
|
|
347
|
+
createJsonRequestBody,
|
|
348
|
+
type PreparedRequestExecutorInput,
|
|
349
|
+
type PreparedRequestExecutor,
|
|
350
|
+
} from '@402flow/sdk';
|
|
351
|
+
|
|
352
|
+
async function callDexter(
|
|
353
|
+
prepared: PreparedRequestExecutorInput['prepared'],
|
|
354
|
+
) {
|
|
355
|
+
// Replace this with your real Dexter SDK call.
|
|
356
|
+
return {
|
|
357
|
+
status: 200,
|
|
358
|
+
body: { ok: true },
|
|
359
|
+
settlementReference: 'settlement-ref-1',
|
|
360
|
+
paymentReference: 'payment-ref-1',
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function mapDexterResult(
|
|
365
|
+
prepared: PreparedRequestExecutorInput['prepared'],
|
|
366
|
+
result: Awaited<ReturnType<typeof callDexter>>,
|
|
367
|
+
) {
|
|
368
|
+
return {
|
|
369
|
+
protocol: prepared.protocol,
|
|
370
|
+
executionStatus: 'succeeded' as const,
|
|
371
|
+
settlementEvidenceClass: 'settled' as const,
|
|
372
|
+
merchantOutcome: 'success_response' as const,
|
|
373
|
+
merchantResponse: {
|
|
374
|
+
status: result.status,
|
|
375
|
+
headers: {
|
|
376
|
+
'content-type': 'application/json',
|
|
377
|
+
},
|
|
378
|
+
body: JSON.stringify(result.body),
|
|
379
|
+
},
|
|
380
|
+
settlementReference: result.settlementReference,
|
|
381
|
+
paymentReference: result.paymentReference,
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const dexterExecutor: PreparedRequestExecutor = {
|
|
386
|
+
provider: 'dexter',
|
|
387
|
+
async execute({ prepared }) {
|
|
388
|
+
const dexterResult = await callDexter(prepared);
|
|
389
|
+
return mapDexterResult(prepared, dexterResult);
|
|
390
|
+
},
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
const prepared = await client.preparePaidRequest(
|
|
394
|
+
'https://merchant.example.com/images/generate',
|
|
395
|
+
{
|
|
396
|
+
method: 'POST',
|
|
397
|
+
headers: {
|
|
398
|
+
'content-type': 'application/json',
|
|
399
|
+
},
|
|
400
|
+
body: createJsonRequestBody({
|
|
401
|
+
prompt: 'foggy coastline',
|
|
402
|
+
}),
|
|
403
|
+
},
|
|
404
|
+
);
|
|
405
|
+
|
|
406
|
+
if (prepared.kind === 'ready') {
|
|
407
|
+
const result = await client.executePreparedRequest(prepared, {
|
|
408
|
+
description: 'generate image through delegated execution',
|
|
409
|
+
executionProvider: 'dexter',
|
|
410
|
+
executor: dexterExecutor,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
console.log('paid response status:', result.response.status);
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
This snippet shows the intended split directly: your host-owned code does the provider call and maps it into the delegated execution contract, while the SDK still owns authorize, finalize, and the outward result shape. For a real host-owned Dexter integration that performs the paid call, see `third-party-executors/examples/dexter-delegated-executor.mjs`.
|
|
418
|
+
|
|
419
|
+
Responsibility split:
|
|
420
|
+
|
|
421
|
+
1. the SDK asks the control plane for delegated authorization
|
|
422
|
+
2. if authorized, the SDK invokes your executor
|
|
423
|
+
3. your executor performs the provider-specific paid request and returns `SdkDelegatedExecutionResult`
|
|
424
|
+
4. the SDK finalizes that result with the control plane
|
|
425
|
+
5. the SDK returns the same outward `PaidResponse` or `FetchPaidError` contract as the direct path
|
|
426
|
+
|
|
427
|
+
If your host app wants to execute through Dexter, pay.sh, or another provider, that integration should install and own the third-party SDK directly. `@402flow/sdk` only owns the executor contract and the governed authorize/finalize flow.
|
|
428
|
+
|
|
429
|
+
The repo keeps third-party executor proofs in the separate `third-party-executors/` package so the main `@402flow/sdk` install path stays provider-neutral.
|
|
430
|
+
|
|
431
|
+
That package is a private repo-local set of reference adapters, not part of the published `@402flow/sdk` package itself.
|
|
432
|
+
|
|
433
|
+
Current repo-local adapters:
|
|
434
|
+
|
|
435
|
+
| Adapter | Current scope | Key dependencies |
|
|
436
|
+
| --- | --- | --- |
|
|
437
|
+
| Dexter | Host-owned delegated execution against Dexter's paid request client | `@dexterai/x402` |
|
|
438
|
+
| pay.sh | Host-owned x402 Solana exact delegated execution | `@x402/core`, `@x402/svm`, `@solana/kit` |
|
|
439
|
+
|
|
440
|
+
The pay.sh adapter intentionally does not depend on `@solana/pay` today. The current proof targets pay.sh's x402 Solana exact flow, so challenge parsing, signed payment payload creation, and paid response parsing come from `@x402/core` plus `@x402/svm`, while `@solana/kit` only supplies the signer. `@solana/pay` becomes relevant when the repo adds a separate Solana Pay or MPP-specific adapter path.
|
|
441
|
+
|
|
442
|
+
For a repo-wide verification pass from the SDK root, run:
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
npm run install:all
|
|
446
|
+
npm run check:all
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
`npm run install:all` installs both the main SDK package and the separate `third-party-executors` package from the SDK root. `npm run check` still validates only the main SDK package. `npm run check:all` runs the main SDK checks first, then runs the separate `third-party-executors` package checks from the top level.
|
|
450
|
+
|
|
451
|
+
For a repo-local host-owned Dexter example, run:
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
cd third-party-executors
|
|
455
|
+
npm install
|
|
456
|
+
export DEXTER_EVM_PRIVATE_KEY="..."
|
|
457
|
+
|
|
458
|
+
npm run example:dexter-delegated-executor -- \
|
|
459
|
+
"https://merchant.example.com/paid-endpoint" \
|
|
460
|
+
'{"topic":"sdk integration rollout","audience":"platform engineers","format":"bullets"}'
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
For a repo-local host-owned pay.sh x402 example, run:
|
|
464
|
+
|
|
465
|
+
```bash
|
|
466
|
+
cd third-party-executors
|
|
467
|
+
npm install
|
|
468
|
+
npm run example:pay-sh-delegated-executor -- --help
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
The pay.sh example expects the standard SDK auth environment plus a local Solana signer path in `PAY_SH_SOLANA_KEYPAIR_PATH`. Run the `--help` form first to see the full required environment and argument contract.
|
|
472
|
+
|
|
327
473
|
## Prepared Result Semantics
|
|
328
474
|
|
|
329
475
|
`preparePaidRequest()` separates request checking from paid execution.
|
|
@@ -477,8 +623,10 @@ When unset, first-party fixtures default to the self-hosted demo merchant at `ht
|
|
|
477
623
|
## Publish
|
|
478
624
|
|
|
479
625
|
```bash
|
|
480
|
-
npm install
|
|
481
|
-
npm run check
|
|
626
|
+
npm run install:all
|
|
627
|
+
npm run check:all
|
|
482
628
|
npm run pack:check
|
|
483
629
|
npm publish --access public
|
|
484
|
-
```
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
`npm publish` now also runs `npm run check:all` through the root `prepublishOnly` hook, so the repo-wide test pass is enforced before publish even if you skip that step manually.
|