@grantex/conformance 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 +115 -0
- package/dist/cleanup.d.ts +15 -0
- package/dist/cleanup.d.ts.map +1 -0
- package/dist/cleanup.js +62 -0
- package/dist/cleanup.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +41 -0
- package/dist/cli.js.map +1 -0
- package/dist/flow.d.ts +29 -0
- package/dist/flow.d.ts.map +1 -0
- package/dist/flow.js +77 -0
- package/dist/flow.js.map +1 -0
- package/dist/helpers.d.ts +15 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +70 -0
- package/dist/helpers.js.map +1 -0
- package/dist/http-client.d.ts +15 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +71 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter.d.ts +4 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +72 -0
- package/dist/reporter.js.map +1 -0
- package/dist/runner.d.ts +3 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +160 -0
- package/dist/runner.js.map +1 -0
- package/dist/suites/agents.d.ts +3 -0
- package/dist/suites/agents.d.ts.map +1 -0
- package/dist/suites/agents.js +53 -0
- package/dist/suites/agents.js.map +1 -0
- package/dist/suites/anomalies.d.ts +3 -0
- package/dist/suites/anomalies.d.ts.map +1 -0
- package/dist/suites/anomalies.js +27 -0
- package/dist/suites/anomalies.js.map +1 -0
- package/dist/suites/audit.d.ts +3 -0
- package/dist/suites/audit.d.ts.map +1 -0
- package/dist/suites/audit.js +70 -0
- package/dist/suites/audit.js.map +1 -0
- package/dist/suites/authorize.d.ts +3 -0
- package/dist/suites/authorize.d.ts.map +1 -0
- package/dist/suites/authorize.js +54 -0
- package/dist/suites/authorize.js.map +1 -0
- package/dist/suites/compliance.d.ts +3 -0
- package/dist/suites/compliance.d.ts.map +1 -0
- package/dist/suites/compliance.js +33 -0
- package/dist/suites/compliance.js.map +1 -0
- package/dist/suites/delegation.d.ts +3 -0
- package/dist/suites/delegation.d.ts.map +1 -0
- package/dist/suites/delegation.js +120 -0
- package/dist/suites/delegation.js.map +1 -0
- package/dist/suites/grants.d.ts +3 -0
- package/dist/suites/grants.d.ts.map +1 -0
- package/dist/suites/grants.js +34 -0
- package/dist/suites/grants.js.map +1 -0
- package/dist/suites/health.d.ts +3 -0
- package/dist/suites/health.d.ts.map +1 -0
- package/dist/suites/health.js +30 -0
- package/dist/suites/health.js.map +1 -0
- package/dist/suites/policies.d.ts +3 -0
- package/dist/suites/policies.d.ts.map +1 -0
- package/dist/suites/policies.js +51 -0
- package/dist/suites/policies.js.map +1 -0
- package/dist/suites/scim.d.ts +3 -0
- package/dist/suites/scim.d.ts.map +1 -0
- package/dist/suites/scim.js +64 -0
- package/dist/suites/scim.js.map +1 -0
- package/dist/suites/security.d.ts +3 -0
- package/dist/suites/security.d.ts.map +1 -0
- package/dist/suites/security.js +69 -0
- package/dist/suites/security.js.map +1 -0
- package/dist/suites/sso.d.ts +3 -0
- package/dist/suites/sso.d.ts.map +1 -0
- package/dist/suites/sso.js +35 -0
- package/dist/suites/sso.js.map +1 -0
- package/dist/suites/token.d.ts +3 -0
- package/dist/suites/token.d.ts.map +1 -0
- package/dist/suites/token.js +61 -0
- package/dist/suites/token.js.map +1 -0
- package/dist/suites/tokens.d.ts +3 -0
- package/dist/suites/tokens.d.ts.map +1 -0
- package/dist/suites/tokens.js +43 -0
- package/dist/suites/tokens.js.map +1 -0
- package/dist/suites/webhooks.d.ts +3 -0
- package/dist/suites/webhooks.d.ts.map +1 -0
- package/dist/suites/webhooks.js +36 -0
- package/dist/suites/webhooks.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @grantex/conformance
|
|
2
|
+
|
|
3
|
+
Conformance test suite for the [Grantex protocol](https://grantex.dev). Validates that a server implementation correctly implements the Grantex specification by running black-box HTTP tests against a live endpoint.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @grantex/conformance --base-url http://localhost:3001 --api-key YOUR_API_KEY
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @grantex/conformance
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
grantex-conformance --base-url URL --api-key KEY [options]
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
--base-url <url> Base URL of the Grantex auth service (required)
|
|
24
|
+
--api-key <key> API key for authentication (required)
|
|
25
|
+
--suite <name> Run a specific suite only
|
|
26
|
+
--include <ext,...> Include optional extensions (comma-separated)
|
|
27
|
+
--format <format> Output format: text or json (default: text)
|
|
28
|
+
--bail Stop on first failure
|
|
29
|
+
-h, --help Display help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Run all core suites
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
grantex-conformance --base-url http://localhost:3001 --api-key sk_test_xxx
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Run a single suite
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
grantex-conformance --base-url http://localhost:3001 --api-key sk_test_xxx --suite health
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Include optional extensions
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
grantex-conformance --base-url http://localhost:3001 --api-key sk_test_xxx \
|
|
48
|
+
--include policies,webhooks,scim
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### JSON output
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
grantex-conformance --base-url http://localhost:3001 --api-key sk_test_xxx --format json
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Core Suites (37 tests)
|
|
58
|
+
|
|
59
|
+
| Suite | Tests | Description |
|
|
60
|
+
|-------|-------|-------------|
|
|
61
|
+
| `health` | 2 | Health check endpoint and JWKS key validation |
|
|
62
|
+
| `agents` | 5 | Agent registration, listing, retrieval, update, deletion |
|
|
63
|
+
| `authorize` | 4 | Authorization request creation and consent flow |
|
|
64
|
+
| `token` | 3 | Token exchange, invalid code rejection, code reuse prevention |
|
|
65
|
+
| `tokens` | 4 | Token verification, revocation, post-revoke verification |
|
|
66
|
+
| `grants` | 4 | Grant listing, retrieval, revocation, status validation |
|
|
67
|
+
| `delegation` | 5 | Grant delegation, JWT claims, scope enforcement, depth limits, cascade revocation |
|
|
68
|
+
| `audit` | 5 | Audit log creation, hash chain integrity, entry retrieval |
|
|
69
|
+
| `security` | 5 | Auth enforcement, JWKS algorithm, scope escalation prevention, audit immutability |
|
|
70
|
+
|
|
71
|
+
## Optional Extensions
|
|
72
|
+
|
|
73
|
+
| Suite | Tests | Description |
|
|
74
|
+
|-------|-------|-------------|
|
|
75
|
+
| `policies` | 5 | Policy CRUD operations |
|
|
76
|
+
| `webhooks` | 3 | Webhook registration and management |
|
|
77
|
+
| `scim` | 6 | SCIM 2.0 provisioning endpoints |
|
|
78
|
+
| `sso` | 4 | SSO configuration and flow |
|
|
79
|
+
| `anomalies` | 3 | Anomaly detection and acknowledgement |
|
|
80
|
+
| `compliance` | 4 | Compliance reporting and evidence export |
|
|
81
|
+
|
|
82
|
+
## Programmatic API
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
import { runConformanceTests } from '@grantex/conformance/runner';
|
|
86
|
+
import { reportJson } from '@grantex/conformance/reporter';
|
|
87
|
+
|
|
88
|
+
const report = await runConformanceTests({
|
|
89
|
+
baseUrl: 'http://localhost:3001',
|
|
90
|
+
apiKey: 'sk_test_xxx',
|
|
91
|
+
format: 'json',
|
|
92
|
+
bail: false,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
console.log(reportJson(report));
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Server Requirements
|
|
99
|
+
|
|
100
|
+
- The server must implement the Grantex protocol endpoints
|
|
101
|
+
- An API key with sufficient permissions to create agents, authorize, and manage grants
|
|
102
|
+
- For sandbox mode servers, authorization codes are returned directly
|
|
103
|
+
- For non-sandbox servers, the `/v1/consent/:id/approve` endpoint must be available
|
|
104
|
+
|
|
105
|
+
## Exit Codes
|
|
106
|
+
|
|
107
|
+
| Code | Meaning |
|
|
108
|
+
|------|---------|
|
|
109
|
+
| `0` | All tests passed |
|
|
110
|
+
| `1` | One or more tests failed |
|
|
111
|
+
| `2` | Configuration or runtime error |
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
Apache-2.0
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ConformanceHttpClient } from './http-client.js';
|
|
2
|
+
export declare class CleanupTracker {
|
|
3
|
+
private readonly http;
|
|
4
|
+
private agents;
|
|
5
|
+
private grants;
|
|
6
|
+
private policies;
|
|
7
|
+
private webhooks;
|
|
8
|
+
constructor(http: ConformanceHttpClient);
|
|
9
|
+
trackAgent(id: string): void;
|
|
10
|
+
trackGrant(id: string): void;
|
|
11
|
+
trackPolicy(id: string): void;
|
|
12
|
+
trackWebhook(id: string): void;
|
|
13
|
+
teardown(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=cleanup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.d.ts","sourceRoot":"","sources":["../src/cleanup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAE9D,qBAAa,cAAc;IAMb,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,QAAQ,CAAgB;gBAEH,IAAI,EAAE,qBAAqB;IAExD,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI5B,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI5B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAI7B,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAIxB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAoChC"}
|
package/dist/cleanup.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export class CleanupTracker {
|
|
2
|
+
http;
|
|
3
|
+
agents = [];
|
|
4
|
+
grants = [];
|
|
5
|
+
policies = [];
|
|
6
|
+
webhooks = [];
|
|
7
|
+
constructor(http) {
|
|
8
|
+
this.http = http;
|
|
9
|
+
}
|
|
10
|
+
trackAgent(id) {
|
|
11
|
+
this.agents.push(id);
|
|
12
|
+
}
|
|
13
|
+
trackGrant(id) {
|
|
14
|
+
this.grants.push(id);
|
|
15
|
+
}
|
|
16
|
+
trackPolicy(id) {
|
|
17
|
+
this.policies.push(id);
|
|
18
|
+
}
|
|
19
|
+
trackWebhook(id) {
|
|
20
|
+
this.webhooks.push(id);
|
|
21
|
+
}
|
|
22
|
+
async teardown() {
|
|
23
|
+
// Delete in reverse order of dependency: grants → agents → policies → webhooks
|
|
24
|
+
for (const id of this.grants) {
|
|
25
|
+
try {
|
|
26
|
+
await this.http.delete(`/v1/grants/${id}`);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// best-effort
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
for (const id of this.agents) {
|
|
33
|
+
try {
|
|
34
|
+
await this.http.delete(`/v1/agents/${id}`);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// best-effort
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const id of this.policies) {
|
|
41
|
+
try {
|
|
42
|
+
await this.http.delete(`/v1/policies/${id}`);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// best-effort
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const id of this.webhooks) {
|
|
49
|
+
try {
|
|
50
|
+
await this.http.delete(`/v1/webhooks/${id}`);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// best-effort
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
this.agents = [];
|
|
57
|
+
this.grants = [];
|
|
58
|
+
this.policies = [];
|
|
59
|
+
this.webhooks = [];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=cleanup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cleanup.js","sourceRoot":"","sources":["../src/cleanup.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,cAAc;IAMI;IALrB,MAAM,GAAa,EAAE,CAAC;IACtB,MAAM,GAAa,EAAE,CAAC;IACtB,QAAQ,GAAa,EAAE,CAAC;IACxB,QAAQ,GAAa,EAAE,CAAC;IAEhC,YAA6B,IAA2B;QAA3B,SAAI,GAAJ,IAAI,CAAuB;IAAG,CAAC;IAE5D,UAAU,CAAC,EAAU;QACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC;IAED,UAAU,CAAC,EAAU;QACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC;IAED,WAAW,CAAC,EAAU;QACpB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;IAED,YAAY,CAAC,EAAU;QACrB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,QAAQ;QACZ,+EAA+E;QAC/E,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc;YAChB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc;YAChB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc;YAChB,CAAC;QACH,CAAC;QACD,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc;YAChB,CAAC;QACH,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;CACF"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAKA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CA8CzC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { runConformanceTests } from './runner.js';
|
|
3
|
+
import { reportText, reportJson } from './reporter.js';
|
|
4
|
+
export async function run() {
|
|
5
|
+
const program = new Command();
|
|
6
|
+
program
|
|
7
|
+
.name('grantex-conformance')
|
|
8
|
+
.description('Conformance test suite for the Grantex protocol')
|
|
9
|
+
.requiredOption('--base-url <url>', 'Base URL of the Grantex auth service')
|
|
10
|
+
.requiredOption('--api-key <key>', 'API key for authentication')
|
|
11
|
+
.option('--suite <name>', 'Run a specific suite only')
|
|
12
|
+
.option('--include <extensions>', 'Include optional extensions (comma-separated)')
|
|
13
|
+
.option('--format <format>', 'Output format: text or json', 'text')
|
|
14
|
+
.option('--bail', 'Stop on first failure', false)
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
const config = {
|
|
17
|
+
baseUrl: opts.baseUrl.replace(/\/$/, ''),
|
|
18
|
+
apiKey: opts.apiKey,
|
|
19
|
+
suite: opts.suite,
|
|
20
|
+
include: opts.include ? opts.include.split(',').map((s) => s.trim()) : undefined,
|
|
21
|
+
format: opts.format === 'json' ? 'json' : 'text',
|
|
22
|
+
bail: opts.bail,
|
|
23
|
+
};
|
|
24
|
+
try {
|
|
25
|
+
const report = await runConformanceTests(config);
|
|
26
|
+
if (config.format === 'json') {
|
|
27
|
+
process.stdout.write(reportJson(report) + '\n');
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
process.stdout.write(reportText(report));
|
|
31
|
+
}
|
|
32
|
+
process.exit(report.summary.failed > 0 ? 1 : 0);
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
36
|
+
process.exit(2);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
await program.parseAsync(process.argv);
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,qBAAqB,CAAC;SAC3B,WAAW,CAAC,iDAAiD,CAAC;SAC9D,cAAc,CAAC,kBAAkB,EAAE,sCAAsC,CAAC;SAC1E,cAAc,CAAC,iBAAiB,EAAE,4BAA4B,CAAC;SAC/D,MAAM,CAAC,gBAAgB,EAAE,2BAA2B,CAAC;SACrD,MAAM,CAAC,wBAAwB,EAAE,+CAA+C,CAAC;SACjF,MAAM,CAAC,mBAAmB,EAAE,6BAA6B,EAAE,MAAM,CAAC;SAClE,MAAM,CAAC,QAAQ,EAAE,uBAAuB,EAAE,KAAK,CAAC;SAChD,MAAM,CAAC,KAAK,EAAE,IAOd,EAAE,EAAE;QACH,MAAM,MAAM,GAAc;YACxB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;YACxC,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;YAChF,MAAM,EAAE,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;YAChD,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,CAAC;YAEjD,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;YAClD,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YAC3C,CAAC;YAED,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACrF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;IAEL,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC"}
|
package/dist/flow.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ConformanceHttpClient } from './http-client.js';
|
|
2
|
+
import type { CleanupTracker } from './cleanup.js';
|
|
3
|
+
export interface FlowResult {
|
|
4
|
+
agentId: string;
|
|
5
|
+
agentDid: string;
|
|
6
|
+
authRequestId: string;
|
|
7
|
+
code: string;
|
|
8
|
+
grantToken: string;
|
|
9
|
+
refreshToken: string;
|
|
10
|
+
grantId: string;
|
|
11
|
+
scopes: string[];
|
|
12
|
+
expiresAt: string;
|
|
13
|
+
principalId: string;
|
|
14
|
+
}
|
|
15
|
+
export interface FlowOptions {
|
|
16
|
+
/** Use an existing agent instead of creating a new one */
|
|
17
|
+
agentId?: string;
|
|
18
|
+
agentDid?: string;
|
|
19
|
+
agentName?: string;
|
|
20
|
+
scopes?: string[];
|
|
21
|
+
principalId?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare class AuthFlowHelper {
|
|
24
|
+
private readonly http;
|
|
25
|
+
private readonly cleanup;
|
|
26
|
+
constructor(http: ConformanceHttpClient, cleanup: CleanupTracker);
|
|
27
|
+
executeFullFlow(options?: FlowOptions): Promise<FlowResult>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AA8BD,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;gBADP,IAAI,EAAE,qBAAqB,EAC3B,OAAO,EAAE,cAAc;IAGpC,eAAe,CAAC,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;CA2ElE"}
|
package/dist/flow.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
export class AuthFlowHelper {
|
|
2
|
+
http;
|
|
3
|
+
cleanup;
|
|
4
|
+
constructor(http, cleanup) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
this.cleanup = cleanup;
|
|
7
|
+
}
|
|
8
|
+
async executeFullFlow(options) {
|
|
9
|
+
const scopes = options?.scopes ?? ['read', 'write'];
|
|
10
|
+
const principalId = options?.principalId ?? `principal-${Date.now()}`;
|
|
11
|
+
let agentId;
|
|
12
|
+
let agentDid;
|
|
13
|
+
if (options?.agentId && options.agentDid) {
|
|
14
|
+
// Reuse existing agent
|
|
15
|
+
agentId = options.agentId;
|
|
16
|
+
agentDid = options.agentDid;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
// Create agent
|
|
20
|
+
const agentName = options?.agentName ?? `conformance-agent-${Date.now()}`;
|
|
21
|
+
const agentRes = await this.http.post('/v1/agents', {
|
|
22
|
+
name: agentName,
|
|
23
|
+
scopes,
|
|
24
|
+
});
|
|
25
|
+
if (agentRes.status !== 201) {
|
|
26
|
+
throw new Error(`Failed to create agent: ${agentRes.status} ${agentRes.rawText}`);
|
|
27
|
+
}
|
|
28
|
+
agentId = agentRes.body.agentId;
|
|
29
|
+
agentDid = agentRes.body.did;
|
|
30
|
+
this.cleanup.trackAgent(agentId);
|
|
31
|
+
}
|
|
32
|
+
// Authorize
|
|
33
|
+
const authRes = await this.http.post('/v1/authorize', {
|
|
34
|
+
agentId,
|
|
35
|
+
principalId,
|
|
36
|
+
scopes,
|
|
37
|
+
});
|
|
38
|
+
if (authRes.status !== 201) {
|
|
39
|
+
throw new Error(`Failed to authorize: ${authRes.status} ${authRes.rawText}`);
|
|
40
|
+
}
|
|
41
|
+
const { authRequestId } = authRes.body;
|
|
42
|
+
// Get code — sandbox auto-provides it, otherwise approve consent
|
|
43
|
+
let code;
|
|
44
|
+
if (authRes.body.code) {
|
|
45
|
+
code = authRes.body.code;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const consentRes = await this.http.requestPublic('POST', `/v1/consent/${authRequestId}/approve`);
|
|
49
|
+
if (consentRes.status !== 200) {
|
|
50
|
+
throw new Error(`Failed to approve consent: ${consentRes.status} ${consentRes.rawText}`);
|
|
51
|
+
}
|
|
52
|
+
code = consentRes.body.code;
|
|
53
|
+
}
|
|
54
|
+
// Exchange code for token
|
|
55
|
+
const tokenRes = await this.http.post('/v1/token', {
|
|
56
|
+
code,
|
|
57
|
+
agentId,
|
|
58
|
+
});
|
|
59
|
+
if (tokenRes.status !== 201) {
|
|
60
|
+
throw new Error(`Failed to exchange token: ${tokenRes.status} ${tokenRes.rawText}`);
|
|
61
|
+
}
|
|
62
|
+
this.cleanup.trackGrant(tokenRes.body.grantId);
|
|
63
|
+
return {
|
|
64
|
+
agentId,
|
|
65
|
+
agentDid,
|
|
66
|
+
authRequestId,
|
|
67
|
+
code,
|
|
68
|
+
grantToken: tokenRes.body.grantToken,
|
|
69
|
+
refreshToken: tokenRes.body.refreshToken,
|
|
70
|
+
grantId: tokenRes.body.grantId,
|
|
71
|
+
scopes: tokenRes.body.scopes,
|
|
72
|
+
expiresAt: tokenRes.body.expiresAt,
|
|
73
|
+
principalId,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=flow.js.map
|
package/dist/flow.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HttpResponse, TestResult } from './types.js';
|
|
2
|
+
export declare function test(name: string, specRef: string, fn: () => Promise<void>): Promise<TestResult>;
|
|
3
|
+
export declare function skip(name: string, specRef: string, reason: string): TestResult;
|
|
4
|
+
export declare class AssertionError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
export declare function expectStatus(res: HttpResponse, expected: number): void;
|
|
8
|
+
export declare function expectKeys(body: unknown, keys: string[]): void;
|
|
9
|
+
export declare function expectString(val: unknown, field: string): void;
|
|
10
|
+
export declare function expectArray(val: unknown, field: string): void;
|
|
11
|
+
export declare function expectBoolean(val: unknown, field: string): void;
|
|
12
|
+
export declare function expectIsoDate(val: unknown, field: string): void;
|
|
13
|
+
export declare function expectEqual(actual: unknown, expected: unknown, field: string): void;
|
|
14
|
+
export declare function expectIncludes(arr: unknown[], value: unknown, field: string): void;
|
|
15
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAc,MAAM,YAAY,CAAC;AAEvE,wBAAsB,IAAI,CACxB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GACtB,OAAO,CAAC,UAAU,CAAC,CASrB;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAE9E;AAED,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAMtE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAS9D;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI9D;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI7D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI/D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQ/D;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAMnF;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAMlF"}
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export async function test(name, specRef, fn) {
|
|
2
|
+
const start = Date.now();
|
|
3
|
+
try {
|
|
4
|
+
await fn();
|
|
5
|
+
return { name, status: 'pass', durationMs: Date.now() - start, specRef };
|
|
6
|
+
}
|
|
7
|
+
catch (err) {
|
|
8
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
9
|
+
return { name, status: 'fail', durationMs: Date.now() - start, specRef, error };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function skip(name, specRef, reason) {
|
|
13
|
+
return { name, status: 'skip', durationMs: 0, specRef, error: reason };
|
|
14
|
+
}
|
|
15
|
+
export class AssertionError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'AssertionError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function expectStatus(res, expected) {
|
|
22
|
+
if (res.status !== expected) {
|
|
23
|
+
throw new AssertionError(`Expected status ${expected}, got ${res.status}: ${res.rawText.slice(0, 200)}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function expectKeys(body, keys) {
|
|
27
|
+
if (typeof body !== 'object' || body === null) {
|
|
28
|
+
throw new AssertionError(`Expected object, got ${typeof body}`);
|
|
29
|
+
}
|
|
30
|
+
const obj = body;
|
|
31
|
+
const missing = keys.filter((k) => !(k in obj));
|
|
32
|
+
if (missing.length > 0) {
|
|
33
|
+
throw new AssertionError(`Missing keys: ${missing.join(', ')}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function expectString(val, field) {
|
|
37
|
+
if (typeof val !== 'string' || val.length === 0) {
|
|
38
|
+
throw new AssertionError(`Expected non-empty string for "${field}", got ${JSON.stringify(val)}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function expectArray(val, field) {
|
|
42
|
+
if (!Array.isArray(val)) {
|
|
43
|
+
throw new AssertionError(`Expected array for "${field}", got ${typeof val}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function expectBoolean(val, field) {
|
|
47
|
+
if (typeof val !== 'boolean') {
|
|
48
|
+
throw new AssertionError(`Expected boolean for "${field}", got ${typeof val}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function expectIsoDate(val, field) {
|
|
52
|
+
if (typeof val !== 'string') {
|
|
53
|
+
throw new AssertionError(`Expected ISO date string for "${field}", got ${typeof val}`);
|
|
54
|
+
}
|
|
55
|
+
const d = new Date(val);
|
|
56
|
+
if (isNaN(d.getTime())) {
|
|
57
|
+
throw new AssertionError(`Invalid ISO date for "${field}": ${val}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function expectEqual(actual, expected, field) {
|
|
61
|
+
if (actual !== expected) {
|
|
62
|
+
throw new AssertionError(`Expected "${field}" to be ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function expectIncludes(arr, value, field) {
|
|
66
|
+
if (!arr.includes(value)) {
|
|
67
|
+
throw new AssertionError(`Expected "${field}" to include ${JSON.stringify(value)}, got ${JSON.stringify(arr)}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { HttpResponse } from './types.js';
|
|
2
|
+
export declare class ConformanceHttpClient {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private readonly apiKey;
|
|
5
|
+
constructor(baseUrl: string, apiKey: string);
|
|
6
|
+
request<T = unknown>(method: string, path: string, body?: unknown): Promise<HttpResponse<T>>;
|
|
7
|
+
requestPublic<T = unknown>(method: string, path: string, body?: unknown): Promise<HttpResponse<T>>;
|
|
8
|
+
get<T = unknown>(path: string): Promise<HttpResponse<T>>;
|
|
9
|
+
post<T = unknown>(path: string, body?: unknown): Promise<HttpResponse<T>>;
|
|
10
|
+
patch<T = unknown>(path: string, body?: unknown): Promise<HttpResponse<T>>;
|
|
11
|
+
delete(path: string): Promise<HttpResponse>;
|
|
12
|
+
doRequestWithToken<T = unknown>(method: string, path: string, token: string, body?: unknown): Promise<HttpResponse<T>>;
|
|
13
|
+
private doRequest;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,qBAAa,qBAAqB;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM;IAG3B,OAAO,CAAC,CAAC,GAAG,OAAO,EACvB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,GACb,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAMrB,aAAa,CAAC,CAAC,GAAG,OAAO,EAC7B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,OAAO,GACb,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAIrB,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAIxD,IAAI,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAIzE,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAI1E,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAI3C,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,OAAO,GACb,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAMb,SAAS;CAgDxB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const USER_AGENT = '@grantex/conformance/0.1.0';
|
|
2
|
+
export class ConformanceHttpClient {
|
|
3
|
+
baseUrl;
|
|
4
|
+
apiKey;
|
|
5
|
+
constructor(baseUrl, apiKey) {
|
|
6
|
+
this.baseUrl = baseUrl;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
}
|
|
9
|
+
async request(method, path, body) {
|
|
10
|
+
return this.doRequest(method, path, body, {
|
|
11
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async requestPublic(method, path, body) {
|
|
15
|
+
return this.doRequest(method, path, body, {});
|
|
16
|
+
}
|
|
17
|
+
async get(path) {
|
|
18
|
+
return this.request('GET', path);
|
|
19
|
+
}
|
|
20
|
+
async post(path, body) {
|
|
21
|
+
return this.request('POST', path, body);
|
|
22
|
+
}
|
|
23
|
+
async patch(path, body) {
|
|
24
|
+
return this.request('PATCH', path, body);
|
|
25
|
+
}
|
|
26
|
+
async delete(path) {
|
|
27
|
+
return this.request('DELETE', path);
|
|
28
|
+
}
|
|
29
|
+
async doRequestWithToken(method, path, token, body) {
|
|
30
|
+
return this.doRequest(method, path, body, {
|
|
31
|
+
Authorization: `Bearer ${token}`,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async doRequest(method, path, body, headers) {
|
|
35
|
+
const url = `${this.baseUrl}${path}`;
|
|
36
|
+
const reqHeaders = {
|
|
37
|
+
'User-Agent': USER_AGENT,
|
|
38
|
+
...headers,
|
|
39
|
+
};
|
|
40
|
+
if (body !== undefined) {
|
|
41
|
+
reqHeaders['Content-Type'] = 'application/json';
|
|
42
|
+
}
|
|
43
|
+
const init = {
|
|
44
|
+
method,
|
|
45
|
+
headers: reqHeaders,
|
|
46
|
+
};
|
|
47
|
+
if (body !== undefined) {
|
|
48
|
+
init.body = JSON.stringify(body);
|
|
49
|
+
}
|
|
50
|
+
const start = Date.now();
|
|
51
|
+
let res = await fetch(url, init);
|
|
52
|
+
// Retry once on 429 (rate limited) after waiting the specified time
|
|
53
|
+
if (res.status === 429) {
|
|
54
|
+
const retryMatch = (await res.text()).match(/retry in (\d+)/);
|
|
55
|
+
const waitSec = retryMatch ? Math.min(parseInt(retryMatch[1], 10), 60) : 10;
|
|
56
|
+
await new Promise((resolve) => setTimeout(resolve, waitSec * 1000));
|
|
57
|
+
res = await fetch(url, init);
|
|
58
|
+
}
|
|
59
|
+
const durationMs = Date.now() - start;
|
|
60
|
+
const rawText = await res.text();
|
|
61
|
+
let parsed;
|
|
62
|
+
try {
|
|
63
|
+
parsed = JSON.parse(rawText);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
parsed = rawText;
|
|
67
|
+
}
|
|
68
|
+
return { status: res.status, body: parsed, rawText, durationMs };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=http-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../src/http-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,GAAG,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAA2B,MAAM,YAAY,CAAC;AA6B7E,wBAAgB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CA6C5D;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM,CAE5D"}
|