@infracraft/pulumi 1.16.5 → 1.16.7
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.
- package/dist/commands/deploy.cjs +4 -2
- package/dist/commands/deploy.cjs.map +1 -1
- package/dist/commands/deploy.d.cts +3 -1
- package/dist/commands/deploy.d.cts.map +1 -1
- package/dist/commands/deploy.d.mts +3 -1
- package/dist/commands/deploy.d.mts.map +1 -1
- package/dist/commands/deploy.mjs +5 -4
- package/dist/commands/deploy.mjs.map +1 -1
- package/dist/fly/deploy.cjs +4 -6
- package/dist/fly/deploy.cjs.map +1 -1
- package/dist/fly/deploy.d.cts +2 -0
- package/dist/fly/deploy.d.cts.map +1 -1
- package/dist/fly/deploy.d.mts +2 -0
- package/dist/fly/deploy.d.mts.map +1 -1
- package/dist/fly/deploy.mjs +5 -7
- package/dist/fly/deploy.mjs.map +1 -1
- package/dist/hash.cjs +84 -11
- package/dist/hash.cjs.map +1 -1
- package/dist/hash.d.cts +14 -1
- package/dist/hash.d.cts.map +1 -1
- package/dist/hash.d.mts +14 -1
- package/dist/hash.d.mts.map +1 -1
- package/dist/hash.mjs +84 -12
- package/dist/hash.mjs.map +1 -1
- package/dist/railway/deploy.cjs +14 -5
- package/dist/railway/deploy.cjs.map +1 -1
- package/dist/railway/deploy.d.cts +2 -0
- package/dist/railway/deploy.d.cts.map +1 -1
- package/dist/railway/deploy.d.mts +2 -0
- package/dist/railway/deploy.d.mts.map +1 -1
- package/dist/railway/deploy.mjs +14 -5
- package/dist/railway/deploy.mjs.map +1 -1
- package/dist/sandbox.cjs +43 -10
- package/dist/sandbox.cjs.map +1 -1
- package/dist/sandbox.d.cts +30 -9
- package/dist/sandbox.d.cts.map +1 -1
- package/dist/sandbox.d.mts +30 -9
- package/dist/sandbox.d.mts.map +1 -1
- package/dist/sandbox.mjs +43 -11
- package/dist/sandbox.mjs.map +1 -1
- package/package.json +1 -1
package/dist/commands/deploy.cjs
CHANGED
|
@@ -24,10 +24,11 @@ function createDeployCommand(args, opts) {
|
|
|
24
24
|
const sandbox = deps.some(require_sandbox.isDeploySandbox);
|
|
25
25
|
const gitGuard = deps.some(require_git_guard.isGitGuard);
|
|
26
26
|
if (gitGuard && !sandbox) throw new Error(`[infracraft] ${args.name}: GitGuard has no effect without a DeploySandbox in dependsOn`);
|
|
27
|
+
let mode = "NONE";
|
|
28
|
+
if (sandbox) mode = gitGuard ? "STUB" : "ORIGINAL";
|
|
27
29
|
const env = _pulumi_pulumi.getStack();
|
|
28
30
|
const create = _pulumi_pulumi.output(args.cli).apply((cli) => require_sandbox.buildSandboxScript({
|
|
29
|
-
|
|
30
|
-
gitGuard,
|
|
31
|
+
mode,
|
|
31
32
|
appName: args.name,
|
|
32
33
|
env,
|
|
33
34
|
excludePaths: args.excludePaths,
|
|
@@ -47,4 +48,5 @@ function createDeployCommand(args, opts) {
|
|
|
47
48
|
|
|
48
49
|
//#endregion
|
|
49
50
|
exports.createDeployCommand = createDeployCommand;
|
|
51
|
+
exports.dependsOnList = dependsOnList;
|
|
50
52
|
//# sourceMappingURL=deploy.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.cjs","names":["isDeploySandbox","isGitGuard","pulumi","buildSandboxScript","command"],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["// src/commands/deploy.ts\nimport * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { isGitGuard } from \"../git-guard\";\nimport { buildSandboxScript, isDeploySandbox } from \"../sandbox\";\n\nexport interface CreateDeployCommandArgs {\n\t/** Resource name; the child command is `<name>` and the sandbox dir uses it. */\n\tname: string;\n\t/** Fully-formed platform deploy command (may be an Output, e.g. Railway). */\n\tcli: pulumi.Input<string>;\n\t/** Redeploy triggers (source/env hashes). */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\t/** Upload-scoping excludes (applied only in stub mode). */\n\texcludePaths?: string[];\n\t/** Shell run in the working dir before `cli` (e.g. write railpack.json). */\n\tsetup?: string;\n\t/** Env passed to the command (secrets that survive preview; not the inlined ones). */\n\tenvironment?: Record<string, pulumi.Input<string>>;\n}\n\nexport interface CreateDeployCommandResult {\n\tcommand: command.local.Command;\n\t/** The deploy CLI's final stdout line (the production URL for Vercel/Fly). */\n\tdeploymentUrl: pulumi.Output<string>;\n}\n\n/** Reads a `dependsOn` opt into a flat array of resource instances. */\
|
|
1
|
+
{"version":3,"file":"deploy.cjs","names":["isDeploySandbox","isGitGuard","pulumi","buildSandboxScript","command"],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["// src/commands/deploy.ts\nimport * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { isGitGuard } from \"../git-guard\";\nimport { buildSandboxScript, isDeploySandbox, SandboxMode } from \"../sandbox\";\n\nexport interface CreateDeployCommandArgs {\n\t/** Resource name; the child command is `<name>` and the sandbox dir uses it. */\n\tname: string;\n\t/** Fully-formed platform deploy command (may be an Output, e.g. Railway). */\n\tcli: pulumi.Input<string>;\n\t/** Redeploy triggers (source/env hashes). */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\t/** Upload-scoping excludes (applied only in stub mode). */\n\texcludePaths?: string[];\n\t/** Shell run in the working dir before `cli` (e.g. write railpack.json). */\n\tsetup?: string;\n\t/** Env passed to the command (secrets that survive preview; not the inlined ones). */\n\tenvironment?: Record<string, pulumi.Input<string>>;\n}\n\nexport interface CreateDeployCommandResult {\n\tcommand: command.local.Command;\n\t/** The deploy CLI's final stdout line (the production URL for Vercel/Fly). */\n\tdeploymentUrl: pulumi.Output<string>;\n}\n\n/** Reads a `dependsOn` opt into a flat array of resource instances. */\nexport function dependsOnList(\n\topts: pulumi.ComponentResourceOptions,\n): unknown[] {\n\tconst dep = opts.dependsOn;\n\n\tif (Array.isArray(dep)) {\n\t\treturn dep;\n\t}\n\n\treturn dep ? [dep] : [];\n}\n\n/**\n * Builds a sandboxed deploy command. Inspects `opts.dependsOn` by brand:\n * a DeploySandbox → isolate; a GitGuard → stub `.git`; GitGuard alone → throw.\n * The platform deploy resources call ONLY this; they never touch the sandbox.\n */\nexport function createDeployCommand(\n\targs: CreateDeployCommandArgs,\n\topts: pulumi.ComponentResourceOptions,\n): CreateDeployCommandResult {\n\tconst deps = dependsOnList(opts);\n\tconst sandbox = deps.some(isDeploySandbox);\n\tconst gitGuard = deps.some(isGitGuard);\n\n\tif (gitGuard && !sandbox) {\n\t\tthrow new Error(\n\t\t\t`[infracraft] ${args.name}: GitGuard has no effect without a DeploySandbox in dependsOn`,\n\t\t);\n\t}\n\n\tlet mode = SandboxMode.NONE;\n\n\tif (sandbox) {\n\t\tmode = gitGuard ? SandboxMode.STUB : SandboxMode.ORIGINAL;\n\t}\n\n\tconst env = pulumi.getStack();\n\n\tconst create = pulumi.output(args.cli).apply((cli) =>\n\t\tbuildSandboxScript({\n\t\t\tmode,\n\t\t\tappName: args.name,\n\t\t\tenv,\n\t\t\texcludePaths: args.excludePaths,\n\t\t\tsetup: args.setup,\n\t\t\tcli,\n\t\t}),\n\t);\n\n\tconst cmd = new command.local.Command(\n\t\targs.name,\n\t\t{ create, triggers: args.triggers, environment: args.environment },\n\t\topts,\n\t);\n\n\tconst deploymentUrl = cmd.stdout.apply(\n\t\t(out) => out.trim().split(\"\\n\").pop() ?? \"\",\n\t);\n\n\treturn { command: cmd, deploymentUrl };\n}\n"],"mappings":";;;;;;;;;;;AA6BA,SAAgB,cACf,MACY;CACZ,MAAM,MAAM,KAAK;CAEjB,IAAI,MAAM,QAAQ,GAAG,GACpB,OAAO;CAGR,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC;AACvB;;;;;;AAOA,SAAgB,oBACf,MACA,MAC4B;CAC5B,MAAM,OAAO,cAAc,IAAI;CAC/B,MAAM,UAAU,KAAK,KAAKA,+BAAe;CACzC,MAAM,WAAW,KAAK,KAAKC,4BAAU;CAErC,IAAI,YAAY,CAAC,SAChB,MAAM,IAAI,MACT,gBAAgB,KAAK,KAAK,8DAC3B;CAGD,IAAI;CAEJ,IAAI,SACH,OAAO;CAGR,MAAM,MAAMC,eAAO,SAAS;CAE5B,MAAM,SAASA,eAAO,OAAO,KAAK,GAAG,EAAE,OAAO,QAC7CC,mCAAmB;EAClB;EACA,SAAS,KAAK;EACd;EACA,cAAc,KAAK;EACnB,OAAO,KAAK;EACZ;CACD,CAAC,CACF;CAEA,MAAM,MAAM,IAAIC,gBAAQ,MAAM,QAC7B,KAAK,MACL;EAAE;EAAQ,UAAU,KAAK;EAAU,aAAa,KAAK;CAAY,GACjE,IACD;CAMA,OAAO;EAAE,SAAS;EAAK,eAJD,IAAI,OAAO,OAC/B,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI,EAAE,IAAI,KAAK,EAGP;CAAE;AACtC"}
|
|
@@ -22,6 +22,8 @@ interface CreateDeployCommandResult {
|
|
|
22
22
|
/** The deploy CLI's final stdout line (the production URL for Vercel/Fly). */
|
|
23
23
|
deploymentUrl: pulumi.Output<string>;
|
|
24
24
|
}
|
|
25
|
+
/** Reads a `dependsOn` opt into a flat array of resource instances. */
|
|
26
|
+
declare function dependsOnList(opts: pulumi.ComponentResourceOptions): unknown[];
|
|
25
27
|
/**
|
|
26
28
|
* Builds a sandboxed deploy command. Inspects `opts.dependsOn` by brand:
|
|
27
29
|
* a DeploySandbox → isolate; a GitGuard → stub `.git`; GitGuard alone → throw.
|
|
@@ -29,5 +31,5 @@ interface CreateDeployCommandResult {
|
|
|
29
31
|
*/
|
|
30
32
|
declare function createDeployCommand(args: CreateDeployCommandArgs, opts: pulumi.ComponentResourceOptions): CreateDeployCommandResult;
|
|
31
33
|
//#endregion
|
|
32
|
-
export { CreateDeployCommandArgs, CreateDeployCommandResult, createDeployCommand };
|
|
34
|
+
export { CreateDeployCommandArgs, CreateDeployCommandResult, createDeployCommand, dependsOnList };
|
|
33
35
|
//# sourceMappingURL=deploy.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.cts","names":[],"sources":["../../src/commands/deploy.ts"],"mappings":";;;;;UAOiB,uBAAA;;EAEhB,IAAA;EAFgB;EAIhB,GAAA,EAAK,MAAA,CAAO,KAAA;;EAEZ,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAAP;EAEvB,YAAA;EAI6B;EAF7B,KAAA;EAEoB;EAApB,WAAA,GAAc,MAAA,SAAe,MAAA,CAAO,KAAA;AAAA;AAAA,UAGpB,yBAAA;EAChB,OAAA,EAAS,OAAA,CAAQ,KAAA,CAAM,OAAA;EAZX;EAcZ,aAAA,EAAe,MAAA,CAAO,MAAM;AAAA;;;;;;
|
|
1
|
+
{"version":3,"file":"deploy.d.cts","names":[],"sources":["../../src/commands/deploy.ts"],"mappings":";;;;;UAOiB,uBAAA;;EAEhB,IAAA;EAFgB;EAIhB,GAAA,EAAK,MAAA,CAAO,KAAA;;EAEZ,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAAP;EAEvB,YAAA;EAI6B;EAF7B,KAAA;EAEoB;EAApB,WAAA,GAAc,MAAA,SAAe,MAAA,CAAO,KAAA;AAAA;AAAA,UAGpB,yBAAA;EAChB,OAAA,EAAS,OAAA,CAAQ,KAAA,CAAM,OAAA;EAZX;EAcZ,aAAA,EAAe,MAAA,CAAO,MAAM;AAAA;;iBAIb,aAAA,CACf,IAAA,EAAM,MAAA,CAAO,wBAAwB;;;;;;iBAgBtB,mBAAA,CACf,IAAA,EAAM,uBAAA,EACN,IAAA,EAAM,MAAA,CAAO,wBAAA,GACX,yBAAA"}
|
|
@@ -22,6 +22,8 @@ interface CreateDeployCommandResult {
|
|
|
22
22
|
/** The deploy CLI's final stdout line (the production URL for Vercel/Fly). */
|
|
23
23
|
deploymentUrl: pulumi.Output<string>;
|
|
24
24
|
}
|
|
25
|
+
/** Reads a `dependsOn` opt into a flat array of resource instances. */
|
|
26
|
+
declare function dependsOnList(opts: pulumi.ComponentResourceOptions): unknown[];
|
|
25
27
|
/**
|
|
26
28
|
* Builds a sandboxed deploy command. Inspects `opts.dependsOn` by brand:
|
|
27
29
|
* a DeploySandbox → isolate; a GitGuard → stub `.git`; GitGuard alone → throw.
|
|
@@ -29,5 +31,5 @@ interface CreateDeployCommandResult {
|
|
|
29
31
|
*/
|
|
30
32
|
declare function createDeployCommand(args: CreateDeployCommandArgs, opts: pulumi.ComponentResourceOptions): CreateDeployCommandResult;
|
|
31
33
|
//#endregion
|
|
32
|
-
export { CreateDeployCommandArgs, CreateDeployCommandResult, createDeployCommand };
|
|
34
|
+
export { CreateDeployCommandArgs, CreateDeployCommandResult, createDeployCommand, dependsOnList };
|
|
33
35
|
//# sourceMappingURL=deploy.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.mts","names":[],"sources":["../../src/commands/deploy.ts"],"mappings":";;;;;UAOiB,uBAAA;;EAEhB,IAAA;EAFgB;EAIhB,GAAA,EAAK,MAAA,CAAO,KAAA;;EAEZ,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAAP;EAEvB,YAAA;EAI6B;EAF7B,KAAA;EAEoB;EAApB,WAAA,GAAc,MAAA,SAAe,MAAA,CAAO,KAAA;AAAA;AAAA,UAGpB,yBAAA;EAChB,OAAA,EAAS,OAAA,CAAQ,KAAA,CAAM,OAAA;EAZX;EAcZ,aAAA,EAAe,MAAA,CAAO,MAAM;AAAA;;;;;;
|
|
1
|
+
{"version":3,"file":"deploy.d.mts","names":[],"sources":["../../src/commands/deploy.ts"],"mappings":";;;;;UAOiB,uBAAA;;EAEhB,IAAA;EAFgB;EAIhB,GAAA,EAAK,MAAA,CAAO,KAAA;;EAEZ,QAAA,EAAU,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,KAAA;EAAP;EAEvB,YAAA;EAI6B;EAF7B,KAAA;EAEoB;EAApB,WAAA,GAAc,MAAA,SAAe,MAAA,CAAO,KAAA;AAAA;AAAA,UAGpB,yBAAA;EAChB,OAAA,EAAS,OAAA,CAAQ,KAAA,CAAM,OAAA;EAZX;EAcZ,aAAA,EAAe,MAAA,CAAO,MAAM;AAAA;;iBAIb,aAAA,CACf,IAAA,EAAM,MAAA,CAAO,wBAAwB;;;;;;iBAgBtB,mBAAA,CACf,IAAA,EAAM,uBAAA,EACN,IAAA,EAAM,MAAA,CAAO,wBAAA,GACX,yBAAA"}
|
package/dist/commands/deploy.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as __name } from "../chunk-OPjESj5l.mjs";
|
|
2
2
|
import { isGitGuard } from "../git-guard.mjs";
|
|
3
|
-
import { buildSandboxScript, isDeploySandbox } from "../sandbox.mjs";
|
|
3
|
+
import { SandboxMode, buildSandboxScript, isDeploySandbox } from "../sandbox.mjs";
|
|
4
4
|
import * as pulumi from "@pulumi/pulumi";
|
|
5
5
|
import * as command from "@pulumi/command";
|
|
6
6
|
|
|
@@ -21,10 +21,11 @@ function createDeployCommand(args, opts) {
|
|
|
21
21
|
const sandbox = deps.some(isDeploySandbox);
|
|
22
22
|
const gitGuard = deps.some(isGitGuard);
|
|
23
23
|
if (gitGuard && !sandbox) throw new Error(`[infracraft] ${args.name}: GitGuard has no effect without a DeploySandbox in dependsOn`);
|
|
24
|
+
let mode = "NONE";
|
|
25
|
+
if (sandbox) mode = gitGuard ? "STUB" : "ORIGINAL";
|
|
24
26
|
const env = pulumi.getStack();
|
|
25
27
|
const create = pulumi.output(args.cli).apply((cli) => buildSandboxScript({
|
|
26
|
-
|
|
27
|
-
gitGuard,
|
|
28
|
+
mode,
|
|
28
29
|
appName: args.name,
|
|
29
30
|
env,
|
|
30
31
|
excludePaths: args.excludePaths,
|
|
@@ -43,5 +44,5 @@ function createDeployCommand(args, opts) {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
//#endregion
|
|
46
|
-
export { createDeployCommand };
|
|
47
|
+
export { createDeployCommand, dependsOnList };
|
|
47
48
|
//# sourceMappingURL=deploy.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["// src/commands/deploy.ts\nimport * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { isGitGuard } from \"../git-guard\";\nimport { buildSandboxScript, isDeploySandbox } from \"../sandbox\";\n\nexport interface CreateDeployCommandArgs {\n\t/** Resource name; the child command is `<name>` and the sandbox dir uses it. */\n\tname: string;\n\t/** Fully-formed platform deploy command (may be an Output, e.g. Railway). */\n\tcli: pulumi.Input<string>;\n\t/** Redeploy triggers (source/env hashes). */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\t/** Upload-scoping excludes (applied only in stub mode). */\n\texcludePaths?: string[];\n\t/** Shell run in the working dir before `cli` (e.g. write railpack.json). */\n\tsetup?: string;\n\t/** Env passed to the command (secrets that survive preview; not the inlined ones). */\n\tenvironment?: Record<string, pulumi.Input<string>>;\n}\n\nexport interface CreateDeployCommandResult {\n\tcommand: command.local.Command;\n\t/** The deploy CLI's final stdout line (the production URL for Vercel/Fly). */\n\tdeploymentUrl: pulumi.Output<string>;\n}\n\n/** Reads a `dependsOn` opt into a flat array of resource instances. */\
|
|
1
|
+
{"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/commands/deploy.ts"],"sourcesContent":["// src/commands/deploy.ts\nimport * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { isGitGuard } from \"../git-guard\";\nimport { buildSandboxScript, isDeploySandbox, SandboxMode } from \"../sandbox\";\n\nexport interface CreateDeployCommandArgs {\n\t/** Resource name; the child command is `<name>` and the sandbox dir uses it. */\n\tname: string;\n\t/** Fully-formed platform deploy command (may be an Output, e.g. Railway). */\n\tcli: pulumi.Input<string>;\n\t/** Redeploy triggers (source/env hashes). */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\t/** Upload-scoping excludes (applied only in stub mode). */\n\texcludePaths?: string[];\n\t/** Shell run in the working dir before `cli` (e.g. write railpack.json). */\n\tsetup?: string;\n\t/** Env passed to the command (secrets that survive preview; not the inlined ones). */\n\tenvironment?: Record<string, pulumi.Input<string>>;\n}\n\nexport interface CreateDeployCommandResult {\n\tcommand: command.local.Command;\n\t/** The deploy CLI's final stdout line (the production URL for Vercel/Fly). */\n\tdeploymentUrl: pulumi.Output<string>;\n}\n\n/** Reads a `dependsOn` opt into a flat array of resource instances. */\nexport function dependsOnList(\n\topts: pulumi.ComponentResourceOptions,\n): unknown[] {\n\tconst dep = opts.dependsOn;\n\n\tif (Array.isArray(dep)) {\n\t\treturn dep;\n\t}\n\n\treturn dep ? [dep] : [];\n}\n\n/**\n * Builds a sandboxed deploy command. Inspects `opts.dependsOn` by brand:\n * a DeploySandbox → isolate; a GitGuard → stub `.git`; GitGuard alone → throw.\n * The platform deploy resources call ONLY this; they never touch the sandbox.\n */\nexport function createDeployCommand(\n\targs: CreateDeployCommandArgs,\n\topts: pulumi.ComponentResourceOptions,\n): CreateDeployCommandResult {\n\tconst deps = dependsOnList(opts);\n\tconst sandbox = deps.some(isDeploySandbox);\n\tconst gitGuard = deps.some(isGitGuard);\n\n\tif (gitGuard && !sandbox) {\n\t\tthrow new Error(\n\t\t\t`[infracraft] ${args.name}: GitGuard has no effect without a DeploySandbox in dependsOn`,\n\t\t);\n\t}\n\n\tlet mode = SandboxMode.NONE;\n\n\tif (sandbox) {\n\t\tmode = gitGuard ? SandboxMode.STUB : SandboxMode.ORIGINAL;\n\t}\n\n\tconst env = pulumi.getStack();\n\n\tconst create = pulumi.output(args.cli).apply((cli) =>\n\t\tbuildSandboxScript({\n\t\t\tmode,\n\t\t\tappName: args.name,\n\t\t\tenv,\n\t\t\texcludePaths: args.excludePaths,\n\t\t\tsetup: args.setup,\n\t\t\tcli,\n\t\t}),\n\t);\n\n\tconst cmd = new command.local.Command(\n\t\targs.name,\n\t\t{ create, triggers: args.triggers, environment: args.environment },\n\t\topts,\n\t);\n\n\tconst deploymentUrl = cmd.stdout.apply(\n\t\t(out) => out.trim().split(\"\\n\").pop() ?? \"\",\n\t);\n\n\treturn { command: cmd, deploymentUrl };\n}\n"],"mappings":";;;;;;;;AA6BA,SAAgB,cACf,MACY;CACZ,MAAM,MAAM,KAAK;CAEjB,IAAI,MAAM,QAAQ,GAAG,GACpB,OAAO;CAGR,OAAO,MAAM,CAAC,GAAG,IAAI,CAAC;AACvB;;;;;;AAOA,SAAgB,oBACf,MACA,MAC4B;CAC5B,MAAM,OAAO,cAAc,IAAI;CAC/B,MAAM,UAAU,KAAK,KAAK,eAAe;CACzC,MAAM,WAAW,KAAK,KAAK,UAAU;CAErC,IAAI,YAAY,CAAC,SAChB,MAAM,IAAI,MACT,gBAAgB,KAAK,KAAK,8DAC3B;CAGD,IAAI;CAEJ,IAAI,SACH,OAAO;CAGR,MAAM,MAAM,OAAO,SAAS;CAE5B,MAAM,SAAS,OAAO,OAAO,KAAK,GAAG,EAAE,OAAO,QAC7C,mBAAmB;EAClB;EACA,SAAS,KAAK;EACd;EACA,cAAc,KAAK;EACnB,OAAO,KAAK;EACZ;CACD,CAAC,CACF;CAEA,MAAM,MAAM,IAAI,QAAQ,MAAM,QAC7B,KAAK,MACL;EAAE;EAAQ,UAAU,KAAK;EAAU,aAAa,KAAK;CAAY,GACjE,IACD;CAMA,OAAO;EAAE,SAAS;EAAK,eAJD,IAAI,OAAO,OAC/B,QAAQ,IAAI,KAAK,EAAE,MAAM,IAAI,EAAE,IAAI,KAAK,EAGP;CAAE;AACtC"}
|
package/dist/fly/deploy.cjs
CHANGED
|
@@ -22,11 +22,8 @@ var FlyDeploy = class extends _pulumi_pulumi.ComponentResource {
|
|
|
22
22
|
const setup = `mkdir -p .fly && printf '%s' "$FLY_TOML_CONTENT" > ${configPath}`;
|
|
23
23
|
const cli = `fly deploy --config ${configPath} --remote-only --ha=${highAvailability} --wait-timeout ${waitTimeout} --release-command-timeout ${releaseCommandTimeout}`;
|
|
24
24
|
const triggers = _pulumi_pulumi.output(args.triggers).apply((values) => [...values, tomlContent]);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
else if (pulumiOpts.dependsOn) consumerDeps = [pulumiOpts.dependsOn];
|
|
28
|
-
else consumerDeps = [];
|
|
29
|
-
require_commands_deploy.createDeployCommand({
|
|
25
|
+
const consumerDeps = require_commands_deploy.dependsOnList(pulumiOpts);
|
|
26
|
+
const { deploymentUrl } = require_commands_deploy.createDeployCommand({
|
|
30
27
|
name,
|
|
31
28
|
cli,
|
|
32
29
|
triggers,
|
|
@@ -40,7 +37,8 @@ var FlyDeploy = class extends _pulumi_pulumi.ComponentResource {
|
|
|
40
37
|
parent: this,
|
|
41
38
|
dependsOn: [app, ...consumerDeps]
|
|
42
39
|
});
|
|
43
|
-
this.
|
|
40
|
+
this.deploymentUrl = deploymentUrl;
|
|
41
|
+
this.registerOutputs({ deploymentUrl: this.deploymentUrl });
|
|
44
42
|
}
|
|
45
43
|
};
|
|
46
44
|
|
package/dist/fly/deploy.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.cjs","names":["pulumi","generateFlyToml"],"sources":["../../src/fly/deploy.ts"],"sourcesContent":["// src/fly/deploy.ts (replace entire file)\nimport * as pulumi from \"@pulumi/pulumi\";\n\nimport { createDeployCommand } 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\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\
|
|
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"}
|
package/dist/fly/deploy.d.cts
CHANGED
|
@@ -26,6 +26,8 @@ interface FlyDeployArgs {
|
|
|
26
26
|
* Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).
|
|
27
27
|
*/
|
|
28
28
|
declare class FlyDeploy extends pulumi.ComponentResource {
|
|
29
|
+
/** The deploy CLI's final stdout line (the Fly app URL when emitted). */
|
|
30
|
+
readonly deploymentUrl: pulumi.Output<string>;
|
|
29
31
|
constructor(name: string, args: FlyDeployArgs, opts: FlyDeployOptions);
|
|
30
32
|
}
|
|
31
33
|
//#endregion
|
|
@@ -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;
|
|
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"}
|
package/dist/fly/deploy.d.mts
CHANGED
|
@@ -26,6 +26,8 @@ interface FlyDeployArgs {
|
|
|
26
26
|
* Isolation/git are the seam's job (list a `DeploySandbox`, optionally a `GitGuard`).
|
|
27
27
|
*/
|
|
28
28
|
declare class FlyDeploy extends pulumi.ComponentResource {
|
|
29
|
+
/** The deploy CLI's final stdout line (the Fly app URL when emitted). */
|
|
30
|
+
readonly deploymentUrl: pulumi.Output<string>;
|
|
29
31
|
constructor(name: string, args: FlyDeployArgs, opts: FlyDeployOptions);
|
|
30
32
|
}
|
|
31
33
|
//#endregion
|
|
@@ -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;
|
|
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"}
|
package/dist/fly/deploy.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as __name } from "../chunk-OPjESj5l.mjs";
|
|
2
|
-
import { createDeployCommand } from "../commands/deploy.mjs";
|
|
2
|
+
import { createDeployCommand, dependsOnList } from "../commands/deploy.mjs";
|
|
3
3
|
import { generateFlyToml } from "./toml.mjs";
|
|
4
4
|
import * as pulumi from "@pulumi/pulumi";
|
|
5
5
|
|
|
@@ -20,11 +20,8 @@ var FlyDeploy = class extends pulumi.ComponentResource {
|
|
|
20
20
|
const setup = `mkdir -p .fly && printf '%s' "$FLY_TOML_CONTENT" > ${configPath}`;
|
|
21
21
|
const cli = `fly deploy --config ${configPath} --remote-only --ha=${highAvailability} --wait-timeout ${waitTimeout} --release-command-timeout ${releaseCommandTimeout}`;
|
|
22
22
|
const triggers = pulumi.output(args.triggers).apply((values) => [...values, tomlContent]);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
else if (pulumiOpts.dependsOn) consumerDeps = [pulumiOpts.dependsOn];
|
|
26
|
-
else consumerDeps = [];
|
|
27
|
-
createDeployCommand({
|
|
23
|
+
const consumerDeps = dependsOnList(pulumiOpts);
|
|
24
|
+
const { deploymentUrl } = createDeployCommand({
|
|
28
25
|
name,
|
|
29
26
|
cli,
|
|
30
27
|
triggers,
|
|
@@ -38,7 +35,8 @@ var FlyDeploy = class extends pulumi.ComponentResource {
|
|
|
38
35
|
parent: this,
|
|
39
36
|
dependsOn: [app, ...consumerDeps]
|
|
40
37
|
});
|
|
41
|
-
this.
|
|
38
|
+
this.deploymentUrl = deploymentUrl;
|
|
39
|
+
this.registerOutputs({ deploymentUrl: this.deploymentUrl });
|
|
42
40
|
}
|
|
43
41
|
};
|
|
44
42
|
|
package/dist/fly/deploy.mjs.map
CHANGED
|
@@ -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 } 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\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\
|
|
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"}
|
package/dist/hash.cjs
CHANGED
|
@@ -29,22 +29,95 @@ function hash(input, options) {
|
|
|
29
29
|
}
|
|
30
30
|
const ignore = options?.ignore ?? DEFAULT_IGNORE;
|
|
31
31
|
const digest = node_crypto.createHash("sha256");
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
hashDirInto(digest, input, ignore);
|
|
33
|
+
return digest.digest("hex");
|
|
34
|
+
}
|
|
35
|
+
/** Recursively folds a directory's file names + contents into `digest`. */
|
|
36
|
+
function hashDirInto(digest, currentPath, ignore) {
|
|
37
|
+
const entries = node_fs.readdirSync(currentPath, { withFileTypes: true });
|
|
38
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
39
|
+
if (ignore.has(entry.name)) continue;
|
|
40
|
+
const fullPath = node_path.join(currentPath, entry.name);
|
|
41
|
+
if (entry.isDirectory()) hashDirInto(digest, fullPath, ignore);
|
|
42
|
+
else if (entry.isFile()) {
|
|
43
|
+
digest.update(entry.name);
|
|
44
|
+
digest.update(node_fs.readFileSync(fullPath));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function readWorkspacePackage(directory) {
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(node_fs.readFileSync(node_path.join(directory, "package.json"), "utf8"));
|
|
51
|
+
} catch {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Indexes every workspace package by its `package.json` `name` -> directory, by
|
|
57
|
+
* scanning `apps/*` and `packages/*`. Robust to a package whose directory name
|
|
58
|
+
* differs from its published name.
|
|
59
|
+
*/
|
|
60
|
+
function buildWorkspaceIndex(monorepoRoot) {
|
|
61
|
+
const index = /* @__PURE__ */ new Map();
|
|
62
|
+
for (const group of ["apps", "packages"]) {
|
|
63
|
+
const base = node_path.join(monorepoRoot, group);
|
|
64
|
+
let entries;
|
|
65
|
+
try {
|
|
66
|
+
entries = node_fs.readdirSync(base, { withFileTypes: true });
|
|
67
|
+
} catch {
|
|
68
|
+
continue;
|
|
42
69
|
}
|
|
70
|
+
for (const entry of entries) {
|
|
71
|
+
if (!entry.isDirectory()) continue;
|
|
72
|
+
const directory = node_path.join(base, entry.name);
|
|
73
|
+
const pkg = readWorkspacePackage(directory);
|
|
74
|
+
if (pkg?.name) index.set(pkg.name, directory);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return index;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Hashes an app's source AND every workspace package it depends on
|
|
81
|
+
* (transitively), for use as a redeploy trigger. Resolving the dependency
|
|
82
|
+
* closure from each `package.json` means a change to a shared `packages/*` an
|
|
83
|
+
* app depends on correctly retriggers that app's deploy — and adding a new app
|
|
84
|
+
* needs no hand-maintained list of which packages to hash.
|
|
85
|
+
*
|
|
86
|
+
* @param monorepoRoot Absolute repo root (holds `apps/` and `packages/`).
|
|
87
|
+
* @param appDirectory The app to hash, relative to the root (e.g. `apps/mesh`).
|
|
88
|
+
* @example
|
|
89
|
+
* triggers: [hashApp(monorepoRoot, "apps/mesh"), hash(env)]
|
|
90
|
+
*/
|
|
91
|
+
function hashApp(monorepoRoot, appDirectory, options) {
|
|
92
|
+
const ignore = options?.ignore ?? DEFAULT_IGNORE;
|
|
93
|
+
const index = buildWorkspaceIndex(monorepoRoot);
|
|
94
|
+
const start = node_path.join(monorepoRoot, appDirectory);
|
|
95
|
+
const visited = /* @__PURE__ */ new Set();
|
|
96
|
+
const queue = [start];
|
|
97
|
+
while (queue.length > 0) {
|
|
98
|
+
const directory = queue.pop();
|
|
99
|
+
if (!directory || visited.has(directory)) continue;
|
|
100
|
+
visited.add(directory);
|
|
101
|
+
const pkg = readWorkspacePackage(directory);
|
|
102
|
+
if (!pkg) continue;
|
|
103
|
+
const deps = {
|
|
104
|
+
...pkg.dependencies,
|
|
105
|
+
...pkg.devDependencies
|
|
106
|
+
};
|
|
107
|
+
for (const depName of Object.keys(deps)) {
|
|
108
|
+
const depDirectory = index.get(depName);
|
|
109
|
+
if (depDirectory && !visited.has(depDirectory)) queue.push(depDirectory);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const digest = node_crypto.createHash("sha256");
|
|
113
|
+
for (const directory of [...visited].sort()) {
|
|
114
|
+
digest.update(`\0${node_path.relative(monorepoRoot, directory)}\0`);
|
|
115
|
+
hashDirInto(digest, directory, ignore);
|
|
43
116
|
}
|
|
44
|
-
walk(input);
|
|
45
117
|
return digest.digest("hex");
|
|
46
118
|
}
|
|
47
119
|
|
|
48
120
|
//#endregion
|
|
49
121
|
exports.hash = hash;
|
|
122
|
+
exports.hashApp = hashApp;
|
|
50
123
|
//# sourceMappingURL=hash.cjs.map
|
package/dist/hash.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.cjs","names":["pulumi","crypto","fs","path"],"sources":["../src/hash.ts"],"sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nconst DEFAULT_IGNORE = new Set([\n\t\"node_modules\",\n\t\"dist\",\n\t\".turbo\",\n\t\".next\",\n\t\".git\",\n\t\".vercel\",\n]);\n\ninterface HashOptions {\n\tignore?: Set<string>;\n}\n\n/**\n * Produces a stable SHA-256 hex digest for use as a resource/deploy trigger,\n * from either a source directory or an environment map.\n *\n * - **Directory** (`string`): recursively hashes file names + contents (build\n * and VCS directories skipped). Synchronous — returns a plain `string`.\n * - **Env map** (`Record<string, Input<string>>`): resolves the values, sorts\n * by key, and hashes them into a single non-secret `Output<string>`. Passing\n * secret `Output`s straight into a dynamic resource's inputs intermittently\n * races Pulumi's gRPC secret serialization (`Unexpected struct type`, issue\n * #16041) — the reason such deploys otherwise need `--parallel 1`. Collapsing\n * the env to one `unsecret` digest keeps the trigger moving on any change\n * while carrying no secret, so deploys are safe to (re)create at full\n * parallelism. Exposing the digest is safe: it is a one-way hash of\n * high-entropy secrets.\n *\n * @param input A source directory path, or a map of env var name to value.\n * @param options Directory mode only: `ignore` overrides the default skip set.\n * @returns `string` for a directory, `Output<string>` for an env map.\n * @example\n * triggers: [hash(appDir), hash(env)]\n */\nexport function hash(directory: string, options?: HashOptions): string;\nexport function hash(\n\tenv: Record<string, pulumi.Input<string>>,\n): pulumi.Output<string>;\nexport function hash(\n\tinput: string | Record<string, pulumi.Input<string>>,\n\toptions?: HashOptions,\n): string | pulumi.Output<string> {\n\tif (typeof input !== \"string\") {\n\t\tconst keys = Object.keys(input).sort();\n\n\t\treturn pulumi.unsecret(\n\t\t\tpulumi.all(keys.map((key) => input[key])).apply((values) => {\n\t\t\t\tconst digest = crypto.createHash(\"sha256\");\n\n\t\t\t\tfor (const [index, key] of keys.entries()) {\n\t\t\t\t\tdigest.update(`${key}=${values[index]}\\0`);\n\t\t\t\t}\n\n\t\t\t\treturn digest.digest(\"hex\");\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst ignore = options?.ignore ?? DEFAULT_IGNORE;\n\tconst digest = crypto.createHash(\"sha256\");\n\n\
|
|
1
|
+
{"version":3,"file":"hash.cjs","names":["pulumi","crypto","fs","path"],"sources":["../src/hash.ts"],"sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nconst DEFAULT_IGNORE = new Set([\n\t\"node_modules\",\n\t\"dist\",\n\t\".turbo\",\n\t\".next\",\n\t\".git\",\n\t\".vercel\",\n]);\n\ninterface HashOptions {\n\tignore?: Set<string>;\n}\n\n/**\n * Produces a stable SHA-256 hex digest for use as a resource/deploy trigger,\n * from either a source directory or an environment map.\n *\n * - **Directory** (`string`): recursively hashes file names + contents (build\n * and VCS directories skipped). Synchronous — returns a plain `string`.\n * - **Env map** (`Record<string, Input<string>>`): resolves the values, sorts\n * by key, and hashes them into a single non-secret `Output<string>`. Passing\n * secret `Output`s straight into a dynamic resource's inputs intermittently\n * races Pulumi's gRPC secret serialization (`Unexpected struct type`, issue\n * #16041) — the reason such deploys otherwise need `--parallel 1`. Collapsing\n * the env to one `unsecret` digest keeps the trigger moving on any change\n * while carrying no secret, so deploys are safe to (re)create at full\n * parallelism. Exposing the digest is safe: it is a one-way hash of\n * high-entropy secrets.\n *\n * @param input A source directory path, or a map of env var name to value.\n * @param options Directory mode only: `ignore` overrides the default skip set.\n * @returns `string` for a directory, `Output<string>` for an env map.\n * @example\n * triggers: [hash(appDir), hash(env)]\n */\nexport function hash(directory: string, options?: HashOptions): string;\nexport function hash(\n\tenv: Record<string, pulumi.Input<string>>,\n): pulumi.Output<string>;\nexport function hash(\n\tinput: string | Record<string, pulumi.Input<string>>,\n\toptions?: HashOptions,\n): string | pulumi.Output<string> {\n\tif (typeof input !== \"string\") {\n\t\tconst keys = Object.keys(input).sort();\n\n\t\treturn pulumi.unsecret(\n\t\t\tpulumi.all(keys.map((key) => input[key])).apply((values) => {\n\t\t\t\tconst digest = crypto.createHash(\"sha256\");\n\n\t\t\t\tfor (const [index, key] of keys.entries()) {\n\t\t\t\t\tdigest.update(`${key}=${values[index]}\\0`);\n\t\t\t\t}\n\n\t\t\t\treturn digest.digest(\"hex\");\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst ignore = options?.ignore ?? DEFAULT_IGNORE;\n\tconst digest = crypto.createHash(\"sha256\");\n\n\thashDirInto(digest, input, ignore);\n\n\treturn digest.digest(\"hex\");\n}\n\n/** Recursively folds a directory's file names + contents into `digest`. */\nfunction hashDirInto(\n\tdigest: crypto.Hash,\n\tcurrentPath: string,\n\tignore: Set<string>,\n): void {\n\tconst entries = fs.readdirSync(currentPath, { withFileTypes: true });\n\n\tfor (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n\t\tif (ignore.has(entry.name)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fullPath = path.join(currentPath, entry.name);\n\n\t\tif (entry.isDirectory()) {\n\t\t\thashDirInto(digest, fullPath, ignore);\n\t\t} else if (entry.isFile()) {\n\t\t\tdigest.update(entry.name);\n\t\t\tdigest.update(fs.readFileSync(fullPath));\n\t\t}\n\t}\n}\n\ninterface WorkspacePackage {\n\tname?: string;\n\tdependencies?: Record<string, string>;\n\tdevDependencies?: Record<string, string>;\n}\n\nfunction readWorkspacePackage(directory: string): WorkspacePackage | undefined {\n\ttry {\n\t\treturn JSON.parse(\n\t\t\tfs.readFileSync(path.join(directory, \"package.json\"), \"utf8\"),\n\t\t) as WorkspacePackage;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Indexes every workspace package by its `package.json` `name` -> directory, by\n * scanning `apps/*` and `packages/*`. Robust to a package whose directory name\n * differs from its published name.\n */\nfunction buildWorkspaceIndex(monorepoRoot: string): Map<string, string> {\n\tconst index = new Map<string, string>();\n\n\tfor (const group of [\"apps\", \"packages\"]) {\n\t\tconst base = path.join(monorepoRoot, group);\n\n\t\tlet entries: fs.Dirent[];\n\n\t\ttry {\n\t\t\tentries = fs.readdirSync(base, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.isDirectory()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst directory = path.join(base, entry.name);\n\t\t\tconst pkg = readWorkspacePackage(directory);\n\n\t\t\tif (pkg?.name) {\n\t\t\t\tindex.set(pkg.name, directory);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn index;\n}\n\n/**\n * Hashes an app's source AND every workspace package it depends on\n * (transitively), for use as a redeploy trigger. Resolving the dependency\n * closure from each `package.json` means a change to a shared `packages/*` an\n * app depends on correctly retriggers that app's deploy — and adding a new app\n * needs no hand-maintained list of which packages to hash.\n *\n * @param monorepoRoot Absolute repo root (holds `apps/` and `packages/`).\n * @param appDirectory The app to hash, relative to the root (e.g. `apps/mesh`).\n * @example\n * triggers: [hashApp(monorepoRoot, \"apps/mesh\"), hash(env)]\n */\nexport function hashApp(\n\tmonorepoRoot: string,\n\tappDirectory: string,\n\toptions?: HashOptions,\n): string {\n\tconst ignore = options?.ignore ?? DEFAULT_IGNORE;\n\tconst index = buildWorkspaceIndex(monorepoRoot);\n\n\tconst start = path.join(monorepoRoot, appDirectory);\n\tconst visited = new Set<string>();\n\tconst queue = [start];\n\n\twhile (queue.length > 0) {\n\t\tconst directory = queue.pop();\n\n\t\tif (!directory || visited.has(directory)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvisited.add(directory);\n\n\t\tconst pkg = readWorkspacePackage(directory);\n\n\t\tif (!pkg) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n\t\tfor (const depName of Object.keys(deps)) {\n\t\t\tconst depDirectory = index.get(depName);\n\n\t\t\t// Only workspace packages are in the index — external deps are ignored.\n\t\t\tif (depDirectory && !visited.has(depDirectory)) {\n\t\t\t\tqueue.push(depDirectory);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst digest = crypto.createHash(\"sha256\");\n\n\t// Sort by directory so the digest is independent of traversal order; include\n\t// the relative path so moving content between packages changes the hash.\n\tfor (const directory of [...visited].sort()) {\n\t\tdigest.update(`\\0${path.relative(monorepoRoot, directory)}\\0`);\n\t\thashDirInto(digest, directory, ignore);\n\t}\n\n\treturn digest.digest(\"hex\");\n}\n"],"mappings":"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"}
|
package/dist/hash.d.cts
CHANGED
|
@@ -29,6 +29,19 @@ interface HashOptions {
|
|
|
29
29
|
*/
|
|
30
30
|
declare function hash(directory: string, options?: HashOptions): string;
|
|
31
31
|
declare function hash(env: Record<string, pulumi.Input<string>>): pulumi.Output<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Hashes an app's source AND every workspace package it depends on
|
|
34
|
+
* (transitively), for use as a redeploy trigger. Resolving the dependency
|
|
35
|
+
* closure from each `package.json` means a change to a shared `packages/*` an
|
|
36
|
+
* app depends on correctly retriggers that app's deploy — and adding a new app
|
|
37
|
+
* needs no hand-maintained list of which packages to hash.
|
|
38
|
+
*
|
|
39
|
+
* @param monorepoRoot Absolute repo root (holds `apps/` and `packages/`).
|
|
40
|
+
* @param appDirectory The app to hash, relative to the root (e.g. `apps/mesh`).
|
|
41
|
+
* @example
|
|
42
|
+
* triggers: [hashApp(monorepoRoot, "apps/mesh"), hash(env)]
|
|
43
|
+
*/
|
|
44
|
+
declare function hashApp(monorepoRoot: string, appDirectory: string, options?: HashOptions): string;
|
|
32
45
|
//#endregion
|
|
33
|
-
export { hash };
|
|
46
|
+
export { hash, hashApp };
|
|
34
47
|
//# sourceMappingURL=hash.d.cts.map
|
package/dist/hash.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.cts","names":[],"sources":["../src/hash.ts"],"mappings":";;;;UAcU,WAAA;EACT,MAAA,GAAS,GAAG;AAAA;AAZ4B;;;;AAY5B;AAyBb;;;;;;;;AAA6D;AAC7D;;;;;;;;AAtCyC,iBAqCzB,IAAA,CAAK,SAAA,UAAmB,OAAA,GAAU,WAAW;AAAA,iBAC7C,IAAA,CACf,GAAA,EAAK,MAAA,SAAe,MAAA,CAAO,KAAA,YACzB,MAAA,CAAO,MAAA"}
|
|
1
|
+
{"version":3,"file":"hash.d.cts","names":[],"sources":["../src/hash.ts"],"mappings":";;;;UAcU,WAAA;EACT,MAAA,GAAS,GAAG;AAAA;AAZ4B;;;;AAY5B;AAyBb;;;;;;;;AAA6D;AAC7D;;;;;;;;AAtCyC,iBAqCzB,IAAA,CAAK,SAAA,UAAmB,OAAA,GAAU,WAAW;AAAA,iBAC7C,IAAA,CACf,GAAA,EAAK,MAAA,SAAe,MAAA,CAAO,KAAA,YACzB,MAAA,CAAO,MAAA;;;;;;AAAM;AAqHhB;;;;;;iBAAgB,OAAA,CACf,YAAA,UACA,YAAA,UACA,OAAA,GAAU,WAAW"}
|
package/dist/hash.d.mts
CHANGED
|
@@ -29,6 +29,19 @@ interface HashOptions {
|
|
|
29
29
|
*/
|
|
30
30
|
declare function hash(directory: string, options?: HashOptions): string;
|
|
31
31
|
declare function hash(env: Record<string, pulumi.Input<string>>): pulumi.Output<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Hashes an app's source AND every workspace package it depends on
|
|
34
|
+
* (transitively), for use as a redeploy trigger. Resolving the dependency
|
|
35
|
+
* closure from each `package.json` means a change to a shared `packages/*` an
|
|
36
|
+
* app depends on correctly retriggers that app's deploy — and adding a new app
|
|
37
|
+
* needs no hand-maintained list of which packages to hash.
|
|
38
|
+
*
|
|
39
|
+
* @param monorepoRoot Absolute repo root (holds `apps/` and `packages/`).
|
|
40
|
+
* @param appDirectory The app to hash, relative to the root (e.g. `apps/mesh`).
|
|
41
|
+
* @example
|
|
42
|
+
* triggers: [hashApp(monorepoRoot, "apps/mesh"), hash(env)]
|
|
43
|
+
*/
|
|
44
|
+
declare function hashApp(monorepoRoot: string, appDirectory: string, options?: HashOptions): string;
|
|
32
45
|
//#endregion
|
|
33
|
-
export { hash };
|
|
46
|
+
export { hash, hashApp };
|
|
34
47
|
//# sourceMappingURL=hash.d.mts.map
|
package/dist/hash.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.mts","names":[],"sources":["../src/hash.ts"],"mappings":";;;;UAcU,WAAA;EACT,MAAA,GAAS,GAAG;AAAA;AAZ4B;;;;AAY5B;AAyBb;;;;;;;;AAA6D;AAC7D;;;;;;;;AAtCyC,iBAqCzB,IAAA,CAAK,SAAA,UAAmB,OAAA,GAAU,WAAW;AAAA,iBAC7C,IAAA,CACf,GAAA,EAAK,MAAA,SAAe,MAAA,CAAO,KAAA,YACzB,MAAA,CAAO,MAAA"}
|
|
1
|
+
{"version":3,"file":"hash.d.mts","names":[],"sources":["../src/hash.ts"],"mappings":";;;;UAcU,WAAA;EACT,MAAA,GAAS,GAAG;AAAA;AAZ4B;;;;AAY5B;AAyBb;;;;;;;;AAA6D;AAC7D;;;;;;;;AAtCyC,iBAqCzB,IAAA,CAAK,SAAA,UAAmB,OAAA,GAAU,WAAW;AAAA,iBAC7C,IAAA,CACf,GAAA,EAAK,MAAA,SAAe,MAAA,CAAO,KAAA,YACzB,MAAA,CAAO,MAAA;;;;;;AAAM;AAqHhB;;;;;;iBAAgB,OAAA,CACf,YAAA,UACA,YAAA,UACA,OAAA,GAAU,WAAW"}
|
package/dist/hash.mjs
CHANGED
|
@@ -24,22 +24,94 @@ function hash(input, options) {
|
|
|
24
24
|
}
|
|
25
25
|
const ignore = options?.ignore ?? DEFAULT_IGNORE;
|
|
26
26
|
const digest = crypto.createHash("sha256");
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
hashDirInto(digest, input, ignore);
|
|
28
|
+
return digest.digest("hex");
|
|
29
|
+
}
|
|
30
|
+
/** Recursively folds a directory's file names + contents into `digest`. */
|
|
31
|
+
function hashDirInto(digest, currentPath, ignore) {
|
|
32
|
+
const entries = fs.readdirSync(currentPath, { withFileTypes: true });
|
|
33
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
34
|
+
if (ignore.has(entry.name)) continue;
|
|
35
|
+
const fullPath = path.join(currentPath, entry.name);
|
|
36
|
+
if (entry.isDirectory()) hashDirInto(digest, fullPath, ignore);
|
|
37
|
+
else if (entry.isFile()) {
|
|
38
|
+
digest.update(entry.name);
|
|
39
|
+
digest.update(fs.readFileSync(fullPath));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function readWorkspacePackage(directory) {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(fs.readFileSync(path.join(directory, "package.json"), "utf8"));
|
|
46
|
+
} catch {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Indexes every workspace package by its `package.json` `name` -> directory, by
|
|
52
|
+
* scanning `apps/*` and `packages/*`. Robust to a package whose directory name
|
|
53
|
+
* differs from its published name.
|
|
54
|
+
*/
|
|
55
|
+
function buildWorkspaceIndex(monorepoRoot) {
|
|
56
|
+
const index = /* @__PURE__ */ new Map();
|
|
57
|
+
for (const group of ["apps", "packages"]) {
|
|
58
|
+
const base = path.join(monorepoRoot, group);
|
|
59
|
+
let entries;
|
|
60
|
+
try {
|
|
61
|
+
entries = fs.readdirSync(base, { withFileTypes: true });
|
|
62
|
+
} catch {
|
|
63
|
+
continue;
|
|
37
64
|
}
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
if (!entry.isDirectory()) continue;
|
|
67
|
+
const directory = path.join(base, entry.name);
|
|
68
|
+
const pkg = readWorkspacePackage(directory);
|
|
69
|
+
if (pkg?.name) index.set(pkg.name, directory);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return index;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Hashes an app's source AND every workspace package it depends on
|
|
76
|
+
* (transitively), for use as a redeploy trigger. Resolving the dependency
|
|
77
|
+
* closure from each `package.json` means a change to a shared `packages/*` an
|
|
78
|
+
* app depends on correctly retriggers that app's deploy — and adding a new app
|
|
79
|
+
* needs no hand-maintained list of which packages to hash.
|
|
80
|
+
*
|
|
81
|
+
* @param monorepoRoot Absolute repo root (holds `apps/` and `packages/`).
|
|
82
|
+
* @param appDirectory The app to hash, relative to the root (e.g. `apps/mesh`).
|
|
83
|
+
* @example
|
|
84
|
+
* triggers: [hashApp(monorepoRoot, "apps/mesh"), hash(env)]
|
|
85
|
+
*/
|
|
86
|
+
function hashApp(monorepoRoot, appDirectory, options) {
|
|
87
|
+
const ignore = options?.ignore ?? DEFAULT_IGNORE;
|
|
88
|
+
const index = buildWorkspaceIndex(monorepoRoot);
|
|
89
|
+
const start = path.join(monorepoRoot, appDirectory);
|
|
90
|
+
const visited = /* @__PURE__ */ new Set();
|
|
91
|
+
const queue = [start];
|
|
92
|
+
while (queue.length > 0) {
|
|
93
|
+
const directory = queue.pop();
|
|
94
|
+
if (!directory || visited.has(directory)) continue;
|
|
95
|
+
visited.add(directory);
|
|
96
|
+
const pkg = readWorkspacePackage(directory);
|
|
97
|
+
if (!pkg) continue;
|
|
98
|
+
const deps = {
|
|
99
|
+
...pkg.dependencies,
|
|
100
|
+
...pkg.devDependencies
|
|
101
|
+
};
|
|
102
|
+
for (const depName of Object.keys(deps)) {
|
|
103
|
+
const depDirectory = index.get(depName);
|
|
104
|
+
if (depDirectory && !visited.has(depDirectory)) queue.push(depDirectory);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const digest = crypto.createHash("sha256");
|
|
108
|
+
for (const directory of [...visited].sort()) {
|
|
109
|
+
digest.update(`\0${path.relative(monorepoRoot, directory)}\0`);
|
|
110
|
+
hashDirInto(digest, directory, ignore);
|
|
38
111
|
}
|
|
39
|
-
walk(input);
|
|
40
112
|
return digest.digest("hex");
|
|
41
113
|
}
|
|
42
114
|
|
|
43
115
|
//#endregion
|
|
44
|
-
export { hash };
|
|
116
|
+
export { hash, hashApp };
|
|
45
117
|
//# sourceMappingURL=hash.mjs.map
|
package/dist/hash.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.mjs","names":[],"sources":["../src/hash.ts"],"sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nconst DEFAULT_IGNORE = new Set([\n\t\"node_modules\",\n\t\"dist\",\n\t\".turbo\",\n\t\".next\",\n\t\".git\",\n\t\".vercel\",\n]);\n\ninterface HashOptions {\n\tignore?: Set<string>;\n}\n\n/**\n * Produces a stable SHA-256 hex digest for use as a resource/deploy trigger,\n * from either a source directory or an environment map.\n *\n * - **Directory** (`string`): recursively hashes file names + contents (build\n * and VCS directories skipped). Synchronous — returns a plain `string`.\n * - **Env map** (`Record<string, Input<string>>`): resolves the values, sorts\n * by key, and hashes them into a single non-secret `Output<string>`. Passing\n * secret `Output`s straight into a dynamic resource's inputs intermittently\n * races Pulumi's gRPC secret serialization (`Unexpected struct type`, issue\n * #16041) — the reason such deploys otherwise need `--parallel 1`. Collapsing\n * the env to one `unsecret` digest keeps the trigger moving on any change\n * while carrying no secret, so deploys are safe to (re)create at full\n * parallelism. Exposing the digest is safe: it is a one-way hash of\n * high-entropy secrets.\n *\n * @param input A source directory path, or a map of env var name to value.\n * @param options Directory mode only: `ignore` overrides the default skip set.\n * @returns `string` for a directory, `Output<string>` for an env map.\n * @example\n * triggers: [hash(appDir), hash(env)]\n */\nexport function hash(directory: string, options?: HashOptions): string;\nexport function hash(\n\tenv: Record<string, pulumi.Input<string>>,\n): pulumi.Output<string>;\nexport function hash(\n\tinput: string | Record<string, pulumi.Input<string>>,\n\toptions?: HashOptions,\n): string | pulumi.Output<string> {\n\tif (typeof input !== \"string\") {\n\t\tconst keys = Object.keys(input).sort();\n\n\t\treturn pulumi.unsecret(\n\t\t\tpulumi.all(keys.map((key) => input[key])).apply((values) => {\n\t\t\t\tconst digest = crypto.createHash(\"sha256\");\n\n\t\t\t\tfor (const [index, key] of keys.entries()) {\n\t\t\t\t\tdigest.update(`${key}=${values[index]}\\0`);\n\t\t\t\t}\n\n\t\t\t\treturn digest.digest(\"hex\");\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst ignore = options?.ignore ?? DEFAULT_IGNORE;\n\tconst digest = crypto.createHash(\"sha256\");\n\n\
|
|
1
|
+
{"version":3,"file":"hash.mjs","names":[],"sources":["../src/hash.ts"],"sourcesContent":["import * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as pulumi from \"@pulumi/pulumi\";\n\nconst DEFAULT_IGNORE = new Set([\n\t\"node_modules\",\n\t\"dist\",\n\t\".turbo\",\n\t\".next\",\n\t\".git\",\n\t\".vercel\",\n]);\n\ninterface HashOptions {\n\tignore?: Set<string>;\n}\n\n/**\n * Produces a stable SHA-256 hex digest for use as a resource/deploy trigger,\n * from either a source directory or an environment map.\n *\n * - **Directory** (`string`): recursively hashes file names + contents (build\n * and VCS directories skipped). Synchronous — returns a plain `string`.\n * - **Env map** (`Record<string, Input<string>>`): resolves the values, sorts\n * by key, and hashes them into a single non-secret `Output<string>`. Passing\n * secret `Output`s straight into a dynamic resource's inputs intermittently\n * races Pulumi's gRPC secret serialization (`Unexpected struct type`, issue\n * #16041) — the reason such deploys otherwise need `--parallel 1`. Collapsing\n * the env to one `unsecret` digest keeps the trigger moving on any change\n * while carrying no secret, so deploys are safe to (re)create at full\n * parallelism. Exposing the digest is safe: it is a one-way hash of\n * high-entropy secrets.\n *\n * @param input A source directory path, or a map of env var name to value.\n * @param options Directory mode only: `ignore` overrides the default skip set.\n * @returns `string` for a directory, `Output<string>` for an env map.\n * @example\n * triggers: [hash(appDir), hash(env)]\n */\nexport function hash(directory: string, options?: HashOptions): string;\nexport function hash(\n\tenv: Record<string, pulumi.Input<string>>,\n): pulumi.Output<string>;\nexport function hash(\n\tinput: string | Record<string, pulumi.Input<string>>,\n\toptions?: HashOptions,\n): string | pulumi.Output<string> {\n\tif (typeof input !== \"string\") {\n\t\tconst keys = Object.keys(input).sort();\n\n\t\treturn pulumi.unsecret(\n\t\t\tpulumi.all(keys.map((key) => input[key])).apply((values) => {\n\t\t\t\tconst digest = crypto.createHash(\"sha256\");\n\n\t\t\t\tfor (const [index, key] of keys.entries()) {\n\t\t\t\t\tdigest.update(`${key}=${values[index]}\\0`);\n\t\t\t\t}\n\n\t\t\t\treturn digest.digest(\"hex\");\n\t\t\t}),\n\t\t);\n\t}\n\n\tconst ignore = options?.ignore ?? DEFAULT_IGNORE;\n\tconst digest = crypto.createHash(\"sha256\");\n\n\thashDirInto(digest, input, ignore);\n\n\treturn digest.digest(\"hex\");\n}\n\n/** Recursively folds a directory's file names + contents into `digest`. */\nfunction hashDirInto(\n\tdigest: crypto.Hash,\n\tcurrentPath: string,\n\tignore: Set<string>,\n): void {\n\tconst entries = fs.readdirSync(currentPath, { withFileTypes: true });\n\n\tfor (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n\t\tif (ignore.has(entry.name)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fullPath = path.join(currentPath, entry.name);\n\n\t\tif (entry.isDirectory()) {\n\t\t\thashDirInto(digest, fullPath, ignore);\n\t\t} else if (entry.isFile()) {\n\t\t\tdigest.update(entry.name);\n\t\t\tdigest.update(fs.readFileSync(fullPath));\n\t\t}\n\t}\n}\n\ninterface WorkspacePackage {\n\tname?: string;\n\tdependencies?: Record<string, string>;\n\tdevDependencies?: Record<string, string>;\n}\n\nfunction readWorkspacePackage(directory: string): WorkspacePackage | undefined {\n\ttry {\n\t\treturn JSON.parse(\n\t\t\tfs.readFileSync(path.join(directory, \"package.json\"), \"utf8\"),\n\t\t) as WorkspacePackage;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Indexes every workspace package by its `package.json` `name` -> directory, by\n * scanning `apps/*` and `packages/*`. Robust to a package whose directory name\n * differs from its published name.\n */\nfunction buildWorkspaceIndex(monorepoRoot: string): Map<string, string> {\n\tconst index = new Map<string, string>();\n\n\tfor (const group of [\"apps\", \"packages\"]) {\n\t\tconst base = path.join(monorepoRoot, group);\n\n\t\tlet entries: fs.Dirent[];\n\n\t\ttry {\n\t\t\tentries = fs.readdirSync(base, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const entry of entries) {\n\t\t\tif (!entry.isDirectory()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst directory = path.join(base, entry.name);\n\t\t\tconst pkg = readWorkspacePackage(directory);\n\n\t\t\tif (pkg?.name) {\n\t\t\t\tindex.set(pkg.name, directory);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn index;\n}\n\n/**\n * Hashes an app's source AND every workspace package it depends on\n * (transitively), for use as a redeploy trigger. Resolving the dependency\n * closure from each `package.json` means a change to a shared `packages/*` an\n * app depends on correctly retriggers that app's deploy — and adding a new app\n * needs no hand-maintained list of which packages to hash.\n *\n * @param monorepoRoot Absolute repo root (holds `apps/` and `packages/`).\n * @param appDirectory The app to hash, relative to the root (e.g. `apps/mesh`).\n * @example\n * triggers: [hashApp(monorepoRoot, \"apps/mesh\"), hash(env)]\n */\nexport function hashApp(\n\tmonorepoRoot: string,\n\tappDirectory: string,\n\toptions?: HashOptions,\n): string {\n\tconst ignore = options?.ignore ?? DEFAULT_IGNORE;\n\tconst index = buildWorkspaceIndex(monorepoRoot);\n\n\tconst start = path.join(monorepoRoot, appDirectory);\n\tconst visited = new Set<string>();\n\tconst queue = [start];\n\n\twhile (queue.length > 0) {\n\t\tconst directory = queue.pop();\n\n\t\tif (!directory || visited.has(directory)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tvisited.add(directory);\n\n\t\tconst pkg = readWorkspacePackage(directory);\n\n\t\tif (!pkg) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst deps = { ...pkg.dependencies, ...pkg.devDependencies };\n\n\t\tfor (const depName of Object.keys(deps)) {\n\t\t\tconst depDirectory = index.get(depName);\n\n\t\t\t// Only workspace packages are in the index — external deps are ignored.\n\t\t\tif (depDirectory && !visited.has(depDirectory)) {\n\t\t\t\tqueue.push(depDirectory);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst digest = crypto.createHash(\"sha256\");\n\n\t// Sort by directory so the digest is independent of traversal order; include\n\t// the relative path so moving content between packages changes the hash.\n\tfor (const directory of [...visited].sort()) {\n\t\tdigest.update(`\\0${path.relative(monorepoRoot, directory)}\\0`);\n\t\thashDirInto(digest, directory, ignore);\n\t}\n\n\treturn digest.digest(\"hex\");\n}\n"],"mappings":"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"}
|