firebase-tools 11.15.0 → 11.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/lib/commands/database-push.js +5 -0
  2. package/lib/commands/database-remove.js +2 -1
  3. package/lib/commands/database-set.js +5 -0
  4. package/lib/commands/database-update.js +5 -0
  5. package/lib/database/remove.js +2 -2
  6. package/lib/database/removeRemote.js +7 -2
  7. package/lib/deploy/functions/build.js +3 -0
  8. package/lib/deploy/functions/prepare.js +21 -8
  9. package/lib/deploy/functions/release/fabricator.js +2 -2
  10. package/lib/deploy/functions/release/sourceTokenScraper.js +34 -7
  11. package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +2 -1
  12. package/lib/deploy/hosting/convertConfig.js +21 -7
  13. package/lib/deploy/hosting/prepare.js +16 -5
  14. package/lib/deploy/hosting/release.js +2 -2
  15. package/lib/dynamicImport.js +7 -10
  16. package/lib/emulator/auth/server.js +2 -3
  17. package/lib/emulator/download.js +2 -1
  18. package/lib/emulator/downloadableEmulators.js +65 -50
  19. package/lib/emulator/extensionsEmulator.js +1 -1
  20. package/lib/emulator/functionsEmulator.js +2 -1
  21. package/lib/emulator/functionsEmulatorShared.js +12 -1
  22. package/lib/emulator/functionsRuntimeWorker.js +9 -2
  23. package/lib/emulator/storage/apis/firebase.js +7 -27
  24. package/lib/emulator/storage/apis/gcloud.js +9 -33
  25. package/lib/emulator/storage/apis/shared.js +43 -0
  26. package/lib/emulator/storage/rules/config.js +9 -0
  27. package/lib/emulator/storage/upload.js +2 -2
  28. package/lib/experiments.js +1 -3
  29. package/lib/extensions/provisioningHelper.js +10 -4
  30. package/lib/frameworks/index.js +9 -4
  31. package/lib/frameworks/next/index.js +57 -17
  32. package/lib/serve/hosting.js +4 -4
  33. package/npm-shrinkwrap.json +600 -50
  34. package/package.json +2 -2
  35. package/templates/emulators/default_storage.rules +8 -0
  36. package/templates/init/functions/golang/functions.go +1 -1
  37. package/templates/init/functions/javascript/index.js +2 -2
  38. package/templates/init/functions/typescript/index.ts +1 -1
@@ -44,7 +44,7 @@ class ExtensionsEmulator {
44
44
  if (!functionsEmulator) {
45
45
  throw new error_1.FirebaseError("Extensions Emulator is running but Functions emulator is not. This should never happen.");
46
46
  }
47
- return functionsEmulator.getInfo();
47
+ return Object.assign(Object.assign({}, functionsEmulator.getInfo()), { name: this.getName() });
48
48
  }
49
49
  getName() {
50
50
  return types_1.Emulators.EXTENSIONS;
@@ -137,10 +137,11 @@ class FunctionsEmulator {
137
137
  method: req.method,
138
138
  path: `/functions/projects/${projectId}/triggers/${triggerId}`,
139
139
  headers: req.headers,
140
- }, resolve);
140
+ });
141
141
  trigReq.on("error", reject);
142
142
  trigReq.write(rawBody);
143
143
  trigReq.end();
144
+ resolve();
144
145
  });
145
146
  });
146
147
  });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toBackendInfo = exports.getSecretLocalPath = exports.getSignatureType = exports.formatHost = exports.findModuleRoot = exports.waitForBody = exports.getServiceFromEventType = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.emulatedFunctionsFromEndpoints = exports.prepareEndpoints = exports.eventServiceImplemented = exports.EmulatedTrigger = exports.HttpConstants = void 0;
3
+ exports.toBackendInfo = exports.getSecretLocalPath = exports.getSignatureType = exports.formatHost = exports.findModuleRoot = exports.waitForBody = exports.getServiceFromEventType = exports.getFunctionService = exports.getTemporarySocketPath = exports.getEmulatedTriggersFromDefinitions = exports.emulatedFunctionsByRegion = exports.emulatedFunctionsFromEndpoints = exports.prepareEndpoints = exports.eventServiceImplemented = exports.EmulatedTrigger = exports.HttpConstants = exports.EVENTARC_SOURCE_ENV = void 0;
4
4
  const os = require("os");
5
5
  const path = require("path");
6
6
  const fs = require("fs");
@@ -20,6 +20,7 @@ const V2_EVENTS = [
20
20
  ...events.v2.STORAGE_EVENTS,
21
21
  ...events.v2.DATABASE_EVENTS,
22
22
  ];
23
+ exports.EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE";
23
24
  class HttpConstants {
24
25
  }
25
26
  exports.HttpConstants = HttpConstants;
@@ -73,6 +74,16 @@ function emulatedFunctionsFromEndpoints(endpoints) {
73
74
  };
74
75
  def.availableMemoryMb = endpoint.availableMemoryMb || 256;
75
76
  def.labels = endpoint.labels || {};
77
+ if (endpoint.platform === "gcfv1") {
78
+ def.labels[exports.EVENTARC_SOURCE_ENV] =
79
+ "cloudfunctions-emulated.googleapis.com" +
80
+ `/projects/${endpoint.project || "project"}/locations/${endpoint.region}/functions/${endpoint.id}`;
81
+ }
82
+ else if (endpoint.platform === "gcfv2") {
83
+ def.labels[exports.EVENTARC_SOURCE_ENV] =
84
+ "run-emulated.googleapis.com" +
85
+ `/projects/${endpoint.project || "project"}/locations/${endpoint.region}/services/${endpoint.id}`;
86
+ }
76
87
  def.timeoutSeconds = endpoint.timeoutSeconds || 60;
77
88
  def.secretEnvironmentVariables = endpoint.secretEnvironmentVariables || [];
78
89
  def.platform = endpoint.platform;
@@ -9,6 +9,7 @@ const emulatorLogger_1 = require("./emulatorLogger");
9
9
  const error_1 = require("../error");
10
10
  var RuntimeWorkerState;
11
11
  (function (RuntimeWorkerState) {
12
+ RuntimeWorkerState["CREATED"] = "CREATED";
12
13
  RuntimeWorkerState["IDLE"] = "IDLE";
13
14
  RuntimeWorkerState["BUSY"] = "BUSY";
14
15
  RuntimeWorkerState["FINISHING"] = "FINISHING";
@@ -18,7 +19,7 @@ class RuntimeWorker {
18
19
  constructor(key, runtime) {
19
20
  this.stateEvents = new events_1.EventEmitter();
20
21
  this.logListeners = [];
21
- this._state = RuntimeWorkerState.IDLE;
22
+ this._state = RuntimeWorkerState.CREATED;
22
23
  this.id = uuid.v4();
23
24
  this.key = key;
24
25
  this.runtime = runtime;
@@ -58,6 +59,9 @@ class RuntimeWorker {
58
59
  }
59
60
  return lines[lines.length - 1];
60
61
  }
62
+ readyForWork() {
63
+ this.state = RuntimeWorkerState.IDLE;
64
+ }
61
65
  sendDebugMsg(debug) {
62
66
  return new Promise((resolve, reject) => {
63
67
  this.runtime.process.send(JSON.stringify(debug), (err) => {
@@ -138,7 +142,10 @@ class RuntimeWorker {
138
142
  method: "GET",
139
143
  path: "/__/health",
140
144
  socketPath: this.runtime.socketPath,
141
- }, () => resolve())
145
+ }, () => {
146
+ this.readyForWork();
147
+ resolve();
148
+ })
142
149
  .end();
143
150
  req.on("error", (error) => {
144
151
  reject(error);
@@ -4,9 +4,9 @@ exports.createFirebaseEndpoints = void 0;
4
4
  const emulatorLogger_1 = require("../../emulatorLogger");
5
5
  const types_1 = require("../../types");
6
6
  const uuid = require("uuid");
7
- const zlib_1 = require("zlib");
8
7
  const metadata_1 = require("../metadata");
9
8
  const express_1 = require("express");
9
+ const shared_1 = require("./shared");
10
10
  const registry_1 = require("../../registry");
11
11
  const multipart_1 = require("../multipart");
12
12
  const errors_1 = require("../errors");
@@ -17,7 +17,7 @@ function createFirebaseEndpoints(emulator) {
17
17
  const { storageLayer, uploadService } = emulator;
18
18
  if (process.env.STORAGE_EMULATOR_DEBUG) {
19
19
  firebaseStorageAPI.use((req, res, next) => {
20
- console.log("--------------INCOMING REQUEST--------------");
20
+ console.log("--------------INCOMING FIREBASE REQUEST--------------");
21
21
  console.log(`${req.method.toUpperCase()} ${req.path}`);
22
22
  console.log("-- query:");
23
23
  console.log(JSON.stringify(req.query, undefined, 2));
@@ -98,24 +98,7 @@ function createFirebaseEndpoints(emulator) {
98
98
  metadata.addDownloadToken(true);
99
99
  }
100
100
  if (req.query.alt === "media") {
101
- const isGZipped = metadata.contentEncoding === "gzip";
102
- if (isGZipped) {
103
- data = (0, zlib_1.gunzipSync)(data);
104
- }
105
- res.setHeader("Accept-Ranges", "bytes");
106
- res.setHeader("Content-Type", metadata.contentType || "application/octet-stream");
107
- res.setHeader("Content-Disposition", metadata.contentDisposition || "inline");
108
- setObjectHeaders(res, metadata, { "Content-Encoding": isGZipped ? "identity" : undefined });
109
- const byteRange = req.range(data.byteLength, { combine: true });
110
- if (Array.isArray(byteRange) && byteRange.type === "bytes" && byteRange.length > 0) {
111
- const range = byteRange[0];
112
- res.setHeader("Content-Range", `${byteRange.type} ${range.start}-${range.end}/${data.byteLength}`);
113
- res.status(206).end(data.slice(range.start, range.end + 1));
114
- }
115
- else {
116
- res.end(data);
117
- }
118
- return;
101
+ return (0, shared_1.sendFileBytes)(metadata, data, req, res);
119
102
  }
120
103
  return res.json(new metadata_1.OutgoingFirebaseMetadata(metadata));
121
104
  });
@@ -215,7 +198,7 @@ function createFirebaseEndpoints(emulator) {
215
198
  const upload = uploadService.startResumableUpload({
216
199
  bucketId,
217
200
  objectId,
218
- metadataRaw: JSON.stringify(req.body),
201
+ metadata: req.body,
219
202
  authorization: req.header("authorization"),
220
203
  });
221
204
  res.header("x-goog-upload-chunk-granularity", "10000");
@@ -330,7 +313,7 @@ function createFirebaseEndpoints(emulator) {
330
313
  const upload = uploadService.multipartUpload({
331
314
  bucketId,
332
315
  objectId,
333
- metadataRaw,
316
+ metadata: JSON.parse(metadataRaw),
334
317
  dataRaw: dataRaw,
335
318
  authorization: req.header("authorization"),
336
319
  });
@@ -480,14 +463,11 @@ function createFirebaseEndpoints(emulator) {
480
463
  return firebaseStorageAPI;
481
464
  }
482
465
  exports.createFirebaseEndpoints = createFirebaseEndpoints;
483
- function setObjectHeaders(res, metadata, headerOverride = { "Content-Encoding": undefined }) {
466
+ function setObjectHeaders(res, metadata) {
484
467
  if (metadata.contentDisposition) {
485
468
  res.setHeader("Content-Disposition", metadata.contentDisposition);
486
469
  }
487
- if (headerOverride["Content-Encoding"]) {
488
- res.setHeader("Content-Encoding", headerOverride["Content-Encoding"]);
489
- }
490
- else if (metadata.contentEncoding) {
470
+ if (metadata.contentEncoding) {
491
471
  res.setHeader("Content-Encoding", metadata.contentEncoding);
492
472
  }
493
473
  if (metadata.cacheControl) {
@@ -2,12 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createCloudEndpoints = void 0;
4
4
  const express_1 = require("express");
5
- const zlib_1 = require("zlib");
6
5
  const types_1 = require("../../types");
7
6
  const metadata_1 = require("../metadata");
7
+ const shared_1 = require("./shared");
8
8
  const registry_1 = require("../../registry");
9
9
  const emulatorLogger_1 = require("../../emulatorLogger");
10
- const crc_1 = require("../crc");
11
10
  const multipart_1 = require("../multipart");
12
11
  const upload_1 = require("../upload");
13
12
  const errors_1 = require("../errors");
@@ -17,7 +16,7 @@ function createCloudEndpoints(emulator) {
17
16
  const { adminStorageLayer, uploadService } = emulator;
18
17
  if (process.env.STORAGE_EMULATOR_DEBUG) {
19
18
  gcloudStorageAPI.use((req, res, next) => {
20
- console.log("--------------INCOMING REQUEST--------------");
19
+ console.log("--------------INCOMING GCS REQUEST--------------");
21
20
  console.log(`${req.method.toUpperCase()} ${req.path}`);
22
21
  console.log("-- query:");
23
22
  console.log(JSON.stringify(req.query, undefined, 2));
@@ -86,7 +85,7 @@ function createCloudEndpoints(emulator) {
86
85
  throw err;
87
86
  }
88
87
  if (req.query.alt === "media") {
89
- return sendFileBytes(getObjectResponse.metadata, getObjectResponse.data, req, res);
88
+ return (0, shared_1.sendFileBytes)(getObjectResponse.metadata, getObjectResponse.data, req, res);
90
89
  }
91
90
  return res.json(new metadata_1.CloudStorageObjectMetadata(getObjectResponse.metadata));
92
91
  });
@@ -110,7 +109,7 @@ function createCloudEndpoints(emulator) {
110
109
  }
111
110
  return res.json(new metadata_1.CloudStorageObjectMetadata(updatedMetadata));
112
111
  });
113
- gcloudStorageAPI.get("/b/:bucketId/o", async (req, res) => {
112
+ gcloudStorageAPI.get(["/b/:bucketId/o", "/storage/v1/b/:bucketId/o"], async (req, res) => {
114
113
  var _a;
115
114
  let listResponse;
116
115
  try {
@@ -228,10 +227,11 @@ function createCloudEndpoints(emulator) {
228
227
  res.sendStatus(400);
229
228
  return;
230
229
  }
230
+ const contentType = req.header("x-upload-content-type");
231
231
  const upload = uploadService.startResumableUpload({
232
232
  bucketId: req.params.bucketId,
233
233
  objectId: name,
234
- metadataRaw: JSON.stringify(req.body),
234
+ metadata: Object.assign({ contentType }, req.body),
235
235
  authorization: req.header("authorization"),
236
236
  });
237
237
  const uploadUrl = registry_1.EmulatorRegistry.url(types_1.Emulators.STORAGE, req);
@@ -256,6 +256,7 @@ function createCloudEndpoints(emulator) {
256
256
  }
257
257
  if (uploadType === "multipart") {
258
258
  const contentTypeHeader = req.header("content-type") || req.header("x-upload-content-type");
259
+ const contentType = req.header("x-upload-content-type");
259
260
  if (!contentTypeHeader) {
260
261
  return res.sendStatus(400);
261
262
  }
@@ -283,7 +284,7 @@ function createCloudEndpoints(emulator) {
283
284
  const upload = uploadService.multipartUpload({
284
285
  bucketId: req.params.bucketId,
285
286
  objectId: name,
286
- metadataRaw: metadataRaw,
287
+ metadata: Object.assign({ contentType }, JSON.parse(metadataRaw)),
287
288
  dataRaw: dataRaw,
288
289
  authorization: req.header("authorization"),
289
290
  });
@@ -318,7 +319,7 @@ function createCloudEndpoints(emulator) {
318
319
  }
319
320
  throw err;
320
321
  }
321
- return sendFileBytes(getObjectResponse.metadata, getObjectResponse.data, req, res);
322
+ return (0, shared_1.sendFileBytes)(getObjectResponse.metadata, getObjectResponse.data, req, res);
322
323
  });
323
324
  gcloudStorageAPI.post("/b/:bucketId/o/:objectId/:method(rewriteTo|copyTo)/b/:destBucketId/o/:destObjectId", (req, res, next) => {
324
325
  if (req.params.method === "rewriteTo" && req.query.rewriteToken) {
@@ -375,31 +376,6 @@ function createCloudEndpoints(emulator) {
375
376
  return gcloudStorageAPI;
376
377
  }
377
378
  exports.createCloudEndpoints = createCloudEndpoints;
378
- function sendFileBytes(md, data, req, res) {
379
- const isGZipped = md.contentEncoding === "gzip";
380
- if (isGZipped) {
381
- data = (0, zlib_1.gunzipSync)(data);
382
- }
383
- res.setHeader("Accept-Ranges", "bytes");
384
- res.setHeader("Content-Type", md.contentType || "application/octet-stream");
385
- res.setHeader("Content-Disposition", md.contentDisposition || "attachment");
386
- res.setHeader("Content-Encoding", isGZipped ? "identity" : md.contentEncoding || "");
387
- res.setHeader("ETag", md.etag);
388
- res.setHeader("Cache-Control", md.cacheControl || "");
389
- res.setHeader("x-goog-generation", `${md.generation}`);
390
- res.setHeader("x-goog-metadatageneration", `${md.metageneration}`);
391
- res.setHeader("x-goog-storage-class", md.storageClass);
392
- res.setHeader("x-goog-hash", `crc32c=${(0, crc_1.crc32cToString)(md.crc32c)},md5=${md.md5Hash}`);
393
- const byteRange = req.range(data.byteLength, { combine: true });
394
- if (Array.isArray(byteRange) && byteRange.type === "bytes" && byteRange.length > 0) {
395
- const range = byteRange[0];
396
- res.setHeader("Content-Range", `${byteRange.type} ${range.start}-${range.end}/${data.byteLength}`);
397
- res.status(206).end(data.slice(range.start, range.end + 1));
398
- }
399
- else {
400
- res.end(data);
401
- }
402
- }
403
379
  function sendObjectNotFound(req, res) {
404
380
  res.status(404);
405
381
  const message = `No such object: ${req.params.bucketId}/${req.params.objectId}`;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendFileBytes = void 0;
4
+ const zlib_1 = require("zlib");
5
+ const crc_1 = require("../crc");
6
+ function sendFileBytes(md, data, req, res) {
7
+ let didGunzip = false;
8
+ if (md.contentEncoding === "gzip") {
9
+ const acceptEncoding = req.header("accept-encoding") || "";
10
+ const shouldGunzip = !acceptEncoding.includes("gzip");
11
+ if (shouldGunzip) {
12
+ data = (0, zlib_1.gunzipSync)(data);
13
+ didGunzip = true;
14
+ }
15
+ }
16
+ res.setHeader("Accept-Ranges", "bytes");
17
+ res.setHeader("Content-Type", md.contentType || "application/octet-stream");
18
+ res.setHeader("Content-Disposition", md.contentDisposition || "attachment");
19
+ if (didGunzip) {
20
+ res.setHeader("Transfer-Encoding", "chunked");
21
+ }
22
+ else {
23
+ res.setHeader("Content-Encoding", md.contentEncoding || "");
24
+ }
25
+ res.setHeader("ETag", md.etag);
26
+ res.setHeader("Cache-Control", md.cacheControl || "");
27
+ res.setHeader("x-goog-generation", `${md.generation}`);
28
+ res.setHeader("x-goog-metadatageneration", `${md.metageneration}`);
29
+ res.setHeader("x-goog-storage-class", md.storageClass);
30
+ res.setHeader("x-goog-hash", `crc32c=${(0, crc_1.crc32cToString)(md.crc32c)},md5=${md.md5Hash}`);
31
+ const shouldRespectContentRange = !didGunzip;
32
+ if (shouldRespectContentRange) {
33
+ const byteRange = req.range(data.byteLength, { combine: true });
34
+ if (Array.isArray(byteRange) && byteRange.type === "bytes" && byteRange.length > 0) {
35
+ const range = byteRange[0];
36
+ res.setHeader("Content-Range", `${byteRange.type} ${range.start}-${range.end}/${data.byteLength}`);
37
+ res.status(206).end(data.slice(range.start, range.end + 1));
38
+ return;
39
+ }
40
+ }
41
+ res.end(data);
42
+ }
43
+ exports.sendFileBytes = sendFileBytes;
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getStorageRulesConfig = void 0;
4
4
  const error_1 = require("../../../error");
5
5
  const fsutils_1 = require("../../../fsutils");
6
+ const constants_1 = require("../../constants");
7
+ const types_1 = require("../../types");
8
+ const emulatorLogger_1 = require("../../emulatorLogger");
6
9
  function getSourceFile(rules, options) {
7
10
  const path = options.config.path(rules);
8
11
  return { name: path, content: (0, fsutils_1.readFile)(path) };
@@ -10,6 +13,12 @@ function getSourceFile(rules, options) {
10
13
  function getStorageRulesConfig(projectId, options) {
11
14
  const storageConfig = options.config.data.storage;
12
15
  if (!storageConfig) {
16
+ if (constants_1.Constants.isDemoProject(projectId)) {
17
+ const storageLogger = emulatorLogger_1.EmulatorLogger.forEmulator(types_1.Emulators.STORAGE);
18
+ storageLogger.logLabeled("BULLET", "storage", `Detected demo project ID "${projectId}", using a default (open) rules configuration.`);
19
+ const path = __dirname + "/../../../../templates/emulators/default_storage.rules";
20
+ return { name: path, content: (0, fsutils_1.readFile)(path) };
21
+ }
13
22
  throw new error_1.FirebaseError("Cannot start the Storage emulator without rules file specified in firebase.json: run 'firebase init' and set up your Storage configuration");
14
23
  }
15
24
  if (!Array.isArray(storageConfig)) {
@@ -50,7 +50,7 @@ class UploadService {
50
50
  objectId: request.objectId,
51
51
  uploadType: UploadType.MULTIPART,
52
52
  dataRaw: request.dataRaw,
53
- metadata: JSON.parse(request.metadataRaw),
53
+ metadata: request.metadata,
54
54
  authorization: request.authorization,
55
55
  });
56
56
  this._persistence.deleteFile(upload.path, true);
@@ -82,7 +82,7 @@ class UploadService {
82
82
  type: UploadType.RESUMABLE,
83
83
  path: this.getStagingFileName(id, request.bucketId, request.objectId),
84
84
  status: UploadStatus.ACTIVE,
85
- metadata: JSON.parse(request.metadataRaw),
85
+ metadata: request.metadata,
86
86
  size: 0,
87
87
  authorization: request.authorization,
88
88
  };
@@ -46,9 +46,7 @@ exports.ALL_EXPERIMENTS = experiments({
46
46
  },
47
47
  functionsparams: {
48
48
  shortDescription: "Adds support for paramaterizing functions deployments",
49
- },
50
- skipdeployingnoopfunctions: {
51
- shortDescription: "Detect that there have been no changes to a function and skip deployment",
49
+ default: true,
52
50
  },
53
51
  emulatoruisnapshot: {
54
52
  shortDescription: "Load pre-release versions of the emulator UI",
@@ -7,6 +7,7 @@ const apiv2_1 = require("../apiv2");
7
7
  const functional_1 = require("../functional");
8
8
  const error_1 = require("../error");
9
9
  const planner_1 = require("../deploy/extensions/planner");
10
+ const logger_1 = require("../logger");
10
11
  var DeferredProduct;
11
12
  (function (DeferredProduct) {
12
13
  DeferredProduct[DeferredProduct["STORAGE"] = 0] = "STORAGE";
@@ -35,11 +36,16 @@ async function checkProducts(projectId, usedProducts) {
35
36
  if (usedProducts.includes(DeferredProduct.AUTH)) {
36
37
  isAuthProvisionedPromise = isAuthProvisioned(projectId);
37
38
  }
38
- if (isStorageProvisionedPromise && !(await isStorageProvisionedPromise)) {
39
- needProvisioning.push(DeferredProduct.STORAGE);
39
+ try {
40
+ if (isStorageProvisionedPromise && !(await isStorageProvisionedPromise)) {
41
+ needProvisioning.push(DeferredProduct.STORAGE);
42
+ }
43
+ if (isAuthProvisionedPromise && !(await isAuthProvisionedPromise)) {
44
+ needProvisioning.push(DeferredProduct.AUTH);
45
+ }
40
46
  }
41
- if (isAuthProvisionedPromise && !(await isAuthProvisionedPromise)) {
42
- needProvisioning.push(DeferredProduct.AUTH);
47
+ catch (err) {
48
+ logger_1.logger.debug(`Error while checking product provisioning, failing open: ${err}`);
43
49
  }
44
50
  if (needProvisioning.length > 0) {
45
51
  let errorMessage = "Some services used by this extension have not been set up on your " +
@@ -139,12 +139,14 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
139
139
  }
140
140
  const configs = (0, config_1.hostingConfig)(options);
141
141
  let firebaseDefaults = undefined;
142
- if (configs.length === 0)
142
+ if (configs.length === 0) {
143
143
  return;
144
+ }
144
145
  for (const config of configs) {
145
146
  const { source, site, public: publicDir } = config;
146
- if (!source)
147
+ if (!source) {
147
148
  continue;
149
+ }
148
150
  config.rewrites || (config.rewrites = []);
149
151
  config.redirects || (config.redirects = []);
150
152
  config.headers || (config.headers = []);
@@ -152,8 +154,9 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
152
154
  const dist = (0, path_1.join)(projectRoot, ".firebase", site);
153
155
  const hostingDist = (0, path_1.join)(dist, "hosting");
154
156
  const functionsDist = (0, path_1.join)(dist, "functions");
155
- if (publicDir)
157
+ if (publicDir) {
156
158
  throw new Error(`hosting.public and hosting.source cannot both be set in firebase.json`);
159
+ }
157
160
  const getProjectPath = (...args) => (0, path_1.join)(projectRoot, source, ...args);
158
161
  const functionName = `ssr${site.toLowerCase().replace(/-/g, "")}`;
159
162
  const usesFirebaseAdminSdk = !!findDependency("firebase-admin", { cwd: getProjectPath() });
@@ -232,8 +235,9 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
232
235
  if (devModeHandle) {
233
236
  config.public = (0, path_1.relative)(projectRoot, publicDirectory);
234
237
  options.frameworksDevModeHandle = devModeHandle;
235
- if (mayWantBackend && firebaseDefaults)
238
+ if (mayWantBackend && firebaseDefaults) {
236
239
  codegenFunctionsDirectory = codegenDevModeFunctionsDirectory;
240
+ }
237
241
  }
238
242
  else {
239
243
  const { wantsBackend = false, rewrites = [], redirects = [], headers = [], } = (await build(getProjectPath())) || {};
@@ -248,6 +252,7 @@ async function prepareFrameworks(targetNames, context, options, emulators = [])
248
252
  if (wantsBackend)
249
253
  codegenFunctionsDirectory = codegenProdModeFunctionsDirectory;
250
254
  }
255
+ config.webFramework = `${framework}${codegenFunctionsDirectory ? "_ssr" : ""}`;
251
256
  if (codegenFunctionsDirectory) {
252
257
  if (firebaseDefaults)
253
258
  firebaseDefaults._authTokenSyncURL = "/__session";
@@ -12,6 +12,7 @@ const prompt_1 = require("../../prompt");
12
12
  const semver_1 = require("semver");
13
13
  const logger_1 = require("../../logger");
14
14
  const error_1 = require("../../error");
15
+ const fsutils_1 = require("../../fsutils");
15
16
  const CLI_COMMAND = (0, path_1.join)("node_modules", ".bin", process.platform === "win32" ? "next.cmd" : "next");
16
17
  exports.name = "Next.js";
17
18
  exports.support = "experimental";
@@ -20,6 +21,10 @@ function getNextVersion(cwd) {
20
21
  var _a;
21
22
  return (_a = (0, __1.findDependency)("next", { cwd, depth: 0, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
22
23
  }
24
+ function getReactVersion(cwd) {
25
+ var _a;
26
+ return (_a = (0, __1.findDependency)("react-dom", { cwd, omitDev: false })) === null || _a === void 0 ? void 0 : _a.version;
27
+ }
23
28
  async function discover(dir) {
24
29
  if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
25
30
  return;
@@ -30,6 +35,10 @@ async function discover(dir) {
30
35
  exports.discover = discover;
31
36
  async function build(dir) {
32
37
  const { default: nextBuild } = (0, __1.relativeRequire)(dir, "next/dist/build");
38
+ const reactVersion = getReactVersion(dir);
39
+ if (reactVersion && (0, semver_1.gte)(reactVersion, "18.0.0")) {
40
+ process.env.__NEXT_REACT_ROOT = "true";
41
+ }
33
42
  await nextBuild(dir, null, false, false, true).catch((e) => {
34
43
  console.error(e.message);
35
44
  throw e;
@@ -46,12 +55,19 @@ async function build(dir) {
46
55
  const exportDetailBuffer = exportDetailExists ? await (0, promises_1.readFile)(exportDetailPath) : undefined;
47
56
  const exportDetailJson = exportDetailBuffer && JSON.parse(exportDetailBuffer.toString());
48
57
  if (exportDetailJson === null || exportDetailJson === void 0 ? void 0 : exportDetailJson.success) {
58
+ const appPathRoutesManifestPath = (0, path_1.join)(dir, distDir, "app-path-routes-manifest.json");
59
+ const appPathRoutesManifestJSON = (0, fsutils_1.fileExistsSync)(appPathRoutesManifestPath)
60
+ ? await (0, promises_1.readFile)(appPathRoutesManifestPath).then((it) => JSON.parse(it.toString()))
61
+ : {};
49
62
  const prerenderManifestJSON = await (0, promises_1.readFile)((0, path_1.join)(dir, distDir, "prerender-manifest.json")).then((it) => JSON.parse(it.toString()));
50
63
  const anyDynamicRouteFallbacks = !!Object.values(prerenderManifestJSON.dynamicRoutes || {}).find((it) => it.fallback !== false);
51
64
  const pagesManifestJSON = await (0, promises_1.readFile)((0, path_1.join)(dir, distDir, "server", "pages-manifest.json")).then((it) => JSON.parse(it.toString()));
52
65
  const prerenderedRoutes = Object.keys(prerenderManifestJSON.routes);
53
66
  const dynamicRoutes = Object.keys(prerenderManifestJSON.dynamicRoutes);
54
- const unrenderedPages = Object.keys(pagesManifestJSON).filter((it) => !(["/_app", "/_error", "/_document", "/404"].includes(it) ||
67
+ const unrenderedPages = [
68
+ ...Object.keys(pagesManifestJSON),
69
+ ...Object.values(appPathRoutesManifestJSON),
70
+ ].filter((it) => !(["/_app", "/", "/_error", "/_document", "/404"].includes(it) ||
55
71
  prerenderedRoutes.includes(it) ||
56
72
  dynamicRoutes.includes(it)));
57
73
  if (!anyDynamicRouteFallbacks && unrenderedPages.length === 0) {
@@ -85,7 +101,7 @@ async function init(setup) {
85
101
  message: "What language would you like to use?",
86
102
  choices: ["JavaScript", "TypeScript"],
87
103
  });
88
- (0, child_process_1.execSync)(`npx --yes create-next-app@latest -e hello-world ${setup.hosting.source} ${language === "TypeScript" ? "--ts" : ""}`, { stdio: "inherit" });
104
+ (0, child_process_1.execSync)(`npx --yes create-next-app@latest -e hello-world ${setup.hosting.source} --use-npm ${language === "TypeScript" ? "--ts" : ""}`, { stdio: "inherit" });
89
105
  }
90
106
  exports.init = init;
91
107
  async function ɵcodegenPublicDirectory(sourceDir, destDir) {
@@ -104,20 +120,26 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir) {
104
120
  await (0, fs_extra_1.copy)(publicPath, destDir);
105
121
  }
106
122
  await (0, fs_extra_1.copy)((0, path_1.join)(sourceDir, distDir, "static"), (0, path_1.join)(destDir, "_next", "static"));
107
- const serverPagesDir = (0, path_1.join)(sourceDir, distDir, "server", "pages");
108
- await (0, fs_extra_1.copy)(serverPagesDir, destDir, {
109
- filter: async (filename) => {
110
- const status = await (0, promises_1.stat)(filename);
111
- if (status.isDirectory())
112
- return true;
113
- return (0, path_1.extname)(filename) === ".html";
114
- },
115
- });
123
+ for (const file of ["index.html", "404.html", "500.html"]) {
124
+ const pagesPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", file);
125
+ if (await (0, fs_extra_1.pathExists)(pagesPath)) {
126
+ await (0, promises_1.copyFile)(pagesPath, (0, path_1.join)(destDir, file));
127
+ continue;
128
+ }
129
+ const appPath = (0, path_1.join)(sourceDir, distDir, "server", "app", file);
130
+ if (await (0, fs_extra_1.pathExists)(appPath)) {
131
+ await (0, promises_1.copyFile)(appPath, (0, path_1.join)(destDir, file));
132
+ }
133
+ }
116
134
  const prerenderManifestBuffer = await (0, promises_1.readFile)((0, path_1.join)(sourceDir, distDir, "prerender-manifest.json"));
117
135
  const prerenderManifest = JSON.parse(prerenderManifestBuffer.toString());
118
- for (const route in prerenderManifest.routes) {
119
- if (prerenderManifest.routes[route]) {
120
- const parts = route
136
+ for (const path in prerenderManifest.routes) {
137
+ if (prerenderManifest.routes[path]) {
138
+ const { initialRevalidateSeconds } = prerenderManifest.routes[path];
139
+ if (initialRevalidateSeconds) {
140
+ continue;
141
+ }
142
+ const parts = path
121
143
  .split("/")
122
144
  .slice(1)
123
145
  .filter((it) => !!it);
@@ -125,10 +147,28 @@ async function ɵcodegenPublicDirectory(sourceDir, destDir) {
125
147
  const dataPath = `${(0, path_1.join)(...partsOrIndex)}.json`;
126
148
  const htmlPath = `${(0, path_1.join)(...partsOrIndex)}.html`;
127
149
  await (0, promises_1.mkdir)((0, path_1.join)(destDir, (0, path_1.dirname)(htmlPath)), { recursive: true });
128
- await (0, promises_1.copyFile)((0, path_1.join)(sourceDir, distDir, "server", "pages", htmlPath), (0, path_1.join)(destDir, htmlPath));
129
- const dataRoute = prerenderManifest.routes[route].dataRoute;
150
+ const pagesHtmlPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", htmlPath);
151
+ if (await (0, fs_extra_1.pathExists)(pagesHtmlPath)) {
152
+ await (0, promises_1.copyFile)(pagesHtmlPath, (0, path_1.join)(destDir, htmlPath));
153
+ }
154
+ else {
155
+ const appHtmlPath = (0, path_1.join)(sourceDir, distDir, "server", "app", htmlPath);
156
+ if (await (0, fs_extra_1.pathExists)(appHtmlPath)) {
157
+ await (0, promises_1.copyFile)(appHtmlPath, (0, path_1.join)(destDir, htmlPath));
158
+ }
159
+ }
160
+ const dataRoute = prerenderManifest.routes[path].dataRoute;
130
161
  await (0, promises_1.mkdir)((0, path_1.join)(destDir, (0, path_1.dirname)(dataRoute)), { recursive: true });
131
- await (0, promises_1.copyFile)((0, path_1.join)(sourceDir, distDir, "server", "pages", dataPath), (0, path_1.join)(destDir, dataRoute));
162
+ const pagesDataPath = (0, path_1.join)(sourceDir, distDir, "server", "pages", dataPath);
163
+ if (await (0, fs_extra_1.pathExists)(pagesDataPath)) {
164
+ await (0, promises_1.copyFile)(pagesDataPath, (0, path_1.join)(destDir, dataRoute));
165
+ }
166
+ else {
167
+ const appDataPath = (0, path_1.join)(sourceDir, distDir, "server", "app", dataPath);
168
+ if (await (0, fs_extra_1.pathExists)(appDataPath)) {
169
+ await (0, promises_1.copyFile)(appDataPath, (0, path_1.join)(destDir, dataRoute));
170
+ }
171
+ }
132
172
  }
133
173
  }
134
174
  }
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.connect = exports.start = exports.stop = void 0;
4
4
  const morgan = require("morgan");
5
- const superstatic_1 = require("superstatic");
5
+ const { server: superstatic } = require("superstatic");
6
6
  const clc = require("colorette");
7
7
  const net_1 = require("net");
8
8
  const detectProjectRoot_1 = require("../detectProjectRoot");
@@ -36,13 +36,13 @@ function startServer(options, config, port, init) {
36
36
  const after = options.frameworksDevModeHandle && {
37
37
  files: options.frameworksDevModeHandle,
38
38
  };
39
- const server = (0, superstatic_1.server)({
39
+ const server = superstatic({
40
40
  debug: false,
41
41
  port: port,
42
- hostname: options.host,
42
+ host: options.host,
43
43
  config: config,
44
44
  compression: true,
45
- cwd: (0, detectProjectRoot_1.detectProjectRoot)(options) || undefined,
45
+ cwd: (0, detectProjectRoot_1.detectProjectRoot)(options),
46
46
  stack: "strict",
47
47
  before: {
48
48
  files: (req, res, next) => {