@infracraft/pulumi 1.5.2 → 1.6.1

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.
Files changed (73) hide show
  1. package/dist/neon/branch.cjs +27 -6
  2. package/dist/neon/branch.cjs.map +1 -1
  3. package/dist/neon/branch.d.cts +35 -2
  4. package/dist/neon/branch.d.cts.map +1 -1
  5. package/dist/neon/branch.d.mts +35 -2
  6. package/dist/neon/branch.d.mts.map +1 -1
  7. package/dist/neon/branch.mjs +27 -7
  8. package/dist/neon/branch.mjs.map +1 -1
  9. package/dist/railway/deploy.cjs +4 -5
  10. package/dist/railway/deploy.cjs.map +1 -1
  11. package/dist/railway/deploy.d.cts +4 -4
  12. package/dist/railway/deploy.d.cts.map +1 -1
  13. package/dist/railway/deploy.d.mts +4 -4
  14. package/dist/railway/deploy.d.mts.map +1 -1
  15. package/dist/railway/deploy.mjs +4 -5
  16. package/dist/railway/deploy.mjs.map +1 -1
  17. package/dist/railway/environment.cjs +58 -11
  18. package/dist/railway/environment.cjs.map +1 -1
  19. package/dist/railway/environment.d.cts +57 -4
  20. package/dist/railway/environment.d.cts.map +1 -1
  21. package/dist/railway/environment.d.mts +57 -4
  22. package/dist/railway/environment.d.mts.map +1 -1
  23. package/dist/railway/environment.mjs +58 -12
  24. package/dist/railway/environment.mjs.map +1 -1
  25. package/dist/railway/index.cjs +2 -0
  26. package/dist/railway/index.d.cts +2 -1
  27. package/dist/railway/index.d.mts +2 -1
  28. package/dist/railway/index.mjs +2 -1
  29. package/dist/railway/project-token.cjs +153 -0
  30. package/dist/railway/project-token.cjs.map +1 -0
  31. package/dist/railway/project-token.d.cts +115 -0
  32. package/dist/railway/project-token.d.cts.map +1 -0
  33. package/dist/railway/project-token.d.mts +115 -0
  34. package/dist/railway/project-token.d.mts.map +1 -0
  35. package/dist/railway/project-token.mjs +150 -0
  36. package/dist/railway/project-token.mjs.map +1 -0
  37. package/dist/railway/project.cjs +7 -48
  38. package/dist/railway/project.cjs.map +1 -1
  39. package/dist/railway/project.d.cts +3 -4
  40. package/dist/railway/project.d.cts.map +1 -1
  41. package/dist/railway/project.d.mts +3 -4
  42. package/dist/railway/project.d.mts.map +1 -1
  43. package/dist/railway/project.mjs +7 -48
  44. package/dist/railway/project.mjs.map +1 -1
  45. package/dist/vercel/index.cjs +6 -0
  46. package/dist/vercel/index.d.cts +4 -1
  47. package/dist/vercel/index.d.mts +4 -1
  48. package/dist/vercel/index.mjs +4 -1
  49. package/dist/vercel/integration.cjs +94 -0
  50. package/dist/vercel/integration.cjs.map +1 -0
  51. package/dist/vercel/integration.d.cts +72 -0
  52. package/dist/vercel/integration.d.cts.map +1 -0
  53. package/dist/vercel/integration.d.mts +72 -0
  54. package/dist/vercel/integration.d.mts.map +1 -0
  55. package/dist/vercel/integration.mjs +91 -0
  56. package/dist/vercel/integration.mjs.map +1 -0
  57. package/dist/vercel/marketplace-resource.cjs +126 -0
  58. package/dist/vercel/marketplace-resource.cjs.map +1 -0
  59. package/dist/vercel/marketplace-resource.d.cts +114 -0
  60. package/dist/vercel/marketplace-resource.d.cts.map +1 -0
  61. package/dist/vercel/marketplace-resource.d.mts +114 -0
  62. package/dist/vercel/marketplace-resource.d.mts.map +1 -0
  63. package/dist/vercel/marketplace-resource.mjs +123 -0
  64. package/dist/vercel/marketplace-resource.mjs.map +1 -0
  65. package/dist/vercel/resource-connection.cjs +107 -0
  66. package/dist/vercel/resource-connection.cjs.map +1 -0
  67. package/dist/vercel/resource-connection.d.cts +93 -0
  68. package/dist/vercel/resource-connection.d.cts.map +1 -0
  69. package/dist/vercel/resource-connection.d.mts +93 -0
  70. package/dist/vercel/resource-connection.d.mts.map +1 -0
  71. package/dist/vercel/resource-connection.mjs +104 -0
  72. package/dist/vercel/resource-connection.mjs.map +1 -0
  73. package/package.json +1 -1
@@ -15,17 +15,28 @@ async function findBranchByName(client, projectId, name) {
15
15
  * Dynamic provider implementing CRUD for Neon branches.
16
16
  *
17
17
  * Uses adopt-or-create on `create()`: finds an existing branch by name
18
- * before creating a new one.
18
+ * before creating a new one. When `parentName` is supplied, resolves it
19
+ * to a `parent_id` and includes it in the POST body.
19
20
  */
21
+ /** @internal Exported only for unit testing; not part of the public API surface. */
20
22
  var NeonBranchResourceProvider = class {
21
23
  async create(inputs) {
22
24
  const client = new require_neon_client.NeonClient(inputs.apiKey);
23
25
  let branchId = await findBranchByName(client, inputs.projectId, inputs.name);
24
- if (branchId) _pulumi_pulumi.log.info(`Adopting existing Neon branch "${inputs.name}" (${branchId})`);
25
- else branchId = (await client.post(`/projects/${inputs.projectId}/branches`, { branch: { name: inputs.name } })).branch.id;
26
+ if (branchId) if (inputs.parentName) _pulumi_pulumi.log.warn(`Adopting existing Neon branch "${inputs.name}" — parentName "${inputs.parentName}" is ignored for adopted branches (existing lineage preserved).`);
27
+ else _pulumi_pulumi.log.info(`Adopting existing Neon branch "${inputs.name}" (${branchId})`);
28
+ else {
29
+ const body = { branch: { name: inputs.name } };
30
+ if (inputs.parentName) {
31
+ const parentId = await findBranchByName(client, inputs.projectId, inputs.parentName);
32
+ if (!parentId) throw new Error(`Neon parent branch "${inputs.parentName}" not found in project ${inputs.projectId}`);
33
+ body.branch.parent_id = parentId;
34
+ }
35
+ branchId = (await client.post(`/projects/${inputs.projectId}/branches`, body)).branch.id;
36
+ }
26
37
  return {
27
38
  id: branchId,
28
- outs: inputs
39
+ outs: { ...inputs }
29
40
  };
30
41
  }
31
42
  async read(id, props) {
@@ -49,6 +60,7 @@ var NeonBranchResourceProvider = class {
49
60
  async diff(_id, olds, news) {
50
61
  const replaces = [];
51
62
  if (olds.projectId !== news.projectId) replaces.push("projectId");
63
+ if (olds.parentName !== news.parentName) replaces.push("parentName");
52
64
  return {
53
65
  changes: replaces.length > 0 || olds.name !== news.name,
54
66
  replaces,
@@ -67,9 +79,16 @@ var NeonBranchResource = class extends _pulumi_pulumi.dynamic.Resource {
67
79
  *
68
80
  * @example
69
81
  * ```typescript
70
- * const branch = new NeonBranch("production", {
82
+ * // Root branch (Neon default parent)
83
+ * const production = new NeonBranch("production", {
71
84
  * name: "production",
72
85
  * }, { provider, project });
86
+ *
87
+ * // Copy-on-write branch from production
88
+ * const staging = new NeonBranch("staging", {
89
+ * name: "staging",
90
+ * parent: "production",
91
+ * }, { provider, project });
73
92
  * ```
74
93
  */
75
94
  var NeonBranch = class extends _pulumi_pulumi.ComponentResource {
@@ -79,7 +98,8 @@ var NeonBranch = class extends _pulumi_pulumi.ComponentResource {
79
98
  const resource = new NeonBranchResource(`${name}-resource`, {
80
99
  apiKey: provider.apiKey,
81
100
  projectId: project.id,
82
- name: args.name
101
+ name: args.name,
102
+ parentName: args.parent
83
103
  }, { parent: this });
84
104
  this.id = resource.id;
85
105
  this.registerOutputs({ id: this.id });
@@ -88,4 +108,5 @@ var NeonBranch = class extends _pulumi_pulumi.ComponentResource {
88
108
 
89
109
  //#endregion
90
110
  exports.NeonBranch = NeonBranch;
111
+ exports.NeonBranchResourceProvider = NeonBranchResourceProvider;
91
112
  //# sourceMappingURL=branch.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch.cjs","names":["NeonClient","pulumi"],"sources":["../../src/neon/branch.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { NeonClient } from \"./client\";\nimport type { NeonProject } from \"./project\";\nimport type { NeonProvider } from \"./provider\";\n\n/** Resolved inputs for the Neon branch dynamic provider. */\nexport interface NeonBranchInputs {\n\t/** Neon API key. */\n\tapiKey: string;\n\n\t/** Neon project ID (e.g. `\"quiet-forest-69719462\"`). */\n\tprojectId: string;\n\n\t/** Branch display name (e.g. `\"production\"`, `\"development\"`). */\n\tname: string;\n}\n\n/** Persisted state for the Neon branch. */\ninterface NeonBranchOutputs extends NeonBranchInputs {}\n\n/** Neon API response for a branch. */\ninterface BranchResponse {\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tproject_id: string;\n\t};\n}\n\n/** Neon API response for branch creation. */\ninterface BranchCreateResponse {\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tproject_id: string;\n\t};\n}\n\n/** Neon API response for listing branches. */\ninterface BranchListResponse {\n\tbranches: Array<{\n\t\tid: string;\n\t\tname: string;\n\t}>;\n}\n\n/**\n * Finds an existing Neon branch by name within a project.\n */\nasync function findBranchByName(\n\tclient: NeonClient,\n\tprojectId: string,\n\tname: string,\n): Promise<string | undefined> {\n\tconst result = await client.get<BranchListResponse>(\n\t\t`/projects/${projectId}/branches`,\n\t);\n\n\tconst match = result.branches.find((b) => b.name === name);\n\n\treturn match?.id;\n}\n\n/**\n * Dynamic provider implementing CRUD for Neon branches.\n *\n * Uses adopt-or-create on `create()`: finds an existing branch by name\n * before creating a new one.\n */\nclass NeonBranchResourceProvider implements pulumi.dynamic.ResourceProvider {\n\tasync create(inputs: NeonBranchInputs): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new NeonClient(inputs.apiKey);\n\n\t\tlet branchId = await findBranchByName(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (branchId) {\n\t\t\tpulumi.log.info(\n\t\t\t\t`Adopting existing Neon branch \"${inputs.name}\" (${branchId})`,\n\t\t\t);\n\t\t} else {\n\t\t\tconst result = await client.post<BranchCreateResponse>(\n\t\t\t\t`/projects/${inputs.projectId}/branches`,\n\t\t\t\t{ branch: { name: inputs.name } },\n\t\t\t);\n\n\t\t\tbranchId = result.branch.id;\n\t\t}\n\n\t\treturn { id: branchId, outs: inputs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: NeonBranchOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\tconst result = await client.get<BranchResponse>(\n\t\t\t`/projects/${props.projectId}/branches/${id}`,\n\t\t);\n\n\t\treturn {\n\t\t\tid: result.branch.id,\n\t\t\tprops: { ...props, name: result.branch.name },\n\t\t};\n\t}\n\n\tasync delete(id: string, props: NeonBranchOutputs): Promise<void> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\ttry {\n\t\t\tawait client.delete(`/projects/${props.projectId}/branches/${id}`);\n\t\t} catch {\n\t\t\tpulumi.log.warn(`Failed to delete Neon branch (may already be deleted)`);\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: NeonBranchOutputs,\n\t\tnews: NeonBranchInputs,\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\treturn {\n\t\t\tchanges: replaces.length > 0 || olds.name !== news.name,\n\t\t\treplaces,\n\t\t\tdeleteBeforeReplace: true,\n\t\t};\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass NeonBranchResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly branchId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\tapiKey: pulumi.Input<string>;\n\t\t\tprojectId: pulumi.Input<string>;\n\t\t\tname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(new NeonBranchResourceProvider(), name, { ...args }, opts);\n\t}\n}\n\n/** Options type for NeonBranch — replaces Pulumi's native `provider` field. */\ntype NeonBranchOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Neon authentication context. */\n\tprovider: NeonProvider;\n\n\t/** Neon project context. */\n\tproject: NeonProject;\n};\n\n/** Args for NeonBranch. */\nexport interface NeonBranchArgs {\n\t/** Branch display name. */\n\tname: pulumi.Input<string>;\n}\n\n/**\n * Manages a Neon branch with adopt-or-create semantics.\n *\n * @example\n * ```typescript\n * const branch = new NeonBranch(\"production\", {\n * name: \"production\",\n * }, { provider, project });\n * ```\n */\nexport class NeonBranch extends pulumi.ComponentResource {\n\t/** Neon branch ID. */\n\tpublic readonly id: pulumi.Output<string>;\n\n\tconstructor(name: string, args: NeonBranchArgs, opts: NeonBranchOptions) {\n\t\tconst { provider, project, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:neon:Branch\", name, {}, pulumiOpts);\n\n\t\tconst resource = new NeonBranchResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\tapiKey: provider.apiKey,\n\t\t\t\tprojectId: project.id,\n\t\t\t\tname: args.name,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = resource.id;\n\n\t\tthis.registerOutputs({ id: this.id });\n\t}\n}\n"],"mappings":";;;;;;;;;;AAiDA,eAAe,iBACd,QACA,WACA,MAC8B;CAO9B,QAFc,MAJO,OAAO,IAC3B,aAAa,UAAU,UACxB,GAEqB,SAAS,MAAM,MAAM,EAAE,SAAS,IAE1C,GAAG;AACf;;;;;;;AAQA,IAAM,6BAAN,MAA4E;CAC3E,MAAM,OAAO,QAAgE;EAC5E,MAAM,SAAS,IAAIA,+BAAW,OAAO,MAAM;EAE3C,IAAI,WAAW,MAAM,iBACpB,QACA,OAAO,WACP,OAAO,IACR;EAEA,IAAI,UACH,eAAO,IAAI,KACV,kCAAkC,OAAO,KAAK,KAAK,SAAS,EAC7D;OAOA,YAAW,MALU,OAAO,KAC3B,aAAa,OAAO,UAAU,YAC9B,EAAE,QAAQ,EAAE,MAAM,OAAO,KAAK,EAAE,CACjC,GAEkB,OAAO;EAG1B,OAAO;GAAE,IAAI;GAAU,MAAM;EAAO;CACrC;CAEA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,SAAS,MAAM,IAFFA,+BAAW,MAAM,MAEV,EAAE,IAC3B,aAAa,MAAM,UAAU,YAAY,IAC1C;EAEA,OAAO;GACN,IAAI,OAAO,OAAO;GAClB,OAAO;IAAE,GAAG;IAAO,MAAM,OAAO,OAAO;GAAK;EAC7C;CACD;CAEA,MAAM,OAAO,IAAY,OAAyC;EACjE,MAAM,SAAS,IAAIA,+BAAW,MAAM,MAAM;EAE1C,IAAI;GACH,MAAM,OAAO,OAAO,aAAa,MAAM,UAAU,YAAY,IAAI;EAClE,QAAQ;GACP,eAAO,IAAI,KAAK,uDAAuD;EACxE;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,cAAc,KAAK,WAC3B,SAAS,KAAK,WAAW;EAG1B,OAAO;GACN,SAAS,SAAS,SAAS,KAAK,KAAK,SAAS,KAAK;GACnD;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,qBAAN,cAAiCC,eAAO,QAAQ,SAAS;CAGxD,YACC,MACA,MAKA,MACC;EACD,MAAM,IAAI,2BAA2B,GAAG,MAAM,EAAE,GAAG,KAAK,GAAG,IAAI;CAChE;AACD;;;;;;;;;;;AA2BA,IAAa,aAAb,cAAgCA,eAAO,kBAAkB;CAIxD,YAAY,MAAc,MAAsB,MAAyB;EACxE,MAAM,EAAE,UAAU,SAAS,GAAG,eAAe;EAE7C,MAAM,0BAA0B,MAAM,CAAC,GAAG,UAAU;EAEpD,MAAM,WAAW,IAAI,mBACpB,GAAG,KAAK,YACR;GACC,QAAQ,SAAS;GACjB,WAAW,QAAQ;GACnB,MAAM,KAAK;EACZ,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,KAAK,SAAS;EAEnB,KAAK,gBAAgB,EAAE,IAAI,KAAK,GAAG,CAAC;CACrC;AACD"}
1
+ {"version":3,"file":"branch.cjs","names":["NeonClient","pulumi"],"sources":["../../src/neon/branch.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { NeonClient } from \"./client\";\nimport type { NeonProject } from \"./project\";\nimport type { NeonProvider } from \"./provider\";\n\n/** Resolved inputs for the Neon branch dynamic provider. */\nexport interface NeonBranchInputs {\n\t/** Neon API key. */\n\tapiKey: string;\n\n\t/** Neon project ID (e.g. `\"quiet-forest-69719462\"`). */\n\tprojectId: string;\n\n\t/** Branch display name (e.g. `\"production\"`, `\"development\"`). */\n\tname: string;\n\n\t/**\n\t * Parent branch NAME. Resolved to `parent_id` inside `create()` via\n\t * `findBranchByName`. Omit for project-root branches.\n\t */\n\tparentName?: string;\n}\n\n/** Persisted state for the Neon branch. */\ninterface NeonBranchOutputs extends NeonBranchInputs {}\n\n/** Neon API response for a branch. */\ninterface BranchResponse {\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tproject_id: string;\n\t};\n}\n\n/** Neon API response for branch creation. */\ninterface BranchCreateResponse {\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tproject_id: string;\n\t};\n}\n\n/** Neon API response for listing branches. */\ninterface BranchListResponse {\n\tbranches: Array<{\n\t\tid: string;\n\t\tname: string;\n\t}>;\n}\n\n/**\n * Finds an existing Neon branch by name within a project.\n */\nasync function findBranchByName(\n\tclient: NeonClient,\n\tprojectId: string,\n\tname: string,\n): Promise<string | undefined> {\n\tconst result = await client.get<BranchListResponse>(\n\t\t`/projects/${projectId}/branches`,\n\t);\n\n\tconst match = result.branches.find((b) => b.name === name);\n\n\treturn match?.id;\n}\n\n/**\n * Dynamic provider implementing CRUD for Neon branches.\n *\n * Uses adopt-or-create on `create()`: finds an existing branch by name\n * before creating a new one. When `parentName` is supplied, resolves it\n * to a `parent_id` and includes it in the POST body.\n */\n/** @internal Exported only for unit testing; not part of the public API surface. */\nexport class NeonBranchResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(inputs: NeonBranchInputs): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new NeonClient(inputs.apiKey);\n\n\t\tlet branchId = await findBranchByName(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (branchId) {\n\t\t\tif (inputs.parentName) {\n\t\t\t\tpulumi.log.warn(\n\t\t\t\t\t`Adopting existing Neon branch \"${inputs.name}\" — parentName \"${inputs.parentName}\" is ignored for adopted branches (existing lineage preserved).`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpulumi.log.info(\n\t\t\t\t\t`Adopting existing Neon branch \"${inputs.name}\" (${branchId})`,\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tconst body: { branch: { name: string; parent_id?: string } } = {\n\t\t\t\tbranch: { name: inputs.name },\n\t\t\t};\n\n\t\t\tif (inputs.parentName) {\n\t\t\t\tconst parentId = await findBranchByName(\n\t\t\t\t\tclient,\n\t\t\t\t\tinputs.projectId,\n\t\t\t\t\tinputs.parentName,\n\t\t\t\t);\n\n\t\t\t\tif (!parentId) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Neon parent branch \"${inputs.parentName}\" not found in project ${inputs.projectId}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tbody.branch.parent_id = parentId;\n\t\t\t}\n\n\t\t\tconst result = await client.post<BranchCreateResponse>(\n\t\t\t\t`/projects/${inputs.projectId}/branches`,\n\t\t\t\tbody,\n\t\t\t);\n\n\t\t\tbranchId = result.branch.id;\n\t\t}\n\n\t\treturn { id: branchId, outs: { ...inputs } };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: NeonBranchOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\tconst result = await client.get<BranchResponse>(\n\t\t\t`/projects/${props.projectId}/branches/${id}`,\n\t\t);\n\n\t\t// parentName is preserved from prior state (props): the Neon API does not expose\n\t\t// a branch's parent on GET /branches/:id, so it cannot be re-derived here.\n\t\treturn {\n\t\t\tid: result.branch.id,\n\t\t\tprops: { ...props, name: result.branch.name },\n\t\t};\n\t}\n\n\tasync delete(id: string, props: NeonBranchOutputs): Promise<void> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\ttry {\n\t\t\tawait client.delete(`/projects/${props.projectId}/branches/${id}`);\n\t\t} catch {\n\t\t\tpulumi.log.warn(`Failed to delete Neon branch (may already be deleted)`);\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: NeonBranchOutputs,\n\t\tnews: NeonBranchInputs,\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.parentName !== news.parentName) {\n\t\t\treplaces.push(\"parentName\");\n\t\t}\n\n\t\treturn {\n\t\t\tchanges: replaces.length > 0 || olds.name !== news.name,\n\t\t\treplaces,\n\t\t\tdeleteBeforeReplace: true,\n\t\t};\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass NeonBranchResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly branchId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\tapiKey: pulumi.Input<string>;\n\t\t\tprojectId: pulumi.Input<string>;\n\t\t\tname: pulumi.Input<string>;\n\t\t\t/** Name of the parent branch; omit for project-root branches. */\n\t\t\tparentName?: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(new NeonBranchResourceProvider(), name, { ...args }, opts);\n\t}\n}\n\n/** Options type for NeonBranch — replaces Pulumi's native `provider` field. */\ntype NeonBranchOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Neon authentication context. */\n\tprovider: NeonProvider;\n\n\t/** Neon project context. */\n\tproject: NeonProject;\n};\n\n/** Args for NeonBranch. */\nexport interface NeonBranchArgs {\n\t/** Branch display name. */\n\tname: pulumi.Input<string>;\n\n\t/**\n\t * Name of the parent branch to branch from (copy-on-write). Omit to\n\t * branch from the project root (Neon default branch).\n\t */\n\tparent?: pulumi.Input<string>;\n}\n\n/**\n * Manages a Neon branch with adopt-or-create semantics.\n *\n * @example\n * ```typescript\n * // Root branch (Neon default parent)\n * const production = new NeonBranch(\"production\", {\n * name: \"production\",\n * }, { provider, project });\n *\n * // Copy-on-write branch from production\n * const staging = new NeonBranch(\"staging\", {\n * name: \"staging\",\n * parent: \"production\",\n * }, { provider, project });\n * ```\n */\nexport class NeonBranch extends pulumi.ComponentResource {\n\t/** Neon branch ID. */\n\tpublic readonly id: pulumi.Output<string>;\n\n\tconstructor(name: string, args: NeonBranchArgs, opts: NeonBranchOptions) {\n\t\tconst { provider, project, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:neon:Branch\", name, {}, pulumiOpts);\n\n\t\tconst resource = new NeonBranchResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\tapiKey: provider.apiKey,\n\t\t\t\tprojectId: project.id,\n\t\t\t\tname: args.name,\n\t\t\t\tparentName: args.parent,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = resource.id;\n\n\t\tthis.registerOutputs({ id: this.id });\n\t}\n}\n"],"mappings":";;;;;;;;;;AAuDA,eAAe,iBACd,QACA,WACA,MAC8B;CAO9B,QAFc,MAJO,OAAO,IAC3B,aAAa,UAAU,UACxB,GAEqB,SAAS,MAAM,MAAM,EAAE,SAAS,IAE1C,GAAG;AACf;;;;;;;;;AAUA,IAAa,6BAAb,MAEA;CACC,MAAM,OAAO,QAAgE;EAC5E,MAAM,SAAS,IAAIA,+BAAW,OAAO,MAAM;EAE3C,IAAI,WAAW,MAAM,iBACpB,QACA,OAAO,WACP,OAAO,IACR;EAEA,IAAI,UACH,IAAI,OAAO,YACV,eAAO,IAAI,KACV,kCAAkC,OAAO,KAAK,kBAAkB,OAAO,WAAW,gEACnF;OAEA,eAAO,IAAI,KACV,kCAAkC,OAAO,KAAK,KAAK,SAAS,EAC7D;OAEK;GACN,MAAM,OAAyD,EAC9D,QAAQ,EAAE,MAAM,OAAO,KAAK,EAC7B;GAEA,IAAI,OAAO,YAAY;IACtB,MAAM,WAAW,MAAM,iBACtB,QACA,OAAO,WACP,OAAO,UACR;IAEA,IAAI,CAAC,UACJ,MAAM,IAAI,MACT,uBAAuB,OAAO,WAAW,yBAAyB,OAAO,WAC1E;IAGD,KAAK,OAAO,YAAY;GACzB;GAOA,YAAW,MALU,OAAO,KAC3B,aAAa,OAAO,UAAU,YAC9B,IACD,GAEkB,OAAO;EAC1B;EAEA,OAAO;GAAE,IAAI;GAAU,MAAM,EAAE,GAAG,OAAO;EAAE;CAC5C;CAEA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,SAAS,MAAM,IAFFA,+BAAW,MAAM,MAEV,EAAE,IAC3B,aAAa,MAAM,UAAU,YAAY,IAC1C;EAIA,OAAO;GACN,IAAI,OAAO,OAAO;GAClB,OAAO;IAAE,GAAG;IAAO,MAAM,OAAO,OAAO;GAAK;EAC7C;CACD;CAEA,MAAM,OAAO,IAAY,OAAyC;EACjE,MAAM,SAAS,IAAIA,+BAAW,MAAM,MAAM;EAE1C,IAAI;GACH,MAAM,OAAO,OAAO,aAAa,MAAM,UAAU,YAAY,IAAI;EAClE,QAAQ;GACP,eAAO,IAAI,KAAK,uDAAuD;EACxE;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,cAAc,KAAK,WAC3B,SAAS,KAAK,WAAW;EAG1B,IAAI,KAAK,eAAe,KAAK,YAC5B,SAAS,KAAK,YAAY;EAG3B,OAAO;GACN,SAAS,SAAS,SAAS,KAAK,KAAK,SAAS,KAAK;GACnD;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,qBAAN,cAAiCC,eAAO,QAAQ,SAAS;CAGxD,YACC,MACA,MAOA,MACC;EACD,MAAM,IAAI,2BAA2B,GAAG,MAAM,EAAE,GAAG,KAAK,GAAG,IAAI;CAChE;AACD;;;;;;;;;;;;;;;;;;AAwCA,IAAa,aAAb,cAAgCA,eAAO,kBAAkB;CAIxD,YAAY,MAAc,MAAsB,MAAyB;EACxE,MAAM,EAAE,UAAU,SAAS,GAAG,eAAe;EAE7C,MAAM,0BAA0B,MAAM,CAAC,GAAG,UAAU;EAEpD,MAAM,WAAW,IAAI,mBACpB,GAAG,KAAK,YACR;GACC,QAAQ,SAAS;GACjB,WAAW,QAAQ;GACnB,MAAM,KAAK;GACX,YAAY,KAAK;EAClB,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,KAAK,SAAS;EAEnB,KAAK,gBAAgB,EAAE,IAAI,KAAK,GAAG,CAAC;CACrC;AACD"}
@@ -12,6 +12,27 @@ interface NeonBranchInputs {
12
12
  projectId: string;
13
13
  /** Branch display name (e.g. `"production"`, `"development"`). */
14
14
  name: string;
15
+ /**
16
+ * Parent branch NAME. Resolved to `parent_id` inside `create()` via
17
+ * `findBranchByName`. Omit for project-root branches.
18
+ */
19
+ parentName?: string;
20
+ }
21
+ /** Persisted state for the Neon branch. */
22
+ interface NeonBranchOutputs extends NeonBranchInputs {}
23
+ /**
24
+ * Dynamic provider implementing CRUD for Neon branches.
25
+ *
26
+ * Uses adopt-or-create on `create()`: finds an existing branch by name
27
+ * before creating a new one. When `parentName` is supplied, resolves it
28
+ * to a `parent_id` and includes it in the POST body.
29
+ */
30
+ /** @internal Exported only for unit testing; not part of the public API surface. */
31
+ declare class NeonBranchResourceProvider implements pulumi.dynamic.ResourceProvider {
32
+ create(inputs: NeonBranchInputs): Promise<pulumi.dynamic.CreateResult>;
33
+ read(id: string, props: NeonBranchOutputs): Promise<pulumi.dynamic.ReadResult>;
34
+ delete(id: string, props: NeonBranchOutputs): Promise<void>;
35
+ diff(_id: string, olds: NeonBranchOutputs, news: NeonBranchInputs): Promise<pulumi.dynamic.DiffResult>;
15
36
  }
16
37
  /** Options type for NeonBranch — replaces Pulumi's native `provider` field. */
17
38
  type NeonBranchOptions = Omit<pulumi.ComponentResourceOptions, "provider"> & {
@@ -22,15 +43,27 @@ type NeonBranchOptions = Omit<pulumi.ComponentResourceOptions, "provider"> & {
22
43
  interface NeonBranchArgs {
23
44
  /** Branch display name. */
24
45
  name: pulumi.Input<string>;
46
+ /**
47
+ * Name of the parent branch to branch from (copy-on-write). Omit to
48
+ * branch from the project root (Neon default branch).
49
+ */
50
+ parent?: pulumi.Input<string>;
25
51
  }
26
52
  /**
27
53
  * Manages a Neon branch with adopt-or-create semantics.
28
54
  *
29
55
  * @example
30
56
  * ```typescript
31
- * const branch = new NeonBranch("production", {
57
+ * // Root branch (Neon default parent)
58
+ * const production = new NeonBranch("production", {
32
59
  * name: "production",
33
60
  * }, { provider, project });
61
+ *
62
+ * // Copy-on-write branch from production
63
+ * const staging = new NeonBranch("staging", {
64
+ * name: "staging",
65
+ * parent: "production",
66
+ * }, { provider, project });
34
67
  * ```
35
68
  */
36
69
  declare class NeonBranch extends pulumi.ComponentResource {
@@ -39,5 +72,5 @@ declare class NeonBranch extends pulumi.ComponentResource {
39
72
  constructor(name: string, args: NeonBranchArgs, opts: NeonBranchOptions);
40
73
  }
41
74
  //#endregion
42
- export { NeonBranch, NeonBranchArgs, NeonBranchInputs };
75
+ export { NeonBranch, NeonBranchArgs, NeonBranchInputs, NeonBranchResourceProvider };
43
76
  //# sourceMappingURL=branch.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch.d.cts","names":[],"sources":["../../src/neon/branch.ts"],"mappings":";;;;;;;UAMiB,gBAAA;;EAEhB,MAAA;EAFgC;EAKhC,SAAA;EALgC;EAQhC,IAAA;AAAA;;KAgJI,iBAAA,GAAoB,IAAA,CAAK,MAAA,CAAO,wBAAA;EAhJhC,mCAkJJ,QAAA,EAAU,YAAA,EAFW;EAKrB,OAAA,EAAS,WAAA;AAAA;;UAIO,cAAA;EAJP;EAMT,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;AANE;AAIrB;cAea,UAAA,SAAmB,MAAA,CAAO,iBAAA;;WAEtB,EAAA,EAAI,MAAA,CAAO,MAAA;cAEf,IAAA,UAAc,IAAA,EAAM,cAAA,EAAgB,IAAA,EAAM,iBAAA;AAAA"}
1
+ {"version":3,"file":"branch.d.cts","names":[],"sources":["../../src/neon/branch.ts"],"mappings":";;;;;;;UAMiB,gBAAA;;EAEhB,MAAA;EAFgC;EAKhC,SAAA;EALgC;EAQhC,IAAA;EAHA;;;;EASA,UAAA;AAAA;;UAIS,iBAAA,SAA0B,gBAAgB;AAAA;AAqDpD;;;;;;;cAAa,0BAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CAAO,MAAA,EAAQ,gBAAA,GAAmB,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAmDzD,IAAA,CACL,EAAA,UACA,KAAA,EAAO,iBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAepB,MAAA,CAAO,EAAA,UAAY,KAAA,EAAO,iBAAA,GAAoB,OAAA;EAU9C,IAAA,CACL,GAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,EAAM,gBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KAuCtB,iBAAA,GAAoB,IAAA,CAAK,MAAA,CAAO,wBAAA;EA5HzB,mCA8HX,QAAA,EAAU,YAAA,EA9HgC;EAiI1C,OAAA,EAAS,WAAA;AAAA;;UAIO,cAAA;EAnIK;EAqIrB,IAAA,EAAM,MAAA,CAAO,KAAA;EArI2B;;;;EA2IxC,MAAA,GAAS,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;;;;;;;cAoBT,UAAA,SAAmB,MAAA,CAAO,iBAAA;EA5E3B;EAAA,SA8EK,EAAA,EAAI,MAAA,CAAO,MAAA;cAEf,IAAA,UAAc,IAAA,EAAM,cAAA,EAAgB,IAAA,EAAM,iBAAA;AAAA"}
@@ -12,6 +12,27 @@ interface NeonBranchInputs {
12
12
  projectId: string;
13
13
  /** Branch display name (e.g. `"production"`, `"development"`). */
14
14
  name: string;
15
+ /**
16
+ * Parent branch NAME. Resolved to `parent_id` inside `create()` via
17
+ * `findBranchByName`. Omit for project-root branches.
18
+ */
19
+ parentName?: string;
20
+ }
21
+ /** Persisted state for the Neon branch. */
22
+ interface NeonBranchOutputs extends NeonBranchInputs {}
23
+ /**
24
+ * Dynamic provider implementing CRUD for Neon branches.
25
+ *
26
+ * Uses adopt-or-create on `create()`: finds an existing branch by name
27
+ * before creating a new one. When `parentName` is supplied, resolves it
28
+ * to a `parent_id` and includes it in the POST body.
29
+ */
30
+ /** @internal Exported only for unit testing; not part of the public API surface. */
31
+ declare class NeonBranchResourceProvider implements pulumi.dynamic.ResourceProvider {
32
+ create(inputs: NeonBranchInputs): Promise<pulumi.dynamic.CreateResult>;
33
+ read(id: string, props: NeonBranchOutputs): Promise<pulumi.dynamic.ReadResult>;
34
+ delete(id: string, props: NeonBranchOutputs): Promise<void>;
35
+ diff(_id: string, olds: NeonBranchOutputs, news: NeonBranchInputs): Promise<pulumi.dynamic.DiffResult>;
15
36
  }
16
37
  /** Options type for NeonBranch — replaces Pulumi's native `provider` field. */
17
38
  type NeonBranchOptions = Omit<pulumi.ComponentResourceOptions, "provider"> & {
@@ -22,15 +43,27 @@ type NeonBranchOptions = Omit<pulumi.ComponentResourceOptions, "provider"> & {
22
43
  interface NeonBranchArgs {
23
44
  /** Branch display name. */
24
45
  name: pulumi.Input<string>;
46
+ /**
47
+ * Name of the parent branch to branch from (copy-on-write). Omit to
48
+ * branch from the project root (Neon default branch).
49
+ */
50
+ parent?: pulumi.Input<string>;
25
51
  }
26
52
  /**
27
53
  * Manages a Neon branch with adopt-or-create semantics.
28
54
  *
29
55
  * @example
30
56
  * ```typescript
31
- * const branch = new NeonBranch("production", {
57
+ * // Root branch (Neon default parent)
58
+ * const production = new NeonBranch("production", {
32
59
  * name: "production",
33
60
  * }, { provider, project });
61
+ *
62
+ * // Copy-on-write branch from production
63
+ * const staging = new NeonBranch("staging", {
64
+ * name: "staging",
65
+ * parent: "production",
66
+ * }, { provider, project });
34
67
  * ```
35
68
  */
36
69
  declare class NeonBranch extends pulumi.ComponentResource {
@@ -39,5 +72,5 @@ declare class NeonBranch extends pulumi.ComponentResource {
39
72
  constructor(name: string, args: NeonBranchArgs, opts: NeonBranchOptions);
40
73
  }
41
74
  //#endregion
42
- export { NeonBranch, NeonBranchArgs, NeonBranchInputs };
75
+ export { NeonBranch, NeonBranchArgs, NeonBranchInputs, NeonBranchResourceProvider };
43
76
  //# sourceMappingURL=branch.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch.d.mts","names":[],"sources":["../../src/neon/branch.ts"],"mappings":";;;;;;;UAMiB,gBAAA;;EAEhB,MAAA;EAFgC;EAKhC,SAAA;EALgC;EAQhC,IAAA;AAAA;;KAgJI,iBAAA,GAAoB,IAAA,CAAK,MAAA,CAAO,wBAAA;EAhJhC,mCAkJJ,QAAA,EAAU,YAAA,EAFW;EAKrB,OAAA,EAAS,WAAA;AAAA;;UAIO,cAAA;EAJP;EAMT,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;AANE;AAIrB;cAea,UAAA,SAAmB,MAAA,CAAO,iBAAA;;WAEtB,EAAA,EAAI,MAAA,CAAO,MAAA;cAEf,IAAA,UAAc,IAAA,EAAM,cAAA,EAAgB,IAAA,EAAM,iBAAA;AAAA"}
1
+ {"version":3,"file":"branch.d.mts","names":[],"sources":["../../src/neon/branch.ts"],"mappings":";;;;;;;UAMiB,gBAAA;;EAEhB,MAAA;EAFgC;EAKhC,SAAA;EALgC;EAQhC,IAAA;EAHA;;;;EASA,UAAA;AAAA;;UAIS,iBAAA,SAA0B,gBAAgB;AAAA;AAqDpD;;;;;;;cAAa,0BAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CAAO,MAAA,EAAQ,gBAAA,GAAmB,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAmDzD,IAAA,CACL,EAAA,UACA,KAAA,EAAO,iBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAepB,MAAA,CAAO,EAAA,UAAY,KAAA,EAAO,iBAAA,GAAoB,OAAA;EAU9C,IAAA,CACL,GAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,EAAM,gBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KAuCtB,iBAAA,GAAoB,IAAA,CAAK,MAAA,CAAO,wBAAA;EA5HzB,mCA8HX,QAAA,EAAU,YAAA,EA9HgC;EAiI1C,OAAA,EAAS,WAAA;AAAA;;UAIO,cAAA;EAnIK;EAqIrB,IAAA,EAAM,MAAA,CAAO,KAAA;EArI2B;;;;EA2IxC,MAAA,GAAS,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;;;;;;;cAoBT,UAAA,SAAmB,MAAA,CAAO,iBAAA;EA5E3B;EAAA,SA8EK,EAAA,EAAI,MAAA,CAAO,MAAA;cAEf,IAAA,UAAc,IAAA,EAAM,cAAA,EAAgB,IAAA,EAAM,iBAAA;AAAA"}
@@ -13,17 +13,28 @@ async function findBranchByName(client, projectId, name) {
13
13
  * Dynamic provider implementing CRUD for Neon branches.
14
14
  *
15
15
  * Uses adopt-or-create on `create()`: finds an existing branch by name
16
- * before creating a new one.
16
+ * before creating a new one. When `parentName` is supplied, resolves it
17
+ * to a `parent_id` and includes it in the POST body.
17
18
  */
19
+ /** @internal Exported only for unit testing; not part of the public API surface. */
18
20
  var NeonBranchResourceProvider = class {
19
21
  async create(inputs) {
20
22
  const client = new NeonClient(inputs.apiKey);
21
23
  let branchId = await findBranchByName(client, inputs.projectId, inputs.name);
22
- if (branchId) pulumi.log.info(`Adopting existing Neon branch "${inputs.name}" (${branchId})`);
23
- else branchId = (await client.post(`/projects/${inputs.projectId}/branches`, { branch: { name: inputs.name } })).branch.id;
24
+ if (branchId) if (inputs.parentName) pulumi.log.warn(`Adopting existing Neon branch "${inputs.name}" — parentName "${inputs.parentName}" is ignored for adopted branches (existing lineage preserved).`);
25
+ else pulumi.log.info(`Adopting existing Neon branch "${inputs.name}" (${branchId})`);
26
+ else {
27
+ const body = { branch: { name: inputs.name } };
28
+ if (inputs.parentName) {
29
+ const parentId = await findBranchByName(client, inputs.projectId, inputs.parentName);
30
+ if (!parentId) throw new Error(`Neon parent branch "${inputs.parentName}" not found in project ${inputs.projectId}`);
31
+ body.branch.parent_id = parentId;
32
+ }
33
+ branchId = (await client.post(`/projects/${inputs.projectId}/branches`, body)).branch.id;
34
+ }
24
35
  return {
25
36
  id: branchId,
26
- outs: inputs
37
+ outs: { ...inputs }
27
38
  };
28
39
  }
29
40
  async read(id, props) {
@@ -47,6 +58,7 @@ var NeonBranchResourceProvider = class {
47
58
  async diff(_id, olds, news) {
48
59
  const replaces = [];
49
60
  if (olds.projectId !== news.projectId) replaces.push("projectId");
61
+ if (olds.parentName !== news.parentName) replaces.push("parentName");
50
62
  return {
51
63
  changes: replaces.length > 0 || olds.name !== news.name,
52
64
  replaces,
@@ -65,9 +77,16 @@ var NeonBranchResource = class extends pulumi.dynamic.Resource {
65
77
  *
66
78
  * @example
67
79
  * ```typescript
68
- * const branch = new NeonBranch("production", {
80
+ * // Root branch (Neon default parent)
81
+ * const production = new NeonBranch("production", {
69
82
  * name: "production",
70
83
  * }, { provider, project });
84
+ *
85
+ * // Copy-on-write branch from production
86
+ * const staging = new NeonBranch("staging", {
87
+ * name: "staging",
88
+ * parent: "production",
89
+ * }, { provider, project });
71
90
  * ```
72
91
  */
73
92
  var NeonBranch = class extends pulumi.ComponentResource {
@@ -77,7 +96,8 @@ var NeonBranch = class extends pulumi.ComponentResource {
77
96
  const resource = new NeonBranchResource(`${name}-resource`, {
78
97
  apiKey: provider.apiKey,
79
98
  projectId: project.id,
80
- name: args.name
99
+ name: args.name,
100
+ parentName: args.parent
81
101
  }, { parent: this });
82
102
  this.id = resource.id;
83
103
  this.registerOutputs({ id: this.id });
@@ -85,5 +105,5 @@ var NeonBranch = class extends pulumi.ComponentResource {
85
105
  };
86
106
 
87
107
  //#endregion
88
- export { NeonBranch };
108
+ export { NeonBranch, NeonBranchResourceProvider };
89
109
  //# sourceMappingURL=branch.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch.mjs","names":[],"sources":["../../src/neon/branch.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { NeonClient } from \"./client\";\nimport type { NeonProject } from \"./project\";\nimport type { NeonProvider } from \"./provider\";\n\n/** Resolved inputs for the Neon branch dynamic provider. */\nexport interface NeonBranchInputs {\n\t/** Neon API key. */\n\tapiKey: string;\n\n\t/** Neon project ID (e.g. `\"quiet-forest-69719462\"`). */\n\tprojectId: string;\n\n\t/** Branch display name (e.g. `\"production\"`, `\"development\"`). */\n\tname: string;\n}\n\n/** Persisted state for the Neon branch. */\ninterface NeonBranchOutputs extends NeonBranchInputs {}\n\n/** Neon API response for a branch. */\ninterface BranchResponse {\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tproject_id: string;\n\t};\n}\n\n/** Neon API response for branch creation. */\ninterface BranchCreateResponse {\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tproject_id: string;\n\t};\n}\n\n/** Neon API response for listing branches. */\ninterface BranchListResponse {\n\tbranches: Array<{\n\t\tid: string;\n\t\tname: string;\n\t}>;\n}\n\n/**\n * Finds an existing Neon branch by name within a project.\n */\nasync function findBranchByName(\n\tclient: NeonClient,\n\tprojectId: string,\n\tname: string,\n): Promise<string | undefined> {\n\tconst result = await client.get<BranchListResponse>(\n\t\t`/projects/${projectId}/branches`,\n\t);\n\n\tconst match = result.branches.find((b) => b.name === name);\n\n\treturn match?.id;\n}\n\n/**\n * Dynamic provider implementing CRUD for Neon branches.\n *\n * Uses adopt-or-create on `create()`: finds an existing branch by name\n * before creating a new one.\n */\nclass NeonBranchResourceProvider implements pulumi.dynamic.ResourceProvider {\n\tasync create(inputs: NeonBranchInputs): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new NeonClient(inputs.apiKey);\n\n\t\tlet branchId = await findBranchByName(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (branchId) {\n\t\t\tpulumi.log.info(\n\t\t\t\t`Adopting existing Neon branch \"${inputs.name}\" (${branchId})`,\n\t\t\t);\n\t\t} else {\n\t\t\tconst result = await client.post<BranchCreateResponse>(\n\t\t\t\t`/projects/${inputs.projectId}/branches`,\n\t\t\t\t{ branch: { name: inputs.name } },\n\t\t\t);\n\n\t\t\tbranchId = result.branch.id;\n\t\t}\n\n\t\treturn { id: branchId, outs: inputs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: NeonBranchOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\tconst result = await client.get<BranchResponse>(\n\t\t\t`/projects/${props.projectId}/branches/${id}`,\n\t\t);\n\n\t\treturn {\n\t\t\tid: result.branch.id,\n\t\t\tprops: { ...props, name: result.branch.name },\n\t\t};\n\t}\n\n\tasync delete(id: string, props: NeonBranchOutputs): Promise<void> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\ttry {\n\t\t\tawait client.delete(`/projects/${props.projectId}/branches/${id}`);\n\t\t} catch {\n\t\t\tpulumi.log.warn(`Failed to delete Neon branch (may already be deleted)`);\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: NeonBranchOutputs,\n\t\tnews: NeonBranchInputs,\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\treturn {\n\t\t\tchanges: replaces.length > 0 || olds.name !== news.name,\n\t\t\treplaces,\n\t\t\tdeleteBeforeReplace: true,\n\t\t};\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass NeonBranchResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly branchId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\tapiKey: pulumi.Input<string>;\n\t\t\tprojectId: pulumi.Input<string>;\n\t\t\tname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(new NeonBranchResourceProvider(), name, { ...args }, opts);\n\t}\n}\n\n/** Options type for NeonBranch — replaces Pulumi's native `provider` field. */\ntype NeonBranchOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Neon authentication context. */\n\tprovider: NeonProvider;\n\n\t/** Neon project context. */\n\tproject: NeonProject;\n};\n\n/** Args for NeonBranch. */\nexport interface NeonBranchArgs {\n\t/** Branch display name. */\n\tname: pulumi.Input<string>;\n}\n\n/**\n * Manages a Neon branch with adopt-or-create semantics.\n *\n * @example\n * ```typescript\n * const branch = new NeonBranch(\"production\", {\n * name: \"production\",\n * }, { provider, project });\n * ```\n */\nexport class NeonBranch extends pulumi.ComponentResource {\n\t/** Neon branch ID. */\n\tpublic readonly id: pulumi.Output<string>;\n\n\tconstructor(name: string, args: NeonBranchArgs, opts: NeonBranchOptions) {\n\t\tconst { provider, project, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:neon:Branch\", name, {}, pulumiOpts);\n\n\t\tconst resource = new NeonBranchResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\tapiKey: provider.apiKey,\n\t\t\t\tprojectId: project.id,\n\t\t\t\tname: args.name,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = resource.id;\n\n\t\tthis.registerOutputs({ id: this.id });\n\t}\n}\n"],"mappings":";;;;;;;;AAiDA,eAAe,iBACd,QACA,WACA,MAC8B;CAO9B,QAFc,MAJO,OAAO,IAC3B,aAAa,UAAU,UACxB,GAEqB,SAAS,MAAM,MAAM,EAAE,SAAS,IAE1C,GAAG;AACf;;;;;;;AAQA,IAAM,6BAAN,MAA4E;CAC3E,MAAM,OAAO,QAAgE;EAC5E,MAAM,SAAS,IAAI,WAAW,OAAO,MAAM;EAE3C,IAAI,WAAW,MAAM,iBACpB,QACA,OAAO,WACP,OAAO,IACR;EAEA,IAAI,UACH,OAAO,IAAI,KACV,kCAAkC,OAAO,KAAK,KAAK,SAAS,EAC7D;OAOA,YAAW,MALU,OAAO,KAC3B,aAAa,OAAO,UAAU,YAC9B,EAAE,QAAQ,EAAE,MAAM,OAAO,KAAK,EAAE,CACjC,GAEkB,OAAO;EAG1B,OAAO;GAAE,IAAI;GAAU,MAAM;EAAO;CACrC;CAEA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,SAAS,MAAM,IAFF,WAAW,MAAM,MAEV,EAAE,IAC3B,aAAa,MAAM,UAAU,YAAY,IAC1C;EAEA,OAAO;GACN,IAAI,OAAO,OAAO;GAClB,OAAO;IAAE,GAAG;IAAO,MAAM,OAAO,OAAO;GAAK;EAC7C;CACD;CAEA,MAAM,OAAO,IAAY,OAAyC;EACjE,MAAM,SAAS,IAAI,WAAW,MAAM,MAAM;EAE1C,IAAI;GACH,MAAM,OAAO,OAAO,aAAa,MAAM,UAAU,YAAY,IAAI;EAClE,QAAQ;GACP,OAAO,IAAI,KAAK,uDAAuD;EACxE;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,cAAc,KAAK,WAC3B,SAAS,KAAK,WAAW;EAG1B,OAAO;GACN,SAAS,SAAS,SAAS,KAAK,KAAK,SAAS,KAAK;GACnD;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,qBAAN,cAAiC,OAAO,QAAQ,SAAS;CAGxD,YACC,MACA,MAKA,MACC;EACD,MAAM,IAAI,2BAA2B,GAAG,MAAM,EAAE,GAAG,KAAK,GAAG,IAAI;CAChE;AACD;;;;;;;;;;;AA2BA,IAAa,aAAb,cAAgC,OAAO,kBAAkB;CAIxD,YAAY,MAAc,MAAsB,MAAyB;EACxE,MAAM,EAAE,UAAU,SAAS,GAAG,eAAe;EAE7C,MAAM,0BAA0B,MAAM,CAAC,GAAG,UAAU;EAEpD,MAAM,WAAW,IAAI,mBACpB,GAAG,KAAK,YACR;GACC,QAAQ,SAAS;GACjB,WAAW,QAAQ;GACnB,MAAM,KAAK;EACZ,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,KAAK,SAAS;EAEnB,KAAK,gBAAgB,EAAE,IAAI,KAAK,GAAG,CAAC;CACrC;AACD"}
1
+ {"version":3,"file":"branch.mjs","names":[],"sources":["../../src/neon/branch.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport { NeonClient } from \"./client\";\nimport type { NeonProject } from \"./project\";\nimport type { NeonProvider } from \"./provider\";\n\n/** Resolved inputs for the Neon branch dynamic provider. */\nexport interface NeonBranchInputs {\n\t/** Neon API key. */\n\tapiKey: string;\n\n\t/** Neon project ID (e.g. `\"quiet-forest-69719462\"`). */\n\tprojectId: string;\n\n\t/** Branch display name (e.g. `\"production\"`, `\"development\"`). */\n\tname: string;\n\n\t/**\n\t * Parent branch NAME. Resolved to `parent_id` inside `create()` via\n\t * `findBranchByName`. Omit for project-root branches.\n\t */\n\tparentName?: string;\n}\n\n/** Persisted state for the Neon branch. */\ninterface NeonBranchOutputs extends NeonBranchInputs {}\n\n/** Neon API response for a branch. */\ninterface BranchResponse {\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tproject_id: string;\n\t};\n}\n\n/** Neon API response for branch creation. */\ninterface BranchCreateResponse {\n\tbranch: {\n\t\tid: string;\n\t\tname: string;\n\t\tproject_id: string;\n\t};\n}\n\n/** Neon API response for listing branches. */\ninterface BranchListResponse {\n\tbranches: Array<{\n\t\tid: string;\n\t\tname: string;\n\t}>;\n}\n\n/**\n * Finds an existing Neon branch by name within a project.\n */\nasync function findBranchByName(\n\tclient: NeonClient,\n\tprojectId: string,\n\tname: string,\n): Promise<string | undefined> {\n\tconst result = await client.get<BranchListResponse>(\n\t\t`/projects/${projectId}/branches`,\n\t);\n\n\tconst match = result.branches.find((b) => b.name === name);\n\n\treturn match?.id;\n}\n\n/**\n * Dynamic provider implementing CRUD for Neon branches.\n *\n * Uses adopt-or-create on `create()`: finds an existing branch by name\n * before creating a new one. When `parentName` is supplied, resolves it\n * to a `parent_id` and includes it in the POST body.\n */\n/** @internal Exported only for unit testing; not part of the public API surface. */\nexport class NeonBranchResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(inputs: NeonBranchInputs): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new NeonClient(inputs.apiKey);\n\n\t\tlet branchId = await findBranchByName(\n\t\t\tclient,\n\t\t\tinputs.projectId,\n\t\t\tinputs.name,\n\t\t);\n\n\t\tif (branchId) {\n\t\t\tif (inputs.parentName) {\n\t\t\t\tpulumi.log.warn(\n\t\t\t\t\t`Adopting existing Neon branch \"${inputs.name}\" — parentName \"${inputs.parentName}\" is ignored for adopted branches (existing lineage preserved).`,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tpulumi.log.info(\n\t\t\t\t\t`Adopting existing Neon branch \"${inputs.name}\" (${branchId})`,\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tconst body: { branch: { name: string; parent_id?: string } } = {\n\t\t\t\tbranch: { name: inputs.name },\n\t\t\t};\n\n\t\t\tif (inputs.parentName) {\n\t\t\t\tconst parentId = await findBranchByName(\n\t\t\t\t\tclient,\n\t\t\t\t\tinputs.projectId,\n\t\t\t\t\tinputs.parentName,\n\t\t\t\t);\n\n\t\t\t\tif (!parentId) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Neon parent branch \"${inputs.parentName}\" not found in project ${inputs.projectId}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tbody.branch.parent_id = parentId;\n\t\t\t}\n\n\t\t\tconst result = await client.post<BranchCreateResponse>(\n\t\t\t\t`/projects/${inputs.projectId}/branches`,\n\t\t\t\tbody,\n\t\t\t);\n\n\t\t\tbranchId = result.branch.id;\n\t\t}\n\n\t\treturn { id: branchId, outs: { ...inputs } };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: NeonBranchOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\tconst result = await client.get<BranchResponse>(\n\t\t\t`/projects/${props.projectId}/branches/${id}`,\n\t\t);\n\n\t\t// parentName is preserved from prior state (props): the Neon API does not expose\n\t\t// a branch's parent on GET /branches/:id, so it cannot be re-derived here.\n\t\treturn {\n\t\t\tid: result.branch.id,\n\t\t\tprops: { ...props, name: result.branch.name },\n\t\t};\n\t}\n\n\tasync delete(id: string, props: NeonBranchOutputs): Promise<void> {\n\t\tconst client = new NeonClient(props.apiKey);\n\n\t\ttry {\n\t\t\tawait client.delete(`/projects/${props.projectId}/branches/${id}`);\n\t\t} catch {\n\t\t\tpulumi.log.warn(`Failed to delete Neon branch (may already be deleted)`);\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: NeonBranchOutputs,\n\t\tnews: NeonBranchInputs,\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.parentName !== news.parentName) {\n\t\t\treplaces.push(\"parentName\");\n\t\t}\n\n\t\treturn {\n\t\t\tchanges: replaces.length > 0 || olds.name !== news.name,\n\t\t\treplaces,\n\t\t\tdeleteBeforeReplace: true,\n\t\t};\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass NeonBranchResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly branchId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\tapiKey: pulumi.Input<string>;\n\t\t\tprojectId: pulumi.Input<string>;\n\t\t\tname: pulumi.Input<string>;\n\t\t\t/** Name of the parent branch; omit for project-root branches. */\n\t\t\tparentName?: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(new NeonBranchResourceProvider(), name, { ...args }, opts);\n\t}\n}\n\n/** Options type for NeonBranch — replaces Pulumi's native `provider` field. */\ntype NeonBranchOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Neon authentication context. */\n\tprovider: NeonProvider;\n\n\t/** Neon project context. */\n\tproject: NeonProject;\n};\n\n/** Args for NeonBranch. */\nexport interface NeonBranchArgs {\n\t/** Branch display name. */\n\tname: pulumi.Input<string>;\n\n\t/**\n\t * Name of the parent branch to branch from (copy-on-write). Omit to\n\t * branch from the project root (Neon default branch).\n\t */\n\tparent?: pulumi.Input<string>;\n}\n\n/**\n * Manages a Neon branch with adopt-or-create semantics.\n *\n * @example\n * ```typescript\n * // Root branch (Neon default parent)\n * const production = new NeonBranch(\"production\", {\n * name: \"production\",\n * }, { provider, project });\n *\n * // Copy-on-write branch from production\n * const staging = new NeonBranch(\"staging\", {\n * name: \"staging\",\n * parent: \"production\",\n * }, { provider, project });\n * ```\n */\nexport class NeonBranch extends pulumi.ComponentResource {\n\t/** Neon branch ID. */\n\tpublic readonly id: pulumi.Output<string>;\n\n\tconstructor(name: string, args: NeonBranchArgs, opts: NeonBranchOptions) {\n\t\tconst { provider, project, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:neon:Branch\", name, {}, pulumiOpts);\n\n\t\tconst resource = new NeonBranchResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\tapiKey: provider.apiKey,\n\t\t\t\tprojectId: project.id,\n\t\t\t\tname: args.name,\n\t\t\t\tparentName: args.parent,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = resource.id;\n\n\t\tthis.registerOutputs({ id: this.id });\n\t}\n}\n"],"mappings":";;;;;;;;AAuDA,eAAe,iBACd,QACA,WACA,MAC8B;CAO9B,QAFc,MAJO,OAAO,IAC3B,aAAa,UAAU,UACxB,GAEqB,SAAS,MAAM,MAAM,EAAE,SAAS,IAE1C,GAAG;AACf;;;;;;;;;AAUA,IAAa,6BAAb,MAEA;CACC,MAAM,OAAO,QAAgE;EAC5E,MAAM,SAAS,IAAI,WAAW,OAAO,MAAM;EAE3C,IAAI,WAAW,MAAM,iBACpB,QACA,OAAO,WACP,OAAO,IACR;EAEA,IAAI,UACH,IAAI,OAAO,YACV,OAAO,IAAI,KACV,kCAAkC,OAAO,KAAK,kBAAkB,OAAO,WAAW,gEACnF;OAEA,OAAO,IAAI,KACV,kCAAkC,OAAO,KAAK,KAAK,SAAS,EAC7D;OAEK;GACN,MAAM,OAAyD,EAC9D,QAAQ,EAAE,MAAM,OAAO,KAAK,EAC7B;GAEA,IAAI,OAAO,YAAY;IACtB,MAAM,WAAW,MAAM,iBACtB,QACA,OAAO,WACP,OAAO,UACR;IAEA,IAAI,CAAC,UACJ,MAAM,IAAI,MACT,uBAAuB,OAAO,WAAW,yBAAyB,OAAO,WAC1E;IAGD,KAAK,OAAO,YAAY;GACzB;GAOA,YAAW,MALU,OAAO,KAC3B,aAAa,OAAO,UAAU,YAC9B,IACD,GAEkB,OAAO;EAC1B;EAEA,OAAO;GAAE,IAAI;GAAU,MAAM,EAAE,GAAG,OAAO;EAAE;CAC5C;CAEA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,SAAS,MAAM,IAFF,WAAW,MAAM,MAEV,EAAE,IAC3B,aAAa,MAAM,UAAU,YAAY,IAC1C;EAIA,OAAO;GACN,IAAI,OAAO,OAAO;GAClB,OAAO;IAAE,GAAG;IAAO,MAAM,OAAO,OAAO;GAAK;EAC7C;CACD;CAEA,MAAM,OAAO,IAAY,OAAyC;EACjE,MAAM,SAAS,IAAI,WAAW,MAAM,MAAM;EAE1C,IAAI;GACH,MAAM,OAAO,OAAO,aAAa,MAAM,UAAU,YAAY,IAAI;EAClE,QAAQ;GACP,OAAO,IAAI,KAAK,uDAAuD;EACxE;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,cAAc,KAAK,WAC3B,SAAS,KAAK,WAAW;EAG1B,IAAI,KAAK,eAAe,KAAK,YAC5B,SAAS,KAAK,YAAY;EAG3B,OAAO;GACN,SAAS,SAAS,SAAS,KAAK,KAAK,SAAS,KAAK;GACnD;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,qBAAN,cAAiC,OAAO,QAAQ,SAAS;CAGxD,YACC,MACA,MAOA,MACC;EACD,MAAM,IAAI,2BAA2B,GAAG,MAAM,EAAE,GAAG,KAAK,GAAG,IAAI;CAChE;AACD;;;;;;;;;;;;;;;;;;AAwCA,IAAa,aAAb,cAAgC,OAAO,kBAAkB;CAIxD,YAAY,MAAc,MAAsB,MAAyB;EACxE,MAAM,EAAE,UAAU,SAAS,GAAG,eAAe;EAE7C,MAAM,0BAA0B,MAAM,CAAC,GAAG,UAAU;EAEpD,MAAM,WAAW,IAAI,mBACpB,GAAG,KAAK,YACR;GACC,QAAQ,SAAS;GACjB,WAAW,QAAQ;GACnB,MAAM,KAAK;GACX,YAAY,KAAK;EAClB,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,KAAK,SAAS;EAEnB,KAAK,gBAAgB,EAAE,IAAI,KAAK,GAAG,CAAC;CACrC;AACD"}
@@ -20,14 +20,13 @@ const LOCK_DIR = "/tmp/.railway-upload-lock";
20
20
  * ```typescript
21
21
  * new RailwayDeploy("api-deploy", {
22
22
  * directory: monorepoRoot,
23
- * sourceHash,
24
- * env: { DATABASE_URL: dbUrl },
25
- * }, { provider, project, environment, service });
23
+ * triggers: [sourceHash],
24
+ * }, { provider, project, environment, service, projectToken: stagingToken.token });
26
25
  * ```
27
26
  */
28
27
  var RailwayDeploy = class extends _pulumi_pulumi.ComponentResource {
29
28
  constructor(name, args, opts) {
30
- const { provider, project, environment, service, ...pulumiOpts } = opts;
29
+ const { provider, project, environment, service, projectToken, ...pulumiOpts } = opts;
31
30
  super("infracraft:railway:Deploy", name, {}, pulumiOpts);
32
31
  const ignorePatterns = (args.excludePaths ?? []).map((dir) => {
33
32
  if (dir.startsWith("apps/")) return `${dir}/**\\n!${dir}/package.json`;
@@ -39,7 +38,7 @@ var RailwayDeploy = class extends _pulumi_pulumi.ComponentResource {
39
38
  create: deployCmd,
40
39
  triggers: args.triggers,
41
40
  dir: require_stable_dir.stableDir(args.directory),
42
- environment: { RAILWAY_TOKEN: project.projectToken }
41
+ environment: { RAILWAY_TOKEN: projectToken }
43
42
  }, { parent: this });
44
43
  this.registerOutputs({});
45
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.cjs","names":["pulumi","command","stableDir"],"sources":["../../src/railway/deploy.ts"],"sourcesContent":["import * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport { stableDir } from \"../stable-dir\";\nimport type { RailwayEnvironment } from \"./environment\";\nimport type { RailwayProject } from \"./project\";\nimport type { RailwayProvider } from \"./provider\";\nimport { RailwayBuilder, type RailwayService } from \"./service\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system to use when building the service. */\n\tbuilder?: RailwayBuilder;\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\n/** Args for RailwayDeploy. */\nexport interface RailwayDeployArgs {\n\t/**\n\t * Absolute path to the monorepo root (working directory for `railway up`).\n\t * Stored relative to the Pulumi program directory so the command stays stable\n\t * across machines and CI (see {@link stableDir}).\n\t */\n\tdirectory: string;\n\n\t/** Values that trigger a redeploy when changed (e.g. source hashes, env hashes). */\n\ttriggers: pulumi.Input<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\n/** Options type for RailwayDeploy — replaces Pulumi's native `provider` field. */\ntype RailwayDeployOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Railway authentication context. */\n\tprovider: RailwayProvider;\n\n\t/** Railway project context. */\n\tproject: RailwayProject;\n\n\t/** Railway environment context. */\n\tenvironment: RailwayEnvironment;\n\n\t/** Railway service context. */\n\tservice: RailwayService;\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 *\n * @example\n * ```typescript\n * new RailwayDeploy(\"api-deploy\", {\n * directory: monorepoRoot,\n * sourceHash,\n * env: { DATABASE_URL: dbUrl },\n * }, { provider, project, environment, service });\n * ```\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts: RailwayDeployOptions,\n\t) {\n\t\tconst { provider, project, environment, service, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:railway:Deploy\", name, {}, pulumiOpts);\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 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 ${project.id} --service ${service.id} --environment ${environment.id}; 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.triggers,\n\t\t\t\tdir: stableDir(args.directory),\n\t\t\t\tenvironment: {\n\t\t\t\t\tRAILWAY_TOKEN: project.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":";;;;;;;;;AAyDA,MAAM,WAAW;;;;;;;;;;;;;;;;;;AAmBjB,IAAa,gBAAb,cAAmCA,eAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,SAAS,aAAa,SAAS,GAAG,eAAe;EAEnE,MAAM,6BAA6B,MAAM,CAAC,GAAG,UAAU;EAEvD,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,YAAY,eAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,8CAA8C,QAAQ,GAAG,aAAa,QAAQ,GAAG,iBAAiB,YAAY,GAAG,uDAAuD,SAAS;EAE9V,IAAIC,gBAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,KAAK;GACf,KAAKC,6BAAU,KAAK,SAAS;GAC7B,aAAa,EACZ,eAAe,QAAQ,aACxB;EACD,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}
1
+ {"version":3,"file":"deploy.cjs","names":["pulumi","command","stableDir"],"sources":["../../src/railway/deploy.ts"],"sourcesContent":["import * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport { stableDir } from \"../stable-dir\";\nimport type { RailwayEnvironment } from \"./environment\";\nimport type { RailwayProject } from \"./project\";\nimport type { RailwayProvider } from \"./provider\";\nimport { RailwayBuilder, type RailwayService } from \"./service\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system to use when building the service. */\n\tbuilder?: RailwayBuilder;\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\n/** Args for RailwayDeploy. */\nexport interface RailwayDeployArgs {\n\t/**\n\t * Absolute path to the monorepo root (working directory for `railway up`).\n\t * Stored relative to the Pulumi program directory so the command stays stable\n\t * across machines and CI (see {@link stableDir}).\n\t */\n\tdirectory: string;\n\n\t/** Values that trigger a redeploy when changed (e.g. source hashes, env hashes). */\n\ttriggers: pulumi.Input<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\n/** Options type for RailwayDeploy — replaces Pulumi's native `provider` field. */\ntype RailwayDeployOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Railway authentication context. */\n\tprovider: RailwayProvider;\n\n\t/** Railway project context. */\n\tproject: RailwayProject;\n\n\t/** Railway environment context. */\n\tenvironment: RailwayEnvironment;\n\n\t/** Railway service context. */\n\tservice: RailwayService;\n\n\t/** Environment-scoped Railway deploy token. Provision via {@link RailwayProjectToken}. */\n\tprojectToken: pulumi.Input<string>;\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 *\n * @example\n * ```typescript\n * new RailwayDeploy(\"api-deploy\", {\n * directory: monorepoRoot,\n * triggers: [sourceHash],\n * }, { provider, project, environment, service, projectToken: stagingToken.token });\n * ```\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts: RailwayDeployOptions,\n\t) {\n\t\tconst {\n\t\t\tprovider,\n\t\t\tproject,\n\t\t\tenvironment,\n\t\t\tservice,\n\t\t\tprojectToken,\n\t\t\t...pulumiOpts\n\t\t} = opts;\n\n\t\tsuper(\"infracraft:railway:Deploy\", name, {}, pulumiOpts);\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 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 ${project.id} --service ${service.id} --environment ${environment.id}; 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.triggers,\n\t\t\t\tdir: stableDir(args.directory),\n\t\t\t\tenvironment: {\n\t\t\t\t\tRAILWAY_TOKEN: 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":";;;;;;;;;AA4DA,MAAM,WAAW;;;;;;;;;;;;;;;;;AAkBjB,IAAa,gBAAb,cAAmCA,eAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,EACL,UACA,SACA,aACA,SACA,cACA,GAAG,eACA;EAEJ,MAAM,6BAA6B,MAAM,CAAC,GAAG,UAAU;EAEvD,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,YAAY,eAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,8CAA8C,QAAQ,GAAG,aAAa,QAAQ,GAAG,iBAAiB,YAAY,GAAG,uDAAuD,SAAS;EAE9V,IAAIC,gBAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,KAAK;GACf,KAAKC,6BAAU,KAAK,SAAS;GAC7B,aAAa,EACZ,eAAe,aAChB;EACD,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}
@@ -35,7 +35,8 @@ type RailwayDeployOptions = Omit<pulumi.ComponentResourceOptions, "provider"> &
35
35
  /** Railway authentication context. */provider: RailwayProvider; /** Railway project context. */
36
36
  project: RailwayProject; /** Railway environment context. */
37
37
  environment: RailwayEnvironment; /** Railway service context. */
38
- service: RailwayService;
38
+ service: RailwayService; /** Environment-scoped Railway deploy token. Provision via {@link RailwayProjectToken}. */
39
+ projectToken: pulumi.Input<string>;
39
40
  };
40
41
  /**
41
42
  * Deploys a Railway service and waits for the build to complete.
@@ -49,9 +50,8 @@ type RailwayDeployOptions = Omit<pulumi.ComponentResourceOptions, "provider"> &
49
50
  * ```typescript
50
51
  * new RailwayDeploy("api-deploy", {
51
52
  * directory: monorepoRoot,
52
- * sourceHash,
53
- * env: { DATABASE_URL: dbUrl },
54
- * }, { provider, project, environment, service });
53
+ * triggers: [sourceHash],
54
+ * }, { provider, project, environment, service, projectToken: stagingToken.token });
55
55
  * ```
56
56
  */
57
57
  declare class RailwayDeploy extends pulumi.ComponentResource {
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.cts","names":[],"sources":["../../src/railway/deploy.ts"],"mappings":";;;;;;;;;UASiB,mBAAA;;EAEhB,OAAA,GAAU,cAAc;EAFW;EAKnC,YAAA;EAHwB;EAMxB,gBAAA;AAAA;;UAIgB,iBAAA;EAJA;AAAA;AAIjB;;;EAMC,SAAA;EAGU;EAAV,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAMP;EAHvB,YAAA;EANA;EASA,cAAA,GAAiB,MAAA;AAAA;;KAIb,oBAAA,GAAuB,IAAA,CAC3B,MAAA,CAAO,wBAAA;EAXuB,sCAe9B,QAAA,EAAU,eAAA,EATV;EAYA,OAAA,EAAS,cAAA,EAZc;EAevB,WAAA,EAAa,kBAAA,EAXT;EAcJ,OAAA,EAAS,cAAA;AAAA;;;;;;;;;;;;;;;;;;cAsBG,aAAA,SAAsB,MAAA,CAAO,iBAAA;cAExC,IAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,EAAM,oBAAA;AAAA"}
1
+ {"version":3,"file":"deploy.d.cts","names":[],"sources":["../../src/railway/deploy.ts"],"mappings":";;;;;;;;;UASiB,mBAAA;;EAEhB,OAAA,GAAU,cAAc;EAFW;EAKnC,YAAA;EAHwB;EAMxB,gBAAA;AAAA;;UAIgB,iBAAA;EAJA;AAAA;AAIjB;;;EAMC,SAAA;EAGU;EAAV,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAMP;EAHvB,YAAA;EANA;EASA,cAAA,GAAiB,MAAA;AAAA;;KAIb,oBAAA,GAAuB,IAAA,CAC3B,MAAA,CAAO,wBAAA;EAXuB,sCAe9B,QAAA,EAAU,eAAA,EATV;EAYA,OAAA,EAAS,cAAA,EAZc;EAevB,WAAA,EAAa,kBAAA,EAXT;EAcJ,OAAA,EAAS,cAAA;EAGT,YAAA,EAAc,MAAA,CAAO,KAAA;AAAA;;;;;;;;;;;;;;;;;cAqBT,aAAA,SAAsB,MAAA,CAAO,iBAAA;cAExC,IAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,EAAM,oBAAA;AAAA"}
@@ -35,7 +35,8 @@ type RailwayDeployOptions = Omit<pulumi.ComponentResourceOptions, "provider"> &
35
35
  /** Railway authentication context. */provider: RailwayProvider; /** Railway project context. */
36
36
  project: RailwayProject; /** Railway environment context. */
37
37
  environment: RailwayEnvironment; /** Railway service context. */
38
- service: RailwayService;
38
+ service: RailwayService; /** Environment-scoped Railway deploy token. Provision via {@link RailwayProjectToken}. */
39
+ projectToken: pulumi.Input<string>;
39
40
  };
40
41
  /**
41
42
  * Deploys a Railway service and waits for the build to complete.
@@ -49,9 +50,8 @@ type RailwayDeployOptions = Omit<pulumi.ComponentResourceOptions, "provider"> &
49
50
  * ```typescript
50
51
  * new RailwayDeploy("api-deploy", {
51
52
  * directory: monorepoRoot,
52
- * sourceHash,
53
- * env: { DATABASE_URL: dbUrl },
54
- * }, { provider, project, environment, service });
53
+ * triggers: [sourceHash],
54
+ * }, { provider, project, environment, service, projectToken: stagingToken.token });
55
55
  * ```
56
56
  */
57
57
  declare class RailwayDeploy extends pulumi.ComponentResource {
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.mts","names":[],"sources":["../../src/railway/deploy.ts"],"mappings":";;;;;;;;;UASiB,mBAAA;;EAEhB,OAAA,GAAU,cAAc;EAFW;EAKnC,YAAA;EAHwB;EAMxB,gBAAA;AAAA;;UAIgB,iBAAA;EAJA;AAAA;AAIjB;;;EAMC,SAAA;EAGU;EAAV,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAMP;EAHvB,YAAA;EANA;EASA,cAAA,GAAiB,MAAA;AAAA;;KAIb,oBAAA,GAAuB,IAAA,CAC3B,MAAA,CAAO,wBAAA;EAXuB,sCAe9B,QAAA,EAAU,eAAA,EATV;EAYA,OAAA,EAAS,cAAA,EAZc;EAevB,WAAA,EAAa,kBAAA,EAXT;EAcJ,OAAA,EAAS,cAAA;AAAA;;;;;;;;;;;;;;;;;;cAsBG,aAAA,SAAsB,MAAA,CAAO,iBAAA;cAExC,IAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,EAAM,oBAAA;AAAA"}
1
+ {"version":3,"file":"deploy.d.mts","names":[],"sources":["../../src/railway/deploy.ts"],"mappings":";;;;;;;;;UASiB,mBAAA;;EAEhB,OAAA,GAAU,cAAc;EAFW;EAKnC,YAAA;EAHwB;EAMxB,gBAAA;AAAA;;UAIgB,iBAAA;EAJA;AAAA;AAIjB;;;EAMC,SAAA;EAGU;EAAV,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAMP;EAHvB,YAAA;EANA;EASA,cAAA,GAAiB,MAAA;AAAA;;KAIb,oBAAA,GAAuB,IAAA,CAC3B,MAAA,CAAO,wBAAA;EAXuB,sCAe9B,QAAA,EAAU,eAAA,EATV;EAYA,OAAA,EAAS,cAAA,EAZc;EAevB,WAAA,EAAa,kBAAA,EAXT;EAcJ,OAAA,EAAS,cAAA;EAGT,YAAA,EAAc,MAAA,CAAO,KAAA;AAAA;;;;;;;;;;;;;;;;;cAqBT,aAAA,SAAsB,MAAA,CAAO,iBAAA;cAExC,IAAA,UACA,IAAA,EAAM,iBAAA,EACN,IAAA,EAAM,oBAAA;AAAA"}
@@ -17,14 +17,13 @@ const LOCK_DIR = "/tmp/.railway-upload-lock";
17
17
  * ```typescript
18
18
  * new RailwayDeploy("api-deploy", {
19
19
  * directory: monorepoRoot,
20
- * sourceHash,
21
- * env: { DATABASE_URL: dbUrl },
22
- * }, { provider, project, environment, service });
20
+ * triggers: [sourceHash],
21
+ * }, { provider, project, environment, service, projectToken: stagingToken.token });
23
22
  * ```
24
23
  */
25
24
  var RailwayDeploy = class extends pulumi.ComponentResource {
26
25
  constructor(name, args, opts) {
27
- const { provider, project, environment, service, ...pulumiOpts } = opts;
26
+ const { provider, project, environment, service, projectToken, ...pulumiOpts } = opts;
28
27
  super("infracraft:railway:Deploy", name, {}, pulumiOpts);
29
28
  const ignorePatterns = (args.excludePaths ?? []).map((dir) => {
30
29
  if (dir.startsWith("apps/")) return `${dir}/**\\n!${dir}/package.json`;
@@ -36,7 +35,7 @@ var RailwayDeploy = class extends pulumi.ComponentResource {
36
35
  create: deployCmd,
37
36
  triggers: args.triggers,
38
37
  dir: stableDir(args.directory),
39
- environment: { RAILWAY_TOKEN: project.projectToken }
38
+ environment: { RAILWAY_TOKEN: projectToken }
40
39
  }, { parent: this });
41
40
  this.registerOutputs({});
42
41
  }
@@ -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\";\nimport { stableDir } from \"../stable-dir\";\nimport type { RailwayEnvironment } from \"./environment\";\nimport type { RailwayProject } from \"./project\";\nimport type { RailwayProvider } from \"./provider\";\nimport { RailwayBuilder, type RailwayService } from \"./service\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system to use when building the service. */\n\tbuilder?: RailwayBuilder;\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\n/** Args for RailwayDeploy. */\nexport interface RailwayDeployArgs {\n\t/**\n\t * Absolute path to the monorepo root (working directory for `railway up`).\n\t * Stored relative to the Pulumi program directory so the command stays stable\n\t * across machines and CI (see {@link stableDir}).\n\t */\n\tdirectory: string;\n\n\t/** Values that trigger a redeploy when changed (e.g. source hashes, env hashes). */\n\ttriggers: pulumi.Input<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\n/** Options type for RailwayDeploy — replaces Pulumi's native `provider` field. */\ntype RailwayDeployOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Railway authentication context. */\n\tprovider: RailwayProvider;\n\n\t/** Railway project context. */\n\tproject: RailwayProject;\n\n\t/** Railway environment context. */\n\tenvironment: RailwayEnvironment;\n\n\t/** Railway service context. */\n\tservice: RailwayService;\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 *\n * @example\n * ```typescript\n * new RailwayDeploy(\"api-deploy\", {\n * directory: monorepoRoot,\n * sourceHash,\n * env: { DATABASE_URL: dbUrl },\n * }, { provider, project, environment, service });\n * ```\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts: RailwayDeployOptions,\n\t) {\n\t\tconst { provider, project, environment, service, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:railway:Deploy\", name, {}, pulumiOpts);\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 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 ${project.id} --service ${service.id} --environment ${environment.id}; 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.triggers,\n\t\t\t\tdir: stableDir(args.directory),\n\t\t\t\tenvironment: {\n\t\t\t\t\tRAILWAY_TOKEN: project.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":";;;;;;AAyDA,MAAM,WAAW;;;;;;;;;;;;;;;;;;AAmBjB,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,SAAS,aAAa,SAAS,GAAG,eAAe;EAEnE,MAAM,6BAA6B,MAAM,CAAC,GAAG,UAAU;EAEvD,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,YAAY,OAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,8CAA8C,QAAQ,GAAG,aAAa,QAAQ,GAAG,iBAAiB,YAAY,GAAG,uDAAuD,SAAS;EAE9V,IAAI,QAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,KAAK;GACf,KAAK,UAAU,KAAK,SAAS;GAC7B,aAAa,EACZ,eAAe,QAAQ,aACxB;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\";\nimport { stableDir } from \"../stable-dir\";\nimport type { RailwayEnvironment } from \"./environment\";\nimport type { RailwayProject } from \"./project\";\nimport type { RailwayProvider } from \"./provider\";\nimport { RailwayBuilder, type RailwayService } from \"./service\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system to use when building the service. */\n\tbuilder?: RailwayBuilder;\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\n/** Args for RailwayDeploy. */\nexport interface RailwayDeployArgs {\n\t/**\n\t * Absolute path to the monorepo root (working directory for `railway up`).\n\t * Stored relative to the Pulumi program directory so the command stays stable\n\t * across machines and CI (see {@link stableDir}).\n\t */\n\tdirectory: string;\n\n\t/** Values that trigger a redeploy when changed (e.g. source hashes, env hashes). */\n\ttriggers: pulumi.Input<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\n/** Options type for RailwayDeploy — replaces Pulumi's native `provider` field. */\ntype RailwayDeployOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Railway authentication context. */\n\tprovider: RailwayProvider;\n\n\t/** Railway project context. */\n\tproject: RailwayProject;\n\n\t/** Railway environment context. */\n\tenvironment: RailwayEnvironment;\n\n\t/** Railway service context. */\n\tservice: RailwayService;\n\n\t/** Environment-scoped Railway deploy token. Provision via {@link RailwayProjectToken}. */\n\tprojectToken: pulumi.Input<string>;\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 *\n * @example\n * ```typescript\n * new RailwayDeploy(\"api-deploy\", {\n * directory: monorepoRoot,\n * triggers: [sourceHash],\n * }, { provider, project, environment, service, projectToken: stagingToken.token });\n * ```\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts: RailwayDeployOptions,\n\t) {\n\t\tconst {\n\t\t\tprovider,\n\t\t\tproject,\n\t\t\tenvironment,\n\t\t\tservice,\n\t\t\tprojectToken,\n\t\t\t...pulumiOpts\n\t\t} = opts;\n\n\t\tsuper(\"infracraft:railway:Deploy\", name, {}, pulumiOpts);\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 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 ${project.id} --service ${service.id} --environment ${environment.id}; 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.triggers,\n\t\t\t\tdir: stableDir(args.directory),\n\t\t\t\tenvironment: {\n\t\t\t\t\tRAILWAY_TOKEN: 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":";;;;;;AA4DA,MAAM,WAAW;;;;;;;;;;;;;;;;;AAkBjB,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,EACL,UACA,SACA,aACA,SACA,cACA,GAAG,eACA;EAEJ,MAAM,6BAA6B,MAAM,CAAC,GAAG,UAAU;EAEvD,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,YAAY,OAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,8CAA8C,QAAQ,GAAG,aAAa,QAAQ,GAAG,iBAAiB,YAAY,GAAG,uDAAuD,SAAS;EAE9V,IAAI,QAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,KAAK;GACf,KAAK,UAAU,KAAK,SAAS;GAC7B,aAAa,EACZ,eAAe,aAChB;EACD,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}