@robbeverhelst/do 1.303.0 → 1.305.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 +2135 -320
- package/package.json +1 -1
package/dist/do.js
CHANGED
|
@@ -4949,6 +4949,20 @@ var moneyRecurring = pgTable("money_recurring", {
|
|
|
4949
4949
|
check("money_recurring_amount", sql`${t.expectedAmount} > 0`),
|
|
4950
4950
|
check("money_recurring_business_share", sql`${t.businessShare} BETWEEN 0 AND 100`)
|
|
4951
4951
|
]);
|
|
4952
|
+
var moneySnapshotSource = pgEnum("money_snapshot_source", ["balance", "ledger", "manual"]);
|
|
4953
|
+
var moneySnapshots = pgTable("money_snapshots", {
|
|
4954
|
+
id: text("id").primaryKey(),
|
|
4955
|
+
tenantId: text("tenant_id").notNull().references(() => tenants.id),
|
|
4956
|
+
accountId: text("account_id").notNull().references(() => moneyAccounts.id, { onDelete: "cascade" }),
|
|
4957
|
+
month: char("month", { length: 7 }).notNull(),
|
|
4958
|
+
value: numeric("value", { precision: 14, scale: 2 }).notNull(),
|
|
4959
|
+
source: moneySnapshotSource("source").notNull().default("balance"),
|
|
4960
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
4961
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
4962
|
+
}, (t) => [
|
|
4963
|
+
unique("money_snapshots_account_month_key").on(t.tenantId, t.accountId, t.month),
|
|
4964
|
+
check("money_snapshots_month", sql`${t.month} ~ '^[0-9]{4}-(0[1-9]|1[0-2])$'`)
|
|
4965
|
+
]);
|
|
4952
4966
|
|
|
4953
4967
|
// ../../packages/schema/src/db/money-connections.ts
|
|
4954
4968
|
var moneyConnectionStatus = pgEnum("money_connection_status", [
|
|
@@ -5632,6 +5646,18 @@ var foodWeekReads = pgTable("food_week_reads", {
|
|
|
5632
5646
|
weekStart: text("week_start").notNull()
|
|
5633
5647
|
}, (t) => [unique("food_week_reads_owner_week_uniq").on(t.tenantId, t.ownerUserId, t.weekStart)]);
|
|
5634
5648
|
|
|
5649
|
+
// ../../packages/schema/src/db/webhooks.ts
|
|
5650
|
+
var webhookSubscriptions = pgTable("webhook_subscriptions", {
|
|
5651
|
+
id: text("id").primaryKey(),
|
|
5652
|
+
tenantId: text("tenant_id").notNull().references(() => tenants.id),
|
|
5653
|
+
url: text("url").notNull(),
|
|
5654
|
+
events: text("events").array().notNull().default([]),
|
|
5655
|
+
secret: text("secret").notNull(),
|
|
5656
|
+
active: boolean("active").notNull().default(true),
|
|
5657
|
+
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5658
|
+
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
5659
|
+
}, (t) => [index("webhook_subscriptions_tenant_idx").on(t.tenantId)]);
|
|
5660
|
+
|
|
5635
5661
|
// ../../packages/schema/src/db/collaboration.ts
|
|
5636
5662
|
var capability = pgEnum("collab_capability", ["view", "comment", "edit", "admin"]);
|
|
5637
5663
|
var grantSubjectType = pgEnum("grant_subject_type", ["member", "role"]);
|
|
@@ -20509,6 +20535,21 @@ var collectionCoverBackfillResultSchema = object({
|
|
|
20509
20535
|
found: number2().int().min(0),
|
|
20510
20536
|
colored: number2().int().min(0).default(0)
|
|
20511
20537
|
});
|
|
20538
|
+
function normalizeTag(raw) {
|
|
20539
|
+
return raw.trim().toLowerCase().replace(/\s+/g, " ");
|
|
20540
|
+
}
|
|
20541
|
+
function normalizeTags(raw) {
|
|
20542
|
+
const seen = new Set;
|
|
20543
|
+
const out = [];
|
|
20544
|
+
for (const r of raw) {
|
|
20545
|
+
const tag = normalizeTag(r);
|
|
20546
|
+
if (!tag || seen.has(tag))
|
|
20547
|
+
continue;
|
|
20548
|
+
seen.add(tag);
|
|
20549
|
+
out.push(tag);
|
|
20550
|
+
}
|
|
20551
|
+
return out;
|
|
20552
|
+
}
|
|
20512
20553
|
var collectionSavedViewSchema = object({
|
|
20513
20554
|
id: string2().min(1),
|
|
20514
20555
|
name: string2().min(1),
|
|
@@ -20547,6 +20588,53 @@ var collectionLogResultSchema = object({
|
|
|
20547
20588
|
item: collectionItemDetailSchema
|
|
20548
20589
|
});
|
|
20549
20590
|
|
|
20591
|
+
// ../../packages/schema/src/contracts/list-filters.ts
|
|
20592
|
+
function csvList(item) {
|
|
20593
|
+
return preprocess((raw) => (Array.isArray(raw) ? raw : [raw]).flatMap((v) => typeof v === "string" ? v.split(",") : [v]).map((v) => typeof v === "string" ? v.trim() : v).filter((v) => v !== ""), array(item).min(1));
|
|
20594
|
+
}
|
|
20595
|
+
var booleanQuerySchema = _enum2(["true", "false", "1", "0"]).transform((v) => v === "true" || v === "1");
|
|
20596
|
+
var instantQuerySchema = union([exports_iso.datetime({ offset: true }), exports_iso.date()]).transform((s) => new Date(s));
|
|
20597
|
+
var tagListSchema = csvList(string2().min(1)).transform((tags, ctx) => {
|
|
20598
|
+
const normalized = normalizeTags(tags.map((t) => t.replace(/^#/, "")));
|
|
20599
|
+
if (normalized.length === 0) {
|
|
20600
|
+
ctx.addIssue({ code: "custom", message: "must name at least one tag" });
|
|
20601
|
+
return NEVER;
|
|
20602
|
+
}
|
|
20603
|
+
return normalized;
|
|
20604
|
+
});
|
|
20605
|
+
function partyFilterSchema(party) {
|
|
20606
|
+
return union([_enum2(["any", "none"]), party]);
|
|
20607
|
+
}
|
|
20608
|
+
var taskListQuerySchema = object({
|
|
20609
|
+
areaId: ulidSchema.optional(),
|
|
20610
|
+
projectId: ulidSchema.optional(),
|
|
20611
|
+
status: csvList(taskStatusSchema).optional(),
|
|
20612
|
+
tag: tagListSchema.optional(),
|
|
20613
|
+
updatedSince: instantQuerySchema.optional(),
|
|
20614
|
+
dueBefore: instantQuerySchema.optional(),
|
|
20615
|
+
owner: partyFilterSchema(taskOwnerInputSchema).optional(),
|
|
20616
|
+
waitingOn: partyFilterSchema(taskWaitingOnInputSchema).optional(),
|
|
20617
|
+
completedSince: instantQuerySchema.optional(),
|
|
20618
|
+
completedBefore: instantQuerySchema.optional(),
|
|
20619
|
+
proposed: booleanQuerySchema.optional(),
|
|
20620
|
+
ready: booleanQuerySchema.optional(),
|
|
20621
|
+
drifted: booleanQuerySchema.optional()
|
|
20622
|
+
});
|
|
20623
|
+
var projectListQuerySchema = object({
|
|
20624
|
+
areaId: ulidSchema.optional(),
|
|
20625
|
+
status: csvList(projectStatusSchema).optional(),
|
|
20626
|
+
updatedSince: instantQuerySchema.optional(),
|
|
20627
|
+
dueBefore: instantQuerySchema.optional()
|
|
20628
|
+
});
|
|
20629
|
+
var habitListQuerySchema = object({
|
|
20630
|
+
areaId: ulidSchema.optional(),
|
|
20631
|
+
updatedSince: instantQuerySchema.optional(),
|
|
20632
|
+
retired: _enum2(["true", "false"]).transform((v) => v === "true").optional()
|
|
20633
|
+
});
|
|
20634
|
+
var areaListQuerySchema = object({
|
|
20635
|
+
archived: _enum2(["true", "false"]).transform((v) => v === "true").optional()
|
|
20636
|
+
});
|
|
20637
|
+
|
|
20550
20638
|
// ../../packages/schema/src/contracts/habit-sources.ts
|
|
20551
20639
|
var habitSourceSchema = _enum2(["manual", "google_fit", "strava", "github"]);
|
|
20552
20640
|
|
|
@@ -24665,6 +24753,50 @@ var dayRecordUndoResultSchema = object({
|
|
|
24665
24753
|
});
|
|
24666
24754
|
var STATUS_QUARTER_MS = RECORD_ROUND_MINUTES * 60000;
|
|
24667
24755
|
|
|
24756
|
+
// ../../packages/schema/src/contracts/today.ts
|
|
24757
|
+
var occurrenceViewSchema = occurrenceSchema.extend({
|
|
24758
|
+
title: string2(),
|
|
24759
|
+
templateKind: _enum2(["task", "habit", "routine"]),
|
|
24760
|
+
measurementType: habitMeasurementTypeSchema.nullable()
|
|
24761
|
+
});
|
|
24762
|
+
var todayResponseSchema = object({
|
|
24763
|
+
from: exports_coerce.date(),
|
|
24764
|
+
to: exports_coerce.date(),
|
|
24765
|
+
scheduledTasks: array(taskViewSchema),
|
|
24766
|
+
dueOccurrences: array(occurrenceViewSchema),
|
|
24767
|
+
overdueTasks: array(taskViewSchema),
|
|
24768
|
+
overdueOccurrences: array(occurrenceViewSchema)
|
|
24769
|
+
});
|
|
24770
|
+
var rolloverInputSchema = object({
|
|
24771
|
+
taskIds: array(string2().min(1)).default([]),
|
|
24772
|
+
occurrenceIds: array(string2().min(1)).default([]),
|
|
24773
|
+
action: _enum2(["reschedule", "someday", "drop"]),
|
|
24774
|
+
to: exports_coerce.date().optional()
|
|
24775
|
+
}).refine((v) => v.action !== "reschedule" || v.to !== undefined, {
|
|
24776
|
+
message: "`to` is required when action is `reschedule`",
|
|
24777
|
+
path: ["to"]
|
|
24778
|
+
});
|
|
24779
|
+
var rolloverResultSchema = object({
|
|
24780
|
+
tasks: number2().int().nonnegative(),
|
|
24781
|
+
occurrences: number2().int().nonnegative()
|
|
24782
|
+
});
|
|
24783
|
+
var fromEarlierQuerySchema = object({
|
|
24784
|
+
from: instantQuerySchema.optional(),
|
|
24785
|
+
areaId: ulidSchema.optional()
|
|
24786
|
+
});
|
|
24787
|
+
var fromEarlierResponseSchema = object({
|
|
24788
|
+
from: exports_coerce.date(),
|
|
24789
|
+
since: exports_coerce.date(),
|
|
24790
|
+
laterThisWeek: exports_coerce.date(),
|
|
24791
|
+
tasks: array(taskViewSchema)
|
|
24792
|
+
});
|
|
24793
|
+
var reviewDayStatSchema = object({
|
|
24794
|
+
date: string2(),
|
|
24795
|
+
completedTasks: number2().int().nonnegative(),
|
|
24796
|
+
completedOccurrences: number2().int().nonnegative()
|
|
24797
|
+
});
|
|
24798
|
+
var reviewStatsSchema = array(reviewDayStatSchema);
|
|
24799
|
+
|
|
24668
24800
|
// ../../packages/schema/src/contracts/insights.ts
|
|
24669
24801
|
var insightsActivityPointSchema = object({
|
|
24670
24802
|
day: string2(),
|
|
@@ -25976,10 +26108,16 @@ var moneyTransactionViewSchema = moneyTransactionSchema.omit({ dedupHash: true }
|
|
|
25976
26108
|
nodeId: ulidSchema,
|
|
25977
26109
|
kind: moneyLinkKindSchema,
|
|
25978
26110
|
title: string2(),
|
|
25979
|
-
type: string2()
|
|
26111
|
+
type: string2(),
|
|
26112
|
+
warrantyEnds: keyDateDaySchema.nullable().default(null)
|
|
25980
26113
|
})).default([]),
|
|
25981
26114
|
recurring: string2().nullable().default(null),
|
|
25982
|
-
contact: object({
|
|
26115
|
+
contact: object({
|
|
26116
|
+
id: ulidSchema,
|
|
26117
|
+
name: string2(),
|
|
26118
|
+
kind: _enum2(["person", "organization"]).default("person"),
|
|
26119
|
+
payments: number2().int().nonnegative()
|
|
26120
|
+
}).nullable().default(null),
|
|
25983
26121
|
split: object({
|
|
25984
26122
|
parts: number2().int().positive(),
|
|
25985
26123
|
even: boolean3(),
|
|
@@ -27249,6 +27387,51 @@ var steamSyncResultSchema = object({
|
|
|
27249
27387
|
games: array(steamGameSyncSchema)
|
|
27250
27388
|
});
|
|
27251
27389
|
|
|
27390
|
+
// ../../packages/schema/src/contracts/money-net-worth.ts
|
|
27391
|
+
var amount5 = string2();
|
|
27392
|
+
var moneySnapshotSourceSchema = _enum2(moneySnapshotSource.enumValues);
|
|
27393
|
+
var moneyNetWorthQuerySchema = object({
|
|
27394
|
+
scope: moneyBudgetScopeSchema.optional(),
|
|
27395
|
+
months: exports_coerce.number().int().min(2).max(60).optional()
|
|
27396
|
+
});
|
|
27397
|
+
var moneyNetWorthPointSchema = object({
|
|
27398
|
+
month: moneyMonthSchema,
|
|
27399
|
+
total: amount5.nullable(),
|
|
27400
|
+
have: amount5.nullable(),
|
|
27401
|
+
owe: amount5.nullable()
|
|
27402
|
+
});
|
|
27403
|
+
var moneyNetWorthAccountSchema = object({
|
|
27404
|
+
accountId: ulidSchema,
|
|
27405
|
+
title: string2(),
|
|
27406
|
+
kind: moneyAccountKindSchema,
|
|
27407
|
+
visibility: _enum2(NODE_VISIBILITY_VALUES),
|
|
27408
|
+
currency: string2(),
|
|
27409
|
+
value: amount5,
|
|
27410
|
+
source: moneySnapshotSourceSchema,
|
|
27411
|
+
month: moneyMonthSchema
|
|
27412
|
+
});
|
|
27413
|
+
var moneyNetWorthSchema = object({
|
|
27414
|
+
scope: moneyBudgetScopeSchema,
|
|
27415
|
+
month: moneyMonthSchema,
|
|
27416
|
+
total: amount5,
|
|
27417
|
+
have: amount5,
|
|
27418
|
+
owe: amount5,
|
|
27419
|
+
points: array(moneyNetWorthPointSchema),
|
|
27420
|
+
accounts: array(moneyNetWorthAccountSchema)
|
|
27421
|
+
});
|
|
27422
|
+
var setMoneyNetWorthValueInputSchema = object({
|
|
27423
|
+
accountId: ulidSchema,
|
|
27424
|
+
value: moneyAmountSchema,
|
|
27425
|
+
month: moneyMonthSchema.optional()
|
|
27426
|
+
}).strict();
|
|
27427
|
+
var moneySnapshotSchema = object({
|
|
27428
|
+
id: ulidSchema,
|
|
27429
|
+
accountId: ulidSchema,
|
|
27430
|
+
month: moneyMonthSchema,
|
|
27431
|
+
value: amount5,
|
|
27432
|
+
source: moneySnapshotSourceSchema
|
|
27433
|
+
});
|
|
27434
|
+
|
|
27252
27435
|
// ../../packages/schema/src/contracts/money-splits.ts
|
|
27253
27436
|
var moneyPartySchema = union([
|
|
27254
27437
|
object({ userId: ulidSchema }).strict(),
|
|
@@ -27990,7 +28173,8 @@ var GUEST_EXPORT_KINDS = [
|
|
|
27990
28173
|
"floor-plan",
|
|
27991
28174
|
"church",
|
|
27992
28175
|
"answers",
|
|
27993
|
-
"invitations"
|
|
28176
|
+
"invitations",
|
|
28177
|
+
"printer"
|
|
27994
28178
|
];
|
|
27995
28179
|
var guestExportKindSchema = _enum2(GUEST_EXPORT_KINDS);
|
|
27996
28180
|
var thankYouGiftSchema = object({
|
|
@@ -28576,6 +28760,209 @@ function scopeGranted(granted, required) {
|
|
|
28576
28760
|
return granted.includes(FULL_ACCESS_SCOPE);
|
|
28577
28761
|
}
|
|
28578
28762
|
|
|
28763
|
+
// ../../packages/schema/src/net/ssrf.ts
|
|
28764
|
+
var BLOCKED_HOST_SUFFIXES = [".internal", ".local", ".localhost"];
|
|
28765
|
+
var BLOCKED_HOSTNAMES = new Set(["localhost"]);
|
|
28766
|
+
function parseIpv4(host) {
|
|
28767
|
+
const parts = host.split(".");
|
|
28768
|
+
if (parts.length !== 4)
|
|
28769
|
+
return null;
|
|
28770
|
+
let value = 0;
|
|
28771
|
+
for (const part of parts) {
|
|
28772
|
+
if (!/^\d{1,3}$/.test(part))
|
|
28773
|
+
return null;
|
|
28774
|
+
const octet = Number(part);
|
|
28775
|
+
if (octet > 255)
|
|
28776
|
+
return null;
|
|
28777
|
+
value = value * 256 + octet;
|
|
28778
|
+
}
|
|
28779
|
+
return value >>> 0;
|
|
28780
|
+
}
|
|
28781
|
+
function isBlockedIpv4(ip) {
|
|
28782
|
+
const inRange = (base, bits) => {
|
|
28783
|
+
const baseIp = parseIpv4(base);
|
|
28784
|
+
if (baseIp === null)
|
|
28785
|
+
return false;
|
|
28786
|
+
const mask = bits === 0 ? 0 : 4294967295 << 32 - bits >>> 0;
|
|
28787
|
+
return (ip & mask) === (baseIp & mask);
|
|
28788
|
+
};
|
|
28789
|
+
return inRange("0.0.0.0", 8) || inRange("10.0.0.0", 8) || inRange("100.64.0.0", 10) || inRange("127.0.0.0", 8) || inRange("169.254.0.0", 16) || inRange("172.16.0.0", 12) || inRange("192.0.0.0", 24) || inRange("192.0.2.0", 24) || inRange("192.168.0.0", 16) || inRange("198.18.0.0", 15) || inRange("224.0.0.0", 4) || inRange("240.0.0.0", 4);
|
|
28790
|
+
}
|
|
28791
|
+
function parseIpv6(host) {
|
|
28792
|
+
let text = host;
|
|
28793
|
+
const zone = text.indexOf("%");
|
|
28794
|
+
if (zone !== -1)
|
|
28795
|
+
text = text.slice(0, zone);
|
|
28796
|
+
if (!text.includes(":"))
|
|
28797
|
+
return null;
|
|
28798
|
+
const lastColon = text.lastIndexOf(":");
|
|
28799
|
+
const tail = text.slice(lastColon + 1);
|
|
28800
|
+
if (tail.includes(".")) {
|
|
28801
|
+
const v4 = parseIpv4(tail);
|
|
28802
|
+
if (v4 === null)
|
|
28803
|
+
return null;
|
|
28804
|
+
const hex = `${(v4 >>> 16 & 65535).toString(16)}:${(v4 & 65535).toString(16)}`;
|
|
28805
|
+
text = text.slice(0, lastColon + 1) + hex;
|
|
28806
|
+
}
|
|
28807
|
+
const halves = text.split("::");
|
|
28808
|
+
if (halves.length > 2)
|
|
28809
|
+
return null;
|
|
28810
|
+
const toGroups = (segment) => {
|
|
28811
|
+
if (segment === "")
|
|
28812
|
+
return [];
|
|
28813
|
+
const out = [];
|
|
28814
|
+
for (const g of segment.split(":")) {
|
|
28815
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(g))
|
|
28816
|
+
return null;
|
|
28817
|
+
out.push(Number.parseInt(g, 16));
|
|
28818
|
+
}
|
|
28819
|
+
return out;
|
|
28820
|
+
};
|
|
28821
|
+
const head = toGroups(halves[0] ?? "");
|
|
28822
|
+
if (head === null)
|
|
28823
|
+
return null;
|
|
28824
|
+
let groups;
|
|
28825
|
+
if (halves.length === 2) {
|
|
28826
|
+
const back = toGroups(halves[1] ?? "");
|
|
28827
|
+
if (back === null)
|
|
28828
|
+
return null;
|
|
28829
|
+
const fill = 8 - head.length - back.length;
|
|
28830
|
+
if (fill < 0)
|
|
28831
|
+
return null;
|
|
28832
|
+
groups = [...head, ...Array(fill).fill(0), ...back];
|
|
28833
|
+
} else {
|
|
28834
|
+
groups = head;
|
|
28835
|
+
}
|
|
28836
|
+
return groups.length === 8 ? groups : null;
|
|
28837
|
+
}
|
|
28838
|
+
function isBlockedIpv6(groups) {
|
|
28839
|
+
const isZero = groups.every((g) => g === 0);
|
|
28840
|
+
if (isZero)
|
|
28841
|
+
return true;
|
|
28842
|
+
if (groups.slice(0, 7).every((g) => g === 0) && groups[7] === 1)
|
|
28843
|
+
return true;
|
|
28844
|
+
const isV4Mapped = groups.slice(0, 5).every((g) => g === 0) && groups[5] === 65535;
|
|
28845
|
+
const isV4Compat = groups.slice(0, 6).every((g) => g === 0);
|
|
28846
|
+
if (isV4Mapped || isV4Compat) {
|
|
28847
|
+
const v4 = ((groups[6] ?? 0) << 16 | (groups[7] ?? 0)) >>> 0;
|
|
28848
|
+
return isBlockedIpv4(v4);
|
|
28849
|
+
}
|
|
28850
|
+
const first = groups[0] ?? 0;
|
|
28851
|
+
if ((first & 65024) === 64512)
|
|
28852
|
+
return true;
|
|
28853
|
+
if ((first & 65472) === 65152)
|
|
28854
|
+
return true;
|
|
28855
|
+
if ((first & 65280) === 65280)
|
|
28856
|
+
return true;
|
|
28857
|
+
return false;
|
|
28858
|
+
}
|
|
28859
|
+
function isBlockedIp(host) {
|
|
28860
|
+
const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
28861
|
+
const v4 = parseIpv4(bare);
|
|
28862
|
+
if (v4 !== null)
|
|
28863
|
+
return isBlockedIpv4(v4);
|
|
28864
|
+
const v6 = parseIpv6(bare);
|
|
28865
|
+
if (v6 !== null)
|
|
28866
|
+
return isBlockedIpv6(v6);
|
|
28867
|
+
return false;
|
|
28868
|
+
}
|
|
28869
|
+
|
|
28870
|
+
class BlockedWebhookUrlError extends Error {
|
|
28871
|
+
constructor(reason) {
|
|
28872
|
+
super(`webhook url rejected: ${reason}`);
|
|
28873
|
+
this.name = "BlockedWebhookUrlError";
|
|
28874
|
+
}
|
|
28875
|
+
}
|
|
28876
|
+
function bareHost(hostname) {
|
|
28877
|
+
return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
|
|
28878
|
+
}
|
|
28879
|
+
function isInternalHost(hostname) {
|
|
28880
|
+
const host = hostname.toLowerCase();
|
|
28881
|
+
if (BLOCKED_HOSTNAMES.has(host) || BLOCKED_HOST_SUFFIXES.some((s) => host.endsWith(s))) {
|
|
28882
|
+
return true;
|
|
28883
|
+
}
|
|
28884
|
+
return isBlockedIp(host);
|
|
28885
|
+
}
|
|
28886
|
+
function assertSafeEgressUrl(rawUrl, policy) {
|
|
28887
|
+
let url;
|
|
28888
|
+
try {
|
|
28889
|
+
url = new URL(rawUrl);
|
|
28890
|
+
} catch {
|
|
28891
|
+
throw policy.fail("not a valid URL");
|
|
28892
|
+
}
|
|
28893
|
+
if (!policy.protocols.includes(url.protocol)) {
|
|
28894
|
+
const allowsHttp = policy.protocols.includes("http:");
|
|
28895
|
+
throw policy.fail(`only ${allowsHttp ? "http(s)" : "https"} URLs are allowed`);
|
|
28896
|
+
}
|
|
28897
|
+
if (url.username || url.password) {
|
|
28898
|
+
throw policy.fail("credentials in the URL are not allowed");
|
|
28899
|
+
}
|
|
28900
|
+
if (isInternalHost(url.hostname)) {
|
|
28901
|
+
const kind = isBlockedIp(url.hostname) ? "a private or reserved address" : "internal";
|
|
28902
|
+
throw policy.fail(`host '${url.hostname}' is ${kind}`);
|
|
28903
|
+
}
|
|
28904
|
+
return url;
|
|
28905
|
+
}
|
|
28906
|
+
function webhookUrlAllowlistFromEnv() {
|
|
28907
|
+
const env = globalThis.process?.env;
|
|
28908
|
+
const raw = env?.WEBHOOK_URL_ALLOWLIST;
|
|
28909
|
+
if (!raw)
|
|
28910
|
+
return [];
|
|
28911
|
+
return raw.split(",").map((h) => h.trim().toLowerCase()).filter(Boolean);
|
|
28912
|
+
}
|
|
28913
|
+
function isAllowlistedHost(hostname, allowedHosts) {
|
|
28914
|
+
const host = hostname.toLowerCase();
|
|
28915
|
+
const bare = bareHost(host);
|
|
28916
|
+
return allowedHosts.some((h) => h === host || h === bare);
|
|
28917
|
+
}
|
|
28918
|
+
function assertSafeWebhookUrl(rawUrl, opts = {}) {
|
|
28919
|
+
let url;
|
|
28920
|
+
try {
|
|
28921
|
+
url = new URL(rawUrl);
|
|
28922
|
+
} catch {
|
|
28923
|
+
throw new BlockedWebhookUrlError("not a valid URL");
|
|
28924
|
+
}
|
|
28925
|
+
const allowedHosts = opts.allowedHosts ?? webhookUrlAllowlistFromEnv();
|
|
28926
|
+
if (isAllowlistedHost(url.hostname, allowedHosts)) {
|
|
28927
|
+
return url;
|
|
28928
|
+
}
|
|
28929
|
+
return assertSafeEgressUrl(rawUrl, {
|
|
28930
|
+
protocols: ["https:"],
|
|
28931
|
+
fail: (reason) => new BlockedWebhookUrlError(reason)
|
|
28932
|
+
});
|
|
28933
|
+
}
|
|
28934
|
+
|
|
28935
|
+
// ../../packages/schema/src/contracts/webhooks.ts
|
|
28936
|
+
var webhookUrlSchema = string2().superRefine((value, ctx) => {
|
|
28937
|
+
try {
|
|
28938
|
+
assertSafeWebhookUrl(value);
|
|
28939
|
+
} catch (err) {
|
|
28940
|
+
ctx.addIssue({
|
|
28941
|
+
code: ZodIssueCode.custom,
|
|
28942
|
+
message: err instanceof BlockedWebhookUrlError ? err.message : "invalid webhook url"
|
|
28943
|
+
});
|
|
28944
|
+
}
|
|
28945
|
+
});
|
|
28946
|
+
var webhookEventSchema = string2().min(1).max(120).regex(/^[a-z0-9]+(\.[a-z0-9]+)+$/, "must be a dotted event name like 'task.created'");
|
|
28947
|
+
var webhookSubscriptionSchema = createSelectSchema(webhookSubscriptions, {
|
|
28948
|
+
events: array(webhookEventSchema),
|
|
28949
|
+
createdAt: exports_coerce.date(),
|
|
28950
|
+
updatedAt: exports_coerce.date()
|
|
28951
|
+
});
|
|
28952
|
+
var webhookSubscriptionPublicSchema = webhookSubscriptionSchema.omit({ secret: true });
|
|
28953
|
+
var createWebhookSubscriptionInputSchema = createInsertSchema(webhookSubscriptions, {
|
|
28954
|
+
url: webhookUrlSchema,
|
|
28955
|
+
events: array(webhookEventSchema).min(1),
|
|
28956
|
+
secret: string2().min(16).max(200).optional()
|
|
28957
|
+
}).omit({ id: true, tenantId: true, active: true, createdAt: true, updatedAt: true }).strict();
|
|
28958
|
+
var createWebhookSubscriptionResultSchema = webhookSubscriptionPublicSchema.extend({
|
|
28959
|
+
secret: string2()
|
|
28960
|
+
});
|
|
28961
|
+
var updateWebhookSubscriptionInputSchema = createUpdateSchema(webhookSubscriptions, {
|
|
28962
|
+
url: webhookUrlSchema.optional(),
|
|
28963
|
+
events: array(webhookEventSchema).min(1).optional()
|
|
28964
|
+
}).omit({ id: true, tenantId: true, secret: true, createdAt: true, updatedAt: true }).strict();
|
|
28965
|
+
|
|
28579
28966
|
// ../../packages/schema/src/contracts/roles.ts
|
|
28580
28967
|
var permissionSetSchema = createSelectSchema(permissionSets, {
|
|
28581
28968
|
createdAt: exports_coerce.date(),
|
|
@@ -29624,6 +30011,37 @@ function toCollectionTypeSummary(config) {
|
|
|
29624
30011
|
}
|
|
29625
30012
|
var COLLECTION_TYPE_SUMMARIES = COLLECTION_TYPE_LIST.map(toCollectionTypeSummary);
|
|
29626
30013
|
|
|
30014
|
+
// ../../packages/schema/src/operations/define.ts
|
|
30015
|
+
function defineOperations(table) {
|
|
30016
|
+
return table;
|
|
30017
|
+
}
|
|
30018
|
+
var PUBLIC_API_PREFIX = "/api/v1";
|
|
30019
|
+
function pathOf(op, params = {}) {
|
|
30020
|
+
return op.path.replace(/\{([A-Za-z0-9_]+)\}/g, (_, name) => {
|
|
30021
|
+
const value = params[name];
|
|
30022
|
+
if (value === undefined)
|
|
30023
|
+
throw new Error(`pathOf: no value for {${name}} in ${op.path}`);
|
|
30024
|
+
return encodeURIComponent(value);
|
|
30025
|
+
});
|
|
30026
|
+
}
|
|
30027
|
+
function routeOf(op) {
|
|
30028
|
+
return `${op.method.toUpperCase()} ${PUBLIC_API_PREFIX}${op.path}`;
|
|
30029
|
+
}
|
|
30030
|
+
|
|
30031
|
+
// ../../packages/schema/src/operations/agents.ts
|
|
30032
|
+
var agentOperations = defineOperations({
|
|
30033
|
+
list: {
|
|
30034
|
+
method: "get",
|
|
30035
|
+
path: "/agents",
|
|
30036
|
+
scopes: ["agents:read"],
|
|
30037
|
+
tag: "Agents",
|
|
30038
|
+
summary: "List agents",
|
|
30039
|
+
description: "The Space's live Agents (`id`, `name`), oldest first, to resolve an Agent by name.",
|
|
30040
|
+
status: 200,
|
|
30041
|
+
response: { description: "The Space's Agents.", list: true }
|
|
30042
|
+
}
|
|
30043
|
+
});
|
|
30044
|
+
|
|
29627
30045
|
// ../../packages/schema/src/operations/crud.ts
|
|
29628
30046
|
function crudOperations(r) {
|
|
29629
30047
|
const base = `/${r.segment}`;
|
|
@@ -29695,22 +30113,520 @@ function crudOperations(r) {
|
|
|
29695
30113
|
};
|
|
29696
30114
|
}
|
|
29697
30115
|
|
|
29698
|
-
// ../../packages/schema/src/operations/
|
|
29699
|
-
|
|
29700
|
-
|
|
29701
|
-
|
|
29702
|
-
|
|
29703
|
-
|
|
29704
|
-
|
|
29705
|
-
|
|
29706
|
-
|
|
29707
|
-
|
|
29708
|
-
|
|
29709
|
-
|
|
29710
|
-
|
|
29711
|
-
|
|
29712
|
-
|
|
29713
|
-
}
|
|
30116
|
+
// ../../packages/schema/src/operations/block-templates.ts
|
|
30117
|
+
var crud = crudOperations({
|
|
30118
|
+
segment: "block-templates",
|
|
30119
|
+
tag: "Calendar",
|
|
30120
|
+
noun: "block template",
|
|
30121
|
+
read: "calendar:read",
|
|
30122
|
+
write: "calendar:write",
|
|
30123
|
+
create: createBlockTemplateInputSchema,
|
|
30124
|
+
update: updateBlockTemplateInputSchema,
|
|
30125
|
+
listQuery: []
|
|
30126
|
+
});
|
|
30127
|
+
var blockTemplateOperations = defineOperations({
|
|
30128
|
+
...crud,
|
|
30129
|
+
create: { ...crud.create, webhook: undefined },
|
|
30130
|
+
update: { ...crud.update, webhook: undefined },
|
|
30131
|
+
remove: { ...crud.remove, webhook: undefined },
|
|
30132
|
+
week: {
|
|
30133
|
+
method: "get",
|
|
30134
|
+
path: "/block-templates/week",
|
|
30135
|
+
scopes: ["calendar:read"],
|
|
30136
|
+
tag: "Calendar",
|
|
30137
|
+
summary: "Lay out a week from the block templates",
|
|
30138
|
+
description: "Every life block the key's member's templates lay out for the week starting `start` (a Monday), in time order, on their wall clock: `{ templateId, lifeKind, title, startAt, endAt, routineId }`. Writes nothing; this is what Sunday planning proposes.",
|
|
30139
|
+
query: [{ name: "start", description: "The week's Monday (YYYY-MM-DD).", format: "date" }],
|
|
30140
|
+
querySchema: blockTemplateWeekQuerySchema,
|
|
30141
|
+
status: 200,
|
|
30142
|
+
response: { description: "The week's blocks." },
|
|
30143
|
+
errors: { 400: true }
|
|
30144
|
+
},
|
|
30145
|
+
defaults: {
|
|
30146
|
+
method: "post",
|
|
30147
|
+
path: "/block-templates/defaults",
|
|
30148
|
+
scopes: ["calendar:write"],
|
|
30149
|
+
tag: "Calendar",
|
|
30150
|
+
summary: "Seed the default week",
|
|
30151
|
+
description: "Give a member with no block templates the default week: sleep, the morning, reading, two work blocks, lunch and dinner with clean-up, a buffer, a free evening and a wind-down. A member who has templates keeps them; the call then returns them unchanged.",
|
|
30152
|
+
status: 200,
|
|
30153
|
+
response: { description: "The member's templates." }
|
|
30154
|
+
}
|
|
30155
|
+
});
|
|
30156
|
+
|
|
30157
|
+
// ../../packages/schema/src/operations/collection-upkeep.ts
|
|
30158
|
+
var collectionUpkeepOperations = defineOperations({
|
|
30159
|
+
list: {
|
|
30160
|
+
method: "get",
|
|
30161
|
+
path: "/collection/{id}/upkeep",
|
|
30162
|
+
scopes: ["collections:read"],
|
|
30163
|
+
tag: "Collection",
|
|
30164
|
+
summary: "List an asset's upkeep and repairs",
|
|
30165
|
+
description: "The Tasks that look after this asset: `upkeep` (`maintains` \u2014 usually recurring, e.g. every 4 weeks from the last time) and `repairs` (one-off fix-it Tasks), open ones first. 404 unless the item is a live `asset`. Returns `{ itemId, upkeep, repairs }`.",
|
|
30166
|
+
status: 200,
|
|
30167
|
+
response: { description: "The asset's Tasks." },
|
|
30168
|
+
errors: { 404: true }
|
|
30169
|
+
},
|
|
30170
|
+
link: {
|
|
30171
|
+
method: "post",
|
|
30172
|
+
path: "/collection/{id}/upkeep",
|
|
30173
|
+
scopes: ["collections:write"],
|
|
30174
|
+
tag: "Collection",
|
|
30175
|
+
summary: "Tie a Task to an asset",
|
|
30176
|
+
description: 'Tie a Task in the Space to this asset as its upkeep (`kind: "maintains"`, the default) or a repair (`"repairs"`). Make the Task (its recurrence, Place, Area) through the tasks API first. When a tied Task is finished \u2014 a one-off marked done, or one occurrence of a recurring one checked off \u2014 the asset gets a `service` / `repair` Entry with the Task on it, once per day, and upkeep moves its `lastServicedAt` forward. Returns the asset\'s Tasks.',
|
|
30177
|
+
body: linkAssetTaskInputSchema,
|
|
30178
|
+
status: 201,
|
|
30179
|
+
response: { description: "The asset's Tasks." },
|
|
30180
|
+
errors: { 400: true, 404: true }
|
|
30181
|
+
},
|
|
30182
|
+
unlink: {
|
|
30183
|
+
method: "delete",
|
|
30184
|
+
path: "/collection/{id}/upkeep/{taskId}",
|
|
30185
|
+
pathParams: { taskId: "The Task's ULID." },
|
|
30186
|
+
scopes: ["collections:write"],
|
|
30187
|
+
tag: "Collection",
|
|
30188
|
+
summary: "Untie a Task from an asset",
|
|
30189
|
+
description: "Untie the Task from this asset; the Task itself stays. Returns the asset's Tasks.",
|
|
30190
|
+
status: 200,
|
|
30191
|
+
response: { description: "The asset's Tasks." },
|
|
30192
|
+
errors: { 404: true }
|
|
30193
|
+
}
|
|
30194
|
+
});
|
|
30195
|
+
|
|
30196
|
+
// ../../packages/schema/src/operations/google-contacts.ts
|
|
30197
|
+
var googleContactsOperations = defineOperations({
|
|
30198
|
+
list: {
|
|
30199
|
+
method: "get",
|
|
30200
|
+
path: "/people/google-contacts",
|
|
30201
|
+
scopes: ["contacts:read"],
|
|
30202
|
+
tag: "People",
|
|
30203
|
+
summary: "Your Google Contacts, to pick from",
|
|
30204
|
+
description: "The key's member's Google Contacts link (`status`: `available`, `mode`, `connected`, `account`) and the people in it matching `q` (a name or an email; everyone without), each with `resourceName`, `name`, `emails`, `phones`, `birthday` (`yearKnown: false` for a day and month only), the contact in do they'd merge into (`match`: by `email`, `phone` or a unique `name`; never a company) and what importing adds (`adds`). Not connected: no candidates. Connecting needs a browser (People \u2192 Import). A key with no member is a 403. Off until `GOOGLE_CONTACTS_API` is `fake` or `live`.",
|
|
30205
|
+
query: [{ name: "q", description: "A name or email to narrow to." }],
|
|
30206
|
+
querySchema: googleContactsQuerySchema,
|
|
30207
|
+
status: 200,
|
|
30208
|
+
response: { description: "The link and the candidates." },
|
|
30209
|
+
errors: { 403: "Not a member's key." }
|
|
30210
|
+
},
|
|
30211
|
+
import: {
|
|
30212
|
+
method: "post",
|
|
30213
|
+
path: "/people/google-contacts/import",
|
|
30214
|
+
scopes: ["contacts:write"],
|
|
30215
|
+
tag: "People",
|
|
30216
|
+
summary: "Import the people you picked from Google Contacts",
|
|
30217
|
+
description: "Only the picked people (`resourceNames`, Google's `people/\u2026` ids, at most 200). Each merges into the contact it matches and fills in only a missing email, phone or birthday (a key date that becomes a Task), else becomes a new contact, so importing twice never duplicates anyone. Returns `{ created, merged (with what each got: added), missing }`. Not connected is a 409; off until `GOOGLE_CONTACTS_API` is set (403).",
|
|
30218
|
+
body: importGoogleContactsInputSchema,
|
|
30219
|
+
status: 200,
|
|
30220
|
+
response: { description: "What the import did." },
|
|
30221
|
+
errors: {
|
|
30222
|
+
400: true,
|
|
30223
|
+
403: "Off, or not a member's key.",
|
|
30224
|
+
409: "Google Contacts isn't connected (or asks to sign in again)."
|
|
30225
|
+
}
|
|
30226
|
+
}
|
|
30227
|
+
});
|
|
30228
|
+
|
|
30229
|
+
// ../../packages/schema/src/operations/google-health.ts
|
|
30230
|
+
var googleHealthOperations = defineOperations({
|
|
30231
|
+
status: {
|
|
30232
|
+
method: "get",
|
|
30233
|
+
path: "/health/google-health",
|
|
30234
|
+
scopes: ["health:read"],
|
|
30235
|
+
tag: "Health",
|
|
30236
|
+
summary: "Get the Google Health link",
|
|
30237
|
+
description: "The key's member's Google Health link (connected in the app, Settings \u2192 Health): `available` and `mode` (off \xB7 fake \xB7 live, the server's switch), `connected`, the Google `account`, `lastSyncAt` and each resource's (sleep, resting_heart_rate, hrv, steps, workouts), and `failure` (`reauth` \xB7 `not_linked` \xB7 `unavailable` \xB7 `other`, with a title and a hint) when the sync stopped, and `nutrition` (writing the member's food back to Google Health, opt-in in the app: `enabled`, `granted` (the link has the write scope), `lastWrittenDay`, `failure`). Never another member's.",
|
|
30238
|
+
status: 200,
|
|
30239
|
+
response: { description: "The link's status." },
|
|
30240
|
+
errors: { 403: true }
|
|
30241
|
+
},
|
|
30242
|
+
sync: {
|
|
30243
|
+
method: "post",
|
|
30244
|
+
path: "/health/google-health/sync",
|
|
30245
|
+
scopes: ["health:write"],
|
|
30246
|
+
tag: "Health",
|
|
30247
|
+
summary: "Sync Google Health now",
|
|
30248
|
+
description: "As the key's member, one sync of their Google Health, as the 07:30 morning sync does: last night's sleep (on the wake day, joining the Sleep and Bedtime Metrics), the day's resting heart rate and HRV, steps and workouts (joining the sessions) onto their own ledger, nothing twice. Returns written and skipped per resource and the status after it; a sync that stops answers 200 with `status.failure`. 409 before the member connected, 403 while the server has Google Health off.",
|
|
30249
|
+
status: 200,
|
|
30250
|
+
response: { description: "What came in, and the status after it." },
|
|
30251
|
+
errors: { 403: true, 409: true }
|
|
30252
|
+
}
|
|
30253
|
+
});
|
|
30254
|
+
|
|
30255
|
+
// ../../packages/schema/src/operations/guest-list-events.ts
|
|
30256
|
+
var crud2 = crudOperations({
|
|
30257
|
+
segment: "guest-list-events",
|
|
30258
|
+
tag: "Guests",
|
|
30259
|
+
noun: "guest list event",
|
|
30260
|
+
read: "contacts:read",
|
|
30261
|
+
write: "contacts:write",
|
|
30262
|
+
create: createGuestListEventInputSchema,
|
|
30263
|
+
update: updateGuestListEventInputSchema,
|
|
30264
|
+
listQuery: [{ name: "guestListId", description: "The guest list (required)." }],
|
|
30265
|
+
listQuerySchema: guestListEventsQuerySchema
|
|
30266
|
+
});
|
|
30267
|
+
var guestListEventOperations = defineOperations({
|
|
30268
|
+
...crud2,
|
|
30269
|
+
create: { ...crud2.create, webhook: "guest.event.created" },
|
|
30270
|
+
update: { ...crud2.update, webhook: "guest.event.updated" },
|
|
30271
|
+
remove: { ...crud2.remove, webhook: "guest.event.deleted" }
|
|
30272
|
+
});
|
|
30273
|
+
|
|
30274
|
+
// ../../packages/schema/src/operations/guest-tables.ts
|
|
30275
|
+
var guestTableOperations = defineOperations({
|
|
30276
|
+
...crudOperations({
|
|
30277
|
+
segment: "guest-tables",
|
|
30278
|
+
tag: "Guests",
|
|
30279
|
+
noun: "guest table",
|
|
30280
|
+
read: "contacts:read",
|
|
30281
|
+
write: "contacts:write",
|
|
30282
|
+
create: createGuestTableInputSchema,
|
|
30283
|
+
update: updateGuestTableInputSchema,
|
|
30284
|
+
listQuery: [{ name: "guestListId", description: "The guest list (required)." }],
|
|
30285
|
+
listQuerySchema: guestTablesQuerySchema
|
|
30286
|
+
})
|
|
30287
|
+
});
|
|
30288
|
+
|
|
30289
|
+
// ../../packages/schema/src/operations/guests.ts
|
|
30290
|
+
var guestOperations = defineOperations({
|
|
30291
|
+
...crudOperations({
|
|
30292
|
+
segment: "guests",
|
|
30293
|
+
tag: "Guests",
|
|
30294
|
+
noun: "guest",
|
|
30295
|
+
read: "contacts:read",
|
|
30296
|
+
write: "contacts:write",
|
|
30297
|
+
create: createGuestInputSchema,
|
|
30298
|
+
update: updateGuestInputSchema,
|
|
30299
|
+
listQuery: [
|
|
30300
|
+
{ name: "guestListId", description: "Only this guest list's guests." },
|
|
30301
|
+
{ name: "contactId", description: "Only this contact's guest rows." },
|
|
30302
|
+
{ name: "state", description: "`yes`, `no`, `maybe` or `waiting`: their overall answer." }
|
|
30303
|
+
],
|
|
30304
|
+
listQuerySchema: guestsQuerySchema
|
|
30305
|
+
}),
|
|
30306
|
+
sent: {
|
|
30307
|
+
method: "post",
|
|
30308
|
+
path: "/guests/sent",
|
|
30309
|
+
scopes: ["contacts:write"],
|
|
30310
|
+
tag: "Guests",
|
|
30311
|
+
summary: "Stamp save-the-dates or invitations as sent",
|
|
30312
|
+
description: "Stamps `saveTheDateAt` (`what: save_the_date`) or `inviteSentAt` (`what: invite`) on every guest in `guestIds`, at `at` or now. Returns the guests; fires `guest.sent`.",
|
|
30313
|
+
body: markGuestsSentInputSchema,
|
|
30314
|
+
status: 200,
|
|
30315
|
+
response: { description: "The stamped guests." },
|
|
30316
|
+
errors: { 400: true, 404: true },
|
|
30317
|
+
webhook: "guest.sent"
|
|
30318
|
+
}
|
|
30319
|
+
});
|
|
30320
|
+
|
|
30321
|
+
// ../../packages/schema/src/operations/habits.ts
|
|
30322
|
+
var habitListQuery = habitListQuerySchema.extend(paginationQuerySchema.shape);
|
|
30323
|
+
var habitOperations = defineOperations({
|
|
30324
|
+
list: {
|
|
30325
|
+
method: "get",
|
|
30326
|
+
path: "/habits",
|
|
30327
|
+
scopes: ["habits:read"],
|
|
30328
|
+
tag: "Habits",
|
|
30329
|
+
summary: "List habits",
|
|
30330
|
+
description: "Every growing habit (with streaks) in the Space, oldest first. `retired=true` lists the Grown shelf instead: the retired habits, history kept.",
|
|
30331
|
+
query: [
|
|
30332
|
+
{ name: "areaId", description: "Only rows in this Area (ULID)." },
|
|
30333
|
+
{
|
|
30334
|
+
name: "updatedSince",
|
|
30335
|
+
description: "Only rows whose `updatedAt` is at or after this instant \u2014 an ISO 8601 datetime with offset, or a bare `YYYY-MM-DD` (UTC midnight).",
|
|
30336
|
+
format: "date-time"
|
|
30337
|
+
},
|
|
30338
|
+
{
|
|
30339
|
+
name: "retired",
|
|
30340
|
+
description: "`true` lists the retired (Grown) habits instead of the growing ones.",
|
|
30341
|
+
enum: ["true", "false"]
|
|
30342
|
+
}
|
|
30343
|
+
],
|
|
30344
|
+
querySchema: habitListQuery,
|
|
30345
|
+
paginated: true,
|
|
30346
|
+
status: 200,
|
|
30347
|
+
response: { description: "The Space's habits." }
|
|
30348
|
+
},
|
|
30349
|
+
today: {
|
|
30350
|
+
method: "get",
|
|
30351
|
+
path: "/habits/today",
|
|
30352
|
+
scopes: ["habits:read"],
|
|
30353
|
+
tag: "Habits",
|
|
30354
|
+
summary: "What's left today",
|
|
30355
|
+
description: "\"What's left?\" (#866): the habits due on the key's member's day (their saved time zone), already filtered by schedule, grouped by part of day (morning, midday, evening, anytime). Each says its value today, `done`/`open`/`skipped` (never overdue: habits don't carry over), the week for an N-per-week habit, and its last check-in (`by` names the Agent). Also today's routines with how many steps are done. Quit habits are left out.",
|
|
30356
|
+
status: 200,
|
|
30357
|
+
response: { description: "Today's habits and routines." },
|
|
30358
|
+
operationId: "habits_today"
|
|
30359
|
+
},
|
|
30360
|
+
getAway: {
|
|
30361
|
+
method: "get",
|
|
30362
|
+
path: "/habits/away",
|
|
30363
|
+
scopes: ["habits:read"],
|
|
30364
|
+
tag: "Habits",
|
|
30365
|
+
summary: "Get away state",
|
|
30366
|
+
description: "The Space's \"Away until \u2026\": `{ until }` while away (the day you're back, YYYY-MM-DD), else `{ until: null }`.",
|
|
30367
|
+
status: 200,
|
|
30368
|
+
response: { description: "The away state." }
|
|
30369
|
+
},
|
|
30370
|
+
setAway: {
|
|
30371
|
+
method: "put",
|
|
30372
|
+
path: "/habits/away",
|
|
30373
|
+
scopes: ["habits:write"],
|
|
30374
|
+
tag: "Habits",
|
|
30375
|
+
summary: "Set away",
|
|
30376
|
+
description: '"Away till Monday": every habit rests until `until` (the day you\'re back, after today): off Now, no push, streaks and plants wait. `until: null` comes back now. Tasks and events carry on. Fires `habit.updated`.',
|
|
30377
|
+
body: awayInputSchema,
|
|
30378
|
+
status: 200,
|
|
30379
|
+
response: { description: "The away state." },
|
|
30380
|
+
errors: { 400: true },
|
|
30381
|
+
webhook: "habit.updated"
|
|
30382
|
+
},
|
|
30383
|
+
get: {
|
|
30384
|
+
method: "get",
|
|
30385
|
+
path: "/habits/{id}",
|
|
30386
|
+
scopes: ["habits:read"],
|
|
30387
|
+
tag: "Habits",
|
|
30388
|
+
summary: "Get a habit",
|
|
30389
|
+
description: "One habit with its streak + heatmap.",
|
|
30390
|
+
status: 200,
|
|
30391
|
+
response: { description: "The habit." },
|
|
30392
|
+
errors: { 404: true }
|
|
30393
|
+
},
|
|
30394
|
+
create: {
|
|
30395
|
+
method: "post",
|
|
30396
|
+
path: "/habits",
|
|
30397
|
+
scopes: ["habits:write"],
|
|
30398
|
+
tag: "Habits",
|
|
30399
|
+
summary: "Create a habit",
|
|
30400
|
+
description: "Create a habit; fires `habit.created`.",
|
|
30401
|
+
body: createHabitInputSchema,
|
|
30402
|
+
status: 201,
|
|
30403
|
+
response: { description: "The created habit." },
|
|
30404
|
+
errors: { 400: true },
|
|
30405
|
+
webhook: "habit.created"
|
|
30406
|
+
},
|
|
30407
|
+
update: {
|
|
30408
|
+
method: "patch",
|
|
30409
|
+
path: "/habits/{id}",
|
|
30410
|
+
scopes: ["habits:write"],
|
|
30411
|
+
tag: "Habits",
|
|
30412
|
+
summary: "Update a habit",
|
|
30413
|
+
description: "Patch a habit; fires `habit.updated`.",
|
|
30414
|
+
body: updateHabitInputSchema,
|
|
30415
|
+
status: 200,
|
|
30416
|
+
response: { description: "The updated habit." },
|
|
30417
|
+
errors: {
|
|
30418
|
+
400: true,
|
|
30419
|
+
404: true
|
|
30420
|
+
},
|
|
30421
|
+
webhook: "habit.updated"
|
|
30422
|
+
},
|
|
30423
|
+
remove: {
|
|
30424
|
+
method: "delete",
|
|
30425
|
+
path: "/habits/{id}",
|
|
30426
|
+
scopes: ["habits:write"],
|
|
30427
|
+
tag: "Habits",
|
|
30428
|
+
summary: "Archive a habit",
|
|
30429
|
+
description: "Soft-delete a habit; fires `habit.deleted`.",
|
|
30430
|
+
status: 204,
|
|
30431
|
+
response: { description: "Archived." },
|
|
30432
|
+
errors: { 404: true },
|
|
30433
|
+
webhook: "habit.deleted"
|
|
30434
|
+
},
|
|
30435
|
+
checkInByTitle: {
|
|
30436
|
+
method: "post",
|
|
30437
|
+
path: "/habits/check-in",
|
|
30438
|
+
scopes: ["habits:write"],
|
|
30439
|
+
tag: "Habits",
|
|
30440
|
+
summary: "Check in a habit by title",
|
|
30441
|
+
description: 'Check in the habit whose `title` or one of whose aliases is this (case-insensitive) \u2014 "wake", "did my run", "meditated". `value` defaults to 1. `mode: "add"` (default) logs it on top of the day ("12 pages"); `mode: "set"` makes it the day\'s total ("read 40 total") by writing one entry with the difference, keeping earlier check-ins (amount habits only, else 400). `occurredAt` back-dates it: an instant, or a `YYYY-MM-DD` member\'s day (noon in their zone); `set` works on the member\'s day it lands in. Several matching habits are a 409 with `error.code: "ambiguous_habit"` and `error.details.candidates` (`id`, `title`, `aliases`) to ask which; none is a 404 naming close titles; a habit counted from an ingest (Google Fit, Strava, GitHub) is a 409 \u2014 it checks itself in. An Agent\'s key records an `agent` check-in naming the Agent. `note` puts a short note on the check-in ("drill done, felt heavy" \u2192 `note: "felt heavy"`); a `set` that changes nothing puts it on the day\'s latest check-in. The refreshed habit\'s `lastCheckIn.id` is the entry, for adding a note later. Returns the refreshed habit; fires `habit.updated`.',
|
|
30442
|
+
body: habitCheckInByTitleInputSchema,
|
|
30443
|
+
status: 201,
|
|
30444
|
+
response: { description: "The refreshed habit." },
|
|
30445
|
+
errors: {
|
|
30446
|
+
400: true,
|
|
30447
|
+
404: true,
|
|
30448
|
+
409: "Several habits answer to the title (with the candidates), or it is counted from an ingest."
|
|
30449
|
+
},
|
|
30450
|
+
webhook: "habit.updated"
|
|
30451
|
+
},
|
|
30452
|
+
addAlias: {
|
|
30453
|
+
method: "post",
|
|
30454
|
+
path: "/habits/{id}/aliases",
|
|
30455
|
+
scopes: ["habits:write"],
|
|
30456
|
+
tag: "Habits",
|
|
30457
|
+
summary: "Add a habit alias",
|
|
30458
|
+
description: 'Add another name a check-in by title matches ("wake" for "Wake up by 07:00"); one already there (ignoring case) is a no-op, at most 12. Returns the refreshed habit; fires `habit.updated`.',
|
|
30459
|
+
body: habitAliasInputSchema,
|
|
30460
|
+
status: 201,
|
|
30461
|
+
response: { description: "The refreshed habit." },
|
|
30462
|
+
errors: {
|
|
30463
|
+
400: true,
|
|
30464
|
+
404: true
|
|
30465
|
+
},
|
|
30466
|
+
webhook: "habit.updated"
|
|
30467
|
+
},
|
|
30468
|
+
removeAlias: {
|
|
30469
|
+
method: "delete",
|
|
30470
|
+
path: "/habits/{id}/aliases/{alias}",
|
|
30471
|
+
pathParams: { alias: "The alias to drop (ignoring case)." },
|
|
30472
|
+
scopes: ["habits:write"],
|
|
30473
|
+
tag: "Habits",
|
|
30474
|
+
summary: "Remove a habit alias",
|
|
30475
|
+
description: "Drop an alias; 404 when the habit doesn't have it. Returns the refreshed habit; fires `habit.updated`.",
|
|
30476
|
+
status: 200,
|
|
30477
|
+
response: { description: "The refreshed habit." },
|
|
30478
|
+
errors: { 404: true },
|
|
30479
|
+
webhook: "habit.updated"
|
|
30480
|
+
},
|
|
30481
|
+
listCheckIns: {
|
|
30482
|
+
method: "get",
|
|
30483
|
+
path: "/habits/{id}/check-ins",
|
|
30484
|
+
scopes: ["habits:read"],
|
|
30485
|
+
tag: "Habits",
|
|
30486
|
+
summary: "List a habit's check-ins",
|
|
30487
|
+
description: "A page of the habit's check-ins, newest first; pass the oldest one's `occurredAt` as `before` for the next page.",
|
|
30488
|
+
query: [
|
|
30489
|
+
{ name: "before", description: "Only check-ins before this instant (ISO 8601)." },
|
|
30490
|
+
{ name: "limit", description: "Page size, 1\u2013200 (default 50).", type: "integer" }
|
|
30491
|
+
],
|
|
30492
|
+
querySchema: habitEntriesQuerySchema,
|
|
30493
|
+
status: 200,
|
|
30494
|
+
response: { description: "The check-ins." },
|
|
30495
|
+
errors: { 404: true }
|
|
30496
|
+
},
|
|
30497
|
+
checkIn: {
|
|
30498
|
+
method: "post",
|
|
30499
|
+
path: "/habits/{id}/check-ins",
|
|
30500
|
+
scopes: ["habits:write"],
|
|
30501
|
+
tag: "Habits",
|
|
30502
|
+
summary: "Check in",
|
|
30503
|
+
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.",
|
|
30504
|
+
body: createHabitEntryInputSchema,
|
|
30505
|
+
status: 201,
|
|
30506
|
+
response: { description: "The refreshed habit." },
|
|
30507
|
+
errors: {
|
|
30508
|
+
400: true,
|
|
30509
|
+
404: true
|
|
30510
|
+
},
|
|
30511
|
+
webhook: "habit.updated",
|
|
30512
|
+
operationId: "check_in_habit"
|
|
30513
|
+
},
|
|
30514
|
+
skip: {
|
|
30515
|
+
method: "post",
|
|
30516
|
+
path: "/habits/{id}/skip",
|
|
30517
|
+
scopes: ["habits:write"],
|
|
30518
|
+
tag: "Habits",
|
|
30519
|
+
summary: "Skip a habit",
|
|
30520
|
+
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`.',
|
|
30521
|
+
body: habitSkipInputSchema,
|
|
30522
|
+
status: 201,
|
|
30523
|
+
response: { description: "The refreshed habit." },
|
|
30524
|
+
errors: {
|
|
30525
|
+
400: true,
|
|
30526
|
+
404: true
|
|
30527
|
+
},
|
|
30528
|
+
webhook: "habit.updated"
|
|
30529
|
+
},
|
|
30530
|
+
pause: {
|
|
30531
|
+
method: "post",
|
|
30532
|
+
path: "/habits/{id}/pause",
|
|
30533
|
+
scopes: ["habits:write"],
|
|
30534
|
+
tag: "Habits",
|
|
30535
|
+
summary: "Pause a habit",
|
|
30536
|
+
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`.',
|
|
30537
|
+
body: habitPauseInputSchema,
|
|
30538
|
+
status: 201,
|
|
30539
|
+
response: { description: "The refreshed habit." },
|
|
30540
|
+
errors: {
|
|
30541
|
+
400: true,
|
|
30542
|
+
404: true
|
|
30543
|
+
},
|
|
30544
|
+
webhook: "habit.updated"
|
|
30545
|
+
},
|
|
30546
|
+
resume: {
|
|
30547
|
+
method: "post",
|
|
30548
|
+
path: "/habits/{id}/resume",
|
|
30549
|
+
scopes: ["habits:write"],
|
|
30550
|
+
tag: "Habits",
|
|
30551
|
+
summary: "Resume a habit",
|
|
30552
|
+
description: "End a habit's pause: it's back today. The rest so far stays neutral. Returns the refreshed habit; fires `habit.updated`.",
|
|
30553
|
+
status: 201,
|
|
30554
|
+
response: { description: "The refreshed habit." },
|
|
30555
|
+
errors: { 404: true },
|
|
30556
|
+
webhook: "habit.updated"
|
|
30557
|
+
},
|
|
30558
|
+
retire: {
|
|
30559
|
+
method: "post",
|
|
30560
|
+
path: "/habits/{id}/retire",
|
|
30561
|
+
scopes: ["habits:write"],
|
|
30562
|
+
tag: "Habits",
|
|
30563
|
+
summary: "Retire a habit",
|
|
30564
|
+
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`.',
|
|
30565
|
+
status: 201,
|
|
30566
|
+
response: { description: "The refreshed habit." },
|
|
30567
|
+
errors: { 404: true },
|
|
30568
|
+
webhook: "habit.updated"
|
|
30569
|
+
},
|
|
30570
|
+
unretire: {
|
|
30571
|
+
method: "post",
|
|
30572
|
+
path: "/habits/{id}/unretire",
|
|
30573
|
+
scopes: ["habits:write"],
|
|
30574
|
+
tag: "Habits",
|
|
30575
|
+
summary: "Bring a habit back",
|
|
30576
|
+
description: "Bring a grown (retired) habit back: it's growing again from today, its history intact. Returns the refreshed habit; fires `habit.updated`.",
|
|
30577
|
+
status: 201,
|
|
30578
|
+
response: { description: "The refreshed habit." },
|
|
30579
|
+
errors: { 404: true },
|
|
30580
|
+
webhook: "habit.updated"
|
|
30581
|
+
},
|
|
30582
|
+
updateCheckIn: {
|
|
30583
|
+
method: "patch",
|
|
30584
|
+
path: "/habits/{id}/check-ins/{entryId}",
|
|
30585
|
+
pathParams: { entryId: "The check-in entry's ULID." },
|
|
30586
|
+
scopes: ["habits:write"],
|
|
30587
|
+
tag: "Habits",
|
|
30588
|
+
summary: "Note a check-in",
|
|
30589
|
+
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`.",
|
|
30590
|
+
body: updateHabitEntryInputSchema,
|
|
30591
|
+
status: 200,
|
|
30592
|
+
response: { description: "The check-in, with its note." },
|
|
30593
|
+
errors: {
|
|
30594
|
+
400: true,
|
|
30595
|
+
404: true
|
|
30596
|
+
},
|
|
30597
|
+
webhook: "habit.updated",
|
|
30598
|
+
operationId: "note_habit_check_in"
|
|
30599
|
+
},
|
|
30600
|
+
removeCheckIn: {
|
|
30601
|
+
method: "delete",
|
|
30602
|
+
path: "/habits/{id}/check-ins/{entryId}",
|
|
30603
|
+
pathParams: { entryId: "The check-in entry's ULID." },
|
|
30604
|
+
scopes: ["habits:write"],
|
|
30605
|
+
tag: "Habits",
|
|
30606
|
+
summary: "Undo a check-in",
|
|
30607
|
+
description: "Delete a check-in; fires `habit.updated`.",
|
|
30608
|
+
status: 200,
|
|
30609
|
+
response: { description: "The refreshed habit." },
|
|
30610
|
+
errors: { 404: true },
|
|
30611
|
+
webhook: "habit.updated",
|
|
30612
|
+
operationId: "undo_habit_check_in"
|
|
30613
|
+
}
|
|
30614
|
+
});
|
|
30615
|
+
|
|
30616
|
+
// ../../packages/schema/src/operations/households.ts
|
|
30617
|
+
var householdOperations = defineOperations({
|
|
30618
|
+
...crudOperations({
|
|
30619
|
+
segment: "households",
|
|
30620
|
+
tag: "Guests",
|
|
30621
|
+
noun: "household",
|
|
30622
|
+
read: "contacts:read",
|
|
30623
|
+
write: "contacts:write",
|
|
30624
|
+
create: createHouseholdInputSchema,
|
|
30625
|
+
update: updateHouseholdInputSchema,
|
|
30626
|
+
listQuery: [{ name: "contactId", description: "Only the households this contact is in." }],
|
|
30627
|
+
listQuerySchema: householdsQuerySchema
|
|
30628
|
+
})
|
|
30629
|
+
});
|
|
29714
30630
|
|
|
29715
30631
|
// ../../packages/schema/src/operations/inventory-items.ts
|
|
29716
30632
|
var inventoryItemOperations = defineOperations({
|
|
@@ -29727,6 +30643,75 @@ var inventoryItemOperations = defineOperations({
|
|
|
29727
30643
|
})
|
|
29728
30644
|
});
|
|
29729
30645
|
|
|
30646
|
+
// ../../packages/schema/src/operations/mail-campaigns.ts
|
|
30647
|
+
var pathParams = { id: "The campaign's ULID." };
|
|
30648
|
+
var mailCampaignOperations = defineOperations({
|
|
30649
|
+
list: {
|
|
30650
|
+
method: "get",
|
|
30651
|
+
path: "/mail-campaigns",
|
|
30652
|
+
scopes: ["contacts:read"],
|
|
30653
|
+
tag: "Guests",
|
|
30654
|
+
summary: "List a guest list's mail campaigns",
|
|
30655
|
+
description: "Its drafted and sent mails, newest first.",
|
|
30656
|
+
query: [{ name: "guestListId", description: "The guest list (required)." }],
|
|
30657
|
+
querySchema: mailCampaignsQuerySchema,
|
|
30658
|
+
status: 200,
|
|
30659
|
+
response: { description: "The campaigns." },
|
|
30660
|
+
errors: { 400: true }
|
|
30661
|
+
},
|
|
30662
|
+
create: {
|
|
30663
|
+
method: "post",
|
|
30664
|
+
path: "/mail-campaigns",
|
|
30665
|
+
scopes: ["contacts:write"],
|
|
30666
|
+
tag: "Guests",
|
|
30667
|
+
summary: "Draft a mail campaign",
|
|
30668
|
+
description: "A draft for a guest list's households: its `kind` (`message`, `save_the_date` or `invitation`), the template's `data` (the copy per language, Dutch required) and an optional reply address. A key can draft, preview and edit, never test or send: only a member's own session sends.",
|
|
30669
|
+
body: createMailCampaignInputSchema,
|
|
30670
|
+
status: 201,
|
|
30671
|
+
response: { description: "The draft." },
|
|
30672
|
+
errors: { 400: true, 404: true }
|
|
30673
|
+
},
|
|
30674
|
+
get: {
|
|
30675
|
+
method: "get",
|
|
30676
|
+
path: "/mail-campaigns/{id}",
|
|
30677
|
+
pathParams,
|
|
30678
|
+
scopes: ["contacts:read"],
|
|
30679
|
+
tag: "Guests",
|
|
30680
|
+
summary: "Get a mail campaign",
|
|
30681
|
+
description: "",
|
|
30682
|
+
status: 200,
|
|
30683
|
+
response: { description: "The campaign." },
|
|
30684
|
+
errors: { 404: true }
|
|
30685
|
+
},
|
|
30686
|
+
update: {
|
|
30687
|
+
method: "patch",
|
|
30688
|
+
path: "/mail-campaigns/{id}",
|
|
30689
|
+
pathParams,
|
|
30690
|
+
scopes: ["contacts:write"],
|
|
30691
|
+
tag: "Guests",
|
|
30692
|
+
summary: "Edit a draft",
|
|
30693
|
+
description: "Change its kind, data or reply address. Any edit makes the last test stale: a new test is needed before it can be sent.",
|
|
30694
|
+
body: updateMailCampaignInputSchema,
|
|
30695
|
+
status: 200,
|
|
30696
|
+
response: { description: "The draft." },
|
|
30697
|
+
errors: { 400: true, 404: true }
|
|
30698
|
+
},
|
|
30699
|
+
preview: {
|
|
30700
|
+
method: "get",
|
|
30701
|
+
path: "/mail-campaigns/{id}/preview",
|
|
30702
|
+
pathParams,
|
|
30703
|
+
scopes: ["contacts:read"],
|
|
30704
|
+
tag: "Guests",
|
|
30705
|
+
summary: "Preview a mail campaign",
|
|
30706
|
+
description: "The mail as a household would get it in one language (`nl` by default, or `pt`): its subject and rendered body.",
|
|
30707
|
+
query: [{ name: "language", description: "`nl` (default) or `pt`." }],
|
|
30708
|
+
querySchema: mailPreviewQuerySchema,
|
|
30709
|
+
status: 200,
|
|
30710
|
+
response: { description: "The rendered mail." },
|
|
30711
|
+
errors: { 400: true, 404: true }
|
|
30712
|
+
}
|
|
30713
|
+
});
|
|
30714
|
+
|
|
29730
30715
|
// ../../packages/schema/src/operations/meal-plans.ts
|
|
29731
30716
|
var mealPlanOperations = defineOperations({
|
|
29732
30717
|
...crudOperations({
|
|
@@ -29740,6 +30725,48 @@ var mealPlanOperations = defineOperations({
|
|
|
29740
30725
|
})
|
|
29741
30726
|
});
|
|
29742
30727
|
|
|
30728
|
+
// ../../packages/schema/src/operations/occurrences.ts
|
|
30729
|
+
var occurrenceOperations = defineOperations({
|
|
30730
|
+
list: {
|
|
30731
|
+
method: "get",
|
|
30732
|
+
path: "/occurrences",
|
|
30733
|
+
scopes: ["occurrences:read"],
|
|
30734
|
+
tag: "Occurrences",
|
|
30735
|
+
summary: "List a template's occurrences",
|
|
30736
|
+
description: "Occurrences of one task/habit template, oldest-first.",
|
|
30737
|
+
query: [{ name: "templateId", description: "The task/habit template's ULID.", required: true }],
|
|
30738
|
+
querySchema: object({ templateId: ulidSchema }),
|
|
30739
|
+
status: 200,
|
|
30740
|
+
response: { description: "The template's occurrences." },
|
|
30741
|
+
errors: { 400: true }
|
|
30742
|
+
},
|
|
30743
|
+
update: {
|
|
30744
|
+
method: "patch",
|
|
30745
|
+
path: "/occurrences/{id}",
|
|
30746
|
+
scopes: ["occurrences:write"],
|
|
30747
|
+
tag: "Occurrences",
|
|
30748
|
+
summary: "Override an occurrence",
|
|
30749
|
+
description: 'Reschedule/skip one occurrence ("edit this"); fires `occurrence.updated`.',
|
|
30750
|
+
body: updateOccurrenceInputSchema,
|
|
30751
|
+
status: 200,
|
|
30752
|
+
response: { description: "The overridden occurrence." },
|
|
30753
|
+
errors: { 400: true, 404: true },
|
|
30754
|
+
webhook: "occurrence.updated"
|
|
30755
|
+
},
|
|
30756
|
+
complete: {
|
|
30757
|
+
method: "post",
|
|
30758
|
+
path: "/occurrences/{id}/complete",
|
|
30759
|
+
scopes: ["occurrences:write"],
|
|
30760
|
+
tag: "Occurrences",
|
|
30761
|
+
summary: "Complete an occurrence",
|
|
30762
|
+
description: "Mark an occurrence done; fires `occurrence.completed`.",
|
|
30763
|
+
status: 201,
|
|
30764
|
+
response: { description: "The completed occurrence." },
|
|
30765
|
+
errors: { 404: true },
|
|
30766
|
+
webhook: "occurrence.completed"
|
|
30767
|
+
}
|
|
30768
|
+
});
|
|
30769
|
+
|
|
29743
30770
|
// ../../packages/schema/src/operations/periods.ts
|
|
29744
30771
|
var periodOperations = defineOperations({
|
|
29745
30772
|
...crudOperations({
|
|
@@ -29765,6 +30792,474 @@ var periodOperations = defineOperations({
|
|
|
29765
30792
|
})
|
|
29766
30793
|
});
|
|
29767
30794
|
|
|
30795
|
+
// ../../packages/schema/src/operations/planning-rules.ts
|
|
30796
|
+
var planningRuleOperations = defineOperations({
|
|
30797
|
+
...crudOperations({
|
|
30798
|
+
segment: "planning/rules",
|
|
30799
|
+
tag: "Planning rules",
|
|
30800
|
+
noun: "planning rule",
|
|
30801
|
+
read: "planning:read",
|
|
30802
|
+
write: "planning:write",
|
|
30803
|
+
create: createPlanningRuleInputSchema,
|
|
30804
|
+
update: updatePlanningRuleInputSchema,
|
|
30805
|
+
listQuery: [
|
|
30806
|
+
{ name: "forUserId", description: "Only this member's rules." },
|
|
30807
|
+
{
|
|
30808
|
+
name: "kind",
|
|
30809
|
+
description: "Only this kind (`fixed_time`, `keep_free`, `meaning`, `whose`, `limit`, `note`)."
|
|
30810
|
+
}
|
|
30811
|
+
],
|
|
30812
|
+
listQuerySchema: planningRulesQuerySchema
|
|
30813
|
+
})
|
|
30814
|
+
});
|
|
30815
|
+
|
|
30816
|
+
// ../../packages/schema/src/operations/plans.ts
|
|
30817
|
+
function decision(path, verb, what) {
|
|
30818
|
+
return {
|
|
30819
|
+
method: "post",
|
|
30820
|
+
path,
|
|
30821
|
+
scopes: ["tasks:write"],
|
|
30822
|
+
tag: "Plans",
|
|
30823
|
+
summary: `${verb[0]?.toUpperCase()}${verb.slice(1)} plan items`,
|
|
30824
|
+
description: `${what} \`itemIds\` narrows it to those items; absent (or an empty body) answers every item it applies to. An unknown item id is a 404.`,
|
|
30825
|
+
body: planDecisionInputSchema,
|
|
30826
|
+
bodyOptional: true,
|
|
30827
|
+
status: 200,
|
|
30828
|
+
response: { description: "The plan, after.", view: "Plan" },
|
|
30829
|
+
errors: { 400: true, 404: true }
|
|
30830
|
+
};
|
|
30831
|
+
}
|
|
30832
|
+
var planOperations = defineOperations({
|
|
30833
|
+
list: {
|
|
30834
|
+
method: "get",
|
|
30835
|
+
path: "/plans",
|
|
30836
|
+
scopes: ["tasks:read"],
|
|
30837
|
+
tag: "Plans",
|
|
30838
|
+
summary: "List plans",
|
|
30839
|
+
description: "The Space's plan proposals, newest first (the latest 20), each with its items and each item's task as it is now. `status`: `open` (an item waits for an answer), `settled` (none does) or `replaced` (a newer plan for the same week or day took its place).",
|
|
30840
|
+
query: [
|
|
30841
|
+
{ name: "kind", description: "`week` or `day`." },
|
|
30842
|
+
{ name: "status", description: "`open`, `settled` or `replaced`." },
|
|
30843
|
+
{ name: "startsOn", description: "The week's Monday, or the day (`YYYY-MM-DD`)." },
|
|
30844
|
+
{ name: "forUserId", description: "Only this member's plans." }
|
|
30845
|
+
],
|
|
30846
|
+
querySchema: planListQuerySchema.extend({ forUserId: string2().min(1).optional() }),
|
|
30847
|
+
status: 200,
|
|
30848
|
+
response: { description: "The plans.", list: true, view: "Plan" },
|
|
30849
|
+
errors: { 400: true }
|
|
30850
|
+
},
|
|
30851
|
+
create: {
|
|
30852
|
+
method: "post",
|
|
30853
|
+
path: "/plans",
|
|
30854
|
+
scopes: ["tasks:write"],
|
|
30855
|
+
tag: "Plans",
|
|
30856
|
+
summary: "Propose a plan",
|
|
30857
|
+
description: "The agent proposes a week (`kind: week`, `startsOn` a Monday) or a day for a member (`forUserId`, default the member the key acts for). Each item is about one open task: `plan` it on a `day` (all-day, in the member's zone) or `at` a time (with `durationMinutes` when known), take it back to `someday`, or `let_go`. `reason` is the line shown with it. Nothing is written to a task until the member accepts; a newer plan for the same week or day replaces an open one. An Agent's own work joins only while it waits on the member. A block that is already there (a task, a life block or an event on that day with a similar title) is folded in, not added twice: a task is planned into the block's time, anything else is left out, and `merged` lists each with a hint; `onDuplicate: reject` refuses the plan with those hints instead.",
|
|
30858
|
+
body: createPlanInputSchema,
|
|
30859
|
+
status: 201,
|
|
30860
|
+
response: {
|
|
30861
|
+
description: "The plan, open, with the duplicates it folded in.",
|
|
30862
|
+
view: "PlanCreateResult"
|
|
30863
|
+
},
|
|
30864
|
+
errors: { 400: true }
|
|
30865
|
+
},
|
|
30866
|
+
get: {
|
|
30867
|
+
method: "get",
|
|
30868
|
+
path: "/plans/{id}",
|
|
30869
|
+
scopes: ["tasks:read"],
|
|
30870
|
+
tag: "Plans",
|
|
30871
|
+
summary: "Get a plan",
|
|
30872
|
+
description: "One plan with its items.",
|
|
30873
|
+
status: 200,
|
|
30874
|
+
response: { description: "The plan.", view: "Plan" },
|
|
30875
|
+
errors: { 404: true }
|
|
30876
|
+
},
|
|
30877
|
+
accept: {
|
|
30878
|
+
...decision("/plans/{id}/accept", "accept", "Accept proposed items: each task is written as the item says (a planned day or time, Someday, or cancelled for Let go; a task still Proposed by the agent joins the plan too), and the item keeps what it replaced for Undo. An item whose task has closed since is dismissed instead."),
|
|
30879
|
+
errors: { 400: true, 404: true, 409: "A newer plan replaced this one." }
|
|
30880
|
+
},
|
|
30881
|
+
dismiss: decision("/plans/{id}/dismiss", "dismiss", "Leave proposed items out. Nothing is written to a task."),
|
|
30882
|
+
undo: decision("/plans/{id}/undo", "undo", "Undo answered items: an accepted item's task is put back as it was before; a dismissed item simply waits again. Both read as proposed afterwards.")
|
|
30883
|
+
});
|
|
30884
|
+
|
|
30885
|
+
// ../../packages/schema/src/operations/routines.ts
|
|
30886
|
+
var routineOperations = defineOperations({
|
|
30887
|
+
getRun: {
|
|
30888
|
+
method: "get",
|
|
30889
|
+
path: "/routines/runs/{runId}",
|
|
30890
|
+
pathParams: { runId: "The routine run's ULID." },
|
|
30891
|
+
scopes: ["routines:read"],
|
|
30892
|
+
tag: "Routines",
|
|
30893
|
+
summary: "Get a run",
|
|
30894
|
+
description: "One run with its per-step state.",
|
|
30895
|
+
status: 200,
|
|
30896
|
+
response: { description: "The run." },
|
|
30897
|
+
errors: { 404: true }
|
|
30898
|
+
},
|
|
30899
|
+
updateRun: {
|
|
30900
|
+
method: "patch",
|
|
30901
|
+
path: "/routines/runs/{runId}",
|
|
30902
|
+
pathParams: { runId: "The routine run's ULID." },
|
|
30903
|
+
scopes: ["routines:write"],
|
|
30904
|
+
tag: "Routines",
|
|
30905
|
+
summary: "Update a run",
|
|
30906
|
+
description: "Advance/finish a run; fires `routine.run.updated`.",
|
|
30907
|
+
body: updateRoutineRunInputSchema,
|
|
30908
|
+
status: 200,
|
|
30909
|
+
response: { description: "The updated run." },
|
|
30910
|
+
errors: { 400: true, 404: true },
|
|
30911
|
+
webhook: "routine.run.updated"
|
|
30912
|
+
},
|
|
30913
|
+
updateRunStep: {
|
|
30914
|
+
method: "patch",
|
|
30915
|
+
path: "/routines/runs/{runId}/steps/{stepRunId}",
|
|
30916
|
+
pathParams: { runId: "The routine run's ULID.", stepRunId: "The run step's ULID." },
|
|
30917
|
+
scopes: ["routines:write"],
|
|
30918
|
+
tag: "Routines",
|
|
30919
|
+
summary: "Update a run step",
|
|
30920
|
+
description: "Check off / edit one run step; fires `routine.run.updated`.",
|
|
30921
|
+
body: updateRoutineRunStepInputSchema,
|
|
30922
|
+
status: 200,
|
|
30923
|
+
response: { description: "The updated run." },
|
|
30924
|
+
errors: { 400: true, 404: true },
|
|
30925
|
+
webhook: "routine.run.updated"
|
|
30926
|
+
},
|
|
30927
|
+
undoSteps: {
|
|
30928
|
+
method: "post",
|
|
30929
|
+
path: "/routines/runs/{runId}/undo",
|
|
30930
|
+
pathParams: { runId: "The routine run's ULID." },
|
|
30931
|
+
scopes: ["routines:write"],
|
|
30932
|
+
tag: "Routines",
|
|
30933
|
+
summary: "Undo All taken",
|
|
30934
|
+
description: 'Take an "All taken" back in one call: each named step goes back to open and loses exactly the check-in it wrote; a finished run reopens. Steps no longer done are left alone. Fires `routine.run.updated`.',
|
|
30935
|
+
body: routineRunUndoInputSchema,
|
|
30936
|
+
status: 200,
|
|
30937
|
+
response: { description: "The run." },
|
|
30938
|
+
errors: { 400: true, 404: true },
|
|
30939
|
+
webhook: "routine.run.updated",
|
|
30940
|
+
operationId: "undo_routine_all_taken"
|
|
30941
|
+
},
|
|
30942
|
+
list: {
|
|
30943
|
+
method: "get",
|
|
30944
|
+
path: "/routines",
|
|
30945
|
+
scopes: ["routines:read"],
|
|
30946
|
+
tag: "Routines",
|
|
30947
|
+
summary: "List routines",
|
|
30948
|
+
description: "Every routine (with its steps) in the Space, newest first.",
|
|
30949
|
+
querySchema: paginationQuerySchema,
|
|
30950
|
+
paginated: true,
|
|
30951
|
+
status: 200,
|
|
30952
|
+
response: { description: "The Space's routines." }
|
|
30953
|
+
},
|
|
30954
|
+
get: {
|
|
30955
|
+
method: "get",
|
|
30956
|
+
path: "/routines/{id}",
|
|
30957
|
+
scopes: ["routines:read"],
|
|
30958
|
+
tag: "Routines",
|
|
30959
|
+
summary: "Get a routine",
|
|
30960
|
+
description: "One routine with its step templates.",
|
|
30961
|
+
status: 200,
|
|
30962
|
+
response: { description: "The routine." },
|
|
30963
|
+
errors: { 404: true }
|
|
30964
|
+
},
|
|
30965
|
+
create: {
|
|
30966
|
+
method: "post",
|
|
30967
|
+
path: "/routines",
|
|
30968
|
+
scopes: ["routines:write"],
|
|
30969
|
+
tag: "Routines",
|
|
30970
|
+
summary: "Create a routine",
|
|
30971
|
+
description: "Create a routine (steps ride in the payload); fires `routine.created`.",
|
|
30972
|
+
body: createRoutineInputSchema,
|
|
30973
|
+
status: 201,
|
|
30974
|
+
response: { description: "The created routine." },
|
|
30975
|
+
errors: { 400: true },
|
|
30976
|
+
webhook: "routine.created"
|
|
30977
|
+
},
|
|
30978
|
+
update: {
|
|
30979
|
+
method: "patch",
|
|
30980
|
+
path: "/routines/{id}",
|
|
30981
|
+
scopes: ["routines:write"],
|
|
30982
|
+
tag: "Routines",
|
|
30983
|
+
summary: "Update a routine",
|
|
30984
|
+
description: "Patch a routine; fires `routine.updated`.",
|
|
30985
|
+
body: updateRoutineInputSchema,
|
|
30986
|
+
status: 200,
|
|
30987
|
+
response: { description: "The updated routine." },
|
|
30988
|
+
errors: { 400: true, 404: true },
|
|
30989
|
+
webhook: "routine.updated"
|
|
30990
|
+
},
|
|
30991
|
+
remove: {
|
|
30992
|
+
method: "delete",
|
|
30993
|
+
path: "/routines/{id}",
|
|
30994
|
+
scopes: ["routines:write"],
|
|
30995
|
+
tag: "Routines",
|
|
30996
|
+
summary: "Delete a routine",
|
|
30997
|
+
description: "Soft-delete a routine; fires `routine.deleted`.",
|
|
30998
|
+
status: 204,
|
|
30999
|
+
response: { description: "Deleted." },
|
|
31000
|
+
errors: { 404: true },
|
|
31001
|
+
webhook: "routine.deleted"
|
|
31002
|
+
},
|
|
31003
|
+
attachRecurrence: {
|
|
31004
|
+
method: "put",
|
|
31005
|
+
path: "/routines/{id}/recurrence",
|
|
31006
|
+
scopes: ["routines:write"],
|
|
31007
|
+
tag: "Routines",
|
|
31008
|
+
summary: "Attach recurrence",
|
|
31009
|
+
description: "Attach/replace the routine's recurrence rule; fires `routine.updated`.",
|
|
31010
|
+
body: updateRecurrenceRuleInputSchema,
|
|
31011
|
+
status: 200,
|
|
31012
|
+
response: { description: "The routine." },
|
|
31013
|
+
errors: { 400: true, 404: true },
|
|
31014
|
+
webhook: "routine.updated"
|
|
31015
|
+
},
|
|
31016
|
+
detachRecurrence: {
|
|
31017
|
+
method: "delete",
|
|
31018
|
+
path: "/routines/{id}/recurrence",
|
|
31019
|
+
scopes: ["routines:write"],
|
|
31020
|
+
tag: "Routines",
|
|
31021
|
+
summary: "Detach recurrence",
|
|
31022
|
+
description: "Remove the routine's recurrence rule; returns the routine; fires `routine.updated`.",
|
|
31023
|
+
status: 200,
|
|
31024
|
+
response: { description: "The routine." },
|
|
31025
|
+
errors: { 404: true },
|
|
31026
|
+
webhook: "routine.updated"
|
|
31027
|
+
},
|
|
31028
|
+
markDone: {
|
|
31029
|
+
method: "post",
|
|
31030
|
+
path: "/routines/{id}/done",
|
|
31031
|
+
scopes: ["routines:write"],
|
|
31032
|
+
tag: "Routines",
|
|
31033
|
+
summary: "Check in a whole routine (All taken)",
|
|
31034
|
+
description: "\"Took my supplements\" (#873): one call checks in every open step of today's run (the key's member's day), starting today's run when there's none. Each habit step writes a check-in (`source: routine`); a habit already done today goes done without a second one; a step whose habit is skipped today is left alone. The run finishes once nothing is open. Returns the run and `taken`, the steps it resolved; hand their `stepRunId`s to `POST /api/v1/routines/runs/{runId}/undo` to take it all back. Calling it again changes nothing. Fires `routine.run.updated`.",
|
|
31035
|
+
body: routineDoneInputSchema,
|
|
31036
|
+
status: 200,
|
|
31037
|
+
response: { description: "`{ run, taken }`." },
|
|
31038
|
+
errors: { 400: true, 404: true },
|
|
31039
|
+
webhook: "routine.run.updated",
|
|
31040
|
+
operationId: "routine_all_taken"
|
|
31041
|
+
},
|
|
31042
|
+
startRun: {
|
|
31043
|
+
method: "post",
|
|
31044
|
+
path: "/routines/{id}/runs",
|
|
31045
|
+
scopes: ["routines:write"],
|
|
31046
|
+
tag: "Routines",
|
|
31047
|
+
summary: "Start a run",
|
|
31048
|
+
description: "Start a run of the routine; fires `routine.run.started`.",
|
|
31049
|
+
body: startRoutineRunInputSchema,
|
|
31050
|
+
status: 201,
|
|
31051
|
+
response: { description: "The started run." },
|
|
31052
|
+
errors: { 400: true, 404: true },
|
|
31053
|
+
webhook: "routine.run.started"
|
|
31054
|
+
},
|
|
31055
|
+
listRuns: {
|
|
31056
|
+
method: "get",
|
|
31057
|
+
path: "/routines/{id}/runs",
|
|
31058
|
+
scopes: ["routines:read"],
|
|
31059
|
+
tag: "Routines",
|
|
31060
|
+
summary: "List a routine's runs",
|
|
31061
|
+
description: "The routine's runs, newest-first.",
|
|
31062
|
+
status: 200,
|
|
31063
|
+
response: { description: "The routine's runs." },
|
|
31064
|
+
errors: { 404: true }
|
|
31065
|
+
}
|
|
31066
|
+
});
|
|
31067
|
+
|
|
31068
|
+
// ../../packages/schema/src/operations/rsvp-answers.ts
|
|
31069
|
+
var rsvpAnswerOperations = defineOperations({
|
|
31070
|
+
list: {
|
|
31071
|
+
method: "get",
|
|
31072
|
+
path: "/rsvp-answers",
|
|
31073
|
+
scopes: ["contacts:read"],
|
|
31074
|
+
tag: "Guests",
|
|
31075
|
+
summary: "List RSVP answers",
|
|
31076
|
+
description: "A guest list's answers to its RSVP questions (`guestListId`, required), or one household's (`householdId`): `{ questionId, householdId, guestId, value }`, `guestId` null for the household's own.",
|
|
31077
|
+
query: [
|
|
31078
|
+
{ name: "guestListId", description: "The guest list (required)." },
|
|
31079
|
+
{ name: "householdId", description: "Only this household's answers." }
|
|
31080
|
+
],
|
|
31081
|
+
querySchema: rsvpAnswersQuerySchema,
|
|
31082
|
+
status: 200,
|
|
31083
|
+
response: { description: "The answers." },
|
|
31084
|
+
errors: { 400: true, 404: true }
|
|
31085
|
+
},
|
|
31086
|
+
set: {
|
|
31087
|
+
method: "put",
|
|
31088
|
+
path: "/rsvp-answers",
|
|
31089
|
+
scopes: ["contacts:write"],
|
|
31090
|
+
tag: "Guests",
|
|
31091
|
+
summary: "Set a household's RSVP answers",
|
|
31092
|
+
description: "Lays `answers` over the household's stored ones (`value: null` clears one; answers left out stay) and returns what stands. An unknown question, a guest not in the household, a per-guest question without a guest, an event the guest isn't invited to, or a value that doesn't fit the kind is a 422; an answer whose question no longer shows (its `showIf`) is dropped. Fires `rsvp.answers.updated`.",
|
|
31093
|
+
body: setRsvpAnswersInputSchema,
|
|
31094
|
+
status: 200,
|
|
31095
|
+
response: { description: "The household's answers after." },
|
|
31096
|
+
errors: { 400: true, 404: true, 422: "An answer that can't be given (see the message)." },
|
|
31097
|
+
webhook: "rsvp.answers.updated"
|
|
31098
|
+
}
|
|
31099
|
+
});
|
|
31100
|
+
|
|
31101
|
+
// ../../packages/schema/src/operations/rsvp-questions.ts
|
|
31102
|
+
var rsvpQuestionOperations = defineOperations({
|
|
31103
|
+
...crudOperations({
|
|
31104
|
+
segment: "rsvp-questions",
|
|
31105
|
+
tag: "Guests",
|
|
31106
|
+
noun: "RSVP question",
|
|
31107
|
+
eventBase: "rsvp.question",
|
|
31108
|
+
read: "contacts:read",
|
|
31109
|
+
write: "contacts:write",
|
|
31110
|
+
create: createRsvpQuestionInputSchema,
|
|
31111
|
+
update: updateRsvpQuestionInputSchema,
|
|
31112
|
+
listQuery: [{ name: "guestListId", description: "The guest list (required)." }],
|
|
31113
|
+
listQuerySchema: rsvpQuestionsQuerySchema
|
|
31114
|
+
}),
|
|
31115
|
+
presets: {
|
|
31116
|
+
method: "post",
|
|
31117
|
+
path: "/rsvp-questions/presets",
|
|
31118
|
+
scopes: ["contacts:write"],
|
|
31119
|
+
tag: "Guests",
|
|
31120
|
+
summary: "Add the built-in RSVP questions",
|
|
31121
|
+
description: "Adds the preset questions after the list's own (`diet`: per guest, shown to a guest who said yes to anything, with vegetarian \xB7 vegan \xB7 gluten-free \xB7 lactose-free \xB7 nut allergy \xB7 other, and a text line shown when other is picked; `message`: the household's, once). A preset the list already has stays as it is. Returns the list's questions; fires `rsvp.question.created`.",
|
|
31122
|
+
body: addRsvpPresetsInputSchema,
|
|
31123
|
+
status: 200,
|
|
31124
|
+
response: { description: "The list's questions." },
|
|
31125
|
+
errors: { 400: true, 404: true },
|
|
31126
|
+
webhook: "rsvp.question.created"
|
|
31127
|
+
}
|
|
31128
|
+
});
|
|
31129
|
+
|
|
31130
|
+
// ../../packages/schema/src/operations/sensors.ts
|
|
31131
|
+
var sensorOperations = defineOperations({
|
|
31132
|
+
status: {
|
|
31133
|
+
method: "get",
|
|
31134
|
+
path: "/sensors/home-assistant",
|
|
31135
|
+
scopes: ["places:read"],
|
|
31136
|
+
tag: "Sensors",
|
|
31137
|
+
summary: "Get the Home Assistant link",
|
|
31138
|
+
description: "Whether the Space has linked Home Assistant (in Settings in the app; the token is never returned), the `host` it was linked at, how many entities are mapped (`links`) and `lastReadingAt`, when the newest reading from it landed.",
|
|
31139
|
+
status: 200,
|
|
31140
|
+
response: { description: "The link's status." },
|
|
31141
|
+
errors: { 403: true }
|
|
31142
|
+
},
|
|
31143
|
+
entities: {
|
|
31144
|
+
method: "get",
|
|
31145
|
+
path: "/sensors/home-assistant/entities",
|
|
31146
|
+
scopes: ["places:read"],
|
|
31147
|
+
tag: "Sensors",
|
|
31148
|
+
summary: "List Home Assistant's entities",
|
|
31149
|
+
description: "Every entity Home Assistant has, by `entityId`: its name, domain, state, unit, device class, `lastUpdated`, the reading it most likely gives on a Place and on an asset (`suggested`) and the sensor link it's mapped by, or null. 409 before Home Assistant is linked; 503 when it doesn't answer.",
|
|
31150
|
+
status: 200,
|
|
31151
|
+
response: { description: "The entities, by id." },
|
|
31152
|
+
errors: { 403: true, 409: true, 503: "Home Assistant didn't answer, or refused the token." }
|
|
31153
|
+
},
|
|
31154
|
+
sync: {
|
|
31155
|
+
method: "post",
|
|
31156
|
+
path: "/sensors/home-assistant/sync",
|
|
31157
|
+
scopes: ["places:write"],
|
|
31158
|
+
tag: "Sensors",
|
|
31159
|
+
summary: "Sync Home Assistant now",
|
|
31160
|
+
description: "Read every mapped entity's state once and append it to the datapoints ledger: on a Place as `shed.temp`, `shed.humidity`, `shed.heater`, `shed.water_pct`, `shed.door`, `shed.feed_kg` or `shed.light` (what an animal's room card and the room alarm read), on an asset as `asset.state`, `asset.power` or `asset.energy`. A state already on the ledger, or one Home Assistant can't read, is skipped. The worker does the same every five minutes. Returns `{ syncedAt, entities, written, skipped, missing, error }` (`unauthorized`, `unavailable`, `bad_response`). 409 before Home Assistant is linked.",
|
|
31161
|
+
status: 200,
|
|
31162
|
+
response: { description: "What the sync did." },
|
|
31163
|
+
errors: { 403: true, 409: true }
|
|
31164
|
+
},
|
|
31165
|
+
unifiStatus: {
|
|
31166
|
+
method: "get",
|
|
31167
|
+
path: "/sensors/unifi",
|
|
31168
|
+
scopes: ["places:read"],
|
|
31169
|
+
tag: "Sensors",
|
|
31170
|
+
summary: "Whether UniFi is linked",
|
|
31171
|
+
description: "Whether the Space has linked its UniFi controller (in the app's Settings \u2192 Home), the host and site it was linked at, how many devices are mapped to an asset, and when the newest presence reading landed. Never the API key: a key can't link or unlink UniFi.",
|
|
31172
|
+
status: 200,
|
|
31173
|
+
response: { description: "The status." },
|
|
31174
|
+
errors: { 403: true }
|
|
31175
|
+
},
|
|
31176
|
+
unifiDevices: {
|
|
31177
|
+
method: "get",
|
|
31178
|
+
path: "/sensors/unifi/devices",
|
|
31179
|
+
scopes: ["places:read", "collections:read"],
|
|
31180
|
+
tag: "Sensors",
|
|
31181
|
+
summary: "The devices UniFi sees",
|
|
31182
|
+
description: "Every device the controller manages (gateway, switches, access points, cameras) and every client connected now: `mac`, `name`, `kind` (`device` | `client`), `model`, `online`, `firmware`, and the sensor `link` to the asset it's mapped to (behind the nodes wall). Network details. 409 before UniFi is linked; 503 when the controller can't be read.",
|
|
31183
|
+
status: 200,
|
|
31184
|
+
response: { description: "The devices." },
|
|
31185
|
+
errors: { 403: true, 409: true }
|
|
31186
|
+
},
|
|
31187
|
+
syncUnifi: {
|
|
31188
|
+
method: "post",
|
|
31189
|
+
path: "/sensors/unifi/sync",
|
|
31190
|
+
scopes: ["places:write"],
|
|
31191
|
+
tag: "Sensors",
|
|
31192
|
+
summary: "Sync UniFi now",
|
|
31193
|
+
description: "Map every asset whose facet names a UniFi MAC (`external.unifiMac`), ask the controller once, and put each mapped device's presence on its asset as `asset.presence` (1 online, 0 offline, with its firmware): what the asset page's Live card reads. A reading lands when the presence or firmware changes, else hourly; a device the controller doesn't list reads offline and is named in `missing`. The worker does the same every five minutes. 409 before UniFi is linked.",
|
|
31194
|
+
status: 200,
|
|
31195
|
+
response: { description: "What the sync did." },
|
|
31196
|
+
errors: { 403: true, 409: true }
|
|
31197
|
+
},
|
|
31198
|
+
links: {
|
|
31199
|
+
method: "get",
|
|
31200
|
+
path: "/sensors/links",
|
|
31201
|
+
scopes: ["places:read"],
|
|
31202
|
+
tag: "Sensors",
|
|
31203
|
+
summary: "List the mapped entities",
|
|
31204
|
+
description: "Every mapped entity, or only the ones on `nodeId`, with the name of what it lands on (`nodeTitle`). A mapping on an asset kept Not shared is its member's alone.",
|
|
31205
|
+
query: [{ name: "nodeId", description: "Only the mappings on this Place or asset." }],
|
|
31206
|
+
querySchema: sensorLinksQuerySchema,
|
|
31207
|
+
status: 200,
|
|
31208
|
+
response: { description: "The mappings, by entity id." },
|
|
31209
|
+
errors: { 400: true }
|
|
31210
|
+
},
|
|
31211
|
+
createLink: {
|
|
31212
|
+
method: "post",
|
|
31213
|
+
path: "/sensors/links",
|
|
31214
|
+
scopes: ["places:write"],
|
|
31215
|
+
tag: "Sensors",
|
|
31216
|
+
summary: "Map an entity",
|
|
31217
|
+
description: "Map a Home Assistant entity (`externalId`) to a Place, an asset, or an animal (its room: the Place it's housed in) as a `reading`: a Place takes `temp`, `humidity`, `heater`, `water`, `door`, `feeder` or `light`; an asset `state`, `power` or `energy`. Mapping an entity that's already mapped moves it. 400 when the reading doesn't fit; 404 for no such node; 409 for an animal with no room.",
|
|
31218
|
+
body: createSensorLinkInputSchema,
|
|
31219
|
+
status: 201,
|
|
31220
|
+
response: { description: "The mapping." },
|
|
31221
|
+
errors: { 400: true, 404: true, 409: true }
|
|
31222
|
+
},
|
|
31223
|
+
removeLink: {
|
|
31224
|
+
method: "delete",
|
|
31225
|
+
path: "/sensors/links/{id}",
|
|
31226
|
+
scopes: ["places:write"],
|
|
31227
|
+
tag: "Sensors",
|
|
31228
|
+
summary: "Unmap an entity",
|
|
31229
|
+
description: "Remove one mapping; the readings it gave stay on the ledger.",
|
|
31230
|
+
status: 204,
|
|
31231
|
+
response: { description: "Removed." },
|
|
31232
|
+
errors: { 404: true }
|
|
31233
|
+
}
|
|
31234
|
+
});
|
|
31235
|
+
|
|
31236
|
+
// ../../packages/schema/src/operations/settings.ts
|
|
31237
|
+
var settingsOperations = defineOperations({
|
|
31238
|
+
get: {
|
|
31239
|
+
method: "get",
|
|
31240
|
+
path: "/settings",
|
|
31241
|
+
scopes: ["settings:read"],
|
|
31242
|
+
tag: "Settings",
|
|
31243
|
+
summary: "Get settings",
|
|
31244
|
+
description: "The caller's settings (lazily created). The key must carry a user identity.",
|
|
31245
|
+
status: 200,
|
|
31246
|
+
response: { description: "The caller's settings." }
|
|
31247
|
+
},
|
|
31248
|
+
update: {
|
|
31249
|
+
method: "patch",
|
|
31250
|
+
path: "/settings",
|
|
31251
|
+
scopes: ["settings:write"],
|
|
31252
|
+
tag: "Settings",
|
|
31253
|
+
summary: "Update settings",
|
|
31254
|
+
description: "Patch the caller's settings; fires `settings.updated`.",
|
|
31255
|
+
body: updateUserSettingsInputSchema,
|
|
31256
|
+
status: 200,
|
|
31257
|
+
response: { description: "The updated settings." },
|
|
31258
|
+
errors: { 400: true },
|
|
31259
|
+
webhook: "settings.updated"
|
|
31260
|
+
}
|
|
31261
|
+
});
|
|
31262
|
+
|
|
29768
31263
|
// ../../packages/schema/src/operations/shopping-lists.ts
|
|
29769
31264
|
var shoppingListOperations = defineOperations({
|
|
29770
31265
|
...crudOperations({
|
|
@@ -29783,7 +31278,7 @@ var shoppingListOperations = defineOperations({
|
|
|
29783
31278
|
// ../../packages/schema/src/operations/tap-tags.ts
|
|
29784
31279
|
var READ = ["habits:read", "routines:read"];
|
|
29785
31280
|
var WRITE = ["habits:write", "routines:write"];
|
|
29786
|
-
var
|
|
31281
|
+
var pathParams2 = { id: "The tag's id: the ULID the sticker's link carries (`/t/{id}`)." };
|
|
29787
31282
|
var tapTagOperations = defineOperations({
|
|
29788
31283
|
list: {
|
|
29789
31284
|
method: "get",
|
|
@@ -29811,7 +31306,7 @@ var tapTagOperations = defineOperations({
|
|
|
29811
31306
|
get: {
|
|
29812
31307
|
method: "get",
|
|
29813
31308
|
path: "/tap-tags/{id}",
|
|
29814
|
-
pathParams,
|
|
31309
|
+
pathParams: pathParams2,
|
|
29815
31310
|
scopes: READ,
|
|
29816
31311
|
tag: "Habits",
|
|
29817
31312
|
summary: "Get a tap tag",
|
|
@@ -29823,7 +31318,7 @@ var tapTagOperations = defineOperations({
|
|
|
29823
31318
|
update: {
|
|
29824
31319
|
method: "patch",
|
|
29825
31320
|
path: "/tap-tags/{id}",
|
|
29826
|
-
pathParams,
|
|
31321
|
+
pathParams: pathParams2,
|
|
29827
31322
|
scopes: WRITE,
|
|
29828
31323
|
tag: "Habits",
|
|
29829
31324
|
summary: "Rename or rebind a tap tag",
|
|
@@ -29836,7 +31331,7 @@ var tapTagOperations = defineOperations({
|
|
|
29836
31331
|
remove: {
|
|
29837
31332
|
method: "delete",
|
|
29838
31333
|
path: "/tap-tags/{id}",
|
|
29839
|
-
pathParams,
|
|
31334
|
+
pathParams: pathParams2,
|
|
29840
31335
|
scopes: WRITE,
|
|
29841
31336
|
tag: "Habits",
|
|
29842
31337
|
summary: "Delete a tap tag",
|
|
@@ -29848,7 +31343,7 @@ var tapTagOperations = defineOperations({
|
|
|
29848
31343
|
tap: {
|
|
29849
31344
|
method: "post",
|
|
29850
31345
|
path: "/tap-tags/{id}/tap",
|
|
29851
|
-
pathParams,
|
|
31346
|
+
pathParams: pathParams2,
|
|
29852
31347
|
scopes: WRITE,
|
|
29853
31348
|
tag: "Habits",
|
|
29854
31349
|
summary: "Tap a tap tag",
|
|
@@ -29859,6 +31354,292 @@ var tapTagOperations = defineOperations({
|
|
|
29859
31354
|
}
|
|
29860
31355
|
});
|
|
29861
31356
|
|
|
31357
|
+
// ../../packages/schema/src/operations/tasks.ts
|
|
31358
|
+
var taskListQuery = taskListQuerySchema.extend(paginationQuerySchema.shape).extend({ filter: taskListFilterSchema.optional().default("all") });
|
|
31359
|
+
var taskOperations = defineOperations({
|
|
31360
|
+
list: {
|
|
31361
|
+
method: "get",
|
|
31362
|
+
path: "/tasks",
|
|
31363
|
+
scopes: ["tasks:read"],
|
|
31364
|
+
tag: "Tasks",
|
|
31365
|
+
summary: "List tasks",
|
|
31366
|
+
description: "Every task in the key's Space, newest first.",
|
|
31367
|
+
query: [
|
|
31368
|
+
{
|
|
31369
|
+
name: "filter",
|
|
31370
|
+
description: "`all` (default), `unsorted` (the Inbox's tasks to file: open, top-level, not proposed, with no planned day, Deadline, Area or Project) or `starred`.",
|
|
31371
|
+
enum: ["all", "unsorted", "starred"]
|
|
31372
|
+
},
|
|
31373
|
+
{
|
|
31374
|
+
name: "areaId",
|
|
31375
|
+
description: "Only rows in this Area (ULID) \u2014 a project task by its project's Area (its effective Area)."
|
|
31376
|
+
},
|
|
31377
|
+
{ name: "projectId", description: "Only tasks attached to this project (ULID)." },
|
|
31378
|
+
{
|
|
31379
|
+
name: "status",
|
|
31380
|
+
description: "Only rows in any of these statuses (comma list or repeated key): `todo`, `in_progress`, `done`, `cancelled`."
|
|
31381
|
+
},
|
|
31382
|
+
{
|
|
31383
|
+
name: "tag",
|
|
31384
|
+
description: "Only tasks carrying every listed tag (comma list or repeated key; case-insensitive, a leading `#` is ignored)."
|
|
31385
|
+
},
|
|
31386
|
+
{
|
|
31387
|
+
name: "updatedSince",
|
|
31388
|
+
description: "Only rows whose `updatedAt` is at or after this instant \u2014 an ISO 8601 datetime with offset, or a bare `YYYY-MM-DD` (UTC midnight).",
|
|
31389
|
+
format: "date-time"
|
|
31390
|
+
},
|
|
31391
|
+
{
|
|
31392
|
+
name: "dueBefore",
|
|
31393
|
+
description: "Only rows due strictly before this instant (undated rows are excluded) \u2014 an ISO 8601 datetime with offset, or a bare `YYYY-MM-DD` (UTC midnight).",
|
|
31394
|
+
format: "date-time"
|
|
31395
|
+
},
|
|
31396
|
+
{
|
|
31397
|
+
name: "owner",
|
|
31398
|
+
description: "Only tasks with this Owner: `me`, `member:<id|email>`, `agent:<id|name>` (every desk) or `agent:<id|name>/<desk>`; `any` = owned, `none` = unowned. An unknown party is a 400."
|
|
31399
|
+
},
|
|
31400
|
+
{
|
|
31401
|
+
name: "waitingOn",
|
|
31402
|
+
description: "Only tasks waiting on this party: `me`, `member:<id|email>` or `agent:<id|name>`; `any` = waiting on someone, `none` = not waiting. An unknown party is a 400."
|
|
31403
|
+
},
|
|
31404
|
+
{
|
|
31405
|
+
name: "completedSince",
|
|
31406
|
+
description: "Only tasks finished at or after this instant (`completedAt`; open and cancelled tasks have none) \u2014 an ISO 8601 datetime with offset, or a bare `YYYY-MM-DD` (UTC midnight).",
|
|
31407
|
+
format: "date-time"
|
|
31408
|
+
},
|
|
31409
|
+
{
|
|
31410
|
+
name: "completedBefore",
|
|
31411
|
+
description: "Only tasks finished strictly before this instant \u2014 an ISO 8601 datetime with offset, or a bare `YYYY-MM-DD` (UTC midnight).",
|
|
31412
|
+
format: "date-time"
|
|
31413
|
+
},
|
|
31414
|
+
{
|
|
31415
|
+
name: "proposed",
|
|
31416
|
+
description: "`true` = only tasks Proposed by the agent (an Agent made them for a member, who hasn't accepted yet); `false` = only tasks on the plan. Absent = both.",
|
|
31417
|
+
type: "boolean"
|
|
31418
|
+
},
|
|
31419
|
+
{
|
|
31420
|
+
name: "ready",
|
|
31421
|
+
description: "`true` = only open tasks whose Owner marked them Ready for you; `false` = the rest. Absent = both.",
|
|
31422
|
+
type: "boolean"
|
|
31423
|
+
},
|
|
31424
|
+
{
|
|
31425
|
+
name: "drifted",
|
|
31426
|
+
description: "`true` = only open tasks whose planned day moved 3+ times (the weekly plan's Drifted card); `false` = the rest. Absent = both.",
|
|
31427
|
+
type: "boolean"
|
|
31428
|
+
}
|
|
31429
|
+
],
|
|
31430
|
+
querySchema: taskListQuery,
|
|
31431
|
+
paginated: true,
|
|
31432
|
+
status: 200,
|
|
31433
|
+
response: { description: "The Space's tasks.", list: true }
|
|
31434
|
+
},
|
|
31435
|
+
listSubtasks: {
|
|
31436
|
+
method: "get",
|
|
31437
|
+
path: "/tasks/{id}/subtasks",
|
|
31438
|
+
scopes: ["tasks:read"],
|
|
31439
|
+
tag: "Tasks",
|
|
31440
|
+
summary: "List subtasks",
|
|
31441
|
+
description: "The direct children of a task, ordered by `sortOrder` (ascending), then newest first.",
|
|
31442
|
+
status: 200,
|
|
31443
|
+
response: { description: "The ordered subtasks." },
|
|
31444
|
+
errors: { 404: true }
|
|
31445
|
+
},
|
|
31446
|
+
get: {
|
|
31447
|
+
method: "get",
|
|
31448
|
+
path: "/tasks/{id}",
|
|
31449
|
+
scopes: ["tasks:read"],
|
|
31450
|
+
tag: "Tasks",
|
|
31451
|
+
summary: "Get a task",
|
|
31452
|
+
description: "Fetch one task by id.",
|
|
31453
|
+
status: 200,
|
|
31454
|
+
response: { description: "The task." },
|
|
31455
|
+
errors: { 404: true }
|
|
31456
|
+
},
|
|
31457
|
+
create: {
|
|
31458
|
+
method: "post",
|
|
31459
|
+
path: "/tasks",
|
|
31460
|
+
scopes: ["tasks:write"],
|
|
31461
|
+
tag: "Tasks",
|
|
31462
|
+
summary: "Create a task",
|
|
31463
|
+
description: "Create a task; fires the `task.created` webhook.",
|
|
31464
|
+
body: createTaskInputSchema,
|
|
31465
|
+
status: 201,
|
|
31466
|
+
response: { description: "The created task." },
|
|
31467
|
+
errors: { 400: true, 409: true },
|
|
31468
|
+
webhook: "task.created"
|
|
31469
|
+
},
|
|
31470
|
+
update: {
|
|
31471
|
+
method: "patch",
|
|
31472
|
+
path: "/tasks/{id}",
|
|
31473
|
+
scopes: ["tasks:write"],
|
|
31474
|
+
tag: "Tasks",
|
|
31475
|
+
summary: "Update a task",
|
|
31476
|
+
description: "Patch a task; fires the `task.updated` webhook.",
|
|
31477
|
+
body: updateTaskInputSchema,
|
|
31478
|
+
status: 200,
|
|
31479
|
+
response: { description: "The updated task." },
|
|
31480
|
+
errors: { 400: true, 404: true, 409: true },
|
|
31481
|
+
webhook: "task.updated"
|
|
31482
|
+
},
|
|
31483
|
+
cancel: {
|
|
31484
|
+
method: "post",
|
|
31485
|
+
path: "/tasks/{id}/cancel",
|
|
31486
|
+
scopes: ["tasks:write"],
|
|
31487
|
+
tag: "Tasks",
|
|
31488
|
+
summary: "Cancel a task",
|
|
31489
|
+
description: 'Drop a task: its status becomes `cancelled` and any `completedAt` is cleared, so a drop never counts as Landed (#648). Fires `task.updated`. The same as a PATCH to `status: "cancelled"`.',
|
|
31490
|
+
status: 200,
|
|
31491
|
+
response: { description: "The cancelled task." },
|
|
31492
|
+
errors: { 404: true },
|
|
31493
|
+
webhook: "task.updated"
|
|
31494
|
+
},
|
|
31495
|
+
accept: {
|
|
31496
|
+
method: "post",
|
|
31497
|
+
path: "/tasks/{id}/accept",
|
|
31498
|
+
scopes: ["tasks:write"],
|
|
31499
|
+
tag: "Tasks",
|
|
31500
|
+
summary: "Accept a proposal",
|
|
31501
|
+
description: "Take a task Proposed by the agent onto the member's plan as it was suggested: its planned day, Deadline and Area stay; `proposedAt` clears (#889). A no-op success on a task that isn't a proposal. Fires `task.updated`. The same as a PATCH to `proposed: false`.",
|
|
31502
|
+
status: 200,
|
|
31503
|
+
response: { description: "The accepted task." },
|
|
31504
|
+
errors: { 404: true },
|
|
31505
|
+
webhook: "task.updated"
|
|
31506
|
+
},
|
|
31507
|
+
notNow: {
|
|
31508
|
+
method: "post",
|
|
31509
|
+
path: "/tasks/{id}/not-now",
|
|
31510
|
+
scopes: ["tasks:write"],
|
|
31511
|
+
tag: "Tasks",
|
|
31512
|
+
summary: "Not now on a proposal",
|
|
31513
|
+
description: "Keep a task Proposed by the agent, but out of the member's Inbox for a week (`notNowUntil`, #889). Let go is `cancel`. Fires `task.updated`.",
|
|
31514
|
+
status: 200,
|
|
31515
|
+
response: { description: "The proposal, back in a week." },
|
|
31516
|
+
errors: { 404: true, 409: "The task isn't a proposal." },
|
|
31517
|
+
webhook: "task.updated"
|
|
31518
|
+
},
|
|
31519
|
+
ready: {
|
|
31520
|
+
method: "post",
|
|
31521
|
+
path: "/tasks/{id}/ready",
|
|
31522
|
+
scopes: ["tasks:write"],
|
|
31523
|
+
tag: "Tasks",
|
|
31524
|
+
summary: "Mark Ready for you",
|
|
31525
|
+
description: "The task's Owner (the Space's agent, a Desk, a coding agent) finished something the member should look at: `readyAt` is set and the task reaches Now's Needs you with Review (#902). Looks good marks it done; Send back is a PATCH to `ready: false` (it reads Working on it again). The optional `note` is what's ready, in a line, with a link when there is one; absent keeps the note already there. Fires `task.updated`.",
|
|
31526
|
+
body: markTaskReadyInputSchema,
|
|
31527
|
+
status: 200,
|
|
31528
|
+
response: { description: "The task, Ready for you." },
|
|
31529
|
+
errors: { 404: true, 409: "The task is done or let go; only an open task can be ready." },
|
|
31530
|
+
webhook: "task.updated"
|
|
31531
|
+
},
|
|
31532
|
+
remove: {
|
|
31533
|
+
method: "delete",
|
|
31534
|
+
path: "/tasks/{id}",
|
|
31535
|
+
scopes: ["tasks:write"],
|
|
31536
|
+
tag: "Tasks",
|
|
31537
|
+
summary: "Delete a task",
|
|
31538
|
+
description: "Delete a task; fires the `task.deleted` webhook.",
|
|
31539
|
+
status: 204,
|
|
31540
|
+
response: { description: "Deleted." },
|
|
31541
|
+
errors: { 404: true },
|
|
31542
|
+
webhook: "task.deleted"
|
|
31543
|
+
}
|
|
31544
|
+
});
|
|
31545
|
+
|
|
31546
|
+
// ../../packages/schema/src/operations/today.ts
|
|
31547
|
+
var todayOperations = defineOperations({
|
|
31548
|
+
fromEarlier: {
|
|
31549
|
+
method: "get",
|
|
31550
|
+
path: "/today/from-earlier",
|
|
31551
|
+
scopes: ["tasks:read"],
|
|
31552
|
+
tag: "Reads",
|
|
31553
|
+
summary: "From earlier",
|
|
31554
|
+
description: 'The planned tasks that slipped (#888): open, non-recurring tasks whose all-day planned day falls in the 14 days before `from`, newest plan first. Timed tasks, tasks placed in a past time block and agent-owned work never roll; older plans simply leave the list (nothing is rewritten). A Space back from 21+ days away gets no pile. Also names `laterThisWeek`, the quietest later day this week (Monday-first; tomorrow on a Sunday) that "Later this week" lands on. Answer with `POST /api/v1/today/rollover`.',
|
|
31555
|
+
query: [
|
|
31556
|
+
{
|
|
31557
|
+
name: "from",
|
|
31558
|
+
description: "Your local day start, an ISO instant (or a bare date, read as UTC midnight). Defaults to the current UTC day."
|
|
31559
|
+
},
|
|
31560
|
+
{ name: "areaId", description: "Only tasks in this Area (own or their Project's)." }
|
|
31561
|
+
],
|
|
31562
|
+
querySchema: fromEarlierQuerySchema,
|
|
31563
|
+
status: 200,
|
|
31564
|
+
response: { description: "From earlier.", view: "FromEarlierResponse" },
|
|
31565
|
+
errors: { 400: true }
|
|
31566
|
+
},
|
|
31567
|
+
rollover: {
|
|
31568
|
+
method: "post",
|
|
31569
|
+
path: "/today/rollover",
|
|
31570
|
+
scopes: ["tasks:write"],
|
|
31571
|
+
tag: "Tasks",
|
|
31572
|
+
summary: "Answer From earlier",
|
|
31573
|
+
description: 'Answer many tasks (and habit/routine occurrences) at once: `reschedule` to `to` (all-day; From earlier\'s Today and Later this week), `someday` (clear the planned day, keep the Area or Project; occurrences untouched), or `drop` ("Let go": tasks cancelled, occurrences skipped; a cancelled task never counts as Landed). Only open tasks and unresolved occurrences change; unknown ids are skipped. Returns how many of each moved. Occurrence ids need `habits:write` too.',
|
|
31574
|
+
body: rolloverInputSchema,
|
|
31575
|
+
status: 201,
|
|
31576
|
+
response: { description: "How many tasks and occurrences changed." },
|
|
31577
|
+
errors: { 400: true }
|
|
31578
|
+
}
|
|
31579
|
+
});
|
|
31580
|
+
|
|
31581
|
+
// ../../packages/schema/src/operations/webhooks.ts
|
|
31582
|
+
var webhookOperations = defineOperations({
|
|
31583
|
+
list: {
|
|
31584
|
+
method: "get",
|
|
31585
|
+
path: "/webhooks",
|
|
31586
|
+
scopes: ["webhooks:read"],
|
|
31587
|
+
tag: "Webhooks",
|
|
31588
|
+
summary: "List webhook subscriptions",
|
|
31589
|
+
description: "The Space's outbound webhook endpoints (secrets omitted), newest first.",
|
|
31590
|
+
querySchema: paginationQuerySchema,
|
|
31591
|
+
paginated: true,
|
|
31592
|
+
status: 200,
|
|
31593
|
+
response: { description: "The subscriptions." }
|
|
31594
|
+
},
|
|
31595
|
+
create: {
|
|
31596
|
+
method: "post",
|
|
31597
|
+
path: "/webhooks",
|
|
31598
|
+
scopes: ["webhooks:write"],
|
|
31599
|
+
tag: "Webhooks",
|
|
31600
|
+
summary: "Register a webhook subscription",
|
|
31601
|
+
description: "Register an endpoint + events; returns the signing secret once.",
|
|
31602
|
+
body: createWebhookSubscriptionInputSchema,
|
|
31603
|
+
status: 201,
|
|
31604
|
+
response: { description: "The created subscription (with its one-time secret)." },
|
|
31605
|
+
errors: { 400: true }
|
|
31606
|
+
},
|
|
31607
|
+
get: {
|
|
31608
|
+
method: "get",
|
|
31609
|
+
path: "/webhooks/{id}",
|
|
31610
|
+
scopes: ["webhooks:read"],
|
|
31611
|
+
tag: "Webhooks",
|
|
31612
|
+
summary: "Get a webhook subscription",
|
|
31613
|
+
description: "One subscription (secret omitted).",
|
|
31614
|
+
status: 200,
|
|
31615
|
+
response: { description: "The subscription." },
|
|
31616
|
+
errors: { 404: true }
|
|
31617
|
+
},
|
|
31618
|
+
update: {
|
|
31619
|
+
method: "patch",
|
|
31620
|
+
path: "/webhooks/{id}",
|
|
31621
|
+
scopes: ["webhooks:write"],
|
|
31622
|
+
tag: "Webhooks",
|
|
31623
|
+
summary: "Update a webhook subscription",
|
|
31624
|
+
description: "Patch url/events, or pause with `active: false`.",
|
|
31625
|
+
body: updateWebhookSubscriptionInputSchema,
|
|
31626
|
+
status: 200,
|
|
31627
|
+
response: { description: "The updated subscription." },
|
|
31628
|
+
errors: { 400: true, 404: true }
|
|
31629
|
+
},
|
|
31630
|
+
remove: {
|
|
31631
|
+
method: "delete",
|
|
31632
|
+
path: "/webhooks/{id}",
|
|
31633
|
+
scopes: ["webhooks:write"],
|
|
31634
|
+
tag: "Webhooks",
|
|
31635
|
+
summary: "Delete a webhook subscription",
|
|
31636
|
+
description: "Remove an endpoint.",
|
|
31637
|
+
status: 204,
|
|
31638
|
+
response: { description: "Deleted." },
|
|
31639
|
+
errors: { 404: true }
|
|
31640
|
+
}
|
|
31641
|
+
});
|
|
31642
|
+
|
|
29862
31643
|
// ../../node_modules/ulidx/dist/node/index.js
|
|
29863
31644
|
import crypto from "crypto";
|
|
29864
31645
|
|
|
@@ -30111,7 +31892,7 @@ function parseCapture2(input, now) {
|
|
|
30111
31892
|
|
|
30112
31893
|
// src/meta.ts
|
|
30113
31894
|
var CLI_NAME = "do";
|
|
30114
|
-
var VERSION = "1.
|
|
31895
|
+
var VERSION = "1.305.0";
|
|
30115
31896
|
var API_PREFIX = "/api/v1";
|
|
30116
31897
|
var DEFAULT_API_URL = "http://localhost:3001";
|
|
30117
31898
|
|
|
@@ -30530,12 +32311,9 @@ function entityFromOperations(ops, spec) {
|
|
|
30530
32311
|
};
|
|
30531
32312
|
}
|
|
30532
32313
|
var ENTITIES = [
|
|
30533
|
-
{
|
|
32314
|
+
entityFromOperations(taskOperations, {
|
|
30534
32315
|
name: "tasks",
|
|
30535
|
-
path: "/tasks",
|
|
30536
|
-
readScopes: ["tasks:read"],
|
|
30537
32316
|
returns: "Task",
|
|
30538
|
-
canGet: true,
|
|
30539
32317
|
listFlags: [
|
|
30540
32318
|
{
|
|
30541
32319
|
name: "filter",
|
|
@@ -30577,21 +32355,12 @@ var ENTITIES = [
|
|
|
30577
32355
|
boolean: true
|
|
30578
32356
|
}
|
|
30579
32357
|
],
|
|
30580
|
-
|
|
30581
|
-
|
|
30582
|
-
|
|
30583
|
-
|
|
30584
|
-
updateSchema: updateTaskInputSchema,
|
|
30585
|
-
updateInput: "UpdateTaskInput",
|
|
30586
|
-
canDelete: true
|
|
30587
|
-
}
|
|
30588
|
-
},
|
|
30589
|
-
{
|
|
32358
|
+
createInput: "CreateTaskInput",
|
|
32359
|
+
updateInput: "UpdateTaskInput"
|
|
32360
|
+
}),
|
|
32361
|
+
entityFromOperations(habitOperations, {
|
|
30590
32362
|
name: "habits",
|
|
30591
|
-
path: "/habits",
|
|
30592
|
-
readScopes: ["habits:read"],
|
|
30593
32363
|
returns: "HabitSummary",
|
|
30594
|
-
canGet: true,
|
|
30595
32364
|
listFlags: [
|
|
30596
32365
|
AREA_FLAG,
|
|
30597
32366
|
UPDATED_SINCE_FLAG,
|
|
@@ -30600,15 +32369,9 @@ var ENTITIES = [
|
|
|
30600
32369
|
description: "list the Grown shelf (retired habits) instead of the growing ones"
|
|
30601
32370
|
}
|
|
30602
32371
|
],
|
|
30603
|
-
|
|
30604
|
-
|
|
30605
|
-
|
|
30606
|
-
createInput: "CreateHabitInput",
|
|
30607
|
-
updateSchema: updateHabitInputSchema,
|
|
30608
|
-
updateInput: "UpdateHabitInput",
|
|
30609
|
-
canDelete: true
|
|
30610
|
-
}
|
|
30611
|
-
},
|
|
32372
|
+
createInput: "CreateHabitInput",
|
|
32373
|
+
updateInput: "UpdateHabitInput"
|
|
32374
|
+
}),
|
|
30612
32375
|
{
|
|
30613
32376
|
name: "projects",
|
|
30614
32377
|
path: "/projects",
|
|
@@ -30673,22 +32436,13 @@ var ENTITIES = [
|
|
|
30673
32436
|
canDelete: true
|
|
30674
32437
|
}
|
|
30675
32438
|
},
|
|
30676
|
-
{
|
|
32439
|
+
entityFromOperations(routineOperations, {
|
|
30677
32440
|
name: "routines",
|
|
30678
|
-
path: "/routines",
|
|
30679
|
-
readScopes: ["routines:read"],
|
|
30680
32441
|
returns: "RoutineView",
|
|
30681
|
-
canGet: true,
|
|
30682
32442
|
listFlags: [],
|
|
30683
|
-
|
|
30684
|
-
|
|
30685
|
-
|
|
30686
|
-
createInput: "CreateRoutineInput",
|
|
30687
|
-
updateSchema: updateRoutineInputSchema,
|
|
30688
|
-
updateInput: "UpdateRoutineInput",
|
|
30689
|
-
canDelete: true
|
|
30690
|
-
}
|
|
30691
|
-
},
|
|
32443
|
+
createInput: "CreateRoutineInput",
|
|
32444
|
+
updateInput: "UpdateRoutineInput"
|
|
32445
|
+
}),
|
|
30692
32446
|
{
|
|
30693
32447
|
name: "notes",
|
|
30694
32448
|
path: "/notes",
|
|
@@ -30820,12 +32574,9 @@ var ENTITIES = [
|
|
|
30820
32574
|
canDelete: true
|
|
30821
32575
|
}
|
|
30822
32576
|
},
|
|
30823
|
-
{
|
|
32577
|
+
entityFromOperations(householdOperations, {
|
|
30824
32578
|
name: "households",
|
|
30825
|
-
path: "/households",
|
|
30826
|
-
readScopes: ["contacts:read"],
|
|
30827
32579
|
returns: "HouseholdView",
|
|
30828
|
-
canGet: true,
|
|
30829
32580
|
listFlags: [
|
|
30830
32581
|
{
|
|
30831
32582
|
name: "contact",
|
|
@@ -30833,15 +32584,9 @@ var ENTITIES = [
|
|
|
30833
32584
|
query: "contactId"
|
|
30834
32585
|
}
|
|
30835
32586
|
],
|
|
30836
|
-
|
|
30837
|
-
|
|
30838
|
-
|
|
30839
|
-
createInput: "CreateHouseholdInput",
|
|
30840
|
-
updateSchema: updateHouseholdInputSchema,
|
|
30841
|
-
updateInput: "UpdateHouseholdInput",
|
|
30842
|
-
canDelete: true
|
|
30843
|
-
}
|
|
30844
|
-
},
|
|
32587
|
+
createInput: "CreateHouseholdInput",
|
|
32588
|
+
updateInput: "UpdateHouseholdInput"
|
|
32589
|
+
}),
|
|
30845
32590
|
{
|
|
30846
32591
|
name: "guest-lists",
|
|
30847
32592
|
path: "/guest-lists",
|
|
@@ -30858,80 +32603,44 @@ var ENTITIES = [
|
|
|
30858
32603
|
canDelete: true
|
|
30859
32604
|
}
|
|
30860
32605
|
},
|
|
30861
|
-
{
|
|
32606
|
+
entityFromOperations(guestListEventOperations, {
|
|
30862
32607
|
name: "guest-list-events",
|
|
30863
|
-
path: "/guest-list-events",
|
|
30864
|
-
readScopes: ["contacts:read"],
|
|
30865
32608
|
returns: "GuestListEvent",
|
|
30866
|
-
canGet: true,
|
|
30867
32609
|
listFlags: [
|
|
30868
32610
|
{ name: "list", description: "the guest list's id (required)", query: "guestListId" }
|
|
30869
32611
|
],
|
|
30870
|
-
|
|
30871
|
-
|
|
30872
|
-
|
|
30873
|
-
|
|
30874
|
-
updateSchema: updateGuestListEventInputSchema,
|
|
30875
|
-
updateInput: "UpdateGuestListEventInput",
|
|
30876
|
-
canDelete: true
|
|
30877
|
-
}
|
|
30878
|
-
},
|
|
30879
|
-
{
|
|
32612
|
+
createInput: "CreateGuestListEventInput",
|
|
32613
|
+
updateInput: "UpdateGuestListEventInput"
|
|
32614
|
+
}),
|
|
32615
|
+
entityFromOperations(guestTableOperations, {
|
|
30880
32616
|
name: "guest-tables",
|
|
30881
|
-
path: "/guest-tables",
|
|
30882
|
-
readScopes: ["contacts:read"],
|
|
30883
32617
|
returns: "GuestTableView",
|
|
30884
|
-
canGet: true,
|
|
30885
32618
|
listFlags: [
|
|
30886
32619
|
{ name: "list", description: "the guest list's id (required)", query: "guestListId" }
|
|
30887
32620
|
],
|
|
30888
|
-
|
|
30889
|
-
|
|
30890
|
-
|
|
30891
|
-
|
|
30892
|
-
updateSchema: updateGuestTableInputSchema,
|
|
30893
|
-
updateInput: "UpdateGuestTableInput",
|
|
30894
|
-
canDelete: true
|
|
30895
|
-
}
|
|
30896
|
-
},
|
|
30897
|
-
{
|
|
32621
|
+
createInput: "CreateGuestTableInput",
|
|
32622
|
+
updateInput: "UpdateGuestTableInput"
|
|
32623
|
+
}),
|
|
32624
|
+
entityFromOperations(rsvpQuestionOperations, {
|
|
30898
32625
|
name: "rsvp-questions",
|
|
30899
|
-
path: "/rsvp-questions",
|
|
30900
|
-
readScopes: ["contacts:read"],
|
|
30901
32626
|
returns: "RsvpQuestion",
|
|
30902
|
-
canGet: true,
|
|
30903
32627
|
listFlags: [
|
|
30904
32628
|
{ name: "list", description: "the guest list's id (required)", query: "guestListId" }
|
|
30905
32629
|
],
|
|
30906
|
-
|
|
30907
|
-
|
|
30908
|
-
|
|
30909
|
-
|
|
30910
|
-
updateSchema: updateRsvpQuestionInputSchema,
|
|
30911
|
-
updateInput: "UpdateRsvpQuestionInput",
|
|
30912
|
-
canDelete: true
|
|
30913
|
-
}
|
|
30914
|
-
},
|
|
30915
|
-
{
|
|
32630
|
+
createInput: "CreateRsvpQuestionInput",
|
|
32631
|
+
updateInput: "UpdateRsvpQuestionInput"
|
|
32632
|
+
}),
|
|
32633
|
+
entityFromOperations(guestOperations, {
|
|
30916
32634
|
name: "guests",
|
|
30917
|
-
path: "/guests",
|
|
30918
|
-
readScopes: ["contacts:read"],
|
|
30919
32635
|
returns: "GuestView",
|
|
30920
|
-
canGet: true,
|
|
30921
32636
|
listFlags: [
|
|
30922
32637
|
{ name: "list", description: "only this guest list's guests", query: "guestListId" },
|
|
30923
32638
|
{ name: "contact", description: "only this contact's guest rows", query: "contactId" },
|
|
30924
32639
|
{ name: "state", description: "yes, no, maybe or waiting (overall)", query: "state" }
|
|
30925
32640
|
],
|
|
30926
|
-
|
|
30927
|
-
|
|
30928
|
-
|
|
30929
|
-
createInput: "CreateGuestInput",
|
|
30930
|
-
updateSchema: updateGuestInputSchema,
|
|
30931
|
-
updateInput: "UpdateGuestInput",
|
|
30932
|
-
canDelete: true
|
|
30933
|
-
}
|
|
30934
|
-
},
|
|
32641
|
+
createInput: "CreateGuestInput",
|
|
32642
|
+
updateInput: "UpdateGuestInput"
|
|
32643
|
+
}),
|
|
30935
32644
|
{
|
|
30936
32645
|
name: "key-dates",
|
|
30937
32646
|
path: "/key-dates",
|
|
@@ -31137,12 +32846,9 @@ var ENTITIES = [
|
|
|
31137
32846
|
createInput: "CreateMealPlanInput",
|
|
31138
32847
|
updateInput: "UpdateMealPlanInput"
|
|
31139
32848
|
}),
|
|
31140
|
-
{
|
|
32849
|
+
entityFromOperations({ list: occurrenceOperations.list }, {
|
|
31141
32850
|
name: "occurrences",
|
|
31142
|
-
path: "/occurrences",
|
|
31143
|
-
readScopes: ["occurrences:read"],
|
|
31144
32851
|
returns: "Occurrence",
|
|
31145
|
-
canGet: false,
|
|
31146
32852
|
listFlags: [
|
|
31147
32853
|
{
|
|
31148
32854
|
name: "template-id",
|
|
@@ -31151,7 +32857,7 @@ var ENTITIES = [
|
|
|
31151
32857
|
query: "templateId"
|
|
31152
32858
|
}
|
|
31153
32859
|
]
|
|
31154
|
-
},
|
|
32860
|
+
}),
|
|
31155
32861
|
{
|
|
31156
32862
|
name: "time-blocks",
|
|
31157
32863
|
path: "/time-blocks",
|
|
@@ -31175,30 +32881,14 @@ var ENTITIES = [
|
|
|
31175
32881
|
canDelete: true
|
|
31176
32882
|
}
|
|
31177
32883
|
},
|
|
31178
|
-
{
|
|
32884
|
+
entityFromOperations(blockTemplateOperations, {
|
|
31179
32885
|
name: "block-templates",
|
|
31180
|
-
path: "/block-templates",
|
|
31181
|
-
readScopes: ["calendar:read"],
|
|
31182
32886
|
returns: "BlockTemplateView",
|
|
31183
|
-
canGet: true,
|
|
31184
32887
|
listFlags: [],
|
|
31185
|
-
|
|
31186
|
-
|
|
31187
|
-
|
|
31188
|
-
|
|
31189
|
-
updateSchema: updateBlockTemplateInputSchema,
|
|
31190
|
-
updateInput: "UpdateBlockTemplateInput",
|
|
31191
|
-
canDelete: true
|
|
31192
|
-
}
|
|
31193
|
-
},
|
|
31194
|
-
{
|
|
31195
|
-
name: "webhooks",
|
|
31196
|
-
path: "/webhooks",
|
|
31197
|
-
readScopes: ["webhooks:read"],
|
|
31198
|
-
returns: "WebhookSubscription",
|
|
31199
|
-
canGet: true,
|
|
31200
|
-
listFlags: []
|
|
31201
|
-
}
|
|
32888
|
+
createInput: "CreateBlockTemplateInput",
|
|
32889
|
+
updateInput: "UpdateBlockTemplateInput"
|
|
32890
|
+
}),
|
|
32891
|
+
entityFromOperations({ list: webhookOperations.list, get: webhookOperations.get }, { name: "webhooks", returns: "WebhookSubscription", listFlags: [] })
|
|
31202
32892
|
];
|
|
31203
32893
|
var entityByName = (name) => ENTITIES.find((e) => e.name === name);
|
|
31204
32894
|
function entityOperations(e) {
|
|
@@ -31628,18 +33318,18 @@ var HEALTH_COMMAND_SPECS = [
|
|
|
31628
33318
|
summary: "Whether your Google Health is connected, the last sync, and what stops it.",
|
|
31629
33319
|
args: [],
|
|
31630
33320
|
flags: [],
|
|
31631
|
-
scopes:
|
|
33321
|
+
scopes: [...googleHealthOperations.status.scopes],
|
|
31632
33322
|
returns: "GoogleHealthStatus",
|
|
31633
|
-
notes:
|
|
33323
|
+
notes: `${routeOf(googleHealthOperations.status)}. Connecting needs Google's consent in a browser: Settings \u2192 Health in do. \`failure\` (reauth, not_linked, unavailable, other) says what stops the sync, with a title and a hint. \`nutrition\` says whether your food is written back to Google Health (turned on in do; each settled day once, one entry per meal type) and the last day written.`
|
|
31634
33324
|
},
|
|
31635
33325
|
{
|
|
31636
33326
|
path: ["health", "google", "sync"],
|
|
31637
33327
|
summary: "Sync your Google Health now (sleep, resting heart rate, HRV, steps, workouts), as the morning sync does.",
|
|
31638
33328
|
args: [],
|
|
31639
33329
|
flags: [],
|
|
31640
|
-
scopes:
|
|
33330
|
+
scopes: [...googleHealthOperations.sync.scopes],
|
|
31641
33331
|
returns: "GoogleHealthSyncResult",
|
|
31642
|
-
notes:
|
|
33332
|
+
notes: `${routeOf(googleHealthOperations.sync)}. Written and skipped per resource, and the status after it; a sync that stops answers 200 with \`status.failure\`. 409 before Google Health is connected, 403 while the server has it switched off.`
|
|
31643
33333
|
},
|
|
31644
33334
|
{
|
|
31645
33335
|
path: ["health", "withings", "status"],
|
|
@@ -31923,9 +33613,9 @@ var COMMAND_SPECS = [
|
|
|
31923
33613
|
summary: "From earlier: planned tasks of the last 14 days that weren't done, newest first, and the day Later this week lands on.",
|
|
31924
33614
|
args: [],
|
|
31925
33615
|
flags: [{ name: "area", type: "string", description: "Only tasks in this Area (id)." }],
|
|
31926
|
-
scopes: [
|
|
33616
|
+
scopes: [...todayOperations.fromEarlier.scopes],
|
|
31927
33617
|
returns: "FromEarlierResponse",
|
|
31928
|
-
notes:
|
|
33618
|
+
notes: `${routeOf(todayOperations.fromEarlier)}, from your local day. Nothing here is late: timed tasks, time blocks and agents' work never roll, and a plan older than 14 days just waits where it was filed. Answer with \`do today answer\`.`
|
|
31929
33619
|
},
|
|
31930
33620
|
{
|
|
31931
33621
|
path: ["today", "answer"],
|
|
@@ -32406,27 +34096,27 @@ var COMMAND_SPECS = [
|
|
|
32406
34096
|
summary: "Drop a task: status cancelled, never counted as Landed.",
|
|
32407
34097
|
args: [{ name: "id", required: true, description: "Task ULID." }],
|
|
32408
34098
|
flags: [],
|
|
32409
|
-
scopes: [
|
|
34099
|
+
scopes: [...taskOperations.cancel.scopes],
|
|
32410
34100
|
returns: "Task",
|
|
32411
|
-
notes:
|
|
34101
|
+
notes: `${routeOf(taskOperations.cancel)}. Use this, not \`task done\`, for a dropped task.`
|
|
32412
34102
|
},
|
|
32413
34103
|
{
|
|
32414
34104
|
path: ["tasks", "accept"],
|
|
32415
34105
|
summary: "Accept a task Proposed by the agent: it joins the plan as suggested (day, Deadline, Area kept).",
|
|
32416
34106
|
args: [{ name: "id", required: true, description: "Task ULID." }],
|
|
32417
34107
|
flags: [],
|
|
32418
|
-
scopes: [
|
|
34108
|
+
scopes: [...taskOperations.accept.scopes],
|
|
32419
34109
|
returns: "Task",
|
|
32420
|
-
notes:
|
|
34110
|
+
notes: `${routeOf(taskOperations.accept)} (#889). A no-op on a task that isn't a proposal. List proposals with \`do tasks list --proposed\`.`
|
|
32421
34111
|
},
|
|
32422
34112
|
{
|
|
32423
34113
|
path: ["tasks", "dismiss"],
|
|
32424
34114
|
summary: "Not now on a task Proposed by the agent: it leaves the Inbox for a week, still proposed.",
|
|
32425
34115
|
args: [{ name: "id", required: true, description: "Task ULID." }],
|
|
32426
34116
|
flags: [],
|
|
32427
|
-
scopes: [
|
|
34117
|
+
scopes: [...taskOperations.notNow.scopes],
|
|
32428
34118
|
returns: "Task",
|
|
32429
|
-
notes:
|
|
34119
|
+
notes: `${routeOf(taskOperations.notNow)} (#889); 409 when the task isn't a proposal. Let go is \`do task cancel\`.`
|
|
32430
34120
|
},
|
|
32431
34121
|
{
|
|
32432
34122
|
path: ["block-templates", "week"],
|
|
@@ -32435,18 +34125,18 @@ var COMMAND_SPECS = [
|
|
|
32435
34125
|
flags: [
|
|
32436
34126
|
{ name: "start", type: "string", description: "The week's Monday (YYYY-MM-DD). Required." }
|
|
32437
34127
|
],
|
|
32438
|
-
scopes: [
|
|
34128
|
+
scopes: [...blockTemplateOperations.week.scopes],
|
|
32439
34129
|
returns: "BlockTemplateInstance[]",
|
|
32440
|
-
notes:
|
|
34130
|
+
notes: `${routeOf(blockTemplateOperations.week)}?start= (plan vs record, phase 1).`
|
|
32441
34131
|
},
|
|
32442
34132
|
{
|
|
32443
34133
|
path: ["block-templates", "defaults"],
|
|
32444
34134
|
summary: "Give a member with no block templates the default week (sleep, morning, work, meals, a free evening). A no-op when they have templates.",
|
|
32445
34135
|
args: [],
|
|
32446
34136
|
flags: [],
|
|
32447
|
-
scopes: [
|
|
34137
|
+
scopes: [...blockTemplateOperations.defaults.scopes],
|
|
32448
34138
|
returns: "BlockTemplateView[]",
|
|
32449
|
-
notes:
|
|
34139
|
+
notes: `${routeOf(blockTemplateOperations.defaults)} (plan vs record, phase 1).`
|
|
32450
34140
|
},
|
|
32451
34141
|
{
|
|
32452
34142
|
path: ["time-blocks", "record"],
|
|
@@ -32584,18 +34274,18 @@ var COMMAND_SPECS = [
|
|
|
32584
34274
|
},
|
|
32585
34275
|
{ name: "for", type: "string", description: "Only this member's plans (user id)." }
|
|
32586
34276
|
],
|
|
32587
|
-
scopes: [
|
|
34277
|
+
scopes: [...planOperations.list.scopes],
|
|
32588
34278
|
returns: "Plan[]",
|
|
32589
|
-
notes:
|
|
34279
|
+
notes: `${routeOf(planOperations.list)} (#912): the latest 20.`
|
|
32590
34280
|
},
|
|
32591
34281
|
{
|
|
32592
34282
|
path: ["plans", "get"],
|
|
32593
34283
|
summary: "One plan proposal with its items and each item's task as it is now.",
|
|
32594
34284
|
args: [{ name: "id", required: true, description: "Plan id." }],
|
|
32595
34285
|
flags: [],
|
|
32596
|
-
scopes: [
|
|
34286
|
+
scopes: [...planOperations.get.scopes],
|
|
32597
34287
|
returns: "Plan",
|
|
32598
|
-
notes:
|
|
34288
|
+
notes: `${routeOf(planOperations.get)} (#912).`
|
|
32599
34289
|
},
|
|
32600
34290
|
{
|
|
32601
34291
|
path: ["plans", "propose"],
|
|
@@ -32608,9 +34298,9 @@ var COMMAND_SPECS = [
|
|
|
32608
34298
|
description: 'The CreatePlanInput as JSON: {"kind":"week","startsOn":"2026-10-19","note":"\u2026","items":[{"taskId":"\u2026","day":"2026-10-20","reason":"Deadline Friday"},{"taskId":"\u2026","at":"2026-10-21T09:00:00Z","durationMinutes":45},{"taskId":"\u2026","action":"someday"},{"taskId":"\u2026","action":"let_go"}],"blocks":[{"templateId":"\u2026","lifeKind":"meal","startAt":"2026-10-19T10:30:00Z","endAt":"2026-10-19T11:30:00Z"}]}. Blocks are life blocks (lay a week out with `do block-templates week`); a plan needs at least one item or block.'
|
|
32609
34299
|
}
|
|
32610
34300
|
],
|
|
32611
|
-
scopes: [
|
|
34301
|
+
scopes: [...planOperations.create.scopes],
|
|
32612
34302
|
returns: "Plan",
|
|
32613
|
-
notes:
|
|
34303
|
+
notes: `${routeOf(planOperations.create)} (#912). A week starts on a Monday; days are the member's, times are ISO instants inside the week. \`forUserId\` names the member (default: the member the key acts for). A newer plan for the same week or day replaces the open one.`
|
|
32614
34304
|
},
|
|
32615
34305
|
{
|
|
32616
34306
|
path: ["plans", "accept"],
|
|
@@ -32620,9 +34310,9 @@ var COMMAND_SPECS = [
|
|
|
32620
34310
|
{ name: "items", required: false, description: "Item ids (default: every proposed item)." }
|
|
32621
34311
|
],
|
|
32622
34312
|
flags: [],
|
|
32623
|
-
scopes: [
|
|
34313
|
+
scopes: [...planOperations.accept.scopes],
|
|
32624
34314
|
returns: "Plan",
|
|
32625
|
-
notes:
|
|
34315
|
+
notes: `${routeOf(planOperations.accept)} (#912). Undo with \`do plans undo\`.`
|
|
32626
34316
|
},
|
|
32627
34317
|
{
|
|
32628
34318
|
path: ["plans", "dismiss"],
|
|
@@ -32632,9 +34322,9 @@ var COMMAND_SPECS = [
|
|
|
32632
34322
|
{ name: "items", required: false, description: "Item ids (default: every proposed item)." }
|
|
32633
34323
|
],
|
|
32634
34324
|
flags: [],
|
|
32635
|
-
scopes: [
|
|
34325
|
+
scopes: [...planOperations.dismiss.scopes],
|
|
32636
34326
|
returns: "Plan",
|
|
32637
|
-
notes:
|
|
34327
|
+
notes: `${routeOf(planOperations.dismiss)} (#912). Nothing is written to a task.`
|
|
32638
34328
|
},
|
|
32639
34329
|
{
|
|
32640
34330
|
path: ["plans", "undo"],
|
|
@@ -32644,9 +34334,9 @@ var COMMAND_SPECS = [
|
|
|
32644
34334
|
{ name: "items", required: false, description: "Item ids (default: every answered item)." }
|
|
32645
34335
|
],
|
|
32646
34336
|
flags: [],
|
|
32647
|
-
scopes: [
|
|
34337
|
+
scopes: [...planOperations.undo.scopes],
|
|
32648
34338
|
returns: "Plan",
|
|
32649
|
-
notes:
|
|
34339
|
+
notes: `${routeOf(planOperations.undo)} (#912). The items read as proposed again.`
|
|
32650
34340
|
},
|
|
32651
34341
|
{
|
|
32652
34342
|
path: ["plan", "rules", "list"],
|
|
@@ -32660,9 +34350,9 @@ var COMMAND_SPECS = [
|
|
|
32660
34350
|
description: "fixed_time, keep_free, meaning, whose, limit or note."
|
|
32661
34351
|
}
|
|
32662
34352
|
],
|
|
32663
|
-
scopes: [
|
|
34353
|
+
scopes: [...planningRuleOperations.list.scopes],
|
|
32664
34354
|
returns: "PlanningRule[]",
|
|
32665
|
-
notes:
|
|
34355
|
+
notes: `${routeOf(planningRuleOperations.list)}. Oldest first; \`addedByAgent\` marks the ones an agent added.`
|
|
32666
34356
|
},
|
|
32667
34357
|
{
|
|
32668
34358
|
path: ["plan", "rules", "add"],
|
|
@@ -32680,9 +34370,9 @@ var COMMAND_SPECS = [
|
|
|
32680
34370
|
description: "The member it is for (user id; default: the member the key acts for)."
|
|
32681
34371
|
}
|
|
32682
34372
|
],
|
|
32683
|
-
scopes: [
|
|
34373
|
+
scopes: [...planningRuleOperations.create.scopes],
|
|
32684
34374
|
returns: "PlanningRule",
|
|
32685
|
-
notes:
|
|
34375
|
+
notes: `${routeOf(planningRuleOperations.create)}. \`forUserId\` (--for) names the member; a rule without --rule is a note.`
|
|
32686
34376
|
},
|
|
32687
34377
|
{
|
|
32688
34378
|
path: ["plan", "rules", "update"],
|
|
@@ -32696,18 +34386,18 @@ var COMMAND_SPECS = [
|
|
|
32696
34386
|
description: "The new structured part as JSON (see `plan rules add`), or `none` to make it a note."
|
|
32697
34387
|
}
|
|
32698
34388
|
],
|
|
32699
|
-
scopes: [
|
|
34389
|
+
scopes: [...planningRuleOperations.update.scopes],
|
|
32700
34390
|
returns: "PlanningRule",
|
|
32701
|
-
notes:
|
|
34391
|
+
notes: `${routeOf(planningRuleOperations.update)}.`
|
|
32702
34392
|
},
|
|
32703
34393
|
{
|
|
32704
34394
|
path: ["plan", "rules", "remove"],
|
|
32705
34395
|
summary: "Remove a planning rule (to the trash).",
|
|
32706
34396
|
args: [{ name: "id", required: true, description: "Rule id." }],
|
|
32707
34397
|
flags: [],
|
|
32708
|
-
scopes: [
|
|
34398
|
+
scopes: [...planningRuleOperations.remove.scopes],
|
|
32709
34399
|
returns: "void",
|
|
32710
|
-
notes:
|
|
34400
|
+
notes: `${routeOf(planningRuleOperations.remove)}. Destructive: needs --allow-destructive.`
|
|
32711
34401
|
},
|
|
32712
34402
|
{
|
|
32713
34403
|
path: ["tasks", "ready"],
|
|
@@ -32720,16 +34410,16 @@ var COMMAND_SPECS = [
|
|
|
32720
34410
|
description: `What's ready, in a line, with a link when there is one ("Draft ready: 38 hours, 3,420 euro \u2014 https://\u2026"); at most 500 characters. Absent keeps the note already there.`
|
|
32721
34411
|
}
|
|
32722
34412
|
],
|
|
32723
|
-
scopes: [
|
|
34413
|
+
scopes: [...taskOperations.ready.scopes],
|
|
32724
34414
|
returns: "Task",
|
|
32725
|
-
notes:
|
|
34415
|
+
notes: `${routeOf(taskOperations.ready)} (#902); 409 when the task is done or let go. It reaches Now's Needs you with Review (Looks good = done, Send back = \`ready: false\`). List them with \`do tasks list --ready\`.`
|
|
32726
34416
|
},
|
|
32727
34417
|
{
|
|
32728
34418
|
path: ["task", "reopen"],
|
|
32729
34419
|
summary: "Reopen a done or cancelled task (status todo; clears completedAt).",
|
|
32730
34420
|
args: [{ name: "id", required: true, description: "Task ULID." }],
|
|
32731
34421
|
flags: [],
|
|
32732
|
-
scopes: [
|
|
34422
|
+
scopes: [...taskOperations.update.scopes],
|
|
32733
34423
|
returns: "Task"
|
|
32734
34424
|
},
|
|
32735
34425
|
{
|
|
@@ -32749,7 +34439,7 @@ var COMMAND_SPECS = [
|
|
|
32749
34439
|
description: "How long it takes, in minutes (sets durationMinutes)."
|
|
32750
34440
|
}
|
|
32751
34441
|
],
|
|
32752
|
-
scopes: [
|
|
34442
|
+
scopes: [...taskOperations.update.scopes],
|
|
32753
34443
|
returns: "Task"
|
|
32754
34444
|
},
|
|
32755
34445
|
{
|
|
@@ -32768,7 +34458,7 @@ var COMMAND_SPECS = [
|
|
|
32768
34458
|
description: "How long it takes, in minutes (sets durationMinutes)."
|
|
32769
34459
|
}
|
|
32770
34460
|
],
|
|
32771
|
-
scopes: [
|
|
34461
|
+
scopes: [...taskOperations.update.scopes],
|
|
32772
34462
|
returns: "Task"
|
|
32773
34463
|
},
|
|
32774
34464
|
{
|
|
@@ -32789,7 +34479,7 @@ var COMMAND_SPECS = [
|
|
|
32789
34479
|
description: 'A short note on the check-in ("felt heavy"), at most 280 characters.'
|
|
32790
34480
|
}
|
|
32791
34481
|
],
|
|
32792
|
-
scopes: [
|
|
34482
|
+
scopes: [...habitOperations.checkIn.scopes],
|
|
32793
34483
|
returns: "HabitSummary"
|
|
32794
34484
|
},
|
|
32795
34485
|
{
|
|
@@ -32816,7 +34506,7 @@ var COMMAND_SPECS = [
|
|
|
32816
34506
|
description: 'A short note on the check-in ("felt heavy"), at most 280 characters.'
|
|
32817
34507
|
}
|
|
32818
34508
|
],
|
|
32819
|
-
scopes: [
|
|
34509
|
+
scopes: [...habitOperations.checkInByTitle.scopes],
|
|
32820
34510
|
returns: "HabitSummary",
|
|
32821
34511
|
notes: `POST /api/v1/habits/check-in. Title or alias, case-insensitive; several matches \u2192 409 with error.details.candidates (id, title, aliases), none \u2192 404 naming close titles; a habit counted from Google Fit, Strava or GitHub \u2192 409. --set writes the difference to the day's total as its own check-in. An Agent's key records the check-in as that Agent's ("<agent>, 07:12"). --note puts a short note on it ("drill done, felt heavy" \u2192 --note "felt heavy"); the reply's lastCheckIn.id is the check-in, for \`do habit note\` later.`
|
|
32822
34512
|
},
|
|
@@ -32828,7 +34518,7 @@ var COMMAND_SPECS = [
|
|
|
32828
34518
|
{ name: "alias", required: true, description: "The other name." }
|
|
32829
34519
|
],
|
|
32830
34520
|
flags: [],
|
|
32831
|
-
scopes: [
|
|
34521
|
+
scopes: [...habitOperations.addAlias.scopes],
|
|
32832
34522
|
returns: "HabitSummary",
|
|
32833
34523
|
notes: "POST /api/v1/habits/:id/aliases. One already there (ignoring case) is a no-op; at most 12."
|
|
32834
34524
|
},
|
|
@@ -32840,7 +34530,7 @@ var COMMAND_SPECS = [
|
|
|
32840
34530
|
{ name: "alias", required: true, description: "The alias to drop (ignoring case)." }
|
|
32841
34531
|
],
|
|
32842
34532
|
flags: [],
|
|
32843
|
-
scopes: [
|
|
34533
|
+
scopes: [...habitOperations.removeAlias.scopes],
|
|
32844
34534
|
returns: "HabitSummary",
|
|
32845
34535
|
notes: "DELETE /api/v1/habits/:id/aliases/:alias. 404 when the habit doesn't have it."
|
|
32846
34536
|
},
|
|
@@ -32849,9 +34539,9 @@ var COMMAND_SPECS = [
|
|
|
32849
34539
|
summary: "What's left today: the habits due by part of day, and today's routines.",
|
|
32850
34540
|
args: [],
|
|
32851
34541
|
flags: [],
|
|
32852
|
-
scopes: [
|
|
34542
|
+
scopes: [...habitOperations.today.scopes],
|
|
32853
34543
|
returns: "HabitsTodayResponse",
|
|
32854
|
-
notes:
|
|
34544
|
+
notes: `${routeOf(habitOperations.today)}. Your saved time zone's day; already filtered by schedule. Each habit says done/open/skipped (never overdue), its value today, the week for an N-per-week habit and its last check-in (\`by\` names the Agent). Quit habits are left out.`
|
|
32855
34545
|
},
|
|
32856
34546
|
{
|
|
32857
34547
|
path: ["habit", "check-ins"],
|
|
@@ -32861,7 +34551,7 @@ var COMMAND_SPECS = [
|
|
|
32861
34551
|
{ name: "before", type: "string", description: "Only check-ins before this instant (ISO)." },
|
|
32862
34552
|
{ name: "limit", type: "string", description: "Page size 1\u2013200 (default 50)." }
|
|
32863
34553
|
],
|
|
32864
|
-
scopes: [
|
|
34554
|
+
scopes: [...habitOperations.listCheckIns.scopes],
|
|
32865
34555
|
returns: "HabitEntry"
|
|
32866
34556
|
},
|
|
32867
34557
|
{
|
|
@@ -32877,9 +34567,9 @@ var COMMAND_SPECS = [
|
|
|
32877
34567
|
{ name: "note", required: false, description: "The note, at most 280 characters." }
|
|
32878
34568
|
],
|
|
32879
34569
|
flags: [{ name: "clear", type: "boolean", description: "Drop the check-in's note." }],
|
|
32880
|
-
scopes: [
|
|
34570
|
+
scopes: [...habitOperations.updateCheckIn.scopes],
|
|
32881
34571
|
returns: "HabitEntry",
|
|
32882
|
-
notes:
|
|
34572
|
+
notes: `${routeOf(habitOperations.updateCheckIn)}. Replaces the note; the amount and time stay (undo a wrong check-in instead). A skip's note is its why.`
|
|
32883
34573
|
},
|
|
32884
34574
|
{
|
|
32885
34575
|
path: ["habit", "skip"],
|
|
@@ -32893,9 +34583,9 @@ var COMMAND_SPECS = [
|
|
|
32893
34583
|
description: 'Why, if you like ("Dentist"); shows in the log.'
|
|
32894
34584
|
}
|
|
32895
34585
|
],
|
|
32896
|
-
scopes: [
|
|
34586
|
+
scopes: [...habitOperations.skip.scopes],
|
|
32897
34587
|
returns: "HabitSummary",
|
|
32898
|
-
notes:
|
|
34588
|
+
notes: `${routeOf(habitOperations.skip)}. The streak treats the period as neutral and spends no grace; the habit leaves Now for the day. Skipping a skipped day changes nothing. Undo: delete the skip entry (\`do habit check-ins <id>\` lists it with kind \`skip\`).`
|
|
32899
34589
|
},
|
|
32900
34590
|
{
|
|
32901
34591
|
path: ["routine", "done"],
|
|
@@ -32908,9 +34598,9 @@ var COMMAND_SPECS = [
|
|
|
32908
34598
|
}
|
|
32909
34599
|
],
|
|
32910
34600
|
flags: [],
|
|
32911
|
-
scopes: [
|
|
34601
|
+
scopes: [...routineOperations.markDone.scopes],
|
|
32912
34602
|
returns: "RoutineDoneResult",
|
|
32913
|
-
notes:
|
|
34603
|
+
notes: `${routeOf(routineOperations.markDone)}. Today's run (your saved time zone's day), started if there's none. Each habit step checks in its habit; a habit already done today isn't counted twice; a step whose habit is skipped today is left alone. Calling it again changes nothing. Returns \`run\` and \`taken\` (the steps it resolved). Undo all of it with \`do routine undo <run.id> <taken stepRunIds\u2026>\`.`
|
|
32914
34604
|
},
|
|
32915
34605
|
{
|
|
32916
34606
|
path: ["routine", "undo"],
|
|
@@ -32928,9 +34618,9 @@ var COMMAND_SPECS = [
|
|
|
32928
34618
|
}
|
|
32929
34619
|
],
|
|
32930
34620
|
flags: [],
|
|
32931
|
-
scopes: [
|
|
34621
|
+
scopes: [...routineOperations.undoSteps.scopes],
|
|
32932
34622
|
returns: "RoutineRunView",
|
|
32933
|
-
notes:
|
|
34623
|
+
notes: `${routeOf(routineOperations.undoSteps)}. Exactly the check-ins those steps wrote are removed; a finished run reopens. Steps no longer done are left alone.`
|
|
32934
34624
|
},
|
|
32935
34625
|
{
|
|
32936
34626
|
path: ["habit", "pause"],
|
|
@@ -32943,9 +34633,9 @@ var COMMAND_SPECS = [
|
|
|
32943
34633
|
description: "The day it's back (YYYY-MM-DD), after today. Required."
|
|
32944
34634
|
}
|
|
32945
34635
|
],
|
|
32946
|
-
scopes: [
|
|
34636
|
+
scopes: [...habitOperations.pause.scopes],
|
|
32947
34637
|
returns: "HabitSummary",
|
|
32948
|
-
notes:
|
|
34638
|
+
notes: `${routeOf(habitOperations.pause)}. Pausing a paused habit moves the day it's back. Paused days are neutral: the streak is frozen, never broken.`
|
|
32949
34639
|
},
|
|
32950
34640
|
{
|
|
32951
34641
|
path: ["habit", "remind"],
|
|
@@ -32955,36 +34645,36 @@ var COMMAND_SPECS = [
|
|
|
32955
34645
|
{ name: "state", required: true, description: "`on` or `off`." }
|
|
32956
34646
|
],
|
|
32957
34647
|
flags: [],
|
|
32958
|
-
scopes: [
|
|
34648
|
+
scopes: [...habitOperations.update.scopes],
|
|
32959
34649
|
returns: "HabitSummary",
|
|
32960
|
-
notes:
|
|
34650
|
+
notes: `${routeOf(habitOperations.update)} {remind}. Off by default. On, the habit sends one Web Push a day at its time of day (a part of day: morning 08:00, midday 12:00, evening 18:00; none: 09:00), only in waking hours (07:00\u201322:00), with Done / +1 / Skip today buttons; not when it's done, skipped, paused or off today.`
|
|
32961
34651
|
},
|
|
32962
34652
|
{
|
|
32963
34653
|
path: ["habit", "resume"],
|
|
32964
34654
|
summary: "Resume a paused habit: it's back today.",
|
|
32965
34655
|
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
32966
34656
|
flags: [],
|
|
32967
|
-
scopes: [
|
|
34657
|
+
scopes: [...habitOperations.resume.scopes],
|
|
32968
34658
|
returns: "HabitSummary",
|
|
32969
|
-
notes:
|
|
34659
|
+
notes: `${routeOf(habitOperations.resume)}. The rest so far stays neutral.`
|
|
32970
34660
|
},
|
|
32971
34661
|
{
|
|
32972
34662
|
path: ["habit", "retire"],
|
|
32973
34663
|
summary: `Retire a habit to the Grown shelf ("I'm done with the cold showers habit"): history kept.`,
|
|
32974
34664
|
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
32975
34665
|
flags: [],
|
|
32976
|
-
scopes: [
|
|
34666
|
+
scopes: [...habitOperations.retire.scopes],
|
|
32977
34667
|
returns: "HabitSummary",
|
|
32978
|
-
notes:
|
|
34668
|
+
notes: `${routeOf(habitOperations.retire)}. Not a delete: it keeps every check-in and its plant blooms on the Grown shelf. It leaves Now and Today, sends no push, takes no check-in by title and is never due; Progress keeps its past. \`do habits list --retired\` lists the shelf. Undo: \`do habit unretire <id>\`.`
|
|
32979
34669
|
},
|
|
32980
34670
|
{
|
|
32981
34671
|
path: ["habit", "unretire"],
|
|
32982
34672
|
summary: "Bring a grown (retired) habit back: growing again from today.",
|
|
32983
34673
|
args: [{ name: "id", required: true, description: "Habit ULID." }],
|
|
32984
34674
|
flags: [],
|
|
32985
|
-
scopes: [
|
|
34675
|
+
scopes: [...habitOperations.unretire.scopes],
|
|
32986
34676
|
returns: "HabitSummary",
|
|
32987
|
-
notes:
|
|
34677
|
+
notes: `${routeOf(habitOperations.unretire)}. Its history is intact.`
|
|
32988
34678
|
},
|
|
32989
34679
|
{
|
|
32990
34680
|
path: ["away"],
|
|
@@ -33828,7 +35518,7 @@ var COMMAND_SPECS = [
|
|
|
33828
35518
|
summary: "List the Space's Agents (id + name).",
|
|
33829
35519
|
args: [],
|
|
33830
35520
|
flags: [],
|
|
33831
|
-
scopes: [
|
|
35521
|
+
scopes: [...agentOperations.list.scopes],
|
|
33832
35522
|
returns: "AgentSummary",
|
|
33833
35523
|
notes: "Creating an Agent and minting its keys stays a member's job in the app."
|
|
33834
35524
|
},
|
|
@@ -34145,7 +35835,7 @@ var COMMAND_SPECS = [
|
|
|
34145
35835
|
summary: "Show the caller's settings for the Space.",
|
|
34146
35836
|
args: [],
|
|
34147
35837
|
flags: [],
|
|
34148
|
-
scopes: [
|
|
35838
|
+
scopes: [...settingsOperations.get.scopes],
|
|
34149
35839
|
returns: "UserSettings",
|
|
34150
35840
|
notes: "Needs a key minted while logged in (it carries the user identity)."
|
|
34151
35841
|
},
|
|
@@ -34154,7 +35844,7 @@ var COMMAND_SPECS = [
|
|
|
34154
35844
|
summary: "Patch the caller's settings.",
|
|
34155
35845
|
args: [],
|
|
34156
35846
|
flags: [{ name: "data", type: "string", description: "JSON of fields to change." }],
|
|
34157
|
-
scopes: [
|
|
35847
|
+
scopes: [...settingsOperations.update.scopes],
|
|
34158
35848
|
returns: "UserSettings"
|
|
34159
35849
|
},
|
|
34160
35850
|
{
|
|
@@ -34312,9 +36002,9 @@ var COMMAND_SPECS = [
|
|
|
34312
36002
|
summary: "An asset's upkeep and repair Tasks, open ones first.",
|
|
34313
36003
|
args: [{ name: "id", required: true, description: "Asset (Collection Item) ULID." }],
|
|
34314
36004
|
flags: [],
|
|
34315
|
-
scopes: [
|
|
36005
|
+
scopes: [...collectionUpkeepOperations.list.scopes],
|
|
34316
36006
|
returns: "AssetUpkeep",
|
|
34317
|
-
notes:
|
|
36007
|
+
notes: `${routeOf(collectionUpkeepOperations.list)} (LifeOS House). Returns { itemId, upkeep, repairs }.`
|
|
34318
36008
|
},
|
|
34319
36009
|
{
|
|
34320
36010
|
path: ["collection", "link-task"],
|
|
@@ -34324,9 +36014,9 @@ var COMMAND_SPECS = [
|
|
|
34324
36014
|
{ name: "taskId", required: true, description: "Task ULID." }
|
|
34325
36015
|
],
|
|
34326
36016
|
flags: [{ name: "repair", type: "boolean", description: "A one-off repair, not upkeep." }],
|
|
34327
|
-
scopes: [
|
|
36017
|
+
scopes: [...collectionUpkeepOperations.link.scopes],
|
|
34328
36018
|
returns: "AssetUpkeep",
|
|
34329
|
-
notes:
|
|
36019
|
+
notes: `${routeOf(collectionUpkeepOperations.link)}. Make the Task (recurrence, Place, Area) first. Finishing it writes the asset's service / repair Entry by itself.`
|
|
34330
36020
|
},
|
|
34331
36021
|
{
|
|
34332
36022
|
path: ["collection", "unlink-task"],
|
|
@@ -34336,7 +36026,7 @@ var COMMAND_SPECS = [
|
|
|
34336
36026
|
{ name: "taskId", required: true, description: "Task ULID." }
|
|
34337
36027
|
],
|
|
34338
36028
|
flags: [],
|
|
34339
|
-
scopes: [
|
|
36029
|
+
scopes: [...collectionUpkeepOperations.unlink.scopes],
|
|
34340
36030
|
returns: "AssetUpkeep"
|
|
34341
36031
|
},
|
|
34342
36032
|
{
|
|
@@ -35183,6 +36873,35 @@ var COMMAND_SPECS = [
|
|
|
35183
36873
|
returns: "MoneyYear",
|
|
35184
36874
|
notes: "GET /api/v1/money/year. totals (income, spent, saved) and lastYear (the same months a year earlier, null with nothing booked then); months Jan\u2013Dec; spending and income by category, biggest first, each with lastYear; recurring streams with thisYear, lastYear and change (new \xB7 stopped \xB7 up \xB7 down \xB7 same); goals with what went toward them this year. A year under way counts to this month (through)."
|
|
35185
36875
|
},
|
|
36876
|
+
{
|
|
36877
|
+
path: ["money", "net-worth"],
|
|
36878
|
+
summary: "Net worth now and its month-end line (the accounts that count in it).",
|
|
36879
|
+
args: [],
|
|
36880
|
+
flags: [
|
|
36881
|
+
{ name: "scope", type: "string", description: "all (default) | space | owner." },
|
|
36882
|
+
{
|
|
36883
|
+
name: "months",
|
|
36884
|
+
type: "string",
|
|
36885
|
+
description: "How many months the line covers (2\u201360, default 12)."
|
|
36886
|
+
}
|
|
36887
|
+
],
|
|
36888
|
+
scopes: ["finance:read"],
|
|
36889
|
+
returns: "MoneyNetWorth",
|
|
36890
|
+
notes: "GET /api/v1/money/net-worth. total, have and owe this month; points per month (oldest first, total null before any value); accounts biggest first with value, source (balance \xB7 ledger \xB7 manual) and the month it's from. A loan or a card always counts as owed."
|
|
36891
|
+
},
|
|
36892
|
+
{
|
|
36893
|
+
path: ["money", "net-worth-set"],
|
|
36894
|
+
summary: "Set an account's value for a month by hand (a house, a car); again replaces it.",
|
|
36895
|
+
args: [{ name: "accountId", required: true, description: "Account ULID." }],
|
|
36896
|
+
flags: [
|
|
36897
|
+
{ name: "value", type: "string", description: "The value, e.g. 310000 or 1234.56." },
|
|
36898
|
+
{ name: "month", type: "string", description: "The month, YYYY-MM (default this month)." },
|
|
36899
|
+
{ name: "data", type: "string", description: "SetMoneyNetWorthValueInput JSON instead." }
|
|
36900
|
+
],
|
|
36901
|
+
scopes: ["finance:write"],
|
|
36902
|
+
returns: "MoneySnapshot",
|
|
36903
|
+
notes: "PUT /api/v1/money/net-worth/values. A month ahead is refused. This month's value also becomes the account's balance unless a bank link keeps it. `do money net-worth-set <accountId> --value 310000`."
|
|
36904
|
+
},
|
|
35186
36905
|
{
|
|
35187
36906
|
path: ["money", "goals"],
|
|
35188
36907
|
summary: "List money goals: what's saved toward each, soonest first.",
|
|
@@ -35639,63 +37358,63 @@ var COMMAND_SPECS = [
|
|
|
35639
37358
|
summary: "Whether the Space has linked Home Assistant, how many entities are mapped, the newest reading.",
|
|
35640
37359
|
args: [],
|
|
35641
37360
|
flags: [],
|
|
35642
|
-
scopes: [
|
|
37361
|
+
scopes: [...sensorOperations.status.scopes],
|
|
35643
37362
|
returns: "HomeAssistantStatus",
|
|
35644
|
-
notes:
|
|
37363
|
+
notes: `${routeOf(sensorOperations.status)}. Home Assistant is linked in the app's Settings \u2192 Home; the token is never returned.`
|
|
35645
37364
|
},
|
|
35646
37365
|
{
|
|
35647
37366
|
path: ["sensors", "entities"],
|
|
35648
37367
|
summary: "Every entity Home Assistant has, with its state, the reading it likely gives and what it's mapped to.",
|
|
35649
37368
|
args: [],
|
|
35650
37369
|
flags: [],
|
|
35651
|
-
scopes: [
|
|
37370
|
+
scopes: [...sensorOperations.entities.scopes],
|
|
35652
37371
|
returns: "HomeAssistantEntity[]",
|
|
35653
|
-
notes:
|
|
37372
|
+
notes: `${routeOf(sensorOperations.entities)}. 409 before Home Assistant is linked; 503 when it doesn't answer.`
|
|
35654
37373
|
},
|
|
35655
37374
|
{
|
|
35656
37375
|
path: ["sensors", "sync"],
|
|
35657
37376
|
summary: "Read every mapped entity now and put its state on the ledger, as the five-minute sync does.",
|
|
35658
37377
|
args: [],
|
|
35659
37378
|
flags: [],
|
|
35660
|
-
scopes: [
|
|
37379
|
+
scopes: [...sensorOperations.sync.scopes],
|
|
35661
37380
|
returns: "SensorSyncResult",
|
|
35662
|
-
notes:
|
|
37381
|
+
notes: `${routeOf(sensorOperations.sync)}. A room's readings feed its card and the room alarm; an asset's show on its page. Returns entities, written, skipped, missing and the error (unauthorized, unavailable, bad_response). 409 before Home Assistant is linked.`
|
|
35663
37382
|
},
|
|
35664
37383
|
{
|
|
35665
37384
|
path: ["sensors", "unifi"],
|
|
35666
37385
|
summary: "Whether the Space has linked UniFi, how many devices are mapped, the newest reading.",
|
|
35667
37386
|
args: [],
|
|
35668
37387
|
flags: [],
|
|
35669
|
-
scopes: [
|
|
37388
|
+
scopes: [...sensorOperations.unifiStatus.scopes],
|
|
35670
37389
|
returns: "UnifiStatus",
|
|
35671
|
-
notes:
|
|
37390
|
+
notes: `${routeOf(sensorOperations.unifiStatus)}. Linking UniFi (address + API key) is a member's, in Settings \u2192 Home; a key never sees the API key.`
|
|
35672
37391
|
},
|
|
35673
37392
|
{
|
|
35674
37393
|
path: ["sensors", "unifi-devices"],
|
|
35675
37394
|
summary: "Every device and connected client UniFi sees, with the asset each is mapped to.",
|
|
35676
37395
|
args: [],
|
|
35677
37396
|
flags: [],
|
|
35678
|
-
scopes: [
|
|
37397
|
+
scopes: [...sensorOperations.unifiDevices.scopes],
|
|
35679
37398
|
returns: "UnifiDevice[]",
|
|
35680
|
-
notes:
|
|
37399
|
+
notes: `${routeOf(sensorOperations.unifiDevices)}. Map one with \`do sensors map <mac> <asset> --reading presence --provider unifi\`, or give the asset \`external.unifiMac\` on its facet. 409 before UniFi is linked.`
|
|
35681
37400
|
},
|
|
35682
37401
|
{
|
|
35683
37402
|
path: ["sensors", "unifi-sync"],
|
|
35684
37403
|
summary: "Put every mapped device's presence (online/offline, firmware) on its asset now.",
|
|
35685
37404
|
args: [],
|
|
35686
37405
|
flags: [],
|
|
35687
|
-
scopes: [
|
|
37406
|
+
scopes: [...sensorOperations.syncUnifi.scopes],
|
|
35688
37407
|
returns: "SensorSyncResult",
|
|
35689
|
-
notes:
|
|
37408
|
+
notes: `${routeOf(sensorOperations.syncUnifi)}. Assets whose facet names a UniFi MAC are mapped first; readings land as asset.presence on change, else hourly. The worker does the same every five minutes. 409 before UniFi is linked.`
|
|
35690
37409
|
},
|
|
35691
37410
|
{
|
|
35692
37411
|
path: ["sensors", "links"],
|
|
35693
37412
|
summary: "The mapped entities, or the ones on one Place or asset.",
|
|
35694
37413
|
args: [],
|
|
35695
37414
|
flags: [{ name: "node", type: "string", description: "Only the mappings on this node ULID." }],
|
|
35696
|
-
scopes: [
|
|
37415
|
+
scopes: [...sensorOperations.links.scopes],
|
|
35697
37416
|
returns: "SensorLink[]",
|
|
35698
|
-
notes:
|
|
37417
|
+
notes: `${routeOf(sensorOperations.links)}.`
|
|
35699
37418
|
},
|
|
35700
37419
|
{
|
|
35701
37420
|
path: ["sensors", "map"],
|
|
@@ -35721,18 +37440,18 @@ var COMMAND_SPECS = [
|
|
|
35721
37440
|
},
|
|
35722
37441
|
{ name: "label", type: "string", description: "A name for it (Home Assistant's own)." }
|
|
35723
37442
|
],
|
|
35724
|
-
scopes: [
|
|
37443
|
+
scopes: [...sensorOperations.createLink.scopes],
|
|
35725
37444
|
returns: "SensorLink",
|
|
35726
|
-
notes:
|
|
37445
|
+
notes: `${routeOf(sensorOperations.createLink)}. An animal maps to the Place it's housed in (409 when it has none). Mapping an entity again moves it.`
|
|
35727
37446
|
},
|
|
35728
37447
|
{
|
|
35729
37448
|
path: ["sensors", "unmap"],
|
|
35730
37449
|
summary: "Unmap an entity; the readings it gave stay.",
|
|
35731
37450
|
args: [{ name: "link", required: true, description: "The sensor link ULID." }],
|
|
35732
37451
|
flags: [],
|
|
35733
|
-
scopes: [
|
|
37452
|
+
scopes: [...sensorOperations.removeLink.scopes],
|
|
35734
37453
|
returns: "None",
|
|
35735
|
-
notes:
|
|
37454
|
+
notes: `${routeOf(sensorOperations.removeLink)}.`
|
|
35736
37455
|
},
|
|
35737
37456
|
{
|
|
35738
37457
|
path: ["runs", "sessions", "list"],
|
|
@@ -35932,7 +37651,7 @@ var COMMAND_SPECS = [
|
|
|
35932
37651
|
summary: "Your Google Contacts, to pick from: who they'd merge into and what importing adds.",
|
|
35933
37652
|
args: [],
|
|
35934
37653
|
flags: [{ name: "q", type: "string", description: "A name or email to narrow to." }],
|
|
35935
|
-
scopes: [
|
|
37654
|
+
scopes: [...googleContactsOperations.list.scopes],
|
|
35936
37655
|
returns: "GoogleContactsList",
|
|
35937
37656
|
notes: "Connecting needs a browser (People \u2192 Import). Not connected: candidates is empty and status.connected false. A key with no member is forbidden."
|
|
35938
37657
|
},
|
|
@@ -35947,7 +37666,7 @@ var COMMAND_SPECS = [
|
|
|
35947
37666
|
}
|
|
35948
37667
|
],
|
|
35949
37668
|
flags: [],
|
|
35950
|
-
scopes: [
|
|
37669
|
+
scopes: [...googleContactsOperations.import.scopes],
|
|
35951
37670
|
returns: "GoogleContactsImportResult",
|
|
35952
37671
|
notes: "Each merges into the contact it matches (email, then phone, then a unique name) and fills in only a missing email, phone or birthday; the rest become new contacts. Ids Google no longer has come back as missing. Not connected is a conflict."
|
|
35953
37672
|
},
|
|
@@ -36042,7 +37761,7 @@ var COMMAND_SPECS = [
|
|
|
36042
37761
|
description: 'JSON MarkGuestsSentInput, e.g. {"guestIds":["01\u2026"],"what":"save_the_date"} (or "invite"; "at" defaults to now).'
|
|
36043
37762
|
}
|
|
36044
37763
|
],
|
|
36045
|
-
scopes: [
|
|
37764
|
+
scopes: [...guestOperations.sent.scopes],
|
|
36046
37765
|
returns: "GuestView"
|
|
36047
37766
|
},
|
|
36048
37767
|
{
|
|
@@ -36056,7 +37775,7 @@ var COMMAND_SPECS = [
|
|
|
36056
37775
|
description: 'JSON AddRsvpPresetsInput, e.g. {"guestListId":"01\u2026","presets":["diet","message"]}'
|
|
36057
37776
|
}
|
|
36058
37777
|
],
|
|
36059
|
-
scopes: [
|
|
37778
|
+
scopes: [...rsvpQuestionOperations.presets.scopes],
|
|
36060
37779
|
returns: "RsvpQuestion"
|
|
36061
37780
|
},
|
|
36062
37781
|
{
|
|
@@ -36067,7 +37786,7 @@ var COMMAND_SPECS = [
|
|
|
36067
37786
|
{ name: "list", type: "string", description: "The guest list's id (required)." },
|
|
36068
37787
|
{ name: "household", type: "string", description: "Only this household's answers." }
|
|
36069
37788
|
],
|
|
36070
|
-
scopes: [
|
|
37789
|
+
scopes: [...rsvpAnswerOperations.list.scopes],
|
|
36071
37790
|
returns: "RsvpAnswer"
|
|
36072
37791
|
},
|
|
36073
37792
|
{
|
|
@@ -36081,7 +37800,7 @@ var COMMAND_SPECS = [
|
|
|
36081
37800
|
description: 'JSON SetRsvpAnswersInput, e.g. {"guestListId":"01\u2026","householdId":"01\u2026","answers":[{"questionId":"01\u2026","value":true},{"questionId":"01\u2026","guestId":"01\u2026","value":["vegan"]}]}'
|
|
36082
37801
|
}
|
|
36083
37802
|
],
|
|
36084
|
-
scopes: [
|
|
37803
|
+
scopes: [...rsvpAnswerOperations.set.scopes],
|
|
36085
37804
|
returns: "RsvpAnswer"
|
|
36086
37805
|
},
|
|
36087
37806
|
{
|
|
@@ -36128,7 +37847,7 @@ var COMMAND_SPECS = [
|
|
|
36128
37847
|
summary: "A guest list's mail campaigns (save-the-dates, invitations), newest first.",
|
|
36129
37848
|
args: [],
|
|
36130
37849
|
flags: [{ name: "list", type: "string", description: "The guest list's id (required)." }],
|
|
36131
|
-
scopes: [
|
|
37850
|
+
scopes: [...mailCampaignOperations.list.scopes],
|
|
36132
37851
|
returns: "MailCampaignView",
|
|
36133
37852
|
notes: "Each campaign carries the households it reaches (a draft: who it would go to) with their status, its mails by status, and readyToSend."
|
|
36134
37853
|
},
|
|
@@ -36137,7 +37856,7 @@ var COMMAND_SPECS = [
|
|
|
36137
37856
|
summary: "One mail campaign, with its households and how far it got.",
|
|
36138
37857
|
args: [{ name: "id", required: true, description: "The campaign's id." }],
|
|
36139
37858
|
flags: [],
|
|
36140
|
-
scopes: [
|
|
37859
|
+
scopes: [...mailCampaignOperations.get.scopes],
|
|
36141
37860
|
returns: "MailCampaignView"
|
|
36142
37861
|
},
|
|
36143
37862
|
{
|
|
@@ -36151,7 +37870,7 @@ var COMMAND_SPECS = [
|
|
|
36151
37870
|
description: 'JSON CreateMailCampaignInput, e.g. {"guestListId":"01\u2026","kind":"save_the_date","template":"message","data":{"nl":{"subject":"\u2026","heading":"\u2026","paragraphs":["\u2026"]},"pt":{\u2026},"footer":{"deleteBy":"2027-12-31"}},"replyTo":"hallo@example.com"}'
|
|
36152
37871
|
}
|
|
36153
37872
|
],
|
|
36154
|
-
scopes: [
|
|
37873
|
+
scopes: [...mailCampaignOperations.create.scopes],
|
|
36155
37874
|
returns: "MailCampaignView",
|
|
36156
37875
|
notes: "Drafting only: a member previews it, sends a test to the Space's members and sends it from the Mail tab. An agent can never test or send."
|
|
36157
37876
|
},
|
|
@@ -36166,7 +37885,7 @@ var COMMAND_SPECS = [
|
|
|
36166
37885
|
description: 'JSON UpdateMailCampaignInput, e.g. {"data":{"nl":{\u2026}}}'
|
|
36167
37886
|
}
|
|
36168
37887
|
],
|
|
36169
|
-
scopes: [
|
|
37888
|
+
scopes: [...mailCampaignOperations.update.scopes],
|
|
36170
37889
|
returns: "MailCampaignView",
|
|
36171
37890
|
notes: "Only a draft changes (409 otherwise); an edit makes the last test stale."
|
|
36172
37891
|
},
|
|
@@ -36175,7 +37894,7 @@ var COMMAND_SPECS = [
|
|
|
36175
37894
|
summary: "Draw a campaign's mail as its first household would get it.",
|
|
36176
37895
|
args: [{ name: "id", required: true, description: "The campaign's id." }],
|
|
36177
37896
|
flags: [{ name: "language", type: "string", description: "nl (default) or pt." }],
|
|
36178
|
-
scopes: [
|
|
37897
|
+
scopes: [...mailCampaignOperations.preview.scopes],
|
|
36179
37898
|
returns: "MailPreview"
|
|
36180
37899
|
},
|
|
36181
37900
|
{
|
|
@@ -36195,7 +37914,7 @@ var COMMAND_SPECS = [
|
|
|
36195
37914
|
{
|
|
36196
37915
|
name: "kind",
|
|
36197
37916
|
type: "string",
|
|
36198
|
-
description: "caterer (meals and diets per table), venue (who sits where), church (who comes to the ceremony), answers (every RSVP answer, a row per guest), floor-plan (PDF)
|
|
37917
|
+
description: "caterer (meals and diets per table), venue (who sits where), church (who comes to the ceremony), answers (every RSVP answer, a row per guest), floor-plan (PDF), invitations (PDF: a card per household with a live RSVP link, its QR and code) or printer (CSV of those cards: household, address lines, country, language, code, URL)."
|
|
36199
37918
|
},
|
|
36200
37919
|
{
|
|
36201
37920
|
name: "out",
|
|
@@ -38767,7 +40486,7 @@ var HANDLERS = {
|
|
|
38767
40486
|
"today earlier": async ({ flags, io, requireClient }) => {
|
|
38768
40487
|
const area = flagString(flags, "area");
|
|
38769
40488
|
return {
|
|
38770
|
-
data: await requireClient().get(
|
|
40489
|
+
data: await requireClient().get(pathOf(todayOperations.fromEarlier), {
|
|
38771
40490
|
query: { from: localDayStart(io.now()).toISOString(), areaId: area }
|
|
38772
40491
|
}),
|
|
38773
40492
|
render: renderFromEarlier
|
|
@@ -39692,27 +41411,36 @@ var HANDLERS = {
|
|
|
39692
41411
|
},
|
|
39693
41412
|
"task cancel": async ({ args, requireClient }) => {
|
|
39694
41413
|
const id = requireArg(args, 0, "task id");
|
|
39695
|
-
return {
|
|
41414
|
+
return {
|
|
41415
|
+
data: await requireClient().post(pathOf(taskOperations.cancel, { id }), {}),
|
|
41416
|
+
render: renderTask
|
|
41417
|
+
};
|
|
39696
41418
|
},
|
|
39697
41419
|
"tasks accept": async ({ args, requireClient }) => {
|
|
39698
41420
|
const id = requireArg(args, 0, "task id");
|
|
39699
|
-
return {
|
|
41421
|
+
return {
|
|
41422
|
+
data: await requireClient().post(pathOf(taskOperations.accept, { id }), {}),
|
|
41423
|
+
render: renderTask
|
|
41424
|
+
};
|
|
39700
41425
|
},
|
|
39701
41426
|
"tasks dismiss": async ({ args, requireClient }) => {
|
|
39702
41427
|
const id = requireArg(args, 0, "task id");
|
|
39703
|
-
return {
|
|
41428
|
+
return {
|
|
41429
|
+
data: await requireClient().post(pathOf(taskOperations.notNow, { id }), {}),
|
|
41430
|
+
render: renderTask
|
|
41431
|
+
};
|
|
39704
41432
|
},
|
|
39705
41433
|
"block-templates week": async ({ flags, requireClient }) => {
|
|
39706
41434
|
const start = flagString(flags, "start");
|
|
39707
41435
|
if (start === undefined)
|
|
39708
41436
|
throw usageError("block-templates week needs --start");
|
|
39709
41437
|
return {
|
|
39710
|
-
data: await requireClient().get(
|
|
41438
|
+
data: await requireClient().get(pathOf(blockTemplateOperations.week), { query: { start } }),
|
|
39711
41439
|
render: renderRecord
|
|
39712
41440
|
};
|
|
39713
41441
|
},
|
|
39714
41442
|
"block-templates defaults": async ({ requireClient }) => ({
|
|
39715
|
-
data: await requireClient().post(
|
|
41443
|
+
data: await requireClient().post(pathOf(blockTemplateOperations.defaults), {}),
|
|
39716
41444
|
render: renderRecord
|
|
39717
41445
|
}),
|
|
39718
41446
|
"time-blocks record": async ({ args, requireClient }) => {
|
|
@@ -39797,7 +41525,7 @@ var HANDLERS = {
|
|
|
39797
41525
|
};
|
|
39798
41526
|
},
|
|
39799
41527
|
"plans list": async ({ flags, requireClient }) => {
|
|
39800
|
-
const plans = await requireClient().get(
|
|
41528
|
+
const plans = await requireClient().get(pathOf(planOperations.list), {
|
|
39801
41529
|
query: {
|
|
39802
41530
|
kind: flagString(flags, "kind"),
|
|
39803
41531
|
status: flagString(flags, "status"),
|
|
@@ -39809,19 +41537,25 @@ var HANDLERS = {
|
|
|
39809
41537
|
},
|
|
39810
41538
|
"plans get": async ({ args, requireClient }) => {
|
|
39811
41539
|
const id = requireArg(args, 0, "plan id");
|
|
39812
|
-
return {
|
|
41540
|
+
return {
|
|
41541
|
+
data: await requireClient().get(pathOf(planOperations.get, { id })),
|
|
41542
|
+
render: renderPlan
|
|
41543
|
+
};
|
|
39813
41544
|
},
|
|
39814
41545
|
"plans propose": async ({ flags, requireClient }) => {
|
|
39815
41546
|
if (flagString(flags, "data") === undefined)
|
|
39816
41547
|
throw usageError("plans propose needs --data");
|
|
39817
41548
|
const body = parseInput(createPlanInputSchema, readDataFlag(flags));
|
|
39818
|
-
return {
|
|
41549
|
+
return {
|
|
41550
|
+
data: await requireClient().post(pathOf(planOperations.create), body),
|
|
41551
|
+
render: renderPlan
|
|
41552
|
+
};
|
|
39819
41553
|
},
|
|
39820
41554
|
"plans accept": async (ctx) => planDecision(ctx, "accept"),
|
|
39821
41555
|
"plans dismiss": async (ctx) => planDecision(ctx, "dismiss"),
|
|
39822
41556
|
"plans undo": async (ctx) => planDecision(ctx, "undo"),
|
|
39823
41557
|
"plan rules list": async ({ flags, requireClient }) => {
|
|
39824
|
-
const rules = await requireClient().get(
|
|
41558
|
+
const rules = await requireClient().get(pathOf(planningRuleOperations.list), {
|
|
39825
41559
|
query: { forUserId: flagString(flags, "for"), kind: flagString(flags, "kind") }
|
|
39826
41560
|
});
|
|
39827
41561
|
return { data: rules, render: renderPlanningRules };
|
|
@@ -39838,7 +41572,7 @@ var HANDLERS = {
|
|
|
39838
41572
|
...flagString(flags, "for") ? { forUserId: flagString(flags, "for") } : {}
|
|
39839
41573
|
});
|
|
39840
41574
|
return {
|
|
39841
|
-
data: await requireClient().post(
|
|
41575
|
+
data: await requireClient().post(pathOf(planningRuleOperations.create), body),
|
|
39842
41576
|
render: renderPlanningRule
|
|
39843
41577
|
};
|
|
39844
41578
|
},
|
|
@@ -39850,26 +41584,32 @@ var HANDLERS = {
|
|
|
39850
41584
|
...rule !== undefined ? { rule } : {}
|
|
39851
41585
|
});
|
|
39852
41586
|
return {
|
|
39853
|
-
data: await requireClient().patch(
|
|
41587
|
+
data: await requireClient().patch(pathOf(planningRuleOperations.update, { id }), body),
|
|
39854
41588
|
render: renderPlanningRule
|
|
39855
41589
|
};
|
|
39856
41590
|
},
|
|
39857
41591
|
"plan rules remove": async ({ args, flags, requireClient }) => {
|
|
39858
41592
|
const id = requireArg(args, 0, "rule id");
|
|
39859
41593
|
assertDestructiveAllowed(flags, "remove a planning rule");
|
|
39860
|
-
await requireClient().delete(
|
|
41594
|
+
await requireClient().delete(pathOf(planningRuleOperations.remove, { id }));
|
|
39861
41595
|
return { data: { id, removed: true }, render: () => `Removed rule ${id}.` };
|
|
39862
41596
|
},
|
|
39863
41597
|
"tasks ready": async ({ args, flags, requireClient }) => {
|
|
39864
41598
|
const id = requireArg(args, 0, "task id");
|
|
39865
41599
|
const note = flagString(flags, "note");
|
|
39866
41600
|
const body = parseInput(markTaskReadyInputSchema, note !== undefined ? { note } : {});
|
|
39867
|
-
return {
|
|
41601
|
+
return {
|
|
41602
|
+
data: await requireClient().post(pathOf(taskOperations.ready, { id }), body),
|
|
41603
|
+
render: renderTask
|
|
41604
|
+
};
|
|
39868
41605
|
},
|
|
39869
41606
|
"task reopen": async ({ args, requireClient }) => {
|
|
39870
41607
|
const id = requireArg(args, 0, "task id");
|
|
39871
41608
|
const body = parseInput(updateTaskInputSchema, { status: "todo" });
|
|
39872
|
-
return {
|
|
41609
|
+
return {
|
|
41610
|
+
data: await requireClient().patch(pathOf(taskOperations.update, { id }), body),
|
|
41611
|
+
render: renderTask
|
|
41612
|
+
};
|
|
39873
41613
|
},
|
|
39874
41614
|
"task snooze": async ({ args, flags, io, requireClient }) => {
|
|
39875
41615
|
const id = requireArg(args, 0, "task id");
|
|
@@ -39881,7 +41621,10 @@ var HANDLERS = {
|
|
|
39881
41621
|
...until ? { allDay: until.allDay } : {},
|
|
39882
41622
|
...duration ? { durationMinutes: duration } : {}
|
|
39883
41623
|
});
|
|
39884
|
-
return {
|
|
41624
|
+
return {
|
|
41625
|
+
data: await requireClient().patch(pathOf(taskOperations.update, { id }), body),
|
|
41626
|
+
render: renderTask
|
|
41627
|
+
};
|
|
39885
41628
|
},
|
|
39886
41629
|
"task schedule": async ({ args, flags, requireClient }) => {
|
|
39887
41630
|
const id = requireArg(args, 0, "task id");
|
|
@@ -39894,7 +41637,10 @@ var HANDLERS = {
|
|
|
39894
41637
|
allDay: at.allDay,
|
|
39895
41638
|
...duration ? { durationMinutes: duration } : {}
|
|
39896
41639
|
});
|
|
39897
|
-
return {
|
|
41640
|
+
return {
|
|
41641
|
+
data: await requireClient().patch(pathOf(taskOperations.update, { id }), body),
|
|
41642
|
+
render: renderTask
|
|
41643
|
+
};
|
|
39898
41644
|
},
|
|
39899
41645
|
"habit log": async ({ args, flags, requireClient }) => {
|
|
39900
41646
|
const id = requireArg(args, 0, "habit id");
|
|
@@ -39911,7 +41657,7 @@ var HANDLERS = {
|
|
|
39911
41657
|
...note !== undefined ? { note } : {}
|
|
39912
41658
|
});
|
|
39913
41659
|
return {
|
|
39914
|
-
data: await requireClient().post(
|
|
41660
|
+
data: await requireClient().post(pathOf(habitOperations.checkIn, { id }), input),
|
|
39915
41661
|
render: renderHabit
|
|
39916
41662
|
};
|
|
39917
41663
|
},
|
|
@@ -39935,7 +41681,10 @@ var HANDLERS = {
|
|
|
39935
41681
|
...at ? { occurredAt: at } : {},
|
|
39936
41682
|
...note !== undefined ? { note } : {}
|
|
39937
41683
|
});
|
|
39938
|
-
return {
|
|
41684
|
+
return {
|
|
41685
|
+
data: await requireClient().post(pathOf(habitOperations.checkInByTitle), input),
|
|
41686
|
+
render: renderHabit
|
|
41687
|
+
};
|
|
39939
41688
|
},
|
|
39940
41689
|
"habit alias add": async ({ args, requireClient }) => {
|
|
39941
41690
|
const id = requireArg(args, 0, "habit id");
|
|
@@ -39944,7 +41693,7 @@ var HANDLERS = {
|
|
|
39944
41693
|
throw usageError("habit alias add needs an alias, e.g. `do habit alias add <id> wake`");
|
|
39945
41694
|
const input = parseInput(habitAliasInputSchema, { alias });
|
|
39946
41695
|
return {
|
|
39947
|
-
data: await requireClient().post(
|
|
41696
|
+
data: await requireClient().post(pathOf(habitOperations.addAlias, { id }), input),
|
|
39948
41697
|
render: renderHabit
|
|
39949
41698
|
};
|
|
39950
41699
|
},
|
|
@@ -39954,12 +41703,12 @@ var HANDLERS = {
|
|
|
39954
41703
|
if (!alias)
|
|
39955
41704
|
throw usageError("habit alias rm needs the alias to drop");
|
|
39956
41705
|
return {
|
|
39957
|
-
data: await requireClient().delete(
|
|
41706
|
+
data: await requireClient().delete(pathOf(habitOperations.removeAlias, { id, alias })),
|
|
39958
41707
|
render: renderHabit
|
|
39959
41708
|
};
|
|
39960
41709
|
},
|
|
39961
41710
|
"habits today": async ({ requireClient }) => ({
|
|
39962
|
-
data: await requireClient().get(
|
|
41711
|
+
data: await requireClient().get(pathOf(habitOperations.today)),
|
|
39963
41712
|
render: renderHabitsToday
|
|
39964
41713
|
}),
|
|
39965
41714
|
"habit check-ins": async ({ args, flags, requireClient }) => {
|
|
@@ -39969,7 +41718,7 @@ var HANDLERS = {
|
|
|
39969
41718
|
limit: flagString(flags, "limit")
|
|
39970
41719
|
};
|
|
39971
41720
|
return {
|
|
39972
|
-
data: await requireClient().get(
|
|
41721
|
+
data: await requireClient().get(pathOf(habitOperations.listCheckIns, { id }), { query }),
|
|
39973
41722
|
render: renderList
|
|
39974
41723
|
};
|
|
39975
41724
|
},
|
|
@@ -39984,7 +41733,7 @@ var HANDLERS = {
|
|
|
39984
41733
|
throw usageError('habit note needs the note, e.g. `do habit note <id> <check-in id> "felt heavy"`');
|
|
39985
41734
|
const input = parseInput(updateHabitEntryInputSchema, { note: clear ? null : text });
|
|
39986
41735
|
return {
|
|
39987
|
-
data: await requireClient().patch(
|
|
41736
|
+
data: await requireClient().patch(pathOf(habitOperations.updateCheckIn, { id, entryId }), input),
|
|
39988
41737
|
render: renderHabitEntry
|
|
39989
41738
|
};
|
|
39990
41739
|
},
|
|
@@ -39996,7 +41745,10 @@ var HANDLERS = {
|
|
|
39996
41745
|
...date ? { date } : {},
|
|
39997
41746
|
...note !== undefined ? { note } : {}
|
|
39998
41747
|
});
|
|
39999
|
-
return {
|
|
41748
|
+
return {
|
|
41749
|
+
data: await requireClient().post(pathOf(habitOperations.skip, { id }), input),
|
|
41750
|
+
render: renderHabit
|
|
41751
|
+
};
|
|
40000
41752
|
},
|
|
40001
41753
|
"habit pause": async ({ args, flags, requireClient }) => {
|
|
40002
41754
|
const id = requireArg(args, 0, "habit id");
|
|
@@ -40004,7 +41756,10 @@ var HANDLERS = {
|
|
|
40004
41756
|
if (!until)
|
|
40005
41757
|
throw usageError("habit pause needs --until <YYYY-MM-DD>, the day it's back");
|
|
40006
41758
|
const input = parseInput(habitPauseInputSchema, { until });
|
|
40007
|
-
return {
|
|
41759
|
+
return {
|
|
41760
|
+
data: await requireClient().post(pathOf(habitOperations.pause, { id }), input),
|
|
41761
|
+
render: renderHabit
|
|
41762
|
+
};
|
|
40008
41763
|
},
|
|
40009
41764
|
"habit remind": async ({ args, requireClient }) => {
|
|
40010
41765
|
const id = requireArg(args, 0, "habit id");
|
|
@@ -40012,19 +41767,31 @@ var HANDLERS = {
|
|
|
40012
41767
|
if (state !== "on" && state !== "off")
|
|
40013
41768
|
throw usageError("habit remind takes `on` or `off`");
|
|
40014
41769
|
const input = parseInput(updateHabitInputSchema, { remind: state === "on" });
|
|
40015
|
-
return {
|
|
41770
|
+
return {
|
|
41771
|
+
data: await requireClient().patch(pathOf(habitOperations.update, { id }), input),
|
|
41772
|
+
render: renderHabit
|
|
41773
|
+
};
|
|
40016
41774
|
},
|
|
40017
41775
|
"habit resume": async ({ args, requireClient }) => {
|
|
40018
41776
|
const id = requireArg(args, 0, "habit id");
|
|
40019
|
-
return {
|
|
41777
|
+
return {
|
|
41778
|
+
data: await requireClient().post(pathOf(habitOperations.resume, { id }), {}),
|
|
41779
|
+
render: renderHabit
|
|
41780
|
+
};
|
|
40020
41781
|
},
|
|
40021
41782
|
"habit retire": async ({ args, requireClient }) => {
|
|
40022
41783
|
const id = requireArg(args, 0, "habit id");
|
|
40023
|
-
return {
|
|
41784
|
+
return {
|
|
41785
|
+
data: await requireClient().post(pathOf(habitOperations.retire, { id }), {}),
|
|
41786
|
+
render: renderHabit
|
|
41787
|
+
};
|
|
40024
41788
|
},
|
|
40025
41789
|
"habit unretire": async ({ args, requireClient }) => {
|
|
40026
41790
|
const id = requireArg(args, 0, "habit id");
|
|
40027
|
-
return {
|
|
41791
|
+
return {
|
|
41792
|
+
data: await requireClient().post(pathOf(habitOperations.unretire, { id }), {}),
|
|
41793
|
+
render: renderHabit
|
|
41794
|
+
};
|
|
40028
41795
|
},
|
|
40029
41796
|
away: async ({ args, flags, requireClient }) => {
|
|
40030
41797
|
const until = flagString(flags, "until");
|
|
@@ -40043,7 +41810,7 @@ var HANDLERS = {
|
|
|
40043
41810
|
const id = requireArg(args, 0, "routine id");
|
|
40044
41811
|
const input = parseInput(routineDoneInputSchema, {});
|
|
40045
41812
|
return {
|
|
40046
|
-
data: await requireClient().post(
|
|
41813
|
+
data: await requireClient().post(pathOf(routineOperations.markDone, { id }), input),
|
|
40047
41814
|
render: renderRoutineDone
|
|
40048
41815
|
};
|
|
40049
41816
|
},
|
|
@@ -40055,7 +41822,7 @@ var HANDLERS = {
|
|
|
40055
41822
|
}
|
|
40056
41823
|
const input = parseInput(routineRunUndoInputSchema, { stepRunIds });
|
|
40057
41824
|
return {
|
|
40058
|
-
data: await requireClient().post(
|
|
41825
|
+
data: await requireClient().post(pathOf(routineOperations.undoSteps, { runId }), input),
|
|
40059
41826
|
render: renderRoutineUndo
|
|
40060
41827
|
};
|
|
40061
41828
|
},
|
|
@@ -40099,7 +41866,7 @@ var HANDLERS = {
|
|
|
40099
41866
|
};
|
|
40100
41867
|
},
|
|
40101
41868
|
"agents list": async ({ requireClient }) => ({
|
|
40102
|
-
data: await requireClient().getPage(
|
|
41869
|
+
data: await requireClient().getPage(pathOf(agentOperations.list)),
|
|
40103
41870
|
render: renderList
|
|
40104
41871
|
}),
|
|
40105
41872
|
"agent connection get": async ({ requireClient }) => ({
|
|
@@ -40215,12 +41982,15 @@ var HANDLERS = {
|
|
|
40215
41982
|
};
|
|
40216
41983
|
},
|
|
40217
41984
|
"settings get": async ({ requireClient }) => ({
|
|
40218
|
-
data: await requireClient().get(
|
|
41985
|
+
data: await requireClient().get(pathOf(settingsOperations.get)),
|
|
40219
41986
|
render: renderRecord
|
|
40220
41987
|
}),
|
|
40221
41988
|
"settings update": async ({ flags, requireClient }) => {
|
|
40222
41989
|
const body = parseInput(updateUserSettingsInputSchema, readDataFlag(flags));
|
|
40223
|
-
return {
|
|
41990
|
+
return {
|
|
41991
|
+
data: await requireClient().patch(pathOf(settingsOperations.update), body),
|
|
41992
|
+
render: renderRecord
|
|
41993
|
+
};
|
|
40224
41994
|
},
|
|
40225
41995
|
"modules list": async ({ requireClient }) => {
|
|
40226
41996
|
const settings = await requireClient().get("/settings");
|
|
@@ -40314,7 +42084,10 @@ var HANDLERS = {
|
|
|
40314
42084
|
},
|
|
40315
42085
|
"collection upkeep": async ({ args, requireClient }) => {
|
|
40316
42086
|
const id = requireArg(args, 0, "item id");
|
|
40317
|
-
return {
|
|
42087
|
+
return {
|
|
42088
|
+
data: await requireClient().get(pathOf(collectionUpkeepOperations.list, { id })),
|
|
42089
|
+
render: renderRecord
|
|
42090
|
+
};
|
|
40318
42091
|
},
|
|
40319
42092
|
"collection link-task": async ({ args, flags, requireClient }) => {
|
|
40320
42093
|
const id = requireArg(args, 0, "item id");
|
|
@@ -40324,7 +42097,7 @@ var HANDLERS = {
|
|
|
40324
42097
|
kind: flagBool(flags, "repair") ? "repairs" : "maintains"
|
|
40325
42098
|
});
|
|
40326
42099
|
return {
|
|
40327
|
-
data: await requireClient().post(
|
|
42100
|
+
data: await requireClient().post(pathOf(collectionUpkeepOperations.link, { id }), body),
|
|
40328
42101
|
render: renderRecord
|
|
40329
42102
|
};
|
|
40330
42103
|
},
|
|
@@ -40332,7 +42105,7 @@ var HANDLERS = {
|
|
|
40332
42105
|
const id = requireArg(args, 0, "item id");
|
|
40333
42106
|
const taskId = requireArg(args, 1, "task id");
|
|
40334
42107
|
return {
|
|
40335
|
-
data: await requireClient().delete(
|
|
42108
|
+
data: await requireClient().delete(pathOf(collectionUpkeepOperations.unlink, { id, taskId })),
|
|
40336
42109
|
render: renderRecord
|
|
40337
42110
|
};
|
|
40338
42111
|
},
|
|
@@ -40897,6 +42670,23 @@ var HANDLERS = {
|
|
|
40897
42670
|
});
|
|
40898
42671
|
return { data: await requireClient().post("/money/budget/copy", body), render: renderRecord };
|
|
40899
42672
|
},
|
|
42673
|
+
"money net-worth": async ({ flags, requireClient }) => ({
|
|
42674
|
+
data: await requireClient().get("/money/net-worth", {
|
|
42675
|
+
query: { scope: flagString(flags, "scope"), months: flagString(flags, "months") }
|
|
42676
|
+
}),
|
|
42677
|
+
render: renderRecord
|
|
42678
|
+
}),
|
|
42679
|
+
"money net-worth-set": async ({ args, flags, requireClient }) => {
|
|
42680
|
+
const body = flagString(flags, "data") !== undefined ? parseInput(setMoneyNetWorthValueInputSchema, readDataFlag(flags)) : parseInput(setMoneyNetWorthValueInputSchema, {
|
|
42681
|
+
accountId: requireArg(args, 0, "account id"),
|
|
42682
|
+
value: requireFlag(flags, "value", "money net-worth-set needs --value <amount>"),
|
|
42683
|
+
month: flagString(flags, "month")
|
|
42684
|
+
});
|
|
42685
|
+
return {
|
|
42686
|
+
data: await requireClient().put("/money/net-worth/values", body),
|
|
42687
|
+
render: renderRecord
|
|
42688
|
+
};
|
|
42689
|
+
},
|
|
40900
42690
|
"money goals": async ({ requireClient }) => ({
|
|
40901
42691
|
data: await requireClient().get("/money/goals"),
|
|
40902
42692
|
render: renderList
|
|
@@ -41206,31 +42996,31 @@ var HANDLERS = {
|
|
|
41206
42996
|
return { data: await requireClient().post("/runs/steam/sync", body), render: renderRecord };
|
|
41207
42997
|
},
|
|
41208
42998
|
"sensors status": async ({ requireClient }) => ({
|
|
41209
|
-
data: await requireClient().get(
|
|
42999
|
+
data: await requireClient().get(pathOf(sensorOperations.status)),
|
|
41210
43000
|
render: renderRecord
|
|
41211
43001
|
}),
|
|
41212
43002
|
"sensors entities": async ({ requireClient }) => ({
|
|
41213
|
-
data: await requireClient().get(
|
|
43003
|
+
data: await requireClient().get(pathOf(sensorOperations.entities)),
|
|
41214
43004
|
render: renderList
|
|
41215
43005
|
}),
|
|
41216
43006
|
"sensors sync": async ({ requireClient }) => ({
|
|
41217
|
-
data: await requireClient().post(
|
|
43007
|
+
data: await requireClient().post(pathOf(sensorOperations.sync), {}),
|
|
41218
43008
|
render: renderRecord
|
|
41219
43009
|
}),
|
|
41220
43010
|
"sensors unifi": async ({ requireClient }) => ({
|
|
41221
|
-
data: await requireClient().get(
|
|
43011
|
+
data: await requireClient().get(pathOf(sensorOperations.unifiStatus)),
|
|
41222
43012
|
render: renderRecord
|
|
41223
43013
|
}),
|
|
41224
43014
|
"sensors unifi-devices": async ({ requireClient }) => ({
|
|
41225
|
-
data: await requireClient().get(
|
|
43015
|
+
data: await requireClient().get(pathOf(sensorOperations.unifiDevices)),
|
|
41226
43016
|
render: renderList
|
|
41227
43017
|
}),
|
|
41228
43018
|
"sensors unifi-sync": async ({ requireClient }) => ({
|
|
41229
|
-
data: await requireClient().post(
|
|
43019
|
+
data: await requireClient().post(pathOf(sensorOperations.syncUnifi), {}),
|
|
41230
43020
|
render: renderRecord
|
|
41231
43021
|
}),
|
|
41232
43022
|
"sensors links": async ({ flags, requireClient }) => ({
|
|
41233
|
-
data: await requireClient().get(
|
|
43023
|
+
data: await requireClient().get(pathOf(sensorOperations.links), {
|
|
41234
43024
|
query: { nodeId: flagString(flags, "node") }
|
|
41235
43025
|
}),
|
|
41236
43026
|
render: renderList
|
|
@@ -41243,11 +43033,14 @@ var HANDLERS = {
|
|
|
41243
43033
|
...flagString(flags, "provider") ? { provider: flagString(flags, "provider") } : {},
|
|
41244
43034
|
...flagString(flags, "label") ? { label: flagString(flags, "label") } : {}
|
|
41245
43035
|
});
|
|
41246
|
-
return {
|
|
43036
|
+
return {
|
|
43037
|
+
data: await requireClient().post(pathOf(sensorOperations.createLink), body),
|
|
43038
|
+
render: renderRecord
|
|
43039
|
+
};
|
|
41247
43040
|
},
|
|
41248
43041
|
"sensors unmap": async ({ args, requireClient }) => {
|
|
41249
43042
|
const id = requireArg(args, 0, "sensor link id");
|
|
41250
|
-
await requireClient().delete(
|
|
43043
|
+
await requireClient().delete(pathOf(sensorOperations.removeLink, { id }));
|
|
41251
43044
|
return { data: { ok: true, unmapped: id }, render: renderRecord };
|
|
41252
43045
|
},
|
|
41253
43046
|
"runs sessions list": async ({ args, requireClient }) => {
|
|
@@ -41360,11 +43153,11 @@ var HANDLERS = {
|
|
|
41360
43153
|
render: renderRecord
|
|
41361
43154
|
}),
|
|
41362
43155
|
"health google status": async ({ requireClient }) => ({
|
|
41363
|
-
data: await requireClient().get(
|
|
43156
|
+
data: await requireClient().get(pathOf(googleHealthOperations.status)),
|
|
41364
43157
|
render: renderRecord
|
|
41365
43158
|
}),
|
|
41366
43159
|
"health google sync": async ({ requireClient }) => ({
|
|
41367
|
-
data: await requireClient().post(
|
|
43160
|
+
data: await requireClient().post(pathOf(googleHealthOperations.sync), {}),
|
|
41368
43161
|
render: renderRecord
|
|
41369
43162
|
}),
|
|
41370
43163
|
"health consent": async ({ requireClient }) => ({
|
|
@@ -41595,7 +43388,9 @@ var HANDLERS = {
|
|
|
41595
43388
|
"people google": async ({ flags, requireClient }) => {
|
|
41596
43389
|
const q = flagString(flags, "q");
|
|
41597
43390
|
return {
|
|
41598
|
-
data: await requireClient().get(
|
|
43391
|
+
data: await requireClient().get(pathOf(googleContactsOperations.list), {
|
|
43392
|
+
query: q ? { q } : {}
|
|
43393
|
+
}),
|
|
41599
43394
|
render: renderRecord
|
|
41600
43395
|
};
|
|
41601
43396
|
},
|
|
@@ -41605,7 +43400,7 @@ var HANDLERS = {
|
|
|
41605
43400
|
}
|
|
41606
43401
|
const body = parseInput(importGoogleContactsInputSchema, { resourceNames: args });
|
|
41607
43402
|
return {
|
|
41608
|
-
data: await requireClient().post(
|
|
43403
|
+
data: await requireClient().post(pathOf(googleContactsOperations.import), body),
|
|
41609
43404
|
render: renderRecord
|
|
41610
43405
|
};
|
|
41611
43406
|
},
|
|
@@ -41748,12 +43543,15 @@ var HANDLERS = {
|
|
|
41748
43543
|
},
|
|
41749
43544
|
"guests sent": async ({ flags, requireClient }) => {
|
|
41750
43545
|
const body = parseInput(markGuestsSentInputSchema, readDataFlag(flags));
|
|
41751
|
-
return {
|
|
43546
|
+
return {
|
|
43547
|
+
data: await requireClient().post(pathOf(guestOperations.sent), body),
|
|
43548
|
+
render: renderRecord
|
|
43549
|
+
};
|
|
41752
43550
|
},
|
|
41753
43551
|
"rsvp-questions presets": async ({ flags, requireClient }) => {
|
|
41754
43552
|
const body = parseInput(addRsvpPresetsInputSchema, readDataFlag(flags));
|
|
41755
43553
|
return {
|
|
41756
|
-
data: await requireClient().post(
|
|
43554
|
+
data: await requireClient().post(pathOf(rsvpQuestionOperations.presets), body),
|
|
41757
43555
|
render: renderRecord
|
|
41758
43556
|
};
|
|
41759
43557
|
},
|
|
@@ -41766,11 +43564,17 @@ var HANDLERS = {
|
|
|
41766
43564
|
guestListId: list,
|
|
41767
43565
|
...household ? { householdId: household } : {}
|
|
41768
43566
|
});
|
|
41769
|
-
return {
|
|
43567
|
+
return {
|
|
43568
|
+
data: await requireClient().get(pathOf(rsvpAnswerOperations.list), { query }),
|
|
43569
|
+
render: renderRecord
|
|
43570
|
+
};
|
|
41770
43571
|
},
|
|
41771
43572
|
"rsvp-answers set": async ({ flags, requireClient }) => {
|
|
41772
43573
|
const body = parseInput(setRsvpAnswersInputSchema, readDataFlag(flags));
|
|
41773
|
-
return {
|
|
43574
|
+
return {
|
|
43575
|
+
data: await requireClient().put(pathOf(rsvpAnswerOperations.set), body),
|
|
43576
|
+
render: renderRecord
|
|
43577
|
+
};
|
|
41774
43578
|
},
|
|
41775
43579
|
"seating-proposals list": async ({ flags, requireClient }) => {
|
|
41776
43580
|
const list = flagString(flags, "list");
|
|
@@ -41809,23 +43613,31 @@ var HANDLERS = {
|
|
|
41809
43613
|
throw usageError("mail-campaigns list needs --list <guest list id>");
|
|
41810
43614
|
parseInput(mailCampaignsQuerySchema, { guestListId: list });
|
|
41811
43615
|
return {
|
|
41812
|
-
data: await requireClient().get(
|
|
43616
|
+
data: await requireClient().get(pathOf(mailCampaignOperations.list), {
|
|
43617
|
+
query: { guestListId: list }
|
|
43618
|
+
}),
|
|
41813
43619
|
render: renderRecord
|
|
41814
43620
|
};
|
|
41815
43621
|
},
|
|
41816
43622
|
"mail-campaigns get": async ({ args, requireClient }) => {
|
|
41817
43623
|
const id = requireArg(args, 0, "campaign id");
|
|
41818
|
-
return {
|
|
43624
|
+
return {
|
|
43625
|
+
data: await requireClient().get(pathOf(mailCampaignOperations.get, { id })),
|
|
43626
|
+
render: renderRecord
|
|
43627
|
+
};
|
|
41819
43628
|
},
|
|
41820
43629
|
"mail-campaigns create": async ({ flags, requireClient }) => {
|
|
41821
43630
|
const body = parseInput(createMailCampaignInputSchema, { id: ulid3(), ...readDataFlag(flags) });
|
|
41822
|
-
return {
|
|
43631
|
+
return {
|
|
43632
|
+
data: await requireClient().post(pathOf(mailCampaignOperations.create), body),
|
|
43633
|
+
render: renderRecord
|
|
43634
|
+
};
|
|
41823
43635
|
},
|
|
41824
43636
|
"mail-campaigns update": async ({ args, flags, requireClient }) => {
|
|
41825
43637
|
const id = requireArg(args, 0, "campaign id");
|
|
41826
43638
|
const body = parseInput(updateMailCampaignInputSchema, readDataFlag(flags));
|
|
41827
43639
|
return {
|
|
41828
|
-
data: await requireClient().patch(
|
|
43640
|
+
data: await requireClient().patch(pathOf(mailCampaignOperations.update, { id }), body),
|
|
41829
43641
|
render: renderRecord
|
|
41830
43642
|
};
|
|
41831
43643
|
},
|
|
@@ -41835,7 +43647,7 @@ var HANDLERS = {
|
|
|
41835
43647
|
language: flagString(flags, "language") ?? "nl"
|
|
41836
43648
|
});
|
|
41837
43649
|
return {
|
|
41838
|
-
data: await requireClient().get(
|
|
43650
|
+
data: await requireClient().get(pathOf(mailCampaignOperations.preview, { id }), { query }),
|
|
41839
43651
|
render: renderRecord
|
|
41840
43652
|
};
|
|
41841
43653
|
},
|
|
@@ -42310,7 +44122,10 @@ async function planDecision({ args, requireClient }, verb) {
|
|
|
42310
44122
|
const id = requireArg(args, 0, "plan id");
|
|
42311
44123
|
const itemIds = args.slice(1);
|
|
42312
44124
|
const body = parseInput(planDecisionInputSchema, itemIds.length > 0 ? { itemIds } : {});
|
|
42313
|
-
return {
|
|
44125
|
+
return {
|
|
44126
|
+
data: await requireClient().post(pathOf(planOperations[verb], { id }), body),
|
|
44127
|
+
render: renderPlan
|
|
44128
|
+
};
|
|
42314
44129
|
}
|
|
42315
44130
|
function parseInput(schema, value) {
|
|
42316
44131
|
const result = schema.safeParse(value);
|