@myelinbridge/cli 0.4.0 → 0.6.1

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.
Files changed (3) hide show
  1. package/README.md +106 -59
  2. package/bin/myelin.js +616 -496
  3. package/package.json +23 -23
package/README.md CHANGED
@@ -1,59 +1,106 @@
1
- # @myelinbridge/cli
2
-
3
- Push R&D data deliveries into [Myelin](https://myelinbridge.com) from a pipeline —
4
- preflight against the client's published quality rules, resumable upload, submit,
5
- and track review outcomes. Full API reference: https://myelinbridge.com/developers.
6
-
7
- ## Quick start (~10 minutes from key to first submit)
8
-
9
- ```bash
10
- export MYELIN_API_KEY=myl_live_… # created by your bridge owner in Bridge → API
11
-
12
- npx @myelinbridge/cli ping # verifies auth, prints your projects
13
- npx @myelinbridge/cli datasets # what you can deliver to, and whose move it is
14
- npx @myelinbridge/cli contract --dataset onco1-wes # what is expected of your delivery
15
- npx @myelinbridge/cli sample-depth 1 --dataset onco1-wes # once, before your first submit
16
- npx @myelinbridge/cli check ./run_042 --dataset onco1-wes # validate BEFORE uploading a byte
17
- npx @myelinbridge/cli push ./run_042 --dataset onco1-wes --submit
18
- ```
19
-
20
- - **Declare your sample depth once, first.** The client creates and describes the
21
- dataset; you own your output structure, so you tell Myelin at which folder depth a
22
- sample sits — `0` = the delivery root is one sample, `1` (default) = each top-level
23
- folder is a sample, `2` = one level deeper. Sample-scoped quality checks group by it,
24
- so getting it right up front is what makes per-sample verdicts mean anything. It is
25
- **idempotent** (safe to assert on every pipeline run) and **locks once your first
26
- batch leaves draft**, so that verdicts stay comparable across deliveries — after that
27
- the command exits `2`. This is the only dataset field you can write.
28
-
29
- - **Resume = re-run.** `push` is idempotent: already-uploaded files are skipped
30
- (path + size), and within a large file, parts that already landed are skipped
31
- too (S3 multipart). Uploads go direct to storage over short-lived presigned
32
- URLs — no credential is stored on your machine, and revoking the API key cuts
33
- off signing immediately.
34
- - **Read the contract before you build the delivery.** `contract` prints what the
35
- client expects — every check as one plain sentence, grouped by what it answers
36
- (completeness, structure, validity, consistency, integrity, privacy), and marked
37
- `!` when a failure blocks validation. It also tells you which checks `check` can
38
- verify locally and which only run once the files are uploaded, so nothing about
39
- the bar is a surprise at review time.
40
-
41
- - **`check` costs nothing.** It evaluates your local manifest against the dataset's
42
- quality checks server-side — same engine, same verdicts as submit — without
43
- uploading. Exit code 2 means a blocking rule fails.
44
- - **The fix loop is machine-readable.** On `changes_requested`,
45
- `myelin status <batch> --json` returns the failed files, reviewer comments, and
46
- rule remediation hints; fix, re-`push --submit`, unchanged files keep their
47
- review votes.
48
-
49
- ## Machine mode
50
-
51
- Every command takes `--json`. Exit codes: `0` ok · `1` error · `2` blocked
52
- (blocking preflight failure, locked delivery, blocked submit, locked sample depth).
53
-
54
- ## Webhooks instead of polling
55
-
56
- Register an HTTPS endpoint (portal Bridge API, or `POST /v1/webhook-endpoints`)
57
- to receive signed events (`batch.validated`, `batch.changes_requested`,
58
- `batch.transferred`, …). Verification snippets: https://myelinbridge.com/developers.
59
- Polling fallback: `GET /v1/events?cursor=…`.
1
+ # @myelinbridge/cli
2
+
3
+ Push R&D data deliveries into [Myelin](https://myelinbridge.com) from a pipeline —
4
+ preflight against the client's published quality rules, resumable upload, submit,
5
+ and track review outcomes. Full API reference: https://myelinbridge.com/developers.
6
+
7
+ ## Quick start (~10 minutes from key to first submit)
8
+
9
+ ```bash
10
+ export MYELIN_API_KEY=myl_live_… # created by your bridge owner in Bridge → API
11
+
12
+ npx @myelinbridge/cli ping # verifies auth, prints your projects
13
+ npx @myelinbridge/cli datasets # what you can deliver to, and whose move it is
14
+ npx @myelinbridge/cli contract --dataset onco1-wes # what is expected of your delivery
15
+ npx @myelinbridge/cli sample-depth 1 --dataset onco1-wes # once, before your first submit
16
+ npx @myelinbridge/cli check ./run_042 --dataset onco1-wes # validate BEFORE uploading a byte
17
+ npx @myelinbridge/cli push ./run_042 --dataset onco1-wes --submit
18
+ ```
19
+
20
+ - **Declare your sample depth once, first.** The client creates and describes the
21
+ dataset; you own your output structure, so you tell Myelin at which folder depth a
22
+ sample sits — `0` = the delivery root is one sample, `1` (default) = each top-level
23
+ folder is a sample, `2` = one level deeper. Sample-scoped quality checks group by it,
24
+ so getting it right up front is what makes per-sample verdicts mean anything. It is
25
+ **idempotent** (safe to assert on every pipeline run) and **locks once your first
26
+ batch leaves draft**, so that verdicts stay comparable across deliveries — after that
27
+ the command exits `2`. This is the only dataset field you can write.
28
+
29
+ - **Resume = re-run.** `push` is idempotent: already-uploaded files are skipped
30
+ (path + size), and within a large file, parts that already landed are skipped
31
+ too (S3 multipart). Uploads go direct to storage over short-lived presigned
32
+ URLs — no credential is stored on your machine, and revoking the API key cuts
33
+ off signing immediately.
34
+ - **Read the contract before you build the delivery.** `contract` prints what the
35
+ client expects — every check as one plain sentence, grouped by what it answers
36
+ (completeness, structure, validity, consistency, integrity, privacy), and marked
37
+ `!` when a failure blocks validation. It also tells you which checks `check` can
38
+ verify locally and which only run once the files are uploaded, so nothing about
39
+ the bar is a surprise at review time.
40
+
41
+ - **`check` costs nothing.** It evaluates your local file list against the dataset's
42
+ quality checks server-side — same engine, same verdicts as submit — without
43
+ uploading. Exit code 2 means a blocking rule fails.
44
+ - **The fix loop is machine-readable.** On `changes_requested`,
45
+ `myelin status <batch> --json` returns the failed files, reviewer comments, and
46
+ rule remediation hints; fix, re-`push --submit`, unchanged files keep their
47
+ review votes.
48
+
49
+ ## If you are the client, not the partner
50
+
51
+ Two kinds of key exist, and they are not interchangeable. Everything above needs a
52
+ **partner key** (write: upload, submit). A **client key** is read-only and answers the
53
+ question your own systems ask once the data has landed: *the bucket is full of UUIDs —
54
+ what is this?*
55
+
56
+ Where they live follows from what they are. A **partner key belongs to one bridge**, because a
57
+ partner does. A **client key belongs to your organisation**: one key, every partner, one answer.
58
+ Your organisation admin creates it in **Organisation → API keys**. To narrow one to a single
59
+ partner's data, scope it to that partner's projects.
60
+
61
+ ```bash
62
+ export MYELIN_API_KEY=myl_live_…
63
+
64
+ # What has landed, newest first
65
+ myelin deliveries --dataset <dataset-id>
66
+
67
+ # What is this object, exactly?
68
+ myelin resolve gs://acme-landing/inbox/acme-cro/4319…/de99…/7aa5…/data/SAMPLE_01/reads.fastq.gz
69
+ # file · gs://…/reads.fastq.gz
70
+ # project ONCO1 — Oncology discovery
71
+ # dataset WES batch 7 (Genomics)
72
+ # batch ONCO1-WES-007 · #7
73
+ # validated 2026-08-07T18:05:12Z · delivered 2026-08-07T18:06:20Z
74
+ # manifest gs://…/7aa5…/_myelin/manifest.json
75
+ # file reads.fastq.gz · 4096 bytes
76
+ ```
77
+
78
+ `resolve` accepts a full `gs://`/`s3://` URI, a bare prefix, or a single id, and answers at
79
+ whatever granularity the path supports.
80
+
81
+ Each delivery also carries the same record **as a file**, written next to the data at
82
+ `_myelin/manifest.json` (plus `_myelin/files.csv`, a flat table you can load straight into a
83
+ warehouse). Prefer the file for anything auditable: it is frozen at delivery time, needs no
84
+ credentials, and does not depend on Myelin being reachable. Use the API when you want it live.
85
+
86
+ A partner key calling these gets `403 wrong_key_side`, and vice versa.
87
+
88
+ ## Machine mode
89
+
90
+ Every command takes `--json`. Exit codes: `0` ok · `1` error · `2` blocked
91
+ (blocking preflight failure, locked delivery, blocked submit, locked sample depth).
92
+
93
+ ## Environment
94
+
95
+ | Variable | |
96
+ |---|---|
97
+ | `MYELIN_API_KEY` | Required. Created by your bridge owner in **Bridge → API**. |
98
+ | `MYELIN_API_URL` | Optional. Defaults to `https://myelinbridge.com/api/v1`. |
99
+ | `MYELIN_API_HEADER` | Optional. Extra headers sent with every API call, one `Name: value` per line — for a Myelin deployment fronted by something that authenticates before Myelin does (a corporate gateway, an SSO-protected preview). It can never override `Authorization`. |
100
+
101
+ ## Webhooks instead of polling
102
+
103
+ Register an HTTPS endpoint (portal Bridge → API, or `POST /v1/webhook-endpoints`)
104
+ to receive signed events (`batch.validated`, `batch.changes_requested`,
105
+ `batch.transferred`, …). Verification snippets: https://myelinbridge.com/developers.
106
+ Polling fallback: `GET /v1/events?cursor=…`.