@robbeverhelst/do 1.296.0 → 1.298.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.
Files changed (2) hide show
  1. package/dist/do.js +1914 -855
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -4496,6 +4496,41 @@ var periods = pgTable("periods", {
4496
4496
  index("periods_tenant_starts_idx").on(t.tenantId, t.startsAt)
4497
4497
  ]);
4498
4498
 
4499
+ // ../../packages/schema/src/db/sensors.ts
4500
+ var sensorProvider = pgEnum("sensor_provider", ["home_assistant", "unifi"]);
4501
+ var sensorTarget = pgEnum("sensor_target", ["place", "asset"]);
4502
+ var sensorLinks = pgTable("sensor_links", {
4503
+ id: text("id").primaryKey(),
4504
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
4505
+ provider: sensorProvider("provider").notNull(),
4506
+ externalId: text("external_id").notNull(),
4507
+ nodeId: text("node_id").notNull().references(() => nodes.id),
4508
+ target: sensorTarget("target").notNull(),
4509
+ reading: text("reading").notNull(),
4510
+ label: text("label"),
4511
+ createdBy: text("created_by").references(() => users.id, { onDelete: "set null" }),
4512
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
4513
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
4514
+ }, (t) => [
4515
+ uniqueIndex("sensor_links_entity_idx").on(t.tenantId, t.provider, t.externalId),
4516
+ index("sensor_links_node_idx").on(t.nodeId)
4517
+ ]);
4518
+
4519
+ // ../../packages/schema/src/db/tap-tags.ts
4520
+ var tapTagKind = pgEnum("tap_tag_kind", ["habit", "routine"]);
4521
+ var tapTags = pgTable("tap_tags", {
4522
+ id: text("id").primaryKey(),
4523
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
4524
+ label: text("label").notNull(),
4525
+ kind: tapTagKind("kind").notNull(),
4526
+ targetId: text("target_id").notNull().references(() => nodes.id),
4527
+ createdBy: text("created_by").references(() => users.id, { onDelete: "set null" }),
4528
+ lastTappedAt: timestamp("last_tapped_at", { withTimezone: true }),
4529
+ lastTappedBy: text("last_tapped_by").references(() => users.id, { onDelete: "set null" }),
4530
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
4531
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
4532
+ }, (t) => [index("tap_tags_tenant_idx").on(t.tenantId), index("tap_tags_target_idx").on(t.targetId)]);
4533
+
4499
4534
  // ../../packages/schema/src/db/planning-rules.ts
4500
4535
  var planningRuleKind = pgEnum("planning_rule_kind", [
4501
4536
  "fixed_time",
@@ -4579,6 +4614,17 @@ var animals = pgTable("animals", {
4579
4614
  breeding: animalBreeding("breeding").notNull().default("avoid"),
4580
4615
  areaId: text("area_id").references(() => areas.id, { onDelete: "set null" })
4581
4616
  }, (t) => [index("animals_tenant_idx").on(t.tenantId), index("animals_species_idx").on(t.speciesId)]);
4617
+ var animalLostCards = pgTable("animal_lost_cards", {
4618
+ animalId: text("animal_id").primaryKey().references(() => animals.id, { onDelete: "cascade" }),
4619
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
4620
+ token: text("token").notNull().unique(),
4621
+ photoFileId: text("photo_file_id"),
4622
+ phone: text("phone"),
4623
+ showChipped: boolean("show_chipped").notNull().default(false),
4624
+ note: text("note"),
4625
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
4626
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
4627
+ }, (t) => [index("animal_lost_cards_tenant_idx").on(t.tenantId)]);
4582
4628
 
4583
4629
  // ../../packages/schema/src/db/integrations.ts
4584
4630
  var connectionStatus = pgEnum("connection_status", [
@@ -5016,6 +5062,38 @@ var contactCircles = pgTable("contact_circles", {
5016
5062
  primaryKey({ columns: [t.contactId, t.circleId] }),
5017
5063
  index("contact_circles_circle_idx").on(t.circleId)
5018
5064
  ]);
5065
+ var personProposalKind = pgEnum("person_proposal_kind", [
5066
+ "birth",
5067
+ "move",
5068
+ "new_job",
5069
+ "wedding",
5070
+ "engagement",
5071
+ "death",
5072
+ "other"
5073
+ ]);
5074
+ var personProposalStatus = pgEnum("person_proposal_status", [
5075
+ "pending",
5076
+ "accepted",
5077
+ "skipped"
5078
+ ]);
5079
+ var personProposals = pgTable("person_proposals", {
5080
+ id: text("id").primaryKey(),
5081
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
5082
+ userId: text("user_id").notNull().references(() => users.id),
5083
+ contactId: text("contact_id").notNull().references(() => contacts.id, { onDelete: "cascade" }),
5084
+ kind: personProposalKind("kind").notNull().default("other"),
5085
+ title: text("title").notNull(),
5086
+ source: text("source").notNull(),
5087
+ heardAt: timestamp("heard_at", { withTimezone: true }).notNull(),
5088
+ items: jsonb("items").$type().notNull(),
5089
+ status: personProposalStatus("status").notNull().default("pending"),
5090
+ decidedAt: timestamp("decided_at", { withTimezone: true }),
5091
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5092
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5093
+ }, (t) => [
5094
+ uniqueIndex("person_proposals_source_uniq").on(t.tenantId, t.userId, t.source),
5095
+ index("person_proposals_user_status_idx").on(t.tenantId, t.userId, t.status)
5096
+ ]);
5019
5097
 
5020
5098
  // ../../packages/schema/src/db/files.ts
5021
5099
  var bytea = customType({
@@ -5065,6 +5143,7 @@ var households = pgTable("households", {
5065
5143
  address: jsonb("address").$type(),
5066
5144
  language: text("language").notNull().default("nl"),
5067
5145
  group: boolean("group").notNull().default(false),
5146
+ addressConfirmedAt: timestamp("address_confirmed_at", { withTimezone: true }),
5068
5147
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5069
5148
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5070
5149
  }, (t) => [index("households_tenant_idx").on(t.tenantId)]);
@@ -5078,6 +5157,9 @@ var guestLists = pgTable("guest_lists", {
5078
5157
  rsvpKeyDateId: text("rsvp_key_date_id").references(() => keyDates.id, {
5079
5158
  onDelete: "set null"
5080
5159
  }),
5160
+ finalInfoKeyDateId: text("final_info_key_date_id").references(() => keyDates.id, {
5161
+ onDelete: "set null"
5162
+ }),
5081
5163
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5082
5164
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5083
5165
  }, (t) => [uniqueIndex("guest_lists_project_uniq").on(t.tenantId, t.projectId)]);
@@ -5131,12 +5213,15 @@ var guests = pgTable("guests", {
5131
5213
  uniqueIndex("guests_list_contact_uniq").on(t.guestListId, t.contactId),
5132
5214
  index("guests_contact_idx").on(t.contactId)
5133
5215
  ]);
5216
+ var rsvpLinkMode = pgEnum("rsvp_link_mode", ["address", "full"]);
5134
5217
  var rsvpLinks = pgTable("rsvp_links", {
5135
5218
  id: text("id").primaryKey(),
5136
5219
  tenantId: text("tenant_id").notNull().references(() => tenants.id),
5137
5220
  guestListId: text("guest_list_id").notNull().references(() => guestLists.id, { onDelete: "cascade" }),
5138
5221
  householdId: text("household_id").notNull().references(() => households.id),
5139
5222
  tokenHash: text("token_hash").notNull().unique(),
5223
+ mode: rsvpLinkMode("mode").notNull().default("full"),
5224
+ tokenSealed: text("token_sealed"),
5140
5225
  expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
5141
5226
  revokedAt: timestamp("revoked_at", { withTimezone: true }),
5142
5227
  lastUsedAt: timestamp("last_used_at", { withTimezone: true }),
@@ -20604,7 +20689,8 @@ var habitTodayItemSchema = object({
20604
20689
  source: habitEntrySourceSchema,
20605
20690
  by: string2().optional(),
20606
20691
  at: exports_coerce.date()
20607
- }).nullable().default(null)
20692
+ }).nullable().default(null),
20693
+ private: boolean3().default(false)
20608
20694
  });
20609
20695
  var habitTodayRoutineSchema = object({
20610
20696
  routineId: ulidSchema,
@@ -20635,7 +20721,8 @@ var metricSourceSchema = _enum2([
20635
20721
  "device",
20636
20722
  "agent",
20637
20723
  "google_fit",
20638
- "google_health"
20724
+ "google_health",
20725
+ "health_connect"
20639
20726
  ]);
20640
20727
  var loggedMetricSourceSchema = _enum2(["manual", "device", "agent"]);
20641
20728
  var metricPointSchema = object({
@@ -20670,6 +20757,21 @@ var logMetricInputSchema = object({
20670
20757
  occurredAt: exports_coerce.date().optional(),
20671
20758
  source: loggedMetricSourceSchema.optional()
20672
20759
  }).strict();
20760
+ var HEALTH_CONNECT_METRICS = ["weight", "sleep", "bedtime"];
20761
+ var importedMetricPointSchema = object({
20762
+ key: _enum2(HEALTH_CONNECT_METRICS),
20763
+ value: number2().finite(),
20764
+ occurredAt: exports_coerce.date(),
20765
+ recordId: string2().min(1).max(200)
20766
+ }).strict();
20767
+ var importMetricsInputSchema = object({
20768
+ source: literal("health_connect"),
20769
+ points: array(importedMetricPointSchema).min(1).max(500)
20770
+ }).strict();
20771
+ var importMetricsResultSchema = object({
20772
+ imported: number2().int().min(0),
20773
+ skipped: number2().int().min(0)
20774
+ });
20673
20775
  function bedtimeMinutes(clock) {
20674
20776
  const m = /^([01]?\d|2[0-3]):([0-5]\d)$/.exec(clock.trim());
20675
20777
  if (!m)
@@ -21306,129 +21408,939 @@ var assetUpkeepSchema = object({
21306
21408
  repairs: array(taskViewSchema)
21307
21409
  });
21308
21410
 
21309
- // ../../packages/schema/src/contracts/house.ts
21310
- var day = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "must be a calendar day (YYYY-MM-DD)");
21311
- var houseBrokenSchema = object({
21312
- item: collectionItemViewSchema,
21313
- repair: taskViewSchema.nullable()
21411
+ // ../../packages/schema/src/contracts/key-dates.ts
21412
+ var keyDateDaySchema = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD").refine((s) => {
21413
+ const d = new Date(`${s}T00:00:00Z`);
21414
+ return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === s;
21415
+ }, "not a real date");
21416
+ var keyDateRepeatSchema = _enum2(["yearly"]);
21417
+ var keyDateSchema = createSelectSchema(keyDates, {
21418
+ date: keyDateDaySchema,
21419
+ confirmedAt: exports_coerce.date().nullable(),
21420
+ createdAt: exports_coerce.date(),
21421
+ updatedAt: exports_coerce.date()
21314
21422
  });
21315
- var houseUpkeepSoonSchema = object({
21316
- task: taskViewSchema,
21317
- itemId: string2(),
21318
- itemTitle: string2(),
21319
- nextOn: day.nullable(),
21320
- placeTitle: string2().nullable().default(null),
21321
- lastOn: day.nullable().default(null)
21423
+ var keyDateViewSchema = keyDateSchema.extend({
21424
+ nodeTitle: string2(),
21425
+ nodeType: string2(),
21426
+ repeat: keyDateRepeatSchema.nullable(),
21427
+ nextOn: keyDateDaySchema,
21428
+ task: object({
21429
+ id: ulidSchema,
21430
+ status: string2(),
21431
+ dueAt: exports_coerce.date().nullable(),
21432
+ title: string2().nullable().optional(),
21433
+ area: string2().nullable().optional()
21434
+ }).nullable()
21322
21435
  });
21323
- var housePlaceTileSchema = object({
21324
- id: string2(),
21325
- title: string2(),
21326
- kind: string2(),
21327
- gardenFeatureId: string2().nullable(),
21328
- thingCount: number2().int().min(0)
21436
+ var leadDaysSchema = number2().int().min(0).max(366);
21437
+ var sourceSchema = string2().trim().min(1).max(120);
21438
+ var createKeyDateInputSchema = object({
21439
+ id: ulidSchema,
21440
+ nodeId: ulidSchema,
21441
+ kind: keyDateKindSchema.optional(),
21442
+ label: string2().trim().min(1).max(200).nullish(),
21443
+ date: keyDateDaySchema,
21444
+ yearKnown: boolean3().optional(),
21445
+ repeat: keyDateRepeatSchema.nullish(),
21446
+ leadDays: leadDaysSchema.optional(),
21447
+ derivedFrom: string2().trim().min(1).max(120).nullish(),
21448
+ source: sourceSchema.optional(),
21449
+ confirmed: boolean3().optional()
21450
+ }).strict();
21451
+ var updateKeyDateInputSchema = object({
21452
+ kind: keyDateKindSchema.optional(),
21453
+ label: string2().trim().min(1).max(200).nullish(),
21454
+ date: keyDateDaySchema.optional(),
21455
+ yearKnown: boolean3().optional(),
21456
+ repeat: keyDateRepeatSchema.nullish(),
21457
+ leadDays: leadDaysSchema.optional(),
21458
+ derivedFrom: string2().trim().min(1).max(120).nullish(),
21459
+ source: sourceSchema.optional(),
21460
+ confirmed: boolean3().optional()
21461
+ }).strict();
21462
+ var keyDatesQuerySchema = object({
21463
+ nodeId: ulidSchema.optional(),
21464
+ kind: keyDateKindSchema.optional(),
21465
+ from: keyDateDaySchema.optional(),
21466
+ to: keyDateDaySchema.optional()
21329
21467
  });
21330
- var houseOverviewSchema = object({
21331
- broken: array(houseBrokenSchema),
21332
- upkeepSoon: array(houseUpkeepSoonSchema),
21333
- places: array(housePlaceTileSchema),
21334
- thingCount: number2().int().min(0),
21335
- upkeepCount: number2().int().min(0),
21336
- toolCount: number2().int().min(0),
21337
- animalCount: number2().int().min(0),
21338
- toConfirm: number2().int().min(0).default(0)
21468
+
21469
+ // ../../packages/schema/src/contracts/periods.ts
21470
+ var periodKindSchema = _enum2(periodKind.enumValues);
21471
+ var periodRuleSchema = record(string2(), unknown());
21472
+ var periodSchema = createSelectSchema(periods, {
21473
+ startsAt: exports_coerce.date(),
21474
+ endsAt: exports_coerce.date().nullable(),
21475
+ plannedEndAt: exports_coerce.date().nullable(),
21476
+ rule: periodRuleSchema,
21477
+ createdAt: exports_coerce.date(),
21478
+ updatedAt: exports_coerce.date()
21339
21479
  });
21340
- var upkeepScheduleSchema = object({
21341
- every: number2().int().min(1).max(365),
21342
- unit: _enum2(["day", "week", "month", "year"]),
21343
- startOn: day.optional()
21480
+ var periodViewSchema = periodSchema.extend({
21481
+ nodeTitle: string2(),
21482
+ nodeType: string2(),
21483
+ active: boolean3()
21484
+ });
21485
+ var noteSchema2 = string2().trim().min(1).max(500);
21486
+ function endsAfterStart(p, ctx) {
21487
+ if (!p.startsAt)
21488
+ return;
21489
+ for (const key of ["endsAt", "plannedEndAt"]) {
21490
+ const at = p[key];
21491
+ if (at && at < p.startsAt) {
21492
+ ctx.addIssue({ code: "custom", path: [key], message: `${key} is before startsAt` });
21493
+ }
21494
+ }
21495
+ }
21496
+ var createPeriodInputSchema = object({
21497
+ id: ulidSchema,
21498
+ nodeId: ulidSchema,
21499
+ kind: periodKindSchema.optional(),
21500
+ startsAt: exports_coerce.date(),
21501
+ endsAt: exports_coerce.date().nullish(),
21502
+ plannedEndAt: exports_coerce.date().nullish(),
21503
+ rule: periodRuleSchema.optional(),
21504
+ note: noteSchema2.nullish()
21505
+ }).strict().superRefine(endsAfterStart);
21506
+ var updatePeriodInputSchema = object({
21507
+ kind: periodKindSchema.optional(),
21508
+ startsAt: exports_coerce.date().optional(),
21509
+ endsAt: exports_coerce.date().nullish(),
21510
+ plannedEndAt: exports_coerce.date().nullish(),
21511
+ rule: periodRuleSchema.optional(),
21512
+ note: noteSchema2.nullish()
21513
+ }).strict().superRefine(endsAfterStart);
21514
+ var periodsQuerySchema = object({
21515
+ nodeId: ulidSchema.optional(),
21516
+ kind: periodKindSchema.optional(),
21517
+ active: _enum2(["true", "false"]).transform((v) => v === "true").optional()
21518
+ });
21519
+
21520
+ // ../../packages/schema/src/contracts/animals.ts
21521
+ var animalFormSchema = _enum2(animalForm.enumValues);
21522
+ var animalStatusSchema = _enum2(animalStatus.enumValues);
21523
+ var animalAcquiredHowSchema = _enum2(animalAcquiredHow.enumValues);
21524
+ var animalSexSchema = _enum2(animalSex.enumValues);
21525
+ var animalBreedingSchema = _enum2(animalBreeding.enumValues);
21526
+ var animalClassSchema = _enum2(animalClass.enumValues);
21527
+ var animalLegalSchema = _enum2(animalLegal.enumValues);
21528
+ var animalBornOnSchema = string2().regex(/^\d{4}(-(0[1-9]|1[0-2])(-(0[1-9]|[12]\d|3[01]))?)?$/, "expected YYYY, YYYY-MM or YYYY-MM-DD");
21529
+ var animalIdsSchema = object({
21530
+ chipNoMasked: string2().trim().min(1).max(40).optional(),
21531
+ passportNoMasked: string2().trim().min(1).max(40).optional(),
21532
+ ringNo: string2().trim().min(1).max(40).optional(),
21533
+ ringYear: number2().int().min(1900).max(2200).optional(),
21534
+ ringIssuer: string2().trim().min(1).max(80).optional(),
21535
+ ringType: _enum2(["open", "closed"]).optional()
21344
21536
  }).strict();
21345
- var setAssetUpkeepInputSchema = object({
21346
- title: string2().trim().min(1).max(200),
21347
- schedule: upkeepScheduleSchema,
21348
- placeId: ulidSchema.nullish(),
21349
- areaId: ulidSchema.nullish(),
21350
- nextStep: string2().trim().max(500).nullish()
21537
+ function isMaskedNumber(value) {
21538
+ const shown = value.replace(/[\s*\u2022xX.-]/g, "");
21539
+ return shown.length <= 4 && shown.length < value.replace(/\s/g, "").length;
21540
+ }
21541
+ var maskedIdsSchema = animalIdsSchema.superRefine((ids, ctx) => {
21542
+ for (const key of ["chipNoMasked", "passportNoMasked"]) {
21543
+ const v = ids[key];
21544
+ if (v && !isMaskedNumber(v)) {
21545
+ ctx.addIssue({
21546
+ code: "custom",
21547
+ path: [key],
21548
+ message: "mask all but the last four characters (e.g. ***********1234)"
21549
+ });
21550
+ }
21551
+ }
21552
+ });
21553
+ var animalScheduleStepSchema = object({
21554
+ key: string2().trim().min(1).max(40),
21555
+ label: string2().trim().min(1).max(120),
21556
+ everyMonths: number2().int().min(1).max(120)
21351
21557
  }).strict();
21352
- var fileAssetInputSchema = object({
21353
- id: ulidSchema.optional(),
21354
- title: string2().trim().min(1).max(200),
21355
- placeId: ulidSchema.nullish(),
21356
- areaId: ulidSchema.nullish(),
21357
- status: _enum2(["want", "have"]).optional(),
21358
- facet: record(string2(), unknown()).optional(),
21359
- tags: array(string2().min(1).max(60)).max(20).optional(),
21360
- fileIds: array(ulidSchema).max(20).optional(),
21361
- match: boolean3().default(true),
21362
- upkeep: setAssetUpkeepInputSchema.optional(),
21363
- fault: object({
21364
- note: string2().trim().min(1).max(2000),
21365
- repairTitle: string2().trim().min(1).max(200).optional()
21366
- }).strict().optional()
21558
+ var animalSpeciesSchema = createSelectSchema(animalSpecies, {
21559
+ incompatibleWith: array(string2()),
21560
+ defaultSchedule: array(animalScheduleStepSchema),
21561
+ createdAt: exports_coerce.date()
21562
+ });
21563
+ var speciesKeySchema = string2().regex(/^[a-z][a-z0-9_]{1,39}$/, "a lowercase slug, e.g. hermann_tortoise");
21564
+ var createAnimalSpeciesInputSchema = object({
21565
+ id: ulidSchema,
21566
+ key: speciesKeySchema,
21567
+ commonName: string2().trim().min(1).max(120),
21568
+ commonNameNl: string2().trim().min(1).max(120).nullish(),
21569
+ latin: string2().trim().min(1).max(120).nullish(),
21570
+ class: animalClassSchema.optional(),
21571
+ legal: animalLegalSchema.optional(),
21572
+ hibernates: boolean3().optional(),
21573
+ defaultForm: animalFormSchema.optional(),
21574
+ minGroupSize: number2().int().min(1).max(1000).nullish(),
21575
+ incompatibleWith: array(speciesKeySchema).max(20).optional(),
21576
+ defaultSchedule: array(animalScheduleStepSchema).max(20).optional(),
21577
+ careSheetMd: string2().trim().min(1).max(20000).nullish()
21367
21578
  }).strict();
21368
- var houseReceiptSchema = object({
21369
- itemId: string2(),
21370
- created: boolean3(),
21371
- before: object({
21372
- facet: record(string2(), unknown()).nullable(),
21373
- placeId: string2().nullable(),
21374
- status: string2()
21375
- }).nullable(),
21376
- taskIds: array(string2()),
21377
- entryIds: array(string2()),
21378
- files: array(object({ id: string2(), previousOwnerId: string2().nullable() }))
21579
+ var updateAnimalSpeciesInputSchema = createAnimalSpeciesInputSchema.omit({ id: true, key: true }).partial().strict();
21580
+ var DEWORM = {
21581
+ key: "deworm",
21582
+ label: "Deworm",
21583
+ everyMonths: 3
21584
+ };
21585
+ var BOOSTER = { key: "booster", label: "Yearly booster", everyMonths: 12 };
21586
+ var NATIVE_FINCH = {
21587
+ class: "bird",
21588
+ legal: "native_closed_ring"
21589
+ };
21590
+ var EXOTIC_FINCH = {
21591
+ class: "bird",
21592
+ legal: "none",
21593
+ defaultForm: "group",
21594
+ minGroupSize: 2
21595
+ };
21596
+ var ANIMAL_SPECIES_SEED = [
21597
+ {
21598
+ key: "dog",
21599
+ commonName: "Dog",
21600
+ commonNameNl: "Hond",
21601
+ latin: "Canis familiaris",
21602
+ class: "mammal",
21603
+ legal: "dog_id",
21604
+ defaultSchedule: [DEWORM, BOOSTER]
21605
+ },
21606
+ {
21607
+ key: "cat",
21608
+ commonName: "Cat",
21609
+ commonNameNl: "Kat",
21610
+ latin: "Felis catus",
21611
+ class: "mammal",
21612
+ legal: "cat_id",
21613
+ defaultSchedule: [DEWORM, BOOSTER]
21614
+ },
21615
+ {
21616
+ key: "chicken",
21617
+ commonName: "Chicken",
21618
+ commonNameNl: "Kip",
21619
+ latin: "Gallus gallus domesticus",
21620
+ class: "bird",
21621
+ defaultForm: "group",
21622
+ minGroupSize: 3,
21623
+ defaultSchedule: [
21624
+ { key: "mite_check", label: "Mite check", everyMonths: 1 },
21625
+ { key: "deworm", label: "Deworm", everyMonths: 6 }
21626
+ ]
21627
+ },
21628
+ {
21629
+ key: "duck",
21630
+ commonName: "Duck",
21631
+ commonNameNl: "Eend",
21632
+ latin: "Anas platyrhynchos domesticus",
21633
+ class: "bird",
21634
+ defaultForm: "group",
21635
+ minGroupSize: 2
21636
+ },
21637
+ {
21638
+ key: "quail",
21639
+ commonName: "Quail",
21640
+ commonNameNl: "Kwartel",
21641
+ latin: "Coturnix japonica",
21642
+ class: "bird",
21643
+ defaultForm: "group",
21644
+ minGroupSize: 3
21645
+ },
21646
+ {
21647
+ key: "hermann_tortoise",
21648
+ commonName: "Hermann's tortoise",
21649
+ commonNameNl: "Griekse landschildpad",
21650
+ latin: "Testudo hermanni",
21651
+ class: "reptile",
21652
+ legal: "cites_a",
21653
+ hibernates: true,
21654
+ defaultSchedule: [{ key: "health_check", label: "Health check", everyMonths: 12 }]
21655
+ },
21656
+ {
21657
+ key: "zebra_finch",
21658
+ commonName: "Zebra finch",
21659
+ commonNameNl: "Zebravink",
21660
+ latin: "Taeniopygia guttata",
21661
+ ...EXOTIC_FINCH
21662
+ },
21663
+ {
21664
+ key: "bengalese_finch",
21665
+ commonName: "Bengalese finch",
21666
+ commonNameNl: "Japans meeuwtje",
21667
+ latin: "Lonchura striata domestica",
21668
+ ...EXOTIC_FINCH
21669
+ },
21670
+ {
21671
+ key: "star_finch",
21672
+ commonName: "Star finch",
21673
+ commonNameNl: "Binsenastrild",
21674
+ latin: "Bathilda ruficauda",
21675
+ ...EXOTIC_FINCH
21676
+ },
21677
+ {
21678
+ key: "diamond_dove",
21679
+ commonName: "Diamond dove",
21680
+ commonNameNl: "Diamantduif",
21681
+ latin: "Geopelia cuneata",
21682
+ ...EXOTIC_FINCH
21683
+ },
21684
+ {
21685
+ key: "bullfinch",
21686
+ commonName: "Eurasian bullfinch",
21687
+ commonNameNl: "Goudvink",
21688
+ latin: "Pyrrhula pyrrhula",
21689
+ ...NATIVE_FINCH
21690
+ },
21691
+ {
21692
+ key: "bearded_reedling",
21693
+ commonName: "Bearded reedling",
21694
+ commonNameNl: "Baardmannetje",
21695
+ latin: "Panurus biarmicus",
21696
+ ...NATIVE_FINCH
21697
+ },
21698
+ {
21699
+ key: "siskin",
21700
+ commonName: "Eurasian siskin",
21701
+ commonNameNl: "Sijs",
21702
+ latin: "Spinus spinus",
21703
+ ...NATIVE_FINCH
21704
+ },
21705
+ {
21706
+ key: "goldfinch",
21707
+ commonName: "European goldfinch",
21708
+ commonNameNl: "Putter",
21709
+ latin: "Carduelis carduelis",
21710
+ ...NATIVE_FINCH
21711
+ },
21712
+ {
21713
+ key: "linnet",
21714
+ commonName: "Common linnet",
21715
+ commonNameNl: "Kneu",
21716
+ latin: "Linaria cannabina",
21717
+ ...NATIVE_FINCH
21718
+ },
21719
+ {
21720
+ key: "rabbit",
21721
+ commonName: "Rabbit",
21722
+ commonNameNl: "Konijn",
21723
+ latin: "Oryctolagus cuniculus",
21724
+ class: "mammal",
21725
+ defaultForm: "group",
21726
+ minGroupSize: 2,
21727
+ incompatibleWith: ["guinea_pig"],
21728
+ defaultSchedule: [{ key: "vaccine", label: "Myxo/RHD vaccine", everyMonths: 12 }]
21729
+ },
21730
+ {
21731
+ key: "guinea_pig",
21732
+ commonName: "Guinea pig",
21733
+ commonNameNl: "Cavia",
21734
+ latin: "Cavia porcellus",
21735
+ class: "mammal",
21736
+ defaultForm: "group",
21737
+ minGroupSize: 2,
21738
+ incompatibleWith: ["rabbit"]
21739
+ }
21740
+ ];
21741
+ var animalSchema = createSelectSchema(animals, {
21742
+ ids: animalIdsSchema
21379
21743
  });
21380
- var houseWriteResultSchema = object({
21381
- item: collectionItemDetailSchema,
21382
- receipt: houseReceiptSchema
21744
+ var animalSpeciesRefSchema = object({
21745
+ id: ulidSchema,
21746
+ key: string2(),
21747
+ commonName: string2(),
21748
+ latin: string2().nullable(),
21749
+ class: animalClassSchema,
21750
+ legal: animalLegalSchema,
21751
+ hibernates: boolean3()
21383
21752
  });
21384
- var undoHouseWriteInputSchema = houseReceiptSchema.strict();
21385
- var houseTrailStepSchema = object({ id: string2(), title: string2() });
21386
- var houseAssetPartSchema = object({
21387
- id: string2(),
21753
+ var animalViewSchema = animalSchema.extend({
21388
21754
  title: string2(),
21755
+ parentId: ulidSchema.nullable(),
21756
+ species: animalSpeciesRefSchema.nullable(),
21757
+ memberCount: number2().int(),
21758
+ heads: number2().int(),
21759
+ createdAt: exports_coerce.date(),
21760
+ updatedAt: exports_coerce.date()
21761
+ });
21762
+ var nodeRefSchema = object({ id: ulidSchema, title: string2() });
21763
+ var animalHabitSchema = nodeRefSchema.extend({ doneToday: boolean3() });
21764
+ var animalSupplySchema = nodeRefSchema.extend({
21389
21765
  quantity: number2(),
21390
21766
  unit: string2().nullable(),
21391
- lowStockThreshold: number2().nullable()
21767
+ lowStock: boolean3(),
21768
+ dailyUse: number2().nullable(),
21769
+ perHead: boolean3(),
21770
+ daysLeft: number2().int().nullable(),
21771
+ full: number2().nullable(),
21772
+ onList: string2().nullable()
21392
21773
  });
21393
- var houseAssetLinkSchema = object({
21394
- nodeId: string2(),
21395
- title: string2(),
21396
- type: string2(),
21397
- kind: string2(),
21398
- direction: _enum2(["in", "out"]),
21399
- label: string2().nullable().default(null),
21400
- context: string2().nullable().default(null),
21401
- at: exports_coerce.date().nullable().default(null),
21402
- timed: boolean3().default(false)
21774
+ var animalDayCountSchema = object({ day: string2(), count: number2().int() });
21775
+ var animalWeightPointSchema = object({
21776
+ day: string2(),
21777
+ grams: number2(),
21778
+ at: exports_coerce.date()
21403
21779
  });
21404
- var houseAssetSchema = object({
21405
- item: collectionItemDetailSchema,
21406
- trail: array(houseTrailStepSchema),
21407
- parts: array(houseAssetPartSchema),
21408
- linked: array(houseAssetLinkSchema),
21409
- warrantyUntil: day.nullable(),
21410
- visibility: _enum2(NODE_VISIBILITY_VALUES).default("space")
21780
+ var animalFileSchema = object({
21781
+ id: ulidSchema,
21782
+ name: string2(),
21783
+ mime: string2(),
21784
+ size: number2().int(),
21785
+ createdAt: exports_coerce.date()
21411
21786
  });
21412
- var setAssetVisibilityInputSchema = object({ visibility: _enum2(NODE_VISIBILITY_VALUES) }).strict();
21413
- var linkAssetPartInputSchema = object({ inventoryItemId: ulidSchema }).strict();
21414
- var lendAssetInputSchema = object({
21415
- direction: _enum2(["lent", "borrowed"]),
21416
- who: string2().trim().min(1).max(200),
21417
- contactId: ulidSchema.nullish(),
21418
- since: day.optional(),
21419
- dueBack: day.nullish(),
21420
- note: string2().trim().max(500).nullish()
21421
- }).strict();
21422
- var returnAssetInputSchema = object({
21423
- on: day.optional(),
21424
- note: string2().trim().max(500).nullish()
21425
- }).strict();
21426
- var houseValueProofSchema = _enum2(["receipt_photo", "receipt", "photo", "none"]);
21427
- var houseValueRowSchema = object({
21428
- id: string2(),
21429
- title: string2(),
21430
- model: string2().nullable(),
21431
- placeId: string2().nullable(),
21787
+ var animalVetSchema = nodeRefSchema.extend({ role: string2().nullable() });
21788
+ var animalPaperSchema = nodeRefSchema.extend({
21789
+ status: _enum2(documentStatus.enumValues),
21790
+ reference: string2().nullable()
21791
+ });
21792
+ var animalLinksSchema = object({
21793
+ place: nodeRefSchema.nullable(),
21794
+ vets: array(animalVetSchema),
21795
+ cameFrom: nodeRefSchema.nullable(),
21796
+ habits: array(animalHabitSchema),
21797
+ supplies: array(animalSupplySchema),
21798
+ papers: array(animalPaperSchema),
21799
+ files: array(animalFileSchema),
21800
+ healthVisits: object({ count: number2().int(), lastAt: exports_coerce.date().nullable() }),
21801
+ assets: array(nodeRefSchema.extend({ location: string2().nullable() })),
21802
+ companions: array(nodeRefSchema)
21803
+ });
21804
+ var animalPapersCheckSchema = object({
21805
+ needed: string2(),
21806
+ onFile: boolean3()
21807
+ });
21808
+ var animalMemberSchema = animalViewSchema.extend({
21809
+ papersCheck: animalPapersCheckSchema.nullable()
21810
+ });
21811
+ var SHED_READING_TYPES = {
21812
+ temp: "shed.temp",
21813
+ humidity: "shed.humidity",
21814
+ heater: "shed.heater",
21815
+ water: "shed.water_pct",
21816
+ door: "shed.door",
21817
+ feeder: "shed.feed_kg",
21818
+ light: "shed.light"
21819
+ };
21820
+ var animalRoomReadingSchema = object({
21821
+ kind: _enum2(Object.keys(SHED_READING_TYPES)),
21822
+ value: number2().nullable(),
21823
+ unit: string2().nullable(),
21824
+ text: string2().nullable(),
21825
+ detail: string2().nullish(),
21826
+ device: string2().nullish(),
21827
+ at: exports_coerce.date()
21828
+ });
21829
+ var animalRoomAlertSchema = object({
21830
+ id: string2(),
21831
+ at: exports_coerce.date(),
21832
+ text: string2(),
21833
+ detail: string2().nullable(),
21834
+ source: _enum2(["camera", "power", "other"])
21835
+ });
21836
+ var animalRoomSchema = object({
21837
+ place: nodeRefSchema,
21838
+ readings: array(animalRoomReadingSchema),
21839
+ temperature24h: array(object({ at: exports_coerce.date(), value: number2() })),
21840
+ alerts: array(animalRoomAlertSchema)
21841
+ });
21842
+ var animalDetailSchema = animalViewSchema.extend({
21843
+ group: nodeRefSchema.nullable(),
21844
+ members: array(animalMemberSchema),
21845
+ links: animalLinksSchema,
21846
+ weights: array(animalWeightPointSchema),
21847
+ latestLength: object({ mm: number2(), at: exports_coerce.date() }).nullable(),
21848
+ eggs: array(animalDayCountSchema),
21849
+ periods: array(periodViewSchema),
21850
+ keyDates: array(keyDateViewSchema),
21851
+ papersCheck: animalPapersCheckSchema.nullable(),
21852
+ room: animalRoomSchema.nullable()
21853
+ });
21854
+ var titleSchema = string2().trim().min(1).max(120);
21855
+ var shortText = (max) => string2().trim().min(1).max(max);
21856
+ var idList = array(ulidSchema).max(20);
21857
+ var animalFieldsSchema = object({
21858
+ title: titleSchema,
21859
+ form: animalFormSchema,
21860
+ speciesId: ulidSchema.nullish(),
21861
+ speciesKey: speciesKeySchema,
21862
+ breed: shortText(120).nullish(),
21863
+ sex: animalSexSchema.nullish(),
21864
+ bornOn: animalBornOnSchema.nullish(),
21865
+ bornApprox: boolean3(),
21866
+ acquiredOn: keyDateDaySchema.nullish(),
21867
+ acquiredHow: animalAcquiredHowSchema.nullish(),
21868
+ status: animalStatusSchema,
21869
+ endedOn: keyDateDaySchema.nullish(),
21870
+ endNote: shortText(500).nullish(),
21871
+ headCount: number2().int().min(0).max(1e4).nullish(),
21872
+ ids: maskedIdsSchema,
21873
+ markings: shortText(200).nullish(),
21874
+ breeding: animalBreedingSchema,
21875
+ groupId: ulidSchema.nullish(),
21876
+ areaId: ulidSchema.nullish(),
21877
+ placeId: ulidSchema.nullish(),
21878
+ vetIds: idList,
21879
+ cameFromId: ulidSchema.nullish(),
21880
+ habitIds: idList,
21881
+ supplyIds: idList,
21882
+ paperIds: idList,
21883
+ assetIds: idList
21884
+ });
21885
+ var createAnimalInputSchema = animalFieldsSchema.partial().required({ title: true }).extend({ id: ulidSchema }).strict();
21886
+ var updateAnimalInputSchema = animalFieldsSchema.partial().strict();
21887
+ var animalsQuerySchema = object({
21888
+ status: animalStatusSchema.optional(),
21889
+ form: animalFormSchema.optional(),
21890
+ groupId: ulidSchema.optional(),
21891
+ includeEnded: _enum2(["true", "false"]).transform((v) => v === "true").optional()
21892
+ });
21893
+ var occurredAtSchema = exports_coerce.date().optional();
21894
+ var animalLogInputSchema = discriminatedUnion("kind", [
21895
+ object({
21896
+ kind: literal("weight"),
21897
+ value: number2().positive().max(200000),
21898
+ unit: _enum2(["g", "kg"]).default("g"),
21899
+ occurredAt: occurredAtSchema
21900
+ }).strict(),
21901
+ object({
21902
+ kind: literal("length"),
21903
+ value: number2().positive().max(5000),
21904
+ occurredAt: occurredAtSchema
21905
+ }).strict(),
21906
+ object({
21907
+ kind: literal("eggs"),
21908
+ count: number2().int().min(0).max(500),
21909
+ occurredAt: occurredAtSchema
21910
+ }).strict(),
21911
+ object({
21912
+ kind: literal("note"),
21913
+ text: string2().trim().min(1).max(1000),
21914
+ occurredAt: occurredAtSchema
21915
+ }).strict()
21916
+ ]);
21917
+ var animalVetVisitSourceSchema = _enum2(["sticker", "photo", "said"]);
21918
+ var visitTextSchema = string2().trim().min(1).max(120);
21919
+ var visitCostSchema = object({
21920
+ amount: number2().positive().max(1e5),
21921
+ currency: string2().trim().length(3).default("EUR")
21922
+ }).strict();
21923
+ var animalVetVisitInputSchema = object({
21924
+ id: ulidSchema,
21925
+ at: exports_coerce.date().optional(),
21926
+ vetContactId: ulidSchema.optional(),
21927
+ clinician: visitTextSchema.optional(),
21928
+ reason: visitTextSchema.optional(),
21929
+ vaccine: object({ name: visitTextSchema, source: animalVetVisitSourceSchema.optional() }).strict().optional(),
21930
+ dewormer: visitTextSchema.optional(),
21931
+ weight: object({
21932
+ value: number2().positive().max(200000),
21933
+ unit: _enum2(["g", "kg"]).default("kg")
21934
+ }).strict().optional(),
21935
+ nextDates: array(object({
21936
+ id: ulidSchema,
21937
+ label: visitTextSchema,
21938
+ date: string2().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD")
21939
+ }).strict()).max(5).default([]),
21940
+ files: array(object({ id: ulidSchema, name: visitTextSchema.optional() }).strict()).max(5).default([]),
21941
+ cost: visitCostSchema.optional()
21942
+ }).strict();
21943
+ var animalVetVisitPatchSchema = object({
21944
+ vetContactId: ulidSchema.nullable().optional(),
21945
+ clinician: visitTextSchema.nullable().optional(),
21946
+ reason: visitTextSchema.nullable().optional(),
21947
+ vaccine: object({ name: visitTextSchema, source: animalVetVisitSourceSchema.optional() }).strict().nullable().optional(),
21948
+ dewormer: visitTextSchema.nullable().optional(),
21949
+ cost: visitCostSchema.nullable().optional()
21950
+ }).strict().refine((v) => Object.keys(v).length > 0, { message: "Change at least one field." });
21951
+ var animalVetVisitSchema = object({
21952
+ id: ulidSchema,
21953
+ animal: object({
21954
+ id: ulidSchema,
21955
+ title: string2(),
21956
+ speciesKey: string2().nullable(),
21957
+ speciesClass: animalClassSchema.nullable()
21958
+ }),
21959
+ at: exports_coerce.date(),
21960
+ vet: nodeRefSchema.nullable(),
21961
+ clinician: string2().nullable(),
21962
+ reason: string2().nullable(),
21963
+ vaccine: object({ name: string2(), source: animalVetVisitSourceSchema.nullable() }).nullable(),
21964
+ dewormer: string2().nullable(),
21965
+ weight: object({
21966
+ grams: number2(),
21967
+ deltaGrams: number2().nullable(),
21968
+ since: string2().nullable()
21969
+ }).nullable(),
21970
+ keyDates: array(object({ id: string2(), label: string2(), date: string2() })),
21971
+ files: array(object({ id: string2(), name: string2() })),
21972
+ cost: object({ amount: number2(), currency: string2() }).nullable(),
21973
+ byAgent: boolean3(),
21974
+ undone: boolean3()
21975
+ });
21976
+ var animalTimelineEntrySchema = object({
21977
+ id: string2(),
21978
+ at: exports_coerce.date(),
21979
+ kind: _enum2([
21980
+ "weight",
21981
+ "length",
21982
+ "eggs",
21983
+ "note",
21984
+ "vet_visit",
21985
+ "period_started",
21986
+ "period_ended",
21987
+ "key_date"
21988
+ ]),
21989
+ animalId: ulidSchema,
21990
+ animalTitle: string2(),
21991
+ value: number2().nullable(),
21992
+ text: string2().nullable(),
21993
+ byAgent: boolean3().default(false)
21994
+ });
21995
+ var animalTimelineQuerySchema = object({
21996
+ days: exports_coerce.number().int().min(1).max(3650).default(90)
21997
+ });
21998
+ var animalEggsTodaySchema = object({
21999
+ animalId: ulidSchema,
22000
+ title: string2(),
22001
+ today: number2().int(),
22002
+ heads: number2().int(),
22003
+ last7: array(animalDayCountSchema)
22004
+ });
22005
+ var animalsOverviewSchema = object({
22006
+ animals: array(animalViewSchema),
22007
+ today: object({
22008
+ day: string2(),
22009
+ eggs: array(animalEggsTodaySchema),
22010
+ supplies: array(animalSupplySchema),
22011
+ habits: array(animalHabitSchema)
22012
+ }),
22013
+ comingUp: array(keyDateViewSchema.extend({ vet: string2().nullable() })),
22014
+ periods: array(periodViewSchema)
22015
+ });
22016
+ var animalHolidayModeSchema = object({
22017
+ popHole: boolean3(),
22018
+ heater: boolean3(),
22019
+ alerts: boolean3(),
22020
+ dailyPhoto: boolean3(),
22021
+ feedReorder: boolean3()
22022
+ });
22023
+ var animalHandoverRuleSchema = object({
22024
+ sitter: string2().trim().min(1).max(120).optional(),
22025
+ houseNote: string2().trim().min(1).max(300).optional(),
22026
+ holidayMode: animalHolidayModeSchema.partial().optional(),
22027
+ share: object({ tokenHash: string2(), until: string2() }).optional(),
22028
+ agentNote: string2().trim().min(1).max(500).optional()
22029
+ }).passthrough();
22030
+ var animalHandoverQuerySchema = object({ periodId: ulidSchema.optional() });
22031
+ var animalHandoverTripSchema = object({
22032
+ periodId: ulidSchema.nullable(),
22033
+ title: string2(),
22034
+ from: string2(),
22035
+ to: string2(),
22036
+ sitter: string2().nullable(),
22037
+ houseNote: string2().nullable(),
22038
+ holidayMode: animalHolidayModeSchema,
22039
+ sharedUntil: string2().nullable(),
22040
+ agentNote: string2().nullable(),
22041
+ calendar: string2().nullable()
22042
+ });
22043
+ var animalHandoverAnimalSchema = object({
22044
+ id: ulidSchema,
22045
+ title: string2(),
22046
+ form: animalFormSchema,
22047
+ heads: number2().int(),
22048
+ species: string2().nullable(),
22049
+ speciesKey: string2().nullable(),
22050
+ speciesClass: animalClassSchema.nullable(),
22051
+ asleep: boolean3(),
22052
+ steps: array(string2()),
22053
+ aside: string2().nullable()
22054
+ });
22055
+ var animalHandoverContactSchema = object({
22056
+ id: ulidSchema,
22057
+ title: string2(),
22058
+ kind: _enum2(["vet", "member"]),
22059
+ label: string2().nullable(),
22060
+ phone: string2().nullable()
22061
+ });
22062
+ var animalHandoverSupplySchema = animalSupplySchema.extend({
22063
+ lastsTrip: boolean3().nullable()
22064
+ });
22065
+ var animalHandoverHabitSchema = nodeRefSchema.extend({ restsThroughTrip: boolean3() });
22066
+ var animalHandoverSchema = object({
22067
+ trip: animalHandoverTripSchema.nullable(),
22068
+ areaId: ulidSchema.nullable(),
22069
+ animals: array(animalHandoverAnimalSchema),
22070
+ contacts: array(animalHandoverContactSchema),
22071
+ supplies: array(animalHandoverSupplySchema),
22072
+ habits: array(animalHandoverHabitSchema),
22073
+ sensors: boolean3(),
22074
+ generatedAt: exports_coerce.date()
22075
+ });
22076
+ var animalHolidayModeInputSchema = animalHolidayModeSchema.partial().extend({ periodId: ulidSchema }).strict().refine((v) => Object.keys(v).length > 1, { message: "Turn at least one switch." });
22077
+ var animalHandoverShareInputSchema = object({ periodId: ulidSchema }).strict();
22078
+ var animalHandoverShareSchema = object({
22079
+ token: string2(),
22080
+ path: string2(),
22081
+ until: string2()
22082
+ });
22083
+ var animalLostCardInputSchema = object({
22084
+ photoFileId: ulidSchema.nullish(),
22085
+ phone: string2().trim().regex(/^\+?[0-9][0-9 ()./-]{4,30}$/, "A phone number: digits, spaces, + ( ) . / -").nullish(),
22086
+ showChipped: boolean3().optional(),
22087
+ note: string2().trim().min(1).max(200).nullish()
22088
+ }).strict();
22089
+ var animalLostCardPhotoSchema = object({ id: ulidSchema, name: string2() });
22090
+ var animalLostCardPublicSchema = object({
22091
+ name: string2(),
22092
+ speciesKey: string2().nullable(),
22093
+ kind: string2().nullable(),
22094
+ missing: boolean3(),
22095
+ hasPhoto: boolean3(),
22096
+ phone: string2().nullable(),
22097
+ chipped: boolean3(),
22098
+ note: string2().nullable()
22099
+ });
22100
+ var animalLostCardStateSchema = object({
22101
+ card: object({
22102
+ path: string2(),
22103
+ photoFileId: ulidSchema.nullable(),
22104
+ phone: string2().nullable(),
22105
+ showChipped: boolean3(),
22106
+ note: string2().nullable(),
22107
+ since: exports_coerce.date(),
22108
+ preview: animalLostCardPublicSchema
22109
+ }).nullable(),
22110
+ photos: array(animalLostCardPhotoSchema),
22111
+ chipOnFile: boolean3()
22112
+ });
22113
+ var animalAcquisitionInputSchema = object({
22114
+ pickUpOn: keyDateDaySchema.nullish(),
22115
+ quarantine: boolean3().optional(),
22116
+ extraSteps: array(string2().trim().min(1).max(200)).max(10).optional()
22117
+ }).strict();
22118
+ var animalAcquisitionStepSchema = object({
22119
+ id: ulidSchema,
22120
+ title: string2(),
22121
+ done: boolean3(),
22122
+ quarantine: boolean3()
22123
+ });
22124
+ var animalAcquisitionSchema = object({
22125
+ taskId: ulidSchema,
22126
+ title: string2(),
22127
+ pickUpOn: string2().nullable(),
22128
+ arrived: boolean3(),
22129
+ steps: array(animalAcquisitionStepSchema),
22130
+ blockers: array(string2())
22131
+ });
22132
+ var animalArrivedInputSchema = object({
22133
+ on: keyDateDaySchema.optional(),
22134
+ quarantineMonths: number2().int().min(0).max(12).optional()
22135
+ }).strict();
22136
+
22137
+ // ../../packages/schema/src/contracts/sensors.ts
22138
+ var sensorProviderValues = ["home_assistant", "unifi"];
22139
+ var sensorProviderSchema = _enum2(sensorProviderValues);
22140
+ var sensorTargetValues = ["place", "asset"];
22141
+ var sensorTargetSchema = _enum2(sensorTargetValues);
22142
+ var PLACE_SENSOR_READINGS = Object.keys(SHED_READING_TYPES);
22143
+ var ASSET_READING_TYPES = {
22144
+ state: "asset.state",
22145
+ power: "asset.power",
22146
+ energy: "asset.energy"
22147
+ };
22148
+ var ASSET_SENSOR_READINGS = Object.keys(ASSET_READING_TYPES);
22149
+ var sensorReadingValues = [
22150
+ ...new Set([...PLACE_SENSOR_READINGS, ...ASSET_SENSOR_READINGS])
22151
+ ];
22152
+ var sensorReadingSchema = _enum2(sensorReadingValues);
22153
+ var SENSOR_DATAPOINT_TYPES = [
22154
+ ...Object.values(SHED_READING_TYPES),
22155
+ ...Object.values(ASSET_READING_TYPES)
22156
+ ];
22157
+ var homeAssistantLinkInputSchema = object({
22158
+ baseUrl: string2().trim().url().refine((u) => /^https?:\/\//i.test(u), "must start with http:// or https://"),
22159
+ token: string2().trim().min(1).max(2000)
22160
+ }).strict();
22161
+ var homeAssistantStatusSchema = object({
22162
+ linked: boolean3(),
22163
+ host: string2().nullable(),
22164
+ links: number2().int().nonnegative(),
22165
+ lastReadingAt: string2().nullable()
22166
+ });
22167
+ var homeAssistantErrorValues = ["unauthorized", "unavailable", "bad_response"];
22168
+ var homeAssistantErrorSchema = _enum2(homeAssistantErrorValues);
22169
+ var sensorSyncResultSchema = object({
22170
+ syncedAt: string2(),
22171
+ entities: number2().int().nonnegative(),
22172
+ written: number2().int().nonnegative(),
22173
+ skipped: number2().int().nonnegative(),
22174
+ missing: array(string2()),
22175
+ error: homeAssistantErrorSchema.nullable()
22176
+ });
22177
+ var sensorLinkRowSchema = createSelectSchema(sensorLinks, {
22178
+ createdAt: exports_coerce.date(),
22179
+ updatedAt: exports_coerce.date()
22180
+ });
22181
+ var sensorLinkSchema = object({
22182
+ id: ulidSchema,
22183
+ provider: sensorProviderSchema,
22184
+ externalId: string2(),
22185
+ nodeId: ulidSchema,
22186
+ target: sensorTargetSchema,
22187
+ reading: string2(),
22188
+ label: string2().nullable(),
22189
+ nodeTitle: string2(),
22190
+ createdAt: exports_coerce.date()
22191
+ });
22192
+ var createSensorLinkInputSchema = object({
22193
+ provider: sensorProviderSchema.default("home_assistant"),
22194
+ externalId: string2().trim().min(1).max(255),
22195
+ nodeId: ulidSchema,
22196
+ reading: sensorReadingSchema,
22197
+ label: string2().trim().min(1).max(200).nullish()
22198
+ }).strict();
22199
+ var sensorLinksQuerySchema = object({ nodeId: ulidSchema.optional() });
22200
+ var homeAssistantEntitySchema = object({
22201
+ entityId: string2(),
22202
+ name: string2(),
22203
+ domain: string2(),
22204
+ state: string2(),
22205
+ unit: string2().nullable(),
22206
+ deviceClass: string2().nullable(),
22207
+ lastUpdated: string2(),
22208
+ suggested: object({ place: string2().nullable(), asset: string2().nullable() }),
22209
+ link: sensorLinkSchema.nullable()
22210
+ });
22211
+ var assetReadingSchema = object({
22212
+ kind: _enum2(ASSET_SENSOR_READINGS),
22213
+ value: number2().nullable(),
22214
+ unit: string2().nullable(),
22215
+ text: string2().nullable(),
22216
+ device: string2().nullable(),
22217
+ at: exports_coerce.date()
22218
+ });
22219
+
22220
+ // ../../packages/schema/src/contracts/house.ts
22221
+ var day = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "must be a calendar day (YYYY-MM-DD)");
22222
+ var houseBrokenSchema = object({
22223
+ item: collectionItemViewSchema,
22224
+ repair: taskViewSchema.nullable()
22225
+ });
22226
+ var houseUpkeepSoonSchema = object({
22227
+ task: taskViewSchema,
22228
+ itemId: string2(),
22229
+ itemTitle: string2(),
22230
+ nextOn: day.nullable(),
22231
+ placeTitle: string2().nullable().default(null),
22232
+ lastOn: day.nullable().default(null)
22233
+ });
22234
+ var housePlaceTileSchema = object({
22235
+ id: string2(),
22236
+ title: string2(),
22237
+ kind: string2(),
22238
+ gardenFeatureId: string2().nullable(),
22239
+ thingCount: number2().int().min(0)
22240
+ });
22241
+ var houseOverviewSchema = object({
22242
+ broken: array(houseBrokenSchema),
22243
+ upkeepSoon: array(houseUpkeepSoonSchema),
22244
+ places: array(housePlaceTileSchema),
22245
+ thingCount: number2().int().min(0),
22246
+ upkeepCount: number2().int().min(0),
22247
+ toolCount: number2().int().min(0),
22248
+ animalCount: number2().int().min(0),
22249
+ toConfirm: number2().int().min(0).default(0)
22250
+ });
22251
+ var upkeepScheduleSchema = object({
22252
+ every: number2().int().min(1).max(365),
22253
+ unit: _enum2(["day", "week", "month", "year"]),
22254
+ startOn: day.optional()
22255
+ }).strict();
22256
+ var setAssetUpkeepInputSchema = object({
22257
+ title: string2().trim().min(1).max(200),
22258
+ schedule: upkeepScheduleSchema,
22259
+ placeId: ulidSchema.nullish(),
22260
+ areaId: ulidSchema.nullish(),
22261
+ nextStep: string2().trim().max(500).nullish()
22262
+ }).strict();
22263
+ var fileAssetInputSchema = object({
22264
+ id: ulidSchema.optional(),
22265
+ title: string2().trim().min(1).max(200),
22266
+ placeId: ulidSchema.nullish(),
22267
+ areaId: ulidSchema.nullish(),
22268
+ status: _enum2(["want", "have"]).optional(),
22269
+ facet: record(string2(), unknown()).optional(),
22270
+ tags: array(string2().min(1).max(60)).max(20).optional(),
22271
+ fileIds: array(ulidSchema).max(20).optional(),
22272
+ match: boolean3().default(true),
22273
+ upkeep: setAssetUpkeepInputSchema.optional(),
22274
+ fault: object({
22275
+ note: string2().trim().min(1).max(2000),
22276
+ repairTitle: string2().trim().min(1).max(200).optional()
22277
+ }).strict().optional()
22278
+ }).strict();
22279
+ var houseReceiptSchema = object({
22280
+ itemId: string2(),
22281
+ created: boolean3(),
22282
+ before: object({
22283
+ facet: record(string2(), unknown()).nullable(),
22284
+ placeId: string2().nullable(),
22285
+ status: string2()
22286
+ }).nullable(),
22287
+ taskIds: array(string2()),
22288
+ entryIds: array(string2()),
22289
+ files: array(object({ id: string2(), previousOwnerId: string2().nullable() }))
22290
+ });
22291
+ var houseWriteResultSchema = object({
22292
+ item: collectionItemDetailSchema,
22293
+ receipt: houseReceiptSchema
22294
+ });
22295
+ var undoHouseWriteInputSchema = houseReceiptSchema.strict();
22296
+ var houseTrailStepSchema = object({ id: string2(), title: string2() });
22297
+ var houseAssetPartSchema = object({
22298
+ id: string2(),
22299
+ title: string2(),
22300
+ quantity: number2(),
22301
+ unit: string2().nullable(),
22302
+ lowStockThreshold: number2().nullable()
22303
+ });
22304
+ var houseAssetLinkSchema = object({
22305
+ nodeId: string2(),
22306
+ title: string2(),
22307
+ type: string2(),
22308
+ kind: string2(),
22309
+ direction: _enum2(["in", "out"]),
22310
+ label: string2().nullable().default(null),
22311
+ context: string2().nullable().default(null),
22312
+ at: exports_coerce.date().nullable().default(null),
22313
+ timed: boolean3().default(false)
22314
+ });
22315
+ var houseAssetSchema = object({
22316
+ item: collectionItemDetailSchema,
22317
+ trail: array(houseTrailStepSchema),
22318
+ parts: array(houseAssetPartSchema),
22319
+ linked: array(houseAssetLinkSchema),
22320
+ warrantyUntil: day.nullable(),
22321
+ visibility: _enum2(NODE_VISIBILITY_VALUES).default("space"),
22322
+ readings: array(assetReadingSchema).default([])
22323
+ });
22324
+ var setAssetVisibilityInputSchema = object({ visibility: _enum2(NODE_VISIBILITY_VALUES) }).strict();
22325
+ var linkAssetPartInputSchema = object({ inventoryItemId: ulidSchema }).strict();
22326
+ var lendAssetInputSchema = object({
22327
+ direction: _enum2(["lent", "borrowed"]),
22328
+ who: string2().trim().min(1).max(200),
22329
+ contactId: ulidSchema.nullish(),
22330
+ since: day.optional(),
22331
+ dueBack: day.nullish(),
22332
+ note: string2().trim().max(500).nullish()
22333
+ }).strict();
22334
+ var returnAssetInputSchema = object({
22335
+ on: day.optional(),
22336
+ note: string2().trim().max(500).nullish()
22337
+ }).strict();
22338
+ var houseValueProofSchema = _enum2(["receipt_photo", "receipt", "photo", "none"]);
22339
+ var houseValueRowSchema = object({
22340
+ id: string2(),
22341
+ title: string2(),
22342
+ model: string2().nullable(),
22343
+ placeId: string2().nullable(),
21432
22344
  placeTitle: string2().nullable(),
21433
22345
  placeGroup: string2().nullable().default(null),
21434
22346
  withHouse: boolean3().default(false),
@@ -22093,12 +23005,15 @@ var healthProfileSchema = createSelectSchema(healthProfiles, {
22093
23005
  notes: string2().nullable().default(null),
22094
23006
  sex: string2().nullable().default(null)
22095
23007
  });
23008
+ var HEALTH_CONSENT_VERSION = "2026-10-18";
22096
23009
  var healthConsentStateSchema = object({
22097
23010
  granted: boolean3(),
22098
23011
  version: string2().nullable(),
22099
- grantedAt: exports_coerce.date().nullable()
23012
+ grantedAt: exports_coerce.date().nullable(),
23013
+ currentVersion: string2().default(HEALTH_CONSENT_VERSION),
23014
+ renewalNeeded: boolean3().default(false),
23015
+ aiProvider: string2().nullable().default(null)
22100
23016
  });
22101
- var HEALTH_CONSENT_VERSION = "2026-10-18";
22102
23017
  var subject = { subjectNodeId: ulidSchema.nullish() };
22103
23018
  var createHealthConditionInputSchema = object({
22104
23019
  id: ulidSchema.optional(),
@@ -22325,6 +23240,20 @@ var healthSummarySchema = object({
22325
23240
  trends: array(healthTrendSchema).default([])
22326
23241
  });
22327
23242
  var healthSummaryQuerySchema = object({ episodeId: ulidSchema.optional() });
23243
+ var healthMedicalIdSchema = object({
23244
+ name: string2().nullable(),
23245
+ bloodGroup: string2().nullable(),
23246
+ allergies: array(string2()),
23247
+ heightCm: number2().nullable(),
23248
+ medications: array(object({
23249
+ id: string2(),
23250
+ title: string2(),
23251
+ dose: string2().nullable(),
23252
+ kind: healthMedicationKindSchema,
23253
+ schedule: healthMedicationScheduleSchema
23254
+ })),
23255
+ emergencyContact: object({ id: string2(), name: string2(), phone: string2().nullable() }).nullable()
23256
+ });
22328
23257
 
22329
23258
  // ../../packages/schema/src/contracts/health-labs.ts
22330
23259
  var LAB_GROUP_VALUES = [
@@ -22785,10 +23714,10 @@ var JOURNAL_MILESTONE_PRECISION_VALUES = ["year", "month", "day"];
22785
23714
  var journalMilestonePrecisionSchema = _enum2(JOURNAL_MILESTONE_PRECISION_VALUES);
22786
23715
  var journalMilestoneStatusSchema = _enum2(["suggested", "kept"]);
22787
23716
  var journalMilestoneVisibilitySchema = _enum2(["owner", "space"]);
22788
- var titleSchema = string2().trim().min(1).max(200);
23717
+ var titleSchema2 = string2().trim().min(1).max(200);
22789
23718
  var descriptionSchema = string2().trim().min(1).max(2000);
22790
23719
  var journalCreateMilestoneInputSchema = object({
22791
- title: titleSchema,
23720
+ title: titleSchema2,
22792
23721
  kind: journalMilestoneKindSchema.default("other"),
22793
23722
  happenedOn: journalDateSchema,
22794
23723
  precision: journalMilestonePrecisionSchema.default("day"),
@@ -22803,7 +23732,7 @@ var journalCreateMilestoneInputSchema = object({
22803
23732
  path: ["remindYearly"]
22804
23733
  });
22805
23734
  var journalUpdateMilestoneInputSchema = object({
22806
- title: titleSchema.optional(),
23735
+ title: titleSchema2.optional(),
22807
23736
  kind: journalMilestoneKindSchema.optional(),
22808
23737
  happenedOn: journalDateSchema.optional(),
22809
23738
  precision: journalMilestonePrecisionSchema.optional(),
@@ -22951,6 +23880,60 @@ var journalWeekSchema = object({
22951
23880
  usual: number2().nullable(),
22952
23881
  numbers: journalWeekNumbersSchema
22953
23882
  });
23883
+ var journalMonthKeySchema = string2().regex(/^\d{4}-(0[1-9]|1[0-2])$/, "must be a month (YYYY-MM)");
23884
+ var journalYearKeySchema = string2().regex(/^\d{4}$/, "must be a year (YYYY)");
23885
+ var journalPeriodKeySchema = union([
23886
+ journalWeekKeySchema,
23887
+ journalMonthKeySchema,
23888
+ journalYearKeySchema
23889
+ ]);
23890
+ function journalPeriodKind(key) {
23891
+ if (journalWeekKeySchema.safeParse(key).success)
23892
+ return "week";
23893
+ if (journalMonthKeySchema.safeParse(key).success)
23894
+ return "month";
23895
+ if (journalYearKeySchema.safeParse(key).success)
23896
+ return "year";
23897
+ return null;
23898
+ }
23899
+ var journalPeriodMilestoneSchema = object({
23900
+ id: string2(),
23901
+ title: string2(),
23902
+ kind: journalMilestoneKindSchema,
23903
+ happenedOn: journalDateSchema,
23904
+ precision: journalMilestonePrecisionSchema,
23905
+ planned: boolean3()
23906
+ });
23907
+ var journalMonthSchema = object({
23908
+ month: journalMonthKeySchema,
23909
+ from: journalDateSchema,
23910
+ to: journalDateSchema,
23911
+ timezone: string2().min(1),
23912
+ recap: journalRecapSchema.nullable(),
23913
+ days: array(journalDayListItemSchema),
23914
+ usual: number2().nullable(),
23915
+ numbers: journalWeekNumbersSchema,
23916
+ milestones: array(journalPeriodMilestoneSchema)
23917
+ });
23918
+ var journalYearMonthSchema = object({
23919
+ month: journalMonthKeySchema,
23920
+ average: number2().nullable(),
23921
+ rated: number2().int().nonnegative(),
23922
+ kept: number2().int().nonnegative(),
23923
+ best: journalDateSchema.nullable()
23924
+ });
23925
+ var journalYearSchema = object({
23926
+ year: journalYearKeySchema,
23927
+ from: journalDateSchema,
23928
+ to: journalDateSchema,
23929
+ timezone: string2().min(1),
23930
+ recap: journalRecapSchema.nullable(),
23931
+ days: array(journalDayListItemSchema),
23932
+ months: array(journalYearMonthSchema),
23933
+ usual: number2().nullable(),
23934
+ numbers: journalWeekNumbersSchema,
23935
+ milestones: array(journalPeriodMilestoneSchema)
23936
+ });
22954
23937
 
22955
23938
  // ../../packages/schema/src/contracts/modules.ts
22956
23939
  var MODULE_KEYS = [
@@ -24225,62 +25208,6 @@ var mealPlanCookResultSchema = object({
24225
25208
  ingredients: array(cookedIngredientSchema)
24226
25209
  });
24227
25210
 
24228
- // ../../packages/schema/src/contracts/key-dates.ts
24229
- var keyDateDaySchema = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD").refine((s) => {
24230
- const d = new Date(`${s}T00:00:00Z`);
24231
- return !Number.isNaN(d.getTime()) && d.toISOString().slice(0, 10) === s;
24232
- }, "not a real date");
24233
- var keyDateRepeatSchema = _enum2(["yearly"]);
24234
- var keyDateSchema = createSelectSchema(keyDates, {
24235
- date: keyDateDaySchema,
24236
- confirmedAt: exports_coerce.date().nullable(),
24237
- createdAt: exports_coerce.date(),
24238
- updatedAt: exports_coerce.date()
24239
- });
24240
- var keyDateViewSchema = keyDateSchema.extend({
24241
- nodeTitle: string2(),
24242
- nodeType: string2(),
24243
- repeat: keyDateRepeatSchema.nullable(),
24244
- nextOn: keyDateDaySchema,
24245
- task: object({
24246
- id: ulidSchema,
24247
- status: string2(),
24248
- dueAt: exports_coerce.date().nullable()
24249
- }).nullable()
24250
- });
24251
- var leadDaysSchema = number2().int().min(0).max(366);
24252
- var sourceSchema = string2().trim().min(1).max(120);
24253
- var createKeyDateInputSchema = object({
24254
- id: ulidSchema,
24255
- nodeId: ulidSchema,
24256
- kind: keyDateKindSchema.optional(),
24257
- label: string2().trim().min(1).max(200).nullish(),
24258
- date: keyDateDaySchema,
24259
- yearKnown: boolean3().optional(),
24260
- repeat: keyDateRepeatSchema.nullish(),
24261
- leadDays: leadDaysSchema.optional(),
24262
- derivedFrom: string2().trim().min(1).max(120).nullish(),
24263
- source: sourceSchema.optional(),
24264
- confirmed: boolean3().optional()
24265
- }).strict();
24266
- var updateKeyDateInputSchema = object({
24267
- kind: keyDateKindSchema.optional(),
24268
- label: string2().trim().min(1).max(200).nullish(),
24269
- date: keyDateDaySchema.optional(),
24270
- yearKnown: boolean3().optional(),
24271
- repeat: keyDateRepeatSchema.nullish(),
24272
- leadDays: leadDaysSchema.optional(),
24273
- derivedFrom: string2().trim().min(1).max(120).nullish(),
24274
- source: sourceSchema.optional(),
24275
- confirmed: boolean3().optional()
24276
- }).strict();
24277
- var keyDatesQuerySchema = object({
24278
- nodeId: ulidSchema.optional(),
24279
- kind: keyDateKindSchema.optional(),
24280
- from: keyDateDaySchema.optional(),
24281
- to: keyDateDaySchema.optional()
24282
- });
24283
-
24284
25211
  // ../../packages/schema/src/contracts/people.ts
24285
25212
  var sourceSchema2 = string2().trim().min(1).max(120);
24286
25213
  var rhythmDaysSchema = number2().int().min(1).max(366);
@@ -24466,6 +25393,43 @@ var personNoteUndoResultSchema = object({
24466
25393
  id: ulidSchema,
24467
25394
  removed: number2().int()
24468
25395
  });
25396
+ var personProposalKindSchema = _enum2(personProposalKind.enumValues);
25397
+ var personProposalStatusSchema = _enum2(personProposalStatus.enumValues);
25398
+ var mailSourceSchema = string2().trim().regex(/^gmail:[A-Za-z0-9_-]{1,100}$/, "a mail source is gmail:<message id>");
25399
+ var createPersonProposalInputSchema = object({
25400
+ id: ulidSchema,
25401
+ contactId: ulidSchema.optional(),
25402
+ person: string2().trim().min(1).max(120).optional(),
25403
+ kind: personProposalKindSchema.default("other"),
25404
+ title: string2().trim().min(1).max(200),
25405
+ source: mailSourceSchema,
25406
+ heardAt: exports_coerce.date(),
25407
+ items: array(personNoteItemSchema).min(1).max(10).optional()
25408
+ }).strict().refine((n) => Boolean(n.contactId) !== Boolean(n.person), {
25409
+ message: "name the person by contactId or by person, not both",
25410
+ path: ["contactId"]
25411
+ });
25412
+ var personProposalSchema = object({
25413
+ id: ulidSchema,
25414
+ contactId: ulidSchema,
25415
+ contactTitle: string2(),
25416
+ kind: personProposalKindSchema,
25417
+ title: string2(),
25418
+ source: string2(),
25419
+ heardAt: exports_coerce.date(),
25420
+ items: array(personNoteItemSchema),
25421
+ status: personProposalStatusSchema,
25422
+ decidedAt: exports_coerce.date().nullable(),
25423
+ createdAt: exports_coerce.date()
25424
+ });
25425
+ var personProposalsQuerySchema = object({
25426
+ status: personProposalStatusSchema.optional(),
25427
+ source: mailSourceSchema.optional()
25428
+ });
25429
+ var personProposalAcceptResultSchema = object({
25430
+ proposal: personProposalSchema,
25431
+ receipt: personNoteReceiptSchema
25432
+ });
24469
25433
  var personFindQuerySchema = object({
24470
25434
  q: string2().trim().min(1).max(120),
24471
25435
  limit: exports_coerce.number().int().min(1).max(20).optional()
@@ -24568,6 +25532,7 @@ var peopleOverviewSchema = object({
24568
25532
  phone: string2().nullable().default(null)
24569
25533
  })),
24570
25534
  heardLately: array(contactMomentViewSchema),
25535
+ proposals: array(personProposalSchema).default([]),
24571
25536
  lent: array(object({
24572
25537
  itemId: ulidSchema,
24573
25538
  title: string2(),
@@ -25246,9 +26211,12 @@ var insuranceFieldsSchema = object({
25246
26211
  product: text4,
25247
26212
  insuredObject: text4,
25248
26213
  insuredValue: amount4,
26214
+ buildingValue: amount4,
25249
26215
  premium: amount4,
25250
26216
  cadence: documentCadenceSchema,
26217
+ paymentMethod: text4,
25251
26218
  deductible: amount4,
26219
+ deductibleIndexed: boolean3(),
25252
26220
  extras: array(text4).max(30),
25253
26221
  claimPhone: phone,
25254
26222
  claimHours: text4,
@@ -25299,7 +26267,8 @@ var warrantyFieldsSchema = object({
25299
26267
  amount: amount4,
25300
26268
  purchaseDate: keyDateDaySchema,
25301
26269
  warrantyMonths: number2().int().min(0).max(600),
25302
- serial: text4
26270
+ serial: text4,
26271
+ room: text4
25303
26272
  }).partial().strict();
25304
26273
  var payToIban = string2().transform(compactIban).pipe(string2().regex(/^[A-Z]{2}\d{2}[A-Z0-9]{8,30}$/, "expected an IBAN"));
25305
26274
  var payRef = string2().trim().min(1).max(140);
@@ -25384,11 +26353,28 @@ var documentLinkSchema = object({
25384
26353
  title: string2(),
25385
26354
  type: string2(),
25386
26355
  kind: string2(),
25387
- direction: _enum2(["in", "out"])
26356
+ direction: _enum2(["in", "out"]),
26357
+ facts: object({
26358
+ dueOn: keyDateDaySchema.nullable(),
26359
+ status: string2().nullable(),
26360
+ amount: number2().nullable(),
26361
+ cadence: string2().nullable(),
26362
+ area: string2().nullable(),
26363
+ roles: array(string2()),
26364
+ phone: string2().nullable(),
26365
+ papers: array(object({ title: string2(), certType: string2().nullable() }))
26366
+ }).partial().default({})
26367
+ });
26368
+ var documentBrokerSchema = object({
26369
+ id: ulidSchema,
26370
+ title: string2(),
26371
+ phone: string2().nullable()
25388
26372
  });
25389
26373
  var documentDetailSchema = documentViewSchema.extend({
25390
26374
  keyDates: array(keyDateViewSchema),
25391
- linked: array(documentLinkSchema).default([])
26375
+ linked: array(documentLinkSchema).default([]),
26376
+ providerRoles: array(string2()).default([]),
26377
+ broker: documentBrokerSchema.nullable().default(null)
25392
26378
  });
25393
26379
  var fieldsInputSchema = record(string2(), unknown());
25394
26380
  function checkFields(kind, fields, ctx) {
@@ -25539,55 +26525,42 @@ var incidentsQuerySchema = object({
25539
26525
  policyId: ulidSchema.optional()
25540
26526
  });
25541
26527
 
25542
- // ../../packages/schema/src/contracts/periods.ts
25543
- var periodKindSchema = _enum2(periodKind.enumValues);
25544
- var periodRuleSchema = record(string2(), unknown());
25545
- var periodSchema = createSelectSchema(periods, {
25546
- startsAt: exports_coerce.date(),
25547
- endsAt: exports_coerce.date().nullable(),
25548
- plannedEndAt: exports_coerce.date().nullable(),
25549
- rule: periodRuleSchema,
25550
- createdAt: exports_coerce.date(),
25551
- updatedAt: exports_coerce.date()
25552
- });
25553
- var periodViewSchema = periodSchema.extend({
25554
- nodeTitle: string2(),
25555
- nodeType: string2(),
25556
- active: boolean3()
26528
+ // ../../packages/schema/src/contracts/tap-tags.ts
26529
+ var tapTagKindSchema = _enum2(tapTagKind.enumValues);
26530
+ var tapTagViewSchema = object({
26531
+ id: string2(),
26532
+ label: string2(),
26533
+ kind: tapTagKindSchema,
26534
+ targetId: string2(),
26535
+ targetTitle: string2(),
26536
+ path: string2(),
26537
+ lastTappedAt: exports_coerce.date().nullable(),
26538
+ createdAt: exports_coerce.date()
25557
26539
  });
25558
- var noteSchema2 = string2().trim().min(1).max(500);
25559
- function endsAfterStart(p, ctx) {
25560
- if (!p.startsAt)
25561
- return;
25562
- for (const key of ["endsAt", "plannedEndAt"]) {
25563
- const at = p[key];
25564
- if (at && at < p.startsAt) {
25565
- ctx.addIssue({ code: "custom", path: [key], message: `${key} is before startsAt` });
25566
- }
25567
- }
25568
- }
25569
- var createPeriodInputSchema = object({
26540
+ var labelSchema = string2().trim().min(1).max(80);
26541
+ var createTapTagInputSchema = object({
25570
26542
  id: ulidSchema,
25571
- nodeId: ulidSchema,
25572
- kind: periodKindSchema.optional(),
25573
- startsAt: exports_coerce.date(),
25574
- endsAt: exports_coerce.date().nullish(),
25575
- plannedEndAt: exports_coerce.date().nullish(),
25576
- rule: periodRuleSchema.optional(),
25577
- note: noteSchema2.nullish()
25578
- }).strict().superRefine(endsAfterStart);
25579
- var updatePeriodInputSchema = object({
25580
- kind: periodKindSchema.optional(),
25581
- startsAt: exports_coerce.date().optional(),
25582
- endsAt: exports_coerce.date().nullish(),
25583
- plannedEndAt: exports_coerce.date().nullish(),
25584
- rule: periodRuleSchema.optional(),
25585
- note: noteSchema2.nullish()
25586
- }).strict().superRefine(endsAfterStart);
25587
- var periodsQuerySchema = object({
25588
- nodeId: ulidSchema.optional(),
25589
- kind: periodKindSchema.optional(),
25590
- active: _enum2(["true", "false"]).transform((v) => v === "true").optional()
26543
+ label: labelSchema,
26544
+ kind: tapTagKindSchema,
26545
+ targetId: string2().min(1)
26546
+ }).strict();
26547
+ var updateTapTagInputSchema = object({
26548
+ label: labelSchema.optional(),
26549
+ kind: tapTagKindSchema.optional(),
26550
+ targetId: string2().min(1).optional()
26551
+ }).strict().refine((v) => v.kind === undefined === (v.targetId === undefined), {
26552
+ message: "kind and targetId are changed together",
26553
+ path: ["targetId"]
26554
+ }).refine((v) => Object.keys(v).length > 0, { message: "nothing to change" });
26555
+ var tapUndoSchema = discriminatedUnion("kind", [
26556
+ object({ kind: literal("habit_entry"), habitId: string2(), entryId: string2() }),
26557
+ object({ kind: literal("routine_run"), runId: string2(), stepRunIds: array(string2()) })
26558
+ ]);
26559
+ var tapResultSchema = object({
26560
+ tag: tapTagViewSchema,
26561
+ outcome: _enum2(["done", "already"]),
26562
+ line: string2(),
26563
+ undo: tapUndoSchema.nullable()
25591
26564
  });
25592
26565
 
25593
26566
  // ../../packages/schema/src/contracts/planning-rules.ts
@@ -25765,27 +26738,27 @@ var runPlayStatusValues = [
25765
26738
  var runPlayStatusSchema = _enum2(runPlayStatusValues);
25766
26739
  var name = string2().trim().min(1).max(200);
25767
26740
  var text5 = string2().trim().max(2000);
25768
- var shortText = string2().trim().max(300);
26741
+ var shortText2 = string2().trim().max(300);
25769
26742
  var isoDate = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "must be an ISO date (YYYY-MM-DD)");
25770
26743
  var ref = string2().trim().min(1).max(200);
25771
26744
  var runCharacterSchema = object({
25772
26745
  name,
25773
26746
  pronoun: _enum2(["he", "she", "they"]).nullish(),
25774
- subtitle: shortText.nullish(),
26747
+ subtitle: shortText2.nullish(),
25775
26748
  level: number2().int().min(0).max(1e4).nullish(),
25776
- build: shortText.nullish(),
25777
- stats: array(object({ k: name, v: union([number2(), shortText]) }).strict()).max(40).optional(),
25778
- traits: array(shortText).max(20).optional(),
26749
+ build: shortText2.nullish(),
26750
+ stats: array(object({ k: name, v: union([number2(), shortText2]) }).strict()).max(40).optional(),
26751
+ traits: array(shortText2).max(20).optional(),
25779
26752
  backstory: text5.nullish(),
25780
- rules: array(shortText).max(30).optional(),
25781
- faith: shortText.nullish()
26753
+ rules: array(shortText2).max(30).optional(),
26754
+ faith: shortText2.nullish()
25782
26755
  }).strict();
25783
26756
  var runArcSchema = object({
25784
- title: shortText.nullish(),
26757
+ title: shortText2.nullish(),
25785
26758
  chapters: array(object({
25786
26759
  key: name,
25787
26760
  name,
25788
- range: shortText.nullish(),
26761
+ range: shortText2.nullish(),
25789
26762
  moral: text5.nullish()
25790
26763
  }).strict()).max(40),
25791
26764
  current: name.nullish()
@@ -25793,7 +26766,7 @@ var runArcSchema = object({
25793
26766
  var runStepStatusValues = ["done", "now", "todo", "skipped"];
25794
26767
  var runStepStatusSchema = _enum2(runStepStatusValues);
25795
26768
  var runOrderStepSchema = object({
25796
- text: shortText.pipe(string2().min(1)),
26769
+ text: shortText2.pipe(string2().min(1)),
25797
26770
  status: runStepStatusSchema.default("todo"),
25798
26771
  questRef: ref.nullish()
25799
26772
  }).strict();
@@ -25802,33 +26775,33 @@ var runQuestStatusSchema = _enum2(runQuestStatusValues);
25802
26775
  var runQuestSchema = object({
25803
26776
  ref: ref.nullish(),
25804
26777
  name,
25805
- line: shortText.nullish(),
26778
+ line: shortText2.nullish(),
25806
26779
  status: runQuestStatusSchema.default("active"),
25807
26780
  objective: text5.nullish(),
25808
- hint: shortText.nullish(),
25809
- reward: shortText.nullish(),
25810
- place: shortText.nullish(),
26781
+ hint: shortText2.nullish(),
26782
+ reward: shortText2.nullish(),
26783
+ place: shortText2.nullish(),
25811
26784
  steps: array(object({
25812
- text: shortText.pipe(string2().min(1)),
26785
+ text: shortText2.pipe(string2().min(1)),
25813
26786
  done: boolean3().default(false),
25814
26787
  now: boolean3().optional(),
25815
- hint: shortText.nullish()
26788
+ hint: shortText2.nullish()
25816
26789
  }).strict()).max(40).optional(),
25817
- pausedAt: shortText.nullish(),
26790
+ pausedAt: shortText2.nullish(),
25818
26791
  why: text5.nullish(),
25819
26792
  revisitAt: name.nullish()
25820
26793
  }).strict();
25821
26794
  var runNextStepsSchema = object({
25822
- items: array(shortText.pipe(string2().min(1))).max(3),
26795
+ items: array(shortText2.pipe(string2().min(1))).max(3),
25823
26796
  pinned: boolean3().default(false),
25824
26797
  note: text5.nullish()
25825
26798
  }).strict();
25826
26799
  var runChoiceSchema = object({
25827
26800
  ref: ref.nullish(),
25828
26801
  title: name,
25829
- place: shortText.nullish(),
26802
+ place: shortText2.nullish(),
25830
26803
  status: _enum2(["made", "planned"]).default("made"),
25831
- options: array(shortText).max(6).optional(),
26804
+ options: array(shortText2).max(6).optional(),
25832
26805
  why: text5.nullish(),
25833
26806
  consequence: text5.nullish(),
25834
26807
  revisitAt: name.nullish(),
@@ -25840,9 +26813,9 @@ var runHomeSchema = object({
25840
26813
  ref: ref.nullish(),
25841
26814
  name,
25842
26815
  role: _enum2(["home", "collector", "storage", "planned", "later"]).default("home"),
25843
- place: shortText.nullish(),
26816
+ place: shortText2.nullish(),
25844
26817
  upgrades: array(object({ name, done: boolean3().default(false) }).strict()).max(40).optional(),
25845
- steward: shortText.nullish(),
26818
+ steward: shortText2.nullish(),
25846
26819
  note: text5.nullish()
25847
26820
  }).strict();
25848
26821
  var runPersonSchema = object({
@@ -25850,7 +26823,7 @@ var runPersonSchema = object({
25850
26823
  name,
25851
26824
  role: _enum2(["child", "spouse", "steward", "follower", "pet", "rival", "other"]),
25852
26825
  status: _enum2(["with", "planned", "lost"]).default("with"),
25853
- home: shortText.nullish(),
26826
+ home: shortText2.nullish(),
25854
26827
  note: text5.nullish()
25855
26828
  }).strict();
25856
26829
  var runMountSchema = object({
@@ -25862,46 +26835,46 @@ var runUniqueSchema = object({
25862
26835
  ref: ref.nullish(),
25863
26836
  name,
25864
26837
  status: _enum2(["have", "now", "want"]).default("have"),
25865
- source: shortText.nullish(),
25866
- displayAt: shortText.nullish(),
26838
+ source: shortText2.nullish(),
26839
+ displayAt: shortText2.nullish(),
25867
26840
  set: name.nullish()
25868
26841
  }).strict();
25869
26842
  var runChecklistSchema = object({
25870
26843
  key: string2().trim().min(1).max(60).regex(/^[a-z0-9][a-z0-9_-]*$/, "must be a lowercase slug"),
25871
26844
  label: name,
25872
26845
  total: number2().int().min(0).max(5000).nullish(),
25873
- items: array(object({ id: ref, label: shortText.nullish() }).strict()).max(5000).optional(),
26846
+ items: array(object({ id: ref, label: shortText2.nullish() }).strict()).max(5000).optional(),
25874
26847
  done: array(ref).max(5000),
25875
- notes: record(ref, shortText).optional(),
26848
+ notes: record(ref, shortText2).optional(),
25876
26849
  carrying: array(ref).max(5000).optional(),
25877
- legend: shortText.nullish()
26850
+ legend: shortText2.nullish()
25878
26851
  }).strict();
25879
26852
  var runTeamMemberSchema = object({
25880
26853
  species: name,
25881
- nick: shortText.nullish(),
26854
+ nick: shortText2.nullish(),
25882
26855
  level: number2().int().min(1).max(100).nullish(),
25883
- nature: shortText.nullish(),
25884
- types: array(shortText).max(2).optional(),
25885
- moves: array(shortText).max(4).optional(),
26856
+ nature: shortText2.nullish(),
26857
+ types: array(shortText2).max(2).optional(),
26858
+ moves: array(shortText2).max(4).optional(),
25886
26859
  hp: number2().int().min(0).max(100).nullish(),
25887
- note: shortText.nullish(),
26860
+ note: shortText2.nullish(),
25888
26861
  status: _enum2(["team", "plan", "boxed"]).default("team")
25889
26862
  }).strict();
25890
26863
  var runAchievementsSchema = object({
25891
26864
  source: _enum2(["steam", "xbox", "psn", "manual"]).default("manual"),
25892
26865
  total: number2().int().min(0).max(5000).nullish(),
25893
26866
  enabled: boolean3().default(true),
25894
- unlocked: array(object({ name, on: isoDate.nullish(), hint: shortText.nullish(), key: ref.nullish() }).strict()).max(5000),
25895
- locked: array(object({ name, hint: shortText.nullish(), key: ref.nullish() }).strict()).max(5000).optional(),
26867
+ unlocked: array(object({ name, on: isoDate.nullish(), hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000),
26868
+ locked: array(object({ name, hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000).optional(),
25896
26869
  syncedAt: string2().datetime({ offset: true }).nullish()
25897
26870
  }).strict();
25898
26871
  var runRareFindsSchema = object({
25899
- place: shortText.nullish(),
25900
- items: array(shortText).max(200),
26872
+ place: shortText2.nullish(),
26873
+ items: array(shortText2).max(200),
25901
26874
  note: text5.nullish()
25902
26875
  }).strict();
25903
26876
  var runInstallSchema = object({
25904
- edition: shortText.nullish(),
26877
+ edition: shortText2.nullish(),
25905
26878
  mods: array(object({ name, url: string2().url().max(2000).nullish() }).strict()).max(200).default([]),
25906
26879
  savePath: string2().trim().max(500).nullish(),
25907
26880
  lastBackup: isoDate.nullish(),
@@ -25910,22 +26883,22 @@ var runInstallSchema = object({
25910
26883
  var SAVE_SCREENSHOT_MAX_BASE64 = 1500000;
25911
26884
  var runSaveFields = {
25912
26885
  game: _enum2(["skyrim"]).default("skyrim"),
25913
- fileName: shortText.nullish(),
26886
+ fileName: shortText2.nullish(),
25914
26887
  saveNumber: number2().int().min(0).max(1e9),
25915
26888
  playerName: name,
25916
26889
  level: number2().int().min(0).max(1e4),
25917
- location: shortText,
25918
- race: shortText.nullish(),
26890
+ location: shortText2,
26891
+ race: shortText2.nullish(),
25919
26892
  sex: _enum2(["male", "female"]).nullish(),
25920
26893
  playTimeMinutes: number2().int().min(0).max(1e4 * 60).nullish(),
25921
26894
  savedAt: string2().datetime({ offset: true }).nullish(),
25922
26895
  gameDate: object({
25923
- text: shortText.pipe(string2().min(1)),
26896
+ text: shortText2.pipe(string2().min(1)),
25924
26897
  hour: number2().min(0).max(24).nullish(),
25925
26898
  daysPassed: number2().min(0).max(1e6).nullish()
25926
26899
  }).strict().nullish(),
25927
- plugins: array(shortText).max(600).optional(),
25928
- stats: record(shortText, number2().int()).refine((r) => Object.keys(r).length <= 300, "at most 300 stats").optional()
26900
+ plugins: array(shortText2).max(600).optional(),
26901
+ stats: record(shortText2, number2().int()).refine((r) => Object.keys(r).length <= 300, "at most 300 stats").optional()
25929
26902
  };
25930
26903
  var runSaveSchema = object({
25931
26904
  ...runSaveFields,
@@ -25938,9 +26911,9 @@ var uploadRunSaveHeaderInputSchema = object({
25938
26911
  }).strict();
25939
26912
  var runFacetSchema = object({
25940
26913
  theme: runThemeSchema.default("generic"),
25941
- edition: shortText.nullish(),
25942
- platform: shortText.nullish(),
25943
- modeFlags: array(shortText).max(20).optional(),
26914
+ edition: shortText2.nullish(),
26915
+ platform: shortText2.nullish(),
26916
+ modeFlags: array(shortText2).max(20).optional(),
25944
26917
  character: runCharacterSchema.nullish(),
25945
26918
  arc: runArcSchema.nullish(),
25946
26919
  orderOfPlay: array(runOrderStepSchema).max(200).optional(),
@@ -25957,7 +26930,7 @@ var runFacetSchema = object({
25957
26930
  rareFinds: runRareFindsSchema.nullish(),
25958
26931
  install: runInstallSchema.nullish(),
25959
26932
  save: runSaveSchema.nullish(),
25960
- money: object({ goal: shortText.nullish(), purpose: shortText.nullish() }).strict().nullish(),
26933
+ money: object({ goal: shortText2.nullish(), purpose: shortText2.nullish() }).strict().nullish(),
25961
26934
  links: array(object({ label: name, url: string2().url().max(2000) }).strict()).max(50).optional()
25962
26935
  }).strict();
25963
26936
  var runListSectionValues = [
@@ -26145,569 +27118,6 @@ var steamSyncResultSchema = object({
26145
27118
  games: array(steamGameSyncSchema)
26146
27119
  });
26147
27120
 
26148
- // ../../packages/schema/src/contracts/animals.ts
26149
- var animalFormSchema = _enum2(animalForm.enumValues);
26150
- var animalStatusSchema = _enum2(animalStatus.enumValues);
26151
- var animalAcquiredHowSchema = _enum2(animalAcquiredHow.enumValues);
26152
- var animalSexSchema = _enum2(animalSex.enumValues);
26153
- var animalBreedingSchema = _enum2(animalBreeding.enumValues);
26154
- var animalClassSchema = _enum2(animalClass.enumValues);
26155
- var animalLegalSchema = _enum2(animalLegal.enumValues);
26156
- var animalBornOnSchema = string2().regex(/^\d{4}(-(0[1-9]|1[0-2])(-(0[1-9]|[12]\d|3[01]))?)?$/, "expected YYYY, YYYY-MM or YYYY-MM-DD");
26157
- var animalIdsSchema = object({
26158
- chipNoMasked: string2().trim().min(1).max(40).optional(),
26159
- passportNoMasked: string2().trim().min(1).max(40).optional(),
26160
- ringNo: string2().trim().min(1).max(40).optional(),
26161
- ringYear: number2().int().min(1900).max(2200).optional(),
26162
- ringIssuer: string2().trim().min(1).max(80).optional(),
26163
- ringType: _enum2(["open", "closed"]).optional()
26164
- }).strict();
26165
- function isMaskedNumber(value) {
26166
- const shown = value.replace(/[\s*\u2022xX.-]/g, "");
26167
- return shown.length <= 4 && shown.length < value.replace(/\s/g, "").length;
26168
- }
26169
- var maskedIdsSchema = animalIdsSchema.superRefine((ids, ctx) => {
26170
- for (const key of ["chipNoMasked", "passportNoMasked"]) {
26171
- const v = ids[key];
26172
- if (v && !isMaskedNumber(v)) {
26173
- ctx.addIssue({
26174
- code: "custom",
26175
- path: [key],
26176
- message: "mask all but the last four characters (e.g. ***********1234)"
26177
- });
26178
- }
26179
- }
26180
- });
26181
- var animalScheduleStepSchema = object({
26182
- key: string2().trim().min(1).max(40),
26183
- label: string2().trim().min(1).max(120),
26184
- everyMonths: number2().int().min(1).max(120)
26185
- }).strict();
26186
- var animalSpeciesSchema = createSelectSchema(animalSpecies, {
26187
- incompatibleWith: array(string2()),
26188
- defaultSchedule: array(animalScheduleStepSchema),
26189
- createdAt: exports_coerce.date()
26190
- });
26191
- var speciesKeySchema = string2().regex(/^[a-z][a-z0-9_]{1,39}$/, "a lowercase slug, e.g. hermann_tortoise");
26192
- var createAnimalSpeciesInputSchema = object({
26193
- id: ulidSchema,
26194
- key: speciesKeySchema,
26195
- commonName: string2().trim().min(1).max(120),
26196
- commonNameNl: string2().trim().min(1).max(120).nullish(),
26197
- latin: string2().trim().min(1).max(120).nullish(),
26198
- class: animalClassSchema.optional(),
26199
- legal: animalLegalSchema.optional(),
26200
- hibernates: boolean3().optional(),
26201
- defaultForm: animalFormSchema.optional(),
26202
- minGroupSize: number2().int().min(1).max(1000).nullish(),
26203
- incompatibleWith: array(speciesKeySchema).max(20).optional(),
26204
- defaultSchedule: array(animalScheduleStepSchema).max(20).optional(),
26205
- careSheetMd: string2().trim().min(1).max(20000).nullish()
26206
- }).strict();
26207
- var updateAnimalSpeciesInputSchema = createAnimalSpeciesInputSchema.omit({ id: true, key: true }).partial().strict();
26208
- var DEWORM = {
26209
- key: "deworm",
26210
- label: "Deworm",
26211
- everyMonths: 3
26212
- };
26213
- var BOOSTER = { key: "booster", label: "Yearly booster", everyMonths: 12 };
26214
- var NATIVE_FINCH = {
26215
- class: "bird",
26216
- legal: "native_closed_ring"
26217
- };
26218
- var EXOTIC_FINCH = {
26219
- class: "bird",
26220
- legal: "none",
26221
- defaultForm: "group",
26222
- minGroupSize: 2
26223
- };
26224
- var ANIMAL_SPECIES_SEED = [
26225
- {
26226
- key: "dog",
26227
- commonName: "Dog",
26228
- commonNameNl: "Hond",
26229
- latin: "Canis familiaris",
26230
- class: "mammal",
26231
- legal: "dog_id",
26232
- defaultSchedule: [DEWORM, BOOSTER]
26233
- },
26234
- {
26235
- key: "cat",
26236
- commonName: "Cat",
26237
- commonNameNl: "Kat",
26238
- latin: "Felis catus",
26239
- class: "mammal",
26240
- legal: "cat_id",
26241
- defaultSchedule: [DEWORM, BOOSTER]
26242
- },
26243
- {
26244
- key: "chicken",
26245
- commonName: "Chicken",
26246
- commonNameNl: "Kip",
26247
- latin: "Gallus gallus domesticus",
26248
- class: "bird",
26249
- defaultForm: "group",
26250
- minGroupSize: 3,
26251
- defaultSchedule: [
26252
- { key: "mite_check", label: "Mite check", everyMonths: 1 },
26253
- { key: "deworm", label: "Deworm", everyMonths: 6 }
26254
- ]
26255
- },
26256
- {
26257
- key: "duck",
26258
- commonName: "Duck",
26259
- commonNameNl: "Eend",
26260
- latin: "Anas platyrhynchos domesticus",
26261
- class: "bird",
26262
- defaultForm: "group",
26263
- minGroupSize: 2
26264
- },
26265
- {
26266
- key: "quail",
26267
- commonName: "Quail",
26268
- commonNameNl: "Kwartel",
26269
- latin: "Coturnix japonica",
26270
- class: "bird",
26271
- defaultForm: "group",
26272
- minGroupSize: 3
26273
- },
26274
- {
26275
- key: "hermann_tortoise",
26276
- commonName: "Hermann's tortoise",
26277
- commonNameNl: "Griekse landschildpad",
26278
- latin: "Testudo hermanni",
26279
- class: "reptile",
26280
- legal: "cites_a",
26281
- hibernates: true,
26282
- defaultSchedule: [{ key: "health_check", label: "Health check", everyMonths: 12 }]
26283
- },
26284
- {
26285
- key: "zebra_finch",
26286
- commonName: "Zebra finch",
26287
- commonNameNl: "Zebravink",
26288
- latin: "Taeniopygia guttata",
26289
- ...EXOTIC_FINCH
26290
- },
26291
- {
26292
- key: "bengalese_finch",
26293
- commonName: "Bengalese finch",
26294
- commonNameNl: "Japans meeuwtje",
26295
- latin: "Lonchura striata domestica",
26296
- ...EXOTIC_FINCH
26297
- },
26298
- {
26299
- key: "star_finch",
26300
- commonName: "Star finch",
26301
- commonNameNl: "Binsenastrild",
26302
- latin: "Bathilda ruficauda",
26303
- ...EXOTIC_FINCH
26304
- },
26305
- {
26306
- key: "diamond_dove",
26307
- commonName: "Diamond dove",
26308
- commonNameNl: "Diamantduif",
26309
- latin: "Geopelia cuneata",
26310
- ...EXOTIC_FINCH
26311
- },
26312
- {
26313
- key: "bullfinch",
26314
- commonName: "Eurasian bullfinch",
26315
- commonNameNl: "Goudvink",
26316
- latin: "Pyrrhula pyrrhula",
26317
- ...NATIVE_FINCH
26318
- },
26319
- {
26320
- key: "bearded_reedling",
26321
- commonName: "Bearded reedling",
26322
- commonNameNl: "Baardmannetje",
26323
- latin: "Panurus biarmicus",
26324
- ...NATIVE_FINCH
26325
- },
26326
- {
26327
- key: "siskin",
26328
- commonName: "Eurasian siskin",
26329
- commonNameNl: "Sijs",
26330
- latin: "Spinus spinus",
26331
- ...NATIVE_FINCH
26332
- },
26333
- {
26334
- key: "goldfinch",
26335
- commonName: "European goldfinch",
26336
- commonNameNl: "Putter",
26337
- latin: "Carduelis carduelis",
26338
- ...NATIVE_FINCH
26339
- },
26340
- {
26341
- key: "linnet",
26342
- commonName: "Common linnet",
26343
- commonNameNl: "Kneu",
26344
- latin: "Linaria cannabina",
26345
- ...NATIVE_FINCH
26346
- },
26347
- {
26348
- key: "rabbit",
26349
- commonName: "Rabbit",
26350
- commonNameNl: "Konijn",
26351
- latin: "Oryctolagus cuniculus",
26352
- class: "mammal",
26353
- defaultForm: "group",
26354
- minGroupSize: 2,
26355
- incompatibleWith: ["guinea_pig"],
26356
- defaultSchedule: [{ key: "vaccine", label: "Myxo/RHD vaccine", everyMonths: 12 }]
26357
- },
26358
- {
26359
- key: "guinea_pig",
26360
- commonName: "Guinea pig",
26361
- commonNameNl: "Cavia",
26362
- latin: "Cavia porcellus",
26363
- class: "mammal",
26364
- defaultForm: "group",
26365
- minGroupSize: 2,
26366
- incompatibleWith: ["rabbit"]
26367
- }
26368
- ];
26369
- var animalSchema = createSelectSchema(animals, {
26370
- ids: animalIdsSchema
26371
- });
26372
- var animalSpeciesRefSchema = object({
26373
- id: ulidSchema,
26374
- key: string2(),
26375
- commonName: string2(),
26376
- latin: string2().nullable(),
26377
- class: animalClassSchema,
26378
- legal: animalLegalSchema,
26379
- hibernates: boolean3()
26380
- });
26381
- var animalViewSchema = animalSchema.extend({
26382
- title: string2(),
26383
- parentId: ulidSchema.nullable(),
26384
- species: animalSpeciesRefSchema.nullable(),
26385
- memberCount: number2().int(),
26386
- heads: number2().int(),
26387
- createdAt: exports_coerce.date(),
26388
- updatedAt: exports_coerce.date()
26389
- });
26390
- var nodeRefSchema = object({ id: ulidSchema, title: string2() });
26391
- var animalHabitSchema = nodeRefSchema.extend({ doneToday: boolean3() });
26392
- var animalSupplySchema = nodeRefSchema.extend({
26393
- quantity: number2(),
26394
- unit: string2().nullable(),
26395
- lowStock: boolean3(),
26396
- dailyUse: number2().nullable(),
26397
- perHead: boolean3(),
26398
- daysLeft: number2().int().nullable(),
26399
- full: number2().nullable(),
26400
- onList: string2().nullable()
26401
- });
26402
- var animalDayCountSchema = object({ day: string2(), count: number2().int() });
26403
- var animalWeightPointSchema = object({
26404
- day: string2(),
26405
- grams: number2(),
26406
- at: exports_coerce.date()
26407
- });
26408
- var animalFileSchema = object({
26409
- id: ulidSchema,
26410
- name: string2(),
26411
- mime: string2(),
26412
- size: number2().int(),
26413
- createdAt: exports_coerce.date()
26414
- });
26415
- var animalVetSchema = nodeRefSchema.extend({ role: string2().nullable() });
26416
- var animalPaperSchema = nodeRefSchema.extend({
26417
- status: _enum2(documentStatus.enumValues),
26418
- reference: string2().nullable()
26419
- });
26420
- var animalLinksSchema = object({
26421
- place: nodeRefSchema.nullable(),
26422
- vets: array(animalVetSchema),
26423
- cameFrom: nodeRefSchema.nullable(),
26424
- habits: array(animalHabitSchema),
26425
- supplies: array(animalSupplySchema),
26426
- papers: array(animalPaperSchema),
26427
- files: array(animalFileSchema),
26428
- healthVisits: object({ count: number2().int(), lastAt: exports_coerce.date().nullable() }),
26429
- assets: array(nodeRefSchema.extend({ location: string2().nullable() })),
26430
- companions: array(nodeRefSchema)
26431
- });
26432
- var animalPapersCheckSchema = object({
26433
- needed: string2(),
26434
- onFile: boolean3()
26435
- });
26436
- var animalMemberSchema = animalViewSchema.extend({
26437
- papersCheck: animalPapersCheckSchema.nullable()
26438
- });
26439
- var SHED_READING_TYPES = {
26440
- temp: "shed.temp",
26441
- heater: "shed.heater",
26442
- water: "shed.water_pct",
26443
- door: "shed.door",
26444
- feeder: "shed.feed_kg",
26445
- light: "shed.light"
26446
- };
26447
- var animalRoomReadingSchema = object({
26448
- kind: _enum2(Object.keys(SHED_READING_TYPES)),
26449
- value: number2().nullable(),
26450
- unit: string2().nullable(),
26451
- text: string2().nullable(),
26452
- detail: string2().nullish(),
26453
- device: string2().nullish(),
26454
- at: exports_coerce.date()
26455
- });
26456
- var animalRoomAlertSchema = object({
26457
- id: string2(),
26458
- at: exports_coerce.date(),
26459
- text: string2(),
26460
- detail: string2().nullable(),
26461
- source: _enum2(["camera", "power", "other"])
26462
- });
26463
- var animalRoomSchema = object({
26464
- place: nodeRefSchema,
26465
- readings: array(animalRoomReadingSchema),
26466
- temperature24h: array(object({ at: exports_coerce.date(), value: number2() })),
26467
- alerts: array(animalRoomAlertSchema)
26468
- });
26469
- var animalDetailSchema = animalViewSchema.extend({
26470
- group: nodeRefSchema.nullable(),
26471
- members: array(animalMemberSchema),
26472
- links: animalLinksSchema,
26473
- weights: array(animalWeightPointSchema),
26474
- latestLength: object({ mm: number2(), at: exports_coerce.date() }).nullable(),
26475
- eggs: array(animalDayCountSchema),
26476
- periods: array(periodViewSchema),
26477
- keyDates: array(keyDateViewSchema),
26478
- papersCheck: animalPapersCheckSchema.nullable(),
26479
- room: animalRoomSchema.nullable()
26480
- });
26481
- var titleSchema2 = string2().trim().min(1).max(120);
26482
- var shortText2 = (max) => string2().trim().min(1).max(max);
26483
- var idList = array(ulidSchema).max(20);
26484
- var animalFieldsSchema = object({
26485
- title: titleSchema2,
26486
- form: animalFormSchema,
26487
- speciesId: ulidSchema.nullish(),
26488
- speciesKey: speciesKeySchema,
26489
- breed: shortText2(120).nullish(),
26490
- sex: animalSexSchema.nullish(),
26491
- bornOn: animalBornOnSchema.nullish(),
26492
- bornApprox: boolean3(),
26493
- acquiredOn: keyDateDaySchema.nullish(),
26494
- acquiredHow: animalAcquiredHowSchema.nullish(),
26495
- status: animalStatusSchema,
26496
- endedOn: keyDateDaySchema.nullish(),
26497
- endNote: shortText2(500).nullish(),
26498
- headCount: number2().int().min(0).max(1e4).nullish(),
26499
- ids: maskedIdsSchema,
26500
- markings: shortText2(200).nullish(),
26501
- breeding: animalBreedingSchema,
26502
- groupId: ulidSchema.nullish(),
26503
- areaId: ulidSchema.nullish(),
26504
- placeId: ulidSchema.nullish(),
26505
- vetIds: idList,
26506
- cameFromId: ulidSchema.nullish(),
26507
- habitIds: idList,
26508
- supplyIds: idList,
26509
- paperIds: idList,
26510
- assetIds: idList
26511
- });
26512
- var createAnimalInputSchema = animalFieldsSchema.partial().required({ title: true }).extend({ id: ulidSchema }).strict();
26513
- var updateAnimalInputSchema = animalFieldsSchema.partial().strict();
26514
- var animalsQuerySchema = object({
26515
- status: animalStatusSchema.optional(),
26516
- form: animalFormSchema.optional(),
26517
- groupId: ulidSchema.optional(),
26518
- includeEnded: _enum2(["true", "false"]).transform((v) => v === "true").optional()
26519
- });
26520
- var occurredAtSchema = exports_coerce.date().optional();
26521
- var animalLogInputSchema = discriminatedUnion("kind", [
26522
- object({
26523
- kind: literal("weight"),
26524
- value: number2().positive().max(200000),
26525
- unit: _enum2(["g", "kg"]).default("g"),
26526
- occurredAt: occurredAtSchema
26527
- }).strict(),
26528
- object({
26529
- kind: literal("length"),
26530
- value: number2().positive().max(5000),
26531
- occurredAt: occurredAtSchema
26532
- }).strict(),
26533
- object({
26534
- kind: literal("eggs"),
26535
- count: number2().int().min(0).max(500),
26536
- occurredAt: occurredAtSchema
26537
- }).strict(),
26538
- object({
26539
- kind: literal("note"),
26540
- text: string2().trim().min(1).max(1000),
26541
- occurredAt: occurredAtSchema
26542
- }).strict()
26543
- ]);
26544
- var animalVetVisitSourceSchema = _enum2(["sticker", "photo", "said"]);
26545
- var visitTextSchema = string2().trim().min(1).max(120);
26546
- var visitCostSchema = object({
26547
- amount: number2().positive().max(1e5),
26548
- currency: string2().trim().length(3).default("EUR")
26549
- }).strict();
26550
- var animalVetVisitInputSchema = object({
26551
- id: ulidSchema,
26552
- at: exports_coerce.date().optional(),
26553
- vetContactId: ulidSchema.optional(),
26554
- clinician: visitTextSchema.optional(),
26555
- reason: visitTextSchema.optional(),
26556
- vaccine: object({ name: visitTextSchema, source: animalVetVisitSourceSchema.optional() }).strict().optional(),
26557
- dewormer: visitTextSchema.optional(),
26558
- weight: object({
26559
- value: number2().positive().max(200000),
26560
- unit: _enum2(["g", "kg"]).default("kg")
26561
- }).strict().optional(),
26562
- nextDates: array(object({
26563
- id: ulidSchema,
26564
- label: visitTextSchema,
26565
- date: string2().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD")
26566
- }).strict()).max(5).default([]),
26567
- files: array(object({ id: ulidSchema, name: visitTextSchema.optional() }).strict()).max(5).default([]),
26568
- cost: visitCostSchema.optional()
26569
- }).strict();
26570
- var animalVetVisitPatchSchema = object({
26571
- vetContactId: ulidSchema.nullable().optional(),
26572
- clinician: visitTextSchema.nullable().optional(),
26573
- reason: visitTextSchema.nullable().optional(),
26574
- vaccine: object({ name: visitTextSchema, source: animalVetVisitSourceSchema.optional() }).strict().nullable().optional(),
26575
- dewormer: visitTextSchema.nullable().optional(),
26576
- cost: visitCostSchema.nullable().optional()
26577
- }).strict().refine((v) => Object.keys(v).length > 0, { message: "Change at least one field." });
26578
- var animalVetVisitSchema = object({
26579
- id: ulidSchema,
26580
- animal: object({
26581
- id: ulidSchema,
26582
- title: string2(),
26583
- speciesKey: string2().nullable(),
26584
- speciesClass: animalClassSchema.nullable()
26585
- }),
26586
- at: exports_coerce.date(),
26587
- vet: nodeRefSchema.nullable(),
26588
- clinician: string2().nullable(),
26589
- reason: string2().nullable(),
26590
- vaccine: object({ name: string2(), source: animalVetVisitSourceSchema.nullable() }).nullable(),
26591
- dewormer: string2().nullable(),
26592
- weight: object({
26593
- grams: number2(),
26594
- deltaGrams: number2().nullable(),
26595
- since: string2().nullable()
26596
- }).nullable(),
26597
- keyDates: array(object({ id: string2(), label: string2(), date: string2() })),
26598
- files: array(object({ id: string2(), name: string2() })),
26599
- cost: object({ amount: number2(), currency: string2() }).nullable(),
26600
- byAgent: boolean3(),
26601
- undone: boolean3()
26602
- });
26603
- var animalTimelineEntrySchema = object({
26604
- id: string2(),
26605
- at: exports_coerce.date(),
26606
- kind: _enum2([
26607
- "weight",
26608
- "length",
26609
- "eggs",
26610
- "note",
26611
- "vet_visit",
26612
- "period_started",
26613
- "period_ended",
26614
- "key_date"
26615
- ]),
26616
- animalId: ulidSchema,
26617
- animalTitle: string2(),
26618
- value: number2().nullable(),
26619
- text: string2().nullable(),
26620
- byAgent: boolean3().default(false)
26621
- });
26622
- var animalTimelineQuerySchema = object({
26623
- days: exports_coerce.number().int().min(1).max(3650).default(90)
26624
- });
26625
- var animalEggsTodaySchema = object({
26626
- animalId: ulidSchema,
26627
- title: string2(),
26628
- today: number2().int(),
26629
- heads: number2().int(),
26630
- last7: array(animalDayCountSchema)
26631
- });
26632
- var animalsOverviewSchema = object({
26633
- animals: array(animalViewSchema),
26634
- today: object({
26635
- day: string2(),
26636
- eggs: array(animalEggsTodaySchema),
26637
- supplies: array(animalSupplySchema),
26638
- habits: array(animalHabitSchema)
26639
- }),
26640
- comingUp: array(keyDateViewSchema.extend({ vet: string2().nullable() })),
26641
- periods: array(periodViewSchema)
26642
- });
26643
- var animalHolidayModeSchema = object({
26644
- popHole: boolean3(),
26645
- heater: boolean3(),
26646
- alerts: boolean3(),
26647
- dailyPhoto: boolean3(),
26648
- feedReorder: boolean3()
26649
- });
26650
- var animalHandoverRuleSchema = object({
26651
- sitter: string2().trim().min(1).max(120).optional(),
26652
- houseNote: string2().trim().min(1).max(300).optional(),
26653
- holidayMode: animalHolidayModeSchema.partial().optional(),
26654
- share: object({ tokenHash: string2(), until: string2() }).optional(),
26655
- agentNote: string2().trim().min(1).max(500).optional()
26656
- }).passthrough();
26657
- var animalHandoverQuerySchema = object({ periodId: ulidSchema.optional() });
26658
- var animalHandoverTripSchema = object({
26659
- periodId: ulidSchema.nullable(),
26660
- title: string2(),
26661
- from: string2(),
26662
- to: string2(),
26663
- sitter: string2().nullable(),
26664
- houseNote: string2().nullable(),
26665
- holidayMode: animalHolidayModeSchema,
26666
- sharedUntil: string2().nullable(),
26667
- agentNote: string2().nullable(),
26668
- calendar: string2().nullable()
26669
- });
26670
- var animalHandoverAnimalSchema = object({
26671
- id: ulidSchema,
26672
- title: string2(),
26673
- form: animalFormSchema,
26674
- heads: number2().int(),
26675
- species: string2().nullable(),
26676
- speciesKey: string2().nullable(),
26677
- speciesClass: animalClassSchema.nullable(),
26678
- asleep: boolean3(),
26679
- steps: array(string2()),
26680
- aside: string2().nullable()
26681
- });
26682
- var animalHandoverContactSchema = object({
26683
- id: ulidSchema,
26684
- title: string2(),
26685
- kind: _enum2(["vet", "member"]),
26686
- label: string2().nullable(),
26687
- phone: string2().nullable()
26688
- });
26689
- var animalHandoverSupplySchema = animalSupplySchema.extend({
26690
- lastsTrip: boolean3().nullable()
26691
- });
26692
- var animalHandoverHabitSchema = nodeRefSchema.extend({ restsThroughTrip: boolean3() });
26693
- var animalHandoverSchema = object({
26694
- trip: animalHandoverTripSchema.nullable(),
26695
- areaId: ulidSchema.nullable(),
26696
- animals: array(animalHandoverAnimalSchema),
26697
- contacts: array(animalHandoverContactSchema),
26698
- supplies: array(animalHandoverSupplySchema),
26699
- habits: array(animalHandoverHabitSchema),
26700
- sensors: boolean3(),
26701
- generatedAt: exports_coerce.date()
26702
- });
26703
- var animalHolidayModeInputSchema = animalHolidayModeSchema.partial().extend({ periodId: ulidSchema }).strict().refine((v) => Object.keys(v).length > 1, { message: "Turn at least one switch." });
26704
- var animalHandoverShareInputSchema = object({ periodId: ulidSchema }).strict();
26705
- var animalHandoverShareSchema = object({
26706
- token: string2(),
26707
- path: string2(),
26708
- until: string2()
26709
- });
26710
-
26711
27121
  // ../../packages/schema/src/contracts/money-splits.ts
26712
27122
  var moneyPartySchema = union([
26713
27123
  object({ userId: ulidSchema }).strict(),
@@ -27039,6 +27449,7 @@ var householdAddressSchema = object({
27039
27449
  var householdRowSchema = createSelectSchema(households, {
27040
27450
  address: householdAddressSchema.nullable(),
27041
27451
  group: boolean3().default(false),
27452
+ addressConfirmedAt: exports_coerce.date().nullable(),
27042
27453
  createdAt: exports_coerce.date(),
27043
27454
  updatedAt: exports_coerce.date()
27044
27455
  });
@@ -27066,6 +27477,7 @@ var guestListSchema = createSelectSchema(guestLists, {
27066
27477
  var guestListViewSchema = guestListSchema.extend({
27067
27478
  projectTitle: string2(),
27068
27479
  rsvpBy: keyDateDaySchema.nullable(),
27480
+ finalInfoFrom: keyDateDaySchema.nullable().default(null),
27069
27481
  projectDay: keyDateDaySchema.nullable().default(null)
27070
27482
  });
27071
27483
  var createGuestListInputSchema = object({
@@ -27074,7 +27486,8 @@ var createGuestListInputSchema = object({
27074
27486
  tiers: array(guestTierSchema).min(1).max(6).optional(),
27075
27487
  caps: capsSchema.optional(),
27076
27488
  sides: array(sideSchema).max(4).optional(),
27077
- rsvpBy: keyDateDaySchema.nullish()
27489
+ rsvpBy: keyDateDaySchema.nullish(),
27490
+ finalInfoFrom: keyDateDaySchema.nullish()
27078
27491
  }).strict();
27079
27492
  var updateGuestListInputSchema = createGuestListInputSchema.omit({ id: true, projectId: true }).partial().strict();
27080
27493
  var guestListsQuerySchema = object({ projectId: ulidSchema.optional() });
@@ -27146,6 +27559,7 @@ var guestListOverviewSchema = object({
27146
27559
  householdId: ulidSchema.nullable(),
27147
27560
  title: string2(),
27148
27561
  address: householdAddressSchema.nullable(),
27562
+ addressConfirmedAt: exports_coerce.date().nullable(),
27149
27563
  language: rsvpLanguageSchema,
27150
27564
  group: boolean3().default(false),
27151
27565
  guests: array(guestViewSchema)
@@ -27171,16 +27585,20 @@ var guestListOverviewSchema = object({
27171
27585
  })
27172
27586
  });
27173
27587
  var RSVP_TOKEN_RE = /^rsvp_[A-Za-z0-9_-]{43}$/;
27588
+ var RSVP_LINK_MODES = ["address", "full"];
27589
+ var rsvpLinkModeSchema = _enum2(RSVP_LINK_MODES);
27174
27590
  var rsvpLinkSchema = object({
27175
27591
  id: ulidSchema,
27176
27592
  guestListId: ulidSchema,
27177
27593
  householdId: ulidSchema,
27178
27594
  householdTitle: string2(),
27595
+ mode: rsvpLinkModeSchema,
27179
27596
  expiresAt: exports_coerce.date(),
27180
27597
  revokedAt: exports_coerce.date().nullable(),
27181
27598
  lastUsedAt: exports_coerce.date().nullable(),
27182
27599
  createdAt: exports_coerce.date(),
27183
- live: boolean3()
27600
+ live: boolean3(),
27601
+ revealable: boolean3()
27184
27602
  });
27185
27603
  var mintedRsvpLinkSchema = rsvpLinkSchema.extend({
27186
27604
  token: string2().regex(RSVP_TOKEN_RE),
@@ -27189,6 +27607,7 @@ var mintedRsvpLinkSchema = rsvpLinkSchema.extend({
27189
27607
  var createRsvpLinksInputSchema = object({
27190
27608
  guestListId: ulidSchema,
27191
27609
  householdIds: array(ulidSchema).min(1).max(500).optional(),
27610
+ mode: rsvpLinkModeSchema.optional(),
27192
27611
  expiresAt: exports_coerce.date().optional()
27193
27612
  }).strict();
27194
27613
  var rsvpLinksQuerySchema = object({ guestListId: ulidSchema });
@@ -27200,14 +27619,29 @@ var publicRsvpGuestSchema = object({
27200
27619
  rsvp: answersSchema,
27201
27620
  diet: string2().nullable(),
27202
27621
  plusOne: boolean3(),
27203
- plusOneName: string2().nullable()
27622
+ plusOneName: string2().nullable(),
27623
+ table: string2().nullable().default(null)
27624
+ }).strict();
27625
+ var publicRsvpEventSchema = object({
27626
+ key: guestTierSchema,
27627
+ name: object({ nl: string2().optional(), pt: string2().optional() }),
27628
+ startsAt: exports_coerce.date().nullable(),
27629
+ endsAt: exports_coerce.date().nullable(),
27630
+ placeName: string2().nullable(),
27631
+ address: string2().nullable(),
27632
+ mapUrl: string2().nullable(),
27633
+ dressCode: object({ nl: string2().optional(), pt: string2().optional() }).nullable(),
27634
+ note: object({ nl: string2().optional(), pt: string2().optional() }).nullable()
27204
27635
  }).strict();
27205
27636
  var publicRsvpViewSchema = object({
27637
+ mode: rsvpLinkModeSchema,
27206
27638
  language: rsvpLanguageSchema,
27207
27639
  event: string2(),
27208
27640
  household: string2(),
27209
27641
  rsvpBy: keyDateDaySchema.nullable(),
27642
+ finalInfoFrom: keyDateDaySchema.nullable().default(null),
27210
27643
  tiers: array(guestTierSchema),
27644
+ events: array(publicRsvpEventSchema).default([]),
27211
27645
  guests: array(publicRsvpGuestSchema),
27212
27646
  address: householdAddressSchema.nullable(),
27213
27647
  answeredAt: exports_coerce.date().nullable()
@@ -27219,9 +27653,12 @@ var submitRsvpInputSchema = object({
27219
27653
  diet: string2().trim().max(200).nullish(),
27220
27654
  plusOneName: string2().trim().max(120).nullish(),
27221
27655
  email: string2().trim().email().max(254).nullish()
27222
- }).strict()).min(1).max(30),
27223
- address: householdAddressSchema.nullish()
27224
- }).strict();
27656
+ }).strict()).max(30).default([]),
27657
+ address: householdAddressSchema.nullish(),
27658
+ language: rsvpLanguageSchema.optional()
27659
+ }).strict().refine((i) => i.guests.length > 0 || !!i.address || !!i.language, {
27660
+ message: "nothing to send: answers, an address or a language"
27661
+ });
27225
27662
  var eventTextSchema = (max) => object({
27226
27663
  nl: string2().trim().min(1).max(max).optional(),
27227
27664
  pt: string2().trim().min(1).max(max).optional()
@@ -27584,6 +28021,99 @@ var rsvpAnswersQuerySchema = object({
27584
28021
  householdId: ulidSchema.optional()
27585
28022
  });
27586
28023
 
28024
+ // ../../packages/schema/src/contracts/google-contacts.ts
28025
+ var googleContactsModeSchema = _enum2(["off", "fake", "live"]);
28026
+ var googleContactsStatusSchema = object({
28027
+ available: boolean3(),
28028
+ mode: googleContactsModeSchema,
28029
+ connected: boolean3(),
28030
+ account: string2().nullable()
28031
+ });
28032
+ var googleContactsConnectResultSchema = object({
28033
+ connectionId: ulidSchema,
28034
+ authorizationUrl: string2()
28035
+ });
28036
+ var GOOGLE_CONTACT_FIELDS = ["email", "phone", "birthday"];
28037
+ var googleContactFieldSchema = _enum2(GOOGLE_CONTACT_FIELDS);
28038
+ var googleContactCandidateSchema = object({
28039
+ resourceName: string2(),
28040
+ name: string2(),
28041
+ emails: array(string2()),
28042
+ phones: array(string2()),
28043
+ birthday: object({ date: string2().regex(/^\d{4}-\d{2}-\d{2}$/), yearKnown: boolean3() }).nullable(),
28044
+ match: object({
28045
+ contactId: ulidSchema,
28046
+ title: string2(),
28047
+ by: _enum2(["email", "phone", "name"])
28048
+ }).nullable(),
28049
+ adds: array(googleContactFieldSchema)
28050
+ });
28051
+ var googleContactsQuerySchema = object({
28052
+ q: string2().trim().max(120).optional()
28053
+ });
28054
+ var googleContactsListSchema = object({
28055
+ status: googleContactsStatusSchema,
28056
+ candidates: array(googleContactCandidateSchema)
28057
+ });
28058
+ var importGoogleContactsInputSchema = object({
28059
+ resourceNames: array(string2().trim().regex(/^people\/[A-Za-z0-9_-]{1,120}$/, "a Google person id")).min(1).max(200)
28060
+ }).strict();
28061
+ var googleContactsImportResultSchema = object({
28062
+ created: array(object({ contactId: ulidSchema, title: string2() })),
28063
+ merged: array(object({
28064
+ contactId: ulidSchema,
28065
+ title: string2(),
28066
+ added: array(googleContactFieldSchema)
28067
+ })),
28068
+ missing: array(string2())
28069
+ });
28070
+
28071
+ // ../../packages/schema/src/contracts/github.ts
28072
+ var GITHUB_RESOURCES = ["commits", "pull_requests", "issues"];
28073
+ var githubResourceSchema = _enum2(GITHUB_RESOURCES);
28074
+ var githubBase = {
28075
+ repo: string2().min(1),
28076
+ url: string2().min(1)
28077
+ };
28078
+ var githubCommitValueSchema = object({
28079
+ ...githubBase,
28080
+ sha: string2().min(1),
28081
+ message: string2().default(""),
28082
+ by: _enum2(["human", "agent"]).optional(),
28083
+ agent: string2().nullish()
28084
+ }).strict();
28085
+ var githubPullRequestValueSchema = object({
28086
+ ...githubBase,
28087
+ number: number2().int().positive(),
28088
+ title: string2().default(""),
28089
+ state: string2().min(1),
28090
+ merged: boolean3().default(false)
28091
+ }).strict();
28092
+ var githubIssueValueSchema = object({
28093
+ ...githubBase,
28094
+ number: number2().int().positive(),
28095
+ title: string2().default(""),
28096
+ state: string2().min(1)
28097
+ }).strict();
28098
+ var githubCommitsQuerySchema = object({
28099
+ days: exports_coerce.number().int().refine((d) => d === 7 || d === 30, "7 or 30").default(7)
28100
+ });
28101
+ var githubCommitsDaySchema = object({
28102
+ day: string2(),
28103
+ byYou: number2().int(),
28104
+ byAgents: number2().int()
28105
+ });
28106
+ var githubCommitsSchema = object({
28107
+ days: number2().int(),
28108
+ from: string2(),
28109
+ to: string2(),
28110
+ byYou: number2().int(),
28111
+ byAgents: number2().int(),
28112
+ unsorted: number2().int(),
28113
+ agents: array(object({ name: string2(), count: number2().int() })),
28114
+ perDay: array(githubCommitsDaySchema)
28115
+ });
28116
+
27587
28117
  // ../../packages/schema/src/contracts/calendar.ts
27588
28118
  var calendarEventLinkSchema = createSelectSchema(calendarEventLinks, {
27589
28119
  createdAt: exports_coerce.date(),
@@ -29176,7 +29706,7 @@ function parseCapture2(input, now) {
29176
29706
 
29177
29707
  // src/meta.ts
29178
29708
  var CLI_NAME = "do";
29179
- var VERSION = "1.296.0";
29709
+ var VERSION = "1.298.0";
29180
29710
  var API_PREFIX = "/api/v1";
29181
29711
  var DEFAULT_API_URL = "http://localhost:3001";
29182
29712
 
@@ -30081,6 +30611,22 @@ var ENTITIES = [
30081
30611
  canDelete: true
30082
30612
  }
30083
30613
  },
30614
+ {
30615
+ name: "tap-tags",
30616
+ path: "/tap-tags",
30617
+ readScope: "habits:read",
30618
+ returns: "TapTagView",
30619
+ canGet: true,
30620
+ listFlags: [],
30621
+ write: {
30622
+ scope: "habits:write",
30623
+ createSchema: createTapTagInputSchema,
30624
+ createInput: "CreateTapTagInput",
30625
+ updateSchema: updateTapTagInputSchema,
30626
+ updateInput: "UpdateTapTagInput",
30627
+ canDelete: true
30628
+ }
30629
+ },
30084
30630
  {
30085
30631
  name: "animals",
30086
30632
  path: "/animals",
@@ -30339,7 +30885,8 @@ var HEALTH_COMMAND_SPECS = [
30339
30885
  args: [],
30340
30886
  flags: [],
30341
30887
  scopes: READ,
30342
- returns: "HealthConsentState"
30888
+ returns: "HealthConsentState",
30889
+ notes: "`granted` is on at today's consent text (`currentVersion`); `renewalNeeded` means you agreed to an older text, so writes wait until you agree again in do. `aiProvider` names who processes what the agent reads (null when this deployment names none)."
30343
30890
  },
30344
30891
  {
30345
30892
  path: ["health", "profile"],
@@ -30349,6 +30896,15 @@ var HEALTH_COMMAND_SPECS = [
30349
30896
  scopes: READ,
30350
30897
  returns: "HealthProfile"
30351
30898
  },
30899
+ {
30900
+ path: ["health", "medical-id"],
30901
+ summary: "Show your Medical ID: name, blood group, allergies, current medications, height, emergency contact.",
30902
+ args: [],
30903
+ flags: [],
30904
+ scopes: READ,
30905
+ returns: "HealthMedicalId",
30906
+ notes: "The few facts someone helping in an emergency needs. The emergency contact comes with their name and phone; a field not set is null. Each read by a key is logged for the member."
30907
+ },
30352
30908
  {
30353
30909
  path: ["health", "profile", "set"],
30354
30910
  summary: `Set profile fields (--data '{"bloodGroup":"A+"}', --notes "Kell negative").`,
@@ -31100,10 +31656,34 @@ var COMMAND_SPECS = [
31100
31656
  returns: "JournalWeek",
31101
31657
  notes: "GET /api/v1/journal/weeks/{week} \u2014 your own week only. `recap` is null until one was written. journal:read is a sensitive scope."
31102
31658
  },
31659
+ {
31660
+ path: ["journal", "month"],
31661
+ summary: "One month of the Journal: its recap, its days, the usual rating, the numbers from Progress and the milestones that happened in it.",
31662
+ args: [{ name: "month", required: true, description: "The month, e.g. 2026-10." }],
31663
+ flags: [],
31664
+ scopes: ["journal:read"],
31665
+ returns: "JournalMonth",
31666
+ notes: "GET /api/v1/journal/months/{month} \u2014 your own month only. `recap` is null until one was written; `usual` is the mean rating over the three months before. journal:read is a sensitive scope."
31667
+ },
31668
+ {
31669
+ path: ["journal", "year"],
31670
+ summary: "One year of the Journal: its recap, its days (the rating pixels), each month's average and best day, the usual, the numbers and the year's milestones.",
31671
+ args: [{ name: "year", required: true, description: "The year, e.g. 2026." }],
31672
+ flags: [],
31673
+ scopes: ["journal:read"],
31674
+ returns: "JournalYear",
31675
+ notes: "GET /api/v1/journal/years/{year} \u2014 your own year only. `recap` is null until one was written; `usual` is the mean rating of the year before. journal:read is a sensitive scope."
31676
+ },
31103
31677
  {
31104
31678
  path: ["journal", "recap"],
31105
- summary: "Write or replace a week's recap: the prose, its best moments and one pattern line.",
31106
- args: [{ name: "week", required: true, description: "The ISO week, e.g. 2026-W42." }],
31679
+ summary: "Write or replace a week's, a month's or a year's recap: the prose, its best moments and one pattern line.",
31680
+ args: [
31681
+ {
31682
+ name: "period",
31683
+ required: true,
31684
+ description: "The ISO week (2026-W42), the month (2026-10) or the year (2026)."
31685
+ }
31686
+ ],
31107
31687
  flags: [
31108
31688
  { name: "body", type: "string", description: "The recap in markdown." },
31109
31689
  {
@@ -31114,7 +31694,7 @@ var COMMAND_SPECS = [
31114
31694
  ],
31115
31695
  scopes: ["journal:write"],
31116
31696
  returns: "JournalWeek",
31117
- notes: "PUT /api/v1/journal/weeks/{week}/recap (journal_write_recap). The body replaces the prose; moments and pattern replace theirs when given (pattern null clears it). Returns the week."
31697
+ notes: "PUT /api/v1/journal/weeks/{week}/recap (journal_write_recap), /api/v1/journal/months/{month}/recap or /api/v1/journal/years/{year}/recap, by the period's shape. The body replaces the prose; moments and pattern replace theirs when given (pattern null clears it). Returns the period (a JournalWeek, JournalMonth or JournalYear)."
31118
31698
  },
31119
31699
  {
31120
31700
  path: ["journal", "write"],
@@ -31281,6 +31861,15 @@ var COMMAND_SPECS = [
31281
31861
  returns: "JournalExport",
31282
31862
  notes: "GET /api/v1/journal/export. Prints `nextSince`; pass it as --since next time. do is the record: the files are read-only copies and are overwritten."
31283
31863
  },
31864
+ {
31865
+ path: ["progress", "commits"],
31866
+ summary: "Your GitHub commits: the ones you made, and your agents' on your account.",
31867
+ args: [],
31868
+ flags: [{ name: "days", type: "string", description: "7 (default) or 30." }],
31869
+ scopes: ["habits:read"],
31870
+ returns: "GithubCommits",
31871
+ notes: "GET /api/v1/progress/commits \u2014 your own only. `byYou`, `byAgents` with `agents` by name, `unsorted` (synced before the split) and `perDay`. Only your own commits count toward Insights and a GitHub-sourced habit."
31872
+ },
31284
31873
  {
31285
31874
  path: ["progress", "questions"],
31286
31875
  summary: "Insights' answers: late nights vs the next day, the morning routine, good runs, bedtime, best days, reading.",
@@ -31978,6 +32567,15 @@ var COMMAND_SPECS = [
31978
32567
  returns: "AwayState",
31979
32568
  notes: "GET/PUT /api/v1/habits/away. While away, habits leave Now, reminders stop and plants wait; tasks and events carry on. Reading needs habits:read, setting habits:write."
31980
32569
  },
32570
+ {
32571
+ path: ["tap-tags", "tap"],
32572
+ summary: "Tap a tag as if the phone read its sticker: check its habit in, or mark today's run of its routine done.",
32573
+ args: [{ name: "id", required: true, description: "The tag id (the ULID in /t/<id>)." }],
32574
+ flags: [],
32575
+ scopes: ["habits:write", "routines:write"],
32576
+ returns: "TapResult",
32577
+ notes: "POST /api/v1/tap-tags/{id}/tap. Acts as the key's member; a second tap within 30 s does nothing (outcome already). The receipt's undo names the check-in (DELETE /habits/{habitId}/entries/{entryId}) or the run's steps (POST /routines/runs/{runId}/undo)."
32578
+ },
31981
32579
  {
31982
32580
  path: ["metrics", "list"],
31983
32581
  summary: "Show weight, sleep, mood, the day rating, energy and bedtime as daily trend lines (no target, no streak).",
@@ -32017,6 +32615,21 @@ var COMMAND_SPECS = [
32017
32615
  returns: "Metric",
32018
32616
  notes: "Logging again the same day replaces that day's point. A bedtime belongs to the night's wake day (logged at 23:30 or the next morning, it lands on the morning). The key must act for a member."
32019
32617
  },
32618
+ {
32619
+ path: ["metrics", "import"],
32620
+ summary: "Import a batch of weight, sleep and bedtime values read off Health Connect (what the Android app sends).",
32621
+ args: [],
32622
+ flags: [
32623
+ {
32624
+ name: "data",
32625
+ type: "string",
32626
+ description: 'The batch as JSON: {"points":[{"key":"sleep","value":7.5,"occurredAt":"2026-10-20T07:00:00Z","recordId":"\u2026"}]} (source defaults to health_connect).'
32627
+ }
32628
+ ],
32629
+ scopes: ["habits:write"],
32630
+ returns: "ImportMetricsResult",
32631
+ notes: "POST /api/v1/metrics/import. Each record lands once (its recordId); one already imported, out of range or in the future is skipped. At most 500 points."
32632
+ },
32020
32633
  {
32021
32634
  path: ["documents", "file"],
32022
32635
  summary: "File a paper in one call (doc_file): the provider, the document, its file and a receipt card.",
@@ -34389,6 +35002,88 @@ var COMMAND_SPECS = [
34389
35002
  returns: "AnimalVetVisit",
34390
35003
  notes: "POST /api/v1/animals/vet-visits/{visitId}/undo. The visit, its weight, its key dates and the filed photos all go back."
34391
35004
  },
35005
+ {
35006
+ path: ["animals", "lost-card"],
35007
+ summary: "An animal's lost-pet card: on or off, its link, and what it could show.",
35008
+ args: [{ name: "id", required: true, description: "Animal ULID." }],
35009
+ flags: [],
35010
+ scopes: ["animals:read"],
35011
+ returns: "AnimalLostCardState",
35012
+ notes: "GET /api/v1/animals/{id}/lost-card. `card` is null while it's off; else its `path` (`/lost/<token>`, the page a QR code opens), what it shows and `preview` (the finder's page). `photos` are the pictures on the animal it may show; `chipOnFile` says whether it can say chipped."
35013
+ },
35014
+ {
35015
+ path: ["animals", "lost-card-set"],
35016
+ summary: "Turn an animal's lost-pet card on, or change what it shows.",
35017
+ args: [{ name: "id", required: true, description: "Animal ULID." }],
35018
+ flags: [
35019
+ {
35020
+ name: "data",
35021
+ type: "string",
35022
+ description: 'JSON: `{ "phone": "+32 470 \u2026", "photoFileId": "\u2026", "showChipped": true, "note": "\u2026" }`; null takes a field off.'
35023
+ }
35024
+ ],
35025
+ scopes: ["animals:write"],
35026
+ returns: "AnimalLostCardState",
35027
+ notes: "PUT /api/v1/animals/{id}/lost-card. An individual still with the household (a lost one included). The name always shows; the photo must be a picture on the animal; `showChipped` needs its chip on file and never shows the number. The link stays the same while the card is on."
35028
+ },
35029
+ {
35030
+ path: ["animals", "lost-card-off"],
35031
+ summary: "Turn an animal's lost-pet card off (its link stops working).",
35032
+ args: [{ name: "id", required: true, description: "Animal ULID." }],
35033
+ flags: [],
35034
+ scopes: ["animals:write"],
35035
+ returns: "void",
35036
+ notes: "DELETE /api/v1/animals/{id}/lost-card. Destructive: a printed QR stops working, so it needs --allow-destructive. Turning it on again makes a new link."
35037
+ },
35038
+ {
35039
+ path: ["animals", "acquisition"],
35040
+ summary: "Bringing a planned animal home: its checklist.",
35041
+ args: [{ name: "id", required: true, description: "Animal ULID." }],
35042
+ flags: [],
35043
+ scopes: ["animals:read"],
35044
+ returns: "AnimalAcquisition",
35045
+ notes: 'GET /api/v1/animals/{id}/acquisition. The Task "Bring <name> home", its steps in order, `blockers` to sort before the pick-up (papers its kind needs that aren\'t on file) and `arrived`; 404 when none was planned.'
35046
+ },
35047
+ {
35048
+ path: ["animals", "acquisition-plan"],
35049
+ summary: "Plan bringing a planned animal home: a Task with a step per line of the checklist.",
35050
+ args: [{ name: "id", required: true, description: "Animal ULID." }],
35051
+ flags: [
35052
+ {
35053
+ name: "pick-up",
35054
+ type: "string",
35055
+ description: "The pick-up day, YYYY-MM-DD (the Task's due day)."
35056
+ },
35057
+ {
35058
+ name: "data",
35059
+ type: "string",
35060
+ description: 'JSON: `{ "quarantine": true, "extraSteps": ["Buy a UV lamp"] }`.'
35061
+ }
35062
+ ],
35063
+ scopes: ["animals:write"],
35064
+ returns: "AnimalAcquisition",
35065
+ notes: "POST /api/v1/animals/{id}/acquisition. The steps: the papers its kind needs (DogID, CatID, CITES A, closed ring), the vet check, its home, and the quarantine before it meets the others (on by default for a reptile or a bird). Only a planned animal; one per animal (409)."
35066
+ },
35067
+ {
35068
+ path: ["animals", "arrived"],
35069
+ summary: "A planned animal is home: its status, the quarantine Period, the Task done.",
35070
+ args: [{ name: "id", required: true, description: "Animal ULID." }],
35071
+ flags: [
35072
+ {
35073
+ name: "on",
35074
+ type: "string",
35075
+ description: "The day it came home, YYYY-MM-DD (today by default)."
35076
+ },
35077
+ {
35078
+ name: "quarantine-months",
35079
+ type: "string",
35080
+ description: "How long it stays apart (0\u201312); 3 when its checklist has the quarantine step."
35081
+ }
35082
+ ],
35083
+ scopes: ["animals:write"],
35084
+ returns: "AnimalDetail",
35085
+ notes: "POST /api/v1/animals/{id}/arrived. Sets acquiredOn and the status (`quarantine` with a Period, else `active`); open steps stay open."
35086
+ },
34392
35087
  {
34393
35088
  path: ["runs", "change"],
34394
35089
  summary: "Apply a chat update to a run: its changes, with a receipt and Undo.",
@@ -34483,6 +35178,74 @@ var COMMAND_SPECS = [
34483
35178
  returns: "SteamSyncResult",
34484
35179
  notes: "POST /api/v1/runs/steam/sync. Writes into each run whose achievements come from Steam or aren't kept yet; runs kept by hand are left alone. Per game: outcome, runs, unlocked, total and the error (unauthorized, private, no_stats, unavailable, bad_response). 409 before Steam is linked."
34485
35180
  },
35181
+ {
35182
+ path: ["sensors", "status"],
35183
+ summary: "Whether the Space has linked Home Assistant, how many entities are mapped, the newest reading.",
35184
+ args: [],
35185
+ flags: [],
35186
+ scopes: ["places:read"],
35187
+ returns: "HomeAssistantStatus",
35188
+ notes: "GET /api/v1/sensors/home-assistant. Home Assistant is linked in the app's Settings \u2192 Home; the token is never returned."
35189
+ },
35190
+ {
35191
+ path: ["sensors", "entities"],
35192
+ summary: "Every entity Home Assistant has, with its state, the reading it likely gives and what it's mapped to.",
35193
+ args: [],
35194
+ flags: [],
35195
+ scopes: ["places:read"],
35196
+ returns: "HomeAssistantEntity[]",
35197
+ notes: "GET /api/v1/sensors/home-assistant/entities. 409 before Home Assistant is linked; 503 when it doesn't answer."
35198
+ },
35199
+ {
35200
+ path: ["sensors", "sync"],
35201
+ summary: "Read every mapped entity now and put its state on the ledger, as the five-minute sync does.",
35202
+ args: [],
35203
+ flags: [],
35204
+ scopes: ["places:write"],
35205
+ returns: "SensorSyncResult",
35206
+ notes: "POST /api/v1/sensors/home-assistant/sync. A room's readings feed its card and the room alarm; an asset's show on its page. Returns entities, written, skipped, missing and the error (unauthorized, unavailable, bad_response). 409 before Home Assistant is linked."
35207
+ },
35208
+ {
35209
+ path: ["sensors", "links"],
35210
+ summary: "The mapped entities, or the ones on one Place or asset.",
35211
+ args: [],
35212
+ flags: [{ name: "node", type: "string", description: "Only the mappings on this node ULID." }],
35213
+ scopes: ["places:read"],
35214
+ returns: "SensorLink[]",
35215
+ notes: "GET /api/v1/sensors/links."
35216
+ },
35217
+ {
35218
+ path: ["sensors", "map"],
35219
+ summary: "Map a Home Assistant entity to a Place, an asset or an animal's room.",
35220
+ args: [
35221
+ {
35222
+ name: "entity",
35223
+ required: true,
35224
+ description: "The entity id, e.g. sensor.shed_temperature."
35225
+ },
35226
+ { name: "node", required: true, description: "The Place, asset or animal ULID." }
35227
+ ],
35228
+ flags: [
35229
+ {
35230
+ name: "reading",
35231
+ type: "string",
35232
+ description: "A room's temp|humidity|heater|water|door|feeder|light, or an asset's state|power|energy."
35233
+ },
35234
+ { name: "label", type: "string", description: "A name for it (Home Assistant's own)." }
35235
+ ],
35236
+ scopes: ["places:write"],
35237
+ returns: "SensorLink",
35238
+ notes: "POST /api/v1/sensors/links. An animal maps to the Place it's housed in (409 when it has none). Mapping an entity again moves it."
35239
+ },
35240
+ {
35241
+ path: ["sensors", "unmap"],
35242
+ summary: "Unmap an entity; the readings it gave stay.",
35243
+ args: [{ name: "link", required: true, description: "The sensor link ULID." }],
35244
+ flags: [],
35245
+ scopes: ["places:write"],
35246
+ returns: "None",
35247
+ notes: "DELETE /api/v1/sensors/links/{id}."
35248
+ },
34486
35249
  {
34487
35250
  path: ["runs", "sessions", "list"],
34488
35251
  summary: "A run's sessions, newest first, with recaps and change batches.",
@@ -34521,6 +35284,52 @@ var COMMAND_SPECS = [
34521
35284
  returns: "RunDetail",
34522
35285
  notes: "PATCH /api/v1/runs/{id}/sessions/{sessionId}."
34523
35286
  },
35287
+ {
35288
+ path: ["people", "propose"],
35289
+ summary: "Propose a life event read in the member's mail; nothing is written until they save it.",
35290
+ args: [],
35291
+ flags: [
35292
+ {
35293
+ name: "data",
35294
+ type: "string",
35295
+ description: 'JSON CreatePersonProposalInput, e.g. {"person":"Sam","kind":"birth","title":"Baby girl, Mila","source":"gmail:18c2f0a1b2","heardAt":"2026-10-18T08:00:00Z"}.'
35296
+ }
35297
+ ],
35298
+ scopes: ["contacts:write"],
35299
+ returns: "PersonProposal",
35300
+ notes: "Needs a member's key and PEOPLE_MAIL_PROPOSALS_ENABLED on the server (else forbidden). Kinds: birth, move, new_job, wedding, engagement, death, other. Without items, saving writes one life update (the title, on heardAt). The same mail again returns the proposal it already made. Only the member whose key it is sees it."
35301
+ },
35302
+ {
35303
+ path: ["people", "proposals"],
35304
+ summary: "Your life events from mail: pending, saved or skipped.",
35305
+ args: [],
35306
+ flags: [
35307
+ { name: "status", type: "string", description: "pending, accepted or skipped." },
35308
+ {
35309
+ name: "source",
35310
+ type: "string",
35311
+ description: "gmail:<id>: whether this mail was proposed already (the watch dedupes with it)."
35312
+ }
35313
+ ],
35314
+ scopes: ["contacts:read"],
35315
+ returns: "PersonProposal"
35316
+ },
35317
+ {
35318
+ path: ["people", "accept"],
35319
+ summary: "Save a proposal: write its life update (and its items) on the person.",
35320
+ args: [{ name: "id", required: true, description: "The proposal's id." }],
35321
+ flags: [],
35322
+ scopes: ["contacts:write"],
35323
+ returns: "PersonProposalAcceptResult"
35324
+ },
35325
+ {
35326
+ path: ["people", "skip"],
35327
+ summary: "Skip a proposal: nothing is written, and the mail isn't proposed again.",
35328
+ args: [{ name: "id", required: true, description: "The proposal's id." }],
35329
+ flags: [],
35330
+ scopes: ["contacts:write"],
35331
+ returns: "PersonProposal"
35332
+ },
34524
35333
  {
34525
35334
  path: ["runs", "sessions", "delete"],
34526
35335
  summary: "Delete a session (its changes stay applied; destructive).",
@@ -34630,6 +35439,30 @@ var COMMAND_SPECS = [
34630
35439
  returns: "PeopleOverview",
34631
35440
  notes: "The Sunday card is `--days 7`. Rhythm is a wish: niceToSee lists only who came round and isn't snoozed, longest first. Never say overdue."
34632
35441
  },
35442
+ {
35443
+ path: ["people", "google"],
35444
+ summary: "Your Google Contacts, to pick from: who they'd merge into and what importing adds.",
35445
+ args: [],
35446
+ flags: [{ name: "q", type: "string", description: "A name or email to narrow to." }],
35447
+ scopes: ["contacts:read"],
35448
+ returns: "GoogleContactsList",
35449
+ notes: "Connecting needs a browser (People \u2192 Import). Not connected: candidates is empty and status.connected false. A key with no member is forbidden."
35450
+ },
35451
+ {
35452
+ path: ["people", "google-import"],
35453
+ summary: "Import the people you picked from Google Contacts (merging, never duplicating).",
35454
+ args: [
35455
+ {
35456
+ name: "resourceNames",
35457
+ required: true,
35458
+ description: "Google person ids (people/c123), as `do people google` lists them."
35459
+ }
35460
+ ],
35461
+ flags: [],
35462
+ scopes: ["contacts:write"],
35463
+ returns: "GoogleContactsImportResult",
35464
+ 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."
35465
+ },
34633
35466
  {
34634
35467
  path: ["people", "brief"],
34635
35468
  summary: "Before you see them: last seen, life updates, follow-ups, gift ideas, dates.",
@@ -34888,13 +35721,30 @@ var COMMAND_SPECS = [
34888
35721
  {
34889
35722
  name: "data",
34890
35723
  type: "string",
34891
- description: 'JSON CreateRsvpLinksInput, e.g. {"guestListId":"01\u2026"} (every household without a live link) or with "householdIds":["01\u2026"] (re-mints, revoking the old link).'
35724
+ description: 'JSON CreateRsvpLinksInput, e.g. {"guestListId":"01\u2026"} (every household without a live link), "mode":"address" for the save-the-date (address only), or with "householdIds":["01\u2026"] (re-mints, revoking the old link; prefer `do rsvp-links replace`).'
34892
35725
  }
34893
35726
  ],
34894
35727
  scopes: ["contacts:write"],
34895
35728
  returns: "MintedRsvpLink",
34896
35729
  notes: "A guest in no household gets a household of one first. A link stops at the end of the RSVP deadline day (or after 120 days without one) unless expiresAt says otherwise. Send each household its own `path` on the web app."
34897
35730
  },
35731
+ {
35732
+ path: ["rsvp-links", "token"],
35733
+ summary: "Show a live RSVP link again: the same token it was minted with.",
35734
+ args: [{ name: "id", required: true, description: "The link's id." }],
35735
+ flags: [],
35736
+ scopes: ["contacts:write"],
35737
+ returns: "MintedRsvpLink",
35738
+ notes: "The mail and the paper QR carry this one link. A revoked or expired link is gone; one minted before tokens were kept can't be shown: replace it."
35739
+ },
35740
+ {
35741
+ path: ["rsvp-links", "replace"],
35742
+ summary: "Replace an RSVP link: a new token, and the old link (and its QR) stops working.",
35743
+ args: [{ name: "id", required: true, description: "The link's id." }],
35744
+ flags: [],
35745
+ scopes: ["contacts:write"],
35746
+ returns: "MintedRsvpLink"
35747
+ },
34898
35748
  {
34899
35749
  path: ["rsvp-links", "revoke"],
34900
35750
  summary: "Stop one RSVP link working.",
@@ -36472,14 +37322,32 @@ function renderJournalMilestone(data, mode) {
36472
37322
  return out.join(`
36473
37323
  `);
36474
37324
  }
36475
- function renderJournalWeek(data, mode) {
37325
+ function renderJournalPeriod(data, mode) {
36476
37326
  const d = data;
36477
- const out = [`Week ${d.week?.slice(6) ?? "?"} ${paint(mode, "dim", `${d.from} \u2013 ${d.to}`)}`];
37327
+ const kind = d.week ? "week" : d.month ? "month" : "year";
37328
+ const head = d.week ? `Week ${d.week.slice(6)}` : d.month ?? d.year ?? "?";
37329
+ const out = [`${head} ${paint(mode, "dim", `${d.from} \u2013 ${d.to}`)}`];
36478
37330
  const days = d.days ?? [];
36479
- const ratings = days.flatMap((day) => day.metrics?.rating === undefined ? [] : [`${day.date.slice(5)} ${day.metrics.rating}`]);
36480
- if (ratings.length > 0) {
36481
- const usual = d.usual == null ? "" : paint(mode, "dim", ` (usual ${d.usual})`);
36482
- out.push(`${ratings.join(" \xB7 ")}${usual}`);
37331
+ const usual = d.usual == null ? "" : paint(mode, "dim", ` (usual ${d.usual})`);
37332
+ if (kind === "week") {
37333
+ const ratings = days.flatMap((day) => day.metrics?.rating === undefined ? [] : [`${day.date.slice(5)} ${day.metrics.rating}`]);
37334
+ if (ratings.length > 0)
37335
+ out.push(`${ratings.join(" \xB7 ")}${usual}`);
37336
+ } else if (kind === "month") {
37337
+ const ratings = days.flatMap((day) => day.metrics?.rating === undefined ? [] : [day.metrics.rating]);
37338
+ if (ratings.length > 0) {
37339
+ const avg = Math.round(ratings.reduce((a, b) => a + b, 0) / ratings.length * 10) / 10;
37340
+ out.push(`avg ${avg} \xB7 ${ratings.length} rated${usual}`);
37341
+ }
37342
+ } else {
37343
+ for (const m of d.months ?? []) {
37344
+ if (m.rated === 0 && m.kept === 0)
37345
+ continue;
37346
+ const avg = m.average == null ? "\u2014" : String(m.average);
37347
+ out.push(` ${m.month} avg ${avg} \xB7 ${m.rated} rated \xB7 ${m.kept} kept`);
37348
+ }
37349
+ if (d.usual != null)
37350
+ out.push(paint(mode, "dim", ` usual ${d.usual} the year before`));
36483
37351
  }
36484
37352
  if (d.recap) {
36485
37353
  out.push("", d.recap.body);
@@ -36491,7 +37359,12 @@ function renderJournalWeek(data, mode) {
36491
37359
  if (d.recap.pattern)
36492
37360
  out.push("", `${paint(mode, "dim", "Pattern")} ${d.recap.pattern}`);
36493
37361
  } else {
36494
- out.push("", paint(mode, "dim", "(no recap for this week yet)"));
37362
+ out.push("", paint(mode, "dim", `(no recap for this ${kind} yet)`));
37363
+ }
37364
+ if ((d.milestones ?? []).length > 0) {
37365
+ out.push("", paint(mode, "dim", "Milestones"));
37366
+ for (const m of d.milestones ?? [])
37367
+ out.push(` \u25C6 ${m.title}${paint(mode, "dim", ` \xB7 ${m.happenedOn}`)}`);
36495
37368
  }
36496
37369
  const n = d.numbers;
36497
37370
  if (n) {
@@ -37459,6 +38332,16 @@ var HANDLERS = {
37459
38332
  data: await requireClient().get("/progress/habits"),
37460
38333
  render: renderProgressHabits
37461
38334
  }),
38335
+ "progress commits": async ({ flags, requireClient }) => {
38336
+ const days = flagString(flags, "days");
38337
+ const query = parseInput(githubCommitsQuerySchema, days ? { days } : {});
38338
+ return {
38339
+ data: await requireClient().get("/progress/commits", {
38340
+ query: { days: String(query.days) }
38341
+ }),
38342
+ render: renderRecord
38343
+ };
38344
+ },
37462
38345
  "progress questions": async ({ requireClient }) => ({
37463
38346
  data: await requireClient().get("/progress/questions"),
37464
38347
  render: renderInsightsAnswers
@@ -37551,19 +38434,43 @@ var HANDLERS = {
37551
38434
  const week = journalWeekArg(args, "week");
37552
38435
  return {
37553
38436
  data: await requireClient().get(`/journal/weeks/${week}`),
37554
- render: renderJournalWeek
38437
+ render: renderJournalPeriod
38438
+ };
38439
+ },
38440
+ "journal month": async ({ args, requireClient }) => {
38441
+ const month = args[0] ?? "";
38442
+ if (journalPeriodKind(month) !== "month") {
38443
+ throw usageError("journal month needs a month as YYYY-MM, e.g. `do journal month 2026-10`");
38444
+ }
38445
+ return {
38446
+ data: await requireClient().get(`/journal/months/${month}`),
38447
+ render: renderJournalPeriod
38448
+ };
38449
+ },
38450
+ "journal year": async ({ args, requireClient }) => {
38451
+ const year = args[0] ?? "";
38452
+ if (journalPeriodKind(year) !== "year") {
38453
+ throw usageError("journal year needs a year as YYYY, e.g. `do journal year 2026`");
38454
+ }
38455
+ return {
38456
+ data: await requireClient().get(`/journal/years/${year}`),
38457
+ render: renderJournalPeriod
37555
38458
  };
37556
38459
  },
37557
38460
  "journal recap": async ({ args, flags, requireClient }) => {
37558
- const week = journalWeekArg(args, "recap");
38461
+ const period = args[0] ?? "";
38462
+ const kind = journalPeriodKind(period);
38463
+ if (kind === null) {
38464
+ throw usageError("journal recap needs a week (2026-W42), a month (2026-10) or a year (2026), e.g. `do journal recap 2026-W42`");
38465
+ }
37559
38466
  const body = { ...readDataFlag(flags) };
37560
38467
  const text = flagString(flags, "body");
37561
38468
  if (text !== undefined)
37562
38469
  body.body = text;
37563
38470
  const input = parseInput(journalWriteRecapInputSchema, body);
37564
38471
  return {
37565
- data: await requireClient().put(`/journal/weeks/${week}/recap`, input),
37566
- render: renderJournalWeek
38472
+ data: await requireClient().put(`/journal/${kind}s/${period}/recap`, input),
38473
+ render: renderJournalPeriod
37567
38474
  };
37568
38475
  },
37569
38476
  "journal write": async ({ args, flags, requireClient }) => {
@@ -38639,6 +39546,20 @@ var HANDLERS = {
38639
39546
  });
38640
39547
  return { data: await requireClient().post(`/metrics/${key}`, input), render: renderRecord };
38641
39548
  },
39549
+ "metrics import": async ({ flags, requireClient }) => {
39550
+ const input = parseInput(importMetricsInputSchema, {
39551
+ source: "health_connect",
39552
+ ...readDataFlag(flags)
39553
+ });
39554
+ return { data: await requireClient().post("/metrics/import", input), render: renderRecord };
39555
+ },
39556
+ "tap-tags tap": async ({ args, requireClient }) => {
39557
+ const id = requireArg(args, 0, "tag id");
39558
+ return {
39559
+ data: await requireClient().post(`/tap-tags/${encodeURIComponent(id)}/tap`, {}),
39560
+ render: renderRecord
39561
+ };
39562
+ },
38642
39563
  "agents list": async ({ requireClient }) => ({
38643
39564
  data: await requireClient().getPage("/agents"),
38644
39565
  render: renderList
@@ -39606,6 +40527,53 @@ var HANDLERS = {
39606
40527
  data: await requireClient().post(`/animals/vet-visits/${requireArg(args, 0, "visit id")}/undo`, {}),
39607
40528
  render: renderRecord
39608
40529
  }),
40530
+ "animals lost-card": async ({ args, requireClient }) => ({
40531
+ data: await requireClient().get(`/animals/${requireArg(args, 0, "animal id")}/lost-card`),
40532
+ render: renderRecord
40533
+ }),
40534
+ "animals lost-card-set": async ({ args, flags, requireClient }) => {
40535
+ const id = requireArg(args, 0, "animal id");
40536
+ const body = parseInput(animalLostCardInputSchema, readDataFlag(flags));
40537
+ return {
40538
+ data: await requireClient().put(`/animals/${id}/lost-card`, body),
40539
+ render: renderRecord
40540
+ };
40541
+ },
40542
+ "animals lost-card-off": async ({ args, flags, requireClient }) => {
40543
+ const id = requireArg(args, 0, "animal id");
40544
+ assertDestructiveAllowed(flags, `turn off the lost-pet card of ${id} (its printed QR stops working)`);
40545
+ await requireClient().delete(`/animals/${id}/lost-card`);
40546
+ return { data: { ok: true, animalId: id }, render: renderRecord };
40547
+ },
40548
+ "animals acquisition": async ({ args, requireClient }) => ({
40549
+ data: await requireClient().get(`/animals/${requireArg(args, 0, "animal id")}/acquisition`),
40550
+ render: renderRecord
40551
+ }),
40552
+ "animals acquisition-plan": async ({ args, flags, requireClient }) => {
40553
+ const id = requireArg(args, 0, "animal id");
40554
+ const pickUp = flagString(flags, "pick-up");
40555
+ const body = parseInput(animalAcquisitionInputSchema, {
40556
+ ...readDataFlag(flags),
40557
+ ...pickUp ? { pickUpOn: pickUp } : {}
40558
+ });
40559
+ return {
40560
+ data: await requireClient().post(`/animals/${id}/acquisition`, body),
40561
+ render: renderRecord
40562
+ };
40563
+ },
40564
+ "animals arrived": async ({ args, flags, requireClient }) => {
40565
+ const id = requireArg(args, 0, "animal id");
40566
+ const on = flagString(flags, "on");
40567
+ const months = flagString(flags, "quarantine-months");
40568
+ const body = parseInput(animalArrivedInputSchema, {
40569
+ ...on ? { on } : {},
40570
+ ...months !== undefined ? { quarantineMonths: Number(months) } : {}
40571
+ });
40572
+ return {
40573
+ data: await requireClient().post(`/animals/${id}/arrived`, body),
40574
+ render: renderRecord
40575
+ };
40576
+ },
39609
40577
  "runs change": async ({ args, flags, requireClient }) => {
39610
40578
  const id = requireArg(args, 0, "run id");
39611
40579
  const body = { ...readDataFlag(flags) };
@@ -39693,6 +40661,38 @@ var HANDLERS = {
39693
40661
  });
39694
40662
  return { data: await requireClient().post("/runs/steam/sync", body), render: renderRecord };
39695
40663
  },
40664
+ "sensors status": async ({ requireClient }) => ({
40665
+ data: await requireClient().get("/sensors/home-assistant"),
40666
+ render: renderRecord
40667
+ }),
40668
+ "sensors entities": async ({ requireClient }) => ({
40669
+ data: await requireClient().get("/sensors/home-assistant/entities"),
40670
+ render: renderList
40671
+ }),
40672
+ "sensors sync": async ({ requireClient }) => ({
40673
+ data: await requireClient().post("/sensors/home-assistant/sync", {}),
40674
+ render: renderRecord
40675
+ }),
40676
+ "sensors links": async ({ flags, requireClient }) => ({
40677
+ data: await requireClient().get("/sensors/links", {
40678
+ query: { nodeId: flagString(flags, "node") }
40679
+ }),
40680
+ render: renderList
40681
+ }),
40682
+ "sensors map": async ({ args, flags, requireClient }) => {
40683
+ const body = parseInput(createSensorLinkInputSchema, {
40684
+ externalId: requireArg(args, 0, "entity id"),
40685
+ nodeId: requireArg(args, 1, "node id"),
40686
+ reading: flagString(flags, "reading"),
40687
+ ...flagString(flags, "label") ? { label: flagString(flags, "label") } : {}
40688
+ });
40689
+ return { data: await requireClient().post("/sensors/links", body), render: renderRecord };
40690
+ },
40691
+ "sensors unmap": async ({ args, requireClient }) => {
40692
+ const id = requireArg(args, 0, "sensor link id");
40693
+ await requireClient().delete(`/sensors/links/${id}`);
40694
+ return { data: { ok: true, unmapped: id }, render: renderRecord };
40695
+ },
39696
40696
  "runs sessions list": async ({ args, requireClient }) => {
39697
40697
  const id = requireArg(args, 0, "run id");
39698
40698
  return { data: await requireClient().get(`/runs/${id}/sessions`), render: renderList };
@@ -39770,6 +40770,10 @@ var HANDLERS = {
39770
40770
  render: renderRecord
39771
40771
  };
39772
40772
  },
40773
+ "health medical-id": async ({ requireClient }) => ({
40774
+ data: await requireClient().get("/health/medical-id"),
40775
+ render: renderRecord
40776
+ }),
39773
40777
  "health summary": async ({ flags, requireClient }) => ({
39774
40778
  data: await requireClient().get("/health/summary", {
39775
40779
  query: { episodeId: flagString(flags, "episode") }
@@ -40017,6 +41021,50 @@ var HANDLERS = {
40017
41021
  const query = days ? { days } : {};
40018
41022
  return { data: await requireClient().get("/people/overview", { query }), render: renderRecord };
40019
41023
  },
41024
+ "people google": async ({ flags, requireClient }) => {
41025
+ const q = flagString(flags, "q");
41026
+ return {
41027
+ data: await requireClient().get("/people/google-contacts", { query: q ? { q } : {} }),
41028
+ render: renderRecord
41029
+ };
41030
+ },
41031
+ "people google-import": async ({ args, requireClient }) => {
41032
+ if (args.length === 0) {
41033
+ throw usageError("people google-import needs Google person ids, e.g. people/c123");
41034
+ }
41035
+ const body = parseInput(importGoogleContactsInputSchema, { resourceNames: args });
41036
+ return {
41037
+ data: await requireClient().post("/people/google-contacts/import", body),
41038
+ render: renderRecord
41039
+ };
41040
+ },
41041
+ "people propose": async ({ flags, requireClient }) => {
41042
+ const body = parseInput(createPersonProposalInputSchema, {
41043
+ id: ulid3(),
41044
+ ...readDataFlag(flags)
41045
+ });
41046
+ return { data: await requireClient().post("/people/proposals", body), render: renderRecord };
41047
+ },
41048
+ "people proposals": async ({ flags, requireClient }) => {
41049
+ const status = flagString(flags, "status");
41050
+ const source = flagString(flags, "source");
41051
+ const query = parseInput(personProposalsQuerySchema, {
41052
+ ...status ? { status } : {},
41053
+ ...source ? { source } : {}
41054
+ });
41055
+ return {
41056
+ data: await requireClient().get("/people/proposals", { query }),
41057
+ render: renderRecord
41058
+ };
41059
+ },
41060
+ "people accept": async ({ args, requireClient }) => ({
41061
+ data: await requireClient().post(`/people/proposals/${requireArg(args, 0, "proposal id")}/accept`, {}),
41062
+ render: renderRecord
41063
+ }),
41064
+ "people skip": async ({ args, requireClient }) => ({
41065
+ data: await requireClient().post(`/people/proposals/${requireArg(args, 0, "proposal id")}/skip`, {}),
41066
+ render: renderRecord
41067
+ }),
40020
41068
  "people brief": async ({ args, requireClient }) => {
40021
41069
  const id = requireArg(args, 0, "contact id");
40022
41070
  return { data: await requireClient().get(`/people/${id}/brief`), render: renderRecord };
@@ -40250,6 +41298,17 @@ var HANDLERS = {
40250
41298
  const body = parseInput(createRsvpLinksInputSchema, readDataFlag(flags));
40251
41299
  return { data: await requireClient().post("/rsvp-links", body), render: renderRecord };
40252
41300
  },
41301
+ "rsvp-links token": async ({ args, requireClient }) => {
41302
+ const id = requireArg(args, 0, "rsvp link id");
41303
+ return { data: await requireClient().get(`/rsvp-links/${id}/token`), render: renderRecord };
41304
+ },
41305
+ "rsvp-links replace": async ({ args, requireClient }) => {
41306
+ const id = requireArg(args, 0, "rsvp link id");
41307
+ return {
41308
+ data: await requireClient().post(`/rsvp-links/${id}/replace`, {}),
41309
+ render: renderRecord
41310
+ };
41311
+ },
40253
41312
  "rsvp-links revoke": async ({ args, requireClient }) => {
40254
41313
  const id = requireArg(args, 0, "rsvp link id");
40255
41314
  return {