diff --git a/src/Sekiban.Infrastructure.IndexedDb/Runtime/Runtime.code-workspace b/src/Sekiban.Infrastructure.IndexedDb/Runtime/Runtime.code-workspace
index 0bca7b3c..a56b5182 100644
--- a/src/Sekiban.Infrastructure.IndexedDb/Runtime/Runtime.code-workspace
+++ b/src/Sekiban.Infrastructure.IndexedDb/Runtime/Runtime.code-workspace
@@ -13,6 +13,14 @@
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
},
+ "[javascript]": {
+ "editor.codeActionsOnSave": {
+ "source.fixAll": "explicit",
+ "source.organizeImports": "explicit",
+ },
+ "editor.defaultFormatter": "biomejs.biome",
+ "editor.formatOnSave": true,
+ },
"[json]": {
"editor.defaultFormatter": "vscode.json-language-features",
},
diff --git a/src/Sekiban.Infrastructure.IndexedDb/Runtime/build.js b/src/Sekiban.Infrastructure.IndexedDb/Runtime/build.js
new file mode 100644
index 00000000..a0d52d98
--- /dev/null
+++ b/src/Sekiban.Infrastructure.IndexedDb/Runtime/build.js
@@ -0,0 +1,67 @@
+// @ts-check
+
+import child_process from "node:child_process";
+import fs from "node:fs/promises";
+import process from "node:process";
+
+const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
+
+const obtainLock = async () => {
+ try {
+ await fs.mkdir("build-lock");
+ return true;
+ } catch (e) {
+ if (e.code === "EEXIST") {
+ return false;
+ }
+
+ throw new Error(e.message, { cause: e });
+ }
+};
+
+const releaseLock = async () => await fs.rmdir("build-lock");
+
+const waitAnotherBuild = async () => {
+ while (true) {
+ await sleep(1000);
+
+ try {
+ await fs.stat("build-lock");
+ } catch (e) {
+ if (e.code === "ENOENT") {
+ return;
+ }
+
+ throw new Error(e.message, { cause: e });
+ }
+ }
+};
+
+const main = async () => {
+ if (!(await obtainLock())) {
+ // An another build task is running concurrently.
+ // Wait until it done.
+ await waitAnotherBuild();
+ process.exit(0);
+ }
+
+ try {
+ const restore = child_process.spawnSync("npm", ["install"], {
+ stdio: "inherit",
+ });
+ if (restore.status !== 0) {
+ process.exit(restore.status);
+ }
+
+ const build = child_process.spawnSync("npm", ["run", "build"], {
+ stdio: "inherit",
+ });
+ if (build.status !== 0) {
+ process.exit(build.status);
+ }
+ } finally {
+ await releaseLock();
+ }
+};
+
+main();
diff --git a/src/Sekiban.Infrastructure.IndexedDb/Sekiban.Infrastructure.IndexedDb.csproj b/src/Sekiban.Infrastructure.IndexedDb/Sekiban.Infrastructure.IndexedDb.csproj
index 3a004aee..ef2908c1 100644
--- a/src/Sekiban.Infrastructure.IndexedDb/Sekiban.Infrastructure.IndexedDb.csproj
+++ b/src/Sekiban.Infrastructure.IndexedDb/Sekiban.Infrastructure.IndexedDb.csproj
@@ -40,9 +40,8 @@
-
-
-
+
+