@infracraft/pulumi 0.1.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.

Potentially problematic release.


This version of @infracraft/pulumi might be problematic. Click here for more details.

Files changed (151) hide show
  1. package/dist/chunk-BVYJZCqc.cjs +44 -0
  2. package/dist/chunk-OPjESj5l.mjs +9 -0
  3. package/dist/git-guard.cjs +62 -0
  4. package/dist/git-guard.cjs.map +1 -0
  5. package/dist/git-guard.d.cts +13 -0
  6. package/dist/git-guard.d.cts.map +1 -0
  7. package/dist/git-guard.d.mts +13 -0
  8. package/dist/git-guard.d.mts.map +1 -0
  9. package/dist/git-guard.mjs +56 -0
  10. package/dist/git-guard.mjs.map +1 -0
  11. package/dist/hash.cjs +40 -0
  12. package/dist/hash.cjs.map +1 -0
  13. package/dist/hash.d.cts +10 -0
  14. package/dist/hash.d.cts.map +1 -0
  15. package/dist/hash.d.mts +10 -0
  16. package/dist/hash.d.mts.map +1 -0
  17. package/dist/hash.mjs +36 -0
  18. package/dist/hash.mjs.map +1 -0
  19. package/dist/neon/branch.cjs +113 -0
  20. package/dist/neon/branch.cjs.map +1 -0
  21. package/dist/neon/branch.d.cts +40 -0
  22. package/dist/neon/branch.d.cts.map +1 -0
  23. package/dist/neon/branch.d.mts +40 -0
  24. package/dist/neon/branch.d.mts.map +1 -0
  25. package/dist/neon/branch.mjs +111 -0
  26. package/dist/neon/branch.mjs.map +1 -0
  27. package/dist/neon/client.cjs +85 -0
  28. package/dist/neon/client.cjs.map +1 -0
  29. package/dist/neon/client.d.cts +59 -0
  30. package/dist/neon/client.d.cts.map +1 -0
  31. package/dist/neon/client.d.mts +59 -0
  32. package/dist/neon/client.d.mts.map +1 -0
  33. package/dist/neon/client.mjs +84 -0
  34. package/dist/neon/client.mjs.map +1 -0
  35. package/dist/neon/database.cjs +117 -0
  36. package/dist/neon/database.cjs.map +1 -0
  37. package/dist/neon/database.d.cts +48 -0
  38. package/dist/neon/database.d.cts.map +1 -0
  39. package/dist/neon/database.d.mts +48 -0
  40. package/dist/neon/database.d.mts.map +1 -0
  41. package/dist/neon/database.mjs +115 -0
  42. package/dist/neon/database.mjs.map +1 -0
  43. package/dist/neon/endpoint.cjs +167 -0
  44. package/dist/neon/endpoint.cjs.map +1 -0
  45. package/dist/neon/endpoint.d.cts +57 -0
  46. package/dist/neon/endpoint.d.cts.map +1 -0
  47. package/dist/neon/endpoint.d.mts +57 -0
  48. package/dist/neon/endpoint.d.mts.map +1 -0
  49. package/dist/neon/endpoint.mjs +165 -0
  50. package/dist/neon/endpoint.mjs.map +1 -0
  51. package/dist/neon/index.cjs +14 -0
  52. package/dist/neon/index.d.cts +7 -0
  53. package/dist/neon/index.d.mts +7 -0
  54. package/dist/neon/index.mjs +8 -0
  55. package/dist/neon/project.cjs +120 -0
  56. package/dist/neon/project.cjs.map +1 -0
  57. package/dist/neon/project.d.cts +52 -0
  58. package/dist/neon/project.d.cts.map +1 -0
  59. package/dist/neon/project.d.mts +52 -0
  60. package/dist/neon/project.d.mts.map +1 -0
  61. package/dist/neon/project.mjs +118 -0
  62. package/dist/neon/project.mjs.map +1 -0
  63. package/dist/neon/role.cjs +135 -0
  64. package/dist/neon/role.cjs.map +1 -0
  65. package/dist/neon/role.d.cts +49 -0
  66. package/dist/neon/role.d.cts.map +1 -0
  67. package/dist/neon/role.d.mts +49 -0
  68. package/dist/neon/role.d.mts.map +1 -0
  69. package/dist/neon/role.mjs +133 -0
  70. package/dist/neon/role.mjs.map +1 -0
  71. package/dist/railway/client.cjs +59 -0
  72. package/dist/railway/client.cjs.map +1 -0
  73. package/dist/railway/client.d.cts +39 -0
  74. package/dist/railway/client.d.cts.map +1 -0
  75. package/dist/railway/client.d.mts +39 -0
  76. package/dist/railway/client.d.mts.map +1 -0
  77. package/dist/railway/client.mjs +58 -0
  78. package/dist/railway/client.mjs.map +1 -0
  79. package/dist/railway/deploy.cjs +40 -0
  80. package/dist/railway/deploy.cjs.map +1 -0
  81. package/dist/railway/deploy.d.cts +47 -0
  82. package/dist/railway/deploy.d.cts.map +1 -0
  83. package/dist/railway/deploy.d.mts +47 -0
  84. package/dist/railway/deploy.d.mts.map +1 -0
  85. package/dist/railway/deploy.mjs +37 -0
  86. package/dist/railway/deploy.mjs.map +1 -0
  87. package/dist/railway/domain.cjs +236 -0
  88. package/dist/railway/domain.cjs.map +1 -0
  89. package/dist/railway/domain.d.cts +52 -0
  90. package/dist/railway/domain.d.cts.map +1 -0
  91. package/dist/railway/domain.d.mts +52 -0
  92. package/dist/railway/domain.d.mts.map +1 -0
  93. package/dist/railway/domain.mjs +234 -0
  94. package/dist/railway/domain.mjs.map +1 -0
  95. package/dist/railway/index.cjs +16 -0
  96. package/dist/railway/index.d.cts +8 -0
  97. package/dist/railway/index.d.mts +8 -0
  98. package/dist/railway/index.mjs +9 -0
  99. package/dist/railway/project.cjs +231 -0
  100. package/dist/railway/project.cjs.map +1 -0
  101. package/dist/railway/project.d.cts +52 -0
  102. package/dist/railway/project.d.cts.map +1 -0
  103. package/dist/railway/project.d.mts +52 -0
  104. package/dist/railway/project.d.mts.map +1 -0
  105. package/dist/railway/project.mjs +229 -0
  106. package/dist/railway/project.mjs.map +1 -0
  107. package/dist/railway/service.cjs +268 -0
  108. package/dist/railway/service.cjs.map +1 -0
  109. package/dist/railway/service.d.cts +88 -0
  110. package/dist/railway/service.d.cts.map +1 -0
  111. package/dist/railway/service.d.mts +88 -0
  112. package/dist/railway/service.d.mts.map +1 -0
  113. package/dist/railway/service.mjs +266 -0
  114. package/dist/railway/service.mjs.map +1 -0
  115. package/dist/railway/variable.cjs +149 -0
  116. package/dist/railway/variable.cjs.map +1 -0
  117. package/dist/railway/variable.d.cts +52 -0
  118. package/dist/railway/variable.d.cts.map +1 -0
  119. package/dist/railway/variable.d.mts +52 -0
  120. package/dist/railway/variable.d.mts.map +1 -0
  121. package/dist/railway/variable.mjs +147 -0
  122. package/dist/railway/variable.mjs.map +1 -0
  123. package/dist/railway/volume.cjs +179 -0
  124. package/dist/railway/volume.cjs.map +1 -0
  125. package/dist/railway/volume.d.cts +52 -0
  126. package/dist/railway/volume.d.cts.map +1 -0
  127. package/dist/railway/volume.d.mts +52 -0
  128. package/dist/railway/volume.d.mts.map +1 -0
  129. package/dist/railway/volume.mjs +177 -0
  130. package/dist/railway/volume.mjs.map +1 -0
  131. package/dist/vercel/deploy.cjs +65 -0
  132. package/dist/vercel/deploy.cjs.map +1 -0
  133. package/dist/vercel/deploy.d.cts +54 -0
  134. package/dist/vercel/deploy.d.cts.map +1 -0
  135. package/dist/vercel/deploy.d.mts +54 -0
  136. package/dist/vercel/deploy.d.mts.map +1 -0
  137. package/dist/vercel/deploy.mjs +61 -0
  138. package/dist/vercel/deploy.mjs.map +1 -0
  139. package/dist/vercel/index.cjs +6 -0
  140. package/dist/vercel/index.d.cts +3 -0
  141. package/dist/vercel/index.d.mts +3 -0
  142. package/dist/vercel/index.mjs +4 -0
  143. package/dist/vercel/variable.cjs +280 -0
  144. package/dist/vercel/variable.cjs.map +1 -0
  145. package/dist/vercel/variable.d.cts +55 -0
  146. package/dist/vercel/variable.d.cts.map +1 -0
  147. package/dist/vercel/variable.d.mts +55 -0
  148. package/dist/vercel/variable.d.mts.map +1 -0
  149. package/dist/vercel/variable.mjs +278 -0
  150. package/dist/vercel/variable.mjs.map +1 -0
  151. package/package.json +62 -0
@@ -0,0 +1,236 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_chunk = require('../chunk-BVYJZCqc.cjs');
3
+ const require_railway_client = require('./client.cjs');
4
+ let _pulumi_pulumi = require("@pulumi/pulumi");
5
+ _pulumi_pulumi = require_chunk.__toESM(_pulumi_pulumi, 1);
6
+
7
+ //#region src/railway/domain.ts
8
+ const SERVICE_DOMAINS_QUERY = `
9
+ query($projectId: String!, $serviceId: String!, $environmentId: String!) {
10
+ domains(
11
+ projectId: $projectId
12
+ serviceId: $serviceId
13
+ environmentId: $environmentId
14
+ ) {
15
+ serviceDomains { id domain }
16
+ customDomains { id domain }
17
+ }
18
+ }
19
+ `;
20
+ const SERVICE_DOMAIN_CREATE = `
21
+ mutation($input: ServiceDomainCreateInput!) {
22
+ serviceDomainCreate(input: $input) { id domain }
23
+ }
24
+ `;
25
+ const CUSTOM_DOMAIN_CREATE = `
26
+ mutation($input: CustomDomainCreateInput!) {
27
+ customDomainCreate(input: $input) { id domain }
28
+ }
29
+ `;
30
+ const CUSTOM_DOMAIN_DELETE = `
31
+ mutation($id: String!) { customDomainDelete(id: $id) }
32
+ `;
33
+ const SERVICE_DOMAIN_DELETE = `
34
+ mutation($id: String!) { serviceDomainDelete(id: $id) }
35
+ `;
36
+ /**
37
+ * Queries all existing domains (service and custom) for a Railway service.
38
+ *
39
+ * @param client Authenticated Railway API client
40
+ * @param projectId Railway project UUID
41
+ * @param serviceId Railway service UUID
42
+ * @param environmentId Railway environment UUID
43
+ * @returns Separate arrays of service domains and custom domains with their IDs and FQDNs
44
+ */
45
+ async function findExistingDomains(client, projectId, serviceId, environmentId) {
46
+ return (await client.query(SERVICE_DOMAINS_QUERY, {
47
+ projectId,
48
+ serviceId,
49
+ environmentId
50
+ })).domains;
51
+ }
52
+ /**
53
+ * Dynamic provider implementing CRUD for Railway domains.
54
+ *
55
+ * Uses adopt-or-create: queries existing domains before creating new ones
56
+ * to prevent duplicates. Uses the FQDN as the Pulumi resource ID so
57
+ * `domain.id` returns the domain name directly (useful for URL composition).
58
+ *
59
+ * Supports both auto-generated Railway service domains and custom domains.
60
+ */
61
+ var RailwayDomainProvider = class {
62
+ /**
63
+ * Creates or adopts a Railway domain.
64
+ *
65
+ * If `customDomain` is set, creates/adopts a custom domain.
66
+ * Otherwise, creates/adopts an auto-generated Railway service domain.
67
+ *
68
+ * @param inputs Resolved domain configuration
69
+ * @returns The FQDN as the resource ID
70
+ */
71
+ async create(inputs) {
72
+ const client = new require_railway_client.RailwayClient(inputs.token);
73
+ const existing = await findExistingDomains(client, inputs.projectId, inputs.serviceId, inputs.environmentId);
74
+ if (inputs.customDomain) {
75
+ const found = existing.customDomains.find((d) => d.domain === inputs.customDomain);
76
+ if (found) {
77
+ _pulumi_pulumi.log.info(`Adopting existing custom domain "${found.domain}"`);
78
+ return {
79
+ id: found.domain,
80
+ outs: {
81
+ ...inputs,
82
+ domainId: found.id,
83
+ fqdn: found.domain
84
+ }
85
+ };
86
+ }
87
+ const result = await client.query(CUSTOM_DOMAIN_CREATE, { input: {
88
+ projectId: inputs.projectId,
89
+ serviceId: inputs.serviceId,
90
+ environmentId: inputs.environmentId,
91
+ domain: inputs.customDomain
92
+ } });
93
+ return {
94
+ id: result.customDomainCreate.domain,
95
+ outs: {
96
+ ...inputs,
97
+ domainId: result.customDomainCreate.id,
98
+ fqdn: result.customDomainCreate.domain
99
+ }
100
+ };
101
+ }
102
+ if (existing.serviceDomains.length > 0) {
103
+ const found = existing.serviceDomains[0];
104
+ _pulumi_pulumi.log.info(`Adopting existing service domain "${found.domain}"`);
105
+ return {
106
+ id: found.domain,
107
+ outs: {
108
+ ...inputs,
109
+ domainId: found.id,
110
+ fqdn: found.domain
111
+ }
112
+ };
113
+ }
114
+ const result = await client.query(SERVICE_DOMAIN_CREATE, { input: {
115
+ serviceId: inputs.serviceId,
116
+ environmentId: inputs.environmentId
117
+ } });
118
+ return {
119
+ id: result.serviceDomainCreate.domain,
120
+ outs: {
121
+ ...inputs,
122
+ domainId: result.serviceDomainCreate.id,
123
+ fqdn: result.serviceDomainCreate.domain
124
+ }
125
+ };
126
+ }
127
+ /**
128
+ * Reads current state for `pulumi refresh` by querying existing domains.
129
+ *
130
+ * @param id Current FQDN resource ID
131
+ * @param props Last known persisted state
132
+ * @returns Refreshed resource ID and properties
133
+ * @throws {Error} If the domain no longer exists in Railway
134
+ */
135
+ async read(_id, props) {
136
+ const existing = await findExistingDomains(new require_railway_client.RailwayClient(props.token), props.projectId, props.serviceId, props.environmentId);
137
+ if (props.customDomain) {
138
+ const found = existing.customDomains.find((d) => d.domain === props.customDomain);
139
+ if (!found) throw new Error(`Custom domain "${props.customDomain}" not found during refresh`);
140
+ return {
141
+ id: found.domain,
142
+ props: {
143
+ ...props,
144
+ domainId: found.id,
145
+ fqdn: found.domain
146
+ }
147
+ };
148
+ }
149
+ if (existing.serviceDomains.length > 0) {
150
+ const found = existing.serviceDomains[0];
151
+ return {
152
+ id: found.domain,
153
+ props: {
154
+ ...props,
155
+ domainId: found.id,
156
+ fqdn: found.domain
157
+ }
158
+ };
159
+ }
160
+ throw new Error("Railway domain not found during refresh");
161
+ }
162
+ /**
163
+ * Deletes the Railway domain. Uses `domainId` (UUID) for the API call.
164
+ * Silently succeeds if already deleted.
165
+ *
166
+ * @param _id Current FQDN resource ID (unused for API call)
167
+ * @param props Last known persisted state (contains `domainId` for deletion)
168
+ */
169
+ async delete(_id, props) {
170
+ const client = new require_railway_client.RailwayClient(props.token);
171
+ const mutation = props.customDomain ? CUSTOM_DOMAIN_DELETE : SERVICE_DOMAIN_DELETE;
172
+ try {
173
+ await client.query(mutation, { id: props.domainId });
174
+ } catch {
175
+ _pulumi_pulumi.log.warn("Failed to delete Railway domain (may already be deleted)");
176
+ }
177
+ }
178
+ /**
179
+ * Compares old and new inputs to determine what changed.
180
+ *
181
+ * Triggers replacement when `serviceId`, `customDomain`, or `environmentId` changes,
182
+ * since domains cannot be moved between services or environments.
183
+ *
184
+ * @param _id Current resource ID (unused)
185
+ * @param olds Previous persisted state
186
+ * @param news New desired configuration
187
+ * @returns Diff result with replacement triggers
188
+ */
189
+ async diff(_id, olds, news) {
190
+ const replaces = [];
191
+ if (olds.serviceId !== news.serviceId) replaces.push("serviceId");
192
+ if (olds.customDomain !== news.customDomain) replaces.push("customDomain");
193
+ if (olds.environmentId !== news.environmentId) replaces.push("environmentId");
194
+ return {
195
+ changes: replaces.length > 0,
196
+ replaces,
197
+ deleteBeforeReplace: true
198
+ };
199
+ }
200
+ };
201
+ /**
202
+ * Manages a Railway domain (service or custom) with adopt-or-create semantics.
203
+ *
204
+ * Uses the FQDN as the Pulumi resource ID so `domain.id` returns the domain name
205
+ * directly, enabling `pulumi.interpolate\`https://${domain.id}\`` for URL composition.
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * const domain = new RailwayDomain("railway-domain-api", {
210
+ * token: project.projectToken,
211
+ * projectId: project.projectId,
212
+ * serviceId: service.serviceId,
213
+ * environmentId: project.productionEnvironmentId,
214
+ * });
215
+ *
216
+ * const url = pulumi.interpolate`https://${domain.id}`;
217
+ * ```
218
+ */
219
+ var RailwayDomain = class extends _pulumi_pulumi.dynamic.Resource {
220
+ /**
221
+ * @param name Pulumi resource name (logical identifier in state)
222
+ * @param args Domain configuration inputs
223
+ * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)
224
+ */
225
+ constructor(name, args, opts) {
226
+ super(new RailwayDomainProvider(), name, {
227
+ ...args,
228
+ domainId: void 0,
229
+ fqdn: void 0
230
+ }, opts);
231
+ }
232
+ };
233
+
234
+ //#endregion
235
+ exports.RailwayDomain = RailwayDomain;
236
+ //# sourceMappingURL=domain.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.cjs","names":["RailwayClient","pulumi"],"sources":["../../src/railway/domain.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { RailwayClient } from \"./client.js\";\n\n/** Resolved inputs for the Railway domain dynamic provider. */\nexport interface RailwayDomainInputs {\n\t/** Railway API bearer token. */\n\ttoken: string;\n\n\t/** Railway project UUID. */\n\tprojectId: string;\n\n\t/** Railway service UUID to attach the domain to. */\n\tserviceId: string;\n\n\t/** Railway environment UUID (e.g. production). */\n\tenvironmentId: string;\n\n\t/** Custom domain FQDN (e.g. `\"api.example.com\"`). Omit for auto-generated Railway domain. */\n\tcustomDomain?: string;\n}\n\n/** Persisted state for the Railway domain, extending inputs with Railway-assigned identifiers. */\ninterface RailwayDomainOutputs extends RailwayDomainInputs {\n\t/** Railway-assigned domain UUID (used for deletion API calls). */\n\tdomainId: string;\n\n\t/** Fully qualified domain name (e.g. `\"api-production-abc.up.railway.app\"`). */\n\tfqdn: string;\n}\n\nconst SERVICE_DOMAINS_QUERY = `\n query($projectId: String!, $serviceId: String!, $environmentId: String!) {\n domains(\n projectId: $projectId\n serviceId: $serviceId\n environmentId: $environmentId\n ) {\n serviceDomains { id domain }\n customDomains { id domain }\n }\n }\n`;\n\nconst SERVICE_DOMAIN_CREATE = `\n mutation($input: ServiceDomainCreateInput!) {\n serviceDomainCreate(input: $input) { id domain }\n }\n`;\n\nconst CUSTOM_DOMAIN_CREATE = `\n mutation($input: CustomDomainCreateInput!) {\n customDomainCreate(input: $input) { id domain }\n }\n`;\n\nconst CUSTOM_DOMAIN_DELETE = `\n mutation($id: String!) { customDomainDelete(id: $id) }\n`;\n\nconst SERVICE_DOMAIN_DELETE = `\n mutation($id: String!) { serviceDomainDelete(id: $id) }\n`;\n\n/**\n * Queries all existing domains (service and custom) for a Railway service.\n *\n * @param client Authenticated Railway API client\n * @param projectId Railway project UUID\n * @param serviceId Railway service UUID\n * @param environmentId Railway environment UUID\n * @returns Separate arrays of service domains and custom domains with their IDs and FQDNs\n */\nasync function findExistingDomains(\n\tclient: RailwayClient,\n\tprojectId: string,\n\tserviceId: string,\n\tenvironmentId: string,\n): Promise<{\n\tserviceDomains: Array<{ id: string; domain: string }>;\n\tcustomDomains: Array<{ id: string; domain: string }>;\n}> {\n\tconst result = await client.query<{\n\t\tdomains: {\n\t\t\tserviceDomains: Array<{ id: string; domain: string }>;\n\t\t\tcustomDomains: Array<{ id: string; domain: string }>;\n\t\t};\n\t}>(SERVICE_DOMAINS_QUERY, { projectId, serviceId, environmentId });\n\n\treturn result.domains;\n}\n\n/**\n * Dynamic provider implementing CRUD for Railway domains.\n *\n * Uses adopt-or-create: queries existing domains before creating new ones\n * to prevent duplicates. Uses the FQDN as the Pulumi resource ID so\n * `domain.id` returns the domain name directly (useful for URL composition).\n *\n * Supports both auto-generated Railway service domains and custom domains.\n */\nclass RailwayDomainProvider implements pulumi.dynamic.ResourceProvider {\n\t/**\n\t * Creates or adopts a Railway domain.\n\t *\n\t * If `customDomain` is set, creates/adopts a custom domain.\n\t * Otherwise, creates/adopts an auto-generated Railway service domain.\n\t *\n\t * @param inputs Resolved domain configuration\n\t * @returns The FQDN as the resource ID\n\t */\n\tasync create(\n\t\tinputs: RailwayDomainInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new RailwayClient(inputs.token);\n\n\t\tconst existing = await findExistingDomains(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.serviceId,\n\t\t\tinputs.environmentId,\n\t\t);\n\n\t\tif (inputs.customDomain) {\n\t\t\tconst found = existing.customDomains.find(\n\t\t\t\t(d) => d.domain === inputs.customDomain,\n\t\t\t);\n\n\t\t\tif (found) {\n\t\t\t\tpulumi.log.info(`Adopting existing custom domain \"${found.domain}\"`);\n\n\t\t\t\treturn {\n\t\t\t\t\tid: found.domain,\n\t\t\t\t\touts: { ...inputs, domainId: found.id, fqdn: found.domain },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = await client.query<{\n\t\t\t\tcustomDomainCreate: { id: string; domain: string };\n\t\t\t}>(CUSTOM_DOMAIN_CREATE, {\n\t\t\t\tinput: {\n\t\t\t\t\tprojectId: inputs.projectId,\n\t\t\t\t\tserviceId: inputs.serviceId,\n\t\t\t\t\tenvironmentId: inputs.environmentId,\n\t\t\t\t\tdomain: inputs.customDomain,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tid: result.customDomainCreate.domain,\n\t\t\t\touts: {\n\t\t\t\t\t...inputs,\n\t\t\t\t\tdomainId: result.customDomainCreate.id,\n\t\t\t\t\tfqdn: result.customDomainCreate.domain,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tif (existing.serviceDomains.length > 0) {\n\t\t\tconst found = existing.serviceDomains[0];\n\n\t\t\tpulumi.log.info(`Adopting existing service domain \"${found.domain}\"`);\n\n\t\t\treturn {\n\t\t\t\tid: found.domain,\n\t\t\t\touts: { ...inputs, domainId: found.id, fqdn: found.domain },\n\t\t\t};\n\t\t}\n\n\t\tconst result = await client.query<{\n\t\t\tserviceDomainCreate: { id: string; domain: string };\n\t\t}>(SERVICE_DOMAIN_CREATE, {\n\t\t\tinput: {\n\t\t\t\tserviceId: inputs.serviceId,\n\t\t\t\tenvironmentId: inputs.environmentId,\n\t\t\t},\n\t\t});\n\n\t\treturn {\n\t\t\tid: result.serviceDomainCreate.domain,\n\t\t\touts: {\n\t\t\t\t...inputs,\n\t\t\t\tdomainId: result.serviceDomainCreate.id,\n\t\t\t\tfqdn: result.serviceDomainCreate.domain,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Reads current state for `pulumi refresh` by querying existing domains.\n\t *\n\t * @param id Current FQDN resource ID\n\t * @param props Last known persisted state\n\t * @returns Refreshed resource ID and properties\n\t * @throws {Error} If the domain no longer exists in Railway\n\t */\n\tasync read(\n\t\t_id: string,\n\t\tprops: RailwayDomainOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new RailwayClient(props.token);\n\n\t\tconst existing = await findExistingDomains(\n\t\t\tclient,\n\t\t\tprops.projectId,\n\t\t\tprops.serviceId,\n\t\t\tprops.environmentId,\n\t\t);\n\n\t\tif (props.customDomain) {\n\t\t\tconst found = existing.customDomains.find(\n\t\t\t\t(d) => d.domain === props.customDomain,\n\t\t\t);\n\n\t\t\tif (!found) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Custom domain \"${props.customDomain}\" not found during refresh`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tid: found.domain,\n\t\t\t\tprops: { ...props, domainId: found.id, fqdn: found.domain },\n\t\t\t};\n\t\t}\n\n\t\tif (existing.serviceDomains.length > 0) {\n\t\t\tconst found = existing.serviceDomains[0];\n\n\t\t\treturn {\n\t\t\t\tid: found.domain,\n\t\t\t\tprops: { ...props, domainId: found.id, fqdn: found.domain },\n\t\t\t};\n\t\t}\n\n\t\tthrow new Error(\"Railway domain not found during refresh\");\n\t}\n\n\t/**\n\t * Deletes the Railway domain. Uses `domainId` (UUID) for the API call.\n\t * Silently succeeds if already deleted.\n\t *\n\t * @param _id Current FQDN resource ID (unused for API call)\n\t * @param props Last known persisted state (contains `domainId` for deletion)\n\t */\n\tasync delete(_id: string, props: RailwayDomainOutputs): Promise<void> {\n\t\tconst client = new RailwayClient(props.token);\n\n\t\tconst mutation = props.customDomain\n\t\t\t? CUSTOM_DOMAIN_DELETE\n\t\t\t: SERVICE_DOMAIN_DELETE;\n\n\t\ttry {\n\t\t\tawait client.query(mutation, { id: props.domainId });\n\t\t} catch {\n\t\t\tpulumi.log.warn(\n\t\t\t\t\"Failed to delete Railway domain (may already be deleted)\",\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Compares old and new inputs to determine what changed.\n\t *\n\t * Triggers replacement when `serviceId`, `customDomain`, or `environmentId` changes,\n\t * since domains cannot be moved between services or environments.\n\t *\n\t * @param _id Current resource ID (unused)\n\t * @param olds Previous persisted state\n\t * @param news New desired configuration\n\t * @returns Diff result with replacement triggers\n\t */\n\tasync diff(\n\t\t_id: string,\n\t\tolds: RailwayDomainOutputs,\n\t\tnews: RailwayDomainInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.serviceId !== news.serviceId) {\n\t\t\treplaces.push(\"serviceId\");\n\t\t}\n\n\t\tif (olds.customDomain !== news.customDomain) {\n\t\t\treplaces.push(\"customDomain\");\n\t\t}\n\n\t\tif (olds.environmentId !== news.environmentId) {\n\t\t\treplaces.push(\"environmentId\");\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/**\n * Manages a Railway domain (service or custom) with adopt-or-create semantics.\n *\n * Uses the FQDN as the Pulumi resource ID so `domain.id` returns the domain name\n * directly, enabling `pulumi.interpolate\\`https://${domain.id}\\`` for URL composition.\n *\n * @example\n * ```typescript\n * const domain = new RailwayDomain(\"railway-domain-api\", {\n * token: project.projectToken,\n * projectId: project.projectId,\n * serviceId: service.serviceId,\n * environmentId: project.productionEnvironmentId,\n * });\n *\n * const url = pulumi.interpolate`https://${domain.id}`;\n * ```\n */\nexport class RailwayDomain extends pulumi.dynamic.Resource {\n\t/**\n\t * @param name Pulumi resource name (logical identifier in state)\n\t * @param args Domain configuration inputs\n\t * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)\n\t */\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\t/** Railway API bearer token. */\n\t\t\ttoken: pulumi.Input<string>;\n\n\t\t\t/** Railway project UUID. */\n\t\t\tprojectId: pulumi.Input<string>;\n\n\t\t\t/** Railway service UUID to attach the domain to. */\n\t\t\tserviceId: pulumi.Input<string>;\n\n\t\t\t/** Railway environment UUID (e.g. production). */\n\t\t\tenvironmentId: pulumi.Input<string>;\n\n\t\t\t/** Custom domain FQDN. Omit to create an auto-generated Railway service domain. */\n\t\t\tcustomDomain?: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew RailwayDomainProvider(),\n\t\t\tname,\n\t\t\t{ ...args, domainId: undefined, fqdn: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.cjs";
2
+ import * as pulumi from "@pulumi/pulumi";
3
+
4
+ //#region src/railway/domain.d.ts
5
+ /** Resolved inputs for the Railway domain dynamic provider. */
6
+ interface RailwayDomainInputs {
7
+ /** Railway API bearer token. */
8
+ token: string;
9
+ /** Railway project UUID. */
10
+ projectId: string;
11
+ /** Railway service UUID to attach the domain to. */
12
+ serviceId: string;
13
+ /** Railway environment UUID (e.g. production). */
14
+ environmentId: string;
15
+ /** Custom domain FQDN (e.g. `"api.example.com"`). Omit for auto-generated Railway domain. */
16
+ customDomain?: string;
17
+ }
18
+ /**
19
+ * Manages a Railway domain (service or custom) with adopt-or-create semantics.
20
+ *
21
+ * Uses the FQDN as the Pulumi resource ID so `domain.id` returns the domain name
22
+ * directly, enabling `pulumi.interpolate\`https://${domain.id}\`` for URL composition.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const domain = new RailwayDomain("railway-domain-api", {
27
+ * token: project.projectToken,
28
+ * projectId: project.projectId,
29
+ * serviceId: service.serviceId,
30
+ * environmentId: project.productionEnvironmentId,
31
+ * });
32
+ *
33
+ * const url = pulumi.interpolate`https://${domain.id}`;
34
+ * ```
35
+ */
36
+ declare class RailwayDomain extends pulumi.dynamic.Resource {
37
+ /**
38
+ * @param name Pulumi resource name (logical identifier in state)
39
+ * @param args Domain configuration inputs
40
+ * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)
41
+ */
42
+ constructor(name: string, args: {
43
+ /** Railway API bearer token. */token: pulumi.Input<string>; /** Railway project UUID. */
44
+ projectId: pulumi.Input<string>; /** Railway service UUID to attach the domain to. */
45
+ serviceId: pulumi.Input<string>; /** Railway environment UUID (e.g. production). */
46
+ environmentId: pulumi.Input<string>; /** Custom domain FQDN. Omit to create an auto-generated Railway service domain. */
47
+ customDomain?: pulumi.Input<string>;
48
+ }, opts?: pulumi.CustomResourceOptions);
49
+ }
50
+ //#endregion
51
+ export { RailwayDomain, RailwayDomainInputs };
52
+ //# sourceMappingURL=domain.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.d.cts","names":[],"sources":["../../src/railway/domain.ts"],"mappings":";;;;;UAIiB,mBAAA;;EAEhB,KAAA;EAFmC;EAKnC,SAAA;EALmC;EAQnC,SAAA;EAHA;EAMA,aAAA;EAAA;EAGA,YAAA;AAAA;AAAY;AA0Sb;;;;;;;;;;;;;;;;;AA1Sa,cA0SA,aAAA,SAAsB,MAAA,CAAO,OAAA,CAAQ,QAAA;EAUxC;;;;;cAHR,IAAA,UACA,IAAA;IAQY,gCANX,KAAA,EAAO,MAAA,CAAO,KAAA,UASd;IANA,SAAA,EAAW,MAAA,CAAO,KAAA,UAMI;IAHtB,SAAA,EAAW,MAAA,CAAO,KAAA,UAMH;IAHf,aAAA,EAAe,MAAA,CAAO,KAAA,UAXvB;IAcC,YAAA,GAAe,MAAA,CAAO,KAAA;EAAA,GAEvB,IAAA,GAAO,MAAA,CAAO,qBAAA;AAAA"}
@@ -0,0 +1,52 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.mjs";
2
+ import * as pulumi from "@pulumi/pulumi";
3
+
4
+ //#region src/railway/domain.d.ts
5
+ /** Resolved inputs for the Railway domain dynamic provider. */
6
+ interface RailwayDomainInputs {
7
+ /** Railway API bearer token. */
8
+ token: string;
9
+ /** Railway project UUID. */
10
+ projectId: string;
11
+ /** Railway service UUID to attach the domain to. */
12
+ serviceId: string;
13
+ /** Railway environment UUID (e.g. production). */
14
+ environmentId: string;
15
+ /** Custom domain FQDN (e.g. `"api.example.com"`). Omit for auto-generated Railway domain. */
16
+ customDomain?: string;
17
+ }
18
+ /**
19
+ * Manages a Railway domain (service or custom) with adopt-or-create semantics.
20
+ *
21
+ * Uses the FQDN as the Pulumi resource ID so `domain.id` returns the domain name
22
+ * directly, enabling `pulumi.interpolate\`https://${domain.id}\`` for URL composition.
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const domain = new RailwayDomain("railway-domain-api", {
27
+ * token: project.projectToken,
28
+ * projectId: project.projectId,
29
+ * serviceId: service.serviceId,
30
+ * environmentId: project.productionEnvironmentId,
31
+ * });
32
+ *
33
+ * const url = pulumi.interpolate`https://${domain.id}`;
34
+ * ```
35
+ */
36
+ declare class RailwayDomain extends pulumi.dynamic.Resource {
37
+ /**
38
+ * @param name Pulumi resource name (logical identifier in state)
39
+ * @param args Domain configuration inputs
40
+ * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)
41
+ */
42
+ constructor(name: string, args: {
43
+ /** Railway API bearer token. */token: pulumi.Input<string>; /** Railway project UUID. */
44
+ projectId: pulumi.Input<string>; /** Railway service UUID to attach the domain to. */
45
+ serviceId: pulumi.Input<string>; /** Railway environment UUID (e.g. production). */
46
+ environmentId: pulumi.Input<string>; /** Custom domain FQDN. Omit to create an auto-generated Railway service domain. */
47
+ customDomain?: pulumi.Input<string>;
48
+ }, opts?: pulumi.CustomResourceOptions);
49
+ }
50
+ //#endregion
51
+ export { RailwayDomain, RailwayDomainInputs };
52
+ //# sourceMappingURL=domain.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.d.mts","names":[],"sources":["../../src/railway/domain.ts"],"mappings":";;;;;UAIiB,mBAAA;;EAEhB,KAAA;EAFmC;EAKnC,SAAA;EALmC;EAQnC,SAAA;EAHA;EAMA,aAAA;EAAA;EAGA,YAAA;AAAA;AAAY;AA0Sb;;;;;;;;;;;;;;;;;AA1Sa,cA0SA,aAAA,SAAsB,MAAA,CAAO,OAAA,CAAQ,QAAA;EAUxC;;;;;cAHR,IAAA,UACA,IAAA;IAQY,gCANX,KAAA,EAAO,MAAA,CAAO,KAAA,UASd;IANA,SAAA,EAAW,MAAA,CAAO,KAAA,UAMI;IAHtB,SAAA,EAAW,MAAA,CAAO,KAAA,UAMH;IAHf,aAAA,EAAe,MAAA,CAAO,KAAA,UAXvB;IAcC,YAAA,GAAe,MAAA,CAAO,KAAA;EAAA,GAEvB,IAAA,GAAO,MAAA,CAAO,qBAAA;AAAA"}
@@ -0,0 +1,234 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.mjs";
2
+ import { RailwayClient } from "./client.mjs";
3
+ import * as pulumi from "@pulumi/pulumi";
4
+
5
+ //#region src/railway/domain.ts
6
+ const SERVICE_DOMAINS_QUERY = `
7
+ query($projectId: String!, $serviceId: String!, $environmentId: String!) {
8
+ domains(
9
+ projectId: $projectId
10
+ serviceId: $serviceId
11
+ environmentId: $environmentId
12
+ ) {
13
+ serviceDomains { id domain }
14
+ customDomains { id domain }
15
+ }
16
+ }
17
+ `;
18
+ const SERVICE_DOMAIN_CREATE = `
19
+ mutation($input: ServiceDomainCreateInput!) {
20
+ serviceDomainCreate(input: $input) { id domain }
21
+ }
22
+ `;
23
+ const CUSTOM_DOMAIN_CREATE = `
24
+ mutation($input: CustomDomainCreateInput!) {
25
+ customDomainCreate(input: $input) { id domain }
26
+ }
27
+ `;
28
+ const CUSTOM_DOMAIN_DELETE = `
29
+ mutation($id: String!) { customDomainDelete(id: $id) }
30
+ `;
31
+ const SERVICE_DOMAIN_DELETE = `
32
+ mutation($id: String!) { serviceDomainDelete(id: $id) }
33
+ `;
34
+ /**
35
+ * Queries all existing domains (service and custom) for a Railway service.
36
+ *
37
+ * @param client Authenticated Railway API client
38
+ * @param projectId Railway project UUID
39
+ * @param serviceId Railway service UUID
40
+ * @param environmentId Railway environment UUID
41
+ * @returns Separate arrays of service domains and custom domains with their IDs and FQDNs
42
+ */
43
+ async function findExistingDomains(client, projectId, serviceId, environmentId) {
44
+ return (await client.query(SERVICE_DOMAINS_QUERY, {
45
+ projectId,
46
+ serviceId,
47
+ environmentId
48
+ })).domains;
49
+ }
50
+ /**
51
+ * Dynamic provider implementing CRUD for Railway domains.
52
+ *
53
+ * Uses adopt-or-create: queries existing domains before creating new ones
54
+ * to prevent duplicates. Uses the FQDN as the Pulumi resource ID so
55
+ * `domain.id` returns the domain name directly (useful for URL composition).
56
+ *
57
+ * Supports both auto-generated Railway service domains and custom domains.
58
+ */
59
+ var RailwayDomainProvider = class {
60
+ /**
61
+ * Creates or adopts a Railway domain.
62
+ *
63
+ * If `customDomain` is set, creates/adopts a custom domain.
64
+ * Otherwise, creates/adopts an auto-generated Railway service domain.
65
+ *
66
+ * @param inputs Resolved domain configuration
67
+ * @returns The FQDN as the resource ID
68
+ */
69
+ async create(inputs) {
70
+ const client = new RailwayClient(inputs.token);
71
+ const existing = await findExistingDomains(client, inputs.projectId, inputs.serviceId, inputs.environmentId);
72
+ if (inputs.customDomain) {
73
+ const found = existing.customDomains.find((d) => d.domain === inputs.customDomain);
74
+ if (found) {
75
+ pulumi.log.info(`Adopting existing custom domain "${found.domain}"`);
76
+ return {
77
+ id: found.domain,
78
+ outs: {
79
+ ...inputs,
80
+ domainId: found.id,
81
+ fqdn: found.domain
82
+ }
83
+ };
84
+ }
85
+ const result = await client.query(CUSTOM_DOMAIN_CREATE, { input: {
86
+ projectId: inputs.projectId,
87
+ serviceId: inputs.serviceId,
88
+ environmentId: inputs.environmentId,
89
+ domain: inputs.customDomain
90
+ } });
91
+ return {
92
+ id: result.customDomainCreate.domain,
93
+ outs: {
94
+ ...inputs,
95
+ domainId: result.customDomainCreate.id,
96
+ fqdn: result.customDomainCreate.domain
97
+ }
98
+ };
99
+ }
100
+ if (existing.serviceDomains.length > 0) {
101
+ const found = existing.serviceDomains[0];
102
+ pulumi.log.info(`Adopting existing service domain "${found.domain}"`);
103
+ return {
104
+ id: found.domain,
105
+ outs: {
106
+ ...inputs,
107
+ domainId: found.id,
108
+ fqdn: found.domain
109
+ }
110
+ };
111
+ }
112
+ const result = await client.query(SERVICE_DOMAIN_CREATE, { input: {
113
+ serviceId: inputs.serviceId,
114
+ environmentId: inputs.environmentId
115
+ } });
116
+ return {
117
+ id: result.serviceDomainCreate.domain,
118
+ outs: {
119
+ ...inputs,
120
+ domainId: result.serviceDomainCreate.id,
121
+ fqdn: result.serviceDomainCreate.domain
122
+ }
123
+ };
124
+ }
125
+ /**
126
+ * Reads current state for `pulumi refresh` by querying existing domains.
127
+ *
128
+ * @param id Current FQDN resource ID
129
+ * @param props Last known persisted state
130
+ * @returns Refreshed resource ID and properties
131
+ * @throws {Error} If the domain no longer exists in Railway
132
+ */
133
+ async read(_id, props) {
134
+ const existing = await findExistingDomains(new RailwayClient(props.token), props.projectId, props.serviceId, props.environmentId);
135
+ if (props.customDomain) {
136
+ const found = existing.customDomains.find((d) => d.domain === props.customDomain);
137
+ if (!found) throw new Error(`Custom domain "${props.customDomain}" not found during refresh`);
138
+ return {
139
+ id: found.domain,
140
+ props: {
141
+ ...props,
142
+ domainId: found.id,
143
+ fqdn: found.domain
144
+ }
145
+ };
146
+ }
147
+ if (existing.serviceDomains.length > 0) {
148
+ const found = existing.serviceDomains[0];
149
+ return {
150
+ id: found.domain,
151
+ props: {
152
+ ...props,
153
+ domainId: found.id,
154
+ fqdn: found.domain
155
+ }
156
+ };
157
+ }
158
+ throw new Error("Railway domain not found during refresh");
159
+ }
160
+ /**
161
+ * Deletes the Railway domain. Uses `domainId` (UUID) for the API call.
162
+ * Silently succeeds if already deleted.
163
+ *
164
+ * @param _id Current FQDN resource ID (unused for API call)
165
+ * @param props Last known persisted state (contains `domainId` for deletion)
166
+ */
167
+ async delete(_id, props) {
168
+ const client = new RailwayClient(props.token);
169
+ const mutation = props.customDomain ? CUSTOM_DOMAIN_DELETE : SERVICE_DOMAIN_DELETE;
170
+ try {
171
+ await client.query(mutation, { id: props.domainId });
172
+ } catch {
173
+ pulumi.log.warn("Failed to delete Railway domain (may already be deleted)");
174
+ }
175
+ }
176
+ /**
177
+ * Compares old and new inputs to determine what changed.
178
+ *
179
+ * Triggers replacement when `serviceId`, `customDomain`, or `environmentId` changes,
180
+ * since domains cannot be moved between services or environments.
181
+ *
182
+ * @param _id Current resource ID (unused)
183
+ * @param olds Previous persisted state
184
+ * @param news New desired configuration
185
+ * @returns Diff result with replacement triggers
186
+ */
187
+ async diff(_id, olds, news) {
188
+ const replaces = [];
189
+ if (olds.serviceId !== news.serviceId) replaces.push("serviceId");
190
+ if (olds.customDomain !== news.customDomain) replaces.push("customDomain");
191
+ if (olds.environmentId !== news.environmentId) replaces.push("environmentId");
192
+ return {
193
+ changes: replaces.length > 0,
194
+ replaces,
195
+ deleteBeforeReplace: true
196
+ };
197
+ }
198
+ };
199
+ /**
200
+ * Manages a Railway domain (service or custom) with adopt-or-create semantics.
201
+ *
202
+ * Uses the FQDN as the Pulumi resource ID so `domain.id` returns the domain name
203
+ * directly, enabling `pulumi.interpolate\`https://${domain.id}\`` for URL composition.
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * const domain = new RailwayDomain("railway-domain-api", {
208
+ * token: project.projectToken,
209
+ * projectId: project.projectId,
210
+ * serviceId: service.serviceId,
211
+ * environmentId: project.productionEnvironmentId,
212
+ * });
213
+ *
214
+ * const url = pulumi.interpolate`https://${domain.id}`;
215
+ * ```
216
+ */
217
+ var RailwayDomain = class extends pulumi.dynamic.Resource {
218
+ /**
219
+ * @param name Pulumi resource name (logical identifier in state)
220
+ * @param args Domain configuration inputs
221
+ * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)
222
+ */
223
+ constructor(name, args, opts) {
224
+ super(new RailwayDomainProvider(), name, {
225
+ ...args,
226
+ domainId: void 0,
227
+ fqdn: void 0
228
+ }, opts);
229
+ }
230
+ };
231
+
232
+ //#endregion
233
+ export { RailwayDomain };
234
+ //# sourceMappingURL=domain.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain.mjs","names":[],"sources":["../../src/railway/domain.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { RailwayClient } from \"./client.js\";\n\n/** Resolved inputs for the Railway domain dynamic provider. */\nexport interface RailwayDomainInputs {\n\t/** Railway API bearer token. */\n\ttoken: string;\n\n\t/** Railway project UUID. */\n\tprojectId: string;\n\n\t/** Railway service UUID to attach the domain to. */\n\tserviceId: string;\n\n\t/** Railway environment UUID (e.g. production). */\n\tenvironmentId: string;\n\n\t/** Custom domain FQDN (e.g. `\"api.example.com\"`). Omit for auto-generated Railway domain. */\n\tcustomDomain?: string;\n}\n\n/** Persisted state for the Railway domain, extending inputs with Railway-assigned identifiers. */\ninterface RailwayDomainOutputs extends RailwayDomainInputs {\n\t/** Railway-assigned domain UUID (used for deletion API calls). */\n\tdomainId: string;\n\n\t/** Fully qualified domain name (e.g. `\"api-production-abc.up.railway.app\"`). */\n\tfqdn: string;\n}\n\nconst SERVICE_DOMAINS_QUERY = `\n query($projectId: String!, $serviceId: String!, $environmentId: String!) {\n domains(\n projectId: $projectId\n serviceId: $serviceId\n environmentId: $environmentId\n ) {\n serviceDomains { id domain }\n customDomains { id domain }\n }\n }\n`;\n\nconst SERVICE_DOMAIN_CREATE = `\n mutation($input: ServiceDomainCreateInput!) {\n serviceDomainCreate(input: $input) { id domain }\n }\n`;\n\nconst CUSTOM_DOMAIN_CREATE = `\n mutation($input: CustomDomainCreateInput!) {\n customDomainCreate(input: $input) { id domain }\n }\n`;\n\nconst CUSTOM_DOMAIN_DELETE = `\n mutation($id: String!) { customDomainDelete(id: $id) }\n`;\n\nconst SERVICE_DOMAIN_DELETE = `\n mutation($id: String!) { serviceDomainDelete(id: $id) }\n`;\n\n/**\n * Queries all existing domains (service and custom) for a Railway service.\n *\n * @param client Authenticated Railway API client\n * @param projectId Railway project UUID\n * @param serviceId Railway service UUID\n * @param environmentId Railway environment UUID\n * @returns Separate arrays of service domains and custom domains with their IDs and FQDNs\n */\nasync function findExistingDomains(\n\tclient: RailwayClient,\n\tprojectId: string,\n\tserviceId: string,\n\tenvironmentId: string,\n): Promise<{\n\tserviceDomains: Array<{ id: string; domain: string }>;\n\tcustomDomains: Array<{ id: string; domain: string }>;\n}> {\n\tconst result = await client.query<{\n\t\tdomains: {\n\t\t\tserviceDomains: Array<{ id: string; domain: string }>;\n\t\t\tcustomDomains: Array<{ id: string; domain: string }>;\n\t\t};\n\t}>(SERVICE_DOMAINS_QUERY, { projectId, serviceId, environmentId });\n\n\treturn result.domains;\n}\n\n/**\n * Dynamic provider implementing CRUD for Railway domains.\n *\n * Uses adopt-or-create: queries existing domains before creating new ones\n * to prevent duplicates. Uses the FQDN as the Pulumi resource ID so\n * `domain.id` returns the domain name directly (useful for URL composition).\n *\n * Supports both auto-generated Railway service domains and custom domains.\n */\nclass RailwayDomainProvider implements pulumi.dynamic.ResourceProvider {\n\t/**\n\t * Creates or adopts a Railway domain.\n\t *\n\t * If `customDomain` is set, creates/adopts a custom domain.\n\t * Otherwise, creates/adopts an auto-generated Railway service domain.\n\t *\n\t * @param inputs Resolved domain configuration\n\t * @returns The FQDN as the resource ID\n\t */\n\tasync create(\n\t\tinputs: RailwayDomainInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new RailwayClient(inputs.token);\n\n\t\tconst existing = await findExistingDomains(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.serviceId,\n\t\t\tinputs.environmentId,\n\t\t);\n\n\t\tif (inputs.customDomain) {\n\t\t\tconst found = existing.customDomains.find(\n\t\t\t\t(d) => d.domain === inputs.customDomain,\n\t\t\t);\n\n\t\t\tif (found) {\n\t\t\t\tpulumi.log.info(`Adopting existing custom domain \"${found.domain}\"`);\n\n\t\t\t\treturn {\n\t\t\t\t\tid: found.domain,\n\t\t\t\t\touts: { ...inputs, domainId: found.id, fqdn: found.domain },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = await client.query<{\n\t\t\t\tcustomDomainCreate: { id: string; domain: string };\n\t\t\t}>(CUSTOM_DOMAIN_CREATE, {\n\t\t\t\tinput: {\n\t\t\t\t\tprojectId: inputs.projectId,\n\t\t\t\t\tserviceId: inputs.serviceId,\n\t\t\t\t\tenvironmentId: inputs.environmentId,\n\t\t\t\t\tdomain: inputs.customDomain,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tid: result.customDomainCreate.domain,\n\t\t\t\touts: {\n\t\t\t\t\t...inputs,\n\t\t\t\t\tdomainId: result.customDomainCreate.id,\n\t\t\t\t\tfqdn: result.customDomainCreate.domain,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tif (existing.serviceDomains.length > 0) {\n\t\t\tconst found = existing.serviceDomains[0];\n\n\t\t\tpulumi.log.info(`Adopting existing service domain \"${found.domain}\"`);\n\n\t\t\treturn {\n\t\t\t\tid: found.domain,\n\t\t\t\touts: { ...inputs, domainId: found.id, fqdn: found.domain },\n\t\t\t};\n\t\t}\n\n\t\tconst result = await client.query<{\n\t\t\tserviceDomainCreate: { id: string; domain: string };\n\t\t}>(SERVICE_DOMAIN_CREATE, {\n\t\t\tinput: {\n\t\t\t\tserviceId: inputs.serviceId,\n\t\t\t\tenvironmentId: inputs.environmentId,\n\t\t\t},\n\t\t});\n\n\t\treturn {\n\t\t\tid: result.serviceDomainCreate.domain,\n\t\t\touts: {\n\t\t\t\t...inputs,\n\t\t\t\tdomainId: result.serviceDomainCreate.id,\n\t\t\t\tfqdn: result.serviceDomainCreate.domain,\n\t\t\t},\n\t\t};\n\t}\n\n\t/**\n\t * Reads current state for `pulumi refresh` by querying existing domains.\n\t *\n\t * @param id Current FQDN resource ID\n\t * @param props Last known persisted state\n\t * @returns Refreshed resource ID and properties\n\t * @throws {Error} If the domain no longer exists in Railway\n\t */\n\tasync read(\n\t\t_id: string,\n\t\tprops: RailwayDomainOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new RailwayClient(props.token);\n\n\t\tconst existing = await findExistingDomains(\n\t\t\tclient,\n\t\t\tprops.projectId,\n\t\t\tprops.serviceId,\n\t\t\tprops.environmentId,\n\t\t);\n\n\t\tif (props.customDomain) {\n\t\t\tconst found = existing.customDomains.find(\n\t\t\t\t(d) => d.domain === props.customDomain,\n\t\t\t);\n\n\t\t\tif (!found) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Custom domain \"${props.customDomain}\" not found during refresh`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tid: found.domain,\n\t\t\t\tprops: { ...props, domainId: found.id, fqdn: found.domain },\n\t\t\t};\n\t\t}\n\n\t\tif (existing.serviceDomains.length > 0) {\n\t\t\tconst found = existing.serviceDomains[0];\n\n\t\t\treturn {\n\t\t\t\tid: found.domain,\n\t\t\t\tprops: { ...props, domainId: found.id, fqdn: found.domain },\n\t\t\t};\n\t\t}\n\n\t\tthrow new Error(\"Railway domain not found during refresh\");\n\t}\n\n\t/**\n\t * Deletes the Railway domain. Uses `domainId` (UUID) for the API call.\n\t * Silently succeeds if already deleted.\n\t *\n\t * @param _id Current FQDN resource ID (unused for API call)\n\t * @param props Last known persisted state (contains `domainId` for deletion)\n\t */\n\tasync delete(_id: string, props: RailwayDomainOutputs): Promise<void> {\n\t\tconst client = new RailwayClient(props.token);\n\n\t\tconst mutation = props.customDomain\n\t\t\t? CUSTOM_DOMAIN_DELETE\n\t\t\t: SERVICE_DOMAIN_DELETE;\n\n\t\ttry {\n\t\t\tawait client.query(mutation, { id: props.domainId });\n\t\t} catch {\n\t\t\tpulumi.log.warn(\n\t\t\t\t\"Failed to delete Railway domain (may already be deleted)\",\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Compares old and new inputs to determine what changed.\n\t *\n\t * Triggers replacement when `serviceId`, `customDomain`, or `environmentId` changes,\n\t * since domains cannot be moved between services or environments.\n\t *\n\t * @param _id Current resource ID (unused)\n\t * @param olds Previous persisted state\n\t * @param news New desired configuration\n\t * @returns Diff result with replacement triggers\n\t */\n\tasync diff(\n\t\t_id: string,\n\t\tolds: RailwayDomainOutputs,\n\t\tnews: RailwayDomainInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.serviceId !== news.serviceId) {\n\t\t\treplaces.push(\"serviceId\");\n\t\t}\n\n\t\tif (olds.customDomain !== news.customDomain) {\n\t\t\treplaces.push(\"customDomain\");\n\t\t}\n\n\t\tif (olds.environmentId !== news.environmentId) {\n\t\t\treplaces.push(\"environmentId\");\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/**\n * Manages a Railway domain (service or custom) with adopt-or-create semantics.\n *\n * Uses the FQDN as the Pulumi resource ID so `domain.id` returns the domain name\n * directly, enabling `pulumi.interpolate\\`https://${domain.id}\\`` for URL composition.\n *\n * @example\n * ```typescript\n * const domain = new RailwayDomain(\"railway-domain-api\", {\n * token: project.projectToken,\n * projectId: project.projectId,\n * serviceId: service.serviceId,\n * environmentId: project.productionEnvironmentId,\n * });\n *\n * const url = pulumi.interpolate`https://${domain.id}`;\n * ```\n */\nexport class RailwayDomain extends pulumi.dynamic.Resource {\n\t/**\n\t * @param name Pulumi resource name (logical identifier in state)\n\t * @param args Domain configuration inputs\n\t * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)\n\t */\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\t/** Railway API bearer token. */\n\t\t\ttoken: pulumi.Input<string>;\n\n\t\t\t/** Railway project UUID. */\n\t\t\tprojectId: pulumi.Input<string>;\n\n\t\t\t/** Railway service UUID to attach the domain to. */\n\t\t\tserviceId: pulumi.Input<string>;\n\n\t\t\t/** Railway environment UUID (e.g. production). */\n\t\t\tenvironmentId: pulumi.Input<string>;\n\n\t\t\t/** Custom domain FQDN. Omit to create an auto-generated Railway service domain. */\n\t\t\tcustomDomain?: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew RailwayDomainProvider(),\n\t\t\tname,\n\t\t\t{ ...args, domainId: undefined, fqdn: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_railway_client = require('./client.cjs');
3
+ const require_railway_deploy = require('./deploy.cjs');
4
+ const require_railway_domain = require('./domain.cjs');
5
+ const require_railway_project = require('./project.cjs');
6
+ const require_railway_service = require('./service.cjs');
7
+ const require_railway_variable = require('./variable.cjs');
8
+ const require_railway_volume = require('./volume.cjs');
9
+
10
+ exports.RailwayClient = require_railway_client.RailwayClient;
11
+ exports.RailwayDeploy = require_railway_deploy.RailwayDeploy;
12
+ exports.RailwayDomain = require_railway_domain.RailwayDomain;
13
+ exports.RailwayProject = require_railway_project.RailwayProject;
14
+ exports.RailwayService = require_railway_service.RailwayService;
15
+ exports.RailwayVariable = require_railway_variable.RailwayVariable;
16
+ exports.RailwayVolume = require_railway_volume.RailwayVolume;
@@ -0,0 +1,8 @@
1
+ import { RailwayClient } from "./client.cjs";
2
+ import { RailwayDeploy, RailwayDeployConfig } from "./deploy.cjs";
3
+ import { RailwayDomain, RailwayDomainInputs } from "./domain.cjs";
4
+ import { RailwayProject, RailwayProjectInputs } from "./project.cjs";
5
+ import { RailwayService, RailwayServiceInputs } from "./service.cjs";
6
+ import { RailwayVariable, RailwayVariableInputs } from "./variable.cjs";
7
+ import { RailwayVolume, RailwayVolumeInputs } from "./volume.cjs";
8
+ export { RailwayClient, RailwayDeploy, type RailwayDeployConfig, RailwayDomain, type RailwayDomainInputs, RailwayProject, type RailwayProjectInputs, RailwayService, type RailwayServiceInputs, RailwayVariable, type RailwayVariableInputs, RailwayVolume, type RailwayVolumeInputs };