@robbeverhelst/do 1.391.0 → 1.393.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 +719 -30
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -14420,7 +14420,7 @@ var configError = (message) => new CliError("config", message, EXIT.CONFIG);
14420
14420
 
14421
14421
  // src/meta.ts
14422
14422
  var CLI_NAME = "do";
14423
- var VERSION = "1.391.0";
14423
+ var VERSION = "1.393.0";
14424
14424
  var API_PREFIX = "/api/v1";
14425
14425
  var DEFAULT_API_URL = "http://localhost:3001";
14426
14426
 
@@ -20801,6 +20801,49 @@ var animalHandoverNotes = pgTable("animal_handover_notes", {
20801
20801
  photoFileId: text("photo_file_id").references(() => files.id, { onDelete: "set null" }),
20802
20802
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
20803
20803
  }, (t) => [index("animal_handover_notes_period_idx").on(t.tenantId, t.periodId)]);
20804
+ var animalMedicineEveryUnit = pgEnum("animal_medicine_every_unit", [
20805
+ "day",
20806
+ "week",
20807
+ "month"
20808
+ ]);
20809
+ var animalMedicines = pgTable("animal_medicines", {
20810
+ id: text("id").primaryKey(),
20811
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
20812
+ title: text("title").notNull(),
20813
+ dose: text("dose"),
20814
+ everyCount: integer2("every_count").notNull().default(1),
20815
+ everyUnit: animalMedicineEveryUnit("every_unit").notNull().default("day"),
20816
+ timeOfDay: text("time_of_day"),
20817
+ startsOn: date5("starts_on", { mode: "string" }),
20818
+ endsOn: date5("ends_on", { mode: "string" }),
20819
+ nextOn: date5("next_on", { mode: "string" }),
20820
+ stock: doublePrecision("stock"),
20821
+ unit: text("unit"),
20822
+ perDose: doublePrecision("per_dose").notNull().default(1),
20823
+ lowAt: doublePrecision("low_at"),
20824
+ note: text("note"),
20825
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
20826
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
20827
+ }, (t) => [index("animal_medicines_tenant_idx").on(t.tenantId)]);
20828
+ var animalMedicineAnimals = pgTable("animal_medicine_animals", {
20829
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
20830
+ medicineId: text("medicine_id").notNull().references(() => animalMedicines.id, { onDelete: "cascade" }),
20831
+ animalId: text("animal_id").notNull().references(() => animals.id, { onDelete: "cascade" })
20832
+ }, (t) => [
20833
+ primaryKey({ columns: [t.medicineId, t.animalId] }),
20834
+ index("animal_medicine_animals_animal_idx").on(t.tenantId, t.animalId)
20835
+ ]);
20836
+ var animalMedicineDoses = pgTable("animal_medicine_doses", {
20837
+ id: text("id").primaryKey(),
20838
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
20839
+ medicineId: text("medicine_id").notNull().references(() => animalMedicines.id, { onDelete: "cascade" }),
20840
+ day: date5("day", { mode: "string" }).notNull(),
20841
+ givenAt: timestamp("given_at", { withTimezone: true }).notNull().defaultNow(),
20842
+ givenByUserId: text("given_by_user_id").references(() => users.id, { onDelete: "set null" }),
20843
+ took: doublePrecision("took").notNull().default(0),
20844
+ nextWas: date5("next_was", { mode: "string" }),
20845
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
20846
+ }, (t) => [unique("animal_medicine_doses_day_uniq").on(t.medicineId, t.day)]);
20804
20847
 
20805
20848
  // ../../packages/schema/src/db/documents.ts
20806
20849
  var documentKind = pgEnum("document_kind", [
@@ -21712,6 +21755,61 @@ var animalArrivedInputSchema = object({
21712
21755
  on: keyDateDaySchema.optional(),
21713
21756
  quarantineMonths: number2().int().min(0).max(12).optional()
21714
21757
  }).strict();
21758
+ var animalMedicineEveryUnitSchema = _enum2(animalMedicineEveryUnit.enumValues);
21759
+ var animalMedicineViewSchema = object({
21760
+ id: ulidSchema,
21761
+ title: string2(),
21762
+ dose: string2().nullable(),
21763
+ everyCount: number2().int(),
21764
+ everyUnit: animalMedicineEveryUnitSchema,
21765
+ timeOfDay: string2().nullable(),
21766
+ startsOn: string2().nullable(),
21767
+ endsOn: string2().nullable(),
21768
+ nextOn: string2().nullable(),
21769
+ stock: number2().nullable(),
21770
+ unit: string2().nullable(),
21771
+ perDose: number2(),
21772
+ lowAt: number2().nullable(),
21773
+ note: string2().nullable(),
21774
+ animals: array(nodeRefSchema),
21775
+ daily: boolean2(),
21776
+ low: boolean2(),
21777
+ ended: boolean2(),
21778
+ course: object({ day: number2().int(), of: number2().int() }).nullable(),
21779
+ dueToday: boolean2(),
21780
+ doneToday: boolean2(),
21781
+ lastGivenOn: string2().nullable(),
21782
+ createdAt: exports_coerce.date(),
21783
+ updatedAt: exports_coerce.date()
21784
+ });
21785
+ var medicineText = (max) => string2().trim().min(1).max(max);
21786
+ var animalMedicineFields = object({
21787
+ id: ulidSchema,
21788
+ title: medicineText(120),
21789
+ animalIds: array(ulidSchema).min(1).max(20),
21790
+ dose: medicineText(120).nullish(),
21791
+ everyCount: number2().int().min(1).max(366).optional(),
21792
+ everyUnit: animalMedicineEveryUnitSchema.optional(),
21793
+ timeOfDay: string2().regex(/^(morning|midday|afternoon|evening|night|([01][0-9]|2[0-3]):[0-5][0-9])$/).nullish(),
21794
+ startsOn: keyDateDaySchema.nullish(),
21795
+ endsOn: keyDateDaySchema.nullish(),
21796
+ nextOn: keyDateDaySchema.nullish(),
21797
+ stock: number2().min(0).max(1e5).nullish(),
21798
+ unit: medicineText(30).nullish(),
21799
+ perDose: number2().positive().max(1e4).optional(),
21800
+ lowAt: number2().min(0).max(1e5).nullish(),
21801
+ note: medicineText(300).nullish()
21802
+ }).strict();
21803
+ var endsAfterStart2 = (v) => !v.startsOn || !v.endsOn || v.endsOn >= v.startsOn;
21804
+ var endsMessage = { message: "endsOn is before startsOn", path: ["endsOn"] };
21805
+ var createAnimalMedicineInputSchema = animalMedicineFields.refine(endsAfterStart2, endsMessage);
21806
+ var updateAnimalMedicineInputSchema = animalMedicineFields.omit({ id: true }).partial().strict().refine(endsAfterStart2, endsMessage);
21807
+ var animalMedicinesQuerySchema = object({
21808
+ animalId: ulidSchema.optional(),
21809
+ day: keyDateDaySchema.optional(),
21810
+ includeEnded: _enum2(["true", "false"]).transform((v) => v === "true").optional()
21811
+ });
21812
+ var animalMedicineDoseInputSchema = object({ day: keyDateDaySchema.optional() }).strict();
21715
21813
 
21716
21814
  // ../../packages/schema/src/operations/crud.ts
21717
21815
  var DELETE_REASON_QUERY = [
@@ -21795,6 +21893,7 @@ function crudOperations(r) {
21795
21893
  var READ = ["animals:read"];
21796
21894
  var WRITE = ["animals:write"];
21797
21895
  var visit = { visitId: "The vet visit's ULID." };
21896
+ var medicine = { medicineId: "The medicine's ULID." };
21798
21897
  var animalOperations = defineOperations({
21799
21898
  ...crudOperations({
21800
21899
  segment: "animals",
@@ -21883,6 +21982,96 @@ var animalOperations = defineOperations({
21883
21982
  response: { description: "The species profile." },
21884
21983
  errors: { 400: true }
21885
21984
  },
21985
+ listMedicines: {
21986
+ method: "get",
21987
+ path: "/animals/medicines",
21988
+ scopes: READ,
21989
+ tag: "Animals",
21990
+ summary: "List the animals' medicines",
21991
+ description: "By title: each medicine with the `animals` it's for, its `dose`, how often (`everyCount` `everyUnit`; `daily` when every 1 day), `timeOfDay`, a course's `startsOn`/`endsOn` and its `course` day N of M, the `nextOn` day of one that isn't daily, the counted `stock` (`unit`, `perDose`, `low` at `lowAt`), the `note`, and on `day` (UTC today by default) whether it's `dueToday` and `doneToday`, with `lastGivenOn`. Ended courses only with `includeEnded`.",
21992
+ query: [
21993
+ { name: "animalId", description: "Only this animal's (an animal's ULID)." },
21994
+ { name: "day", description: "The reader's day, `YYYY-MM-DD`; UTC today when left out." },
21995
+ { name: "includeEnded", description: "`true`: ended courses too." }
21996
+ ],
21997
+ querySchema: animalMedicinesQuerySchema,
21998
+ status: 200,
21999
+ response: { description: "The medicines." }
22000
+ },
22001
+ createMedicine: {
22002
+ method: "post",
22003
+ path: "/animals/medicines",
22004
+ scopes: WRITE,
22005
+ tag: "Animals",
22006
+ summary: "Add a medicine for one animal or a few",
22007
+ description: "A daily one (the default, every 1 day), a course (`startsOn` to `endsOn`) or one that comes round (`everyCount` `everyUnit`, with its `nextOn`). Count the `stock` to have each dose take `perDose` (default 1) from it and say low at `lowAt`. Every animal must be one in this Space (400).",
22008
+ body: createAnimalMedicineInputSchema,
22009
+ status: 201,
22010
+ response: { description: "The medicine." },
22011
+ errors: { 400: true }
22012
+ },
22013
+ getMedicine: {
22014
+ method: "get",
22015
+ path: "/animals/medicines/{medicineId}",
22016
+ pathParams: medicine,
22017
+ scopes: READ,
22018
+ tag: "Animals",
22019
+ summary: "A medicine, as it stands today",
22020
+ description: "The same shape as a row of the list, on UTC today.",
22021
+ status: 200,
22022
+ response: { description: "The medicine." },
22023
+ errors: { 404: true }
22024
+ },
22025
+ updateMedicine: {
22026
+ method: "patch",
22027
+ path: "/animals/medicines/{medicineId}",
22028
+ pathParams: medicine,
22029
+ scopes: WRITE,
22030
+ tag: "Animals",
22031
+ summary: "Change a medicine",
22032
+ description: "A field left out stays; `null` clears it; `animalIds` replaces who it's for. Set `stock` when a new box comes in.",
22033
+ body: updateAnimalMedicineInputSchema,
22034
+ status: 200,
22035
+ response: { description: "The medicine." },
22036
+ errors: { 400: true, 404: true }
22037
+ },
22038
+ removeMedicine: {
22039
+ method: "delete",
22040
+ path: "/animals/medicines/{medicineId}",
22041
+ pathParams: medicine,
22042
+ scopes: WRITE,
22043
+ tag: "Animals",
22044
+ summary: "Remove a medicine",
22045
+ description: "With the doses given; to stop a course and keep it, set its `endsOn` instead.",
22046
+ status: 204,
22047
+ response: { description: "Removed." },
22048
+ errors: { 404: true }
22049
+ },
22050
+ giveMedicineDose: {
22051
+ method: "post",
22052
+ path: "/animals/medicines/{medicineId}/doses",
22053
+ pathParams: medicine,
22054
+ scopes: WRITE,
22055
+ tag: "Animals",
22056
+ summary: "Give a medicine's dose",
22057
+ description: "The dose for `day` (UTC today by default): it takes `perDose` from a counted stock (never below 0) and moves the next day of one that isn't daily on from that day. Again that day changes nothing.",
22058
+ body: animalMedicineDoseInputSchema,
22059
+ status: 200,
22060
+ response: { description: "The medicine, on that day." },
22061
+ errors: { 400: true, 404: true }
22062
+ },
22063
+ undoMedicineDose: {
22064
+ method: "delete",
22065
+ path: "/animals/medicines/{medicineId}/doses/{day}",
22066
+ pathParams: { ...medicine, day: "The day it was given for, `YYYY-MM-DD`." },
22067
+ scopes: WRITE,
22068
+ tag: "Animals",
22069
+ summary: "Take a medicine's dose back",
22070
+ description: "The stock and the next day go back to before it; 404 when none was given that day.",
22071
+ status: 200,
22072
+ response: { description: "The medicine, on that day." },
22073
+ errors: { 400: "`day` isn't a `YYYY-MM-DD` day.", 404: true }
22074
+ },
21886
22075
  vetVisit: {
21887
22076
  method: "get",
21888
22077
  path: "/animals/vet-visits/{visitId}",
@@ -23933,6 +24122,24 @@ var collectionSavedViews = pgTable("collection_saved_views", {
23933
24122
  }, (t) => [
23934
24123
  index("collection_saved_views_tenant_idx").on(t.tenantId)
23935
24124
  ]);
24125
+ var collectionKinds = pgTable("collection_kinds", {
24126
+ id: text("id").primaryKey(),
24127
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
24128
+ key: text("key").notNull(),
24129
+ name: text("name").notNull(),
24130
+ one: text("one").notNull(),
24131
+ many: text("many").notNull(),
24132
+ icon: text("icon").notNull().default("tag"),
24133
+ preset: text("preset"),
24134
+ fields: jsonb("fields").$type().notNull().default([]),
24135
+ statusWords: jsonb("status_words").$type().notNull(),
24136
+ view: text("view").notNull().default("grid"),
24137
+ createdByUserId: text("created_by_user_id").references(() => users.id, {
24138
+ onDelete: "set null"
24139
+ }),
24140
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
24141
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
24142
+ }, (t) => [unique("collection_kinds_tenant_key_uniq").on(t.tenantId, t.key)]);
23936
24143
 
23937
24144
  // ../../packages/schema/src/contracts/collection-values.ts
23938
24145
  var collectionStatusValues = ["want", "have", "doing", "done", "dropped", "gone"];
@@ -26139,6 +26346,162 @@ var circleOperations = defineOperations({
26139
26346
  })
26140
26347
  });
26141
26348
 
26349
+ // ../../packages/schema/src/contracts/collection-kinds.ts
26350
+ var collectionKindFieldTypeValues = [
26351
+ "text",
26352
+ "number",
26353
+ "choice",
26354
+ "year",
26355
+ "date",
26356
+ "yesno"
26357
+ ];
26358
+ var collectionKindFieldTypeSchema = _enum2(collectionKindFieldTypeValues);
26359
+ var collectionKindIconValues = [
26360
+ "disc",
26361
+ "dice",
26362
+ "brick",
26363
+ "book",
26364
+ "pad",
26365
+ "sprout",
26366
+ "paw",
26367
+ "tag"
26368
+ ];
26369
+ var collectionKindIconSchema = _enum2(collectionKindIconValues);
26370
+ var collectionKindPresetValues = ["lego", "vinyl", "board", "custom"];
26371
+ var collectionKindPresetSchema = _enum2(collectionKindPresetValues);
26372
+ var slug = string2().min(1).max(40).regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, "lowercase letters and digits, dashes between");
26373
+ var collectionKindKeySchema = slug.refine((k) => !collectionTypeValues.includes(k), "that's a built-in kind");
26374
+ var collectionKindFieldSchema = object({
26375
+ key: slug,
26376
+ label: string2().trim().min(1).max(40),
26377
+ type: collectionKindFieldTypeSchema,
26378
+ choices: array(string2().trim().min(1).max(40)).max(30).optional()
26379
+ }).strict().refine((f) => f.type === "choice" || f.choices === undefined, {
26380
+ message: "only a choice field has choices",
26381
+ path: ["choices"]
26382
+ });
26383
+ var collectionKindFieldsSchema = array(collectionKindFieldSchema).max(12).refine((fs) => new Set(fs.map((f) => f.key)).size === fs.length, "each field key once");
26384
+ var word = string2().trim().min(1).max(30);
26385
+ var collectionKindStatusWordsSchema = object({ want: word, have: word, doing: word, done: word, dropped: word }).strict();
26386
+ var collectionKindSchema = object({
26387
+ id: ulidSchema,
26388
+ key: string2(),
26389
+ name: string2(),
26390
+ one: string2(),
26391
+ many: string2(),
26392
+ icon: string2(),
26393
+ preset: string2().nullable(),
26394
+ fields: array(object({
26395
+ key: string2(),
26396
+ label: string2(),
26397
+ type: string2(),
26398
+ choices: array(string2()).optional()
26399
+ })),
26400
+ statusWords: collectionKindStatusWordsSchema,
26401
+ view: string2(),
26402
+ itemCount: number2().int(),
26403
+ createdAt: exports_coerce.date(),
26404
+ updatedAt: exports_coerce.date()
26405
+ });
26406
+ var name2 = string2().trim().min(1).max(40);
26407
+ var createCollectionKindInputSchema = object({
26408
+ id: ulidSchema,
26409
+ name: name2,
26410
+ key: collectionKindKeySchema.optional(),
26411
+ one: name2.optional(),
26412
+ many: name2.optional(),
26413
+ icon: collectionKindIconSchema.optional(),
26414
+ preset: collectionKindPresetSchema.optional(),
26415
+ fields: collectionKindFieldsSchema.optional(),
26416
+ statusWords: collectionKindStatusWordsSchema.optional()
26417
+ }).strict();
26418
+ var updateCollectionKindInputSchema = object({
26419
+ name: name2.optional(),
26420
+ one: name2.optional(),
26421
+ many: name2.optional(),
26422
+ icon: collectionKindIconSchema.optional(),
26423
+ fields: collectionKindFieldsSchema.optional(),
26424
+ statusWords: collectionKindStatusWordsSchema.optional()
26425
+ }).strict();
26426
+ var f = (label, type) => ({
26427
+ key: kindSlug(label),
26428
+ label,
26429
+ type
26430
+ });
26431
+ var COLLECTION_KIND_PRESETS = {
26432
+ lego: {
26433
+ name: "LEGO",
26434
+ one: "set",
26435
+ icon: "brick",
26436
+ fields: [
26437
+ f("Set number", "text"),
26438
+ f("Pieces", "number"),
26439
+ f("Theme", "choice"),
26440
+ f("Bags", "number"),
26441
+ f("Minifigures", "number"),
26442
+ f("Released", "year")
26443
+ ],
26444
+ statusWords: {
26445
+ want: "Want",
26446
+ have: "In the box",
26447
+ doing: "Building",
26448
+ done: "Built",
26449
+ dropped: "Parted out"
26450
+ }
26451
+ },
26452
+ vinyl: {
26453
+ name: "Vinyl",
26454
+ one: "record",
26455
+ icon: "disc",
26456
+ fields: [
26457
+ f("Artist", "text"),
26458
+ f("Label", "choice"),
26459
+ f("Pressing", "text"),
26460
+ f("Speed", "number"),
26461
+ f("Condition", "choice"),
26462
+ f("Released", "year")
26463
+ ],
26464
+ statusWords: {
26465
+ want: "Want",
26466
+ have: "Have",
26467
+ doing: "On rotation",
26468
+ done: "Played out",
26469
+ dropped: "Sold"
26470
+ }
26471
+ },
26472
+ board: {
26473
+ name: "Board games",
26474
+ one: "board game",
26475
+ icon: "dice",
26476
+ fields: [
26477
+ f("Players", "number"),
26478
+ f("Play time", "text"),
26479
+ f("Designer", "text"),
26480
+ f("Expansions", "text"),
26481
+ f("Plays", "number"),
26482
+ f("Released", "year")
26483
+ ],
26484
+ statusWords: {
26485
+ want: "Want",
26486
+ have: "Have",
26487
+ doing: "Learning",
26488
+ done: "Played",
26489
+ dropped: "Gave away"
26490
+ }
26491
+ },
26492
+ custom: {
26493
+ name: "",
26494
+ one: "",
26495
+ icon: "tag",
26496
+ fields: [f("Maker", "text"), f("Year", "year"), f("Condition", "choice")],
26497
+ statusWords: { want: "Want", have: "Have", doing: "Using", done: "Done", dropped: "Gone" }
26498
+ }
26499
+ };
26500
+ function kindSlug(name) {
26501
+ const s = name.toLowerCase().normalize("NFKD").replace(/[\u0300-\u036F]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
26502
+ return s || "kind";
26503
+ }
26504
+
26142
26505
  // ../../packages/schema/src/contracts/pagination.ts
26143
26506
  var paginationQuerySchema = object({
26144
26507
  limit: exports_coerce.number().int().positive().optional(),
@@ -26149,6 +26512,7 @@ var paginationQuerySchema = object({
26149
26512
  var READ2 = ["collections:read"];
26150
26513
  var WRITE2 = ["collections:write"];
26151
26514
  var entryParams = { entryId: "The entry's ULID." };
26515
+ var kindParams = { kindId: "The kind's ULID." };
26152
26516
  var collectionOperations = defineOperations({
26153
26517
  ...crudOperations({
26154
26518
  segment: "collection",
@@ -26204,6 +26568,65 @@ var collectionOperations = defineOperations({
26204
26568
  status: 200,
26205
26569
  response: { description: "The Type registry." }
26206
26570
  },
26571
+ listKinds: {
26572
+ method: "get",
26573
+ path: "/collection/kinds",
26574
+ scopes: READ2,
26575
+ tag: "Collection",
26576
+ summary: "List the Space's own kinds",
26577
+ description: "The kinds the Space added (vinyl, board games, \u2026) beside the built-in Types, by name: each with its `key` (what an Item of it carries as its `type`), `name`, `one`/`many`, `icon`, the `preset` it started from, its `fields` (key, label, type: `text`, `number`, `choice`, `year`, `date` or `yesno`, and a choice field's `choices`; the first three show on its tile), its `statusWords` for want, have, doing, done and dropped, its `view` (`grid`) and `itemCount`.",
26578
+ status: 200,
26579
+ response: { description: "The kinds." }
26580
+ },
26581
+ createKind: {
26582
+ method: "post",
26583
+ path: "/collection/kinds",
26584
+ scopes: WRITE2,
26585
+ tag: "Collection",
26586
+ summary: "Add a kind",
26587
+ description: "Start from a `preset` (`lego`, `vinyl`, `board` or `custom`, \"Something else\") and a `name`; what's left out comes from the preset (the icon, the fields, the status words), the `key` is the name's slug (never a built-in Type; 409 when the Space has it) and `one`/`many` come from the name. It starts on the clean grid.",
26588
+ body: createCollectionKindInputSchema,
26589
+ status: 201,
26590
+ response: { description: "The kind." },
26591
+ errors: { 400: true, 409: "The Space already has a kind with this key." }
26592
+ },
26593
+ getKind: {
26594
+ method: "get",
26595
+ path: "/collection/kinds/{kindId}",
26596
+ pathParams: kindParams,
26597
+ scopes: READ2,
26598
+ tag: "Collection",
26599
+ summary: "A kind of the Space's own",
26600
+ description: "The same shape as a row of the list.",
26601
+ status: 200,
26602
+ response: { description: "The kind." },
26603
+ errors: { 404: true }
26604
+ },
26605
+ updateKind: {
26606
+ method: "patch",
26607
+ path: "/collection/kinds/{kindId}",
26608
+ pathParams: kindParams,
26609
+ scopes: WRITE2,
26610
+ tag: "Collection",
26611
+ summary: "Change a kind",
26612
+ description: "Its name, one/many, icon, `fields` (replaces the list) or `statusWords`; a field left out stays. The key never changes.",
26613
+ body: updateCollectionKindInputSchema,
26614
+ status: 200,
26615
+ response: { description: "The kind." },
26616
+ errors: { 400: true, 404: true }
26617
+ },
26618
+ removeKind: {
26619
+ method: "delete",
26620
+ path: "/collection/kinds/{kindId}",
26621
+ pathParams: kindParams,
26622
+ scopes: WRITE2,
26623
+ tag: "Collection",
26624
+ summary: "Remove a kind",
26625
+ description: "Only a kind with no Items (409 otherwise: move or remove them first).",
26626
+ status: 204,
26627
+ response: { description: "Removed." },
26628
+ errors: { 404: true, 409: "The kind still has Items." }
26629
+ },
26207
26630
  backfillCovers: {
26208
26631
  method: "post",
26209
26632
  path: "/collection/covers",
@@ -31309,9 +31732,9 @@ var eventFields = {
31309
31732
  note: eventTextSchema(1000).nullish(),
31310
31733
  sort: number2().int().min(0).max(1e4).optional()
31311
31734
  };
31312
- var endsAfterStart2 = (e) => !e.startsAt || !e.endsAt || e.endsAt >= e.startsAt;
31313
- var createGuestListEventInputSchema = object({ id: ulidSchema, guestListId: ulidSchema, key: guestEventKeySchema, ...eventFields }).strict().refine(endsAfterStart2, { message: "endsAt is before startsAt", path: ["endsAt"] });
31314
- var updateGuestListEventInputSchema = object(eventFields).partial().strict().refine(endsAfterStart2, { message: "endsAt is before startsAt", path: ["endsAt"] });
31735
+ var endsAfterStart3 = (e) => !e.startsAt || !e.endsAt || e.endsAt >= e.startsAt;
31736
+ var createGuestListEventInputSchema = object({ id: ulidSchema, guestListId: ulidSchema, key: guestEventKeySchema, ...eventFields }).strict().refine(endsAfterStart3, { message: "endsAt is before startsAt", path: ["endsAt"] });
31737
+ var updateGuestListEventInputSchema = object(eventFields).partial().strict().refine(endsAfterStart3, { message: "endsAt is before startsAt", path: ["endsAt"] });
31315
31738
  var guestListEventsQuerySchema = object({ guestListId: ulidSchema });
31316
31739
  var guestTableSchema = createSelectSchema(guestTables, {
31317
31740
  createdAt: exports_coerce.date(),
@@ -40340,18 +40763,18 @@ var runPlayStatusValues = [
40340
40763
  "dropped"
40341
40764
  ];
40342
40765
  var runPlayStatusSchema = _enum2(runPlayStatusValues);
40343
- var name2 = string2().trim().min(1).max(200);
40766
+ var name3 = string2().trim().min(1).max(200);
40344
40767
  var text5 = string2().trim().max(2000);
40345
40768
  var shortText2 = string2().trim().max(300);
40346
40769
  var isoDate = string2().regex(/^\d{4}-\d{2}-\d{2}$/, "must be an ISO date (YYYY-MM-DD)");
40347
40770
  var ref = string2().trim().min(1).max(200);
40348
40771
  var runCharacterSchema = object({
40349
- name: name2,
40772
+ name: name3,
40350
40773
  pronoun: _enum2(["he", "she", "they"]).nullish(),
40351
40774
  subtitle: shortText2.nullish(),
40352
40775
  level: number2().int().min(0).max(1e4).nullish(),
40353
40776
  build: shortText2.nullish(),
40354
- stats: array(object({ k: name2, v: union([number2(), shortText2]) }).strict()).max(40).optional(),
40777
+ stats: array(object({ k: name3, v: union([number2(), shortText2]) }).strict()).max(40).optional(),
40355
40778
  traits: array(shortText2).max(20).optional(),
40356
40779
  backstory: text5.nullish(),
40357
40780
  rules: array(shortText2).max(30).optional(),
@@ -40360,12 +40783,12 @@ var runCharacterSchema = object({
40360
40783
  var runArcSchema = object({
40361
40784
  title: shortText2.nullish(),
40362
40785
  chapters: array(object({
40363
- key: name2,
40364
- name: name2,
40786
+ key: name3,
40787
+ name: name3,
40365
40788
  range: shortText2.nullish(),
40366
40789
  moral: text5.nullish()
40367
40790
  }).strict()).max(40),
40368
- current: name2.nullish()
40791
+ current: name3.nullish()
40369
40792
  }).strict();
40370
40793
  var runStepStatusValues = ["done", "now", "todo", "skipped"];
40371
40794
  var runStepStatusSchema = _enum2(runStepStatusValues);
@@ -40378,7 +40801,7 @@ var runQuestStatusValues = ["active", "paused", "planned", "done", "failed"];
40378
40801
  var runQuestStatusSchema = _enum2(runQuestStatusValues);
40379
40802
  var runQuestSchema = object({
40380
40803
  ref: ref.nullish(),
40381
- name: name2,
40804
+ name: name3,
40382
40805
  line: shortText2.nullish(),
40383
40806
  status: runQuestStatusSchema.default("active"),
40384
40807
  objective: text5.nullish(),
@@ -40393,7 +40816,7 @@ var runQuestSchema = object({
40393
40816
  }).strict()).max(40).optional(),
40394
40817
  pausedAt: shortText2.nullish(),
40395
40818
  why: text5.nullish(),
40396
- revisitAt: name2.nullish()
40819
+ revisitAt: name3.nullish()
40397
40820
  }).strict();
40398
40821
  var runNextStepsSchema = object({
40399
40822
  items: array(shortText2.pipe(string2().min(1))).max(3),
@@ -40402,50 +40825,50 @@ var runNextStepsSchema = object({
40402
40825
  }).strict();
40403
40826
  var runChoiceSchema = object({
40404
40827
  ref: ref.nullish(),
40405
- title: name2,
40828
+ title: name3,
40406
40829
  place: shortText2.nullish(),
40407
40830
  status: _enum2(["made", "planned"]).default("made"),
40408
40831
  options: array(shortText2).max(6).optional(),
40409
40832
  why: text5.nullish(),
40410
40833
  consequence: text5.nullish(),
40411
- revisitAt: name2.nullish(),
40412
- chapter: name2.nullish(),
40834
+ revisitAt: name3.nullish(),
40835
+ chapter: name3.nullish(),
40413
40836
  tone: _enum2(["good", "grey", "dark"]).nullish(),
40414
40837
  on: isoDate.nullish()
40415
40838
  }).strict();
40416
40839
  var runHomeSchema = object({
40417
40840
  ref: ref.nullish(),
40418
- name: name2,
40841
+ name: name3,
40419
40842
  role: _enum2(["home", "collector", "storage", "planned", "later"]).default("home"),
40420
40843
  place: shortText2.nullish(),
40421
- upgrades: array(object({ name: name2, done: boolean2().default(false) }).strict()).max(40).optional(),
40844
+ upgrades: array(object({ name: name3, done: boolean2().default(false) }).strict()).max(40).optional(),
40422
40845
  steward: shortText2.nullish(),
40423
40846
  note: text5.nullish()
40424
40847
  }).strict();
40425
40848
  var runPersonSchema = object({
40426
40849
  ref: ref.nullish(),
40427
- name: name2,
40850
+ name: name3,
40428
40851
  role: _enum2(["child", "spouse", "steward", "follower", "pet", "rival", "other"]),
40429
40852
  status: _enum2(["with", "planned", "lost"]).default("with"),
40430
40853
  home: shortText2.nullish(),
40431
40854
  note: text5.nullish()
40432
40855
  }).strict();
40433
40856
  var runMountSchema = object({
40434
- name: name2,
40857
+ name: name3,
40435
40858
  status: _enum2(["with", "planned", "lost"]).default("with"),
40436
40859
  note: text5.nullish()
40437
40860
  }).strict();
40438
40861
  var runUniqueSchema = object({
40439
40862
  ref: ref.nullish(),
40440
- name: name2,
40863
+ name: name3,
40441
40864
  status: _enum2(["have", "now", "want"]).default("have"),
40442
40865
  source: shortText2.nullish(),
40443
40866
  displayAt: shortText2.nullish(),
40444
- set: name2.nullish()
40867
+ set: name3.nullish()
40445
40868
  }).strict();
40446
40869
  var runChecklistSchema = object({
40447
40870
  key: string2().trim().min(1).max(60).regex(/^[a-z0-9][a-z0-9_-]*$/, "must be a lowercase slug"),
40448
- label: name2,
40871
+ label: name3,
40449
40872
  total: number2().int().min(0).max(5000).nullish(),
40450
40873
  items: array(object({ id: ref, label: shortText2.nullish() }).strict()).max(5000).optional(),
40451
40874
  done: array(ref).max(5000),
@@ -40454,7 +40877,7 @@ var runChecklistSchema = object({
40454
40877
  legend: shortText2.nullish()
40455
40878
  }).strict();
40456
40879
  var runTeamMemberSchema = object({
40457
- species: name2,
40880
+ species: name3,
40458
40881
  nick: shortText2.nullish(),
40459
40882
  level: number2().int().min(1).max(100).nullish(),
40460
40883
  nature: shortText2.nullish(),
@@ -40468,8 +40891,8 @@ var runAchievementsSchema = object({
40468
40891
  source: _enum2(["steam", "xbox", "psn", "manual"]).default("manual"),
40469
40892
  total: number2().int().min(0).max(5000).nullish(),
40470
40893
  enabled: boolean2().default(true),
40471
- unlocked: array(object({ name: name2, on: isoDate.nullish(), hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000),
40472
- locked: array(object({ name: name2, hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000).optional(),
40894
+ unlocked: array(object({ name: name3, on: isoDate.nullish(), hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000),
40895
+ locked: array(object({ name: name3, hint: shortText2.nullish(), key: ref.nullish() }).strict()).max(5000).optional(),
40473
40896
  syncedAt: string2().datetime({ offset: true }).nullish()
40474
40897
  }).strict();
40475
40898
  var runRareFindsSchema = object({
@@ -40479,7 +40902,7 @@ var runRareFindsSchema = object({
40479
40902
  }).strict();
40480
40903
  var runInstallSchema = object({
40481
40904
  edition: shortText2.nullish(),
40482
- mods: array(object({ name: name2, url: string2().url().max(2000).nullish() }).strict()).max(200).default([]),
40905
+ mods: array(object({ name: name3, url: string2().url().max(2000).nullish() }).strict()).max(200).default([]),
40483
40906
  savePath: string2().trim().max(500).nullish(),
40484
40907
  lastBackup: isoDate.nullish(),
40485
40908
  notes: text5.nullish()
@@ -40489,7 +40912,7 @@ var runSaveFields = {
40489
40912
  game: _enum2(["skyrim"]).default("skyrim"),
40490
40913
  fileName: shortText2.nullish(),
40491
40914
  saveNumber: number2().int().min(0).max(1e9),
40492
- playerName: name2,
40915
+ playerName: name3,
40493
40916
  level: number2().int().min(0).max(1e4),
40494
40917
  location: shortText2,
40495
40918
  race: shortText2.nullish(),
@@ -40535,7 +40958,7 @@ var runFacetSchema = object({
40535
40958
  install: runInstallSchema.nullish(),
40536
40959
  save: runSaveSchema.nullish(),
40537
40960
  money: object({ goal: shortText2.nullish(), purpose: shortText2.nullish() }).strict().nullish(),
40538
- links: array(object({ label: name2, url: string2().url().max(2000) }).strict()).max(50).optional()
40961
+ links: array(object({ label: name3, url: string2().url().max(2000) }).strict()).max(50).optional()
40539
40962
  }).strict();
40540
40963
  var runListSectionValues = [
40541
40964
  "orderOfPlay",
@@ -40689,12 +41112,12 @@ var runSaveHeaderResultSchema = object({
40689
41112
  var createRunInputSchema = object({
40690
41113
  id: ulidSchema,
40691
41114
  gameId: ulidSchema,
40692
- title: name2,
41115
+ title: name3,
40693
41116
  status: runPlayStatusSchema.optional(),
40694
41117
  facet: runFacetSchema.optional()
40695
41118
  }).strict();
40696
41119
  var updateRunInputSchema = object({
40697
- title: name2.optional(),
41120
+ title: name3.optional(),
40698
41121
  status: runPlayStatusSchema.optional(),
40699
41122
  facet: runFacetSchema.optional()
40700
41123
  }).strict();
@@ -46064,6 +46487,172 @@ var commands2 = [
46064
46487
  return { data: { ok: true, animalId: id }, render: renderRecord };
46065
46488
  }
46066
46489
  },
46490
+ {
46491
+ spec: {
46492
+ path: ["animals", "medicines"],
46493
+ summary: "List the animals' medicines and where each stands today.",
46494
+ args: [],
46495
+ flags: [
46496
+ { name: "animal", type: "string", description: "Only this animal's (ULID)." },
46497
+ {
46498
+ name: "day",
46499
+ type: "string",
46500
+ description: "The day to read for, YYYY-MM-DD (default UTC today)."
46501
+ },
46502
+ { name: "include-ended", type: "boolean", description: "Ended courses too." }
46503
+ ],
46504
+ scopes: [...animalOperations.listMedicines.scopes],
46505
+ returns: "AnimalMedicineView[]",
46506
+ notes: `${routeOf(animalOperations.listMedicines)}. Each with its animals, dose, how often, the course's day N of M, the next day, the stock (low or not), and dueToday / doneToday.`
46507
+ },
46508
+ run: async ({ flags, requireClient }) => {
46509
+ const raw = {};
46510
+ const animal = flagString(flags, "animal");
46511
+ const day = flagString(flags, "day");
46512
+ if (animal)
46513
+ raw.animalId = animal;
46514
+ if (day)
46515
+ raw.day = day;
46516
+ if (flagBool(flags, "include-ended"))
46517
+ raw.includeEnded = "true";
46518
+ parseInput(animalMedicinesQuerySchema, raw);
46519
+ return {
46520
+ data: await requireClient().getPage(pathOf(animalOperations.listMedicines), { query: raw }),
46521
+ render: renderList
46522
+ };
46523
+ }
46524
+ },
46525
+ {
46526
+ spec: {
46527
+ path: ["animals", "medicine"],
46528
+ summary: "One medicine, as it stands today.",
46529
+ args: [{ name: "id", required: true, description: "Medicine ULID." }],
46530
+ flags: [],
46531
+ scopes: [...animalOperations.getMedicine.scopes],
46532
+ returns: "AnimalMedicineView",
46533
+ notes: `${routeOf(animalOperations.getMedicine)}.`
46534
+ },
46535
+ run: readOperation(animalOperations.getMedicine, renderRecord, { medicineId: "medicine id" })
46536
+ },
46537
+ {
46538
+ spec: {
46539
+ path: ["animals", "medicine-add"],
46540
+ summary: "Add a medicine for one animal or a few: daily, a course, or one that comes round.",
46541
+ args: [],
46542
+ flags: [
46543
+ {
46544
+ name: "data",
46545
+ type: "string",
46546
+ description: 'JSON: `{ "title": "Joint tablet", "animalIds": ["\u2026"], "dose": "1 tablet with breakfast", "timeOfDay": "morning", "stock": 22, "unit": "tablets", "lowAt": 5 }`; a course adds `startsOn`/`endsOn`, one that comes round `everyCount`/`everyUnit` (`day`, `week`, `month`) and `nextOn`. The id is minted.'
46547
+ }
46548
+ ],
46549
+ scopes: [...animalOperations.createMedicine.scopes],
46550
+ returns: "AnimalMedicineView",
46551
+ notes: `${routeOf(animalOperations.createMedicine)}. Daily unless said; each dose takes \`perDose\` (default 1) from a counted stock.`
46552
+ },
46553
+ run: async ({ flags, requireClient }) => {
46554
+ const body = parseInput(createAnimalMedicineInputSchema, {
46555
+ id: ulid3(),
46556
+ ...readDataFlag(flags)
46557
+ });
46558
+ return {
46559
+ data: await requireClient().post(pathOf(animalOperations.createMedicine), body),
46560
+ render: renderRecord
46561
+ };
46562
+ }
46563
+ },
46564
+ {
46565
+ spec: {
46566
+ path: ["animals", "medicine-update"],
46567
+ summary: "Change a medicine (a new box: set its stock).",
46568
+ args: [{ name: "id", required: true, description: "Medicine ULID." }],
46569
+ flags: [
46570
+ {
46571
+ name: "data",
46572
+ type: "string",
46573
+ description: "UpdateAnimalMedicineInput JSON; null clears a field."
46574
+ }
46575
+ ],
46576
+ scopes: [...animalOperations.updateMedicine.scopes],
46577
+ returns: "AnimalMedicineView",
46578
+ notes: `${routeOf(animalOperations.updateMedicine)}. \`animalIds\` replaces who it's for.`
46579
+ },
46580
+ run: async ({ args, flags, requireClient }) => {
46581
+ const medicineId = requireArg(args, 0, "medicine id");
46582
+ const body = parseInput(updateAnimalMedicineInputSchema, readDataFlag(flags));
46583
+ return {
46584
+ data: await requireClient().patch(pathOf(animalOperations.updateMedicine, { medicineId }), body),
46585
+ render: renderRecord
46586
+ };
46587
+ }
46588
+ },
46589
+ {
46590
+ spec: {
46591
+ path: ["animals", "medicine-remove"],
46592
+ summary: "Remove a medicine, with the doses given.",
46593
+ args: [{ name: "id", required: true, description: "Medicine ULID." }],
46594
+ flags: [],
46595
+ scopes: [...animalOperations.removeMedicine.scopes],
46596
+ returns: "void",
46597
+ notes: `${routeOf(animalOperations.removeMedicine)}. Destructive: the doses go too, so it needs --allow-destructive; to stop a course and keep it, set its endsOn.`
46598
+ },
46599
+ run: async ({ args, flags, requireClient }) => {
46600
+ const medicineId = requireArg(args, 0, "medicine id");
46601
+ assertDestructiveAllowed(flags, `remove medicine ${medicineId} and its doses`);
46602
+ await requireClient().delete(pathOf(animalOperations.removeMedicine, { medicineId }));
46603
+ return { data: { ok: true, medicineId }, render: renderRecord };
46604
+ }
46605
+ },
46606
+ {
46607
+ spec: {
46608
+ path: ["animals", "medicine-dose"],
46609
+ summary: "Give a medicine's dose (today, or --day).",
46610
+ args: [{ name: "id", required: true, description: "Medicine ULID." }],
46611
+ flags: [
46612
+ {
46613
+ name: "day",
46614
+ type: "string",
46615
+ description: "The day it's for, YYYY-MM-DD (default UTC today)."
46616
+ }
46617
+ ],
46618
+ scopes: [...animalOperations.giveMedicineDose.scopes],
46619
+ returns: "AnimalMedicineView",
46620
+ notes: `${routeOf(animalOperations.giveMedicineDose)}. Takes \`perDose\` from a counted stock and moves the next day on; again that day changes nothing.`
46621
+ },
46622
+ run: async ({ args, flags, requireClient }) => {
46623
+ const medicineId = requireArg(args, 0, "medicine id");
46624
+ const day = flagString(flags, "day");
46625
+ const body = parseInput(animalMedicineDoseInputSchema, day ? { day } : {});
46626
+ return {
46627
+ data: await requireClient().post(pathOf(animalOperations.giveMedicineDose, { medicineId }), body),
46628
+ render: renderRecord
46629
+ };
46630
+ }
46631
+ },
46632
+ {
46633
+ spec: {
46634
+ path: ["animals", "medicine-undose"],
46635
+ summary: "Take a medicine's dose back.",
46636
+ args: [
46637
+ { name: "id", required: true, description: "Medicine ULID." },
46638
+ { name: "day", required: true, description: "The day it was given for, YYYY-MM-DD." }
46639
+ ],
46640
+ flags: [],
46641
+ scopes: [...animalOperations.undoMedicineDose.scopes],
46642
+ returns: "AnimalMedicineView",
46643
+ notes: `${routeOf(animalOperations.undoMedicineDose)}. The stock and the next day go back to before it.`
46644
+ },
46645
+ run: async ({ args, requireClient }) => {
46646
+ const medicineId = requireArg(args, 0, "medicine id");
46647
+ const { day } = parseInput(animalMedicineDoseInputSchema, {
46648
+ day: requireArg(args, 1, "day")
46649
+ });
46650
+ return {
46651
+ data: await requireClient().delete(pathOf(animalOperations.undoMedicineDose, { medicineId, day })),
46652
+ render: renderRecord
46653
+ };
46654
+ }
46655
+ },
46067
46656
  {
46068
46657
  spec: {
46069
46658
  path: ["animals", "acquisition"],
@@ -47132,6 +47721,106 @@ var commands9 = [
47132
47721
  return { data: types, render: renderList };
47133
47722
  }
47134
47723
  },
47724
+ {
47725
+ spec: {
47726
+ path: ["collection", "kinds"],
47727
+ summary: "List the Space's own kinds (vinyl, board games, \u2026) with their fields and words.",
47728
+ args: [],
47729
+ flags: [],
47730
+ scopes: [...collectionOperations.listKinds.scopes],
47731
+ returns: "CollectionKind[]",
47732
+ notes: `${routeOf(collectionOperations.listKinds)}. Each kind's \`key\` is what an Item of it carries as its \`type\`.`
47733
+ },
47734
+ run: async ({ requireClient }) => ({
47735
+ data: await requireClient().getPage(pathOf(collectionOperations.listKinds)),
47736
+ render: renderList
47737
+ })
47738
+ },
47739
+ {
47740
+ spec: {
47741
+ path: ["collection", "kind"],
47742
+ summary: "One of the Space's own kinds.",
47743
+ args: [{ name: "id", required: true, description: "Kind ULID." }],
47744
+ flags: [],
47745
+ scopes: [...collectionOperations.getKind.scopes],
47746
+ returns: "CollectionKind",
47747
+ notes: `${routeOf(collectionOperations.getKind)}.`
47748
+ },
47749
+ run: readOperation(collectionOperations.getKind, renderRecord, { kindId: "kind id" })
47750
+ },
47751
+ {
47752
+ spec: {
47753
+ path: ["collection", "kind-add"],
47754
+ summary: "Add a kind: from a preset (lego, vinyl, board, custom) or from scratch.",
47755
+ args: [{ name: "name", required: true, description: 'Its name ("Vinyl").' }],
47756
+ flags: [
47757
+ {
47758
+ name: "preset",
47759
+ type: "string",
47760
+ description: `Start from ${Object.keys(COLLECTION_KIND_PRESETS).join(", ")}; what's left out comes from it.`
47761
+ },
47762
+ {
47763
+ name: "data",
47764
+ type: "string",
47765
+ description: 'More JSON: `{ "key": "\u2026", "one": "record", "many": "records", "icon": "disc", "fields": [{ "key": "artist", "label": "Artist", "type": "text" }], "statusWords": { \u2026 } }`. The id is minted.'
47766
+ }
47767
+ ],
47768
+ scopes: [...collectionOperations.createKind.scopes],
47769
+ returns: "CollectionKind",
47770
+ notes: `${routeOf(collectionOperations.createKind)}. The key is the name's slug unless given; a key the Space has is a 409. \`do collection kind-add Vinyl --preset vinyl\`.`
47771
+ },
47772
+ run: async ({ args, flags, requireClient }) => {
47773
+ const name = requireArg(args, 0, "name");
47774
+ const preset = flagString(flags, "preset");
47775
+ if (preset)
47776
+ parseInput(collectionKindPresetSchema, preset);
47777
+ const body = parseInput(createCollectionKindInputSchema, {
47778
+ id: ulid3(),
47779
+ name,
47780
+ ...preset ? { preset } : {},
47781
+ ...readDataFlag(flags)
47782
+ });
47783
+ return {
47784
+ data: await requireClient().post(pathOf(collectionOperations.createKind), body),
47785
+ render: renderRecord
47786
+ };
47787
+ }
47788
+ },
47789
+ {
47790
+ spec: {
47791
+ path: ["collection", "kind-update"],
47792
+ summary: "Change a kind: its name, one/many, icon, fields or status words (the key stays).",
47793
+ args: [{ name: "id", required: true, description: "Kind ULID." }],
47794
+ flags: [{ name: "data", type: "string", description: "UpdateCollectionKindInput JSON." }],
47795
+ scopes: [...collectionOperations.updateKind.scopes],
47796
+ returns: "CollectionKind",
47797
+ notes: `${routeOf(collectionOperations.updateKind)}. \`fields\` replaces the list.`
47798
+ },
47799
+ run: async ({ args, flags, requireClient }) => {
47800
+ const kindId = requireArg(args, 0, "kind id");
47801
+ const body = parseInput(updateCollectionKindInputSchema, readDataFlag(flags));
47802
+ return {
47803
+ data: await requireClient().patch(pathOf(collectionOperations.updateKind, { kindId }), body),
47804
+ render: renderRecord
47805
+ };
47806
+ }
47807
+ },
47808
+ {
47809
+ spec: {
47810
+ path: ["collection", "kind-remove"],
47811
+ summary: "Remove a kind that has no Items.",
47812
+ args: [{ name: "id", required: true, description: "Kind ULID." }],
47813
+ flags: [],
47814
+ scopes: [...collectionOperations.removeKind.scopes],
47815
+ returns: "void",
47816
+ notes: `${routeOf(collectionOperations.removeKind)}. A 409 while it still has Items.`
47817
+ },
47818
+ run: async ({ args, requireClient }) => {
47819
+ const kindId = requireArg(args, 0, "kind id");
47820
+ await requireClient().delete(pathOf(collectionOperations.removeKind, { kindId }));
47821
+ return { data: { ok: true, kindId }, render: renderRecord };
47822
+ }
47823
+ },
47135
47824
  {
47136
47825
  spec: {
47137
47826
  path: ["collection", "list"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.391.0",
3
+ "version": "1.393.0",
4
4
  "private": false,
5
5
  "description": "do — the agent-drivable CLI over the public /api/v1 surface",
6
6
  "homepage": "https://github.com/robbeverhelst/do/tree/main/apps/cli",