@infracraft/pulumi 1.19.0 → 1.20.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.
@@ -6,10 +6,29 @@ _pulumi_pulumi = require_chunk.__toESM(_pulumi_pulumi, 1);
6
6
  //#region src/vercel/domain.ts
7
7
  const VERCEL_API_URL = "https://api.vercel.com";
8
8
  /**
9
- * Vercel's documented CNAME target for attaching a subdomain to a project.
9
+ * Fallback CNAME target, used only when Vercel's domain-config endpoint returns no
10
+ * recommendation (see {@link fetchCnameTarget}). Not the primary source of truth —
11
+ * `VercelDomain.cnameTarget` queries Vercel's per-domain recommendation dynamically,
12
+ * since the actual target can vary by account/domain.
10
13
  * https://vercel.com/docs/domains/working-with-domains/add-a-domain
11
14
  */
12
- const VERCEL_CNAME_TARGET = "cname.vercel-dns.com";
15
+ const VERCEL_CNAME_TARGET_FALLBACK = "cname.vercel-dns.com";
16
+ /**
17
+ * Fetches Vercel's recommended CNAME target for a domain from its DNS config endpoint.
18
+ * Falls back to {@link VERCEL_CNAME_TARGET_FALLBACK} if Vercel returns no recommendation
19
+ * (logged, since that's an unusual state worth noticing rather than silently accepting).
20
+ */
21
+ async function fetchCnameTarget(token, teamId, name) {
22
+ const response = await fetch(`${VERCEL_API_URL}/v6/domains/${encodeURIComponent(name)}/config?teamId=${teamId}`, { headers: { Authorization: `Bearer ${token}` } });
23
+ if (!response.ok) throw new Error(`Vercel API error fetching domain config for "${name}" (${response.status}): ${await response.text()}`);
24
+ const { recommendedCNAME = [] } = await response.json();
25
+ const preferred = [...recommendedCNAME].sort((a, b) => a.rank - b.rank)[0];
26
+ if (!preferred) {
27
+ _pulumi_pulumi.log.info(`Vercel returned no recommended CNAME for "${name}" — falling back to "${VERCEL_CNAME_TARGET_FALLBACK}"`);
28
+ return VERCEL_CNAME_TARGET_FALLBACK;
29
+ }
30
+ return preferred.value;
31
+ }
13
32
  /**
14
33
  * Fetches a project domain by name. Returns `null` if not attached (404).
15
34
  */
@@ -34,7 +53,8 @@ var VercelDomainResourceProvider = class {
34
53
  _pulumi_pulumi.log.info(`Adopted existing Vercel domain "${inputs.name}" on project ${inputs.projectId}`);
35
54
  const outs = {
36
55
  ...inputs,
37
- verified: existing.verified
56
+ verified: existing.verified,
57
+ cnameTarget: await fetchCnameTarget(inputs.token, inputs.teamId, inputs.name)
38
58
  };
39
59
  return {
40
60
  id: `${inputs.projectId}/${inputs.name}`,
@@ -53,7 +73,8 @@ var VercelDomainResourceProvider = class {
53
73
  const created = await response.json();
54
74
  const outs = {
55
75
  ...inputs,
56
- verified: created.verified
76
+ verified: created.verified,
77
+ cnameTarget: await fetchCnameTarget(inputs.token, inputs.teamId, inputs.name)
57
78
  };
58
79
  return {
59
80
  id: `${inputs.projectId}/${inputs.name}`,
@@ -67,15 +88,17 @@ var VercelDomainResourceProvider = class {
67
88
  id: `${props.projectId}/${props.name}`,
68
89
  props: {
69
90
  ...props,
70
- verified: domain.verified
91
+ verified: domain.verified,
92
+ cnameTarget: await fetchCnameTarget(props.token, props.teamId, props.name)
71
93
  }
72
94
  };
73
95
  }
74
96
  /** All fields replace (see `diff`) — this is never actually invoked. */
75
- async update(_id, _olds, news) {
97
+ async update(_id, olds, news) {
76
98
  return { outs: {
77
99
  ...news,
78
- verified: false
100
+ verified: false,
101
+ cnameTarget: olds.cnameTarget
79
102
  } };
80
103
  }
81
104
  async delete(_id, props) {
@@ -111,7 +134,8 @@ var VercelDomainResource = class extends _pulumi_pulumi.dynamic.Resource {
111
134
  constructor(name, args, opts) {
112
135
  super(new VercelDomainResourceProvider(), name, {
113
136
  ...args,
114
- verified: void 0
137
+ verified: void 0,
138
+ cnameTarget: void 0
115
139
  }, opts);
116
140
  }
117
141
  };
@@ -120,7 +144,10 @@ var VercelDomainResource = class extends _pulumi_pulumi.dynamic.Resource {
120
144
  *
121
145
  * @example
122
146
  * ```typescript
123
- * new VercelDomain("aura-domain", { name: "app.example.com" }, { provider, project });
147
+ * const domain = new VercelDomain("aura-domain", { name: "app.example.com" }, { provider, project });
148
+ *
149
+ * // Point app.example.com's DNS CNAME at this value.
150
+ * const cnameTarget = domain.cnameTarget;
124
151
  * ```
125
152
  */
126
153
  var VercelDomain = class extends _pulumi_pulumi.ComponentResource {
@@ -135,15 +162,16 @@ var VercelDomain = class extends _pulumi_pulumi.ComponentResource {
135
162
  }, { parent: this });
136
163
  this.verified = resource.verified;
137
164
  this.name = resource.name;
165
+ this.cnameTarget = resource.cnameTarget;
138
166
  this.registerOutputs({
139
167
  verified: this.verified,
140
- name: this.name
168
+ name: this.name,
169
+ cnameTarget: this.cnameTarget
141
170
  });
142
171
  }
143
172
  };
144
173
 
145
174
  //#endregion
146
- exports.VERCEL_CNAME_TARGET = VERCEL_CNAME_TARGET;
147
175
  exports.VercelDomain = VercelDomain;
148
176
  exports.VercelDomainResourceProvider = VercelDomainResourceProvider;
149
177
  //# sourceMappingURL=domain.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"domain.cjs","names":["pulumi"],"sources":["../../src/vercel/domain.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport type { VercelProject } from \"./project\";\nimport type { VercelProvider } from \"./provider\";\n\nconst VERCEL_API_URL = \"https://api.vercel.com\";\n\n/**\n * Vercel's documented CNAME target for attaching a subdomain to a project.\n * https://vercel.com/docs/domains/working-with-domains/add-a-domain\n */\nexport const VERCEL_CNAME_TARGET = \"cname.vercel-dns.com\";\n\n/** Resolved inputs for the Vercel domain dynamic provider. */\nexport interface VercelDomainInputs {\n\t/** Vercel API bearer token. */\n\ttoken: string;\n\n\t/** Vercel team/org ID. */\n\tteamId: string;\n\n\t/** Vercel project ID to attach the domain to. */\n\tprojectId: string;\n\n\t/** Domain name (e.g. `\"app.example.com\"`). */\n\tname: string;\n}\n\n/** Persisted state for the Vercel domain, extending inputs with verification status. */\ninterface VercelDomainOutputs extends VercelDomainInputs {\n\t/** `true` once the domain's DNS has been verified by Vercel. */\n\tverified: boolean;\n}\n\n/** Vercel API response shape for a project domain. */\ninterface VercelDomainResponse {\n\tname: string;\n\tprojectId: string;\n\tverified: boolean;\n}\n\n/**\n * Fetches a project domain by name. Returns `null` if not attached (404).\n */\nasync function fetchDomain(\n\ttoken: string,\n\tteamId: string,\n\tprojectId: string,\n\tname: string,\n): Promise<VercelDomainResponse | null> {\n\tconst response = await fetch(\n\t\t`${VERCEL_API_URL}/v9/projects/${encodeURIComponent(projectId)}/domains/${encodeURIComponent(name)}?teamId=${teamId}`,\n\t\t{ headers: { Authorization: `Bearer ${token}` } },\n\t);\n\n\tif (response.status === 404) {\n\t\treturn null;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow new Error(\n\t\t\t`Vercel API error fetching domain \"${name}\" (${response.status}): ${await response.text()}`,\n\t\t);\n\t}\n\n\treturn (await response.json()) as VercelDomainResponse;\n}\n\n/**\n * Dynamic provider implementing adopt-or-create for a Vercel project domain.\n *\n * On `create()`, calls `GET /v9/projects/{projectId}/domains/{name}`. If found, adopts\n * the existing attachment. If 404, attaches it via `POST /v10/projects/{projectId}/domains`.\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class VercelDomainResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst existing = await fetchDomain(\n\t\t\tinputs.token,\n\t\t\tinputs.teamId,\n\t\t\tinputs.projectId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (existing) {\n\t\t\tpulumi.log.info(\n\t\t\t\t`Adopted existing Vercel domain \"${inputs.name}\" on project ${inputs.projectId}`,\n\t\t\t);\n\n\t\t\tconst outs: VercelDomainOutputs = {\n\t\t\t\t...inputs,\n\t\t\t\tverified: existing.verified,\n\t\t\t};\n\n\t\t\treturn { id: `${inputs.projectId}/${inputs.name}`, outs };\n\t\t}\n\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v10/projects/${encodeURIComponent(inputs.projectId)}/domains?teamId=${inputs.teamId}`,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${inputs.token}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({ name: inputs.name }),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error creating domain \"${inputs.name}\" (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tconst created = (await response.json()) as VercelDomainResponse;\n\n\t\tconst outs: VercelDomainOutputs = { ...inputs, verified: created.verified };\n\n\t\treturn { id: `${inputs.projectId}/${inputs.name}`, outs };\n\t}\n\n\tasync read(\n\t\t_id: string,\n\t\tprops: VercelDomainOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst domain = await fetchDomain(\n\t\t\tprops.token,\n\t\t\tprops.teamId,\n\t\t\tprops.projectId,\n\t\t\tprops.name,\n\t\t);\n\n\t\tif (!domain) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel domain \"${props.name}\" not found on project ${props.projectId}`,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tid: `${props.projectId}/${props.name}`,\n\t\t\tprops: { ...props, verified: domain.verified },\n\t\t};\n\t}\n\n\t/** All fields replace (see `diff`) — this is never actually invoked. */\n\tasync update(\n\t\t_id: string,\n\t\t_olds: VercelDomainOutputs,\n\t\tnews: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\treturn { outs: { ...news, verified: false } };\n\t}\n\n\tasync delete(_id: string, props: VercelDomainOutputs): Promise<void> {\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v9/projects/${encodeURIComponent(props.projectId)}/domains/${encodeURIComponent(props.name)}?teamId=${props.teamId}`,\n\t\t\t{\n\t\t\t\tmethod: \"DELETE\",\n\t\t\t\theaders: { Authorization: `Bearer ${props.token}` },\n\t\t\t},\n\t\t);\n\n\t\tif (response.status === 404) {\n\t\t\tpulumi.log.warn(\n\t\t\t\t`Vercel domain \"${props.name}\" already gone from project ${props.projectId}`,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error deleting domain \"${props.name}\" (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tpulumi.log.info(\n\t\t\t`Deleted Vercel domain \"${props.name}\" from project ${props.projectId}`,\n\t\t);\n\t}\n\n\t/**\n\t * A domain can only be attached to one project, so every field change replaces\n\t * rather than updates.\n\t */\n\tasync diff(\n\t\t_id: string,\n\t\tolds: VercelDomainOutputs,\n\t\tnews: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.name !== news.name) {\n\t\t\treplaces.push(\"name\");\n\t\t}\n\n\t\tif (olds.projectId !== news.projectId) {\n\t\t\treplaces.push(\"projectId\");\n\t\t}\n\n\t\tif (olds.teamId !== news.teamId) {\n\t\t\treplaces.push(\"teamId\");\n\t\t}\n\n\t\treturn {\n\t\t\tchanges: replaces.length > 0,\n\t\t\treplaces,\n\t\t\tdeleteBeforeReplace: true,\n\t\t};\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass VercelDomainResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly verified: pulumi.Output<boolean>;\n\tpublic declare readonly name: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tteamId: pulumi.Input<string>;\n\t\t\tprojectId: pulumi.Input<string>;\n\t\t\tname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew VercelDomainResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, verified: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n\n/** Options type for VercelDomain — replaces Pulumi's native `provider` field. */\ntype VercelDomainOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Vercel authentication context. */\n\tprovider: VercelProvider;\n\n\t/** Vercel project to attach the domain to. */\n\tproject: VercelProject;\n};\n\n/** Args for VercelDomain. */\nexport interface VercelDomainArgs {\n\t/** Domain name (e.g. `\"app.example.com\"`). */\n\tname: pulumi.Input<string>;\n}\n\n/**\n * Attaches a custom domain to a Vercel project, with adopt-or-create semantics.\n *\n * @example\n * ```typescript\n * new VercelDomain(\"aura-domain\", { name: \"app.example.com\" }, { provider, project });\n * ```\n */\nexport class VercelDomain extends pulumi.ComponentResource {\n\t/** `true` once the domain's DNS has been verified by Vercel. */\n\tpublic readonly verified: pulumi.Output<boolean>;\n\n\t/** The attached domain name. */\n\tpublic readonly name: pulumi.Output<string>;\n\n\tconstructor(name: string, args: VercelDomainArgs, opts: VercelDomainOptions) {\n\t\tconst { provider, project, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:vercel:Domain\", name, {}, pulumiOpts);\n\n\t\tconst resource = new VercelDomainResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tteamId: provider.teamId,\n\t\t\t\tprojectId: project.id,\n\t\t\t\t...args,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.verified = resource.verified;\n\t\tthis.name = resource.name;\n\n\t\tthis.registerOutputs({ verified: this.verified, name: this.name });\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"domain.cjs","names":["pulumi"],"sources":["../../src/vercel/domain.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport type { VercelProject } from \"./project\";\nimport type { VercelProvider } from \"./provider\";\n\nconst VERCEL_API_URL = \"https://api.vercel.com\";\n\n/**\n * Fallback CNAME target, used only when Vercel's domain-config endpoint returns no\n * recommendation (see {@link fetchCnameTarget}). Not the primary source of truth —\n * `VercelDomain.cnameTarget` queries Vercel's per-domain recommendation dynamically,\n * since the actual target can vary by account/domain.\n * https://vercel.com/docs/domains/working-with-domains/add-a-domain\n */\nconst VERCEL_CNAME_TARGET_FALLBACK = \"cname.vercel-dns.com\";\n\n/** Resolved inputs for the Vercel domain dynamic provider. */\nexport interface VercelDomainInputs {\n\t/** Vercel API bearer token. */\n\ttoken: string;\n\n\t/** Vercel team/org ID. */\n\tteamId: string;\n\n\t/** Vercel project ID to attach the domain to. */\n\tprojectId: string;\n\n\t/** Domain name (e.g. `\"app.example.com\"`). */\n\tname: string;\n}\n\n/** Persisted state for the Vercel domain, extending inputs with verification status. */\ninterface VercelDomainOutputs extends VercelDomainInputs {\n\t/** `true` once the domain's DNS has been verified by Vercel. */\n\tverified: boolean;\n\n\t/** The value to CNAME `name` to, per Vercel's own per-domain recommendation. */\n\tcnameTarget: string;\n}\n\n/** Vercel API response shape for a project domain. */\ninterface VercelDomainResponse {\n\tname: string;\n\tprojectId: string;\n\tverified: boolean;\n}\n\n/** A single ranked CNAME recommendation from `GET /v6/domains/{domain}/config`. */\ninterface VercelRecommendedCname {\n\trank: number;\n\tvalue: string;\n}\n\n/**\n * Fetches Vercel's recommended CNAME target for a domain from its DNS config endpoint.\n * Falls back to {@link VERCEL_CNAME_TARGET_FALLBACK} if Vercel returns no recommendation\n * (logged, since that's an unusual state worth noticing rather than silently accepting).\n */\nasync function fetchCnameTarget(\n\ttoken: string,\n\tteamId: string,\n\tname: string,\n): Promise<string> {\n\tconst response = await fetch(\n\t\t`${VERCEL_API_URL}/v6/domains/${encodeURIComponent(name)}/config?teamId=${teamId}`,\n\t\t{ headers: { Authorization: `Bearer ${token}` } },\n\t);\n\n\tif (!response.ok) {\n\t\tthrow new Error(\n\t\t\t`Vercel API error fetching domain config for \"${name}\" (${response.status}): ${await response.text()}`,\n\t\t);\n\t}\n\n\tconst { recommendedCNAME = [] } = (await response.json()) as {\n\t\trecommendedCNAME?: VercelRecommendedCname[];\n\t};\n\n\tconst preferred = [...recommendedCNAME].sort((a, b) => a.rank - b.rank)[0];\n\n\tif (!preferred) {\n\t\tpulumi.log.info(\n\t\t\t`Vercel returned no recommended CNAME for \"${name}\" — falling back to \"${VERCEL_CNAME_TARGET_FALLBACK}\"`,\n\t\t);\n\n\t\treturn VERCEL_CNAME_TARGET_FALLBACK;\n\t}\n\n\treturn preferred.value;\n}\n\n/**\n * Fetches a project domain by name. Returns `null` if not attached (404).\n */\nasync function fetchDomain(\n\ttoken: string,\n\tteamId: string,\n\tprojectId: string,\n\tname: string,\n): Promise<VercelDomainResponse | null> {\n\tconst response = await fetch(\n\t\t`${VERCEL_API_URL}/v9/projects/${encodeURIComponent(projectId)}/domains/${encodeURIComponent(name)}?teamId=${teamId}`,\n\t\t{ headers: { Authorization: `Bearer ${token}` } },\n\t);\n\n\tif (response.status === 404) {\n\t\treturn null;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow new Error(\n\t\t\t`Vercel API error fetching domain \"${name}\" (${response.status}): ${await response.text()}`,\n\t\t);\n\t}\n\n\treturn (await response.json()) as VercelDomainResponse;\n}\n\n/**\n * Dynamic provider implementing adopt-or-create for a Vercel project domain.\n *\n * On `create()`, calls `GET /v9/projects/{projectId}/domains/{name}`. If found, adopts\n * the existing attachment. If 404, attaches it via `POST /v10/projects/{projectId}/domains`.\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class VercelDomainResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst existing = await fetchDomain(\n\t\t\tinputs.token,\n\t\t\tinputs.teamId,\n\t\t\tinputs.projectId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (existing) {\n\t\t\tpulumi.log.info(\n\t\t\t\t`Adopted existing Vercel domain \"${inputs.name}\" on project ${inputs.projectId}`,\n\t\t\t);\n\n\t\t\tconst outs: VercelDomainOutputs = {\n\t\t\t\t...inputs,\n\t\t\t\tverified: existing.verified,\n\t\t\t\tcnameTarget: await fetchCnameTarget(\n\t\t\t\t\tinputs.token,\n\t\t\t\t\tinputs.teamId,\n\t\t\t\t\tinputs.name,\n\t\t\t\t),\n\t\t\t};\n\n\t\t\treturn { id: `${inputs.projectId}/${inputs.name}`, outs };\n\t\t}\n\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v10/projects/${encodeURIComponent(inputs.projectId)}/domains?teamId=${inputs.teamId}`,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${inputs.token}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({ name: inputs.name }),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error creating domain \"${inputs.name}\" (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tconst created = (await response.json()) as VercelDomainResponse;\n\n\t\tconst outs: VercelDomainOutputs = {\n\t\t\t...inputs,\n\t\t\tverified: created.verified,\n\t\t\tcnameTarget: await fetchCnameTarget(\n\t\t\t\tinputs.token,\n\t\t\t\tinputs.teamId,\n\t\t\t\tinputs.name,\n\t\t\t),\n\t\t};\n\n\t\treturn { id: `${inputs.projectId}/${inputs.name}`, outs };\n\t}\n\n\tasync read(\n\t\t_id: string,\n\t\tprops: VercelDomainOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst domain = await fetchDomain(\n\t\t\tprops.token,\n\t\t\tprops.teamId,\n\t\t\tprops.projectId,\n\t\t\tprops.name,\n\t\t);\n\n\t\tif (!domain) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel domain \"${props.name}\" not found on project ${props.projectId}`,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tid: `${props.projectId}/${props.name}`,\n\t\t\tprops: {\n\t\t\t\t...props,\n\t\t\t\tverified: domain.verified,\n\t\t\t\tcnameTarget: await fetchCnameTarget(\n\t\t\t\t\tprops.token,\n\t\t\t\t\tprops.teamId,\n\t\t\t\t\tprops.name,\n\t\t\t\t),\n\t\t\t},\n\t\t};\n\t}\n\n\t/** All fields replace (see `diff`) — this is never actually invoked. */\n\tasync update(\n\t\t_id: string,\n\t\tolds: VercelDomainOutputs,\n\t\tnews: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\treturn {\n\t\t\touts: { ...news, verified: false, cnameTarget: olds.cnameTarget },\n\t\t};\n\t}\n\n\tasync delete(_id: string, props: VercelDomainOutputs): Promise<void> {\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v9/projects/${encodeURIComponent(props.projectId)}/domains/${encodeURIComponent(props.name)}?teamId=${props.teamId}`,\n\t\t\t{\n\t\t\t\tmethod: \"DELETE\",\n\t\t\t\theaders: { Authorization: `Bearer ${props.token}` },\n\t\t\t},\n\t\t);\n\n\t\tif (response.status === 404) {\n\t\t\tpulumi.log.warn(\n\t\t\t\t`Vercel domain \"${props.name}\" already gone from project ${props.projectId}`,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error deleting domain \"${props.name}\" (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tpulumi.log.info(\n\t\t\t`Deleted Vercel domain \"${props.name}\" from project ${props.projectId}`,\n\t\t);\n\t}\n\n\t/**\n\t * A domain can only be attached to one project, so every field change replaces\n\t * rather than updates.\n\t */\n\tasync diff(\n\t\t_id: string,\n\t\tolds: VercelDomainOutputs,\n\t\tnews: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.name !== news.name) {\n\t\t\treplaces.push(\"name\");\n\t\t}\n\n\t\tif (olds.projectId !== news.projectId) {\n\t\t\treplaces.push(\"projectId\");\n\t\t}\n\n\t\tif (olds.teamId !== news.teamId) {\n\t\t\treplaces.push(\"teamId\");\n\t\t}\n\n\t\treturn {\n\t\t\tchanges: replaces.length > 0,\n\t\t\treplaces,\n\t\t\tdeleteBeforeReplace: true,\n\t\t};\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass VercelDomainResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly verified: pulumi.Output<boolean>;\n\tpublic declare readonly name: pulumi.Output<string>;\n\tpublic declare readonly cnameTarget: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tteamId: pulumi.Input<string>;\n\t\t\tprojectId: pulumi.Input<string>;\n\t\t\tname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew VercelDomainResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, verified: undefined, cnameTarget: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n\n/** Options type for VercelDomain — replaces Pulumi's native `provider` field. */\ntype VercelDomainOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Vercel authentication context. */\n\tprovider: VercelProvider;\n\n\t/** Vercel project to attach the domain to. */\n\tproject: VercelProject;\n};\n\n/** Args for VercelDomain. */\nexport interface VercelDomainArgs {\n\t/** Domain name (e.g. `\"app.example.com\"`). */\n\tname: pulumi.Input<string>;\n}\n\n/**\n * Attaches a custom domain to a Vercel project, with adopt-or-create semantics.\n *\n * @example\n * ```typescript\n * const domain = new VercelDomain(\"aura-domain\", { name: \"app.example.com\" }, { provider, project });\n *\n * // Point app.example.com's DNS CNAME at this value.\n * const cnameTarget = domain.cnameTarget;\n * ```\n */\nexport class VercelDomain extends pulumi.ComponentResource {\n\t/** `true` once the domain's DNS has been verified by Vercel. */\n\tpublic readonly verified: pulumi.Output<boolean>;\n\n\t/** The attached domain name. */\n\tpublic readonly name: pulumi.Output<string>;\n\n\t/**\n\t * The value to CNAME `name` to — Vercel's own recommendation for this specific\n\t * domain, fetched fresh from its DNS config endpoint (falls back to a static default\n\t * only if Vercel returns no recommendation).\n\t */\n\tpublic readonly cnameTarget: pulumi.Output<string>;\n\n\tconstructor(name: string, args: VercelDomainArgs, opts: VercelDomainOptions) {\n\t\tconst { provider, project, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:vercel:Domain\", name, {}, pulumiOpts);\n\n\t\tconst resource = new VercelDomainResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tteamId: provider.teamId,\n\t\t\t\tprojectId: project.id,\n\t\t\t\t...args,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.verified = resource.verified;\n\t\tthis.name = resource.name;\n\t\tthis.cnameTarget = resource.cnameTarget;\n\n\t\tthis.registerOutputs({\n\t\t\tverified: this.verified,\n\t\t\tname: this.name,\n\t\t\tcnameTarget: this.cnameTarget,\n\t\t});\n\t}\n}\n"],"mappings":"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"}
@@ -4,11 +4,6 @@ import { VercelProject } from "./project.cjs";
4
4
  import * as pulumi from "@pulumi/pulumi";
5
5
 
6
6
  //#region src/vercel/domain.d.ts
7
- /**
8
- * Vercel's documented CNAME target for attaching a subdomain to a project.
9
- * https://vercel.com/docs/domains/working-with-domains/add-a-domain
10
- */
11
- declare const VERCEL_CNAME_TARGET = "cname.vercel-dns.com";
12
7
  /** Resolved inputs for the Vercel domain dynamic provider. */
13
8
  interface VercelDomainInputs {
14
9
  /** Vercel API bearer token. */
@@ -24,6 +19,8 @@ interface VercelDomainInputs {
24
19
  interface VercelDomainOutputs extends VercelDomainInputs {
25
20
  /** `true` once the domain's DNS has been verified by Vercel. */
26
21
  verified: boolean;
22
+ /** The value to CNAME `name` to, per Vercel's own per-domain recommendation. */
23
+ cnameTarget: string;
27
24
  }
28
25
  /**
29
26
  * Dynamic provider implementing adopt-or-create for a Vercel project domain.
@@ -37,7 +34,7 @@ declare class VercelDomainResourceProvider implements pulumi.dynamic.ResourcePro
37
34
  create(inputs: VercelDomainInputs): Promise<pulumi.dynamic.CreateResult>;
38
35
  read(_id: string, props: VercelDomainOutputs): Promise<pulumi.dynamic.ReadResult>;
39
36
  /** All fields replace (see `diff`) — this is never actually invoked. */
40
- update(_id: string, _olds: VercelDomainOutputs, news: VercelDomainInputs): Promise<pulumi.dynamic.UpdateResult>;
37
+ update(_id: string, olds: VercelDomainOutputs, news: VercelDomainInputs): Promise<pulumi.dynamic.UpdateResult>;
41
38
  delete(_id: string, props: VercelDomainOutputs): Promise<void>;
42
39
  /**
43
40
  * A domain can only be attached to one project, so every field change replaces
@@ -60,7 +57,10 @@ interface VercelDomainArgs {
60
57
  *
61
58
  * @example
62
59
  * ```typescript
63
- * new VercelDomain("aura-domain", { name: "app.example.com" }, { provider, project });
60
+ * const domain = new VercelDomain("aura-domain", { name: "app.example.com" }, { provider, project });
61
+ *
62
+ * // Point app.example.com's DNS CNAME at this value.
63
+ * const cnameTarget = domain.cnameTarget;
64
64
  * ```
65
65
  */
66
66
  declare class VercelDomain extends pulumi.ComponentResource {
@@ -68,8 +68,14 @@ declare class VercelDomain extends pulumi.ComponentResource {
68
68
  readonly verified: pulumi.Output<boolean>;
69
69
  /** The attached domain name. */
70
70
  readonly name: pulumi.Output<string>;
71
+ /**
72
+ * The value to CNAME `name` to — Vercel's own recommendation for this specific
73
+ * domain, fetched fresh from its DNS config endpoint (falls back to a static default
74
+ * only if Vercel returns no recommendation).
75
+ */
76
+ readonly cnameTarget: pulumi.Output<string>;
71
77
  constructor(name: string, args: VercelDomainArgs, opts: VercelDomainOptions);
72
78
  }
73
79
  //#endregion
74
- export { VERCEL_CNAME_TARGET, VercelDomain, VercelDomainArgs, VercelDomainInputs, VercelDomainResourceProvider };
80
+ export { VercelDomain, VercelDomainArgs, VercelDomainInputs, VercelDomainResourceProvider };
75
81
  //# sourceMappingURL=domain.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"domain.d.cts","names":[],"sources":["../../src/vercel/domain.ts"],"mappings":";;;;;;;;;AAUA;cAAa,mBAAA;;UAGI,kBAAA;EAHe;EAK/B,KAAA;EAFkC;EAKlC,MAAA;EALkC;EAQlC,SAAA;EAHA;EAMA,IAAA;AAAA;;UAIS,mBAAA,SAA4B,kBAAkB;EAA9C;EAET,QAAQ;AAAA;;AAAA;AA6CT;;;;;;cAAa,4BAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,kBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EA8CpB,IAAA,CACL,GAAA,UACA,KAAA,EAAO,mBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAuBlB;EAFF,MAAA,CACL,GAAA,UACA,KAAA,EAAO,mBAAA,EACP,IAAA,EAAM,kBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAIpB,MAAA,CAAO,GAAA,UAAa,KAAA,EAAO,mBAAA,GAAsB,OAAA;EAJpD;;;;EAoCG,IAAA,CACL,GAAA,UACA,IAAA,EAAM,mBAAA,EACN,IAAA,EAAM,kBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KAgDtB,mBAAA,GAAsB,IAAA,CAAK,MAAA,CAAO,wBAAA;EAtKI,qCAwK1C,QAAA,EAAU,cAAA,EAxKC;EA2KX,OAAA,EAAS,aAAA;AAAA;;UAIO,gBAAA;EA5Kf;EA8KD,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;cAWN,YAAA,SAAqB,MAAA,CAAO,iBAAA;EAvId;EAAA,SAyIV,QAAA,EAAU,MAAA,CAAO,MAAA;EAnHhC;EAAA,SAsHe,IAAA,EAAM,MAAA,CAAO,MAAA;cAEjB,IAAA,UAAc,IAAA,EAAM,gBAAA,EAAkB,IAAA,EAAM,mBAAA;AAAA"}
1
+ {"version":3,"file":"domain.d.cts","names":[],"sources":["../../src/vercel/domain.ts"],"mappings":";;;;;;;UAgBiB,kBAAA;;EAEhB,KAAA;EAFkC;EAKlC,MAAA;EALkC;EAQlC,SAAA;EAHA;EAMA,IAAA;AAAA;;UAIS,mBAAA,SAA4B,kBAAkB;EAA9C;EAET,QAAA;;EAGA,WAAA;AAAA;;;;AAAW;AAyFZ;;;;cAAa,4BAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,kBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EA2DpB,IAAA,CACL,GAAA,UACA,KAAA,EAAO,mBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAAf;EA6BL,MAAA,CACL,GAAA,UACA,IAAA,EAAM,mBAAA,EACN,IAAA,EAAM,kBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAMpB,MAAA,CAAO,GAAA,UAAa,KAAA,EAAO,mBAAA,GAAsB,OAAA;EAPhD;;;;EAuCD,IAAA,CACL,GAAA,UACA,IAAA,EAAM,mBAAA,EACN,IAAA,EAAM,kBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KAiDtB,mBAAA,GAAsB,IAAA,CAAK,MAAA,CAAO,wBAAA;EAjDnC,qCAmDH,QAAA,EAAU,cAAA,EAhMgC;EAmM1C,OAAA,EAAS,aAAA;AAAA;;UAIO,gBAAA;EArMV;EAuMN,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;cAcN,YAAA,SAAqB,MAAA,CAAO,iBAAA;EAxHlC;EAAA,SA0HU,QAAA,EAAU,MAAA,CAAO,MAAA;EAxH1B;EAAA,SA2HS,IAAA,EAAM,MAAA,CAAO,MAAA;EA1HtB;;;;;EAAA,SAiIS,WAAA,EAAa,MAAA,CAAO,MAAA;cAExB,IAAA,UAAc,IAAA,EAAM,gBAAA,EAAkB,IAAA,EAAM,mBAAA;AAAA"}
@@ -4,11 +4,6 @@ import { VercelProject } from "./project.mjs";
4
4
  import * as pulumi from "@pulumi/pulumi";
5
5
 
6
6
  //#region src/vercel/domain.d.ts
7
- /**
8
- * Vercel's documented CNAME target for attaching a subdomain to a project.
9
- * https://vercel.com/docs/domains/working-with-domains/add-a-domain
10
- */
11
- declare const VERCEL_CNAME_TARGET = "cname.vercel-dns.com";
12
7
  /** Resolved inputs for the Vercel domain dynamic provider. */
13
8
  interface VercelDomainInputs {
14
9
  /** Vercel API bearer token. */
@@ -24,6 +19,8 @@ interface VercelDomainInputs {
24
19
  interface VercelDomainOutputs extends VercelDomainInputs {
25
20
  /** `true` once the domain's DNS has been verified by Vercel. */
26
21
  verified: boolean;
22
+ /** The value to CNAME `name` to, per Vercel's own per-domain recommendation. */
23
+ cnameTarget: string;
27
24
  }
28
25
  /**
29
26
  * Dynamic provider implementing adopt-or-create for a Vercel project domain.
@@ -37,7 +34,7 @@ declare class VercelDomainResourceProvider implements pulumi.dynamic.ResourcePro
37
34
  create(inputs: VercelDomainInputs): Promise<pulumi.dynamic.CreateResult>;
38
35
  read(_id: string, props: VercelDomainOutputs): Promise<pulumi.dynamic.ReadResult>;
39
36
  /** All fields replace (see `diff`) — this is never actually invoked. */
40
- update(_id: string, _olds: VercelDomainOutputs, news: VercelDomainInputs): Promise<pulumi.dynamic.UpdateResult>;
37
+ update(_id: string, olds: VercelDomainOutputs, news: VercelDomainInputs): Promise<pulumi.dynamic.UpdateResult>;
41
38
  delete(_id: string, props: VercelDomainOutputs): Promise<void>;
42
39
  /**
43
40
  * A domain can only be attached to one project, so every field change replaces
@@ -60,7 +57,10 @@ interface VercelDomainArgs {
60
57
  *
61
58
  * @example
62
59
  * ```typescript
63
- * new VercelDomain("aura-domain", { name: "app.example.com" }, { provider, project });
60
+ * const domain = new VercelDomain("aura-domain", { name: "app.example.com" }, { provider, project });
61
+ *
62
+ * // Point app.example.com's DNS CNAME at this value.
63
+ * const cnameTarget = domain.cnameTarget;
64
64
  * ```
65
65
  */
66
66
  declare class VercelDomain extends pulumi.ComponentResource {
@@ -68,8 +68,14 @@ declare class VercelDomain extends pulumi.ComponentResource {
68
68
  readonly verified: pulumi.Output<boolean>;
69
69
  /** The attached domain name. */
70
70
  readonly name: pulumi.Output<string>;
71
+ /**
72
+ * The value to CNAME `name` to — Vercel's own recommendation for this specific
73
+ * domain, fetched fresh from its DNS config endpoint (falls back to a static default
74
+ * only if Vercel returns no recommendation).
75
+ */
76
+ readonly cnameTarget: pulumi.Output<string>;
71
77
  constructor(name: string, args: VercelDomainArgs, opts: VercelDomainOptions);
72
78
  }
73
79
  //#endregion
74
- export { VERCEL_CNAME_TARGET, VercelDomain, VercelDomainArgs, VercelDomainInputs, VercelDomainResourceProvider };
80
+ export { VercelDomain, VercelDomainArgs, VercelDomainInputs, VercelDomainResourceProvider };
75
81
  //# sourceMappingURL=domain.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"domain.d.mts","names":[],"sources":["../../src/vercel/domain.ts"],"mappings":";;;;;;;;;AAUA;cAAa,mBAAA;;UAGI,kBAAA;EAHe;EAK/B,KAAA;EAFkC;EAKlC,MAAA;EALkC;EAQlC,SAAA;EAHA;EAMA,IAAA;AAAA;;UAIS,mBAAA,SAA4B,kBAAkB;EAA9C;EAET,QAAQ;AAAA;;AAAA;AA6CT;;;;;;cAAa,4BAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,kBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EA8CpB,IAAA,CACL,GAAA,UACA,KAAA,EAAO,mBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAuBlB;EAFF,MAAA,CACL,GAAA,UACA,KAAA,EAAO,mBAAA,EACP,IAAA,EAAM,kBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAIpB,MAAA,CAAO,GAAA,UAAa,KAAA,EAAO,mBAAA,GAAsB,OAAA;EAJpD;;;;EAoCG,IAAA,CACL,GAAA,UACA,IAAA,EAAM,mBAAA,EACN,IAAA,EAAM,kBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KAgDtB,mBAAA,GAAsB,IAAA,CAAK,MAAA,CAAO,wBAAA;EAtKI,qCAwK1C,QAAA,EAAU,cAAA,EAxKC;EA2KX,OAAA,EAAS,aAAA;AAAA;;UAIO,gBAAA;EA5Kf;EA8KD,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;cAWN,YAAA,SAAqB,MAAA,CAAO,iBAAA;EAvId;EAAA,SAyIV,QAAA,EAAU,MAAA,CAAO,MAAA;EAnHhC;EAAA,SAsHe,IAAA,EAAM,MAAA,CAAO,MAAA;cAEjB,IAAA,UAAc,IAAA,EAAM,gBAAA,EAAkB,IAAA,EAAM,mBAAA;AAAA"}
1
+ {"version":3,"file":"domain.d.mts","names":[],"sources":["../../src/vercel/domain.ts"],"mappings":";;;;;;;UAgBiB,kBAAA;;EAEhB,KAAA;EAFkC;EAKlC,MAAA;EALkC;EAQlC,SAAA;EAHA;EAMA,IAAA;AAAA;;UAIS,mBAAA,SAA4B,kBAAkB;EAA9C;EAET,QAAA;;EAGA,WAAA;AAAA;;;;AAAW;AAyFZ;;;;cAAa,4BAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,kBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EA2DpB,IAAA,CACL,GAAA,UACA,KAAA,EAAO,mBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAAf;EA6BL,MAAA,CACL,GAAA,UACA,IAAA,EAAM,mBAAA,EACN,IAAA,EAAM,kBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAMpB,MAAA,CAAO,GAAA,UAAa,KAAA,EAAO,mBAAA,GAAsB,OAAA;EAPhD;;;;EAuCD,IAAA,CACL,GAAA,UACA,IAAA,EAAM,mBAAA,EACN,IAAA,EAAM,kBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KAiDtB,mBAAA,GAAsB,IAAA,CAAK,MAAA,CAAO,wBAAA;EAjDnC,qCAmDH,QAAA,EAAU,cAAA,EAhMgC;EAmM1C,OAAA,EAAS,aAAA;AAAA;;UAIO,gBAAA;EArMV;EAuMN,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;cAcN,YAAA,SAAqB,MAAA,CAAO,iBAAA;EAxHlC;EAAA,SA0HU,QAAA,EAAU,MAAA,CAAO,MAAA;EAxH1B;EAAA,SA2HS,IAAA,EAAM,MAAA,CAAO,MAAA;EA1HtB;;;;;EAAA,SAiIS,WAAA,EAAa,MAAA,CAAO,MAAA;cAExB,IAAA,UAAc,IAAA,EAAM,gBAAA,EAAkB,IAAA,EAAM,mBAAA;AAAA"}
@@ -4,10 +4,29 @@ import * as pulumi from "@pulumi/pulumi";
4
4
  //#region src/vercel/domain.ts
5
5
  const VERCEL_API_URL = "https://api.vercel.com";
6
6
  /**
7
- * Vercel's documented CNAME target for attaching a subdomain to a project.
7
+ * Fallback CNAME target, used only when Vercel's domain-config endpoint returns no
8
+ * recommendation (see {@link fetchCnameTarget}). Not the primary source of truth —
9
+ * `VercelDomain.cnameTarget` queries Vercel's per-domain recommendation dynamically,
10
+ * since the actual target can vary by account/domain.
8
11
  * https://vercel.com/docs/domains/working-with-domains/add-a-domain
9
12
  */
10
- const VERCEL_CNAME_TARGET = "cname.vercel-dns.com";
13
+ const VERCEL_CNAME_TARGET_FALLBACK = "cname.vercel-dns.com";
14
+ /**
15
+ * Fetches Vercel's recommended CNAME target for a domain from its DNS config endpoint.
16
+ * Falls back to {@link VERCEL_CNAME_TARGET_FALLBACK} if Vercel returns no recommendation
17
+ * (logged, since that's an unusual state worth noticing rather than silently accepting).
18
+ */
19
+ async function fetchCnameTarget(token, teamId, name) {
20
+ const response = await fetch(`${VERCEL_API_URL}/v6/domains/${encodeURIComponent(name)}/config?teamId=${teamId}`, { headers: { Authorization: `Bearer ${token}` } });
21
+ if (!response.ok) throw new Error(`Vercel API error fetching domain config for "${name}" (${response.status}): ${await response.text()}`);
22
+ const { recommendedCNAME = [] } = await response.json();
23
+ const preferred = [...recommendedCNAME].sort((a, b) => a.rank - b.rank)[0];
24
+ if (!preferred) {
25
+ pulumi.log.info(`Vercel returned no recommended CNAME for "${name}" — falling back to "${VERCEL_CNAME_TARGET_FALLBACK}"`);
26
+ return VERCEL_CNAME_TARGET_FALLBACK;
27
+ }
28
+ return preferred.value;
29
+ }
11
30
  /**
12
31
  * Fetches a project domain by name. Returns `null` if not attached (404).
13
32
  */
@@ -32,7 +51,8 @@ var VercelDomainResourceProvider = class {
32
51
  pulumi.log.info(`Adopted existing Vercel domain "${inputs.name}" on project ${inputs.projectId}`);
33
52
  const outs = {
34
53
  ...inputs,
35
- verified: existing.verified
54
+ verified: existing.verified,
55
+ cnameTarget: await fetchCnameTarget(inputs.token, inputs.teamId, inputs.name)
36
56
  };
37
57
  return {
38
58
  id: `${inputs.projectId}/${inputs.name}`,
@@ -51,7 +71,8 @@ var VercelDomainResourceProvider = class {
51
71
  const created = await response.json();
52
72
  const outs = {
53
73
  ...inputs,
54
- verified: created.verified
74
+ verified: created.verified,
75
+ cnameTarget: await fetchCnameTarget(inputs.token, inputs.teamId, inputs.name)
55
76
  };
56
77
  return {
57
78
  id: `${inputs.projectId}/${inputs.name}`,
@@ -65,15 +86,17 @@ var VercelDomainResourceProvider = class {
65
86
  id: `${props.projectId}/${props.name}`,
66
87
  props: {
67
88
  ...props,
68
- verified: domain.verified
89
+ verified: domain.verified,
90
+ cnameTarget: await fetchCnameTarget(props.token, props.teamId, props.name)
69
91
  }
70
92
  };
71
93
  }
72
94
  /** All fields replace (see `diff`) — this is never actually invoked. */
73
- async update(_id, _olds, news) {
95
+ async update(_id, olds, news) {
74
96
  return { outs: {
75
97
  ...news,
76
- verified: false
98
+ verified: false,
99
+ cnameTarget: olds.cnameTarget
77
100
  } };
78
101
  }
79
102
  async delete(_id, props) {
@@ -109,7 +132,8 @@ var VercelDomainResource = class extends pulumi.dynamic.Resource {
109
132
  constructor(name, args, opts) {
110
133
  super(new VercelDomainResourceProvider(), name, {
111
134
  ...args,
112
- verified: void 0
135
+ verified: void 0,
136
+ cnameTarget: void 0
113
137
  }, opts);
114
138
  }
115
139
  };
@@ -118,7 +142,10 @@ var VercelDomainResource = class extends pulumi.dynamic.Resource {
118
142
  *
119
143
  * @example
120
144
  * ```typescript
121
- * new VercelDomain("aura-domain", { name: "app.example.com" }, { provider, project });
145
+ * const domain = new VercelDomain("aura-domain", { name: "app.example.com" }, { provider, project });
146
+ *
147
+ * // Point app.example.com's DNS CNAME at this value.
148
+ * const cnameTarget = domain.cnameTarget;
122
149
  * ```
123
150
  */
124
151
  var VercelDomain = class extends pulumi.ComponentResource {
@@ -133,13 +160,15 @@ var VercelDomain = class extends pulumi.ComponentResource {
133
160
  }, { parent: this });
134
161
  this.verified = resource.verified;
135
162
  this.name = resource.name;
163
+ this.cnameTarget = resource.cnameTarget;
136
164
  this.registerOutputs({
137
165
  verified: this.verified,
138
- name: this.name
166
+ name: this.name,
167
+ cnameTarget: this.cnameTarget
139
168
  });
140
169
  }
141
170
  };
142
171
 
143
172
  //#endregion
144
- export { VERCEL_CNAME_TARGET, VercelDomain, VercelDomainResourceProvider };
173
+ export { VercelDomain, VercelDomainResourceProvider };
145
174
  //# sourceMappingURL=domain.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"domain.mjs","names":[],"sources":["../../src/vercel/domain.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport type { VercelProject } from \"./project\";\nimport type { VercelProvider } from \"./provider\";\n\nconst VERCEL_API_URL = \"https://api.vercel.com\";\n\n/**\n * Vercel's documented CNAME target for attaching a subdomain to a project.\n * https://vercel.com/docs/domains/working-with-domains/add-a-domain\n */\nexport const VERCEL_CNAME_TARGET = \"cname.vercel-dns.com\";\n\n/** Resolved inputs for the Vercel domain dynamic provider. */\nexport interface VercelDomainInputs {\n\t/** Vercel API bearer token. */\n\ttoken: string;\n\n\t/** Vercel team/org ID. */\n\tteamId: string;\n\n\t/** Vercel project ID to attach the domain to. */\n\tprojectId: string;\n\n\t/** Domain name (e.g. `\"app.example.com\"`). */\n\tname: string;\n}\n\n/** Persisted state for the Vercel domain, extending inputs with verification status. */\ninterface VercelDomainOutputs extends VercelDomainInputs {\n\t/** `true` once the domain's DNS has been verified by Vercel. */\n\tverified: boolean;\n}\n\n/** Vercel API response shape for a project domain. */\ninterface VercelDomainResponse {\n\tname: string;\n\tprojectId: string;\n\tverified: boolean;\n}\n\n/**\n * Fetches a project domain by name. Returns `null` if not attached (404).\n */\nasync function fetchDomain(\n\ttoken: string,\n\tteamId: string,\n\tprojectId: string,\n\tname: string,\n): Promise<VercelDomainResponse | null> {\n\tconst response = await fetch(\n\t\t`${VERCEL_API_URL}/v9/projects/${encodeURIComponent(projectId)}/domains/${encodeURIComponent(name)}?teamId=${teamId}`,\n\t\t{ headers: { Authorization: `Bearer ${token}` } },\n\t);\n\n\tif (response.status === 404) {\n\t\treturn null;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow new Error(\n\t\t\t`Vercel API error fetching domain \"${name}\" (${response.status}): ${await response.text()}`,\n\t\t);\n\t}\n\n\treturn (await response.json()) as VercelDomainResponse;\n}\n\n/**\n * Dynamic provider implementing adopt-or-create for a Vercel project domain.\n *\n * On `create()`, calls `GET /v9/projects/{projectId}/domains/{name}`. If found, adopts\n * the existing attachment. If 404, attaches it via `POST /v10/projects/{projectId}/domains`.\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class VercelDomainResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst existing = await fetchDomain(\n\t\t\tinputs.token,\n\t\t\tinputs.teamId,\n\t\t\tinputs.projectId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (existing) {\n\t\t\tpulumi.log.info(\n\t\t\t\t`Adopted existing Vercel domain \"${inputs.name}\" on project ${inputs.projectId}`,\n\t\t\t);\n\n\t\t\tconst outs: VercelDomainOutputs = {\n\t\t\t\t...inputs,\n\t\t\t\tverified: existing.verified,\n\t\t\t};\n\n\t\t\treturn { id: `${inputs.projectId}/${inputs.name}`, outs };\n\t\t}\n\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v10/projects/${encodeURIComponent(inputs.projectId)}/domains?teamId=${inputs.teamId}`,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${inputs.token}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({ name: inputs.name }),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error creating domain \"${inputs.name}\" (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tconst created = (await response.json()) as VercelDomainResponse;\n\n\t\tconst outs: VercelDomainOutputs = { ...inputs, verified: created.verified };\n\n\t\treturn { id: `${inputs.projectId}/${inputs.name}`, outs };\n\t}\n\n\tasync read(\n\t\t_id: string,\n\t\tprops: VercelDomainOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst domain = await fetchDomain(\n\t\t\tprops.token,\n\t\t\tprops.teamId,\n\t\t\tprops.projectId,\n\t\t\tprops.name,\n\t\t);\n\n\t\tif (!domain) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel domain \"${props.name}\" not found on project ${props.projectId}`,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tid: `${props.projectId}/${props.name}`,\n\t\t\tprops: { ...props, verified: domain.verified },\n\t\t};\n\t}\n\n\t/** All fields replace (see `diff`) — this is never actually invoked. */\n\tasync update(\n\t\t_id: string,\n\t\t_olds: VercelDomainOutputs,\n\t\tnews: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\treturn { outs: { ...news, verified: false } };\n\t}\n\n\tasync delete(_id: string, props: VercelDomainOutputs): Promise<void> {\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v9/projects/${encodeURIComponent(props.projectId)}/domains/${encodeURIComponent(props.name)}?teamId=${props.teamId}`,\n\t\t\t{\n\t\t\t\tmethod: \"DELETE\",\n\t\t\t\theaders: { Authorization: `Bearer ${props.token}` },\n\t\t\t},\n\t\t);\n\n\t\tif (response.status === 404) {\n\t\t\tpulumi.log.warn(\n\t\t\t\t`Vercel domain \"${props.name}\" already gone from project ${props.projectId}`,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error deleting domain \"${props.name}\" (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tpulumi.log.info(\n\t\t\t`Deleted Vercel domain \"${props.name}\" from project ${props.projectId}`,\n\t\t);\n\t}\n\n\t/**\n\t * A domain can only be attached to one project, so every field change replaces\n\t * rather than updates.\n\t */\n\tasync diff(\n\t\t_id: string,\n\t\tolds: VercelDomainOutputs,\n\t\tnews: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.name !== news.name) {\n\t\t\treplaces.push(\"name\");\n\t\t}\n\n\t\tif (olds.projectId !== news.projectId) {\n\t\t\treplaces.push(\"projectId\");\n\t\t}\n\n\t\tif (olds.teamId !== news.teamId) {\n\t\t\treplaces.push(\"teamId\");\n\t\t}\n\n\t\treturn {\n\t\t\tchanges: replaces.length > 0,\n\t\t\treplaces,\n\t\t\tdeleteBeforeReplace: true,\n\t\t};\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass VercelDomainResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly verified: pulumi.Output<boolean>;\n\tpublic declare readonly name: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tteamId: pulumi.Input<string>;\n\t\t\tprojectId: pulumi.Input<string>;\n\t\t\tname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew VercelDomainResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, verified: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n\n/** Options type for VercelDomain — replaces Pulumi's native `provider` field. */\ntype VercelDomainOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Vercel authentication context. */\n\tprovider: VercelProvider;\n\n\t/** Vercel project to attach the domain to. */\n\tproject: VercelProject;\n};\n\n/** Args for VercelDomain. */\nexport interface VercelDomainArgs {\n\t/** Domain name (e.g. `\"app.example.com\"`). */\n\tname: pulumi.Input<string>;\n}\n\n/**\n * Attaches a custom domain to a Vercel project, with adopt-or-create semantics.\n *\n * @example\n * ```typescript\n * new VercelDomain(\"aura-domain\", { name: \"app.example.com\" }, { provider, project });\n * ```\n */\nexport class VercelDomain extends pulumi.ComponentResource {\n\t/** `true` once the domain's DNS has been verified by Vercel. */\n\tpublic readonly verified: pulumi.Output<boolean>;\n\n\t/** The attached domain name. */\n\tpublic readonly name: pulumi.Output<string>;\n\n\tconstructor(name: string, args: VercelDomainArgs, opts: VercelDomainOptions) {\n\t\tconst { provider, project, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:vercel:Domain\", name, {}, pulumiOpts);\n\n\t\tconst resource = new VercelDomainResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tteamId: provider.teamId,\n\t\t\t\tprojectId: project.id,\n\t\t\t\t...args,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.verified = resource.verified;\n\t\tthis.name = resource.name;\n\n\t\tthis.registerOutputs({ verified: this.verified, name: this.name });\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"domain.mjs","names":[],"sources":["../../src/vercel/domain.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport type { VercelProject } from \"./project\";\nimport type { VercelProvider } from \"./provider\";\n\nconst VERCEL_API_URL = \"https://api.vercel.com\";\n\n/**\n * Fallback CNAME target, used only when Vercel's domain-config endpoint returns no\n * recommendation (see {@link fetchCnameTarget}). Not the primary source of truth —\n * `VercelDomain.cnameTarget` queries Vercel's per-domain recommendation dynamically,\n * since the actual target can vary by account/domain.\n * https://vercel.com/docs/domains/working-with-domains/add-a-domain\n */\nconst VERCEL_CNAME_TARGET_FALLBACK = \"cname.vercel-dns.com\";\n\n/** Resolved inputs for the Vercel domain dynamic provider. */\nexport interface VercelDomainInputs {\n\t/** Vercel API bearer token. */\n\ttoken: string;\n\n\t/** Vercel team/org ID. */\n\tteamId: string;\n\n\t/** Vercel project ID to attach the domain to. */\n\tprojectId: string;\n\n\t/** Domain name (e.g. `\"app.example.com\"`). */\n\tname: string;\n}\n\n/** Persisted state for the Vercel domain, extending inputs with verification status. */\ninterface VercelDomainOutputs extends VercelDomainInputs {\n\t/** `true` once the domain's DNS has been verified by Vercel. */\n\tverified: boolean;\n\n\t/** The value to CNAME `name` to, per Vercel's own per-domain recommendation. */\n\tcnameTarget: string;\n}\n\n/** Vercel API response shape for a project domain. */\ninterface VercelDomainResponse {\n\tname: string;\n\tprojectId: string;\n\tverified: boolean;\n}\n\n/** A single ranked CNAME recommendation from `GET /v6/domains/{domain}/config`. */\ninterface VercelRecommendedCname {\n\trank: number;\n\tvalue: string;\n}\n\n/**\n * Fetches Vercel's recommended CNAME target for a domain from its DNS config endpoint.\n * Falls back to {@link VERCEL_CNAME_TARGET_FALLBACK} if Vercel returns no recommendation\n * (logged, since that's an unusual state worth noticing rather than silently accepting).\n */\nasync function fetchCnameTarget(\n\ttoken: string,\n\tteamId: string,\n\tname: string,\n): Promise<string> {\n\tconst response = await fetch(\n\t\t`${VERCEL_API_URL}/v6/domains/${encodeURIComponent(name)}/config?teamId=${teamId}`,\n\t\t{ headers: { Authorization: `Bearer ${token}` } },\n\t);\n\n\tif (!response.ok) {\n\t\tthrow new Error(\n\t\t\t`Vercel API error fetching domain config for \"${name}\" (${response.status}): ${await response.text()}`,\n\t\t);\n\t}\n\n\tconst { recommendedCNAME = [] } = (await response.json()) as {\n\t\trecommendedCNAME?: VercelRecommendedCname[];\n\t};\n\n\tconst preferred = [...recommendedCNAME].sort((a, b) => a.rank - b.rank)[0];\n\n\tif (!preferred) {\n\t\tpulumi.log.info(\n\t\t\t`Vercel returned no recommended CNAME for \"${name}\" — falling back to \"${VERCEL_CNAME_TARGET_FALLBACK}\"`,\n\t\t);\n\n\t\treturn VERCEL_CNAME_TARGET_FALLBACK;\n\t}\n\n\treturn preferred.value;\n}\n\n/**\n * Fetches a project domain by name. Returns `null` if not attached (404).\n */\nasync function fetchDomain(\n\ttoken: string,\n\tteamId: string,\n\tprojectId: string,\n\tname: string,\n): Promise<VercelDomainResponse | null> {\n\tconst response = await fetch(\n\t\t`${VERCEL_API_URL}/v9/projects/${encodeURIComponent(projectId)}/domains/${encodeURIComponent(name)}?teamId=${teamId}`,\n\t\t{ headers: { Authorization: `Bearer ${token}` } },\n\t);\n\n\tif (response.status === 404) {\n\t\treturn null;\n\t}\n\n\tif (!response.ok) {\n\t\tthrow new Error(\n\t\t\t`Vercel API error fetching domain \"${name}\" (${response.status}): ${await response.text()}`,\n\t\t);\n\t}\n\n\treturn (await response.json()) as VercelDomainResponse;\n}\n\n/**\n * Dynamic provider implementing adopt-or-create for a Vercel project domain.\n *\n * On `create()`, calls `GET /v9/projects/{projectId}/domains/{name}`. If found, adopts\n * the existing attachment. If 404, attaches it via `POST /v10/projects/{projectId}/domains`.\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class VercelDomainResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst existing = await fetchDomain(\n\t\t\tinputs.token,\n\t\t\tinputs.teamId,\n\t\t\tinputs.projectId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (existing) {\n\t\t\tpulumi.log.info(\n\t\t\t\t`Adopted existing Vercel domain \"${inputs.name}\" on project ${inputs.projectId}`,\n\t\t\t);\n\n\t\t\tconst outs: VercelDomainOutputs = {\n\t\t\t\t...inputs,\n\t\t\t\tverified: existing.verified,\n\t\t\t\tcnameTarget: await fetchCnameTarget(\n\t\t\t\t\tinputs.token,\n\t\t\t\t\tinputs.teamId,\n\t\t\t\t\tinputs.name,\n\t\t\t\t),\n\t\t\t};\n\n\t\t\treturn { id: `${inputs.projectId}/${inputs.name}`, outs };\n\t\t}\n\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v10/projects/${encodeURIComponent(inputs.projectId)}/domains?teamId=${inputs.teamId}`,\n\t\t\t{\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\tAuthorization: `Bearer ${inputs.token}`,\n\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t},\n\t\t\t\tbody: JSON.stringify({ name: inputs.name }),\n\t\t\t},\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error creating domain \"${inputs.name}\" (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tconst created = (await response.json()) as VercelDomainResponse;\n\n\t\tconst outs: VercelDomainOutputs = {\n\t\t\t...inputs,\n\t\t\tverified: created.verified,\n\t\t\tcnameTarget: await fetchCnameTarget(\n\t\t\t\tinputs.token,\n\t\t\t\tinputs.teamId,\n\t\t\t\tinputs.name,\n\t\t\t),\n\t\t};\n\n\t\treturn { id: `${inputs.projectId}/${inputs.name}`, outs };\n\t}\n\n\tasync read(\n\t\t_id: string,\n\t\tprops: VercelDomainOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst domain = await fetchDomain(\n\t\t\tprops.token,\n\t\t\tprops.teamId,\n\t\t\tprops.projectId,\n\t\t\tprops.name,\n\t\t);\n\n\t\tif (!domain) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel domain \"${props.name}\" not found on project ${props.projectId}`,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tid: `${props.projectId}/${props.name}`,\n\t\t\tprops: {\n\t\t\t\t...props,\n\t\t\t\tverified: domain.verified,\n\t\t\t\tcnameTarget: await fetchCnameTarget(\n\t\t\t\t\tprops.token,\n\t\t\t\t\tprops.teamId,\n\t\t\t\t\tprops.name,\n\t\t\t\t),\n\t\t\t},\n\t\t};\n\t}\n\n\t/** All fields replace (see `diff`) — this is never actually invoked. */\n\tasync update(\n\t\t_id: string,\n\t\tolds: VercelDomainOutputs,\n\t\tnews: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\treturn {\n\t\t\touts: { ...news, verified: false, cnameTarget: olds.cnameTarget },\n\t\t};\n\t}\n\n\tasync delete(_id: string, props: VercelDomainOutputs): Promise<void> {\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v9/projects/${encodeURIComponent(props.projectId)}/domains/${encodeURIComponent(props.name)}?teamId=${props.teamId}`,\n\t\t\t{\n\t\t\t\tmethod: \"DELETE\",\n\t\t\t\theaders: { Authorization: `Bearer ${props.token}` },\n\t\t\t},\n\t\t);\n\n\t\tif (response.status === 404) {\n\t\t\tpulumi.log.warn(\n\t\t\t\t`Vercel domain \"${props.name}\" already gone from project ${props.projectId}`,\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error deleting domain \"${props.name}\" (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tpulumi.log.info(\n\t\t\t`Deleted Vercel domain \"${props.name}\" from project ${props.projectId}`,\n\t\t);\n\t}\n\n\t/**\n\t * A domain can only be attached to one project, so every field change replaces\n\t * rather than updates.\n\t */\n\tasync diff(\n\t\t_id: string,\n\t\tolds: VercelDomainOutputs,\n\t\tnews: VercelDomainInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.name !== news.name) {\n\t\t\treplaces.push(\"name\");\n\t\t}\n\n\t\tif (olds.projectId !== news.projectId) {\n\t\t\treplaces.push(\"projectId\");\n\t\t}\n\n\t\tif (olds.teamId !== news.teamId) {\n\t\t\treplaces.push(\"teamId\");\n\t\t}\n\n\t\treturn {\n\t\t\tchanges: replaces.length > 0,\n\t\t\treplaces,\n\t\t\tdeleteBeforeReplace: true,\n\t\t};\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass VercelDomainResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly verified: pulumi.Output<boolean>;\n\tpublic declare readonly name: pulumi.Output<string>;\n\tpublic declare readonly cnameTarget: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tteamId: pulumi.Input<string>;\n\t\t\tprojectId: pulumi.Input<string>;\n\t\t\tname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew VercelDomainResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, verified: undefined, cnameTarget: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n\n/** Options type for VercelDomain — replaces Pulumi's native `provider` field. */\ntype VercelDomainOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Vercel authentication context. */\n\tprovider: VercelProvider;\n\n\t/** Vercel project to attach the domain to. */\n\tproject: VercelProject;\n};\n\n/** Args for VercelDomain. */\nexport interface VercelDomainArgs {\n\t/** Domain name (e.g. `\"app.example.com\"`). */\n\tname: pulumi.Input<string>;\n}\n\n/**\n * Attaches a custom domain to a Vercel project, with adopt-or-create semantics.\n *\n * @example\n * ```typescript\n * const domain = new VercelDomain(\"aura-domain\", { name: \"app.example.com\" }, { provider, project });\n *\n * // Point app.example.com's DNS CNAME at this value.\n * const cnameTarget = domain.cnameTarget;\n * ```\n */\nexport class VercelDomain extends pulumi.ComponentResource {\n\t/** `true` once the domain's DNS has been verified by Vercel. */\n\tpublic readonly verified: pulumi.Output<boolean>;\n\n\t/** The attached domain name. */\n\tpublic readonly name: pulumi.Output<string>;\n\n\t/**\n\t * The value to CNAME `name` to — Vercel's own recommendation for this specific\n\t * domain, fetched fresh from its DNS config endpoint (falls back to a static default\n\t * only if Vercel returns no recommendation).\n\t */\n\tpublic readonly cnameTarget: pulumi.Output<string>;\n\n\tconstructor(name: string, args: VercelDomainArgs, opts: VercelDomainOptions) {\n\t\tconst { provider, project, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:vercel:Domain\", name, {}, pulumiOpts);\n\n\t\tconst resource = new VercelDomainResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tteamId: provider.teamId,\n\t\t\t\tprojectId: project.id,\n\t\t\t\t...args,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.verified = resource.verified;\n\t\tthis.name = resource.name;\n\t\tthis.cnameTarget = resource.cnameTarget;\n\n\t\tthis.registerOutputs({\n\t\t\tverified: this.verified,\n\t\t\tname: this.name,\n\t\t\tcnameTarget: this.cnameTarget,\n\t\t});\n\t}\n}\n"],"mappings":"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"}
@@ -8,7 +8,6 @@ const require_vercel_provider = require('./provider.cjs');
8
8
  const require_vercel_resource_connection = require('./resource-connection.cjs');
9
9
  const require_vercel_variable = require('./variable.cjs');
10
10
 
11
- exports.VERCEL_CNAME_TARGET = require_vercel_domain.VERCEL_CNAME_TARGET;
12
11
  exports.VERCEL_FRAMEWORKS = require_vercel_project.VERCEL_FRAMEWORKS;
13
12
  exports.VercelDeploy = require_vercel_deploy.VercelDeploy;
14
13
  exports.VercelDomain = require_vercel_domain.VercelDomain;
@@ -1,9 +1,9 @@
1
1
  import { VercelProvider, VercelProviderArgs } from "./provider.cjs";
2
2
  import { VERCEL_FRAMEWORKS, VercelFramework, VercelProject, VercelProjectArgs } from "./project.cjs";
3
3
  import { VercelDeploy, VercelDeployArgs } from "./deploy.cjs";
4
- import { VERCEL_CNAME_TARGET, VercelDomain, VercelDomainArgs } from "./domain.cjs";
4
+ import { VercelDomain, VercelDomainArgs } from "./domain.cjs";
5
5
  import { VercelIntegration, VercelIntegrationArgs } from "./integration.cjs";
6
6
  import { VercelMarketplaceResource, VercelMarketplaceResourceArgs } from "./marketplace-resource.cjs";
7
7
  import { VercelResourceConnection, VercelResourceConnectionArgs } from "./resource-connection.cjs";
8
8
  import { VercelVariable, VercelVariableArgs } from "./variable.cjs";
9
- export { VERCEL_CNAME_TARGET, VERCEL_FRAMEWORKS, VercelDeploy, type VercelDeployArgs, VercelDomain, type VercelDomainArgs, type VercelFramework, VercelIntegration, type VercelIntegrationArgs, VercelMarketplaceResource, type VercelMarketplaceResourceArgs, VercelProject, type VercelProjectArgs, VercelProvider, type VercelProviderArgs, VercelResourceConnection, type VercelResourceConnectionArgs, VercelVariable, type VercelVariableArgs };
9
+ export { VERCEL_FRAMEWORKS, VercelDeploy, type VercelDeployArgs, VercelDomain, type VercelDomainArgs, type VercelFramework, VercelIntegration, type VercelIntegrationArgs, VercelMarketplaceResource, type VercelMarketplaceResourceArgs, VercelProject, type VercelProjectArgs, VercelProvider, type VercelProviderArgs, VercelResourceConnection, type VercelResourceConnectionArgs, VercelVariable, type VercelVariableArgs };
@@ -1,9 +1,9 @@
1
1
  import { VercelProvider, VercelProviderArgs } from "./provider.mjs";
2
2
  import { VERCEL_FRAMEWORKS, VercelFramework, VercelProject, VercelProjectArgs } from "./project.mjs";
3
3
  import { VercelDeploy, VercelDeployArgs } from "./deploy.mjs";
4
- import { VERCEL_CNAME_TARGET, VercelDomain, VercelDomainArgs } from "./domain.mjs";
4
+ import { VercelDomain, VercelDomainArgs } from "./domain.mjs";
5
5
  import { VercelIntegration, VercelIntegrationArgs } from "./integration.mjs";
6
6
  import { VercelMarketplaceResource, VercelMarketplaceResourceArgs } from "./marketplace-resource.mjs";
7
7
  import { VercelResourceConnection, VercelResourceConnectionArgs } from "./resource-connection.mjs";
8
8
  import { VercelVariable, VercelVariableArgs } from "./variable.mjs";
9
- export { VERCEL_CNAME_TARGET, VERCEL_FRAMEWORKS, VercelDeploy, type VercelDeployArgs, VercelDomain, type VercelDomainArgs, type VercelFramework, VercelIntegration, type VercelIntegrationArgs, VercelMarketplaceResource, type VercelMarketplaceResourceArgs, VercelProject, type VercelProjectArgs, VercelProvider, type VercelProviderArgs, VercelResourceConnection, type VercelResourceConnectionArgs, VercelVariable, type VercelVariableArgs };
9
+ export { VERCEL_FRAMEWORKS, VercelDeploy, type VercelDeployArgs, VercelDomain, type VercelDomainArgs, type VercelFramework, VercelIntegration, type VercelIntegrationArgs, VercelMarketplaceResource, type VercelMarketplaceResourceArgs, VercelProject, type VercelProjectArgs, VercelProvider, type VercelProviderArgs, VercelResourceConnection, type VercelResourceConnectionArgs, VercelVariable, type VercelVariableArgs };
@@ -1,5 +1,5 @@
1
1
  import { VercelDeploy } from "./deploy.mjs";
2
- import { VERCEL_CNAME_TARGET, VercelDomain } from "./domain.mjs";
2
+ import { VercelDomain } from "./domain.mjs";
3
3
  import { VercelIntegration } from "./integration.mjs";
4
4
  import { VercelMarketplaceResource } from "./marketplace-resource.mjs";
5
5
  import { VERCEL_FRAMEWORKS, VercelProject } from "./project.mjs";
@@ -7,4 +7,4 @@ import { VercelProvider } from "./provider.mjs";
7
7
  import { VercelResourceConnection } from "./resource-connection.mjs";
8
8
  import { VercelVariable } from "./variable.mjs";
9
9
 
10
- export { VERCEL_CNAME_TARGET, VERCEL_FRAMEWORKS, VercelDeploy, VercelDomain, VercelIntegration, VercelMarketplaceResource, VercelProject, VercelProvider, VercelResourceConnection, VercelVariable };
10
+ export { VERCEL_FRAMEWORKS, VercelDeploy, VercelDomain, VercelIntegration, VercelMarketplaceResource, VercelProject, VercelProvider, VercelResourceConnection, VercelVariable };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infracraft/pulumi",
3
- "version": "1.19.0",
3
+ "version": "1.20.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Native Pulumi providers for Railway, Neon, Vercel, and Fly.io with adopt-or-create semantics and deploy orchestration. No Terraform bridge.",