@hogsend/cli 0.20.0 → 0.21.1

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
@@ -61,13 +61,13 @@ async function request(baseUrl, key, missingKeyMessage, method, path, opts) {
61
61
  const msg = cause instanceof Error ? cause.message : String(cause);
62
62
  throw makeHttpError(`cannot reach ${baseUrl} (${msg})`, 0, void 0);
63
63
  }
64
- const text3 = await res.text();
64
+ const text4 = await res.text();
65
65
  let parsed;
66
- if (text3.length > 0) {
66
+ if (text4.length > 0) {
67
67
  try {
68
- parsed = JSON.parse(text3);
68
+ parsed = JSON.parse(text4);
69
69
  } catch {
70
- parsed = text3;
70
+ parsed = text4;
71
71
  }
72
72
  }
73
73
  if (!res.ok) {
@@ -149,7 +149,7 @@ function renderTable(rows, columns) {
149
149
  const widths = cols.map(
150
150
  (c) => Math.max(c.length, ...rows.map((r) => cell(r[c]).length))
151
151
  );
152
- const pad = (text3, width) => text3 + " ".repeat(width - text3.length);
152
+ const pad = (text4, width) => text4 + " ".repeat(width - text4.length);
153
153
  const header = cols.map((c, i) => color.bold(pad(c, widths[i] ?? 0))).join(" ");
154
154
  const sep4 = cols.map((_, i) => "-".repeat(widths[i] ?? 0)).join(" ");
155
155
  const body = rows.map((r) => cols.map((c, i) => pad(cell(r[c]), widths[i] ?? 0)).join(" ")).join("\n");
@@ -472,7 +472,7 @@ var campaignsCommand = {
472
472
 
473
473
  // src/commands/connect.ts
474
474
  import { parseArgs as parseArgs2 } from "util";
475
- import { confirm } from "@clack/prompts";
475
+ import { confirm, select, text } from "@clack/prompts";
476
476
 
477
477
  // src/lib/browser.ts
478
478
  import { spawn } from "child_process";
@@ -497,7 +497,7 @@ import { createServer } from "http";
497
497
  // src/lib/oauth.ts
498
498
  import { createHash, randomBytes } from "crypto";
499
499
  var POSTHOG_CLIENT_ID = "https://hogsend.com/.well-known/hogsend-posthog-client.json";
500
- var POSTHOG_SCOPES = "person:read person:write project:read hog_function:write";
500
+ var POSTHOG_SCOPES = "person:read person:write project:read organization:read hog_function:read hog_function:write feature_flag:read cohort:read cohort:write query:read insight:read event_definition:read property_definition:read";
501
501
  var LOOPBACK_PORTS = [8423, 8424, 8425];
502
502
  var CALLBACK_PATH = "/callback";
503
503
  var CALLBACK_TIMEOUT_MS = 3e5;
@@ -584,10 +584,10 @@ async function exchangeCode(opts) {
584
584
  })
585
585
  });
586
586
  if (!res.ok) {
587
- const text3 = await res.text().catch(() => "");
588
- let detail = text3;
587
+ const text4 = await res.text().catch(() => "");
588
+ let detail = text4;
589
589
  try {
590
- const parsed = JSON.parse(text3);
590
+ const parsed = JSON.parse(text4);
591
591
  if (typeof parsed === "object" && parsed !== null && typeof parsed.error === "string") {
592
592
  detail = parsed.error;
593
593
  }
@@ -776,7 +776,10 @@ var ConnectError = class extends Error {
776
776
  this.hint = hint;
777
777
  }
778
778
  };
779
- var HINT_NOT_CONFIGURED = "Set POSTHOG_API_KEY (and POSTHOG_HOST for EU/self-hosted) on the instance, redeploy, then re-run. The server's PostHog config tells the CLI which region to authorize against.";
779
+ var HINT_NOT_CONFIGURED = "Pass --posthog-host https://eu.posthog.com (or https://us.posthog.com, or your self-hosted app URL) to pick the region to authorize against. Alternatively set POSTHOG_HOST on the instance, redeploy, then re-run.";
780
+ var POSTHOG_EU_HOST = "https://eu.posthog.com";
781
+ var POSTHOG_US_HOST = "https://us.posthog.com";
782
+ var normalizeHost = (host) => host.replace(/\/+$/, "");
780
783
  var hintOauthUnsupported = (privateHost) => `${privateHost} doesn't advertise an OAuth server (discovery returned 404).
781
784
  Self-hosted PostHog builds may not ship OAuth. Use a personal API key instead:
782
785
 
@@ -804,12 +807,6 @@ skipped (a destination pointing at localhost would be unreachable).
804
807
  Once deployed, wire the loop against the real instance:
805
808
 
806
809
  hogsend connect posthog --provision-only --url https://your-instance`;
807
- var WEBHOOK_SECRET_NOTE = `Credential stored \u2014 but the PostHog -> Hogsend event loop needs a shared
808
- webhook secret, and this instance doesn't have one yet. Finish the loop:
809
-
810
- 1. Generate a secret: openssl rand -hex 32
811
- 2. Set it on the instance: POSTHOG_WEBHOOK_SECRET=<secret> (api AND worker)
812
- 3. Redeploy, then run: hogsend connect posthog --provision-only`;
813
810
  var errMsg = (err) => err instanceof Error ? err.message : String(err);
814
811
  var httpErrorBody = (err) => {
815
812
  if (!isHttpError(err)) return void 0;
@@ -843,13 +840,6 @@ function fromLoopbackError(err) {
843
840
  }
844
841
  }
845
842
  async function runProvisionOnly(deps, info, base) {
846
- if (info.webhookSecretConfigured === false) {
847
- deps.out.note(WEBHOOK_SECRET_NOTE, "Webhook secret missing");
848
- throw new ConnectError(
849
- "webhook_secret_missing",
850
- "POSTHOG_WEBHOOK_SECRET is not set on the instance \u2014 nothing to provision against"
851
- );
852
- }
853
843
  if (isLoopbackUrl(info.apiPublicUrl)) {
854
844
  deps.out.note(LOOPBACK_URL_NOTE, "Instance not publicly reachable");
855
845
  throw new ConnectError(
@@ -902,24 +892,39 @@ function printProvisioned(out, result) {
902
892
  ].join("\n")
903
893
  );
904
894
  }
895
+ async function resolvePrivateHost(deps, info, opts) {
896
+ if (info.privateHost !== null) {
897
+ return info.privateHost;
898
+ }
899
+ if (opts.posthogHost) {
900
+ return normalizeHost(opts.posthogHost);
901
+ }
902
+ if (deps.interactive) {
903
+ if (deps.selectRegion) {
904
+ return normalizeHost(await deps.selectRegion());
905
+ }
906
+ const useUs = await deps.confirm(
907
+ `Use PostHog US Cloud (${POSTHOG_US_HOST})? (No selects PostHog EU Cloud, ${POSTHOG_EU_HOST})`
908
+ );
909
+ return useUs ? POSTHOG_US_HOST : POSTHOG_EU_HOST;
910
+ }
911
+ throw new ConnectError(
912
+ "not_configured",
913
+ "this instance has no PostHog configuration",
914
+ HINT_NOT_CONFIGURED
915
+ );
916
+ }
905
917
  async function runConnectPosthog(deps, opts) {
906
918
  const base = deps.http.cfg.baseUrl;
907
919
  const info = await deps.out.step(
908
920
  `GET ${base}/v1/admin/analytics/connect-info`,
909
921
  () => deps.http.get("/v1/admin/analytics/connect-info")
910
922
  );
911
- const privateHost = info.privateHost;
912
- if (privateHost === null) {
913
- throw new ConnectError(
914
- "not_configured",
915
- "this instance has no PostHog configuration",
916
- HINT_NOT_CONFIGURED
917
- );
918
- }
919
923
  if (opts.provisionOnly) {
920
924
  return runProvisionOnly(deps, info, base);
921
925
  }
922
- if (info.hostExplicit === false) {
926
+ const privateHost = await resolvePrivateHost(deps, info, opts);
927
+ if (info.privateHost !== null && info.hostExplicit === false) {
923
928
  if (deps.interactive) {
924
929
  const proceed = await deps.confirm(
925
930
  `No POSTHOG_HOST set on the instance \u2014 assume PostHog US Cloud (${privateHost})?`
@@ -1068,6 +1073,13 @@ async function runConnectPosthog(deps, opts) {
1068
1073
  },
1069
1074
  credential: { stored: true, expiresAt }
1070
1075
  };
1076
+ const requestedScopes = POSTHOG_SCOPES.split(" ");
1077
+ const missingScopes = requestedScopes.filter((s) => !scopes.includes(s));
1078
+ if (missingScopes.length > 0) {
1079
+ deps.out.log(
1080
+ `note: PostHog granted ${scopes.length}/${requestedScopes.length} requested scope(s); missing: ${missingScopes.join(", ")}. Re-run \`hogsend connect posthog\` to grant the full set.`
1081
+ );
1082
+ }
1071
1083
  if (opts.noProvision) {
1072
1084
  return {
1073
1085
  verdict: "connected_no_provision",
@@ -1075,14 +1087,6 @@ async function runConnectPosthog(deps, opts) {
1075
1087
  provision: { attempted: false, skipped: "no_provision_flag" }
1076
1088
  };
1077
1089
  }
1078
- if (info.webhookSecretConfigured === false) {
1079
- deps.out.note(WEBHOOK_SECRET_NOTE, "Webhook secret missing");
1080
- return {
1081
- verdict: "connected_no_provision",
1082
- ...stored,
1083
- provision: { attempted: false, skipped: "webhook_secret_missing" }
1084
- };
1085
- }
1086
1090
  if (isLoopbackUrl(info.apiPublicUrl)) {
1087
1091
  deps.out.note(LOOPBACK_URL_NOTE, "Instance not publicly reachable");
1088
1092
  return {
@@ -1135,7 +1139,7 @@ function bail(value) {
1135
1139
  }
1136
1140
 
1137
1141
  // src/commands/connect.ts
1138
- var usage2 = `hogsend connect <provider> [--provision-only] [--no-provision] [--no-browser] [--json]
1142
+ var usage2 = `hogsend connect <provider> [--posthog-host <url>] [--provision-only] [--no-provision] [--no-browser] [--json]
1139
1143
 
1140
1144
  Connect this Hogsend instance to an analytics provider via OAuth. Providers:
1141
1145
 
@@ -1149,6 +1153,10 @@ The browser consent must happen on THIS machine (the OAuth callback lands on
1149
1153
  this command from your laptop, not from an SSH session on the server.
1150
1154
 
1151
1155
  Options:
1156
+ --posthog-host PostHog app/private host to authorize against, e.g.
1157
+ https://eu.posthog.com or https://us.posthog.com (NOT the
1158
+ i. ingestion host). Required when the instance has no
1159
+ PostHog config and you're running non-interactively.
1152
1160
  --provision-only Skip OAuth; (re-)provision the event loop using the
1153
1161
  already-stored credential.
1154
1162
  --no-provision Stop after storing the credential.
@@ -1163,6 +1171,7 @@ async function run2(ctx) {
1163
1171
  allowPositionals: true,
1164
1172
  strict: false,
1165
1173
  options: {
1174
+ "posthog-host": { type: "string" },
1166
1175
  "provision-only": { type: "boolean", default: false },
1167
1176
  "no-provision": { type: "boolean", default: false },
1168
1177
  "no-browser": { type: "boolean", default: false },
@@ -1204,13 +1213,43 @@ async function run2(ctx) {
1204
1213
  exchangeCode,
1205
1214
  openBrowser,
1206
1215
  confirm: async (message) => bail(await confirm({ message })),
1216
+ selectRegion: async () => {
1217
+ const choice = bail(
1218
+ await select({
1219
+ message: "Which PostHog region should Hogsend authorize against?",
1220
+ options: [
1221
+ { value: "https://eu.posthog.com", label: "PostHog EU Cloud" },
1222
+ { value: "https://us.posthog.com", label: "PostHog US Cloud" },
1223
+ { value: "custom", label: "Custom / self-hosted" }
1224
+ ]
1225
+ })
1226
+ );
1227
+ if (choice !== "custom") return choice;
1228
+ return bail(
1229
+ await text({
1230
+ message: "PostHog app/private host URL (e.g. https://posthog.example.com)",
1231
+ placeholder: "https://posthog.example.com",
1232
+ validate: (value) => {
1233
+ try {
1234
+ const url = new URL(value ?? "");
1235
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
1236
+ return "Enter a full URL, e.g. https://posthog.example.com";
1237
+ }
1238
+ } catch {
1239
+ return "Enter a full URL, e.g. https://posthog.example.com";
1240
+ }
1241
+ }
1242
+ })
1243
+ );
1244
+ },
1207
1245
  now: () => /* @__PURE__ */ new Date()
1208
1246
  };
1209
1247
  try {
1210
1248
  const result = await runConnectPosthog(deps, {
1211
1249
  provisionOnly: Boolean(values2["provision-only"]),
1212
1250
  noProvision: Boolean(values2["no-provision"]),
1213
- noBrowser: Boolean(values2["no-browser"])
1251
+ noBrowser: Boolean(values2["no-browser"]),
1252
+ posthogHost: typeof values2["posthog-host"] === "string" ? values2["posthog-host"] : void 0
1214
1253
  });
1215
1254
  if (ctx.json) {
1216
1255
  ctx.out.json({ ok: true, ...result });
@@ -4928,7 +4967,7 @@ import { parseArgs as parseArgs18 } from "util";
4928
4967
 
4929
4968
  // src/commands/studio-admin.ts
4930
4969
  import { parseArgs as parseArgs17 } from "util";
4931
- import { password as passwordPrompt, text as text2 } from "@clack/prompts";
4970
+ import { password as passwordPrompt, text as text3 } from "@clack/prompts";
4932
4971
 
4933
4972
  // ../../node_modules/.pnpm/postgres@3.4.9/node_modules/postgres/src/index.js
4934
4973
  import os from "os";
@@ -5234,7 +5273,7 @@ function values(first, rest, parameters, types2, options) {
5234
5273
  const columns = rest.length ? rest.flat() : Object.keys(multi ? first[0] : first);
5235
5274
  return valuesBuilder(multi ? first : [first], parameters, types2, columns, options);
5236
5275
  }
5237
- function select(first, rest, parameters, types2, options) {
5276
+ function select2(first, rest, parameters, types2, options) {
5238
5277
  typeof first === "string" && (first = [first].concat(rest));
5239
5278
  if (Array.isArray(first))
5240
5279
  return escapeIdentifiers(first, options);
@@ -5251,10 +5290,10 @@ var builders = Object.entries({
5251
5290
  const x = values(...xs);
5252
5291
  return x === "()" ? "(null)" : x;
5253
5292
  },
5254
- select,
5255
- as: select,
5256
- returning: select,
5257
- "\\(": select,
5293
+ select: select2,
5294
+ as: select2,
5295
+ returning: select2,
5296
+ "\\(": select2,
5258
5297
  update(first, rest, parameters, types2, options) {
5259
5298
  return (rest.length ? rest.flat() : Object.keys(first)).map(
5260
5299
  (x) => escapeIdentifier(options.transform.column.to ? options.transform.column.to(x) : x) + "=" + stringifyValue("values", first[x], parameters, types2, options)
@@ -9602,7 +9641,7 @@ var PgText = class extends PgColumn {
9602
9641
  return "text";
9603
9642
  }
9604
9643
  };
9605
- function text(a, b2 = {}) {
9644
+ function text2(a, b2 = {}) {
9606
9645
  const { name, config } = getColumnNameAndConfig(a, b2);
9607
9646
  return new PgTextBuilder(name, config);
9608
9647
  }
@@ -9924,7 +9963,7 @@ function getPgColumnBuilders() {
9924
9963
  serial,
9925
9964
  smallint,
9926
9965
  smallserial,
9927
- text,
9966
+ text: text2,
9928
9967
  time,
9929
9968
  timestamp,
9930
9969
  uuid,
@@ -10933,14 +10972,14 @@ var PgDialect = class {
10933
10972
  const offsetSql = offset ? sql` offset ${offset}` : void 0;
10934
10973
  return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`;
10935
10974
  }
10936
- buildInsertQuery({ table, values: valuesOrSelect, onConflict, returning, withList, select: select2, overridingSystemValue_ }) {
10975
+ buildInsertQuery({ table, values: valuesOrSelect, onConflict, returning, withList, select: select3, overridingSystemValue_ }) {
10937
10976
  const valuesSqlList = [];
10938
10977
  const columns = table[Table.Symbol.Columns];
10939
10978
  const colEntries = Object.entries(columns).filter(([_, col]) => !col.shouldDisableInsert());
10940
10979
  const insertOrder = colEntries.map(
10941
10980
  ([, column]) => sql.identifier(this.casing.getColumnCasing(column))
10942
10981
  );
10943
- if (select2) {
10982
+ if (select3) {
10944
10983
  const select22 = valuesOrSelect;
10945
10984
  if (is(select22, SQL)) {
10946
10985
  valuesSqlList.push(select22);
@@ -12513,10 +12552,10 @@ var PgSelectBase = class extends PgSelectQueryBuilderBase {
12513
12552
  applyMixins(PgSelectBase, [QueryPromise]);
12514
12553
  function createSetOperator(type, isAll) {
12515
12554
  return (leftSelect, rightSelect, ...restSelects) => {
12516
- const setOperators = [rightSelect, ...restSelects].map((select2) => ({
12555
+ const setOperators = [rightSelect, ...restSelects].map((select3) => ({
12517
12556
  type,
12518
12557
  isAll,
12519
- rightSelect: select2
12558
+ rightSelect: select3
12520
12559
  }));
12521
12560
  for (const setOperator of setOperators) {
12522
12561
  if (!haveSameKeys(leftSelect.getSelectedFields(), setOperator.rightSelect.getSelectedFields())) {
@@ -12572,7 +12611,7 @@ var QueryBuilder = class {
12572
12611
  };
12573
12612
  with(...queries) {
12574
12613
  const self = this;
12575
- function select2(fields) {
12614
+ function select3(fields) {
12576
12615
  return new PgSelectBuilder({
12577
12616
  fields: fields ?? void 0,
12578
12617
  session: void 0,
@@ -12596,7 +12635,7 @@ var QueryBuilder = class {
12596
12635
  distinct: { on }
12597
12636
  });
12598
12637
  }
12599
- return { select: select2, selectDistinct, selectDistinctOn };
12638
+ return { select: select3, selectDistinct, selectDistinctOn };
12600
12639
  }
12601
12640
  select(fields) {
12602
12641
  return new PgSelectBuilder({
@@ -12785,21 +12824,21 @@ var PgInsertBuilder = class {
12785
12824
  ).setToken(this.authToken);
12786
12825
  }
12787
12826
  select(selectQuery) {
12788
- const select2 = typeof selectQuery === "function" ? selectQuery(new QueryBuilder()) : selectQuery;
12789
- if (!is(select2, SQL) && !haveSameKeys(this.table[Columns], select2._.selectedFields)) {
12827
+ const select3 = typeof selectQuery === "function" ? selectQuery(new QueryBuilder()) : selectQuery;
12828
+ if (!is(select3, SQL) && !haveSameKeys(this.table[Columns], select3._.selectedFields)) {
12790
12829
  throw new Error(
12791
12830
  "Insert select error: selected fields are not the same or are in a different order compared to the table definition"
12792
12831
  );
12793
12832
  }
12794
- return new PgInsertBase(this.table, select2, this.session, this.dialect, this.withList, true);
12833
+ return new PgInsertBase(this.table, select3, this.session, this.dialect, this.withList, true);
12795
12834
  }
12796
12835
  };
12797
12836
  var PgInsertBase = class extends QueryPromise {
12798
- constructor(table, values2, session2, dialect, withList, select2, overridingSystemValue_) {
12837
+ constructor(table, values2, session2, dialect, withList, select3, overridingSystemValue_) {
12799
12838
  super();
12800
12839
  this.session = session2;
12801
12840
  this.dialect = dialect;
12802
- this.config = { table, values: values2, withList, select: select2, overridingSystemValue_ };
12841
+ this.config = { table, values: values2, withList, select: select3, overridingSystemValue_ };
12803
12842
  }
12804
12843
  static [entityKind] = "PgInsert";
12805
12844
  config;
@@ -13502,7 +13541,7 @@ var PgDatabase = class {
13502
13541
  */
13503
13542
  with(...queries) {
13504
13543
  const self = this;
13505
- function select2(fields) {
13544
+ function select3(fields) {
13506
13545
  return new PgSelectBuilder({
13507
13546
  fields: fields ?? void 0,
13508
13547
  session: self.session,
@@ -13537,7 +13576,7 @@ var PgDatabase = class {
13537
13576
  function delete_(table) {
13538
13577
  return new PgDeleteBase(table, self.session, self.dialect, queries);
13539
13578
  }
13540
- return { select: select2, selectDistinct, selectDistinctOn, update, insert, delete: delete_ };
13579
+ return { select: select3, selectDistinct, selectDistinctOn, update, insert, delete: delete_ };
13541
13580
  }
13542
13581
  select(fields) {
13543
13582
  return new PgSelectBuilder({
@@ -14201,7 +14240,7 @@ var alertRules = pgTable(
14201
14240
  "alert_rules",
14202
14241
  {
14203
14242
  id: uuid("id").defaultRandom().primaryKey(),
14204
- name: text("name").notNull(),
14243
+ name: text2("name").notNull(),
14205
14244
  type: alertRuleTypeEnum("type").notNull(),
14206
14245
  threshold: jsonb("threshold").$type().notNull(),
14207
14246
  channel: alertChannelEnum("channel").notNull(),
@@ -14226,8 +14265,8 @@ var alertHistory = pgTable(
14226
14265
  id: uuid("id").defaultRandom().primaryKey(),
14227
14266
  alertRuleId: uuid("alert_rule_id").notNull().references(() => alertRules.id),
14228
14267
  payload: jsonb("payload").$type(),
14229
- deliveryStatus: text("delivery_status").notNull(),
14230
- error: text("error"),
14268
+ deliveryStatus: text2("delivery_status").notNull(),
14269
+ error: text2("error"),
14231
14270
  ...timestamps
14232
14271
  },
14233
14272
  (table) => [
@@ -14241,12 +14280,12 @@ var apiKeys = pgTable(
14241
14280
  "api_keys",
14242
14281
  {
14243
14282
  id: uuid("id").defaultRandom().primaryKey(),
14244
- organizationId: text("organization_id"),
14245
- name: text("name").notNull(),
14246
- keyPrefix: text("key_prefix").notNull(),
14247
- keyHash: text("key_hash").notNull().unique(),
14283
+ organizationId: text2("organization_id"),
14284
+ name: text2("name").notNull(),
14285
+ keyPrefix: text2("key_prefix").notNull(),
14286
+ keyHash: text2("key_hash").notNull().unique(),
14248
14287
  scopes: jsonb("scopes").$type().notNull().default(["read"]),
14249
- createdBy: text("created_by"),
14288
+ createdBy: text2("created_by"),
14250
14289
  lastUsedAt: timestamp("last_used_at", { withTimezone: true }),
14251
14290
  revokedAt: timestamp("revoked_at", { withTimezone: true }),
14252
14291
  expiresAt: timestamp("expires_at", { withTimezone: true }),
@@ -14263,13 +14302,13 @@ var auditLogs = pgTable(
14263
14302
  "audit_logs",
14264
14303
  {
14265
14304
  id: uuid("id").defaultRandom().primaryKey(),
14266
- actor: text("actor").notNull(),
14305
+ actor: text2("actor").notNull(),
14267
14306
  actorKeyId: uuid("actor_key_id"),
14268
- action: text("action").notNull(),
14269
- resource: text("resource").notNull(),
14270
- resourceId: text("resource_id"),
14307
+ action: text2("action").notNull(),
14308
+ resource: text2("resource").notNull(),
14309
+ resourceId: text2("resource_id"),
14271
14310
  detail: jsonb("detail").$type(),
14272
- ipAddress: text("ip_address"),
14311
+ ipAddress: text2("ip_address"),
14273
14312
  ...timestamps
14274
14313
  },
14275
14314
  (table) => [
@@ -14281,71 +14320,71 @@ var auditLogs = pgTable(
14281
14320
 
14282
14321
  // ../db/src/schema/auth.ts
14283
14322
  var user = pgTable("user", {
14284
- id: text("id").primaryKey(),
14285
- name: text("name").notNull(),
14286
- email: text("email").notNull().unique(),
14323
+ id: text2("id").primaryKey(),
14324
+ name: text2("name").notNull(),
14325
+ email: text2("email").notNull().unique(),
14287
14326
  emailVerified: boolean("email_verified").notNull().default(false),
14288
- image: text("image"),
14327
+ image: text2("image"),
14289
14328
  ...timestamps
14290
14329
  });
14291
14330
  var session = pgTable("session", {
14292
- id: text("id").primaryKey(),
14331
+ id: text2("id").primaryKey(),
14293
14332
  expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
14294
- token: text("token").notNull().unique(),
14295
- ipAddress: text("ip_address"),
14296
- userAgent: text("user_agent"),
14297
- userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
14298
- activeOrganizationId: text("active_organization_id"),
14333
+ token: text2("token").notNull().unique(),
14334
+ ipAddress: text2("ip_address"),
14335
+ userAgent: text2("user_agent"),
14336
+ userId: text2("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
14337
+ activeOrganizationId: text2("active_organization_id"),
14299
14338
  ...timestamps
14300
14339
  });
14301
14340
  var account = pgTable("account", {
14302
- id: text("id").primaryKey(),
14303
- accountId: text("account_id").notNull(),
14304
- providerId: text("provider_id").notNull(),
14305
- userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
14306
- accessToken: text("access_token"),
14307
- refreshToken: text("refresh_token"),
14308
- idToken: text("id_token"),
14341
+ id: text2("id").primaryKey(),
14342
+ accountId: text2("account_id").notNull(),
14343
+ providerId: text2("provider_id").notNull(),
14344
+ userId: text2("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
14345
+ accessToken: text2("access_token"),
14346
+ refreshToken: text2("refresh_token"),
14347
+ idToken: text2("id_token"),
14309
14348
  accessTokenExpiresAt: timestamp("access_token_expires_at", {
14310
14349
  withTimezone: true
14311
14350
  }),
14312
14351
  refreshTokenExpiresAt: timestamp("refresh_token_expires_at", {
14313
14352
  withTimezone: true
14314
14353
  }),
14315
- scope: text("scope"),
14316
- password: text("password"),
14354
+ scope: text2("scope"),
14355
+ password: text2("password"),
14317
14356
  ...timestamps
14318
14357
  });
14319
14358
  var verification = pgTable("verification", {
14320
- id: text("id").primaryKey(),
14321
- identifier: text("identifier").notNull(),
14322
- value: text("value").notNull(),
14359
+ id: text2("id").primaryKey(),
14360
+ identifier: text2("identifier").notNull(),
14361
+ value: text2("value").notNull(),
14323
14362
  expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
14324
14363
  ...timestamps
14325
14364
  });
14326
14365
  var organization = pgTable("organization", {
14327
- id: text("id").primaryKey(),
14328
- name: text("name").notNull(),
14329
- slug: text("slug").unique(),
14330
- logo: text("logo"),
14331
- metadata: text("metadata"),
14366
+ id: text2("id").primaryKey(),
14367
+ name: text2("name").notNull(),
14368
+ slug: text2("slug").unique(),
14369
+ logo: text2("logo"),
14370
+ metadata: text2("metadata"),
14332
14371
  ...timestamps
14333
14372
  });
14334
14373
  var member = pgTable("member", {
14335
- id: text("id").primaryKey(),
14336
- organizationId: text("organization_id").notNull().references(() => organization.id, { onDelete: "cascade" }),
14337
- userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
14338
- role: text("role").notNull().default("member"),
14374
+ id: text2("id").primaryKey(),
14375
+ organizationId: text2("organization_id").notNull().references(() => organization.id, { onDelete: "cascade" }),
14376
+ userId: text2("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
14377
+ role: text2("role").notNull().default("member"),
14339
14378
  ...timestamps
14340
14379
  });
14341
14380
  var invitation = pgTable("invitation", {
14342
- id: text("id").primaryKey(),
14343
- organizationId: text("organization_id").notNull().references(() => organization.id, { onDelete: "cascade" }),
14344
- email: text("email").notNull(),
14345
- role: text("role"),
14346
- status: text("status").notNull().default("pending"),
14381
+ id: text2("id").primaryKey(),
14382
+ organizationId: text2("organization_id").notNull().references(() => organization.id, { onDelete: "cascade" }),
14383
+ email: text2("email").notNull(),
14384
+ role: text2("role"),
14385
+ status: text2("status").notNull().default("pending"),
14347
14386
  expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
14348
- inviterId: text("inviter_id").notNull().references(() => user.id, { onDelete: "cascade" }),
14387
+ inviterId: text2("inviter_id").notNull().references(() => user.id, { onDelete: "cascade" }),
14349
14388
  ...timestamps
14350
14389
  });
14351
14390
 
@@ -14354,12 +14393,12 @@ var bucketConfigs = pgTable(
14354
14393
  "bucket_configs",
14355
14394
  {
14356
14395
  id: uuid("id").defaultRandom().primaryKey(),
14357
- bucketId: text("bucket_id").notNull(),
14396
+ bucketId: text2("bucket_id").notNull(),
14358
14397
  enabled: boolean("enabled").notNull().default(true),
14359
14398
  // Stable hash of the normalized ConditionEval, written at boot. Diffed on the
14360
14399
  // next boot to detect a CRITERIA CHANGE and enqueue the re-evaluation job
14361
14400
  // (Section 6.6 B). Nullable until the first registration.
14362
- criteriaHash: text("criteria_hash"),
14401
+ criteriaHash: text2("criteria_hash"),
14363
14402
  ...timestamps
14364
14403
  },
14365
14404
  (table) => [uniqueIndex("bucket_configs_bucket_id_idx").on(table.bucketId)]
@@ -14371,13 +14410,13 @@ var bucketMemberships = pgTable(
14371
14410
  {
14372
14411
  id: uuid("id").defaultRandom().primaryKey(),
14373
14412
  // multi-tenant insurance (nullable today, NOT in the unique key — see note)
14374
- organizationId: text("organization_id"),
14413
+ organizationId: text2("organization_id"),
14375
14414
  // logical join to contacts.externalId — NO FK (matches userEvents /
14376
14415
  // journeyStates; membership rows can predate a contacts row).
14377
- userId: text("user_id").notNull(),
14378
- userEmail: text("user_email"),
14416
+ userId: text2("user_id").notNull(),
14417
+ userEmail: text2("user_email"),
14379
14418
  // denormalized so emitted events carry it
14380
- bucketId: text("bucket_id").notNull(),
14419
+ bucketId: text2("bucket_id").notNull(),
14381
14420
  status: bucketMembershipStatusEnum("status").notNull().default("active"),
14382
14421
  enteredAt: timestamp("entered_at", { withTimezone: true }).defaultNow().notNull(),
14383
14422
  leftAt: timestamp("left_at", { withTimezone: true }),
@@ -14390,7 +14429,7 @@ var bucketMemberships = pgTable(
14390
14429
  maxDwellAt: timestamp("max_dwell_at", { withTimezone: true }),
14391
14430
  lastEvaluatedAt: timestamp("last_evaluated_at", { withTimezone: true }),
14392
14431
  entryCount: integer("entry_count").notNull().default(1),
14393
- source: text("source"),
14432
+ source: text2("source"),
14394
14433
  // "event" | "reconcile" | "backfill" | "manual"
14395
14434
  context: jsonb("context").$type().default({}),
14396
14435
  // Per-membership dwell bookkeeping. JSON map keyed by dwellLabel → ISO of
@@ -14458,18 +14497,18 @@ var campaigns = pgTable(
14458
14497
  "campaigns",
14459
14498
  {
14460
14499
  id: uuid("id").defaultRandom().primaryKey(),
14461
- organizationId: text("organization_id"),
14462
- name: text("name").notNull(),
14500
+ organizationId: text2("organization_id"),
14501
+ name: text2("name").notNull(),
14463
14502
  // queued | sending | sent | failed
14464
- status: text("status").notNull().default("queued"),
14503
+ status: text2("status").notNull().default("queued"),
14465
14504
  // "list" | "bucket"
14466
- audienceKind: text("audience_kind").notNull(),
14505
+ audienceKind: text2("audience_kind").notNull(),
14467
14506
  // the list id (ListRegistry) or bucket id (BucketRegistry)
14468
- audienceId: text("audience_id").notNull(),
14469
- templateKey: text("template_key").notNull(),
14507
+ audienceId: text2("audience_id").notNull(),
14508
+ templateKey: text2("template_key").notNull(),
14470
14509
  props: jsonb("props").$type().default({}),
14471
- fromEmail: text("from_email"),
14472
- subject: text("subject"),
14510
+ fromEmail: text2("from_email"),
14511
+ subject: text2("subject"),
14473
14512
  /**
14474
14513
  * Optional client-supplied idempotency key (POST /v1/campaigns
14475
14514
  * `Idempotency-Key` header / body field). A retried create with the same key
@@ -14478,7 +14517,7 @@ var campaigns = pgTable(
14478
14517
  * idempotency key, double-sending the blast). Uniqueness is enforced by the
14479
14518
  * partial-unique index below (NULL keys are unconstrained).
14480
14519
  */
14481
- idempotencyKey: text("idempotency_key"),
14520
+ idempotencyKey: text2("idempotency_key"),
14482
14521
  totalRecipients: integer("total_recipients").notNull().default(0),
14483
14522
  sentCount: integer("sent_count").notNull().default(0),
14484
14523
  skippedCount: integer("skipped_count").notNull().default(0),
@@ -14502,7 +14541,7 @@ var contacts = pgTable(
14502
14541
  "contacts",
14503
14542
  {
14504
14543
  id: uuid("id").defaultRandom().primaryKey(),
14505
- organizationId: text("organization_id"),
14544
+ organizationId: text2("organization_id"),
14506
14545
  /**
14507
14546
  * Stable external/distinct id (= the `user_id` text key joined by every
14508
14547
  * contact-referencing table). NULLABLE since D1: contacts can be email-only
@@ -14511,21 +14550,21 @@ var contacts = pgTable(
14511
14550
  * — a soft-deleted loser row must be able to keep its stale external_id
14512
14551
  * until a merge re-points it.
14513
14552
  */
14514
- externalId: text("external_id"),
14515
- email: text("email"),
14553
+ externalId: text2("external_id"),
14554
+ email: text2("email"),
14516
14555
  /**
14517
14556
  * Stable anonymous/distinct id for the future anonymous→identified path.
14518
14557
  * NULLABLE. Like external_id, uniqueness is enforced by a partial-unique
14519
14558
  * index scoped to live, non-deleted rows.
14520
14559
  */
14521
- anonymousId: text("anonymous_id"),
14560
+ anonymousId: text2("anonymous_id"),
14522
14561
  /**
14523
14562
  * Opportunistic IANA-timezone cache (e.g. "America/New_York"). Populated
14524
14563
  * best-effort when a tz is resolved from PostHog person props. PostHog and
14525
14564
  * `properties` jsonb remain authoritative sources — this column sits below
14526
14565
  * them in the resolution precedence, so nothing is blocked on it.
14527
14566
  */
14528
- timezone: text("timezone"),
14567
+ timezone: text2("timezone"),
14529
14568
  properties: jsonb("properties").$type().default({}),
14530
14569
  firstSeenAt: timestamp("first_seen_at", { withTimezone: true }).defaultNow().notNull(),
14531
14570
  lastSeenAt: timestamp("last_seen_at", { withTimezone: true }).defaultNow().notNull(),
@@ -14556,15 +14595,15 @@ var contactAliases = pgTable(
14556
14595
  // The SURVIVOR a stale key resolves TO.
14557
14596
  contactId: uuid("contact_id").notNull().references(() => contacts.id, { onDelete: "cascade" }),
14558
14597
  // 'email' | 'external' | 'anonymous'
14559
- aliasKind: text("alias_kind").notNull(),
14598
+ aliasKind: text2("alias_kind").notNull(),
14560
14599
  // The stale key value (the loser's old external_id / normalized email /
14561
14600
  // anonymous_id).
14562
- aliasValue: text("alias_value").notNull(),
14601
+ aliasValue: text2("alias_value").notNull(),
14563
14602
  // Provenance: the loser contact id this alias came from (nullable — a
14564
14603
  // 'promote' alias may have no distinct loser row).
14565
14604
  fromContactId: uuid("from_contact_id"),
14566
14605
  // 'merge' | 'promote'
14567
- reason: text("reason").notNull(),
14606
+ reason: text2("reason").notNull(),
14568
14607
  ...timestamps
14569
14608
  },
14570
14609
  (table) => [
@@ -14582,10 +14621,10 @@ var deadLetterQueue = pgTable(
14582
14621
  "dead_letter_queue",
14583
14622
  {
14584
14623
  id: uuid("id").defaultRandom().primaryKey(),
14585
- source: text("source").notNull(),
14586
- sourceId: text("source_id"),
14624
+ source: text2("source").notNull(),
14625
+ sourceId: text2("source_id"),
14587
14626
  payload: jsonb("payload").$type().notNull(),
14588
- error: text("error").notNull(),
14627
+ error: text2("error").notNull(),
14589
14628
  retryCount: integer("retry_count").notNull().default(0),
14590
14629
  status: dlqStatusEnum("status").notNull().default("pending"),
14591
14630
  retriedAt: timestamp("retried_at", { withTimezone: true }),
@@ -14603,8 +14642,8 @@ var emailPreferences = pgTable(
14603
14642
  "email_preferences",
14604
14643
  {
14605
14644
  id: uuid("id").defaultRandom().primaryKey(),
14606
- userId: text("user_id").notNull(),
14607
- email: text("email").notNull(),
14645
+ userId: text2("user_id").notNull(),
14646
+ email: text2("email").notNull(),
14608
14647
  unsubscribedAll: boolean("unsubscribed_all").notNull().default(false),
14609
14648
  suppressed: boolean("suppressed").notNull().default(false),
14610
14649
  bounceCount: integer("bounce_count").notNull().default(0),
@@ -14626,15 +14665,15 @@ var journeyStates = pgTable(
14626
14665
  "journey_states",
14627
14666
  {
14628
14667
  id: uuid("id").defaultRandom().primaryKey(),
14629
- organizationId: text("organization_id"),
14630
- userId: text("user_id").notNull(),
14631
- userEmail: text("user_email").notNull(),
14632
- journeyId: text("journey_id").notNull(),
14633
- currentNodeId: text("current_node_id").notNull(),
14668
+ organizationId: text2("organization_id"),
14669
+ userId: text2("user_id").notNull(),
14670
+ userEmail: text2("user_email").notNull(),
14671
+ journeyId: text2("journey_id").notNull(),
14672
+ currentNodeId: text2("current_node_id").notNull(),
14634
14673
  status: journeyStatusEnum("status").notNull().default("active"),
14635
- hatchetRunId: text("hatchet_run_id"),
14674
+ hatchetRunId: text2("hatchet_run_id"),
14636
14675
  context: jsonb("context").$type().default({}),
14637
- errorMessage: text("error_message"),
14676
+ errorMessage: text2("error_message"),
14638
14677
  entryCount: integer("entry_count").notNull().default(1),
14639
14678
  completedAt: timestamp("completed_at", { withTimezone: true }),
14640
14679
  exitedAt: timestamp("exited_at", { withTimezone: true }),
@@ -14672,19 +14711,19 @@ var emailSends = pgTable(
14672
14711
  "email_sends",
14673
14712
  {
14674
14713
  id: uuid("id").defaultRandom().primaryKey(),
14675
- organizationId: text("organization_id"),
14714
+ organizationId: text2("organization_id"),
14676
14715
  journeyStateId: uuid("journey_state_id").references(() => journeyStates.id),
14677
14716
  // Denormalized recipient identity, set at send time. Lets reporting attribute
14678
14717
  // a send to a contact without joining journey_states, and captures journeyless
14679
14718
  // (raw/batch) sends that have no journey linkage. Both nullable.
14680
- userId: text("user_id"),
14681
- userEmail: text("user_email"),
14682
- templateKey: text("template_key"),
14683
- messageId: text("message_id"),
14684
- fromEmail: text("from_email").notNull(),
14685
- toEmail: text("to_email").notNull(),
14686
- subject: text("subject").notNull(),
14687
- category: text("category"),
14719
+ userId: text2("user_id"),
14720
+ userEmail: text2("user_email"),
14721
+ templateKey: text2("template_key"),
14722
+ messageId: text2("message_id"),
14723
+ fromEmail: text2("from_email").notNull(),
14724
+ toEmail: text2("to_email").notNull(),
14725
+ subject: text2("subject").notNull(),
14726
+ category: text2("category"),
14688
14727
  status: emailSendStatusEnum("status").notNull().default("queued"),
14689
14728
  sentAt: timestamp("sent_at", { withTimezone: true }),
14690
14729
  deliveredAt: timestamp("delivered_at", { withTimezone: true }),
@@ -14693,13 +14732,13 @@ var emailSends = pgTable(
14693
14732
  bouncedAt: timestamp("bounced_at", { withTimezone: true }),
14694
14733
  complainedAt: timestamp("complained_at", { withTimezone: true }),
14695
14734
  // Bounce classification from the Resend webhook (hard/soft/transient + reason).
14696
- bounceType: text("bounce_type"),
14697
- bounceReason: text("bounce_reason"),
14735
+ bounceType: text2("bounce_type"),
14736
+ bounceReason: text2("bounce_reason"),
14698
14737
  // Caller-supplied idempotency key (POST /v1/emails). A retry with the same
14699
14738
  // key short-circuits to the prior send instead of dispatching a duplicate —
14700
14739
  // mirrors the user_events idempotency pattern. Nullable: journey/system sends
14701
14740
  // don't set it.
14702
- idempotencyKey: text("idempotency_key"),
14741
+ idempotencyKey: text2("idempotency_key"),
14703
14742
  // Free-form per-send annotations. Set ONLY by test-mode redirected sends
14704
14743
  // today — `{ testMode: true, originalTo: <real recipient> }` — so Studio can
14705
14744
  // flag a TEST row and show who the mail was REALLY for. Nullable: normal
@@ -14735,8 +14774,8 @@ var importJobs = pgTable(
14735
14774
  "import_jobs",
14736
14775
  {
14737
14776
  id: uuid("id").defaultRandom().primaryKey(),
14738
- fileName: text("file_name"),
14739
- format: text("format").notNull(),
14777
+ fileName: text2("file_name"),
14778
+ format: text2("format").notNull(),
14740
14779
  status: importJobStatusEnum("status").notNull().default("pending"),
14741
14780
  totalRows: integer("total_rows"),
14742
14781
  processedRows: integer("processed_rows").notNull().default(0),
@@ -14752,7 +14791,7 @@ var journeyConfigs = pgTable(
14752
14791
  "journey_configs",
14753
14792
  {
14754
14793
  id: uuid("id").defaultRandom().primaryKey(),
14755
- journeyId: text("journey_id").notNull(),
14794
+ journeyId: text2("journey_id").notNull(),
14756
14795
  enabled: boolean("enabled").notNull().default(true),
14757
14796
  ...timestamps
14758
14797
  },
@@ -14767,9 +14806,9 @@ var journeyLogs = pgTable(
14767
14806
  {
14768
14807
  id: uuid("id").defaultRandom().primaryKey(),
14769
14808
  journeyStateId: uuid("journey_state_id").notNull().references(() => journeyStates.id, { onDelete: "cascade" }),
14770
- fromNodeId: text("from_node_id"),
14771
- toNodeId: text("to_node_id"),
14772
- action: text("action").notNull(),
14809
+ fromNodeId: text2("from_node_id"),
14810
+ toNodeId: text2("to_node_id"),
14811
+ action: text2("action").notNull(),
14773
14812
  detail: jsonb("detail").$type(),
14774
14813
  ...timestamps
14775
14814
  },
@@ -14784,12 +14823,12 @@ var trackedLinks = pgTable(
14784
14823
  {
14785
14824
  id: uuid("id").defaultRandom().primaryKey(),
14786
14825
  emailSendId: uuid("email_send_id").notNull().references(() => emailSends.id, { onDelete: "cascade" }),
14787
- originalUrl: text("original_url").notNull(),
14826
+ originalUrl: text2("original_url").notNull(),
14788
14827
  clickCount: integer("click_count").notNull().default(0),
14789
14828
  // Semantic link metadata, lifted from the template's data-hs-* attributes
14790
14829
  // at send time. NULL for plain tracked links. `event` is the consumer event
14791
14830
  // name emitted at click time; `eventProperties` its scalar payload.
14792
- event: text("event"),
14831
+ event: text2("event"),
14793
14832
  eventProperties: jsonb("event_properties").$type(),
14794
14833
  // Set exactly once by the click route when the semantic event is emitted —
14795
14834
  // the per-link emit-once gate today, and the provisional-then-confirm
@@ -14808,8 +14847,8 @@ var linkClicks = pgTable(
14808
14847
  {
14809
14848
  id: uuid("id").defaultRandom().primaryKey(),
14810
14849
  trackedLinkId: uuid("tracked_link_id").notNull().references(() => trackedLinks.id, { onDelete: "cascade" }),
14811
- ipAddress: text("ip_address"),
14812
- userAgent: text("user_agent"),
14850
+ ipAddress: text2("ip_address"),
14851
+ userAgent: text2("user_agent"),
14813
14852
  clickedAt: timestamp("clicked_at", { withTimezone: true }).defaultNow().notNull()
14814
14853
  },
14815
14854
  (table) => [
@@ -14825,11 +14864,11 @@ var providerCredentials = pgTable(
14825
14864
  id: uuid("id").defaultRandom().primaryKey(),
14826
14865
  // e.g. "posthog" — matches an AnalyticsProvider meta.id by convention,
14827
14866
  // but deliberately NOT foreign-keyed: providers are code-defined.
14828
- providerId: text("provider_id").notNull(),
14867
+ providerId: text2("provider_id").notNull(),
14829
14868
  // "oauth" today; "api_key" is the anticipated future kind.
14830
- kind: text("kind").notNull().default("oauth"),
14869
+ kind: text2("kind").notNull().default("oauth"),
14831
14870
  // Encrypted JSON: base64url(iv || ciphertext || gcmTag).
14832
- payload: text("payload").notNull(),
14871
+ payload: text2("payload").notNull(),
14833
14872
  ...timestamps
14834
14873
  },
14835
14874
  (table) => [
@@ -14847,11 +14886,11 @@ var userEvents = pgTable(
14847
14886
  "user_events",
14848
14887
  {
14849
14888
  id: uuid("id").defaultRandom().primaryKey(),
14850
- organizationId: text("organization_id"),
14851
- userId: text("user_id").notNull(),
14852
- event: text("event").notNull(),
14889
+ organizationId: text2("organization_id"),
14890
+ userId: text2("user_id").notNull(),
14891
+ event: text2("event").notNull(),
14853
14892
  properties: jsonb("properties").$type(),
14854
- idempotencyKey: text("idempotency_key"),
14893
+ idempotencyKey: text2("idempotency_key"),
14855
14894
  occurredAt: timestamp("occurred_at", { withTimezone: true }).defaultNow().notNull()
14856
14895
  },
14857
14896
  (table) => [
@@ -14872,15 +14911,15 @@ var webhookEndpoints = pgTable(
14872
14911
  "webhook_endpoints",
14873
14912
  {
14874
14913
  id: uuid("id").defaultRandom().primaryKey(),
14875
- organizationId: text("organization_id"),
14876
- url: text("url").notNull(),
14877
- description: text("description"),
14914
+ organizationId: text2("organization_id"),
14915
+ url: text2("url").notNull(),
14916
+ description: text2("description"),
14878
14917
  // The delivery adapter selector. "webhook" (the default) is the signed
14879
14918
  // Standard-Webhooks POST that existing subscribers receive — byte-identical
14880
14919
  // to before this column existed. Any other value (e.g. "posthog") selects a
14881
14920
  // delivery-time TRANSFORM adapter that reuses the same durable delivery
14882
14921
  // machinery but rewrites url/headers/body for a vendor destination.
14883
- kind: text("kind").notNull().default("webhook"),
14922
+ kind: text2("kind").notNull().default("webhook"),
14884
14923
  // Per-destination configuration for keyed adapters (e.g. PostHog's
14885
14924
  // `{ apiKey, host }`). Null for `kind="webhook"` (it reads `secret` instead).
14886
14925
  // Keyed destinations keep their credentials HERE, not in a fake `whsec_`.
@@ -14889,9 +14928,9 @@ var webhookEndpoints = pgTable(
14889
14928
  // Nullable: only `kind="webhook"` carries a signing secret; keyed
14890
14929
  // destinations authenticate via `config` and the webhook adapter is the only
14891
14930
  // reader of this column.
14892
- secret: text("secret"),
14931
+ secret: text2("secret"),
14893
14932
  // e.g. "whsec_AbCd" — safe to show on list/get. Nullable alongside `secret`.
14894
- secretPrefix: text("secret_prefix"),
14933
+ secretPrefix: text2("secret_prefix"),
14895
14934
  eventTypes: jsonb("event_types").$type().notNull().default([]),
14896
14935
  disabled: boolean("disabled").notNull().default(false),
14897
14936
  // written by the delivery task on a successful (2xx) delivery.
@@ -14912,13 +14951,13 @@ var webhookDeliveries = pgTable(
14912
14951
  id: uuid("id").defaultRandom().primaryKey(),
14913
14952
  endpointId: uuid("endpoint_id").notNull().references(() => webhookEndpoints.id, { onDelete: "cascade" }),
14914
14953
  // denormalized, nullable (MT deferred).
14915
- organizationId: text("organization_id"),
14954
+ organizationId: text2("organization_id"),
14916
14955
  // == Webhook-Id header; ONE per logical event, shared across endpoints +
14917
14956
  // reused across retries.
14918
- webhookId: text("webhook_id").notNull(),
14919
- eventType: text("event_type").notNull(),
14957
+ webhookId: text2("webhook_id").notNull(),
14958
+ eventType: text2("event_type").notNull(),
14920
14959
  // producer-side dedup (idempotencyKey/stateId/emailSendId/...).
14921
- dedupeKey: text("dedupe_key"),
14960
+ dedupeKey: text2("dedupe_key"),
14922
14961
  // the EXACT signed envelope { id, type, timestamp, data }.
14923
14962
  payload: jsonb("payload").$type().notNull(),
14924
14963
  status: webhookDeliveryStatusEnum("status").notNull().default("pending"),
@@ -14927,9 +14966,9 @@ var webhookDeliveries = pgTable(
14927
14966
  lastAttemptAt: timestamp("last_attempt_at", { withTimezone: true }),
14928
14967
  responseStatus: integer("response_status"),
14929
14968
  // truncated to ≤1KB in app.
14930
- responseBodySnippet: text("response_body_snippet"),
14969
+ responseBodySnippet: text2("response_body_snippet"),
14931
14970
  deliveredAt: timestamp("delivered_at", { withTimezone: true }),
14932
- lastError: text("last_error"),
14971
+ lastError: text2("last_error"),
14933
14972
  ...timestamps
14934
14973
  },
14935
14974
  (table) => [
@@ -15386,7 +15425,7 @@ async function resolveEmail(ctx, flags, defaultEmail) {
15386
15425
  ctx.out.fail("--email is required (no TTY to prompt).");
15387
15426
  }
15388
15427
  const value = bail(
15389
- await text2({
15428
+ await text3({
15390
15429
  message: "Admin email",
15391
15430
  placeholder: defaultEmail ?? "admin@example.com",
15392
15431
  initialValue: defaultEmail,