@robbeverhelst/do 1.294.0 → 1.295.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 +158 -7
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -5051,7 +5051,14 @@ var files = pgTable("files", {
5051
5051
  ]);
5052
5052
 
5053
5053
  // ../../packages/schema/src/db/guests.ts
5054
- var guestTier = pgEnum("guest_tier", ["ceremony", "reception", "dinner", "party"]);
5054
+ var guestTier = pgEnum("guest_tier", [
5055
+ "civil",
5056
+ "church",
5057
+ "ceremony",
5058
+ "reception",
5059
+ "dinner",
5060
+ "party"
5061
+ ]);
5055
5062
  var households = pgTable("households", {
5056
5063
  id: text("id").primaryKey().references(() => nodes.id),
5057
5064
  tenantId: text("tenant_id").notNull().references(() => tenants.id),
@@ -5084,6 +5091,23 @@ var guestTables = pgTable("guest_tables", {
5084
5091
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5085
5092
  updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5086
5093
  }, (t) => [index("guest_tables_list_idx").on(t.guestListId)]);
5094
+ var guestListEvents = pgTable("guest_list_events", {
5095
+ id: text("id").primaryKey(),
5096
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
5097
+ guestListId: text("guest_list_id").notNull().references(() => guestLists.id, { onDelete: "cascade" }),
5098
+ key: guestTier("key").notNull(),
5099
+ name: jsonb("name").$type().notNull(),
5100
+ startsAt: timestamp("starts_at", { withTimezone: true }),
5101
+ endsAt: timestamp("ends_at", { withTimezone: true }),
5102
+ placeName: text("place_name"),
5103
+ address: text("address"),
5104
+ mapUrl: text("map_url"),
5105
+ dressCode: jsonb("dress_code").$type(),
5106
+ note: jsonb("note").$type(),
5107
+ sort: integer("sort").notNull().default(0),
5108
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5109
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5110
+ }, (t) => [uniqueIndex("guest_list_events_key_uniq").on(t.guestListId, t.key)]);
5087
5111
  var guests = pgTable("guests", {
5088
5112
  id: text("id").primaryKey(),
5089
5113
  tenantId: text("tenant_id").notNull().references(() => tenants.id),
@@ -25131,6 +25155,7 @@ var insuranceFieldsSchema = object({
25131
25155
  }).partial().strict();
25132
25156
  var contractFieldsSchema = object({
25133
25157
  customerNo: text4,
25158
+ product: text4,
25134
25159
  plan: text4,
25135
25160
  price: amount4,
25136
25161
  cadence: documentCadenceSchema,
@@ -26941,7 +26966,7 @@ var guestListViewSchema = guestListSchema.extend({
26941
26966
  var createGuestListInputSchema = object({
26942
26967
  id: ulidSchema,
26943
26968
  projectId: ulidSchema,
26944
- tiers: array(guestTierSchema).min(1).max(4).optional(),
26969
+ tiers: array(guestTierSchema).min(1).max(6).optional(),
26945
26970
  caps: capsSchema.optional(),
26946
26971
  sides: array(sideSchema).max(4).optional(),
26947
26972
  rsvpBy: keyDateDaySchema.nullish()
@@ -26970,7 +26995,7 @@ var createGuestInputSchema = object({
26970
26995
  guestListId: ulidSchema,
26971
26996
  contactId: ulidSchema,
26972
26997
  side: sideSchema.nullish(),
26973
- tiers: array(guestTierSchema).max(4).optional(),
26998
+ tiers: array(guestTierSchema).max(6).optional(),
26974
26999
  rsvp: answersSchema.optional(),
26975
27000
  plusOne: boolean3().optional(),
26976
27001
  plusOneName: string2().trim().min(1).max(120).nullish(),
@@ -27092,6 +27117,35 @@ var submitRsvpInputSchema = object({
27092
27117
  }).strict()).min(1).max(30),
27093
27118
  address: householdAddressSchema.nullish()
27094
27119
  }).strict();
27120
+ var eventTextSchema = (max) => object({
27121
+ nl: string2().trim().min(1).max(max).optional(),
27122
+ pt: string2().trim().min(1).max(max).optional()
27123
+ }).strict().refine((t) => t.nl !== undefined || t.pt !== undefined, "give it in NL or PT");
27124
+ var guestEventKeySchema = guestTierSchema;
27125
+ var guestListEventSchema = createSelectSchema(guestListEvents, {
27126
+ name: object({ nl: string2().optional(), pt: string2().optional() }),
27127
+ dressCode: object({ nl: string2().optional(), pt: string2().optional() }).nullable(),
27128
+ note: object({ nl: string2().optional(), pt: string2().optional() }).nullable(),
27129
+ startsAt: exports_coerce.date().nullable(),
27130
+ endsAt: exports_coerce.date().nullable(),
27131
+ createdAt: exports_coerce.date(),
27132
+ updatedAt: exports_coerce.date()
27133
+ });
27134
+ var eventFields = {
27135
+ name: eventTextSchema(120),
27136
+ startsAt: exports_coerce.date().nullish(),
27137
+ endsAt: exports_coerce.date().nullish(),
27138
+ placeName: string2().trim().min(1).max(120).nullish(),
27139
+ address: string2().trim().min(1).max(300).nullish(),
27140
+ mapUrl: string2().trim().url().max(500).refine((u) => /^https?:\/\//.test(u), "expected an http(s) link").nullish(),
27141
+ dressCode: eventTextSchema(200).nullish(),
27142
+ note: eventTextSchema(1000).nullish(),
27143
+ sort: number2().int().min(0).max(1e4).optional()
27144
+ };
27145
+ var endsAfterStart2 = (e) => !e.startsAt || !e.endsAt || e.endsAt >= e.startsAt;
27146
+ var createGuestListEventInputSchema = object({ id: ulidSchema, guestListId: ulidSchema, key: guestEventKeySchema, ...eventFields }).strict().refine(endsAfterStart2, { message: "endsAt is before startsAt", path: ["endsAt"] });
27147
+ var updateGuestListEventInputSchema = object(eventFields).partial().strict().refine(endsAfterStart2, { message: "endsAt is before startsAt", path: ["endsAt"] });
27148
+ var guestListEventsQuerySchema = object({ guestListId: ulidSchema });
27095
27149
  var guestTableSchema = createSelectSchema(guestTables, {
27096
27150
  createdAt: exports_coerce.date(),
27097
27151
  updatedAt: exports_coerce.date()
@@ -28881,7 +28935,7 @@ function parseCapture2(input, now) {
28881
28935
 
28882
28936
  // src/meta.ts
28883
28937
  var CLI_NAME = "do";
28884
- var VERSION = "1.294.0";
28938
+ var VERSION = "1.295.0";
28885
28939
  var API_PREFIX = "/api/v1";
28886
28940
  var DEFAULT_API_URL = "http://localhost:3001";
28887
28941
 
@@ -29596,6 +29650,24 @@ var ENTITIES = [
29596
29650
  canDelete: true
29597
29651
  }
29598
29652
  },
29653
+ {
29654
+ name: "guest-list-events",
29655
+ path: "/guest-list-events",
29656
+ readScope: "contacts:read",
29657
+ returns: "GuestListEvent",
29658
+ canGet: true,
29659
+ listFlags: [
29660
+ { name: "list", description: "the guest list's id (required)", query: "guestListId" }
29661
+ ],
29662
+ write: {
29663
+ scope: "contacts:write",
29664
+ createSchema: createGuestListEventInputSchema,
29665
+ createInput: "CreateGuestListEventInput",
29666
+ updateSchema: updateGuestListEventInputSchema,
29667
+ updateInput: "UpdateGuestListEventInput",
29668
+ canDelete: true
29669
+ }
29670
+ },
29599
29671
  {
29600
29672
  name: "guest-tables",
29601
29673
  path: "/guest-tables",
@@ -31736,6 +31808,44 @@ var COMMAND_SPECS = [
31736
31808
  returns: "DoccleStatus",
31737
31809
  notes: "PATCH /api/v1/documents/doccle with { archiveAfterImport }."
31738
31810
  },
31811
+ {
31812
+ path: ["documents", "ask"],
31813
+ summary: "Ask the papers a question (doc_ask): the passages that answer, best first, each with its paper, file and page.",
31814
+ args: [
31815
+ {
31816
+ name: "question",
31817
+ required: true,
31818
+ description: '"Is water damage from a burst pipe covered?"'
31819
+ }
31820
+ ],
31821
+ flags: [
31822
+ { name: "document", type: "string", description: "Ask this paper only (document id)." },
31823
+ {
31824
+ name: "limit",
31825
+ type: "string",
31826
+ description: "How many passages at most (default 5, up to 20)."
31827
+ }
31828
+ ],
31829
+ scopes: ["documents:read"],
31830
+ returns: "DocumentAnswer",
31831
+ notes: "POST /api/v1/documents/ask with { question, documentId?, limit? }. Reads the papers' key fields and their files' text (a page per form feed). do writes no prose: word the answer from the passages, quote the pages, and say it is not legal advice. `withoutText` names the papers with no file text to read. An Only me paper answers only its owner's key with documents:private."
31832
+ },
31833
+ {
31834
+ path: ["documents", "search"],
31835
+ summary: "Search the papers' words (key fields and file text), a passage per hit.",
31836
+ args: [{ name: "words", required: true, description: "The words to find." }],
31837
+ flags: [
31838
+ { name: "document", type: "string", description: "Only this paper (document id)." },
31839
+ {
31840
+ name: "limit",
31841
+ type: "string",
31842
+ description: "How many hits at most (default 20, up to 50)."
31843
+ }
31844
+ ],
31845
+ scopes: ["documents:read"],
31846
+ returns: "{ q, hits: DocumentPassage[] }",
31847
+ notes: "GET /api/v1/documents/search?q=&documentId=&limit=."
31848
+ },
31739
31849
  {
31740
31850
  path: ["documents", "unmatched"],
31741
31851
  summary: "List the papers that ask for money (an amount due) and have no payment linked yet, oldest due first.",
@@ -34415,18 +34525,23 @@ var COMMAND_SPECS = [
34415
34525
  },
34416
34526
  {
34417
34527
  path: ["guest-lists", "export"],
34418
- summary: "Export for the caterer (CSV), the venue (CSV) or the floor plan (PDF) to stdout.",
34528
+ summary: "Export for the caterer (CSV) or the venue (CSV) to stdout, or save the floor plan (PDF) to a file.",
34419
34529
  args: [{ name: "id", required: true, description: "The guest list's id." }],
34420
34530
  flags: [
34421
34531
  {
34422
34532
  name: "kind",
34423
34533
  type: "string",
34424
34534
  description: "caterer (meals and diets per table), venue (who sits where) or floor-plan (PDF)."
34535
+ },
34536
+ {
34537
+ name: "out",
34538
+ type: "string",
34539
+ description: "Where to save the floor plan (default: the name the API gives it)."
34425
34540
  }
34426
34541
  ],
34427
34542
  scopes: ["contacts:read"],
34428
34543
  returns: "string",
34429
- notes: "Redirect to a file: `do guest-lists export <id> --kind floor-plan > plan.pdf`."
34544
+ notes: "A CSV goes to stdout (`> tables.csv`); the floor plan is saved: `do guest-lists export <id> --kind floor-plan --out plan.pdf`."
34430
34545
  },
34431
34546
  {
34432
34547
  path: ["rsvp-links", "list"],
@@ -37531,6 +37646,32 @@ var HANDLERS = {
37531
37646
  render: renderRecord
37532
37647
  };
37533
37648
  },
37649
+ "documents ask": async ({ args, flags, requireClient }) => {
37650
+ const question = args.join(" ").trim();
37651
+ if (!question)
37652
+ throw usageError('documents ask needs a question ("Is water damage covered?")');
37653
+ const limit = flagString(flags, "limit");
37654
+ const body = Object.fromEntries(Object.entries({
37655
+ question,
37656
+ documentId: flagString(flags, "document"),
37657
+ limit: limit === undefined ? undefined : Number(limit)
37658
+ }).filter(([, value]) => value !== undefined));
37659
+ return { data: await requireClient().post("/documents/ask", body), render: renderRecord };
37660
+ },
37661
+ "documents search": async ({ args, flags, requireClient }) => {
37662
+ const q = args.join(" ").trim();
37663
+ if (!q)
37664
+ throw usageError("documents search needs the words to find");
37665
+ const query = Object.fromEntries(Object.entries({
37666
+ q,
37667
+ documentId: flagString(flags, "document"),
37668
+ limit: flagString(flags, "limit")
37669
+ }).filter(([, value]) => value !== undefined));
37670
+ return {
37671
+ data: await requireClient().get("/documents/search", { query }),
37672
+ render: renderRecord
37673
+ };
37674
+ },
37534
37675
  "documents unmatched": async ({ requireClient }) => ({
37535
37676
  data: await requireClient().get("/documents/unmatched"),
37536
37677
  render: renderList
@@ -39682,7 +39823,17 @@ var HANDLERS = {
39682
39823
  "guest-lists export": async ({ args, flags, requireClient }) => {
39683
39824
  const id = requireArg(args, 0, "guest list id");
39684
39825
  const kind = parseInput(guestExportKindSchema, flagString(flags, "kind") ?? "venue");
39685
- const raw = await requireClient().getText(`/guest-lists/${id}/exports/${kind}`);
39826
+ const path = `/guest-lists/${id}/exports/${kind}`;
39827
+ if (kind === "floor-plan") {
39828
+ const file = await requireClient().getBytes(path);
39829
+ const out = flagString(flags, "out") ?? basename2(file.name ?? "floor-plan.pdf");
39830
+ writeFileSync2(out, file.bytes);
39831
+ return {
39832
+ data: { id, kind, saved: out, size: file.bytes.byteLength, type: file.contentType },
39833
+ render: renderRecord
39834
+ };
39835
+ }
39836
+ const raw = await requireClient().getText(path);
39686
39837
  return { raw, data: undefined, render: () => raw };
39687
39838
  },
39688
39839
  "rsvp-links list": async ({ flags, requireClient }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.294.0",
3
+ "version": "1.295.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",