@hogsend/cli 0.25.0 → 0.27.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/dist/bin.js CHANGED
@@ -545,10 +545,15 @@ async function runConnectDiscord(deps, opts) {
545
545
  ` secrets stored ${info.credentialStored ? "yes" : "no"}`,
546
546
  ` interactions ${info.botInstalled ? "wired" : "not wired"}`,
547
547
  ` guild id ${info.guildId ?? "(not yet captured)"}`,
548
- ` ingress secret ${info.ingressSecretConfigured ? "set" : "unset"}`,
548
+ ` worker online ${info.workerOnline ? "yes" : "no"}`,
549
549
  ` install url ${info.installUrl ?? "(stored secrets first)"}`
550
550
  ].join("\n")
551
551
  );
552
+ if (info.credentialStored && !info.workerOnline) {
553
+ deps.out.log(
554
+ "Worker offline: set DISCORD_BOT_TOKEN + the API's REDIS_URL on the worker service and redeploy. If it stays offline with the token set, enable the 3 privileged gateway intents in the Discord portal."
555
+ );
556
+ }
552
557
  return {
553
558
  verdict: info.botInstalled ? "connected" : "secrets_stored_not_wired",
554
559
  providerId: "discord",
@@ -587,6 +592,13 @@ async function runConnectDiscord(deps, opts) {
587
592
  })
588
593
  );
589
594
  } catch (err) {
595
+ if (isHttpError(err) && err.status === 404) {
596
+ throw new ConnectDiscordError(
597
+ "store_failed",
598
+ "this instance has not mounted the Discord admin routes (PUT /v1/admin/connectors/discord/secrets returned 404)",
599
+ "Mount the consumer /secrets + /wire routes \u2014 see docs/connect-discord-consumer-routes.md."
600
+ );
601
+ }
590
602
  throw new ConnectDiscordError("store_failed", errMsg(err));
591
603
  }
592
604
  const stored = await deps.out.step(
@@ -628,6 +640,13 @@ Wire it against your deployed instance:
628
640
  HINT_LOOPBACK
629
641
  );
630
642
  }
643
+ if (isHttpError(err) && err.status === 404) {
644
+ throw new ConnectDiscordError(
645
+ "wire_failed",
646
+ "this instance has not mounted the Discord /wire route (404)",
647
+ "Mount the consumer /secrets + /wire routes \u2014 see docs/connect-discord-consumer-routes.md."
648
+ );
649
+ }
631
650
  throw new ConnectDiscordError("wire_failed", errMsg(err));
632
651
  }
633
652
  let opened = false;
@@ -14447,6 +14466,7 @@ __export(schema_exports, {
14447
14466
  journeyStatusEnum: () => journeyStatusEnum,
14448
14467
  linkClicks: () => linkClicks,
14449
14468
  linkClicksRelations: () => linkClicksRelations,
14469
+ links: () => links,
14450
14470
  member: () => member,
14451
14471
  memberRelations: () => memberRelations,
14452
14472
  organization: () => organization,
@@ -15169,6 +15189,40 @@ var journeyLogs = pgTable(
15169
15189
  ]
15170
15190
  );
15171
15191
 
15192
+ // ../db/src/schema/links.ts
15193
+ var links = pgTable(
15194
+ "links",
15195
+ {
15196
+ id: uuid("id").defaultRandom().primaryKey(),
15197
+ originalUrl: text2("original_url").notNull(),
15198
+ // "personal" = single-recipient, identity-bearing (carries `distinctId`, may
15199
+ // mint a SINGLE-USE `hs_t`); "public" = shareable, NEVER carries a person
15200
+ // token (campaign/UTM attribution only). Default "public" — the safe default.
15201
+ type: text2("type").notNull().default("public"),
15202
+ // Operator-facing name (Studio list).
15203
+ label: text2("label"),
15204
+ // UTM-style campaign grouping for public links.
15205
+ campaign: text2("campaign"),
15206
+ // Originating channel: "studio" | "discord" | "sms" | … (open string).
15207
+ source: text2("source").notNull(),
15208
+ // The canonical contact key a click should stitch the visitor's anon session
15209
+ // into — set ONLY for personal links; NULL for public/broadcast (a shareable
15210
+ // link must never carry a person).
15211
+ distinctId: text2("distinct_id"),
15212
+ // The admin actor who minted it (mirrors api_keys.createdBy).
15213
+ createdBy: text2("created_by"),
15214
+ // Soft-delete: archive (not hard-delete) so historical `link_clicks` survive
15215
+ // (the `tracked_links.link_id` FK is ON DELETE set null as a backstop).
15216
+ archivedAt: timestamp("archived_at", { withTimezone: true }),
15217
+ ...timestamps
15218
+ },
15219
+ (table) => [
15220
+ index("links_source_idx").on(table.source),
15221
+ index("links_campaign_idx").on(table.campaign),
15222
+ index("links_created_at_idx").on(table.createdAt)
15223
+ ]
15224
+ );
15225
+
15172
15226
  // ../db/src/schema/tracked-links.ts
15173
15227
  var trackedLinks = pgTable(
15174
15228
  "tracked_links",
@@ -15181,6 +15235,13 @@ var trackedLinks = pgTable(
15181
15235
  emailSendId: uuid("email_send_id").references(() => emailSends.id, {
15182
15236
  onDelete: "cascade"
15183
15237
  }),
15238
+ // The managed `links` row this click-counter belongs to, when the link was
15239
+ // minted via `mintLink` (Studio / Discord / share links). NULL for email's
15240
+ // per-send rewritten links (they resolve identity from `email_sends`). ON
15241
+ // DELETE set null so archiving/removing a `links` row keeps the click spine.
15242
+ linkId: uuid("link_id").references(() => links.id, {
15243
+ onDelete: "set null"
15244
+ }),
15184
15245
  // Subject of a stitch-bearing NON-email link: the canonical contact key the
15185
15246
  // click should fold the visitor's anon session into. NULL for broadcast
15186
15247
  // links (Discord/referral default) — broadcast links are tracked for click
@@ -15206,7 +15267,10 @@ var trackedLinks = pgTable(
15206
15267
  }),
15207
15268
  ...timestamps
15208
15269
  },
15209
- (table) => [index("tracked_links_email_send_id_idx").on(table.emailSendId)]
15270
+ (table) => [
15271
+ index("tracked_links_email_send_id_idx").on(table.emailSendId),
15272
+ index("tracked_links_link_id_idx").on(table.linkId)
15273
+ ]
15210
15274
  );
15211
15275
 
15212
15276
  // ../db/src/schema/link-clicks.ts