-
Notifications
You must be signed in to change notification settings - Fork 73
Expand file tree
/
Copy pathserver.ts
More file actions
132 lines (115 loc) · 4.16 KB
/
server.ts
File metadata and controls
132 lines (115 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createServer } from 'http';
import type { ListenOptions } from 'net';
import * as path from 'path';
import express from 'express';
import { fetchMaybeWithCredentials } from './src/components/common/rest_api';
/*
This file defines Node.js server-side logic for the Emulator UI.
During development, the express app is loaded into the Vite dev server
(configured via ./vite.config.ts) and exposes the /api/* endpoints below.
For production, this file serves as an entry point and runs additional logic
(see `import.meta.env.PROD` below) to start the server on a port which serves
static assets in addition to APIs.
This file may NOT import any front-end code or types from src/.
*/
const app = express();
const projectEnv = 'GCLOUD_PROJECT';
const hubEnv = 'FIREBASE_EMULATOR_HUB';
const projectId = process.env[projectEnv];
const hubHost = process.env[hubEnv];
if (!projectId || !hubHost) {
throw new Error(
`Please specify these environment variables: ${projectEnv} ${hubEnv}\n` +
'(Are you using firebase-tools@>=7.14.0 with `--project your-project`?)'
);
}
// Exposes the host and port of various emulators to facilitate accessing
// them using client SDKs. For features that involve multiple emulators or
// hard to accomplish using client SDKs, consider adding an API below.
app.get(
'/api/config',
jsonHandler(async () => {
const hubDiscoveryUrl = new URL(`http://${hubHost}/emulators`);
const emulatorsRes = await fetchMaybeWithCredentials(
hubDiscoveryUrl.toString()
);
const emulators = (await emulatorsRes.json()) as any;
const json = { projectId, experiments: [], ...emulators };
// Googlers: see go/firebase-emulator-ui-usage-collection-design?pli=1#heading=h.jwz7lj6r67z8
// for more detail
if (process.env.FIREBASE_GA_SESSION) {
json.analytics = JSON.parse(process.env.FIREBASE_GA_SESSION);
}
// pick up any experiments enabled with `firebase experiment:enable`
if (process.env.FIREBASE_ENABLED_EXPERIMENTS) {
json.experiments = JSON.parse(process.env.FIREBASE_ENABLED_EXPERIMENTS);
}
return json;
})
);
export const viteNodeApp = app;
if (import.meta.env.PROD) {
const webDir = path.join(path.dirname(process.argv[1]), '..', 'client');
app.use(express.static(webDir));
// Required for the router to work properly.
app.get('*', function (_, res) {
res.sendFile(path.join(webDir, 'index.html'));
});
let listen: ListenOptions[];
if (process.env.LISTEN) {
listen = JSON.parse(process.env.LISTEN);
} else {
// Mainly used when starting in dev mode (without CLI).
const host = process.env.HOST || '127.0.0.1';
const port = Number(process.env.PORT) || 5173;
listen = [{ host, port }];
}
for (const opts of listen) {
const server = createServer(app).listen(opts);
server.once('listening', () => {
console.log(`Web / API server started at ${opts.host}:${opts.port}`);
});
server.once('error', (err) => {
console.error(`Failed to start server at ${opts.host}:${opts.port}`);
console.error(err);
if (opts === listen[0]) {
// If we failed to listen on the primary address, surface the error.
process.exit(1);
}
});
}
}
function jsonHandler(
handler: (req: express.Request) => Promise<object>
): express.Handler {
return (req, res) => {
handler(req).then(
(body) => {
res.status(200).json(body);
},
(err) => {
console.error(err);
res.status(500).json({
message: err.message,
stack: err.stack,
raw: err,
});
}
);
};
}