@dench.com/cli 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cron.ts CHANGED
@@ -18,11 +18,9 @@
18
18
  * both formats; we just pass whichever bearer the parent runtime
19
19
  * resolved through `sessionToken`.
20
20
  *
21
- * Convex calls go direct via `ConvexHttpClient` (same pattern as
22
- * `cli/crm.ts`); `run-now` is the one operation that goes through
23
- * the REST API hop (`POST /api/cron/jobs/<id>/run-now`) because it
24
- * needs to start a Vercel Workflow which can only be done from a
25
- * Next.js route.
21
+ * Convex calls generally go direct via `ConvexHttpClient` (same pattern as
22
+ * `cli/crm.ts`). Run-now and delete go through REST: run-now starts a Vercel
23
+ * Workflow, while delete coordinates upstream app-event cleanup.
26
24
  *
27
25
  * Subcommands:
28
26
  * list List all cron jobs in the org.
@@ -166,6 +164,28 @@ async function getJson(
166
164
  return json;
167
165
  }
168
166
 
167
+ async function deleteJson(
168
+ url: string,
169
+ headers: Record<string, string>,
170
+ ): Promise<unknown> {
171
+ const response = await fetch(url, { method: "DELETE", headers });
172
+ const text = await response.text();
173
+ let json: unknown;
174
+ try {
175
+ json = text ? JSON.parse(text) : null;
176
+ } catch {
177
+ json = { raw: text };
178
+ }
179
+ if (!response.ok) {
180
+ const detail =
181
+ json && typeof json === "object" && "error" in json
182
+ ? String((json as Record<string, unknown>).error)
183
+ : JSON.stringify(json);
184
+ throw new CronCliError(`${url} failed (${response.status}): ${detail}`);
185
+ }
186
+ return json;
187
+ }
188
+
169
189
  async function callQuery(
170
190
  ctx: CronCliContext,
171
191
  fn: Parameters<ConvexHttpClient["query"]>[0],
@@ -339,9 +359,6 @@ const createCronTriggerRef = makeFunctionReference<"mutation">(
339
359
  const updateCronTriggerRef = makeFunctionReference<"mutation">(
340
360
  "functions/triggers:updateCronTrigger",
341
361
  );
342
- const deleteCronTriggerRef = makeFunctionReference<"mutation">(
343
- "functions/triggers:deleteCronTrigger",
344
- );
345
362
  const setCronEnabledRef = makeFunctionReference<"mutation">(
346
363
  "functions/triggers:setCronEnabled",
347
364
  );
@@ -709,7 +726,10 @@ async function runUpdate(ctx: CronCliContext): Promise<void> {
709
726
 
710
727
  async function runDelete(ctx: CronCliContext): Promise<void> {
711
728
  const jobId = shift(ctx.args, "job id");
712
- const result = await callMutation(ctx, deleteCronTriggerRef, { jobId });
729
+ const result = await deleteJson(
730
+ `${getApiBase()}/api/cron/jobs/${encodeURIComponent(jobId)}`,
731
+ apiKeyHeaders(ctx.sessionToken ?? ""),
732
+ );
713
733
  out(ctx, result);
714
734
  }
715
735
 
package/email.ts CHANGED
@@ -197,6 +197,8 @@ Usage:
197
197
  dench email identity disable --identity <identityId|email|domain> [--json]
198
198
  dench email identity restore --identity <identityId|email|domain> [--json]
199
199
  dench email identity delete --identity <identityId|email|domain> [--json]
200
+ dench email identity forward --identity <identityId|email> --to inbox@you.com [--json] # forward this sender's sequence replies
201
+ dench email identity forward --identity <identityId|email> --off [--json] # turn forwarding off
200
202
  dench email send --from founder@example.com --to "Ada <ada@x.com>,bob@y.com" --subject "Hi" (--html-file body.html | --text "...") [--cc ...] [--bcc ...] [--from-name "Ada"] [--reply-to support@x.com] [--reply-message-id <messageId|rfc-id>] [--json]
201
203
  dench email message status --message <messageId> [--json]
202
204
  dench email message list [--limit 25] [--json]
@@ -500,6 +502,7 @@ async function runIdentity(ctx: EmailCliContext) {
500
502
  `${identity.identityId} ${identity.fromEmail} type=${identity.type}` +
501
503
  `${identity.domain ? ` domain=${identity.domain}` : ""}` +
502
504
  ` delivery=${identity.deliveryVerificationStatus} workspace=${identity.denchVerificationStatus}` +
505
+ `${identity.forwardRepliesTo ? ` forward=${identity.forwardRepliesTo}` : ""}` +
503
506
  `${identity.disabled ? " DISABLED" : ""}`,
504
507
  )
505
508
  .join("\n");
@@ -545,6 +548,34 @@ async function runIdentity(ctx: EmailCliContext) {
545
548
  out(ctx, payload, text);
546
549
  return;
547
550
  }
551
+ if (sub === "forward") {
552
+ // Configure where a sender's managed sequence replies are forwarded.
553
+ // `--to <email>` turns it on (composed from the verified sender, Reply-To =
554
+ // the prospect); `--off` clears it. Replies are always still captured
555
+ // in-app regardless — forwarding is an extra copy to a chosen inbox.
556
+ const identity = requiredFlag(ctx.args, "--identity");
557
+ const off = hasFlag(ctx.args, "--off");
558
+ const to = off ? "" : (getFlag(ctx.args, "--to")?.trim() ?? "");
559
+ if (!off && !to) {
560
+ throw new Error(
561
+ "Provide --to <email> to forward this sender's replies, or --off to turn forwarding off.",
562
+ );
563
+ }
564
+ const payload = (await callMutation(
565
+ ctx,
566
+ "functions/emailCampaigns:setSenderReplyForward",
567
+ { identity, forwardRepliesTo: to },
568
+ )) as JsonRecord;
569
+ const forwardTo =
570
+ typeof payload.forwardRepliesTo === "string"
571
+ ? payload.forwardRepliesTo
572
+ : null;
573
+ const text = forwardTo
574
+ ? `Replies to ${identity}'s sequences will be forwarded to ${forwardTo}.`
575
+ : `Reply forwarding turned off for ${identity}.`;
576
+ out(ctx, { ok: true, ...payload }, text);
577
+ return;
578
+ }
548
579
  if (sub === "dns") {
549
580
  const identity = requiredFlag(ctx.args, "--identity");
550
581
  if (!identity.includes("@") && !identity.includes(".")) {
@@ -29,6 +29,7 @@ export type CustomOperation = {
29
29
  | "commandsList"
30
30
  | "chatSpawn"
31
31
  | "chatFollow"
32
+ | "cronDelete"
32
33
  | "cronRunNow"
33
34
  | "billingTopup"
34
35
  | "upgrade"
@@ -1895,7 +1896,7 @@ const rawApiOperations = [
1895
1896
  path: "/routines/{jobId}",
1896
1897
  requestSchema: anyObject,
1897
1898
  responseSchema: anyResponse,
1898
- backend: convex("mutation", "functions/triggers:deleteCronTrigger"),
1899
+ backend: custom("cronDelete", "bearer"),
1899
1900
  }),
1900
1901
  op({
1901
1902
  id: "cron.enable",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dench.com/cli",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "Dench agent workspace CLI. v2 unifies auth behind `dench signin`; the legacy `dench login` / `dench onboard` / `dench setup` / `dench what-can-i-do` / `dench register` commands now error with a redirect.",
5
5
  "type": "module",
6
6
  "bin": {