@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,147 @@
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/variable.ts
6
+ const VARIABLE_UPSERT = `
7
+ mutation($input: VariableCollectionUpsertInput!) {
8
+ variableCollectionUpsert(input: $input)
9
+ }
10
+ `;
11
+ const VARIABLE_DELETE = `
12
+ mutation($input: VariableDeleteInput!) {
13
+ variableDelete(input: $input)
14
+ }
15
+ `;
16
+ /**
17
+ * Dynamic provider implementing CRUD for Railway service environment variables.
18
+ *
19
+ * Uses `skipDeploys: true` on all upsert operations to prevent
20
+ * "Cannot redeploy without snapshot" errors on newly created services.
21
+ */
22
+ var RailwayVariableProvider = class {
23
+ /**
24
+ * Creates all variables on the target service via batch upsert.
25
+ *
26
+ * @param inputs Resolved variable configuration
27
+ * @returns Composite ID in the form `{serviceId}:variables`
28
+ */
29
+ async create(inputs) {
30
+ await new RailwayClient(inputs.token).query(VARIABLE_UPSERT, { input: {
31
+ projectId: inputs.projectId,
32
+ serviceId: inputs.serviceId,
33
+ environmentId: inputs.environmentId,
34
+ variables: inputs.variables,
35
+ skipDeploys: true
36
+ } });
37
+ return {
38
+ id: `${inputs.serviceId}:variables`,
39
+ outs: inputs
40
+ };
41
+ }
42
+ /**
43
+ * Updates variables by deleting removed keys individually, then upserting the rest.
44
+ *
45
+ * @param _id Current resource ID (unused)
46
+ * @param olds Previous persisted variable state
47
+ * @param news New desired variable configuration
48
+ * @returns Updated outputs
49
+ */
50
+ async update(_id, olds, news) {
51
+ const client = new RailwayClient(news.token);
52
+ const removedKeys = Object.keys(olds.variables).filter((key) => !(key in news.variables));
53
+ for (const key of removedKeys) await client.query(VARIABLE_DELETE, { input: {
54
+ projectId: news.projectId,
55
+ serviceId: news.serviceId,
56
+ environmentId: news.environmentId,
57
+ name: key
58
+ } });
59
+ if (Object.keys(news.variables).length > 0) await client.query(VARIABLE_UPSERT, { input: {
60
+ projectId: news.projectId,
61
+ serviceId: news.serviceId,
62
+ environmentId: news.environmentId,
63
+ variables: news.variables,
64
+ skipDeploys: true
65
+ } });
66
+ return { outs: news };
67
+ }
68
+ /**
69
+ * Reads current state for `pulumi refresh`.
70
+ * Returns persisted props since Railway has no single-call variable read API.
71
+ *
72
+ * @param id Current resource ID
73
+ * @param props Last known persisted state
74
+ * @returns Unchanged resource ID and properties
75
+ */
76
+ async read(id, props) {
77
+ return {
78
+ id,
79
+ props
80
+ };
81
+ }
82
+ /**
83
+ * Deletes all variables one by one. Silently succeeds if already deleted.
84
+ *
85
+ * @param _id Current resource ID (unused)
86
+ * @param props Last known persisted state
87
+ */
88
+ async delete(_id, props) {
89
+ const client = new RailwayClient(props.token);
90
+ for (const key of Object.keys(props.variables)) try {
91
+ await client.query(VARIABLE_DELETE, { input: {
92
+ projectId: props.projectId,
93
+ serviceId: props.serviceId,
94
+ environmentId: props.environmentId,
95
+ name: key
96
+ } });
97
+ } catch {
98
+ pulumi.log.warn(`Failed to delete Railway variable "${key}" (may already be deleted)`);
99
+ }
100
+ }
101
+ /**
102
+ * Compares old and new variable maps by key set and value equality.
103
+ *
104
+ * @param _id Current resource ID (unused)
105
+ * @param olds Previous persisted state
106
+ * @param news New desired configuration
107
+ * @returns Whether any keys or values changed
108
+ */
109
+ async diff(_id, olds, news) {
110
+ const oldKeys = Object.keys(olds.variables).sort().join(",");
111
+ const newKeys = Object.keys(news.variables).sort().join(",");
112
+ const valuesChanged = Object.entries(news.variables).some(([key, value]) => olds.variables[key] !== value);
113
+ return { changes: oldKeys !== newKeys || valuesChanged };
114
+ }
115
+ };
116
+ /**
117
+ * Manages Railway service environment variables with `skipDeploys` to prevent snapshot errors.
118
+ *
119
+ * Handles batch upsert on create/update and per-key deletion when variables are removed.
120
+ * All mutations use `skipDeploys: true` to avoid triggering deploys before the service
121
+ * has a build snapshot.
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * new RailwayVariable("railway-variable-api", {
126
+ * token: project.projectToken,
127
+ * projectId: project.projectId,
128
+ * serviceId: service.serviceId,
129
+ * environmentId: project.productionEnvironmentId,
130
+ * variables: { DATABASE_URL: databaseUrl, NODE_ENV: "production" },
131
+ * });
132
+ * ```
133
+ */
134
+ var RailwayVariable = class extends pulumi.dynamic.Resource {
135
+ /**
136
+ * @param name Pulumi resource name (logical identifier in state)
137
+ * @param args Variable configuration inputs
138
+ * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)
139
+ */
140
+ constructor(name, args, opts) {
141
+ super(new RailwayVariableProvider(), name, { ...args }, opts);
142
+ }
143
+ };
144
+
145
+ //#endregion
146
+ export { RailwayVariable };
147
+ //# sourceMappingURL=variable.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variable.mjs","names":[],"sources":["../../src/railway/variable.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { RailwayClient } from \"./client.js\";\n\n/** Resolved inputs for the Railway variable dynamic provider. */\nexport interface RailwayVariableInputs {\n\t/** Railway API bearer token. */\n\ttoken: string;\n\n\t/** Railway project UUID. */\n\tprojectId: string;\n\n\t/** Railway service UUID that owns these variables. */\n\tserviceId: string;\n\n\t/** Railway environment UUID (e.g. production). */\n\tenvironmentId: string;\n\n\t/** Key-value map of environment variable names to their values. */\n\tvariables: Record<string, string>;\n}\n\n/** Persisted state for Railway variables (identical to inputs). */\ninterface RailwayVariableOutputs extends RailwayVariableInputs {}\n\nconst VARIABLE_UPSERT = `\n mutation($input: VariableCollectionUpsertInput!) {\n variableCollectionUpsert(input: $input)\n }\n`;\n\nconst VARIABLE_DELETE = `\n mutation($input: VariableDeleteInput!) {\n variableDelete(input: $input)\n }\n`;\n\n/**\n * Dynamic provider implementing CRUD for Railway service environment variables.\n *\n * Uses `skipDeploys: true` on all upsert operations to prevent\n * \"Cannot redeploy without snapshot\" errors on newly created services.\n */\nclass RailwayVariableProvider implements pulumi.dynamic.ResourceProvider {\n\t/**\n\t * Creates all variables on the target service via batch upsert.\n\t *\n\t * @param inputs Resolved variable configuration\n\t * @returns Composite ID in the form `{serviceId}:variables`\n\t */\n\tasync create(\n\t\tinputs: RailwayVariableInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new RailwayClient(inputs.token);\n\n\t\tawait client.query(VARIABLE_UPSERT, {\n\t\t\tinput: {\n\t\t\t\tprojectId: inputs.projectId,\n\t\t\t\tserviceId: inputs.serviceId,\n\t\t\t\tenvironmentId: inputs.environmentId,\n\t\t\t\tvariables: inputs.variables,\n\t\t\t\tskipDeploys: true,\n\t\t\t},\n\t\t});\n\n\t\tconst id = `${inputs.serviceId}:variables`;\n\n\t\treturn { id, outs: inputs };\n\t}\n\n\t/**\n\t * Updates variables by deleting removed keys individually, then upserting the rest.\n\t *\n\t * @param _id Current resource ID (unused)\n\t * @param olds Previous persisted variable state\n\t * @param news New desired variable configuration\n\t * @returns Updated outputs\n\t */\n\tasync update(\n\t\t_id: string,\n\t\tolds: RailwayVariableOutputs,\n\t\tnews: RailwayVariableInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\tconst client = new RailwayClient(news.token);\n\n\t\tconst removedKeys = Object.keys(olds.variables).filter(\n\t\t\t(key) => !(key in news.variables),\n\t\t);\n\n\t\tfor (const key of removedKeys) {\n\t\t\tawait client.query(VARIABLE_DELETE, {\n\t\t\t\tinput: {\n\t\t\t\t\tprojectId: news.projectId,\n\t\t\t\t\tserviceId: news.serviceId,\n\t\t\t\t\tenvironmentId: news.environmentId,\n\t\t\t\t\tname: key,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tif (Object.keys(news.variables).length > 0) {\n\t\t\tawait client.query(VARIABLE_UPSERT, {\n\t\t\t\tinput: {\n\t\t\t\t\tprojectId: news.projectId,\n\t\t\t\t\tserviceId: news.serviceId,\n\t\t\t\t\tenvironmentId: news.environmentId,\n\t\t\t\t\tvariables: news.variables,\n\t\t\t\t\tskipDeploys: true,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\treturn { outs: news };\n\t}\n\n\t/**\n\t * Reads current state for `pulumi refresh`.\n\t * Returns persisted props since Railway has no single-call variable read API.\n\t *\n\t * @param id Current resource ID\n\t * @param props Last known persisted state\n\t * @returns Unchanged resource ID and properties\n\t */\n\tasync read(\n\t\tid: string,\n\t\tprops: RailwayVariableOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\treturn { id, props };\n\t}\n\n\t/**\n\t * Deletes all variables one by one. Silently succeeds if already deleted.\n\t *\n\t * @param _id Current resource ID (unused)\n\t * @param props Last known persisted state\n\t */\n\tasync delete(_id: string, props: RailwayVariableOutputs): Promise<void> {\n\t\tconst client = new RailwayClient(props.token);\n\n\t\tfor (const key of Object.keys(props.variables)) {\n\t\t\ttry {\n\t\t\t\tawait client.query(VARIABLE_DELETE, {\n\t\t\t\t\tinput: {\n\t\t\t\t\t\tprojectId: props.projectId,\n\t\t\t\t\t\tserviceId: props.serviceId,\n\t\t\t\t\t\tenvironmentId: props.environmentId,\n\t\t\t\t\t\tname: key,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\tpulumi.log.warn(\n\t\t\t\t\t`Failed to delete Railway variable \"${key}\" (may already be deleted)`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Compares old and new variable maps by key set and value equality.\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 Whether any keys or values changed\n\t */\n\tasync diff(\n\t\t_id: string,\n\t\tolds: RailwayVariableOutputs,\n\t\tnews: RailwayVariableInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst oldKeys = Object.keys(olds.variables).sort().join(\",\");\n\t\tconst newKeys = Object.keys(news.variables).sort().join(\",\");\n\n\t\tconst valuesChanged = Object.entries(news.variables).some(\n\t\t\t([key, value]) => olds.variables[key] !== value,\n\t\t);\n\n\t\treturn {\n\t\t\tchanges: oldKeys !== newKeys || valuesChanged,\n\t\t};\n\t}\n}\n\n/**\n * Manages Railway service environment variables with `skipDeploys` to prevent snapshot errors.\n *\n * Handles batch upsert on create/update and per-key deletion when variables are removed.\n * All mutations use `skipDeploys: true` to avoid triggering deploys before the service\n * has a build snapshot.\n *\n * @example\n * ```typescript\n * new RailwayVariable(\"railway-variable-api\", {\n * token: project.projectToken,\n * projectId: project.projectId,\n * serviceId: service.serviceId,\n * environmentId: project.productionEnvironmentId,\n * variables: { DATABASE_URL: databaseUrl, NODE_ENV: \"production\" },\n * });\n * ```\n */\nexport class RailwayVariable extends pulumi.dynamic.Resource {\n\t/**\n\t * @param name Pulumi resource name (logical identifier in state)\n\t * @param args Variable 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 that owns these variables. */\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/** Key-value map of environment variable names to their values. */\n\t\t\tvariables: pulumi.Input<Record<string, pulumi.Input<string>>>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(new RailwayVariableProvider(), name, { ...args }, opts);\n\t}\n}\n"],"mappings":";;;;;AAwBA,MAAM,kBAAkB;;;;;AAMxB,MAAM,kBAAkB;;;;;;;;;;;AAYxB,IAAM,0BAAN,MAAyE;;;;;;;CAOxE,MAAM,OACL,QACuC;EAGvC,MAAM,IAFa,cAAc,OAAO,KAE7B,EAAE,MAAM,iBAAiB,EACnC,OAAO;GACN,WAAW,OAAO;GAClB,WAAW,OAAO;GAClB,eAAe,OAAO;GACtB,WAAW,OAAO;GAClB,aAAa;EACd,EACD,CAAC;EAID,OAAO;GAAE,OAFK,OAAO,UAAU;GAElB,MAAM;EAAO;CAC3B;;;;;;;;;CAUA,MAAM,OACL,KACA,MACA,MACuC;EACvC,MAAM,SAAS,IAAI,cAAc,KAAK,KAAK;EAE3C,MAAM,cAAc,OAAO,KAAK,KAAK,SAAS,EAAE,QAC9C,QAAQ,EAAE,OAAO,KAAK,UACxB;EAEA,KAAK,MAAM,OAAO,aACjB,MAAM,OAAO,MAAM,iBAAiB,EACnC,OAAO;GACN,WAAW,KAAK;GAChB,WAAW,KAAK;GAChB,eAAe,KAAK;GACpB,MAAM;EACP,EACD,CAAC;EAGF,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,SAAS,GACxC,MAAM,OAAO,MAAM,iBAAiB,EACnC,OAAO;GACN,WAAW,KAAK;GAChB,WAAW,KAAK;GAChB,eAAe,KAAK;GACpB,WAAW,KAAK;GAChB,aAAa;EACd,EACD,CAAC;EAGF,OAAO,EAAE,MAAM,KAAK;CACrB;;;;;;;;;CAUA,MAAM,KACL,IACA,OACqC;EACrC,OAAO;GAAE;GAAI;EAAM;CACpB;;;;;;;CAQA,MAAM,OAAO,KAAa,OAA8C;EACvE,MAAM,SAAS,IAAI,cAAc,MAAM,KAAK;EAE5C,KAAK,MAAM,OAAO,OAAO,KAAK,MAAM,SAAS,GAC5C,IAAI;GACH,MAAM,OAAO,MAAM,iBAAiB,EACnC,OAAO;IACN,WAAW,MAAM;IACjB,WAAW,MAAM;IACjB,eAAe,MAAM;IACrB,MAAM;GACP,EACD,CAAC;EACF,QAAQ;GACP,OAAO,IAAI,KACV,sCAAsC,IAAI,2BAC3C;EACD;CAEF;;;;;;;;;CAUA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,UAAU,OAAO,KAAK,KAAK,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG;EAC3D,MAAM,UAAU,OAAO,KAAK,KAAK,SAAS,EAAE,KAAK,EAAE,KAAK,GAAG;EAE3D,MAAM,gBAAgB,OAAO,QAAQ,KAAK,SAAS,EAAE,MACnD,CAAC,KAAK,WAAW,KAAK,UAAU,SAAS,KAC3C;EAEA,OAAO,EACN,SAAS,YAAY,WAAW,cACjC;CACD;AACD;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,kBAAb,cAAqC,OAAO,QAAQ,SAAS;;;;;;CAM5D,YACC,MACA,MAgBA,MACC;EACD,MAAM,IAAI,wBAAwB,GAAG,MAAM,EAAE,GAAG,KAAK,GAAG,IAAI;CAC7D;AACD"}
@@ -0,0 +1,179 @@
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/volume.ts
8
+ const VOLUME_CREATE = `
9
+ mutation($input: VolumeCreateInput!) {
10
+ volumeCreate(input: $input) {
11
+ id
12
+ name
13
+ }
14
+ }
15
+ `;
16
+ const VOLUME_DELETE = `
17
+ mutation($volumeId: String!) {
18
+ volumeDelete(volumeId: $volumeId)
19
+ }
20
+ `;
21
+ const VOLUMES_QUERY = `
22
+ query($projectId: String!) {
23
+ project(id: $projectId) {
24
+ volumes {
25
+ edges {
26
+ node {
27
+ id
28
+ name
29
+ volumeInstances {
30
+ edges {
31
+ node {
32
+ id
33
+ mountPath
34
+ serviceId
35
+ }
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ }
42
+ }
43
+ `;
44
+ /**
45
+ * Finds an existing volume attached to a specific service within a project.
46
+ *
47
+ * @param client Authenticated Railway API client
48
+ * @param projectId Railway project UUID to search within
49
+ * @param serviceId Railway service UUID to match volume instances against
50
+ * @returns The volume UUID if found, `undefined` otherwise
51
+ */
52
+ async function findVolumeByService(client, projectId, serviceId) {
53
+ return (await client.query(VOLUMES_QUERY, { projectId })).project.volumes.edges.find((edge) => edge.node.volumeInstances.edges.some((vi) => vi.node.serviceId === serviceId))?.node.id;
54
+ }
55
+ /**
56
+ * Dynamic provider implementing CRUD for Railway persistent volumes.
57
+ *
58
+ * Uses adopt-or-create on `create()`: finds an existing volume by service
59
+ * before creating a new one, making `pulumi up` idempotent from zero.
60
+ * Volumes are immutable after creation — changing `serviceId`, `mountPath`,
61
+ * `environmentId`, or `projectId` triggers replacement (delete + create).
62
+ */
63
+ var RailwayVolumeProvider = class {
64
+ /**
65
+ * Creates or adopts a Railway volume for the target service.
66
+ *
67
+ * @param inputs Resolved volume configuration
68
+ * @returns The Railway volume UUID as the resource ID
69
+ */
70
+ async create(inputs) {
71
+ const client = new require_railway_client.RailwayClient(inputs.token);
72
+ let volumeId = await findVolumeByService(client, inputs.projectId, inputs.serviceId);
73
+ if (volumeId) _pulumi_pulumi.log.info(`Adopting existing volume for service (${volumeId})`);
74
+ else volumeId = (await client.query(VOLUME_CREATE, { input: {
75
+ projectId: inputs.projectId,
76
+ serviceId: inputs.serviceId,
77
+ environmentId: inputs.environmentId,
78
+ mountPath: inputs.mountPath
79
+ } })).volumeCreate.id;
80
+ return {
81
+ id: volumeId,
82
+ outs: {
83
+ ...inputs,
84
+ volumeId
85
+ }
86
+ };
87
+ }
88
+ /**
89
+ * Reads current state for `pulumi refresh` by looking up the volume.
90
+ *
91
+ * @param id Current Railway volume UUID
92
+ * @param props Last known persisted state
93
+ * @returns Refreshed resource ID and properties
94
+ * @throws {Error} If the volume no longer exists in Railway
95
+ */
96
+ async read(_id, props) {
97
+ const volumeId = await findVolumeByService(new require_railway_client.RailwayClient(props.token), props.projectId, props.serviceId);
98
+ if (!volumeId) throw new Error("Railway volume not found during refresh");
99
+ return {
100
+ id: volumeId,
101
+ props: {
102
+ ...props,
103
+ volumeId
104
+ }
105
+ };
106
+ }
107
+ /**
108
+ * Deletes the Railway volume. Silently succeeds if already deleted.
109
+ *
110
+ * @param id Railway volume UUID to delete
111
+ * @param props Last known persisted state (used for token)
112
+ */
113
+ async delete(id, props) {
114
+ const client = new require_railway_client.RailwayClient(props.token);
115
+ try {
116
+ await client.query(VOLUME_DELETE, { volumeId: id });
117
+ } catch {
118
+ _pulumi_pulumi.log.warn("Failed to delete Railway volume (may already be deleted)");
119
+ }
120
+ }
121
+ /**
122
+ * Compares old and new inputs to determine what changed.
123
+ *
124
+ * All mutable properties trigger replacement since Railway volumes
125
+ * cannot be moved between services, mount paths, environments, or projects.
126
+ *
127
+ * @param _id Current resource ID (unused)
128
+ * @param olds Previous persisted state
129
+ * @param news New desired configuration
130
+ * @returns Diff result with replacement triggers
131
+ */
132
+ async diff(_id, olds, news) {
133
+ const replaces = [];
134
+ if (olds.serviceId !== news.serviceId) replaces.push("serviceId");
135
+ if (olds.mountPath !== news.mountPath) replaces.push("mountPath");
136
+ if (olds.environmentId !== news.environmentId) replaces.push("environmentId");
137
+ if (olds.projectId !== news.projectId) replaces.push("projectId");
138
+ return {
139
+ changes: replaces.length > 0,
140
+ replaces,
141
+ deleteBeforeReplace: true
142
+ };
143
+ }
144
+ };
145
+ /**
146
+ * Manages a Railway persistent volume with adopt-or-create semantics.
147
+ *
148
+ * Finds existing volumes attached to the target service before creating
149
+ * new ones. Changing `serviceId`, `mountPath`, `environmentId`, or `projectId`
150
+ * triggers replacement (delete + create with new settings).
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * new RailwayVolume("railway-volume-redis", {
155
+ * token: project.projectToken,
156
+ * projectId: project.projectId,
157
+ * serviceId: service.serviceId,
158
+ * environmentId: project.productionEnvironmentId,
159
+ * mountPath: "/data",
160
+ * });
161
+ * ```
162
+ */
163
+ var RailwayVolume = class extends _pulumi_pulumi.dynamic.Resource {
164
+ /**
165
+ * @param name Pulumi resource name (logical identifier in state)
166
+ * @param args Volume configuration inputs
167
+ * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)
168
+ */
169
+ constructor(name, args, opts) {
170
+ super(new RailwayVolumeProvider(), name, {
171
+ ...args,
172
+ volumeId: void 0
173
+ }, opts);
174
+ }
175
+ };
176
+
177
+ //#endregion
178
+ exports.RailwayVolume = RailwayVolume;
179
+ //# sourceMappingURL=volume.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volume.cjs","names":["RailwayClient","pulumi"],"sources":["../../src/railway/volume.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { RailwayClient } from \"./client.js\";\n\n/** Resolved inputs for the Railway volume dynamic provider. */\nexport interface RailwayVolumeInputs {\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 volume to. */\n\tserviceId: string;\n\n\t/** Railway environment UUID (e.g. production). */\n\tenvironmentId: string;\n\n\t/** Absolute path inside the container where the volume is mounted (e.g. `\"/data\"`). */\n\tmountPath: string;\n}\n\n/** Persisted state for the Railway volume, extending inputs with the Railway-assigned ID. */\ninterface RailwayVolumeOutputs extends RailwayVolumeInputs {\n\t/** Railway-assigned volume UUID (set after create or adopt). */\n\tvolumeId: string;\n}\n\nconst VOLUME_CREATE = `\n mutation($input: VolumeCreateInput!) {\n volumeCreate(input: $input) {\n id\n name\n }\n }\n`;\n\nconst VOLUME_DELETE = `\n mutation($volumeId: String!) {\n volumeDelete(volumeId: $volumeId)\n }\n`;\n\nconst VOLUMES_QUERY = `\n query($projectId: String!) {\n project(id: $projectId) {\n volumes {\n edges {\n node {\n id\n name\n volumeInstances {\n edges {\n node {\n id\n mountPath\n serviceId\n }\n }\n }\n }\n }\n }\n }\n }\n`;\n\n/**\n * Finds an existing volume attached to a specific service within a project.\n *\n * @param client Authenticated Railway API client\n * @param projectId Railway project UUID to search within\n * @param serviceId Railway service UUID to match volume instances against\n * @returns The volume UUID if found, `undefined` otherwise\n */\nasync function findVolumeByService(\n\tclient: RailwayClient,\n\tprojectId: string,\n\tserviceId: string,\n): Promise<string | undefined> {\n\tconst result = await client.query<{\n\t\tproject: {\n\t\t\tvolumes: {\n\t\t\t\tedges: Array<{\n\t\t\t\t\tnode: {\n\t\t\t\t\t\tid: string;\n\t\t\t\t\t\tvolumeInstances: {\n\t\t\t\t\t\t\tedges: Array<{\n\t\t\t\t\t\t\t\tnode: { serviceId: string };\n\t\t\t\t\t\t\t}>;\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\t\t\t\t}>;\n\t\t\t};\n\t\t};\n\t}>(VOLUMES_QUERY, { projectId });\n\n\tconst match = result.project.volumes.edges.find((edge) =>\n\t\tedge.node.volumeInstances.edges.some(\n\t\t\t(vi) => vi.node.serviceId === serviceId,\n\t\t),\n\t);\n\n\treturn match?.node.id;\n}\n\n/**\n * Dynamic provider implementing CRUD for Railway persistent volumes.\n *\n * Uses adopt-or-create on `create()`: finds an existing volume by service\n * before creating a new one, making `pulumi up` idempotent from zero.\n * Volumes are immutable after creation — changing `serviceId`, `mountPath`,\n * `environmentId`, or `projectId` triggers replacement (delete + create).\n */\nclass RailwayVolumeProvider implements pulumi.dynamic.ResourceProvider {\n\t/**\n\t * Creates or adopts a Railway volume for the target service.\n\t *\n\t * @param inputs Resolved volume configuration\n\t * @returns The Railway volume UUID as the resource ID\n\t */\n\tasync create(\n\t\tinputs: RailwayVolumeInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new RailwayClient(inputs.token);\n\n\t\tlet volumeId = await findVolumeByService(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.serviceId,\n\t\t);\n\n\t\tif (volumeId) {\n\t\t\tpulumi.log.info(`Adopting existing volume for service (${volumeId})`);\n\t\t} else {\n\t\t\tconst result = await client.query<{\n\t\t\t\tvolumeCreate: { id: string };\n\t\t\t}>(VOLUME_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\tmountPath: inputs.mountPath,\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tvolumeId = result.volumeCreate.id;\n\t\t}\n\n\t\treturn {\n\t\t\tid: volumeId,\n\t\t\touts: { ...inputs, volumeId },\n\t\t};\n\t}\n\n\t/**\n\t * Reads current state for `pulumi refresh` by looking up the volume.\n\t *\n\t * @param id Current Railway volume UUID\n\t * @param props Last known persisted state\n\t * @returns Refreshed resource ID and properties\n\t * @throws {Error} If the volume no longer exists in Railway\n\t */\n\tasync read(\n\t\t_id: string,\n\t\tprops: RailwayVolumeOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new RailwayClient(props.token);\n\n\t\tconst volumeId = await findVolumeByService(\n\t\t\tclient,\n\t\t\tprops.projectId,\n\t\t\tprops.serviceId,\n\t\t);\n\n\t\tif (!volumeId) {\n\t\t\tthrow new Error(\"Railway volume not found during refresh\");\n\t\t}\n\n\t\treturn { id: volumeId, props: { ...props, volumeId } };\n\t}\n\n\t/**\n\t * Deletes the Railway volume. Silently succeeds if already deleted.\n\t *\n\t * @param id Railway volume UUID to delete\n\t * @param props Last known persisted state (used for token)\n\t */\n\tasync delete(id: string, props: RailwayVolumeOutputs): Promise<void> {\n\t\tconst client = new RailwayClient(props.token);\n\n\t\ttry {\n\t\t\tawait client.query(VOLUME_DELETE, { volumeId: id });\n\t\t} catch {\n\t\t\tpulumi.log.warn(\n\t\t\t\t\"Failed to delete Railway volume (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 * All mutable properties trigger replacement since Railway volumes\n\t * cannot be moved between services, mount paths, environments, or projects.\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: RailwayVolumeOutputs,\n\t\tnews: RailwayVolumeInputs,\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.mountPath !== news.mountPath) {\n\t\t\treplaces.push(\"mountPath\");\n\t\t}\n\n\t\tif (olds.environmentId !== news.environmentId) {\n\t\t\treplaces.push(\"environmentId\");\n\t\t}\n\n\t\tif (olds.projectId !== news.projectId) {\n\t\t\treplaces.push(\"projectId\");\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 persistent volume with adopt-or-create semantics.\n *\n * Finds existing volumes attached to the target service before creating\n * new ones. Changing `serviceId`, `mountPath`, `environmentId`, or `projectId`\n * triggers replacement (delete + create with new settings).\n *\n * @example\n * ```typescript\n * new RailwayVolume(\"railway-volume-redis\", {\n * token: project.projectToken,\n * projectId: project.projectId,\n * serviceId: service.serviceId,\n * environmentId: project.productionEnvironmentId,\n * mountPath: \"/data\",\n * });\n * ```\n */\nexport class RailwayVolume extends pulumi.dynamic.Resource {\n\t/**\n\t * @param name Pulumi resource name (logical identifier in state)\n\t * @param args Volume 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 volume 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/** Absolute path inside the container where the volume is mounted. */\n\t\t\tmountPath: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew RailwayVolumeProvider(),\n\t\t\tname,\n\t\t\t{ ...args, volumeId: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n"],"mappings":";;;;;;;AA2BA,MAAM,gBAAgB;;;;;;;;AAStB,MAAM,gBAAgB;;;;;AAMtB,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCtB,eAAe,oBACd,QACA,WACA,WAC8B;CAwB9B,QANc,MAjBO,OAAO,MAezB,eAAe,EAAE,UAAU,CAAC,GAEV,QAAQ,QAAQ,MAAM,MAAM,SAChD,KAAK,KAAK,gBAAgB,MAAM,MAC9B,OAAO,GAAG,KAAK,cAAc,SAC/B,CAGU,GAAG,KAAK;AACpB;;;;;;;;;AAUA,IAAM,wBAAN,MAAuE;;;;;;;CAOtE,MAAM,OACL,QACuC;EACvC,MAAM,SAAS,IAAIA,qCAAc,OAAO,KAAK;EAE7C,IAAI,WAAW,MAAM,oBACpB,QACA,OAAO,WACP,OAAO,SACR;EAEA,IAAI,UACH,eAAO,IAAI,KAAK,yCAAyC,SAAS,EAAE;OAapE,YAAW,MAXU,OAAO,MAEzB,eAAe,EACjB,OAAO;GACN,WAAW,OAAO;GAClB,WAAW,OAAO;GAClB,eAAe,OAAO;GACtB,WAAW,OAAO;EACnB,EACD,CAAC,GAEiB,aAAa;EAGhC,OAAO;GACN,IAAI;GACJ,MAAM;IAAE,GAAG;IAAQ;GAAS;EAC7B;CACD;;;;;;;;;CAUA,MAAM,KACL,KACA,OACqC;EAGrC,MAAM,WAAW,MAAM,oBACtB,IAHkBA,qCAAc,MAAM,KAGjC,GACL,MAAM,WACN,MAAM,SACP;EAEA,IAAI,CAAC,UACJ,MAAM,IAAI,MAAM,yCAAyC;EAG1D,OAAO;GAAE,IAAI;GAAU,OAAO;IAAE,GAAG;IAAO;GAAS;EAAE;CACtD;;;;;;;CAQA,MAAM,OAAO,IAAY,OAA4C;EACpE,MAAM,SAAS,IAAIA,qCAAc,MAAM,KAAK;EAE5C,IAAI;GACH,MAAM,OAAO,MAAM,eAAe,EAAE,UAAU,GAAG,CAAC;EACnD,QAAQ;GACP,eAAO,IAAI,KACV,0DACD;EACD;CACD;;;;;;;;;;;;CAaA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,cAAc,KAAK,WAC3B,SAAS,KAAK,WAAW;EAG1B,IAAI,KAAK,cAAc,KAAK,WAC3B,SAAS,KAAK,WAAW;EAG1B,IAAI,KAAK,kBAAkB,KAAK,eAC/B,SAAS,KAAK,eAAe;EAG9B,IAAI,KAAK,cAAc,KAAK,WAC3B,SAAS,KAAK,WAAW;EAG1B,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,gBAAb,cAAmCC,eAAO,QAAQ,SAAS;;;;;;CAM1D,YACC,MACA,MAgBA,MACC;EACD,MACC,IAAI,sBAAsB,GAC1B,MACA;GAAE,GAAG;GAAM,UAAU;EAAU,GAC/B,IACD;CACD;AACD"}
@@ -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/volume.d.ts
5
+ /** Resolved inputs for the Railway volume dynamic provider. */
6
+ interface RailwayVolumeInputs {
7
+ /** Railway API bearer token. */
8
+ token: string;
9
+ /** Railway project UUID. */
10
+ projectId: string;
11
+ /** Railway service UUID to attach the volume to. */
12
+ serviceId: string;
13
+ /** Railway environment UUID (e.g. production). */
14
+ environmentId: string;
15
+ /** Absolute path inside the container where the volume is mounted (e.g. `"/data"`). */
16
+ mountPath: string;
17
+ }
18
+ /**
19
+ * Manages a Railway persistent volume with adopt-or-create semantics.
20
+ *
21
+ * Finds existing volumes attached to the target service before creating
22
+ * new ones. Changing `serviceId`, `mountPath`, `environmentId`, or `projectId`
23
+ * triggers replacement (delete + create with new settings).
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * new RailwayVolume("railway-volume-redis", {
28
+ * token: project.projectToken,
29
+ * projectId: project.projectId,
30
+ * serviceId: service.serviceId,
31
+ * environmentId: project.productionEnvironmentId,
32
+ * mountPath: "/data",
33
+ * });
34
+ * ```
35
+ */
36
+ declare class RailwayVolume extends pulumi.dynamic.Resource {
37
+ /**
38
+ * @param name Pulumi resource name (logical identifier in state)
39
+ * @param args Volume 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 volume to. */
45
+ serviceId: pulumi.Input<string>; /** Railway environment UUID (e.g. production). */
46
+ environmentId: pulumi.Input<string>; /** Absolute path inside the container where the volume is mounted. */
47
+ mountPath: pulumi.Input<string>;
48
+ }, opts?: pulumi.CustomResourceOptions);
49
+ }
50
+ //#endregion
51
+ export { RailwayVolume, RailwayVolumeInputs };
52
+ //# sourceMappingURL=volume.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volume.d.cts","names":[],"sources":["../../src/railway/volume.ts"],"mappings":";;;;;UAIiB,mBAAA;;EAEhB,KAAA;EAFmC;EAKnC,SAAA;EALmC;EAQnC,SAAA;EAHA;EAMA,aAAA;EAAA;EAGA,SAAA;AAAA;AAAS;AAiPV;;;;;;;;;;;;;;;;;AAjPU,cAiPG,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,UAMP;IAHX,aAAA,EAAe,MAAA,CAAO,KAAA,UAXvB;IAcC,SAAA,EAAW,MAAA,CAAO,KAAA;EAAA,GAEnB,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/volume.d.ts
5
+ /** Resolved inputs for the Railway volume dynamic provider. */
6
+ interface RailwayVolumeInputs {
7
+ /** Railway API bearer token. */
8
+ token: string;
9
+ /** Railway project UUID. */
10
+ projectId: string;
11
+ /** Railway service UUID to attach the volume to. */
12
+ serviceId: string;
13
+ /** Railway environment UUID (e.g. production). */
14
+ environmentId: string;
15
+ /** Absolute path inside the container where the volume is mounted (e.g. `"/data"`). */
16
+ mountPath: string;
17
+ }
18
+ /**
19
+ * Manages a Railway persistent volume with adopt-or-create semantics.
20
+ *
21
+ * Finds existing volumes attached to the target service before creating
22
+ * new ones. Changing `serviceId`, `mountPath`, `environmentId`, or `projectId`
23
+ * triggers replacement (delete + create with new settings).
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * new RailwayVolume("railway-volume-redis", {
28
+ * token: project.projectToken,
29
+ * projectId: project.projectId,
30
+ * serviceId: service.serviceId,
31
+ * environmentId: project.productionEnvironmentId,
32
+ * mountPath: "/data",
33
+ * });
34
+ * ```
35
+ */
36
+ declare class RailwayVolume extends pulumi.dynamic.Resource {
37
+ /**
38
+ * @param name Pulumi resource name (logical identifier in state)
39
+ * @param args Volume 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 volume to. */
45
+ serviceId: pulumi.Input<string>; /** Railway environment UUID (e.g. production). */
46
+ environmentId: pulumi.Input<string>; /** Absolute path inside the container where the volume is mounted. */
47
+ mountPath: pulumi.Input<string>;
48
+ }, opts?: pulumi.CustomResourceOptions);
49
+ }
50
+ //#endregion
51
+ export { RailwayVolume, RailwayVolumeInputs };
52
+ //# sourceMappingURL=volume.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volume.d.mts","names":[],"sources":["../../src/railway/volume.ts"],"mappings":";;;;;UAIiB,mBAAA;;EAEhB,KAAA;EAFmC;EAKnC,SAAA;EALmC;EAQnC,SAAA;EAHA;EAMA,aAAA;EAAA;EAGA,SAAA;AAAA;AAAS;AAiPV;;;;;;;;;;;;;;;;;AAjPU,cAiPG,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,UAMP;IAHX,aAAA,EAAe,MAAA,CAAO,KAAA,UAXvB;IAcC,SAAA,EAAW,MAAA,CAAO,KAAA;EAAA,GAEnB,IAAA,GAAO,MAAA,CAAO,qBAAA;AAAA"}
@@ -0,0 +1,177 @@
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/volume.ts
6
+ const VOLUME_CREATE = `
7
+ mutation($input: VolumeCreateInput!) {
8
+ volumeCreate(input: $input) {
9
+ id
10
+ name
11
+ }
12
+ }
13
+ `;
14
+ const VOLUME_DELETE = `
15
+ mutation($volumeId: String!) {
16
+ volumeDelete(volumeId: $volumeId)
17
+ }
18
+ `;
19
+ const VOLUMES_QUERY = `
20
+ query($projectId: String!) {
21
+ project(id: $projectId) {
22
+ volumes {
23
+ edges {
24
+ node {
25
+ id
26
+ name
27
+ volumeInstances {
28
+ edges {
29
+ node {
30
+ id
31
+ mountPath
32
+ serviceId
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
38
+ }
39
+ }
40
+ }
41
+ `;
42
+ /**
43
+ * Finds an existing volume attached to a specific service within a project.
44
+ *
45
+ * @param client Authenticated Railway API client
46
+ * @param projectId Railway project UUID to search within
47
+ * @param serviceId Railway service UUID to match volume instances against
48
+ * @returns The volume UUID if found, `undefined` otherwise
49
+ */
50
+ async function findVolumeByService(client, projectId, serviceId) {
51
+ return (await client.query(VOLUMES_QUERY, { projectId })).project.volumes.edges.find((edge) => edge.node.volumeInstances.edges.some((vi) => vi.node.serviceId === serviceId))?.node.id;
52
+ }
53
+ /**
54
+ * Dynamic provider implementing CRUD for Railway persistent volumes.
55
+ *
56
+ * Uses adopt-or-create on `create()`: finds an existing volume by service
57
+ * before creating a new one, making `pulumi up` idempotent from zero.
58
+ * Volumes are immutable after creation — changing `serviceId`, `mountPath`,
59
+ * `environmentId`, or `projectId` triggers replacement (delete + create).
60
+ */
61
+ var RailwayVolumeProvider = class {
62
+ /**
63
+ * Creates or adopts a Railway volume for the target service.
64
+ *
65
+ * @param inputs Resolved volume configuration
66
+ * @returns The Railway volume UUID as the resource ID
67
+ */
68
+ async create(inputs) {
69
+ const client = new RailwayClient(inputs.token);
70
+ let volumeId = await findVolumeByService(client, inputs.projectId, inputs.serviceId);
71
+ if (volumeId) pulumi.log.info(`Adopting existing volume for service (${volumeId})`);
72
+ else volumeId = (await client.query(VOLUME_CREATE, { input: {
73
+ projectId: inputs.projectId,
74
+ serviceId: inputs.serviceId,
75
+ environmentId: inputs.environmentId,
76
+ mountPath: inputs.mountPath
77
+ } })).volumeCreate.id;
78
+ return {
79
+ id: volumeId,
80
+ outs: {
81
+ ...inputs,
82
+ volumeId
83
+ }
84
+ };
85
+ }
86
+ /**
87
+ * Reads current state for `pulumi refresh` by looking up the volume.
88
+ *
89
+ * @param id Current Railway volume UUID
90
+ * @param props Last known persisted state
91
+ * @returns Refreshed resource ID and properties
92
+ * @throws {Error} If the volume no longer exists in Railway
93
+ */
94
+ async read(_id, props) {
95
+ const volumeId = await findVolumeByService(new RailwayClient(props.token), props.projectId, props.serviceId);
96
+ if (!volumeId) throw new Error("Railway volume not found during refresh");
97
+ return {
98
+ id: volumeId,
99
+ props: {
100
+ ...props,
101
+ volumeId
102
+ }
103
+ };
104
+ }
105
+ /**
106
+ * Deletes the Railway volume. Silently succeeds if already deleted.
107
+ *
108
+ * @param id Railway volume UUID to delete
109
+ * @param props Last known persisted state (used for token)
110
+ */
111
+ async delete(id, props) {
112
+ const client = new RailwayClient(props.token);
113
+ try {
114
+ await client.query(VOLUME_DELETE, { volumeId: id });
115
+ } catch {
116
+ pulumi.log.warn("Failed to delete Railway volume (may already be deleted)");
117
+ }
118
+ }
119
+ /**
120
+ * Compares old and new inputs to determine what changed.
121
+ *
122
+ * All mutable properties trigger replacement since Railway volumes
123
+ * cannot be moved between services, mount paths, environments, or projects.
124
+ *
125
+ * @param _id Current resource ID (unused)
126
+ * @param olds Previous persisted state
127
+ * @param news New desired configuration
128
+ * @returns Diff result with replacement triggers
129
+ */
130
+ async diff(_id, olds, news) {
131
+ const replaces = [];
132
+ if (olds.serviceId !== news.serviceId) replaces.push("serviceId");
133
+ if (olds.mountPath !== news.mountPath) replaces.push("mountPath");
134
+ if (olds.environmentId !== news.environmentId) replaces.push("environmentId");
135
+ if (olds.projectId !== news.projectId) replaces.push("projectId");
136
+ return {
137
+ changes: replaces.length > 0,
138
+ replaces,
139
+ deleteBeforeReplace: true
140
+ };
141
+ }
142
+ };
143
+ /**
144
+ * Manages a Railway persistent volume with adopt-or-create semantics.
145
+ *
146
+ * Finds existing volumes attached to the target service before creating
147
+ * new ones. Changing `serviceId`, `mountPath`, `environmentId`, or `projectId`
148
+ * triggers replacement (delete + create with new settings).
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * new RailwayVolume("railway-volume-redis", {
153
+ * token: project.projectToken,
154
+ * projectId: project.projectId,
155
+ * serviceId: service.serviceId,
156
+ * environmentId: project.productionEnvironmentId,
157
+ * mountPath: "/data",
158
+ * });
159
+ * ```
160
+ */
161
+ var RailwayVolume = class extends pulumi.dynamic.Resource {
162
+ /**
163
+ * @param name Pulumi resource name (logical identifier in state)
164
+ * @param args Volume configuration inputs
165
+ * @param opts Standard Pulumi resource options (e.g. `dependsOn`, `parent`)
166
+ */
167
+ constructor(name, args, opts) {
168
+ super(new RailwayVolumeProvider(), name, {
169
+ ...args,
170
+ volumeId: void 0
171
+ }, opts);
172
+ }
173
+ };
174
+
175
+ //#endregion
176
+ export { RailwayVolume };
177
+ //# sourceMappingURL=volume.mjs.map