@@ -8,7 +8,7 @@ import { join, resolve, relative } from 'pathe'
8
8
import { execa } from 'execa'
9
9
import { setupDotenv } from 'c12'
10
10
import { $api , fetchUser , selectTeam , selectProject , projectPath , fetchProject , linkProject , gitInfo } from '../utils/index.mjs'
11
- import { getStorage , getPathsToDeploy , getFile , uploadAssetsToCloudflare , isMetaPath , isServerPath , getPublicFiles } from '../utils/deploy.mjs'
11
+ import { getStorage , getPathsToDeploy , getFile , uploadAssetsToCloudflare , uploadWorkersAssetsToCloudflare , isMetaPath , isWorkerMetaPath , isServerPath , isWorkerServerPath , getPublicFiles , getWorkerPublicFiles } from '../utils/deploy.mjs'
12
12
import { createMigrationsTable , fetchRemoteMigrations , queryDatabase } from '../utils/database.mjs'
13
13
import login from './login.mjs'
14
14
import ensure from './ensure.mjs'
@@ -105,6 +105,16 @@ export default defineCommand({
105
105
consola . success ( `Connected to ${ colors . blueBright ( linkedProject . teamSlug ) } team.` )
106
106
consola . success ( `Linked to ${ colors . blueBright ( linkedProject . slug ) } project.` )
107
107
108
+ if ( linkedProject . type === 'worker' && deployEnv === 'preview' ) {
109
+ consola . warn ( 'Currently NuxtHub on Workers (BETA) does not support preview environments.' )
110
+ const shouldDeploy = await confirm ( {
111
+ message : `Deploy ${ colors . blueBright ( projectPath ( ) ) } to production instead?`
112
+ } )
113
+ if ( ! shouldDeploy || isCancel ( shouldDeploy ) ) {
114
+ return consola . log ( 'Cancelled.' )
115
+ }
116
+ }
117
+
108
118
// #region Build
109
119
if ( args . build ) {
110
120
consola . info ( 'Building the Nuxt project...' )
@@ -135,6 +145,11 @@ export default defineCommand({
135
145
const fileKeys = await storage . getKeys ( )
136
146
const pathsToDeploy = getPathsToDeploy ( fileKeys )
137
147
const config = await storage . getItem ( 'hub.config.json' )
148
+ if ( ! config . nitroPreset && linkedProject . type === 'worker' ) {
149
+ consola . error ( 'Please upgrade `@nuxthub/core` to the latest version to deploy to a worker project.' )
150
+ process . exit ( 1 )
151
+ }
152
+ const isWorkerPreset = [ 'cloudflare_module' , 'cloudflare_durable' , 'cloudflare-module' , 'cloudflare-durable' ] . includes ( config . nitroPreset )
138
153
const { format : formatNumber } = new Intl . NumberFormat ( 'en-US' )
139
154
140
155
let spinner = ora ( `Preparing ${ colors . blueBright ( linkedProject . slug ) } deployment for ${ deployEnvColored } ...` ) . start ( )
@@ -145,40 +160,64 @@ export default defineCommand({
145
160
spinnerColorIndex = ( spinnerColorIndex + 1 ) % spinnerColors . length
146
161
} , 2500 )
147
162
148
- let deploymentKey , serverFiles , metaFiles
163
+ let deploymentKey , serverFiles , metaFiles , completionToken
149
164
try {
150
- const publicFiles = await getPublicFiles ( storage , pathsToDeploy )
151
-
152
- const deploymentInfo = await $api ( `/teams/${ linkedProject . teamSlug } /projects/${ linkedProject . slug } /${ deployEnv } /deploy/prepare` , {
165
+ let url = `/teams/${ linkedProject . teamSlug } /projects/${ linkedProject . slug } /${ deployEnv } /deploy/prepare`
166
+ let publicFiles , publicManifest
167
+
168
+ if ( isWorkerPreset ) {
169
+ url = `/teams/${ linkedProject . teamSlug } /projects/${ linkedProject . slug } /${ deployEnv } /deploy/worker/prepare`
170
+ publicFiles = await getWorkerPublicFiles ( storage , pathsToDeploy )
171
+ /**
172
+ * { "/index.html": { hash: "hash", size: 30 }
173
+ */
174
+ publicManifest = publicFiles . reduce ( ( acc , file ) => {
175
+ acc [ file . path ] = {
176
+ hash : file . hash ,
177
+ size : file . size
178
+ }
179
+ return acc
180
+ } , { } )
181
+ } else {
182
+ publicFiles = await getPublicFiles ( storage , pathsToDeploy )
183
+ /**
184
+ * { "/index.html": "hash" }
185
+ */
186
+ publicManifest = publicFiles . reduce ( ( acc , file ) => {
187
+ acc [ file . path ] = file . hash
188
+ return acc
189
+ } , { } )
190
+ }
191
+ // Get deployment info by preparing the deployment
192
+ const deploymentInfo = await $api ( url , {
153
193
method : 'POST' ,
154
194
body : {
155
195
config,
156
- /**
157
- * Public manifest is a map of file paths to their unique hash (SHA256 sliced to 32 characters).
158
- * @example
159
- * {
160
- * "/index.html": "hash",
161
- * "/assets/image.png": "hash"
162
- * }
163
- */
164
- publicManifest : publicFiles . reduce ( ( acc , file ) => {
165
- acc [ file . path ] = file . hash
166
- return acc
167
- } , { } )
196
+ publicManifest
168
197
}
169
198
} )
170
199
spinner . succeed ( `${ colors . blueBright ( linkedProject . slug ) } ready to deploy.` )
171
- const { missingPublicHashes, cloudflareUploadJwt } = deploymentInfo
172
200
deploymentKey = deploymentInfo . deploymentKey
201
+
202
+ const { cloudflareUploadJwt, buckets, accountId } = deploymentInfo
203
+ // missingPublicHash is sent for pages & buckets for worker
204
+ let missingPublicHashes = deploymentInfo . missingPublicHashes || buckets . flat ( )
173
205
const publicFilesToUpload = publicFiles . filter ( file => missingPublicHashes . includes ( file . hash ) )
174
206
175
207
if ( publicFilesToUpload . length ) {
176
208
const totalSizeToUpload = publicFilesToUpload . reduce ( ( acc , file ) => acc + file . size , 0 )
177
209
spinner = ora ( `Uploading ${ colors . blueBright ( formatNumber ( publicFilesToUpload . length ) ) } new static assets (${ colors . blueBright ( prettyBytes ( totalSizeToUpload ) ) } )...` ) . start ( )
178
- await uploadAssetsToCloudflare ( publicFilesToUpload , cloudflareUploadJwt , ( { progressSize, totalSize } ) => {
179
- const percentage = Math . round ( ( progressSize / totalSize ) * 100 )
180
- spinner . text = `${ percentage } % uploaded (${ prettyBytes ( progressSize ) } /${ prettyBytes ( totalSize ) } )...`
181
- } )
210
+ if ( linkedProject . type === 'pages' ) {
211
+ await uploadAssetsToCloudflare ( publicFilesToUpload , cloudflareUploadJwt , ( { progressSize, totalSize } ) => {
212
+ const percentage = Math . round ( ( progressSize / totalSize ) * 100 )
213
+ spinner . text = `${ percentage } % uploaded (${ prettyBytes ( progressSize ) } /${ prettyBytes ( totalSize ) } )...`
214
+ } )
215
+ } else {
216
+ completionToken = await uploadWorkersAssetsToCloudflare ( accountId , publicFilesToUpload , cloudflareUploadJwt , ( { progressSize, totalSize } ) => {
217
+ const percentage = Math . round ( ( progressSize / totalSize ) * 100 )
218
+ spinner . text = `${ percentage } % uploaded (${ prettyBytes ( progressSize ) } /${ prettyBytes ( totalSize ) } )...`
219
+ } )
220
+ }
182
221
spinner . succeed ( `${ colors . blueBright ( formatNumber ( publicFilesToUpload . length ) ) } new static assets uploaded (${ colors . blueBright ( prettyBytes ( totalSizeToUpload ) ) } )` )
183
222
}
184
223
@@ -188,8 +227,14 @@ export default defineCommand({
188
227
consola . info ( `${ colors . blueBright ( formatNumber ( publicFiles . length ) ) } static assets (${ colors . blueBright ( prettyBytes ( totalSize ) ) } / ${ colors . blueBright ( prettyBytes ( totalGzipSize ) ) } gzip)` )
189
228
}
190
229
191
- metaFiles = await Promise . all ( pathsToDeploy . filter ( isMetaPath ) . map ( p => getFile ( storage , p , 'base64' ) ) )
192
- serverFiles = await Promise . all ( pathsToDeploy . filter ( isServerPath ) . map ( p => getFile ( storage , p , 'base64' ) ) )
230
+ metaFiles = await Promise . all ( pathsToDeploy . filter ( isWorkerPreset ? isWorkerMetaPath : isMetaPath ) . map ( p => getFile ( storage , p , 'base64' ) ) )
231
+ serverFiles = await Promise . all ( pathsToDeploy . filter ( isWorkerPreset ? isWorkerServerPath : isServerPath ) . map ( p => getFile ( storage , p , 'base64' ) ) )
232
+ if ( isWorkerPreset ) {
233
+ serverFiles = serverFiles . map ( file => ( {
234
+ ...file ,
235
+ path : file . path . replace ( '/server/' , '/' )
236
+ } ) )
237
+ }
193
238
const serverFilesSize = serverFiles . reduce ( ( acc , file ) => acc + file . size , 0 )
194
239
const serverFilesGzipSize = serverFiles . reduce ( ( acc , file ) => acc + file . gzipSize , 0 )
195
240
consola . info ( `${ colors . blueBright ( formatNumber ( serverFiles . length ) ) } server files (${ colors . blueBright ( prettyBytes ( serverFilesSize ) ) } / ${ colors . blueBright ( prettyBytes ( serverFilesGzipSize ) ) } gzip)...` )
@@ -284,13 +329,14 @@ export default defineCommand({
284
329
285
330
// #region Complete deployment
286
331
spinner = ora ( `Deploying ${ colors . blueBright ( linkedProject . slug ) } to ${ deployEnvColored } ...` ) . start ( )
287
- const deployment = await $api ( `/teams/${ linkedProject . teamSlug } /projects/${ linkedProject . slug } /${ deployEnv } /deploy/complete` , {
332
+ const deployment = await $api ( `/teams/${ linkedProject . teamSlug } /projects/${ linkedProject . slug } /${ deployEnv } /deploy/${ isWorkerPreset ? 'worker/ complete' : 'complete' } ` , {
288
333
method : 'POST' ,
289
334
body : {
290
335
deploymentKey,
291
336
git,
292
337
serverFiles,
293
- metaFiles
338
+ metaFiles,
339
+ completionToken
294
340
} ,
295
341
} ) . catch ( ( err ) => {
296
342
spinner . fail ( `Failed to deploy ${ colors . blueBright ( linkedProject . slug ) } to ${ deployEnvColored } .` )
0 commit comments