attio 0.0.1-experimental.20240911.2 → 0.0.1-experimental.20240913
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/lib/build/client/create-client-build-config.js +3 -7
- package/lib/build/client/generate-client-entry.js +29 -2
- package/lib/build/server/create-server-build-config.js +3 -7
- package/lib/build/server/generate-server-entry.js +61 -27
- package/lib/machines/dev-machine.js +1 -1
- package/lib/machines/js-machine.js +77 -10
- package/package.json +1 -1
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import globalExternals from "@fal-works/esbuild-plugin-global-externals";
|
|
2
2
|
import { proxyServerModulesPlugin } from "../proxy-server-modules-plugin.js";
|
|
3
|
-
export function createClientBuildConfig({ appDir,
|
|
3
|
+
export function createClientBuildConfig({ appDir, entryPoint, }) {
|
|
4
4
|
return {
|
|
5
|
-
|
|
6
|
-
contents,
|
|
7
|
-
resolveDir: ".",
|
|
8
|
-
loader: "tsx",
|
|
9
|
-
},
|
|
5
|
+
entryPoints: [entryPoint],
|
|
10
6
|
logLevel: "silent",
|
|
11
7
|
bundle: true,
|
|
12
8
|
platform: "browser",
|
|
@@ -14,7 +10,7 @@ export function createClientBuildConfig({ appDir, contents, }) {
|
|
|
14
10
|
plugins: [
|
|
15
11
|
globalExternals({
|
|
16
12
|
"react": "React",
|
|
17
|
-
"
|
|
13
|
+
"attio/client": {
|
|
18
14
|
varName: "ATTIO_CLIENT_EXTENSION_SDK",
|
|
19
15
|
type: "cjs",
|
|
20
16
|
},
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import fs from "fs/promises";
|
|
1
2
|
import { glob } from "glob";
|
|
2
3
|
import path from "path";
|
|
3
4
|
const ROUTE_FILE_EXTENSIONS = ["tsx", "jsx", "ts", "js"];
|
|
4
|
-
|
|
5
|
+
const ASSET_FILE_EXTENSIONS = ["png"];
|
|
6
|
+
export async function generateClientEntry({ filePath, appDir, assetsDir, routes, log, }) {
|
|
5
7
|
log?.(`💥 Found entry point at ${path.resolve(appDir)}`);
|
|
6
8
|
const paths = routes.flatMap((route) => ROUTE_FILE_EXTENSIONS.map((fileExtension) => route + "." + fileExtension));
|
|
7
9
|
const concreteRoutes = (await Promise.all(paths.map(async (path) => {
|
|
@@ -22,11 +24,36 @@ export async function generateClientEntry({ appDir, routes, log, }) {
|
|
|
22
24
|
return [];
|
|
23
25
|
}
|
|
24
26
|
}))).flat();
|
|
27
|
+
let assetFiles;
|
|
28
|
+
try {
|
|
29
|
+
assetFiles = await fs.readdir(assetsDir, { recursive: true });
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
assetFiles = [];
|
|
33
|
+
}
|
|
34
|
+
const assets = assetFiles
|
|
35
|
+
.filter((relativeAssetPath) => ASSET_FILE_EXTENSIONS.some((extension) => relativeAssetPath.endsWith(extension)))
|
|
36
|
+
.map((relativeAssetPath) => ({
|
|
37
|
+
path: path.join(assetsDir, relativeAssetPath),
|
|
38
|
+
name: relativeAssetPath,
|
|
39
|
+
}));
|
|
25
40
|
return `
|
|
26
41
|
${concreteRoutes
|
|
27
|
-
.map((routeAndPath, index) => `import C${index} from ${JSON.stringify(
|
|
42
|
+
.map((routeAndPath, index) => `import C${index} from ${JSON.stringify(path.relative(filePath, path.join(appDir, routeAndPath.path)))}`)
|
|
28
43
|
.join("\n")}
|
|
29
44
|
|
|
45
|
+
const assets = []
|
|
46
|
+
|
|
47
|
+
${assets
|
|
48
|
+
.map((asset, index) => `
|
|
49
|
+
import A${index} from ${JSON.stringify(path.relative(filePath, asset.path))};
|
|
50
|
+
|
|
51
|
+
assets.push({name: ${JSON.stringify(asset.name)}, data: A${index}})
|
|
52
|
+
`)
|
|
53
|
+
.join("\n")}
|
|
54
|
+
|
|
55
|
+
registerAssets(assets)
|
|
56
|
+
|
|
30
57
|
${concreteRoutes
|
|
31
58
|
.map((routeAndPath, index) => `registerExtensionComponent({route: ${JSON.stringify(routeAndPath.route)}, component: C${index}})`)
|
|
32
59
|
.join("\n")}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import globalExternals from "@fal-works/esbuild-plugin-global-externals";
|
|
2
|
-
export function createServerBuildConfig(
|
|
2
|
+
export function createServerBuildConfig(entryPoint) {
|
|
3
3
|
return {
|
|
4
|
-
|
|
5
|
-
contents,
|
|
6
|
-
resolveDir: ".",
|
|
7
|
-
loader: "ts",
|
|
8
|
-
},
|
|
4
|
+
entryPoints: [entryPoint],
|
|
9
5
|
bundle: true,
|
|
10
6
|
platform: "browser",
|
|
11
7
|
format: "esm",
|
|
12
8
|
plugins: [
|
|
13
9
|
globalExternals({
|
|
14
|
-
"
|
|
10
|
+
"attio/client": {
|
|
15
11
|
varName: "ATTIO_CLIENT_EXTENSION_SDK",
|
|
16
12
|
type: "cjs",
|
|
17
13
|
},
|
|
@@ -1,55 +1,89 @@
|
|
|
1
1
|
import { glob } from "glob";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { getModuleHash } from "../get-module-hash.js";
|
|
4
|
-
export async function generateServerEntry({ appDir, log, }) {
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
export async function generateServerEntry({ appDir, webhooksDir, filePath, log, }) {
|
|
5
|
+
const [serverFunctionConcretePaths, webhookConcretePaths] = await Promise.all([
|
|
6
|
+
Promise.all([
|
|
7
|
+
glob("**/*.server.ts", { nodir: true, cwd: appDir }),
|
|
8
|
+
glob("**/*.server.js", { nodir: true, cwd: appDir }),
|
|
9
|
+
]).then((paths) => paths.flat()),
|
|
10
|
+
Promise.all([
|
|
11
|
+
glob("**/*.webhook.ts", { nodir: true, cwd: webhooksDir }),
|
|
12
|
+
glob("**/*.webhook.js", { nodir: true, cwd: webhooksDir }),
|
|
13
|
+
]).then((paths) => paths.flat()),
|
|
14
|
+
]);
|
|
15
|
+
const serverFunctionModules = serverFunctionConcretePaths.map((path) => ({
|
|
10
16
|
path,
|
|
11
17
|
hash: getModuleHash(path.replace(/\.(js|ts)$/, "")),
|
|
12
18
|
}));
|
|
13
|
-
|
|
19
|
+
const webhookModules = webhookConcretePaths.map((path) => ({
|
|
20
|
+
path,
|
|
21
|
+
id: path.replace(/\.webhook\.(js|ts)$/, ""),
|
|
22
|
+
}));
|
|
23
|
+
for (const module of serverFunctionModules) {
|
|
14
24
|
log?.(`🔎 Found server module "${module.path}"`);
|
|
15
25
|
}
|
|
16
26
|
return `
|
|
17
27
|
|
|
18
28
|
const modules = new Map()
|
|
19
|
-
|
|
29
|
+
const webhookModules = new Map()
|
|
20
30
|
|
|
21
31
|
|
|
22
|
-
${
|
|
23
|
-
.map((module) => `modules.set("${module.hash}", () => import(${JSON.stringify(
|
|
32
|
+
${serverFunctionModules
|
|
33
|
+
.map((module) => `modules.set("${module.hash}", () => import(${JSON.stringify(path.relative(filePath, path.join(appDir, module.path)))}))`)
|
|
24
34
|
.join("\n")}
|
|
25
35
|
|
|
36
|
+
${webhookModules
|
|
37
|
+
.map((module) => `webhookModules.set("${module.id}", () => import(${JSON.stringify(path.relative(filePath, path.join(webhooksDir, module.path)))}))`)
|
|
38
|
+
.join("\n")}
|
|
26
39
|
|
|
27
|
-
var stdin_default;
|
|
28
|
-
|
|
29
|
-
|
|
40
|
+
var stdin_default;
|
|
41
|
+
var stdin_webhooks_default;
|
|
42
|
+
function main() {
|
|
43
|
+
stdin_default = async function(moduleHash, args) {
|
|
44
|
+
const module = modules.get(moduleHash)
|
|
30
45
|
|
|
46
|
+
if (!module) {
|
|
47
|
+
throw new Error(\`Module \${moduleHash} not found\`)
|
|
48
|
+
}
|
|
31
49
|
|
|
32
|
-
|
|
50
|
+
const func = (await module()).default
|
|
33
51
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
52
|
+
if (!func) {
|
|
53
|
+
throw new Error(\`Default export not found in module \${moduleHash}\`)
|
|
54
|
+
}
|
|
37
55
|
|
|
38
|
-
|
|
56
|
+
if (typeof func !== "function") {
|
|
57
|
+
throw new Error(\`\${moduleHash} does not export a function\`)
|
|
58
|
+
}
|
|
39
59
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
60
|
+
return func(...args)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
stdin_webhooks_default = async function(webhookModuleId, args) {
|
|
64
|
+
const module = webhookModules.get(webhookModuleId)
|
|
43
65
|
|
|
44
|
-
|
|
45
|
-
|
|
66
|
+
if (!module) {
|
|
67
|
+
throw new Error(\`Webhook handler not found: \${webhookModuleId}\`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const func = (await module()).default
|
|
71
|
+
|
|
72
|
+
if (!func) {
|
|
73
|
+
throw new Error(\`Default export not found in module \${webhookModuleId}\`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (typeof func !== "function") {
|
|
77
|
+
throw new Error(\`\${webhookModuleId} does not export a function\`)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return func(...args)
|
|
81
|
+
}
|
|
46
82
|
}
|
|
47
83
|
|
|
48
|
-
return func(...args)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
84
|
|
|
52
|
-
|
|
85
|
+
|
|
86
|
+
main()
|
|
53
87
|
|
|
54
88
|
`;
|
|
55
89
|
}
|
|
@@ -93,7 +93,7 @@ export const devMachine = setup({
|
|
|
93
93
|
upload().catch((error) => sendBack({ type: "Upload Error", error }));
|
|
94
94
|
}),
|
|
95
95
|
watch: fromCallback(({ sendBack }) => {
|
|
96
|
-
const watcher = chokidar.watch("src/app");
|
|
96
|
+
const watcher = chokidar.watch(["src/app", "src/assets", "src/webhooks"]);
|
|
97
97
|
watcher.on("ready", () => watcher.on("all", () => {
|
|
98
98
|
sendBack({ type: "Change" });
|
|
99
99
|
}));
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as esbuild from "esbuild";
|
|
2
|
+
import fs from "fs/promises";
|
|
2
3
|
import path from "path";
|
|
4
|
+
import tmp from "tmp-promise";
|
|
3
5
|
import { assign, setup, fromCallback, sendTo } from "xstate";
|
|
4
6
|
import { ROUTES, errorSchema } from "../build.js";
|
|
5
7
|
import { createClientBuildConfig } from "../build/client/create-client-build-config.js";
|
|
@@ -20,20 +22,85 @@ export const jsMachine = setup({
|
|
|
20
22
|
let buildContexts;
|
|
21
23
|
const prepare = async () => {
|
|
22
24
|
const appDir = "src/app";
|
|
25
|
+
const assetsDir = "src/assets";
|
|
26
|
+
const webhooksDir = "src/webhooks";
|
|
23
27
|
const log = (message) => {
|
|
24
28
|
sendBack({ type: "Log", message });
|
|
25
29
|
};
|
|
26
30
|
buildContexts = (await Promise.all([
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
tmp.file({ postfix: ".js" }).then(async (tempFile) => {
|
|
32
|
+
let lastJS;
|
|
33
|
+
const updateTempFile = async () => {
|
|
34
|
+
const js = await generateClientEntry({
|
|
35
|
+
filePath: tempFile.path,
|
|
36
|
+
appDir,
|
|
37
|
+
assetsDir,
|
|
38
|
+
routes: ROUTES,
|
|
39
|
+
log,
|
|
40
|
+
});
|
|
41
|
+
if (js === lastJS) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
lastJS = js;
|
|
45
|
+
await fs.writeFile(tempFile.path, js);
|
|
46
|
+
};
|
|
47
|
+
await updateTempFile();
|
|
48
|
+
const esbuildContext = await esbuild.context({
|
|
49
|
+
...createClientBuildConfig({
|
|
50
|
+
entryPoint: tempFile.path,
|
|
51
|
+
appDir,
|
|
52
|
+
}),
|
|
53
|
+
write,
|
|
54
|
+
outfile: path.resolve("dist", "index.js"),
|
|
55
|
+
loader: { ".png": "dataurl" },
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
rebuild: async () => {
|
|
59
|
+
await updateTempFile();
|
|
60
|
+
return esbuildContext.rebuild();
|
|
61
|
+
},
|
|
62
|
+
dispose: async () => {
|
|
63
|
+
await Promise.all([
|
|
64
|
+
esbuildContext.dispose(),
|
|
65
|
+
tempFile.cleanup(),
|
|
66
|
+
]);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}),
|
|
70
|
+
tmp.file({ postfix: ".js" }).then(async (tempFile) => {
|
|
71
|
+
let lastJS;
|
|
72
|
+
const updateTempFile = async () => {
|
|
73
|
+
const js = await generateServerEntry({
|
|
74
|
+
filePath: tempFile.path,
|
|
75
|
+
appDir,
|
|
76
|
+
webhooksDir,
|
|
77
|
+
log,
|
|
78
|
+
});
|
|
79
|
+
if (js === lastJS) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
lastJS = js;
|
|
83
|
+
await fs.writeFile(tempFile.path, js);
|
|
84
|
+
};
|
|
85
|
+
await updateTempFile();
|
|
86
|
+
const esbuildContext = await esbuild.context({
|
|
87
|
+
...createServerBuildConfig(tempFile.path),
|
|
88
|
+
write,
|
|
89
|
+
outfile: path.resolve("dist", "server.js"),
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
rebuild: async () => {
|
|
93
|
+
await updateTempFile();
|
|
94
|
+
return esbuildContext.rebuild();
|
|
95
|
+
},
|
|
96
|
+
dispose: async () => {
|
|
97
|
+
await Promise.all([
|
|
98
|
+
esbuildContext.dispose(),
|
|
99
|
+
tempFile.cleanup(),
|
|
100
|
+
]);
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}),
|
|
37
104
|
])).flat();
|
|
38
105
|
sendBack({
|
|
39
106
|
type: "Build Contexts Prepared",
|