11import * as pulumi from '@pulumi/pulumi'
2+ import * as fs from 'fs/promises'
3+ import * as path from 'path'
4+ import execa = require( 'execa' )
25import {
36 assertGraphiQL ,
47 assertQuery ,
58 env ,
6- execPromise ,
79 fsPromises ,
810 waitForEndpoint ,
911} from '../utils'
1012import { DeploymentConfiguration } from '../types'
1113
12- type VercelProviderInputs = {
13- name : string
14- files : {
15- file : string
16- data : string
17- } [ ]
18- projectSettings : { }
19- version : 2
20- }
21-
22- type VercelDeploymentInputs = {
23- [ K in keyof VercelProviderInputs ] : pulumi . Input < VercelProviderInputs [ K ] >
24- }
14+ type VercelDeploymentInputs = { }
2515
2616class VercelProvider implements pulumi . dynamic . ResourceProvider {
2717 private baseUrl = 'https://api.vercel.com'
2818 private authToken = env ( 'VERCEL_AUTH_TOKEN' )
19+ private directory = path . resolve ( __dirname , '..' , 'examples' , 'nextjs-edge' )
2920
3021 private getTeamId ( ) : string | null {
3122 try {
@@ -58,25 +49,25 @@ class VercelProvider implements pulumi.dynamic.ResourceProvider {
5849 }
5950 }
6051
61- async create (
62- inputs : VercelProviderInputs ,
63- ) : Promise < pulumi . dynamic . CreateResult > {
52+ async create ( ) : Promise < pulumi . dynamic . CreateResult > {
53+ // Create project
6454 const teamId = this . getTeamId ( )
65- const response = await fetch (
66- `${ this . baseUrl } /v13/deployments${ teamId ? `?teamId=${ teamId } ` : '' } ` ,
67- {
68- method : 'POST' ,
69- headers : {
70- 'content-type' : 'application/json' ,
71- Authorization : `Bearer ${ this . authToken } ` ,
72- } ,
73- body : JSON . stringify ( {
74- name : inputs . name ,
75- files : inputs . files ,
76- projectSettings : inputs . projectSettings ,
77- } ) ,
55+
56+ const url = new URL ( `${ this . baseUrl } /v9/projects` )
57+ url . searchParams . set ( 'teamId' , teamId )
58+
59+ const response = await fetch ( url . toString ( ) , {
60+ method : 'POST' ,
61+ headers : {
62+ Authorization : `Bearer ${ this . authToken } ` ,
7863 } ,
79- )
64+ body : JSON . stringify ( {
65+ name : new Date ( ) . toISOString ( ) ,
66+ framework : 'nextjs' ,
67+ } ) ,
68+ } )
69+
70+ await pulumi . log . info ( `Create deployment (status=${ response . status } )` )
8071
8172 if ( response . status !== 200 ) {
8273 throw new Error (
@@ -86,12 +77,63 @@ class VercelProvider implements pulumi.dynamic.ResourceProvider {
8677 )
8778 }
8879
89- const responseJson = await response . json ( )
80+ const responseJson : {
81+ id : string
82+ // url: string
83+ } = await response . json ( )
84+
85+ // Deploy project
86+ await fs . rmdir ( path . join ( this . directory , '.vercel' ) , {
87+ recursive : true ,
88+ // @ts -expect-error
89+ force : true ,
90+ } )
91+
92+ await fs . mkdir ( path . join ( this . directory , '.vercel' ) )
93+
94+ await fs . writeFile (
95+ path . join ( this . directory , '.vercel' , 'project.json' ) ,
96+ JSON . stringify ( {
97+ projectId : responseJson . id ,
98+ // TODO: figure out how we can `orgId` without inlining it.
99+ orgId : 'team_pW5VoIWWt8KcRXmQoKn2dxpa' ,
100+ settings : {
101+ createdAt : 1677572115659 ,
102+ framework : 'nextjs' ,
103+ devCommand : null ,
104+ installCommand : null ,
105+ buildCommand : null ,
106+ outputDirectory : null ,
107+ rootDirectory : null ,
108+ directoryListing : false ,
109+ nodeVersion : '18.x' ,
110+ } ,
111+ } ) ,
112+ )
113+
114+ await execa ( 'pnpm' , [ 'run' , 'end2end:build' ] , {
115+ cwd : this . directory ,
116+ } )
117+
118+ const deployment = await execa ( 'pnpm' , [ 'run' , 'end2end:deploy' ] , {
119+ cwd : this . directory ,
120+ } )
121+
122+ const regex = / \n ✅ P r o d u c t i o n : ( h t t p s : \/ \/ .* .v e r c e l .a p p ) \[ /
123+
124+ const result = deployment . all ?. match ( regex )
125+
126+ if ( ! Array . isArray ( result ) ) {
127+ pulumi . log . info ( "Couldn't find deployment URL in output." )
128+ throw new Error ( "Couldn't find deployment URL in output." )
129+ }
130+
131+ const deploymentUrl = result [ 1 ]
90132
91133 return {
92134 id : responseJson . id ,
93135 outs : {
94- url : responseJson . url ,
136+ url : deploymentUrl ,
95137 } ,
96138 }
97139 }
@@ -120,53 +162,8 @@ export class VercelDeployment extends pulumi.dynamic.Resource {
120162export const vercelEdgeDeployment : DeploymentConfiguration < {
121163 functionUrl : string
122164} > = {
123- prerequisites : async ( ) => {
124- // Build and bundle the function
125- console . info ( '\t\tℹ️ Bundling the Vercel Function....' )
126- await execPromise ( 'pnpm bundle' , {
127- cwd : '../examples/nextjs-edge' ,
128- } )
129- } ,
130165 program : async ( ) => {
131- const nextJSVersion = JSON . parse (
132- (
133- await fsPromises . readFile ( '../examples/nextjs-edge/package.json' )
134- ) . toString ( 'utf-8' ) ,
135- ) [ 'dependencies' ] [ 'next' ]
136-
137- if ( nextJSVersion == null || Number . isNaN ( parseInt ( nextJSVersion [ 0 ] , 10 ) ) ) {
138- throw new Error ( `Failed to parse Next.js version from package.json.` )
139- }
140-
141- const deployment = new VercelDeployment ( 'vercel-edge' , {
142- version : 2 ,
143- files : [
144- {
145- file : '.vercel/output/functions/api/graphql.func/index.js' ,
146- data : await fsPromises . readFile (
147- '../examples/nextjs-edge/dist/index.js' ,
148- 'utf-8' ,
149- ) ,
150- } ,
151- {
152- file : '.vercel/output/functions/api/graphql.func/.vc-config.json' ,
153- data : JSON . stringify ( {
154- runtime : 'edge' ,
155- name : 'api/graphql' ,
156- deploymentTarget : 'v8-worker' ,
157- entrypoint : 'index.js' ,
158- envVarsInUse : [ ] ,
159- assets : [ ] ,
160- framework : {
161- slug : 'nextjs' ,
162- version : nextJSVersion ,
163- } ,
164- } ) ,
165- } ,
166- ] ,
167- name : `yoga-e2e-testing` ,
168- projectSettings : { } ,
169- } )
166+ const deployment = new VercelDeployment ( 'vercel-edge' , { } )
170167
171168 return {
172169 functionUrl : pulumi . interpolate `https://${ deployment . url } /api/graphql` ,
0 commit comments