Offload functions to worker threads with shared memory primitives for Node.js.
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: registry, Task, and mo() with unit tests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

+83
+4
package.json
··· 3 3 "version": "0.0.0", 4 4 "type": "module", 5 5 "exports": "./src/index.ts", 6 + "engines": { 7 + "node": ">=22" 8 + }, 9 + "packageManager": "pnpm@10.33.0", 6 10 "scripts": { 7 11 "test": "node --experimental-strip-types --test test/**/*.test.ts" 8 12 }
+9
pnpm-lock.yaml
··· 1 + lockfileVersion: '9.0' 2 + 3 + settings: 4 + autoInstallPeers: true 5 + excludeLinksFromLockfile: false 6 + 7 + importers: 8 + 9 + .: {}
+2
src/index.ts
··· 1 + export { mo } from './mo.ts'; 2 + export { Task } from './task.ts';
+18
src/mo.ts
··· 1 + import { registry } from './registry.ts'; 2 + import { Task } from './task.ts'; 3 + 4 + const counters = new Map<string, number>(); 5 + 6 + export function mo<A extends unknown[], R>( 7 + importMeta: ImportMeta, 8 + fn: (...args: A) => R, 9 + ): (...args: A) => Task<R> { 10 + const url = importMeta.url; 11 + const index = counters.get(url) ?? 0; 12 + counters.set(url, index + 1); 13 + const id = `${url}#${index}`; 14 + 15 + registry.set(id, fn); 16 + 17 + return (...args: A) => new Task<R>(id, args); 18 + }
+1
src/registry.ts
··· 1 + export const registry = new Map<string, (...args: any[]) => any>();
+16
src/task.ts
··· 1 + export class Task<T> { 2 + readonly id: string; 3 + readonly args: unknown[]; 4 + 5 + constructor(id: string, args: unknown[]) { 6 + this.id = id; 7 + this.args = args; 8 + } 9 + 10 + then<T1 = T, T2 = never>( 11 + onfulfilled?: ((value: T) => T1 | PromiseLike<T1>) | null, 12 + onrejected?: ((reason: any) => T2 | PromiseLike<T2>) | null, 13 + ): Promise<T1 | T2> { 14 + throw new Error('Not implemented: wire up dedicated runner'); 15 + } 16 + }
+33
test/mo.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { mo } from 'moroutine'; 4 + 5 + describe('mo()', () => { 6 + it('returns a function', () => { 7 + const double = mo(import.meta, (x: number) => 2 * x); 8 + assert.equal(typeof double, 'function'); 9 + }); 10 + 11 + it('calling it returns a Task with correct args', () => { 12 + const double = mo(import.meta, (x: number) => 2 * x); 13 + const task = double(2); 14 + assert.deepEqual(task.args, [2]); 15 + }); 16 + 17 + it('Task is a thenable', () => { 18 + const double = mo(import.meta, (x: number) => 2 * x); 19 + const task = double(2); 20 + assert.equal(typeof task.then, 'function'); 21 + }); 22 + 23 + it('tasks from the same moroutine share an id', () => { 24 + const double = mo(import.meta, (x: number) => 2 * x); 25 + assert.equal(double(1).id, double(2).id); 26 + }); 27 + 28 + it('different moroutines have different ids', () => { 29 + const a = mo(import.meta, (x: number) => x + 1); 30 + const b = mo(import.meta, (x: number) => x + 2); 31 + assert.notEqual(a(1).id, b(1).id); 32 + }); 33 + });