@infracraft/pulumi 0.1.0 → 0.1.3

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.

@@ -125,7 +125,7 @@ var NeonRole = class extends _pulumi_pulumi.dynamic.Resource {
125
125
  constructor(name, args, opts) {
126
126
  super(new NeonRoleProvider(), name, {
127
127
  ...args,
128
- password: void 0
128
+ password: _pulumi_pulumi.secret(void 0)
129
129
  }, opts);
130
130
  }
131
131
  };
@@ -1 +1 @@
1
- {"version":3,"file":"role.cjs","names":["NeonClient","pulumi"],"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,IAAIA,+BAAW,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,eAAO,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,IAHkBA,+BAAW,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,IAAIA,+BAAW,MAAM,MAAM;EAE1C,IAAI;GACH,MAAM,OAAO,OACZ,aAAa,MAAM,UAAU,YAAY,MAAM,SAAS,SAAS,MAAM,MACxE;EACD,QAAQ;GACP,eAAO,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,cAA8BC,eAAO,QAAQ,SAAS;;;;;;CASrD,YACC,MACA,MAaA,MACC;EACD,MAAM,IAAI,iBAAiB,GAAG,MAAM;GAAE,GAAG;GAAM,UAAU;EAAU,GAAG,IAAI;CAC3E;AACD"}
1
+ {"version":3,"file":"role.cjs","names":["NeonClient","pulumi"],"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: pulumi.secret(undefined as unknown as string) }, 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,IAAIA,+BAAW,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,eAAO,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,IAHkBA,+BAAW,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,IAAIA,+BAAW,MAAM,MAAM;EAE1C,IAAI;GACH,MAAM,OAAO,OACZ,aAAa,MAAM,UAAU,YAAY,MAAM,SAAS,SAAS,MAAM,MACxE;EACD,QAAQ;GACP,eAAO,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,cAA8BC,eAAO,QAAQ,SAAS;;;;;;CASrD,YACC,MACA,MAaA,MACC;EACD,MAAM,IAAI,iBAAiB,GAAG,MAAM;GAAE,GAAG;GAAM,UAAUA,eAAO,OAAO,MAA8B;EAAE,GAAG,IAAI;CAC/G;AACD"}
@@ -123,7 +123,7 @@ var NeonRole = class extends pulumi.dynamic.Resource {
123
123
  constructor(name, args, opts) {
124
124
  super(new NeonRoleProvider(), name, {
125
125
  ...args,
126
- password: void 0
126
+ password: pulumi.secret(void 0)
127
127
  }, opts);
128
128
  }
129
129
  };
@@ -1 +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"}
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: pulumi.secret(undefined as unknown as string) }, 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,OAAO,OAAO,MAA8B;EAAE,GAAG,IAAI;CAC/G;AACD"}
@@ -46,7 +46,10 @@ var RailwayClient = class {
46
46
  variables
47
47
  })
48
48
  });
49
- if (!response.ok) throw new Error(`Railway API HTTP error: ${response.status} ${response.statusText}`);
49
+ if (!response.ok) {
50
+ const body = await response.text();
51
+ throw new Error(`Railway API HTTP error: ${response.status} ${response.statusText}\n${body}`);
52
+ }
50
53
  const json = await response.json();
51
54
  if (json.errors && json.errors.length > 0) throw new Error(`Railway API error: ${json.errors[0].message}`);
52
55
  if (!json.data) throw new Error("Railway API returned no data");
@@ -1 +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"}
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\tconst body = await response.text();\n\n\t\t\tthrow new Error(\n\t\t\t\t`Railway API HTTP error: ${response.status} ${response.statusText}\\n${body}`,\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,IAAI;GACjB,MAAM,OAAO,MAAM,SAAS,KAAK;GAEjC,MAAM,IAAI,MACT,2BAA2B,SAAS,OAAO,GAAG,SAAS,WAAW,IAAI,MACvE;EACD;EAEA,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"}
@@ -45,7 +45,10 @@ var RailwayClient = class {
45
45
  variables
46
46
  })
47
47
  });
48
- if (!response.ok) throw new Error(`Railway API HTTP error: ${response.status} ${response.statusText}`);
48
+ if (!response.ok) {
49
+ const body = await response.text();
50
+ throw new Error(`Railway API HTTP error: ${response.status} ${response.statusText}\n${body}`);
51
+ }
49
52
  const json = await response.json();
50
53
  if (json.errors && json.errors.length > 0) throw new Error(`Railway API error: ${json.errors[0].message}`);
51
54
  if (!json.data) throw new Error("Railway API returned no data");
@@ -1 +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"}
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\tconst body = await response.text();\n\n\t\t\tthrow new Error(\n\t\t\t\t`Railway API HTTP error: ${response.status} ${response.statusText}\\n${body}`,\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,IAAI;GACjB,MAAM,OAAO,MAAM,SAAS,KAAK;GAEjC,MAAM,IAAI,MACT,2BAA2B,SAAS,OAAO,GAAG,SAAS,WAAW,IAAI,MACvE;EACD;EAEA,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"}
@@ -1 +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"}
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: pulumi.Input<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: pulumi.Input<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"}
@@ -15,11 +15,11 @@ interface RailwayDeployArgs {
15
15
  /** Project-scoped Railway token for `railway up` CLI (stable across runs). */
16
16
  projectToken: pulumi.Input<string>;
17
17
  /** Railway project UUID. */
18
- projectId: string;
18
+ projectId: pulumi.Input<string>;
19
19
  /** Railway service UUID to deploy to. */
20
20
  serviceId: pulumi.Input<string>;
21
21
  /** Railway environment UUID (e.g. production). */
22
- environmentId: string;
22
+ environmentId: pulumi.Input<string>;
23
23
  /** Absolute path to the monorepo root (working directory for `railway up`). */
24
24
  directory: string;
25
25
  /** SHA-256 hash of the app source directory, used as a deploy trigger. */
@@ -1 +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"}
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,EAAW,MAAA,CAAO,KAAA;;EAGlB,SAAA,EAAW,MAAA,CAAO,KAAA;EAHP;EAMX,aAAA,EAAe,MAAA,CAAO,KAAA;EAAP;EAGf,SAAA;EAMK;EAHL,UAAA;EASuB;EANvB,GAAA,EAAK,MAAA,SAAe,MAAA,CAAO,KAAA;EAlB3B;EAqBA,YAAA;EArBqB;EAwBrB,cAAA,GAAiB,MAAA;AAAA;;;;;;;;;cAaL,aAAA,SAAsB,MAAA,CAAO,iBAAA;cAExC,IAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA"}
@@ -15,11 +15,11 @@ interface RailwayDeployArgs {
15
15
  /** Project-scoped Railway token for `railway up` CLI (stable across runs). */
16
16
  projectToken: pulumi.Input<string>;
17
17
  /** Railway project UUID. */
18
- projectId: string;
18
+ projectId: pulumi.Input<string>;
19
19
  /** Railway service UUID to deploy to. */
20
20
  serviceId: pulumi.Input<string>;
21
21
  /** Railway environment UUID (e.g. production). */
22
- environmentId: string;
22
+ environmentId: pulumi.Input<string>;
23
23
  /** Absolute path to the monorepo root (working directory for `railway up`). */
24
24
  directory: string;
25
25
  /** SHA-256 hash of the app source directory, used as a deploy trigger. */
@@ -1 +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"}
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,EAAW,MAAA,CAAO,KAAA;;EAGlB,SAAA,EAAW,MAAA,CAAO,KAAA;EAHP;EAMX,aAAA,EAAe,MAAA,CAAO,KAAA;EAAP;EAGf,SAAA;EAMK;EAHL,UAAA;EASuB;EANvB,GAAA,EAAK,MAAA,SAAe,MAAA,CAAO,KAAA;EAlB3B;EAqBA,YAAA;EArBqB;EAwBrB,cAAA,GAAiB,MAAA;AAAA;;;;;;;;;cAaL,aAAA,SAAsB,MAAA,CAAO,iBAAA;cAExC,IAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,GAAO,MAAA,CAAO,wBAAA;AAAA"}
@@ -1 +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"}
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: pulumi.Input<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: pulumi.Input<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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infracraft/pulumi",
3
- "version": "0.1.0",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {