@superblocksteam/sdk 2.0.3-next.99 → 2.0.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.
- package/dist/application-build.d.mts +12 -0
- package/dist/application-build.d.mts.map +1 -0
- package/dist/application-build.mjs +113 -0
- package/dist/application-build.mjs.map +1 -0
- package/dist/cli-replacement/automatic-upgrades.d.ts +14 -0
- package/dist/cli-replacement/automatic-upgrades.d.ts.map +1 -0
- package/dist/cli-replacement/automatic-upgrades.js +267 -0
- package/dist/cli-replacement/automatic-upgrades.js.map +1 -0
- package/dist/cli-replacement/dev.d.mts +3 -6
- package/dist/cli-replacement/dev.d.mts.map +1 -1
- package/dist/cli-replacement/dev.mjs +80 -3
- package/dist/cli-replacement/dev.mjs.map +1 -1
- package/dist/client.d.ts +2 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -5
- package/dist/client.js.map +1 -1
- package/dist/dev-utils/dev-server.d.mts.map +1 -1
- package/dist/dev-utils/dev-server.mjs +59 -19
- package/dist/dev-utils/dev-server.mjs.map +1 -1
- package/dist/dev-utils/dev-tracer.d.ts +1 -1
- package/dist/dev-utils/dev-tracer.d.ts.map +1 -1
- package/dist/dev-utils/dev-tracer.js +66 -24
- package/dist/dev-utils/dev-tracer.js.map +1 -1
- package/dist/dev-utils/vite-plugin-react-transform.d.mts.map +1 -1
- package/dist/dev-utils/vite-plugin-react-transform.mjs +1 -0
- package/dist/dev-utils/vite-plugin-react-transform.mjs.map +1 -1
- package/dist/dev-utils/vite-plugin-sb-cdn.d.mts.map +1 -1
- package/dist/dev-utils/vite-plugin-sb-cdn.mjs +34 -9
- package/dist/dev-utils/vite-plugin-sb-cdn.mjs.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/socket/handlers.d.ts +2 -2
- package/dist/socket/handlers.d.ts.map +1 -1
- package/dist/socket/handlers.js.map +1 -1
- package/dist/socket/index.d.ts +1 -11
- package/dist/socket/index.d.ts.map +1 -1
- package/dist/socket/index.js +11 -43
- package/dist/socket/index.js.map +1 -1
- package/dist/types/common.d.ts +6 -0
- package/dist/types/common.d.ts.map +1 -1
- package/dist/types/common.js.map +1 -1
- package/dist/vite-plugin-inject-sb-ids-transform.d.mts +15 -0
- package/dist/vite-plugin-inject-sb-ids-transform.d.mts.map +1 -0
- package/dist/vite-plugin-inject-sb-ids-transform.mjs +86 -0
- package/dist/vite-plugin-inject-sb-ids-transform.mjs.map +1 -0
- package/package.json +26 -6
- package/src/application-build.mts +160 -0
- package/src/cli-replacement/automatic-upgrades.ts +363 -0
- package/src/cli-replacement/dev.mts +120 -10
- package/src/client.ts +13 -4
- package/src/dev-utils/dev-server.mts +79 -19
- package/src/dev-utils/dev-tracer.ts +69 -24
- package/src/dev-utils/vite-plugin-react-transform.mts +1 -0
- package/src/dev-utils/vite-plugin-sb-cdn.mts +45 -11
- package/src/index.ts +6 -1
- package/src/socket/handlers.ts +109 -105
- package/src/socket/index.ts +21 -101
- package/src/types/common.ts +7 -0
- package/src/vite-plugin-inject-sb-ids-transform.mts +104 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/socket/socket.d.ts +0 -61
- package/dist/socket/socket.d.ts.map +0 -1
- package/dist/socket/socket.js +0 -251
- package/dist/socket/socket.js.map +0 -1
- package/src/socket/socket.ts +0 -399
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import "../dev-utils/dev-tracer.js";
|
|
2
|
+
|
|
3
|
+
import * as child_process from "node:child_process";
|
|
2
4
|
import * as fsp from "node:fs/promises";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { promisify } from "node:util";
|
|
3
7
|
import { maskUnixSignals } from "@superblocksteam/util";
|
|
4
8
|
import { AiService } from "@superblocksteam/vite-plugin-file-sync/ai-service";
|
|
5
9
|
import {
|
|
@@ -9,26 +13,83 @@ import {
|
|
|
9
13
|
import { OperationQueue } from "@superblocksteam/vite-plugin-file-sync/operation-queue";
|
|
10
14
|
import { SyncService } from "@superblocksteam/vite-plugin-file-sync/sync-service";
|
|
11
15
|
import { green } from "colorette";
|
|
16
|
+
import { diffJson } from "diff";
|
|
17
|
+
import fs from "fs-extra";
|
|
18
|
+
import { resolveCommand } from "package-manager-detector";
|
|
19
|
+
import { detect } from "package-manager-detector/detect";
|
|
20
|
+
|
|
12
21
|
import { getLogger } from "../dev-utils/dev-logger.mjs";
|
|
13
22
|
import { createDevServer } from "../dev-utils/dev-server.mjs";
|
|
23
|
+
import tracer from "../dev-utils/dev-tracer.js";
|
|
14
24
|
import { SuperblocksSdk } from "../sdk.js";
|
|
25
|
+
import {
|
|
26
|
+
checkVersionsAndUpgrade,
|
|
27
|
+
getCurrentCliVersion,
|
|
28
|
+
getCurrentLibraryVersionWithoutPM,
|
|
29
|
+
} from "./automatic-upgrades.js";
|
|
15
30
|
import type { DevLogger } from "../dev-utils/dev-logger.mjs";
|
|
31
|
+
import type { ApplicationConfig } from "../types/common.js";
|
|
16
32
|
import type { DraftInterface } from "@superblocksteam/vite-plugin-file-sync/draft-interface";
|
|
17
33
|
|
|
18
|
-
|
|
19
|
-
superblocksBaseUrl: string;
|
|
20
|
-
token: string;
|
|
21
|
-
id: string;
|
|
22
|
-
branchName: string;
|
|
23
|
-
}
|
|
34
|
+
const exec = promisify(child_process.exec);
|
|
24
35
|
|
|
25
|
-
const passErrorToVSCode = (message: string, logger: DevLogger) => {
|
|
36
|
+
const passErrorToVSCode = (message: string | undefined, logger: DevLogger) => {
|
|
26
37
|
if (message) {
|
|
27
38
|
// Prefixing with `clierr:` will make the VS code extension capture this message and show it to the user.
|
|
28
39
|
logger.error(`clierr: ${JSON.stringify({ message })}`);
|
|
29
40
|
}
|
|
30
41
|
};
|
|
31
42
|
|
|
43
|
+
async function readPkgJson(cwd: string) {
|
|
44
|
+
try {
|
|
45
|
+
const { readPackage } = await import("read-pkg");
|
|
46
|
+
return await readPackage({ cwd });
|
|
47
|
+
} catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function installPackages(cwd: string, logger: DevLogger) {
|
|
53
|
+
try {
|
|
54
|
+
const pm = await detect({
|
|
55
|
+
strategies: [
|
|
56
|
+
"packageManager-field",
|
|
57
|
+
"lockfile",
|
|
58
|
+
"install-metadata",
|
|
59
|
+
"devEngines-field",
|
|
60
|
+
],
|
|
61
|
+
cwd,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!pm) {
|
|
65
|
+
logger.warn(
|
|
66
|
+
"Could not detect package manager, skipping package installation",
|
|
67
|
+
);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const installCommand = resolveCommand(pm.agent, "install", []);
|
|
72
|
+
|
|
73
|
+
if (!installCommand) {
|
|
74
|
+
logger.warn(
|
|
75
|
+
`Could not determine install command for ${pm.agent}, skipping package installation`,
|
|
76
|
+
);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const { command, args } = installCommand;
|
|
81
|
+
logger.info(
|
|
82
|
+
`Running ${command} ${args.join(" ")} to install dependencies…`,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
await exec(`${command} ${args.join(" ")}`, { cwd });
|
|
86
|
+
logger.info("Package installation completed successfully");
|
|
87
|
+
} catch (error) {
|
|
88
|
+
logger.error(`Error during package installation: ${error}`);
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
32
93
|
export async function dev(options: {
|
|
33
94
|
/* cwd is required */
|
|
34
95
|
cwd: string;
|
|
@@ -42,9 +103,15 @@ export async function dev(options: {
|
|
|
42
103
|
skipSync?: boolean;
|
|
43
104
|
|
|
44
105
|
applicationConfig?: ApplicationConfig;
|
|
106
|
+
|
|
107
|
+
/* For debugging purposes to get location of the cli */
|
|
108
|
+
superblocksPath?: string;
|
|
45
109
|
/* For redirecting output, like when running outside of the CLI */
|
|
46
110
|
logger?: (message: string) => void;
|
|
47
111
|
|
|
112
|
+
/* For a child process when restarting the dev server for automatic upgrades */
|
|
113
|
+
skipAutoUpgrade?: boolean;
|
|
114
|
+
|
|
48
115
|
/* To cancel the dev server */
|
|
49
116
|
signal?: AbortSignal;
|
|
50
117
|
}) {
|
|
@@ -58,8 +125,22 @@ export async function dev(options: {
|
|
|
58
125
|
uploadFirst,
|
|
59
126
|
skipSync,
|
|
60
127
|
applicationConfig,
|
|
128
|
+
skipAutoUpgrade,
|
|
61
129
|
} = options;
|
|
62
130
|
|
|
131
|
+
const cliVersion = await getCurrentCliVersion();
|
|
132
|
+
const libraryVersion = await getCurrentLibraryVersionWithoutPM();
|
|
133
|
+
logger.info(
|
|
134
|
+
`Running command: ${options.superblocksPath} dev${options.uploadFirst ? " --upload-first" : ""}${options.downloadFirst ? " --download-first" : ""} with baseUrl: ${applicationConfig?.superblocksBaseUrl}, cliVersion: ${cliVersion}, libraryVersion: ${libraryVersion?.alias} ${libraryVersion?.version}`,
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Add check for node_modules
|
|
138
|
+
if (!fs.existsSync(path.join(cwd, "node_modules"))) {
|
|
139
|
+
throw new Error(
|
|
140
|
+
'node_modules folder is missing. Please run "npm install" first.',
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
63
144
|
if (pidfilePath) {
|
|
64
145
|
await fsp.writeFile(pidfilePath, `${process.pid}\n`);
|
|
65
146
|
}
|
|
@@ -81,6 +162,7 @@ export async function dev(options: {
|
|
|
81
162
|
process.env.SUPERBLOCKS_IS_CSB === "true"
|
|
82
163
|
? LockType.CSB
|
|
83
164
|
: LockType.LOCAL,
|
|
165
|
+
tracer,
|
|
84
166
|
});
|
|
85
167
|
syncService = new SyncService({
|
|
86
168
|
authToken: applicationConfig.token,
|
|
@@ -90,6 +172,7 @@ export async function dev(options: {
|
|
|
90
172
|
branchName: applicationConfig.branchName,
|
|
91
173
|
fsOperationQueue,
|
|
92
174
|
lockService,
|
|
175
|
+
tracer,
|
|
93
176
|
});
|
|
94
177
|
|
|
95
178
|
logger.info("Checking if local files are synced with the server");
|
|
@@ -105,12 +188,21 @@ export async function dev(options: {
|
|
|
105
188
|
if (lockService) {
|
|
106
189
|
try {
|
|
107
190
|
await lockService!.acquireLock();
|
|
191
|
+
|
|
192
|
+
// TODO(code-mode): package naming is preventing upgrade in ephemeral environments
|
|
193
|
+
if (
|
|
194
|
+
!process.env.PACKAGE_SUFFIX ||
|
|
195
|
+
process.env.PACKAGE_SUFFIX === "" ||
|
|
196
|
+
!skipAutoUpgrade
|
|
197
|
+
) {
|
|
198
|
+
await checkVersionsAndUpgrade(lockService, applicationConfig);
|
|
199
|
+
}
|
|
108
200
|
} catch (error) {
|
|
201
|
+
logger.error("Failed to acquire lock on application", error);
|
|
109
202
|
passErrorToVSCode(
|
|
110
|
-
(error as { context
|
|
203
|
+
(error as { context?: { message: string } }).context?.message,
|
|
111
204
|
logger,
|
|
112
205
|
);
|
|
113
|
-
logger.error("Failed to acquire lock on application", error);
|
|
114
206
|
throw new Error(`Failed to acquire lock on application: ${error}`);
|
|
115
207
|
}
|
|
116
208
|
}
|
|
@@ -133,6 +225,7 @@ export async function dev(options: {
|
|
|
133
225
|
anthropicApiKey: process.env.ANTHROPIC_API_KEY || "",
|
|
134
226
|
fsOperationQueue,
|
|
135
227
|
draftInterface: syncService! as DraftInterface,
|
|
228
|
+
tracer,
|
|
136
229
|
});
|
|
137
230
|
|
|
138
231
|
const isSynced = localContents.hash === serverHash;
|
|
@@ -153,12 +246,29 @@ export async function dev(options: {
|
|
|
153
246
|
throw new Error("Choose either --download-first or --upload-first");
|
|
154
247
|
}
|
|
155
248
|
|
|
156
|
-
// TODO(code-mode): pre-process package.json to handle version upgrades
|
|
157
249
|
if (downloadFirst) {
|
|
158
250
|
logger.info(
|
|
159
251
|
"Starting directory sync from server before starting the local server",
|
|
160
252
|
);
|
|
253
|
+
|
|
254
|
+
// Read package.json before download
|
|
255
|
+
const packageJsonBefore = await readPkgJson(cwd);
|
|
256
|
+
|
|
161
257
|
await syncService!.downloadDirectory();
|
|
258
|
+
|
|
259
|
+
// Read package.json after download and compare
|
|
260
|
+
const packageJsonAfter = await readPkgJson(cwd);
|
|
261
|
+
|
|
262
|
+
// Check if package.json changed
|
|
263
|
+
if (packageJsonBefore && packageJsonAfter) {
|
|
264
|
+
const diff = diffJson(packageJsonBefore, packageJsonAfter);
|
|
265
|
+
const hasChanges = diff.some((part) => part.added || part.removed);
|
|
266
|
+
|
|
267
|
+
if (hasChanges) {
|
|
268
|
+
logger.info("package.json has changed, installing packages…");
|
|
269
|
+
await installPackages(cwd, logger);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
162
272
|
} else if (uploadFirst) {
|
|
163
273
|
logger.info("Uploading local files to server before starting");
|
|
164
274
|
await syncService!.uploadDirectory();
|
package/src/client.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
2
3
|
import { Bucketeer, FileDescriptor } from "@superblocksteam/bucketeer-sdk";
|
|
3
4
|
import { ExportViewMode } from "@superblocksteam/shared";
|
|
4
5
|
import {
|
|
@@ -1269,13 +1270,15 @@ export async function uploadApplication({
|
|
|
1269
1270
|
scopedJwt,
|
|
1270
1271
|
url,
|
|
1271
1272
|
cliVersion,
|
|
1273
|
+
appRoot,
|
|
1272
1274
|
}: {
|
|
1273
1275
|
files: string[];
|
|
1274
1276
|
scopedJwt: string;
|
|
1275
1277
|
url: string;
|
|
1276
1278
|
cliVersion: string;
|
|
1279
|
+
appRoot?: string;
|
|
1277
1280
|
}) {
|
|
1278
|
-
const fds = filesToFileDescriptors(files);
|
|
1281
|
+
const fds = filesToFileDescriptors(files, appRoot);
|
|
1279
1282
|
const bucketeer = new Bucketeer({
|
|
1280
1283
|
token: scopedJwt,
|
|
1281
1284
|
baseUrl: url,
|
|
@@ -1285,9 +1288,15 @@ export async function uploadApplication({
|
|
|
1285
1288
|
await bucketeer.uploadApplication(fds);
|
|
1286
1289
|
}
|
|
1287
1290
|
|
|
1288
|
-
function filesToFileDescriptors(files: string[]) {
|
|
1291
|
+
function filesToFileDescriptors(files: string[], appRoot?: string) {
|
|
1289
1292
|
const fds = files.map((file) => {
|
|
1290
|
-
|
|
1293
|
+
const relativePath = appRoot ? path.relative(appRoot, file) : undefined;
|
|
1294
|
+
return new FileDescriptor(
|
|
1295
|
+
file,
|
|
1296
|
+
fs.createReadStream(file),
|
|
1297
|
+
undefined,
|
|
1298
|
+
relativePath,
|
|
1299
|
+
);
|
|
1291
1300
|
});
|
|
1292
1301
|
return fds;
|
|
1293
1302
|
}
|
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
import tracer from "./dev-tracer.js";
|
|
4
4
|
|
|
5
5
|
import net from "node:net";
|
|
6
|
+
import os from "node:os";
|
|
6
7
|
import path from "node:path";
|
|
7
8
|
import { getSuperblocksResourceConfigIfExists } from "@superblocksteam/util";
|
|
8
9
|
import { fileSyncVitePlugin } from "@superblocksteam/vite-plugin-file-sync";
|
|
9
10
|
import react from "@vitejs/plugin-react";
|
|
10
11
|
import { red, yellow } from "colorette";
|
|
12
|
+
import cors from "cors";
|
|
11
13
|
import express from "express";
|
|
12
14
|
import { createLogger, createServer, loadEnv } from "vite";
|
|
13
15
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
@@ -24,8 +26,9 @@ import type { LockService } from "@superblocksteam/vite-plugin-file-sync/lock-se
|
|
|
24
26
|
import type { OperationQueue } from "@superblocksteam/vite-plugin-file-sync/operation-queue";
|
|
25
27
|
import type { SyncService } from "@superblocksteam/vite-plugin-file-sync/sync-service";
|
|
26
28
|
import type http from "node:http";
|
|
29
|
+
import type { HmrOptions, Plugin } from "vite";
|
|
27
30
|
import type { ViteDevServer } from "vite";
|
|
28
|
-
|
|
31
|
+
|
|
29
32
|
interface CreateDevServerOptions {
|
|
30
33
|
root: string;
|
|
31
34
|
mode: "development" | "production";
|
|
@@ -81,12 +84,23 @@ export async function createDevServer({
|
|
|
81
84
|
viteReject = reject;
|
|
82
85
|
});
|
|
83
86
|
|
|
84
|
-
async function gracefulShutdown(
|
|
87
|
+
async function gracefulShutdown({
|
|
88
|
+
logger,
|
|
89
|
+
serverInitiated,
|
|
90
|
+
switchingTo,
|
|
91
|
+
initiatedByEmail,
|
|
92
|
+
}: {
|
|
93
|
+
logger: ReturnType<typeof getLogger>;
|
|
94
|
+
serverInitiated: boolean;
|
|
95
|
+
switchingTo?: "local" | "cloud" | "none";
|
|
96
|
+
initiatedByEmail?: string;
|
|
97
|
+
}) {
|
|
85
98
|
try {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
99
|
+
await lockService?.shutdown({
|
|
100
|
+
serverInitiated,
|
|
101
|
+
switchingTo,
|
|
102
|
+
initiatedByEmail,
|
|
103
|
+
});
|
|
90
104
|
// Cleanup the vite server
|
|
91
105
|
if (viteServer) {
|
|
92
106
|
await viteServer?.close();
|
|
@@ -110,8 +124,16 @@ export async function createDevServer({
|
|
|
110
124
|
}
|
|
111
125
|
}
|
|
112
126
|
|
|
127
|
+
app.use(
|
|
128
|
+
cors({
|
|
129
|
+
origin: true,
|
|
130
|
+
credentials: true,
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
app.use(express.json());
|
|
134
|
+
|
|
113
135
|
app.use((req, res, next) => {
|
|
114
|
-
res.setHeader("
|
|
136
|
+
res.setHeader("Cache-Control", "no-store, max-age=0");
|
|
115
137
|
|
|
116
138
|
if (
|
|
117
139
|
req.url === "/_sb_connect" ||
|
|
@@ -135,14 +157,12 @@ export async function createDevServer({
|
|
|
135
157
|
|
|
136
158
|
app.get("/_sb_health", async (_req, res) => {
|
|
137
159
|
res.setHeader("Content-Type", "application/json");
|
|
138
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
139
160
|
res.send(JSON.stringify(healthResponse));
|
|
140
161
|
});
|
|
141
162
|
|
|
142
163
|
// Attach the vite server to the express app
|
|
143
164
|
app.get("/_sb_connect", async (_req, res) => {
|
|
144
165
|
res.setHeader("Content-Type", "application/json");
|
|
145
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
146
166
|
if (isViteServerInitialized) {
|
|
147
167
|
res.send(JSON.stringify(healthResponse));
|
|
148
168
|
return;
|
|
@@ -150,6 +170,7 @@ export async function createDevServer({
|
|
|
150
170
|
isViteServerInitialized = true;
|
|
151
171
|
// TODO(code-mode): should this include any validation checks, such as getting a token?
|
|
152
172
|
startVite({
|
|
173
|
+
port,
|
|
153
174
|
app,
|
|
154
175
|
root,
|
|
155
176
|
mode,
|
|
@@ -166,15 +187,32 @@ export async function createDevServer({
|
|
|
166
187
|
}, viteReject);
|
|
167
188
|
});
|
|
168
189
|
|
|
190
|
+
// TODO(code-mode): remove this soon
|
|
169
191
|
app.get("/_sb_disconnect", async (_req, res) => {
|
|
192
|
+
console.log("GET /_sb_disconnect");
|
|
170
193
|
// TODO(code-mode): should this include any validation checks, such as getting a token?
|
|
171
|
-
await gracefulShutdown(logger);
|
|
194
|
+
await gracefulShutdown({ logger, serverInitiated: false });
|
|
172
195
|
res.send("ok");
|
|
173
196
|
});
|
|
197
|
+
app.post("/_sb_disconnect", async (req, res) => {
|
|
198
|
+
const { initiatedByEmail, switchingTo } = req.body;
|
|
199
|
+
// TODO(code-mode): should this include any validation checks, such as getting a token?
|
|
200
|
+
try {
|
|
201
|
+
await gracefulShutdown({
|
|
202
|
+
logger,
|
|
203
|
+
serverInitiated: true,
|
|
204
|
+
switchingTo,
|
|
205
|
+
initiatedByEmail: initiatedByEmail as string | undefined,
|
|
206
|
+
});
|
|
207
|
+
res.send("ok");
|
|
208
|
+
} catch (e) {
|
|
209
|
+
console.error("Error disconnecting from dev server", e);
|
|
210
|
+
res.status(500).send("Error disconnecting from dev server");
|
|
211
|
+
}
|
|
212
|
+
});
|
|
174
213
|
|
|
175
214
|
app.get("/_sb_status", async (_req, res) => {
|
|
176
215
|
res.setHeader("Content-Type", "application/json");
|
|
177
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
178
216
|
if (lockService?.isLocked) {
|
|
179
217
|
res.send({
|
|
180
218
|
connectedUsers: lockService.connectedUsers,
|
|
@@ -188,17 +226,17 @@ export async function createDevServer({
|
|
|
188
226
|
|
|
189
227
|
process.on("SIGINT", async () => {
|
|
190
228
|
logger.info("SIGINT received");
|
|
191
|
-
await gracefulShutdown(logger);
|
|
229
|
+
await gracefulShutdown({ logger, serverInitiated: false });
|
|
192
230
|
});
|
|
193
231
|
|
|
194
232
|
process.on("SIGTERM", async () => {
|
|
195
233
|
logger.info("SIGTERM received");
|
|
196
|
-
await gracefulShutdown(logger);
|
|
234
|
+
await gracefulShutdown({ logger, serverInitiated: false });
|
|
197
235
|
});
|
|
198
236
|
|
|
199
237
|
process.on("SIGABRT", async () => {
|
|
200
238
|
logger.info("SIGABRT received");
|
|
201
|
-
await gracefulShutdown(logger);
|
|
239
|
+
await gracefulShutdown({ logger, serverInitiated: false });
|
|
202
240
|
});
|
|
203
241
|
|
|
204
242
|
httpServer = await app.listen(port);
|
|
@@ -210,6 +248,7 @@ async function startVite({
|
|
|
210
248
|
httpServer,
|
|
211
249
|
root,
|
|
212
250
|
mode,
|
|
251
|
+
port,
|
|
213
252
|
fsOperationQueue,
|
|
214
253
|
syncService,
|
|
215
254
|
lockService,
|
|
@@ -243,6 +282,19 @@ async function startVite({
|
|
|
243
282
|
|
|
244
283
|
const hmrPort = await getFreePort();
|
|
245
284
|
|
|
285
|
+
const hmrOptions: HmrOptions = {
|
|
286
|
+
port: hmrPort,
|
|
287
|
+
clientPort: port,
|
|
288
|
+
server: httpServer,
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
// https://codesandbox.io/docs/learn/environment/preview-urls#using-environment-variables
|
|
292
|
+
if (process.env.CSB_BASE_PREVIEW_HOST) {
|
|
293
|
+
const hmrHost = `${os.hostname()}-${port}.${process.env.CSB_BASE_PREVIEW_HOST}`;
|
|
294
|
+
hmrOptions.host = hmrHost;
|
|
295
|
+
hmrOptions.clientPort = 443; // tells client to use default ssl port
|
|
296
|
+
}
|
|
297
|
+
|
|
246
298
|
const viteServer = await createServer({
|
|
247
299
|
root,
|
|
248
300
|
mode,
|
|
@@ -260,12 +312,13 @@ async function startVite({
|
|
|
260
312
|
// appType: "custom",
|
|
261
313
|
server: {
|
|
262
314
|
middlewareMode: true,
|
|
263
|
-
// port: port,
|
|
264
315
|
watch: {
|
|
265
316
|
ignored: [`${customFolder}/**/*`],
|
|
266
317
|
},
|
|
267
|
-
hmr:
|
|
268
|
-
|
|
318
|
+
hmr: hmrOptions,
|
|
319
|
+
cors: {
|
|
320
|
+
origin: true,
|
|
321
|
+
credentials: true,
|
|
269
322
|
},
|
|
270
323
|
},
|
|
271
324
|
build: {
|
|
@@ -297,10 +350,13 @@ async function startVite({
|
|
|
297
350
|
// for now, only use the CDN locally
|
|
298
351
|
superblocksCdnPlugin({
|
|
299
352
|
imports: {
|
|
300
|
-
"@superblocksteam/library":
|
|
353
|
+
"@superblocksteam/library": getValidFileUrl(cdnUrl, "index.js"),
|
|
301
354
|
},
|
|
302
355
|
cssImports: {
|
|
303
|
-
"@superblocksteam/library/index.css":
|
|
356
|
+
"@superblocksteam/library/index.css": getValidFileUrl(
|
|
357
|
+
cdnUrl,
|
|
358
|
+
"index.css",
|
|
359
|
+
),
|
|
304
360
|
},
|
|
305
361
|
}),
|
|
306
362
|
|
|
@@ -340,3 +396,7 @@ function getFreePort() {
|
|
|
340
396
|
});
|
|
341
397
|
});
|
|
342
398
|
}
|
|
399
|
+
|
|
400
|
+
function getValidFileUrl(url: string, file: string): string {
|
|
401
|
+
return new URL(file, url.endsWith("/") ? url : url + "/").href;
|
|
402
|
+
}
|
|
@@ -1,31 +1,76 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { trace } from "@opentelemetry/api";
|
|
2
|
+
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
|
|
3
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
4
|
+
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
|
|
5
|
+
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
|
|
6
|
+
import { Resource } from "@opentelemetry/resources";
|
|
7
|
+
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
8
|
+
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
9
|
+
import { getLocalTokenWithUrl } from "@superblocksteam/util";
|
|
2
10
|
import packageJson from "../../package.json" with { type: "json" };
|
|
11
|
+
import type { Span } from "@opentelemetry/api";
|
|
3
12
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
13
|
+
// NOTE: @joeyagreco - this is how the "env" facet is determined in datadog: https://docs.datadoghq.com/opentelemetry/setup/collector_exporter/#3---configure-your-application
|
|
14
|
+
const ATTR_DEPLOYMENT_ENVIRONMENT = "deployment.environment";
|
|
15
|
+
// NOTE: @joeyagreco - this can be used to determine if we are using mock-csb, staging-csb, prod-csb, etc
|
|
16
|
+
const ATTR_SUPERBLOCKS_BASE_URL = "superblocks.base_url";
|
|
17
|
+
const ATTR_SUPERBLOCKS_CLI_TOKEN = "superblocks.cli_token";
|
|
18
|
+
let superblocksTracesUrl = undefined;
|
|
19
|
+
let superblocksHostname = "unknown";
|
|
20
|
+
let token = "unknown";
|
|
21
|
+
try {
|
|
22
|
+
const tokenWithUrl = await getLocalTokenWithUrl();
|
|
23
|
+
const superblocksBaseUrl = new URL(tokenWithUrl.superblocksBaseUrl);
|
|
24
|
+
superblocksTracesUrl = superblocksBaseUrl.origin + "/api/v1/traces";
|
|
25
|
+
superblocksHostname = superblocksBaseUrl.hostname;
|
|
26
|
+
if ("token" in tokenWithUrl) {
|
|
27
|
+
token = tokenWithUrl.token.substring(0, 8);
|
|
28
|
+
}
|
|
29
|
+
} catch (e) {
|
|
30
|
+
console.error("[tracing init] could not determine superblocks base url", e);
|
|
31
|
+
}
|
|
10
32
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
},
|
|
20
|
-
|
|
33
|
+
// Initialize the OpenTelemetry SDK
|
|
34
|
+
const sdk = new NodeSDK({
|
|
35
|
+
resource: Resource.default().merge(
|
|
36
|
+
new Resource({
|
|
37
|
+
[ATTR_SERVICE_NAME]: "sdk-dev-server",
|
|
38
|
+
[ATTR_DEPLOYMENT_ENVIRONMENT]: process.env.SUPERBLOCKS_CLI_ENV,
|
|
39
|
+
[ATTR_SUPERBLOCKS_BASE_URL]: superblocksHostname,
|
|
40
|
+
[ATTR_SUPERBLOCKS_CLI_TOKEN]: token,
|
|
41
|
+
}),
|
|
42
|
+
),
|
|
43
|
+
traceExporter: new OTLPTraceExporter({
|
|
44
|
+
url: superblocksTracesUrl, // OTLPTraceExporter defaults to sending traffic to http://localhost:4318/v1/traces
|
|
45
|
+
}),
|
|
46
|
+
contextManager: new AsyncLocalStorageContextManager(),
|
|
47
|
+
instrumentations: [
|
|
48
|
+
// Configure HTTP instrumentation with custom attributes
|
|
49
|
+
new HttpInstrumentation({
|
|
50
|
+
requestHook: (span: Span, request: any) => {
|
|
51
|
+
let resource = "GET";
|
|
52
|
+
if (request) {
|
|
53
|
+
resource = `${request.method} ${request.url || request.path}`;
|
|
54
|
+
}
|
|
55
|
+
span.setAttributes({
|
|
56
|
+
"resource.name": resource,
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
// Configure Express instrumentation
|
|
61
|
+
new ExpressInstrumentation({
|
|
62
|
+
requestHook: (span: Span, request: any) => {
|
|
63
|
+
span.setAttributes({
|
|
64
|
+
"resource.name": `${request.method} ${request.url}`,
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
],
|
|
21
69
|
});
|
|
22
70
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
});
|
|
71
|
+
sdk.start();
|
|
72
|
+
|
|
73
|
+
// Get a tracer instance
|
|
74
|
+
const tracer = trace.getTracer("sdk-dev-server", packageJson.version);
|
|
30
75
|
|
|
31
76
|
export default tracer;
|
|
@@ -11,6 +11,7 @@ export function reactTransformPlugin(): Plugin {
|
|
|
11
11
|
return {
|
|
12
12
|
name: "vite-plugin-react-transform",
|
|
13
13
|
enforce: "pre", // Run before other plugins
|
|
14
|
+
apply: "serve",
|
|
14
15
|
async transform(code, id) {
|
|
15
16
|
// Check for React modules
|
|
16
17
|
if (id.includes("node_modules/.vite/deps/react.js")) {
|