@infracraft/pulumi 1.27.0 → 1.28.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 (81) hide show
  1. package/dist/commands/deploy.cjs +1 -1
  2. package/dist/commands/deploy.mjs +1 -1
  3. package/dist/fly/certificate.cjs +3 -0
  4. package/dist/fly/certificate.cjs.map +1 -1
  5. package/dist/fly/certificate.d.cts +32 -1
  6. package/dist/fly/certificate.d.cts.map +1 -1
  7. package/dist/fly/certificate.d.mts +32 -1
  8. package/dist/fly/certificate.d.mts.map +1 -1
  9. package/dist/fly/certificate.mjs +3 -1
  10. package/dist/fly/certificate.mjs.map +1 -1
  11. package/dist/fly/deploy.cjs +4 -0
  12. package/dist/fly/deploy.cjs.map +1 -1
  13. package/dist/fly/deploy.d.cts +4 -0
  14. package/dist/fly/deploy.d.cts.map +1 -1
  15. package/dist/fly/deploy.d.mts +4 -0
  16. package/dist/fly/deploy.d.mts.map +1 -1
  17. package/dist/fly/deploy.mjs +4 -0
  18. package/dist/fly/deploy.mjs.map +1 -1
  19. package/dist/fly/ip.cjs +3 -0
  20. package/dist/fly/ip.cjs.map +1 -1
  21. package/dist/fly/ip.d.cts +34 -1
  22. package/dist/fly/ip.d.cts.map +1 -1
  23. package/dist/fly/ip.d.mts +34 -1
  24. package/dist/fly/ip.d.mts.map +1 -1
  25. package/dist/fly/ip.mjs +3 -1
  26. package/dist/fly/ip.mjs.map +1 -1
  27. package/dist/fly/secret.cjs +3 -0
  28. package/dist/fly/secret.cjs.map +1 -1
  29. package/dist/fly/secret.d.cts +32 -1
  30. package/dist/fly/secret.d.cts.map +1 -1
  31. package/dist/fly/secret.d.mts +32 -1
  32. package/dist/fly/secret.d.mts.map +1 -1
  33. package/dist/fly/secret.mjs +3 -1
  34. package/dist/fly/secret.mjs.map +1 -1
  35. package/dist/railway/deploy.cjs +1 -1
  36. package/dist/railway/deploy.cjs.map +1 -1
  37. package/dist/railway/deploy.mjs +1 -1
  38. package/dist/railway/deploy.mjs.map +1 -1
  39. package/dist/railway/variable.cjs +3 -0
  40. package/dist/railway/variable.cjs.map +1 -1
  41. package/dist/railway/variable.d.cts +47 -1
  42. package/dist/railway/variable.d.cts.map +1 -1
  43. package/dist/railway/variable.d.mts +47 -1
  44. package/dist/railway/variable.d.mts.map +1 -1
  45. package/dist/railway/variable.mjs +3 -1
  46. package/dist/railway/variable.mjs.map +1 -1
  47. package/dist/railway/volume.cjs +10 -5
  48. package/dist/railway/volume.cjs.map +1 -1
  49. package/dist/railway/volume.d.cts.map +1 -1
  50. package/dist/railway/volume.d.mts.map +1 -1
  51. package/dist/railway/volume.mjs +10 -5
  52. package/dist/railway/volume.mjs.map +1 -1
  53. package/dist/{sandbox-BQtqMu-5.mjs → sandbox-Cw11Vveq.mjs} +63 -5
  54. package/dist/sandbox-Cw11Vveq.mjs.map +1 -0
  55. package/dist/{sandbox-BBnhmyM_.cjs → sandbox-DM817Nlx.cjs} +68 -4
  56. package/dist/sandbox-DM817Nlx.cjs.map +1 -0
  57. package/dist/sandbox.cjs +2 -1
  58. package/dist/sandbox.d.cts +20 -4
  59. package/dist/sandbox.d.cts.map +1 -1
  60. package/dist/sandbox.d.mts +20 -4
  61. package/dist/sandbox.d.mts.map +1 -1
  62. package/dist/sandbox.mjs +2 -2
  63. package/dist/vercel/deploy.cjs +4 -0
  64. package/dist/vercel/deploy.cjs.map +1 -1
  65. package/dist/vercel/deploy.d.cts +4 -0
  66. package/dist/vercel/deploy.d.cts.map +1 -1
  67. package/dist/vercel/deploy.d.mts +4 -0
  68. package/dist/vercel/deploy.d.mts.map +1 -1
  69. package/dist/vercel/deploy.mjs +4 -0
  70. package/dist/vercel/deploy.mjs.map +1 -1
  71. package/dist/vercel/variable.cjs +3 -0
  72. package/dist/vercel/variable.cjs.map +1 -1
  73. package/dist/vercel/variable.d.cts +31 -1
  74. package/dist/vercel/variable.d.cts.map +1 -1
  75. package/dist/vercel/variable.d.mts +31 -1
  76. package/dist/vercel/variable.d.mts.map +1 -1
  77. package/dist/vercel/variable.mjs +3 -1
  78. package/dist/vercel/variable.mjs.map +1 -1
  79. package/package.json +1 -1
  80. package/dist/sandbox-BBnhmyM_.cjs.map +0 -1
  81. package/dist/sandbox-BQtqMu-5.mjs.map +0 -1
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_chunk = require('../chunk-BVYJZCqc.cjs');
3
3
  const require_git_guard = require('../git-guard.cjs');
4
- const require_sandbox = require('../sandbox-BBnhmyM_.cjs');
4
+ const require_sandbox = require('../sandbox-DM817Nlx.cjs');
5
5
  let _pulumi_pulumi = require("@pulumi/pulumi");
6
6
  _pulumi_pulumi = require_chunk.__toESM(_pulumi_pulumi, 1);
7
7
  let _pulumi_command = require("@pulumi/command");
@@ -1,6 +1,6 @@
1
1
  import { t as __name } from "../chunk-OPjESj5l.mjs";
2
2
  import { isGitGuard } from "../git-guard.mjs";
3
- import { a as buildSandboxScript, n as isDeploySandbox, r as SandboxMode } from "../sandbox-BQtqMu-5.mjs";
3
+ import { a as buildSandboxScript, n as isDeploySandbox, r as SandboxMode } from "../sandbox-Cw11Vveq.mjs";
4
4
  import * as pulumi from "@pulumi/pulumi";
5
5
  import * as command from "@pulumi/command";
6
6
 
@@ -11,6 +11,8 @@ _pulumi_pulumi = require_chunk.__toESM(_pulumi_pulumi, 1);
11
11
  * for an existing cert by hostname and adopts it, otherwise it requests one via
12
12
  * `POST /v1/apps/{app}/certificates/acme`. The Machines API returns no `id` —
13
13
  * the hostname is the resource key.
14
+ *
15
+ * @internal Exported only for unit testing; not part of the public API surface.
14
16
  */
15
17
  var FlyCertificateResourceProvider = class {
16
18
  async create(inputs) {
@@ -119,4 +121,5 @@ var FlyCertificate = class extends _pulumi_pulumi.ComponentResource {
119
121
 
120
122
  //#endregion
121
123
  exports.FlyCertificate = FlyCertificate;
124
+ exports.FlyCertificateResourceProvider = FlyCertificateResourceProvider;
122
125
  //# sourceMappingURL=certificate.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"certificate.cjs","names":["FlyClient","ApiNotFoundError","pulumi"],"sources":["../../src/fly/certificate.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\n\nimport { ApiNotFoundError } from \"../errors/api-not-found-error\";\nimport type { FlyApp } from \"./app\";\nimport { FlyClient } from \"./client\";\nimport type { FlyProvider } from \"./provider\";\n\n/** DNS records the consumer must create for certificate validation. */\nexport interface FlyDnsRequirements {\n\t/** ACME challenge CNAME record. */\n\tacme_challenge?: { name: string; target: string };\n\n\t/** `_fly-ownership` TXT record. */\n\townership?: { name: string; app_value: string };\n\n\t/** CNAME target for the hostname itself. */\n\tcname?: string;\n}\n\n/** Resolved inputs for the Fly certificate dynamic provider. */\ninterface FlyCertificateInputs {\n\t/** Fly API token. */\n\ttoken: string;\n\n\t/** App name the certificate belongs to. */\n\tappName: string;\n\n\t/** Hostname to issue an ACME certificate for. Used as the resource key. */\n\thostname: string;\n}\n\n/** Persisted state for the Fly certificate. */\ninterface FlyCertificateOutputs extends FlyCertificateInputs {\n\t/** Whether the certificate is fully provisioned (DNS correct). */\n\tconfigured: boolean;\n\n\t/** DNS records required for validation. */\n\tdnsRequirements: FlyDnsRequirements;\n}\n\n/** Certificate response (only the fields we read). */\ninterface FlyCertificateResponse {\n\thostname: string;\n\tconfigured: boolean;\n\tdns_requirements?: FlyDnsRequirements;\n}\n\n/**\n * Dynamic provider for Fly ACME (Let's Encrypt) certificates. `create()` checks\n * for an existing cert by hostname and adopts it, otherwise it requests one via\n * `POST /v1/apps/{app}/certificates/acme`. The Machines API returns no `id` —\n * the hostname is the resource key.\n */\nclass FlyCertificateResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new FlyClient(inputs.token);\n\t\tconst path = `/v1/apps/${inputs.appName}/certificates/${encodeURIComponent(inputs.hostname)}`;\n\n\t\tlet cert = await client.tryGet<FlyCertificateResponse>(path);\n\n\t\tif (cert) {\n\t\t\tpulumi.log.info(`Adopting existing Fly certificate \"${inputs.hostname}\"`);\n\t\t} else {\n\t\t\tcert = await client.post<FlyCertificateResponse>(\n\t\t\t\t`/v1/apps/${inputs.appName}/certificates/acme`,\n\t\t\t\t{ hostname: inputs.hostname },\n\t\t\t);\n\t\t}\n\n\t\tconst outs: FlyCertificateOutputs = {\n\t\t\t...inputs,\n\t\t\tconfigured: cert.configured ?? false,\n\t\t\tdnsRequirements: cert.dns_requirements ?? {},\n\t\t};\n\n\t\treturn { id: inputs.hostname, outs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: FlyCertificateOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\tconst cert = await client.tryGet<FlyCertificateResponse>(\n\t\t\t`/v1/apps/${props.appName}/certificates/${encodeURIComponent(id)}`,\n\t\t);\n\n\t\tif (!cert) {\n\t\t\t// Resource gone → blank id lets refresh reconcile the deletion.\n\t\t\treturn {};\n\t\t}\n\n\t\treturn {\n\t\t\tid,\n\t\t\tprops: {\n\t\t\t\t...props,\n\t\t\t\tconfigured: cert.configured ?? false,\n\t\t\t\tdnsRequirements: cert.dns_requirements ?? {},\n\t\t\t},\n\t\t};\n\t}\n\n\tasync update(\n\t\t_id: string,\n\t\t_olds: FlyCertificateOutputs,\n\t\tnews: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\t// Hostname/app changes force replacement (see diff); nothing else is updatable.\n\t\treturn {\n\t\t\touts: { ...news, configured: false, dnsRequirements: {} },\n\t\t};\n\t}\n\n\tasync delete(id: string, props: FlyCertificateOutputs): Promise<void> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\ttry {\n\t\t\tawait client.delete(\n\t\t\t\t`/v1/apps/${props.appName}/certificates/${encodeURIComponent(id)}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// Already gone — deletion is idempotent.\n\t\t\tif (error instanceof ApiNotFoundError) {\n\t\t\t\tpulumi.log.warn(`Fly certificate \"${id}\" already deleted`);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: FlyCertificateOutputs,\n\t\tnews: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.appName !== news.appName) {\n\t\t\treplaces.push(\"appName\");\n\t\t}\n\n\t\tif (olds.hostname !== news.hostname) {\n\t\t\treplaces.push(\"hostname\");\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/** Internal dynamic resource — not part of the public API. */\nclass FlyCertificateResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly configured: pulumi.Output<boolean>;\n\tpublic declare readonly dnsRequirements: pulumi.Output<FlyDnsRequirements>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tappName: pulumi.Input<string>;\n\t\t\thostname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew FlyCertificateResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, configured: undefined, dnsRequirements: undefined },\n\t\t\t// The API token flows into dynamic-provider state with the outputs — mark it secret there.\n\t\t\t{ ...opts, additionalSecretOutputs: [\"token\"] },\n\t\t);\n\t}\n}\n\n/** Options type for FlyCertificate. */\ntype FlyCertificateOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Fly authentication context. */\n\tprovider: FlyProvider;\n\n\t/** App the certificate belongs to. */\n\tapp: FlyApp;\n};\n\n/** Args for FlyCertificate. */\nexport interface FlyCertificateArgs {\n\t/** Hostname to issue an ACME certificate for (e.g. `\"api.example.com\"`). */\n\thostname: pulumi.Input<string>;\n}\n\n/**\n * Manages a Fly ACME certificate for a custom hostname.\n *\n * Exposes `.configured` and `.dnsRequirements` so the consumer can wire up the\n * required DNS records.\n *\n * @example\n * ```typescript\n * const cert = new FlyCertificate(\"api-cert\", {\n * hostname: \"api.example.com\",\n * }, { provider, app });\n * ```\n */\nexport class FlyCertificate extends pulumi.ComponentResource {\n\t/** Certificate identifier (equals the hostname). */\n\tpublic readonly id: pulumi.Output<string>;\n\n\t/** Whether the certificate is fully provisioned. */\n\tpublic readonly configured: pulumi.Output<boolean>;\n\n\t/** DNS records required for validation. */\n\tpublic readonly dnsRequirements: pulumi.Output<FlyDnsRequirements>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: FlyCertificateArgs,\n\t\topts: FlyCertificateOptions,\n\t) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Certificate\", name, {}, pulumiOpts);\n\n\t\tconst resource = new FlyCertificateResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tappName: app.id,\n\t\t\t\thostname: args.hostname,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = pulumi.output(args.hostname);\n\t\tthis.configured = resource.configured;\n\t\tthis.dnsRequirements = resource.dnsRequirements;\n\n\t\tthis.registerOutputs({\n\t\t\tid: this.id,\n\t\t\tconfigured: this.configured,\n\t\t\tdnsRequirements: this.dnsRequirements,\n\t\t});\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAqDA,IAAM,iCAAN,MAEA;CACC,MAAM,OACL,QACuC;EACvC,MAAM,SAAS,IAAIA,6BAAU,OAAO,KAAK;EACzC,MAAM,OAAO,YAAY,OAAO,QAAQ,gBAAgB,mBAAmB,OAAO,QAAQ;EAE1F,IAAI,OAAO,MAAM,OAAO,OAA+B,IAAI;EAE3D,IAAI,MACH,eAAO,IAAI,KAAK,sCAAsC,OAAO,SAAS,EAAE;OAExE,OAAO,MAAM,OAAO,KACnB,YAAY,OAAO,QAAQ,qBAC3B,EAAE,UAAU,OAAO,SAAS,CAC7B;EAGD,MAAM,OAA8B;GACnC,GAAG;GACH,YAAY,KAAK,cAAc;GAC/B,iBAAiB,KAAK,oBAAoB,CAAC;EAC5C;EAEA,OAAO;GAAE,IAAI,OAAO;GAAU;EAAK;CACpC;CAEA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,OAAO,MAAM,IAFAA,6BAAU,MAAM,KAEX,EAAE,OACzB,YAAY,MAAM,QAAQ,gBAAgB,mBAAmB,EAAE,GAChE;EAEA,IAAI,CAAC,MAEJ,OAAO,CAAC;EAGT,OAAO;GACN;GACA,OAAO;IACN,GAAG;IACH,YAAY,KAAK,cAAc;IAC/B,iBAAiB,KAAK,oBAAoB,CAAC;GAC5C;EACD;CACD;CAEA,MAAM,OACL,KACA,OACA,MACuC;EAEvC,OAAO,EACN,MAAM;GAAE,GAAG;GAAM,YAAY;GAAO,iBAAiB,CAAC;EAAE,EACzD;CACD;CAEA,MAAM,OAAO,IAAY,OAA6C;EACrE,MAAM,SAAS,IAAIA,6BAAU,MAAM,KAAK;EAExC,IAAI;GACH,MAAM,OAAO,OACZ,YAAY,MAAM,QAAQ,gBAAgB,mBAAmB,EAAE,GAChE;EACD,SAAS,OAAO;GAEf,IAAI,iBAAiBC,qDAAkB;IACtC,eAAO,IAAI,KAAK,oBAAoB,GAAG,kBAAkB;IAEzD;GACD;GAEA,MAAM;EACP;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,YAAY,KAAK,SACzB,SAAS,KAAK,SAAS;EAGxB,IAAI,KAAK,aAAa,KAAK,UAC1B,SAAS,KAAK,UAAU;EAGzB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,yBAAN,cAAqCC,eAAO,QAAQ,SAAS;CAI5D,YACC,MACA,MAKA,MACC;EACD,MACC,IAAI,+BAA+B,GACnC,MACA;GAAE,GAAG;GAAM,YAAY;GAAW,iBAAiB;EAAU,GAE7D;GAAE,GAAG;GAAM,yBAAyB,CAAC,OAAO;EAAE,CAC/C;CACD;AACD;;;;;;;;;;;;;;AAiCA,IAAa,iBAAb,cAAoCA,eAAO,kBAAkB;CAU5D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,KAAK,GAAG,eAAe;EAEzC,MAAM,8BAA8B,MAAM,CAAC,GAAG,UAAU;EAExD,MAAM,WAAW,IAAI,uBACpB,GAAG,KAAK,YACR;GACC,OAAO,SAAS;GAChB,SAAS,IAAI;GACb,UAAU,KAAK;EAChB,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,KAAKA,eAAO,OAAO,KAAK,QAAQ;EACrC,KAAK,aAAa,SAAS;EAC3B,KAAK,kBAAkB,SAAS;EAEhC,KAAK,gBAAgB;GACpB,IAAI,KAAK;GACT,YAAY,KAAK;GACjB,iBAAiB,KAAK;EACvB,CAAC;CACF;AACD"}
1
+ {"version":3,"file":"certificate.cjs","names":["FlyClient","ApiNotFoundError","pulumi"],"sources":["../../src/fly/certificate.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\n\nimport { ApiNotFoundError } from \"../errors/api-not-found-error\";\nimport type { FlyApp } from \"./app\";\nimport { FlyClient } from \"./client\";\nimport type { FlyProvider } from \"./provider\";\n\n/** DNS records the consumer must create for certificate validation. */\nexport interface FlyDnsRequirements {\n\t/** ACME challenge CNAME record. */\n\tacme_challenge?: { name: string; target: string };\n\n\t/** `_fly-ownership` TXT record. */\n\townership?: { name: string; app_value: string };\n\n\t/** CNAME target for the hostname itself. */\n\tcname?: string;\n}\n\n/** Resolved inputs for the Fly certificate dynamic provider. */\ninterface FlyCertificateInputs {\n\t/** Fly API token. */\n\ttoken: string;\n\n\t/** App name the certificate belongs to. */\n\tappName: string;\n\n\t/** Hostname to issue an ACME certificate for. Used as the resource key. */\n\thostname: string;\n}\n\n/** Persisted state for the Fly certificate. */\ninterface FlyCertificateOutputs extends FlyCertificateInputs {\n\t/** Whether the certificate is fully provisioned (DNS correct). */\n\tconfigured: boolean;\n\n\t/** DNS records required for validation. */\n\tdnsRequirements: FlyDnsRequirements;\n}\n\n/** Certificate response (only the fields we read). */\ninterface FlyCertificateResponse {\n\thostname: string;\n\tconfigured: boolean;\n\tdns_requirements?: FlyDnsRequirements;\n}\n\n/**\n * Dynamic provider for Fly ACME (Let's Encrypt) certificates. `create()` checks\n * for an existing cert by hostname and adopts it, otherwise it requests one via\n * `POST /v1/apps/{app}/certificates/acme`. The Machines API returns no `id` —\n * the hostname is the resource key.\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class FlyCertificateResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new FlyClient(inputs.token);\n\t\tconst path = `/v1/apps/${inputs.appName}/certificates/${encodeURIComponent(inputs.hostname)}`;\n\n\t\tlet cert = await client.tryGet<FlyCertificateResponse>(path);\n\n\t\tif (cert) {\n\t\t\tpulumi.log.info(`Adopting existing Fly certificate \"${inputs.hostname}\"`);\n\t\t} else {\n\t\t\tcert = await client.post<FlyCertificateResponse>(\n\t\t\t\t`/v1/apps/${inputs.appName}/certificates/acme`,\n\t\t\t\t{ hostname: inputs.hostname },\n\t\t\t);\n\t\t}\n\n\t\tconst outs: FlyCertificateOutputs = {\n\t\t\t...inputs,\n\t\t\tconfigured: cert.configured ?? false,\n\t\t\tdnsRequirements: cert.dns_requirements ?? {},\n\t\t};\n\n\t\treturn { id: inputs.hostname, outs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: FlyCertificateOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\tconst cert = await client.tryGet<FlyCertificateResponse>(\n\t\t\t`/v1/apps/${props.appName}/certificates/${encodeURIComponent(id)}`,\n\t\t);\n\n\t\tif (!cert) {\n\t\t\t// Resource gone → blank id lets refresh reconcile the deletion.\n\t\t\treturn {};\n\t\t}\n\n\t\treturn {\n\t\t\tid,\n\t\t\tprops: {\n\t\t\t\t...props,\n\t\t\t\tconfigured: cert.configured ?? false,\n\t\t\t\tdnsRequirements: cert.dns_requirements ?? {},\n\t\t\t},\n\t\t};\n\t}\n\n\tasync update(\n\t\t_id: string,\n\t\t_olds: FlyCertificateOutputs,\n\t\tnews: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\t// Hostname/app changes force replacement (see diff); nothing else is updatable.\n\t\treturn {\n\t\t\touts: { ...news, configured: false, dnsRequirements: {} },\n\t\t};\n\t}\n\n\tasync delete(id: string, props: FlyCertificateOutputs): Promise<void> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\ttry {\n\t\t\tawait client.delete(\n\t\t\t\t`/v1/apps/${props.appName}/certificates/${encodeURIComponent(id)}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// Already gone — deletion is idempotent.\n\t\t\tif (error instanceof ApiNotFoundError) {\n\t\t\t\tpulumi.log.warn(`Fly certificate \"${id}\" already deleted`);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: FlyCertificateOutputs,\n\t\tnews: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.appName !== news.appName) {\n\t\t\treplaces.push(\"appName\");\n\t\t}\n\n\t\tif (olds.hostname !== news.hostname) {\n\t\t\treplaces.push(\"hostname\");\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/** Internal dynamic resource — not part of the public API. */\nclass FlyCertificateResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly configured: pulumi.Output<boolean>;\n\tpublic declare readonly dnsRequirements: pulumi.Output<FlyDnsRequirements>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tappName: pulumi.Input<string>;\n\t\t\thostname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew FlyCertificateResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, configured: undefined, dnsRequirements: undefined },\n\t\t\t// The API token flows into dynamic-provider state with the outputs — mark it secret there.\n\t\t\t{ ...opts, additionalSecretOutputs: [\"token\"] },\n\t\t);\n\t}\n}\n\n/** Options type for FlyCertificate. */\ntype FlyCertificateOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Fly authentication context. */\n\tprovider: FlyProvider;\n\n\t/** App the certificate belongs to. */\n\tapp: FlyApp;\n};\n\n/** Args for FlyCertificate. */\nexport interface FlyCertificateArgs {\n\t/** Hostname to issue an ACME certificate for (e.g. `\"api.example.com\"`). */\n\thostname: pulumi.Input<string>;\n}\n\n/**\n * Manages a Fly ACME certificate for a custom hostname.\n *\n * Exposes `.configured` and `.dnsRequirements` so the consumer can wire up the\n * required DNS records.\n *\n * @example\n * ```typescript\n * const cert = new FlyCertificate(\"api-cert\", {\n * hostname: \"api.example.com\",\n * }, { provider, app });\n * ```\n */\nexport class FlyCertificate extends pulumi.ComponentResource {\n\t/** Certificate identifier (equals the hostname). */\n\tpublic readonly id: pulumi.Output<string>;\n\n\t/** Whether the certificate is fully provisioned. */\n\tpublic readonly configured: pulumi.Output<boolean>;\n\n\t/** DNS records required for validation. */\n\tpublic readonly dnsRequirements: pulumi.Output<FlyDnsRequirements>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: FlyCertificateArgs,\n\t\topts: FlyCertificateOptions,\n\t) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Certificate\", name, {}, pulumiOpts);\n\n\t\tconst resource = new FlyCertificateResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tappName: app.id,\n\t\t\t\thostname: args.hostname,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = pulumi.output(args.hostname);\n\t\tthis.configured = resource.configured;\n\t\tthis.dnsRequirements = resource.dnsRequirements;\n\n\t\tthis.registerOutputs({\n\t\t\tid: this.id,\n\t\t\tconfigured: this.configured,\n\t\t\tdnsRequirements: this.dnsRequirements,\n\t\t});\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAuDA,IAAa,iCAAb,MAEA;CACC,MAAM,OACL,QACuC;EACvC,MAAM,SAAS,IAAIA,6BAAU,OAAO,KAAK;EACzC,MAAM,OAAO,YAAY,OAAO,QAAQ,gBAAgB,mBAAmB,OAAO,QAAQ;EAE1F,IAAI,OAAO,MAAM,OAAO,OAA+B,IAAI;EAE3D,IAAI,MACH,eAAO,IAAI,KAAK,sCAAsC,OAAO,SAAS,EAAE;OAExE,OAAO,MAAM,OAAO,KACnB,YAAY,OAAO,QAAQ,qBAC3B,EAAE,UAAU,OAAO,SAAS,CAC7B;EAGD,MAAM,OAA8B;GACnC,GAAG;GACH,YAAY,KAAK,cAAc;GAC/B,iBAAiB,KAAK,oBAAoB,CAAC;EAC5C;EAEA,OAAO;GAAE,IAAI,OAAO;GAAU;EAAK;CACpC;CAEA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,OAAO,MAAM,IAFAA,6BAAU,MAAM,KAEX,EAAE,OACzB,YAAY,MAAM,QAAQ,gBAAgB,mBAAmB,EAAE,GAChE;EAEA,IAAI,CAAC,MAEJ,OAAO,CAAC;EAGT,OAAO;GACN;GACA,OAAO;IACN,GAAG;IACH,YAAY,KAAK,cAAc;IAC/B,iBAAiB,KAAK,oBAAoB,CAAC;GAC5C;EACD;CACD;CAEA,MAAM,OACL,KACA,OACA,MACuC;EAEvC,OAAO,EACN,MAAM;GAAE,GAAG;GAAM,YAAY;GAAO,iBAAiB,CAAC;EAAE,EACzD;CACD;CAEA,MAAM,OAAO,IAAY,OAA6C;EACrE,MAAM,SAAS,IAAIA,6BAAU,MAAM,KAAK;EAExC,IAAI;GACH,MAAM,OAAO,OACZ,YAAY,MAAM,QAAQ,gBAAgB,mBAAmB,EAAE,GAChE;EACD,SAAS,OAAO;GAEf,IAAI,iBAAiBC,qDAAkB;IACtC,eAAO,IAAI,KAAK,oBAAoB,GAAG,kBAAkB;IAEzD;GACD;GAEA,MAAM;EACP;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,YAAY,KAAK,SACzB,SAAS,KAAK,SAAS;EAGxB,IAAI,KAAK,aAAa,KAAK,UAC1B,SAAS,KAAK,UAAU;EAGzB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,yBAAN,cAAqCC,eAAO,QAAQ,SAAS;CAI5D,YACC,MACA,MAKA,MACC;EACD,MACC,IAAI,+BAA+B,GACnC,MACA;GAAE,GAAG;GAAM,YAAY;GAAW,iBAAiB;EAAU,GAE7D;GAAE,GAAG;GAAM,yBAAyB,CAAC,OAAO;EAAE,CAC/C;CACD;AACD;;;;;;;;;;;;;;AAiCA,IAAa,iBAAb,cAAoCA,eAAO,kBAAkB;CAU5D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,KAAK,GAAG,eAAe;EAEzC,MAAM,8BAA8B,MAAM,CAAC,GAAG,UAAU;EAExD,MAAM,WAAW,IAAI,uBACpB,GAAG,KAAK,YACR;GACC,OAAO,SAAS;GAChB,SAAS,IAAI;GACb,UAAU,KAAK;EAChB,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,KAAKA,eAAO,OAAO,KAAK,QAAQ;EACrC,KAAK,aAAa,SAAS;EAC3B,KAAK,kBAAkB,SAAS;EAEhC,KAAK,gBAAgB;GACpB,IAAI,KAAK;GACT,YAAY,KAAK;GACjB,iBAAiB,KAAK;EACvB,CAAC;CACF;AACD"}
@@ -19,6 +19,37 @@ interface FlyDnsRequirements {
19
19
  /** CNAME target for the hostname itself. */
20
20
  cname?: string;
21
21
  }
22
+ /** Resolved inputs for the Fly certificate dynamic provider. */
23
+ interface FlyCertificateInputs {
24
+ /** Fly API token. */
25
+ token: string;
26
+ /** App name the certificate belongs to. */
27
+ appName: string;
28
+ /** Hostname to issue an ACME certificate for. Used as the resource key. */
29
+ hostname: string;
30
+ }
31
+ /** Persisted state for the Fly certificate. */
32
+ interface FlyCertificateOutputs extends FlyCertificateInputs {
33
+ /** Whether the certificate is fully provisioned (DNS correct). */
34
+ configured: boolean;
35
+ /** DNS records required for validation. */
36
+ dnsRequirements: FlyDnsRequirements;
37
+ }
38
+ /**
39
+ * Dynamic provider for Fly ACME (Let's Encrypt) certificates. `create()` checks
40
+ * for an existing cert by hostname and adopts it, otherwise it requests one via
41
+ * `POST /v1/apps/{app}/certificates/acme`. The Machines API returns no `id` —
42
+ * the hostname is the resource key.
43
+ *
44
+ * @internal Exported only for unit testing; not part of the public API surface.
45
+ */
46
+ declare class FlyCertificateResourceProvider implements pulumi.dynamic.ResourceProvider {
47
+ create(inputs: FlyCertificateInputs): Promise<pulumi.dynamic.CreateResult>;
48
+ read(id: string, props: FlyCertificateOutputs): Promise<pulumi.dynamic.ReadResult>;
49
+ update(_id: string, _olds: FlyCertificateOutputs, news: FlyCertificateInputs): Promise<pulumi.dynamic.UpdateResult>;
50
+ delete(id: string, props: FlyCertificateOutputs): Promise<void>;
51
+ diff(_id: string, olds: FlyCertificateOutputs, news: FlyCertificateInputs): Promise<pulumi.dynamic.DiffResult>;
52
+ }
22
53
  /** Options type for FlyCertificate. */
23
54
  type FlyCertificateOptions = Omit<pulumi.ComponentResourceOptions, "provider"> & {
24
55
  /** Fly authentication context. */provider: FlyProvider; /** App the certificate belongs to. */
@@ -52,5 +83,5 @@ declare class FlyCertificate extends pulumi.ComponentResource {
52
83
  constructor(name: string, args: FlyCertificateArgs, opts: FlyCertificateOptions);
53
84
  }
54
85
  //#endregion
55
- export { FlyCertificate, FlyCertificateArgs, FlyDnsRequirements };
86
+ export { FlyCertificate, FlyCertificateArgs, FlyCertificateResourceProvider, FlyDnsRequirements };
56
87
  //# sourceMappingURL=certificate.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"certificate.d.cts","names":[],"sources":["../../src/fly/certificate.ts"],"mappings":";;;;;;;UAQiB,kBAAA;;EAEhB,cAAA;IAAmB,IAAA;IAAc,MAAA;EAAA;EAAjC;EAGA,SAAA;IAAc,IAAA;IAAc,SAAA;EAAA;EAAA;EAG5B,KAAA;AAAA;AAAK;AAAA,KAyKD,qBAAA,GAAwB,IAAA,CAC5B,MAAA,CAAO,wBAAA;EADkB,kCAKzB,QAAA,EAAU,WAAA,EAJV;EAOA,GAAA,EAAK,MAAA;AAAA;;UAIW,kBAAA;EAJL;EAMX,QAAA,EAAU,MAAA,CAAO,KAAK;AAAA;;;;;;;AANX;AAIZ;;;;;;cAkBa,cAAA,SAAuB,MAAA,CAAO,iBAAA;EAhBpB;EAAA,SAkBN,EAAA,EAAI,MAAA,CAAO,MAAA;EAFf;EAAA,SAKI,UAAA,EAAY,MAAA,CAAO,MAAA;;WAGnB,eAAA,EAAiB,MAAA,CAAO,MAAA,CAAO,kBAAA;cAG9C,IAAA,UACA,IAAA,EAAM,kBAAA,EACN,IAAA,EAAM,qBAAA;AAAA"}
1
+ {"version":3,"file":"certificate.d.cts","names":[],"sources":["../../src/fly/certificate.ts"],"mappings":";;;;;;;UAQiB,kBAAA;;EAEhB,cAAA;IAAmB,IAAA;IAAc,MAAA;EAAA;EAAjC;EAGA,SAAA;IAAc,IAAA;IAAc,SAAA;EAAA;EAAA;EAG5B,KAAA;AAAA;AAAK;AAAA,UAII,oBAAA;EAAoB;EAE7B,KAAA;EAF6B;EAK7B,OAAA;EAAA;EAGA,QAAA;AAAA;AAAQ;AAAA,UAIC,qBAAA,SAA8B,oBAAoB;EAA5B;EAE/B,UAAA;EAF2D;EAK3D,eAAA,EAAiB,kBAAA;AAAA;;;;AAAkB;AAkBpC;;;;cAAa,8BAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,oBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAwBpB,IAAA,CACL,EAAA,UACA,KAAA,EAAO,qBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAsBpB,MAAA,CACL,GAAA,UACA,KAAA,EAAO,qBAAA,EACP,IAAA,EAAM,oBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAOpB,MAAA,CAAO,EAAA,UAAY,KAAA,EAAO,qBAAA,GAAwB,OAAA;EAmBlD,IAAA,CACL,GAAA,UACA,IAAA,EAAM,qBAAA,EACN,IAAA,EAAM,oBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KA4CtB,qBAAA,GAAwB,IAAA,CAC5B,MAAA,CAAO,wBAAA;EApEyB,kCAwEhC,QAAA,EAAU,WAAA,EAnDH;EAsDP,GAAA,EAAK,MAAA;AAAA;;UAIW,kBAAA;EA/I0B;EAiJ1C,QAAA,EAAU,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;;;cAgBV,cAAA,SAAuB,MAAA,CAAO,iBAAA;EAlI/B;EAAA,SAoIK,EAAA,EAAI,MAAA,CAAO,MAAA;EApID;EAAA,SAuIV,UAAA,EAAY,MAAA,CAAO,MAAA;EAhHlC;EAAA,SAmHe,eAAA,EAAiB,MAAA,CAAO,MAAA,CAAO,kBAAA;cAG9C,IAAA,UACA,IAAA,EAAM,kBAAA,EACN,IAAA,EAAM,qBAAA;AAAA"}
@@ -19,6 +19,37 @@ interface FlyDnsRequirements {
19
19
  /** CNAME target for the hostname itself. */
20
20
  cname?: string;
21
21
  }
22
+ /** Resolved inputs for the Fly certificate dynamic provider. */
23
+ interface FlyCertificateInputs {
24
+ /** Fly API token. */
25
+ token: string;
26
+ /** App name the certificate belongs to. */
27
+ appName: string;
28
+ /** Hostname to issue an ACME certificate for. Used as the resource key. */
29
+ hostname: string;
30
+ }
31
+ /** Persisted state for the Fly certificate. */
32
+ interface FlyCertificateOutputs extends FlyCertificateInputs {
33
+ /** Whether the certificate is fully provisioned (DNS correct). */
34
+ configured: boolean;
35
+ /** DNS records required for validation. */
36
+ dnsRequirements: FlyDnsRequirements;
37
+ }
38
+ /**
39
+ * Dynamic provider for Fly ACME (Let's Encrypt) certificates. `create()` checks
40
+ * for an existing cert by hostname and adopts it, otherwise it requests one via
41
+ * `POST /v1/apps/{app}/certificates/acme`. The Machines API returns no `id` —
42
+ * the hostname is the resource key.
43
+ *
44
+ * @internal Exported only for unit testing; not part of the public API surface.
45
+ */
46
+ declare class FlyCertificateResourceProvider implements pulumi.dynamic.ResourceProvider {
47
+ create(inputs: FlyCertificateInputs): Promise<pulumi.dynamic.CreateResult>;
48
+ read(id: string, props: FlyCertificateOutputs): Promise<pulumi.dynamic.ReadResult>;
49
+ update(_id: string, _olds: FlyCertificateOutputs, news: FlyCertificateInputs): Promise<pulumi.dynamic.UpdateResult>;
50
+ delete(id: string, props: FlyCertificateOutputs): Promise<void>;
51
+ diff(_id: string, olds: FlyCertificateOutputs, news: FlyCertificateInputs): Promise<pulumi.dynamic.DiffResult>;
52
+ }
22
53
  /** Options type for FlyCertificate. */
23
54
  type FlyCertificateOptions = Omit<pulumi.ComponentResourceOptions, "provider"> & {
24
55
  /** Fly authentication context. */provider: FlyProvider; /** App the certificate belongs to. */
@@ -52,5 +83,5 @@ declare class FlyCertificate extends pulumi.ComponentResource {
52
83
  constructor(name: string, args: FlyCertificateArgs, opts: FlyCertificateOptions);
53
84
  }
54
85
  //#endregion
55
- export { FlyCertificate, FlyCertificateArgs, FlyDnsRequirements };
86
+ export { FlyCertificate, FlyCertificateArgs, FlyCertificateResourceProvider, FlyDnsRequirements };
56
87
  //# sourceMappingURL=certificate.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"certificate.d.mts","names":[],"sources":["../../src/fly/certificate.ts"],"mappings":";;;;;;;UAQiB,kBAAA;;EAEhB,cAAA;IAAmB,IAAA;IAAc,MAAA;EAAA;EAAjC;EAGA,SAAA;IAAc,IAAA;IAAc,SAAA;EAAA;EAAA;EAG5B,KAAA;AAAA;AAAK;AAAA,KAyKD,qBAAA,GAAwB,IAAA,CAC5B,MAAA,CAAO,wBAAA;EADkB,kCAKzB,QAAA,EAAU,WAAA,EAJV;EAOA,GAAA,EAAK,MAAA;AAAA;;UAIW,kBAAA;EAJL;EAMX,QAAA,EAAU,MAAA,CAAO,KAAK;AAAA;;;;;;;AANX;AAIZ;;;;;;cAkBa,cAAA,SAAuB,MAAA,CAAO,iBAAA;EAhBpB;EAAA,SAkBN,EAAA,EAAI,MAAA,CAAO,MAAA;EAFf;EAAA,SAKI,UAAA,EAAY,MAAA,CAAO,MAAA;;WAGnB,eAAA,EAAiB,MAAA,CAAO,MAAA,CAAO,kBAAA;cAG9C,IAAA,UACA,IAAA,EAAM,kBAAA,EACN,IAAA,EAAM,qBAAA;AAAA"}
1
+ {"version":3,"file":"certificate.d.mts","names":[],"sources":["../../src/fly/certificate.ts"],"mappings":";;;;;;;UAQiB,kBAAA;;EAEhB,cAAA;IAAmB,IAAA;IAAc,MAAA;EAAA;EAAjC;EAGA,SAAA;IAAc,IAAA;IAAc,SAAA;EAAA;EAAA;EAG5B,KAAA;AAAA;AAAK;AAAA,UAII,oBAAA;EAAoB;EAE7B,KAAA;EAF6B;EAK7B,OAAA;EAAA;EAGA,QAAA;AAAA;AAAQ;AAAA,UAIC,qBAAA,SAA8B,oBAAoB;EAA5B;EAE/B,UAAA;EAF2D;EAK3D,eAAA,EAAiB,kBAAA;AAAA;;;;AAAkB;AAkBpC;;;;cAAa,8BAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,oBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAwBpB,IAAA,CACL,EAAA,UACA,KAAA,EAAO,qBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAsBpB,MAAA,CACL,GAAA,UACA,KAAA,EAAO,qBAAA,EACP,IAAA,EAAM,oBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAOpB,MAAA,CAAO,EAAA,UAAY,KAAA,EAAO,qBAAA,GAAwB,OAAA;EAmBlD,IAAA,CACL,GAAA,UACA,IAAA,EAAM,qBAAA,EACN,IAAA,EAAM,oBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KA4CtB,qBAAA,GAAwB,IAAA,CAC5B,MAAA,CAAO,wBAAA;EApEyB,kCAwEhC,QAAA,EAAU,WAAA,EAnDH;EAsDP,GAAA,EAAK,MAAA;AAAA;;UAIW,kBAAA;EA/I0B;EAiJ1C,QAAA,EAAU,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;;;cAgBV,cAAA,SAAuB,MAAA,CAAO,iBAAA;EAlI/B;EAAA,SAoIK,EAAA,EAAI,MAAA,CAAO,MAAA;EApID;EAAA,SAuIV,UAAA,EAAY,MAAA,CAAO,MAAA;EAhHlC;EAAA,SAmHe,eAAA,EAAiB,MAAA,CAAO,MAAA,CAAO,kBAAA;cAG9C,IAAA,UACA,IAAA,EAAM,kBAAA,EACN,IAAA,EAAM,qBAAA;AAAA"}
@@ -9,6 +9,8 @@ import * as pulumi from "@pulumi/pulumi";
9
9
  * for an existing cert by hostname and adopts it, otherwise it requests one via
10
10
  * `POST /v1/apps/{app}/certificates/acme`. The Machines API returns no `id` —
11
11
  * the hostname is the resource key.
12
+ *
13
+ * @internal Exported only for unit testing; not part of the public API surface.
12
14
  */
13
15
  var FlyCertificateResourceProvider = class {
14
16
  async create(inputs) {
@@ -116,5 +118,5 @@ var FlyCertificate = class extends pulumi.ComponentResource {
116
118
  };
117
119
 
118
120
  //#endregion
119
- export { FlyCertificate };
121
+ export { FlyCertificate, FlyCertificateResourceProvider };
120
122
  //# sourceMappingURL=certificate.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"certificate.mjs","names":[],"sources":["../../src/fly/certificate.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\n\nimport { ApiNotFoundError } from \"../errors/api-not-found-error\";\nimport type { FlyApp } from \"./app\";\nimport { FlyClient } from \"./client\";\nimport type { FlyProvider } from \"./provider\";\n\n/** DNS records the consumer must create for certificate validation. */\nexport interface FlyDnsRequirements {\n\t/** ACME challenge CNAME record. */\n\tacme_challenge?: { name: string; target: string };\n\n\t/** `_fly-ownership` TXT record. */\n\townership?: { name: string; app_value: string };\n\n\t/** CNAME target for the hostname itself. */\n\tcname?: string;\n}\n\n/** Resolved inputs for the Fly certificate dynamic provider. */\ninterface FlyCertificateInputs {\n\t/** Fly API token. */\n\ttoken: string;\n\n\t/** App name the certificate belongs to. */\n\tappName: string;\n\n\t/** Hostname to issue an ACME certificate for. Used as the resource key. */\n\thostname: string;\n}\n\n/** Persisted state for the Fly certificate. */\ninterface FlyCertificateOutputs extends FlyCertificateInputs {\n\t/** Whether the certificate is fully provisioned (DNS correct). */\n\tconfigured: boolean;\n\n\t/** DNS records required for validation. */\n\tdnsRequirements: FlyDnsRequirements;\n}\n\n/** Certificate response (only the fields we read). */\ninterface FlyCertificateResponse {\n\thostname: string;\n\tconfigured: boolean;\n\tdns_requirements?: FlyDnsRequirements;\n}\n\n/**\n * Dynamic provider for Fly ACME (Let's Encrypt) certificates. `create()` checks\n * for an existing cert by hostname and adopts it, otherwise it requests one via\n * `POST /v1/apps/{app}/certificates/acme`. The Machines API returns no `id` —\n * the hostname is the resource key.\n */\nclass FlyCertificateResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new FlyClient(inputs.token);\n\t\tconst path = `/v1/apps/${inputs.appName}/certificates/${encodeURIComponent(inputs.hostname)}`;\n\n\t\tlet cert = await client.tryGet<FlyCertificateResponse>(path);\n\n\t\tif (cert) {\n\t\t\tpulumi.log.info(`Adopting existing Fly certificate \"${inputs.hostname}\"`);\n\t\t} else {\n\t\t\tcert = await client.post<FlyCertificateResponse>(\n\t\t\t\t`/v1/apps/${inputs.appName}/certificates/acme`,\n\t\t\t\t{ hostname: inputs.hostname },\n\t\t\t);\n\t\t}\n\n\t\tconst outs: FlyCertificateOutputs = {\n\t\t\t...inputs,\n\t\t\tconfigured: cert.configured ?? false,\n\t\t\tdnsRequirements: cert.dns_requirements ?? {},\n\t\t};\n\n\t\treturn { id: inputs.hostname, outs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: FlyCertificateOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\tconst cert = await client.tryGet<FlyCertificateResponse>(\n\t\t\t`/v1/apps/${props.appName}/certificates/${encodeURIComponent(id)}`,\n\t\t);\n\n\t\tif (!cert) {\n\t\t\t// Resource gone → blank id lets refresh reconcile the deletion.\n\t\t\treturn {};\n\t\t}\n\n\t\treturn {\n\t\t\tid,\n\t\t\tprops: {\n\t\t\t\t...props,\n\t\t\t\tconfigured: cert.configured ?? false,\n\t\t\t\tdnsRequirements: cert.dns_requirements ?? {},\n\t\t\t},\n\t\t};\n\t}\n\n\tasync update(\n\t\t_id: string,\n\t\t_olds: FlyCertificateOutputs,\n\t\tnews: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\t// Hostname/app changes force replacement (see diff); nothing else is updatable.\n\t\treturn {\n\t\t\touts: { ...news, configured: false, dnsRequirements: {} },\n\t\t};\n\t}\n\n\tasync delete(id: string, props: FlyCertificateOutputs): Promise<void> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\ttry {\n\t\t\tawait client.delete(\n\t\t\t\t`/v1/apps/${props.appName}/certificates/${encodeURIComponent(id)}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// Already gone — deletion is idempotent.\n\t\t\tif (error instanceof ApiNotFoundError) {\n\t\t\t\tpulumi.log.warn(`Fly certificate \"${id}\" already deleted`);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: FlyCertificateOutputs,\n\t\tnews: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.appName !== news.appName) {\n\t\t\treplaces.push(\"appName\");\n\t\t}\n\n\t\tif (olds.hostname !== news.hostname) {\n\t\t\treplaces.push(\"hostname\");\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/** Internal dynamic resource — not part of the public API. */\nclass FlyCertificateResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly configured: pulumi.Output<boolean>;\n\tpublic declare readonly dnsRequirements: pulumi.Output<FlyDnsRequirements>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tappName: pulumi.Input<string>;\n\t\t\thostname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew FlyCertificateResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, configured: undefined, dnsRequirements: undefined },\n\t\t\t// The API token flows into dynamic-provider state with the outputs — mark it secret there.\n\t\t\t{ ...opts, additionalSecretOutputs: [\"token\"] },\n\t\t);\n\t}\n}\n\n/** Options type for FlyCertificate. */\ntype FlyCertificateOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Fly authentication context. */\n\tprovider: FlyProvider;\n\n\t/** App the certificate belongs to. */\n\tapp: FlyApp;\n};\n\n/** Args for FlyCertificate. */\nexport interface FlyCertificateArgs {\n\t/** Hostname to issue an ACME certificate for (e.g. `\"api.example.com\"`). */\n\thostname: pulumi.Input<string>;\n}\n\n/**\n * Manages a Fly ACME certificate for a custom hostname.\n *\n * Exposes `.configured` and `.dnsRequirements` so the consumer can wire up the\n * required DNS records.\n *\n * @example\n * ```typescript\n * const cert = new FlyCertificate(\"api-cert\", {\n * hostname: \"api.example.com\",\n * }, { provider, app });\n * ```\n */\nexport class FlyCertificate extends pulumi.ComponentResource {\n\t/** Certificate identifier (equals the hostname). */\n\tpublic readonly id: pulumi.Output<string>;\n\n\t/** Whether the certificate is fully provisioned. */\n\tpublic readonly configured: pulumi.Output<boolean>;\n\n\t/** DNS records required for validation. */\n\tpublic readonly dnsRequirements: pulumi.Output<FlyDnsRequirements>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: FlyCertificateArgs,\n\t\topts: FlyCertificateOptions,\n\t) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Certificate\", name, {}, pulumiOpts);\n\n\t\tconst resource = new FlyCertificateResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tappName: app.id,\n\t\t\t\thostname: args.hostname,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = pulumi.output(args.hostname);\n\t\tthis.configured = resource.configured;\n\t\tthis.dnsRequirements = resource.dnsRequirements;\n\n\t\tthis.registerOutputs({\n\t\t\tid: this.id,\n\t\t\tconfigured: this.configured,\n\t\t\tdnsRequirements: this.dnsRequirements,\n\t\t});\n\t}\n}\n"],"mappings":";;;;;;;;;;;;AAqDA,IAAM,iCAAN,MAEA;CACC,MAAM,OACL,QACuC;EACvC,MAAM,SAAS,IAAI,UAAU,OAAO,KAAK;EACzC,MAAM,OAAO,YAAY,OAAO,QAAQ,gBAAgB,mBAAmB,OAAO,QAAQ;EAE1F,IAAI,OAAO,MAAM,OAAO,OAA+B,IAAI;EAE3D,IAAI,MACH,OAAO,IAAI,KAAK,sCAAsC,OAAO,SAAS,EAAE;OAExE,OAAO,MAAM,OAAO,KACnB,YAAY,OAAO,QAAQ,qBAC3B,EAAE,UAAU,OAAO,SAAS,CAC7B;EAGD,MAAM,OAA8B;GACnC,GAAG;GACH,YAAY,KAAK,cAAc;GAC/B,iBAAiB,KAAK,oBAAoB,CAAC;EAC5C;EAEA,OAAO;GAAE,IAAI,OAAO;GAAU;EAAK;CACpC;CAEA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,OAAO,MAAM,IAFA,UAAU,MAAM,KAEX,EAAE,OACzB,YAAY,MAAM,QAAQ,gBAAgB,mBAAmB,EAAE,GAChE;EAEA,IAAI,CAAC,MAEJ,OAAO,CAAC;EAGT,OAAO;GACN;GACA,OAAO;IACN,GAAG;IACH,YAAY,KAAK,cAAc;IAC/B,iBAAiB,KAAK,oBAAoB,CAAC;GAC5C;EACD;CACD;CAEA,MAAM,OACL,KACA,OACA,MACuC;EAEvC,OAAO,EACN,MAAM;GAAE,GAAG;GAAM,YAAY;GAAO,iBAAiB,CAAC;EAAE,EACzD;CACD;CAEA,MAAM,OAAO,IAAY,OAA6C;EACrE,MAAM,SAAS,IAAI,UAAU,MAAM,KAAK;EAExC,IAAI;GACH,MAAM,OAAO,OACZ,YAAY,MAAM,QAAQ,gBAAgB,mBAAmB,EAAE,GAChE;EACD,SAAS,OAAO;GAEf,IAAI,iBAAiB,kBAAkB;IACtC,OAAO,IAAI,KAAK,oBAAoB,GAAG,kBAAkB;IAEzD;GACD;GAEA,MAAM;EACP;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,YAAY,KAAK,SACzB,SAAS,KAAK,SAAS;EAGxB,IAAI,KAAK,aAAa,KAAK,UAC1B,SAAS,KAAK,UAAU;EAGzB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,yBAAN,cAAqC,OAAO,QAAQ,SAAS;CAI5D,YACC,MACA,MAKA,MACC;EACD,MACC,IAAI,+BAA+B,GACnC,MACA;GAAE,GAAG;GAAM,YAAY;GAAW,iBAAiB;EAAU,GAE7D;GAAE,GAAG;GAAM,yBAAyB,CAAC,OAAO;EAAE,CAC/C;CACD;AACD;;;;;;;;;;;;;;AAiCA,IAAa,iBAAb,cAAoC,OAAO,kBAAkB;CAU5D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,KAAK,GAAG,eAAe;EAEzC,MAAM,8BAA8B,MAAM,CAAC,GAAG,UAAU;EAExD,MAAM,WAAW,IAAI,uBACpB,GAAG,KAAK,YACR;GACC,OAAO,SAAS;GAChB,SAAS,IAAI;GACb,UAAU,KAAK;EAChB,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,KAAK,OAAO,OAAO,KAAK,QAAQ;EACrC,KAAK,aAAa,SAAS;EAC3B,KAAK,kBAAkB,SAAS;EAEhC,KAAK,gBAAgB;GACpB,IAAI,KAAK;GACT,YAAY,KAAK;GACjB,iBAAiB,KAAK;EACvB,CAAC;CACF;AACD"}
1
+ {"version":3,"file":"certificate.mjs","names":[],"sources":["../../src/fly/certificate.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\n\nimport { ApiNotFoundError } from \"../errors/api-not-found-error\";\nimport type { FlyApp } from \"./app\";\nimport { FlyClient } from \"./client\";\nimport type { FlyProvider } from \"./provider\";\n\n/** DNS records the consumer must create for certificate validation. */\nexport interface FlyDnsRequirements {\n\t/** ACME challenge CNAME record. */\n\tacme_challenge?: { name: string; target: string };\n\n\t/** `_fly-ownership` TXT record. */\n\townership?: { name: string; app_value: string };\n\n\t/** CNAME target for the hostname itself. */\n\tcname?: string;\n}\n\n/** Resolved inputs for the Fly certificate dynamic provider. */\ninterface FlyCertificateInputs {\n\t/** Fly API token. */\n\ttoken: string;\n\n\t/** App name the certificate belongs to. */\n\tappName: string;\n\n\t/** Hostname to issue an ACME certificate for. Used as the resource key. */\n\thostname: string;\n}\n\n/** Persisted state for the Fly certificate. */\ninterface FlyCertificateOutputs extends FlyCertificateInputs {\n\t/** Whether the certificate is fully provisioned (DNS correct). */\n\tconfigured: boolean;\n\n\t/** DNS records required for validation. */\n\tdnsRequirements: FlyDnsRequirements;\n}\n\n/** Certificate response (only the fields we read). */\ninterface FlyCertificateResponse {\n\thostname: string;\n\tconfigured: boolean;\n\tdns_requirements?: FlyDnsRequirements;\n}\n\n/**\n * Dynamic provider for Fly ACME (Let's Encrypt) certificates. `create()` checks\n * for an existing cert by hostname and adopts it, otherwise it requests one via\n * `POST /v1/apps/{app}/certificates/acme`. The Machines API returns no `id` —\n * the hostname is the resource key.\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class FlyCertificateResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new FlyClient(inputs.token);\n\t\tconst path = `/v1/apps/${inputs.appName}/certificates/${encodeURIComponent(inputs.hostname)}`;\n\n\t\tlet cert = await client.tryGet<FlyCertificateResponse>(path);\n\n\t\tif (cert) {\n\t\t\tpulumi.log.info(`Adopting existing Fly certificate \"${inputs.hostname}\"`);\n\t\t} else {\n\t\t\tcert = await client.post<FlyCertificateResponse>(\n\t\t\t\t`/v1/apps/${inputs.appName}/certificates/acme`,\n\t\t\t\t{ hostname: inputs.hostname },\n\t\t\t);\n\t\t}\n\n\t\tconst outs: FlyCertificateOutputs = {\n\t\t\t...inputs,\n\t\t\tconfigured: cert.configured ?? false,\n\t\t\tdnsRequirements: cert.dns_requirements ?? {},\n\t\t};\n\n\t\treturn { id: inputs.hostname, outs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: FlyCertificateOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\tconst cert = await client.tryGet<FlyCertificateResponse>(\n\t\t\t`/v1/apps/${props.appName}/certificates/${encodeURIComponent(id)}`,\n\t\t);\n\n\t\tif (!cert) {\n\t\t\t// Resource gone → blank id lets refresh reconcile the deletion.\n\t\t\treturn {};\n\t\t}\n\n\t\treturn {\n\t\t\tid,\n\t\t\tprops: {\n\t\t\t\t...props,\n\t\t\t\tconfigured: cert.configured ?? false,\n\t\t\t\tdnsRequirements: cert.dns_requirements ?? {},\n\t\t\t},\n\t\t};\n\t}\n\n\tasync update(\n\t\t_id: string,\n\t\t_olds: FlyCertificateOutputs,\n\t\tnews: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.UpdateResult> {\n\t\t// Hostname/app changes force replacement (see diff); nothing else is updatable.\n\t\treturn {\n\t\t\touts: { ...news, configured: false, dnsRequirements: {} },\n\t\t};\n\t}\n\n\tasync delete(id: string, props: FlyCertificateOutputs): Promise<void> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\ttry {\n\t\t\tawait client.delete(\n\t\t\t\t`/v1/apps/${props.appName}/certificates/${encodeURIComponent(id)}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// Already gone — deletion is idempotent.\n\t\t\tif (error instanceof ApiNotFoundError) {\n\t\t\t\tpulumi.log.warn(`Fly certificate \"${id}\" already deleted`);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: FlyCertificateOutputs,\n\t\tnews: FlyCertificateInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.appName !== news.appName) {\n\t\t\treplaces.push(\"appName\");\n\t\t}\n\n\t\tif (olds.hostname !== news.hostname) {\n\t\t\treplaces.push(\"hostname\");\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/** Internal dynamic resource — not part of the public API. */\nclass FlyCertificateResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly configured: pulumi.Output<boolean>;\n\tpublic declare readonly dnsRequirements: pulumi.Output<FlyDnsRequirements>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tappName: pulumi.Input<string>;\n\t\t\thostname: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew FlyCertificateResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, configured: undefined, dnsRequirements: undefined },\n\t\t\t// The API token flows into dynamic-provider state with the outputs — mark it secret there.\n\t\t\t{ ...opts, additionalSecretOutputs: [\"token\"] },\n\t\t);\n\t}\n}\n\n/** Options type for FlyCertificate. */\ntype FlyCertificateOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Fly authentication context. */\n\tprovider: FlyProvider;\n\n\t/** App the certificate belongs to. */\n\tapp: FlyApp;\n};\n\n/** Args for FlyCertificate. */\nexport interface FlyCertificateArgs {\n\t/** Hostname to issue an ACME certificate for (e.g. `\"api.example.com\"`). */\n\thostname: pulumi.Input<string>;\n}\n\n/**\n * Manages a Fly ACME certificate for a custom hostname.\n *\n * Exposes `.configured` and `.dnsRequirements` so the consumer can wire up the\n * required DNS records.\n *\n * @example\n * ```typescript\n * const cert = new FlyCertificate(\"api-cert\", {\n * hostname: \"api.example.com\",\n * }, { provider, app });\n * ```\n */\nexport class FlyCertificate extends pulumi.ComponentResource {\n\t/** Certificate identifier (equals the hostname). */\n\tpublic readonly id: pulumi.Output<string>;\n\n\t/** Whether the certificate is fully provisioned. */\n\tpublic readonly configured: pulumi.Output<boolean>;\n\n\t/** DNS records required for validation. */\n\tpublic readonly dnsRequirements: pulumi.Output<FlyDnsRequirements>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: FlyCertificateArgs,\n\t\topts: FlyCertificateOptions,\n\t) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Certificate\", name, {}, pulumiOpts);\n\n\t\tconst resource = new FlyCertificateResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tappName: app.id,\n\t\t\t\thostname: args.hostname,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = pulumi.output(args.hostname);\n\t\tthis.configured = resource.configured;\n\t\tthis.dnsRequirements = resource.dnsRequirements;\n\n\t\tthis.registerOutputs({\n\t\t\tid: this.id,\n\t\t\tconfigured: this.configured,\n\t\t\tdnsRequirements: this.dnsRequirements,\n\t\t});\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAuDA,IAAa,iCAAb,MAEA;CACC,MAAM,OACL,QACuC;EACvC,MAAM,SAAS,IAAI,UAAU,OAAO,KAAK;EACzC,MAAM,OAAO,YAAY,OAAO,QAAQ,gBAAgB,mBAAmB,OAAO,QAAQ;EAE1F,IAAI,OAAO,MAAM,OAAO,OAA+B,IAAI;EAE3D,IAAI,MACH,OAAO,IAAI,KAAK,sCAAsC,OAAO,SAAS,EAAE;OAExE,OAAO,MAAM,OAAO,KACnB,YAAY,OAAO,QAAQ,qBAC3B,EAAE,UAAU,OAAO,SAAS,CAC7B;EAGD,MAAM,OAA8B;GACnC,GAAG;GACH,YAAY,KAAK,cAAc;GAC/B,iBAAiB,KAAK,oBAAoB,CAAC;EAC5C;EAEA,OAAO;GAAE,IAAI,OAAO;GAAU;EAAK;CACpC;CAEA,MAAM,KACL,IACA,OACqC;EAGrC,MAAM,OAAO,MAAM,IAFA,UAAU,MAAM,KAEX,EAAE,OACzB,YAAY,MAAM,QAAQ,gBAAgB,mBAAmB,EAAE,GAChE;EAEA,IAAI,CAAC,MAEJ,OAAO,CAAC;EAGT,OAAO;GACN;GACA,OAAO;IACN,GAAG;IACH,YAAY,KAAK,cAAc;IAC/B,iBAAiB,KAAK,oBAAoB,CAAC;GAC5C;EACD;CACD;CAEA,MAAM,OACL,KACA,OACA,MACuC;EAEvC,OAAO,EACN,MAAM;GAAE,GAAG;GAAM,YAAY;GAAO,iBAAiB,CAAC;EAAE,EACzD;CACD;CAEA,MAAM,OAAO,IAAY,OAA6C;EACrE,MAAM,SAAS,IAAI,UAAU,MAAM,KAAK;EAExC,IAAI;GACH,MAAM,OAAO,OACZ,YAAY,MAAM,QAAQ,gBAAgB,mBAAmB,EAAE,GAChE;EACD,SAAS,OAAO;GAEf,IAAI,iBAAiB,kBAAkB;IACtC,OAAO,IAAI,KAAK,oBAAoB,GAAG,kBAAkB;IAEzD;GACD;GAEA,MAAM;EACP;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,YAAY,KAAK,SACzB,SAAS,KAAK,SAAS;EAGxB,IAAI,KAAK,aAAa,KAAK,UAC1B,SAAS,KAAK,UAAU;EAGzB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,yBAAN,cAAqC,OAAO,QAAQ,SAAS;CAI5D,YACC,MACA,MAKA,MACC;EACD,MACC,IAAI,+BAA+B,GACnC,MACA;GAAE,GAAG;GAAM,YAAY;GAAW,iBAAiB;EAAU,GAE7D;GAAE,GAAG;GAAM,yBAAyB,CAAC,OAAO;EAAE,CAC/C;CACD;AACD;;;;;;;;;;;;;;AAiCA,IAAa,iBAAb,cAAoC,OAAO,kBAAkB;CAU5D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,KAAK,GAAG,eAAe;EAEzC,MAAM,8BAA8B,MAAM,CAAC,GAAG,UAAU;EAExD,MAAM,WAAW,IAAI,uBACpB,GAAG,KAAK,YACR;GACC,OAAO,SAAS;GAChB,SAAS,IAAI;GACb,UAAU,KAAK;EAChB,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,KAAK,OAAO,OAAO,KAAK,QAAQ;EACrC,KAAK,aAAa,SAAS;EAC3B,KAAK,kBAAkB,SAAS;EAEhC,KAAK,gBAAgB;GACpB,IAAI,KAAK;GACT,YAAY,KAAK;GACjB,iBAAiB,KAAK;EACvB,CAAC;CACF;AACD"}
@@ -9,6 +9,10 @@ _pulumi_pulumi = require_chunk.__toESM(_pulumi_pulumi, 1);
9
9
  /**
10
10
  * Deploys a Fly app via `fly deploy --remote-only` from a generated fly.toml.
11
11
  * Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).
12
+ *
13
+ * Recommended preflight: `assertHostBinaries(["fly"])` (from
14
+ * `@infracraft/pulumi/sandbox`) at program start, so a missing CLI fails fast
15
+ * with an install hint instead of mid-deploy.
12
16
  */
13
17
  var FlyDeploy = class extends _pulumi_pulumi.ComponentResource {
14
18
  constructor(name, args, opts) {
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.cjs","names":["pulumi","generateFlyToml","dependsOnList","createDeployCommand"],"sources":["../../src/fly/deploy.ts"],"sourcesContent":["// src/fly/deploy.ts (replace entire file)\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { createDeployCommand, dependsOnList } from \"../commands/deploy\";\nimport type { FlyApp } from \"./app\";\nimport type { FlyProvider } from \"./provider\";\nimport { type FlyTomlConfig, generateFlyToml } from \"./toml\";\n\ntype FlyDeployOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\tprovider: FlyProvider;\n\tapp: FlyApp;\n};\n\nexport interface FlyDeployArgs {\n\t/** fly.toml configuration. `config.app` must equal the FlyApp name. */\n\tconfig: FlyTomlConfig;\n\t/** Redeploy triggers; the generated toml content is appended automatically. */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\t/** `fly deploy --wait-timeout` seconds (default 300). */\n\twaitTimeout?: number;\n\t/** `fly deploy --release-command-timeout` seconds (default 600). */\n\treleaseCommandTimeout?: number;\n\t/** `fly deploy --ha` (default false). */\n\thighAvailability?: boolean;\n}\n\n/**\n * Deploys a Fly app via `fly deploy --remote-only` from a generated fly.toml.\n * Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).\n */\nexport class FlyDeploy extends pulumi.ComponentResource {\n\t/** The deploy CLI's final stdout line (the Fly app URL when emitted). */\n\tpublic readonly deploymentUrl: pulumi.Output<string>;\n\n\tconstructor(name: string, args: FlyDeployArgs, opts: FlyDeployOptions) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Deploy\", name, {}, pulumiOpts);\n\n\t\tconst tomlContent = generateFlyToml(args.config);\n\t\tconst configPath = `.fly/${args.config.app}.toml`;\n\n\t\tconst waitTimeout = args.waitTimeout ?? 300;\n\t\tconst releaseCommandTimeout = args.releaseCommandTimeout ?? 600;\n\t\tconst highAvailability = args.highAvailability ?? false;\n\n\t\t// The toml content arrives via FLY_TOML_CONTENT (avoids shell escaping).\n\t\tconst setup = `mkdir -p .fly && printf '%s' \"$FLY_TOML_CONTENT\" > ${configPath}`;\n\t\tconst cli = `fly deploy --config ${configPath} --remote-only --ha=${highAvailability} --wait-timeout ${waitTimeout} --release-command-timeout ${releaseCommandTimeout}`;\n\n\t\tconst triggers = pulumi\n\t\t\t.output(args.triggers)\n\t\t\t.apply((values) => [...values, tomlContent]);\n\n\t\t// Keep the `app` ordering anchor first; append the consumer's deps\n\t\t// (DeploySandbox / GitGuard) using the seam's shared normaliser.\n\t\tconst consumerDeps = dependsOnList(pulumiOpts) as pulumi.Resource[];\n\n\t\tconst { deploymentUrl } = createDeployCommand(\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tcli,\n\t\t\t\ttriggers,\n\t\t\t\tsetup,\n\t\t\t\tenvironment: {\n\t\t\t\t\tFLY_API_TOKEN: provider.token,\n\t\t\t\t\tFLY_TOML_CONTENT: tomlContent,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ ...pulumiOpts, parent: this, dependsOn: [app, ...consumerDeps] },\n\t\t);\n\n\t\tthis.deploymentUrl = deploymentUrl;\n\n\t\tthis.registerOutputs({ deploymentUrl: this.deploymentUrl });\n\t}\n}\n"],"mappings":";;;;;;;;;;;;AA8BA,IAAa,YAAb,cAA+BA,eAAO,kBAAkB;CAIvD,YAAY,MAAc,MAAqB,MAAwB;EACtE,MAAM,EAAE,UAAU,KAAK,GAAG,eAAe;EAEzC,MAAM,yBAAyB,MAAM,CAAC,GAAG,UAAU;EAEnD,MAAM,cAAcC,iCAAgB,KAAK,MAAM;EAC/C,MAAM,aAAa,QAAQ,KAAK,OAAO,IAAI;EAE3C,MAAM,cAAc,KAAK,eAAe;EACxC,MAAM,wBAAwB,KAAK,yBAAyB;EAC5D,MAAM,mBAAmB,KAAK,oBAAoB;EAGlD,MAAM,QAAQ,sDAAsD;EACpE,MAAM,MAAM,uBAAuB,WAAW,sBAAsB,iBAAiB,kBAAkB,YAAY,6BAA6B;EAEhJ,MAAM,WAAWD,eACf,OAAO,KAAK,QAAQ,EACpB,OAAO,WAAW,CAAC,GAAG,QAAQ,WAAW,CAAC;EAI5C,MAAM,eAAeE,sCAAc,UAAU;EAE7C,MAAM,EAAE,kBAAkBC,4CACzB;GACC;GACA;GACA;GACA;GACA,aAAa;IACZ,eAAe,SAAS;IACxB,kBAAkB;GACnB;EACD,GACA;GAAE,GAAG;GAAY,QAAQ;GAAM,WAAW,CAAC,KAAK,GAAG,YAAY;EAAE,CAClE;EAEA,KAAK,gBAAgB;EAErB,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,CAAC;CAC3D;AACD"}
1
+ {"version":3,"file":"deploy.cjs","names":["pulumi","generateFlyToml","dependsOnList","createDeployCommand"],"sources":["../../src/fly/deploy.ts"],"sourcesContent":["// src/fly/deploy.ts (replace entire file)\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { createDeployCommand, dependsOnList } from \"../commands/deploy\";\nimport type { FlyApp } from \"./app\";\nimport type { FlyProvider } from \"./provider\";\nimport { type FlyTomlConfig, generateFlyToml } from \"./toml\";\n\ntype FlyDeployOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\tprovider: FlyProvider;\n\tapp: FlyApp;\n};\n\nexport interface FlyDeployArgs {\n\t/** fly.toml configuration. `config.app` must equal the FlyApp name. */\n\tconfig: FlyTomlConfig;\n\t/** Redeploy triggers; the generated toml content is appended automatically. */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\t/** `fly deploy --wait-timeout` seconds (default 300). */\n\twaitTimeout?: number;\n\t/** `fly deploy --release-command-timeout` seconds (default 600). */\n\treleaseCommandTimeout?: number;\n\t/** `fly deploy --ha` (default false). */\n\thighAvailability?: boolean;\n}\n\n/**\n * Deploys a Fly app via `fly deploy --remote-only` from a generated fly.toml.\n * Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).\n *\n * Recommended preflight: `assertHostBinaries([\"fly\"])` (from\n * `@infracraft/pulumi/sandbox`) at program start, so a missing CLI fails fast\n * with an install hint instead of mid-deploy.\n */\nexport class FlyDeploy extends pulumi.ComponentResource {\n\t/** The deploy CLI's final stdout line (the Fly app URL when emitted). */\n\tpublic readonly deploymentUrl: pulumi.Output<string>;\n\n\tconstructor(name: string, args: FlyDeployArgs, opts: FlyDeployOptions) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Deploy\", name, {}, pulumiOpts);\n\n\t\tconst tomlContent = generateFlyToml(args.config);\n\t\tconst configPath = `.fly/${args.config.app}.toml`;\n\n\t\tconst waitTimeout = args.waitTimeout ?? 300;\n\t\tconst releaseCommandTimeout = args.releaseCommandTimeout ?? 600;\n\t\tconst highAvailability = args.highAvailability ?? false;\n\n\t\t// The toml content arrives via FLY_TOML_CONTENT (avoids shell escaping).\n\t\tconst setup = `mkdir -p .fly && printf '%s' \"$FLY_TOML_CONTENT\" > ${configPath}`;\n\t\tconst cli = `fly deploy --config ${configPath} --remote-only --ha=${highAvailability} --wait-timeout ${waitTimeout} --release-command-timeout ${releaseCommandTimeout}`;\n\n\t\tconst triggers = pulumi\n\t\t\t.output(args.triggers)\n\t\t\t.apply((values) => [...values, tomlContent]);\n\n\t\t// Keep the `app` ordering anchor first; append the consumer's deps\n\t\t// (DeploySandbox / GitGuard) using the seam's shared normaliser.\n\t\tconst consumerDeps = dependsOnList(pulumiOpts) as pulumi.Resource[];\n\n\t\tconst { deploymentUrl } = createDeployCommand(\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tcli,\n\t\t\t\ttriggers,\n\t\t\t\tsetup,\n\t\t\t\tenvironment: {\n\t\t\t\t\tFLY_API_TOKEN: provider.token,\n\t\t\t\t\tFLY_TOML_CONTENT: tomlContent,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ ...pulumiOpts, parent: this, dependsOn: [app, ...consumerDeps] },\n\t\t);\n\n\t\tthis.deploymentUrl = deploymentUrl;\n\n\t\tthis.registerOutputs({ deploymentUrl: this.deploymentUrl });\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkCA,IAAa,YAAb,cAA+BA,eAAO,kBAAkB;CAIvD,YAAY,MAAc,MAAqB,MAAwB;EACtE,MAAM,EAAE,UAAU,KAAK,GAAG,eAAe;EAEzC,MAAM,yBAAyB,MAAM,CAAC,GAAG,UAAU;EAEnD,MAAM,cAAcC,iCAAgB,KAAK,MAAM;EAC/C,MAAM,aAAa,QAAQ,KAAK,OAAO,IAAI;EAE3C,MAAM,cAAc,KAAK,eAAe;EACxC,MAAM,wBAAwB,KAAK,yBAAyB;EAC5D,MAAM,mBAAmB,KAAK,oBAAoB;EAGlD,MAAM,QAAQ,sDAAsD;EACpE,MAAM,MAAM,uBAAuB,WAAW,sBAAsB,iBAAiB,kBAAkB,YAAY,6BAA6B;EAEhJ,MAAM,WAAWD,eACf,OAAO,KAAK,QAAQ,EACpB,OAAO,WAAW,CAAC,GAAG,QAAQ,WAAW,CAAC;EAI5C,MAAM,eAAeE,sCAAc,UAAU;EAE7C,MAAM,EAAE,kBAAkBC,4CACzB;GACC;GACA;GACA;GACA;GACA,aAAa;IACZ,eAAe,SAAS;IACxB,kBAAkB;GACnB;EACD,GACA;GAAE,GAAG;GAAY,QAAQ;GAAM,WAAW,CAAC,KAAK,GAAG,YAAY;EAAE,CAClE;EAEA,KAAK,gBAAgB;EAErB,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,CAAC;CAC3D;AACD"}
@@ -24,6 +24,10 @@ interface FlyDeployArgs {
24
24
  /**
25
25
  * Deploys a Fly app via `fly deploy --remote-only` from a generated fly.toml.
26
26
  * Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).
27
+ *
28
+ * Recommended preflight: `assertHostBinaries(["fly"])` (from
29
+ * `@infracraft/pulumi/sandbox`) at program start, so a missing CLI fails fast
30
+ * with an install hint instead of mid-deploy.
27
31
  */
28
32
  declare class FlyDeploy extends pulumi.ComponentResource {
29
33
  /** The deploy CLI's final stdout line (the Fly app URL when emitted). */
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.cts","names":[],"sources":["../../src/fly/deploy.ts"],"mappings":";;;;;;;KAQK,gBAAA,GAAmB,IAAA,CAAK,MAAA,CAAO,wBAAA;EACnC,QAAA,EAAU,WAAA;EACV,GAAA,EAAK,MAAA;AAAA;AAAA,UAGW,aAAA;;EAEhB,MAAA,EAAQ,aAAA;EAPe;EASvB,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAPzB;EASL,WAAA;EATW;EAWX,qBAAA;EAb4B;EAe5B,gBAAA;AAAA;;;;;cAOY,SAAA,SAAkB,MAAA,CAAO,iBAAA;EAjBrB;EAAA,SAmBA,aAAA,EAAe,MAAA,CAAO,MAAA;cAE1B,IAAA,UAAc,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,gBAAA;AAAA"}
1
+ {"version":3,"file":"deploy.d.cts","names":[],"sources":["../../src/fly/deploy.ts"],"mappings":";;;;;;;KAQK,gBAAA,GAAmB,IAAA,CAAK,MAAA,CAAO,wBAAA;EACnC,QAAA,EAAU,WAAA;EACV,GAAA,EAAK,MAAA;AAAA;AAAA,UAGW,aAAA;;EAEhB,MAAA,EAAQ,aAAA;EAPe;EASvB,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAPzB;EASL,WAAA;EATW;EAWX,qBAAA;EAb4B;EAe5B,gBAAA;AAAA;;;;;AAbW;AAGZ;;;cAqBa,SAAA,SAAkB,MAAA,CAAO,iBAAA;EAjBd;EAAA,SAmBP,aAAA,EAAe,MAAA,CAAO,MAAA;cAE1B,IAAA,UAAc,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,gBAAA;AAAA"}
@@ -24,6 +24,10 @@ interface FlyDeployArgs {
24
24
  /**
25
25
  * Deploys a Fly app via `fly deploy --remote-only` from a generated fly.toml.
26
26
  * Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).
27
+ *
28
+ * Recommended preflight: `assertHostBinaries(["fly"])` (from
29
+ * `@infracraft/pulumi/sandbox`) at program start, so a missing CLI fails fast
30
+ * with an install hint instead of mid-deploy.
27
31
  */
28
32
  declare class FlyDeploy extends pulumi.ComponentResource {
29
33
  /** The deploy CLI's final stdout line (the Fly app URL when emitted). */
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.d.mts","names":[],"sources":["../../src/fly/deploy.ts"],"mappings":";;;;;;;KAQK,gBAAA,GAAmB,IAAA,CAAK,MAAA,CAAO,wBAAA;EACnC,QAAA,EAAU,WAAA;EACV,GAAA,EAAK,MAAA;AAAA;AAAA,UAGW,aAAA;;EAEhB,MAAA,EAAQ,aAAA;EAPe;EASvB,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAPzB;EASL,WAAA;EATW;EAWX,qBAAA;EAb4B;EAe5B,gBAAA;AAAA;;;;;cAOY,SAAA,SAAkB,MAAA,CAAO,iBAAA;EAjBrB;EAAA,SAmBA,aAAA,EAAe,MAAA,CAAO,MAAA;cAE1B,IAAA,UAAc,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,gBAAA;AAAA"}
1
+ {"version":3,"file":"deploy.d.mts","names":[],"sources":["../../src/fly/deploy.ts"],"mappings":";;;;;;;KAQK,gBAAA,GAAmB,IAAA,CAAK,MAAA,CAAO,wBAAA;EACnC,QAAA,EAAU,WAAA;EACV,GAAA,EAAK,MAAA;AAAA;AAAA,UAGW,aAAA;;EAEhB,MAAA,EAAQ,aAAA;EAPe;EASvB,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAPzB;EASL,WAAA;EATW;EAWX,qBAAA;EAb4B;EAe5B,gBAAA;AAAA;;;;;AAbW;AAGZ;;;cAqBa,SAAA,SAAkB,MAAA,CAAO,iBAAA;EAjBd;EAAA,SAmBP,aAAA,EAAe,MAAA,CAAO,MAAA;cAE1B,IAAA,UAAc,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,gBAAA;AAAA"}
@@ -7,6 +7,10 @@ import * as pulumi from "@pulumi/pulumi";
7
7
  /**
8
8
  * Deploys a Fly app via `fly deploy --remote-only` from a generated fly.toml.
9
9
  * Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).
10
+ *
11
+ * Recommended preflight: `assertHostBinaries(["fly"])` (from
12
+ * `@infracraft/pulumi/sandbox`) at program start, so a missing CLI fails fast
13
+ * with an install hint instead of mid-deploy.
10
14
  */
11
15
  var FlyDeploy = class extends pulumi.ComponentResource {
12
16
  constructor(name, args, opts) {
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/fly/deploy.ts"],"sourcesContent":["// src/fly/deploy.ts (replace entire file)\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { createDeployCommand, dependsOnList } from \"../commands/deploy\";\nimport type { FlyApp } from \"./app\";\nimport type { FlyProvider } from \"./provider\";\nimport { type FlyTomlConfig, generateFlyToml } from \"./toml\";\n\ntype FlyDeployOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\tprovider: FlyProvider;\n\tapp: FlyApp;\n};\n\nexport interface FlyDeployArgs {\n\t/** fly.toml configuration. `config.app` must equal the FlyApp name. */\n\tconfig: FlyTomlConfig;\n\t/** Redeploy triggers; the generated toml content is appended automatically. */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\t/** `fly deploy --wait-timeout` seconds (default 300). */\n\twaitTimeout?: number;\n\t/** `fly deploy --release-command-timeout` seconds (default 600). */\n\treleaseCommandTimeout?: number;\n\t/** `fly deploy --ha` (default false). */\n\thighAvailability?: boolean;\n}\n\n/**\n * Deploys a Fly app via `fly deploy --remote-only` from a generated fly.toml.\n * Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).\n */\nexport class FlyDeploy extends pulumi.ComponentResource {\n\t/** The deploy CLI's final stdout line (the Fly app URL when emitted). */\n\tpublic readonly deploymentUrl: pulumi.Output<string>;\n\n\tconstructor(name: string, args: FlyDeployArgs, opts: FlyDeployOptions) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Deploy\", name, {}, pulumiOpts);\n\n\t\tconst tomlContent = generateFlyToml(args.config);\n\t\tconst configPath = `.fly/${args.config.app}.toml`;\n\n\t\tconst waitTimeout = args.waitTimeout ?? 300;\n\t\tconst releaseCommandTimeout = args.releaseCommandTimeout ?? 600;\n\t\tconst highAvailability = args.highAvailability ?? false;\n\n\t\t// The toml content arrives via FLY_TOML_CONTENT (avoids shell escaping).\n\t\tconst setup = `mkdir -p .fly && printf '%s' \"$FLY_TOML_CONTENT\" > ${configPath}`;\n\t\tconst cli = `fly deploy --config ${configPath} --remote-only --ha=${highAvailability} --wait-timeout ${waitTimeout} --release-command-timeout ${releaseCommandTimeout}`;\n\n\t\tconst triggers = pulumi\n\t\t\t.output(args.triggers)\n\t\t\t.apply((values) => [...values, tomlContent]);\n\n\t\t// Keep the `app` ordering anchor first; append the consumer's deps\n\t\t// (DeploySandbox / GitGuard) using the seam's shared normaliser.\n\t\tconst consumerDeps = dependsOnList(pulumiOpts) as pulumi.Resource[];\n\n\t\tconst { deploymentUrl } = createDeployCommand(\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tcli,\n\t\t\t\ttriggers,\n\t\t\t\tsetup,\n\t\t\t\tenvironment: {\n\t\t\t\t\tFLY_API_TOKEN: provider.token,\n\t\t\t\t\tFLY_TOML_CONTENT: tomlContent,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ ...pulumiOpts, parent: this, dependsOn: [app, ...consumerDeps] },\n\t\t);\n\n\t\tthis.deploymentUrl = deploymentUrl;\n\n\t\tthis.registerOutputs({ deploymentUrl: this.deploymentUrl });\n\t}\n}\n"],"mappings":";;;;;;;;;;AA8BA,IAAa,YAAb,cAA+B,OAAO,kBAAkB;CAIvD,YAAY,MAAc,MAAqB,MAAwB;EACtE,MAAM,EAAE,UAAU,KAAK,GAAG,eAAe;EAEzC,MAAM,yBAAyB,MAAM,CAAC,GAAG,UAAU;EAEnD,MAAM,cAAc,gBAAgB,KAAK,MAAM;EAC/C,MAAM,aAAa,QAAQ,KAAK,OAAO,IAAI;EAE3C,MAAM,cAAc,KAAK,eAAe;EACxC,MAAM,wBAAwB,KAAK,yBAAyB;EAC5D,MAAM,mBAAmB,KAAK,oBAAoB;EAGlD,MAAM,QAAQ,sDAAsD;EACpE,MAAM,MAAM,uBAAuB,WAAW,sBAAsB,iBAAiB,kBAAkB,YAAY,6BAA6B;EAEhJ,MAAM,WAAW,OACf,OAAO,KAAK,QAAQ,EACpB,OAAO,WAAW,CAAC,GAAG,QAAQ,WAAW,CAAC;EAI5C,MAAM,eAAe,cAAc,UAAU;EAE7C,MAAM,EAAE,kBAAkB,oBACzB;GACC;GACA;GACA;GACA;GACA,aAAa;IACZ,eAAe,SAAS;IACxB,kBAAkB;GACnB;EACD,GACA;GAAE,GAAG;GAAY,QAAQ;GAAM,WAAW,CAAC,KAAK,GAAG,YAAY;EAAE,CAClE;EAEA,KAAK,gBAAgB;EAErB,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,CAAC;CAC3D;AACD"}
1
+ {"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/fly/deploy.ts"],"sourcesContent":["// src/fly/deploy.ts (replace entire file)\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { createDeployCommand, dependsOnList } from \"../commands/deploy\";\nimport type { FlyApp } from \"./app\";\nimport type { FlyProvider } from \"./provider\";\nimport { type FlyTomlConfig, generateFlyToml } from \"./toml\";\n\ntype FlyDeployOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\tprovider: FlyProvider;\n\tapp: FlyApp;\n};\n\nexport interface FlyDeployArgs {\n\t/** fly.toml configuration. `config.app` must equal the FlyApp name. */\n\tconfig: FlyTomlConfig;\n\t/** Redeploy triggers; the generated toml content is appended automatically. */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\t/** `fly deploy --wait-timeout` seconds (default 300). */\n\twaitTimeout?: number;\n\t/** `fly deploy --release-command-timeout` seconds (default 600). */\n\treleaseCommandTimeout?: number;\n\t/** `fly deploy --ha` (default false). */\n\thighAvailability?: boolean;\n}\n\n/**\n * Deploys a Fly app via `fly deploy --remote-only` from a generated fly.toml.\n * Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).\n *\n * Recommended preflight: `assertHostBinaries([\"fly\"])` (from\n * `@infracraft/pulumi/sandbox`) at program start, so a missing CLI fails fast\n * with an install hint instead of mid-deploy.\n */\nexport class FlyDeploy extends pulumi.ComponentResource {\n\t/** The deploy CLI's final stdout line (the Fly app URL when emitted). */\n\tpublic readonly deploymentUrl: pulumi.Output<string>;\n\n\tconstructor(name: string, args: FlyDeployArgs, opts: FlyDeployOptions) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Deploy\", name, {}, pulumiOpts);\n\n\t\tconst tomlContent = generateFlyToml(args.config);\n\t\tconst configPath = `.fly/${args.config.app}.toml`;\n\n\t\tconst waitTimeout = args.waitTimeout ?? 300;\n\t\tconst releaseCommandTimeout = args.releaseCommandTimeout ?? 600;\n\t\tconst highAvailability = args.highAvailability ?? false;\n\n\t\t// The toml content arrives via FLY_TOML_CONTENT (avoids shell escaping).\n\t\tconst setup = `mkdir -p .fly && printf '%s' \"$FLY_TOML_CONTENT\" > ${configPath}`;\n\t\tconst cli = `fly deploy --config ${configPath} --remote-only --ha=${highAvailability} --wait-timeout ${waitTimeout} --release-command-timeout ${releaseCommandTimeout}`;\n\n\t\tconst triggers = pulumi\n\t\t\t.output(args.triggers)\n\t\t\t.apply((values) => [...values, tomlContent]);\n\n\t\t// Keep the `app` ordering anchor first; append the consumer's deps\n\t\t// (DeploySandbox / GitGuard) using the seam's shared normaliser.\n\t\tconst consumerDeps = dependsOnList(pulumiOpts) as pulumi.Resource[];\n\n\t\tconst { deploymentUrl } = createDeployCommand(\n\t\t\t{\n\t\t\t\tname,\n\t\t\t\tcli,\n\t\t\t\ttriggers,\n\t\t\t\tsetup,\n\t\t\t\tenvironment: {\n\t\t\t\t\tFLY_API_TOKEN: provider.token,\n\t\t\t\t\tFLY_TOML_CONTENT: tomlContent,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ ...pulumiOpts, parent: this, dependsOn: [app, ...consumerDeps] },\n\t\t);\n\n\t\tthis.deploymentUrl = deploymentUrl;\n\n\t\tthis.registerOutputs({ deploymentUrl: this.deploymentUrl });\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;AAkCA,IAAa,YAAb,cAA+B,OAAO,kBAAkB;CAIvD,YAAY,MAAc,MAAqB,MAAwB;EACtE,MAAM,EAAE,UAAU,KAAK,GAAG,eAAe;EAEzC,MAAM,yBAAyB,MAAM,CAAC,GAAG,UAAU;EAEnD,MAAM,cAAc,gBAAgB,KAAK,MAAM;EAC/C,MAAM,aAAa,QAAQ,KAAK,OAAO,IAAI;EAE3C,MAAM,cAAc,KAAK,eAAe;EACxC,MAAM,wBAAwB,KAAK,yBAAyB;EAC5D,MAAM,mBAAmB,KAAK,oBAAoB;EAGlD,MAAM,QAAQ,sDAAsD;EACpE,MAAM,MAAM,uBAAuB,WAAW,sBAAsB,iBAAiB,kBAAkB,YAAY,6BAA6B;EAEhJ,MAAM,WAAW,OACf,OAAO,KAAK,QAAQ,EACpB,OAAO,WAAW,CAAC,GAAG,QAAQ,WAAW,CAAC;EAI5C,MAAM,eAAe,cAAc,UAAU;EAE7C,MAAM,EAAE,kBAAkB,oBACzB;GACC;GACA;GACA;GACA;GACA,aAAa;IACZ,eAAe,SAAS;IACxB,kBAAkB;GACnB;EACD,GACA;GAAE,GAAG;GAAY,QAAQ;GAAM,WAAW,CAAC,KAAK,GAAG,YAAY;EAAE,CAClE;EAEA,KAAK,gBAAgB;EAErB,KAAK,gBAAgB,EAAE,eAAe,KAAK,cAAc,CAAC;CAC3D;AACD"}
package/dist/fly/ip.cjs CHANGED
@@ -44,6 +44,8 @@ const RELEASE_IP = `
44
44
  * API. `create()` queries existing IPs and adopts a matching one, otherwise it
45
45
  * allocates. `shared_v4` allocations return a null `ipAddress` in the payload —
46
46
  * the address is read from `app.sharedIpAddress`.
47
+ *
48
+ * @internal Exported only for unit testing; not part of the public API surface.
47
49
  */
48
50
  var FlyIpResourceProvider = class {
49
51
  async create(inputs) {
@@ -160,5 +162,6 @@ var FlyIp = class extends _pulumi_pulumi.ComponentResource {
160
162
 
161
163
  //#endregion
162
164
  exports.FlyIp = FlyIp;
165
+ exports.FlyIpResourceProvider = FlyIpResourceProvider;
163
166
  exports.FlyIpType = FlyIpType;
164
167
  //# sourceMappingURL=ip.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ip.cjs","names":["FlyClient","pulumi"],"sources":["../../src/fly/ip.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\n\nimport type { FlyApp } from \"./app\";\nimport { FlyClient } from \"./client\";\nimport type { FlyProvider } from \"./provider\";\n\n/**\n * Fly IP address type. Enum keys UPPERCASE; values are Fly's GraphQL enum\n * literals (lowercase wire format).\n */\nexport enum FlyIpType {\n\tV4 = \"v4\",\n\tV6 = \"v6\",\n\tSHARED_V4 = \"shared_v4\",\n\tPRIVATE_V6 = \"private_v6\",\n}\n\n/** Resolved inputs for the Fly IP dynamic provider. */\ninterface FlyIpInputs {\n\t/** Fly API token. */\n\ttoken: string;\n\n\t/** App name (used as GraphQL appId). */\n\tappName: string;\n\n\t/** IP address type. */\n\ttype: FlyIpType;\n\n\t/** Region (IATA code); omit for global. */\n\tregion?: string;\n}\n\n/** Persisted state for the Fly IP. */\ninterface FlyIpOutputs extends FlyIpInputs {\n\t/** Allocated IP address (also the `.id`). */\n\taddress: string;\n\n\t/** GraphQL node ID, when present (absent for `shared_v4`). */\n\tipAddressId?: string;\n}\n\nconst LIST_IPS = `\n\tquery ($appName: String!) {\n\t\tapp(name: $appName) {\n\t\t\tsharedIpAddress\n\t\t\tipAddresses {\n\t\t\t\tnodes { id address type region }\n\t\t\t}\n\t\t}\n\t}\n`;\n\nconst ALLOCATE_IP = `\n\tmutation ($input: AllocateIPAddressInput!) {\n\t\tallocateIpAddress(input: $input) {\n\t\t\tipAddress { id address type region }\n\t\t\tapp { sharedIpAddress }\n\t\t}\n\t}\n`;\n\nconst RELEASE_IP = `\n\tmutation ($input: ReleaseIPAddressInput!) {\n\t\treleaseIpAddress(input: $input) { clientMutationId }\n\t}\n`;\n\ninterface IpNode {\n\tid: string;\n\taddress: string;\n\ttype: string;\n\tregion: string | null;\n}\n\ninterface ListIpsResult {\n\tapp: {\n\t\tsharedIpAddress: string | null;\n\t\tipAddresses: { nodes: IpNode[] };\n\t};\n}\n\ninterface AllocateResult {\n\tallocateIpAddress: {\n\t\tipAddress: IpNode | null;\n\t\tapp: { sharedIpAddress: string | null };\n\t};\n}\n\n/**\n * Dynamic provider for Fly dedicated/shared IP allocation via the Fly GraphQL\n * API. `create()` queries existing IPs and adopts a matching one, otherwise it\n * allocates. `shared_v4` allocations return a null `ipAddress` in the payload —\n * the address is read from `app.sharedIpAddress`.\n */\nclass FlyIpResourceProvider implements pulumi.dynamic.ResourceProvider {\n\tasync create(inputs: FlyIpInputs): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new FlyClient(inputs.token);\n\n\t\tconst existing = await this.findExisting(client, inputs);\n\n\t\tif (existing) {\n\t\t\tpulumi.log.info(\n\t\t\t\t`Adopting existing Fly ${inputs.type} IP \"${existing.address}\"`,\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tid: existing.address,\n\t\t\t\touts: {\n\t\t\t\t\t...inputs,\n\t\t\t\t\taddress: existing.address,\n\t\t\t\t\tipAddressId: existing.ipAddressId,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst result = await client.graphql<AllocateResult>(ALLOCATE_IP, {\n\t\t\tinput: {\n\t\t\t\tappId: inputs.appName,\n\t\t\t\ttype: inputs.type,\n\t\t\t\tregion: inputs.region,\n\t\t\t},\n\t\t});\n\n\t\tconst node = result.allocateIpAddress.ipAddress;\n\n\t\tconst address =\n\t\t\tinputs.type === FlyIpType.SHARED_V4\n\t\t\t\t? (result.allocateIpAddress.app.sharedIpAddress ?? \"\")\n\t\t\t\t: (node?.address ?? \"\");\n\n\t\tif (!address) {\n\t\t\tthrow new Error(\n\t\t\t\t`Fly IP allocation for app \"${inputs.appName}\" (${inputs.type}) returned no address`,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tid: address,\n\t\t\touts: { ...inputs, address, ipAddressId: node?.id },\n\t\t};\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: FlyIpOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\treturn { id, props };\n\t}\n\n\tasync delete(_id: string, props: FlyIpOutputs): Promise<void> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\tconst input: Record<string, string> = { appId: props.appName };\n\n\t\tif (props.ipAddressId) {\n\t\t\tinput.ipAddressId = props.ipAddressId;\n\t\t} else {\n\t\t\tinput.ip = props.address;\n\t\t}\n\n\t\ttry {\n\t\t\tawait client.graphql(RELEASE_IP, { input });\n\t\t} catch (error) {\n\t\t\t// Fly reports an already-released IP as a GraphQL \"not found\" error —\n\t\t\t// deletion is idempotent, so tolerate it.\n\t\t\tif (\n\t\t\t\terror instanceof Error &&\n\t\t\t\t/not found|could not find/i.test(error.message)\n\t\t\t) {\n\t\t\t\tpulumi.log.warn(`Fly IP \"${props.address}\" already released`);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: FlyIpOutputs,\n\t\tnews: FlyIpInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.appName !== news.appName) {\n\t\t\treplaces.push(\"appName\");\n\t\t}\n\n\t\tif (olds.type !== news.type) {\n\t\t\treplaces.push(\"type\");\n\t\t}\n\n\t\tif (olds.region !== news.region) {\n\t\t\treplaces.push(\"region\");\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\tprivate async findExisting(\n\t\tclient: FlyClient,\n\t\tinputs: FlyIpInputs,\n\t): Promise<{ address: string; ipAddressId?: string } | null> {\n\t\tconst result = await client.graphql<ListIpsResult>(LIST_IPS, {\n\t\t\tappName: inputs.appName,\n\t\t});\n\n\t\tif (inputs.type === FlyIpType.SHARED_V4) {\n\t\t\tconst shared = result.app.sharedIpAddress;\n\n\t\t\treturn shared ? { address: shared } : null;\n\t\t}\n\n\t\tconst match = result.app.ipAddresses.nodes.find(\n\t\t\t(node) =>\n\t\t\t\tnode.type === inputs.type &&\n\t\t\t\t(inputs.region === undefined || node.region === inputs.region),\n\t\t);\n\n\t\treturn match ? { address: match.address, ipAddressId: match.id } : null;\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass FlyIpResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly address: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tappName: pulumi.Input<string>;\n\t\t\ttype: pulumi.Input<FlyIpType>;\n\t\t\tregion?: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew FlyIpResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, address: undefined, ipAddressId: undefined },\n\t\t\t// The API token flows into dynamic-provider state with the outputs — mark it secret there.\n\t\t\t{ ...opts, additionalSecretOutputs: [\"token\"] },\n\t\t);\n\t}\n}\n\n/** Options type for FlyIp. */\ntype FlyIpOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Fly authentication context. */\n\tprovider: FlyProvider;\n\n\t/** App the IP belongs to. */\n\tapp: FlyApp;\n};\n\n/** Args for FlyIp. */\nexport interface FlyIpArgs {\n\t/** IP address type. */\n\ttype: pulumi.Input<FlyIpType>;\n\n\t/** Region (IATA code); omit for a global address. */\n\tregion?: pulumi.Input<string>;\n}\n\n/**\n * Allocates a Fly IP address (dedicated or shared) via the Fly GraphQL API.\n *\n * @example\n * ```typescript\n * const ip = new FlyIp(\"api-ip\", { type: FlyIpType.SHARED_V4 }, { provider, app });\n * ```\n */\nexport class FlyIp extends pulumi.ComponentResource {\n\t/** Allocated IP address. */\n\tpublic readonly id: pulumi.Output<string>;\n\n\tconstructor(name: string, args: FlyIpArgs, opts: FlyIpOptions) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Ip\", name, {}, pulumiOpts);\n\n\t\tconst resource = new FlyIpResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tappName: app.id,\n\t\t\t\ttype: args.type,\n\t\t\t\tregion: args.region,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = resource.address;\n\n\t\tthis.registerOutputs({ id: this.id });\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ip.cjs","names":["FlyClient","pulumi"],"sources":["../../src/fly/ip.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\n\nimport type { FlyApp } from \"./app\";\nimport { FlyClient } from \"./client\";\nimport type { FlyProvider } from \"./provider\";\n\n/**\n * Fly IP address type. Enum keys UPPERCASE; values are Fly's GraphQL enum\n * literals (lowercase wire format).\n */\nexport enum FlyIpType {\n\tV4 = \"v4\",\n\tV6 = \"v6\",\n\tSHARED_V4 = \"shared_v4\",\n\tPRIVATE_V6 = \"private_v6\",\n}\n\n/** Resolved inputs for the Fly IP dynamic provider. */\ninterface FlyIpInputs {\n\t/** Fly API token. */\n\ttoken: string;\n\n\t/** App name (used as GraphQL appId). */\n\tappName: string;\n\n\t/** IP address type. */\n\ttype: FlyIpType;\n\n\t/** Region (IATA code); omit for global. */\n\tregion?: string;\n}\n\n/** Persisted state for the Fly IP. */\ninterface FlyIpOutputs extends FlyIpInputs {\n\t/** Allocated IP address (also the `.id`). */\n\taddress: string;\n\n\t/** GraphQL node ID, when present (absent for `shared_v4`). */\n\tipAddressId?: string;\n}\n\nconst LIST_IPS = `\n\tquery ($appName: String!) {\n\t\tapp(name: $appName) {\n\t\t\tsharedIpAddress\n\t\t\tipAddresses {\n\t\t\t\tnodes { id address type region }\n\t\t\t}\n\t\t}\n\t}\n`;\n\nconst ALLOCATE_IP = `\n\tmutation ($input: AllocateIPAddressInput!) {\n\t\tallocateIpAddress(input: $input) {\n\t\t\tipAddress { id address type region }\n\t\t\tapp { sharedIpAddress }\n\t\t}\n\t}\n`;\n\nconst RELEASE_IP = `\n\tmutation ($input: ReleaseIPAddressInput!) {\n\t\treleaseIpAddress(input: $input) { clientMutationId }\n\t}\n`;\n\ninterface IpNode {\n\tid: string;\n\taddress: string;\n\ttype: string;\n\tregion: string | null;\n}\n\ninterface ListIpsResult {\n\tapp: {\n\t\tsharedIpAddress: string | null;\n\t\tipAddresses: { nodes: IpNode[] };\n\t};\n}\n\ninterface AllocateResult {\n\tallocateIpAddress: {\n\t\tipAddress: IpNode | null;\n\t\tapp: { sharedIpAddress: string | null };\n\t};\n}\n\n/**\n * Dynamic provider for Fly dedicated/shared IP allocation via the Fly GraphQL\n * API. `create()` queries existing IPs and adopts a matching one, otherwise it\n * allocates. `shared_v4` allocations return a null `ipAddress` in the payload —\n * the address is read from `app.sharedIpAddress`.\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class FlyIpResourceProvider implements pulumi.dynamic.ResourceProvider {\n\tasync create(inputs: FlyIpInputs): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst client = new FlyClient(inputs.token);\n\n\t\tconst existing = await this.findExisting(client, inputs);\n\n\t\tif (existing) {\n\t\t\tpulumi.log.info(\n\t\t\t\t`Adopting existing Fly ${inputs.type} IP \"${existing.address}\"`,\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\tid: existing.address,\n\t\t\t\touts: {\n\t\t\t\t\t...inputs,\n\t\t\t\t\taddress: existing.address,\n\t\t\t\t\tipAddressId: existing.ipAddressId,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst result = await client.graphql<AllocateResult>(ALLOCATE_IP, {\n\t\t\tinput: {\n\t\t\t\tappId: inputs.appName,\n\t\t\t\ttype: inputs.type,\n\t\t\t\tregion: inputs.region,\n\t\t\t},\n\t\t});\n\n\t\tconst node = result.allocateIpAddress.ipAddress;\n\n\t\tconst address =\n\t\t\tinputs.type === FlyIpType.SHARED_V4\n\t\t\t\t? (result.allocateIpAddress.app.sharedIpAddress ?? \"\")\n\t\t\t\t: (node?.address ?? \"\");\n\n\t\tif (!address) {\n\t\t\tthrow new Error(\n\t\t\t\t`Fly IP allocation for app \"${inputs.appName}\" (${inputs.type}) returned no address`,\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tid: address,\n\t\t\touts: { ...inputs, address, ipAddressId: node?.id },\n\t\t};\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: FlyIpOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\treturn { id, props };\n\t}\n\n\tasync delete(_id: string, props: FlyIpOutputs): Promise<void> {\n\t\tconst client = new FlyClient(props.token);\n\n\t\tconst input: Record<string, string> = { appId: props.appName };\n\n\t\tif (props.ipAddressId) {\n\t\t\tinput.ipAddressId = props.ipAddressId;\n\t\t} else {\n\t\t\tinput.ip = props.address;\n\t\t}\n\n\t\ttry {\n\t\t\tawait client.graphql(RELEASE_IP, { input });\n\t\t} catch (error) {\n\t\t\t// Fly reports an already-released IP as a GraphQL \"not found\" error —\n\t\t\t// deletion is idempotent, so tolerate it.\n\t\t\tif (\n\t\t\t\terror instanceof Error &&\n\t\t\t\t/not found|could not find/i.test(error.message)\n\t\t\t) {\n\t\t\t\tpulumi.log.warn(`Fly IP \"${props.address}\" already released`);\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: FlyIpOutputs,\n\t\tnews: FlyIpInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.appName !== news.appName) {\n\t\t\treplaces.push(\"appName\");\n\t\t}\n\n\t\tif (olds.type !== news.type) {\n\t\t\treplaces.push(\"type\");\n\t\t}\n\n\t\tif (olds.region !== news.region) {\n\t\t\treplaces.push(\"region\");\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\tprivate async findExisting(\n\t\tclient: FlyClient,\n\t\tinputs: FlyIpInputs,\n\t): Promise<{ address: string; ipAddressId?: string } | null> {\n\t\tconst result = await client.graphql<ListIpsResult>(LIST_IPS, {\n\t\t\tappName: inputs.appName,\n\t\t});\n\n\t\tif (inputs.type === FlyIpType.SHARED_V4) {\n\t\t\tconst shared = result.app.sharedIpAddress;\n\n\t\t\treturn shared ? { address: shared } : null;\n\t\t}\n\n\t\tconst match = result.app.ipAddresses.nodes.find(\n\t\t\t(node) =>\n\t\t\t\tnode.type === inputs.type &&\n\t\t\t\t(inputs.region === undefined || node.region === inputs.region),\n\t\t);\n\n\t\treturn match ? { address: match.address, ipAddressId: match.id } : null;\n\t}\n}\n\n/** Internal dynamic resource — not part of the public API. */\nclass FlyIpResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly address: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tappName: pulumi.Input<string>;\n\t\t\ttype: pulumi.Input<FlyIpType>;\n\t\t\tregion?: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew FlyIpResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, address: undefined, ipAddressId: undefined },\n\t\t\t// The API token flows into dynamic-provider state with the outputs — mark it secret there.\n\t\t\t{ ...opts, additionalSecretOutputs: [\"token\"] },\n\t\t);\n\t}\n}\n\n/** Options type for FlyIp. */\ntype FlyIpOptions = Omit<pulumi.ComponentResourceOptions, \"provider\"> & {\n\t/** Fly authentication context. */\n\tprovider: FlyProvider;\n\n\t/** App the IP belongs to. */\n\tapp: FlyApp;\n};\n\n/** Args for FlyIp. */\nexport interface FlyIpArgs {\n\t/** IP address type. */\n\ttype: pulumi.Input<FlyIpType>;\n\n\t/** Region (IATA code); omit for a global address. */\n\tregion?: pulumi.Input<string>;\n}\n\n/**\n * Allocates a Fly IP address (dedicated or shared) via the Fly GraphQL API.\n *\n * @example\n * ```typescript\n * const ip = new FlyIp(\"api-ip\", { type: FlyIpType.SHARED_V4 }, { provider, app });\n * ```\n */\nexport class FlyIp extends pulumi.ComponentResource {\n\t/** Allocated IP address. */\n\tpublic readonly id: pulumi.Output<string>;\n\n\tconstructor(name: string, args: FlyIpArgs, opts: FlyIpOptions) {\n\t\tconst { provider, app, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:fly:Ip\", name, {}, pulumiOpts);\n\n\t\tconst resource = new FlyIpResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tappName: app.id,\n\t\t\t\ttype: args.type,\n\t\t\t\tregion: args.region,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.id = resource.address;\n\n\t\tthis.registerOutputs({ id: this.id });\n\t}\n}\n"],"mappings":"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"}
package/dist/fly/ip.d.cts CHANGED
@@ -14,6 +14,39 @@ declare enum FlyIpType {
14
14
  SHARED_V4 = "shared_v4",
15
15
  PRIVATE_V6 = "private_v6"
16
16
  }
17
+ /** Resolved inputs for the Fly IP dynamic provider. */
18
+ interface FlyIpInputs {
19
+ /** Fly API token. */
20
+ token: string;
21
+ /** App name (used as GraphQL appId). */
22
+ appName: string;
23
+ /** IP address type. */
24
+ type: FlyIpType;
25
+ /** Region (IATA code); omit for global. */
26
+ region?: string;
27
+ }
28
+ /** Persisted state for the Fly IP. */
29
+ interface FlyIpOutputs extends FlyIpInputs {
30
+ /** Allocated IP address (also the `.id`). */
31
+ address: string;
32
+ /** GraphQL node ID, when present (absent for `shared_v4`). */
33
+ ipAddressId?: string;
34
+ }
35
+ /**
36
+ * Dynamic provider for Fly dedicated/shared IP allocation via the Fly GraphQL
37
+ * API. `create()` queries existing IPs and adopts a matching one, otherwise it
38
+ * allocates. `shared_v4` allocations return a null `ipAddress` in the payload —
39
+ * the address is read from `app.sharedIpAddress`.
40
+ *
41
+ * @internal Exported only for unit testing; not part of the public API surface.
42
+ */
43
+ declare class FlyIpResourceProvider implements pulumi.dynamic.ResourceProvider {
44
+ create(inputs: FlyIpInputs): Promise<pulumi.dynamic.CreateResult>;
45
+ read(id: string, props: FlyIpOutputs): Promise<pulumi.dynamic.ReadResult>;
46
+ delete(_id: string, props: FlyIpOutputs): Promise<void>;
47
+ diff(_id: string, olds: FlyIpOutputs, news: FlyIpInputs): Promise<pulumi.dynamic.DiffResult>;
48
+ private findExisting;
49
+ }
17
50
  /** Options type for FlyIp. */
18
51
  type FlyIpOptions = Omit<pulumi.ComponentResourceOptions, "provider"> & {
19
52
  /** Fly authentication context. */provider: FlyProvider; /** App the IP belongs to. */
@@ -40,5 +73,5 @@ declare class FlyIp extends pulumi.ComponentResource {
40
73
  constructor(name: string, args: FlyIpArgs, opts: FlyIpOptions);
41
74
  }
42
75
  //#endregion
43
- export { FlyIp, FlyIpArgs, FlyIpType };
76
+ export { FlyIp, FlyIpArgs, FlyIpResourceProvider, FlyIpType };
44
77
  //# sourceMappingURL=ip.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ip.d.cts","names":[],"sources":["../../src/fly/ip.ts"],"mappings":";;;;;;;;;AAUA;aAAY,SAAA;EACX,EAAA;EACA,EAAA;EACA,SAAA;EACA,UAAA;AAAA;;KA+OI,YAAA,GAAe,IAAA,CAAK,MAAA,CAAO,wBAAA;EA/OrB,kCAiPV,QAAA,EAAU,WAAA,EAFM;EAKhB,GAAA,EAAK,MAAA;AAAA;;UAIW,SAAA;EAJX;EAML,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,SAAA;EANR;EASX,MAAA,GAAS,MAAA,CAAO,KAAA;AAAA;;;;;;;AATL;AAIZ;cAgBa,KAAA,SAAc,MAAA,CAAO,iBAAA;;WAEjB,EAAA,EAAI,MAAA,CAAO,MAAA;cAEf,IAAA,UAAc,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,YAAA;AAAA"}
1
+ {"version":3,"file":"ip.d.cts","names":[],"sources":["../../src/fly/ip.ts"],"mappings":";;;;;;;;;AAUA;aAAY,SAAA;EACX,EAAA;EACA,EAAA;EACA,SAAA;EACA,UAAA;AAAA;;UAIS,WAAA;EAJC;EAMV,KAAA;EAFoB;EAKpB,OAAA;EAGe;EAAf,IAAA,EAAM,SAAS;EAHf;EAMA,MAAA;AAAA;;UAIS,YAAA,SAAqB,WAAW;EAJnC;EAMN,OAAA;EAFsB;EAKtB,WAAA;AAAA;;;;;AAAW;AA0DZ;;;cAAa,qBAAA,YAAiC,MAAA,CAAO,OAAA,CAAQ,gBAAA;EACtD,MAAA,CAAO,MAAA,EAAQ,WAAA,GAAc,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EA+CpD,IAAA,CACL,EAAA,UACA,KAAA,EAAO,YAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAIpB,MAAA,CAAO,GAAA,UAAa,KAAA,EAAO,YAAA,GAAe,OAAA;EA6B1C,IAAA,CACL,GAAA,UACA,IAAA,EAAM,YAAA,EACN,IAAA,EAAM,WAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAAA,QAsBZ,YAAA;AAAA;;KAiDV,YAAA,GAAe,IAAA,CAAK,MAAA,CAAO,wBAAA;EAxExB,kCA0EP,QAAA,EAAU,WAAA,EAzEP;EA4EH,GAAA,EAAK,MAAA;AAAA;;UAIW,SAAA;EAxKoC;EA0KpD,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,SAAA;EAzKb;EA4KN,MAAA,GAAS,MAAA,CAAO,KAAA;AAAA;;;;;;;;;cAWJ,KAAA,SAAc,MAAA,CAAO,iBAAA;EArItB;EAAA,SAuIK,EAAA,EAAI,MAAA,CAAO,MAAA;cAEf,IAAA,UAAc,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,YAAA;AAAA"}
package/dist/fly/ip.d.mts CHANGED
@@ -14,6 +14,39 @@ declare enum FlyIpType {
14
14
  SHARED_V4 = "shared_v4",
15
15
  PRIVATE_V6 = "private_v6"
16
16
  }
17
+ /** Resolved inputs for the Fly IP dynamic provider. */
18
+ interface FlyIpInputs {
19
+ /** Fly API token. */
20
+ token: string;
21
+ /** App name (used as GraphQL appId). */
22
+ appName: string;
23
+ /** IP address type. */
24
+ type: FlyIpType;
25
+ /** Region (IATA code); omit for global. */
26
+ region?: string;
27
+ }
28
+ /** Persisted state for the Fly IP. */
29
+ interface FlyIpOutputs extends FlyIpInputs {
30
+ /** Allocated IP address (also the `.id`). */
31
+ address: string;
32
+ /** GraphQL node ID, when present (absent for `shared_v4`). */
33
+ ipAddressId?: string;
34
+ }
35
+ /**
36
+ * Dynamic provider for Fly dedicated/shared IP allocation via the Fly GraphQL
37
+ * API. `create()` queries existing IPs and adopts a matching one, otherwise it
38
+ * allocates. `shared_v4` allocations return a null `ipAddress` in the payload —
39
+ * the address is read from `app.sharedIpAddress`.
40
+ *
41
+ * @internal Exported only for unit testing; not part of the public API surface.
42
+ */
43
+ declare class FlyIpResourceProvider implements pulumi.dynamic.ResourceProvider {
44
+ create(inputs: FlyIpInputs): Promise<pulumi.dynamic.CreateResult>;
45
+ read(id: string, props: FlyIpOutputs): Promise<pulumi.dynamic.ReadResult>;
46
+ delete(_id: string, props: FlyIpOutputs): Promise<void>;
47
+ diff(_id: string, olds: FlyIpOutputs, news: FlyIpInputs): Promise<pulumi.dynamic.DiffResult>;
48
+ private findExisting;
49
+ }
17
50
  /** Options type for FlyIp. */
18
51
  type FlyIpOptions = Omit<pulumi.ComponentResourceOptions, "provider"> & {
19
52
  /** Fly authentication context. */provider: FlyProvider; /** App the IP belongs to. */
@@ -40,5 +73,5 @@ declare class FlyIp extends pulumi.ComponentResource {
40
73
  constructor(name: string, args: FlyIpArgs, opts: FlyIpOptions);
41
74
  }
42
75
  //#endregion
43
- export { FlyIp, FlyIpArgs, FlyIpType };
76
+ export { FlyIp, FlyIpArgs, FlyIpResourceProvider, FlyIpType };
44
77
  //# sourceMappingURL=ip.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ip.d.mts","names":[],"sources":["../../src/fly/ip.ts"],"mappings":";;;;;;;;;AAUA;aAAY,SAAA;EACX,EAAA;EACA,EAAA;EACA,SAAA;EACA,UAAA;AAAA;;KA+OI,YAAA,GAAe,IAAA,CAAK,MAAA,CAAO,wBAAA;EA/OrB,kCAiPV,QAAA,EAAU,WAAA,EAFM;EAKhB,GAAA,EAAK,MAAA;AAAA;;UAIW,SAAA;EAJX;EAML,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,SAAA;EANR;EASX,MAAA,GAAS,MAAA,CAAO,KAAA;AAAA;;;;;;;AATL;AAIZ;cAgBa,KAAA,SAAc,MAAA,CAAO,iBAAA;;WAEjB,EAAA,EAAI,MAAA,CAAO,MAAA;cAEf,IAAA,UAAc,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,YAAA;AAAA"}
1
+ {"version":3,"file":"ip.d.mts","names":[],"sources":["../../src/fly/ip.ts"],"mappings":";;;;;;;;;AAUA;aAAY,SAAA;EACX,EAAA;EACA,EAAA;EACA,SAAA;EACA,UAAA;AAAA;;UAIS,WAAA;EAJC;EAMV,KAAA;EAFoB;EAKpB,OAAA;EAGe;EAAf,IAAA,EAAM,SAAS;EAHf;EAMA,MAAA;AAAA;;UAIS,YAAA,SAAqB,WAAW;EAJnC;EAMN,OAAA;EAFsB;EAKtB,WAAA;AAAA;;;;;AAAW;AA0DZ;;;cAAa,qBAAA,YAAiC,MAAA,CAAO,OAAA,CAAQ,gBAAA;EACtD,MAAA,CAAO,MAAA,EAAQ,WAAA,GAAc,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EA+CpD,IAAA,CACL,EAAA,UACA,KAAA,EAAO,YAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAIpB,MAAA,CAAO,GAAA,UAAa,KAAA,EAAO,YAAA,GAAe,OAAA;EA6B1C,IAAA,CACL,GAAA,UACA,IAAA,EAAM,YAAA,EACN,IAAA,EAAM,WAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAAA,QAsBZ,YAAA;AAAA;;KAiDV,YAAA,GAAe,IAAA,CAAK,MAAA,CAAO,wBAAA;EAxExB,kCA0EP,QAAA,EAAU,WAAA,EAzEP;EA4EH,GAAA,EAAK,MAAA;AAAA;;UAIW,SAAA;EAxKoC;EA0KpD,IAAA,EAAM,MAAA,CAAO,KAAA,CAAM,SAAA;EAzKb;EA4KN,MAAA,GAAS,MAAA,CAAO,KAAA;AAAA;;;;;;;;;cAWJ,KAAA,SAAc,MAAA,CAAO,iBAAA;EArItB;EAAA,SAuIK,EAAA,EAAI,MAAA,CAAO,MAAA;cAEf,IAAA,UAAc,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,YAAA;AAAA"}
package/dist/fly/ip.mjs CHANGED
@@ -42,6 +42,8 @@ const RELEASE_IP = `
42
42
  * API. `create()` queries existing IPs and adopts a matching one, otherwise it
43
43
  * allocates. `shared_v4` allocations return a null `ipAddress` in the payload —
44
44
  * the address is read from `app.sharedIpAddress`.
45
+ *
46
+ * @internal Exported only for unit testing; not part of the public API surface.
45
47
  */
46
48
  var FlyIpResourceProvider = class {
47
49
  async create(inputs) {
@@ -157,5 +159,5 @@ var FlyIp = class extends pulumi.ComponentResource {
157
159
  };
158
160
 
159
161
  //#endregion
160
- export { FlyIp, FlyIpType };
162
+ export { FlyIp, FlyIpResourceProvider, FlyIpType };
161
163
  //# sourceMappingURL=ip.mjs.map