@superblocksteam/sdk 1.14.2 → 1.99.99-next.2
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/.mocharc.json +7 -0
- package/.prettierrc +18 -0
- package/dist/cli-replacement/automatic-upgrades.d.ts +4 -0
- package/dist/cli-replacement/automatic-upgrades.d.ts.map +1 -0
- package/dist/cli-replacement/automatic-upgrades.js +246 -0
- package/dist/cli-replacement/automatic-upgrades.js.map +1 -0
- package/dist/cli-replacement/dev.d.mts +14 -0
- package/dist/cli-replacement/dev.d.mts.map +1 -0
- package/dist/cli-replacement/dev.mjs +195 -0
- package/dist/cli-replacement/dev.mjs.map +1 -0
- package/dist/cli-replacement/init.d.ts +14 -0
- package/dist/cli-replacement/init.d.ts.map +1 -0
- package/dist/cli-replacement/init.js +26 -0
- package/dist/cli-replacement/init.js.map +1 -0
- package/dist/client.d.ts +31 -17
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +137 -155
- package/dist/client.js.map +1 -0
- package/dist/dbfs/client.d.ts +6 -0
- package/dist/dbfs/client.d.ts.map +1 -0
- package/dist/dbfs/client.js +117 -0
- package/dist/dbfs/client.js.map +1 -0
- package/dist/dbfs/local.d.ts +15 -0
- package/dist/dbfs/local.d.ts.map +1 -0
- package/dist/dbfs/local.js +126 -0
- package/dist/dbfs/local.js.map +1 -0
- package/dist/dev-utils/custom-build.d.mts +4 -0
- package/dist/dev-utils/custom-build.d.mts.map +1 -0
- package/dist/dev-utils/custom-build.mjs +99 -0
- package/dist/dev-utils/custom-build.mjs.map +1 -0
- package/dist/dev-utils/custom-config.d.mts +2 -0
- package/dist/dev-utils/custom-config.d.mts.map +1 -0
- package/dist/dev-utils/custom-config.mjs +57 -0
- package/dist/dev-utils/custom-config.mjs.map +1 -0
- package/dist/dev-utils/dev-logger.d.mts +8 -0
- package/dist/dev-utils/dev-logger.d.mts.map +1 -0
- package/dist/dev-utils/dev-logger.mjs +25 -0
- package/dist/dev-utils/dev-logger.mjs.map +1 -0
- package/dist/dev-utils/dev-server.d.mts +18 -0
- package/dist/dev-utils/dev-server.d.mts.map +1 -0
- package/dist/dev-utils/dev-server.mjs +283 -0
- package/dist/dev-utils/dev-server.mjs.map +1 -0
- package/dist/dev-utils/dev-tracer.d.ts +3 -0
- package/dist/dev-utils/dev-tracer.d.ts.map +1 -0
- package/dist/dev-utils/dev-tracer.js +38 -0
- package/dist/dev-utils/dev-tracer.js.map +1 -0
- package/dist/dev-utils/vite-plugin-dd-rum.d.mts +10 -0
- package/dist/dev-utils/vite-plugin-dd-rum.d.mts.map +1 -0
- package/dist/dev-utils/vite-plugin-dd-rum.mjs +34 -0
- package/dist/dev-utils/vite-plugin-dd-rum.mjs.map +1 -0
- package/dist/dev-utils/vite-plugin-react-transform.d.mts +7 -0
- package/dist/dev-utils/vite-plugin-react-transform.d.mts.map +1 -0
- package/dist/dev-utils/vite-plugin-react-transform.mjs +110 -0
- package/dist/dev-utils/vite-plugin-react-transform.mjs.map +1 -0
- package/dist/dev-utils/vite-plugin-sb-cdn.d.mts +34 -0
- package/dist/dev-utils/vite-plugin-sb-cdn.d.mts.map +1 -0
- package/dist/dev-utils/vite-plugin-sb-cdn.mjs +720 -0
- package/dist/dev-utils/vite-plugin-sb-cdn.mjs.map +1 -0
- package/dist/errors.d.ts +1 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +4 -9
- package/dist/errors.js.map +1 -0
- package/dist/flag.d.ts +2 -2
- package/dist/flag.d.ts.map +1 -0
- package/dist/flag.js +5 -9
- package/dist/flag.js.map +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -20
- package/dist/index.js.map +1 -0
- package/dist/sdk.d.ts +42 -18
- package/dist/sdk.d.ts.map +1 -0
- package/dist/sdk.js +47 -43
- package/dist/sdk.js.map +1 -0
- package/dist/socket/handlers.d.ts +3 -128
- package/dist/socket/handlers.d.ts.map +1 -0
- package/dist/socket/handlers.js +7 -9
- package/dist/socket/handlers.js.map +1 -0
- package/dist/socket/index.d.ts +4 -3
- package/dist/socket/index.d.ts.map +1 -0
- package/dist/socket/index.js +12 -21
- package/dist/socket/index.js.map +1 -0
- package/dist/socket/signing.d.ts +3 -1
- package/dist/socket/signing.d.ts.map +1 -0
- package/dist/socket/signing.js +8 -17
- package/dist/socket/signing.js.map +1 -0
- package/dist/types/common.d.ts +8 -103
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/common.js +8 -24
- package/dist/types/common.js.map +1 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -20
- package/dist/types/index.js.map +1 -0
- package/dist/types/plugin.d.ts +1 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +3 -5
- package/dist/types/plugin.js.map +1 -0
- package/dist/types/signing.d.ts +2 -1
- package/dist/types/signing.d.ts.map +1 -0
- package/dist/types/signing.js +2 -2
- package/dist/types/signing.js.map +1 -0
- package/dist/types/socket.d.ts +1 -0
- package/dist/types/socket.d.ts.map +1 -0
- package/dist/types/socket.js +2 -5
- package/dist/types/socket.js.map +1 -0
- package/dist/utils.d.ts +3 -1
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +14 -23
- package/dist/utils.js.map +1 -0
- package/dist/version-control.d.mts +59 -0
- package/dist/version-control.d.mts.map +1 -0
- package/dist/version-control.mjs +899 -0
- package/dist/version-control.mjs.map +1 -0
- package/eslint.config.js +85 -0
- package/package.json +85 -30
- package/src/cli-replacement/automatic-upgrades.ts +335 -0
- package/src/cli-replacement/dev.mts +276 -0
- package/src/cli-replacement/init.ts +47 -0
- package/src/client.ts +114 -38
- package/src/dbfs/client.ts +162 -0
- package/src/dbfs/local.ts +163 -0
- package/src/dev-utils/custom-build.mts +113 -0
- package/src/dev-utils/custom-config.mts +66 -0
- package/src/dev-utils/dev-logger.mts +39 -0
- package/src/dev-utils/dev-server.mts +371 -0
- package/src/dev-utils/dev-tracer.ts +42 -0
- package/src/dev-utils/vite-plugin-dd-rum.mts +47 -0
- package/src/dev-utils/vite-plugin-react-transform.mts +130 -0
- package/src/dev-utils/vite-plugin-sb-cdn.mts +988 -0
- package/src/flag.ts +2 -3
- package/src/index.ts +120 -4
- package/src/sdk.ts +91 -17
- package/src/socket/handlers.ts +9 -147
- package/src/socket/index.ts +6 -9
- package/src/socket/signing.ts +7 -8
- package/src/types/common.ts +9 -119
- package/src/types/index.ts +4 -4
- package/src/types/signing.ts +1 -1
- package/src/types/socket.ts +1 -1
- package/src/utils.ts +5 -6
- package/src/version-control.mts +1351 -0
- package/test/dev-utils/fixture/index.html +12 -0
- package/test/dev-utils/fixture/main.jsx +22 -0
- package/test/dev-utils/fixture/package-lock.json +25 -0
- package/test/dev-utils/fixture/package.json +9 -0
- package/test/dev-utils/vite-plugin-sb-cdn.test.mts +74 -0
- package/test/tsconfig.json +9 -0
- package/test/version-control.test.mts +1412 -0
- package/tsconfig.json +15 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/.eslintrc.json +0 -55
- package/dist/socket/socket.d.ts +0 -60
- package/dist/socket/socket.js +0 -261
- package/src/socket/socket.ts +0 -400
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { unreachable } from "@superblocksteam/util";
|
|
2
|
+
import { connectToISocketRPCServer } from "../socket/index.js";
|
|
3
|
+
import { doDownloadDirectoryToLocal, doUploadLocalDirectory } from "./local.js";
|
|
4
|
+
|
|
5
|
+
// TODO(code-mode): this is re-implemented in the vite-plugin-file-sync package
|
|
6
|
+
// because SDK depends on vite-plugin-file-sync, but can't be circular
|
|
7
|
+
export async function getApplicationDirectoryHash(
|
|
8
|
+
token: string,
|
|
9
|
+
superblocksBaseUrl: string,
|
|
10
|
+
applicationId: string,
|
|
11
|
+
branch: string | undefined,
|
|
12
|
+
) {
|
|
13
|
+
const rpcClient = await connectToISocketRPCServer({
|
|
14
|
+
token,
|
|
15
|
+
superblocksBaseUrl,
|
|
16
|
+
});
|
|
17
|
+
try {
|
|
18
|
+
const response =
|
|
19
|
+
await rpcClient.call.v3.application.liveEditDirectoryContents.get({
|
|
20
|
+
applicationId,
|
|
21
|
+
branchName: branch,
|
|
22
|
+
});
|
|
23
|
+
const liveEditHash = response.data.hash;
|
|
24
|
+
if (!liveEditHash) {
|
|
25
|
+
throw new Error("No live edit hash found");
|
|
26
|
+
}
|
|
27
|
+
return liveEditHash;
|
|
28
|
+
} finally {
|
|
29
|
+
rpcClient.close();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function downloadApplicationDirectory(
|
|
34
|
+
token: string,
|
|
35
|
+
superblocksBaseUrl: string,
|
|
36
|
+
applicationId: string,
|
|
37
|
+
branch: string | undefined,
|
|
38
|
+
localDirectoryPath: string,
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
const rpcClient = await connectToISocketRPCServer({
|
|
41
|
+
token,
|
|
42
|
+
superblocksBaseUrl,
|
|
43
|
+
});
|
|
44
|
+
try {
|
|
45
|
+
const liveEditHash = await getApplicationDirectoryHash(
|
|
46
|
+
token,
|
|
47
|
+
superblocksBaseUrl,
|
|
48
|
+
applicationId,
|
|
49
|
+
branch,
|
|
50
|
+
);
|
|
51
|
+
await doDownloadDirectoryToLocal(
|
|
52
|
+
rpcClient,
|
|
53
|
+
liveEditHash,
|
|
54
|
+
localDirectoryPath,
|
|
55
|
+
);
|
|
56
|
+
} finally {
|
|
57
|
+
rpcClient.close();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function uploadLocalApplication(
|
|
62
|
+
token: string,
|
|
63
|
+
superblocksBaseUrl: string,
|
|
64
|
+
applicationId: string,
|
|
65
|
+
branch: string | undefined,
|
|
66
|
+
localDirectoryPath: string,
|
|
67
|
+
): Promise<void> {
|
|
68
|
+
const rpcClient = await connectToISocketRPCServer({
|
|
69
|
+
token,
|
|
70
|
+
superblocksBaseUrl,
|
|
71
|
+
});
|
|
72
|
+
try {
|
|
73
|
+
const directoryHash = await doUploadLocalDirectory(
|
|
74
|
+
rpcClient,
|
|
75
|
+
localDirectoryPath,
|
|
76
|
+
);
|
|
77
|
+
console.log(`New application directory hash: ${directoryHash}`);
|
|
78
|
+
await rpcClient.call.v3.application.liveEditDirectoryContents.set({
|
|
79
|
+
applicationId,
|
|
80
|
+
branchName: branch,
|
|
81
|
+
hash: directoryHash,
|
|
82
|
+
});
|
|
83
|
+
} finally {
|
|
84
|
+
rpcClient.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function printDirectoryEntries(
|
|
89
|
+
token: string,
|
|
90
|
+
superblocksBaseUrl: string,
|
|
91
|
+
directoryHash: string,
|
|
92
|
+
): Promise<void> {
|
|
93
|
+
const rpcClient = await connectToISocketRPCServer({
|
|
94
|
+
token,
|
|
95
|
+
superblocksBaseUrl,
|
|
96
|
+
});
|
|
97
|
+
try {
|
|
98
|
+
const directoryContentsResponse =
|
|
99
|
+
await rpcClient.call.v1.dbfs.directoryContents.get({
|
|
100
|
+
hash: directoryHash,
|
|
101
|
+
});
|
|
102
|
+
for (const entry of directoryContentsResponse.data.contents) {
|
|
103
|
+
let executable: boolean;
|
|
104
|
+
let hash: string;
|
|
105
|
+
let target: string | undefined;
|
|
106
|
+
switch (entry.type) {
|
|
107
|
+
case "-": {
|
|
108
|
+
executable = entry.executable;
|
|
109
|
+
hash = entry.hash;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case "l": {
|
|
113
|
+
executable = false;
|
|
114
|
+
target = entry.target;
|
|
115
|
+
hash = " ".repeat(Math.ceil(256 / 24) * 4);
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
case "d": {
|
|
119
|
+
executable = false;
|
|
120
|
+
hash = entry.hash;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
default: {
|
|
124
|
+
unreachable(entry);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
console.log(
|
|
128
|
+
`${entry.type}${executable ? "x" : " "} ${hash} ${entry.name}${
|
|
129
|
+
target ? ` -> ${target}` : ""
|
|
130
|
+
}`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
} finally {
|
|
134
|
+
rpcClient.close();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function printFileContents(
|
|
139
|
+
token: string,
|
|
140
|
+
superblocksBaseUrl: string,
|
|
141
|
+
fileHash: string,
|
|
142
|
+
): Promise<void> {
|
|
143
|
+
const rpcClient = await connectToISocketRPCServer({
|
|
144
|
+
token,
|
|
145
|
+
superblocksBaseUrl,
|
|
146
|
+
});
|
|
147
|
+
try {
|
|
148
|
+
const fileContentsResponse = await rpcClient.call.v1.dbfs.fileContents.get({
|
|
149
|
+
hash: fileHash,
|
|
150
|
+
});
|
|
151
|
+
// The file can contain binary data, do not interpret it as text
|
|
152
|
+
// Note: `Buffer.from` is a Node.js specific API
|
|
153
|
+
const fileContents = Buffer.from(
|
|
154
|
+
fileContentsResponse.data.contents,
|
|
155
|
+
"base64",
|
|
156
|
+
);
|
|
157
|
+
// Note: `process.stdout.write` is a Node.js specific API
|
|
158
|
+
process.stdout.write(fileContents);
|
|
159
|
+
} finally {
|
|
160
|
+
rpcClient.close();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import * as fsp from "node:fs/promises";
|
|
2
|
+
import {
|
|
3
|
+
hashDirectoryContents,
|
|
4
|
+
hashFileContents,
|
|
5
|
+
type DirectoryEntry,
|
|
6
|
+
} from "@superblocksteam/shared";
|
|
7
|
+
import { unreachable } from "@superblocksteam/util";
|
|
8
|
+
import { listLocalDirectory } from "@superblocksteam/vite-plugin-file-sync/list-dir";
|
|
9
|
+
import type { StdISocketRPCClient } from "../socket/index.js";
|
|
10
|
+
|
|
11
|
+
export async function doDownloadDirectoryToLocal(
|
|
12
|
+
rpcClient: StdISocketRPCClient,
|
|
13
|
+
directoryHash: string,
|
|
14
|
+
localDirectoryPath: string,
|
|
15
|
+
): Promise<void> {
|
|
16
|
+
// ensure that the top-level local directory exists
|
|
17
|
+
await fsp.mkdir(localDirectoryPath, { recursive: true });
|
|
18
|
+
await doDownloadDirectoryToLocalRec(
|
|
19
|
+
rpcClient,
|
|
20
|
+
directoryHash,
|
|
21
|
+
localDirectoryPath,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function doDownloadDirectoryToLocalRec(
|
|
26
|
+
rpcClient: StdISocketRPCClient,
|
|
27
|
+
directoryHash: string,
|
|
28
|
+
localDirectoryPath: string,
|
|
29
|
+
): Promise<void> {
|
|
30
|
+
const directoryContentsResponse =
|
|
31
|
+
await rpcClient.call.v1.dbfs.directoryContents.get({ hash: directoryHash });
|
|
32
|
+
if (!directoryContentsResponse.data) {
|
|
33
|
+
throw new Error("Failed to get directory contents");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for (const entry of directoryContentsResponse.data.contents) {
|
|
37
|
+
const localFilePath = `${localDirectoryPath}/${entry.name}`;
|
|
38
|
+
switch (entry.type) {
|
|
39
|
+
case "-": {
|
|
40
|
+
const fileContentsResponse =
|
|
41
|
+
await rpcClient.call.v1.dbfs.fileContents.get({ hash: entry.hash });
|
|
42
|
+
const fileContents = Buffer.from(
|
|
43
|
+
fileContentsResponse.data.contents,
|
|
44
|
+
"base64",
|
|
45
|
+
);
|
|
46
|
+
await fsp.writeFile(localFilePath, fileContents);
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
case "l": {
|
|
50
|
+
await fsp.symlink(entry.target, localFilePath);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
case "d": {
|
|
54
|
+
await fsp.mkdir(localFilePath, {
|
|
55
|
+
recursive: true /* do not reject if exists */,
|
|
56
|
+
});
|
|
57
|
+
await doDownloadDirectoryToLocalRec(
|
|
58
|
+
rpcClient,
|
|
59
|
+
entry.hash,
|
|
60
|
+
localFilePath,
|
|
61
|
+
);
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
default: {
|
|
65
|
+
unreachable(entry);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Computes the hash of a local directory, including the hashes of all its contents recursively.
|
|
73
|
+
*
|
|
74
|
+
* @param localDirectoryPath - The path to the local directory to hash.
|
|
75
|
+
* @returns A promise that resolves to the hash of the directory and its contents.
|
|
76
|
+
*/
|
|
77
|
+
export async function hashLocalDirectory(localDirectoryPath: string): Promise<{
|
|
78
|
+
hash: string;
|
|
79
|
+
contents: DirectoryEntry[];
|
|
80
|
+
}> {
|
|
81
|
+
const directoryContents: any[] = [];
|
|
82
|
+
const localDirListing = listLocalDirectory(localDirectoryPath);
|
|
83
|
+
for await (const localDirEntry of localDirListing) {
|
|
84
|
+
let entry: any;
|
|
85
|
+
switch (localDirEntry.type) {
|
|
86
|
+
case "-": {
|
|
87
|
+
const hash = await hashFileContents(localDirEntry.contents);
|
|
88
|
+
entry = {
|
|
89
|
+
type: "-",
|
|
90
|
+
executable: localDirEntry.executable,
|
|
91
|
+
name: localDirEntry.name,
|
|
92
|
+
hash,
|
|
93
|
+
};
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case "d": {
|
|
97
|
+
const { hash, contents: subdirectoryContents } =
|
|
98
|
+
await hashLocalDirectory(localDirEntry.localPath);
|
|
99
|
+
entry = {
|
|
100
|
+
type: "d",
|
|
101
|
+
name: localDirEntry.name,
|
|
102
|
+
hash,
|
|
103
|
+
contents: subdirectoryContents,
|
|
104
|
+
};
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
case "l": {
|
|
108
|
+
entry = {
|
|
109
|
+
type: "l",
|
|
110
|
+
target: localDirEntry.target,
|
|
111
|
+
name: localDirEntry.name,
|
|
112
|
+
};
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
default:
|
|
116
|
+
unreachable(localDirEntry);
|
|
117
|
+
}
|
|
118
|
+
directoryContents.push(entry);
|
|
119
|
+
}
|
|
120
|
+
const hash = await hashDirectoryContents(directoryContents);
|
|
121
|
+
return { contents: directoryContents, hash };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function doUploadLocalDirectory(
|
|
125
|
+
rpcClient: StdISocketRPCClient,
|
|
126
|
+
localDirectoryPath: string,
|
|
127
|
+
): Promise<string> {
|
|
128
|
+
const directoryContents: DirectoryEntry[] = [];
|
|
129
|
+
const localDirListing = listLocalDirectory(localDirectoryPath);
|
|
130
|
+
for await (const localDirEntry of localDirListing) {
|
|
131
|
+
let entry: DirectoryEntry;
|
|
132
|
+
if (localDirEntry.type === "-") {
|
|
133
|
+
const putFileResponse = await rpcClient.call.v1.dbfs.fileContents.put({
|
|
134
|
+
contents: localDirEntry.contents.toString("base64"),
|
|
135
|
+
});
|
|
136
|
+
entry = {
|
|
137
|
+
type: "-",
|
|
138
|
+
hash: putFileResponse.data.hash,
|
|
139
|
+
executable: localDirEntry.executable,
|
|
140
|
+
name: localDirEntry.name,
|
|
141
|
+
};
|
|
142
|
+
} else if (localDirEntry.type === "d") {
|
|
143
|
+
const childHash = await doUploadLocalDirectory(
|
|
144
|
+
rpcClient,
|
|
145
|
+
localDirEntry.localPath,
|
|
146
|
+
);
|
|
147
|
+
entry = { type: "d", name: localDirEntry.name, hash: childHash };
|
|
148
|
+
} else if (localDirEntry.type === "l") {
|
|
149
|
+
entry = {
|
|
150
|
+
type: "l",
|
|
151
|
+
target: localDirEntry.target,
|
|
152
|
+
name: localDirEntry.name,
|
|
153
|
+
};
|
|
154
|
+
} else {
|
|
155
|
+
unreachable(localDirEntry);
|
|
156
|
+
}
|
|
157
|
+
directoryContents.push(entry);
|
|
158
|
+
}
|
|
159
|
+
const putDirResponse = await rpcClient.call.v1.dbfs.directoryContents.put({
|
|
160
|
+
contents: directoryContents,
|
|
161
|
+
});
|
|
162
|
+
return putDirResponse.data.hash;
|
|
163
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import watcher, { type FSWatcher } from "chokidar";
|
|
3
|
+
import { red } from "colorette";
|
|
4
|
+
import fs from "fs-extra";
|
|
5
|
+
import semver from "semver";
|
|
6
|
+
import { build } from "vite";
|
|
7
|
+
import { getLegacyComponentsConfig } from "./custom-config.mjs";
|
|
8
|
+
import type { Plugin, UserConfig, ViteDevServer } from "vite";
|
|
9
|
+
|
|
10
|
+
// we only need to build if not on React 18
|
|
11
|
+
export async function isCustomComponentsEnabled() {
|
|
12
|
+
try {
|
|
13
|
+
const packageJson = await fs.readJson(
|
|
14
|
+
path.join(process.cwd(), "custom", "package.json"),
|
|
15
|
+
);
|
|
16
|
+
const reactVersion =
|
|
17
|
+
packageJson.dependencies?.["react"] ||
|
|
18
|
+
packageJson.devDependencies?.["react"];
|
|
19
|
+
if (!reactVersion) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return semver.lt(semver.coerce(reactVersion)!, "18.0.0");
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function buildCustomComponents(config: UserConfig) {
|
|
29
|
+
try {
|
|
30
|
+
console.log("Building custom components...");
|
|
31
|
+
await build(config);
|
|
32
|
+
console.log("Custom components build complete");
|
|
33
|
+
return true;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error(red("Custom components build failed:"), "\n", error);
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let __watcher: FSWatcher | undefined;
|
|
41
|
+
|
|
42
|
+
async function watchCustomComponents(folder: string) {
|
|
43
|
+
if (__watcher) {
|
|
44
|
+
return __watcher;
|
|
45
|
+
}
|
|
46
|
+
__watcher = watcher.watch(folder, {
|
|
47
|
+
ignored: [/dist/, /node_modules/],
|
|
48
|
+
persistent: true,
|
|
49
|
+
ignoreInitial: true,
|
|
50
|
+
});
|
|
51
|
+
return __watcher;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function buildCustomComponentsProject() {
|
|
55
|
+
const customComponentsFolder = path.join(process.cwd(), "custom");
|
|
56
|
+
const config = getLegacyComponentsConfig(customComponentsFolder);
|
|
57
|
+
await buildCustomComponents(config);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// on file changes, we want to rebuild the custom components library
|
|
61
|
+
// and let our vite server process that the file as changed, which triggers HMR
|
|
62
|
+
// Related reading: https://vite.dev/changes/hotupdate-hook.html
|
|
63
|
+
// TODO: can we run a vite dev server instead of a vite build in order to use hotUpdate to get changes?
|
|
64
|
+
async function watchForChanges(server: ViteDevServer) {
|
|
65
|
+
const customComponentsFolder = path.join(process.cwd(), "custom");
|
|
66
|
+
const watcher = await watchCustomComponents(customComponentsFolder);
|
|
67
|
+
|
|
68
|
+
const handleChange = async (filePath: string) => {
|
|
69
|
+
// We need to rebuild the configuration to pick up on any file system changes
|
|
70
|
+
const config = getLegacyComponentsConfig(customComponentsFolder);
|
|
71
|
+
|
|
72
|
+
console.log(`Custom component file changed: ${filePath}`);
|
|
73
|
+
const url = path.relative(customComponentsFolder, filePath);
|
|
74
|
+
await buildCustomComponents(config);
|
|
75
|
+
|
|
76
|
+
const module = await server.moduleGraph.getModuleByUrl(
|
|
77
|
+
`/custom/dist/${url}`.replace(/\.tsx?$/, ".js"),
|
|
78
|
+
);
|
|
79
|
+
if (module) {
|
|
80
|
+
server.reloadModule(module);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
watcher.on("change", handleChange);
|
|
85
|
+
watcher.on("add", handleChange);
|
|
86
|
+
watcher.on("unlink", handleChange);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const customComponentsPlugin = (): Plugin => {
|
|
90
|
+
return {
|
|
91
|
+
enforce: "pre",
|
|
92
|
+
name: "custom-components",
|
|
93
|
+
// vite is calling this twice during the initial dev server start due to how remix loads
|
|
94
|
+
// configs via resolveConfig
|
|
95
|
+
async buildStart() {
|
|
96
|
+
const enabled = await isCustomComponentsEnabled();
|
|
97
|
+
if (!enabled) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
await buildCustomComponentsProject();
|
|
101
|
+
},
|
|
102
|
+
async configureServer(server) {
|
|
103
|
+
const enabled = await isCustomComponentsEnabled();
|
|
104
|
+
if (!enabled) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
await watchForChanges(server);
|
|
108
|
+
},
|
|
109
|
+
buildEnd() {
|
|
110
|
+
__watcher?.close();
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import glob from "fast-glob";
|
|
4
|
+
import { defineConfig } from "vite";
|
|
5
|
+
|
|
6
|
+
export function getLegacyComponentsConfig(componentsFolder: string) {
|
|
7
|
+
const entries = glob.sync("**/*.{jsx,tsx}", {
|
|
8
|
+
cwd: componentsFolder,
|
|
9
|
+
absolute: true,
|
|
10
|
+
ignore: ["node_modules/**", "dist/**"],
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const entryPoints = entries.reduce(
|
|
14
|
+
(acc, entry) => {
|
|
15
|
+
const relativePath = path.relative(path.join(componentsFolder), entry);
|
|
16
|
+
const entryName = relativePath.replace(/\.(jsx|tsx)$/, "");
|
|
17
|
+
acc[entryName] = relativePath;
|
|
18
|
+
return acc;
|
|
19
|
+
},
|
|
20
|
+
{} as Record<string, string>,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// we build a copy of react and react-dom because we need to import the old versions
|
|
24
|
+
// inside our vite plugins virtual wrapper
|
|
25
|
+
entryPoints["react"] = path.join(componentsFolder, "node_modules/react");
|
|
26
|
+
entryPoints["react-dom"] = path.join(
|
|
27
|
+
componentsFolder,
|
|
28
|
+
"node_modules/react-dom",
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return defineConfig({
|
|
32
|
+
root: componentsFolder,
|
|
33
|
+
logLevel: "warn",
|
|
34
|
+
resolve: {
|
|
35
|
+
preserveSymlinks: true,
|
|
36
|
+
alias: {
|
|
37
|
+
react: path.join(componentsFolder, "node_modules/react"),
|
|
38
|
+
"react-dom": path.join(componentsFolder, "node_modules/react-dom"),
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
build: {
|
|
42
|
+
sourcemap: true,
|
|
43
|
+
outDir: path.resolve(componentsFolder, "dist"),
|
|
44
|
+
lib: {
|
|
45
|
+
entry: entryPoints,
|
|
46
|
+
formats: ["es"],
|
|
47
|
+
fileName: (format, entryName) => `${entryName}.js`,
|
|
48
|
+
},
|
|
49
|
+
modulePreload: false,
|
|
50
|
+
minify: false,
|
|
51
|
+
rollupOptions: {
|
|
52
|
+
output: {
|
|
53
|
+
preserveModules: true,
|
|
54
|
+
preserveModulesRoot: ".",
|
|
55
|
+
entryFileNames: "[name].js",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
optimizeDeps: {
|
|
60
|
+
include: ["react", "react-dom"],
|
|
61
|
+
force: true,
|
|
62
|
+
},
|
|
63
|
+
// TODO(omar): there is a type mismatch in the monorepo
|
|
64
|
+
plugins: [react() as any],
|
|
65
|
+
});
|
|
66
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createLogger, format, transports } from "winston";
|
|
2
|
+
|
|
3
|
+
export type DevLogger = {
|
|
4
|
+
debug: (message: string, ...meta: any[]) => void;
|
|
5
|
+
info: (message: string, ...meta: any[]) => void;
|
|
6
|
+
warn: (message: string, ...meta: any[]) => void;
|
|
7
|
+
error: (message: string, ...meta: any[]) => void;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
const winstonLogger = createLogger({
|
|
11
|
+
level: "info",
|
|
12
|
+
exitOnError: false,
|
|
13
|
+
format: format.json(),
|
|
14
|
+
transports: [
|
|
15
|
+
new transports.File({ filename: `/tmp/dev-server.log`, level: "info" }),
|
|
16
|
+
new transports.Console({
|
|
17
|
+
format: format.combine(
|
|
18
|
+
format.printf(({ message }) => `${message}`),
|
|
19
|
+
format.colorize({ message: true }),
|
|
20
|
+
),
|
|
21
|
+
level: "debug",
|
|
22
|
+
}),
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export function getLogger(
|
|
27
|
+
loggerOverride?: (message: string) => void,
|
|
28
|
+
): DevLogger {
|
|
29
|
+
if (!loggerOverride) {
|
|
30
|
+
return winstonLogger;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
debug: loggerOverride,
|
|
35
|
+
info: loggerOverride,
|
|
36
|
+
warn: loggerOverride,
|
|
37
|
+
error: loggerOverride,
|
|
38
|
+
};
|
|
39
|
+
}
|