@infracraft/pulumi 1.6.1 → 1.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -33,12 +33,11 @@ var RailwayDeploy = class extends _pulumi_pulumi.ComponentResource {
33
33
  return dir;
34
34
  }).join("\\n");
35
35
  const setupLines = [ignorePatterns ? `printf '${ignorePatterns}\\n' > .railwayignore` : "", args.railpackConfig ? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, "\\'")}' > railpack.json` : ""].filter(Boolean).join("; ");
36
- const deployCmd = _pulumi_pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & railway up --ci --project ${project.id} --service ${service.id} --environment ${environment.id}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;
36
+ const deployCmd = _pulumi_pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & RAILWAY_TOKEN=${projectToken} railway up --ci --project ${project.id} --service ${service.id} --environment ${environment.id}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;
37
37
  new _pulumi_command.local.Command(`${name}-deploy`, {
38
38
  create: deployCmd,
39
39
  triggers: args.triggers,
40
- dir: require_stable_dir.stableDir(args.directory),
41
- environment: { RAILWAY_TOKEN: projectToken }
40
+ dir: require_stable_dir.stableDir(args.directory)
42
41
  }, { parent: this });
43
42
  this.registerOutputs({});
44
43
  }
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.cjs","names":["pulumi","command","stableDir"],"sources":["../../src/railway/deploy.ts"],"sourcesContent":["import * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport { stableDir } from \"../stable-dir\";\nimport type { RailwayEnvironment } from \"./environment\";\nimport type { RailwayProject } from \"./project\";\nimport type { RailwayProvider } from \"./provider\";\nimport { RailwayBuilder, type RailwayService } from \"./service\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system to use when building the service. */\n\tbuilder?: RailwayBuilder;\n\n\t/** Shell command executed to start the service at runtime. */\n\tstartCommand?: string;\n\n\t/** Shell command executed before the main deploy (e.g. migrations). */\n\tpreDeployCommand?: string;\n}\n\n/** Args for RailwayDeploy. */\nexport interface RailwayDeployArgs {\n\t/**\n\t * Absolute path to the monorepo root (working directory for `railway up`).\n\t * Stored relative to the Pulumi program directory so the command stays stable\n\t * across machines and CI (see {@link stableDir}).\n\t */\n\tdirectory: string;\n\n\t/** Values that trigger a redeploy when changed (e.g. source hashes, env hashes). */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\n\t/** Directories to exclude via `.railwayignore`. */\n\texcludePaths?: string[];\n\n\t/** Railpack configuration written to `railpack.json` before deploy. */\n\trailpackConfig?: Record<string, unknown>;\n}\n\n/** Options type for RailwayDeploy — replaces Pulumi's native `provider` field. */\ntype RailwayDeployOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Railway authentication context. */\n\tprovider: RailwayProvider;\n\n\t/** Railway project context. */\n\tproject: RailwayProject;\n\n\t/** Railway environment context. */\n\tenvironment: RailwayEnvironment;\n\n\t/** Railway service context. */\n\tservice: RailwayService;\n\n\t/** Environment-scoped Railway deploy token. Provision via {@link RailwayProjectToken}. */\n\tprojectToken: pulumi.Input<string>;\n};\n\nconst LOCK_DIR = \"/tmp/.railway-upload-lock\";\n\n/**\n * Deploys a Railway service and waits for the build to complete.\n *\n * Uses `railway up --ci` which blocks until the build finishes.\n * Multiple deploys run in parallel — a mkdir lock serializes only the\n * brief upload phase (~5s) when `.railwayignore` must be consistent,\n * then releases so builds stream concurrently.\n *\n * @example\n * ```typescript\n * new RailwayDeploy(\"api-deploy\", {\n * directory: monorepoRoot,\n * triggers: [sourceHash],\n * }, { provider, project, environment, service, projectToken: stagingToken.token });\n * ```\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts: RailwayDeployOptions,\n\t) {\n\t\tconst {\n\t\t\tprovider,\n\t\t\tproject,\n\t\t\tenvironment,\n\t\t\tservice,\n\t\t\tprojectToken,\n\t\t\t...pulumiOpts\n\t\t} = opts;\n\n\t\tsuper(\"infracraft:railway:Deploy\", name, {}, pulumiOpts);\n\n\t\tconst ignorePatterns = (args.excludePaths ?? [])\n\t\t\t.map((dir) => {\n\t\t\t\tif (dir.startsWith(\"apps/\")) {\n\t\t\t\t\treturn `${dir}/**\\\\n!${dir}/package.json`;\n\t\t\t\t}\n\n\t\t\t\treturn dir;\n\t\t\t})\n\t\t\t.join(\"\\\\n\");\n\n\t\tconst writeIgnore = ignorePatterns\n\t\t\t? `printf '${ignorePatterns}\\\\n' > .railwayignore`\n\t\t\t: \"\";\n\n\t\tconst writeRailpack = args.railpackConfig\n\t\t\t? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, \"\\\\'\")}' > railpack.json`\n\t\t\t: \"\";\n\n\t\tconst setupLines = [writeIgnore, writeRailpack].filter(Boolean).join(\"; \");\n\n\t\tconst deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & railway up --ci --project ${project.id} --service ${service.id} --environment ${environment.id}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;\n\n\t\tnew command.local.Command(\n\t\t\t`${name}-deploy`,\n\t\t\t{\n\t\t\t\tcreate: deployCmd,\n\t\t\t\ttriggers: args.triggers,\n\t\t\t\tdir: stableDir(args.directory),\n\t\t\t\tenvironment: {\n\t\t\t\t\tRAILWAY_TOKEN: projectToken,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.registerOutputs({});\n\t}\n}\n"],"mappings":";;;;;;;;;AA4DA,MAAM,WAAW;;;;;;;;;;;;;;;;;AAkBjB,IAAa,gBAAb,cAAmCA,eAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,EACL,UACA,SACA,aACA,SACA,cACA,GAAG,eACA;EAEJ,MAAM,6BAA6B,MAAM,CAAC,GAAG,UAAU;EAEvD,MAAM,kBAAkB,KAAK,gBAAgB,CAAC,GAC5C,KAAK,QAAQ;GACb,IAAI,IAAI,WAAW,OAAO,GACzB,OAAO,GAAG,IAAI,SAAS,IAAI;GAG5B,OAAO;EACR,CAAC,EACA,KAAK,KAAK;EAUZ,MAAM,aAAa,CARC,iBACjB,WAAW,eAAe,yBAC1B,IAEmB,KAAK,iBACxB,WAAW,KAAK,UAAU,KAAK,cAAc,EAAE,QAAQ,MAAM,KAAK,EAAE,qBACpE,EAE2C,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;EAEzE,MAAM,YAAY,eAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,8CAA8C,QAAQ,GAAG,aAAa,QAAQ,GAAG,iBAAiB,YAAY,GAAG,uDAAuD,SAAS;EAE9V,IAAIC,gBAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,KAAK;GACf,KAAKC,6BAAU,KAAK,SAAS;GAC7B,aAAa,EACZ,eAAe,aAChB;EACD,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}
1
+ {"version":3,"file":"deploy.cjs","names":["pulumi","command","stableDir"],"sources":["../../src/railway/deploy.ts"],"sourcesContent":["import * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport { stableDir } from \"../stable-dir\";\nimport type { RailwayEnvironment } from \"./environment\";\nimport type { RailwayProject } from \"./project\";\nimport type { RailwayProvider } from \"./provider\";\nimport { RailwayBuilder, type RailwayService } from \"./service\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system to use when building the service. */\n\tbuilder?: RailwayBuilder;\n\n\t/** Shell command executed to start the service at runtime. */\n\tstartCommand?: string;\n\n\t/** Shell command executed before the main deploy (e.g. migrations). */\n\tpreDeployCommand?: string;\n}\n\n/** Args for RailwayDeploy. */\nexport interface RailwayDeployArgs {\n\t/**\n\t * Absolute path to the monorepo root (working directory for `railway up`).\n\t * Stored relative to the Pulumi program directory so the command stays stable\n\t * across machines and CI (see {@link stableDir}).\n\t */\n\tdirectory: string;\n\n\t/** Values that trigger a redeploy when changed (e.g. source hashes, env hashes). */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\n\t/** Directories to exclude via `.railwayignore`. */\n\texcludePaths?: string[];\n\n\t/** Railpack configuration written to `railpack.json` before deploy. */\n\trailpackConfig?: Record<string, unknown>;\n}\n\n/** Options type for RailwayDeploy — replaces Pulumi's native `provider` field. */\ntype RailwayDeployOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Railway authentication context. */\n\tprovider: RailwayProvider;\n\n\t/** Railway project context. */\n\tproject: RailwayProject;\n\n\t/** Railway environment context. */\n\tenvironment: RailwayEnvironment;\n\n\t/** Railway service context. */\n\tservice: RailwayService;\n\n\t/** Environment-scoped Railway deploy token. Provision via {@link RailwayProjectToken}. */\n\tprojectToken: pulumi.Input<string>;\n};\n\nconst LOCK_DIR = \"/tmp/.railway-upload-lock\";\n\n/**\n * Deploys a Railway service and waits for the build to complete.\n *\n * Uses `railway up --ci` which blocks until the build finishes.\n * Multiple deploys run in parallel — a mkdir lock serializes only the\n * brief upload phase (~5s) when `.railwayignore` must be consistent,\n * then releases so builds stream concurrently.\n *\n * @example\n * ```typescript\n * new RailwayDeploy(\"api-deploy\", {\n * directory: monorepoRoot,\n * triggers: [sourceHash],\n * }, { provider, project, environment, service, projectToken: stagingToken.token });\n * ```\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts: RailwayDeployOptions,\n\t) {\n\t\tconst {\n\t\t\tprovider,\n\t\t\tproject,\n\t\t\tenvironment,\n\t\t\tservice,\n\t\t\tprojectToken,\n\t\t\t...pulumiOpts\n\t\t} = opts;\n\n\t\tsuper(\"infracraft:railway:Deploy\", name, {}, pulumiOpts);\n\n\t\tconst ignorePatterns = (args.excludePaths ?? [])\n\t\t\t.map((dir) => {\n\t\t\t\tif (dir.startsWith(\"apps/\")) {\n\t\t\t\t\treturn `${dir}/**\\\\n!${dir}/package.json`;\n\t\t\t\t}\n\n\t\t\t\treturn dir;\n\t\t\t})\n\t\t\t.join(\"\\\\n\");\n\n\t\tconst writeIgnore = ignorePatterns\n\t\t\t? `printf '${ignorePatterns}\\\\n' > .railwayignore`\n\t\t\t: \"\";\n\n\t\tconst writeRailpack = args.railpackConfig\n\t\t\t? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, \"\\\\'\")}' > railpack.json`\n\t\t\t: \"\";\n\n\t\tconst setupLines = [writeIgnore, writeRailpack].filter(Boolean).join(\"; \");\n\n\t\t// The deploy token is inlined into the create command (RAILWAY_TOKEN=… railway up) rather\n\t\t// than passed via command.local.Command's `environment` map. The token is auto-minted (a\n\t\t// RailwayProjectToken), so it is an UNKNOWN secret at preview time, and an unknown secret in\n\t\t// the `environment` map makes `pulumi preview` fail (\"malformed RPC secret: missing value\").\n\t\t// Inlining keeps the token secret in state while letting preview serialize cleanly.\n\t\tconst deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & RAILWAY_TOKEN=${projectToken} railway up --ci --project ${project.id} --service ${service.id} --environment ${environment.id}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;\n\n\t\tnew command.local.Command(\n\t\t\t`${name}-deploy`,\n\t\t\t{\n\t\t\t\tcreate: deployCmd,\n\t\t\t\ttriggers: args.triggers,\n\t\t\t\tdir: stableDir(args.directory),\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.registerOutputs({});\n\t}\n}\n"],"mappings":";;;;;;;;;AA4DA,MAAM,WAAW;;;;;;;;;;;;;;;;;AAkBjB,IAAa,gBAAb,cAAmCA,eAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,EACL,UACA,SACA,aACA,SACA,cACA,GAAG,eACA;EAEJ,MAAM,6BAA6B,MAAM,CAAC,GAAG,UAAU;EAEvD,MAAM,kBAAkB,KAAK,gBAAgB,CAAC,GAC5C,KAAK,QAAQ;GACb,IAAI,IAAI,WAAW,OAAO,GACzB,OAAO,GAAG,IAAI,SAAS,IAAI;GAG5B,OAAO;EACR,CAAC,EACA,KAAK,KAAK;EAUZ,MAAM,aAAa,CARC,iBACjB,WAAW,eAAe,yBAC1B,IAEmB,KAAK,iBACxB,WAAW,KAAK,UAAU,KAAK,cAAc,EAAE,QAAQ,MAAM,KAAK,EAAE,qBACpE,EAE2C,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;EAOzE,MAAM,YAAY,eAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,kCAAkC,aAAa,6BAA6B,QAAQ,GAAG,aAAa,QAAQ,GAAG,iBAAiB,YAAY,GAAG,uDAAuD,SAAS;EAE5X,IAAIC,gBAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,KAAK;GACf,KAAKC,6BAAU,KAAK,SAAS;EAC9B,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}
@@ -30,12 +30,11 @@ var RailwayDeploy = class extends pulumi.ComponentResource {
30
30
  return dir;
31
31
  }).join("\\n");
32
32
  const setupLines = [ignorePatterns ? `printf '${ignorePatterns}\\n' > .railwayignore` : "", args.railpackConfig ? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, "\\'")}' > railpack.json` : ""].filter(Boolean).join("; ");
33
- const deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & railway up --ci --project ${project.id} --service ${service.id} --environment ${environment.id}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;
33
+ const deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & RAILWAY_TOKEN=${projectToken} railway up --ci --project ${project.id} --service ${service.id} --environment ${environment.id}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;
34
34
  new command.local.Command(`${name}-deploy`, {
35
35
  create: deployCmd,
36
36
  triggers: args.triggers,
37
- dir: stableDir(args.directory),
38
- environment: { RAILWAY_TOKEN: projectToken }
37
+ dir: stableDir(args.directory)
39
38
  }, { parent: this });
40
39
  this.registerOutputs({});
41
40
  }
@@ -1 +1 @@
1
- {"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/railway/deploy.ts"],"sourcesContent":["import * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport { stableDir } from \"../stable-dir\";\nimport type { RailwayEnvironment } from \"./environment\";\nimport type { RailwayProject } from \"./project\";\nimport type { RailwayProvider } from \"./provider\";\nimport { RailwayBuilder, type RailwayService } from \"./service\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system to use when building the service. */\n\tbuilder?: RailwayBuilder;\n\n\t/** Shell command executed to start the service at runtime. */\n\tstartCommand?: string;\n\n\t/** Shell command executed before the main deploy (e.g. migrations). */\n\tpreDeployCommand?: string;\n}\n\n/** Args for RailwayDeploy. */\nexport interface RailwayDeployArgs {\n\t/**\n\t * Absolute path to the monorepo root (working directory for `railway up`).\n\t * Stored relative to the Pulumi program directory so the command stays stable\n\t * across machines and CI (see {@link stableDir}).\n\t */\n\tdirectory: string;\n\n\t/** Values that trigger a redeploy when changed (e.g. source hashes, env hashes). */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\n\t/** Directories to exclude via `.railwayignore`. */\n\texcludePaths?: string[];\n\n\t/** Railpack configuration written to `railpack.json` before deploy. */\n\trailpackConfig?: Record<string, unknown>;\n}\n\n/** Options type for RailwayDeploy — replaces Pulumi's native `provider` field. */\ntype RailwayDeployOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Railway authentication context. */\n\tprovider: RailwayProvider;\n\n\t/** Railway project context. */\n\tproject: RailwayProject;\n\n\t/** Railway environment context. */\n\tenvironment: RailwayEnvironment;\n\n\t/** Railway service context. */\n\tservice: RailwayService;\n\n\t/** Environment-scoped Railway deploy token. Provision via {@link RailwayProjectToken}. */\n\tprojectToken: pulumi.Input<string>;\n};\n\nconst LOCK_DIR = \"/tmp/.railway-upload-lock\";\n\n/**\n * Deploys a Railway service and waits for the build to complete.\n *\n * Uses `railway up --ci` which blocks until the build finishes.\n * Multiple deploys run in parallel — a mkdir lock serializes only the\n * brief upload phase (~5s) when `.railwayignore` must be consistent,\n * then releases so builds stream concurrently.\n *\n * @example\n * ```typescript\n * new RailwayDeploy(\"api-deploy\", {\n * directory: monorepoRoot,\n * triggers: [sourceHash],\n * }, { provider, project, environment, service, projectToken: stagingToken.token });\n * ```\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts: RailwayDeployOptions,\n\t) {\n\t\tconst {\n\t\t\tprovider,\n\t\t\tproject,\n\t\t\tenvironment,\n\t\t\tservice,\n\t\t\tprojectToken,\n\t\t\t...pulumiOpts\n\t\t} = opts;\n\n\t\tsuper(\"infracraft:railway:Deploy\", name, {}, pulumiOpts);\n\n\t\tconst ignorePatterns = (args.excludePaths ?? [])\n\t\t\t.map((dir) => {\n\t\t\t\tif (dir.startsWith(\"apps/\")) {\n\t\t\t\t\treturn `${dir}/**\\\\n!${dir}/package.json`;\n\t\t\t\t}\n\n\t\t\t\treturn dir;\n\t\t\t})\n\t\t\t.join(\"\\\\n\");\n\n\t\tconst writeIgnore = ignorePatterns\n\t\t\t? `printf '${ignorePatterns}\\\\n' > .railwayignore`\n\t\t\t: \"\";\n\n\t\tconst writeRailpack = args.railpackConfig\n\t\t\t? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, \"\\\\'\")}' > railpack.json`\n\t\t\t: \"\";\n\n\t\tconst setupLines = [writeIgnore, writeRailpack].filter(Boolean).join(\"; \");\n\n\t\tconst deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & railway up --ci --project ${project.id} --service ${service.id} --environment ${environment.id}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;\n\n\t\tnew command.local.Command(\n\t\t\t`${name}-deploy`,\n\t\t\t{\n\t\t\t\tcreate: deployCmd,\n\t\t\t\ttriggers: args.triggers,\n\t\t\t\tdir: stableDir(args.directory),\n\t\t\t\tenvironment: {\n\t\t\t\t\tRAILWAY_TOKEN: projectToken,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.registerOutputs({});\n\t}\n}\n"],"mappings":";;;;;;AA4DA,MAAM,WAAW;;;;;;;;;;;;;;;;;AAkBjB,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,EACL,UACA,SACA,aACA,SACA,cACA,GAAG,eACA;EAEJ,MAAM,6BAA6B,MAAM,CAAC,GAAG,UAAU;EAEvD,MAAM,kBAAkB,KAAK,gBAAgB,CAAC,GAC5C,KAAK,QAAQ;GACb,IAAI,IAAI,WAAW,OAAO,GACzB,OAAO,GAAG,IAAI,SAAS,IAAI;GAG5B,OAAO;EACR,CAAC,EACA,KAAK,KAAK;EAUZ,MAAM,aAAa,CARC,iBACjB,WAAW,eAAe,yBAC1B,IAEmB,KAAK,iBACxB,WAAW,KAAK,UAAU,KAAK,cAAc,EAAE,QAAQ,MAAM,KAAK,EAAE,qBACpE,EAE2C,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;EAEzE,MAAM,YAAY,OAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,8CAA8C,QAAQ,GAAG,aAAa,QAAQ,GAAG,iBAAiB,YAAY,GAAG,uDAAuD,SAAS;EAE9V,IAAI,QAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,KAAK;GACf,KAAK,UAAU,KAAK,SAAS;GAC7B,aAAa,EACZ,eAAe,aAChB;EACD,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}
1
+ {"version":3,"file":"deploy.mjs","names":[],"sources":["../../src/railway/deploy.ts"],"sourcesContent":["import * as command from \"@pulumi/command\";\nimport * as pulumi from \"@pulumi/pulumi\";\nimport { stableDir } from \"../stable-dir\";\nimport type { RailwayEnvironment } from \"./environment\";\nimport type { RailwayProject } from \"./project\";\nimport type { RailwayProvider } from \"./provider\";\nimport { RailwayBuilder, type RailwayService } from \"./service\";\n\n/** Build and deploy configuration for a Railway service. */\nexport interface RailwayDeployConfig {\n\t/** Build system to use when building the service. */\n\tbuilder?: RailwayBuilder;\n\n\t/** Shell command executed to start the service at runtime. */\n\tstartCommand?: string;\n\n\t/** Shell command executed before the main deploy (e.g. migrations). */\n\tpreDeployCommand?: string;\n}\n\n/** Args for RailwayDeploy. */\nexport interface RailwayDeployArgs {\n\t/**\n\t * Absolute path to the monorepo root (working directory for `railway up`).\n\t * Stored relative to the Pulumi program directory so the command stays stable\n\t * across machines and CI (see {@link stableDir}).\n\t */\n\tdirectory: string;\n\n\t/** Values that trigger a redeploy when changed (e.g. source hashes, env hashes). */\n\ttriggers: pulumi.Input<pulumi.Input<string>[]>;\n\n\t/** Directories to exclude via `.railwayignore`. */\n\texcludePaths?: string[];\n\n\t/** Railpack configuration written to `railpack.json` before deploy. */\n\trailpackConfig?: Record<string, unknown>;\n}\n\n/** Options type for RailwayDeploy — replaces Pulumi's native `provider` field. */\ntype RailwayDeployOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Railway authentication context. */\n\tprovider: RailwayProvider;\n\n\t/** Railway project context. */\n\tproject: RailwayProject;\n\n\t/** Railway environment context. */\n\tenvironment: RailwayEnvironment;\n\n\t/** Railway service context. */\n\tservice: RailwayService;\n\n\t/** Environment-scoped Railway deploy token. Provision via {@link RailwayProjectToken}. */\n\tprojectToken: pulumi.Input<string>;\n};\n\nconst LOCK_DIR = \"/tmp/.railway-upload-lock\";\n\n/**\n * Deploys a Railway service and waits for the build to complete.\n *\n * Uses `railway up --ci` which blocks until the build finishes.\n * Multiple deploys run in parallel — a mkdir lock serializes only the\n * brief upload phase (~5s) when `.railwayignore` must be consistent,\n * then releases so builds stream concurrently.\n *\n * @example\n * ```typescript\n * new RailwayDeploy(\"api-deploy\", {\n * directory: monorepoRoot,\n * triggers: [sourceHash],\n * }, { provider, project, environment, service, projectToken: stagingToken.token });\n * ```\n */\nexport class RailwayDeploy extends pulumi.ComponentResource {\n\tconstructor(\n\t\tname: string,\n\t\targs: RailwayDeployArgs,\n\t\topts: RailwayDeployOptions,\n\t) {\n\t\tconst {\n\t\t\tprovider,\n\t\t\tproject,\n\t\t\tenvironment,\n\t\t\tservice,\n\t\t\tprojectToken,\n\t\t\t...pulumiOpts\n\t\t} = opts;\n\n\t\tsuper(\"infracraft:railway:Deploy\", name, {}, pulumiOpts);\n\n\t\tconst ignorePatterns = (args.excludePaths ?? [])\n\t\t\t.map((dir) => {\n\t\t\t\tif (dir.startsWith(\"apps/\")) {\n\t\t\t\t\treturn `${dir}/**\\\\n!${dir}/package.json`;\n\t\t\t\t}\n\n\t\t\t\treturn dir;\n\t\t\t})\n\t\t\t.join(\"\\\\n\");\n\n\t\tconst writeIgnore = ignorePatterns\n\t\t\t? `printf '${ignorePatterns}\\\\n' > .railwayignore`\n\t\t\t: \"\";\n\n\t\tconst writeRailpack = args.railpackConfig\n\t\t\t? `printf '${JSON.stringify(args.railpackConfig).replace(/'/g, \"\\\\'\")}' > railpack.json`\n\t\t\t: \"\";\n\n\t\tconst setupLines = [writeIgnore, writeRailpack].filter(Boolean).join(\"; \");\n\n\t\t// The deploy token is inlined into the create command (RAILWAY_TOKEN=… railway up) rather\n\t\t// than passed via command.local.Command's `environment` map. The token is auto-minted (a\n\t\t// RailwayProjectToken), so it is an UNKNOWN secret at preview time, and an unknown secret in\n\t\t// the `environment` map makes `pulumi preview` fail (\"malformed RPC secret: missing value\").\n\t\t// Inlining keeps the token secret in state while letting preview serialize cleanly.\n\t\tconst deployCmd = pulumi.interpolate`while ! mkdir ${LOCK_DIR} 2>/dev/null; do sleep 1; done; ${setupLines}; { sleep 5; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; } & RAILWAY_TOKEN=${projectToken} railway up --ci --project ${project.id} --service ${service.id} --environment ${environment.id}; EXIT=$?; rm -f .railwayignore railpack.json; rmdir ${LOCK_DIR} 2>/dev/null; wait; exit $EXIT`;\n\n\t\tnew command.local.Command(\n\t\t\t`${name}-deploy`,\n\t\t\t{\n\t\t\t\tcreate: deployCmd,\n\t\t\t\ttriggers: args.triggers,\n\t\t\t\tdir: stableDir(args.directory),\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.registerOutputs({});\n\t}\n}\n"],"mappings":";;;;;;AA4DA,MAAM,WAAW;;;;;;;;;;;;;;;;;AAkBjB,IAAa,gBAAb,cAAmC,OAAO,kBAAkB;CAC3D,YACC,MACA,MACA,MACC;EACD,MAAM,EACL,UACA,SACA,aACA,SACA,cACA,GAAG,eACA;EAEJ,MAAM,6BAA6B,MAAM,CAAC,GAAG,UAAU;EAEvD,MAAM,kBAAkB,KAAK,gBAAgB,CAAC,GAC5C,KAAK,QAAQ;GACb,IAAI,IAAI,WAAW,OAAO,GACzB,OAAO,GAAG,IAAI,SAAS,IAAI;GAG5B,OAAO;EACR,CAAC,EACA,KAAK,KAAK;EAUZ,MAAM,aAAa,CARC,iBACjB,WAAW,eAAe,yBAC1B,IAEmB,KAAK,iBACxB,WAAW,KAAK,UAAU,KAAK,cAAc,EAAE,QAAQ,MAAM,KAAK,EAAE,qBACpE,EAE2C,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;EAOzE,MAAM,YAAY,OAAO,WAAW,iBAAiB,SAAS,kCAAkC,WAAW,yDAAyD,SAAS,kCAAkC,aAAa,6BAA6B,QAAQ,GAAG,aAAa,QAAQ,GAAG,iBAAiB,YAAY,GAAG,uDAAuD,SAAS;EAE5X,IAAI,QAAQ,MAAM,QACjB,GAAG,KAAK,UACR;GACC,QAAQ;GACR,UAAU,KAAK;GACf,KAAK,UAAU,KAAK,SAAS;EAC9B,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,gBAAgB,CAAC,CAAC;CACxB;AACD"}
@@ -13,10 +13,15 @@ const VERCEL_API_URL = "https://api.vercel.com";
13
13
  */
14
14
  var VercelIntegrationResourceProvider = class {
15
15
  async create(inputs) {
16
- const response = await fetch(`${VERCEL_API_URL}/v1/integrations/configurations?teamId=${inputs.teamId}`, { headers: { Authorization: `Bearer ${inputs.token}` } });
16
+ const response = await fetch(`${VERCEL_API_URL}/v1/integrations/configurations?view=account&teamId=${inputs.teamId}`, { headers: { Authorization: `Bearer ${inputs.token}` } });
17
17
  if (!response.ok) throw new Error(`Vercel API error fetching integrations (${response.status}): ${await response.text()}`);
18
- const config = (await response.json()).configurations.find((c) => c.slug === inputs.slug);
19
- if (!config) throw new Error(`Vercel integration "${inputs.slug}" is not installed on this team`);
18
+ const data = await response.json();
19
+ const configurations = Array.isArray(data) ? data : data.configurations;
20
+ const config = configurations.find((c) => c.slug === inputs.slug);
21
+ if (!config) {
22
+ const available = configurations.map((c) => c.slug).join(", ") || "(none)";
23
+ throw new Error(`Vercel integration "${inputs.slug}" is not installed on this team (available: ${available})`);
24
+ }
20
25
  const outs = {
21
26
  ...inputs,
22
27
  configurationId: config.id
@@ -1 +1 @@
1
- {"version":3,"file":"integration.cjs","names":["pulumi"],"sources":["../../src/vercel/integration.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport type { VercelProvider } from \"./provider\";\n\nconst VERCEL_API_URL = \"https://api.vercel.com\";\n\n/** Resolved inputs for the Vercel integration dynamic provider. */\ninterface VercelIntegrationInputs {\n\t/** Vercel API bearer token. */\n\ttoken: string;\n\n\t/** Vercel team/org ID. */\n\tteamId: string;\n\n\t/** Marketplace integration slug (e.g. `\"upstash\"`, `\"neon\"`). */\n\tslug: string;\n}\n\n/** Persisted state for the Vercel integration. */\ninterface VercelIntegrationOutputs extends VercelIntegrationInputs {\n\t/** Vercel-assigned configuration ID (e.g. `\"icfg_…\"`). */\n\tconfigurationId: string;\n}\n\n/** Vercel API response shape for the integration configurations list. */\ninterface VercelIntegrationsResponse {\n\tconfigurations: Array<{ id: string; slug: string }>;\n}\n\n/**\n * Dynamic provider that resolves an installed Vercel marketplace integration\n * by its slug to its configuration ID (`icfg_…`).\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class VercelIntegrationResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: VercelIntegrationInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v1/integrations/configurations?teamId=${inputs.teamId}`,\n\t\t\t{ headers: { Authorization: `Bearer ${inputs.token}` } },\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error fetching integrations (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await response.json()) as VercelIntegrationsResponse;\n\n\t\tconst config = data.configurations.find((c) => c.slug === inputs.slug);\n\n\t\tif (!config) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel integration \"${inputs.slug}\" is not installed on this team`,\n\t\t\t);\n\t\t}\n\n\t\tconst outs: VercelIntegrationOutputs = {\n\t\t\t...inputs,\n\t\t\tconfigurationId: config.id,\n\t\t};\n\n\t\treturn { id: config.id, outs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: VercelIntegrationOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\t// Resolver-only: the integration's configuration id (icfg_…) is stable for the\n\t\t// lifetime of an installed integration, so read() does not re-query. If the\n\t\t// integration is uninstalled and reinstalled, a subsequent `up` re-resolves via create().\n\t\treturn { id, props };\n\t}\n\n\tasync delete(): Promise<void> {\n\t\tpulumi.log.warn(\n\t\t\t\"VercelIntegration is a read-only resolver — uninstall the integration from the Vercel dashboard if needed\",\n\t\t);\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: VercelIntegrationOutputs,\n\t\tnews: VercelIntegrationInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.teamId !== news.teamId) {\n\t\t\treplaces.push(\"teamId\");\n\t\t}\n\n\t\tif (olds.slug !== news.slug) {\n\t\t\treplaces.push(\"slug\");\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 VercelIntegrationResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly configurationId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tteamId: pulumi.Input<string>;\n\t\t\tslug: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew VercelIntegrationResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, configurationId: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n\n/** Options type for VercelIntegration — replaces Pulumi's native `provider` field. */\ntype VercelIntegrationOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Vercel authentication context. */\n\tprovider: VercelProvider;\n};\n\n/**\n * Args for {@link VercelIntegration}.\n */\nexport interface VercelIntegrationArgs {\n\t/**\n\t * Marketplace integration slug (e.g. `\"upstash\"`, `\"neon\"`).\n\t * The integration must already be installed on the team via the Vercel dashboard.\n\t */\n\tslug: pulumi.Input<string>;\n}\n\n/**\n * Resolves an installed Vercel marketplace integration by slug to its\n * configuration ID (`icfg_…`).\n *\n * The integration must be installed on the team via the Vercel dashboard\n * (one-time OAuth step) before this resource can be used. This resource is\n * read-only: it looks up the configuration ID and exposes it for downstream\n * marketplace-store resources.\n *\n * @example\n * ```typescript\n * const upstash = new VercelIntegration(\"upstash\", {\n * slug: \"upstash\",\n * }, { provider });\n *\n * // Use configurationId in marketplace store resources\n * export const upstashConfigId = upstash.configurationId;\n * ```\n */\nexport class VercelIntegration extends pulumi.ComponentResource {\n\t/** Vercel integration configuration ID (e.g. `\"icfg_…\"`). */\n\tpublic readonly configurationId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: VercelIntegrationArgs,\n\t\topts: VercelIntegrationOptions,\n\t) {\n\t\tconst { provider, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:vercel:Integration\", name, {}, pulumiOpts);\n\n\t\tconst resource = new VercelIntegrationResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tteamId: provider.teamId,\n\t\t\t\tslug: args.slug,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.configurationId = resource.configurationId;\n\n\t\tthis.registerOutputs({ configurationId: this.configurationId });\n\t}\n}\n"],"mappings":";;;;;;AAGA,MAAM,iBAAiB;;;;;;;AA+BvB,IAAa,oCAAb,MAEA;CACC,MAAM,OACL,QACuC;EACvC,MAAM,WAAW,MAAM,MACtB,GAAG,eAAe,yCAAyC,OAAO,UAClE,EAAE,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ,EAAE,CACxD;EAEA,IAAI,CAAC,SAAS,IACb,MAAM,IAAI,MACT,2CAA2C,SAAS,OAAO,KAAK,MAAM,SAAS,KAAK,GACrF;EAKD,MAAM,UAAS,MAFK,SAAS,KAAK,GAEd,eAAe,MAAM,MAAM,EAAE,SAAS,OAAO,IAAI;EAErE,IAAI,CAAC,QACJ,MAAM,IAAI,MACT,uBAAuB,OAAO,KAAK,gCACpC;EAGD,MAAM,OAAiC;GACtC,GAAG;GACH,iBAAiB,OAAO;EACzB;EAEA,OAAO;GAAE,IAAI,OAAO;GAAI;EAAK;CAC9B;CAEA,MAAM,KACL,IACA,OACqC;EAIrC,OAAO;GAAE;GAAI;EAAM;CACpB;CAEA,MAAM,SAAwB;EAC7B,eAAO,IAAI,KACV,2GACD;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,WAAW,KAAK,QACxB,SAAS,KAAK,QAAQ;EAGvB,IAAI,KAAK,SAAS,KAAK,MACtB,SAAS,KAAK,MAAM;EAGrB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,4BAAN,cAAwCA,eAAO,QAAQ,SAAS;CAG/D,YACC,MACA,MAKA,MACC;EACD,MACC,IAAI,kCAAkC,GACtC,MACA;GAAE,GAAG;GAAM,iBAAiB;EAAU,GACtC,IACD;CACD;AACD;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,oBAAb,cAAuCA,eAAO,kBAAkB;CAI/D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,GAAG,eAAe;EAEpC,MAAM,iCAAiC,MAAM,CAAC,GAAG,UAAU;EAE3D,MAAM,WAAW,IAAI,0BACpB,GAAG,KAAK,YACR;GACC,OAAO,SAAS;GAChB,QAAQ,SAAS;GACjB,MAAM,KAAK;EACZ,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,kBAAkB,SAAS;EAEhC,KAAK,gBAAgB,EAAE,iBAAiB,KAAK,gBAAgB,CAAC;CAC/D;AACD"}
1
+ {"version":3,"file":"integration.cjs","names":["pulumi"],"sources":["../../src/vercel/integration.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport type { VercelProvider } from \"./provider\";\n\nconst VERCEL_API_URL = \"https://api.vercel.com\";\n\n/** Resolved inputs for the Vercel integration dynamic provider. */\ninterface VercelIntegrationInputs {\n\t/** Vercel API bearer token. */\n\ttoken: string;\n\n\t/** Vercel team/org ID. */\n\tteamId: string;\n\n\t/** Marketplace integration slug (e.g. `\"upstash\"`, `\"neon\"`). */\n\tslug: string;\n}\n\n/** Persisted state for the Vercel integration. */\ninterface VercelIntegrationOutputs extends VercelIntegrationInputs {\n\t/** Vercel-assigned configuration ID (e.g. `\"icfg_…\"`). */\n\tconfigurationId: string;\n}\n\n/** A single installed Vercel marketplace integration configuration. */\ninterface VercelIntegrationConfiguration {\n\tid: string;\n\tslug: string;\n}\n\n/**\n * Dynamic provider that resolves an installed Vercel marketplace integration\n * by its slug to its configuration ID (`icfg_…`).\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class VercelIntegrationResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: VercelIntegrationInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\t// `view=account` is required by the configurations endpoint (a missing view returns 400).\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v1/integrations/configurations?view=account&teamId=${inputs.teamId}`,\n\t\t\t{ headers: { Authorization: `Bearer ${inputs.token}` } },\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error fetching integrations (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\t// The endpoint returns a top-level array; some responses wrap it in { configurations: [...] }.\n\t\tconst data = (await response.json()) as\n\t\t\t| VercelIntegrationConfiguration[]\n\t\t\t| { configurations: VercelIntegrationConfiguration[] };\n\n\t\tconst configurations = Array.isArray(data) ? data : data.configurations;\n\n\t\tconst config = configurations.find((c) => c.slug === inputs.slug);\n\n\t\tif (!config) {\n\t\t\tconst available =\n\t\t\t\tconfigurations.map((c) => c.slug).join(\", \") || \"(none)\";\n\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel integration \"${inputs.slug}\" is not installed on this team (available: ${available})`,\n\t\t\t);\n\t\t}\n\n\t\tconst outs: VercelIntegrationOutputs = {\n\t\t\t...inputs,\n\t\t\tconfigurationId: config.id,\n\t\t};\n\n\t\treturn { id: config.id, outs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: VercelIntegrationOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\t// Resolver-only: the integration's configuration id (icfg_…) is stable for the\n\t\t// lifetime of an installed integration, so read() does not re-query. If the\n\t\t// integration is uninstalled and reinstalled, a subsequent `up` re-resolves via create().\n\t\treturn { id, props };\n\t}\n\n\tasync delete(): Promise<void> {\n\t\tpulumi.log.warn(\n\t\t\t\"VercelIntegration is a read-only resolver — uninstall the integration from the Vercel dashboard if needed\",\n\t\t);\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: VercelIntegrationOutputs,\n\t\tnews: VercelIntegrationInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.teamId !== news.teamId) {\n\t\t\treplaces.push(\"teamId\");\n\t\t}\n\n\t\tif (olds.slug !== news.slug) {\n\t\t\treplaces.push(\"slug\");\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 VercelIntegrationResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly configurationId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tteamId: pulumi.Input<string>;\n\t\t\tslug: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew VercelIntegrationResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, configurationId: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n\n/** Options type for VercelIntegration — replaces Pulumi's native `provider` field. */\ntype VercelIntegrationOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Vercel authentication context. */\n\tprovider: VercelProvider;\n};\n\n/**\n * Args for {@link VercelIntegration}.\n */\nexport interface VercelIntegrationArgs {\n\t/**\n\t * Marketplace integration slug (e.g. `\"upstash\"`, `\"neon\"`).\n\t * The integration must already be installed on the team via the Vercel dashboard.\n\t */\n\tslug: pulumi.Input<string>;\n}\n\n/**\n * Resolves an installed Vercel marketplace integration by slug to its\n * configuration ID (`icfg_…`).\n *\n * The integration must be installed on the team via the Vercel dashboard\n * (one-time OAuth step) before this resource can be used. This resource is\n * read-only: it looks up the configuration ID and exposes it for downstream\n * marketplace-store resources.\n *\n * @example\n * ```typescript\n * const upstash = new VercelIntegration(\"upstash\", {\n * slug: \"upstash\",\n * }, { provider });\n *\n * // Use configurationId in marketplace store resources\n * export const upstashConfigId = upstash.configurationId;\n * ```\n */\nexport class VercelIntegration extends pulumi.ComponentResource {\n\t/** Vercel integration configuration ID (e.g. `\"icfg_…\"`). */\n\tpublic readonly configurationId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: VercelIntegrationArgs,\n\t\topts: VercelIntegrationOptions,\n\t) {\n\t\tconst { provider, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:vercel:Integration\", name, {}, pulumiOpts);\n\n\t\tconst resource = new VercelIntegrationResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tteamId: provider.teamId,\n\t\t\t\tslug: args.slug,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.configurationId = resource.configurationId;\n\n\t\tthis.registerOutputs({ configurationId: this.configurationId });\n\t}\n}\n"],"mappings":";;;;;;AAGA,MAAM,iBAAiB;;;;;;;AAgCvB,IAAa,oCAAb,MAEA;CACC,MAAM,OACL,QACuC;EAEvC,MAAM,WAAW,MAAM,MACtB,GAAG,eAAe,sDAAsD,OAAO,UAC/E,EAAE,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ,EAAE,CACxD;EAEA,IAAI,CAAC,SAAS,IACb,MAAM,IAAI,MACT,2CAA2C,SAAS,OAAO,KAAK,MAAM,SAAS,KAAK,GACrF;EAID,MAAM,OAAQ,MAAM,SAAS,KAAK;EAIlC,MAAM,iBAAiB,MAAM,QAAQ,IAAI,IAAI,OAAO,KAAK;EAEzD,MAAM,SAAS,eAAe,MAAM,MAAM,EAAE,SAAS,OAAO,IAAI;EAEhE,IAAI,CAAC,QAAQ;GACZ,MAAM,YACL,eAAe,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK;GAEjD,MAAM,IAAI,MACT,uBAAuB,OAAO,KAAK,8CAA8C,UAAU,EAC5F;EACD;EAEA,MAAM,OAAiC;GACtC,GAAG;GACH,iBAAiB,OAAO;EACzB;EAEA,OAAO;GAAE,IAAI,OAAO;GAAI;EAAK;CAC9B;CAEA,MAAM,KACL,IACA,OACqC;EAIrC,OAAO;GAAE;GAAI;EAAM;CACpB;CAEA,MAAM,SAAwB;EAC7B,eAAO,IAAI,KACV,2GACD;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,WAAW,KAAK,QACxB,SAAS,KAAK,QAAQ;EAGvB,IAAI,KAAK,SAAS,KAAK,MACtB,SAAS,KAAK,MAAM;EAGrB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,4BAAN,cAAwCA,eAAO,QAAQ,SAAS;CAG/D,YACC,MACA,MAKA,MACC;EACD,MACC,IAAI,kCAAkC,GACtC,MACA;GAAE,GAAG;GAAM,iBAAiB;EAAU,GACtC,IACD;CACD;AACD;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,oBAAb,cAAuCA,eAAO,kBAAkB;CAI/D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,GAAG,eAAe;EAEpC,MAAM,iCAAiC,MAAM,CAAC,GAAG,UAAU;EAE3D,MAAM,WAAW,IAAI,0BACpB,GAAG,KAAK,YACR;GACC,OAAO,SAAS;GAChB,QAAQ,SAAS;GACjB,MAAM,KAAK;EACZ,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,kBAAkB,SAAS;EAEhC,KAAK,gBAAgB,EAAE,iBAAiB,KAAK,gBAAgB,CAAC;CAC/D;AACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.cts","names":[],"sources":["../../src/vercel/integration.ts"],"mappings":";;;;;;UAMU,uBAAA;;EAET,KAAA;EAFgC;EAKhC,MAAA;EALgC;EAQhC,IAAA;AAAA;;UAIS,wBAAA,SAAiC,uBAAuB;EAJ7D;EAMJ,eAAe;AAAA;;;AAAA;AAchB;;;cAAa,iCAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,uBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EA8BpB,IAAA,CACL,EAAA,UACA,KAAA,EAAO,wBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAOpB,MAAA,CAAA,GAAU,OAAA;EAMV,IAAA,CACL,GAAA,UACA,IAAA,EAAM,wBAAA,EACN,IAAA,EAAM,uBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KA0CtB,wBAAA,GAA2B,IAAA,CAC/B,MAAA,CAAO,wBAAA;EA5CA,qCAgDP,QAAA,EAAU,cAAA;AAAA;;;;UAMM,qBAAA;EA3GE;;;;EAgHlB,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;;;;;;;;;cAsBN,iBAAA,SAA0B,MAAA,CAAO,iBAAA;EAhFlC;EAAA,SAkFK,eAAA,EAAiB,MAAA,CAAO,MAAA;cAGvC,IAAA,UACA,IAAA,EAAM,qBAAA,EACN,IAAA,EAAM,wBAAA;AAAA"}
1
+ {"version":3,"file":"integration.d.cts","names":[],"sources":["../../src/vercel/integration.ts"],"mappings":";;;;;;UAMU,uBAAA;;EAET,KAAA;EAFgC;EAKhC,MAAA;EALgC;EAQhC,IAAA;AAAA;;UAIS,wBAAA,SAAiC,uBAAuB;EAJ7D;EAMJ,eAAe;AAAA;;;AAAA;AAehB;;;cAAa,iCAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,uBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAuCpB,IAAA,CACL,EAAA,UACA,KAAA,EAAO,wBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAOpB,MAAA,CAAA,GAAU,OAAA;EAMV,IAAA,CACL,GAAA,UACA,IAAA,EAAM,wBAAA,EACN,IAAA,EAAM,uBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KA0CtB,wBAAA,GAA2B,IAAA,CAC/B,MAAA,CAAO,wBAAA;EA5CA,qCAgDP,QAAA,EAAU,cAAA;AAAA;;;;UAMM,qBAAA;EApHE;;;;EAyHlB,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;;;;;;;;;cAsBN,iBAAA,SAA0B,MAAA,CAAO,iBAAA;EAhFlC;EAAA,SAkFK,eAAA,EAAiB,MAAA,CAAO,MAAA;cAGvC,IAAA,UACA,IAAA,EAAM,qBAAA,EACN,IAAA,EAAM,wBAAA;AAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"integration.d.mts","names":[],"sources":["../../src/vercel/integration.ts"],"mappings":";;;;;;UAMU,uBAAA;;EAET,KAAA;EAFgC;EAKhC,MAAA;EALgC;EAQhC,IAAA;AAAA;;UAIS,wBAAA,SAAiC,uBAAuB;EAJ7D;EAMJ,eAAe;AAAA;;;AAAA;AAchB;;;cAAa,iCAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,uBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EA8BpB,IAAA,CACL,EAAA,UACA,KAAA,EAAO,wBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAOpB,MAAA,CAAA,GAAU,OAAA;EAMV,IAAA,CACL,GAAA,UACA,IAAA,EAAM,wBAAA,EACN,IAAA,EAAM,uBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KA0CtB,wBAAA,GAA2B,IAAA,CAC/B,MAAA,CAAO,wBAAA;EA5CA,qCAgDP,QAAA,EAAU,cAAA;AAAA;;;;UAMM,qBAAA;EA3GE;;;;EAgHlB,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;;;;;;;;;cAsBN,iBAAA,SAA0B,MAAA,CAAO,iBAAA;EAhFlC;EAAA,SAkFK,eAAA,EAAiB,MAAA,CAAO,MAAA;cAGvC,IAAA,UACA,IAAA,EAAM,qBAAA,EACN,IAAA,EAAM,wBAAA;AAAA"}
1
+ {"version":3,"file":"integration.d.mts","names":[],"sources":["../../src/vercel/integration.ts"],"mappings":";;;;;;UAMU,uBAAA;;EAET,KAAA;EAFgC;EAKhC,MAAA;EALgC;EAQhC,IAAA;AAAA;;UAIS,wBAAA,SAAiC,uBAAuB;EAJ7D;EAMJ,eAAe;AAAA;;;AAAA;AAehB;;;cAAa,iCAAA,YACD,MAAA,CAAO,OAAA,CAAQ,gBAAA;EAEpB,MAAA,CACL,MAAA,EAAQ,uBAAA,GACN,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,YAAA;EAuCpB,IAAA,CACL,EAAA,UACA,KAAA,EAAO,wBAAA,GACL,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;EAOpB,MAAA,CAAA,GAAU,OAAA;EAMV,IAAA,CACL,GAAA,UACA,IAAA,EAAM,wBAAA,EACN,IAAA,EAAM,uBAAA,GACJ,OAAA,CAAQ,MAAA,CAAO,OAAA,CAAQ,UAAA;AAAA;;KA0CtB,wBAAA,GAA2B,IAAA,CAC/B,MAAA,CAAO,wBAAA;EA5CA,qCAgDP,QAAA,EAAU,cAAA;AAAA;;;;UAMM,qBAAA;EApHE;;;;EAyHlB,IAAA,EAAM,MAAA,CAAO,KAAK;AAAA;;;;;;;;;;;;;;;;;;;;cAsBN,iBAAA,SAA0B,MAAA,CAAO,iBAAA;EAhFlC;EAAA,SAkFK,eAAA,EAAiB,MAAA,CAAO,MAAA;cAGvC,IAAA,UACA,IAAA,EAAM,qBAAA,EACN,IAAA,EAAM,wBAAA;AAAA"}
@@ -11,10 +11,15 @@ const VERCEL_API_URL = "https://api.vercel.com";
11
11
  */
12
12
  var VercelIntegrationResourceProvider = class {
13
13
  async create(inputs) {
14
- const response = await fetch(`${VERCEL_API_URL}/v1/integrations/configurations?teamId=${inputs.teamId}`, { headers: { Authorization: `Bearer ${inputs.token}` } });
14
+ const response = await fetch(`${VERCEL_API_URL}/v1/integrations/configurations?view=account&teamId=${inputs.teamId}`, { headers: { Authorization: `Bearer ${inputs.token}` } });
15
15
  if (!response.ok) throw new Error(`Vercel API error fetching integrations (${response.status}): ${await response.text()}`);
16
- const config = (await response.json()).configurations.find((c) => c.slug === inputs.slug);
17
- if (!config) throw new Error(`Vercel integration "${inputs.slug}" is not installed on this team`);
16
+ const data = await response.json();
17
+ const configurations = Array.isArray(data) ? data : data.configurations;
18
+ const config = configurations.find((c) => c.slug === inputs.slug);
19
+ if (!config) {
20
+ const available = configurations.map((c) => c.slug).join(", ") || "(none)";
21
+ throw new Error(`Vercel integration "${inputs.slug}" is not installed on this team (available: ${available})`);
22
+ }
18
23
  const outs = {
19
24
  ...inputs,
20
25
  configurationId: config.id
@@ -1 +1 @@
1
- {"version":3,"file":"integration.mjs","names":[],"sources":["../../src/vercel/integration.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport type { VercelProvider } from \"./provider\";\n\nconst VERCEL_API_URL = \"https://api.vercel.com\";\n\n/** Resolved inputs for the Vercel integration dynamic provider. */\ninterface VercelIntegrationInputs {\n\t/** Vercel API bearer token. */\n\ttoken: string;\n\n\t/** Vercel team/org ID. */\n\tteamId: string;\n\n\t/** Marketplace integration slug (e.g. `\"upstash\"`, `\"neon\"`). */\n\tslug: string;\n}\n\n/** Persisted state for the Vercel integration. */\ninterface VercelIntegrationOutputs extends VercelIntegrationInputs {\n\t/** Vercel-assigned configuration ID (e.g. `\"icfg_…\"`). */\n\tconfigurationId: string;\n}\n\n/** Vercel API response shape for the integration configurations list. */\ninterface VercelIntegrationsResponse {\n\tconfigurations: Array<{ id: string; slug: string }>;\n}\n\n/**\n * Dynamic provider that resolves an installed Vercel marketplace integration\n * by its slug to its configuration ID (`icfg_…`).\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class VercelIntegrationResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: VercelIntegrationInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v1/integrations/configurations?teamId=${inputs.teamId}`,\n\t\t\t{ headers: { Authorization: `Bearer ${inputs.token}` } },\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error fetching integrations (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\tconst data = (await response.json()) as VercelIntegrationsResponse;\n\n\t\tconst config = data.configurations.find((c) => c.slug === inputs.slug);\n\n\t\tif (!config) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel integration \"${inputs.slug}\" is not installed on this team`,\n\t\t\t);\n\t\t}\n\n\t\tconst outs: VercelIntegrationOutputs = {\n\t\t\t...inputs,\n\t\t\tconfigurationId: config.id,\n\t\t};\n\n\t\treturn { id: config.id, outs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: VercelIntegrationOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\t// Resolver-only: the integration's configuration id (icfg_…) is stable for the\n\t\t// lifetime of an installed integration, so read() does not re-query. If the\n\t\t// integration is uninstalled and reinstalled, a subsequent `up` re-resolves via create().\n\t\treturn { id, props };\n\t}\n\n\tasync delete(): Promise<void> {\n\t\tpulumi.log.warn(\n\t\t\t\"VercelIntegration is a read-only resolver — uninstall the integration from the Vercel dashboard if needed\",\n\t\t);\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: VercelIntegrationOutputs,\n\t\tnews: VercelIntegrationInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.teamId !== news.teamId) {\n\t\t\treplaces.push(\"teamId\");\n\t\t}\n\n\t\tif (olds.slug !== news.slug) {\n\t\t\treplaces.push(\"slug\");\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 VercelIntegrationResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly configurationId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tteamId: pulumi.Input<string>;\n\t\t\tslug: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew VercelIntegrationResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, configurationId: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n\n/** Options type for VercelIntegration — replaces Pulumi's native `provider` field. */\ntype VercelIntegrationOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Vercel authentication context. */\n\tprovider: VercelProvider;\n};\n\n/**\n * Args for {@link VercelIntegration}.\n */\nexport interface VercelIntegrationArgs {\n\t/**\n\t * Marketplace integration slug (e.g. `\"upstash\"`, `\"neon\"`).\n\t * The integration must already be installed on the team via the Vercel dashboard.\n\t */\n\tslug: pulumi.Input<string>;\n}\n\n/**\n * Resolves an installed Vercel marketplace integration by slug to its\n * configuration ID (`icfg_…`).\n *\n * The integration must be installed on the team via the Vercel dashboard\n * (one-time OAuth step) before this resource can be used. This resource is\n * read-only: it looks up the configuration ID and exposes it for downstream\n * marketplace-store resources.\n *\n * @example\n * ```typescript\n * const upstash = new VercelIntegration(\"upstash\", {\n * slug: \"upstash\",\n * }, { provider });\n *\n * // Use configurationId in marketplace store resources\n * export const upstashConfigId = upstash.configurationId;\n * ```\n */\nexport class VercelIntegration extends pulumi.ComponentResource {\n\t/** Vercel integration configuration ID (e.g. `\"icfg_…\"`). */\n\tpublic readonly configurationId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: VercelIntegrationArgs,\n\t\topts: VercelIntegrationOptions,\n\t) {\n\t\tconst { provider, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:vercel:Integration\", name, {}, pulumiOpts);\n\n\t\tconst resource = new VercelIntegrationResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tteamId: provider.teamId,\n\t\t\t\tslug: args.slug,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.configurationId = resource.configurationId;\n\n\t\tthis.registerOutputs({ configurationId: this.configurationId });\n\t}\n}\n"],"mappings":";;;;AAGA,MAAM,iBAAiB;;;;;;;AA+BvB,IAAa,oCAAb,MAEA;CACC,MAAM,OACL,QACuC;EACvC,MAAM,WAAW,MAAM,MACtB,GAAG,eAAe,yCAAyC,OAAO,UAClE,EAAE,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ,EAAE,CACxD;EAEA,IAAI,CAAC,SAAS,IACb,MAAM,IAAI,MACT,2CAA2C,SAAS,OAAO,KAAK,MAAM,SAAS,KAAK,GACrF;EAKD,MAAM,UAAS,MAFK,SAAS,KAAK,GAEd,eAAe,MAAM,MAAM,EAAE,SAAS,OAAO,IAAI;EAErE,IAAI,CAAC,QACJ,MAAM,IAAI,MACT,uBAAuB,OAAO,KAAK,gCACpC;EAGD,MAAM,OAAiC;GACtC,GAAG;GACH,iBAAiB,OAAO;EACzB;EAEA,OAAO;GAAE,IAAI,OAAO;GAAI;EAAK;CAC9B;CAEA,MAAM,KACL,IACA,OACqC;EAIrC,OAAO;GAAE;GAAI;EAAM;CACpB;CAEA,MAAM,SAAwB;EAC7B,OAAO,IAAI,KACV,2GACD;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,WAAW,KAAK,QACxB,SAAS,KAAK,QAAQ;EAGvB,IAAI,KAAK,SAAS,KAAK,MACtB,SAAS,KAAK,MAAM;EAGrB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,4BAAN,cAAwC,OAAO,QAAQ,SAAS;CAG/D,YACC,MACA,MAKA,MACC;EACD,MACC,IAAI,kCAAkC,GACtC,MACA;GAAE,GAAG;GAAM,iBAAiB;EAAU,GACtC,IACD;CACD;AACD;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,oBAAb,cAAuC,OAAO,kBAAkB;CAI/D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,GAAG,eAAe;EAEpC,MAAM,iCAAiC,MAAM,CAAC,GAAG,UAAU;EAE3D,MAAM,WAAW,IAAI,0BACpB,GAAG,KAAK,YACR;GACC,OAAO,SAAS;GAChB,QAAQ,SAAS;GACjB,MAAM,KAAK;EACZ,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,kBAAkB,SAAS;EAEhC,KAAK,gBAAgB,EAAE,iBAAiB,KAAK,gBAAgB,CAAC;CAC/D;AACD"}
1
+ {"version":3,"file":"integration.mjs","names":[],"sources":["../../src/vercel/integration.ts"],"sourcesContent":["import * as pulumi from \"@pulumi/pulumi\";\nimport type { VercelProvider } from \"./provider\";\n\nconst VERCEL_API_URL = \"https://api.vercel.com\";\n\n/** Resolved inputs for the Vercel integration dynamic provider. */\ninterface VercelIntegrationInputs {\n\t/** Vercel API bearer token. */\n\ttoken: string;\n\n\t/** Vercel team/org ID. */\n\tteamId: string;\n\n\t/** Marketplace integration slug (e.g. `\"upstash\"`, `\"neon\"`). */\n\tslug: string;\n}\n\n/** Persisted state for the Vercel integration. */\ninterface VercelIntegrationOutputs extends VercelIntegrationInputs {\n\t/** Vercel-assigned configuration ID (e.g. `\"icfg_…\"`). */\n\tconfigurationId: string;\n}\n\n/** A single installed Vercel marketplace integration configuration. */\ninterface VercelIntegrationConfiguration {\n\tid: string;\n\tslug: string;\n}\n\n/**\n * Dynamic provider that resolves an installed Vercel marketplace integration\n * by its slug to its configuration ID (`icfg_…`).\n *\n * @internal Exported only for unit testing; not part of the public API surface.\n */\nexport class VercelIntegrationResourceProvider\n\timplements pulumi.dynamic.ResourceProvider\n{\n\tasync create(\n\t\tinputs: VercelIntegrationInputs,\n\t): Promise<pulumi.dynamic.CreateResult> {\n\t\t// `view=account` is required by the configurations endpoint (a missing view returns 400).\n\t\tconst response = await fetch(\n\t\t\t`${VERCEL_API_URL}/v1/integrations/configurations?view=account&teamId=${inputs.teamId}`,\n\t\t\t{ headers: { Authorization: `Bearer ${inputs.token}` } },\n\t\t);\n\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel API error fetching integrations (${response.status}): ${await response.text()}`,\n\t\t\t);\n\t\t}\n\n\t\t// The endpoint returns a top-level array; some responses wrap it in { configurations: [...] }.\n\t\tconst data = (await response.json()) as\n\t\t\t| VercelIntegrationConfiguration[]\n\t\t\t| { configurations: VercelIntegrationConfiguration[] };\n\n\t\tconst configurations = Array.isArray(data) ? data : data.configurations;\n\n\t\tconst config = configurations.find((c) => c.slug === inputs.slug);\n\n\t\tif (!config) {\n\t\t\tconst available =\n\t\t\t\tconfigurations.map((c) => c.slug).join(\", \") || \"(none)\";\n\n\t\t\tthrow new Error(\n\t\t\t\t`Vercel integration \"${inputs.slug}\" is not installed on this team (available: ${available})`,\n\t\t\t);\n\t\t}\n\n\t\tconst outs: VercelIntegrationOutputs = {\n\t\t\t...inputs,\n\t\t\tconfigurationId: config.id,\n\t\t};\n\n\t\treturn { id: config.id, outs };\n\t}\n\n\tasync read(\n\t\tid: string,\n\t\tprops: VercelIntegrationOutputs,\n\t): Promise<pulumi.dynamic.ReadResult> {\n\t\t// Resolver-only: the integration's configuration id (icfg_…) is stable for the\n\t\t// lifetime of an installed integration, so read() does not re-query. If the\n\t\t// integration is uninstalled and reinstalled, a subsequent `up` re-resolves via create().\n\t\treturn { id, props };\n\t}\n\n\tasync delete(): Promise<void> {\n\t\tpulumi.log.warn(\n\t\t\t\"VercelIntegration is a read-only resolver — uninstall the integration from the Vercel dashboard if needed\",\n\t\t);\n\t}\n\n\tasync diff(\n\t\t_id: string,\n\t\tolds: VercelIntegrationOutputs,\n\t\tnews: VercelIntegrationInputs,\n\t): Promise<pulumi.dynamic.DiffResult> {\n\t\tconst replaces: string[] = [];\n\n\t\tif (olds.teamId !== news.teamId) {\n\t\t\treplaces.push(\"teamId\");\n\t\t}\n\n\t\tif (olds.slug !== news.slug) {\n\t\t\treplaces.push(\"slug\");\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 VercelIntegrationResource extends pulumi.dynamic.Resource {\n\tpublic declare readonly configurationId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: {\n\t\t\ttoken: pulumi.Input<string>;\n\t\t\tteamId: pulumi.Input<string>;\n\t\t\tslug: pulumi.Input<string>;\n\t\t},\n\t\topts?: pulumi.CustomResourceOptions,\n\t) {\n\t\tsuper(\n\t\t\tnew VercelIntegrationResourceProvider(),\n\t\t\tname,\n\t\t\t{ ...args, configurationId: undefined },\n\t\t\topts,\n\t\t);\n\t}\n}\n\n/** Options type for VercelIntegration — replaces Pulumi's native `provider` field. */\ntype VercelIntegrationOptions = Omit<\n\tpulumi.ComponentResourceOptions,\n\t\"provider\"\n> & {\n\t/** Vercel authentication context. */\n\tprovider: VercelProvider;\n};\n\n/**\n * Args for {@link VercelIntegration}.\n */\nexport interface VercelIntegrationArgs {\n\t/**\n\t * Marketplace integration slug (e.g. `\"upstash\"`, `\"neon\"`).\n\t * The integration must already be installed on the team via the Vercel dashboard.\n\t */\n\tslug: pulumi.Input<string>;\n}\n\n/**\n * Resolves an installed Vercel marketplace integration by slug to its\n * configuration ID (`icfg_…`).\n *\n * The integration must be installed on the team via the Vercel dashboard\n * (one-time OAuth step) before this resource can be used. This resource is\n * read-only: it looks up the configuration ID and exposes it for downstream\n * marketplace-store resources.\n *\n * @example\n * ```typescript\n * const upstash = new VercelIntegration(\"upstash\", {\n * slug: \"upstash\",\n * }, { provider });\n *\n * // Use configurationId in marketplace store resources\n * export const upstashConfigId = upstash.configurationId;\n * ```\n */\nexport class VercelIntegration extends pulumi.ComponentResource {\n\t/** Vercel integration configuration ID (e.g. `\"icfg_…\"`). */\n\tpublic readonly configurationId: pulumi.Output<string>;\n\n\tconstructor(\n\t\tname: string,\n\t\targs: VercelIntegrationArgs,\n\t\topts: VercelIntegrationOptions,\n\t) {\n\t\tconst { provider, ...pulumiOpts } = opts;\n\n\t\tsuper(\"infracraft:vercel:Integration\", name, {}, pulumiOpts);\n\n\t\tconst resource = new VercelIntegrationResource(\n\t\t\t`${name}-resource`,\n\t\t\t{\n\t\t\t\ttoken: provider.token,\n\t\t\t\tteamId: provider.teamId,\n\t\t\t\tslug: args.slug,\n\t\t\t},\n\t\t\t{ parent: this },\n\t\t);\n\n\t\tthis.configurationId = resource.configurationId;\n\n\t\tthis.registerOutputs({ configurationId: this.configurationId });\n\t}\n}\n"],"mappings":";;;;AAGA,MAAM,iBAAiB;;;;;;;AAgCvB,IAAa,oCAAb,MAEA;CACC,MAAM,OACL,QACuC;EAEvC,MAAM,WAAW,MAAM,MACtB,GAAG,eAAe,sDAAsD,OAAO,UAC/E,EAAE,SAAS,EAAE,eAAe,UAAU,OAAO,QAAQ,EAAE,CACxD;EAEA,IAAI,CAAC,SAAS,IACb,MAAM,IAAI,MACT,2CAA2C,SAAS,OAAO,KAAK,MAAM,SAAS,KAAK,GACrF;EAID,MAAM,OAAQ,MAAM,SAAS,KAAK;EAIlC,MAAM,iBAAiB,MAAM,QAAQ,IAAI,IAAI,OAAO,KAAK;EAEzD,MAAM,SAAS,eAAe,MAAM,MAAM,EAAE,SAAS,OAAO,IAAI;EAEhE,IAAI,CAAC,QAAQ;GACZ,MAAM,YACL,eAAe,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK;GAEjD,MAAM,IAAI,MACT,uBAAuB,OAAO,KAAK,8CAA8C,UAAU,EAC5F;EACD;EAEA,MAAM,OAAiC;GACtC,GAAG;GACH,iBAAiB,OAAO;EACzB;EAEA,OAAO;GAAE,IAAI,OAAO;GAAI;EAAK;CAC9B;CAEA,MAAM,KACL,IACA,OACqC;EAIrC,OAAO;GAAE;GAAI;EAAM;CACpB;CAEA,MAAM,SAAwB;EAC7B,OAAO,IAAI,KACV,2GACD;CACD;CAEA,MAAM,KACL,KACA,MACA,MACqC;EACrC,MAAM,WAAqB,CAAC;EAE5B,IAAI,KAAK,WAAW,KAAK,QACxB,SAAS,KAAK,QAAQ;EAGvB,IAAI,KAAK,SAAS,KAAK,MACtB,SAAS,KAAK,MAAM;EAGrB,OAAO;GACN,SAAS,SAAS,SAAS;GAC3B;GACA,qBAAqB;EACtB;CACD;AACD;;AAGA,IAAM,4BAAN,cAAwC,OAAO,QAAQ,SAAS;CAG/D,YACC,MACA,MAKA,MACC;EACD,MACC,IAAI,kCAAkC,GACtC,MACA;GAAE,GAAG;GAAM,iBAAiB;EAAU,GACtC,IACD;CACD;AACD;;;;;;;;;;;;;;;;;;;;AAyCA,IAAa,oBAAb,cAAuC,OAAO,kBAAkB;CAI/D,YACC,MACA,MACA,MACC;EACD,MAAM,EAAE,UAAU,GAAG,eAAe;EAEpC,MAAM,iCAAiC,MAAM,CAAC,GAAG,UAAU;EAE3D,MAAM,WAAW,IAAI,0BACpB,GAAG,KAAK,YACR;GACC,OAAO,SAAS;GAChB,QAAQ,SAAS;GACjB,MAAM,KAAK;EACZ,GACA,EAAE,QAAQ,KAAK,CAChB;EAEA,KAAK,kBAAkB,SAAS;EAEhC,KAAK,gBAAgB,EAAE,iBAAiB,KAAK,gBAAgB,CAAC;CAC/D;AACD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infracraft/pulumi",
3
- "version": "1.6.1",
3
+ "version": "1.6.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {