Browse Source

refactor: flatten the monorepo

Eric Dubé 11 months ago
parent
commit
fa7bec3854
38 changed files with 218 additions and 340 deletions
  1. 29 1
      package-lock.json
  2. 1 2
      package.json
  3. 0 23
      packages/backend/packages/puter-js-common/index.js
  4. 0 11
      packages/backend/packages/puter-js-common/package.json
  5. 0 33
      packages/backend/packages/puter-js-common/src/AdvancedBase.js
  6. 0 55
      packages/backend/packages/puter-js-common/src/bases/BasicBase.js
  7. 0 41
      packages/backend/packages/puter-js-common/src/bases/TraitBase.js
  8. 0 59
      packages/backend/packages/puter-js-common/src/traits/NodeModuleDITrait.js
  9. 0 38
      packages/backend/packages/puter-js-common/src/traits/PropertiesTrait.js
  10. 0 72
      packages/backend/packages/puter-js-common/test/test.js
  11. 0 0
      packages/contextlink/.gitignore
  12. 0 0
      packages/contextlink/context.js
  13. 0 0
      packages/contextlink/entry.js
  14. 0 0
      packages/contextlink/package-lock.json
  15. 0 0
      packages/contextlink/package.json
  16. 0 0
      packages/contextlink/test/testcontext.js
  17. 2 0
      packages/git/rollup.config.js
  18. 4 1
      packages/phoenix/rollup.config.js
  19. 4 3
      packages/pty/exports.js
  20. 0 0
      packages/pty/package.json
  21. 0 0
      packages/puter-js-common/README.md
  22. 3 0
      packages/puter-js-common/index.js
  23. 171 0
      packages/puter-js-common/src/libs/promise.js
  24. 0 0
      packages/strataparse/dsl/ParserBuilder.js
  25. 0 0
      packages/strataparse/dsl/ParserRegistry.js
  26. 0 0
      packages/strataparse/exports.js
  27. 0 0
      packages/strataparse/package.json
  28. 0 0
      packages/strataparse/parse.js
  29. 0 0
      packages/strataparse/parse_impls/StrUntilParserImpl.js
  30. 0 0
      packages/strataparse/parse_impls/combinators.js
  31. 0 0
      packages/strataparse/parse_impls/literal.js
  32. 0 0
      packages/strataparse/parse_impls/whitespace.js
  33. 0 0
      packages/strataparse/strata.js
  34. 0 0
      packages/strataparse/strata_impls/ContextSwitchingPStratumImpl.js
  35. 0 0
      packages/strataparse/strata_impls/FirstRecognizedPStratumImpl.js
  36. 0 0
      packages/strataparse/strata_impls/MergeWhitespacePStratumImpl.js
  37. 0 0
      packages/strataparse/strata_impls/terminals.js
  38. 4 1
      packages/terminal/rollup.config.js

+ 29 - 1
package-lock.json

@@ -7,12 +7,12 @@
     "": {
       "name": "puter.com",
       "version": "2.3.0",
-      "hasInstallScript": true,
       "license": "AGPL-3.0-only",
       "workspaces": [
         "packages/*"
       ],
       "dependencies": {
+        "@xterm/xterm": "^5.5.0",
         "json-colorizer": "^3.0.1",
         "uuid": "^9.0.1"
       },
@@ -5456,6 +5456,10 @@
         "node": ">= 0.6"
       }
     },
+    "node_modules/contextlink": {
+      "resolved": "packages/contextlink",
+      "link": true
+    },
     "node_modules/convert-source-map": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
@@ -5789,6 +5793,10 @@
         "node": ">=8"
       }
     },
+    "node_modules/dev-pty": {
+      "resolved": "packages/pty",
+      "link": true
+    },
     "node_modules/diff": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
@@ -10712,6 +10720,10 @@
         "node": ">= 0.8"
       }
     },
+    "node_modules/strataparse": {
+      "resolved": "packages/strataparse",
+      "link": true
+    },
     "node_modules/streamsearch": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
@@ -12061,6 +12073,13 @@
         "typescript": "^5.1.6"
       }
     },
+    "packages/contextlink": {
+      "version": "0.0.0",
+      "license": "AGPL-3.0-only",
+      "devDependencies": {
+        "mocha": "^10.2.0"
+      }
+    },
     "packages/git": {
       "version": "1.0.0",
       "license": "AGPL-3.0-only",
@@ -12312,6 +12331,11 @@
       "extraneous": true,
       "license": "AGPL-3.0-only"
     },
+    "packages/pty": {
+      "name": "dev-pty",
+      "version": "0.0.0",
+      "license": "AGPL-3.0-only"
+    },
     "packages/puter-js": {
       "name": "@heyputer/puterjs",
       "version": "1.0.0",
@@ -12326,6 +12350,10 @@
       "version": "1.0.0",
       "license": "UNLICENSED"
     },
+    "packages/strataparse": {
+      "version": "0.0.0",
+      "license": "AGPL-3.0-only"
+    },
     "packages/terminal": {
       "name": "@heyputer/terminal",
       "version": "0.0.0",

+ 1 - 2
package.json

@@ -29,8 +29,7 @@
     "start=gui": "nodemon --exec \"node dev-server.js\" ",
     "start": "node run-selfhosted.js",
     "build": "node ./build.js",
-    "check-translations": "node tools/check-translations.js",
-    "postinstall": "cd packages/phoenix && cd packages/contextlink && npm install && cd - && cd packages/strataparse && npm install && cd - && cd packages/pty && npm install"
+    "check-translations": "node tools/check-translations.js"
   },
   "workspaces": [
     "packages/*"

+ 0 - 23
packages/backend/packages/puter-js-common/index.js

@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-const { AdvancedBase } = require('./src/AdvancedBase');
-
-module.exports = {
-    AdvancedBase,
-};

+ 0 - 11
packages/backend/packages/puter-js-common/package.json

@@ -1,11 +0,0 @@
-{
-  "name": "@heyputer/puter-js-common",
-  "version": "1.0.0",
-  "description": "",
-  "main": "index.js",
-  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
-  },
-  "author": "Puter Technologies Inc.",
-  "license": "UNLICENSED"
-}

+ 0 - 33
packages/backend/packages/puter-js-common/src/AdvancedBase.js

@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-// This doesn't go in ./bases because it logically depends on
-// both ./bases and ./traits, and ./traits depends on ./bases.
-
-const { TraitBase } = require("./bases/TraitBase");
-
-class AdvancedBase extends TraitBase {
-    static TRAITS = [
-        require('./traits/NodeModuleDITrait'),
-        require('./traits/PropertiesTrait'),
-    ]
-}
-
-module.exports = {
-    AdvancedBase,
-};

+ 0 - 55
packages/backend/packages/puter-js-common/src/bases/BasicBase.js

@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-class BasicBase {
-    _get_inheritance_chain () {
-        const chain = [];
-        let cls = this.constructor;
-        while ( cls && cls !== BasicBase ) {
-            chain.push(cls);
-            cls = cls.__proto__;
-        }
-        return chain.reverse();
-    }
-
-    _get_merged_static_array (key) {
-        const chain = this._get_inheritance_chain();
-        const values = [];
-        for ( const cls of chain ) {
-            if ( cls[key] ) {
-                values.push(...cls[key]);
-            }
-        }
-        return values;
-    }
-
-    _get_merged_static_object (key) {
-        const chain = this._get_inheritance_chain();
-        const values = {};
-        for ( const cls of chain ) {
-            if ( cls[key] ) {
-                Object.assign(values, cls[key]);
-            }
-        }
-        return values;
-    }
-}
-
-module.exports = {
-    BasicBase,
-};

+ 0 - 41
packages/backend/packages/puter-js-common/src/bases/TraitBase.js

@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-const { BasicBase } = require("./BasicBase");
-
-class TraitBase extends BasicBase {
-    constructor (parameters, ...a) {
-        super(parameters, ...a);
-        for ( const trait of this.traits ) {
-            trait.install_in_instance(
-                this,
-                {
-                    parameters: parameters || {},
-                }
-            )
-        }
-    }
-
-    get traits () {
-        return this._get_merged_static_array('TRAITS');
-    }
-}
-
-module.exports = {
-    TraitBase,
-};

+ 0 - 59
packages/backend/packages/puter-js-common/src/traits/NodeModuleDITrait.js

@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-/**
- * This trait allows dependency injection of node modules.
- * This is incredibly useful for passing mock implementations
- * of modules for unit testing.
- *
- * @example
- * class MyClass extends AdvancedBase {
- *   static MODULES = {
- *     axios,
- *   };
- * }
- *
- * const my_class = new MyClass({
- *   modules: {
- *     axios: MY_AXIOS_MOCK,
- *   }
- * });
- */
-module.exports = {
-    install_in_instance: (instance, { parameters }) => {
-        const modules = instance._get_merged_static_object('MODULES');
-
-        if ( parameters.modules ) {
-            for ( const k in parameters.modules ) {
-                modules[k] = parameters.modules[k];
-            }
-        }
-
-        instance.modules = modules;
-
-        // This "require" function can shadow the real one so
-        // that editor tools are aware of the modules that
-        // are being used.
-        instance.require = (name) => {
-            if ( modules[name] ) {
-                return modules[name];
-            }
-            return require(name);
-        }
-    },
-};

+ 0 - 38
packages/backend/packages/puter-js-common/src/traits/PropertiesTrait.js

@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-module.exports = {
-    install_in_instance: (instance) => {
-        const properties = instance._get_merged_static_object('PROPERTIES');
-
-        for ( const k in properties ) {
-            if ( typeof properties[k] === 'function' ) {
-                instance[k] = properties[k]();
-                continue;
-            }
-
-            if ( typeof properties[k] === 'object' ) {
-                // This will be supported in the future.
-                throw new Error(`Property ${k} in ${instance.constructor.name} ` +
-                    `is not a supported property specification.`);
-            }
-
-            instance[k] = properties[k];
-        }
-    }
-}

+ 0 - 72
packages/backend/packages/puter-js-common/test/test.js

@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2024 Puter Technologies Inc.
- *
- * This file is part of Puter.
- *
- * Puter is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-const { expect } = require('chai');
-const { BasicBase } = require('../src/bases/BasicBase');
-const { AdvancedBase } = require('../src/AdvancedBase');
-
-class ClassA extends BasicBase {
-    static STATIC_OBJ = {
-        a: 1,
-        b: 2,
-    };
-    static STATIC_ARR = ['a', 'b'];
-}
-
-class ClassB extends ClassA {
-    static STATIC_OBJ = {
-        c: 3,
-        d: 4,
-    };
-    static STATIC_ARR = ['c', 'd'];
-}
-
-describe('testing', () => {
-    it('does a thing', () => {
-        const b = new ClassB();
-    
-        console.log(b._get_inheritance_chain());
-        console.log([ClassA, ClassB]);
-        expect(b._get_inheritance_chain()).deep.equal([ClassA, ClassB]);
-        expect(b._get_merged_static_array('STATIC_ARR'))
-            .deep.equal(['a', 'b', 'c', 'd']);
-        expect(b._get_merged_static_object('STATIC_OBJ'))
-            .deep.equal({ a: 1, b: 2, c: 3, d: 4 });
-    });
-});
-
-class ClassWithModule extends AdvancedBase {
-    static MODULES = {
-        axios: 'axios',
-    };
-}
-
-describe('AdvancedBase', () => {
-    it('passes DI modules to instance', () => {
-        const c1 = new ClassWithModule();
-        expect(c1.modules.axios).to.equal('axios');
-
-        const c2 = new ClassWithModule({
-            modules: {
-                axios: 'my-axios',
-            },
-        });
-        expect(c2.modules.axios).to.equal('my-axios');
-    });
-});
-

+ 0 - 0
packages/phoenix/packages/contextlink/.gitignore → packages/contextlink/.gitignore


+ 0 - 0
packages/phoenix/packages/contextlink/context.js → packages/contextlink/context.js


+ 0 - 0
packages/phoenix/packages/contextlink/entry.js → packages/contextlink/entry.js


+ 0 - 0
packages/phoenix/packages/contextlink/package-lock.json → packages/contextlink/package-lock.json


+ 0 - 0
packages/phoenix/packages/contextlink/package.json → packages/contextlink/package.json


+ 0 - 0
packages/phoenix/packages/contextlink/test/testcontext.js → packages/contextlink/test/testcontext.js


+ 2 - 0
packages/git/rollup.config.js

@@ -20,6 +20,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
 import commonjs from '@rollup/plugin-commonjs';
 import copy from 'rollup-plugin-copy';
 import process from 'node:process';
+import path from 'node:path';
 
 const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
 await import(`./${configFile}`);
@@ -34,6 +35,7 @@ export default {
         nodeResolve({
             browser: true,
             preferBuiltins: false,
+            rootDir: path.join(process.cwd(), '..'),
         }),
         commonjs(),
         copy({

+ 4 - 1
packages/phoenix/rollup.config.js

@@ -20,6 +20,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
 import commonjs from '@rollup/plugin-commonjs';
 import copy from 'rollup-plugin-copy';
 import process from 'node:process';
+import path from 'node:path';
 
 const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
 await import(`./${configFile}`);
@@ -31,7 +32,9 @@ export default {
         format: "iife"
     },
     plugins: [
-        nodeResolve(),
+        nodeResolve({
+            rootDir: path.join(process.cwd(), '..'),
+        }),
         commonjs(),
         copy({
             targets: [

+ 4 - 3
packages/phoenix/packages/pty/exports.js → packages/pty/exports.js

@@ -16,7 +16,8 @@
  * You should have received a copy of the GNU Affero General Public License
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
-import { TeePromise, raceCase } from '../../src/promise.js';
+import { libs } from '@heyputer/puter-js-common';
+const { TeePromise, raceCase } = libs.promise;
 
 const encoder = new TextEncoder();
 
@@ -187,7 +188,7 @@ export class BetterReader {
                 }
                 if ( which === 'cancel' ) {
                     this.channel_.pushback(...chunks);
-                    return 
+                    return
                 }
                 if ( n_read + chunk.length > opt_buffer.length ) {
                     const diff = opt_buffer.length - n_read;
@@ -320,7 +321,7 @@ export class PTT {
 
 /**
  * PTY: pseudo-terminal
- * 
+ *
  * This implements the PTY device driver.
  */
 export class PTY {

+ 0 - 0
packages/phoenix/packages/pty/package.json → packages/pty/package.json


+ 0 - 0
packages/backend/packages/puter-js-common/README.md → packages/puter-js-common/README.md


+ 3 - 0
packages/puter-js-common/index.js

@@ -2,4 +2,7 @@ const { AdvancedBase } = require('./src/AdvancedBase');
 
 module.exports = {
     AdvancedBase,
+    libs: {
+        promise: require('./src/libs/promise'),
+    },
 };

+ 171 - 0
packages/puter-js-common/src/libs/promise.js

@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2024 Puter Technologies Inc.
+ *
+ * This file is part of Puter.
+ *
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+class TeePromise {
+    static STATUS_PENDING = Symbol('pending');
+    static STATUS_RUNNING = {};
+    static STATUS_DONE = Symbol('done');
+    constructor () {
+        this.status_ = this.constructor.STATUS_PENDING;
+        this.donePromise = new Promise((resolve, reject) => {
+            this.doneResolve = resolve;
+            this.doneReject = reject;
+        });
+    }
+    get status () {
+        return this.status_;
+    }
+    set status (status) {
+        this.status_ = status;
+        if ( status === this.constructor.STATUS_DONE ) {
+            this.doneResolve();
+        }
+    }
+    resolve (value) {
+        this.status_ = this.constructor.STATUS_DONE;
+        this.doneResolve(value);
+    }
+    awaitDone () {
+        return this.donePromise;
+    }
+    then (fn, ...a) {
+        return this.donePromise.then(fn, ...a);
+    }
+
+    reject (err) {
+        this.status_ = this.constructor.STATUS_DONE;
+        this.doneReject(err);
+    }
+
+    /**
+     * @deprecated use then() instead
+     */
+    onComplete(fn) {
+        return this.then(fn);
+    }
+}
+
+class Lock {
+    constructor() {
+        this._locked = false;
+        this._waiting = [];
+    }
+
+    async acquire(callback) {
+        await new Promise(resolve => {
+            if ( ! this._locked ) {
+                this._locked = true;
+                resolve();
+            } else {
+                this._waiting.push({
+                    resolve,
+                });
+            }
+        })
+        if ( callback ) {
+            let retval;
+            try {
+                retval = await callback();
+            } finally {
+                this.release();
+            }
+            return retval;
+        }
+    }
+
+    release() {
+        if (this._waiting.length > 0) {
+            const { resolve } = this._waiting.shift();
+            resolve();
+        } else {
+            this._locked = false;
+        }
+    }
+}
+
+/**
+ * @callback behindScheduleCallback
+ * @param {number} drift - The number of milliseconds that the callback was
+ *    called behind schedule.
+ * @returns {boolean} - If the callback returns true, the timer will be
+ *   cancelled.
+ */
+
+/**
+ * When passing an async callback to setInterval, it's possible for the
+ * callback to be called again before the previous invocation has finished.
+ *
+ * This function wraps setInterval and ensures that the callback is not
+ * called again until the previous invocation has finished.
+ *
+ * @param {Function} callback - The function to call when the timer elapses.
+ * @param {number} delay - The minimum number of milliseconds between invocations.
+ * @param {?Array<any>} args - Additional arguments to pass to setInterval.
+ * @param {?Object} options - Additional options.
+ * @param {behindScheduleCallback} options.onBehindSchedule - A callback to call when the callback is called behind schedule.
+ */
+const asyncSafeSetInterval = async (callback, delay, args, options) => {
+    args = args ?? [];
+    options = options ?? {};
+    const { onBehindSchedule } = options;
+
+    const sleep = (ms) => new Promise(rslv => setTimeout(rslv, ms));
+
+    for ( ;; ) {
+        await sleep(delay);
+
+        const ts_start = Date.now();
+        await callback(...args);
+        const ts_end = Date.now();
+
+        const runtime = ts_end - ts_start;
+        const sleep_time = delay - runtime;
+
+        if ( sleep_time < 0 ) {
+            if ( onBehindSchedule ) {
+                const cancel = await onBehindSchedule(-sleep_time);
+                if ( cancel ) {
+                    return;
+                }
+            }
+        } else {
+            await sleep(sleep_time);
+        }
+    }
+}
+
+/**
+ * raceCase is like Promise.race except it takes an object instead of
+ * an array, and returns the key of the promise that resolves first
+ * as well as the value that it resolved to.
+ *
+ * @param {Object.<string, Promise>} promise_map
+ *
+ * @returns {Promise.<[string, any]>}
+ */
+const raceCase = async (promise_map) => {
+    return Promise.race(Object.entries(promise_map).map(
+        ([key, promise]) => promise.then(value => [key, value])));
+};
+
+module.exports = {
+    TeePromise,
+    Lock,
+    asyncSafeSetInterval,
+    raceCase,
+};

+ 0 - 0
packages/phoenix/packages/strataparse/dsl/ParserBuilder.js → packages/strataparse/dsl/ParserBuilder.js


+ 0 - 0
packages/phoenix/packages/strataparse/dsl/ParserRegistry.js → packages/strataparse/dsl/ParserRegistry.js


+ 0 - 0
packages/phoenix/packages/strataparse/exports.js → packages/strataparse/exports.js


+ 0 - 0
packages/phoenix/packages/strataparse/package.json → packages/strataparse/package.json


+ 0 - 0
packages/phoenix/packages/strataparse/parse.js → packages/strataparse/parse.js


+ 0 - 0
packages/phoenix/packages/strataparse/parse_impls/StrUntilParserImpl.js → packages/strataparse/parse_impls/StrUntilParserImpl.js


+ 0 - 0
packages/phoenix/packages/strataparse/parse_impls/combinators.js → packages/strataparse/parse_impls/combinators.js


+ 0 - 0
packages/phoenix/packages/strataparse/parse_impls/literal.js → packages/strataparse/parse_impls/literal.js


+ 0 - 0
packages/phoenix/packages/strataparse/parse_impls/whitespace.js → packages/strataparse/parse_impls/whitespace.js


+ 0 - 0
packages/phoenix/packages/strataparse/strata.js → packages/strataparse/strata.js


+ 0 - 0
packages/phoenix/packages/strataparse/strata_impls/ContextSwitchingPStratumImpl.js → packages/strataparse/strata_impls/ContextSwitchingPStratumImpl.js


+ 0 - 0
packages/phoenix/packages/strataparse/strata_impls/FirstRecognizedPStratumImpl.js → packages/strataparse/strata_impls/FirstRecognizedPStratumImpl.js


+ 0 - 0
packages/phoenix/packages/strataparse/strata_impls/MergeWhitespacePStratumImpl.js → packages/strataparse/strata_impls/MergeWhitespacePStratumImpl.js


+ 0 - 0
packages/phoenix/packages/strataparse/strata_impls/terminals.js → packages/strataparse/strata_impls/terminals.js


+ 4 - 1
packages/terminal/rollup.config.js

@@ -20,6 +20,7 @@ import { nodeResolve } from '@rollup/plugin-node-resolve'
 import commonjs from '@rollup/plugin-commonjs';
 import copy from 'rollup-plugin-copy';
 import process from 'node:process';
+import path from 'node:path';
 
 const configFile = process.env.CONFIG_FILE ?? 'config/dev.js';
 await import(`./${configFile}`);
@@ -31,7 +32,9 @@ export default {
         format: "iife"
     },
     plugins: [
-        nodeResolve(),
+        nodeResolve({
+            rootDir: path.join(process.cwd(), '..'),
+        }),
         commonjs(),
         copy({
             targets: [