@robbeverhelst/do 1.284.0 → 1.286.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 +419 -3
  2. package/package.json +1 -1
package/dist/do.js CHANGED
@@ -5096,6 +5096,67 @@ var seatingProposals = pgTable("seating_proposals", {
5096
5096
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5097
5097
  }, (t) => [index("seating_proposals_list_idx").on(t.guestListId)]);
5098
5098
 
5099
+ // ../../packages/schema/src/db/mail.ts
5100
+ var mailCampaignStatus = pgEnum("mail_campaign_status", [
5101
+ "draft",
5102
+ "sending",
5103
+ "sent",
5104
+ "cancelled"
5105
+ ]);
5106
+ var mailDeliveryStatus = pgEnum("mail_delivery_status", [
5107
+ "queued",
5108
+ "sending",
5109
+ "sent",
5110
+ "delivered",
5111
+ "bounced",
5112
+ "failed",
5113
+ "skipped"
5114
+ ]);
5115
+ var mailCampaigns = pgTable("mail_campaigns", {
5116
+ id: text("id").primaryKey(),
5117
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
5118
+ guestListId: text("guest_list_id").references(() => guestLists.id, { onDelete: "cascade" }),
5119
+ kind: text("kind").notNull().default("message"),
5120
+ template: text("template").notNull(),
5121
+ data: jsonb("data").$type().notNull().default({}),
5122
+ replyTo: text("reply_to"),
5123
+ status: mailCampaignStatus("status").notNull().default("draft"),
5124
+ createdByUserId: text("created_by_user_id").references(() => users.id),
5125
+ testSentAt: timestamp("test_sent_at", { withTimezone: true }),
5126
+ startedAt: timestamp("started_at", { withTimezone: true }),
5127
+ finishedAt: timestamp("finished_at", { withTimezone: true }),
5128
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
5129
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
5130
+ }, (t) => [
5131
+ index("mail_campaigns_tenant_idx").on(t.tenantId),
5132
+ index("mail_campaigns_status_idx").on(t.status)
5133
+ ]);
5134
+ var mailDeliveries = pgTable("mail_deliveries", {
5135
+ id: text("id").primaryKey(),
5136
+ tenantId: text("tenant_id").notNull().references(() => tenants.id),
5137
+ campaignId: text("campaign_id").notNull().references(() => mailCampaigns.id, { onDelete: "cascade" }),
5138
+ contactId: text("contact_id").references(() => contacts.id),
5139
+ householdId: text("household_id").references(() => households.id),
5140
+ toEmail: text("to_email").notNull(),
5141
+ language: text("language").notNull().default("nl"),
5142
+ data: jsonb("data").$type().notNull().default({}),
5143
+ status: mailDeliveryStatus("status").notNull().default("queued"),
5144
+ transport: text("transport"),
5145
+ providerMessageId: text("provider_message_id"),
5146
+ attempts: integer("attempts").notNull().default(0),
5147
+ error: text("error"),
5148
+ sentAt: timestamp("sent_at", { withTimezone: true }),
5149
+ deliveredAt: timestamp("delivered_at", { withTimezone: true }),
5150
+ bouncedAt: timestamp("bounced_at", { withTimezone: true }),
5151
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
5152
+ }, (t) => [
5153
+ index("mail_deliveries_campaign_status_idx").on(t.campaignId, t.status),
5154
+ index("mail_deliveries_sent_at_idx").on(t.sentAt),
5155
+ index("mail_deliveries_household_idx").on(t.householdId),
5156
+ uniqueIndex("mail_deliveries_provider_message_uniq").on(t.providerMessageId),
5157
+ uniqueIndex("mail_deliveries_campaign_email_uniq").on(t.campaignId, t.toEmail)
5158
+ ]);
5159
+
5099
5160
  // ../../packages/schema/src/db/calendar.ts
5100
5161
  var calendarLinkPurpose = pgEnum("calendar_link_purpose", ["block", "deadline"]);
5101
5162
  var calendarEventLinks = pgTable("calendar_event_links", {
@@ -25324,7 +25385,8 @@ var runQuestSchema = object({
25324
25385
  }).strict();
25325
25386
  var runNextStepsSchema = object({
25326
25387
  items: array(shortText.pipe(string2().min(1))).max(3),
25327
- pinned: boolean3().default(false)
25388
+ pinned: boolean3().default(false),
25389
+ note: text5.nullish()
25328
25390
  }).strict();
25329
25391
  var runChoiceSchema = object({
25330
25392
  ref: ref.nullish(),
@@ -26008,10 +26070,78 @@ var animalLogInputSchema = discriminatedUnion("kind", [
26008
26070
  occurredAt: occurredAtSchema
26009
26071
  }).strict()
26010
26072
  ]);
26073
+ var animalVetVisitSourceSchema = _enum2(["sticker", "photo", "said"]);
26074
+ var visitTextSchema = string2().trim().min(1).max(120);
26075
+ var visitCostSchema = object({
26076
+ amount: number2().positive().max(1e5),
26077
+ currency: string2().trim().length(3).default("EUR")
26078
+ }).strict();
26079
+ var animalVetVisitInputSchema = object({
26080
+ id: ulidSchema,
26081
+ at: exports_coerce.date().optional(),
26082
+ vetContactId: ulidSchema.optional(),
26083
+ clinician: visitTextSchema.optional(),
26084
+ reason: visitTextSchema.optional(),
26085
+ vaccine: object({ name: visitTextSchema, source: animalVetVisitSourceSchema.optional() }).strict().optional(),
26086
+ dewormer: visitTextSchema.optional(),
26087
+ weight: object({
26088
+ value: number2().positive().max(200000),
26089
+ unit: _enum2(["g", "kg"]).default("kg")
26090
+ }).strict().optional(),
26091
+ nextDates: array(object({
26092
+ id: ulidSchema,
26093
+ label: visitTextSchema,
26094
+ date: string2().regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD")
26095
+ }).strict()).max(5).default([]),
26096
+ files: array(object({ id: ulidSchema, name: visitTextSchema.optional() }).strict()).max(5).default([]),
26097
+ cost: visitCostSchema.optional()
26098
+ }).strict();
26099
+ var animalVetVisitPatchSchema = object({
26100
+ vetContactId: ulidSchema.nullable().optional(),
26101
+ clinician: visitTextSchema.nullable().optional(),
26102
+ reason: visitTextSchema.nullable().optional(),
26103
+ vaccine: object({ name: visitTextSchema, source: animalVetVisitSourceSchema.optional() }).strict().nullable().optional(),
26104
+ dewormer: visitTextSchema.nullable().optional(),
26105
+ cost: visitCostSchema.nullable().optional()
26106
+ }).strict().refine((v) => Object.keys(v).length > 0, { message: "Change at least one field." });
26107
+ var animalVetVisitSchema = object({
26108
+ id: ulidSchema,
26109
+ animal: object({
26110
+ id: ulidSchema,
26111
+ title: string2(),
26112
+ speciesKey: string2().nullable(),
26113
+ speciesClass: animalClassSchema.nullable()
26114
+ }),
26115
+ at: exports_coerce.date(),
26116
+ vet: nodeRefSchema.nullable(),
26117
+ clinician: string2().nullable(),
26118
+ reason: string2().nullable(),
26119
+ vaccine: object({ name: string2(), source: animalVetVisitSourceSchema.nullable() }).nullable(),
26120
+ dewormer: string2().nullable(),
26121
+ weight: object({
26122
+ grams: number2(),
26123
+ deltaGrams: number2().nullable(),
26124
+ since: string2().nullable()
26125
+ }).nullable(),
26126
+ keyDates: array(object({ id: string2(), label: string2(), date: string2() })),
26127
+ files: array(object({ id: string2(), name: string2() })),
26128
+ cost: object({ amount: number2(), currency: string2() }).nullable(),
26129
+ byAgent: boolean3(),
26130
+ undone: boolean3()
26131
+ });
26011
26132
  var animalTimelineEntrySchema = object({
26012
26133
  id: string2(),
26013
26134
  at: exports_coerce.date(),
26014
- kind: _enum2(["weight", "length", "eggs", "note", "period_started", "period_ended", "key_date"]),
26135
+ kind: _enum2([
26136
+ "weight",
26137
+ "length",
26138
+ "eggs",
26139
+ "note",
26140
+ "vet_visit",
26141
+ "period_started",
26142
+ "period_ended",
26143
+ "key_date"
26144
+ ]),
26015
26145
  animalId: ulidSchema,
26016
26146
  animalTitle: string2(),
26017
26147
  value: number2().nullable(),
@@ -26670,6 +26800,124 @@ var thankYouViewSchema = object({
26670
26800
  thanked: array(thankYouGiftSchema)
26671
26801
  });
26672
26802
 
26803
+ // ../../packages/schema/src/contracts/mail.ts
26804
+ var MAIL_LANGUAGES = ["nl", "pt"];
26805
+ var mailLanguageSchema = _enum2(MAIL_LANGUAGES);
26806
+ var MAIL_CAMPAIGN_STATUSES = ["draft", "sending", "sent", "cancelled"];
26807
+ var mailCampaignStatusSchema = _enum2(MAIL_CAMPAIGN_STATUSES);
26808
+ var MAIL_DELIVERY_STATUSES = [
26809
+ "queued",
26810
+ "sending",
26811
+ "sent",
26812
+ "delivered",
26813
+ "bounced",
26814
+ "failed",
26815
+ "skipped"
26816
+ ];
26817
+ var mailDeliveryStatusSchema = _enum2(MAIL_DELIVERY_STATUSES);
26818
+ var mailCampaignSchema = createSelectSchema(mailCampaigns, {
26819
+ data: record(string2(), unknown()),
26820
+ testSentAt: exports_coerce.date().nullable().default(null),
26821
+ startedAt: exports_coerce.date().nullable(),
26822
+ finishedAt: exports_coerce.date().nullable(),
26823
+ createdAt: exports_coerce.date(),
26824
+ updatedAt: exports_coerce.date()
26825
+ });
26826
+ var mailDeliverySchema = createSelectSchema(mailDeliveries, {
26827
+ data: record(string2(), unknown()),
26828
+ sentAt: exports_coerce.date().nullable(),
26829
+ deliveredAt: exports_coerce.date().nullable(),
26830
+ bouncedAt: exports_coerce.date().nullable(),
26831
+ createdAt: exports_coerce.date()
26832
+ });
26833
+ var mailFooterSchema = object({
26834
+ deleteBy: keyDateDaySchema.optional(),
26835
+ contact: email2().max(320).optional()
26836
+ }).strict();
26837
+ var lineSchema = string2().trim().min(1).max(2000);
26838
+ var mailMessageCopySchema = object({
26839
+ subject: string2().trim().min(1).max(200),
26840
+ heading: string2().trim().min(1).max(200),
26841
+ paragraphs: array(lineSchema).max(20).default([]),
26842
+ button: object({ label: string2().trim().min(1).max(80), url: url() }).strict().nullish()
26843
+ }).strict();
26844
+ var mailMessageDataSchema = object({
26845
+ nl: mailMessageCopySchema,
26846
+ pt: mailMessageCopySchema.optional(),
26847
+ footer: mailFooterSchema.optional()
26848
+ }).strict();
26849
+ var mailProviderEventSchema = looseObject({
26850
+ type: string2().min(1),
26851
+ created_at: string2().optional(),
26852
+ data: looseObject({
26853
+ email_id: string2().min(1),
26854
+ to: array(string2()).optional(),
26855
+ bounce: looseObject({
26856
+ type: string2().optional(),
26857
+ message: string2().optional()
26858
+ }).optional()
26859
+ })
26860
+ });
26861
+ var MAIL_CAMPAIGN_KINDS = ["message", "save_the_date", "invitation"];
26862
+ var mailCampaignKindSchema = _enum2(MAIL_CAMPAIGN_KINDS);
26863
+ var MAIL_TEMPLATES = ["message"];
26864
+ var mailTemplateSchema = _enum2(MAIL_TEMPLATES);
26865
+ var mailTemplateDataSchemas = {
26866
+ message: mailMessageDataSchema
26867
+ };
26868
+ function mailTemplateDataError(template, data) {
26869
+ const parsed = mailTemplateDataSchemas[template].safeParse(data);
26870
+ return parsed.success ? null : parsed.error.issues[0]?.message ?? "invalid data";
26871
+ }
26872
+ var replyToSchema = email2().max(320);
26873
+ var createMailCampaignInputSchema = object({
26874
+ id: ulidSchema,
26875
+ guestListId: ulidSchema,
26876
+ kind: mailCampaignKindSchema.default("message"),
26877
+ template: mailTemplateSchema.default("message"),
26878
+ data: record(string2(), unknown()),
26879
+ replyTo: replyToSchema.nullish()
26880
+ }).strict().superRefine((input, ctx) => {
26881
+ const error = mailTemplateDataError(input.template, input.data);
26882
+ if (error)
26883
+ ctx.addIssue({ code: "custom", path: ["data"], message: error });
26884
+ });
26885
+ var updateMailCampaignInputSchema = object({
26886
+ kind: mailCampaignKindSchema.optional(),
26887
+ data: record(string2(), unknown()).optional(),
26888
+ replyTo: replyToSchema.nullish()
26889
+ }).strict();
26890
+ var mailCampaignsQuerySchema = object({ guestListId: ulidSchema }).strict();
26891
+ var mailPreviewQuerySchema = object({ language: mailLanguageSchema.default("nl") }).strict();
26892
+ var mailPreviewSchema = object({
26893
+ language: mailLanguageSchema,
26894
+ subject: string2(),
26895
+ html: string2(),
26896
+ text: string2()
26897
+ });
26898
+ var mailTestResultSchema = object({ to: array(string2()) });
26899
+ var sendMailCampaignInputSchema = object({ households: number2().int().positive() }).strict();
26900
+ var householdMailStatusSchema = _enum2([
26901
+ "queued",
26902
+ "sent",
26903
+ "delivered",
26904
+ "bounced",
26905
+ "failed",
26906
+ "skipped"
26907
+ ]);
26908
+ var mailRecipientHouseholdSchema = object({
26909
+ householdId: string2().nullable(),
26910
+ name: string2(),
26911
+ language: mailLanguageSchema,
26912
+ addresses: number2().int().nonnegative(),
26913
+ status: householdMailStatusSchema.nullable()
26914
+ });
26915
+ var mailCampaignViewSchema = mailCampaignSchema.extend({
26916
+ households: array(mailRecipientHouseholdSchema),
26917
+ counts: partialRecord(mailDeliveryStatusSchema, number2().int().nonnegative()),
26918
+ readyToSend: boolean3()
26919
+ });
26920
+
26673
26921
  // ../../packages/schema/src/contracts/calendar.ts
26674
26922
  var calendarEventLinkSchema = createSelectSchema(calendarEventLinks, {
26675
26923
  createdAt: exports_coerce.date(),
@@ -28370,7 +28618,7 @@ function parseCapture2(input, now) {
28370
28618
 
28371
28619
  // src/meta.ts
28372
28620
  var CLI_NAME = "do";
28373
- var VERSION = "1.284.0";
28621
+ var VERSION = "1.286.0";
28374
28622
  var API_PREFIX = "/api/v1";
28375
28623
  var DEFAULT_API_URL = "http://localhost:3001";
28376
28624
 
@@ -33379,6 +33627,54 @@ var COMMAND_SPECS = [
33379
33627
  returns: "AnimalTimelineEntry",
33380
33628
  notes: 'POST /api/v1/animals/{id}/log (`animal_log`). `do animals log <hens> eggs 2`, `do animals log <dog> weight 37.8 --unit kg`, `do animals log <hen> note "eating again"`. Eggs are the day\'s count: logging again that day replaces it.'
33381
33629
  },
33630
+ {
33631
+ path: ["animals", "vet-visit"],
33632
+ summary: "Log a vet visit in one call: where, the vaccine, the dewormer, the weight, the next dates, the photos, the cost.",
33633
+ args: [{ name: "id", required: true, description: "Animal ULID." }],
33634
+ flags: [
33635
+ {
33636
+ name: "data",
33637
+ type: "string",
33638
+ description: "JSON: { vetContactId?, clinician?, reason?, vaccine?: { name, source? }, dewormer?, weight?: { value, unit? }, nextDates?: [{ label, date }], files?: [{ id, name? }], cost?: { amount, currency? }, at? }. The visit's and each date's ids are minted."
33639
+ }
33640
+ ],
33641
+ scopes: ["animals:write"],
33642
+ returns: "AnimalVetVisit",
33643
+ notes: 'POST /api/v1/animals/{id}/vet-visits (`animal_vet_visit`, mockup 03). The visit is the receipt: post it with `receipt: { nodeId: <visit id> }`. `do animals vet-visit <dog> --data \'{"reason":"booster","vaccine":{"name":"DHPPi + L4","source":"sticker"},"weight":{"value":37.8}}\'`.'
33644
+ },
33645
+ {
33646
+ path: ["animals", "vet-visit-get"],
33647
+ summary: "Read a vet visit as its receipt reads.",
33648
+ args: [{ name: "visitId", required: true, description: "Vet visit ULID." }],
33649
+ flags: [],
33650
+ scopes: ["animals:read"],
33651
+ returns: "AnimalVetVisit",
33652
+ notes: "GET /api/v1/animals/vet-visits/{visitId}."
33653
+ },
33654
+ {
33655
+ path: ["animals", "vet-visit-edit"],
33656
+ summary: "Put a vet visit's fields right (the receipt's Edit).",
33657
+ args: [{ name: "visitId", required: true, description: "Vet visit ULID." }],
33658
+ flags: [
33659
+ {
33660
+ name: "data",
33661
+ type: "string",
33662
+ description: "JSON: any of vetContactId, clinician, reason, vaccine, dewormer, cost (null clears one)."
33663
+ }
33664
+ ],
33665
+ scopes: ["animals:write"],
33666
+ returns: "AnimalVetVisit",
33667
+ notes: "PATCH /api/v1/animals/vet-visits/{visitId}. The newest version wins."
33668
+ },
33669
+ {
33670
+ path: ["animals", "vet-visit-undo"],
33671
+ summary: "Take a vet visit back (the receipt's Undo).",
33672
+ args: [{ name: "visitId", required: true, description: "Vet visit ULID." }],
33673
+ flags: [],
33674
+ scopes: ["animals:write"],
33675
+ returns: "AnimalVetVisit",
33676
+ notes: "POST /api/v1/animals/vet-visits/{visitId}/undo. The visit, its weight, its key dates and the filed photos all go back."
33677
+ },
33382
33678
  {
33383
33679
  path: ["runs", "change"],
33384
33680
  summary: "Apply a chat update to a run: its changes, with a receipt and Undo.",
@@ -33711,6 +34007,61 @@ var COMMAND_SPECS = [
33711
34007
  scopes: ["contacts:write"],
33712
34008
  returns: "SeatingProposal"
33713
34009
  },
34010
+ {
34011
+ path: ["mail-campaigns", "list"],
34012
+ summary: "A guest list's mail campaigns (save-the-dates, invitations), newest first.",
34013
+ args: [],
34014
+ flags: [{ name: "list", type: "string", description: "The guest list's id (required)." }],
34015
+ scopes: ["contacts:read"],
34016
+ returns: "MailCampaignView",
34017
+ notes: "Each campaign carries the households it reaches (a draft: who it would go to) with their status, its mails by status, and readyToSend."
34018
+ },
34019
+ {
34020
+ path: ["mail-campaigns", "get"],
34021
+ summary: "One mail campaign, with its households and how far it got.",
34022
+ args: [{ name: "id", required: true, description: "The campaign's id." }],
34023
+ flags: [],
34024
+ scopes: ["contacts:read"],
34025
+ returns: "MailCampaignView"
34026
+ },
34027
+ {
34028
+ path: ["mail-campaigns", "create"],
34029
+ summary: "Draft a mail campaign for a guest list; nothing is sent.",
34030
+ args: [],
34031
+ flags: [
34032
+ {
34033
+ name: "data",
34034
+ type: "string",
34035
+ description: 'JSON CreateMailCampaignInput, e.g. {"guestListId":"01\u2026","kind":"save_the_date","template":"message","data":{"nl":{"subject":"\u2026","heading":"\u2026","paragraphs":["\u2026"]},"pt":{\u2026},"footer":{"deleteBy":"2027-12-31"}},"replyTo":"hallo@example.com"}'
34036
+ }
34037
+ ],
34038
+ scopes: ["contacts:write"],
34039
+ returns: "MailCampaignView",
34040
+ notes: "Drafting only: a member previews it, sends a test to the Space's members and sends it from the Mail tab. An agent can never test or send."
34041
+ },
34042
+ {
34043
+ path: ["mail-campaigns", "update"],
34044
+ summary: "Edit a draft campaign (its copy, kind or reply address).",
34045
+ args: [{ name: "id", required: true, description: "The campaign's id." }],
34046
+ flags: [
34047
+ {
34048
+ name: "data",
34049
+ type: "string",
34050
+ description: 'JSON UpdateMailCampaignInput, e.g. {"data":{"nl":{\u2026}}}'
34051
+ }
34052
+ ],
34053
+ scopes: ["contacts:write"],
34054
+ returns: "MailCampaignView",
34055
+ notes: "Only a draft changes (409 otherwise); an edit makes the last test stale."
34056
+ },
34057
+ {
34058
+ path: ["mail-campaigns", "preview"],
34059
+ summary: "Draw a campaign's mail as its first household would get it.",
34060
+ args: [{ name: "id", required: true, description: "The campaign's id." }],
34061
+ flags: [{ name: "language", type: "string", description: "nl (default) or pt." }],
34062
+ scopes: ["contacts:read"],
34063
+ returns: "MailPreview"
34064
+ },
33714
34065
  {
33715
34066
  path: ["guest-lists", "thank-you"],
33716
34067
  summary: "The gifts for the event: the cards still to send, then the ones sent.",
@@ -38339,6 +38690,35 @@ var HANDLERS = {
38339
38690
  const body = parseInput(animalLogInputSchema, { ...fact, ...at ? { occurredAt: at } : {} });
38340
38691
  return { data: await requireClient().post(`/animals/${id}/log`, body), render: renderRecord };
38341
38692
  },
38693
+ "animals vet-visit": async ({ args, flags, requireClient }) => {
38694
+ const id = requireArg(args, 0, "animal id");
38695
+ const raw = readDataFlag(flags);
38696
+ const body = parseInput(animalVetVisitInputSchema, {
38697
+ id: ulid3(),
38698
+ ...raw,
38699
+ nextDates: (raw.nextDates ?? []).map((d) => ({ id: ulid3(), ...d }))
38700
+ });
38701
+ return {
38702
+ data: await requireClient().post(`/animals/${id}/vet-visits`, body),
38703
+ render: renderRecord
38704
+ };
38705
+ },
38706
+ "animals vet-visit-get": async ({ args, requireClient }) => ({
38707
+ data: await requireClient().get(`/animals/vet-visits/${requireArg(args, 0, "visit id")}`),
38708
+ render: renderRecord
38709
+ }),
38710
+ "animals vet-visit-edit": async ({ args, flags, requireClient }) => {
38711
+ const visitId = requireArg(args, 0, "visit id");
38712
+ const body = parseInput(animalVetVisitPatchSchema, readDataFlag(flags));
38713
+ return {
38714
+ data: await requireClient().patch(`/animals/vet-visits/${visitId}`, body),
38715
+ render: renderRecord
38716
+ };
38717
+ },
38718
+ "animals vet-visit-undo": async ({ args, requireClient }) => ({
38719
+ data: await requireClient().post(`/animals/vet-visits/${requireArg(args, 0, "visit id")}/undo`, {}),
38720
+ render: renderRecord
38721
+ }),
38342
38722
  "runs change": async ({ args, flags, requireClient }) => {
38343
38723
  const id = requireArg(args, 0, "run id");
38344
38724
  const body = { ...readDataFlag(flags) };
@@ -38860,6 +39240,42 @@ var HANDLERS = {
38860
39240
  render: renderRecord
38861
39241
  };
38862
39242
  },
39243
+ "mail-campaigns list": async ({ flags, requireClient }) => {
39244
+ const list = flagString(flags, "list");
39245
+ if (!list)
39246
+ throw usageError("mail-campaigns list needs --list <guest list id>");
39247
+ parseInput(mailCampaignsQuerySchema, { guestListId: list });
39248
+ return {
39249
+ data: await requireClient().get("/mail-campaigns", { query: { guestListId: list } }),
39250
+ render: renderRecord
39251
+ };
39252
+ },
39253
+ "mail-campaigns get": async ({ args, requireClient }) => {
39254
+ const id = requireArg(args, 0, "campaign id");
39255
+ return { data: await requireClient().get(`/mail-campaigns/${id}`), render: renderRecord };
39256
+ },
39257
+ "mail-campaigns create": async ({ flags, requireClient }) => {
39258
+ const body = parseInput(createMailCampaignInputSchema, { id: ulid3(), ...readDataFlag(flags) });
39259
+ return { data: await requireClient().post("/mail-campaigns", body), render: renderRecord };
39260
+ },
39261
+ "mail-campaigns update": async ({ args, flags, requireClient }) => {
39262
+ const id = requireArg(args, 0, "campaign id");
39263
+ const body = parseInput(updateMailCampaignInputSchema, readDataFlag(flags));
39264
+ return {
39265
+ data: await requireClient().patch(`/mail-campaigns/${id}`, body),
39266
+ render: renderRecord
39267
+ };
39268
+ },
39269
+ "mail-campaigns preview": async ({ args, flags, requireClient }) => {
39270
+ const id = requireArg(args, 0, "campaign id");
39271
+ const query = parseInput(mailPreviewQuerySchema, {
39272
+ language: flagString(flags, "language") ?? "nl"
39273
+ });
39274
+ return {
39275
+ data: await requireClient().get(`/mail-campaigns/${id}/preview`, { query }),
39276
+ render: renderRecord
39277
+ };
39278
+ },
38863
39279
  "guest-lists thank-you": async ({ args, requireClient }) => {
38864
39280
  const id = requireArg(args, 0, "guest list id");
38865
39281
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robbeverhelst/do",
3
- "version": "1.284.0",
3
+ "version": "1.286.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",