@robbeverhelst/do 1.302.0 → 1.304.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 +1320 -183
- 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", [
|
|
@@ -5174,6 +5188,8 @@ var guestLists = pgTable("guest_lists", {
|
|
|
5174
5188
|
finalInfoKeyDateId: text("final_info_key_date_id").references(() => keyDates.id, {
|
|
5175
5189
|
onDelete: "set null"
|
|
5176
5190
|
}),
|
|
5191
|
+
siteUrl: text("site_url"),
|
|
5192
|
+
sitePassword: text("site_password"),
|
|
5177
5193
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
5178
5194
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
5179
5195
|
}, (t) => [uniqueIndex("guest_lists_project_uniq").on(t.tenantId, t.projectId)]);
|
|
@@ -5630,6 +5646,18 @@ var foodWeekReads = pgTable("food_week_reads", {
|
|
|
5630
5646
|
weekStart: text("week_start").notNull()
|
|
5631
5647
|
}, (t) => [unique("food_week_reads_owner_week_uniq").on(t.tenantId, t.ownerUserId, t.weekStart)]);
|
|
5632
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
|
+
|
|
5633
5661
|
// ../../packages/schema/src/db/collaboration.ts
|
|
5634
5662
|
var capability = pgEnum("collab_capability", ["view", "comment", "edit", "admin"]);
|
|
5635
5663
|
var grantSubjectType = pgEnum("grant_subject_type", ["member", "role"]);
|
|
@@ -19912,6 +19940,12 @@ var linkGoogleInputSchema = object({
|
|
|
19912
19940
|
state: string2().min(1)
|
|
19913
19941
|
});
|
|
19914
19942
|
|
|
19943
|
+
// ../../packages/schema/src/contracts/pagination.ts
|
|
19944
|
+
var paginationQuerySchema = object({
|
|
19945
|
+
limit: exports_coerce.number().int().positive().optional(),
|
|
19946
|
+
cursor: string2().min(1).optional()
|
|
19947
|
+
});
|
|
19948
|
+
|
|
19915
19949
|
// ../../packages/schema/src/contracts/changes.ts
|
|
19916
19950
|
var changeOpSchema = _enum2(["created", "updated", "deleted"]);
|
|
19917
19951
|
var CHANGE_ENTITY_SCOPES = {
|
|
@@ -20501,6 +20535,21 @@ var collectionCoverBackfillResultSchema = object({
|
|
|
20501
20535
|
found: number2().int().min(0),
|
|
20502
20536
|
colored: number2().int().min(0).default(0)
|
|
20503
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
|
+
}
|
|
20504
20553
|
var collectionSavedViewSchema = object({
|
|
20505
20554
|
id: string2().min(1),
|
|
20506
20555
|
name: string2().min(1),
|
|
@@ -20539,6 +20588,53 @@ var collectionLogResultSchema = object({
|
|
|
20539
20588
|
item: collectionItemDetailSchema
|
|
20540
20589
|
});
|
|
20541
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
|
+
|
|
20542
20638
|
// ../../packages/schema/src/contracts/habit-sources.ts
|
|
20543
20639
|
var habitSourceSchema = _enum2(["manual", "google_fit", "strava", "github"]);
|
|
20544
20640
|
|
|
@@ -20770,7 +20866,8 @@ var metricSourceSchema = _enum2([
|
|
|
20770
20866
|
"agent",
|
|
20771
20867
|
"google_fit",
|
|
20772
20868
|
"google_health",
|
|
20773
|
-
"health_connect"
|
|
20869
|
+
"health_connect",
|
|
20870
|
+
"withings"
|
|
20774
20871
|
]);
|
|
20775
20872
|
var loggedMetricSourceSchema = _enum2(["manual", "device", "agent"]);
|
|
20776
20873
|
var metricPointSchema = object({
|
|
@@ -24656,6 +24753,50 @@ var dayRecordUndoResultSchema = object({
|
|
|
24656
24753
|
});
|
|
24657
24754
|
var STATUS_QUARTER_MS = RECORD_ROUND_MINUTES * 60000;
|
|
24658
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
|
+
|
|
24659
24800
|
// ../../packages/schema/src/contracts/insights.ts
|
|
24660
24801
|
var insightsActivityPointSchema = object({
|
|
24661
24802
|
day: string2(),
|
|
@@ -27240,6 +27381,51 @@ var steamSyncResultSchema = object({
|
|
|
27240
27381
|
games: array(steamGameSyncSchema)
|
|
27241
27382
|
});
|
|
27242
27383
|
|
|
27384
|
+
// ../../packages/schema/src/contracts/money-net-worth.ts
|
|
27385
|
+
var amount5 = string2();
|
|
27386
|
+
var moneySnapshotSourceSchema = _enum2(moneySnapshotSource.enumValues);
|
|
27387
|
+
var moneyNetWorthQuerySchema = object({
|
|
27388
|
+
scope: moneyBudgetScopeSchema.optional(),
|
|
27389
|
+
months: exports_coerce.number().int().min(2).max(60).optional()
|
|
27390
|
+
});
|
|
27391
|
+
var moneyNetWorthPointSchema = object({
|
|
27392
|
+
month: moneyMonthSchema,
|
|
27393
|
+
total: amount5.nullable(),
|
|
27394
|
+
have: amount5.nullable(),
|
|
27395
|
+
owe: amount5.nullable()
|
|
27396
|
+
});
|
|
27397
|
+
var moneyNetWorthAccountSchema = object({
|
|
27398
|
+
accountId: ulidSchema,
|
|
27399
|
+
title: string2(),
|
|
27400
|
+
kind: moneyAccountKindSchema,
|
|
27401
|
+
visibility: _enum2(NODE_VISIBILITY_VALUES),
|
|
27402
|
+
currency: string2(),
|
|
27403
|
+
value: amount5,
|
|
27404
|
+
source: moneySnapshotSourceSchema,
|
|
27405
|
+
month: moneyMonthSchema
|
|
27406
|
+
});
|
|
27407
|
+
var moneyNetWorthSchema = object({
|
|
27408
|
+
scope: moneyBudgetScopeSchema,
|
|
27409
|
+
month: moneyMonthSchema,
|
|
27410
|
+
total: amount5,
|
|
27411
|
+
have: amount5,
|
|
27412
|
+
owe: amount5,
|
|
27413
|
+
points: array(moneyNetWorthPointSchema),
|
|
27414
|
+
accounts: array(moneyNetWorthAccountSchema)
|
|
27415
|
+
});
|
|
27416
|
+
var setMoneyNetWorthValueInputSchema = object({
|
|
27417
|
+
accountId: ulidSchema,
|
|
27418
|
+
value: moneyAmountSchema,
|
|
27419
|
+
month: moneyMonthSchema.optional()
|
|
27420
|
+
}).strict();
|
|
27421
|
+
var moneySnapshotSchema = object({
|
|
27422
|
+
id: ulidSchema,
|
|
27423
|
+
accountId: ulidSchema,
|
|
27424
|
+
month: moneyMonthSchema,
|
|
27425
|
+
value: amount5,
|
|
27426
|
+
source: moneySnapshotSourceSchema
|
|
27427
|
+
});
|
|
27428
|
+
|
|
27243
27429
|
// ../../packages/schema/src/contracts/money-splits.ts
|
|
27244
27430
|
var moneyPartySchema = union([
|
|
27245
27431
|
object({ userId: ulidSchema }).strict(),
|
|
@@ -27700,6 +27886,7 @@ var guestListViewSchema = guestListSchema.extend({
|
|
|
27700
27886
|
finalInfoFrom: keyDateDaySchema.nullable().default(null),
|
|
27701
27887
|
projectDay: keyDateDaySchema.nullable().default(null)
|
|
27702
27888
|
});
|
|
27889
|
+
var siteUrlSchema = string2().trim().max(200).regex(/^https:\/\/[^\s/?#]+(\/[^\s?#]*)?$/, "expected an https:// address without ? or #").transform((u) => u.replace(/\/+$/, ""));
|
|
27703
27890
|
var createGuestListInputSchema = object({
|
|
27704
27891
|
id: ulidSchema,
|
|
27705
27892
|
projectId: ulidSchema,
|
|
@@ -27707,7 +27894,9 @@ var createGuestListInputSchema = object({
|
|
|
27707
27894
|
caps: capsSchema.optional(),
|
|
27708
27895
|
sides: array(sideSchema).max(4).optional(),
|
|
27709
27896
|
rsvpBy: keyDateDaySchema.nullish(),
|
|
27710
|
-
finalInfoFrom: keyDateDaySchema.nullish()
|
|
27897
|
+
finalInfoFrom: keyDateDaySchema.nullish(),
|
|
27898
|
+
siteUrl: siteUrlSchema.nullish(),
|
|
27899
|
+
sitePassword: string2().trim().min(1).max(64).nullish()
|
|
27711
27900
|
}).strict();
|
|
27712
27901
|
var updateGuestListInputSchema = createGuestListInputSchema.omit({ id: true, projectId: true }).partial().strict();
|
|
27713
27902
|
var guestListsQuerySchema = object({ projectId: ulidSchema.optional() });
|
|
@@ -27859,6 +28048,23 @@ var publicRsvpEventSchema = object({
|
|
|
27859
28048
|
dressCode: object({ nl: string2().optional(), pt: string2().optional() }).nullable(),
|
|
27860
28049
|
note: object({ nl: string2().optional(), pt: string2().optional() }).nullable()
|
|
27861
28050
|
}).strict();
|
|
28051
|
+
var publicTextSchema = object({ nl: string2().optional(), pt: string2().optional() });
|
|
28052
|
+
var publicRsvpQuestionSchema = object({
|
|
28053
|
+
id: ulidSchema,
|
|
28054
|
+
kind: rsvpQuestionKindSchema,
|
|
28055
|
+
label: publicTextSchema,
|
|
28056
|
+
options: array(object({ key: string2(), label: publicTextSchema }).strict()),
|
|
28057
|
+
scope: rsvpQuestionScopeSchema,
|
|
28058
|
+
eventKey: string2().nullable(),
|
|
28059
|
+
required: boolean3(),
|
|
28060
|
+
showIf: array(rsvpShowIfConditionSchema),
|
|
28061
|
+
preset: rsvpQuestionPresetSchema.nullable()
|
|
28062
|
+
}).strict();
|
|
28063
|
+
var publicRsvpAnswerSchema = object({
|
|
28064
|
+
questionId: ulidSchema,
|
|
28065
|
+
guestId: ulidSchema.nullable(),
|
|
28066
|
+
value: rsvpAnswerValueSchema
|
|
28067
|
+
}).strict();
|
|
27862
28068
|
var publicRsvpViewSchema = object({
|
|
27863
28069
|
mode: rsvpLinkModeSchema,
|
|
27864
28070
|
language: rsvpLanguageSchema,
|
|
@@ -27868,6 +28074,8 @@ var publicRsvpViewSchema = object({
|
|
|
27868
28074
|
finalInfoFrom: keyDateDaySchema.nullable().default(null),
|
|
27869
28075
|
tiers: array(guestTierSchema),
|
|
27870
28076
|
events: array(publicRsvpEventSchema).default([]),
|
|
28077
|
+
questions: array(publicRsvpQuestionSchema).default([]),
|
|
28078
|
+
answers: array(publicRsvpAnswerSchema).default([]),
|
|
27871
28079
|
guests: array(publicRsvpGuestSchema),
|
|
27872
28080
|
address: householdAddressSchema.nullable(),
|
|
27873
28081
|
answeredAt: exports_coerce.date().nullable()
|
|
@@ -27953,7 +28161,15 @@ var createSeatingProposalInputSchema = object({
|
|
|
27953
28161
|
return new Set(ids).size === ids.length;
|
|
27954
28162
|
}, { message: "a guest can sit at one table only", path: ["tables"] });
|
|
27955
28163
|
var seatingProposalsQuerySchema = object({ guestListId: ulidSchema });
|
|
27956
|
-
var GUEST_EXPORT_KINDS = [
|
|
28164
|
+
var GUEST_EXPORT_KINDS = [
|
|
28165
|
+
"caterer",
|
|
28166
|
+
"venue",
|
|
28167
|
+
"floor-plan",
|
|
28168
|
+
"church",
|
|
28169
|
+
"answers",
|
|
28170
|
+
"invitations",
|
|
28171
|
+
"printer"
|
|
28172
|
+
];
|
|
27957
28173
|
var guestExportKindSchema = _enum2(GUEST_EXPORT_KINDS);
|
|
27958
28174
|
var thankYouGiftSchema = object({
|
|
27959
28175
|
momentId: ulidSchema,
|
|
@@ -28538,6 +28754,209 @@ function scopeGranted(granted, required) {
|
|
|
28538
28754
|
return granted.includes(FULL_ACCESS_SCOPE);
|
|
28539
28755
|
}
|
|
28540
28756
|
|
|
28757
|
+
// ../../packages/schema/src/net/ssrf.ts
|
|
28758
|
+
var BLOCKED_HOST_SUFFIXES = [".internal", ".local", ".localhost"];
|
|
28759
|
+
var BLOCKED_HOSTNAMES = new Set(["localhost"]);
|
|
28760
|
+
function parseIpv4(host) {
|
|
28761
|
+
const parts = host.split(".");
|
|
28762
|
+
if (parts.length !== 4)
|
|
28763
|
+
return null;
|
|
28764
|
+
let value = 0;
|
|
28765
|
+
for (const part of parts) {
|
|
28766
|
+
if (!/^\d{1,3}$/.test(part))
|
|
28767
|
+
return null;
|
|
28768
|
+
const octet = Number(part);
|
|
28769
|
+
if (octet > 255)
|
|
28770
|
+
return null;
|
|
28771
|
+
value = value * 256 + octet;
|
|
28772
|
+
}
|
|
28773
|
+
return value >>> 0;
|
|
28774
|
+
}
|
|
28775
|
+
function isBlockedIpv4(ip) {
|
|
28776
|
+
const inRange = (base, bits) => {
|
|
28777
|
+
const baseIp = parseIpv4(base);
|
|
28778
|
+
if (baseIp === null)
|
|
28779
|
+
return false;
|
|
28780
|
+
const mask = bits === 0 ? 0 : 4294967295 << 32 - bits >>> 0;
|
|
28781
|
+
return (ip & mask) === (baseIp & mask);
|
|
28782
|
+
};
|
|
28783
|
+
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);
|
|
28784
|
+
}
|
|
28785
|
+
function parseIpv6(host) {
|
|
28786
|
+
let text = host;
|
|
28787
|
+
const zone = text.indexOf("%");
|
|
28788
|
+
if (zone !== -1)
|
|
28789
|
+
text = text.slice(0, zone);
|
|
28790
|
+
if (!text.includes(":"))
|
|
28791
|
+
return null;
|
|
28792
|
+
const lastColon = text.lastIndexOf(":");
|
|
28793
|
+
const tail = text.slice(lastColon + 1);
|
|
28794
|
+
if (tail.includes(".")) {
|
|
28795
|
+
const v4 = parseIpv4(tail);
|
|
28796
|
+
if (v4 === null)
|
|
28797
|
+
return null;
|
|
28798
|
+
const hex = `${(v4 >>> 16 & 65535).toString(16)}:${(v4 & 65535).toString(16)}`;
|
|
28799
|
+
text = text.slice(0, lastColon + 1) + hex;
|
|
28800
|
+
}
|
|
28801
|
+
const halves = text.split("::");
|
|
28802
|
+
if (halves.length > 2)
|
|
28803
|
+
return null;
|
|
28804
|
+
const toGroups = (segment) => {
|
|
28805
|
+
if (segment === "")
|
|
28806
|
+
return [];
|
|
28807
|
+
const out = [];
|
|
28808
|
+
for (const g of segment.split(":")) {
|
|
28809
|
+
if (!/^[0-9a-fA-F]{1,4}$/.test(g))
|
|
28810
|
+
return null;
|
|
28811
|
+
out.push(Number.parseInt(g, 16));
|
|
28812
|
+
}
|
|
28813
|
+
return out;
|
|
28814
|
+
};
|
|
28815
|
+
const head = toGroups(halves[0] ?? "");
|
|
28816
|
+
if (head === null)
|
|
28817
|
+
return null;
|
|
28818
|
+
let groups;
|
|
28819
|
+
if (halves.length === 2) {
|
|
28820
|
+
const back = toGroups(halves[1] ?? "");
|
|
28821
|
+
if (back === null)
|
|
28822
|
+
return null;
|
|
28823
|
+
const fill = 8 - head.length - back.length;
|
|
28824
|
+
if (fill < 0)
|
|
28825
|
+
return null;
|
|
28826
|
+
groups = [...head, ...Array(fill).fill(0), ...back];
|
|
28827
|
+
} else {
|
|
28828
|
+
groups = head;
|
|
28829
|
+
}
|
|
28830
|
+
return groups.length === 8 ? groups : null;
|
|
28831
|
+
}
|
|
28832
|
+
function isBlockedIpv6(groups) {
|
|
28833
|
+
const isZero = groups.every((g) => g === 0);
|
|
28834
|
+
if (isZero)
|
|
28835
|
+
return true;
|
|
28836
|
+
if (groups.slice(0, 7).every((g) => g === 0) && groups[7] === 1)
|
|
28837
|
+
return true;
|
|
28838
|
+
const isV4Mapped = groups.slice(0, 5).every((g) => g === 0) && groups[5] === 65535;
|
|
28839
|
+
const isV4Compat = groups.slice(0, 6).every((g) => g === 0);
|
|
28840
|
+
if (isV4Mapped || isV4Compat) {
|
|
28841
|
+
const v4 = ((groups[6] ?? 0) << 16 | (groups[7] ?? 0)) >>> 0;
|
|
28842
|
+
return isBlockedIpv4(v4);
|
|
28843
|
+
}
|
|
28844
|
+
const first = groups[0] ?? 0;
|
|
28845
|
+
if ((first & 65024) === 64512)
|
|
28846
|
+
return true;
|
|
28847
|
+
if ((first & 65472) === 65152)
|
|
28848
|
+
return true;
|
|
28849
|
+
if ((first & 65280) === 65280)
|
|
28850
|
+
return true;
|
|
28851
|
+
return false;
|
|
28852
|
+
}
|
|
28853
|
+
function isBlockedIp(host) {
|
|
28854
|
+
const bare = host.startsWith("[") && host.endsWith("]") ? host.slice(1, -1) : host;
|
|
28855
|
+
const v4 = parseIpv4(bare);
|
|
28856
|
+
if (v4 !== null)
|
|
28857
|
+
return isBlockedIpv4(v4);
|
|
28858
|
+
const v6 = parseIpv6(bare);
|
|
28859
|
+
if (v6 !== null)
|
|
28860
|
+
return isBlockedIpv6(v6);
|
|
28861
|
+
return false;
|
|
28862
|
+
}
|
|
28863
|
+
|
|
28864
|
+
class BlockedWebhookUrlError extends Error {
|
|
28865
|
+
constructor(reason) {
|
|
28866
|
+
super(`webhook url rejected: ${reason}`);
|
|
28867
|
+
this.name = "BlockedWebhookUrlError";
|
|
28868
|
+
}
|
|
28869
|
+
}
|
|
28870
|
+
function bareHost(hostname) {
|
|
28871
|
+
return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
|
|
28872
|
+
}
|
|
28873
|
+
function isInternalHost(hostname) {
|
|
28874
|
+
const host = hostname.toLowerCase();
|
|
28875
|
+
if (BLOCKED_HOSTNAMES.has(host) || BLOCKED_HOST_SUFFIXES.some((s) => host.endsWith(s))) {
|
|
28876
|
+
return true;
|
|
28877
|
+
}
|
|
28878
|
+
return isBlockedIp(host);
|
|
28879
|
+
}
|
|
28880
|
+
function assertSafeEgressUrl(rawUrl, policy) {
|
|
28881
|
+
let url;
|
|
28882
|
+
try {
|
|
28883
|
+
url = new URL(rawUrl);
|
|
28884
|
+
} catch {
|
|
28885
|
+
throw policy.fail("not a valid URL");
|
|
28886
|
+
}
|
|
28887
|
+
if (!policy.protocols.includes(url.protocol)) {
|
|
28888
|
+
const allowsHttp = policy.protocols.includes("http:");
|
|
28889
|
+
throw policy.fail(`only ${allowsHttp ? "http(s)" : "https"} URLs are allowed`);
|
|
28890
|
+
}
|
|
28891
|
+
if (url.username || url.password) {
|
|
28892
|
+
throw policy.fail("credentials in the URL are not allowed");
|
|
28893
|
+
}
|
|
28894
|
+
if (isInternalHost(url.hostname)) {
|
|
28895
|
+
const kind = isBlockedIp(url.hostname) ? "a private or reserved address" : "internal";
|
|
28896
|
+
throw policy.fail(`host '${url.hostname}' is ${kind}`);
|
|
28897
|
+
}
|
|
28898
|
+
return url;
|
|
28899
|
+
}
|
|
28900
|
+
function webhookUrlAllowlistFromEnv() {
|
|
28901
|
+
const env = globalThis.process?.env;
|
|
28902
|
+
const raw = env?.WEBHOOK_URL_ALLOWLIST;
|
|
28903
|
+
if (!raw)
|
|
28904
|
+
return [];
|
|
28905
|
+
return raw.split(",").map((h) => h.trim().toLowerCase()).filter(Boolean);
|
|
28906
|
+
}
|
|
28907
|
+
function isAllowlistedHost(hostname, allowedHosts) {
|
|
28908
|
+
const host = hostname.toLowerCase();
|
|
28909
|
+
const bare = bareHost(host);
|
|
28910
|
+
return allowedHosts.some((h) => h === host || h === bare);
|
|
28911
|
+
}
|
|
28912
|
+
function assertSafeWebhookUrl(rawUrl, opts = {}) {
|
|
28913
|
+
let url;
|
|
28914
|
+
try {
|
|
28915
|
+
url = new URL(rawUrl);
|
|
28916
|
+
} catch {
|
|
28917
|
+
throw new BlockedWebhookUrlError("not a valid URL");
|
|
28918
|
+
}
|
|
28919
|
+
const allowedHosts = opts.allowedHosts ?? webhookUrlAllowlistFromEnv();
|
|
28920
|
+
if (isAllowlistedHost(url.hostname, allowedHosts)) {
|
|
28921
|
+
return url;
|
|
28922
|
+
}
|
|
28923
|
+
return assertSafeEgressUrl(rawUrl, {
|
|
28924
|
+
protocols: ["https:"],
|
|
28925
|
+
fail: (reason) => new BlockedWebhookUrlError(reason)
|
|
28926
|
+
});
|
|
28927
|
+
}
|
|
28928
|
+
|
|
28929
|
+
// ../../packages/schema/src/contracts/webhooks.ts
|
|
28930
|
+
var webhookUrlSchema = string2().superRefine((value, ctx) => {
|
|
28931
|
+
try {
|
|
28932
|
+
assertSafeWebhookUrl(value);
|
|
28933
|
+
} catch (err) {
|
|
28934
|
+
ctx.addIssue({
|
|
28935
|
+
code: ZodIssueCode.custom,
|
|
28936
|
+
message: err instanceof BlockedWebhookUrlError ? err.message : "invalid webhook url"
|
|
28937
|
+
});
|
|
28938
|
+
}
|
|
28939
|
+
});
|
|
28940
|
+
var webhookEventSchema = string2().min(1).max(120).regex(/^[a-z0-9]+(\.[a-z0-9]+)+$/, "must be a dotted event name like 'task.created'");
|
|
28941
|
+
var webhookSubscriptionSchema = createSelectSchema(webhookSubscriptions, {
|
|
28942
|
+
events: array(webhookEventSchema),
|
|
28943
|
+
createdAt: exports_coerce.date(),
|
|
28944
|
+
updatedAt: exports_coerce.date()
|
|
28945
|
+
});
|
|
28946
|
+
var webhookSubscriptionPublicSchema = webhookSubscriptionSchema.omit({ secret: true });
|
|
28947
|
+
var createWebhookSubscriptionInputSchema = createInsertSchema(webhookSubscriptions, {
|
|
28948
|
+
url: webhookUrlSchema,
|
|
28949
|
+
events: array(webhookEventSchema).min(1),
|
|
28950
|
+
secret: string2().min(16).max(200).optional()
|
|
28951
|
+
}).omit({ id: true, tenantId: true, active: true, createdAt: true, updatedAt: true }).strict();
|
|
28952
|
+
var createWebhookSubscriptionResultSchema = webhookSubscriptionPublicSchema.extend({
|
|
28953
|
+
secret: string2()
|
|
28954
|
+
});
|
|
28955
|
+
var updateWebhookSubscriptionInputSchema = createUpdateSchema(webhookSubscriptions, {
|
|
28956
|
+
url: webhookUrlSchema.optional(),
|
|
28957
|
+
events: array(webhookEventSchema).min(1).optional()
|
|
28958
|
+
}).omit({ id: true, tenantId: true, secret: true, createdAt: true, updatedAt: true }).strict();
|
|
28959
|
+
|
|
28541
28960
|
// ../../packages/schema/src/contracts/roles.ts
|
|
28542
28961
|
var permissionSetSchema = createSelectSchema(permissionSets, {
|
|
28543
28962
|
createdAt: exports_coerce.date(),
|
|
@@ -29603,10 +30022,592 @@ function routeOf(op) {
|
|
|
29603
30022
|
return `${op.method.toUpperCase()} ${PUBLIC_API_PREFIX}${op.path}`;
|
|
29604
30023
|
}
|
|
29605
30024
|
|
|
30025
|
+
// ../../packages/schema/src/operations/agents.ts
|
|
30026
|
+
var agentOperations = defineOperations({
|
|
30027
|
+
list: {
|
|
30028
|
+
method: "get",
|
|
30029
|
+
path: "/agents",
|
|
30030
|
+
scopes: ["agents:read"],
|
|
30031
|
+
tag: "Agents",
|
|
30032
|
+
summary: "List agents",
|
|
30033
|
+
description: "The Space's live Agents (`id`, `name`), oldest first, to resolve an Agent by name.",
|
|
30034
|
+
status: 200,
|
|
30035
|
+
response: { description: "The Space's Agents.", list: true }
|
|
30036
|
+
}
|
|
30037
|
+
});
|
|
30038
|
+
|
|
30039
|
+
// ../../packages/schema/src/operations/crud.ts
|
|
30040
|
+
function crudOperations(r) {
|
|
30041
|
+
const base = `/${r.segment}`;
|
|
30042
|
+
const one = `/${r.segment}/{id}`;
|
|
30043
|
+
const event = r.eventBase ?? r.noun.replace(/ /g, ".");
|
|
30044
|
+
return {
|
|
30045
|
+
list: {
|
|
30046
|
+
method: "get",
|
|
30047
|
+
path: base,
|
|
30048
|
+
scopes: [r.read],
|
|
30049
|
+
tag: r.tag,
|
|
30050
|
+
summary: `List ${r.noun}s`,
|
|
30051
|
+
description: `Every ${r.noun} in the key's Space${r.paginated ? ", newest first" : ""}.`,
|
|
30052
|
+
query: r.listQuery,
|
|
30053
|
+
querySchema: r.listQuerySchema,
|
|
30054
|
+
paginated: r.paginated,
|
|
30055
|
+
status: 200,
|
|
30056
|
+
response: { description: `The Space's ${r.noun}s.`, list: true, view: r.view }
|
|
30057
|
+
},
|
|
30058
|
+
get: {
|
|
30059
|
+
method: "get",
|
|
30060
|
+
path: one,
|
|
30061
|
+
scopes: [r.read],
|
|
30062
|
+
tag: r.tag,
|
|
30063
|
+
summary: `Get a ${r.noun}`,
|
|
30064
|
+
description: `Fetch one ${r.noun} by id.`,
|
|
30065
|
+
status: 200,
|
|
30066
|
+
response: { description: `The ${r.noun}.`, view: r.view },
|
|
30067
|
+
errors: { 404: true }
|
|
30068
|
+
},
|
|
30069
|
+
create: {
|
|
30070
|
+
method: "post",
|
|
30071
|
+
path: base,
|
|
30072
|
+
scopes: [r.write],
|
|
30073
|
+
tag: r.tag,
|
|
30074
|
+
summary: `Create a ${r.noun}`,
|
|
30075
|
+
description: `Create a ${r.noun}; fires the \`${event}.created\` webhook.`,
|
|
30076
|
+
body: r.create,
|
|
30077
|
+
status: 201,
|
|
30078
|
+
response: { description: `The created ${r.noun}.`, view: r.view },
|
|
30079
|
+
errors: { 400: true, 409: true },
|
|
30080
|
+
webhook: `${event}.created`
|
|
30081
|
+
},
|
|
30082
|
+
update: {
|
|
30083
|
+
method: "patch",
|
|
30084
|
+
path: one,
|
|
30085
|
+
scopes: [r.write],
|
|
30086
|
+
tag: r.tag,
|
|
30087
|
+
summary: `Update a ${r.noun}`,
|
|
30088
|
+
description: `Patch a ${r.noun}; fires the \`${event}.updated\` webhook.`,
|
|
30089
|
+
body: r.update,
|
|
30090
|
+
status: 200,
|
|
30091
|
+
response: { description: `The updated ${r.noun}.`, view: r.view },
|
|
30092
|
+
errors: { 400: true, 404: true, 409: true },
|
|
30093
|
+
webhook: `${event}.updated`
|
|
30094
|
+
},
|
|
30095
|
+
remove: {
|
|
30096
|
+
method: "delete",
|
|
30097
|
+
path: one,
|
|
30098
|
+
scopes: [r.write],
|
|
30099
|
+
tag: r.tag,
|
|
30100
|
+
summary: `Delete a ${r.noun}`,
|
|
30101
|
+
description: `Delete a ${r.noun}; fires the \`${event}.deleted\` webhook.`,
|
|
30102
|
+
status: 204,
|
|
30103
|
+
response: { description: "Deleted." },
|
|
30104
|
+
errors: { 404: true },
|
|
30105
|
+
webhook: `${event}.deleted`
|
|
30106
|
+
}
|
|
30107
|
+
};
|
|
30108
|
+
}
|
|
30109
|
+
|
|
30110
|
+
// ../../packages/schema/src/operations/block-templates.ts
|
|
30111
|
+
var crud = crudOperations({
|
|
30112
|
+
segment: "block-templates",
|
|
30113
|
+
tag: "Calendar",
|
|
30114
|
+
noun: "block template",
|
|
30115
|
+
read: "calendar:read",
|
|
30116
|
+
write: "calendar:write",
|
|
30117
|
+
create: createBlockTemplateInputSchema,
|
|
30118
|
+
update: updateBlockTemplateInputSchema,
|
|
30119
|
+
listQuery: []
|
|
30120
|
+
});
|
|
30121
|
+
var blockTemplateOperations = defineOperations({
|
|
30122
|
+
...crud,
|
|
30123
|
+
create: { ...crud.create, webhook: undefined },
|
|
30124
|
+
update: { ...crud.update, webhook: undefined },
|
|
30125
|
+
remove: { ...crud.remove, webhook: undefined },
|
|
30126
|
+
week: {
|
|
30127
|
+
method: "get",
|
|
30128
|
+
path: "/block-templates/week",
|
|
30129
|
+
scopes: ["calendar:read"],
|
|
30130
|
+
tag: "Calendar",
|
|
30131
|
+
summary: "Lay out a week from the block templates",
|
|
30132
|
+
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.",
|
|
30133
|
+
query: [{ name: "start", description: "The week's Monday (YYYY-MM-DD).", format: "date" }],
|
|
30134
|
+
querySchema: blockTemplateWeekQuerySchema,
|
|
30135
|
+
status: 200,
|
|
30136
|
+
response: { description: "The week's blocks." },
|
|
30137
|
+
errors: { 400: true }
|
|
30138
|
+
},
|
|
30139
|
+
defaults: {
|
|
30140
|
+
method: "post",
|
|
30141
|
+
path: "/block-templates/defaults",
|
|
30142
|
+
scopes: ["calendar:write"],
|
|
30143
|
+
tag: "Calendar",
|
|
30144
|
+
summary: "Seed the default week",
|
|
30145
|
+
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.",
|
|
30146
|
+
status: 200,
|
|
30147
|
+
response: { description: "The member's templates." }
|
|
30148
|
+
}
|
|
30149
|
+
});
|
|
30150
|
+
|
|
30151
|
+
// ../../packages/schema/src/operations/collection-upkeep.ts
|
|
30152
|
+
var collectionUpkeepOperations = defineOperations({
|
|
30153
|
+
list: {
|
|
30154
|
+
method: "get",
|
|
30155
|
+
path: "/collection/{id}/upkeep",
|
|
30156
|
+
scopes: ["collections:read"],
|
|
30157
|
+
tag: "Collection",
|
|
30158
|
+
summary: "List an asset's upkeep and repairs",
|
|
30159
|
+
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 }`.",
|
|
30160
|
+
status: 200,
|
|
30161
|
+
response: { description: "The asset's Tasks." },
|
|
30162
|
+
errors: { 404: true }
|
|
30163
|
+
},
|
|
30164
|
+
link: {
|
|
30165
|
+
method: "post",
|
|
30166
|
+
path: "/collection/{id}/upkeep",
|
|
30167
|
+
scopes: ["collections:write"],
|
|
30168
|
+
tag: "Collection",
|
|
30169
|
+
summary: "Tie a Task to an asset",
|
|
30170
|
+
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.',
|
|
30171
|
+
body: linkAssetTaskInputSchema,
|
|
30172
|
+
status: 201,
|
|
30173
|
+
response: { description: "The asset's Tasks." },
|
|
30174
|
+
errors: { 400: true, 404: true }
|
|
30175
|
+
},
|
|
30176
|
+
unlink: {
|
|
30177
|
+
method: "delete",
|
|
30178
|
+
path: "/collection/{id}/upkeep/{taskId}",
|
|
30179
|
+
pathParams: { taskId: "The Task's ULID." },
|
|
30180
|
+
scopes: ["collections:write"],
|
|
30181
|
+
tag: "Collection",
|
|
30182
|
+
summary: "Untie a Task from an asset",
|
|
30183
|
+
description: "Untie the Task from this asset; the Task itself stays. Returns the asset's Tasks.",
|
|
30184
|
+
status: 200,
|
|
30185
|
+
response: { description: "The asset's Tasks." },
|
|
30186
|
+
errors: { 404: true }
|
|
30187
|
+
}
|
|
30188
|
+
});
|
|
30189
|
+
|
|
30190
|
+
// ../../packages/schema/src/operations/google-contacts.ts
|
|
30191
|
+
var googleContactsOperations = defineOperations({
|
|
30192
|
+
list: {
|
|
30193
|
+
method: "get",
|
|
30194
|
+
path: "/people/google-contacts",
|
|
30195
|
+
scopes: ["contacts:read"],
|
|
30196
|
+
tag: "People",
|
|
30197
|
+
summary: "Your Google Contacts, to pick from",
|
|
30198
|
+
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`.",
|
|
30199
|
+
query: [{ name: "q", description: "A name or email to narrow to." }],
|
|
30200
|
+
querySchema: googleContactsQuerySchema,
|
|
30201
|
+
status: 200,
|
|
30202
|
+
response: { description: "The link and the candidates." },
|
|
30203
|
+
errors: { 403: "Not a member's key." }
|
|
30204
|
+
},
|
|
30205
|
+
import: {
|
|
30206
|
+
method: "post",
|
|
30207
|
+
path: "/people/google-contacts/import",
|
|
30208
|
+
scopes: ["contacts:write"],
|
|
30209
|
+
tag: "People",
|
|
30210
|
+
summary: "Import the people you picked from Google Contacts",
|
|
30211
|
+
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).",
|
|
30212
|
+
body: importGoogleContactsInputSchema,
|
|
30213
|
+
status: 200,
|
|
30214
|
+
response: { description: "What the import did." },
|
|
30215
|
+
errors: {
|
|
30216
|
+
400: true,
|
|
30217
|
+
403: "Off, or not a member's key.",
|
|
30218
|
+
409: "Google Contacts isn't connected (or asks to sign in again)."
|
|
30219
|
+
}
|
|
30220
|
+
}
|
|
30221
|
+
});
|
|
30222
|
+
|
|
30223
|
+
// ../../packages/schema/src/operations/google-health.ts
|
|
30224
|
+
var googleHealthOperations = defineOperations({
|
|
30225
|
+
status: {
|
|
30226
|
+
method: "get",
|
|
30227
|
+
path: "/health/google-health",
|
|
30228
|
+
scopes: ["health:read"],
|
|
30229
|
+
tag: "Health",
|
|
30230
|
+
summary: "Get the Google Health link",
|
|
30231
|
+
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.",
|
|
30232
|
+
status: 200,
|
|
30233
|
+
response: { description: "The link's status." },
|
|
30234
|
+
errors: { 403: true }
|
|
30235
|
+
},
|
|
30236
|
+
sync: {
|
|
30237
|
+
method: "post",
|
|
30238
|
+
path: "/health/google-health/sync",
|
|
30239
|
+
scopes: ["health:write"],
|
|
30240
|
+
tag: "Health",
|
|
30241
|
+
summary: "Sync Google Health now",
|
|
30242
|
+
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.",
|
|
30243
|
+
status: 200,
|
|
30244
|
+
response: { description: "What came in, and the status after it." },
|
|
30245
|
+
errors: { 403: true, 409: true }
|
|
30246
|
+
}
|
|
30247
|
+
});
|
|
30248
|
+
|
|
30249
|
+
// ../../packages/schema/src/operations/inventory-items.ts
|
|
30250
|
+
var inventoryItemOperations = defineOperations({
|
|
30251
|
+
...crudOperations({
|
|
30252
|
+
segment: "inventory-items",
|
|
30253
|
+
tag: "Inventory",
|
|
30254
|
+
noun: "inventory item",
|
|
30255
|
+
read: "inventory:read",
|
|
30256
|
+
write: "inventory:write",
|
|
30257
|
+
create: createInventoryItemInputSchema,
|
|
30258
|
+
update: updateInventoryItemInputSchema,
|
|
30259
|
+
paginated: true,
|
|
30260
|
+
listQuerySchema: paginationQuerySchema
|
|
30261
|
+
})
|
|
30262
|
+
});
|
|
30263
|
+
|
|
30264
|
+
// ../../packages/schema/src/operations/mail-campaigns.ts
|
|
30265
|
+
var pathParams = { id: "The campaign's ULID." };
|
|
30266
|
+
var mailCampaignOperations = defineOperations({
|
|
30267
|
+
list: {
|
|
30268
|
+
method: "get",
|
|
30269
|
+
path: "/mail-campaigns",
|
|
30270
|
+
scopes: ["contacts:read"],
|
|
30271
|
+
tag: "Guests",
|
|
30272
|
+
summary: "List a guest list's mail campaigns",
|
|
30273
|
+
description: "Its drafted and sent mails, newest first.",
|
|
30274
|
+
query: [{ name: "guestListId", description: "The guest list (required)." }],
|
|
30275
|
+
querySchema: mailCampaignsQuerySchema,
|
|
30276
|
+
status: 200,
|
|
30277
|
+
response: { description: "The campaigns." },
|
|
30278
|
+
errors: { 400: true }
|
|
30279
|
+
},
|
|
30280
|
+
create: {
|
|
30281
|
+
method: "post",
|
|
30282
|
+
path: "/mail-campaigns",
|
|
30283
|
+
scopes: ["contacts:write"],
|
|
30284
|
+
tag: "Guests",
|
|
30285
|
+
summary: "Draft a mail campaign",
|
|
30286
|
+
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.",
|
|
30287
|
+
body: createMailCampaignInputSchema,
|
|
30288
|
+
status: 201,
|
|
30289
|
+
response: { description: "The draft." },
|
|
30290
|
+
errors: { 400: true, 404: true }
|
|
30291
|
+
},
|
|
30292
|
+
get: {
|
|
30293
|
+
method: "get",
|
|
30294
|
+
path: "/mail-campaigns/{id}",
|
|
30295
|
+
pathParams,
|
|
30296
|
+
scopes: ["contacts:read"],
|
|
30297
|
+
tag: "Guests",
|
|
30298
|
+
summary: "Get a mail campaign",
|
|
30299
|
+
description: "",
|
|
30300
|
+
status: 200,
|
|
30301
|
+
response: { description: "The campaign." },
|
|
30302
|
+
errors: { 404: true }
|
|
30303
|
+
},
|
|
30304
|
+
update: {
|
|
30305
|
+
method: "patch",
|
|
30306
|
+
path: "/mail-campaigns/{id}",
|
|
30307
|
+
pathParams,
|
|
30308
|
+
scopes: ["contacts:write"],
|
|
30309
|
+
tag: "Guests",
|
|
30310
|
+
summary: "Edit a draft",
|
|
30311
|
+
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.",
|
|
30312
|
+
body: updateMailCampaignInputSchema,
|
|
30313
|
+
status: 200,
|
|
30314
|
+
response: { description: "The draft." },
|
|
30315
|
+
errors: { 400: true, 404: true }
|
|
30316
|
+
},
|
|
30317
|
+
preview: {
|
|
30318
|
+
method: "get",
|
|
30319
|
+
path: "/mail-campaigns/{id}/preview",
|
|
30320
|
+
pathParams,
|
|
30321
|
+
scopes: ["contacts:read"],
|
|
30322
|
+
tag: "Guests",
|
|
30323
|
+
summary: "Preview a mail campaign",
|
|
30324
|
+
description: "The mail as a household would get it in one language (`nl` by default, or `pt`): its subject and rendered body.",
|
|
30325
|
+
query: [{ name: "language", description: "`nl` (default) or `pt`." }],
|
|
30326
|
+
querySchema: mailPreviewQuerySchema,
|
|
30327
|
+
status: 200,
|
|
30328
|
+
response: { description: "The rendered mail." },
|
|
30329
|
+
errors: { 400: true, 404: true }
|
|
30330
|
+
}
|
|
30331
|
+
});
|
|
30332
|
+
|
|
30333
|
+
// ../../packages/schema/src/operations/meal-plans.ts
|
|
30334
|
+
var mealPlanOperations = defineOperations({
|
|
30335
|
+
...crudOperations({
|
|
30336
|
+
segment: "meal-plans",
|
|
30337
|
+
tag: "Meals",
|
|
30338
|
+
noun: "meal plan",
|
|
30339
|
+
read: "meals:read",
|
|
30340
|
+
write: "meals:write",
|
|
30341
|
+
create: createMealPlanInputSchema,
|
|
30342
|
+
update: updateMealPlanInputSchema
|
|
30343
|
+
})
|
|
30344
|
+
});
|
|
30345
|
+
|
|
30346
|
+
// ../../packages/schema/src/operations/occurrences.ts
|
|
30347
|
+
var occurrenceOperations = defineOperations({
|
|
30348
|
+
list: {
|
|
30349
|
+
method: "get",
|
|
30350
|
+
path: "/occurrences",
|
|
30351
|
+
scopes: ["occurrences:read"],
|
|
30352
|
+
tag: "Occurrences",
|
|
30353
|
+
summary: "List a template's occurrences",
|
|
30354
|
+
description: "Occurrences of one task/habit template, oldest-first.",
|
|
30355
|
+
query: [{ name: "templateId", description: "The task/habit template's ULID.", required: true }],
|
|
30356
|
+
querySchema: object({ templateId: ulidSchema }),
|
|
30357
|
+
status: 200,
|
|
30358
|
+
response: { description: "The template's occurrences." },
|
|
30359
|
+
errors: { 400: true }
|
|
30360
|
+
},
|
|
30361
|
+
update: {
|
|
30362
|
+
method: "patch",
|
|
30363
|
+
path: "/occurrences/{id}",
|
|
30364
|
+
scopes: ["occurrences:write"],
|
|
30365
|
+
tag: "Occurrences",
|
|
30366
|
+
summary: "Override an occurrence",
|
|
30367
|
+
description: 'Reschedule/skip one occurrence ("edit this"); fires `occurrence.updated`.',
|
|
30368
|
+
body: updateOccurrenceInputSchema,
|
|
30369
|
+
status: 200,
|
|
30370
|
+
response: { description: "The overridden occurrence." },
|
|
30371
|
+
errors: { 400: true, 404: true },
|
|
30372
|
+
webhook: "occurrence.updated"
|
|
30373
|
+
},
|
|
30374
|
+
complete: {
|
|
30375
|
+
method: "post",
|
|
30376
|
+
path: "/occurrences/{id}/complete",
|
|
30377
|
+
scopes: ["occurrences:write"],
|
|
30378
|
+
tag: "Occurrences",
|
|
30379
|
+
summary: "Complete an occurrence",
|
|
30380
|
+
description: "Mark an occurrence done; fires `occurrence.completed`.",
|
|
30381
|
+
status: 201,
|
|
30382
|
+
response: { description: "The completed occurrence." },
|
|
30383
|
+
errors: { 404: true },
|
|
30384
|
+
webhook: "occurrence.completed"
|
|
30385
|
+
}
|
|
30386
|
+
});
|
|
30387
|
+
|
|
30388
|
+
// ../../packages/schema/src/operations/periods.ts
|
|
30389
|
+
var periodOperations = defineOperations({
|
|
30390
|
+
...crudOperations({
|
|
30391
|
+
segment: "periods",
|
|
30392
|
+
tag: "Periods",
|
|
30393
|
+
noun: "period",
|
|
30394
|
+
read: "periods:read",
|
|
30395
|
+
write: "periods:write",
|
|
30396
|
+
create: createPeriodInputSchema,
|
|
30397
|
+
update: updatePeriodInputSchema,
|
|
30398
|
+
listQuery: [
|
|
30399
|
+
{ name: "nodeId", description: "Only the periods on this node." },
|
|
30400
|
+
{
|
|
30401
|
+
name: "kind",
|
|
30402
|
+
description: "Only this kind (`hibernation`, `quarantine`, `away`, `treatment_course`, `withdrawal`, \u2026)."
|
|
30403
|
+
},
|
|
30404
|
+
{
|
|
30405
|
+
name: "active",
|
|
30406
|
+
description: "`true`: only running periods; `false`: only ended or not yet started."
|
|
30407
|
+
}
|
|
30408
|
+
],
|
|
30409
|
+
listQuerySchema: periodsQuerySchema
|
|
30410
|
+
})
|
|
30411
|
+
});
|
|
30412
|
+
|
|
30413
|
+
// ../../packages/schema/src/operations/planning-rules.ts
|
|
30414
|
+
var planningRuleOperations = defineOperations({
|
|
30415
|
+
...crudOperations({
|
|
30416
|
+
segment: "planning/rules",
|
|
30417
|
+
tag: "Planning rules",
|
|
30418
|
+
noun: "planning rule",
|
|
30419
|
+
read: "planning:read",
|
|
30420
|
+
write: "planning:write",
|
|
30421
|
+
create: createPlanningRuleInputSchema,
|
|
30422
|
+
update: updatePlanningRuleInputSchema,
|
|
30423
|
+
listQuery: [
|
|
30424
|
+
{ name: "forUserId", description: "Only this member's rules." },
|
|
30425
|
+
{
|
|
30426
|
+
name: "kind",
|
|
30427
|
+
description: "Only this kind (`fixed_time`, `keep_free`, `meaning`, `whose`, `limit`, `note`)."
|
|
30428
|
+
}
|
|
30429
|
+
],
|
|
30430
|
+
listQuerySchema: planningRulesQuerySchema
|
|
30431
|
+
})
|
|
30432
|
+
});
|
|
30433
|
+
|
|
30434
|
+
// ../../packages/schema/src/operations/plans.ts
|
|
30435
|
+
function decision(path, verb, what) {
|
|
30436
|
+
return {
|
|
30437
|
+
method: "post",
|
|
30438
|
+
path,
|
|
30439
|
+
scopes: ["tasks:write"],
|
|
30440
|
+
tag: "Plans",
|
|
30441
|
+
summary: `${verb[0]?.toUpperCase()}${verb.slice(1)} plan items`,
|
|
30442
|
+
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.`,
|
|
30443
|
+
body: planDecisionInputSchema,
|
|
30444
|
+
bodyOptional: true,
|
|
30445
|
+
status: 200,
|
|
30446
|
+
response: { description: "The plan, after.", view: "Plan" },
|
|
30447
|
+
errors: { 400: true, 404: true }
|
|
30448
|
+
};
|
|
30449
|
+
}
|
|
30450
|
+
var planOperations = defineOperations({
|
|
30451
|
+
list: {
|
|
30452
|
+
method: "get",
|
|
30453
|
+
path: "/plans",
|
|
30454
|
+
scopes: ["tasks:read"],
|
|
30455
|
+
tag: "Plans",
|
|
30456
|
+
summary: "List plans",
|
|
30457
|
+
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).",
|
|
30458
|
+
query: [
|
|
30459
|
+
{ name: "kind", description: "`week` or `day`." },
|
|
30460
|
+
{ name: "status", description: "`open`, `settled` or `replaced`." },
|
|
30461
|
+
{ name: "startsOn", description: "The week's Monday, or the day (`YYYY-MM-DD`)." },
|
|
30462
|
+
{ name: "forUserId", description: "Only this member's plans." }
|
|
30463
|
+
],
|
|
30464
|
+
querySchema: planListQuerySchema.extend({ forUserId: string2().min(1).optional() }),
|
|
30465
|
+
status: 200,
|
|
30466
|
+
response: { description: "The plans.", list: true, view: "Plan" },
|
|
30467
|
+
errors: { 400: true }
|
|
30468
|
+
},
|
|
30469
|
+
create: {
|
|
30470
|
+
method: "post",
|
|
30471
|
+
path: "/plans",
|
|
30472
|
+
scopes: ["tasks:write"],
|
|
30473
|
+
tag: "Plans",
|
|
30474
|
+
summary: "Propose a plan",
|
|
30475
|
+
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.",
|
|
30476
|
+
body: createPlanInputSchema,
|
|
30477
|
+
status: 201,
|
|
30478
|
+
response: {
|
|
30479
|
+
description: "The plan, open, with the duplicates it folded in.",
|
|
30480
|
+
view: "PlanCreateResult"
|
|
30481
|
+
},
|
|
30482
|
+
errors: { 400: true }
|
|
30483
|
+
},
|
|
30484
|
+
get: {
|
|
30485
|
+
method: "get",
|
|
30486
|
+
path: "/plans/{id}",
|
|
30487
|
+
scopes: ["tasks:read"],
|
|
30488
|
+
tag: "Plans",
|
|
30489
|
+
summary: "Get a plan",
|
|
30490
|
+
description: "One plan with its items.",
|
|
30491
|
+
status: 200,
|
|
30492
|
+
response: { description: "The plan.", view: "Plan" },
|
|
30493
|
+
errors: { 404: true }
|
|
30494
|
+
},
|
|
30495
|
+
accept: {
|
|
30496
|
+
...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."),
|
|
30497
|
+
errors: { 400: true, 404: true, 409: "A newer plan replaced this one." }
|
|
30498
|
+
},
|
|
30499
|
+
dismiss: decision("/plans/{id}/dismiss", "dismiss", "Leave proposed items out. Nothing is written to a task."),
|
|
30500
|
+
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.")
|
|
30501
|
+
});
|
|
30502
|
+
|
|
30503
|
+
// ../../packages/schema/src/operations/rsvp-answers.ts
|
|
30504
|
+
var rsvpAnswerOperations = defineOperations({
|
|
30505
|
+
list: {
|
|
30506
|
+
method: "get",
|
|
30507
|
+
path: "/rsvp-answers",
|
|
30508
|
+
scopes: ["contacts:read"],
|
|
30509
|
+
tag: "Guests",
|
|
30510
|
+
summary: "List RSVP answers",
|
|
30511
|
+
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.",
|
|
30512
|
+
query: [
|
|
30513
|
+
{ name: "guestListId", description: "The guest list (required)." },
|
|
30514
|
+
{ name: "householdId", description: "Only this household's answers." }
|
|
30515
|
+
],
|
|
30516
|
+
querySchema: rsvpAnswersQuerySchema,
|
|
30517
|
+
status: 200,
|
|
30518
|
+
response: { description: "The answers." },
|
|
30519
|
+
errors: { 400: true, 404: true }
|
|
30520
|
+
},
|
|
30521
|
+
set: {
|
|
30522
|
+
method: "put",
|
|
30523
|
+
path: "/rsvp-answers",
|
|
30524
|
+
scopes: ["contacts:write"],
|
|
30525
|
+
tag: "Guests",
|
|
30526
|
+
summary: "Set a household's RSVP answers",
|
|
30527
|
+
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`.",
|
|
30528
|
+
body: setRsvpAnswersInputSchema,
|
|
30529
|
+
status: 200,
|
|
30530
|
+
response: { description: "The household's answers after." },
|
|
30531
|
+
errors: { 400: true, 404: true, 422: "An answer that can't be given (see the message)." },
|
|
30532
|
+
webhook: "rsvp.answers.updated"
|
|
30533
|
+
}
|
|
30534
|
+
});
|
|
30535
|
+
|
|
30536
|
+
// ../../packages/schema/src/operations/rsvp-questions.ts
|
|
30537
|
+
var rsvpQuestionOperations = defineOperations({
|
|
30538
|
+
...crudOperations({
|
|
30539
|
+
segment: "rsvp-questions",
|
|
30540
|
+
tag: "Guests",
|
|
30541
|
+
noun: "RSVP question",
|
|
30542
|
+
eventBase: "rsvp.question",
|
|
30543
|
+
read: "contacts:read",
|
|
30544
|
+
write: "contacts:write",
|
|
30545
|
+
create: createRsvpQuestionInputSchema,
|
|
30546
|
+
update: updateRsvpQuestionInputSchema,
|
|
30547
|
+
listQuery: [{ name: "guestListId", description: "The guest list (required)." }],
|
|
30548
|
+
listQuerySchema: rsvpQuestionsQuerySchema
|
|
30549
|
+
}),
|
|
30550
|
+
presets: {
|
|
30551
|
+
method: "post",
|
|
30552
|
+
path: "/rsvp-questions/presets",
|
|
30553
|
+
scopes: ["contacts:write"],
|
|
30554
|
+
tag: "Guests",
|
|
30555
|
+
summary: "Add the built-in RSVP questions",
|
|
30556
|
+
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`.",
|
|
30557
|
+
body: addRsvpPresetsInputSchema,
|
|
30558
|
+
status: 200,
|
|
30559
|
+
response: { description: "The list's questions." },
|
|
30560
|
+
errors: { 400: true, 404: true },
|
|
30561
|
+
webhook: "rsvp.question.created"
|
|
30562
|
+
}
|
|
30563
|
+
});
|
|
30564
|
+
|
|
30565
|
+
// ../../packages/schema/src/operations/settings.ts
|
|
30566
|
+
var settingsOperations = defineOperations({
|
|
30567
|
+
get: {
|
|
30568
|
+
method: "get",
|
|
30569
|
+
path: "/settings",
|
|
30570
|
+
scopes: ["settings:read"],
|
|
30571
|
+
tag: "Settings",
|
|
30572
|
+
summary: "Get settings",
|
|
30573
|
+
description: "The caller's settings (lazily created). The key must carry a user identity.",
|
|
30574
|
+
status: 200,
|
|
30575
|
+
response: { description: "The caller's settings." }
|
|
30576
|
+
},
|
|
30577
|
+
update: {
|
|
30578
|
+
method: "patch",
|
|
30579
|
+
path: "/settings",
|
|
30580
|
+
scopes: ["settings:write"],
|
|
30581
|
+
tag: "Settings",
|
|
30582
|
+
summary: "Update settings",
|
|
30583
|
+
description: "Patch the caller's settings; fires `settings.updated`.",
|
|
30584
|
+
body: updateUserSettingsInputSchema,
|
|
30585
|
+
status: 200,
|
|
30586
|
+
response: { description: "The updated settings." },
|
|
30587
|
+
errors: { 400: true },
|
|
30588
|
+
webhook: "settings.updated"
|
|
30589
|
+
}
|
|
30590
|
+
});
|
|
30591
|
+
|
|
30592
|
+
// ../../packages/schema/src/operations/shopping-lists.ts
|
|
30593
|
+
var shoppingListOperations = defineOperations({
|
|
30594
|
+
...crudOperations({
|
|
30595
|
+
segment: "shopping-lists",
|
|
30596
|
+
tag: "Shopping",
|
|
30597
|
+
noun: "shopping list",
|
|
30598
|
+
read: "shopping:read",
|
|
30599
|
+
write: "shopping:write",
|
|
30600
|
+
create: createShoppingListInputSchema,
|
|
30601
|
+
update: updateShoppingListInputSchema,
|
|
30602
|
+
paginated: true,
|
|
30603
|
+
listQuerySchema: paginationQuerySchema
|
|
30604
|
+
})
|
|
30605
|
+
});
|
|
30606
|
+
|
|
29606
30607
|
// ../../packages/schema/src/operations/tap-tags.ts
|
|
29607
30608
|
var READ = ["habits:read", "routines:read"];
|
|
29608
30609
|
var WRITE = ["habits:write", "routines:write"];
|
|
29609
|
-
var
|
|
30610
|
+
var pathParams2 = { id: "The tag's id: the ULID the sticker's link carries (`/t/{id}`)." };
|
|
29610
30611
|
var tapTagOperations = defineOperations({
|
|
29611
30612
|
list: {
|
|
29612
30613
|
method: "get",
|
|
@@ -29634,7 +30635,7 @@ var tapTagOperations = defineOperations({
|
|
|
29634
30635
|
get: {
|
|
29635
30636
|
method: "get",
|
|
29636
30637
|
path: "/tap-tags/{id}",
|
|
29637
|
-
pathParams,
|
|
30638
|
+
pathParams: pathParams2,
|
|
29638
30639
|
scopes: READ,
|
|
29639
30640
|
tag: "Habits",
|
|
29640
30641
|
summary: "Get a tap tag",
|
|
@@ -29646,7 +30647,7 @@ var tapTagOperations = defineOperations({
|
|
|
29646
30647
|
update: {
|
|
29647
30648
|
method: "patch",
|
|
29648
30649
|
path: "/tap-tags/{id}",
|
|
29649
|
-
pathParams,
|
|
30650
|
+
pathParams: pathParams2,
|
|
29650
30651
|
scopes: WRITE,
|
|
29651
30652
|
tag: "Habits",
|
|
29652
30653
|
summary: "Rename or rebind a tap tag",
|
|
@@ -29659,7 +30660,7 @@ var tapTagOperations = defineOperations({
|
|
|
29659
30660
|
remove: {
|
|
29660
30661
|
method: "delete",
|
|
29661
30662
|
path: "/tap-tags/{id}",
|
|
29662
|
-
pathParams,
|
|
30663
|
+
pathParams: pathParams2,
|
|
29663
30664
|
scopes: WRITE,
|
|
29664
30665
|
tag: "Habits",
|
|
29665
30666
|
summary: "Delete a tap tag",
|
|
@@ -29671,7 +30672,7 @@ var tapTagOperations = defineOperations({
|
|
|
29671
30672
|
tap: {
|
|
29672
30673
|
method: "post",
|
|
29673
30674
|
path: "/tap-tags/{id}/tap",
|
|
29674
|
-
pathParams,
|
|
30675
|
+
pathParams: pathParams2,
|
|
29675
30676
|
scopes: WRITE,
|
|
29676
30677
|
tag: "Habits",
|
|
29677
30678
|
summary: "Tap a tap tag",
|
|
@@ -29682,6 +30683,103 @@ var tapTagOperations = defineOperations({
|
|
|
29682
30683
|
}
|
|
29683
30684
|
});
|
|
29684
30685
|
|
|
30686
|
+
// ../../packages/schema/src/operations/today.ts
|
|
30687
|
+
var todayOperations = defineOperations({
|
|
30688
|
+
fromEarlier: {
|
|
30689
|
+
method: "get",
|
|
30690
|
+
path: "/today/from-earlier",
|
|
30691
|
+
scopes: ["tasks:read"],
|
|
30692
|
+
tag: "Reads",
|
|
30693
|
+
summary: "From earlier",
|
|
30694
|
+
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`.',
|
|
30695
|
+
query: [
|
|
30696
|
+
{
|
|
30697
|
+
name: "from",
|
|
30698
|
+
description: "Your local day start, an ISO instant (or a bare date, read as UTC midnight). Defaults to the current UTC day."
|
|
30699
|
+
},
|
|
30700
|
+
{ name: "areaId", description: "Only tasks in this Area (own or their Project's)." }
|
|
30701
|
+
],
|
|
30702
|
+
querySchema: fromEarlierQuerySchema,
|
|
30703
|
+
status: 200,
|
|
30704
|
+
response: { description: "From earlier.", view: "FromEarlierResponse" },
|
|
30705
|
+
errors: { 400: true }
|
|
30706
|
+
},
|
|
30707
|
+
rollover: {
|
|
30708
|
+
method: "post",
|
|
30709
|
+
path: "/today/rollover",
|
|
30710
|
+
scopes: ["tasks:write"],
|
|
30711
|
+
tag: "Tasks",
|
|
30712
|
+
summary: "Answer From earlier",
|
|
30713
|
+
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.',
|
|
30714
|
+
body: rolloverInputSchema,
|
|
30715
|
+
status: 201,
|
|
30716
|
+
response: { description: "How many tasks and occurrences changed." },
|
|
30717
|
+
errors: { 400: true }
|
|
30718
|
+
}
|
|
30719
|
+
});
|
|
30720
|
+
|
|
30721
|
+
// ../../packages/schema/src/operations/webhooks.ts
|
|
30722
|
+
var webhookOperations = defineOperations({
|
|
30723
|
+
list: {
|
|
30724
|
+
method: "get",
|
|
30725
|
+
path: "/webhooks",
|
|
30726
|
+
scopes: ["webhooks:read"],
|
|
30727
|
+
tag: "Webhooks",
|
|
30728
|
+
summary: "List webhook subscriptions",
|
|
30729
|
+
description: "The Space's outbound webhook endpoints (secrets omitted), newest first.",
|
|
30730
|
+
querySchema: paginationQuerySchema,
|
|
30731
|
+
paginated: true,
|
|
30732
|
+
status: 200,
|
|
30733
|
+
response: { description: "The subscriptions." }
|
|
30734
|
+
},
|
|
30735
|
+
create: {
|
|
30736
|
+
method: "post",
|
|
30737
|
+
path: "/webhooks",
|
|
30738
|
+
scopes: ["webhooks:write"],
|
|
30739
|
+
tag: "Webhooks",
|
|
30740
|
+
summary: "Register a webhook subscription",
|
|
30741
|
+
description: "Register an endpoint + events; returns the signing secret once.",
|
|
30742
|
+
body: createWebhookSubscriptionInputSchema,
|
|
30743
|
+
status: 201,
|
|
30744
|
+
response: { description: "The created subscription (with its one-time secret)." },
|
|
30745
|
+
errors: { 400: true }
|
|
30746
|
+
},
|
|
30747
|
+
get: {
|
|
30748
|
+
method: "get",
|
|
30749
|
+
path: "/webhooks/{id}",
|
|
30750
|
+
scopes: ["webhooks:read"],
|
|
30751
|
+
tag: "Webhooks",
|
|
30752
|
+
summary: "Get a webhook subscription",
|
|
30753
|
+
description: "One subscription (secret omitted).",
|
|
30754
|
+
status: 200,
|
|
30755
|
+
response: { description: "The subscription." },
|
|
30756
|
+
errors: { 404: true }
|
|
30757
|
+
},
|
|
30758
|
+
update: {
|
|
30759
|
+
method: "patch",
|
|
30760
|
+
path: "/webhooks/{id}",
|
|
30761
|
+
scopes: ["webhooks:write"],
|
|
30762
|
+
tag: "Webhooks",
|
|
30763
|
+
summary: "Update a webhook subscription",
|
|
30764
|
+
description: "Patch url/events, or pause with `active: false`.",
|
|
30765
|
+
body: updateWebhookSubscriptionInputSchema,
|
|
30766
|
+
status: 200,
|
|
30767
|
+
response: { description: "The updated subscription." },
|
|
30768
|
+
errors: { 400: true, 404: true }
|
|
30769
|
+
},
|
|
30770
|
+
remove: {
|
|
30771
|
+
method: "delete",
|
|
30772
|
+
path: "/webhooks/{id}",
|
|
30773
|
+
scopes: ["webhooks:write"],
|
|
30774
|
+
tag: "Webhooks",
|
|
30775
|
+
summary: "Delete a webhook subscription",
|
|
30776
|
+
description: "Remove an endpoint.",
|
|
30777
|
+
status: 204,
|
|
30778
|
+
response: { description: "Deleted." },
|
|
30779
|
+
errors: { 404: true }
|
|
30780
|
+
}
|
|
30781
|
+
});
|
|
30782
|
+
|
|
29685
30783
|
// ../../node_modules/ulidx/dist/node/index.js
|
|
29686
30784
|
import crypto from "crypto";
|
|
29687
30785
|
|
|
@@ -29934,7 +31032,7 @@ function parseCapture2(input, now) {
|
|
|
29934
31032
|
|
|
29935
31033
|
// src/meta.ts
|
|
29936
31034
|
var CLI_NAME = "do";
|
|
29937
|
-
var VERSION = "1.
|
|
31035
|
+
var VERSION = "1.304.0";
|
|
29938
31036
|
var API_PREFIX = "/api/v1";
|
|
29939
31037
|
var DEFAULT_API_URL = "http://localhost:3001";
|
|
29940
31038
|
|
|
@@ -30717,24 +31815,15 @@ var ENTITIES = [
|
|
|
30717
31815
|
canDelete: true
|
|
30718
31816
|
}
|
|
30719
31817
|
},
|
|
30720
|
-
{
|
|
31818
|
+
entityFromOperations(rsvpQuestionOperations, {
|
|
30721
31819
|
name: "rsvp-questions",
|
|
30722
|
-
path: "/rsvp-questions",
|
|
30723
|
-
readScopes: ["contacts:read"],
|
|
30724
31820
|
returns: "RsvpQuestion",
|
|
30725
|
-
canGet: true,
|
|
30726
31821
|
listFlags: [
|
|
30727
31822
|
{ name: "list", description: "the guest list's id (required)", query: "guestListId" }
|
|
30728
31823
|
],
|
|
30729
|
-
|
|
30730
|
-
|
|
30731
|
-
|
|
30732
|
-
createInput: "CreateRsvpQuestionInput",
|
|
30733
|
-
updateSchema: updateRsvpQuestionInputSchema,
|
|
30734
|
-
updateInput: "UpdateRsvpQuestionInput",
|
|
30735
|
-
canDelete: true
|
|
30736
|
-
}
|
|
30737
|
-
},
|
|
31824
|
+
createInput: "CreateRsvpQuestionInput",
|
|
31825
|
+
updateInput: "UpdateRsvpQuestionInput"
|
|
31826
|
+
}),
|
|
30738
31827
|
{
|
|
30739
31828
|
name: "guests",
|
|
30740
31829
|
path: "/guests",
|
|
@@ -30843,12 +31932,9 @@ var ENTITIES = [
|
|
|
30843
31932
|
canDelete: true
|
|
30844
31933
|
}
|
|
30845
31934
|
},
|
|
30846
|
-
{
|
|
31935
|
+
entityFromOperations(periodOperations, {
|
|
30847
31936
|
name: "periods",
|
|
30848
|
-
path: "/periods",
|
|
30849
|
-
readScopes: ["periods:read"],
|
|
30850
31937
|
returns: "PeriodView",
|
|
30851
|
-
canGet: true,
|
|
30852
31938
|
listFlags: [
|
|
30853
31939
|
{ name: "node", description: "only the periods on this node id", query: "nodeId" },
|
|
30854
31940
|
{
|
|
@@ -30862,15 +31948,9 @@ var ENTITIES = [
|
|
|
30862
31948
|
query: "active"
|
|
30863
31949
|
}
|
|
30864
31950
|
],
|
|
30865
|
-
|
|
30866
|
-
|
|
30867
|
-
|
|
30868
|
-
createInput: "CreatePeriodInput",
|
|
30869
|
-
updateSchema: updatePeriodInputSchema,
|
|
30870
|
-
updateInput: "UpdatePeriodInput",
|
|
30871
|
-
canDelete: true
|
|
30872
|
-
}
|
|
30873
|
-
},
|
|
31951
|
+
createInput: "CreatePeriodInput",
|
|
31952
|
+
updateInput: "UpdatePeriodInput"
|
|
31953
|
+
}),
|
|
30874
31954
|
entityFromOperations(tapTagOperations, {
|
|
30875
31955
|
name: "tap-tags",
|
|
30876
31956
|
returns: "TapTagView",
|
|
@@ -30932,38 +32012,20 @@ var ENTITIES = [
|
|
|
30932
32012
|
canDelete: true
|
|
30933
32013
|
}
|
|
30934
32014
|
},
|
|
30935
|
-
{
|
|
32015
|
+
entityFromOperations(shoppingListOperations, {
|
|
30936
32016
|
name: "shopping-lists",
|
|
30937
|
-
path: "/shopping-lists",
|
|
30938
|
-
readScopes: ["shopping:read"],
|
|
30939
32017
|
returns: "ShoppingList",
|
|
30940
|
-
canGet: true,
|
|
30941
32018
|
listFlags: [],
|
|
30942
|
-
|
|
30943
|
-
|
|
30944
|
-
|
|
30945
|
-
|
|
30946
|
-
updateSchema: updateShoppingListInputSchema,
|
|
30947
|
-
updateInput: "UpdateShoppingListInput",
|
|
30948
|
-
canDelete: true
|
|
30949
|
-
}
|
|
30950
|
-
},
|
|
30951
|
-
{
|
|
32019
|
+
createInput: "CreateShoppingListInput",
|
|
32020
|
+
updateInput: "UpdateShoppingListInput"
|
|
32021
|
+
}),
|
|
32022
|
+
entityFromOperations(inventoryItemOperations, {
|
|
30952
32023
|
name: "inventory-items",
|
|
30953
|
-
path: "/inventory-items",
|
|
30954
|
-
readScopes: ["inventory:read"],
|
|
30955
32024
|
returns: "InventoryItem",
|
|
30956
|
-
canGet: true,
|
|
30957
32025
|
listFlags: [],
|
|
30958
|
-
|
|
30959
|
-
|
|
30960
|
-
|
|
30961
|
-
createInput: "CreateInventoryItemInput",
|
|
30962
|
-
updateSchema: updateInventoryItemInputSchema,
|
|
30963
|
-
updateInput: "UpdateInventoryItemInput",
|
|
30964
|
-
canDelete: true
|
|
30965
|
-
}
|
|
30966
|
-
},
|
|
32026
|
+
createInput: "CreateInventoryItemInput",
|
|
32027
|
+
updateInput: "UpdateInventoryItemInput"
|
|
32028
|
+
}),
|
|
30967
32029
|
{
|
|
30968
32030
|
name: "recipes",
|
|
30969
32031
|
path: "/recipes",
|
|
@@ -30980,28 +32042,16 @@ var ENTITIES = [
|
|
|
30980
32042
|
canDelete: true
|
|
30981
32043
|
}
|
|
30982
32044
|
},
|
|
30983
|
-
{
|
|
32045
|
+
entityFromOperations(mealPlanOperations, {
|
|
30984
32046
|
name: "meal-plans",
|
|
30985
|
-
path: "/meal-plans",
|
|
30986
|
-
readScopes: ["meals:read"],
|
|
30987
32047
|
returns: "MealPlan",
|
|
30988
|
-
canGet: true,
|
|
30989
32048
|
listFlags: [],
|
|
30990
|
-
|
|
30991
|
-
|
|
30992
|
-
|
|
30993
|
-
|
|
30994
|
-
updateSchema: updateMealPlanInputSchema,
|
|
30995
|
-
updateInput: "UpdateMealPlanInput",
|
|
30996
|
-
canDelete: true
|
|
30997
|
-
}
|
|
30998
|
-
},
|
|
30999
|
-
{
|
|
32049
|
+
createInput: "CreateMealPlanInput",
|
|
32050
|
+
updateInput: "UpdateMealPlanInput"
|
|
32051
|
+
}),
|
|
32052
|
+
entityFromOperations({ list: occurrenceOperations.list }, {
|
|
31000
32053
|
name: "occurrences",
|
|
31001
|
-
path: "/occurrences",
|
|
31002
|
-
readScopes: ["occurrences:read"],
|
|
31003
32054
|
returns: "Occurrence",
|
|
31004
|
-
canGet: false,
|
|
31005
32055
|
listFlags: [
|
|
31006
32056
|
{
|
|
31007
32057
|
name: "template-id",
|
|
@@ -31010,7 +32060,7 @@ var ENTITIES = [
|
|
|
31010
32060
|
query: "templateId"
|
|
31011
32061
|
}
|
|
31012
32062
|
]
|
|
31013
|
-
},
|
|
32063
|
+
}),
|
|
31014
32064
|
{
|
|
31015
32065
|
name: "time-blocks",
|
|
31016
32066
|
path: "/time-blocks",
|
|
@@ -31034,30 +32084,14 @@ var ENTITIES = [
|
|
|
31034
32084
|
canDelete: true
|
|
31035
32085
|
}
|
|
31036
32086
|
},
|
|
31037
|
-
{
|
|
32087
|
+
entityFromOperations(blockTemplateOperations, {
|
|
31038
32088
|
name: "block-templates",
|
|
31039
|
-
path: "/block-templates",
|
|
31040
|
-
readScopes: ["calendar:read"],
|
|
31041
32089
|
returns: "BlockTemplateView",
|
|
31042
|
-
canGet: true,
|
|
31043
32090
|
listFlags: [],
|
|
31044
|
-
|
|
31045
|
-
|
|
31046
|
-
|
|
31047
|
-
|
|
31048
|
-
updateSchema: updateBlockTemplateInputSchema,
|
|
31049
|
-
updateInput: "UpdateBlockTemplateInput",
|
|
31050
|
-
canDelete: true
|
|
31051
|
-
}
|
|
31052
|
-
},
|
|
31053
|
-
{
|
|
31054
|
-
name: "webhooks",
|
|
31055
|
-
path: "/webhooks",
|
|
31056
|
-
readScopes: ["webhooks:read"],
|
|
31057
|
-
returns: "WebhookSubscription",
|
|
31058
|
-
canGet: true,
|
|
31059
|
-
listFlags: []
|
|
31060
|
-
}
|
|
32091
|
+
createInput: "CreateBlockTemplateInput",
|
|
32092
|
+
updateInput: "UpdateBlockTemplateInput"
|
|
32093
|
+
}),
|
|
32094
|
+
entityFromOperations({ list: webhookOperations.list, get: webhookOperations.get }, { name: "webhooks", returns: "WebhookSubscription", listFlags: [] })
|
|
31061
32095
|
];
|
|
31062
32096
|
var entityByName = (name) => ENTITIES.find((e) => e.name === name);
|
|
31063
32097
|
function entityOperations(e) {
|
|
@@ -31487,18 +32521,36 @@ var HEALTH_COMMAND_SPECS = [
|
|
|
31487
32521
|
summary: "Whether your Google Health is connected, the last sync, and what stops it.",
|
|
31488
32522
|
args: [],
|
|
31489
32523
|
flags: [],
|
|
31490
|
-
scopes:
|
|
32524
|
+
scopes: [...googleHealthOperations.status.scopes],
|
|
31491
32525
|
returns: "GoogleHealthStatus",
|
|
31492
|
-
notes:
|
|
32526
|
+
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.`
|
|
31493
32527
|
},
|
|
31494
32528
|
{
|
|
31495
32529
|
path: ["health", "google", "sync"],
|
|
31496
32530
|
summary: "Sync your Google Health now (sleep, resting heart rate, HRV, steps, workouts), as the morning sync does.",
|
|
31497
32531
|
args: [],
|
|
31498
32532
|
flags: [],
|
|
31499
|
-
scopes:
|
|
32533
|
+
scopes: [...googleHealthOperations.sync.scopes],
|
|
31500
32534
|
returns: "GoogleHealthSyncResult",
|
|
31501
|
-
notes:
|
|
32535
|
+
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.`
|
|
32536
|
+
},
|
|
32537
|
+
{
|
|
32538
|
+
path: ["health", "withings", "status"],
|
|
32539
|
+
summary: "Whether your Withings scale is connected, the last sync, and what stops it.",
|
|
32540
|
+
args: [],
|
|
32541
|
+
flags: [],
|
|
32542
|
+
scopes: READ2,
|
|
32543
|
+
returns: "WithingsStatus",
|
|
32544
|
+
notes: "GET /api/v1/health/withings. Connecting needs Withings' consent in a browser: Settings \u2192 Health in do. `failure` (reauth, unavailable, other) says what stops the sync, with a title and a hint."
|
|
32545
|
+
},
|
|
32546
|
+
{
|
|
32547
|
+
path: ["health", "withings", "sync"],
|
|
32548
|
+
summary: "Sync your Withings weigh-ins now, as the morning sync does.",
|
|
32549
|
+
args: [],
|
|
32550
|
+
flags: [],
|
|
32551
|
+
scopes: WRITE3,
|
|
32552
|
+
returns: "WithingsSyncResult",
|
|
32553
|
+
notes: "POST /api/v1/health/withings/sync. Written and skipped, and the status after it; a sync that stops answers 200 with `status.failure`. 409 before Withings is connected, 403 while the server has it switched off."
|
|
31502
32554
|
},
|
|
31503
32555
|
{
|
|
31504
32556
|
path: ["health", "analyte"],
|
|
@@ -31764,9 +32816,9 @@ var COMMAND_SPECS = [
|
|
|
31764
32816
|
summary: "From earlier: planned tasks of the last 14 days that weren't done, newest first, and the day Later this week lands on.",
|
|
31765
32817
|
args: [],
|
|
31766
32818
|
flags: [{ name: "area", type: "string", description: "Only tasks in this Area (id)." }],
|
|
31767
|
-
scopes: [
|
|
32819
|
+
scopes: [...todayOperations.fromEarlier.scopes],
|
|
31768
32820
|
returns: "FromEarlierResponse",
|
|
31769
|
-
notes:
|
|
32821
|
+
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\`.`
|
|
31770
32822
|
},
|
|
31771
32823
|
{
|
|
31772
32824
|
path: ["today", "answer"],
|
|
@@ -32276,18 +33328,18 @@ var COMMAND_SPECS = [
|
|
|
32276
33328
|
flags: [
|
|
32277
33329
|
{ name: "start", type: "string", description: "The week's Monday (YYYY-MM-DD). Required." }
|
|
32278
33330
|
],
|
|
32279
|
-
scopes: [
|
|
33331
|
+
scopes: [...blockTemplateOperations.week.scopes],
|
|
32280
33332
|
returns: "BlockTemplateInstance[]",
|
|
32281
|
-
notes:
|
|
33333
|
+
notes: `${routeOf(blockTemplateOperations.week)}?start= (plan vs record, phase 1).`
|
|
32282
33334
|
},
|
|
32283
33335
|
{
|
|
32284
33336
|
path: ["block-templates", "defaults"],
|
|
32285
33337
|
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.",
|
|
32286
33338
|
args: [],
|
|
32287
33339
|
flags: [],
|
|
32288
|
-
scopes: [
|
|
33340
|
+
scopes: [...blockTemplateOperations.defaults.scopes],
|
|
32289
33341
|
returns: "BlockTemplateView[]",
|
|
32290
|
-
notes:
|
|
33342
|
+
notes: `${routeOf(blockTemplateOperations.defaults)} (plan vs record, phase 1).`
|
|
32291
33343
|
},
|
|
32292
33344
|
{
|
|
32293
33345
|
path: ["time-blocks", "record"],
|
|
@@ -32425,18 +33477,18 @@ var COMMAND_SPECS = [
|
|
|
32425
33477
|
},
|
|
32426
33478
|
{ name: "for", type: "string", description: "Only this member's plans (user id)." }
|
|
32427
33479
|
],
|
|
32428
|
-
scopes: [
|
|
33480
|
+
scopes: [...planOperations.list.scopes],
|
|
32429
33481
|
returns: "Plan[]",
|
|
32430
|
-
notes:
|
|
33482
|
+
notes: `${routeOf(planOperations.list)} (#912): the latest 20.`
|
|
32431
33483
|
},
|
|
32432
33484
|
{
|
|
32433
33485
|
path: ["plans", "get"],
|
|
32434
33486
|
summary: "One plan proposal with its items and each item's task as it is now.",
|
|
32435
33487
|
args: [{ name: "id", required: true, description: "Plan id." }],
|
|
32436
33488
|
flags: [],
|
|
32437
|
-
scopes: [
|
|
33489
|
+
scopes: [...planOperations.get.scopes],
|
|
32438
33490
|
returns: "Plan",
|
|
32439
|
-
notes:
|
|
33491
|
+
notes: `${routeOf(planOperations.get)} (#912).`
|
|
32440
33492
|
},
|
|
32441
33493
|
{
|
|
32442
33494
|
path: ["plans", "propose"],
|
|
@@ -32449,9 +33501,9 @@ var COMMAND_SPECS = [
|
|
|
32449
33501
|
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.'
|
|
32450
33502
|
}
|
|
32451
33503
|
],
|
|
32452
|
-
scopes: [
|
|
33504
|
+
scopes: [...planOperations.create.scopes],
|
|
32453
33505
|
returns: "Plan",
|
|
32454
|
-
notes:
|
|
33506
|
+
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.`
|
|
32455
33507
|
},
|
|
32456
33508
|
{
|
|
32457
33509
|
path: ["plans", "accept"],
|
|
@@ -32461,9 +33513,9 @@ var COMMAND_SPECS = [
|
|
|
32461
33513
|
{ name: "items", required: false, description: "Item ids (default: every proposed item)." }
|
|
32462
33514
|
],
|
|
32463
33515
|
flags: [],
|
|
32464
|
-
scopes: [
|
|
33516
|
+
scopes: [...planOperations.accept.scopes],
|
|
32465
33517
|
returns: "Plan",
|
|
32466
|
-
notes:
|
|
33518
|
+
notes: `${routeOf(planOperations.accept)} (#912). Undo with \`do plans undo\`.`
|
|
32467
33519
|
},
|
|
32468
33520
|
{
|
|
32469
33521
|
path: ["plans", "dismiss"],
|
|
@@ -32473,9 +33525,9 @@ var COMMAND_SPECS = [
|
|
|
32473
33525
|
{ name: "items", required: false, description: "Item ids (default: every proposed item)." }
|
|
32474
33526
|
],
|
|
32475
33527
|
flags: [],
|
|
32476
|
-
scopes: [
|
|
33528
|
+
scopes: [...planOperations.dismiss.scopes],
|
|
32477
33529
|
returns: "Plan",
|
|
32478
|
-
notes:
|
|
33530
|
+
notes: `${routeOf(planOperations.dismiss)} (#912). Nothing is written to a task.`
|
|
32479
33531
|
},
|
|
32480
33532
|
{
|
|
32481
33533
|
path: ["plans", "undo"],
|
|
@@ -32485,9 +33537,9 @@ var COMMAND_SPECS = [
|
|
|
32485
33537
|
{ name: "items", required: false, description: "Item ids (default: every answered item)." }
|
|
32486
33538
|
],
|
|
32487
33539
|
flags: [],
|
|
32488
|
-
scopes: [
|
|
33540
|
+
scopes: [...planOperations.undo.scopes],
|
|
32489
33541
|
returns: "Plan",
|
|
32490
|
-
notes:
|
|
33542
|
+
notes: `${routeOf(planOperations.undo)} (#912). The items read as proposed again.`
|
|
32491
33543
|
},
|
|
32492
33544
|
{
|
|
32493
33545
|
path: ["plan", "rules", "list"],
|
|
@@ -32501,9 +33553,9 @@ var COMMAND_SPECS = [
|
|
|
32501
33553
|
description: "fixed_time, keep_free, meaning, whose, limit or note."
|
|
32502
33554
|
}
|
|
32503
33555
|
],
|
|
32504
|
-
scopes: [
|
|
33556
|
+
scopes: [...planningRuleOperations.list.scopes],
|
|
32505
33557
|
returns: "PlanningRule[]",
|
|
32506
|
-
notes:
|
|
33558
|
+
notes: `${routeOf(planningRuleOperations.list)}. Oldest first; \`addedByAgent\` marks the ones an agent added.`
|
|
32507
33559
|
},
|
|
32508
33560
|
{
|
|
32509
33561
|
path: ["plan", "rules", "add"],
|
|
@@ -32521,9 +33573,9 @@ var COMMAND_SPECS = [
|
|
|
32521
33573
|
description: "The member it is for (user id; default: the member the key acts for)."
|
|
32522
33574
|
}
|
|
32523
33575
|
],
|
|
32524
|
-
scopes: [
|
|
33576
|
+
scopes: [...planningRuleOperations.create.scopes],
|
|
32525
33577
|
returns: "PlanningRule",
|
|
32526
|
-
notes:
|
|
33578
|
+
notes: `${routeOf(planningRuleOperations.create)}. \`forUserId\` (--for) names the member; a rule without --rule is a note.`
|
|
32527
33579
|
},
|
|
32528
33580
|
{
|
|
32529
33581
|
path: ["plan", "rules", "update"],
|
|
@@ -32537,18 +33589,18 @@ var COMMAND_SPECS = [
|
|
|
32537
33589
|
description: "The new structured part as JSON (see `plan rules add`), or `none` to make it a note."
|
|
32538
33590
|
}
|
|
32539
33591
|
],
|
|
32540
|
-
scopes: [
|
|
33592
|
+
scopes: [...planningRuleOperations.update.scopes],
|
|
32541
33593
|
returns: "PlanningRule",
|
|
32542
|
-
notes:
|
|
33594
|
+
notes: `${routeOf(planningRuleOperations.update)}.`
|
|
32543
33595
|
},
|
|
32544
33596
|
{
|
|
32545
33597
|
path: ["plan", "rules", "remove"],
|
|
32546
33598
|
summary: "Remove a planning rule (to the trash).",
|
|
32547
33599
|
args: [{ name: "id", required: true, description: "Rule id." }],
|
|
32548
33600
|
flags: [],
|
|
32549
|
-
scopes: [
|
|
33601
|
+
scopes: [...planningRuleOperations.remove.scopes],
|
|
32550
33602
|
returns: "void",
|
|
32551
|
-
notes:
|
|
33603
|
+
notes: `${routeOf(planningRuleOperations.remove)}. Destructive: needs --allow-destructive.`
|
|
32552
33604
|
},
|
|
32553
33605
|
{
|
|
32554
33606
|
path: ["tasks", "ready"],
|
|
@@ -33669,7 +34721,7 @@ var COMMAND_SPECS = [
|
|
|
33669
34721
|
summary: "List the Space's Agents (id + name).",
|
|
33670
34722
|
args: [],
|
|
33671
34723
|
flags: [],
|
|
33672
|
-
scopes: [
|
|
34724
|
+
scopes: [...agentOperations.list.scopes],
|
|
33673
34725
|
returns: "AgentSummary",
|
|
33674
34726
|
notes: "Creating an Agent and minting its keys stays a member's job in the app."
|
|
33675
34727
|
},
|
|
@@ -33986,7 +35038,7 @@ var COMMAND_SPECS = [
|
|
|
33986
35038
|
summary: "Show the caller's settings for the Space.",
|
|
33987
35039
|
args: [],
|
|
33988
35040
|
flags: [],
|
|
33989
|
-
scopes: [
|
|
35041
|
+
scopes: [...settingsOperations.get.scopes],
|
|
33990
35042
|
returns: "UserSettings",
|
|
33991
35043
|
notes: "Needs a key minted while logged in (it carries the user identity)."
|
|
33992
35044
|
},
|
|
@@ -33995,7 +35047,7 @@ var COMMAND_SPECS = [
|
|
|
33995
35047
|
summary: "Patch the caller's settings.",
|
|
33996
35048
|
args: [],
|
|
33997
35049
|
flags: [{ name: "data", type: "string", description: "JSON of fields to change." }],
|
|
33998
|
-
scopes: [
|
|
35050
|
+
scopes: [...settingsOperations.update.scopes],
|
|
33999
35051
|
returns: "UserSettings"
|
|
34000
35052
|
},
|
|
34001
35053
|
{
|
|
@@ -34153,9 +35205,9 @@ var COMMAND_SPECS = [
|
|
|
34153
35205
|
summary: "An asset's upkeep and repair Tasks, open ones first.",
|
|
34154
35206
|
args: [{ name: "id", required: true, description: "Asset (Collection Item) ULID." }],
|
|
34155
35207
|
flags: [],
|
|
34156
|
-
scopes: [
|
|
35208
|
+
scopes: [...collectionUpkeepOperations.list.scopes],
|
|
34157
35209
|
returns: "AssetUpkeep",
|
|
34158
|
-
notes:
|
|
35210
|
+
notes: `${routeOf(collectionUpkeepOperations.list)} (LifeOS House). Returns { itemId, upkeep, repairs }.`
|
|
34159
35211
|
},
|
|
34160
35212
|
{
|
|
34161
35213
|
path: ["collection", "link-task"],
|
|
@@ -34165,9 +35217,9 @@ var COMMAND_SPECS = [
|
|
|
34165
35217
|
{ name: "taskId", required: true, description: "Task ULID." }
|
|
34166
35218
|
],
|
|
34167
35219
|
flags: [{ name: "repair", type: "boolean", description: "A one-off repair, not upkeep." }],
|
|
34168
|
-
scopes: [
|
|
35220
|
+
scopes: [...collectionUpkeepOperations.link.scopes],
|
|
34169
35221
|
returns: "AssetUpkeep",
|
|
34170
|
-
notes:
|
|
35222
|
+
notes: `${routeOf(collectionUpkeepOperations.link)}. Make the Task (recurrence, Place, Area) first. Finishing it writes the asset's service / repair Entry by itself.`
|
|
34171
35223
|
},
|
|
34172
35224
|
{
|
|
34173
35225
|
path: ["collection", "unlink-task"],
|
|
@@ -34177,7 +35229,7 @@ var COMMAND_SPECS = [
|
|
|
34177
35229
|
{ name: "taskId", required: true, description: "Task ULID." }
|
|
34178
35230
|
],
|
|
34179
35231
|
flags: [],
|
|
34180
|
-
scopes: [
|
|
35232
|
+
scopes: [...collectionUpkeepOperations.unlink.scopes],
|
|
34181
35233
|
returns: "AssetUpkeep"
|
|
34182
35234
|
},
|
|
34183
35235
|
{
|
|
@@ -35024,6 +36076,35 @@ var COMMAND_SPECS = [
|
|
|
35024
36076
|
returns: "MoneyYear",
|
|
35025
36077
|
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)."
|
|
35026
36078
|
},
|
|
36079
|
+
{
|
|
36080
|
+
path: ["money", "net-worth"],
|
|
36081
|
+
summary: "Net worth now and its month-end line (the accounts that count in it).",
|
|
36082
|
+
args: [],
|
|
36083
|
+
flags: [
|
|
36084
|
+
{ name: "scope", type: "string", description: "all (default) | space | owner." },
|
|
36085
|
+
{
|
|
36086
|
+
name: "months",
|
|
36087
|
+
type: "string",
|
|
36088
|
+
description: "How many months the line covers (2\u201360, default 12)."
|
|
36089
|
+
}
|
|
36090
|
+
],
|
|
36091
|
+
scopes: ["finance:read"],
|
|
36092
|
+
returns: "MoneyNetWorth",
|
|
36093
|
+
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."
|
|
36094
|
+
},
|
|
36095
|
+
{
|
|
36096
|
+
path: ["money", "net-worth-set"],
|
|
36097
|
+
summary: "Set an account's value for a month by hand (a house, a car); again replaces it.",
|
|
36098
|
+
args: [{ name: "accountId", required: true, description: "Account ULID." }],
|
|
36099
|
+
flags: [
|
|
36100
|
+
{ name: "value", type: "string", description: "The value, e.g. 310000 or 1234.56." },
|
|
36101
|
+
{ name: "month", type: "string", description: "The month, YYYY-MM (default this month)." },
|
|
36102
|
+
{ name: "data", type: "string", description: "SetMoneyNetWorthValueInput JSON instead." }
|
|
36103
|
+
],
|
|
36104
|
+
scopes: ["finance:write"],
|
|
36105
|
+
returns: "MoneySnapshot",
|
|
36106
|
+
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`."
|
|
36107
|
+
},
|
|
35027
36108
|
{
|
|
35028
36109
|
path: ["money", "goals"],
|
|
35029
36110
|
summary: "List money goals: what's saved toward each, soonest first.",
|
|
@@ -35773,7 +36854,7 @@ var COMMAND_SPECS = [
|
|
|
35773
36854
|
summary: "Your Google Contacts, to pick from: who they'd merge into and what importing adds.",
|
|
35774
36855
|
args: [],
|
|
35775
36856
|
flags: [{ name: "q", type: "string", description: "A name or email to narrow to." }],
|
|
35776
|
-
scopes: [
|
|
36857
|
+
scopes: [...googleContactsOperations.list.scopes],
|
|
35777
36858
|
returns: "GoogleContactsList",
|
|
35778
36859
|
notes: "Connecting needs a browser (People \u2192 Import). Not connected: candidates is empty and status.connected false. A key with no member is forbidden."
|
|
35779
36860
|
},
|
|
@@ -35788,7 +36869,7 @@ var COMMAND_SPECS = [
|
|
|
35788
36869
|
}
|
|
35789
36870
|
],
|
|
35790
36871
|
flags: [],
|
|
35791
|
-
scopes: [
|
|
36872
|
+
scopes: [...googleContactsOperations.import.scopes],
|
|
35792
36873
|
returns: "GoogleContactsImportResult",
|
|
35793
36874
|
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."
|
|
35794
36875
|
},
|
|
@@ -35897,7 +36978,7 @@ var COMMAND_SPECS = [
|
|
|
35897
36978
|
description: 'JSON AddRsvpPresetsInput, e.g. {"guestListId":"01\u2026","presets":["diet","message"]}'
|
|
35898
36979
|
}
|
|
35899
36980
|
],
|
|
35900
|
-
scopes: [
|
|
36981
|
+
scopes: [...rsvpQuestionOperations.presets.scopes],
|
|
35901
36982
|
returns: "RsvpQuestion"
|
|
35902
36983
|
},
|
|
35903
36984
|
{
|
|
@@ -35908,7 +36989,7 @@ var COMMAND_SPECS = [
|
|
|
35908
36989
|
{ name: "list", type: "string", description: "The guest list's id (required)." },
|
|
35909
36990
|
{ name: "household", type: "string", description: "Only this household's answers." }
|
|
35910
36991
|
],
|
|
35911
|
-
scopes: [
|
|
36992
|
+
scopes: [...rsvpAnswerOperations.list.scopes],
|
|
35912
36993
|
returns: "RsvpAnswer"
|
|
35913
36994
|
},
|
|
35914
36995
|
{
|
|
@@ -35922,7 +37003,7 @@ var COMMAND_SPECS = [
|
|
|
35922
37003
|
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"]}]}'
|
|
35923
37004
|
}
|
|
35924
37005
|
],
|
|
35925
|
-
scopes: [
|
|
37006
|
+
scopes: [...rsvpAnswerOperations.set.scopes],
|
|
35926
37007
|
returns: "RsvpAnswer"
|
|
35927
37008
|
},
|
|
35928
37009
|
{
|
|
@@ -35969,7 +37050,7 @@ var COMMAND_SPECS = [
|
|
|
35969
37050
|
summary: "A guest list's mail campaigns (save-the-dates, invitations), newest first.",
|
|
35970
37051
|
args: [],
|
|
35971
37052
|
flags: [{ name: "list", type: "string", description: "The guest list's id (required)." }],
|
|
35972
|
-
scopes: [
|
|
37053
|
+
scopes: [...mailCampaignOperations.list.scopes],
|
|
35973
37054
|
returns: "MailCampaignView",
|
|
35974
37055
|
notes: "Each campaign carries the households it reaches (a draft: who it would go to) with their status, its mails by status, and readyToSend."
|
|
35975
37056
|
},
|
|
@@ -35978,7 +37059,7 @@ var COMMAND_SPECS = [
|
|
|
35978
37059
|
summary: "One mail campaign, with its households and how far it got.",
|
|
35979
37060
|
args: [{ name: "id", required: true, description: "The campaign's id." }],
|
|
35980
37061
|
flags: [],
|
|
35981
|
-
scopes: [
|
|
37062
|
+
scopes: [...mailCampaignOperations.get.scopes],
|
|
35982
37063
|
returns: "MailCampaignView"
|
|
35983
37064
|
},
|
|
35984
37065
|
{
|
|
@@ -35992,7 +37073,7 @@ var COMMAND_SPECS = [
|
|
|
35992
37073
|
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"}'
|
|
35993
37074
|
}
|
|
35994
37075
|
],
|
|
35995
|
-
scopes: [
|
|
37076
|
+
scopes: [...mailCampaignOperations.create.scopes],
|
|
35996
37077
|
returns: "MailCampaignView",
|
|
35997
37078
|
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."
|
|
35998
37079
|
},
|
|
@@ -36007,7 +37088,7 @@ var COMMAND_SPECS = [
|
|
|
36007
37088
|
description: 'JSON UpdateMailCampaignInput, e.g. {"data":{"nl":{\u2026}}}'
|
|
36008
37089
|
}
|
|
36009
37090
|
],
|
|
36010
|
-
scopes: [
|
|
37091
|
+
scopes: [...mailCampaignOperations.update.scopes],
|
|
36011
37092
|
returns: "MailCampaignView",
|
|
36012
37093
|
notes: "Only a draft changes (409 otherwise); an edit makes the last test stale."
|
|
36013
37094
|
},
|
|
@@ -36016,7 +37097,7 @@ var COMMAND_SPECS = [
|
|
|
36016
37097
|
summary: "Draw a campaign's mail as its first household would get it.",
|
|
36017
37098
|
args: [{ name: "id", required: true, description: "The campaign's id." }],
|
|
36018
37099
|
flags: [{ name: "language", type: "string", description: "nl (default) or pt." }],
|
|
36019
|
-
scopes: [
|
|
37100
|
+
scopes: [...mailCampaignOperations.preview.scopes],
|
|
36020
37101
|
returns: "MailPreview"
|
|
36021
37102
|
},
|
|
36022
37103
|
{
|
|
@@ -36030,23 +37111,23 @@ var COMMAND_SPECS = [
|
|
|
36030
37111
|
},
|
|
36031
37112
|
{
|
|
36032
37113
|
path: ["guest-lists", "export"],
|
|
36033
|
-
summary: "Export for the caterer, the venue, the church or the RSVP answers (CSV) to stdout, or save the floor plan (PDF) to a file.",
|
|
37114
|
+
summary: "Export for the caterer, the venue, the church or the RSVP answers (CSV) to stdout, or save the floor plan or the paper invitations (PDF) to a file.",
|
|
36034
37115
|
args: [{ name: "id", required: true, description: "The guest list's id." }],
|
|
36035
37116
|
flags: [
|
|
36036
37117
|
{
|
|
36037
37118
|
name: "kind",
|
|
36038
37119
|
type: "string",
|
|
36039
|
-
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)
|
|
37120
|
+
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)."
|
|
36040
37121
|
},
|
|
36041
37122
|
{
|
|
36042
37123
|
name: "out",
|
|
36043
37124
|
type: "string",
|
|
36044
|
-
description: "Where to save
|
|
37125
|
+
description: "Where to save a PDF (default: the name the API gives it)."
|
|
36045
37126
|
}
|
|
36046
37127
|
],
|
|
36047
37128
|
scopes: ["contacts:read"],
|
|
36048
37129
|
returns: "string",
|
|
36049
|
-
notes: "A CSV goes to stdout (`> tables.csv`);
|
|
37130
|
+
notes: "A CSV goes to stdout (`> tables.csv`); a PDF is saved: `do guest-lists export <id> --kind invitations --out invitations.pdf`. Mint the links first (`do rsvp-links create`); the QR opens the list's `siteUrl` + /i/<token>, and its `sitePassword` is printed only when set."
|
|
36050
37131
|
},
|
|
36051
37132
|
{
|
|
36052
37133
|
path: ["rsvp-links", "list"],
|
|
@@ -38608,7 +39689,7 @@ var HANDLERS = {
|
|
|
38608
39689
|
"today earlier": async ({ flags, io, requireClient }) => {
|
|
38609
39690
|
const area = flagString(flags, "area");
|
|
38610
39691
|
return {
|
|
38611
|
-
data: await requireClient().get(
|
|
39692
|
+
data: await requireClient().get(pathOf(todayOperations.fromEarlier), {
|
|
38612
39693
|
query: { from: localDayStart(io.now()).toISOString(), areaId: area }
|
|
38613
39694
|
}),
|
|
38614
39695
|
render: renderFromEarlier
|
|
@@ -39548,12 +40629,12 @@ var HANDLERS = {
|
|
|
39548
40629
|
if (start === undefined)
|
|
39549
40630
|
throw usageError("block-templates week needs --start");
|
|
39550
40631
|
return {
|
|
39551
|
-
data: await requireClient().get(
|
|
40632
|
+
data: await requireClient().get(pathOf(blockTemplateOperations.week), { query: { start } }),
|
|
39552
40633
|
render: renderRecord
|
|
39553
40634
|
};
|
|
39554
40635
|
},
|
|
39555
40636
|
"block-templates defaults": async ({ requireClient }) => ({
|
|
39556
|
-
data: await requireClient().post(
|
|
40637
|
+
data: await requireClient().post(pathOf(blockTemplateOperations.defaults), {}),
|
|
39557
40638
|
render: renderRecord
|
|
39558
40639
|
}),
|
|
39559
40640
|
"time-blocks record": async ({ args, requireClient }) => {
|
|
@@ -39638,7 +40719,7 @@ var HANDLERS = {
|
|
|
39638
40719
|
};
|
|
39639
40720
|
},
|
|
39640
40721
|
"plans list": async ({ flags, requireClient }) => {
|
|
39641
|
-
const plans = await requireClient().get(
|
|
40722
|
+
const plans = await requireClient().get(pathOf(planOperations.list), {
|
|
39642
40723
|
query: {
|
|
39643
40724
|
kind: flagString(flags, "kind"),
|
|
39644
40725
|
status: flagString(flags, "status"),
|
|
@@ -39650,19 +40731,25 @@ var HANDLERS = {
|
|
|
39650
40731
|
},
|
|
39651
40732
|
"plans get": async ({ args, requireClient }) => {
|
|
39652
40733
|
const id = requireArg(args, 0, "plan id");
|
|
39653
|
-
return {
|
|
40734
|
+
return {
|
|
40735
|
+
data: await requireClient().get(pathOf(planOperations.get, { id })),
|
|
40736
|
+
render: renderPlan
|
|
40737
|
+
};
|
|
39654
40738
|
},
|
|
39655
40739
|
"plans propose": async ({ flags, requireClient }) => {
|
|
39656
40740
|
if (flagString(flags, "data") === undefined)
|
|
39657
40741
|
throw usageError("plans propose needs --data");
|
|
39658
40742
|
const body = parseInput(createPlanInputSchema, readDataFlag(flags));
|
|
39659
|
-
return {
|
|
40743
|
+
return {
|
|
40744
|
+
data: await requireClient().post(pathOf(planOperations.create), body),
|
|
40745
|
+
render: renderPlan
|
|
40746
|
+
};
|
|
39660
40747
|
},
|
|
39661
40748
|
"plans accept": async (ctx) => planDecision(ctx, "accept"),
|
|
39662
40749
|
"plans dismiss": async (ctx) => planDecision(ctx, "dismiss"),
|
|
39663
40750
|
"plans undo": async (ctx) => planDecision(ctx, "undo"),
|
|
39664
40751
|
"plan rules list": async ({ flags, requireClient }) => {
|
|
39665
|
-
const rules = await requireClient().get(
|
|
40752
|
+
const rules = await requireClient().get(pathOf(planningRuleOperations.list), {
|
|
39666
40753
|
query: { forUserId: flagString(flags, "for"), kind: flagString(flags, "kind") }
|
|
39667
40754
|
});
|
|
39668
40755
|
return { data: rules, render: renderPlanningRules };
|
|
@@ -39679,7 +40766,7 @@ var HANDLERS = {
|
|
|
39679
40766
|
...flagString(flags, "for") ? { forUserId: flagString(flags, "for") } : {}
|
|
39680
40767
|
});
|
|
39681
40768
|
return {
|
|
39682
|
-
data: await requireClient().post(
|
|
40769
|
+
data: await requireClient().post(pathOf(planningRuleOperations.create), body),
|
|
39683
40770
|
render: renderPlanningRule
|
|
39684
40771
|
};
|
|
39685
40772
|
},
|
|
@@ -39691,14 +40778,14 @@ var HANDLERS = {
|
|
|
39691
40778
|
...rule !== undefined ? { rule } : {}
|
|
39692
40779
|
});
|
|
39693
40780
|
return {
|
|
39694
|
-
data: await requireClient().patch(
|
|
40781
|
+
data: await requireClient().patch(pathOf(planningRuleOperations.update, { id }), body),
|
|
39695
40782
|
render: renderPlanningRule
|
|
39696
40783
|
};
|
|
39697
40784
|
},
|
|
39698
40785
|
"plan rules remove": async ({ args, flags, requireClient }) => {
|
|
39699
40786
|
const id = requireArg(args, 0, "rule id");
|
|
39700
40787
|
assertDestructiveAllowed(flags, "remove a planning rule");
|
|
39701
|
-
await requireClient().delete(
|
|
40788
|
+
await requireClient().delete(pathOf(planningRuleOperations.remove, { id }));
|
|
39702
40789
|
return { data: { id, removed: true }, render: () => `Removed rule ${id}.` };
|
|
39703
40790
|
},
|
|
39704
40791
|
"tasks ready": async ({ args, flags, requireClient }) => {
|
|
@@ -39940,7 +41027,7 @@ var HANDLERS = {
|
|
|
39940
41027
|
};
|
|
39941
41028
|
},
|
|
39942
41029
|
"agents list": async ({ requireClient }) => ({
|
|
39943
|
-
data: await requireClient().getPage(
|
|
41030
|
+
data: await requireClient().getPage(pathOf(agentOperations.list)),
|
|
39944
41031
|
render: renderList
|
|
39945
41032
|
}),
|
|
39946
41033
|
"agent connection get": async ({ requireClient }) => ({
|
|
@@ -40056,12 +41143,15 @@ var HANDLERS = {
|
|
|
40056
41143
|
};
|
|
40057
41144
|
},
|
|
40058
41145
|
"settings get": async ({ requireClient }) => ({
|
|
40059
|
-
data: await requireClient().get(
|
|
41146
|
+
data: await requireClient().get(pathOf(settingsOperations.get)),
|
|
40060
41147
|
render: renderRecord
|
|
40061
41148
|
}),
|
|
40062
41149
|
"settings update": async ({ flags, requireClient }) => {
|
|
40063
41150
|
const body = parseInput(updateUserSettingsInputSchema, readDataFlag(flags));
|
|
40064
|
-
return {
|
|
41151
|
+
return {
|
|
41152
|
+
data: await requireClient().patch(pathOf(settingsOperations.update), body),
|
|
41153
|
+
render: renderRecord
|
|
41154
|
+
};
|
|
40065
41155
|
},
|
|
40066
41156
|
"modules list": async ({ requireClient }) => {
|
|
40067
41157
|
const settings = await requireClient().get("/settings");
|
|
@@ -40155,7 +41245,10 @@ var HANDLERS = {
|
|
|
40155
41245
|
},
|
|
40156
41246
|
"collection upkeep": async ({ args, requireClient }) => {
|
|
40157
41247
|
const id = requireArg(args, 0, "item id");
|
|
40158
|
-
return {
|
|
41248
|
+
return {
|
|
41249
|
+
data: await requireClient().get(pathOf(collectionUpkeepOperations.list, { id })),
|
|
41250
|
+
render: renderRecord
|
|
41251
|
+
};
|
|
40159
41252
|
},
|
|
40160
41253
|
"collection link-task": async ({ args, flags, requireClient }) => {
|
|
40161
41254
|
const id = requireArg(args, 0, "item id");
|
|
@@ -40165,7 +41258,7 @@ var HANDLERS = {
|
|
|
40165
41258
|
kind: flagBool(flags, "repair") ? "repairs" : "maintains"
|
|
40166
41259
|
});
|
|
40167
41260
|
return {
|
|
40168
|
-
data: await requireClient().post(
|
|
41261
|
+
data: await requireClient().post(pathOf(collectionUpkeepOperations.link, { id }), body),
|
|
40169
41262
|
render: renderRecord
|
|
40170
41263
|
};
|
|
40171
41264
|
},
|
|
@@ -40173,7 +41266,7 @@ var HANDLERS = {
|
|
|
40173
41266
|
const id = requireArg(args, 0, "item id");
|
|
40174
41267
|
const taskId = requireArg(args, 1, "task id");
|
|
40175
41268
|
return {
|
|
40176
|
-
data: await requireClient().delete(
|
|
41269
|
+
data: await requireClient().delete(pathOf(collectionUpkeepOperations.unlink, { id, taskId })),
|
|
40177
41270
|
render: renderRecord
|
|
40178
41271
|
};
|
|
40179
41272
|
},
|
|
@@ -40738,6 +41831,23 @@ var HANDLERS = {
|
|
|
40738
41831
|
});
|
|
40739
41832
|
return { data: await requireClient().post("/money/budget/copy", body), render: renderRecord };
|
|
40740
41833
|
},
|
|
41834
|
+
"money net-worth": async ({ flags, requireClient }) => ({
|
|
41835
|
+
data: await requireClient().get("/money/net-worth", {
|
|
41836
|
+
query: { scope: flagString(flags, "scope"), months: flagString(flags, "months") }
|
|
41837
|
+
}),
|
|
41838
|
+
render: renderRecord
|
|
41839
|
+
}),
|
|
41840
|
+
"money net-worth-set": async ({ args, flags, requireClient }) => {
|
|
41841
|
+
const body = flagString(flags, "data") !== undefined ? parseInput(setMoneyNetWorthValueInputSchema, readDataFlag(flags)) : parseInput(setMoneyNetWorthValueInputSchema, {
|
|
41842
|
+
accountId: requireArg(args, 0, "account id"),
|
|
41843
|
+
value: requireFlag(flags, "value", "money net-worth-set needs --value <amount>"),
|
|
41844
|
+
month: flagString(flags, "month")
|
|
41845
|
+
});
|
|
41846
|
+
return {
|
|
41847
|
+
data: await requireClient().put("/money/net-worth/values", body),
|
|
41848
|
+
render: renderRecord
|
|
41849
|
+
};
|
|
41850
|
+
},
|
|
40741
41851
|
"money goals": async ({ requireClient }) => ({
|
|
40742
41852
|
data: await requireClient().get("/money/goals"),
|
|
40743
41853
|
render: renderList
|
|
@@ -41192,12 +42302,20 @@ var HANDLERS = {
|
|
|
41192
42302
|
data: await requireClient().delete(`/health/shares/${requireArg(args, 0, "id")}`),
|
|
41193
42303
|
render: renderRecord
|
|
41194
42304
|
}),
|
|
42305
|
+
"health withings status": async ({ requireClient }) => ({
|
|
42306
|
+
data: await requireClient().get("/health/withings"),
|
|
42307
|
+
render: renderRecord
|
|
42308
|
+
}),
|
|
42309
|
+
"health withings sync": async ({ requireClient }) => ({
|
|
42310
|
+
data: await requireClient().post("/health/withings/sync", {}),
|
|
42311
|
+
render: renderRecord
|
|
42312
|
+
}),
|
|
41195
42313
|
"health google status": async ({ requireClient }) => ({
|
|
41196
|
-
data: await requireClient().get(
|
|
42314
|
+
data: await requireClient().get(pathOf(googleHealthOperations.status)),
|
|
41197
42315
|
render: renderRecord
|
|
41198
42316
|
}),
|
|
41199
42317
|
"health google sync": async ({ requireClient }) => ({
|
|
41200
|
-
data: await requireClient().post(
|
|
42318
|
+
data: await requireClient().post(pathOf(googleHealthOperations.sync), {}),
|
|
41201
42319
|
render: renderRecord
|
|
41202
42320
|
}),
|
|
41203
42321
|
"health consent": async ({ requireClient }) => ({
|
|
@@ -41428,7 +42546,9 @@ var HANDLERS = {
|
|
|
41428
42546
|
"people google": async ({ flags, requireClient }) => {
|
|
41429
42547
|
const q = flagString(flags, "q");
|
|
41430
42548
|
return {
|
|
41431
|
-
data: await requireClient().get(
|
|
42549
|
+
data: await requireClient().get(pathOf(googleContactsOperations.list), {
|
|
42550
|
+
query: q ? { q } : {}
|
|
42551
|
+
}),
|
|
41432
42552
|
render: renderRecord
|
|
41433
42553
|
};
|
|
41434
42554
|
},
|
|
@@ -41438,7 +42558,7 @@ var HANDLERS = {
|
|
|
41438
42558
|
}
|
|
41439
42559
|
const body = parseInput(importGoogleContactsInputSchema, { resourceNames: args });
|
|
41440
42560
|
return {
|
|
41441
|
-
data: await requireClient().post(
|
|
42561
|
+
data: await requireClient().post(pathOf(googleContactsOperations.import), body),
|
|
41442
42562
|
render: renderRecord
|
|
41443
42563
|
};
|
|
41444
42564
|
},
|
|
@@ -41586,7 +42706,7 @@ var HANDLERS = {
|
|
|
41586
42706
|
"rsvp-questions presets": async ({ flags, requireClient }) => {
|
|
41587
42707
|
const body = parseInput(addRsvpPresetsInputSchema, readDataFlag(flags));
|
|
41588
42708
|
return {
|
|
41589
|
-
data: await requireClient().post(
|
|
42709
|
+
data: await requireClient().post(pathOf(rsvpQuestionOperations.presets), body),
|
|
41590
42710
|
render: renderRecord
|
|
41591
42711
|
};
|
|
41592
42712
|
},
|
|
@@ -41599,11 +42719,17 @@ var HANDLERS = {
|
|
|
41599
42719
|
guestListId: list,
|
|
41600
42720
|
...household ? { householdId: household } : {}
|
|
41601
42721
|
});
|
|
41602
|
-
return {
|
|
42722
|
+
return {
|
|
42723
|
+
data: await requireClient().get(pathOf(rsvpAnswerOperations.list), { query }),
|
|
42724
|
+
render: renderRecord
|
|
42725
|
+
};
|
|
41603
42726
|
},
|
|
41604
42727
|
"rsvp-answers set": async ({ flags, requireClient }) => {
|
|
41605
42728
|
const body = parseInput(setRsvpAnswersInputSchema, readDataFlag(flags));
|
|
41606
|
-
return {
|
|
42729
|
+
return {
|
|
42730
|
+
data: await requireClient().put(pathOf(rsvpAnswerOperations.set), body),
|
|
42731
|
+
render: renderRecord
|
|
42732
|
+
};
|
|
41607
42733
|
},
|
|
41608
42734
|
"seating-proposals list": async ({ flags, requireClient }) => {
|
|
41609
42735
|
const list = flagString(flags, "list");
|
|
@@ -41642,23 +42768,31 @@ var HANDLERS = {
|
|
|
41642
42768
|
throw usageError("mail-campaigns list needs --list <guest list id>");
|
|
41643
42769
|
parseInput(mailCampaignsQuerySchema, { guestListId: list });
|
|
41644
42770
|
return {
|
|
41645
|
-
data: await requireClient().get(
|
|
42771
|
+
data: await requireClient().get(pathOf(mailCampaignOperations.list), {
|
|
42772
|
+
query: { guestListId: list }
|
|
42773
|
+
}),
|
|
41646
42774
|
render: renderRecord
|
|
41647
42775
|
};
|
|
41648
42776
|
},
|
|
41649
42777
|
"mail-campaigns get": async ({ args, requireClient }) => {
|
|
41650
42778
|
const id = requireArg(args, 0, "campaign id");
|
|
41651
|
-
return {
|
|
42779
|
+
return {
|
|
42780
|
+
data: await requireClient().get(pathOf(mailCampaignOperations.get, { id })),
|
|
42781
|
+
render: renderRecord
|
|
42782
|
+
};
|
|
41652
42783
|
},
|
|
41653
42784
|
"mail-campaigns create": async ({ flags, requireClient }) => {
|
|
41654
42785
|
const body = parseInput(createMailCampaignInputSchema, { id: ulid3(), ...readDataFlag(flags) });
|
|
41655
|
-
return {
|
|
42786
|
+
return {
|
|
42787
|
+
data: await requireClient().post(pathOf(mailCampaignOperations.create), body),
|
|
42788
|
+
render: renderRecord
|
|
42789
|
+
};
|
|
41656
42790
|
},
|
|
41657
42791
|
"mail-campaigns update": async ({ args, flags, requireClient }) => {
|
|
41658
42792
|
const id = requireArg(args, 0, "campaign id");
|
|
41659
42793
|
const body = parseInput(updateMailCampaignInputSchema, readDataFlag(flags));
|
|
41660
42794
|
return {
|
|
41661
|
-
data: await requireClient().patch(
|
|
42795
|
+
data: await requireClient().patch(pathOf(mailCampaignOperations.update, { id }), body),
|
|
41662
42796
|
render: renderRecord
|
|
41663
42797
|
};
|
|
41664
42798
|
},
|
|
@@ -41668,7 +42802,7 @@ var HANDLERS = {
|
|
|
41668
42802
|
language: flagString(flags, "language") ?? "nl"
|
|
41669
42803
|
});
|
|
41670
42804
|
return {
|
|
41671
|
-
data: await requireClient().get(
|
|
42805
|
+
data: await requireClient().get(pathOf(mailCampaignOperations.preview, { id }), { query }),
|
|
41672
42806
|
render: renderRecord
|
|
41673
42807
|
};
|
|
41674
42808
|
},
|
|
@@ -41683,9 +42817,9 @@ var HANDLERS = {
|
|
|
41683
42817
|
const id = requireArg(args, 0, "guest list id");
|
|
41684
42818
|
const kind = parseInput(guestExportKindSchema, flagString(flags, "kind") ?? "venue");
|
|
41685
42819
|
const path = `/guest-lists/${id}/exports/${kind}`;
|
|
41686
|
-
if (kind === "floor-plan") {
|
|
42820
|
+
if (kind === "floor-plan" || kind === "invitations") {
|
|
41687
42821
|
const file = await requireClient().getBytes(path);
|
|
41688
|
-
const out = flagString(flags, "out") ?? basename2(file.name ??
|
|
42822
|
+
const out = flagString(flags, "out") ?? basename2(file.name ?? `${kind}.pdf`);
|
|
41689
42823
|
writeFileSync2(out, file.bytes);
|
|
41690
42824
|
return {
|
|
41691
42825
|
data: { id, kind, saved: out, size: file.bytes.byteLength, type: file.contentType },
|
|
@@ -42143,7 +43277,10 @@ async function planDecision({ args, requireClient }, verb) {
|
|
|
42143
43277
|
const id = requireArg(args, 0, "plan id");
|
|
42144
43278
|
const itemIds = args.slice(1);
|
|
42145
43279
|
const body = parseInput(planDecisionInputSchema, itemIds.length > 0 ? { itemIds } : {});
|
|
42146
|
-
return {
|
|
43280
|
+
return {
|
|
43281
|
+
data: await requireClient().post(pathOf(planOperations[verb], { id }), body),
|
|
43282
|
+
render: renderPlan
|
|
43283
|
+
};
|
|
42147
43284
|
}
|
|
42148
43285
|
function parseInput(schema, value) {
|
|
42149
43286
|
const result = schema.safeParse(value);
|