@credda/cli 0.1.4 → 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 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 no API key:
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 auto-detected.
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 it is not
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 set `CREDDA_API_KEY` (a `crd_live_…` platform key):
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 no query DSL.
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 and can
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 not a hiring verdict, a
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 the counterparty-confirmation primitive. You propose an
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 bulk-create up to 100
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 they hold a
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 the qualifications-half sibling of confirmations. A résumé
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 they hold a
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 declarative "tell me when this line is crossed", delivered
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 High Risk" --all \
210
- --metric band --direction enter --band "High Risk"
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 delete and recreate
224
+ # the metric is immutable: delete and recreate
216
225
  credda policies delete <id>
217
226
  ```
218
227
 
219
- Score monitors set `CREDDA_API_KEY`. Edge-triggered threshold/band watches
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 a monitor never affects a score:
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 set `CREDDA_API_KEY`. Async batch score reads (up to
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 set `CREDDA_API_KEY`:
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 the Stripe-CLI-style local loop without Credda
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 no `process`, `fs`, or env access,
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) the point is that a received credential can be checked
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 a capability, not a score write.
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 pure of process/env/fs so it's testable with a mocked
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 the CLI
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 only needed for keyed commands. */
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 used by `listen`. */
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 for the CSV
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.3";
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 the prefix is visible locally, so
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 the router
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 or a CSV, in which case only
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 an id containing a comma isn't a valid external id anyway.
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 pure of process/env/fs so it's testable with a mocked
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 the CLI
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.3';
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 the prefix is visible locally, so
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 the router
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 or a CSV, in which case only
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 an id containing a comma isn't a valid external id anyway.
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 fall through to string formats
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 ? '' : String(s.finalScore);
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 this is the call their integration makes.
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 the create
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 it is not a creditor.
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 nothing here scores, writes, or ranks anyone. Optional
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 percentile + distribution.
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 same closed filter set.
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 it can never move a score.
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 name the witness.
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 bulk-create up to 100 requests from a
891
- // JSON file: either an array of request bodies, or { requests: [...] }.
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 the counterparty holds a token, not a key.
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 the reference holds a token, not a key.
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 falls back to the event
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 — don't double it.
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` entry point. All logic lives in cli.ts (testable); this file only
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` entry point. All logic lives in cli.ts (testable); this file only
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) the typed SDK
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()) a hard exit right after a fetch
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
  });
@@ -1,12 +1,12 @@
1
1
  /**
2
- * `credda listen` a local webhook receiver for development.
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 put your own tunnel in front (cloudflared, ngrok, …)
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` a local webhook receiver for development.
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 put your own tunnel in front (cloudflared, ngrok, …)
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 print raw
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",
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.",
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.6.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
  }