mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 04:32:42 +00:00
chore: regenerate OpenAPI spec
This commit is contained in:
1 parent
7c23b14053
commit
a778acac4e
1 file changed
+179
-12
+179
-12
@@ -2731,11 +2731,13 @@ paths:
|
||||
|
||||
Three things the name understates. The list is not limited to tokens a person minted from the settings surface:
|
||||
a native login mints a wildcard access token as an `ApiToken` row, so a signed-in phone shows up here too. There
|
||||
is no mint on this path any more — the generic POST that issued `["medication:ingest"]` was removed, because
|
||||
that scope reached no ingest route while the pre-fail-closed default let it reach everything else; the working
|
||||
credential comes from the per-medication API-endpoint toggle. And unlike the revoke, this read is NOT gated on
|
||||
the operator's instance-wide API switch: that switch governs the surfaces a token is for, not a token's ability
|
||||
to authenticate, so tokens stay live while it is off and their owner has to be able to see them.
|
||||
is no GENERIC mint any more — the POST at this exact path issued `["medication:ingest"]` and was removed,
|
||||
because that scope reached no ingest route while the pre-fail-closed default let it reach everything else. The
|
||||
credentials that work are minted where they are scoped: the per-medication API-endpoint toggle, `POST
|
||||
/api/mcp/tokens` for a connector, and the sibling `POST /api/tokens/measurements` for third-party measurement
|
||||
ingest. And unlike the revoke, this read is NOT gated on the operator's instance-wide API switch: that switch
|
||||
governs the surfaces a token is for, not a token's ability to authenticate, so tokens stay live while it is off
|
||||
and their owner has to be able to see them.
|
||||
responses:
|
||||
"200":
|
||||
description: The caller's tokens, newest first.
|
||||
@@ -2746,6 +2748,86 @@ paths:
|
||||
"401": *a1
|
||||
"422": *a4
|
||||
"429": *a5
|
||||
/api/tokens/measurements:
|
||||
post:
|
||||
tags:
|
||||
- Auth
|
||||
summary: Mint a measurement-ingest token
|
||||
description: >-
|
||||
Mints a Bearer scoped to exactly `measurements:write` and audits the mint. THE RESPONSE CARRIES THE RAW TOKEN —
|
||||
the only place it ever exists; it is stored as an HMAC and no path re-reveals it.
|
||||
|
||||
|
||||
**What it can do.** `POST /api/measurements` and `POST /api/measurements/batch`, on its owner's own record,
|
||||
attributing `source: MANUAL`. An entry naming `APPLE_HEALTH` is refused 422 rather than relabelled: that source
|
||||
is half a dedup key the phone also writes into, it participates in the cross-source merge, and it is what
|
||||
decides the Apple Health card may claim a sync happened. For the same reason a write through this credential
|
||||
does not move the native client's sync checkpoint.
|
||||
|
||||
|
||||
**What it cannot do.** Everything else, including the measurement reads on the same paths, the edit and delete
|
||||
legs, and the export — a scope grants what it names and nothing adjacent. It cannot be pointed at a shared
|
||||
record: a request carrying the account selector is refused 403 before any grant is read, whatever grants its
|
||||
holder actually has. And it cannot mint another token, this endpoint included.
|
||||
|
||||
|
||||
Minting requires a COOKIE SESSION. No Bearer credential reaches this endpoint at any scope, wildcard included —
|
||||
not because a wildcard lacks the reach, but because of the lifetimes involved: a native access token lives a day
|
||||
and what it could mint here lives a year, so admitting one would let a short-lived compromise leave behind a
|
||||
credential that outlives revoking it. Gated by the operator's instance-wide API switch. Body capped at 16 KiB;
|
||||
10 mints per user per minute. Tokens appear in `GET /api/tokens` and are revoked at `DELETE /api/tokens/{id}`
|
||||
like any other.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateMeasurementTokenRequest"
|
||||
responses:
|
||||
"201":
|
||||
description: Token minted. The `token` field is the only copy of the secret.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateMeasurementTokenEnvelope"
|
||||
"400":
|
||||
description: Body is not parseable JSON.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"401": *a1
|
||||
"403":
|
||||
description: The operator has switched the API off instance-wide (`AppSettings.apiGlobal`). Nothing was minted. A Bearer
|
||||
caller does not reach this arm — it is refused 401 before the switch is read.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"413":
|
||||
description: Body exceeds 16 KiB.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"415":
|
||||
description: Content-Type is not `application/json`.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"422":
|
||||
description: Validation failed. The envelope carries every offending issue, not just the first.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"429":
|
||||
description: More than 10 mints from this account in a minute. Nothing was minted.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
/api/tokens/{id}:
|
||||
delete:
|
||||
tags:
|
||||
@@ -3564,9 +3646,18 @@ paths:
|
||||
tags:
|
||||
- Measurements
|
||||
summary: Create one measurement (or a small array)
|
||||
description: Single ingest. The body may also be a bare ARRAY of the same objects — the mode the iOS client uses for a
|
||||
description: >-
|
||||
Single ingest. The body may also be a bare ARRAY of the same objects — the mode the iOS client uses for a
|
||||
combined blood-pressure + pulse or dual-value glucose write — in which case `data` is the array of created rows
|
||||
in request order. Use `/api/measurements/batch` for Apple Health upload streams.
|
||||
|
||||
|
||||
Also reachable with a narrow `measurements:write` Bearer, which is the supported way to push readings from a
|
||||
scale, a watch bridge or a home-automation rule. That credential is confined to its owner's own record — a
|
||||
request carrying the account selector is refused 403 before any sharing grant is read, however the record is
|
||||
actually shared — and to `MANUAL` attribution, so an explicit `APPLE_HEALTH` source is refused 422
|
||||
(`measurement.create.source_not_permitted`). The GET on this same path, and the PUT and DELETE beside it, name
|
||||
no scope and so refuse it.
|
||||
parameters:
|
||||
- *a6
|
||||
requestBody:
|
||||
@@ -3595,7 +3686,14 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"422": *a4
|
||||
"422":
|
||||
description: Validation failed, or (`measurement.create.source_not_permitted`) a narrow `measurements:write` credential
|
||||
named `APPLE_HEALTH` as the source. Refused rather than relabelled, so the caller can fix the payload
|
||||
instead of discovering rows it did not ask for.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"429": *a5
|
||||
/api/measurements/{id}:
|
||||
get:
|
||||
@@ -3715,10 +3813,18 @@ paths:
|
||||
tags:
|
||||
- Measurements
|
||||
summary: Apple Health batch ingest
|
||||
description: Up to 500 HealthKit entries per call. Idempotent via the `Idempotency-Key` header (replay window 24h).
|
||||
Per-entry status lets the iOS client advance its sync cursor accurately. v1.4.25 W8c adds an optional
|
||||
`deviceType` per entry — feed it from `HKDevice.model` so the cross-source canonical picker can break
|
||||
Apple-Watch-vs-iPhone ties; null/absent stays backward-compatible with v1.4.23 clients.
|
||||
description: >-
|
||||
Up to 500 HealthKit entries per call. Idempotent via the `Idempotency-Key` header (replay window 24h). Per-entry
|
||||
status lets the iOS client advance its sync cursor accurately. v1.4.25 W8c adds an optional `deviceType` per
|
||||
entry — feed it from `HKDevice.model` so the cross-source canonical picker can break Apple-Watch-vs-iPhone ties;
|
||||
null/absent stays backward-compatible with v1.4.23 clients.
|
||||
|
||||
|
||||
Also reachable with a narrow `measurements:write` Bearer, for a bridge that is not the phone. Such a credential
|
||||
writes only on its owner's own record; its entries are attributed `MANUAL` whatever they omit, an entry naming
|
||||
`APPLE_HEALTH` is refused 422 (`measurement.batch.source_not_permitted`), and the call does not advance the
|
||||
native sync checkpoint — `lastSyncedAt` means the CLIENT delivered what it was holding, and a third-party push
|
||||
is not that.
|
||||
parameters:
|
||||
- *a6
|
||||
requestBody:
|
||||
@@ -3736,7 +3842,14 @@ paths:
|
||||
$ref: "#/components/schemas/BatchMeasurementsResponse"
|
||||
"401": *a1
|
||||
"409": *a7
|
||||
"422": *a4
|
||||
"422":
|
||||
description: The batch exceeded the 500-entry limit (`measurement.batch.too_large`), failed validation, or
|
||||
(`measurement.batch.source_not_permitted`) carried an entry naming `APPLE_HEALTH` under a narrow
|
||||
`measurements:write` credential. Nothing was written in any of the three cases.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ErrorEnvelope"
|
||||
"429": *a5
|
||||
/api/measurements/by-external-ids:
|
||||
delete:
|
||||
@@ -20732,6 +20845,23 @@ components:
|
||||
required:
|
||||
- refreshToken
|
||||
description: Exchange a one-time-use refresh token for a fresh access + refresh pair.
|
||||
CreateMeasurementTokenRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 100
|
||||
expiresInDays:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 365
|
||||
required:
|
||||
- name
|
||||
description: "Mint a measurement-ingest Bearer. There is no `scope` field: this endpoint mints one shape and the
|
||||
permission array is a literal, so no request can widen it. `name` is what the token is listed under — name it
|
||||
after the thing you are pasting it into, because that is what you will be reading when you decide whether to
|
||||
revoke it. `expiresInDays` defaults to 365."
|
||||
RegisterRequest:
|
||||
type: object
|
||||
properties:
|
||||
@@ -36378,6 +36508,43 @@ components:
|
||||
- createdAt
|
||||
- revoked
|
||||
additionalProperties: false
|
||||
CreateMeasurementTokenEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/CreateMeasurementTokenResponse"
|
||||
error:
|
||||
type: "null"
|
||||
meta:
|
||||
type: object
|
||||
properties:
|
||||
requestId:
|
||||
type: string
|
||||
additionalProperties: false
|
||||
required:
|
||||
- data
|
||||
- error
|
||||
additionalProperties: false
|
||||
CreateMeasurementTokenResponse:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
description: The raw `hlk_` Bearer, RETURNED EXACTLY ONCE. It is stored only as an HMAC-SHA256 hash, so there is no way
|
||||
to retrieve it later; a client that does not capture it here has to mint a replacement. Treat it as a secret
|
||||
in logs, crash reports and analytics.
|
||||
name:
|
||||
type: string
|
||||
expiresAt:
|
||||
type: string
|
||||
format: date-time
|
||||
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
|
||||
required:
|
||||
- token
|
||||
- name
|
||||
- expiresAt
|
||||
additionalProperties: false
|
||||
description: The one response that carries a usable measurement-ingest Bearer value.
|
||||
ApiTokenRevokeEnvelope:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
Reference in new issue
Block a user