@crvouga/mockingbird-service-prism 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +114 -0
- package/dist/chunk-P5X7EJGX.js +2766 -0
- package/dist/chunk-P5X7EJGX.js.map +7 -0
- package/dist/chunk-SJWFOROE.js +364 -0
- package/dist/chunk-SJWFOROE.js.map +7 -0
- package/dist/cli.js +19 -0
- package/dist/cli.js.map +7 -0
- package/dist/index.d.ts +971 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +7 -0
- package/dist/server.d.ts +1264 -0
- package/dist/server.js +12 -0
- package/dist/server.js.map +7 -0
- package/package.json +87 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# @crvouga/mockingbird-service-prism
|
|
2
|
+
|
|
3
|
+
Stateful mock of the **Prism Labs** body-scan API for test suites: subject upsert, scan
|
|
4
|
+
creation, the presigned capture upload the capture page PUTs its video to, per-stage
|
|
5
|
+
processing states, and the READY-scan results our backend persists (body composition,
|
|
6
|
+
measurements, health report with metabolic age, asset URLs). Scans move through the real
|
|
7
|
+
lifecycle (`CREATED` → `PROCESSING` → `READY` / `FAILED`) on command or on the mock clock, and
|
|
8
|
+
results are computed deterministically from the subject's height, weight, sex and age.
|
|
9
|
+
|
|
10
|
+
- Operation coverage: [SUPPORT.md](https://github.com/crvouga/mockingbird/blob/main/packages/service/prism/SUPPORT.md)
|
|
11
|
+
- The contract (`openapi.yaml`) is hand-authored from the consumer's zod schemas
|
|
12
|
+
(`prism-scan.adapter.ts`) and the capture page's upload (`body-scan-capture-page`).
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install -D @crvouga/mockingbird-service-prism
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
ESM only. Node >= 22 or Bun >= 1.2. No native dependencies. Serve it with
|
|
21
|
+
`npx mockingbird-prism serve`, `createServer` from `./server` (Node), or `createRuntime` with
|
|
22
|
+
any Fetch server.
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
Point `PRISM_API_URL` at the mock (http is allowed) and set `PRISM_API_KEY` to anything (or
|
|
27
|
+
pin it with `--api-key`). Without both, our adapter reports `unavailable` and never calls out.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx mockingbird-prism serve --port 8825 --auto-advance 2000
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { createRuntime } from "@crvouga/mockingbird-service-prism"
|
|
35
|
+
|
|
36
|
+
const prism = createRuntime()
|
|
37
|
+
const api = (path: string, body?: unknown) =>
|
|
38
|
+
prism.fetch(
|
|
39
|
+
new Request(`http://prism.test${path}`, {
|
|
40
|
+
method: body === undefined ? "GET" : "POST",
|
|
41
|
+
headers: { authorization: "Bearer k", "content-type": "application/json" },
|
|
42
|
+
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
43
|
+
}),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
// …the app upserts the subject, creates a scan, the capture page PUTs the video…
|
|
47
|
+
// Then finish processing without waiting:
|
|
48
|
+
await api("/__admin/scans/<scan id>/advance", { to: "READY" })
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Routes
|
|
52
|
+
|
|
53
|
+
All with `Authorization: Bearer <key>` and `Accept: application/json;v=1`, except the
|
|
54
|
+
presigned upload and asset URLs.
|
|
55
|
+
|
|
56
|
+
| Route | Behaviour |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `POST /users` | Upsert by `token` (`sex`, `region`, `birthDate`, `weight {value, unit kg\|lb}`, `height {value, unit m\|in}`, `researchConsent`, `termsOfService`) → 201 on create, 200 on update, same `id`. |
|
|
59
|
+
| `POST /scans` | `{userToken, deviceConfigName: IPHONE_SCANNER\|ANDROID_SCANNER, bodyfatMethod, assetConfigId?}` → 201 scan `{id, status: "CREATED", weight, height, …}`; unknown user 404. |
|
|
60
|
+
| `GET /scans/{id}?unit-system=metric\|imperial` | Status and the subject's weight/height in that unit system. |
|
|
61
|
+
| `POST /scans/{id}/upload-url` | `{url, expirationTime}`: a presigned PUT to the mock itself (15 minutes on the mock clock; `/ns/<name>` kept in the URL). 409 once the capture is uploaded. |
|
|
62
|
+
| `PUT /uploads/{id}?expires&signature` | The capture upload. Moves the scan to `PROCESSING` (`captureData` succeeded, `body` started); an empty body fails it. Expired or tampered URLs are S3-style 403 XML. |
|
|
63
|
+
| `GET /scans/{id}/scan-assets` | `{captureData, body, fittedBody, measurement}` each `started` / `succeeded` / `failed` / `null`, with `…UpdatedAt`. |
|
|
64
|
+
| `GET /scans/{id}/bodyfat` | READY only: `{bodyfatMethod, bodyfatPercentage, leanMass, fatMass, skeletalMuscleMass}`. |
|
|
65
|
+
| `GET /scans/{id}/measurements?unit-system=` | READY only: `{waistFit, hipsFit, chestFit, waistToHipRatio, bodyRoundnessIndex, bmiPredicted}` (cm or in). |
|
|
66
|
+
| `GET /scans/{id}/health-report` | READY only: `{metabolicAgeReport: {metabolicAgeYears, chronologicalAgeYears, ageDeltaYears, percentile}, bodyShapeReport}`. |
|
|
67
|
+
| `GET /scans/{id}/asset-urls` | READY only: signed URLs for `previewImage`, `model`, `canonicalBody`, `texture`, `material`, `stripes`, served by `GET /assets/{id}/{file}`. |
|
|
68
|
+
|
|
69
|
+
Results before READY are 404 (our adapter: `not_found`). Errors are `{message, errors?}`.
|
|
70
|
+
|
|
71
|
+
### Admin (beyond the standard contract)
|
|
72
|
+
|
|
73
|
+
| Route | Effect |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| `POST /__admin/scans/:id/advance` | One processing stage on (`{"to": "READY"}` for all of them). The scan must be uploaded. |
|
|
76
|
+
| `POST /__admin/scans/:id/fail` | Fail the started stage; the scan becomes `FAILED`. |
|
|
77
|
+
| `GET /__admin/scans` | The namespace's scans. |
|
|
78
|
+
| `GET/PUT /__admin/settings` | `{apiKeys?, uploadUrlTtlMs?, autoAdvance?: {afterMs, failAt?} \| null}`; auto-advance walks uploaded scans one stage per `afterMs` of mock time. |
|
|
79
|
+
| `POST /__admin/tick` | Apply due auto-advance steps now (the served mock ticks every 100 ms). |
|
|
80
|
+
|
|
81
|
+
Fault presets (`POST /__admin/faults {"preset": "<name>", "count"?: n}`): `unauthorized`,
|
|
82
|
+
`server_error`, `scan_not_found`, `schema_drift` (an unknown scan status), `stage_states_slow`
|
|
83
|
+
(6 s, past our 5 s timeout), `metabolic_age_missing`, `metabolic_age_implausible`,
|
|
84
|
+
`upload_forbidden`, `connection_drop`.
|
|
85
|
+
|
|
86
|
+
### Namespaces
|
|
87
|
+
|
|
88
|
+
`x-mockingbird-namespace`, a `/ns/<name>` prefix on `PRISM_API_URL`, or by API key:
|
|
89
|
+
`PUT /__admin/credentials {"credentials": {"<PRISM_API_KEY>": "<namespace>"}}`. Presigned
|
|
90
|
+
upload and asset URLs carry the namespace in their path, since the capture page's PUT has no
|
|
91
|
+
other carrier.
|
|
92
|
+
|
|
93
|
+
### Deliberately not modelled
|
|
94
|
+
|
|
95
|
+
- Webhooks: our backend polls Prism, it has no receiver.
|
|
96
|
+
- Real body reconstruction: results are formulas over the subject's inputs, and the 3D assets
|
|
97
|
+
are placeholder bytes.
|
|
98
|
+
- Scan deletion, user listing, and every endpoint our adapter does not call.
|
|
99
|
+
|
|
100
|
+
## API
|
|
101
|
+
|
|
102
|
+
| Export | Kind | Description |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `PrismAPI` | class | The in-process mock: `fetch(request)`, `reset()`, `advance(scanId, fail?)`, `tick()`, `scans()`. Options: `sqlite`, `now`, `namespace`, `publicNamespace`, `settings`. |
|
|
105
|
+
| `createRuntime` | function | The mock with the full service contract (health, admin, namespaces, credentials, presets). Options: `settings`, `tickMs`, `clock`, `seed`, `adminKey`, `onLog`, `sqlite`. |
|
|
106
|
+
| `PRISM_PRESETS` | object | Every named fault preset. |
|
|
107
|
+
| `PRISM_NAMESPACE` | string | The service name, `"prism"`. |
|
|
108
|
+
| `STAGES` | array | The processing stages, in order. |
|
|
109
|
+
| `scanResults` | function | The deterministic results a READY scan answers. |
|
|
110
|
+
| `prismError` | function | Build a Prism error response `{message, errors?}`. |
|
|
111
|
+
| `document`, `operationIds`, `supportedOperationIds` | values | The OpenAPI contract and its operation ids. |
|
|
112
|
+
| `createServer`, `serveTarget`, `DEFAULT_PORT` (`./server`) | Node | Serve over `node:http` (auto-advance ticks every 100 ms); the `serve` CLI target (`--api-key`, `--auto-advance`); port 8825. |
|
|
113
|
+
|
|
114
|
+
Part of [mockingbird](https://github.com/crvouga/mockingbird).
|