mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
test(measurements): pin the measurement list and create before moving them into services
A parity walk over GET and POST /api/measurements: every create arm (single, combined, named sleep stage) with its duplicate and refusal, a bridge token, a delegated write, and every list mode. Sealed bytes are recorded by length, since each write carries a fresh nonce.
This commit is contained in:
1 parent
f7051ee15f
commit
8d48733c6a
25 files changed
+3201
No files matched your search
@@ -0,0 +1,282 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"userId": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "EXTERNAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"userId": "<id:2>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 5100,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T12:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-14",
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"userId": "<id:2>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": "seated",
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"userId": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": "after the run",
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:10>",
|
||||
"userId": "<id:2>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:11>",
|
||||
"userId": "<id:2>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T12:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:12>",
|
||||
"userId": "<id:2>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7100,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T12:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-12",
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 11,
|
||||
"limit": 50,
|
||||
"offset": 0
|
||||
}
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.list"
|
||||
},
|
||||
"meta": {
|
||||
"total": 11
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": "seated",
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"userId": "<id:2>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 2,
|
||||
"limit": 100,
|
||||
"offset": 0
|
||||
}
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.list"
|
||||
},
|
||||
"meta": {
|
||||
"total": 2,
|
||||
"type": "PULSE"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 6,
|
||||
"limit": 2,
|
||||
"offset": 1
|
||||
}
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.list"
|
||||
},
|
||||
"meta": {
|
||||
"total": 6
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "sleep:2026-10-14",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"mainAsleepMinutes": 90,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"dayKey": "2026-10-14",
|
||||
"sampleCount": 1,
|
||||
"sleepStages": {
|
||||
"DEEP": 90
|
||||
},
|
||||
"inBedMinutes": null,
|
||||
"awakeMinutes": null,
|
||||
"napCount": 0,
|
||||
"napAsleepMinutes": 0,
|
||||
"awakenings": 0
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 1,
|
||||
"limit": 100,
|
||||
"offset": 0,
|
||||
"groupBy": "night"
|
||||
}
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.list"
|
||||
},
|
||||
"meta": {
|
||||
"total": 1,
|
||||
"type": "SLEEP_DURATION",
|
||||
"mode": "sleep-per-night",
|
||||
"nights": 1,
|
||||
"rowsScanned": 1
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T12:00:00.000Z",
|
||||
"notes": null,
|
||||
"notesEncrypted": null,
|
||||
"externalId": "stats:HKQuantityTypeIdentifierStepCount:2026-10-13",
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": "HEALTHKIT_STATISTICS",
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 1,
|
||||
"limit": 100,
|
||||
"offset": 0,
|
||||
"dayKey": "2026-10-13"
|
||||
}
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.list"
|
||||
},
|
||||
"meta": {
|
||||
"total": 1,
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"dayKey": "2026-10-13",
|
||||
"mode": "drill-down"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"measurements": [
|
||||
{
|
||||
"id": "day:ACTIVITY_STEPS:2026-10-14",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 5100,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-14T12:00:00.000Z",
|
||||
"notes": null,
|
||||
"dayKey": "2026-10-14",
|
||||
"sampleCount": 1
|
||||
},
|
||||
{
|
||||
"id": "day:ACTIVITY_STEPS:2026-10-13",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-13T12:00:00.000Z",
|
||||
"notes": null,
|
||||
"dayKey": "2026-10-13",
|
||||
"sampleCount": 1
|
||||
},
|
||||
{
|
||||
"id": "day:ACTIVITY_STEPS:2026-10-12",
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7100,
|
||||
"unit": "steps",
|
||||
"source": "APPLE_HEALTH",
|
||||
"measuredAt": "2026-10-12T12:00:00.000Z",
|
||||
"notes": null,
|
||||
"dayKey": "2026-10-12",
|
||||
"sampleCount": 1
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 3,
|
||||
"limit": 100,
|
||||
"offset": 0,
|
||||
"groupBy": "day",
|
||||
"droppedDuplicates": 0
|
||||
}
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.list"
|
||||
},
|
||||
"meta": {
|
||||
"total": 3,
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"groupBy": "day",
|
||||
"days": 3,
|
||||
"rowsScanned": 3,
|
||||
"droppedDuplicates": 0
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"measurements": [
|
||||
{
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 7100,
|
||||
"measuredAt": "2026-10-12T00:00:00.000Z",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 8400,
|
||||
"measuredAt": "2026-10-13T00:00:00.000Z",
|
||||
"count": 1
|
||||
},
|
||||
{
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"value": 5100,
|
||||
"measuredAt": "2026-10-14T00:00:00.000Z",
|
||||
"count": 1
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 3,
|
||||
"limit": 100,
|
||||
"offset": 0,
|
||||
"aggregate": "daily"
|
||||
}
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.list"
|
||||
},
|
||||
"meta": {
|
||||
"total": 3,
|
||||
"type": "ACTIVITY_STEPS",
|
||||
"aggregate": "daily",
|
||||
"source": "live"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"measurements": [
|
||||
{
|
||||
"type": "PULSE",
|
||||
"value": 68.5,
|
||||
"measuredAt": "2026-10-12T00:00:00.000Z",
|
||||
"count": 2,
|
||||
"minValue": 66,
|
||||
"maxValue": 71
|
||||
}
|
||||
],
|
||||
"meta": {
|
||||
"total": 1,
|
||||
"limit": 100,
|
||||
"offset": 0,
|
||||
"aggregate": "weekly"
|
||||
}
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.list"
|
||||
},
|
||||
"meta": {
|
||||
"total": 1,
|
||||
"type": "PULSE",
|
||||
"aggregate": "weekly"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"status": 422,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "Validation failed",
|
||||
"details": {
|
||||
"issues": [
|
||||
{
|
||||
"path": "limit",
|
||||
"code": "too_small",
|
||||
"message": "Too small: expected number to be >=1"
|
||||
},
|
||||
{
|
||||
"path": "sortDir",
|
||||
"code": "invalid_value",
|
||||
"message": "Invalid option: expected one of \"asc\"|\"desc\""
|
||||
}
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"errorCode": "http.invalid",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 422,
|
||||
"action": {
|
||||
"name": "measurements.list.validation-failed"
|
||||
},
|
||||
"meta": {
|
||||
"issue_count": 2,
|
||||
"rejected_attempt": "measurements.list.validation-failed"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": []
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"status": 201,
|
||||
"body": {
|
||||
"data": {
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": "after the run",
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 201,
|
||||
"action": {
|
||||
"name": "measurement.create",
|
||||
"entity_type": "measurement",
|
||||
"entity_id": "<id:1>"
|
||||
},
|
||||
"meta": null,
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:2>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitInsertedMeasurementArrivals",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"notesEncrypted": "<bytes:59>",
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": "scale",
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"manual"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "runSafetyFloorCheck",
|
||||
"args": [
|
||||
{
|
||||
"userId": "<id:2>",
|
||||
"written": [
|
||||
{
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"glucoseContext": null
|
||||
}
|
||||
],
|
||||
"timezone": "UTC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "invalidateStatusInsightsForTypes",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
"WEIGHT"
|
||||
],
|
||||
{
|
||||
"source": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"status": 409,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "A measurement with this data already exists",
|
||||
"meta": {
|
||||
"errorCode": "measurement.duplicate_timestamp",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 409,
|
||||
"action": null,
|
||||
"meta": null,
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"status": 422,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "Validation failed",
|
||||
"details": {
|
||||
"issues": [
|
||||
{
|
||||
"path": "value",
|
||||
"code": "invalid_type",
|
||||
"message": "Invalid input: expected number, received string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"errorCode": "measurement.create.invalid",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 422,
|
||||
"action": {
|
||||
"name": "measurements.create.validation-failed"
|
||||
},
|
||||
"meta": {
|
||||
"issue_count": 1,
|
||||
"rejected_attempt": "measurements.create.validation-failed"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
}
|
||||
]
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"status": 201,
|
||||
"body": {
|
||||
"data": {
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 201,
|
||||
"action": {
|
||||
"name": "measurement.create",
|
||||
"entity_type": "measurement",
|
||||
"entity_id": "<id:1>"
|
||||
},
|
||||
"meta": null,
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:2>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitInsertedMeasurementArrivals",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"notesEncrypted": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"manual"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "runSafetyFloorCheck",
|
||||
"args": [
|
||||
{
|
||||
"userId": "<id:2>",
|
||||
"written": [
|
||||
{
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"glucoseContext": "FASTING"
|
||||
}
|
||||
],
|
||||
"symptomsPresent": false,
|
||||
"timezone": "UTC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "invalidateStatusInsightsForTypes",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
"BLOOD_GLUCOSE"
|
||||
],
|
||||
{
|
||||
"source": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
{
|
||||
"status": 201,
|
||||
"body": {
|
||||
"data": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"userId": "<id:2>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": "seated",
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 201,
|
||||
"action": {
|
||||
"name": "measurement.create.batch"
|
||||
},
|
||||
"meta": {
|
||||
"count": 3,
|
||||
"types": [
|
||||
"BLOOD_PRESSURE_SYS",
|
||||
"BLOOD_PRESSURE_DIA",
|
||||
"PULSE"
|
||||
]
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:2>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitInsertedMeasurementArrivals",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"notesEncrypted": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"userId": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"notesEncrypted": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"userId": "<id:2>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"notesEncrypted": "<bytes:51>",
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"manual"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "runSafetyFloorCheck",
|
||||
"args": [
|
||||
{
|
||||
"userId": "<id:2>",
|
||||
"written": [
|
||||
{
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"glucoseContext": null
|
||||
},
|
||||
{
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"glucoseContext": null
|
||||
},
|
||||
{
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"glucoseContext": null
|
||||
}
|
||||
],
|
||||
"symptomsPresent": true,
|
||||
"timezone": "UTC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "invalidateStatusInsightsForTypes",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
"BLOOD_PRESSURE_SYS",
|
||||
"BLOOD_PRESSURE_DIA",
|
||||
"PULSE"
|
||||
],
|
||||
{
|
||||
"source": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
{
|
||||
"status": 409,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "A measurement with this data already exists",
|
||||
"meta": {
|
||||
"errorCode": "measurement.duplicate_timestamp",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 409,
|
||||
"action": null,
|
||||
"meta": null,
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
{
|
||||
"status": 422,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "Validation failed",
|
||||
"details": {
|
||||
"issues": [
|
||||
{
|
||||
"path": "measurements.0.measuredAt",
|
||||
"code": "invalid_type",
|
||||
"message": "Invalid input: expected string, received undefined"
|
||||
}
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"errorCode": "measurement.create.invalid",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 422,
|
||||
"action": {
|
||||
"name": "measurements.create.batch.validation-failed"
|
||||
},
|
||||
"meta": {
|
||||
"issue_count": 1,
|
||||
"rejected_attempt": "measurements.create.batch.validation-failed"
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
{
|
||||
"status": 201,
|
||||
"body": {
|
||||
"data": {
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>",
|
||||
"status": "inserted"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 201,
|
||||
"action": {
|
||||
"name": "measurement.create.sleep-stage",
|
||||
"entity_type": "measurement",
|
||||
"entity_id": "<id:1>"
|
||||
},
|
||||
"meta": {
|
||||
"status": "inserted",
|
||||
"stage": "DEEP",
|
||||
"source": "MANUAL",
|
||||
"cross_source_merge": false
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:2>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitInsertedMeasurementArrivals",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"sleepStage": "DEEP",
|
||||
"externalId": "bridge-sleep-1",
|
||||
"deletedAt": null,
|
||||
"aggregationProvenance": null
|
||||
}
|
||||
],
|
||||
"manual"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "maybeEnqueueMorningRefresh",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
"2026-10-14T02:30:00.000Z"
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "invalidateStatusInsightsForTypes",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
"SLEEP_DURATION"
|
||||
],
|
||||
{
|
||||
"source": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"sleepStage": "DEEP",
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>",
|
||||
"status": "duplicate"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.create.sleep-stage",
|
||||
"entity_type": "measurement",
|
||||
"entity_id": "<id:1>"
|
||||
},
|
||||
"meta": {
|
||||
"status": "duplicate",
|
||||
"stage": "DEEP",
|
||||
"source": "MANUAL",
|
||||
"cross_source_merge": false
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"sleepStage": "DEEP",
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
{
|
||||
"status": 200,
|
||||
"body": {
|
||||
"data": {
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": "DEEP",
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>",
|
||||
"status": "duplicate"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 200,
|
||||
"action": {
|
||||
"name": "measurement.create.sleep-stage",
|
||||
"entity_type": "measurement",
|
||||
"entity_id": "<id:1>"
|
||||
},
|
||||
"meta": {
|
||||
"status": "duplicate",
|
||||
"stage": "DEEP",
|
||||
"source": "APPLE_HEALTH",
|
||||
"cross_source_merge": true
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"sleepStage": "DEEP",
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"status": 422,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "Validation failed",
|
||||
"details": {
|
||||
"issues": [
|
||||
{
|
||||
"path": "startDate",
|
||||
"code": "custom",
|
||||
"message": "Send the segment as startDate and endDate, or as measuredAt (its end) and value (its length in minutes)"
|
||||
}
|
||||
]
|
||||
},
|
||||
"meta": {
|
||||
"errorCode": "measurement.create.invalid",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 422,
|
||||
"action": {
|
||||
"name": "measurements.create.sleep-stage.validation-failed"
|
||||
},
|
||||
"meta": {
|
||||
"issue_count": 1
|
||||
},
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"sleepStage": "DEEP",
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"status": 422,
|
||||
"body": {
|
||||
"data": null,
|
||||
"error": "This credential resolves the source itself; omit the field",
|
||||
"meta": {
|
||||
"errorCode": "measurement.create.source_not_permitted",
|
||||
"requestId": "<requestId>"
|
||||
}
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 422,
|
||||
"action": {
|
||||
"name": "measurements.create.source-not-permitted"
|
||||
},
|
||||
"meta": null,
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:2>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"sleepStage": "DEEP",
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
{
|
||||
"status": 201,
|
||||
"body": {
|
||||
"data": {
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "EXTERNAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 201,
|
||||
"action": {
|
||||
"name": "measurement.create",
|
||||
"entity_type": "measurement",
|
||||
"entity_id": "<id:1>"
|
||||
},
|
||||
"meta": null,
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:2>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitInsertedMeasurementArrivals",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "kg",
|
||||
"source": "EXTERNAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"notesEncrypted": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"manual"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "runSafetyFloorCheck",
|
||||
"args": [
|
||||
{
|
||||
"userId": "<id:2>",
|
||||
"written": [
|
||||
{
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"glucoseContext": null
|
||||
}
|
||||
],
|
||||
"timezone": "UTC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "invalidateStatusInsightsForTypes",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
"WEIGHT"
|
||||
],
|
||||
{
|
||||
"source": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"unit": "kg",
|
||||
"source": "EXTERNAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"sleepStage": "DEEP",
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
{
|
||||
"status": 201,
|
||||
"body": {
|
||||
"data": {
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
},
|
||||
"error": null
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"status": 201,
|
||||
"action": {
|
||||
"name": "measurement.create",
|
||||
"entity_type": "measurement",
|
||||
"entity_id": "<id:1>"
|
||||
},
|
||||
"meta": null,
|
||||
"warnings": null,
|
||||
"error": null
|
||||
}
|
||||
],
|
||||
"effects": [
|
||||
{
|
||||
"effect": "enqueueReminderSatisfy",
|
||||
"args": [
|
||||
"<id:2>"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "emitInsertedMeasurementArrivals",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"userId": "<id:2>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"valueMin": null,
|
||||
"valueMax": null,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"notesEncrypted": null,
|
||||
"externalId": null,
|
||||
"externalSourceVersion": null,
|
||||
"aggregationProvenance": null,
|
||||
"glucoseContext": null,
|
||||
"sleepStage": null,
|
||||
"rhythmClassification": null,
|
||||
"deviceType": null,
|
||||
"syncVersion": "<syncVersion>",
|
||||
"deletedAt": null,
|
||||
"createdAt": "<createdAt>",
|
||||
"updatedAt": "<updatedAt>"
|
||||
}
|
||||
],
|
||||
"manual"
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "runSafetyFloorCheck",
|
||||
"args": [
|
||||
{
|
||||
"userId": "<id:2>",
|
||||
"written": [
|
||||
{
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"measuredAt": "2026-10-15T07:00:00.000Z",
|
||||
"glucoseContext": null
|
||||
}
|
||||
],
|
||||
"timezone": "UTC"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"effect": "invalidateStatusInsightsForTypes",
|
||||
"args": [
|
||||
"<id:2>",
|
||||
[
|
||||
"PULSE"
|
||||
],
|
||||
{
|
||||
"source": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"stored": [
|
||||
{
|
||||
"id": "<id:3>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.4,
|
||||
"unit": "kg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": "scale",
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:4>",
|
||||
"type": "WEIGHT",
|
||||
"value": 80.1,
|
||||
"unit": "kg",
|
||||
"source": "EXTERNAL",
|
||||
"measuredAt": "2026-10-15T06:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:5>",
|
||||
"type": "BLOOD_PRESSURE_SYS",
|
||||
"value": 128,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:6>",
|
||||
"type": "BLOOD_PRESSURE_DIA",
|
||||
"value": 82,
|
||||
"unit": "mmHg",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:7>",
|
||||
"type": "PULSE",
|
||||
"value": 66,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T08:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": true
|
||||
},
|
||||
{
|
||||
"id": "<id:1>",
|
||||
"type": "PULSE",
|
||||
"value": 71,
|
||||
"unit": "bpm",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-15T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:8>",
|
||||
"type": "SLEEP_DURATION",
|
||||
"value": 90,
|
||||
"unit": "minutes",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T02:30:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": null,
|
||||
"deviceType": null,
|
||||
"externalId": "bridge-sleep-1",
|
||||
"sleepStage": "DEEP",
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
},
|
||||
{
|
||||
"id": "<id:9>",
|
||||
"type": "BLOOD_GLUCOSE",
|
||||
"value": 104,
|
||||
"unit": "mg/dL",
|
||||
"source": "MANUAL",
|
||||
"measuredAt": "2026-10-14T07:00:00.000Z",
|
||||
"notes": null,
|
||||
"glucoseContext": "FASTING",
|
||||
"deviceType": null,
|
||||
"externalId": null,
|
||||
"sleepStage": null,
|
||||
"deletedAt": null,
|
||||
"sealedNote": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,411 @@
|
||||
/**
|
||||
* Parity for `GET` and `POST /api/measurements` while their logic moves into
|
||||
* `src/lib/measurements/`.
|
||||
*
|
||||
* The POST walk covers each arm the handler tells apart: a single reading,
|
||||
* its duplicate, a refused one; a combined two-value reading, its duplicate,
|
||||
* a refused one; a named sleep-stage segment, its re-post and its mirror
|
||||
* from the other source; a narrow bridge token with and without a `source`;
|
||||
* and a delegate writing into a record shared with them. The GET walk then
|
||||
* reads the stored rows back through every list mode: the plain page with
|
||||
* filters, the sleep list, the cumulative day drill-down, the day-grouped
|
||||
* list, the rollup series, a live aggregate, and a refused query.
|
||||
*
|
||||
* After each request the snapshot holds the response, the wide event, the
|
||||
* fire-and-forget tails the route handed work to, and (for writes) the
|
||||
* account's stored measurements, a sealed note as its presence.
|
||||
*/
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import { GET, POST } from "@/app/api/measurements/route";
|
||||
import { MEASUREMENTS_WRITE_SCOPE } from "@/lib/measurements/scopes";
|
||||
|
||||
import { callRoute, type RouteAuth } from "../../../kit/call-route";
|
||||
import {
|
||||
makeGrant,
|
||||
makeSession,
|
||||
makeToken,
|
||||
makeUser,
|
||||
} from "../../../kit/factories";
|
||||
import {
|
||||
effectRecorder,
|
||||
eventFacts,
|
||||
expectParity,
|
||||
stable,
|
||||
wideEventRecorder,
|
||||
} from "../../../kit/parity";
|
||||
import {
|
||||
getPrismaClient,
|
||||
switchSessionTo,
|
||||
truncateAllTables,
|
||||
} from "../../setup";
|
||||
|
||||
vi.mock("@/lib/logging/transports", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/logging/transports")>();
|
||||
const { wideEventRecorder: recorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
emitIfSampled: (event: (typeof recorder.events)[number]) => {
|
||||
recorder.events.push(event);
|
||||
},
|
||||
};
|
||||
});
|
||||
vi.mock("@/lib/arrivals/measurement-emit", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/arrivals/measurement-emit")>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
emitInsertedMeasurementArrivals: async (...args: unknown[]) => {
|
||||
effectRecorder.record("emitInsertedMeasurementArrivals", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
vi.mock("@/lib/daily/morning-refresh-trigger", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<
|
||||
typeof import("@/lib/daily/morning-refresh-trigger")
|
||||
>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
maybeEnqueueMorningRefresh: async (...args: unknown[]) => {
|
||||
effectRecorder.record("maybeEnqueueMorningRefresh", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
vi.mock("@/lib/jobs/reminder-satisfy", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/jobs/reminder-satisfy")>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
enqueueReminderSatisfy: async (...args: unknown[]) => {
|
||||
effectRecorder.record("enqueueReminderSatisfy", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
vi.mock("@/lib/insights/status-invalidation", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/insights/status-invalidation")>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
invalidateStatusInsightsForTypes: async (...args: unknown[]) => {
|
||||
effectRecorder.record("invalidateStatusInsightsForTypes", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
vi.mock("@/lib/illness/safety-floor-check", async (importOriginal) => {
|
||||
const actual =
|
||||
await importOriginal<typeof import("@/lib/illness/safety-floor-check")>();
|
||||
const { effectRecorder } = await import("../../../kit/parity");
|
||||
return {
|
||||
...actual,
|
||||
runSafetyFloorCheck: async (...args: unknown[]) => {
|
||||
effectRecorder.record("runSafetyFloorCheck", args);
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const prisma = getPrismaClient();
|
||||
const NOW = new Date("2026-10-15T12:00:00.000Z");
|
||||
const STEPS = "HKQuantityTypeIdentifierStepCount";
|
||||
|
||||
let ownerId: string;
|
||||
let owner: RouteAuth;
|
||||
|
||||
async function stored(userId: string) {
|
||||
const rows = await prisma.measurement.findMany({
|
||||
where: { userId },
|
||||
orderBy: [
|
||||
{ type: "asc" },
|
||||
{ measuredAt: "asc" },
|
||||
{ source: "asc" },
|
||||
{ externalId: "asc" },
|
||||
],
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
value: true,
|
||||
unit: true,
|
||||
source: true,
|
||||
measuredAt: true,
|
||||
notes: true,
|
||||
notesEncrypted: true,
|
||||
glucoseContext: true,
|
||||
deviceType: true,
|
||||
externalId: true,
|
||||
sleepStage: true,
|
||||
deletedAt: true,
|
||||
},
|
||||
});
|
||||
return rows.map(({ notesEncrypted, ...row }) => ({
|
||||
...row,
|
||||
sealedNote: notesEncrypted !== null,
|
||||
}));
|
||||
}
|
||||
|
||||
async function step(
|
||||
name: string,
|
||||
call: {
|
||||
handler: typeof GET | typeof POST;
|
||||
method: "GET" | "POST";
|
||||
body?: unknown;
|
||||
query?: Record<string, string | number>;
|
||||
auth?: RouteAuth;
|
||||
readBack?: string;
|
||||
contract?: { skip: string };
|
||||
},
|
||||
): Promise<void> {
|
||||
wideEventRecorder.take();
|
||||
effectRecorder.take();
|
||||
const res = await callRoute(call.handler, {
|
||||
method: call.method,
|
||||
route: "/api/measurements",
|
||||
body: call.body,
|
||||
query: call.query,
|
||||
auth: call.auth ?? owner,
|
||||
contract: call.contract,
|
||||
});
|
||||
const events = wideEventRecorder.take();
|
||||
expect(events.length).toBeGreaterThan(0);
|
||||
// The tails are handed off without being awaited; let them reach the
|
||||
// recorder before the snapshot is taken.
|
||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||
await expectParity(
|
||||
`measurements.${name}`,
|
||||
stable(
|
||||
{
|
||||
status: res.status,
|
||||
body: res.body,
|
||||
events: events.map(eventFacts),
|
||||
effects: effectRecorder.take(),
|
||||
...(call.readBack ? { stored: await stored(call.readBack) } : {}),
|
||||
},
|
||||
{ since: NOW },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const post = (
|
||||
name: string,
|
||||
body: unknown,
|
||||
auth?: RouteAuth,
|
||||
readBack?: string,
|
||||
) =>
|
||||
step(name, {
|
||||
handler: POST,
|
||||
method: "POST",
|
||||
body,
|
||||
auth,
|
||||
readBack: readBack ?? ownerId,
|
||||
});
|
||||
const get = (
|
||||
name: string,
|
||||
query: Record<string, string | number>,
|
||||
contract?: { skip: string },
|
||||
) => step(name, { handler: GET, method: "GET", query, contract });
|
||||
|
||||
beforeAll(async () => {
|
||||
vi.useFakeTimers({ toFake: ["Date"], now: NOW });
|
||||
await truncateAllTables(prisma);
|
||||
const user = await makeUser({ timezone: "UTC" });
|
||||
ownerId = user.id;
|
||||
owner = await makeSession(user);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
describe("POST /api/measurements parity", () => {
|
||||
it("a single reading, its duplicate, a refused one", async () => {
|
||||
const weight = {
|
||||
type: "WEIGHT",
|
||||
value: 80.4,
|
||||
measuredAt: "2026-10-14T06:30:00.000Z",
|
||||
notes: "after the run",
|
||||
deviceType: "scale",
|
||||
};
|
||||
await post("post-01-single", weight);
|
||||
await post("post-02-single-duplicate", weight);
|
||||
await post("post-03-single-invalid", {
|
||||
type: "WEIGHT",
|
||||
value: "heavy",
|
||||
measuredAt: "2026-10-14T06:30:00.000Z",
|
||||
});
|
||||
await post("post-04-single-glucose", {
|
||||
type: "BLOOD_GLUCOSE",
|
||||
value: 104,
|
||||
measuredAt: "2026-10-14T07:00:00.000Z",
|
||||
glucoseContext: "FASTING",
|
||||
symptomsPresent: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("a combined two-value reading, its duplicate, a refused one", async () => {
|
||||
const reading = [
|
||||
{
|
||||
type: "BLOOD_PRESSURE_SYS",
|
||||
value: 128,
|
||||
measuredAt: "2026-10-14T08:00:00.000Z",
|
||||
},
|
||||
{
|
||||
type: "BLOOD_PRESSURE_DIA",
|
||||
value: 82,
|
||||
measuredAt: "2026-10-14T08:00:00.000Z",
|
||||
},
|
||||
{
|
||||
type: "PULSE",
|
||||
value: 66,
|
||||
measuredAt: "2026-10-14T08:00:00.000Z",
|
||||
notes: "seated",
|
||||
symptomsPresent: true,
|
||||
},
|
||||
];
|
||||
await post("post-05-batch", reading);
|
||||
await post("post-06-batch-duplicate", reading);
|
||||
await post("post-07-batch-invalid", [{ type: "PULSE", value: -1 }]);
|
||||
});
|
||||
|
||||
it("a named sleep-stage segment, its re-post and its mirror", async () => {
|
||||
const segment = {
|
||||
type: "SLEEP_DURATION",
|
||||
sleepStage: "DEEP",
|
||||
startDate: "2026-10-14T01:00:00.000Z",
|
||||
endDate: "2026-10-14T02:30:00.000Z",
|
||||
externalId: "bridge-sleep-1",
|
||||
};
|
||||
await post("post-08-sleep-stage", segment);
|
||||
await post("post-09-sleep-stage-again", segment);
|
||||
await post("post-10-sleep-stage-mirror", {
|
||||
...segment,
|
||||
externalId: "hk-sleep-1",
|
||||
source: "APPLE_HEALTH",
|
||||
});
|
||||
await post("post-11-sleep-stage-invalid", {
|
||||
type: "SLEEP_DURATION",
|
||||
sleepStage: "DEEP",
|
||||
});
|
||||
});
|
||||
|
||||
it("a narrow bridge token with and without a source", async () => {
|
||||
const bridge = await makeToken(
|
||||
{ id: ownerId },
|
||||
{ permissions: [MEASUREMENTS_WRITE_SCOPE] },
|
||||
);
|
||||
await post(
|
||||
"post-12-bridge-with-source",
|
||||
{
|
||||
type: "WEIGHT",
|
||||
value: 80.1,
|
||||
measuredAt: "2026-10-15T06:30:00.000Z",
|
||||
source: "MANUAL",
|
||||
},
|
||||
bridge,
|
||||
);
|
||||
await post(
|
||||
"post-13-bridge",
|
||||
{
|
||||
type: "WEIGHT",
|
||||
value: 80.1,
|
||||
measuredAt: "2026-10-15T06:30:00.000Z",
|
||||
},
|
||||
bridge,
|
||||
);
|
||||
});
|
||||
|
||||
it("a delegate writing into a shared record", async () => {
|
||||
const delegateUser = await makeUser({ timezone: "UTC" });
|
||||
await makeGrant({ id: ownerId }, delegateUser, { access: "WRITE" });
|
||||
const delegate = await makeSession(delegateUser);
|
||||
await switchSessionTo(delegate.sessionId, ownerId);
|
||||
await post(
|
||||
"post-14-delegated",
|
||||
{
|
||||
type: "PULSE",
|
||||
value: 71,
|
||||
measuredAt: "2026-10-15T07:00:00.000Z",
|
||||
},
|
||||
delegate,
|
||||
);
|
||||
await switchSessionTo(delegate.sessionId, null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("GET /api/measurements parity", () => {
|
||||
beforeAll(async () => {
|
||||
// Day totals for the cumulative list modes, from the phone.
|
||||
for (const [day, value] of [
|
||||
["2026-10-12", 7_100],
|
||||
["2026-10-13", 8_400],
|
||||
["2026-10-14", 5_100],
|
||||
] as const) {
|
||||
await prisma.measurement.create({
|
||||
data: {
|
||||
userId: ownerId,
|
||||
type: "ACTIVITY_STEPS",
|
||||
value,
|
||||
unit: "steps",
|
||||
source: "APPLE_HEALTH",
|
||||
measuredAt: new Date(`${day}T12:00:00.000Z`),
|
||||
externalId: `stats:${STEPS}:${day}`,
|
||||
aggregationProvenance: "HEALTHKIT_STATISTICS",
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("the plain page and its filters", async () => {
|
||||
await get("get-01-page", { limit: 50 });
|
||||
await get("get-02-type-sorted", {
|
||||
type: "PULSE",
|
||||
sortBy: "value",
|
||||
sortDir: "asc",
|
||||
});
|
||||
await get("get-03-filtered", {
|
||||
sourceEq: "MANUAL",
|
||||
valueMin: 70,
|
||||
valueMax: 130,
|
||||
from: "2026-10-14T00:00:00.000Z",
|
||||
to: "2026-10-15T23:59:59.000Z",
|
||||
limit: 2,
|
||||
offset: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it("the list modes", async () => {
|
||||
await get("get-04-sleep", { type: "SLEEP_DURATION" });
|
||||
// The drill-down answers the stored rows as they are, `notesEncrypted`
|
||||
// included, which the contract does not declare (the other list modes
|
||||
// strip it). Pinned as it is; this walk records behaviour, it does not
|
||||
// change it.
|
||||
await get(
|
||||
"get-05-drill-down",
|
||||
{ type: "ACTIVITY_STEPS", dayKey: "2026-10-13" },
|
||||
{
|
||||
skip: "the drill-down returns notesEncrypted, which the contract omits",
|
||||
},
|
||||
);
|
||||
await get("get-06-day-grouped", { type: "ACTIVITY_STEPS", groupBy: "day" });
|
||||
await get("get-07-rollup-series", {
|
||||
type: "ACTIVITY_STEPS",
|
||||
source: "rollup",
|
||||
aggregate: "daily",
|
||||
from: "2026-10-10T00:00:00.000Z",
|
||||
to: "2026-10-15T23:59:59.000Z",
|
||||
});
|
||||
await get("get-08-live-aggregate", {
|
||||
type: "PULSE",
|
||||
aggregate: "weekly",
|
||||
from: "2026-09-01T00:00:00.000Z",
|
||||
to: "2026-10-15T23:59:59.000Z",
|
||||
});
|
||||
});
|
||||
|
||||
it("a refused query", async () => {
|
||||
await get("get-09-invalid", { limit: 0, sortDir: "sideways" });
|
||||
});
|
||||
});
|
||||
@@ -72,6 +72,8 @@ export function stable(value: unknown, options: StableOptions): unknown {
|
||||
return `<${key}>`;
|
||||
}
|
||||
if (node instanceof Date) node = node.toISOString();
|
||||
// Sealed columns carry a fresh nonce on every write: keep the length.
|
||||
if (node instanceof Uint8Array) return `<bytes:${node.length}>`;
|
||||
if (typeof node === "string") {
|
||||
if (GENERATED_ID.test(node)) {
|
||||
let label = ids.get(node);
|
||||
|
||||
Reference in new issue
Block a user