@credda/cli 0.1.5 → 0.1.6
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 +37 -28
- package/dist/cli.d.ts +10 -10
- package/dist/cli.js +25 -25
- package/dist/index.d.ts +1 -1
- package/dist/index.js +24 -5
- package/dist/listener.d.ts +2 -2
- package/dist/listener.js +3 -3
- package/package.json +15 -3
package/README.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://credda.io">
|
|
3
|
+
<picture>
|
|
4
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Credda-io/credda-cli/main/assets/creddalockuplongdarktransparent.png">
|
|
5
|
+
<img alt="Credda" src="https://raw.githubusercontent.com/Credda-io/credda-cli/main/assets/creddalockuplonglighttransparent.png" width="360">
|
|
6
|
+
</picture>
|
|
7
|
+
</a>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
1
10
|
> Source mirror for [`@credda/cli`](https://www.npmjs.com/package/@credda/cli). Install from npm: `npm install -g @credda/cli`. Canonical development happens in Credda internal tooling; this repo is for source and issues.
|
|
2
11
|
|
|
3
12
|
# @credda/cli
|
|
@@ -35,14 +44,14 @@ credda quickstart # seed the sandbox with synthetic subjects, print
|
|
|
35
44
|
--no-confirm # stop after the seed; skip the confirmation loop
|
|
36
45
|
```
|
|
37
46
|
|
|
38
|
-
Public
|
|
47
|
+
Public (no API key):
|
|
39
48
|
|
|
40
49
|
```sh
|
|
41
50
|
credda lookup <token> # trust check for a share token (GET /verify/:token)
|
|
42
51
|
credda export <token> # full self-verifying trust export bundle
|
|
43
52
|
credda verify <file|-> # OFFLINE-verify a credential someone handed you:
|
|
44
53
|
# a W3C VC-JWT, a compact Trust Credential, or a
|
|
45
|
-
# saved trust-export bundle
|
|
54
|
+
# saved trust-export bundle (auto-detected).
|
|
46
55
|
# '-' reads stdin. Exit 0 valid / 2 invalid.
|
|
47
56
|
credda registry # federated trust registry (/.well-known)
|
|
48
57
|
credda did # issuer DID document
|
|
@@ -50,7 +59,7 @@ credda benchmarks # cohort-benchmark catalog: the dimensions you can
|
|
|
50
59
|
# benchmark on and the k-anonymity floor below
|
|
51
60
|
# which no cohort is disclosed
|
|
52
61
|
credda reason-codes # adverse-action reason-code catalog (ECOA / Reg B).
|
|
53
|
-
# Credda supplies the attribution only
|
|
62
|
+
# Credda supplies the attribution only: it is not
|
|
54
63
|
# a creditor and issues no notice.
|
|
55
64
|
credda badges list # the closed set of Open Badges 3.0 achievements
|
|
56
65
|
credda badges get <badgeId> # this issuer will sign, and one definition
|
|
@@ -58,14 +67,14 @@ credda outcome-templates [industry]
|
|
|
58
67
|
# how a business maps its work to Credda events, and
|
|
59
68
|
# WHO confirms each outcome. Guidance only.
|
|
60
69
|
credda professional-record public <token>
|
|
61
|
-
# the professional record behind a share token
|
|
62
|
-
# the token IS the subject's consent to present it
|
|
70
|
+
# the professional record behind a share token
|
|
71
|
+
# (the token IS the subject's consent to present it)
|
|
63
72
|
credda career-export --token <token>
|
|
64
73
|
# the whole verified record as a JSON Resume document,
|
|
65
74
|
# behind a share token (no API key sent)
|
|
66
75
|
```
|
|
67
76
|
|
|
68
|
-
Platform
|
|
77
|
+
Platform (set `CREDDA_API_KEY`, a `crd_live_…` platform key):
|
|
69
78
|
|
|
70
79
|
```sh
|
|
71
80
|
credda score <userId> # current score
|
|
@@ -93,7 +102,7 @@ credda users [--score-min <n>] [--score-max <n>] [--band <b>]
|
|
|
93
102
|
[--sort <score|lastActivity|registered|externalId>]
|
|
94
103
|
[--order <asc|desc>] [--cursor <c>] [--limit <n>]
|
|
95
104
|
# query + export your book of subjects. The filter
|
|
96
|
-
# set is closed and validated
|
|
105
|
+
# set is closed and validated: no query DSL.
|
|
97
106
|
# A subject with no score yet reports null, never
|
|
98
107
|
# a placeholder; list those with --unscored.
|
|
99
108
|
credda book-summary [same filters as "users"]
|
|
@@ -114,7 +123,7 @@ credda verified-profile <userId>
|
|
|
114
123
|
# how much of a subject's CLAIMED record
|
|
115
124
|
# (education/skills/certifications/employment) is
|
|
116
125
|
# third-party verified. Counts WHETHER a claim is
|
|
117
|
-
# verified, never how prestigious it is
|
|
126
|
+
# verified, never how prestigious it is, and can
|
|
118
127
|
# never move the Reliability Score.
|
|
119
128
|
credda qualify <userId> --category <education|skill|certification|employment>
|
|
120
129
|
[--label <l>] [--issuer <i>] [--verified-by <witness>]
|
|
@@ -123,7 +132,7 @@ credda qualify <userId> --category <education|skill|certification|employment>
|
|
|
123
132
|
# third-party --verified-by witness.
|
|
124
133
|
credda professional-record get <userId>
|
|
125
134
|
# résumé-shaped summary of a VERIFIED work record.
|
|
126
|
-
# Describes a record
|
|
135
|
+
# Describes a record. Not a hiring verdict, a
|
|
127
136
|
# background check, or a consumer report.
|
|
128
137
|
credda professional-record credential <userId> [--ttl <seconds>]
|
|
129
138
|
# mint the signed, offline-verifiable credential
|
|
@@ -141,7 +150,7 @@ credda mint <userId> # mint a share token
|
|
|
141
150
|
credda revoke <userId> # revoke a share token
|
|
142
151
|
```
|
|
143
152
|
|
|
144
|
-
Confirmation requests
|
|
153
|
+
Confirmation requests: the counterparty-confirmation primitive. You propose an
|
|
145
154
|
outcome and deliver the one-time token yourself; the event is written, verified,
|
|
146
155
|
only when that distinct party confirms:
|
|
147
156
|
|
|
@@ -154,7 +163,7 @@ credda confirmations create --user worker_7 --type CONTRACT_FULFILLED \
|
|
|
154
163
|
# needs CREDDA_API_KEY. The token is shown ONCE;
|
|
155
164
|
# creating a request writes no event.
|
|
156
165
|
credda confirmations batch <file.json> [--idempotency-key <k>]
|
|
157
|
-
# the ACTIVATION ENGINE
|
|
166
|
+
# the ACTIVATION ENGINE: bulk-create up to 100
|
|
158
167
|
# requests from a JSON file (an array of request
|
|
159
168
|
# bodies, or { "requests": [...] }), warming a cold
|
|
160
169
|
# ledger from your book. Needs CREDDA_API_KEY; each
|
|
@@ -163,8 +172,8 @@ credda confirmations list [--status PENDING] [--cursor <c>] [--limit <n>]
|
|
|
163
172
|
credda confirmations get <id>
|
|
164
173
|
credda confirmations cancel <id> # only while PENDING
|
|
165
174
|
|
|
166
|
-
# ⚠️ These two are the COUNTERPARTY's calls and take NO API key
|
|
167
|
-
# token, not a Credda account:
|
|
175
|
+
# ⚠️ These two are the COUNTERPARTY's calls and take NO API key (they hold a
|
|
176
|
+
# token, not a Credda account):
|
|
168
177
|
credda confirmations preview <id> --token <t>
|
|
169
178
|
credda confirmations respond <id> --token <t> --confirm
|
|
170
179
|
credda confirmations respond <id> --token <t> --decline
|
|
@@ -173,7 +182,7 @@ credda confirmations respond <id> --token <t> --decline
|
|
|
173
182
|
# there is no default: you must say which.
|
|
174
183
|
```
|
|
175
184
|
|
|
176
|
-
Reference requests
|
|
185
|
+
Reference requests: the qualifications-half sibling of confirmations. A résumé
|
|
177
186
|
claim (employment / education / certification / skill) becomes verified when the
|
|
178
187
|
named third party who was there confirms it; a reference never moves the score:
|
|
179
188
|
|
|
@@ -189,8 +198,8 @@ credda references list [--status PENDING] [--cursor <c>] [--limit <n>]
|
|
|
189
198
|
credda references get <id>
|
|
190
199
|
credda references cancel <id> # only while PENDING
|
|
191
200
|
|
|
192
|
-
# ⚠️ These two are the REFERENCE's calls and take NO API key
|
|
193
|
-
# token, not a Credda account:
|
|
201
|
+
# ⚠️ These two are the REFERENCE's calls and take NO API key (they hold a
|
|
202
|
+
# token, not a Credda account):
|
|
194
203
|
credda references preview <id> --token <t>
|
|
195
204
|
credda references respond <id> --token <t> --confirm
|
|
196
205
|
credda references respond <id> --token <t> --decline
|
|
@@ -199,26 +208,26 @@ credda references respond <id> --token <t> --decline
|
|
|
199
208
|
# and there is no default: you must say which.
|
|
200
209
|
```
|
|
201
210
|
|
|
202
|
-
Threshold policies
|
|
211
|
+
Threshold policies: declarative "tell me when this line is crossed", delivered
|
|
203
212
|
as `policy.threshold_crossed` through your webhooks. Config only: a policy never
|
|
204
213
|
reads into, blocks, or changes a score:
|
|
205
214
|
|
|
206
215
|
```sh
|
|
207
216
|
credda policies create --name "Watch 60" --user worker_7 \
|
|
208
217
|
--metric score --direction down --threshold 60
|
|
209
|
-
credda policies create --name "Anyone entering
|
|
210
|
-
--metric band --direction enter --band "
|
|
218
|
+
credda policies create --name "Anyone entering At Risk" --all \
|
|
219
|
+
--metric band --direction enter --band "At Risk"
|
|
211
220
|
credda policies list [--cursor <c>] [--limit <n>]
|
|
212
221
|
credda policies get <id>
|
|
213
222
|
credda policies update <id> [--threshold <n>] [--direction <d>] [--band <b>]
|
|
214
223
|
[--component <c>] [--name <n>] [--activate | --deactivate]
|
|
215
|
-
# the metric is immutable
|
|
224
|
+
# the metric is immutable: delete and recreate
|
|
216
225
|
credda policies delete <id>
|
|
217
226
|
```
|
|
218
227
|
|
|
219
|
-
Score monitors
|
|
228
|
+
Score monitors (set `CREDDA_API_KEY`). Edge-triggered threshold/band watches
|
|
220
229
|
that deliver `monitor.triggered` through your subscribed webhooks;
|
|
221
|
-
notification config only
|
|
230
|
+
notification config only (a monitor never affects a score):
|
|
222
231
|
|
|
223
232
|
```sh
|
|
224
233
|
credda monitors list [--cursor <c>] [--limit <n>]
|
|
@@ -232,7 +241,7 @@ credda monitors create --user <externalId> --below 40
|
|
|
232
241
|
credda monitors delete <id>
|
|
233
242
|
```
|
|
234
243
|
|
|
235
|
-
Bulk screenings
|
|
244
|
+
Bulk screenings (set `CREDDA_API_KEY`). Async batch score reads (up to
|
|
236
245
|
10,000 ids per job), strictly read-only:
|
|
237
246
|
|
|
238
247
|
```sh
|
|
@@ -250,7 +259,7 @@ credda screenings results <id> --csv out.csv
|
|
|
250
259
|
# write the CSV attachment instead (raw fetch)
|
|
251
260
|
```
|
|
252
261
|
|
|
253
|
-
Webhooks
|
|
262
|
+
Webhooks (set `CREDDA_API_KEY`):
|
|
254
263
|
|
|
255
264
|
```sh
|
|
256
265
|
credda webhooks list
|
|
@@ -271,7 +280,7 @@ CREDDA_WEBHOOK_SECRET=whsec_... credda listen 4141
|
|
|
271
280
|
same check your production handler must do) and pretty-prints the payload.
|
|
272
281
|
Credda delivers to public HTTPS only, so expose the port with your own tunnel
|
|
273
282
|
(e.g. `cloudflared tunnel --url http://localhost:4141`) and register the
|
|
274
|
-
tunnel URL as the webhook
|
|
283
|
+
tunnel URL as the webhook: the Stripe-CLI-style local loop without Credda
|
|
275
284
|
running a tunneling service.
|
|
276
285
|
|
|
277
286
|
Environment: `CREDDA_API_URL` overrides the API base (default
|
|
@@ -280,16 +289,16 @@ verification in `credda listen`.
|
|
|
280
289
|
|
|
281
290
|
## Design
|
|
282
291
|
|
|
283
|
-
- `src/cli.ts` is the pure command router
|
|
292
|
+
- `src/cli.ts` is the pure command router: no `process`, `fs`, or env access,
|
|
284
293
|
so the whole surface is unit-tested with a mocked `CreddaClient` (same
|
|
285
294
|
pattern as `packages/mcp`'s `tools.ts`).
|
|
286
295
|
- `src/index.ts` only wires the real environment (env vars, stdin/file
|
|
287
296
|
reading, exit codes).
|
|
288
297
|
- `verify` uses the SDK's offline verifiers (WebCrypto Ed25519 + StatusList
|
|
289
|
-
revocation)
|
|
298
|
+
revocation). The point is that a received credential can be checked
|
|
290
299
|
without trusting the wire it arrived on.
|
|
291
300
|
- Every command is read-only against the score. `mint`/`revoke` manage a
|
|
292
|
-
share token
|
|
301
|
+
share token (a capability, not a score write).
|
|
293
302
|
|
|
294
303
|
## License
|
|
295
304
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Command router
|
|
2
|
+
* Command router: pure of process/env/fs so it's testable with a mocked
|
|
3
3
|
* context (same pattern as packages/mcp's tools.ts).
|
|
4
4
|
*
|
|
5
5
|
* Every command is READ-ONLY against Credda's deterministic score. Nothing
|
|
6
|
-
* here writes an Event, adjusts a score, or makes a trust decision
|
|
6
|
+
* here writes an Event, adjusts a score, or makes a trust decision: the CLI
|
|
7
7
|
* looks up and offline-verifies EXISTING, already-computed trust facts.
|
|
8
8
|
* `mint`/`revoke` manage a share token (a capability, not a score write).
|
|
9
9
|
*/
|
|
10
10
|
import type { CreddaClient, VerifiedCredential, VerifiedVc, VerifiedTrustExport, TrustExport } from '@credda/js/headless';
|
|
11
11
|
export interface CliContext {
|
|
12
12
|
client: CreddaClient;
|
|
13
|
-
/** Platform API key from CREDDA_API_KEY
|
|
13
|
+
/** Platform API key from CREDDA_API_KEY, only needed for keyed commands. */
|
|
14
14
|
apiKey?: string;
|
|
15
15
|
out: (line: string) => void;
|
|
16
16
|
err: (line: string) => void;
|
|
@@ -21,7 +21,7 @@ export interface CliContext {
|
|
|
21
21
|
verifiableCredential: (vcJwt: string) => Promise<VerifiedVc>;
|
|
22
22
|
trustExport: (bundle: TrustExport) => Promise<VerifiedTrustExport>;
|
|
23
23
|
};
|
|
24
|
-
/** whsec_… signing secret from CREDDA_WEBHOOK_SECRET
|
|
24
|
+
/** whsec_… signing secret from CREDDA_WEBHOOK_SECRET, used by `listen`. */
|
|
25
25
|
webhookSecret?: string;
|
|
26
26
|
/**
|
|
27
27
|
* Starts the local webhook receiver (`credda listen`). Injected so the pure
|
|
@@ -32,7 +32,7 @@ export interface CliContext {
|
|
|
32
32
|
secret?: string;
|
|
33
33
|
}) => Promise<void>;
|
|
34
34
|
/**
|
|
35
|
-
* Raw authenticated GET returning the response body as text
|
|
35
|
+
* Raw authenticated GET returning the response body as text, for the CSV
|
|
36
36
|
* endpoints (`?format=csv`), which the typed SDK deliberately leaves to raw
|
|
37
37
|
* fetch. `path` is relative to the `/api/v1` prefix.
|
|
38
38
|
*/
|
|
@@ -44,7 +44,7 @@ export interface CliContext {
|
|
|
44
44
|
/** Poll interval for `screen --wait` (default 2000ms). */
|
|
45
45
|
pollIntervalMs?: number;
|
|
46
46
|
}
|
|
47
|
-
export declare const VERSION = "0.1.
|
|
47
|
+
export declare const VERSION = "0.1.6";
|
|
48
48
|
export declare const HELP = "credda: portable trust from the terminal\n\nStart here (needs a sandbox CREDDA_API_KEY, the crd_test_ kind):\n credda quickstart Seed your sandbox with synthetic subjects, print\n their real scores, read one back, and then close\n the counterparty-confirmation loop end to end so\n you finish holding a real VERIFIED event, not\n just a number you read. One command, nothing\n written outside the sandbox.\n --no-confirm Stop after the seed; skip the confirmation loop.\n\nSandbox (crd_test_ keys only; a live key is refused before anything happens):\n credda sandbox seed Populate the sandbox with synthetic subjects.\n Idempotent: an already-seeded subject is left\n alone, never doubled.\n credda sandbox reset Wipe the sandbox and start over.\n\nPublic (no API key):\n credda lookup <token> Trust check for a share token\n credda export <token> Full self-verifying trust export bundle\n credda verify <file|-> Offline-verify a credential: a W3C VC-JWT,\n a compact Trust Credential, or a saved trust\n export bundle (auto-detected). '-' = stdin.\n credda registry Federated trust registry\n credda did Issuer DID document\n credda benchmarks Cohort-benchmark catalog (dimensions + k-anonymity)\n credda reason-codes Adverse-action reason-code catalog (ECOA / Reg B)\n credda outcome-templates [industry]\n How a real-world business maps its work to\n Credda events, and WHO confirms each outcome.\n Guidance only. Optional industry slug filters.\n credda badges list Open Badges 3.0 achievements this issuer signs\n credda badges get <badgeId> One achievement definition\n credda professional-record public <token>\n The professional record behind a share token\n (the subject's own consent to present it)\n credda career-export --token <token>\n The subject's whole verified record as a JSON\n Resume document, behind a share token (the\n subject's own consent, no API key sent)\n\nPlatform (needs CREDDA_API_KEY):\n credda score <userId> Current score\n credda explain <userId> Factor-level score explanation\n credda components <userId> Six named 0-100 score components\n credda risk <userId> Advisory risk signals\n credda trust-summary <userId> [--narrative]\n Deterministic, evidence-based trust summary\n (explains; never a verdict). --narrative adds an\n advisory AI retelling when the server has AI on.\n credda benchmark <userId> [--dimension <d>]\n Where a subject sits within its cohort:\n percentile + the cohort distribution\n credda distribution [--dimension <d>] [--cohort <c>]\n Aggregate, k-anonymised cohort distribution.\n Omit --cohort for every cohort on the dimension.\n credda users [--score-min <n>] [--score-max <n>] [--band <b>]\n [--subject-type <PERSON|AGENT|ORGANIZATION>] [--scored|--unscored] [--frozen]\n [--active-since <iso>] [--registered-since <iso>] [--registered-before <iso>]\n [--verified] [--min-verified <n>]\n [--sort <score|lastActivity|registered|externalId>] [--order <asc|desc>]\n [--cursor <c>] [--limit <n>]\n Query + export your book of subjects.\n A subject with no score yet reports null,\n never a placeholder; list those with\n --unscored.\n credda book-summary [same filters as \"users\"]\n Size a segment WITHOUT paging it: how many\n match, how many are scored, band mix and\n median/mean. Null (not 0) when nothing in the\n segment is scored.\n credda usage [days] [--from <date> --to <date>] [--csv <outfile>]\n Your platform's metered API usage. Either a\n trailing [days] window OR an inclusive\n --from/--to date range (YYYY-MM-DD), not both.\n --csv writes the flat CSV statement to a file.\n credda activity [--action <A>] [--from <t> --to <t>] [--cursor <c>] [--limit <n>]\n Your platform's own activity/audit log,\n newest-first, cursor-paginated\n credda verified-profile <userId>\n How much of a subject's CLAIMED record\n (education/skills/certifications/employment) is\n third-party verified. Counts whether a claim is\n verified, never how prestigious it is, and it\n can never move the Reliability Score.\n credda qualify <userId> --category <education|skill|certification|employment>\n [--label <l>] [--issuer <i>] [--verified-by <witness>]\n Record a qualification claim. Always recorded;\n counts as VERIFIED only with a genuine\n third-party --verified-by witness.\n credda professional-record get <userId>\n R\u00E9sum\u00E9-shaped summary of a VERIFIED work record.\n Describes a record, not a hiring verdict, a\n background check, or a consumer report.\n credda professional-record credential <userId> [--ttl <seconds>]\n Mint the signed, offline-verifiable Professional\n Record Credential (+ an \"Add to LinkedIn\" link)\n credda reliability-report <userId> [--recent <n>] [--benchmark]\n The consolidated worker reliability report a\n staffing agency or employer weighs: reliability,\n metrics, verified experience, tenure, ranked\n drivers, recent outcomes. EVIDENCE, not a hire /\n place / rank verdict, a background check, or a\n consumer report. Use --token <token> for the\n public worker-consent route (NO API key).\n credda career-export <userId> The subject's whole verified record as an open\n JSON Resume document (jsonresume.org). Describes\n a record, not a hiring verdict or a consumer\n report. Use --token <token> for the public route.\n credda mint <userId> Mint a share token for a user\n credda revoke <userId> Revoke a user's share token\n\nConfirmation requests: the counterparty-confirmation primitive. You PROPOSE an\noutcome and deliver the one-time token to the counterparty over YOUR OWN channel;\nthe event is written, verified, only when that distinct party confirms:\n credda confirmations create --user <externalId> --type <eventType>\n --counterparty <ref> [--counterparty-name <n>] [--description <d>]\n [--stake <HIGH|MEDIUM|LOW>] [--value <n>] [--due <iso>] [--completed <iso>]\n [--return-url <url>] [--expires-in <days>] [--idempotency-key <k>]\n Needs CREDDA_API_KEY. Token shown ONCE.\n credda confirmations batch <file.json> [--idempotency-key <k>]\n The ACTIVATION ENGINE: bulk-create up to 100\n requests from a JSON file (an array of request\n bodies, or { \"requests\": [...] }). Warms a cold\n ledger from your book. Needs CREDDA_API_KEY;\n each ok item's token is shown ONCE.\n credda confirmations list [--status <s>] [--cursor <c>] [--limit <n>]\n credda confirmations get <id>\n credda confirmations cancel <id>\n credda confirmations preview <id> --token <t>\n What the counterparty is asked to confirm.\n NO API key; the token is the capability.\n credda confirmations respond <id> --token <t> (--confirm | --decline)\n The counterparty's decision. NO API key.\n --confirm writes the event; --decline writes\n nothing. Single-use either way.\n\nReference requests: the qualifications-half sibling of confirmations. A r\u00E9sum\u00E9\nclaim (employment / education / certification / skill) becomes VERIFIED when the\nnamed third party who was there confirms it. Records no qualification and never\nmoves the reliability score:\n credda references create --user <externalId>\n --category <employment|education|certification|skill>\n --counterparty <ref> [--label <l>] [--issuer <i>] [--jurisdiction <j>]\n [--reference <r>] [--counterparty-name <n>] [--description <d>]\n [--return-url <url>] [--expires-in <days>] [--idempotency-key <k>]\n Needs CREDDA_API_KEY. Token shown ONCE.\n credda references list [--status <s>] [--cursor <c>] [--limit <n>]\n credda references get <id>\n credda references cancel <id>\n credda references preview <id> --token <t>\n What the reference is asked to confirm.\n NO API key; the token is the capability.\n credda references respond <id> --token <t> (--confirm | --decline)\n The reference's decision. NO API key.\n --confirm records the qualification; --decline\n writes nothing. Single-use either way.\n\nThreshold policies (needs CREDDA_API_KEY): declarative \"tell me when this line\nis crossed\"; delivers policy.threshold_crossed through your webhooks. Config\nonly: a policy never reads into, blocks, or changes a score:\n credda policies list [--cursor <c>] [--limit <n>]\n credda policies get <id>\n credda policies create --name <n> (--user <externalId> | --all)\n --metric <score|component|band|verified_events>\n [--direction <up|down|enter|leave>] [--threshold <n>]\n [--component <reliability|timeliness|trustworthiness|verification|consistency|momentum>]\n [--band <b>]\n credda policies update <id> [--name <n>] [--direction <d>] [--threshold <n>]\n [--component <c>] [--band <b>] [--activate | --deactivate]\n The metric is immutable; delete + recreate.\n credda policies delete <id>\n\nScore monitors (needs CREDDA_API_KEY): edge-triggered watches that deliver\n\"monitor.triggered\" through your webhooks; notification config only, a\nmonitor never affects a score:\n credda monitors list [--cursor <c>] [--limit <n>]\n credda monitors get <id>\n credda monitors create --user <externalId> [--below <score>] [--above <score>] [--band-change]\n At least one condition required. --below fires\n on a downward crossing (and on a first score\n already below it), --above on an upward\n crossing, --band-change on any band change.\n credda monitors delete <id>\n\nBulk screenings (needs CREDDA_API_KEY): async batch score reads, up to\n10,000 ids per job, strictly read-only:\n credda screen <ids...> Submit ids (comma/space separated), or:\n credda screen --file <path> One id per line, or a CSV whose FIRST column\n is the id (a leading \"id\"/\"userId\"/\n \"externalId\" header row is skipped).\n [--wait] Poll until the job finishes, then print the\n summary (exit 1 if the job FAILED).\n credda screenings list [--cursor <c>] [--limit <n>]\n credda screenings get <id> Job status + summary\n credda screenings results <id> [--csv <outfile>]\n Per-user results (JSON; --csv writes the CSV\n attachment to a file instead)\n\nWebhooks (needs CREDDA_API_KEY):\n credda webhooks list Your webhook subscriptions\n credda webhooks create <url> <event..> Subscribe (secret shown ONCE)\n credda webhooks delete <id> Remove a webhook\n credda webhooks test <id> Send a synthetic signed delivery\n credda webhooks deliveries <id> Recent delivery attempts (incl. retries)\n credda webhooks recent [event..] Recent events across ALL your endpoints\n (sample data for automation platforms;\n falls back to catalog examples, flagged\n isExample, when nothing has fired yet)\n\nLocal development:\n credda listen [port] Local webhook receiver: verifies each delivery's\n HMAC signature (CREDDA_WEBHOOK_SECRET) and\n pretty-prints the payload. Default port 4141.\n Credda delivers to public HTTPS only; expose\n this port with your own tunnel (e.g. cloudflared).\n\nEnvironment:\n CREDDA_API_URL API base (default https://api.credda.io)\n CREDDA_API_KEY Platform API key for keyed commands\n CREDDA_WEBHOOK_SECRET whsec_\u2026 signing secret for \"credda listen\"\n\nExit codes: 0 ok/valid \u00B7 1 error \u00B7 2 credential failed verification";
|
|
49
49
|
/** Raw-key prefix the API stamps on a sandbox key (lib/testMode.ts). */
|
|
50
50
|
export declare const TEST_KEY_PREFIX = "crd_test_";
|
|
@@ -52,7 +52,7 @@ export declare const TEST_KEY_PREFIX = "crd_test_";
|
|
|
52
52
|
* A sandbox key, or an error that says exactly what to do next.
|
|
53
53
|
*
|
|
54
54
|
* The server refuses a live key anyway (`403 TEST_MODE_ONLY`), but a first-run
|
|
55
|
-
* user does not deserve a 403 to interpret
|
|
55
|
+
* user does not deserve a 403 to interpret: the prefix is visible locally, so
|
|
56
56
|
* the actionable message costs one string comparison. This is the "better
|
|
57
57
|
* first-run errors" rule applied to the single most likely first mistake.
|
|
58
58
|
*/
|
|
@@ -65,7 +65,7 @@ export declare function requireSandboxKey(ctx: CliContext): string;
|
|
|
65
65
|
* Also surfaces the machine code (so it can be looked up in
|
|
66
66
|
* `GET /api/v1/errors`) and any `Retry-After` the server asked for.
|
|
67
67
|
*
|
|
68
|
-
* Duck-typed rather than `instanceof CreddaError` on purpose
|
|
68
|
+
* Duck-typed rather than `instanceof CreddaError` on purpose: the router
|
|
69
69
|
* imports only TYPES from the SDK, so it stays pure and trivially mockable.
|
|
70
70
|
* Pure and exported for testing.
|
|
71
71
|
*/
|
|
@@ -84,10 +84,10 @@ export declare function parseFlags(args: string[], spec?: {
|
|
|
84
84
|
};
|
|
85
85
|
/**
|
|
86
86
|
* Parse the ids for `credda screen`. Inline args may be comma- and/or
|
|
87
|
-
* space-separated. A file is one id per line
|
|
87
|
+
* space-separated. A file is one id per line, or a CSV, in which case only
|
|
88
88
|
* the FIRST column is read (a leading header row named id/userId/externalId
|
|
89
89
|
* is skipped). Deduped, order-preserving. Deliberately simple: no quoted-CSV
|
|
90
|
-
* handling
|
|
90
|
+
* handling (an id containing a comma isn't a valid external id anyway).
|
|
91
91
|
*/
|
|
92
92
|
export declare function parseIdList(input: {
|
|
93
93
|
inline?: string[];
|
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Command router
|
|
2
|
+
* Command router: pure of process/env/fs so it's testable with a mocked
|
|
3
3
|
* context (same pattern as packages/mcp's tools.ts).
|
|
4
4
|
*
|
|
5
5
|
* Every command is READ-ONLY against Credda's deterministic score. Nothing
|
|
6
|
-
* here writes an Event, adjusts a score, or makes a trust decision
|
|
6
|
+
* here writes an Event, adjusts a score, or makes a trust decision: the CLI
|
|
7
7
|
* looks up and offline-verifies EXISTING, already-computed trust facts.
|
|
8
8
|
* `mint`/`revoke` manage a share token (a capability, not a score write).
|
|
9
9
|
*/
|
|
10
|
-
export const VERSION = '0.1.
|
|
10
|
+
export const VERSION = '0.1.6';
|
|
11
11
|
export const HELP = `credda: portable trust from the terminal
|
|
12
12
|
|
|
13
13
|
Start here (needs a sandbox CREDDA_API_KEY, the crd_test_ kind):
|
|
@@ -243,7 +243,7 @@ export const TEST_KEY_PREFIX = 'crd_test_';
|
|
|
243
243
|
* A sandbox key, or an error that says exactly what to do next.
|
|
244
244
|
*
|
|
245
245
|
* The server refuses a live key anyway (`403 TEST_MODE_ONLY`), but a first-run
|
|
246
|
-
* user does not deserve a 403 to interpret
|
|
246
|
+
* user does not deserve a 403 to interpret: the prefix is visible locally, so
|
|
247
247
|
* the actionable message costs one string comparison. This is the "better
|
|
248
248
|
* first-run errors" rule applied to the single most likely first mistake.
|
|
249
249
|
*/
|
|
@@ -278,7 +278,7 @@ function show(ctx, value) {
|
|
|
278
278
|
* Also surfaces the machine code (so it can be looked up in
|
|
279
279
|
* `GET /api/v1/errors`) and any `Retry-After` the server asked for.
|
|
280
280
|
*
|
|
281
|
-
* Duck-typed rather than `instanceof CreddaError` on purpose
|
|
281
|
+
* Duck-typed rather than `instanceof CreddaError` on purpose: the router
|
|
282
282
|
* imports only TYPES from the SDK, so it stays pure and trivially mockable.
|
|
283
283
|
* Pure and exported for testing.
|
|
284
284
|
*/
|
|
@@ -391,10 +391,10 @@ function bookFilterFlags(flags) {
|
|
|
391
391
|
const ID_HEADER_NAMES = /^(id|userid|user_id|externalid|external_id)$/i;
|
|
392
392
|
/**
|
|
393
393
|
* Parse the ids for `credda screen`. Inline args may be comma- and/or
|
|
394
|
-
* space-separated. A file is one id per line
|
|
394
|
+
* space-separated. A file is one id per line, or a CSV, in which case only
|
|
395
395
|
* the FIRST column is read (a leading header row named id/userId/externalId
|
|
396
396
|
* is skipped). Deduped, order-preserving. Deliberately simple: no quoted-CSV
|
|
397
|
-
* handling
|
|
397
|
+
* handling (an id containing a comma isn't a valid external id anyway).
|
|
398
398
|
*/
|
|
399
399
|
export function parseIdList(input) {
|
|
400
400
|
const raw = [];
|
|
@@ -440,7 +440,7 @@ export function classifyCredentialInput(raw) {
|
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
442
|
catch {
|
|
443
|
-
// not JSON
|
|
443
|
+
// not JSON: fall through to string formats
|
|
444
444
|
}
|
|
445
445
|
if (/^eyJ[\w-]*\.[\w-]+\.[\w-]+$/.test(trimmed)) {
|
|
446
446
|
return { kind: 'vc-jwt', jwt: trimmed };
|
|
@@ -486,13 +486,13 @@ export async function runCli(argv, ctx) {
|
|
|
486
486
|
const idWidth = Math.max(...seed.subjects.map((s) => s.userId.length), 7);
|
|
487
487
|
ctx.out(`${pad('SUBJECT', idWidth)} SCORE BAND`);
|
|
488
488
|
for (const s of seed.subjects) {
|
|
489
|
-
const score = s.finalScore === null ? '
|
|
490
|
-
ctx.out(`${pad(s.userId, idWidth)} ${pad(score, 5)} ${s.scoreBand ?? '
|
|
489
|
+
const score = s.finalScore === null ? 'none' : String(s.finalScore);
|
|
490
|
+
ctx.out(`${pad(s.userId, idWidth)} ${pad(score, 5)} ${s.scoreBand ?? 'none'}`);
|
|
491
491
|
}
|
|
492
492
|
ctx.out('');
|
|
493
493
|
for (const s of seed.subjects)
|
|
494
494
|
ctx.out(`${s.userId}: ${s.record}`);
|
|
495
|
-
// Prove a plain read works
|
|
495
|
+
// Prove a plain read works: this is the call their integration makes.
|
|
496
496
|
const first = seed.subjects[0];
|
|
497
497
|
if (first) {
|
|
498
498
|
ctx.out('');
|
|
@@ -505,7 +505,7 @@ export async function runCli(argv, ctx) {
|
|
|
505
505
|
// counterparty-CONFIRMED evidence, and a developer used to be able to
|
|
506
506
|
// finish the entire on-ramp without meeting POST /confirmations. So
|
|
507
507
|
// the quickstart now closes the loop for real: propose an outcome,
|
|
508
|
-
// then respond as the counterparty (legitimate here
|
|
508
|
+
// then respond as the counterparty (legitimate here: the create
|
|
509
509
|
// response hands the raw token to whoever made the request, and this
|
|
510
510
|
// is their own disposable sandbox), and print the verified event id.
|
|
511
511
|
//
|
|
@@ -542,7 +542,7 @@ export async function runCli(argv, ctx) {
|
|
|
542
542
|
ctx.out('');
|
|
543
543
|
ctx.out(' 3. POST /api/v1/confirmations/{id}/respond (NO api key, token only)');
|
|
544
544
|
const decided = await ctx.client.respondToConfirmation(created.confirmation.id, created.confirmationToken, 'confirm');
|
|
545
|
-
ctx.out(` → ${decided.status}, ledger event ${decided.eventId ?? '
|
|
545
|
+
ctx.out(` → ${decided.status}, ledger event ${decided.eventId ?? '(none)'}`);
|
|
546
546
|
ctx.out(' isVerified: true, earned, because a distinct token-holder acted. Declining');
|
|
547
547
|
ctx.out(' would have written nothing at all: no confirmation is never read as a bad outcome.');
|
|
548
548
|
ctx.out('');
|
|
@@ -614,13 +614,13 @@ export async function runCli(argv, ctx) {
|
|
|
614
614
|
return 0;
|
|
615
615
|
case 'reason-codes':
|
|
616
616
|
// Public adverse-action reason-code catalog (ECOA / Reg B). Credda
|
|
617
|
-
// supplies the attribution only
|
|
617
|
+
// supplies the attribution only: it is not a creditor.
|
|
618
618
|
show(ctx, await ctx.client.getReasonCodes());
|
|
619
619
|
return 0;
|
|
620
620
|
case 'outcome-templates': {
|
|
621
621
|
// Public catalog: how a real-world business maps its work to Credda
|
|
622
622
|
// events, and WHO the third-party witness is for each outcome. Guidance
|
|
623
|
-
// only
|
|
623
|
+
// only: nothing here scores, writes, or ranks anyone. Optional
|
|
624
624
|
// positional industry slug filters to one set.
|
|
625
625
|
const [industry] = args;
|
|
626
626
|
show(ctx, await ctx.client.getOutcomeTemplates(industry));
|
|
@@ -663,7 +663,7 @@ export async function runCli(argv, ctx) {
|
|
|
663
663
|
return 0;
|
|
664
664
|
}
|
|
665
665
|
case 'benchmark': {
|
|
666
|
-
// Where one subject sits within a cohort
|
|
666
|
+
// Where one subject sits within a cohort: percentile + distribution.
|
|
667
667
|
const { positional, flags } = parseFlags(args, { valued: ['dimension'] });
|
|
668
668
|
const userId = requireArg(positional, 'userId');
|
|
669
669
|
show(ctx, await ctx.client.getUserBenchmark(userId, requireKey(ctx), {
|
|
@@ -706,7 +706,7 @@ export async function runCli(argv, ctx) {
|
|
|
706
706
|
return 0;
|
|
707
707
|
}
|
|
708
708
|
case 'book-summary': {
|
|
709
|
-
// Size a segment of the book without paging it
|
|
709
|
+
// Size a segment of the book without paging it (same closed filter set).
|
|
710
710
|
const { positional, flags } = parseFlags(args, {
|
|
711
711
|
valued: [
|
|
712
712
|
'score-min', 'score-max', 'band', 'subject-type', 'active-since',
|
|
@@ -766,12 +766,12 @@ export async function runCli(argv, ctx) {
|
|
|
766
766
|
return 0;
|
|
767
767
|
}
|
|
768
768
|
case 'verified-profile':
|
|
769
|
-
// A SECOND measure over the same ledger
|
|
769
|
+
// A SECOND measure over the same ledger (it can never move a score).
|
|
770
770
|
show(ctx, await ctx.client.getVerifiedProfile(requireArg(args, 'userId'), requireKey(ctx)));
|
|
771
771
|
return 0;
|
|
772
772
|
case 'qualify': {
|
|
773
773
|
// The claim is ALWAYS recorded; --verified-by decides whether it counts
|
|
774
|
-
// as verified. Never assert it yourself
|
|
774
|
+
// as verified. Never assert it yourself: name the witness.
|
|
775
775
|
const { positional, flags } = parseFlags(args, {
|
|
776
776
|
valued: ['category', 'label', 'issuer', 'verified-by'],
|
|
777
777
|
});
|
|
@@ -887,8 +887,8 @@ export async function runCli(argv, ctx) {
|
|
|
887
887
|
return 0;
|
|
888
888
|
}
|
|
889
889
|
case 'batch': {
|
|
890
|
-
// The ACTIVATION ENGINE
|
|
891
|
-
// JSON file
|
|
890
|
+
// The ACTIVATION ENGINE: bulk-create up to 100 requests from a
|
|
891
|
+
// JSON file (either an array of request bodies, or { requests: [...] }).
|
|
892
892
|
const { positional, flags } = parseFlags(rest, { valued: ['idempotency-key'] });
|
|
893
893
|
const file = requireArg(positional, 'file');
|
|
894
894
|
const parsed = JSON.parse(await ctx.readInput(file));
|
|
@@ -918,7 +918,7 @@ export async function runCli(argv, ctx) {
|
|
|
918
918
|
show(ctx, await ctx.client.cancelConfirmation(requireArg(rest, 'id'), requireKey(ctx)));
|
|
919
919
|
return 0;
|
|
920
920
|
case 'preview': {
|
|
921
|
-
// KEYLESS on purpose
|
|
921
|
+
// KEYLESS on purpose: the counterparty holds a token, not a key.
|
|
922
922
|
const { positional, flags } = parseFlags(rest, { valued: ['token'] });
|
|
923
923
|
const id = requireArg(positional, 'id');
|
|
924
924
|
const token = strFlag(flags, 'token');
|
|
@@ -1005,7 +1005,7 @@ export async function runCli(argv, ctx) {
|
|
|
1005
1005
|
show(ctx, await ctx.client.cancelReference(requireArg(rest, 'id'), requireKey(ctx)));
|
|
1006
1006
|
return 0;
|
|
1007
1007
|
case 'preview': {
|
|
1008
|
-
// KEYLESS on purpose
|
|
1008
|
+
// KEYLESS on purpose: the reference holds a token, not a key.
|
|
1009
1009
|
const { positional, flags } = parseFlags(rest, { valued: ['token'] });
|
|
1010
1010
|
const id = requireArg(positional, 'id');
|
|
1011
1011
|
const token = strFlag(flags, 'token');
|
|
@@ -1261,7 +1261,7 @@ export async function runCli(argv, ctx) {
|
|
|
1261
1261
|
show(ctx, await ctx.client.getWebhookDeliveries(requireArg(rest, 'id'), key, 25));
|
|
1262
1262
|
return 0;
|
|
1263
1263
|
case 'recent': {
|
|
1264
|
-
// Sample data across ALL endpoints
|
|
1264
|
+
// Sample data across ALL endpoints: falls back to the event
|
|
1265
1265
|
// catalog's examples (isExample:true) when nothing has fired yet.
|
|
1266
1266
|
const eventType = rest.length > 0 ? rest : undefined;
|
|
1267
1267
|
show(ctx, await ctx.client.getRecentWebhookEvents(key, { limit: 25, eventType }));
|
|
@@ -1294,7 +1294,7 @@ export async function runCli(argv, ctx) {
|
|
|
1294
1294
|
}
|
|
1295
1295
|
catch (e) {
|
|
1296
1296
|
const message = e instanceof Error ? e.message : String(e);
|
|
1297
|
-
// SDK errors already carry a "credda:" prefix
|
|
1297
|
+
// SDK errors already carry a "credda:" prefix. Don't double it.
|
|
1298
1298
|
ctx.err(message.startsWith('credda:') ? message : `credda: ${message}`);
|
|
1299
1299
|
for (const line of errorHints(e))
|
|
1300
1300
|
ctx.err(line);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* `credda
|
|
3
|
+
* `credda`: entry point. All logic lives in cli.ts (testable); this file only
|
|
4
4
|
* wires the real environment: env vars, stdin/file reading, process exit.
|
|
5
5
|
*/
|
|
6
6
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* `credda
|
|
3
|
+
* `credda`: entry point. All logic lives in cli.ts (testable); this file only
|
|
4
4
|
* wires the real environment: env vars, stdin/file reading, process exit.
|
|
5
5
|
*/
|
|
6
6
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
@@ -16,10 +16,16 @@ async function readInput(pathOrDash) {
|
|
|
16
16
|
}
|
|
17
17
|
return readFile(pathOrDash, 'utf8');
|
|
18
18
|
}
|
|
19
|
-
// Raw authenticated GET for the CSV endpoints (?format=csv)
|
|
19
|
+
// Raw authenticated GET for the CSV endpoints (?format=csv): the typed SDK
|
|
20
20
|
// returns parsed JSON only and documents CSV as a raw-fetch use case. Built
|
|
21
21
|
// from the same base URL the client is configured with.
|
|
22
22
|
const API_BASE = (process.env.CREDDA_API_URL ?? 'https://api.credda.io').replace(/\/+$/, '');
|
|
23
|
+
/**
|
|
24
|
+
* The did:web identity of the API this CLI talks to, and the issuer every
|
|
25
|
+
* verification expects. `https://api.credda.io` is `did:web:api.credda.io`;
|
|
26
|
+
* point CREDDA_API_URL at staging and the expectation follows it.
|
|
27
|
+
*/
|
|
28
|
+
const ISSUER_DID = `did:web:${new URL(API_BASE).host.toLowerCase()}`;
|
|
23
29
|
async function fetchCsv(path, apiKey) {
|
|
24
30
|
const res = await fetch(`${API_BASE}/api/v1${path}`, {
|
|
25
31
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
@@ -37,7 +43,7 @@ async function fetchCsv(path, apiKey) {
|
|
|
37
43
|
}
|
|
38
44
|
return res.text();
|
|
39
45
|
}
|
|
40
|
-
// process.exitCode (not process.exit())
|
|
46
|
+
// process.exitCode (not process.exit()): a hard exit right after a fetch
|
|
41
47
|
// trips a libuv assertion on Windows Node while handles are still closing.
|
|
42
48
|
process.exitCode = await runCli(process.argv.slice(2), {
|
|
43
49
|
client: new CreddaClient({ apiBase: process.env.CREDDA_API_URL }),
|
|
@@ -49,9 +55,22 @@ process.exitCode = await runCli(process.argv.slice(2), {
|
|
|
49
55
|
out: (line) => console.log(line),
|
|
50
56
|
err: (line) => console.error(line),
|
|
51
57
|
readInput,
|
|
58
|
+
// ⚠️ EVERY VERIFIER IS TOLD WHICH ISSUER IT EXPECTS.
|
|
59
|
+
//
|
|
60
|
+
// `credda verify` reads a credential handed over by somebody else, which is
|
|
61
|
+
// the whole point of it. did:web resolution proves the credential was signed
|
|
62
|
+
// by whoever controls the DID's host; it does NOT prove that host is Credda.
|
|
63
|
+
// Without an expected issuer, a credential minted by anyone with a domain
|
|
64
|
+
// verifies clean and the CLI prints it as valid.
|
|
65
|
+
//
|
|
66
|
+
// Stated explicitly rather than left to the SDK default, because this CLI
|
|
67
|
+
// pins an SDK line that does not have that default, and because a call site
|
|
68
|
+
// that says what it expects keeps saying it after the dependency moves.
|
|
69
|
+
// ISSUER_DID follows CREDDA_API_URL, so a CLI pointed at staging expects
|
|
70
|
+
// staging's issuer rather than production's.
|
|
52
71
|
verifiers: {
|
|
53
72
|
trustCredential: (credential) => verifyTrustCredential(credential),
|
|
54
|
-
verifiableCredential: (vcJwt) => verifyVerifiableCredential(vcJwt),
|
|
55
|
-
trustExport: (bundle) => verifyTrustExport(bundle),
|
|
73
|
+
verifiableCredential: (vcJwt) => verifyVerifiableCredential(vcJwt, { apiBase: API_BASE, issuer: ISSUER_DID }),
|
|
74
|
+
trustExport: (bundle) => verifyTrustExport(bundle, { apiBase: API_BASE, issuer: ISSUER_DID }),
|
|
56
75
|
},
|
|
57
76
|
});
|
package/dist/listener.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `credda listen
|
|
2
|
+
* `credda listen`: a local webhook receiver for development.
|
|
3
3
|
*
|
|
4
4
|
* Accepts POSTs on a local port, verifies each delivery's HMAC signature with
|
|
5
5
|
* the webhook's signing secret (when provided), and pretty-prints the payload.
|
|
6
6
|
* Responds 200 so a tunneled Credda delivery counts as delivered.
|
|
7
7
|
*
|
|
8
8
|
* Honest scope: Credda only delivers to public HTTPS endpoints, so this does
|
|
9
|
-
* NOT tunnel by itself
|
|
9
|
+
* NOT tunnel by itself: put your own tunnel in front (cloudflared, ngrok, …)
|
|
10
10
|
* and register the tunnel URL as the webhook. What this gives you is the
|
|
11
11
|
* Stripe-CLI-style local loop: see every delivery, verify its signature the
|
|
12
12
|
* same way your production handler must, and iterate without redeploying.
|
package/dist/listener.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `credda listen
|
|
2
|
+
* `credda listen`: a local webhook receiver for development.
|
|
3
3
|
*
|
|
4
4
|
* Accepts POSTs on a local port, verifies each delivery's HMAC signature with
|
|
5
5
|
* the webhook's signing secret (when provided), and pretty-prints the payload.
|
|
6
6
|
* Responds 200 so a tunneled Credda delivery counts as delivered.
|
|
7
7
|
*
|
|
8
8
|
* Honest scope: Credda only delivers to public HTTPS endpoints, so this does
|
|
9
|
-
* NOT tunnel by itself
|
|
9
|
+
* NOT tunnel by itself: put your own tunnel in front (cloudflared, ngrok, …)
|
|
10
10
|
* and register the tunnel URL as the webhook. What this gives you is the
|
|
11
11
|
* Stripe-CLI-style local loop: see every delivery, verify its signature the
|
|
12
12
|
* same way your production handler must, and iterate without redeploying.
|
|
@@ -46,7 +46,7 @@ export function startListener(opts) {
|
|
|
46
46
|
pretty = JSON.stringify(parsed, null, 2);
|
|
47
47
|
}
|
|
48
48
|
catch {
|
|
49
|
-
// non-JSON body
|
|
49
|
+
// non-JSON body: print raw
|
|
50
50
|
}
|
|
51
51
|
console.log(`\n── ${time} · ${req.method} ${req.url} · ${String(eventType)} · ${verdict}`);
|
|
52
52
|
console.log(pretty);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@credda/cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Official Credda CLI
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"description": "Official Credda CLI: look up and offline-verify portable trust from the terminal. Public trust checks, credential verification, platform score reads, share-token minting. A thin client over @credda/js; no scoring logic lives here.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/Credda-io/credda-cli#readme",
|
|
7
7
|
"bugs": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"test": "vitest run"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@credda/js": "^0.
|
|
28
|
+
"@credda/js": "^0.8.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^20.14.2",
|
|
@@ -39,5 +39,17 @@
|
|
|
39
39
|
"repository": {
|
|
40
40
|
"type": "git",
|
|
41
41
|
"url": "git+https://github.com/Credda-io/credda-cli.git"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"credda",
|
|
45
|
+
"cli",
|
|
46
|
+
"command-line",
|
|
47
|
+
"trust",
|
|
48
|
+
"reliability-score",
|
|
49
|
+
"verifiable-credentials",
|
|
50
|
+
"sdk"
|
|
51
|
+
],
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18"
|
|
42
54
|
}
|
|
43
55
|
}
|