@robbeverhelst/do 1.314.1 → 1.316.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/do.js +1328 -189
- package/package.json +1 -1
package/dist/do.js
CHANGED
|
@@ -22627,6 +22627,31 @@ var houseUpkeepYearSchema = object({
|
|
|
22627
22627
|
});
|
|
22628
22628
|
var houseUpkeepYearQuerySchema = object({ year: exports_coerce.number().int().min(2000).max(2100).optional() }).strict();
|
|
22629
22629
|
|
|
22630
|
+
// ../../packages/schema/src/contracts/health-export.ts
|
|
22631
|
+
var HEALTH_EXPORT_RESOURCE_TYPES = [
|
|
22632
|
+
"Patient",
|
|
22633
|
+
"AllergyIntolerance",
|
|
22634
|
+
"Condition",
|
|
22635
|
+
"Observation",
|
|
22636
|
+
"Encounter",
|
|
22637
|
+
"MedicationStatement",
|
|
22638
|
+
"MedicationAdministration",
|
|
22639
|
+
"DiagnosticReport",
|
|
22640
|
+
"DocumentReference"
|
|
22641
|
+
];
|
|
22642
|
+
var healthExportQuerySchema = object({
|
|
22643
|
+
files: _enum2(["true", "false"]).default("true").transform((v) => v === "true")
|
|
22644
|
+
});
|
|
22645
|
+
var fhirResourceSchema = object({ resourceType: _enum2(HEALTH_EXPORT_RESOURCE_TYPES), id: string2().min(1) }).passthrough();
|
|
22646
|
+
var healthExportBundleSchema = object({
|
|
22647
|
+
resourceType: literal("Bundle"),
|
|
22648
|
+
id: string2().min(1),
|
|
22649
|
+
type: literal("collection"),
|
|
22650
|
+
timestamp: string2().datetime({ offset: true }),
|
|
22651
|
+
meta: object({ tag: array(object({ system: string2(), code: string2() })) }),
|
|
22652
|
+
entry: array(object({ fullUrl: string2().min(1), resource: fhirResourceSchema }))
|
|
22653
|
+
});
|
|
22654
|
+
|
|
22630
22655
|
// ../../packages/schema/src/receipt-kinds.ts
|
|
22631
22656
|
var MONEY_RECEIPT_NODE_TYPE = "money_transaction";
|
|
22632
22657
|
var RECEIPT_KINDS = {
|
|
@@ -26941,6 +26966,120 @@ var documentsQuerySchema = object({
|
|
|
26941
26966
|
providerId: ulidSchema.optional()
|
|
26942
26967
|
});
|
|
26943
26968
|
|
|
26969
|
+
// ../../packages/schema/src/contracts/document-ask.ts
|
|
26970
|
+
var documentPassageSourceSchema = _enum2(["field", "text"]);
|
|
26971
|
+
var documentPassageSchema = object({
|
|
26972
|
+
documentId: ulidSchema,
|
|
26973
|
+
documentTitle: string2(),
|
|
26974
|
+
documentKind: documentKindSchema,
|
|
26975
|
+
source: documentPassageSourceSchema,
|
|
26976
|
+
fileId: ulidSchema.nullable(),
|
|
26977
|
+
fileName: string2().nullable(),
|
|
26978
|
+
page: number2().int().positive().nullable(),
|
|
26979
|
+
text: string2(),
|
|
26980
|
+
matched: array(string2())
|
|
26981
|
+
});
|
|
26982
|
+
var documentWithoutTextSchema = object({
|
|
26983
|
+
documentId: ulidSchema,
|
|
26984
|
+
documentTitle: string2()
|
|
26985
|
+
});
|
|
26986
|
+
var documentAskInputSchema = object({
|
|
26987
|
+
question: string2().trim().min(2).max(500),
|
|
26988
|
+
documentId: ulidSchema.optional(),
|
|
26989
|
+
limit: exports_coerce.number().int().min(1).max(20).optional()
|
|
26990
|
+
}).strict();
|
|
26991
|
+
var documentAnswerSchema = object({
|
|
26992
|
+
question: string2(),
|
|
26993
|
+
found: boolean3(),
|
|
26994
|
+
passages: array(documentPassageSchema),
|
|
26995
|
+
pages: array(object({ documentId: ulidSchema, pages: array(number2().int()) })),
|
|
26996
|
+
withoutText: array(documentWithoutTextSchema),
|
|
26997
|
+
note: string2()
|
|
26998
|
+
});
|
|
26999
|
+
var documentSearchQuerySchema = object({
|
|
27000
|
+
q: string2().trim().min(2).max(200),
|
|
27001
|
+
documentId: ulidSchema.optional(),
|
|
27002
|
+
limit: exports_coerce.number().int().min(1).max(50).optional()
|
|
27003
|
+
}).strict();
|
|
27004
|
+
var documentSearchResultSchema = object({
|
|
27005
|
+
q: string2(),
|
|
27006
|
+
hits: array(documentPassageSchema)
|
|
27007
|
+
});
|
|
27008
|
+
|
|
27009
|
+
// ../../packages/schema/src/contracts/document-payments.ts
|
|
27010
|
+
var documentPaymentSchema = object({
|
|
27011
|
+
transactionId: ulidSchema,
|
|
27012
|
+
accountId: ulidSchema,
|
|
27013
|
+
accountTitle: string2(),
|
|
27014
|
+
bookedOn: string2(),
|
|
27015
|
+
amount: string2(),
|
|
27016
|
+
currency: string2(),
|
|
27017
|
+
counterpartyName: string2().nullable()
|
|
27018
|
+
});
|
|
27019
|
+
var unmatchedPaperSchema = object({
|
|
27020
|
+
id: ulidSchema,
|
|
27021
|
+
title: string2(),
|
|
27022
|
+
kind: documentKindSchema,
|
|
27023
|
+
amountDue: number2(),
|
|
27024
|
+
payBy: string2().nullable(),
|
|
27025
|
+
providerTitle: string2().nullable(),
|
|
27026
|
+
candidates: number2().int().nonnegative()
|
|
27027
|
+
});
|
|
27028
|
+
var paperMatchStatusSchema = _enum2([
|
|
27029
|
+
"matched",
|
|
27030
|
+
"already",
|
|
27031
|
+
"ambiguous",
|
|
27032
|
+
"none",
|
|
27033
|
+
"not_payable"
|
|
27034
|
+
]);
|
|
27035
|
+
var paperMatchResultSchema = object({
|
|
27036
|
+
documentId: ulidSchema,
|
|
27037
|
+
status: paperMatchStatusSchema,
|
|
27038
|
+
transactionId: ulidSchema.nullable(),
|
|
27039
|
+
by: _enum2(["ref", "iban"]).nullable(),
|
|
27040
|
+
candidates: array(ulidSchema)
|
|
27041
|
+
});
|
|
27042
|
+
var linkPaperPaymentInputSchema = object({ transactionId: ulidSchema }).strict();
|
|
27043
|
+
|
|
27044
|
+
// ../../packages/schema/src/contracts/doccle.ts
|
|
27045
|
+
var DOCCLE_FAILURE_KINDS = ["credentials", "captcha", "changed", "unavailable"];
|
|
27046
|
+
var doccleFailureKindSchema = _enum2(DOCCLE_FAILURE_KINDS);
|
|
27047
|
+
var doccleFailureSchema = object({
|
|
27048
|
+
kind: doccleFailureKindSchema,
|
|
27049
|
+
title: string2(),
|
|
27050
|
+
hint: string2(),
|
|
27051
|
+
since: exports_coerce.date()
|
|
27052
|
+
});
|
|
27053
|
+
var doccleStatusSchema = object({
|
|
27054
|
+
enabled: boolean3(),
|
|
27055
|
+
connected: boolean3(),
|
|
27056
|
+
archiveAfterImport: boolean3(),
|
|
27057
|
+
lastRunAt: exports_coerce.date().nullable(),
|
|
27058
|
+
lastOkAt: exports_coerce.date().nullable(),
|
|
27059
|
+
failure: doccleFailureSchema.nullable(),
|
|
27060
|
+
lastRun: object({
|
|
27061
|
+
filed: number2().int().nonnegative(),
|
|
27062
|
+
alreadyFiled: number2().int().nonnegative(),
|
|
27063
|
+
secured: number2().int().nonnegative()
|
|
27064
|
+
}),
|
|
27065
|
+
imported: number2().int().nonnegative()
|
|
27066
|
+
});
|
|
27067
|
+
var doccleLoginInputSchema = object({
|
|
27068
|
+
username: string2().trim().min(1).max(200),
|
|
27069
|
+
password: string2().min(1).max(200)
|
|
27070
|
+
}).strict();
|
|
27071
|
+
var doccleSettingsInputSchema = object({ archiveAfterImport: boolean3() }).strict();
|
|
27072
|
+
var DOCCLE_RUN_OUTCOMES = ["ok", "failed", "not_connected", "off", "busy"];
|
|
27073
|
+
var doccleSyncResultSchema = object({
|
|
27074
|
+
outcome: _enum2(DOCCLE_RUN_OUTCOMES),
|
|
27075
|
+
filed: number2().int().nonnegative(),
|
|
27076
|
+
alreadyFiled: number2().int().nonnegative(),
|
|
27077
|
+
secured: number2().int().nonnegative(),
|
|
27078
|
+
archived: number2().int().nonnegative(),
|
|
27079
|
+
documentIds: array(string2()),
|
|
27080
|
+
failure: doccleFailureSchema.nullable()
|
|
27081
|
+
});
|
|
27082
|
+
|
|
26944
27083
|
// ../../packages/schema/src/contracts/incidents.ts
|
|
26945
27084
|
var incidentKindSchema = _enum2(incidentKind.enumValues);
|
|
26946
27085
|
var incidentStatusSchema = _enum2(incidentStatus.enumValues);
|
|
@@ -31599,6 +31738,277 @@ var dayOperations = defineOperations({
|
|
|
31599
31738
|
}
|
|
31600
31739
|
});
|
|
31601
31740
|
|
|
31741
|
+
// ../../packages/schema/src/operations/documents.ts
|
|
31742
|
+
var DOCCLE_STATUS = "The import's status.";
|
|
31743
|
+
var PAPER_ID = { id: ulidSchema };
|
|
31744
|
+
var documentOperations = defineOperations({
|
|
31745
|
+
...crudOperations({
|
|
31746
|
+
segment: "documents",
|
|
31747
|
+
tag: "Documents",
|
|
31748
|
+
noun: "document",
|
|
31749
|
+
read: "documents:read",
|
|
31750
|
+
write: "documents:write",
|
|
31751
|
+
create: createDocumentInputSchema,
|
|
31752
|
+
update: updateDocumentInputSchema,
|
|
31753
|
+
listQuery: [
|
|
31754
|
+
{
|
|
31755
|
+
name: "kind",
|
|
31756
|
+
description: "Only this kind (`insurance`, `contract`, `subscription`, `id_paper`, `house_cert`, `warranty`, \u2026)."
|
|
31757
|
+
},
|
|
31758
|
+
{
|
|
31759
|
+
name: "status",
|
|
31760
|
+
description: "Only this status (`active`, `ended`, `superseded`, `draft`)."
|
|
31761
|
+
},
|
|
31762
|
+
{ name: "providerId", description: "Only the documents issued by this Contact." }
|
|
31763
|
+
],
|
|
31764
|
+
listQuerySchema: documentsQuerySchema
|
|
31765
|
+
}),
|
|
31766
|
+
unmatched: {
|
|
31767
|
+
method: "get",
|
|
31768
|
+
path: "/documents/unmatched",
|
|
31769
|
+
scopes: ["documents:read", "finance:read"],
|
|
31770
|
+
tag: "Documents",
|
|
31771
|
+
summary: "Papers waiting for their payment",
|
|
31772
|
+
description: "The papers that ask for money (`fields.amountDue`, with an IBAN or a structured reference to match on) and have no payment linked, oldest due first: `{ id, title, kind, amountDue, payBy, providerTitle, candidates }`. `candidates` counts the payments that fit equally well. A payment on an account the key can't see doesn't count.",
|
|
31773
|
+
status: 200,
|
|
31774
|
+
response: { description: "The unmatched papers." }
|
|
31775
|
+
},
|
|
31776
|
+
matchAll: {
|
|
31777
|
+
method: "post",
|
|
31778
|
+
path: "/documents/match",
|
|
31779
|
+
scopes: ["documents:read", "finance:write"],
|
|
31780
|
+
tag: "Documents",
|
|
31781
|
+
summary: "Match every paper to its payment",
|
|
31782
|
+
description: "Match every paper still waiting for its payment. A payment is money out of exactly the amount due, booked between a week before the paper and 45 days after its due day, carrying its structured reference or (without one) going to its IBAN; it's linked only when exactly one fits, as the transaction's `evidence`. Returns one `{ documentId, status, transactionId, by, candidates }` per paper; `status` is `matched`, `already`, `ambiguous`, `none` or `not_payable`. Papers are also matched when filed or changed by a key with `finance:write`, and after a bank import.",
|
|
31783
|
+
status: 200,
|
|
31784
|
+
response: { description: "One result per paper." }
|
|
31785
|
+
},
|
|
31786
|
+
filed: {
|
|
31787
|
+
method: "get",
|
|
31788
|
+
path: "/documents/filed",
|
|
31789
|
+
scopes: ["documents:read"],
|
|
31790
|
+
tag: "Documents",
|
|
31791
|
+
summary: "Check a filed source",
|
|
31792
|
+
description: "Whether a mail (`gmail:<id>`) or an import was already filed: `{ filed, documentId }`. The Gmail watch and backfill dedupe with it. 403 until `DOCUMENTS_IMPORT_ENABLED=true`.",
|
|
31793
|
+
query: [{ name: "source", description: "`gmail:<id>` or `doccle_zip`." }],
|
|
31794
|
+
querySchema: object({ source: fileSourceSchema }),
|
|
31795
|
+
status: 200,
|
|
31796
|
+
response: { description: "`{ filed, documentId }`." },
|
|
31797
|
+
errors: { 403: "Imports are off." },
|
|
31798
|
+
operationId: "document_filed"
|
|
31799
|
+
},
|
|
31800
|
+
doccleStatus: {
|
|
31801
|
+
method: "get",
|
|
31802
|
+
path: "/documents/doccle",
|
|
31803
|
+
scopes: ["documents:read"],
|
|
31804
|
+
tag: "Documents",
|
|
31805
|
+
summary: "Your Doccle import",
|
|
31806
|
+
description: "The key's member's Doccle import (ADR 0033), which files their Doccle mailbox into Papers every night: `{ enabled, connected, archiveAfterImport, lastRunAt, lastOkAt, failure, lastRun: { filed, alreadyFiled, secured }, imported }`. `failure` (`{ kind, title, hint, since }`, kind `credentials` \xB7 `captcha` \xB7 `changed` \xB7 `unavailable`) says why it is stuck, while it is. The login itself is never returned.",
|
|
31807
|
+
status: 200,
|
|
31808
|
+
response: { description: DOCCLE_STATUS }
|
|
31809
|
+
},
|
|
31810
|
+
doccleSettings: {
|
|
31811
|
+
method: "patch",
|
|
31812
|
+
path: "/documents/doccle",
|
|
31813
|
+
scopes: ["documents:write"],
|
|
31814
|
+
tag: "Documents",
|
|
31815
|
+
summary: "Change your Doccle import's setting",
|
|
31816
|
+
description: "`{ archiveAfterImport }`: archive each document in Doccle once it is filed as a paper (off by default). Returns the status.",
|
|
31817
|
+
body: doccleSettingsInputSchema,
|
|
31818
|
+
status: 200,
|
|
31819
|
+
response: { description: DOCCLE_STATUS },
|
|
31820
|
+
errors: { 400: "Not a boolean." }
|
|
31821
|
+
},
|
|
31822
|
+
doccleConnect: {
|
|
31823
|
+
method: "put",
|
|
31824
|
+
path: "/documents/doccle/login",
|
|
31825
|
+
scopes: ["connections:write"],
|
|
31826
|
+
tag: "Documents",
|
|
31827
|
+
summary: "Connect your Doccle login",
|
|
31828
|
+
description: "`{ username, password }`: do checks the login with Doccle, then keeps it sealed in the connection-secret store (ADR 0032) for the nightly import. It is never returned or logged. Returns the status.",
|
|
31829
|
+
afterScopes: "`*` and `private:*` never grant `connections:write`: a key holds it by name, and a guest's key never does.",
|
|
31830
|
+
body: doccleLoginInputSchema,
|
|
31831
|
+
status: 200,
|
|
31832
|
+
response: { description: "The import's status, connected." },
|
|
31833
|
+
errors: {
|
|
31834
|
+
403: "The key doesn't hold `connections:write`, or is a guest's.",
|
|
31835
|
+
422: "Doccle refused the login or asked for a captcha; nothing is kept.",
|
|
31836
|
+
503: "Doccle couldn't be reached."
|
|
31837
|
+
},
|
|
31838
|
+
mcp: false
|
|
31839
|
+
},
|
|
31840
|
+
doccleDisconnect: {
|
|
31841
|
+
method: "delete",
|
|
31842
|
+
path: "/documents/doccle/login",
|
|
31843
|
+
scopes: ["documents:write"],
|
|
31844
|
+
tag: "Documents",
|
|
31845
|
+
summary: "Forget your Doccle login",
|
|
31846
|
+
description: "The nightly import stops; the papers it filed stay. Returns the status.",
|
|
31847
|
+
status: 200,
|
|
31848
|
+
response: { description: DOCCLE_STATUS }
|
|
31849
|
+
},
|
|
31850
|
+
doccleSync: {
|
|
31851
|
+
method: "post",
|
|
31852
|
+
path: "/documents/doccle/sync",
|
|
31853
|
+
scopes: ["documents:write"],
|
|
31854
|
+
tag: "Documents",
|
|
31855
|
+
summary: "Run your Doccle import now",
|
|
31856
|
+
description: "Each Doccle document not seen before becomes a paper: its sender as the provider (an organisation Contact), its date, its PDF (`source: doccle`), an invoice's amount, IBAN and payment reference, then matched to its payment. Nothing is filed twice: a document is skipped on Doccle's id, and a PDF already in Papers (a Doccle ZIP export, or by hand) on its SHA-256. `{ outcome, filed, alreadyFiled, secured, archived, documentIds, failure }`; `outcome` is `ok`, `failed` (the member is told once), `not_connected`, `off` (`DOCUMENTS_IMPORT_ENABLED` isn't on) or `busy`.",
|
|
31857
|
+
status: 200,
|
|
31858
|
+
response: { description: "What the run did." }
|
|
31859
|
+
},
|
|
31860
|
+
ask: {
|
|
31861
|
+
method: "post",
|
|
31862
|
+
path: "/documents/ask",
|
|
31863
|
+
scopes: ["documents:read"],
|
|
31864
|
+
tag: "Documents",
|
|
31865
|
+
summary: "Ask the papers (doc_ask)",
|
|
31866
|
+
description: "`doc_ask`: `{ question, documentId?, limit? }` asks one paper, or every paper the key can read, and returns the passages that answer, best first, each with its paper, file and page: `{ question, found, passages: [{ documentId, documentTitle, documentKind, source, fileId, fileName, page, text, matched }], pages: [{ documentId, pages }], withoutText, note }`. The words come from the papers' key fields (`source: field`, the page an extraction read it on) and their files' `textExtract` (`source: text`, a page per form feed). do writes no prose: word the answer from the passages, quote the pages, and say it is not legal advice (`note`). `withoutText` names the papers asked (or, asking them all, those the question names) that hold no file text, so you can offer to fetch the conditions. An Only me paper answers only its owner's key with `documents:private`.",
|
|
31867
|
+
body: documentAskInputSchema,
|
|
31868
|
+
status: 200,
|
|
31869
|
+
response: { description: "The passages that answer." },
|
|
31870
|
+
errors: { 404: "No such paper." },
|
|
31871
|
+
reads: true
|
|
31872
|
+
},
|
|
31873
|
+
search: {
|
|
31874
|
+
method: "get",
|
|
31875
|
+
path: "/documents/search",
|
|
31876
|
+
scopes: ["documents:read"],
|
|
31877
|
+
tag: "Documents",
|
|
31878
|
+
summary: "Search the papers' words",
|
|
31879
|
+
description: "Search the papers' key fields and file text: `{ q, hits }`, a passage per page or field that holds the words, best first, shaped as `doc_ask`'s passages.",
|
|
31880
|
+
query: [
|
|
31881
|
+
{ name: "q", description: "The words to find (two letters or more)." },
|
|
31882
|
+
{ name: "documentId", description: "Only this paper." },
|
|
31883
|
+
{ name: "limit", description: "How many hits at most (default 20, up to 50)." }
|
|
31884
|
+
],
|
|
31885
|
+
querySchema: documentSearchQuerySchema,
|
|
31886
|
+
status: 200,
|
|
31887
|
+
response: { description: "The hits." }
|
|
31888
|
+
},
|
|
31889
|
+
matchOne: {
|
|
31890
|
+
method: "post",
|
|
31891
|
+
path: "/documents/{id}/match",
|
|
31892
|
+
scopes: ["documents:read", "finance:write"],
|
|
31893
|
+
tag: "Documents",
|
|
31894
|
+
summary: "Match a paper to its payment",
|
|
31895
|
+
description: "Match this paper to its payment, if exactly one fits: `{ documentId, status, transactionId, by, candidates }`.",
|
|
31896
|
+
pathParamSchemas: PAPER_ID,
|
|
31897
|
+
status: 200,
|
|
31898
|
+
response: { description: "What matching did." },
|
|
31899
|
+
errors: { 404: "No such paper." }
|
|
31900
|
+
},
|
|
31901
|
+
payments: {
|
|
31902
|
+
method: "get",
|
|
31903
|
+
path: "/documents/{id}/payments",
|
|
31904
|
+
scopes: ["documents:read", "finance:read"],
|
|
31905
|
+
tag: "Documents",
|
|
31906
|
+
summary: "A paper's payments",
|
|
31907
|
+
description: "The payments linked to this paper that the key may see: `{ transactionId, accountId, accountTitle, bookedOn, amount, currency, counterpartyName }`.",
|
|
31908
|
+
pathParamSchemas: PAPER_ID,
|
|
31909
|
+
status: 200,
|
|
31910
|
+
response: { description: "The payments." }
|
|
31911
|
+
},
|
|
31912
|
+
linkPayment: {
|
|
31913
|
+
method: "put",
|
|
31914
|
+
path: "/documents/{id}/payments",
|
|
31915
|
+
scopes: ["documents:read", "finance:write"],
|
|
31916
|
+
tag: "Documents",
|
|
31917
|
+
summary: "Link a payment to a paper",
|
|
31918
|
+
description: "Link a payment to this paper by hand (`{ transactionId }`), e.g. one of the fits when matching was ambiguous. Returns the paper's payments.",
|
|
31919
|
+
pathParamSchemas: PAPER_ID,
|
|
31920
|
+
body: linkPaperPaymentInputSchema,
|
|
31921
|
+
status: 200,
|
|
31922
|
+
response: { description: "The paper's payments." },
|
|
31923
|
+
errors: { 404: "No such paper or transaction." }
|
|
31924
|
+
},
|
|
31925
|
+
unlinkPayment: {
|
|
31926
|
+
method: "delete",
|
|
31927
|
+
path: "/documents/{id}/payments/{transactionId}",
|
|
31928
|
+
scopes: ["documents:read", "finance:write"],
|
|
31929
|
+
tag: "Documents",
|
|
31930
|
+
summary: "Take a payment off a paper",
|
|
31931
|
+
description: "Unlink this payment from the paper.",
|
|
31932
|
+
pathParams: { transactionId: "The Money transaction's ULID." },
|
|
31933
|
+
pathParamSchemas: { id: ulidSchema, transactionId: ulidSchema },
|
|
31934
|
+
status: 204,
|
|
31935
|
+
response: { description: "Unlinked." },
|
|
31936
|
+
errors: { 404: "That payment isn't linked to this paper." }
|
|
31937
|
+
}
|
|
31938
|
+
});
|
|
31939
|
+
|
|
31940
|
+
// ../../packages/schema/src/operations/family-tree.ts
|
|
31941
|
+
var familyTreeOperations = defineOperations({
|
|
31942
|
+
get: {
|
|
31943
|
+
method: "get",
|
|
31944
|
+
path: "/family-tree",
|
|
31945
|
+
scopes: ["people:family-tree"],
|
|
31946
|
+
tag: "People",
|
|
31947
|
+
summary: "The family tree",
|
|
31948
|
+
description: "The member's tree: the import facts, the branch two generations up from them once they've said who they are (`side` = `father` or `mother`), and what it noticed. `{ tree: null }` before an import.",
|
|
31949
|
+
afterScopes: "A sensitive scope (ADR 0028): never part of `*`, and only the tree of the member who minted the key.",
|
|
31950
|
+
query: [
|
|
31951
|
+
{ name: "side", description: "Which grandparents the branch climbs to: father or mother." }
|
|
31952
|
+
],
|
|
31953
|
+
querySchema: familyTreeQuerySchema,
|
|
31954
|
+
status: 200,
|
|
31955
|
+
response: { description: "`{ tree }`." },
|
|
31956
|
+
errors: { 400: true, 403: "The key doesn't hold `people:family-tree`, or is no member's." }
|
|
31957
|
+
},
|
|
31958
|
+
people: {
|
|
31959
|
+
method: "get",
|
|
31960
|
+
path: "/family-tree/people",
|
|
31961
|
+
scopes: ["people:family-tree"],
|
|
31962
|
+
tag: "People",
|
|
31963
|
+
summary: "Everyone in the tree",
|
|
31964
|
+
description: "By name, with `q` (a part of the name), `filter` (all \xB7 living \xB7 linked) and `limit` (1\u2013500, default 100): how to find a person's `ref`.",
|
|
31965
|
+
query: [
|
|
31966
|
+
{ name: "q", description: "A part of the name." },
|
|
31967
|
+
{ name: "filter", description: "all, living or linked." },
|
|
31968
|
+
{ name: "limit", description: "At most this many (1\u2013500, default 100)." }
|
|
31969
|
+
],
|
|
31970
|
+
querySchema: familyTreePeopleQuerySchema,
|
|
31971
|
+
status: 200,
|
|
31972
|
+
response: { description: "`{ people, total }`." },
|
|
31973
|
+
errors: { 404: true }
|
|
31974
|
+
},
|
|
31975
|
+
me: {
|
|
31976
|
+
method: "put",
|
|
31977
|
+
path: "/family-tree/me",
|
|
31978
|
+
scopes: ["people:family-tree"],
|
|
31979
|
+
tag: "People",
|
|
31980
|
+
summary: "This is me",
|
|
31981
|
+
description: "`ref`: the member in the tree. It becomes the root of the branch, and a living person is linked to the member's own Contact (the one that is them).",
|
|
31982
|
+
body: familyTreeMeInputSchema,
|
|
31983
|
+
status: 200,
|
|
31984
|
+
response: { description: "The tree." },
|
|
31985
|
+
errors: { 400: true, 404: true }
|
|
31986
|
+
},
|
|
31987
|
+
matches: {
|
|
31988
|
+
method: "get",
|
|
31989
|
+
path: "/family-tree/matches",
|
|
31990
|
+
scopes: ["people:family-tree"],
|
|
31991
|
+
tag: "People",
|
|
31992
|
+
summary: "What the tree noticed",
|
|
31993
|
+
description: "Each with the `id` a decision takes: `suggest` (a living relative who looks like an unlinked Contact), `birthday_differs` (a linked relative's birthday falls on another day than their Contact's), `not_in_tree` (a linked relative's partner or kid who isn't in the tree). What was said no to isn't listed.",
|
|
31994
|
+
status: 200,
|
|
31995
|
+
response: { description: "`{ matches }`." },
|
|
31996
|
+
errors: { 404: true }
|
|
31997
|
+
},
|
|
31998
|
+
decide: {
|
|
31999
|
+
method: "post",
|
|
32000
|
+
path: "/family-tree/matches",
|
|
32001
|
+
scopes: ["people:family-tree"],
|
|
32002
|
+
tag: "People",
|
|
32003
|
+
summary: "Yes or no to a match",
|
|
32004
|
+
description: "`{ id, decision: accept | reject }`. Yes links a suggested relative to the Contact, or takes the tree's birthday onto it; someone not in the tree has nothing to take, so only no (a 400). No hides the match for good. Returns `{ id, did, matches }` (`did`: linked \xB7 birthday_taken \xB7 dismissed).",
|
|
32005
|
+
body: familyTreeMatchDecisionInputSchema,
|
|
32006
|
+
status: 200,
|
|
32007
|
+
response: { description: "`{ id, did, matches }`." },
|
|
32008
|
+
errors: { 400: true, 404: true }
|
|
32009
|
+
}
|
|
32010
|
+
});
|
|
32011
|
+
|
|
31602
32012
|
// ../../packages/schema/src/operations/files.ts
|
|
31603
32013
|
var fileOperations = defineOperations({
|
|
31604
32014
|
list: {
|
|
@@ -32362,122 +32772,796 @@ var habitOperations = defineOperations({
|
|
|
32362
32772
|
response: { description: "The check-ins." },
|
|
32363
32773
|
errors: { 404: true }
|
|
32364
32774
|
},
|
|
32365
|
-
checkIn: {
|
|
32775
|
+
checkIn: {
|
|
32776
|
+
method: "post",
|
|
32777
|
+
path: "/habits/{id}/check-ins",
|
|
32778
|
+
scopes: ["habits:write"],
|
|
32779
|
+
tag: "Habits",
|
|
32780
|
+
summary: "Check in",
|
|
32781
|
+
description: "Record a check-in, with an optional short `note`; fires `habit.updated` with the refreshed streak. A habit counted from an ingest (`source` other than `manual`) answers 409.",
|
|
32782
|
+
body: createHabitEntryInputSchema,
|
|
32783
|
+
status: 201,
|
|
32784
|
+
response: { description: "The refreshed habit." },
|
|
32785
|
+
errors: {
|
|
32786
|
+
400: true,
|
|
32787
|
+
404: true
|
|
32788
|
+
},
|
|
32789
|
+
webhook: "habit.updated",
|
|
32790
|
+
operationId: "check_in_habit"
|
|
32791
|
+
},
|
|
32792
|
+
skip: {
|
|
32793
|
+
method: "post",
|
|
32794
|
+
path: "/habits/{id}/skip",
|
|
32795
|
+
scopes: ["habits:write"],
|
|
32796
|
+
tag: "Habits",
|
|
32797
|
+
summary: "Skip a habit",
|
|
32798
|
+
description: '"Skip gym today": a neutral rest day (a `skip` entry, value 0), never a miss. The streak treats the period as neutral and spends no grace. `date` (YYYY-MM-DD) defaults to today; an optional `note` says why ("Dentist"). Skipping a skipped day changes nothing but its note. Undo by deleting the skip entry like a check-in. Returns the refreshed habit; fires `habit.updated`.',
|
|
32799
|
+
body: habitSkipInputSchema,
|
|
32800
|
+
status: 201,
|
|
32801
|
+
response: { description: "The refreshed habit." },
|
|
32802
|
+
errors: {
|
|
32803
|
+
400: true,
|
|
32804
|
+
404: true
|
|
32805
|
+
},
|
|
32806
|
+
webhook: "habit.updated"
|
|
32807
|
+
},
|
|
32808
|
+
pause: {
|
|
32809
|
+
method: "post",
|
|
32810
|
+
path: "/habits/{id}/pause",
|
|
32811
|
+
scopes: ["habits:write"],
|
|
32812
|
+
tag: "Habits",
|
|
32813
|
+
summary: "Pause a habit",
|
|
32814
|
+
description: '"Pause gym till the 26th": the habit rests until `until` (the day it\'s back, after today): off Now, no push, streak and plant wait. Pausing a paused habit moves its end. Returns the refreshed habit with `pause`; fires `habit.updated`.',
|
|
32815
|
+
body: habitPauseInputSchema,
|
|
32816
|
+
status: 201,
|
|
32817
|
+
response: { description: "The refreshed habit." },
|
|
32818
|
+
errors: {
|
|
32819
|
+
400: true,
|
|
32820
|
+
404: true
|
|
32821
|
+
},
|
|
32822
|
+
webhook: "habit.updated"
|
|
32823
|
+
},
|
|
32824
|
+
resume: {
|
|
32825
|
+
method: "post",
|
|
32826
|
+
path: "/habits/{id}/resume",
|
|
32827
|
+
scopes: ["habits:write"],
|
|
32828
|
+
tag: "Habits",
|
|
32829
|
+
summary: "Resume a habit",
|
|
32830
|
+
description: "End a habit's pause: it's back today. The rest so far stays neutral. Returns the refreshed habit; fires `habit.updated`.",
|
|
32831
|
+
status: 201,
|
|
32832
|
+
response: { description: "The refreshed habit." },
|
|
32833
|
+
errors: { 404: true },
|
|
32834
|
+
webhook: "habit.updated"
|
|
32835
|
+
},
|
|
32836
|
+
retire: {
|
|
32837
|
+
method: "post",
|
|
32838
|
+
path: "/habits/{id}/retire",
|
|
32839
|
+
scopes: ["habits:write"],
|
|
32840
|
+
tag: "Habits",
|
|
32841
|
+
summary: "Retire a habit",
|
|
32842
|
+
description: '"I\'m done with the cold showers habit": the habit moves to the Grown shelf with its plant in bloom and keeps its history. It leaves Now and Today, sends no push, takes no check-in by title and is never due; Progress keeps its past. Returns the refreshed habit with `retiredAt`; undo with `/unretire`. Fires `habit.updated`.',
|
|
32843
|
+
status: 201,
|
|
32844
|
+
response: { description: "The refreshed habit." },
|
|
32845
|
+
errors: { 404: true },
|
|
32846
|
+
webhook: "habit.updated"
|
|
32847
|
+
},
|
|
32848
|
+
unretire: {
|
|
32849
|
+
method: "post",
|
|
32850
|
+
path: "/habits/{id}/unretire",
|
|
32851
|
+
scopes: ["habits:write"],
|
|
32852
|
+
tag: "Habits",
|
|
32853
|
+
summary: "Bring a habit back",
|
|
32854
|
+
description: "Bring a grown (retired) habit back: it's growing again from today, its history intact. Returns the refreshed habit; fires `habit.updated`.",
|
|
32855
|
+
status: 201,
|
|
32856
|
+
response: { description: "The refreshed habit." },
|
|
32857
|
+
errors: { 404: true },
|
|
32858
|
+
webhook: "habit.updated"
|
|
32859
|
+
},
|
|
32860
|
+
updateCheckIn: {
|
|
32861
|
+
method: "patch",
|
|
32862
|
+
path: "/habits/{id}/check-ins/{entryId}",
|
|
32863
|
+
pathParams: { entryId: "The check-in entry's ULID." },
|
|
32864
|
+
scopes: ["habits:write"],
|
|
32865
|
+
tag: "Habits",
|
|
32866
|
+
summary: "Note a check-in",
|
|
32867
|
+
description: "Edit a check-in afterwards: set, replace or clear (`null` or blank) its short `note` (at most 280 characters). The amount and time stay; undo a wrong check-in instead. Returns the check-in; fires `habit.updated`.",
|
|
32868
|
+
body: updateHabitEntryInputSchema,
|
|
32869
|
+
status: 200,
|
|
32870
|
+
response: { description: "The check-in, with its note." },
|
|
32871
|
+
errors: {
|
|
32872
|
+
400: true,
|
|
32873
|
+
404: true
|
|
32874
|
+
},
|
|
32875
|
+
webhook: "habit.updated",
|
|
32876
|
+
operationId: "note_habit_check_in"
|
|
32877
|
+
},
|
|
32878
|
+
removeCheckIn: {
|
|
32879
|
+
method: "delete",
|
|
32880
|
+
path: "/habits/{id}/check-ins/{entryId}",
|
|
32881
|
+
pathParams: { entryId: "The check-in entry's ULID." },
|
|
32882
|
+
scopes: ["habits:write"],
|
|
32883
|
+
tag: "Habits",
|
|
32884
|
+
summary: "Undo a check-in",
|
|
32885
|
+
description: "Delete a check-in; fires `habit.updated`.",
|
|
32886
|
+
status: 200,
|
|
32887
|
+
response: { description: "The refreshed habit." },
|
|
32888
|
+
errors: { 404: true },
|
|
32889
|
+
webhook: "habit.updated",
|
|
32890
|
+
operationId: "undo_habit_check_in"
|
|
32891
|
+
}
|
|
32892
|
+
});
|
|
32893
|
+
|
|
32894
|
+
// ../../packages/schema/src/operations/health.ts
|
|
32895
|
+
var healthOperations = defineOperations({
|
|
32896
|
+
export: {
|
|
32897
|
+
method: "get",
|
|
32898
|
+
path: "/health/export",
|
|
32899
|
+
scopes: ["health:export"],
|
|
32900
|
+
tag: "Health",
|
|
32901
|
+
summary: "Export every health record as FHIR",
|
|
32902
|
+
description: "Every health record the member holds, as one FHIR R4 `collection` Bundle: the member (Patient), allergies, Conditions and Episodes (Condition), symptom entries and lab values (Observation; a correction is `corrected`, what it replaced `entered-in-error`), visits (Encounter), medicines and doses (MedicationStatement, MedicationAdministration), lab draws (DiagnosticReport) and the original documents (DocumentReference, bytes inline as base64 unless `files=false`). Works with Health turned off. Logged in the member's Who looked.",
|
|
32903
|
+
query: [
|
|
32904
|
+
{ name: "files", description: "`false` leaves the documents' bytes out; default `true`." }
|
|
32905
|
+
],
|
|
32906
|
+
querySchema: healthExportQuerySchema,
|
|
32907
|
+
status: 200,
|
|
32908
|
+
response: { description: "The FHIR Bundle." },
|
|
32909
|
+
errors: { 400: true, 403: "Health is off for the member, or the key acts for no member." }
|
|
32910
|
+
},
|
|
32911
|
+
getConsent: {
|
|
32912
|
+
method: "get",
|
|
32913
|
+
path: "/health/consent",
|
|
32914
|
+
scopes: ["health:read"],
|
|
32915
|
+
tag: "Health",
|
|
32916
|
+
summary: "Get the health consent",
|
|
32917
|
+
description: "Whether the member has turned Health on: `{ granted, version, grantedAt, currentVersion, renewalNeeded, aiProvider }`. `granted` means on at today's consent text (`currentVersion`); `renewalNeeded` means the member agreed to an older text and is asked to agree again, so writes wait until they do. `aiProvider` is the AI provider this deployment names for what the agent reads (null when none). Only the member turns it on or off, in do; a key never can.",
|
|
32918
|
+
status: 200,
|
|
32919
|
+
response: { description: "The consent state." },
|
|
32920
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
32921
|
+
},
|
|
32922
|
+
getProfile: {
|
|
32923
|
+
method: "get",
|
|
32924
|
+
path: "/health/profile",
|
|
32925
|
+
scopes: ["health:read"],
|
|
32926
|
+
tag: "Health",
|
|
32927
|
+
summary: "Get the health profile",
|
|
32928
|
+
description: "The member's blood group, allergies, height, emergency contact and GP (Contacts); empty until set.",
|
|
32929
|
+
status: 200,
|
|
32930
|
+
response: { description: "The profile." },
|
|
32931
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
32932
|
+
},
|
|
32933
|
+
updateProfile: {
|
|
32934
|
+
method: "patch",
|
|
32935
|
+
path: "/health/profile",
|
|
32936
|
+
scopes: ["health:write"],
|
|
32937
|
+
tag: "Health",
|
|
32938
|
+
summary: "Update the health profile",
|
|
32939
|
+
description: "Set profile fields; an absent key keeps a field, `null` clears it.",
|
|
32940
|
+
body: updateHealthProfileInputSchema,
|
|
32941
|
+
status: 200,
|
|
32942
|
+
response: { description: "The profile." },
|
|
32943
|
+
errors: { 400: true, 403: "Health is off for the member, or the key acts for no member." }
|
|
32944
|
+
},
|
|
32945
|
+
log: {
|
|
32946
|
+
method: "post",
|
|
32947
|
+
path: "/health/log",
|
|
32948
|
+
scopes: ["health:write"],
|
|
32949
|
+
tag: "Health",
|
|
32950
|
+
summary: "Log a health message",
|
|
32951
|
+
description: "One chat turn about health in one call: name the Episode (`episodeId`) or describe it (`episode`: the member's open Episode in the same region or with the same title, active in the last 14 days, else a new one), then a `symptom`, a `dose` (a Medication by `medicationId`, or by name in `medication`, added as needed if new), or both. Returns a receipt: `{ episode, items[{ kind, id, line, guessed, undo }], entry, dose }`; each item's `undo` goes to `POST /api/v1/health/undo`. With `thread` (the member's home thread by slug, the Space's agent key with `agents:converse`), the receipt card is posted there too (\"Added to **Sprained ankle** (day 5).\" with what was logged, Undo and Edit) and `postId` names it.",
|
|
32952
|
+
body: logHealthInputSchema,
|
|
32953
|
+
status: 201,
|
|
32954
|
+
response: { description: "The receipt." },
|
|
32955
|
+
errors: {
|
|
32956
|
+
400: true,
|
|
32957
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
32958
|
+
404: true
|
|
32959
|
+
}
|
|
32960
|
+
},
|
|
32961
|
+
correct: {
|
|
32962
|
+
method: "post",
|
|
32963
|
+
path: "/health/correct",
|
|
32964
|
+
scopes: ["health:write"],
|
|
32965
|
+
tag: "Health",
|
|
32966
|
+
summary: "Correct a health message",
|
|
32967
|
+
description: "Correct a symptom entry by its id (`{ entryId, change }`): a new entry supersedes it, the history stays. Returns a receipt. 409 when the entry was corrected already.",
|
|
32968
|
+
body: correctHealthInputSchema,
|
|
32969
|
+
status: 201,
|
|
32970
|
+
response: { description: "The receipt." },
|
|
32971
|
+
errors: { 400: true, 404: true, 409: true }
|
|
32972
|
+
},
|
|
32973
|
+
undo: {
|
|
32974
|
+
method: "post",
|
|
32975
|
+
path: "/health/undo",
|
|
32976
|
+
scopes: ["health:write"],
|
|
32977
|
+
tag: "Health",
|
|
32978
|
+
summary: "Undo a health receipt",
|
|
32979
|
+
description: "Take back what a receipt wrote: `{ kind: entry | dose | episode, id }`. A POST, so it doesn't wait on a confirmation the way a delete does.",
|
|
32980
|
+
body: healthUndoInputSchema,
|
|
32981
|
+
status: 200,
|
|
32982
|
+
response: { description: "`{ undone }`." },
|
|
32983
|
+
errors: { 404: true, 409: true }
|
|
32984
|
+
},
|
|
32985
|
+
checkIn: {
|
|
32986
|
+
method: "post",
|
|
32987
|
+
path: "/health/episodes/{id}/check-in",
|
|
32988
|
+
scopes: ["health:write"],
|
|
32989
|
+
tag: "Health",
|
|
32990
|
+
summary: "Check in on an Episode",
|
|
32991
|
+
description: "Better / Same / Worse (`{ trend }`): today's trend against yesterday, as an entry in the member's words. One a day in the member's zone; a second one the same day corrects the first. Returns a receipt whose `undo` goes to `POST /api/v1/health/undo`.",
|
|
32992
|
+
body: healthCheckInInputSchema,
|
|
32993
|
+
status: 201,
|
|
32994
|
+
response: { description: "The receipt." },
|
|
32995
|
+
errors: {
|
|
32996
|
+
400: true,
|
|
32997
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
32998
|
+
404: true
|
|
32999
|
+
}
|
|
33000
|
+
},
|
|
33001
|
+
redFlags: {
|
|
33002
|
+
method: "post",
|
|
33003
|
+
path: "/health/episodes/{id}/red-flags",
|
|
33004
|
+
scopes: ["health:write"],
|
|
33005
|
+
tag: "Health",
|
|
33006
|
+
summary: "Record the red flags asked in chat",
|
|
33007
|
+
description: 'The red-flag screen answered in chat (`{ answers: { fever: false, vomiting: false }, thread? }`): the answers merge into the ones asked before and the Episode is marked checked today, so For the doctor shows it. With `thread` (the Space\'s agent key with `agents:converse`), a card confirms it there ("Noted as **checked: no red flags** (17 Oct).") with ways on to the summary and the Episode. Returns `{ episodeId, redFlags, checkedAt, postId }`.',
|
|
33008
|
+
body: healthRedFlagsInputSchema,
|
|
33009
|
+
status: 200,
|
|
33010
|
+
response: { description: "The answers, when, and the card's post." },
|
|
33011
|
+
errors: {
|
|
33012
|
+
400: true,
|
|
33013
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
33014
|
+
404: true
|
|
33015
|
+
}
|
|
33016
|
+
},
|
|
33017
|
+
upsertEpisode: {
|
|
33018
|
+
method: "post",
|
|
33019
|
+
path: "/health/episodes/upsert",
|
|
33020
|
+
scopes: ["health:write"],
|
|
33021
|
+
tag: "Health",
|
|
33022
|
+
summary: "Find or start a health episode",
|
|
33023
|
+
description: "The member's open Episode this belongs to (same subject, same region or title, active in the last 14 days), or a new one. Returns `{ episode, created }`.",
|
|
33024
|
+
body: upsertHealthEpisodeInputSchema,
|
|
33025
|
+
status: 200,
|
|
33026
|
+
response: { description: "`{ episode, created }`." },
|
|
33027
|
+
errors: { 400: true, 403: "Health is off for the member, or the key acts for no member." }
|
|
33028
|
+
},
|
|
33029
|
+
summary: {
|
|
33030
|
+
method: "get",
|
|
33031
|
+
path: "/health/summary",
|
|
33032
|
+
scopes: ["health:read"],
|
|
33033
|
+
tag: "Health",
|
|
33034
|
+
summary: "Get the doctor summary",
|
|
33035
|
+
description: "Everything the one-page doctor summary reads, for one Episode (`episodeId`, default the latest open one): the Episode and its course day by day, its entries, what was tried with what each did, the open Conditions, current Medications, the profile, the GP, the next visit with its questions, `labs` (the last 3 confirmed lab draws, each with its results, the lab's range and flag), and `trends` (sleep and weight from Metrics over the last 28 days, one point a day). The member's words, never a diagnosis.",
|
|
33036
|
+
query: [{ name: "episodeId", description: "The Episode; default the latest open one." }],
|
|
33037
|
+
querySchema: healthSummaryQuerySchema,
|
|
33038
|
+
status: 200,
|
|
33039
|
+
response: { description: "The summary." },
|
|
33040
|
+
errors: { 403: "Health is off for the member, or the key acts for no member.", 404: true }
|
|
33041
|
+
},
|
|
33042
|
+
medicalId: {
|
|
33043
|
+
method: "get",
|
|
33044
|
+
path: "/health/medical-id",
|
|
33045
|
+
scopes: ["health:read"],
|
|
33046
|
+
tag: "Health",
|
|
33047
|
+
summary: "Get the Medical ID",
|
|
33048
|
+
description: "The few facts someone helping in an emergency needs, like a phone's medical ID: the member's `name` (their display name), `bloodGroup`, `allergies`, `heightCm`, the `medications` they take now (not stopped, scheduled ones first) and the `emergencyContact` from the profile with their name and phone. A field not set is `null` (or empty). Each read by a key is appended to the member's access log.",
|
|
33049
|
+
status: 200,
|
|
33050
|
+
response: { description: "The Medical ID." },
|
|
33051
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33052
|
+
},
|
|
33053
|
+
listConditions: {
|
|
33054
|
+
method: "get",
|
|
33055
|
+
path: "/health/conditions",
|
|
33056
|
+
scopes: ["health:read"],
|
|
33057
|
+
tag: "Health",
|
|
33058
|
+
summary: "List health conditions",
|
|
33059
|
+
description: "The member's conditions. Something lasting (hay fever, runner's knee); `onset` is a fuzzy date. Reads and writes as the member who minted the key; another member's records read as missing.",
|
|
33060
|
+
status: 200,
|
|
33061
|
+
response: { description: "The member's conditions.", list: true },
|
|
33062
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33063
|
+
},
|
|
33064
|
+
getCondition: {
|
|
33065
|
+
method: "get",
|
|
33066
|
+
path: "/health/conditions/{id}",
|
|
33067
|
+
scopes: ["health:read"],
|
|
33068
|
+
tag: "Health",
|
|
33069
|
+
summary: "Get a health condition",
|
|
33070
|
+
description: "One condition.",
|
|
33071
|
+
status: 200,
|
|
33072
|
+
response: { description: "The condition." },
|
|
33073
|
+
errors: { 404: true }
|
|
33074
|
+
},
|
|
33075
|
+
createCondition: {
|
|
33076
|
+
method: "post",
|
|
33077
|
+
path: "/health/conditions",
|
|
33078
|
+
scopes: ["health:write"],
|
|
33079
|
+
tag: "Health",
|
|
33080
|
+
summary: "Create a health condition",
|
|
33081
|
+
description: "Add a condition, always private to the member (`subjectNodeId` names who it is about; absent = the member).",
|
|
33082
|
+
body: createHealthConditionInputSchema,
|
|
33083
|
+
status: 201,
|
|
33084
|
+
response: { description: "The condition." },
|
|
33085
|
+
errors: { 400: true, 403: "Health is off for the member, or the key acts for no member." }
|
|
33086
|
+
},
|
|
33087
|
+
updateCondition: {
|
|
33088
|
+
method: "patch",
|
|
33089
|
+
path: "/health/conditions/{id}",
|
|
33090
|
+
scopes: ["health:write"],
|
|
33091
|
+
tag: "Health",
|
|
33092
|
+
summary: "Update a health condition",
|
|
33093
|
+
description: "Patch a condition; `null` clears a field.",
|
|
33094
|
+
body: updateHealthConditionInputSchema,
|
|
33095
|
+
status: 200,
|
|
33096
|
+
response: { description: "The condition." },
|
|
33097
|
+
errors: {
|
|
33098
|
+
400: true,
|
|
33099
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
33100
|
+
404: true
|
|
33101
|
+
}
|
|
33102
|
+
},
|
|
33103
|
+
deleteCondition: {
|
|
33104
|
+
method: "delete",
|
|
33105
|
+
path: "/health/conditions/{id}",
|
|
33106
|
+
scopes: ["health:write"],
|
|
33107
|
+
tag: "Health",
|
|
33108
|
+
summary: "Delete a health condition",
|
|
33109
|
+
description: "Delete a condition. An Agent's delete waits on the member's confirmation (428).",
|
|
33110
|
+
status: 204,
|
|
33111
|
+
response: { description: "Deleted." },
|
|
33112
|
+
errors: { 403: "Health is off for the member, or the key acts for no member.", 404: true }
|
|
33113
|
+
},
|
|
33114
|
+
addCareTeam: {
|
|
33115
|
+
method: "post",
|
|
33116
|
+
path: "/health/conditions/{id}/care-team",
|
|
33117
|
+
scopes: ["health:write"],
|
|
33118
|
+
tag: "Health",
|
|
33119
|
+
summary: "Add to a health condition's care team",
|
|
33120
|
+
description: "Link a Contact to the Condition (`cared_by`, condition \u2192 contact) with their role on it in `label` (\"dermatologist\"). Adding one already on it sets the role. The Condition's `careTeam` lists them by name with their phone; the Health home's Care team card and For the doctor read them.",
|
|
33121
|
+
body: addHealthCareTeamInputSchema,
|
|
33122
|
+
status: 201,
|
|
33123
|
+
response: { description: "The Condition, with its care team." },
|
|
33124
|
+
errors: {
|
|
33125
|
+
400: true,
|
|
33126
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
33127
|
+
404: true
|
|
33128
|
+
}
|
|
33129
|
+
},
|
|
33130
|
+
removeCareTeam: {
|
|
33131
|
+
method: "delete",
|
|
33132
|
+
path: "/health/conditions/{id}/care-team/{contactId}",
|
|
33133
|
+
scopes: ["health:write"],
|
|
33134
|
+
tag: "Health",
|
|
33135
|
+
summary: "Remove from a health condition's care team",
|
|
33136
|
+
description: "Take the Contact off the Condition's care team (the Contact stays). 404 when they weren't on it.",
|
|
33137
|
+
pathParams: { contactId: "The Contact on the care team." },
|
|
33138
|
+
status: 200,
|
|
33139
|
+
response: { description: "The Condition, with its care team." },
|
|
33140
|
+
errors: { 403: "Health is off for the member, or the key acts for no member.", 404: true }
|
|
33141
|
+
},
|
|
33142
|
+
listEpisodes: {
|
|
33143
|
+
method: "get",
|
|
33144
|
+
path: "/health/episodes",
|
|
33145
|
+
scopes: ["health:read"],
|
|
33146
|
+
tag: "Health",
|
|
33147
|
+
summary: "List health episodes",
|
|
33148
|
+
description: "The member's episodes. One stretch of a complaint, open ones first, with the latest live severity. `GET \u2026/{id}` returns its entries (superseded ones too), doses, visits and Condition. Create one already over with `status: \"resolved\"` and `endedAt` (not before `startedAt`, not in the future; `endedAt` alone implies resolved). Resolving one stamps `endedAt`; `redFlags` answers merge. Reads and writes as the member who minted the key; another member's records read as missing.",
|
|
33149
|
+
query: [{ name: "status", description: "`open`, `watching` or `resolved`." }],
|
|
33150
|
+
querySchema: healthEpisodeListQuerySchema,
|
|
33151
|
+
status: 200,
|
|
33152
|
+
response: { description: "The member's episodes.", list: true },
|
|
33153
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33154
|
+
},
|
|
33155
|
+
getEpisode: {
|
|
33156
|
+
method: "get",
|
|
33157
|
+
path: "/health/episodes/{id}",
|
|
33158
|
+
scopes: ["health:read"],
|
|
33159
|
+
tag: "Health",
|
|
33160
|
+
summary: "Get a health episode",
|
|
33161
|
+
description: "One episode.",
|
|
33162
|
+
status: 200,
|
|
33163
|
+
response: { description: "The episode." },
|
|
33164
|
+
errors: { 404: true }
|
|
33165
|
+
},
|
|
33166
|
+
createEpisode: {
|
|
33167
|
+
method: "post",
|
|
33168
|
+
path: "/health/episodes",
|
|
33169
|
+
scopes: ["health:write"],
|
|
33170
|
+
tag: "Health",
|
|
33171
|
+
summary: "Create a health episode",
|
|
33172
|
+
description: "Add a episode, always private to the member (`subjectNodeId` names who it is about; absent = the member).",
|
|
33173
|
+
body: createHealthEpisodeInputSchema,
|
|
33174
|
+
status: 201,
|
|
33175
|
+
response: { description: "The episode." },
|
|
33176
|
+
errors: { 400: true, 403: "Health is off for the member, or the key acts for no member." }
|
|
33177
|
+
},
|
|
33178
|
+
updateEpisode: {
|
|
33179
|
+
method: "patch",
|
|
33180
|
+
path: "/health/episodes/{id}",
|
|
33181
|
+
scopes: ["health:write"],
|
|
33182
|
+
tag: "Health",
|
|
33183
|
+
summary: "Update a health episode",
|
|
33184
|
+
description: "Patch a episode; `null` clears a field.",
|
|
33185
|
+
body: updateHealthEpisodeInputSchema,
|
|
33186
|
+
status: 200,
|
|
33187
|
+
response: { description: "The episode." },
|
|
33188
|
+
errors: {
|
|
33189
|
+
400: true,
|
|
33190
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
33191
|
+
404: true
|
|
33192
|
+
}
|
|
33193
|
+
},
|
|
33194
|
+
deleteEpisode: {
|
|
33195
|
+
method: "delete",
|
|
33196
|
+
path: "/health/episodes/{id}",
|
|
33197
|
+
scopes: ["health:write"],
|
|
33198
|
+
tag: "Health",
|
|
33199
|
+
summary: "Delete a health episode",
|
|
33200
|
+
description: "Delete a episode. An Agent's delete waits on the member's confirmation (428).",
|
|
33201
|
+
status: 204,
|
|
33202
|
+
response: { description: "Deleted." },
|
|
33203
|
+
errors: { 403: "Health is off for the member, or the key acts for no member.", 404: true }
|
|
33204
|
+
},
|
|
33205
|
+
logSymptom: {
|
|
33206
|
+
method: "post",
|
|
33207
|
+
path: "/health/episodes/{id}/entries",
|
|
33208
|
+
scopes: ["health:write"],
|
|
33209
|
+
tag: "Health",
|
|
33210
|
+
summary: "Log a health symptom",
|
|
33211
|
+
description: "Add one thing said about an Episode (`symptom`, `bodyRegion`, `severity` 0\u201310, `severityGuessed` when it is a guess from the wording, `qualifiers`). An Agent's entry is `source: chat`.",
|
|
33212
|
+
body: logHealthSymptomInputSchema,
|
|
33213
|
+
status: 201,
|
|
33214
|
+
response: { description: "The entry." },
|
|
33215
|
+
errors: {
|
|
33216
|
+
400: true,
|
|
33217
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
33218
|
+
404: true
|
|
33219
|
+
}
|
|
33220
|
+
},
|
|
33221
|
+
correctSymptom: {
|
|
33222
|
+
method: "post",
|
|
33223
|
+
path: "/health/episodes/{id}/entries/{entryId}/correct",
|
|
33224
|
+
scopes: ["health:write"],
|
|
33225
|
+
tag: "Health",
|
|
33226
|
+
summary: "Correct a health symptom",
|
|
33227
|
+
description: 'Correct the live version of an entry ("not the foot, the ankle"): a new entry that supersedes it and copies every field not named, so the history stays. 409 when the entry was corrected already.',
|
|
33228
|
+
pathParams: { entryId: "The symptom entry's id." },
|
|
33229
|
+
body: correctHealthSymptomInputSchema,
|
|
33230
|
+
status: 201,
|
|
33231
|
+
response: { description: "The new entry." },
|
|
33232
|
+
errors: { 400: true, 404: true, 409: true }
|
|
33233
|
+
},
|
|
33234
|
+
deleteSymptom: {
|
|
33235
|
+
method: "delete",
|
|
33236
|
+
path: "/health/episodes/{id}/entries/{entryId}",
|
|
33237
|
+
scopes: ["health:write"],
|
|
33238
|
+
tag: "Health",
|
|
33239
|
+
summary: "Take back a health symptom",
|
|
33240
|
+
description: "Take back the live version of an entry; what it corrected is live again. 409 when it was corrected since.",
|
|
33241
|
+
pathParams: { entryId: "The symptom entry's id." },
|
|
33242
|
+
status: 204,
|
|
33243
|
+
response: { description: "Taken back." },
|
|
33244
|
+
errors: { 404: true, 409: true }
|
|
33245
|
+
},
|
|
33246
|
+
listEncounters: {
|
|
33247
|
+
method: "get",
|
|
33248
|
+
path: "/health/encounters",
|
|
33249
|
+
scopes: ["health:read"],
|
|
33250
|
+
tag: "Health",
|
|
33251
|
+
summary: "List health encounters",
|
|
33252
|
+
description: "The member's encounters. Visits, latest first, each with its doctor's name (a Contact), questions to ask and outcome. Reads and writes as the member who minted the key; another member's records read as missing.",
|
|
33253
|
+
status: 200,
|
|
33254
|
+
response: { description: "The member's encounters.", list: true },
|
|
33255
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33256
|
+
},
|
|
33257
|
+
getEncounter: {
|
|
33258
|
+
method: "get",
|
|
33259
|
+
path: "/health/encounters/{id}",
|
|
33260
|
+
scopes: ["health:read"],
|
|
33261
|
+
tag: "Health",
|
|
33262
|
+
summary: "Get a health encounter",
|
|
33263
|
+
description: "One encounter.",
|
|
33264
|
+
status: 200,
|
|
33265
|
+
response: { description: "The encounter." },
|
|
33266
|
+
errors: { 404: true }
|
|
33267
|
+
},
|
|
33268
|
+
createEncounter: {
|
|
32366
33269
|
method: "post",
|
|
32367
|
-
path: "/
|
|
32368
|
-
scopes: ["
|
|
32369
|
-
tag: "
|
|
32370
|
-
summary: "
|
|
32371
|
-
description: "
|
|
32372
|
-
body:
|
|
33270
|
+
path: "/health/encounters",
|
|
33271
|
+
scopes: ["health:write"],
|
|
33272
|
+
tag: "Health",
|
|
33273
|
+
summary: "Create a health encounter",
|
|
33274
|
+
description: "Add a encounter, always private to the member (`subjectNodeId` names who it is about; absent = the member).",
|
|
33275
|
+
body: createHealthEncounterInputSchema,
|
|
32373
33276
|
status: 201,
|
|
32374
|
-
response: { description: "The
|
|
33277
|
+
response: { description: "The encounter." },
|
|
33278
|
+
errors: { 400: true, 403: "Health is off for the member, or the key acts for no member." }
|
|
33279
|
+
},
|
|
33280
|
+
updateEncounter: {
|
|
33281
|
+
method: "patch",
|
|
33282
|
+
path: "/health/encounters/{id}",
|
|
33283
|
+
scopes: ["health:write"],
|
|
33284
|
+
tag: "Health",
|
|
33285
|
+
summary: "Update a health encounter",
|
|
33286
|
+
description: "Patch a encounter; `null` clears a field.",
|
|
33287
|
+
body: updateHealthEncounterInputSchema,
|
|
33288
|
+
status: 200,
|
|
33289
|
+
response: { description: "The encounter." },
|
|
32375
33290
|
errors: {
|
|
32376
33291
|
400: true,
|
|
33292
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
32377
33293
|
404: true
|
|
32378
|
-
}
|
|
32379
|
-
webhook: "habit.updated",
|
|
32380
|
-
operationId: "check_in_habit"
|
|
33294
|
+
}
|
|
32381
33295
|
},
|
|
32382
|
-
|
|
33296
|
+
deleteEncounter: {
|
|
33297
|
+
method: "delete",
|
|
33298
|
+
path: "/health/encounters/{id}",
|
|
33299
|
+
scopes: ["health:write"],
|
|
33300
|
+
tag: "Health",
|
|
33301
|
+
summary: "Delete a health encounter",
|
|
33302
|
+
description: "Delete a encounter. An Agent's delete waits on the member's confirmation (428).",
|
|
33303
|
+
status: 204,
|
|
33304
|
+
response: { description: "Deleted." },
|
|
33305
|
+
errors: { 403: "Health is off for the member, or the key acts for no member.", 404: true }
|
|
33306
|
+
},
|
|
33307
|
+
listMedications: {
|
|
33308
|
+
method: "get",
|
|
33309
|
+
path: "/health/medications",
|
|
33310
|
+
scopes: ["health:read"],
|
|
33311
|
+
tag: "Health",
|
|
33312
|
+
summary: "List health medications",
|
|
33313
|
+
description: "The member's medications. Drugs and supplements, stopped ones last, with when one was last taken. Reads and writes as the member who minted the key; another member's records read as missing.",
|
|
33314
|
+
status: 200,
|
|
33315
|
+
response: { description: "The member's medications.", list: true },
|
|
33316
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33317
|
+
},
|
|
33318
|
+
getMedication: {
|
|
33319
|
+
method: "get",
|
|
33320
|
+
path: "/health/medications/{id}",
|
|
33321
|
+
scopes: ["health:read"],
|
|
33322
|
+
tag: "Health",
|
|
33323
|
+
summary: "Get a health medication",
|
|
33324
|
+
description: "One medication.",
|
|
33325
|
+
status: 200,
|
|
33326
|
+
response: { description: "The medication." },
|
|
33327
|
+
errors: { 404: true }
|
|
33328
|
+
},
|
|
33329
|
+
createMedication: {
|
|
32383
33330
|
method: "post",
|
|
32384
|
-
path: "/
|
|
32385
|
-
scopes: ["
|
|
32386
|
-
tag: "
|
|
32387
|
-
summary: "
|
|
32388
|
-
description:
|
|
32389
|
-
body:
|
|
33331
|
+
path: "/health/medications",
|
|
33332
|
+
scopes: ["health:write"],
|
|
33333
|
+
tag: "Health",
|
|
33334
|
+
summary: "Create a health medication",
|
|
33335
|
+
description: "Add a medication, always private to the member (`subjectNodeId` names who it is about; absent = the member).",
|
|
33336
|
+
body: createHealthMedicationInputSchema,
|
|
32390
33337
|
status: 201,
|
|
32391
|
-
response: { description: "The
|
|
33338
|
+
response: { description: "The medication." },
|
|
33339
|
+
errors: { 400: true, 403: "Health is off for the member, or the key acts for no member." }
|
|
33340
|
+
},
|
|
33341
|
+
updateMedication: {
|
|
33342
|
+
method: "patch",
|
|
33343
|
+
path: "/health/medications/{id}",
|
|
33344
|
+
scopes: ["health:write"],
|
|
33345
|
+
tag: "Health",
|
|
33346
|
+
summary: "Update a health medication",
|
|
33347
|
+
description: "Patch a medication; `null` clears a field.",
|
|
33348
|
+
body: updateHealthMedicationInputSchema,
|
|
33349
|
+
status: 200,
|
|
33350
|
+
response: { description: "The medication." },
|
|
32392
33351
|
errors: {
|
|
32393
33352
|
400: true,
|
|
33353
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
32394
33354
|
404: true
|
|
32395
|
-
}
|
|
32396
|
-
webhook: "habit.updated"
|
|
33355
|
+
}
|
|
32397
33356
|
},
|
|
32398
|
-
|
|
33357
|
+
deleteMedication: {
|
|
33358
|
+
method: "delete",
|
|
33359
|
+
path: "/health/medications/{id}",
|
|
33360
|
+
scopes: ["health:write"],
|
|
33361
|
+
tag: "Health",
|
|
33362
|
+
summary: "Delete a health medication",
|
|
33363
|
+
description: "Delete a medication. An Agent's delete waits on the member's confirmation (428).",
|
|
33364
|
+
status: 204,
|
|
33365
|
+
response: { description: "Deleted." },
|
|
33366
|
+
errors: { 403: "Health is off for the member, or the key acts for no member.", 404: true }
|
|
33367
|
+
},
|
|
33368
|
+
listDoses: {
|
|
33369
|
+
method: "get",
|
|
33370
|
+
path: "/health/medications/{id}/doses",
|
|
33371
|
+
scopes: ["health:read"],
|
|
33372
|
+
tag: "Health",
|
|
33373
|
+
summary: "List health doses",
|
|
33374
|
+
description: "The doses of one Medication, latest first.",
|
|
33375
|
+
status: 200,
|
|
33376
|
+
response: { description: "The doses.", list: true },
|
|
33377
|
+
errors: { 404: true }
|
|
33378
|
+
},
|
|
33379
|
+
logDose: {
|
|
32399
33380
|
method: "post",
|
|
32400
|
-
path: "/
|
|
32401
|
-
scopes: ["
|
|
32402
|
-
tag: "
|
|
32403
|
-
summary: "
|
|
32404
|
-
description:
|
|
32405
|
-
body:
|
|
33381
|
+
path: "/health/medications/{id}/doses",
|
|
33382
|
+
scopes: ["health:write"],
|
|
33383
|
+
tag: "Health",
|
|
33384
|
+
summary: "Log a health dose",
|
|
33385
|
+
description: "Log a dose taken, optionally for an Episode, with what it did (`effect`: none, a_little, helped, worse).",
|
|
33386
|
+
body: logHealthDoseInputSchema,
|
|
32406
33387
|
status: 201,
|
|
32407
|
-
response: { description: "The
|
|
33388
|
+
response: { description: "The dose." },
|
|
32408
33389
|
errors: {
|
|
32409
33390
|
400: true,
|
|
33391
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
32410
33392
|
404: true
|
|
32411
|
-
}
|
|
32412
|
-
webhook: "habit.updated"
|
|
33393
|
+
}
|
|
32413
33394
|
},
|
|
32414
|
-
|
|
32415
|
-
method: "
|
|
32416
|
-
path: "/
|
|
32417
|
-
scopes: ["
|
|
32418
|
-
tag: "
|
|
32419
|
-
summary: "
|
|
32420
|
-
description: "
|
|
32421
|
-
|
|
32422
|
-
|
|
32423
|
-
|
|
32424
|
-
|
|
33395
|
+
updateDose: {
|
|
33396
|
+
method: "patch",
|
|
33397
|
+
path: "/health/medications/{id}/doses/{doseId}",
|
|
33398
|
+
scopes: ["health:write"],
|
|
33399
|
+
tag: "Health",
|
|
33400
|
+
summary: "Update a health dose",
|
|
33401
|
+
description: "Say later what a dose did, or fix it.",
|
|
33402
|
+
pathParams: { doseId: "The dose's id." },
|
|
33403
|
+
body: updateHealthDoseInputSchema,
|
|
33404
|
+
status: 200,
|
|
33405
|
+
response: { description: "The dose." },
|
|
33406
|
+
errors: { 400: true, 404: true }
|
|
32425
33407
|
},
|
|
32426
|
-
|
|
32427
|
-
method: "
|
|
32428
|
-
path: "/
|
|
32429
|
-
scopes: ["
|
|
32430
|
-
tag: "
|
|
32431
|
-
summary: "
|
|
32432
|
-
description:
|
|
32433
|
-
|
|
32434
|
-
|
|
32435
|
-
|
|
32436
|
-
|
|
33408
|
+
deleteDose: {
|
|
33409
|
+
method: "delete",
|
|
33410
|
+
path: "/health/medications/{id}/doses/{doseId}",
|
|
33411
|
+
scopes: ["health:write"],
|
|
33412
|
+
tag: "Health",
|
|
33413
|
+
summary: "Take back a health dose",
|
|
33414
|
+
description: "Take a dose back.",
|
|
33415
|
+
pathParams: { doseId: "The dose's id." },
|
|
33416
|
+
status: 204,
|
|
33417
|
+
response: { description: "Taken back." },
|
|
33418
|
+
errors: { 404: true }
|
|
32437
33419
|
},
|
|
32438
|
-
|
|
33420
|
+
listShares: {
|
|
33421
|
+
method: "get",
|
|
33422
|
+
path: "/health/shares",
|
|
33423
|
+
scopes: ["health:read"],
|
|
33424
|
+
tag: "Health",
|
|
33425
|
+
summary: "List doctor summary shares",
|
|
33426
|
+
description: "The member's \"For the doctor\" links, newest first: the sections each froze, when it expires or was taken back, how often it was opened, and `live`. Never the link's secret or the snapshot. Only the member makes one, in do.",
|
|
33427
|
+
status: 200,
|
|
33428
|
+
response: { description: "The shares." },
|
|
33429
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33430
|
+
},
|
|
33431
|
+
revokeShare: {
|
|
33432
|
+
method: "delete",
|
|
33433
|
+
path: "/health/shares/{id}",
|
|
33434
|
+
scopes: ["health:write"],
|
|
33435
|
+
tag: "Health",
|
|
33436
|
+
summary: "Take a doctor summary share back",
|
|
33437
|
+
description: "The link stops opening (410). Idempotent.",
|
|
33438
|
+
pathParams: { id: "The share's id." },
|
|
33439
|
+
status: 200,
|
|
33440
|
+
response: { description: "The share." },
|
|
33441
|
+
errors: { 403: "Health is off for the member, or the key acts for no member.", 404: true }
|
|
33442
|
+
},
|
|
33443
|
+
listLabPanels: {
|
|
33444
|
+
method: "get",
|
|
33445
|
+
path: "/health/labs",
|
|
33446
|
+
scopes: ["health:read"],
|
|
33447
|
+
tag: "Health",
|
|
33448
|
+
summary: "List health lab draws",
|
|
33449
|
+
description: "The member's lab draws. Lab draws, latest first, each with its sheet of results (FHIR Observation-shaped: an `analyte` key, `loinc`, a UCUM `unit`, the lab's `refLow`/`refHigh`; `flag` is worked out from the range when absent). A draw read out of a document stays `status: draft` until the member checks it. On update, `results` replaces the whole sheet. Reads and writes as the member who minted the key; another member's records read as missing.",
|
|
33450
|
+
status: 200,
|
|
33451
|
+
response: { description: "The member's lab draws.", list: true },
|
|
33452
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33453
|
+
},
|
|
33454
|
+
listLabAnalytes: {
|
|
33455
|
+
method: "get",
|
|
33456
|
+
path: "/health/labs/analytes",
|
|
33457
|
+
scopes: ["health:read"],
|
|
33458
|
+
tag: "Health",
|
|
33459
|
+
summary: "List the canonical lab analytes",
|
|
33460
|
+
description: 'The fixed analyte vocabulary: `key`, the printed `name`, `group`, the usual `unit`, `loinc` where plain, and `aliases` (English and Dutch; matched regardless of case, spaces, punctuation and accents). A lab result is written under the canonical key its `analyte` or `name` stands for ("ALAT" \u2192 `alt`, "25-OH vitamin D" \u2192 `vitamin_d`); a name that matches none keeps its own slug and comes back in the draw\'s `unmatched`. Trends read old keys as their canonical one.',
|
|
33461
|
+
status: 200,
|
|
33462
|
+
response: { description: "The analytes." },
|
|
33463
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33464
|
+
},
|
|
33465
|
+
labNormalizeReport: {
|
|
33466
|
+
method: "get",
|
|
33467
|
+
path: "/health/labs/normalize",
|
|
33468
|
+
scopes: ["health:read"],
|
|
33469
|
+
tag: "Health",
|
|
33470
|
+
summary: "Report how lab keys would normalize",
|
|
33471
|
+
description: "A dry run: each stored result whose key isn't its canonical one (`changes`: `resultId`, `from`, `to`), and the keys matching no canonical analyte (`unmatched`, with how many results). Nothing is rewritten.",
|
|
33472
|
+
status: 200,
|
|
33473
|
+
response: { description: "The report." },
|
|
33474
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33475
|
+
},
|
|
33476
|
+
getLabPanel: {
|
|
33477
|
+
method: "get",
|
|
33478
|
+
path: "/health/labs/{id}",
|
|
33479
|
+
scopes: ["health:read"],
|
|
33480
|
+
tag: "Health",
|
|
33481
|
+
summary: "Get a health lab draw",
|
|
33482
|
+
description: "One lab draw.",
|
|
33483
|
+
status: 200,
|
|
33484
|
+
response: { description: "The lab draw." },
|
|
33485
|
+
errors: { 404: true }
|
|
33486
|
+
},
|
|
33487
|
+
createLabPanel: {
|
|
32439
33488
|
method: "post",
|
|
32440
|
-
path: "/
|
|
32441
|
-
scopes: ["
|
|
32442
|
-
tag: "
|
|
32443
|
-
summary: "
|
|
32444
|
-
description: "
|
|
33489
|
+
path: "/health/labs",
|
|
33490
|
+
scopes: ["health:write"],
|
|
33491
|
+
tag: "Health",
|
|
33492
|
+
summary: "Create a health lab draw",
|
|
33493
|
+
description: "Add a lab draw, always private to the member (`subjectNodeId` names who it is about; absent = the member).",
|
|
33494
|
+
body: createHealthLabPanelInputSchema,
|
|
32445
33495
|
status: 201,
|
|
32446
|
-
response: { description: "The
|
|
32447
|
-
errors: {
|
|
32448
|
-
webhook: "habit.updated"
|
|
33496
|
+
response: { description: "The lab draw." },
|
|
33497
|
+
errors: { 400: true, 403: "Health is off for the member, or the key acts for no member." }
|
|
32449
33498
|
},
|
|
32450
|
-
|
|
33499
|
+
updateLabPanel: {
|
|
32451
33500
|
method: "patch",
|
|
32452
|
-
path: "/
|
|
32453
|
-
|
|
32454
|
-
|
|
32455
|
-
|
|
32456
|
-
|
|
32457
|
-
|
|
32458
|
-
body: updateHabitEntryInputSchema,
|
|
33501
|
+
path: "/health/labs/{id}",
|
|
33502
|
+
scopes: ["health:write"],
|
|
33503
|
+
tag: "Health",
|
|
33504
|
+
summary: "Update a health lab draw",
|
|
33505
|
+
description: "Patch a lab draw; `null` clears a field.",
|
|
33506
|
+
body: updateHealthLabPanelInputSchema,
|
|
32459
33507
|
status: 200,
|
|
32460
|
-
response: { description: "The
|
|
33508
|
+
response: { description: "The lab draw." },
|
|
32461
33509
|
errors: {
|
|
32462
33510
|
400: true,
|
|
33511
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
32463
33512
|
404: true
|
|
32464
|
-
}
|
|
32465
|
-
webhook: "habit.updated",
|
|
32466
|
-
operationId: "note_habit_check_in"
|
|
33513
|
+
}
|
|
32467
33514
|
},
|
|
32468
|
-
|
|
33515
|
+
deleteLabPanel: {
|
|
32469
33516
|
method: "delete",
|
|
32470
|
-
path: "/
|
|
32471
|
-
|
|
32472
|
-
|
|
32473
|
-
|
|
32474
|
-
|
|
32475
|
-
|
|
33517
|
+
path: "/health/labs/{id}",
|
|
33518
|
+
scopes: ["health:write"],
|
|
33519
|
+
tag: "Health",
|
|
33520
|
+
summary: "Delete a health lab draw",
|
|
33521
|
+
description: "Delete a lab draw. An Agent's delete waits on the member's confirmation (428).",
|
|
33522
|
+
status: 204,
|
|
33523
|
+
response: { description: "Deleted." },
|
|
33524
|
+
errors: { 403: "Health is off for the member, or the key acts for no member.", 404: true }
|
|
33525
|
+
},
|
|
33526
|
+
labOverview: {
|
|
33527
|
+
method: "get",
|
|
33528
|
+
path: "/health/analytes",
|
|
33529
|
+
scopes: ["health:read"],
|
|
33530
|
+
tag: "Health",
|
|
33531
|
+
summary: "List lab analytes",
|
|
33532
|
+
description: "Every analyte the member's draws measured, each with its trend (oldest point first), the personal target band and the supplement taken for it; plus `draws`, `firstAt`, `lastAt`, `lastLab`.",
|
|
32476
33533
|
status: 200,
|
|
32477
|
-
response: { description: "The
|
|
32478
|
-
errors: {
|
|
32479
|
-
|
|
32480
|
-
|
|
33534
|
+
response: { description: "The lab overview." },
|
|
33535
|
+
errors: { 403: "Health is off for the member, or the key acts for no member." }
|
|
33536
|
+
},
|
|
33537
|
+
getLabAnalyte: {
|
|
33538
|
+
method: "get",
|
|
33539
|
+
path: "/health/analytes/{analyte}",
|
|
33540
|
+
scopes: ["health:read"],
|
|
33541
|
+
tag: "Health",
|
|
33542
|
+
summary: "Get a lab analyte",
|
|
33543
|
+
description: "One analyte's trend across draws. 404 when no draw measured it.",
|
|
33544
|
+
pathParams: { analyte: "The analyte key (`vitamin_d`)." },
|
|
33545
|
+
status: 200,
|
|
33546
|
+
response: { description: "The analyte." },
|
|
33547
|
+
errors: { 404: true }
|
|
33548
|
+
},
|
|
33549
|
+
setLabAnalyte: {
|
|
33550
|
+
method: "put",
|
|
33551
|
+
path: "/health/analytes/{analyte}",
|
|
33552
|
+
scopes: ["health:write"],
|
|
33553
|
+
tag: "Health",
|
|
33554
|
+
summary: "Set a lab analyte",
|
|
33555
|
+
description: "Keep a personal target band (`targetLow`/`targetHigh`, who set it in `targetByContactId`) or the Medication taken for it. An absent key keeps a field; `null` clears it.",
|
|
33556
|
+
pathParams: { analyte: "The analyte key (`vitamin_d`)." },
|
|
33557
|
+
body: setHealthLabAnalyteInputSchema,
|
|
33558
|
+
status: 200,
|
|
33559
|
+
response: { description: "The analyte." },
|
|
33560
|
+
errors: {
|
|
33561
|
+
400: true,
|
|
33562
|
+
403: "Health is off for the member, or the key acts for no member.",
|
|
33563
|
+
404: true
|
|
33564
|
+
}
|
|
32481
33565
|
}
|
|
32482
33566
|
});
|
|
32483
33567
|
|
|
@@ -36671,7 +37755,7 @@ function parseCapture2(input, now) {
|
|
|
36671
37755
|
|
|
36672
37756
|
// src/meta.ts
|
|
36673
37757
|
var CLI_NAME = "do";
|
|
36674
|
-
var VERSION = "1.
|
|
37758
|
+
var VERSION = "1.316.0";
|
|
36675
37759
|
var API_PREFIX = "/api/v1";
|
|
36676
37760
|
var DEFAULT_API_URL = "http://localhost:3001";
|
|
36677
37761
|
|
|
@@ -38150,7 +39234,7 @@ var CONNECTION_COMMAND_SPECS = [
|
|
|
38150
39234
|
],
|
|
38151
39235
|
scopes: ["connections:write"],
|
|
38152
39236
|
returns: "DoccleStatus",
|
|
38153
|
-
notes:
|
|
39237
|
+
notes: `${routeOf(documentOperations.doccleConnect)}, as \`do documents doccle connect\`. The password is read from the file's first line, never a flag. 422 when Doccle refuses the login or asks for a captcha (nothing is kept).`
|
|
38154
39238
|
},
|
|
38155
39239
|
{
|
|
38156
39240
|
path: ["steam", "link"],
|
|
@@ -38300,7 +39384,7 @@ async function connectDoccle({
|
|
|
38300
39384
|
}
|
|
38301
39385
|
const secret = password;
|
|
38302
39386
|
return {
|
|
38303
|
-
data: await guarded([secret], () => requireClient().put(
|
|
39387
|
+
data: await guarded([secret], () => requireClient().put(pathOf(documentOperations.doccleConnect), { username, password: secret })),
|
|
38304
39388
|
render: renderRecord
|
|
38305
39389
|
};
|
|
38306
39390
|
}
|
|
@@ -38898,12 +39982,9 @@ var ENTITIES = [
|
|
|
38898
39982
|
createInput: "CreateKeyDateInput",
|
|
38899
39983
|
updateInput: "UpdateKeyDateInput"
|
|
38900
39984
|
}),
|
|
38901
|
-
{
|
|
39985
|
+
entityFromOperations(documentOperations, {
|
|
38902
39986
|
name: "documents",
|
|
38903
|
-
path: "/documents",
|
|
38904
|
-
readScopes: ["documents:read"],
|
|
38905
39987
|
returns: "DocumentView",
|
|
38906
|
-
canGet: true,
|
|
38907
39988
|
listFlags: [
|
|
38908
39989
|
{
|
|
38909
39990
|
name: "kind",
|
|
@@ -38921,15 +40002,9 @@ var ENTITIES = [
|
|
|
38921
40002
|
query: "providerId"
|
|
38922
40003
|
}
|
|
38923
40004
|
],
|
|
38924
|
-
|
|
38925
|
-
|
|
38926
|
-
|
|
38927
|
-
createInput: "CreateDocumentInput",
|
|
38928
|
-
updateSchema: updateDocumentInputSchema,
|
|
38929
|
-
updateInput: "UpdateDocumentInput",
|
|
38930
|
-
canDelete: true
|
|
38931
|
-
}
|
|
38932
|
-
},
|
|
40005
|
+
createInput: "CreateDocumentInput",
|
|
40006
|
+
updateInput: "UpdateDocumentInput"
|
|
40007
|
+
}),
|
|
38933
40008
|
entityFromOperations(incidentOperations, {
|
|
38934
40009
|
name: "incidents",
|
|
38935
40010
|
returns: "IncidentView",
|
|
@@ -39546,12 +40621,42 @@ var HEALTH_COMMAND_SPECS = [
|
|
|
39546
40621
|
notes: "Body: SetHealthLabAnalyteInput. An absent key keeps a field; null clears it."
|
|
39547
40622
|
}
|
|
39548
40623
|
];
|
|
39549
|
-
var
|
|
39550
|
-
condition:
|
|
39551
|
-
|
|
39552
|
-
|
|
39553
|
-
|
|
39554
|
-
|
|
40624
|
+
var HEALTH_RECORD_OPERATIONS = {
|
|
40625
|
+
condition: {
|
|
40626
|
+
list: healthOperations.listConditions,
|
|
40627
|
+
get: healthOperations.getCondition,
|
|
40628
|
+
create: healthOperations.createCondition,
|
|
40629
|
+
update: healthOperations.updateCondition,
|
|
40630
|
+
remove: healthOperations.deleteCondition
|
|
40631
|
+
},
|
|
40632
|
+
episode: {
|
|
40633
|
+
list: healthOperations.listEpisodes,
|
|
40634
|
+
get: healthOperations.getEpisode,
|
|
40635
|
+
create: healthOperations.createEpisode,
|
|
40636
|
+
update: healthOperations.updateEpisode,
|
|
40637
|
+
remove: healthOperations.deleteEpisode
|
|
40638
|
+
},
|
|
40639
|
+
visit: {
|
|
40640
|
+
list: healthOperations.listEncounters,
|
|
40641
|
+
get: healthOperations.getEncounter,
|
|
40642
|
+
create: healthOperations.createEncounter,
|
|
40643
|
+
update: healthOperations.updateEncounter,
|
|
40644
|
+
remove: healthOperations.deleteEncounter
|
|
40645
|
+
},
|
|
40646
|
+
med: {
|
|
40647
|
+
list: healthOperations.listMedications,
|
|
40648
|
+
get: healthOperations.getMedication,
|
|
40649
|
+
create: healthOperations.createMedication,
|
|
40650
|
+
update: healthOperations.updateMedication,
|
|
40651
|
+
remove: healthOperations.deleteMedication
|
|
40652
|
+
},
|
|
40653
|
+
lab: {
|
|
40654
|
+
list: healthOperations.listLabPanels,
|
|
40655
|
+
get: healthOperations.getLabPanel,
|
|
40656
|
+
create: healthOperations.createLabPanel,
|
|
40657
|
+
update: healthOperations.updateLabPanel,
|
|
40658
|
+
remove: healthOperations.deleteLabPanel
|
|
40659
|
+
}
|
|
39555
40660
|
};
|
|
39556
40661
|
|
|
39557
40662
|
// src/journal-import.ts
|
|
@@ -40975,27 +42080,27 @@ var COMMAND_SPECS = [
|
|
|
40975
42080
|
flags: [
|
|
40976
42081
|
{ name: "source", type: "string", description: "gmail:<id> or doccle_zip (required)." }
|
|
40977
42082
|
],
|
|
40978
|
-
scopes: [
|
|
42083
|
+
scopes: [...documentOperations.filed.scopes],
|
|
40979
42084
|
returns: "DocumentFiled",
|
|
40980
|
-
notes:
|
|
42085
|
+
notes: `${routeOf(documentOperations.filed)}?source=. Off (403) until DOCUMENTS_IMPORT_ENABLED=true.`
|
|
40981
42086
|
},
|
|
40982
42087
|
{
|
|
40983
42088
|
path: ["documents", "doccle", "status"],
|
|
40984
42089
|
summary: "Your Doccle import: whether it's connected, archive after import, how the last run went and why it's stuck, if it is.",
|
|
40985
42090
|
args: [],
|
|
40986
42091
|
flags: [],
|
|
40987
|
-
scopes: [
|
|
42092
|
+
scopes: [...documentOperations.doccleStatus.scopes],
|
|
40988
42093
|
returns: "DoccleStatus",
|
|
40989
|
-
notes:
|
|
42094
|
+
notes: `${routeOf(documentOperations.doccleStatus)}. The import files your Doccle mailbox into Papers every night (03:30 Brussels). \`failure\` says why it stopped (credentials, captcha, changed, unavailable) and what to do. Never shows the login.`
|
|
40990
42095
|
},
|
|
40991
42096
|
{
|
|
40992
42097
|
path: ["documents", "doccle", "sync"],
|
|
40993
42098
|
summary: "Run your Doccle import now: each new Doccle document becomes a paper (sender, date, PDF), nothing twice.",
|
|
40994
42099
|
args: [],
|
|
40995
42100
|
flags: [],
|
|
40996
|
-
scopes: [
|
|
42101
|
+
scopes: [...documentOperations.doccleSync.scopes],
|
|
40997
42102
|
returns: "DoccleSyncResult",
|
|
40998
|
-
notes:
|
|
42103
|
+
notes: `${routeOf(documentOperations.doccleSync)}. Deduped on Doccle's id and on the PDF's hash (so papers from a Doccle ZIP export aren't filed again). outcome: ok, failed (see failure), not_connected, off (DOCUMENTS_IMPORT_ENABLED isn't on), busy (a run is going).`
|
|
40999
42104
|
},
|
|
41000
42105
|
{
|
|
41001
42106
|
path: ["documents", "doccle", "connect"],
|
|
@@ -41014,9 +42119,9 @@ var COMMAND_SPECS = [
|
|
|
41014
42119
|
description: "Read the password from the first line of stdin (else DO_DOCCLE_PASSWORD)."
|
|
41015
42120
|
}
|
|
41016
42121
|
],
|
|
41017
|
-
scopes: [
|
|
42122
|
+
scopes: [...documentOperations.doccleConnect.scopes],
|
|
41018
42123
|
returns: "DoccleStatus",
|
|
41019
|
-
notes:
|
|
42124
|
+
notes: `${routeOf(documentOperations.doccleConnect)}. Needs a key with the opt-in connections:write (held by name: Full access never grants it, and a guest's key never holds it). The password is never a flag (shell history): pass --password-file <path>, pipe it in with --password-stdin, or set DO_DOCCLE_PASSWORD. 422 when Doccle refuses the login or asks for a captcha (nothing is kept), 503 when Doccle is down. The login is never returned.`
|
|
41020
42125
|
},
|
|
41021
42126
|
{
|
|
41022
42127
|
path: ["documents", "doccle", "disconnect"],
|
|
@@ -41025,9 +42130,9 @@ var COMMAND_SPECS = [
|
|
|
41025
42130
|
flags: [
|
|
41026
42131
|
{ name: "allow-destructive", type: "boolean", description: "Required to forget the login." }
|
|
41027
42132
|
],
|
|
41028
|
-
scopes: [
|
|
42133
|
+
scopes: [...documentOperations.doccleDisconnect.scopes],
|
|
41029
42134
|
returns: "DoccleStatus",
|
|
41030
|
-
notes:
|
|
42135
|
+
notes: `${routeOf(documentOperations.doccleDisconnect)}. Gated behind --allow-destructive.`
|
|
41031
42136
|
},
|
|
41032
42137
|
{
|
|
41033
42138
|
path: ["documents", "doccle", "set"],
|
|
@@ -41040,9 +42145,9 @@ var COMMAND_SPECS = [
|
|
|
41040
42145
|
description: "on or off (off by default): archive in Doccle after import."
|
|
41041
42146
|
}
|
|
41042
42147
|
],
|
|
41043
|
-
scopes: [
|
|
42148
|
+
scopes: [...documentOperations.doccleSettings.scopes],
|
|
41044
42149
|
returns: "DoccleStatus",
|
|
41045
|
-
notes:
|
|
42150
|
+
notes: `${routeOf(documentOperations.doccleSettings)} with { archiveAfterImport }.`
|
|
41046
42151
|
},
|
|
41047
42152
|
{
|
|
41048
42153
|
path: ["documents", "ask"],
|
|
@@ -41062,9 +42167,9 @@ var COMMAND_SPECS = [
|
|
|
41062
42167
|
description: "How many passages at most (default 5, up to 20)."
|
|
41063
42168
|
}
|
|
41064
42169
|
],
|
|
41065
|
-
scopes: [
|
|
42170
|
+
scopes: [...documentOperations.ask.scopes],
|
|
41066
42171
|
returns: "DocumentAnswer",
|
|
41067
|
-
notes:
|
|
42172
|
+
notes: `${routeOf(documentOperations.ask)} with { question, documentId?, limit? }. Reads the papers' key fields and their files' text (a page per form feed). do writes no prose: word the answer from the passages, quote the pages, and say it is not legal advice. \`withoutText\` names the papers with no file text to read. An Only me paper answers only its owner's key with documents:private.`
|
|
41068
42173
|
},
|
|
41069
42174
|
{
|
|
41070
42175
|
path: ["documents", "search"],
|
|
@@ -41078,36 +42183,36 @@ var COMMAND_SPECS = [
|
|
|
41078
42183
|
description: "How many hits at most (default 20, up to 50)."
|
|
41079
42184
|
}
|
|
41080
42185
|
],
|
|
41081
|
-
scopes: [
|
|
42186
|
+
scopes: [...documentOperations.search.scopes],
|
|
41082
42187
|
returns: "{ q, hits: DocumentPassage[] }",
|
|
41083
|
-
notes:
|
|
42188
|
+
notes: `${routeOf(documentOperations.search)}?q=&documentId=&limit=.`
|
|
41084
42189
|
},
|
|
41085
42190
|
{
|
|
41086
42191
|
path: ["documents", "unmatched"],
|
|
41087
42192
|
summary: "List the papers that ask for money (an amount due) and have no payment linked yet, oldest due first.",
|
|
41088
42193
|
args: [],
|
|
41089
42194
|
flags: [],
|
|
41090
|
-
scopes: [
|
|
42195
|
+
scopes: [...documentOperations.unmatched.scopes],
|
|
41091
42196
|
returns: "UnmatchedPaper",
|
|
41092
|
-
notes:
|
|
42197
|
+
notes: `${routeOf(documentOperations.unmatched)}. \`candidates\` counts the payments that fit equally well (pick one with \`do documents link-payment\`). A payment on an account you can't see doesn't count.`
|
|
41093
42198
|
},
|
|
41094
42199
|
{
|
|
41095
42200
|
path: ["documents", "match"],
|
|
41096
42201
|
summary: "Match a paper (or, without an id, every paper still waiting) to the payment that paid it.",
|
|
41097
42202
|
args: [{ name: "id", required: false, description: "The paper; left out, all of them." }],
|
|
41098
42203
|
flags: [],
|
|
41099
|
-
scopes: [
|
|
42204
|
+
scopes: [...documentOperations.matchOne.scopes],
|
|
41100
42205
|
returns: "PaperMatchResult",
|
|
41101
|
-
notes:
|
|
42206
|
+
notes: `${routeOf(documentOperations.matchOne)} or ${PUBLIC_API_PREFIX}${documentOperations.matchAll.path}. A payment is money out of exactly the amount due, within the paper's window, with its structured reference or to its IBAN. Status: matched, already, ambiguous, none or not_payable.`
|
|
41102
42207
|
},
|
|
41103
42208
|
{
|
|
41104
42209
|
path: ["documents", "payments"],
|
|
41105
42210
|
summary: "Show the payments linked to a paper.",
|
|
41106
42211
|
args: [{ name: "id", required: true, description: "The paper (document id)." }],
|
|
41107
42212
|
flags: [],
|
|
41108
|
-
scopes: [
|
|
42213
|
+
scopes: [...documentOperations.payments.scopes],
|
|
41109
42214
|
returns: "DocumentPayment",
|
|
41110
|
-
notes:
|
|
42215
|
+
notes: `${routeOf(documentOperations.payments)}.`
|
|
41111
42216
|
},
|
|
41112
42217
|
{
|
|
41113
42218
|
path: ["documents", "link-payment"],
|
|
@@ -41117,9 +42222,9 @@ var COMMAND_SPECS = [
|
|
|
41117
42222
|
{ name: "transactionId", required: true, description: "The Money transaction." }
|
|
41118
42223
|
],
|
|
41119
42224
|
flags: [],
|
|
41120
|
-
scopes: [
|
|
42225
|
+
scopes: [...documentOperations.linkPayment.scopes],
|
|
41121
42226
|
returns: "DocumentPayment",
|
|
41122
|
-
notes:
|
|
42227
|
+
notes: `${routeOf(documentOperations.linkPayment)} with { transactionId }.`
|
|
41123
42228
|
},
|
|
41124
42229
|
{
|
|
41125
42230
|
path: ["documents", "unlink-payment"],
|
|
@@ -41129,9 +42234,9 @@ var COMMAND_SPECS = [
|
|
|
41129
42234
|
{ name: "transactionId", required: true, description: "The Money transaction." }
|
|
41130
42235
|
],
|
|
41131
42236
|
flags: [],
|
|
41132
|
-
scopes: [
|
|
42237
|
+
scopes: [...documentOperations.unlinkPayment.scopes],
|
|
41133
42238
|
returns: "{ ok, unlinked }",
|
|
41134
|
-
notes:
|
|
42239
|
+
notes: `${routeOf(documentOperations.unlinkPayment)}.`
|
|
41135
42240
|
},
|
|
41136
42241
|
{
|
|
41137
42242
|
path: ["incidents", "open"],
|
|
@@ -43874,7 +44979,7 @@ var COMMAND_SPECS = [
|
|
|
43874
44979
|
description: "Which grandparents to climb to: father or mother."
|
|
43875
44980
|
}
|
|
43876
44981
|
],
|
|
43877
|
-
scopes: [
|
|
44982
|
+
scopes: [...familyTreeOperations.get.scopes],
|
|
43878
44983
|
returns: "FamilyTreeResponse",
|
|
43879
44984
|
notes: "people:family-tree is sensitive: never part of a full-access key, opened in Settings for one key, and only your own tree. { tree: null } before an import."
|
|
43880
44985
|
},
|
|
@@ -43898,7 +45003,7 @@ var COMMAND_SPECS = [
|
|
|
43898
45003
|
{ name: "filter", type: "string", description: "all (default), living or linked." },
|
|
43899
45004
|
{ name: "limit", type: "string", description: "At most this many (1\u2013500, default 100)." }
|
|
43900
45005
|
],
|
|
43901
|
-
scopes: [
|
|
45006
|
+
scopes: [...familyTreeOperations.people.scopes],
|
|
43902
45007
|
returns: "FamilyTreePeople"
|
|
43903
45008
|
},
|
|
43904
45009
|
{
|
|
@@ -43906,7 +45011,7 @@ var COMMAND_SPECS = [
|
|
|
43906
45011
|
summary: "Say which person in the tree is you.",
|
|
43907
45012
|
args: [{ name: "personId", required: true, description: "Your ref in the tree (I12)." }],
|
|
43908
45013
|
flags: [],
|
|
43909
|
-
scopes: [
|
|
45014
|
+
scopes: [...familyTreeOperations.me.scopes],
|
|
43910
45015
|
returns: "FamilyTreeView",
|
|
43911
45016
|
notes: "The person becomes the root of the branch, and a living one is linked to your own Contact (the one that is you)."
|
|
43912
45017
|
},
|
|
@@ -43922,7 +45027,7 @@ var COMMAND_SPECS = [
|
|
|
43922
45027
|
description: "Say no to this match id (never offered again)."
|
|
43923
45028
|
}
|
|
43924
45029
|
],
|
|
43925
|
-
scopes: [
|
|
45030
|
+
scopes: [...familyTreeOperations.matches.scopes],
|
|
43926
45031
|
returns: "FamilyTreeMatches",
|
|
43927
45032
|
notes: "Without a flag it lists the matches: suggest (a relative who looks like a Contact), birthday_differs, not_in_tree. Yes to a suggest links them; yes to birthday_differs takes the tree's day; not_in_tree only takes no (the fix goes to who sent the tree). Ask the member before either."
|
|
43928
45033
|
},
|
|
@@ -46252,24 +47357,24 @@ var HANDLERS = {
|
|
|
46252
47357
|
return { data: await requireClient().upload("/documents/file", form), render: renderRecord };
|
|
46253
47358
|
},
|
|
46254
47359
|
"documents filed": async ({ flags, requireClient }) => ({
|
|
46255
|
-
data: await requireClient().get(
|
|
47360
|
+
data: await requireClient().get(pathOf(documentOperations.filed), {
|
|
46256
47361
|
query: { source: requireFlag(flags, "source", "documents filed needs --source gmail:<id>") }
|
|
46257
47362
|
}),
|
|
46258
47363
|
render: renderRecord
|
|
46259
47364
|
}),
|
|
46260
47365
|
"documents doccle status": async ({ requireClient }) => ({
|
|
46261
|
-
data: await requireClient().get(
|
|
47366
|
+
data: await requireClient().get(pathOf(documentOperations.doccleStatus)),
|
|
46262
47367
|
render: renderRecord
|
|
46263
47368
|
}),
|
|
46264
47369
|
"documents doccle sync": async ({ requireClient }) => ({
|
|
46265
|
-
data: await requireClient().post(
|
|
47370
|
+
data: await requireClient().post(pathOf(documentOperations.doccleSync), {}),
|
|
46266
47371
|
render: renderRecord
|
|
46267
47372
|
}),
|
|
46268
47373
|
"documents doccle connect": (ctx) => connectDoccle(ctx),
|
|
46269
47374
|
"documents doccle disconnect": async ({ flags, requireClient }) => {
|
|
46270
47375
|
assertDestructiveAllowed(flags, "forget the Doccle login");
|
|
46271
47376
|
return {
|
|
46272
|
-
data: await requireClient().delete(
|
|
47377
|
+
data: await requireClient().delete(pathOf(documentOperations.doccleDisconnect)),
|
|
46273
47378
|
render: renderRecord
|
|
46274
47379
|
};
|
|
46275
47380
|
},
|
|
@@ -46278,7 +47383,7 @@ var HANDLERS = {
|
|
|
46278
47383
|
if (archive !== "on" && archive !== "off")
|
|
46279
47384
|
throw usageError("--archive takes on or off");
|
|
46280
47385
|
return {
|
|
46281
|
-
data: await requireClient().patch(
|
|
47386
|
+
data: await requireClient().patch(pathOf(documentOperations.doccleSettings), {
|
|
46282
47387
|
archiveAfterImport: archive === "on"
|
|
46283
47388
|
}),
|
|
46284
47389
|
render: renderRecord
|
|
@@ -46294,7 +47399,10 @@ var HANDLERS = {
|
|
|
46294
47399
|
documentId: flagString(flags, "document"),
|
|
46295
47400
|
limit: limit === undefined ? undefined : Number(limit)
|
|
46296
47401
|
}).filter(([, value]) => value !== undefined));
|
|
46297
|
-
return {
|
|
47402
|
+
return {
|
|
47403
|
+
data: await requireClient().post(pathOf(documentOperations.ask), body),
|
|
47404
|
+
render: renderRecord
|
|
47405
|
+
};
|
|
46298
47406
|
},
|
|
46299
47407
|
"documents search": async ({ args, flags, requireClient }) => {
|
|
46300
47408
|
const q = args.join(" ").trim();
|
|
@@ -46306,28 +47414,30 @@ var HANDLERS = {
|
|
|
46306
47414
|
limit: flagString(flags, "limit")
|
|
46307
47415
|
}).filter(([, value]) => value !== undefined));
|
|
46308
47416
|
return {
|
|
46309
|
-
data: await requireClient().get(
|
|
47417
|
+
data: await requireClient().get(pathOf(documentOperations.search), { query }),
|
|
46310
47418
|
render: renderRecord
|
|
46311
47419
|
};
|
|
46312
47420
|
},
|
|
46313
47421
|
"documents unmatched": async ({ requireClient }) => ({
|
|
46314
|
-
data: await requireClient().get(
|
|
47422
|
+
data: await requireClient().get(pathOf(documentOperations.unmatched)),
|
|
46315
47423
|
render: renderList
|
|
46316
47424
|
}),
|
|
46317
47425
|
"documents match": async ({ args, requireClient }) => {
|
|
46318
47426
|
const id = args[0];
|
|
46319
|
-
const path = id ?
|
|
47427
|
+
const path = id ? pathOf(documentOperations.matchOne, { id }) : pathOf(documentOperations.matchAll);
|
|
46320
47428
|
return { data: await requireClient().post(path, {}), render: id ? renderRecord : renderList };
|
|
46321
47429
|
},
|
|
46322
47430
|
"documents payments": async ({ args, requireClient }) => ({
|
|
46323
|
-
data: await requireClient().get(
|
|
47431
|
+
data: await requireClient().get(pathOf(documentOperations.payments, { id: requireArg(args, 0, "document id") })),
|
|
46324
47432
|
render: renderList
|
|
46325
47433
|
}),
|
|
46326
47434
|
"documents link-payment": async ({ args, requireClient }) => {
|
|
46327
47435
|
const id = requireArg(args, 0, "document id");
|
|
46328
47436
|
const transactionId = requireArg(args, 1, "transaction id");
|
|
46329
47437
|
return {
|
|
46330
|
-
data: await requireClient().put(
|
|
47438
|
+
data: await requireClient().put(pathOf(documentOperations.linkPayment, { id }), {
|
|
47439
|
+
transactionId
|
|
47440
|
+
}),
|
|
46331
47441
|
render: renderList
|
|
46332
47442
|
};
|
|
46333
47443
|
},
|
|
@@ -46335,7 +47445,7 @@ var HANDLERS = {
|
|
|
46335
47445
|
const id = requireArg(args, 0, "document id");
|
|
46336
47446
|
const transactionId = requireArg(args, 1, "transaction id");
|
|
46337
47447
|
assertDestructiveAllowed(flags, `unlink payment ${transactionId} from ${id}`);
|
|
46338
|
-
await requireClient().delete(
|
|
47448
|
+
await requireClient().delete(pathOf(documentOperations.unlinkPayment, { id, transactionId }));
|
|
46339
47449
|
return { data: { ok: true, unlinked: transactionId }, render: renderRecord };
|
|
46340
47450
|
},
|
|
46341
47451
|
"incidents open": async ({ args, flags, requireClient }) => {
|
|
@@ -48338,18 +49448,24 @@ var HANDLERS = {
|
|
|
48338
49448
|
...healthRecordHandlers(),
|
|
48339
49449
|
"health record": async ({ flags, requireClient }) => {
|
|
48340
49450
|
const body = parseInput(logHealthInputSchema, readDataFlag(flags));
|
|
48341
|
-
return {
|
|
49451
|
+
return {
|
|
49452
|
+
data: await requireClient().post(pathOf(healthOperations.log), body),
|
|
49453
|
+
render: renderRecord
|
|
49454
|
+
};
|
|
48342
49455
|
},
|
|
48343
49456
|
"health fix": async ({ args, flags, requireClient }) => {
|
|
48344
49457
|
const entryId = requireArg(args, 0, "entry");
|
|
48345
49458
|
const body = parseInput(correctHealthInputSchema, { entryId, change: readDataFlag(flags) });
|
|
48346
|
-
return {
|
|
49459
|
+
return {
|
|
49460
|
+
data: await requireClient().post(pathOf(healthOperations.correct), body),
|
|
49461
|
+
render: renderRecord
|
|
49462
|
+
};
|
|
48347
49463
|
},
|
|
48348
49464
|
"health check-in": async ({ args, requireClient }) => {
|
|
48349
49465
|
const episodeId = requireArg(args, 0, "episode");
|
|
48350
49466
|
const body = parseInput(healthCheckInInputSchema, { trend: requireArg(args, 1, "trend") });
|
|
48351
49467
|
return {
|
|
48352
|
-
data: await requireClient().post(
|
|
49468
|
+
data: await requireClient().post(pathOf(healthOperations.checkIn, { id: episodeId }), body),
|
|
48353
49469
|
render: renderRecord
|
|
48354
49470
|
};
|
|
48355
49471
|
},
|
|
@@ -48366,7 +49482,7 @@ var HANDLERS = {
|
|
|
48366
49482
|
...thread ? { thread: { slug: thread } } : {}
|
|
48367
49483
|
});
|
|
48368
49484
|
return {
|
|
48369
|
-
data: await requireClient().post(
|
|
49485
|
+
data: await requireClient().post(pathOf(healthOperations.redFlags, { id: episodeId }), body),
|
|
48370
49486
|
render: renderRecord
|
|
48371
49487
|
};
|
|
48372
49488
|
},
|
|
@@ -48375,37 +49491,40 @@ var HANDLERS = {
|
|
|
48375
49491
|
kind: requireArg(args, 0, "kind"),
|
|
48376
49492
|
id: requireArg(args, 1, "id")
|
|
48377
49493
|
});
|
|
48378
|
-
return {
|
|
49494
|
+
return {
|
|
49495
|
+
data: await requireClient().post(pathOf(healthOperations.undo), body),
|
|
49496
|
+
render: renderRecord
|
|
49497
|
+
};
|
|
48379
49498
|
},
|
|
48380
49499
|
"health find": async ({ flags, requireClient }) => {
|
|
48381
49500
|
const body = parseInput(upsertHealthEpisodeInputSchema, readDataFlag(flags));
|
|
48382
49501
|
return {
|
|
48383
|
-
data: await requireClient().post(
|
|
49502
|
+
data: await requireClient().post(pathOf(healthOperations.upsertEpisode), body),
|
|
48384
49503
|
render: renderRecord
|
|
48385
49504
|
};
|
|
48386
49505
|
},
|
|
48387
49506
|
"health medical-id": async ({ requireClient }) => ({
|
|
48388
|
-
data: await requireClient().get(
|
|
49507
|
+
data: await requireClient().get(pathOf(healthOperations.medicalId)),
|
|
48389
49508
|
render: renderRecord
|
|
48390
49509
|
}),
|
|
48391
49510
|
"health summary": async ({ flags, requireClient }) => ({
|
|
48392
|
-
data: await requireClient().get(
|
|
49511
|
+
data: await requireClient().get(pathOf(healthOperations.summary), {
|
|
48393
49512
|
query: { episodeId: flagString(flags, "episode") }
|
|
48394
49513
|
}),
|
|
48395
49514
|
render: renderRecord
|
|
48396
49515
|
}),
|
|
48397
49516
|
"health export": async ({ flags, requireClient }) => {
|
|
48398
|
-
const raw = await requireClient().getText(
|
|
49517
|
+
const raw = await requireClient().getText(pathOf(healthOperations.export), {
|
|
48399
49518
|
query: { files: flagBool(flags, "no-files") ? "false" : undefined }
|
|
48400
49519
|
});
|
|
48401
49520
|
return { raw, data: undefined, render: () => raw };
|
|
48402
49521
|
},
|
|
48403
49522
|
"health shares": async ({ requireClient }) => ({
|
|
48404
|
-
data: await requireClient().getPage(
|
|
49523
|
+
data: await requireClient().getPage(pathOf(healthOperations.listShares)),
|
|
48405
49524
|
render: renderList
|
|
48406
49525
|
}),
|
|
48407
49526
|
"health share revoke": async ({ args, requireClient }) => ({
|
|
48408
|
-
data: await requireClient().delete(
|
|
49527
|
+
data: await requireClient().delete(pathOf(healthOperations.revokeShare, { id: requireArg(args, 0, "id") })),
|
|
48409
49528
|
render: renderRecord
|
|
48410
49529
|
}),
|
|
48411
49530
|
"health withings status": async ({ requireClient }) => ({
|
|
@@ -48425,11 +49544,11 @@ var HANDLERS = {
|
|
|
48425
49544
|
render: renderRecord
|
|
48426
49545
|
}),
|
|
48427
49546
|
"health consent": async ({ requireClient }) => ({
|
|
48428
|
-
data: await requireClient().get(
|
|
49547
|
+
data: await requireClient().get(pathOf(healthOperations.getConsent)),
|
|
48429
49548
|
render: renderRecord
|
|
48430
49549
|
}),
|
|
48431
49550
|
"health profile": async ({ requireClient }) => ({
|
|
48432
|
-
data: await requireClient().get(
|
|
49551
|
+
data: await requireClient().get(pathOf(healthOperations.getProfile)),
|
|
48433
49552
|
render: renderRecord
|
|
48434
49553
|
}),
|
|
48435
49554
|
"health profile set": async ({ flags, requireClient }) => {
|
|
@@ -48441,7 +49560,10 @@ var HANDLERS = {
|
|
|
48441
49560
|
if (sex !== undefined)
|
|
48442
49561
|
fields.sex = sex.trim() ? sex.trim() : null;
|
|
48443
49562
|
const body = parseInput(updateHealthProfileInputSchema, fields);
|
|
48444
|
-
return {
|
|
49563
|
+
return {
|
|
49564
|
+
data: await requireClient().patch(pathOf(healthOperations.updateProfile), body),
|
|
49565
|
+
render: renderRecord
|
|
49566
|
+
};
|
|
48445
49567
|
},
|
|
48446
49568
|
"health log": async ({ args, flags, requireClient }) => {
|
|
48447
49569
|
const episode = requireArg(args, 0, "episode");
|
|
@@ -48460,7 +49582,7 @@ var HANDLERS = {
|
|
|
48460
49582
|
};
|
|
48461
49583
|
const body = parseInput(logHealthSymptomInputSchema, { id: ulid3(), ...raw });
|
|
48462
49584
|
return {
|
|
48463
|
-
data: await requireClient().post(
|
|
49585
|
+
data: await requireClient().post(pathOf(healthOperations.logSymptom, { id: episode }), body),
|
|
48464
49586
|
render: renderRecord
|
|
48465
49587
|
};
|
|
48466
49588
|
},
|
|
@@ -48472,14 +49594,14 @@ var HANDLERS = {
|
|
|
48472
49594
|
...readDataFlag(flags)
|
|
48473
49595
|
});
|
|
48474
49596
|
return {
|
|
48475
|
-
data: await requireClient().post(
|
|
49597
|
+
data: await requireClient().post(pathOf(healthOperations.correctSymptom, { id: episode, entryId: entry }), body),
|
|
48476
49598
|
render: renderRecord
|
|
48477
49599
|
};
|
|
48478
49600
|
},
|
|
48479
49601
|
"health unlog": async ({ args, requireClient }) => {
|
|
48480
49602
|
const episode = requireArg(args, 0, "episode");
|
|
48481
49603
|
const entry = requireArg(args, 1, "entry");
|
|
48482
|
-
await requireClient().delete(
|
|
49604
|
+
await requireClient().delete(pathOf(healthOperations.deleteSymptom, { id: episode, entryId: entry }));
|
|
48483
49605
|
return { data: { ok: true, deleted: entry }, render: renderRecord };
|
|
48484
49606
|
},
|
|
48485
49607
|
"health lab import": async ({ args, flags, requireClient }) => {
|
|
@@ -48506,14 +49628,17 @@ var HANDLERS = {
|
|
|
48506
49628
|
};
|
|
48507
49629
|
},
|
|
48508
49630
|
"health labs analytes": async ({ requireClient }) => ({
|
|
48509
|
-
data: await requireClient().get(
|
|
49631
|
+
data: await requireClient().get(pathOf(healthOperations.listLabAnalytes)),
|
|
48510
49632
|
render: renderList
|
|
48511
49633
|
}),
|
|
48512
49634
|
"health labs normalize": async ({ flags, requireClient }) => {
|
|
48513
49635
|
if (!flagBool(flags, "dry-run")) {
|
|
48514
49636
|
throw usageError("health labs normalize only reports for now: pass --dry-run (stored keys aren't rewritten)");
|
|
48515
49637
|
}
|
|
48516
|
-
return {
|
|
49638
|
+
return {
|
|
49639
|
+
data: await requireClient().get(pathOf(healthOperations.labNormalizeReport)),
|
|
49640
|
+
render: renderRecord
|
|
49641
|
+
};
|
|
48517
49642
|
},
|
|
48518
49643
|
"health conditions care-team add": async ({ args, flags, requireClient }) => {
|
|
48519
49644
|
const condition = requireArg(args, 0, "condition");
|
|
@@ -48523,7 +49648,7 @@ var HANDLERS = {
|
|
|
48523
49648
|
...label !== undefined ? { label } : {}
|
|
48524
49649
|
});
|
|
48525
49650
|
return {
|
|
48526
|
-
data: await requireClient().post(
|
|
49651
|
+
data: await requireClient().post(pathOf(healthOperations.addCareTeam, { id: condition }), body),
|
|
48527
49652
|
render: renderRecord
|
|
48528
49653
|
};
|
|
48529
49654
|
},
|
|
@@ -48531,28 +49656,28 @@ var HANDLERS = {
|
|
|
48531
49656
|
const condition = requireArg(args, 0, "condition");
|
|
48532
49657
|
const contact = requireArg(args, 1, "contact");
|
|
48533
49658
|
return {
|
|
48534
|
-
data: await requireClient().delete(
|
|
49659
|
+
data: await requireClient().delete(pathOf(healthOperations.removeCareTeam, { id: condition, contactId: contact })),
|
|
48535
49660
|
render: renderRecord
|
|
48536
49661
|
};
|
|
48537
49662
|
},
|
|
48538
49663
|
"health analytes": async ({ requireClient }) => ({
|
|
48539
|
-
data: await requireClient().get(
|
|
49664
|
+
data: await requireClient().get(pathOf(healthOperations.labOverview)),
|
|
48540
49665
|
render: renderRecord
|
|
48541
49666
|
}),
|
|
48542
49667
|
"health analyte": async ({ args, requireClient }) => ({
|
|
48543
|
-
data: await requireClient().get(
|
|
49668
|
+
data: await requireClient().get(pathOf(healthOperations.getLabAnalyte, { analyte: requireArg(args, 0, "analyte") })),
|
|
48544
49669
|
render: renderRecord
|
|
48545
49670
|
}),
|
|
48546
49671
|
"health analyte set": async ({ args, flags, requireClient }) => {
|
|
48547
49672
|
const analyte = requireArg(args, 0, "analyte");
|
|
48548
49673
|
const body = parseInput(setHealthLabAnalyteInputSchema, readDataFlag(flags));
|
|
48549
49674
|
return {
|
|
48550
|
-
data: await requireClient().put(
|
|
49675
|
+
data: await requireClient().put(pathOf(healthOperations.setLabAnalyte, { analyte }), body),
|
|
48551
49676
|
render: renderRecord
|
|
48552
49677
|
};
|
|
48553
49678
|
},
|
|
48554
49679
|
"health doses": async ({ args, requireClient }) => ({
|
|
48555
|
-
data: await requireClient().getPage(
|
|
49680
|
+
data: await requireClient().getPage(pathOf(healthOperations.listDoses, { id: requireArg(args, 0, "med") })),
|
|
48556
49681
|
render: renderList
|
|
48557
49682
|
}),
|
|
48558
49683
|
"health dose": async ({ args, flags, requireClient }) => {
|
|
@@ -48567,7 +49692,7 @@ var HANDLERS = {
|
|
|
48567
49692
|
};
|
|
48568
49693
|
const body = parseInput(logHealthDoseInputSchema, { id: ulid3(), ...raw });
|
|
48569
49694
|
return {
|
|
48570
|
-
data: await requireClient().post(
|
|
49695
|
+
data: await requireClient().post(pathOf(healthOperations.logDose, { id: med }), body),
|
|
48571
49696
|
render: renderRecord
|
|
48572
49697
|
};
|
|
48573
49698
|
},
|
|
@@ -48576,14 +49701,14 @@ var HANDLERS = {
|
|
|
48576
49701
|
const dose = requireArg(args, 1, "dose");
|
|
48577
49702
|
const body = parseInput(updateHealthDoseInputSchema, readDataFlag(flags));
|
|
48578
49703
|
return {
|
|
48579
|
-
data: await requireClient().patch(
|
|
49704
|
+
data: await requireClient().patch(pathOf(healthOperations.updateDose, { id: med, doseId: dose }), body),
|
|
48580
49705
|
render: renderRecord
|
|
48581
49706
|
};
|
|
48582
49707
|
},
|
|
48583
49708
|
"health undose": async ({ args, requireClient }) => {
|
|
48584
49709
|
const med = requireArg(args, 0, "med");
|
|
48585
49710
|
const dose = requireArg(args, 1, "dose");
|
|
48586
|
-
await requireClient().delete(
|
|
49711
|
+
await requireClient().delete(pathOf(healthOperations.deleteDose, { id: med, doseId: dose }));
|
|
48587
49712
|
return { data: { ok: true, deleted: dose }, render: renderRecord };
|
|
48588
49713
|
},
|
|
48589
49714
|
"places import": async ({ args, flags, requireClient }) => {
|
|
@@ -48762,7 +49887,9 @@ var HANDLERS = {
|
|
|
48762
49887
|
const side = flagString(flags, "side");
|
|
48763
49888
|
parseInput(familyTreeQuerySchema, side ? { side } : {});
|
|
48764
49889
|
return {
|
|
48765
|
-
data: await requireClient().get(
|
|
49890
|
+
data: await requireClient().get(pathOf(familyTreeOperations.get), {
|
|
49891
|
+
query: side ? { side } : {}
|
|
49892
|
+
}),
|
|
48766
49893
|
render: renderRecord
|
|
48767
49894
|
};
|
|
48768
49895
|
},
|
|
@@ -48798,13 +49925,16 @@ var HANDLERS = {
|
|
|
48798
49925
|
};
|
|
48799
49926
|
parseInput(familyTreePeopleQuerySchema, query);
|
|
48800
49927
|
return {
|
|
48801
|
-
data: await requireClient().get(
|
|
49928
|
+
data: await requireClient().get(pathOf(familyTreeOperations.people), { query }),
|
|
48802
49929
|
render: renderRecord
|
|
48803
49930
|
};
|
|
48804
49931
|
},
|
|
48805
49932
|
"people tree me": async ({ args, requireClient }) => {
|
|
48806
49933
|
const body = parseInput(familyTreeMeInputSchema, { ref: requireArg(args, 0, "person id") });
|
|
48807
|
-
return {
|
|
49934
|
+
return {
|
|
49935
|
+
data: await requireClient().put(pathOf(familyTreeOperations.me), body),
|
|
49936
|
+
render: renderRecord
|
|
49937
|
+
};
|
|
48808
49938
|
},
|
|
48809
49939
|
"people tree matches": async ({ flags, requireClient }) => {
|
|
48810
49940
|
const accept = flagString(flags, "accept");
|
|
@@ -48813,13 +49943,16 @@ var HANDLERS = {
|
|
|
48813
49943
|
throw usageError("--accept and --reject can't be combined");
|
|
48814
49944
|
const client = requireClient();
|
|
48815
49945
|
if (!accept && !reject) {
|
|
48816
|
-
return { data: await client.get(
|
|
49946
|
+
return { data: await client.get(pathOf(familyTreeOperations.matches)), render: renderRecord };
|
|
48817
49947
|
}
|
|
48818
49948
|
const body = parseInput(familyTreeMatchDecisionInputSchema, {
|
|
48819
49949
|
id: accept ?? reject,
|
|
48820
49950
|
decision: accept ? "accept" : "reject"
|
|
48821
49951
|
});
|
|
48822
|
-
return {
|
|
49952
|
+
return {
|
|
49953
|
+
data: await client.post(pathOf(familyTreeOperations.decide), body),
|
|
49954
|
+
render: renderRecord
|
|
49955
|
+
};
|
|
48823
49956
|
},
|
|
48824
49957
|
"guest-lists overview": async ({ args, requireClient }) => {
|
|
48825
49958
|
const id = requireArg(args, 0, "guest list id");
|
|
@@ -49377,17 +50510,20 @@ function healthRecordHandlers() {
|
|
|
49377
50510
|
lab: "labs"
|
|
49378
50511
|
};
|
|
49379
50512
|
const out = {};
|
|
49380
|
-
for (const kind of Object.keys(
|
|
49381
|
-
const
|
|
50513
|
+
for (const kind of Object.keys(HEALTH_RECORD_OPERATIONS)) {
|
|
50514
|
+
const ops = HEALTH_RECORD_OPERATIONS[kind];
|
|
49382
50515
|
const schemas = schemasOf[kind];
|
|
49383
50516
|
out[`health ${plurals[kind]}`] = async ({ flags, requireClient }) => {
|
|
49384
50517
|
const query = {};
|
|
49385
50518
|
for (const name of schemas.list ?? [])
|
|
49386
50519
|
query[name] = flagString(flags, name);
|
|
49387
|
-
return {
|
|
50520
|
+
return {
|
|
50521
|
+
data: await requireClient().getPage(pathOf(ops.list), { query }),
|
|
50522
|
+
render: renderList
|
|
50523
|
+
};
|
|
49388
50524
|
};
|
|
49389
50525
|
out[`health ${kind}`] = async ({ args, requireClient }) => ({
|
|
49390
|
-
data: await requireClient().get(
|
|
50526
|
+
data: await requireClient().get(pathOf(ops.get, { id: requireArg(args, 0, "id") })),
|
|
49391
50527
|
render: renderRecord
|
|
49392
50528
|
});
|
|
49393
50529
|
out[`health ${kind} add`] = async ({ flags, requireClient }) => {
|
|
@@ -49396,17 +50532,20 @@ function healthRecordHandlers() {
|
|
|
49396
50532
|
...readDataFlag(flags),
|
|
49397
50533
|
...schemas.addFlags?.(flags)
|
|
49398
50534
|
});
|
|
49399
|
-
return { data: await requireClient().post(
|
|
50535
|
+
return { data: await requireClient().post(pathOf(ops.create), body), render: renderRecord };
|
|
49400
50536
|
};
|
|
49401
50537
|
out[`health ${kind} update`] = async ({ args, flags, requireClient }) => {
|
|
49402
50538
|
const id = requireArg(args, 0, "id");
|
|
49403
50539
|
const body = parseInput(schemas.update, readDataFlag(flags));
|
|
49404
|
-
return {
|
|
50540
|
+
return {
|
|
50541
|
+
data: await requireClient().patch(pathOf(ops.update, { id }), body),
|
|
50542
|
+
render: renderRecord
|
|
50543
|
+
};
|
|
49405
50544
|
};
|
|
49406
50545
|
out[`health ${kind} delete`] = async ({ args, flags, requireClient }) => {
|
|
49407
50546
|
const id = requireArg(args, 0, "id");
|
|
49408
50547
|
assertDestructiveAllowed(flags, `delete health ${kind} ${id}`);
|
|
49409
|
-
await requireClient().delete(
|
|
50548
|
+
await requireClient().delete(pathOf(ops.remove, { id }));
|
|
49410
50549
|
return { data: { ok: true, deleted: id, softDelete: true }, render: renderRecord };
|
|
49411
50550
|
};
|
|
49412
50551
|
}
|