@columnus/shared 0.1.63 → 0.2.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.
@@ -1,22 +1,26 @@
1
- export declare function coolifyHostnameFromEnv(env?: NodeJS.ProcessEnv): string | null;
2
- /**
3
- * Browser origin Better Auth expects on server-side OTP probes.
4
- * Preview configure sets SITE_URL to `https://<coolify-host>`; Origin must match.
5
- * Coolify often injects `COOLIFY_URL=http://…` — do not use that scheme.
6
- */
1
+ /** Canonical Kubernetes preview PR identity (matches columnus-pr-N namespaces). */
2
+ export declare const PREVIEW_PR_ID_RE: RegExp;
3
+ export declare const PREVIEW_TENANT_SLUG_PREFIX = "preview-";
4
+ export declare function isPreviewTenantSlug(slug: string): boolean;
5
+ /** Explicit application origin used by CI and runtime preview routing. */
6
+ export declare function previewHostnameFromEnv(env?: NodeJS.ProcessEnv): string | null;
7
+ /** Browser origin for server-side auth probes; never use a Convex HTTP endpoint. */
7
8
  export declare function resolveTrustedAuthOrigin(env?: NodeJS.ProcessEnv): string | undefined;
8
- /** True when Coolify (or CI_PREVIEW) indicates a PR preview Docker build. */
9
+ /** CI_PREVIEW is the local build mode; COLUMNUS_PREVIEW identifies deployed previews. */
9
10
  export declare function isCiPreviewBuild(env?: NodeJS.ProcessEnv): boolean;
11
+ /** Domain suffix only from a recognized preview host, never from branch identity. */
12
+ export declare function previewZoneFromEnv(env?: NodeJS.ProcessEnv): string | null;
10
13
  /** PR id from `preview-<n>.<domain>` / `manage-preview-<n>` hostname or `pull/<n>/head` branch. */
11
14
  export declare function resolvePreviewPrId(env?: NodeJS.ProcessEnv): string | null;
12
- /**
13
- * Resolve the git branch used for Convex `--preview-name`.
14
- * Coolify often sets COOLIFY_BRANCH to `pull/<n>/head` at runtime (see coollabsio/coolify#9572).
15
- */
15
+ /** Resolve the CI git branch used for Convex preview deployment naming. */
16
16
  export declare function resolvePreviewBranch(env?: NodeJS.ProcessEnv): string | null;
17
17
  export declare function sanitizePreviewDeployName(branch: string): string;
18
18
  /** Normalize a preview name from Convex env before `convex deploy --preview-name`. */
19
19
  export declare function normalizePreviewDeployName(name: string): string;
20
+ /** Identifier rule shared by CI configuration and Management registration. */
21
+ export declare const PREVIEW_DEPLOY_NAME_RE: RegExp;
22
+ /** Explicit CI identity, including hostless Management builds. */
23
+ export declare function explicitPreviewDeployName(env?: NodeJS.ProcessEnv): string | null;
20
24
  export declare function ciPreviewDeployName(env?: NodeJS.ProcessEnv): string | null;
21
25
  /** Stale failures from broken preview deploy before the bridge was live. */
22
26
  export declare const STALE_ENDPOINT_DEPLOY_ERROR: RegExp;
@@ -1,54 +1,44 @@
1
1
  // packages/@columnus/shared/src/previewDeployName.ts
2
- function hostnameFromCoolifyToken(raw) {
3
- const token = raw.trim();
4
- if (!token || /^https?:?$/i.test(token)) return null;
2
+ var PREVIEW_PR_ID_RE = /^[1-9][0-9]{0,6}$/;
3
+ var PREVIEW_TENANT_SLUG_PREFIX = "preview-";
4
+ function isPreviewTenantSlug(slug) {
5
+ return slug.startsWith(PREVIEW_TENANT_SLUG_PREFIX);
6
+ }
7
+ function previewHostnameFromEnv(env = process.env) {
8
+ const origin = resolveTrustedAuthOrigin(env);
9
+ if (!origin) return null;
5
10
  try {
6
- if (/^[a-z][a-z0-9+.-]*:\/\//i.test(token)) {
7
- return new URL(token).hostname || null;
8
- }
11
+ return new URL(origin).hostname;
9
12
  } catch {
10
13
  return null;
11
14
  }
12
- const host = token.split("/")[0]?.split(":")[0] ?? "";
13
- if (!host || !host.includes(".") && host !== "localhost") return null;
14
- return host;
15
- }
16
- function coolifyHostnameFromEnv(env = process.env) {
17
- const raw = env.COOLIFY_FQDN ?? env.COOLIFY_URL;
18
- if (!raw) return null;
19
- for (const part of raw.split(",")) {
20
- const host = hostnameFromCoolifyToken(part);
21
- if (host) return host;
22
- }
23
- return null;
24
15
  }
25
16
  function resolveTrustedAuthOrigin(env = process.env) {
26
17
  const explicit = env.COLUMNUS_AUTH_ORIGIN?.trim();
27
18
  if (explicit) return explicit.replace(/\/$/, "");
28
- const host = coolifyHostnameFromEnv(env);
29
- if (host) return `https://${host}`;
30
19
  const siteUrl = env.SITE_URL?.trim();
31
- if (siteUrl && !/\.convex\.site(?:\/|$)/i.test(siteUrl)) {
32
- return siteUrl.replace(/\/$/, "");
33
- }
20
+ if (siteUrl && !/\.convex\.site(?:\/|$)/i.test(siteUrl)) return siteUrl.replace(/\/$/, "");
34
21
  return void 0;
35
22
  }
36
23
  function isCiPreviewBuild(env = process.env) {
37
- if (env.CI_PREVIEW === "true" || env.COOLIFY_IS_PREVIEW === "true") {
38
- return true;
39
- }
40
- const host = coolifyHostnameFromEnv(env);
41
- return Boolean(host && /^(?:manage-|deploy-|renderer-)?preview-\d+\./.test(host));
24
+ if (env.CI_PREVIEW === "true" || env.COLUMNUS_PREVIEW === "true") return true;
25
+ const host = previewHostnameFromEnv(env);
26
+ return Boolean(host && PREVIEW_HOST_PR_RE.test(host));
42
27
  }
43
28
  var PULL_HEAD_BRANCH_RE = /^pull\/(\d+)\/head$/i;
44
29
  var PREVIEW_HOST_PR_RE = /^(?:manage-|deploy-|renderer-)?preview-(\d+)\./;
30
+ function previewZoneFromEnv(env = process.env) {
31
+ const host = previewHostnameFromEnv(env);
32
+ const prefix = host ? PREVIEW_HOST_PR_RE.exec(host)?.[0] : void 0;
33
+ return host && prefix ? host.slice(prefix.length) || null : null;
34
+ }
45
35
  function resolvePreviewPrId(env = process.env) {
46
- const host = coolifyHostnameFromEnv(env);
36
+ const host = previewHostnameFromEnv(env);
47
37
  if (host) {
48
38
  const fromHost = PREVIEW_HOST_PR_RE.exec(host)?.[1];
49
39
  if (fromHost) return fromHost;
50
40
  }
51
- const branch = env.COOLIFY_BRANCH ?? env.GIT_BRANCH;
41
+ const branch = env.GIT_BRANCH;
52
42
  if (branch) {
53
43
  const fromBranch = PULL_HEAD_BRANCH_RE.exec(stripQualifiedBranch(branch))?.[1];
54
44
  if (fromBranch) return fromBranch;
@@ -57,7 +47,7 @@ function resolvePreviewPrId(env = process.env) {
57
47
  }
58
48
  function resolvePreviewBranch(env = process.env) {
59
49
  if (env.GITHUB_HEAD_REF) return stripQualifiedBranch(env.GITHUB_HEAD_REF);
60
- const branch = env.COOLIFY_BRANCH ?? env.GIT_BRANCH;
50
+ const branch = env.GIT_BRANCH;
61
51
  const prId = resolvePreviewPrId(env);
62
52
  if (!branch) {
63
53
  return prId ? `preview-${prId}` : null;
@@ -81,8 +71,19 @@ function sanitizePreviewDeployName(branch) {
81
71
  function normalizePreviewDeployName(name) {
82
72
  return sanitizePreviewDeployName(name.trim());
83
73
  }
74
+ var PREVIEW_DEPLOY_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
75
+ function explicitPreviewDeployName(env = process.env) {
76
+ const name = env.CONVEX_PREVIEW_NAME?.trim();
77
+ if (!name) return null;
78
+ if (!PREVIEW_DEPLOY_NAME_RE.test(name)) {
79
+ throw new Error("CONVEX_PREVIEW_NAME must be a 1\u201364 character preview identifier");
80
+ }
81
+ return name;
82
+ }
84
83
  function ciPreviewDeployName(env = process.env) {
85
84
  if (!isCiPreviewBuild(env)) return null;
85
+ const explicit = explicitPreviewDeployName(env);
86
+ if (explicit) return explicit;
86
87
  const branch = resolvePreviewBranch(env);
87
88
  if (!branch) return null;
88
89
  return sanitizePreviewDeployName(branch);
@@ -100,6 +101,6 @@ function isRecoverableDeployError(error) {
100
101
  return error.includes("convex/bin/main.js") || error.includes("convex CLI (bin/main.js") || error.includes("convex CLI not available");
101
102
  }
102
103
 
103
- export { STALE_ENDPOINT_DEPLOY_ERROR, ciPreviewDeployName, coolifyHostnameFromEnv, isCiPreviewBuild, isRecoverableDeployError, isStaleEndpointDeployError, normalizePreviewDeployName, resolvePreviewBranch, resolvePreviewPrId, resolveTrustedAuthOrigin, sanitizePreviewDeployName };
104
+ export { PREVIEW_DEPLOY_NAME_RE, PREVIEW_PR_ID_RE, PREVIEW_TENANT_SLUG_PREFIX, STALE_ENDPOINT_DEPLOY_ERROR, ciPreviewDeployName, explicitPreviewDeployName, isCiPreviewBuild, isPreviewTenantSlug, isRecoverableDeployError, isStaleEndpointDeployError, normalizePreviewDeployName, previewHostnameFromEnv, previewZoneFromEnv, resolvePreviewBranch, resolvePreviewPrId, resolveTrustedAuthOrigin, sanitizePreviewDeployName };
104
105
  //# sourceMappingURL=previewDeployName.js.map
105
106
  //# sourceMappingURL=previewDeployName.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/previewDeployName.ts"],"names":[],"mappings":"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","file":"previewDeployName.js","sourcesContent":["/**\n * Sanitized Convex preview deployment name for CI / Coolify preview builds.\n * \"/\" breaks preview/<name> lookups in Convex deployment references.\n *\n * Coolify preview env vars: COOLIFY_BRANCH, COOLIFY_IS_PREVIEW, COOLIFY_FQDN,\n * COOLIFY_URL (BuildKit build secrets).\n *\n * Production Coolify often injects a comma-separated FQDN/URL list\n * (`app.columnus.app,bro.columnus.app,…`). Take the first valid hostname —\n * Better Auth Origin must be a single origin, not the whole list.\n */\nfunction hostnameFromCoolifyToken(raw: string): string | null {\n const token = raw.trim();\n if (!token || /^https?:?$/i.test(token)) return null;\n\n try {\n if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(token)) {\n return new URL(token).hostname || null;\n }\n } catch {\n return null;\n }\n\n const host = token.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n if (!host || (!host.includes(\".\") && host !== \"localhost\")) return null;\n return host;\n}\n\nexport function coolifyHostnameFromEnv(env: NodeJS.ProcessEnv = process.env): string | null {\n const raw = env.COOLIFY_FQDN ?? env.COOLIFY_URL;\n if (!raw) return null;\n for (const part of raw.split(\",\")) {\n const host = hostnameFromCoolifyToken(part);\n if (host) return host;\n }\n return null;\n}\n\n/**\n * Browser origin Better Auth expects on server-side OTP probes.\n * Preview configure sets SITE_URL to `https://<coolify-host>`; Origin must match.\n * Coolify often injects `COOLIFY_URL=http://…` — do not use that scheme.\n */\nexport function resolveTrustedAuthOrigin(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const explicit = env.COLUMNUS_AUTH_ORIGIN?.trim();\n if (explicit) return explicit.replace(/\\/$/, \"\");\n\n const host = coolifyHostnameFromEnv(env);\n if (host) return `https://${host}`;\n\n const siteUrl = env.SITE_URL?.trim();\n if (siteUrl && !/\\.convex\\.site(?:\\/|$)/i.test(siteUrl)) {\n return siteUrl.replace(/\\/$/, \"\");\n }\n return undefined;\n}\n\n/** True when Coolify (or CI_PREVIEW) indicates a PR preview Docker build. */\nexport function isCiPreviewBuild(env: NodeJS.ProcessEnv = process.env): boolean {\n if (env.CI_PREVIEW === \"true\" || env.COOLIFY_IS_PREVIEW === \"true\") {\n return true;\n }\n const host = coolifyHostnameFromEnv(env);\n // preview-<pr>, manage-preview-<pr>, deploy-preview-<pr>, renderer-preview-<pr>\n return Boolean(host && /^(?:manage-|deploy-|renderer-)?preview-\\d+\\./.test(host));\n}\n\nconst PULL_HEAD_BRANCH_RE = /^pull\\/(\\d+)\\/head$/i;\nconst PREVIEW_HOST_PR_RE = /^(?:manage-|deploy-|renderer-)?preview-(\\d+)\\./;\n\n/** PR id from `preview-<n>.<domain>` / `manage-preview-<n>` hostname or `pull/<n>/head` branch. */\nexport function resolvePreviewPrId(env: NodeJS.ProcessEnv = process.env): string | null {\n const host = coolifyHostnameFromEnv(env);\n if (host) {\n const fromHost = PREVIEW_HOST_PR_RE.exec(host)?.[1];\n if (fromHost) return fromHost;\n }\n\n const branch = env.COOLIFY_BRANCH ?? env.GIT_BRANCH;\n if (branch) {\n const fromBranch = PULL_HEAD_BRANCH_RE.exec(stripQualifiedBranch(branch))?.[1];\n if (fromBranch) return fromBranch;\n }\n\n return null;\n}\n\n/**\n * Resolve the git branch used for Convex `--preview-name`.\n * Coolify often sets COOLIFY_BRANCH to `pull/<n>/head` at runtime (see coollabsio/coolify#9572).\n */\nexport function resolvePreviewBranch(env: NodeJS.ProcessEnv = process.env): string | null {\n if (env.GITHUB_HEAD_REF) return stripQualifiedBranch(env.GITHUB_HEAD_REF);\n\n const branch = env.COOLIFY_BRANCH ?? env.GIT_BRANCH;\n const prId = resolvePreviewPrId(env);\n if (!branch) {\n return prId ? `preview-${prId}` : null;\n }\n\n const stripped = stripQualifiedBranch(branch);\n if (PULL_HEAD_BRANCH_RE.test(stripped)) {\n if (prId) return `preview-${prId}`;\n }\n // Coolify PR apps often leave COOLIFY_BRANCH=main while FQDN is *-preview-<n>.\n if ((stripped === \"main\" || stripped === \"master\") && prId) {\n return `preview-${prId}`;\n }\n return stripped;\n}\n\n/** Strip Coolify/Convex qualified suffixes (e.g. `pull-48-head:pr-48-coolify`). */\nfunction stripQualifiedBranch(branch: string): string {\n const colon = branch.indexOf(\":\");\n return colon > 0 ? branch.slice(0, colon) : branch;\n}\n\nexport function sanitizePreviewDeployName(branch: string): string {\n return stripQualifiedBranch(branch).replace(/\\//g, \"-\");\n}\n\n/** Normalize a preview name from Convex env before `convex deploy --preview-name`. */\nexport function normalizePreviewDeployName(name: string): string {\n return sanitizePreviewDeployName(name.trim());\n}\n\nexport function ciPreviewDeployName(env: NodeJS.ProcessEnv = process.env): string | null {\n if (!isCiPreviewBuild(env)) return null;\n\n const branch = resolvePreviewBranch(env);\n if (!branch) return null;\n return sanitizePreviewDeployName(branch);\n}\n\n/** Stale failures from broken preview deploy before the bridge was live. */\nexport const STALE_ENDPOINT_DEPLOY_ERROR =\n /^deploy endpoint returned (?:200(?: OK)?|500(?: Internal Server Error)?)$/;\n\nexport function isStaleEndpointDeployError(error: string | undefined): boolean {\n return error != null && STALE_ENDPOINT_DEPLOY_ERROR.test(error);\n}\n\n/** Infra failures from a prior broken deploy that a fresh save can retry. */\nexport function isRecoverableDeployError(error: string | undefined): boolean {\n if (error == null) return false;\n if (isStaleEndpointDeployError(error)) return true;\n if (error.includes(\"502 Bad Gateway\")) return true;\n if (error.includes(\"deploy endpoint unreachable\")) return true;\n if (error.includes(\"deploy endpoint timed out\")) return true;\n return (\n error.includes(\"convex/bin/main.js\") ||\n error.includes(\"convex CLI (bin/main.js\") ||\n error.includes(\"convex CLI not available\")\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/previewDeployName.ts"],"names":[],"mappings":";AACO,IAAM,gBAAA,GAAmB;AACzB,IAAM,0BAAA,GAA6B;AACnC,SAAS,oBAAoB,IAAA,EAAuB;AACzD,EAAA,OAAO,IAAA,CAAK,WAAW,0BAA0B,CAAA;AACnD;AAGO,SAAS,sBAAA,CAAuB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAoB;AAC1F,EAAA,MAAM,MAAA,GAAS,yBAAyB,GAAG,CAAA;AAC3C,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,MAAM,CAAA,CAAE,QAAA;AAAA,EACzB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGO,SAAS,wBAAA,CAAyB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAyB;AACjG,EAAA,MAAM,QAAA,GAAW,GAAA,CAAI,oBAAA,EAAsB,IAAA,EAAK;AAChD,EAAA,IAAI,QAAA,EAAU,OAAO,QAAA,CAAS,OAAA,CAAQ,OAAO,EAAE,CAAA;AAC/C,EAAA,MAAM,OAAA,GAAU,GAAA,CAAI,QAAA,EAAU,IAAA,EAAK;AACnC,EAAA,IAAI,OAAA,IAAW,CAAC,yBAAA,CAA0B,IAAA,CAAK,OAAO,GAAG,OAAO,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACzF,EAAA,OAAO,MAAA;AACT;AAGO,SAAS,gBAAA,CAAiB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAc;AAC9E,EAAA,IAAI,IAAI,UAAA,KAAe,MAAA,IAAU,GAAA,CAAI,gBAAA,KAAqB,QAAQ,OAAO,IAAA;AACzE,EAAA,MAAM,IAAA,GAAO,uBAAuB,GAAG,CAAA;AACvC,EAAA,OAAO,OAAA,CAAQ,IAAA,IAAQ,kBAAA,CAAmB,IAAA,CAAK,IAAI,CAAC,CAAA;AACtD;AAEA,IAAM,mBAAA,GAAsB,sBAAA;AAC5B,IAAM,kBAAA,GAAqB,gDAAA;AAGpB,SAAS,kBAAA,CAAmB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAoB;AACtF,EAAA,MAAM,IAAA,GAAO,uBAAuB,GAAG,CAAA;AACvC,EAAA,MAAM,SAAS,IAAA,GAAO,kBAAA,CAAmB,KAAK,IAAI,CAAA,GAAI,CAAC,CAAA,GAAI,MAAA;AAC3D,EAAA,OAAO,QAAQ,MAAA,GAAS,IAAA,CAAK,MAAM,MAAA,CAAO,MAAM,KAAK,IAAA,GAAO,IAAA;AAC9D;AAGO,SAAS,kBAAA,CAAmB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAoB;AACtF,EAAA,MAAM,IAAA,GAAO,uBAAuB,GAAG,CAAA;AACvC,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,MAAM,QAAA,GAAW,kBAAA,CAAmB,IAAA,CAAK,IAAI,IAAI,CAAC,CAAA;AAClD,IAAA,IAAI,UAAU,OAAO,QAAA;AAAA,EACvB;AAEA,EAAA,MAAM,SAAS,GAAA,CAAI,UAAA;AACnB,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,aAAa,mBAAA,CAAoB,IAAA,CAAK,qBAAqB,MAAM,CAAC,IAAI,CAAC,CAAA;AAC7E,IAAA,IAAI,YAAY,OAAO,UAAA;AAAA,EACzB;AAEA,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,oBAAA,CAAqB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAoB;AACxF,EAAA,IAAI,GAAA,CAAI,eAAA,EAAiB,OAAO,oBAAA,CAAqB,IAAI,eAAe,CAAA;AAExE,EAAA,MAAM,SAAS,GAAA,CAAI,UAAA;AACnB,EAAA,MAAM,IAAA,GAAO,mBAAmB,GAAG,CAAA;AACnC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAO,IAAA,GAAO,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,GAAK,IAAA;AAAA,EACpC;AAEA,EAAA,MAAM,QAAA,GAAW,qBAAqB,MAAM,CAAA;AAC5C,EAAA,IAAI,mBAAA,CAAoB,IAAA,CAAK,QAAQ,CAAA,EAAG;AACtC,IAAA,IAAI,IAAA,EAAM,OAAO,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA;AAAA,EAClC;AAEA,EAAA,IAAA,CAAK,QAAA,KAAa,MAAA,IAAU,QAAA,KAAa,QAAA,KAAa,IAAA,EAAM;AAC1D,IAAA,OAAO,WAAW,IAAI,CAAA,CAAA;AAAA,EACxB;AACA,EAAA,OAAO,QAAA;AACT;AAGA,SAAS,qBAAqB,MAAA,EAAwB;AACpD,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA;AAChC,EAAA,OAAO,QAAQ,CAAA,GAAI,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA,GAAI,MAAA;AAC9C;AAEO,SAAS,0BAA0B,MAAA,EAAwB;AAChE,EAAA,OAAO,oBAAA,CAAqB,MAAM,CAAA,CAAE,OAAA,CAAQ,OAAO,GAAG,CAAA;AACxD;AAGO,SAAS,2BAA2B,IAAA,EAAsB;AAC/D,EAAA,OAAO,yBAAA,CAA0B,IAAA,CAAK,IAAA,EAAM,CAAA;AAC9C;AAGO,IAAM,sBAAA,GAAyB;AAG/B,SAAS,yBAAA,CAA0B,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAoB;AAC7F,EAAA,MAAM,IAAA,GAAO,GAAA,CAAI,mBAAA,EAAqB,IAAA,EAAK;AAC3C,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,IAAI,CAAC,sBAAA,CAAuB,IAAA,CAAK,IAAI,CAAA,EAAG;AACtC,IAAA,MAAM,IAAI,MAAM,sEAAiE,CAAA;AAAA,EACnF;AACA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,mBAAA,CAAoB,GAAA,GAAyB,OAAA,CAAQ,GAAA,EAAoB;AACvF,EAAA,IAAI,CAAC,gBAAA,CAAiB,GAAG,CAAA,EAAG,OAAO,IAAA;AACnC,EAAA,MAAM,QAAA,GAAW,0BAA0B,GAAG,CAAA;AAC9C,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,MAAM,MAAA,GAAS,qBAAqB,GAAG,CAAA;AACvC,EAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AACpB,EAAA,OAAO,0BAA0B,MAAM,CAAA;AACzC;AAGO,IAAM,2BAAA,GACX;AAEK,SAAS,2BAA2B,KAAA,EAAoC;AAC7E,EAAA,OAAO,KAAA,IAAS,IAAA,IAAQ,2BAAA,CAA4B,IAAA,CAAK,KAAK,CAAA;AAChE;AAGO,SAAS,yBAAyB,KAAA,EAAoC;AAC3E,EAAA,IAAI,KAAA,IAAS,MAAM,OAAO,KAAA;AAC1B,EAAA,IAAI,0BAAA,CAA2B,KAAK,CAAA,EAAG,OAAO,IAAA;AAC9C,EAAA,IAAI,KAAA,CAAM,QAAA,CAAS,iBAAiB,CAAA,EAAG,OAAO,IAAA;AAC9C,EAAA,IAAI,KAAA,CAAM,QAAA,CAAS,6BAA6B,CAAA,EAAG,OAAO,IAAA;AAC1D,EAAA,IAAI,KAAA,CAAM,QAAA,CAAS,2BAA2B,CAAA,EAAG,OAAO,IAAA;AACxD,EAAA,OACE,KAAA,CAAM,QAAA,CAAS,oBAAoB,CAAA,IACnC,KAAA,CAAM,SAAS,yBAAyB,CAAA,IACxC,KAAA,CAAM,QAAA,CAAS,0BAA0B,CAAA;AAE7C","file":"previewDeployName.js","sourcesContent":["/** Canonical Kubernetes preview PR identity (matches columnus-pr-N namespaces). */\nexport const PREVIEW_PR_ID_RE = /^[1-9][0-9]{0,6}$/;\nexport const PREVIEW_TENANT_SLUG_PREFIX = \"preview-\";\nexport function isPreviewTenantSlug(slug: string): boolean {\n return slug.startsWith(PREVIEW_TENANT_SLUG_PREFIX);\n}\n\n/** Explicit application origin used by CI and runtime preview routing. */\nexport function previewHostnameFromEnv(env: NodeJS.ProcessEnv = process.env): string | null {\n const origin = resolveTrustedAuthOrigin(env);\n if (!origin) return null;\n try {\n return new URL(origin).hostname;\n } catch {\n return null;\n }\n}\n\n/** Browser origin for server-side auth probes; never use a Convex HTTP endpoint. */\nexport function resolveTrustedAuthOrigin(env: NodeJS.ProcessEnv = process.env): string | undefined {\n const explicit = env.COLUMNUS_AUTH_ORIGIN?.trim();\n if (explicit) return explicit.replace(/\\/$/, \"\");\n const siteUrl = env.SITE_URL?.trim();\n if (siteUrl && !/\\.convex\\.site(?:\\/|$)/i.test(siteUrl)) return siteUrl.replace(/\\/$/, \"\");\n return undefined;\n}\n\n/** CI_PREVIEW is the local build mode; COLUMNUS_PREVIEW identifies deployed previews. */\nexport function isCiPreviewBuild(env: NodeJS.ProcessEnv = process.env): boolean {\n if (env.CI_PREVIEW === \"true\" || env.COLUMNUS_PREVIEW === \"true\") return true;\n const host = previewHostnameFromEnv(env);\n return Boolean(host && PREVIEW_HOST_PR_RE.test(host));\n}\n\nconst PULL_HEAD_BRANCH_RE = /^pull\\/(\\d+)\\/head$/i;\nconst PREVIEW_HOST_PR_RE = /^(?:manage-|deploy-|renderer-)?preview-(\\d+)\\./;\n\n/** Domain suffix only from a recognized preview host, never from branch identity. */\nexport function previewZoneFromEnv(env: NodeJS.ProcessEnv = process.env): string | null {\n const host = previewHostnameFromEnv(env);\n const prefix = host ? PREVIEW_HOST_PR_RE.exec(host)?.[0] : undefined;\n return host && prefix ? host.slice(prefix.length) || null : null;\n}\n\n/** PR id from `preview-<n>.<domain>` / `manage-preview-<n>` hostname or `pull/<n>/head` branch. */\nexport function resolvePreviewPrId(env: NodeJS.ProcessEnv = process.env): string | null {\n const host = previewHostnameFromEnv(env);\n if (host) {\n const fromHost = PREVIEW_HOST_PR_RE.exec(host)?.[1];\n if (fromHost) return fromHost;\n }\n\n const branch = env.GIT_BRANCH;\n if (branch) {\n const fromBranch = PULL_HEAD_BRANCH_RE.exec(stripQualifiedBranch(branch))?.[1];\n if (fromBranch) return fromBranch;\n }\n\n return null;\n}\n\n/** Resolve the CI git branch used for Convex preview deployment naming. */\nexport function resolvePreviewBranch(env: NodeJS.ProcessEnv = process.env): string | null {\n if (env.GITHUB_HEAD_REF) return stripQualifiedBranch(env.GITHUB_HEAD_REF);\n\n const branch = env.GIT_BRANCH;\n const prId = resolvePreviewPrId(env);\n if (!branch) {\n return prId ? `preview-${prId}` : null;\n }\n\n const stripped = stripQualifiedBranch(branch);\n if (PULL_HEAD_BRANCH_RE.test(stripped)) {\n if (prId) return `preview-${prId}`;\n }\n // An explicit preview origin takes priority over the base branch.\n if ((stripped === \"main\" || stripped === \"master\") && prId) {\n return `preview-${prId}`;\n }\n return stripped;\n}\n\n/** Strip qualified branch suffixes before deriving a deployment name. */\nfunction stripQualifiedBranch(branch: string): string {\n const colon = branch.indexOf(\":\");\n return colon > 0 ? branch.slice(0, colon) : branch;\n}\n\nexport function sanitizePreviewDeployName(branch: string): string {\n return stripQualifiedBranch(branch).replace(/\\//g, \"-\");\n}\n\n/** Normalize a preview name from Convex env before `convex deploy --preview-name`. */\nexport function normalizePreviewDeployName(name: string): string {\n return sanitizePreviewDeployName(name.trim());\n}\n\n/** Identifier rule shared by CI configuration and Management registration. */\nexport const PREVIEW_DEPLOY_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;\n\n/** Explicit CI identity, including hostless Management builds. */\nexport function explicitPreviewDeployName(env: NodeJS.ProcessEnv = process.env): string | null {\n const name = env.CONVEX_PREVIEW_NAME?.trim();\n if (!name) return null;\n if (!PREVIEW_DEPLOY_NAME_RE.test(name)) {\n throw new Error(\"CONVEX_PREVIEW_NAME must be a 1–64 character preview identifier\");\n }\n return name;\n}\n\nexport function ciPreviewDeployName(env: NodeJS.ProcessEnv = process.env): string | null {\n if (!isCiPreviewBuild(env)) return null;\n const explicit = explicitPreviewDeployName(env);\n if (explicit) return explicit;\n\n const branch = resolvePreviewBranch(env);\n if (!branch) return null;\n return sanitizePreviewDeployName(branch);\n}\n\n/** Stale failures from broken preview deploy before the bridge was live. */\nexport const STALE_ENDPOINT_DEPLOY_ERROR =\n /^deploy endpoint returned (?:200(?: OK)?|500(?: Internal Server Error)?)$/;\n\nexport function isStaleEndpointDeployError(error: string | undefined): boolean {\n return error != null && STALE_ENDPOINT_DEPLOY_ERROR.test(error);\n}\n\n/** Infra failures from a prior broken deploy that a fresh save can retry. */\nexport function isRecoverableDeployError(error: string | undefined): boolean {\n if (error == null) return false;\n if (isStaleEndpointDeployError(error)) return true;\n if (error.includes(\"502 Bad Gateway\")) return true;\n if (error.includes(\"deploy endpoint unreachable\")) return true;\n if (error.includes(\"deploy endpoint timed out\")) return true;\n return (\n error.includes(\"convex/bin/main.js\") ||\n error.includes(\"convex CLI (bin/main.js\") ||\n error.includes(\"convex CLI not available\")\n );\n}\n"]}
@@ -20199,6 +20199,9 @@ var apiProfileSnapshotSchema = external_exports.object({
20199
20199
  });
20200
20200
  external_exports.array(apiProfileSnapshotSchema);
20201
20201
 
20202
+ // packages/@columnus/shared/src/previewDeployName.ts
20203
+ var PREVIEW_DEPLOY_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
20204
+
20202
20205
  // packages/@columnus/shared/src/bffProtocol.ts
20203
20206
  var COLUMNUS_BFF_PROTOCOL_VERSION = 1;
20204
20207
  var OPERATION_ID_RE = /^[A-Za-z0-9_-]{16,128}$/;
@@ -20414,6 +20417,7 @@ external_exports.discriminatedUnion("operation", [
20414
20417
  })
20415
20418
  ]);
20416
20419
  external_exports.object({
20420
+ previewName: external_exports.string().regex(PREVIEW_DEPLOY_NAME_RE).optional(),
20417
20421
  hostname: external_exports.string().min(1),
20418
20422
  convexUrl: external_exports.string().url(),
20419
20423
  deployKey: external_exports.string().min(1),
@@ -20460,7 +20464,7 @@ external_exports.object({
20460
20464
  external_exports.object({
20461
20465
  ok: external_exports.boolean(),
20462
20466
  commit: external_exports.string().optional(),
20463
- /** ISO-8601 Coolify/image bake time (BRU-76 preview supersede). */
20467
+ /** ISO-8601 deployment/image bake time (BRU-76 preview supersede). */
20464
20468
  deployedAt: external_exports.string().optional()
20465
20469
  });
20466
20470