teppi-check 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -0
- package/npm/checks.d.ts +20 -0
- package/npm/checks.d.ts.map +1 -0
- package/npm/cli.d.ts +3 -0
- package/npm/cli.d.ts.map +1 -0
- package/npm/cli.js +7254 -0
- package/npm/index.d.ts +5 -0
- package/npm/index.d.ts.map +1 -0
- package/npm/index.js +7194 -0
- package/npm/probe.d.ts +31 -0
- package/npm/probe.d.ts.map +1 -0
- package/npm/report.d.ts +5 -0
- package/npm/report.d.ts.map +1 -0
- package/npm/terms.d.ts +31 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# teppi-check
|
|
2
|
+
|
|
3
|
+
Send one unpaid request to any paid endpoint and see what it actually advertises.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx teppi-check https://some-seller.example/v1/extract
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
No install and no dependencies: the published package is a single bundled file, so the validator
|
|
10
|
+
that reads a schema here is the same build that read it when the record was written.
|
|
11
|
+
|
|
12
|
+
It sends the request the scheduled prober sends. Both call one `handshake` function, and a test
|
|
13
|
+
runs the two side by side and fails if the bytes on the wire differ. That is what makes an entry
|
|
14
|
+
in the record something you can check rather than something you are asked to accept.
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
POST https://some-seller.example/v1/extract
|
|
18
|
+
2026-08-30T10:22:14.263Z
|
|
19
|
+
|
|
20
|
+
402 in 118ms
|
|
21
|
+
endpoint answered ok
|
|
22
|
+
asks for payment ok
|
|
23
|
+
payment terms parse ok
|
|
24
|
+
read from the body
|
|
25
|
+
offers at least one way to pay ok
|
|
26
|
+
1 option(s)
|
|
27
|
+
price is stated ok
|
|
28
|
+
network is stated ok
|
|
29
|
+
scheme is stated ok
|
|
30
|
+
payout address is stated ok
|
|
31
|
+
asset is stated ok
|
|
32
|
+
input schema is usable ok
|
|
33
|
+
output schema is usable fail
|
|
34
|
+
not declared, so no response can ever be checked against it
|
|
35
|
+
payment terms are not cached fail
|
|
36
|
+
no cache-control, so a proxy may serve stale terms
|
|
37
|
+
|
|
38
|
+
advertised
|
|
39
|
+
10000 0x2222...2222 on eip155:8453 via exact
|
|
40
|
+
|
|
41
|
+
request sha256:ba6f7ff0...0878
|
|
42
|
+
response sha256:0a83a213...2496
|
|
43
|
+
|
|
44
|
+
2 checks failed
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Why this exists
|
|
48
|
+
|
|
49
|
+
Teppi keeps the Machine Delivery Record: what happened when someone paid a machine service and
|
|
50
|
+
waited for something back. A record is only worth reading if a stranger can check it, so the
|
|
51
|
+
probe that produces it ships as a command anyone can run. Point it at an endpoint, compare the
|
|
52
|
+
output to the published entry, and decide for yourself.
|
|
53
|
+
|
|
54
|
+
This is the unpaid half of the probe. It reports what an endpoint promises. Whether it delivers
|
|
55
|
+
takes a purchase, which the full prober does on a schedule.
|
|
56
|
+
|
|
57
|
+
## What it checks
|
|
58
|
+
|
|
59
|
+
| Check | Fails when |
|
|
60
|
+
|---|---|
|
|
61
|
+
| endpoint answered | connection refused, DNS failure, or timeout |
|
|
62
|
+
| asks for payment | anything other than a 402 |
|
|
63
|
+
| payment terms parse | no readable terms in the `payment-required` header or the body |
|
|
64
|
+
| offers at least one way to pay | `accepts` is missing or empty |
|
|
65
|
+
| price, network, scheme, payout address, asset | any entry in `accepts` leaves one unstated |
|
|
66
|
+
| input schema is usable | absent, or present but not a compilable JSON Schema |
|
|
67
|
+
| output schema is usable | same. Without one, no response can ever be validated |
|
|
68
|
+
| payment terms are not cached | no `no-store` or `no-cache`, so a proxy may serve stale terms and stale nonces |
|
|
69
|
+
|
|
70
|
+
Terms are read from the `payment-required` header (base64 or plain JSON) or from the response
|
|
71
|
+
body, because deployed servers use both.
|
|
72
|
+
|
|
73
|
+
## Options
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
--method <verb> default POST
|
|
77
|
+
--body <json|@file> default {}
|
|
78
|
+
--json machine readable output
|
|
79
|
+
--timeout <ms> default 15000
|
|
80
|
+
--user-agent <ua> default node
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Exit codes: `0` every check passed, `1` a check failed, `2` the endpoint could not be reached.
|
|
84
|
+
|
|
85
|
+
Requests go over HTTPS only, apart from localhost.
|
|
86
|
+
|
|
87
|
+
## Use it in CI
|
|
88
|
+
|
|
89
|
+
```yaml
|
|
90
|
+
- run: npx teppi-check https://your-api.example/v1/thing
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The command fails the build when your own endpoint stops advertising what it should, which is
|
|
94
|
+
the failure mode nobody notices until buyers quietly stop calling.
|
|
95
|
+
|
|
96
|
+
## Library
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { probe } from 'teppi-check';
|
|
100
|
+
|
|
101
|
+
const result = await probe({ url: 'https://some-seller.example/v1/extract' });
|
|
102
|
+
console.log(result.verdict, result.checks);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
MIT.
|
package/npm/checks.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type PaymentTerms } from './terms.js';
|
|
2
|
+
export type CheckStatus = 'pass' | 'fail' | 'skip';
|
|
3
|
+
export type Check = {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly label: string;
|
|
6
|
+
readonly status: CheckStatus;
|
|
7
|
+
readonly detail?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function schemaCheck(id: string, label: string, schema: unknown): Check;
|
|
10
|
+
export type HandshakeInput = {
|
|
11
|
+
readonly status: number;
|
|
12
|
+
readonly headers: Headers;
|
|
13
|
+
readonly terms: PaymentTerms | null;
|
|
14
|
+
readonly parseError: string | null;
|
|
15
|
+
readonly source: string;
|
|
16
|
+
};
|
|
17
|
+
export declare function runHandshakeChecks(input: HandshakeInput): Check[];
|
|
18
|
+
export declare function unreachable(reason: string): Check[];
|
|
19
|
+
export declare function verdictOf(checks: readonly Check[]): 'pass' | 'fail';
|
|
20
|
+
//# sourceMappingURL=checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.d.ts","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAEA,OAAO,EAA2B,KAAK,YAAY,EAAsB,MAAM,mBAAmB,CAAC;AAGnG,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEnD,MAAM,MAAM,KAAK,GAAG;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAqBF,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,KAAK,CAa7E;AAED,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB,CAAC;AA+BF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,KAAK,EAAE,CA4CjE;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,CAEnD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,MAAM,GAAG,MAAM,CAEnE"}
|
package/npm/cli.d.ts
ADDED
package/npm/cli.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|