@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 @@
1
+ {"version":3,"file":"role.d.cts","names":[],"sources":["../../src/neon/role.ts"],"mappings":";;;;;UAIiB,cAAA;;EAEhB,MAAA;EAF8B;EAK9B,SAAA;EAL8B;EAQ9B,QAAA;EAHA;EAMA,IAAA;AAAA;;AAAI;AAyML;;;;;;;;;;;;;;cAAa,QAAA,SAAiB,MAAA,CAAO,OAAA,CAAQ,QAAA;EAEpB;EAAA,SAAA,QAAA,EAAU,MAAA,CAAO,MAAA;EAAA;;;;;cAQxC,IAAA,UACA,IAAA;IAKC,oBAHA,MAAA,EAAQ,MAAA,CAAO,KAAA,UAGG;IAAlB,SAAA,EAAW,MAAA,CAAO,KAAA,UAGR;IAAV,QAAA,EAAU,MAAA,CAAO,KAAA,UAGjB;IAAA,IAAA,EAAM,MAAA,CAAO,KAAA;EAAA,GAEd,IAAA,GAAO,MAAA,CAAO,qBAAA;AAAA"}
@@ -0,0 +1,49 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.mjs";
2
+ import * as pulumi from "@pulumi/pulumi";
3
+
4
+ //#region src/neon/role.d.ts
5
+ /** Resolved inputs for the Neon role dynamic provider. */
6
+ interface NeonRoleInputs {
7
+ /** Neon API key. */
8
+ apiKey: string;
9
+ /** Neon project ID. */
10
+ projectId: string;
11
+ /** Branch ID the role belongs to. */
12
+ branchId: string;
13
+ /** Role name (e.g. `"neondb_owner"`). */
14
+ name: string;
15
+ }
16
+ /**
17
+ * Manages a Neon database role with adopt-or-create semantics.
18
+ * Exposes `password` as a secret output for connection string composition.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const role = new NeonRole("neon-role-owner", {
23
+ * apiKey: config.requireSecret("neonApiKey"),
24
+ * projectId: "quiet-forest-69719462",
25
+ * branchId: branch.id,
26
+ * name: "neondb_owner",
27
+ * });
28
+ *
29
+ * const password = role.password;
30
+ * ```
31
+ */
32
+ declare class NeonRole extends pulumi.dynamic.Resource {
33
+ /** Role password (auto-generated by Neon). */
34
+ readonly password: pulumi.Output<string>;
35
+ /**
36
+ * @param name Pulumi resource name
37
+ * @param args Role configuration inputs
38
+ * @param opts Standard Pulumi resource options
39
+ */
40
+ constructor(name: string, args: {
41
+ /** Neon API key. */apiKey: pulumi.Input<string>; /** Neon project ID. */
42
+ projectId: pulumi.Input<string>; /** Branch ID the role belongs to. */
43
+ branchId: pulumi.Input<string>; /** Role name (e.g. `"neondb_owner"`). */
44
+ name: pulumi.Input<string>;
45
+ }, opts?: pulumi.CustomResourceOptions);
46
+ }
47
+ //#endregion
48
+ export { NeonRole, NeonRoleInputs };
49
+ //# sourceMappingURL=role.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role.d.mts","names":[],"sources":["../../src/neon/role.ts"],"mappings":";;;;;UAIiB,cAAA;;EAEhB,MAAA;EAF8B;EAK9B,SAAA;EAL8B;EAQ9B,QAAA;EAHA;EAMA,IAAA;AAAA;;AAAI;AAyML;;;;;;;;;;;;;;cAAa,QAAA,SAAiB,MAAA,CAAO,OAAA,CAAQ,QAAA;EAEpB;EAAA,SAAA,QAAA,EAAU,MAAA,CAAO,MAAA;EAAA;;;;;cAQxC,IAAA,UACA,IAAA;IAKC,oBAHA,MAAA,EAAQ,MAAA,CAAO,KAAA,UAGG;IAAlB,SAAA,EAAW,MAAA,CAAO,KAAA,UAGR;IAAV,QAAA,EAAU,MAAA,CAAO,KAAA,UAGjB;IAAA,IAAA,EAAM,MAAA,CAAO,KAAA;EAAA,GAEd,IAAA,GAAO,MAAA,CAAO,qBAAA;AAAA"}
@@ -0,0 +1,133 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.mjs";
2
+ import { NeonClient } from "./client.mjs";
3
+ import * as pulumi from "@pulumi/pulumi";
4
+
5
+ //#region src/neon/role.ts
6
+ /**
7
+ * Checks if a role exists by name on a branch.
8
+ *
9
+ * @param client Authenticated Neon API client
10
+ * @param projectId Neon project ID
11
+ * @param branchId Branch ID to search within
12
+ * @param name Exact role name to match
13
+ * @returns `true` if found, `false` otherwise
14
+ */
15
+ async function roleExists(client, projectId, branchId, name) {
16
+ return (await client.get(`/projects/${projectId}/branches/${branchId}/roles`)).roles.some((r) => r.name === name);
17
+ }
18
+ /**
19
+ * Reveals the password for an existing role via the dedicated API endpoint.
20
+ *
21
+ * @param client Authenticated Neon API client
22
+ * @param projectId Neon project ID
23
+ * @param branchId Branch ID
24
+ * @param name Role name
25
+ * @returns The role password
26
+ */
27
+ async function revealPassword(client, projectId, branchId, name) {
28
+ return (await client.get(`/projects/${projectId}/branches/${branchId}/roles/${name}/reveal_password`)).password;
29
+ }
30
+ /**
31
+ * Dynamic provider implementing CRUD for Neon database roles.
32
+ *
33
+ * Uses adopt-or-create on `create()`: finds an existing role by name
34
+ * before creating a new one.
35
+ */
36
+ var NeonRoleProvider = class {
37
+ /**
38
+ * Creates or adopts a Neon role by name.
39
+ *
40
+ * @param inputs Resolved role configuration
41
+ * @returns Composite ID `{branchId}/{roleName}` as the resource ID
42
+ */
43
+ async create(inputs) {
44
+ const client = new NeonClient(inputs.apiKey);
45
+ if (!await roleExists(client, inputs.projectId, inputs.branchId, inputs.name)) await client.post(`/projects/${inputs.projectId}/branches/${inputs.branchId}/roles`, { role: { name: inputs.name } });
46
+ else pulumi.log.info(`Adopting existing Neon role "${inputs.name}"`);
47
+ const password = await revealPassword(client, inputs.projectId, inputs.branchId, inputs.name);
48
+ return {
49
+ id: `${inputs.branchId}/${inputs.name}`,
50
+ outs: {
51
+ ...inputs,
52
+ password
53
+ }
54
+ };
55
+ }
56
+ /**
57
+ * Reads current state for `pulumi refresh`.
58
+ *
59
+ * @param id Current composite role ID
60
+ * @param props Last known persisted state
61
+ * @returns Refreshed resource ID and properties with current password
62
+ * @throws {Error} If the role no longer exists
63
+ */
64
+ async read(id, props) {
65
+ const password = await revealPassword(new NeonClient(props.apiKey), props.projectId, props.branchId, props.name);
66
+ return {
67
+ id,
68
+ props: {
69
+ ...props,
70
+ password
71
+ }
72
+ };
73
+ }
74
+ /**
75
+ * Deletes the Neon role. Silently succeeds if already deleted.
76
+ */
77
+ async delete(_id, props) {
78
+ const client = new NeonClient(props.apiKey);
79
+ try {
80
+ await client.delete(`/projects/${props.projectId}/branches/${props.branchId}/roles/${props.name}`);
81
+ } catch {
82
+ pulumi.log.warn(`Failed to delete Neon role "${props.name}" (may already be deleted)`);
83
+ }
84
+ }
85
+ /**
86
+ * Compares old and new inputs. Changing any field triggers replacement
87
+ * since roles cannot be renamed or moved between branches.
88
+ */
89
+ async diff(_id, olds, news) {
90
+ const replaces = [];
91
+ if (olds.projectId !== news.projectId) replaces.push("projectId");
92
+ if (olds.branchId !== news.branchId) replaces.push("branchId");
93
+ if (olds.name !== news.name) replaces.push("name");
94
+ return {
95
+ changes: replaces.length > 0,
96
+ replaces,
97
+ deleteBeforeReplace: true
98
+ };
99
+ }
100
+ };
101
+ /**
102
+ * Manages a Neon database role with adopt-or-create semantics.
103
+ * Exposes `password` as a secret output for connection string composition.
104
+ *
105
+ * @example
106
+ * ```typescript
107
+ * const role = new NeonRole("neon-role-owner", {
108
+ * apiKey: config.requireSecret("neonApiKey"),
109
+ * projectId: "quiet-forest-69719462",
110
+ * branchId: branch.id,
111
+ * name: "neondb_owner",
112
+ * });
113
+ *
114
+ * const password = role.password;
115
+ * ```
116
+ */
117
+ var NeonRole = class extends pulumi.dynamic.Resource {
118
+ /**
119
+ * @param name Pulumi resource name
120
+ * @param args Role configuration inputs
121
+ * @param opts Standard Pulumi resource options
122
+ */
123
+ constructor(name, args, opts) {
124
+ super(new NeonRoleProvider(), name, {
125
+ ...args,
126
+ password: void 0
127
+ }, opts);
128
+ }
129
+ };
130
+
131
+ //#endregion
132
+ export { NeonRole };
133
+ //# sourceMappingURL=role.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"role.mjs","names":[],"sources":["../../src/neon/role.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { NeonClient } from \"./client.js\";\n\n/** Resolved inputs for the Neon role dynamic provider. */\nexport interface NeonRoleInputs {\n\t/** Neon API key. */\n\tapiKey: string;\n\n\t/** Neon project ID. */\n\tprojectId: string;\n\n\t/** Branch ID the role belongs to. */\n\tbranchId: string;\n\n\t/** Role name (e.g. `\"neondb_owner\"`). */\n\tname: string;\n}\n\n/** Persisted state for the Neon role. */\ninterface NeonRoleOutputs extends NeonRoleInputs {\n\t/** Role password (auto-generated by Neon). */\n\tpassword: string;\n}\n\n/** Neon API response for the reveal_password endpoint. */\ninterface PasswordResponse {\n\tpassword: string;\n}\n\n/** Neon API response for listing roles. */\ninterface RoleListResponse {\n\troles: Array<{\n\t\tname: string;\n\t}>;\n}\n\n/**\n * Checks if a role exists by name on a branch.\n *\n * @param client Authenticated Neon API client\n * @param projectId Neon project ID\n * @param branchId Branch ID to search within\n * @param name Exact role name to match\n * @returns `true` if found, `false` otherwise\n */\nasync function roleExists(\n\tclient: NeonClient,\n\tprojectId: string,\n\tbranchId: string,\n\tname: string,\n): Promise<boolean> {\n\tconst result = await client.get<RoleListResponse>(\n\t\t`/projects/${projectId}/branches/${branchId}/roles`,\n\t);\n\n\treturn result.roles.some((r) => r.name === name);\n}\n\n/**\n * Reveals the password for an existing role via the dedicated API endpoint.\n *\n * @param client Authenticated Neon API client\n * @param projectId Neon project ID\n * @param branchId Branch ID\n * @param name Role name\n * @returns The role password\n */\nasync function revealPassword(\n\tclient: NeonClient,\n\tprojectId: string,\n\tbranchId: string,\n\tname: string,\n): Promise<string> {\n\tconst result = await client.get<PasswordResponse>(\n\t\t`/projects/${projectId}/branches/${branchId}/roles/${name}/reveal_password`,\n\t);\n\n\treturn result.password;\n}\n\n/**\n * Dynamic provider implementing CRUD for Neon database roles.\n *\n * Uses adopt-or-create on `create()`: finds an existing role by name\n * before creating a new one.\n */\nclass NeonRoleProvider implements pulumi.dynamic.ResourceProvider {\n\t/**\n\t * Creates or adopts a Neon role by name.\n\t *\n\t * @param inputs Resolved role configuration\n\t * @returns Composite ID `{branchId}/{roleName}` as the resource ID\n\t */\n\tasync create(inputs: NeonRoleInputs): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new NeonClient(inputs.apiKey);\n\n\t\tconst exists = await roleExists(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.branchId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (!exists) {\n\t\t\tawait client.post(\n\t\t\t\t`/projects/${inputs.projectId}/branches/${inputs.branchId}/roles`,\n\t\t\t\t{ role: { name: inputs.name } },\n\t\t\t);\n\t\t} else {\n\t\t\tpulumi.log.info(`Adopting existing Neon role \"${inputs.name}\"`);\n\t\t}\n\n\t\tconst password = await revealPassword(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.branchId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\treturn {\n\t\t\tid: `${inputs.branchId}/${inputs.name}`,\n\t\t\touts: { ...inputs, password },\n\t\t};\n\t}\n\n\t/**\n\t * Reads current state for `pulumi refresh`.\n\t *\n\t * @param id Current composite role ID\n\t * @param props Last known persisted state\n\t * @returns Refreshed resource ID and properties with current password\n\t * @throws {Error} If the role no longer exists\n\t */\n\tasync read(\n\t\tid: string,\n\t\tprops: NeonRoleOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\tconst password = await revealPassword(\n\t\t\tclient,\n\t\t\tprops.projectId,\n\t\t\tprops.branchId,\n\t\t\tprops.name,\n\t\t);\n\n\t\treturn {\n\t\t\tid,\n\t\t\tprops: { ...props, password },\n\t\t};\n\t}\n\n\t/**\n\t * Deletes the Neon role. Silently succeeds if already deleted.\n\t */\n\tasync delete(_id: string, props: NeonRoleOutputs): Promise<void> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\ttry {\n\t\t\tawait client.delete(\n\t\t\t\t`/projects/${props.projectId}/branches/${props.branchId}/roles/${props.name}`,\n\t\t\t);\n\t\t} catch {\n\t\t\tpulumi.log.warn(\n\t\t\t\t`Failed to delete Neon role \"${props.name}\" (may already be deleted)`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Compares old and new inputs. Changing any field triggers replacement\n\t * since roles cannot be renamed or moved between branches.\n\t */\n\tasync diff(\n\t\t_id: string,\n\t\tolds: NeonRoleOutputs,\n\t\tnews: NeonRoleInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.projectId !== news.projectId) {\n\t\t\treplaces.push(\"projectId\");\n\t\t}\n\n\t\tif (olds.branchId !== news.branchId) {\n\t\t\treplaces.push(\"branchId\");\n\t\t}\n\n\t\tif (olds.name !== news.name) {\n\t\t\treplaces.push(\"name\");\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 Neon database role with adopt-or-create semantics.\n * Exposes `password` as a secret output for connection string composition.\n *\n * @example\n * ```typescript\n * const role = new NeonRole(\"neon-role-owner\", {\n * apiKey: config.requireSecret(\"neonApiKey\"),\n * projectId: \"quiet-forest-69719462\",\n * branchId: branch.id,\n * name: \"neondb_owner\",\n * });\n *\n * const password = role.password;\n * ```\n */\nexport class NeonRole extends pulumi.dynamic.Resource {\n\t/** Role password (auto-generated by Neon). */\n\tpublic declare readonly password: pulumi.Output<string>;\n\n\t/**\n\t * @param name Pulumi resource name\n\t * @param args Role configuration inputs\n\t * @param opts Standard Pulumi resource options\n\t */\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\t/** Neon API key. */\n\t\t\tapiKey: pulumi.Input<string>;\n\n\t\t\t/** Neon project ID. */\n\t\t\tprojectId: pulumi.Input<string>;\n\n\t\t\t/** Branch ID the role belongs to. */\n\t\t\tbranchId: pulumi.Input<string>;\n\n\t\t\t/** Role name (e.g. `\"neondb_owner\"`). */\n\t\t\tname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(new NeonRoleProvider(), name, { ...args, password: undefined }, opts);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AA6CA,eAAe,WACd,QACA,WACA,UACA,MACmB;CAKnB,QAAO,MAJc,OAAO,IAC3B,aAAa,UAAU,YAAY,SAAS,OAC7C,GAEc,MAAM,MAAM,MAAM,EAAE,SAAS,IAAI;AAChD;;;;;;;;;;AAWA,eAAe,eACd,QACA,WACA,UACA,MACkB;CAKlB,QAAO,MAJc,OAAO,IAC3B,aAAa,UAAU,YAAY,SAAS,SAAS,KAAK,iBAC3D,GAEc;AACf;;;;;;;AAQA,IAAM,mBAAN,MAAkE;;;;;;;CAOjE,MAAM,OAAO,QAA8D;EAC1E,MAAM,SAAS,IAAI,WAAW,OAAO,MAAM;EAS3C,IAAI,CAAC,MAPgB,WACpB,QACA,OAAO,WACP,OAAO,UACP,OAAO,IACR,GAGC,MAAM,OAAO,KACZ,aAAa,OAAO,UAAU,YAAY,OAAO,SAAS,SAC1D,EAAE,MAAM,EAAE,MAAM,OAAO,KAAK,EAAE,CAC/B;OAEA,OAAO,IAAI,KAAK,gCAAgC,OAAO,KAAK,EAAE;EAG/D,MAAM,WAAW,MAAM,eACtB,QACA,OAAO,WACP,OAAO,UACP,OAAO,IACR;EAEA,OAAO;GACN,IAAI,GAAG,OAAO,SAAS,GAAG,OAAO;GACjC,MAAM;IAAE,GAAG;IAAQ;GAAS;EAC7B;CACD;;;;;;;;;CAUA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,WAAW,MAAM,eACtB,IAHkB,WAAW,MAAM,MAG9B,GACL,MAAM,WACN,MAAM,UACN,MAAM,IACP;EAEA,OAAO;GACN;GACA,OAAO;IAAE,GAAG;IAAO;GAAS;EAC7B;CACD;;;;CAKA,MAAM,OAAO,KAAa,OAAuC;EAChE,MAAM,SAAS,IAAI,WAAW,MAAM,MAAM;EAE1C,IAAI;GACH,MAAM,OAAO,OACZ,aAAa,MAAM,UAAU,YAAY,MAAM,SAAS,SAAS,MAAM,MACxE;EACD,QAAQ;GACP,OAAO,IAAI,KACV,+BAA+B,MAAM,KAAK,2BAC3C;EACD;CACD;;;;;CAMA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,cAAc,KAAK,WAC3B,SAAS,KAAK,WAAW;EAG1B,IAAI,KAAK,aAAa,KAAK,UAC1B,SAAS,KAAK,UAAU;EAGzB,IAAI,KAAK,SAAS,KAAK,MACtB,SAAS,KAAK,MAAM;EAGrB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;;;;;;;;;;;;;;;;AAkBA,IAAa,WAAb,cAA8B,OAAO,QAAQ,SAAS;;;;;;CASrD,YACC,MACA,MAaA,MACC;EACD,MAAM,IAAI,iBAAiB,GAAG,MAAM;GAAE,GAAG;GAAM,UAAU;EAAU,GAAG,IAAI;CAC3E;AACD"}
@@ -0,0 +1,59 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_chunk = require('../chunk-BVYJZCqc.cjs');
3
+
4
+ //#region src/railway/client.ts
5
+ const RAILWAY_API_URL = "https://backboard.railway.app/graphql/v2";
6
+ /**
7
+ * Typed GraphQL client for Railway's API.
8
+ *
9
+ * Wraps `fetch` with auth headers, JSON serialization, and error
10
+ * extraction so callers only deal with typed response data.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const client = new RailwayClient(token);
15
+ * const result = await client.query<{ project: { id: string } }>(
16
+ * `query { project(id: "abc") { id name } }`
17
+ * );
18
+ * ```
19
+ */
20
+ var RailwayClient = class {
21
+ /**
22
+ * @param token Railway API bearer token (project-scoped or account-scoped)
23
+ */
24
+ constructor(token) {
25
+ this.token = token;
26
+ }
27
+ /**
28
+ * Executes a GraphQL query or mutation against Railway's API.
29
+ *
30
+ * @param query The GraphQL query or mutation string
31
+ * @param variables Optional variables for parameterized queries
32
+ * @returns The typed data payload from the response
33
+ * @throws {Error} On HTTP transport errors (non-2xx status)
34
+ * @throws {Error} On GraphQL-level errors (errors array in response)
35
+ * @throws {Error} When the response contains no data payload
36
+ */
37
+ async query(query, variables) {
38
+ const response = await fetch(RAILWAY_API_URL, {
39
+ method: "POST",
40
+ headers: {
41
+ "Content-Type": "application/json",
42
+ Authorization: `Bearer ${this.token}`
43
+ },
44
+ body: JSON.stringify({
45
+ query,
46
+ variables
47
+ })
48
+ });
49
+ if (!response.ok) throw new Error(`Railway API HTTP error: ${response.status} ${response.statusText}`);
50
+ const json = await response.json();
51
+ if (json.errors && json.errors.length > 0) throw new Error(`Railway API error: ${json.errors[0].message}`);
52
+ if (!json.data) throw new Error("Railway API returned no data");
53
+ return json.data;
54
+ }
55
+ };
56
+
57
+ //#endregion
58
+ exports.RailwayClient = RailwayClient;
59
+ //# sourceMappingURL=client.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.cjs","names":[],"sources":["../../src/railway/client.ts"],"sourcesContent":["const RAILWAY_API_URL = \"https://backboard.railway.app/graphql/v2\";\n\n/** Standard GraphQL response envelope from Railway's API. */\ninterface GraphQLResponse<T> {\n\t/** The resolved data payload, present on success. */\n\tdata?: T;\n\n\t/** Array of GraphQL-level errors, present on partial or full failure. */\n\terrors?: Array<{ message: string }>;\n}\n\n/**\n * Typed GraphQL client for Railway's API.\n *\n * Wraps `fetch` with auth headers, JSON serialization, and error\n * extraction so callers only deal with typed response data.\n *\n * @example\n * ```typescript\n * const client = new RailwayClient(token);\n * const result = await client.query<{ project: { id: string } }>(\n * `query { project(id: \"abc\") { id name } }`\n * );\n * ```\n */\nexport class RailwayClient {\n\t/** Railway API bearer token. */\n\tprivate readonly token: string;\n\n\t/**\n\t * @param token Railway API bearer token (project-scoped or account-scoped)\n\t */\n\tconstructor(token: string) {\n\t\tthis.token = token;\n\t}\n\n\t/**\n\t * Executes a GraphQL query or mutation against Railway's API.\n\t *\n\t * @param query The GraphQL query or mutation string\n\t * @param variables Optional variables for parameterized queries\n\t * @returns The typed data payload from the response\n\t * @throws {Error} On HTTP transport errors (non-2xx status)\n\t * @throws {Error} On GraphQL-level errors (errors array in response)\n\t * @throws {Error} When the response contains no data payload\n\t */\n\tasync query<T>(\n\t\tquery: string,\n\t\tvariables?: Record<string, unknown>,\n\t): Promise<T> {\n\t\tconst response = await fetch(RAILWAY_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${this.token}`,\n\t\t\t},\n\t\t\tbody: JSON.stringify({ query, variables }),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Railway API HTTP error: ${response.status} ${response.statusText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst json = (await response.json()) as GraphQLResponse<T>;\n\n\t\tif (json.errors && json.errors.length > 0) {\n\t\t\tthrow new Error(`Railway API error: ${json.errors[0].message}`);\n\t\t}\n\n\t\tif (!json.data) {\n\t\t\tthrow new Error(\"Railway API returned no data\");\n\t\t}\n\n\t\treturn json.data;\n\t}\n}\n"],"mappings":";;;;AAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;AAyBxB,IAAa,gBAAb,MAA2B;;;;CAO1B,YAAY,OAAe;EAC1B,KAAK,QAAQ;CACd;;;;;;;;;;;CAYA,MAAM,MACL,OACA,WACa;EACb,MAAM,WAAW,MAAM,MAAM,iBAAiB;GAC7C,QAAQ;GACR,SAAS;IACR,gBAAgB;IAChB,eAAe,UAAU,KAAK;GAC/B;GACA,MAAM,KAAK,UAAU;IAAE;IAAO;GAAU,CAAC;EAC1C,CAAC;EAED,IAAI,CAAC,SAAS,IACb,MAAM,IAAI,MACT,2BAA2B,SAAS,OAAO,GAAG,SAAS,YACxD;EAGD,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,KAAK,UAAU,KAAK,OAAO,SAAS,GACvC,MAAM,IAAI,MAAM,sBAAsB,KAAK,OAAO,GAAG,SAAS;EAG/D,IAAI,CAAC,KAAK,MACT,MAAM,IAAI,MAAM,8BAA8B;EAG/C,OAAO,KAAK;CACb;AACD"}
@@ -0,0 +1,39 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.cjs";
2
+
3
+ //#region src/railway/client.d.ts
4
+ /**
5
+ * Typed GraphQL client for Railway's API.
6
+ *
7
+ * Wraps `fetch` with auth headers, JSON serialization, and error
8
+ * extraction so callers only deal with typed response data.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const client = new RailwayClient(token);
13
+ * const result = await client.query<{ project: { id: string } }>(
14
+ * `query { project(id: "abc") { id name } }`
15
+ * );
16
+ * ```
17
+ */
18
+ declare class RailwayClient {
19
+ /** Railway API bearer token. */
20
+ private readonly token;
21
+ /**
22
+ * @param token Railway API bearer token (project-scoped or account-scoped)
23
+ */
24
+ constructor(token: string);
25
+ /**
26
+ * Executes a GraphQL query or mutation against Railway's API.
27
+ *
28
+ * @param query The GraphQL query or mutation string
29
+ * @param variables Optional variables for parameterized queries
30
+ * @returns The typed data payload from the response
31
+ * @throws {Error} On HTTP transport errors (non-2xx status)
32
+ * @throws {Error} On GraphQL-level errors (errors array in response)
33
+ * @throws {Error} When the response contains no data payload
34
+ */
35
+ query<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
36
+ }
37
+ //#endregion
38
+ export { RailwayClient };
39
+ //# sourceMappingURL=client.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.cts","names":[],"sources":["../../src/railway/client.ts"],"mappings":";;;;;;AAyBA;;;;;;;;;;;cAAa,aAAA;EAqBA;EAAA,iBAnBK,KAAA;EAqBJ;;;cAhBD,KAAA;EAiBA;AAAA;;;;;;;;;EAHN,KAAA,GAAA,CACL,KAAA,UACA,SAAA,GAAY,MAAA,oBACV,OAAA,CAAQ,CAAA;AAAA"}
@@ -0,0 +1,39 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.mjs";
2
+
3
+ //#region src/railway/client.d.ts
4
+ /**
5
+ * Typed GraphQL client for Railway's API.
6
+ *
7
+ * Wraps `fetch` with auth headers, JSON serialization, and error
8
+ * extraction so callers only deal with typed response data.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const client = new RailwayClient(token);
13
+ * const result = await client.query<{ project: { id: string } }>(
14
+ * `query { project(id: "abc") { id name } }`
15
+ * );
16
+ * ```
17
+ */
18
+ declare class RailwayClient {
19
+ /** Railway API bearer token. */
20
+ private readonly token;
21
+ /**
22
+ * @param token Railway API bearer token (project-scoped or account-scoped)
23
+ */
24
+ constructor(token: string);
25
+ /**
26
+ * Executes a GraphQL query or mutation against Railway's API.
27
+ *
28
+ * @param query The GraphQL query or mutation string
29
+ * @param variables Optional variables for parameterized queries
30
+ * @returns The typed data payload from the response
31
+ * @throws {Error} On HTTP transport errors (non-2xx status)
32
+ * @throws {Error} On GraphQL-level errors (errors array in response)
33
+ * @throws {Error} When the response contains no data payload
34
+ */
35
+ query<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
36
+ }
37
+ //#endregion
38
+ export { RailwayClient };
39
+ //# sourceMappingURL=client.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.mts","names":[],"sources":["../../src/railway/client.ts"],"mappings":";;;;;;AAyBA;;;;;;;;;;;cAAa,aAAA;EAqBA;EAAA,iBAnBK,KAAA;EAqBJ;;;cAhBD,KAAA;EAiBA;AAAA;;;;;;;;;EAHN,KAAA,GAAA,CACL,KAAA,UACA,SAAA,GAAY,MAAA,oBACV,OAAA,CAAQ,CAAA;AAAA"}
@@ -0,0 +1,58 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.mjs";
2
+
3
+ //#region src/railway/client.ts
4
+ const RAILWAY_API_URL = "https://backboard.railway.app/graphql/v2";
5
+ /**
6
+ * Typed GraphQL client for Railway's API.
7
+ *
8
+ * Wraps `fetch` with auth headers, JSON serialization, and error
9
+ * extraction so callers only deal with typed response data.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const client = new RailwayClient(token);
14
+ * const result = await client.query<{ project: { id: string } }>(
15
+ * `query { project(id: "abc") { id name } }`
16
+ * );
17
+ * ```
18
+ */
19
+ var RailwayClient = class {
20
+ /**
21
+ * @param token Railway API bearer token (project-scoped or account-scoped)
22
+ */
23
+ constructor(token) {
24
+ this.token = token;
25
+ }
26
+ /**
27
+ * Executes a GraphQL query or mutation against Railway's API.
28
+ *
29
+ * @param query The GraphQL query or mutation string
30
+ * @param variables Optional variables for parameterized queries
31
+ * @returns The typed data payload from the response
32
+ * @throws {Error} On HTTP transport errors (non-2xx status)
33
+ * @throws {Error} On GraphQL-level errors (errors array in response)
34
+ * @throws {Error} When the response contains no data payload
35
+ */
36
+ async query(query, variables) {
37
+ const response = await fetch(RAILWAY_API_URL, {
38
+ method: "POST",
39
+ headers: {
40
+ "Content-Type": "application/json",
41
+ Authorization: `Bearer ${this.token}`
42
+ },
43
+ body: JSON.stringify({
44
+ query,
45
+ variables
46
+ })
47
+ });
48
+ if (!response.ok) throw new Error(`Railway API HTTP error: ${response.status} ${response.statusText}`);
49
+ const json = await response.json();
50
+ if (json.errors && json.errors.length > 0) throw new Error(`Railway API error: ${json.errors[0].message}`);
51
+ if (!json.data) throw new Error("Railway API returned no data");
52
+ return json.data;
53
+ }
54
+ };
55
+
56
+ //#endregion
57
+ export { RailwayClient };
58
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../../src/railway/client.ts"],"sourcesContent":["const RAILWAY_API_URL = \"https://backboard.railway.app/graphql/v2\";\n\n/** Standard GraphQL response envelope from Railway's API. */\ninterface GraphQLResponse<T> {\n\t/** The resolved data payload, present on success. */\n\tdata?: T;\n\n\t/** Array of GraphQL-level errors, present on partial or full failure. */\n\terrors?: Array<{ message: string }>;\n}\n\n/**\n * Typed GraphQL client for Railway's API.\n *\n * Wraps `fetch` with auth headers, JSON serialization, and error\n * extraction so callers only deal with typed response data.\n *\n * @example\n * ```typescript\n * const client = new RailwayClient(token);\n * const result = await client.query<{ project: { id: string } }>(\n * `query { project(id: \"abc\") { id name } }`\n * );\n * ```\n */\nexport class RailwayClient {\n\t/** Railway API bearer token. */\n\tprivate readonly token: string;\n\n\t/**\n\t * @param token Railway API bearer token (project-scoped or account-scoped)\n\t */\n\tconstructor(token: string) {\n\t\tthis.token = token;\n\t}\n\n\t/**\n\t * Executes a GraphQL query or mutation against Railway's API.\n\t *\n\t * @param query The GraphQL query or mutation string\n\t * @param variables Optional variables for parameterized queries\n\t * @returns The typed data payload from the response\n\t * @throws {Error} On HTTP transport errors (non-2xx status)\n\t * @throws {Error} On GraphQL-level errors (errors array in response)\n\t * @throws {Error} When the response contains no data payload\n\t */\n\tasync query<T>(\n\t\tquery: string,\n\t\tvariables?: Record<string, unknown>,\n\t): Promise<T> {\n\t\tconst response = await fetch(RAILWAY_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\tAuthorization: `Bearer ${this.token}`,\n\t\t\t},\n\t\t\tbody: JSON.stringify({ query, variables }),\n\t\t});\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Railway API HTTP error: ${response.status} ${response.statusText}`,\n\t\t\t);\n\t\t}\n\n\t\tconst json = (await response.json()) as GraphQLResponse<T>;\n\n\t\tif (json.errors && json.errors.length > 0) {\n\t\t\tthrow new Error(`Railway API error: ${json.errors[0].message}`);\n\t\t}\n\n\t\tif (!json.data) {\n\t\t\tthrow new Error(\"Railway API returned no data\");\n\t\t}\n\n\t\treturn json.data;\n\t}\n}\n"],"mappings":";;;AAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;AAyBxB,IAAa,gBAAb,MAA2B;;;;CAO1B,YAAY,OAAe;EAC1B,KAAK,QAAQ;CACd;;;;;;;;;;;CAYA,MAAM,MACL,OACA,WACa;EACb,MAAM,WAAW,MAAM,MAAM,iBAAiB;GAC7C,QAAQ;GACR,SAAS;IACR,gBAAgB;IAChB,eAAe,UAAU,KAAK;GAC/B;GACA,MAAM,KAAK,UAAU;IAAE;IAAO;GAAU,CAAC;EAC1C,CAAC;EAED,IAAI,CAAC,SAAS,IACb,MAAM,IAAI,MACT,2BAA2B,SAAS,OAAO,GAAG,SAAS,YACxD;EAGD,MAAM,OAAQ,MAAM,SAAS,KAAK;EAElC,IAAI,KAAK,UAAU,KAAK,OAAO,SAAS,GACvC,MAAM,IAAI,MAAM,sBAAsB,KAAK,OAAO,GAAG,SAAS;EAG/D,IAAI,CAAC,KAAK,MACT,MAAM,IAAI,MAAM,8BAA8B;EAG/C,OAAO,KAAK;CACb;AACD"}
@@ -0,0 +1,40 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_chunk = require('../chunk-BVYJZCqc.cjs');
3
+ let _pulumi_command = require("@pulumi/command");
4
+ _pulumi_command = require_chunk.__toESM(_pulumi_command, 1);
5
+ let _pulumi_pulumi = require("@pulumi/pulumi");
6
+ _pulumi_pulumi = require_chunk.__toESM(_pulumi_pulumi, 1);
7
+
8
+ //#region src/railway/deploy.ts
9
+ const LOCK_DIR = "/tmp/.railway-upload-lock";
10
+ /**
11
+ * Deploys a Railway service and waits for the build to complete.
12
+ *
13
+ * Uses `railway up --ci` which blocks until the build finishes.
14
+ * Multiple deploys run in parallel — a mkdir lock serializes only the
15
+ * brief upload phase (~5s) when `.railwayignore` must be consistent,
16
+ * then releases so builds stream concurrently.
17
+ */
18
+ var RailwayDeploy = class extends _pulumi_pulumi.ComponentResource {
19
+ constructor(name, args, opts) {
20
+ super("infrakit:railway:Deploy", name, {}, opts);
21
+ const ignorePatterns = (args.excludePaths ?? []).map((dir) => {
22
+ if (dir.startsWith("apps/")) return `${dir}/**\\n!${dir}/package.json`;
23
+ return dir;
24
+ }).join("\\n");
25
+ const setupLines = [ignorePatterns ? `printf '${ignorePatterns}\\n' > .railwayignore` : "", args.railpackConfig ? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, "\\'")}' > railpack.json` : ""].filter(Boolean).join("; ");
26
+ const envHash = _pulumi_pulumi.all(Object.entries(args.env).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => _pulumi_pulumi.output(v).apply((val) => `${k}=${val}`))).apply((parts) => parts.join(","));
27
+ const deployCmd = _pulumi_pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & railway up --ci --project ${args.projectId} --service ${args.serviceId} --environment ${args.environmentId}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;
28
+ new _pulumi_command.local.Command(`${name}-deploy`, {
29
+ create: deployCmd,
30
+ triggers: [args.sourceHash, envHash],
31
+ dir: args.directory,
32
+ environment: { RAILWAY_TOKEN: args.projectToken }
33
+ }, { parent: this });
34
+ this.registerOutputs({});
35
+ }
36
+ };
37
+
38
+ //#endregion
39
+ exports.RailwayDeploy = RailwayDeploy;
40
+ //# sourceMappingURL=deploy.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.cjs","names":["pulumi","command"],"sources":["../../src/railway/deploy.ts"],"sourcesContent":["import * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system: `\"RAILPACK\"`, `\"NIXPACKS\"`, or `\"DOCKERFILE\"`. */\n\tbuilder?: string;\n\n\t/** Shell command executed to start the service at runtime. */\n\tstartCommand?: string;\n\n\t/** Shell command executed before the main deploy (e.g. migrations). */\n\tpreDeployCommand?: string;\n}\n\ninterface RailwayDeployArgs {\n\t/** Project-scoped Railway token for `railway up` CLI (stable across runs). */\n\tprojectToken: pulumi.Input<string>;\n\n\t/** Railway project UUID. */\n\tprojectId: string;\n\n\t/** Railway service UUID to deploy to. */\n\tserviceId: pulumi.Input<string>;\n\n\t/** Railway environment UUID (e.g. production). */\n\tenvironmentId: string;\n\n\t/** Absolute path to the monorepo root (working directory for `railway up`). */\n\tdirectory: string;\n\n\t/** SHA-256 hash of the app source directory, used as a deploy trigger. */\n\tsourceHash: string;\n\n\t/** Env var map used as deploy trigger. */\n\tenv: Record<string, pulumi.Input<string>>;\n\n\t/** Directories to exclude via `.railwayignore`. */\n\texcludePaths?: string[];\n\n\t/** Railpack configuration written to `railpack.json` before deploy. */\n\trailpackConfig?: Record<string, unknown>;\n}\n\nconst LOCK_DIR = \"/tmp/.railway-upload-lock\";\n\n/**\n * Deploys a Railway service and waits for the build to complete.\n *\n * Uses `railway up --ci` which blocks until the build finishes.\n * Multiple deploys run in parallel — a mkdir lock serializes only the\n * brief upload phase (~5s) when `.railwayignore` must be consistent,\n * then releases so builds stream concurrently.\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts?: pulumi.ComponentResourceOptions,\n\t) {\n\t\tsuper(\"infrakit:railway:Deploy\", name, {}, opts);\n\n\t\tconst ignorePatterns = (args.excludePaths ?? [])\n\t\t\t.map((dir) => {\n\t\t\t\tif (dir.startsWith(\"apps/\")) {\n\t\t\t\t\treturn `${dir}/**\\\\n!${dir}/package.json`;\n\t\t\t\t}\n\n\t\t\t\treturn dir;\n\t\t\t})\n\t\t\t.join(\"\\\\n\");\n\n\t\tconst writeIgnore = ignorePatterns\n\t\t\t? `printf '${ignorePatterns}\\\\n' > .railwayignore`\n\t\t\t: \"\";\n\n\t\tconst writeRailpack = args.railpackConfig\n\t\t\t? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, \"\\\\'\")}' > railpack.json`\n\t\t\t: \"\";\n\n\t\tconst setupLines = [writeIgnore, writeRailpack].filter(Boolean).join(\"; \");\n\n\t\tconst envHash = pulumi\n\t\t\t.all(\n\t\t\t\tObject.entries(args.env)\n\t\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t\t.map(([k, v]) => pulumi.output(v).apply((val) => `${k}=${val}`)),\n\t\t\t)\n\t\t\t.apply((parts) => parts.join(\",\"));\n\n\t\t// Parallel-safe upload: multiple stacks deploy concurrently, but each writes\n\t\t// .railwayignore and railpack.json to the same monorepo root before calling\n\t\t// `railway up`. The mkdir lock serializes that brief window (~5s upload phase).\n\t\t// After upload, the background job releases the lock so builds stream in parallel.\n\t\t//\n\t\t// Flow: acquire lock → write config files → release lock after 5s (background) →\n\t\t// railway up --ci (blocks through upload, then streams build logs) →\n\t\t// cleanup on exit\n\t\tconst deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & railway up --ci --project ${args.projectId} --service ${args.serviceId} --environment ${args.environmentId}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;\n\n\t\tnew command.local.Command(\n\t\t\t`${name}-deploy`,\n\t\t\t{\n\t\t\t\tcreate: deployCmd,\n\t\t\t\ttriggers: [args.sourceHash, envHash],\n\t\t\t\tdir: args.directory,\n\t\t\t\tenvironment: {\n\t\t\t\t\tRAILWAY_TOKEN: args.projectToken,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.registerOutputs({});\n\t}\n}\n"],"mappings":";;;;;;;;AA4CA,MAAM,WAAW;;;;;;;;;AAUjB,IAAa,gBAAb,cAAmCA,eAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,2BAA2B,MAAM,CAAC,GAAG,IAAI;EAE/C,MAAM,kBAAkB,KAAK,gBAAgB,CAAC,GAC5C,KAAK,QAAQ;GACb,IAAI,IAAI,WAAW,OAAO,GACzB,OAAO,GAAG,IAAI,SAAS,IAAI;GAG5B,OAAO;EACR,CAAC,EACA,KAAK,KAAK;EAUZ,MAAM,aAAa,CARC,iBACjB,WAAW,eAAe,yBAC1B,IAEmB,KAAK,iBACxB,WAAW,KAAK,UAAU,KAAK,cAAc,EAAE,QAAQ,MAAM,KAAK,EAAE,qBACpE,EAE2C,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;EAEzE,MAAM,UAAUA,eACd,IACA,OAAO,QAAQ,KAAK,GAAG,EACrB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EACrC,KAAK,CAAC,GAAG,OAAOA,eAAO,OAAO,CAAC,EAAE,OAAO,QAAQ,GAAG,EAAE,GAAG,KAAK,CAAC,CACjE,EACC,OAAO,UAAU,MAAM,KAAK,GAAG,CAAC;EAUlC,MAAM,YAAY,eAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,8CAA8C,KAAK,UAAU,aAAa,KAAK,UAAU,iBAAiB,KAAK,cAAc,uDAAuD,SAAS;EAE1W,IAAIC,gBAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,CAAC,KAAK,YAAY,OAAO;GACnC,KAAK,KAAK;GACV,aAAa,EACZ,eAAe,KAAK,aACrB;EACD,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}
@@ -0,0 +1,47 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.cjs";
2
+ import * as pulumi from "@pulumi/pulumi";
3
+
4
+ //#region src/railway/deploy.d.ts
5
+ /** Build and deploy configuration for a Railway service. */
6
+ interface RailwayDeployConfig {
7
+ /** Build system: `"RAILPACK"`, `"NIXPACKS"`, or `"DOCKERFILE"`. */
8
+ builder?: string;
9
+ /** Shell command executed to start the service at runtime. */
10
+ startCommand?: string;
11
+ /** Shell command executed before the main deploy (e.g. migrations). */
12
+ preDeployCommand?: string;
13
+ }
14
+ interface RailwayDeployArgs {
15
+ /** Project-scoped Railway token for `railway up` CLI (stable across runs). */
16
+ projectToken: pulumi.Input<string>;
17
+ /** Railway project UUID. */
18
+ projectId: string;
19
+ /** Railway service UUID to deploy to. */
20
+ serviceId: pulumi.Input<string>;
21
+ /** Railway environment UUID (e.g. production). */
22
+ environmentId: string;
23
+ /** Absolute path to the monorepo root (working directory for `railway up`). */
24
+ directory: string;
25
+ /** SHA-256 hash of the app source directory, used as a deploy trigger. */
26
+ sourceHash: string;
27
+ /** Env var map used as deploy trigger. */
28
+ env: Record<string, pulumi.Input<string>>;
29
+ /** Directories to exclude via `.railwayignore`. */
30
+ excludePaths?: string[];
31
+ /** Railpack configuration written to `railpack.json` before deploy. */
32
+ railpackConfig?: Record<string, unknown>;
33
+ }
34
+ /**
35
+ * Deploys a Railway service and waits for the build to complete.
36
+ *
37
+ * Uses `railway up --ci` which blocks until the build finishes.
38
+ * Multiple deploys run in parallel — a mkdir lock serializes only the
39
+ * brief upload phase (~5s) when `.railwayignore` must be consistent,
40
+ * then releases so builds stream concurrently.
41
+ */
42
+ declare class RailwayDeploy extends pulumi.ComponentResource {
43
+ constructor(name: string, args: RailwayDeployArgs, opts?: pulumi.ComponentResourceOptions);
44
+ }
45
+ //#endregion
46
+ export { RailwayDeploy, RailwayDeployConfig };
47
+ //# sourceMappingURL=deploy.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.cts","names":[],"sources":["../../src/railway/deploy.ts"],"mappings":";;;;;UAIiB,mBAAA;;EAEhB,OAAA;EAFmC;EAKnC,YAAA;EALmC;EAQnC,gBAAA;AAAA;AAAA,UAGS,iBAAA;EAHO;EAKhB,YAAA,EAAc,MAAA,CAAO,KAAA;EAFZ;EAKT,SAAA;;EAGA,SAAA,EAAW,MAAA,CAAO,KAAA;EAAP;EAGX,aAAA;EASK;EANL,SAAA;EAYuB;EATvB,UAAA;EAfA;EAkBA,GAAA,EAAK,MAAA,SAAe,MAAA,CAAO,KAAA;EAlBN;EAqBrB,YAAA;EAfA;EAkBA,cAAA,GAAiB,MAAA;AAAA;;;;;;;;;cAaL,aAAA,SAAsB,MAAA,CAAO,iBAAA;cAExC,IAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA"}
@@ -0,0 +1,47 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.mjs";
2
+ import * as pulumi from "@pulumi/pulumi";
3
+
4
+ //#region src/railway/deploy.d.ts
5
+ /** Build and deploy configuration for a Railway service. */
6
+ interface RailwayDeployConfig {
7
+ /** Build system: `"RAILPACK"`, `"NIXPACKS"`, or `"DOCKERFILE"`. */
8
+ builder?: string;
9
+ /** Shell command executed to start the service at runtime. */
10
+ startCommand?: string;
11
+ /** Shell command executed before the main deploy (e.g. migrations). */
12
+ preDeployCommand?: string;
13
+ }
14
+ interface RailwayDeployArgs {
15
+ /** Project-scoped Railway token for `railway up` CLI (stable across runs). */
16
+ projectToken: pulumi.Input<string>;
17
+ /** Railway project UUID. */
18
+ projectId: string;
19
+ /** Railway service UUID to deploy to. */
20
+ serviceId: pulumi.Input<string>;
21
+ /** Railway environment UUID (e.g. production). */
22
+ environmentId: string;
23
+ /** Absolute path to the monorepo root (working directory for `railway up`). */
24
+ directory: string;
25
+ /** SHA-256 hash of the app source directory, used as a deploy trigger. */
26
+ sourceHash: string;
27
+ /** Env var map used as deploy trigger. */
28
+ env: Record<string, pulumi.Input<string>>;
29
+ /** Directories to exclude via `.railwayignore`. */
30
+ excludePaths?: string[];
31
+ /** Railpack configuration written to `railpack.json` before deploy. */
32
+ railpackConfig?: Record<string, unknown>;
33
+ }
34
+ /**
35
+ * Deploys a Railway service and waits for the build to complete.
36
+ *
37
+ * Uses `railway up --ci` which blocks until the build finishes.
38
+ * Multiple deploys run in parallel — a mkdir lock serializes only the
39
+ * brief upload phase (~5s) when `.railwayignore` must be consistent,
40
+ * then releases so builds stream concurrently.
41
+ */
42
+ declare class RailwayDeploy extends pulumi.ComponentResource {
43
+ constructor(name: string, args: RailwayDeployArgs, opts?: pulumi.ComponentResourceOptions);
44
+ }
45
+ //#endregion
46
+ export { RailwayDeploy, RailwayDeployConfig };
47
+ //# sourceMappingURL=deploy.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.mts","names":[],"sources":["../../src/railway/deploy.ts"],"mappings":";;;;;UAIiB,mBAAA;;EAEhB,OAAA;EAFmC;EAKnC,YAAA;EALmC;EAQnC,gBAAA;AAAA;AAAA,UAGS,iBAAA;EAHO;EAKhB,YAAA,EAAc,MAAA,CAAO,KAAA;EAFZ;EAKT,SAAA;;EAGA,SAAA,EAAW,MAAA,CAAO,KAAA;EAAP;EAGX,aAAA;EASK;EANL,SAAA;EAYuB;EATvB,UAAA;EAfA;EAkBA,GAAA,EAAK,MAAA,SAAe,MAAA,CAAO,KAAA;EAlBN;EAqBrB,YAAA;EAfA;EAkBA,cAAA,GAAiB,MAAA;AAAA;;;;;;;;;cAaL,aAAA,SAAsB,MAAA,CAAO,iBAAA;cAExC,IAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA"}
@@ -0,0 +1,37 @@
1
+ import { t as __name } from "../chunk-OPjESj5l.mjs";
2
+ import * as command from "@pulumi/command";
3
+ import * as pulumi from "@pulumi/pulumi";
4
+
5
+ //#region src/railway/deploy.ts
6
+ const LOCK_DIR = "/tmp/.railway-upload-lock";
7
+ /**
8
+ * Deploys a Railway service and waits for the build to complete.
9
+ *
10
+ * Uses `railway up --ci` which blocks until the build finishes.
11
+ * Multiple deploys run in parallel — a mkdir lock serializes only the
12
+ * brief upload phase (~5s) when `.railwayignore` must be consistent,
13
+ * then releases so builds stream concurrently.
14
+ */
15
+ var RailwayDeploy = class extends pulumi.ComponentResource {
16
+ constructor(name, args, opts) {
17
+ super("infrakit:railway:Deploy", name, {}, opts);
18
+ const ignorePatterns = (args.excludePaths ?? []).map((dir) => {
19
+ if (dir.startsWith("apps/")) return `${dir}/**\\n!${dir}/package.json`;
20
+ return dir;
21
+ }).join("\\n");
22
+ const setupLines = [ignorePatterns ? `printf '${ignorePatterns}\\n' > .railwayignore` : "", args.railpackConfig ? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, "\\'")}' > railpack.json` : ""].filter(Boolean).join("; ");
23
+ const envHash = pulumi.all(Object.entries(args.env).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => pulumi.output(v).apply((val) => `${k}=${val}`))).apply((parts) => parts.join(","));
24
+ const deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & railway up --ci --project ${args.projectId} --service ${args.serviceId} --environment ${args.environmentId}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;
25
+ new command.local.Command(`${name}-deploy`, {
26
+ create: deployCmd,
27
+ triggers: [args.sourceHash, envHash],
28
+ dir: args.directory,
29
+ environment: { RAILWAY_TOKEN: args.projectToken }
30
+ }, { parent: this });
31
+ this.registerOutputs({});
32
+ }
33
+ };
34
+
35
+ //#endregion
36
+ export { RailwayDeploy };
37
+ //# sourceMappingURL=deploy.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/railway/deploy.ts"],"sourcesContent":["import * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system: `\"RAILPACK\"`, `\"NIXPACKS\"`, or `\"DOCKERFILE\"`. */\n\tbuilder?: string;\n\n\t/** Shell command executed to start the service at runtime. */\n\tstartCommand?: string;\n\n\t/** Shell command executed before the main deploy (e.g. migrations). */\n\tpreDeployCommand?: string;\n}\n\ninterface RailwayDeployArgs {\n\t/** Project-scoped Railway token for `railway up` CLI (stable across runs). */\n\tprojectToken: pulumi.Input<string>;\n\n\t/** Railway project UUID. */\n\tprojectId: string;\n\n\t/** Railway service UUID to deploy to. */\n\tserviceId: pulumi.Input<string>;\n\n\t/** Railway environment UUID (e.g. production). */\n\tenvironmentId: string;\n\n\t/** Absolute path to the monorepo root (working directory for `railway up`). */\n\tdirectory: string;\n\n\t/** SHA-256 hash of the app source directory, used as a deploy trigger. */\n\tsourceHash: string;\n\n\t/** Env var map used as deploy trigger. */\n\tenv: Record<string, pulumi.Input<string>>;\n\n\t/** Directories to exclude via `.railwayignore`. */\n\texcludePaths?: string[];\n\n\t/** Railpack configuration written to `railpack.json` before deploy. */\n\trailpackConfig?: Record<string, unknown>;\n}\n\nconst LOCK_DIR = \"/tmp/.railway-upload-lock\";\n\n/**\n * Deploys a Railway service and waits for the build to complete.\n *\n * Uses `railway up --ci` which blocks until the build finishes.\n * Multiple deploys run in parallel — a mkdir lock serializes only the\n * brief upload phase (~5s) when `.railwayignore` must be consistent,\n * then releases so builds stream concurrently.\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts?: pulumi.ComponentResourceOptions,\n\t) {\n\t\tsuper(\"infrakit:railway:Deploy\", name, {}, opts);\n\n\t\tconst ignorePatterns = (args.excludePaths ?? [])\n\t\t\t.map((dir) => {\n\t\t\t\tif (dir.startsWith(\"apps/\")) {\n\t\t\t\t\treturn `${dir}/**\\\\n!${dir}/package.json`;\n\t\t\t\t}\n\n\t\t\t\treturn dir;\n\t\t\t})\n\t\t\t.join(\"\\\\n\");\n\n\t\tconst writeIgnore = ignorePatterns\n\t\t\t? `printf '${ignorePatterns}\\\\n' > .railwayignore`\n\t\t\t: \"\";\n\n\t\tconst writeRailpack = args.railpackConfig\n\t\t\t? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, \"\\\\'\")}' > railpack.json`\n\t\t\t: \"\";\n\n\t\tconst setupLines = [writeIgnore, writeRailpack].filter(Boolean).join(\"; \");\n\n\t\tconst envHash = pulumi\n\t\t\t.all(\n\t\t\t\tObject.entries(args.env)\n\t\t\t\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t\t\t\t.map(([k, v]) => pulumi.output(v).apply((val) => `${k}=${val}`)),\n\t\t\t)\n\t\t\t.apply((parts) => parts.join(\",\"));\n\n\t\t// Parallel-safe upload: multiple stacks deploy concurrently, but each writes\n\t\t// .railwayignore and railpack.json to the same monorepo root before calling\n\t\t// `railway up`. The mkdir lock serializes that brief window (~5s upload phase).\n\t\t// After upload, the background job releases the lock so builds stream in parallel.\n\t\t//\n\t\t// Flow: acquire lock → write config files → release lock after 5s (background) →\n\t\t// railway up --ci (blocks through upload, then streams build logs) →\n\t\t// cleanup on exit\n\t\tconst deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & railway up --ci --project ${args.projectId} --service ${args.serviceId} --environment ${args.environmentId}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;\n\n\t\tnew command.local.Command(\n\t\t\t`${name}-deploy`,\n\t\t\t{\n\t\t\t\tcreate: deployCmd,\n\t\t\t\ttriggers: [args.sourceHash, envHash],\n\t\t\t\tdir: args.directory,\n\t\t\t\tenvironment: {\n\t\t\t\t\tRAILWAY_TOKEN: args.projectToken,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.registerOutputs({});\n\t}\n}\n"],"mappings":";;;;;AA4CA,MAAM,WAAW;;;;;;;;;AAUjB,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,2BAA2B,MAAM,CAAC,GAAG,IAAI;EAE/C,MAAM,kBAAkB,KAAK,gBAAgB,CAAC,GAC5C,KAAK,QAAQ;GACb,IAAI,IAAI,WAAW,OAAO,GACzB,OAAO,GAAG,IAAI,SAAS,IAAI;GAG5B,OAAO;EACR,CAAC,EACA,KAAK,KAAK;EAUZ,MAAM,aAAa,CARC,iBACjB,WAAW,eAAe,yBAC1B,IAEmB,KAAK,iBACxB,WAAW,KAAK,UAAU,KAAK,cAAc,EAAE,QAAQ,MAAM,KAAK,EAAE,qBACpE,EAE2C,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;EAEzE,MAAM,UAAU,OACd,IACA,OAAO,QAAQ,KAAK,GAAG,EACrB,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EACrC,KAAK,CAAC,GAAG,OAAO,OAAO,OAAO,CAAC,EAAE,OAAO,QAAQ,GAAG,EAAE,GAAG,KAAK,CAAC,CACjE,EACC,OAAO,UAAU,MAAM,KAAK,GAAG,CAAC;EAUlC,MAAM,YAAY,OAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,8CAA8C,KAAK,UAAU,aAAa,KAAK,UAAU,iBAAiB,KAAK,cAAc,uDAAuD,SAAS;EAE1W,IAAI,QAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,CAAC,KAAK,YAAY,OAAO;GACnC,KAAK,KAAK;GACV,aAAa,EACZ,eAAe,KAAK,aACrB;EACD,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}