@playfast/muxmaxing-config 0.1.2 → 0.3.0

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.
@@ -0,0 +1,55 @@
1
+ import { type Cause, type Effect, Schema as S } from 'effect';
2
+ export interface BashResult {
3
+ readonly stdout: string;
4
+ readonly stderr: string;
5
+ readonly exitCode: number;
6
+ }
7
+ type TaggedErrorClass<Tag extends string, A extends Record<string, unknown>> = new (args: A) => Cause.YieldableError & {
8
+ readonly _tag: Tag;
9
+ } & Readonly<A>;
10
+ declare const HookBashErrorBase: TaggedErrorClass<'HookBashError', {
11
+ readonly reason: string;
12
+ }>;
13
+ export declare class HookBashError extends HookBashErrorBase {
14
+ get message(): string;
15
+ }
16
+ export interface HostBridge {
17
+ readonly bash: (command: string) => Effect.Effect<BashResult, HookBashError>;
18
+ readonly env: Readonly<Record<string, string | undefined>>;
19
+ }
20
+ export interface UnitInfo {
21
+ readonly id: string;
22
+ readonly workspaceFolder: string;
23
+ }
24
+ export interface UnitBridge extends UnitInfo {
25
+ readonly bash: (command: string) => Effect.Effect<BashResult, HookBashError>;
26
+ }
27
+ export interface CollectCtx {
28
+ readonly host: HostBridge;
29
+ readonly unit: UnitInfo;
30
+ readonly log: (line: string) => Effect.Effect<void>;
31
+ }
32
+ export interface HookCtx<A> {
33
+ readonly hostInput: A;
34
+ readonly host: HostBridge;
35
+ readonly unit: UnitBridge;
36
+ readonly log: (line: string) => Effect.Effect<void>;
37
+ }
38
+ export interface RemovedCtx<A> {
39
+ readonly hostInput: A;
40
+ readonly host: HostBridge;
41
+ readonly unit: UnitInfo;
42
+ readonly log: (line: string) => Effect.Effect<void>;
43
+ }
44
+ export interface MuxmaxingConfigExternalApi<A, I> {
45
+ readonly hostInput: S.Schema<A, I, never>;
46
+ readonly collectHostDeviceInput: (ctx: CollectCtx) => Effect.Effect<A, unknown>;
47
+ readonly onWorkUnitMachineCreated?: (ctx: HookCtx<A>) => Effect.Effect<void, unknown>;
48
+ readonly onNewTerminal?: (ctx: HookCtx<A>) => Effect.Effect<void, unknown>;
49
+ readonly onWorkUnitRemoved?: (ctx: RemovedCtx<A>) => Effect.Effect<void, unknown>;
50
+ }
51
+ export type MuxmaxingConfig<A, I> = MuxmaxingConfigExternalApi<A, I>;
52
+ export declare const defineConfig: <A, I>(config: MuxmaxingConfig<A, I>) => MuxmaxingConfig<A, I>;
53
+ export declare const isMuxmaxingConfig: (candidate: unknown) => candidate is MuxmaxingConfig<unknown, unknown>;
54
+ export {};
55
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ import { Data, Schema as S } from 'effect';
2
+ const HookBashErrorBase = (Data.TaggedError('HookBashError'));
3
+ export class HookBashError extends HookBashErrorBase {
4
+ // Cause.pretty would otherwise print the generic "An error has occurred".
5
+ get message() {
6
+ return this.reason;
7
+ }
8
+ }
9
+ export const defineConfig = (config) => config;
10
+ export const isMuxmaxingConfig = (candidate) => {
11
+ if (typeof candidate !== 'object' || candidate === null) {
12
+ return false;
13
+ }
14
+ const record = { ...candidate };
15
+ const optionalHook = (name) => record[name] === undefined || typeof record[name] === 'function';
16
+ return (S.isSchema(record['hostInput']) &&
17
+ typeof record['collectHostDeviceInput'] === 'function' &&
18
+ optionalHook('onWorkUnitMachineCreated') &&
19
+ optionalHook('onNewTerminal') &&
20
+ optionalHook('onWorkUnitRemoved'));
21
+ };
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,IAAI,EAAe,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAanE,MAAM,iBAAiB,GACrB,CAAA,IAAI,CAAC,WAAW,CAAC,eAAe,CAA8B,CAAA,CAAA;AAEhE,MAAM,OAAO,aAAc,SAAQ,iBAAiB;IAClD,0EAA0E;IAC1E,IAAa,OAAO;QAClB,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;CACF;AA+CD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAO,MAA6B,EAAyB,EAAE,CAAC,MAAM,CAAA;AAElG,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,SAAkB,EAC8B,EAAE;IAClD,IAAI,OAAO,SAAS,KAAK,QAAQ,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACxD,OAAO,KAAK,CAAA;IACd,CAAC;IACD,MAAM,MAAM,GAA4B,EAAE,GAAG,SAAS,EAAE,CAAA;IACxD,MAAM,YAAY,GAAG,CAAC,IAAY,EAAW,EAAE,CAC7C,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,UAAU,CAAA;IAClE,OAAO,CACL,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC/B,OAAO,MAAM,CAAC,wBAAwB,CAAC,KAAK,UAAU;QACtD,YAAY,CAAC,0BAA0B,CAAC;QACxC,YAAY,CAAC,eAAe,CAAC;QAC7B,YAAY,CAAC,mBAAmB,CAAC,CAClC,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,58 @@
1
+ import { Schema as S } from 'effect';
2
+ export declare const HookName: S.Literal<['collect', 'machineCreated', 'newTerminal', 'removed']>;
3
+ export type HookName = typeof HookName.Type;
4
+ export declare const UnitRef: S.Struct<{
5
+ id: typeof S.String;
6
+ workspaceFolder: typeof S.String;
7
+ }>;
8
+ export type UnitRef = typeof UnitRef.Type;
9
+ export declare const RunHookRequest: S.TaggedStruct<'RunHook', {
10
+ hook: typeof HookName;
11
+ configPath: typeof S.String;
12
+ hostInput: S.NullOr<typeof S.Unknown>;
13
+ unit: typeof UnitRef;
14
+ }>;
15
+ export type RunHookRequest = typeof RunHookRequest.Type;
16
+ export declare const BashOk: S.TaggedStruct<'BashOk', {
17
+ stdout: typeof S.String;
18
+ stderr: typeof S.String;
19
+ exitCode: typeof S.Number;
20
+ }>;
21
+ export type BashOk = typeof BashOk.Type;
22
+ export declare const BashFailed: S.TaggedStruct<'BashFailed', {
23
+ reason: typeof S.String;
24
+ }>;
25
+ export type BashFailed = typeof BashFailed.Type;
26
+ export declare const BashReply: S.TaggedStruct<'BashReply', {
27
+ id: typeof S.Number;
28
+ result: S.Union<[typeof BashOk, typeof BashFailed]>;
29
+ }>;
30
+ export type BashReply = typeof BashReply.Type;
31
+ export declare const EngineToWorker: S.Union<[typeof RunHookRequest, typeof BashReply]>;
32
+ export type EngineToWorker = typeof EngineToWorker.Type;
33
+ export declare const BashRequest: S.TaggedStruct<'Bash', {
34
+ id: typeof S.Number;
35
+ target: S.Literal<['unit', 'host']>;
36
+ command: typeof S.String;
37
+ }>;
38
+ export type BashRequest = typeof BashRequest.Type;
39
+ export declare const LogMessage: S.TaggedStruct<'Log', {
40
+ line: typeof S.String;
41
+ }>;
42
+ export type LogMessage = typeof LogMessage.Type;
43
+ export declare const HookDone: S.TaggedStruct<'HookDone', {
44
+ hostInput: S.NullOr<typeof S.Unknown>;
45
+ }>;
46
+ export type HookDone = typeof HookDone.Type;
47
+ export declare const HookFailed: S.TaggedStruct<'HookFailed', {
48
+ reason: typeof S.String;
49
+ }>;
50
+ export type HookFailed = typeof HookFailed.Type;
51
+ export declare const WorkerToEngine: S.Union<[
52
+ typeof BashRequest,
53
+ typeof LogMessage,
54
+ typeof HookDone,
55
+ typeof HookFailed
56
+ ]>;
57
+ export type WorkerToEngine = typeof WorkerToEngine.Type;
58
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { Schema as S } from 'effect';
2
+ // TaggedStruct consts (not TaggedClass) so declarations survive isolatedDeclarations.
3
+ export const HookName = S.Literal('collect', 'machineCreated', 'newTerminal', 'removed');
4
+ export const UnitRef = S.Struct({ id: S.String, workspaceFolder: S.String });
5
+ export const RunHookRequest = S.TaggedStruct('RunHook', {
6
+ hook: HookName,
7
+ configPath: S.String,
8
+ hostInput: S.NullOr(S.Unknown),
9
+ unit: UnitRef,
10
+ });
11
+ export const BashOk = S.TaggedStruct('BashOk', { stdout: S.String, stderr: S.String, exitCode: S.Number });
12
+ export const BashFailed = S.TaggedStruct('BashFailed', { reason: S.String });
13
+ export const BashReply = S.TaggedStruct('BashReply', { id: S.Number, result: S.Union(BashOk, BashFailed) });
14
+ export const EngineToWorker = S.Union(RunHookRequest, BashReply);
15
+ export const BashRequest = S.TaggedStruct('Bash', {
16
+ id: S.Number,
17
+ target: S.Literal('unit', 'host'),
18
+ command: S.String,
19
+ });
20
+ export const LogMessage = S.TaggedStruct('Log', {
21
+ line: S.String,
22
+ });
23
+ export const HookDone = S.TaggedStruct('HookDone', { hostInput: S.NullOr(S.Unknown) });
24
+ export const HookFailed = S.TaggedStruct('HookFailed', { reason: S.String });
25
+ export const WorkerToEngine = S.Union(BashRequest, LogMessage, HookDone, HookFailed);
26
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,QAAQ,CAAA;AAEpC,sFAAsF;AACtF,MAAM,CAAC,MAAM,QAAQ,GACnB,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,SAAS,CAAC,CAAA;AAGlE,MAAM,CAAC,MAAM,OAAO,GAClB,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAA;AAGvD,MAAM,CAAC,MAAM,cAAc,GAQvB,CAAC,CAAC,YAAY,CAAC,SAAS,EAAE;IAC5B,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,CAAC,CAAC,MAAM;IACpB,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;IAC9B,IAAI,EAAE,OAAO;CACd,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,MAAM,GAGf,CAAC,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAA;AAGxF,MAAM,CAAC,MAAM,UAAU,GAA8D,CAAC,CAAC,YAAY,CACjG,YAAY,EACZ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CACrB,CAAA;AAGD,MAAM,CAAC,MAAM,SAAS,GAGlB,CAAC,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,CAAA;AAGtF,MAAM,CAAC,MAAM,cAAc,GAAuD,CAAC,CAAC,KAAK,CACvF,cAAc,EACd,SAAS,CACV,CAAA;AAGD,MAAM,CAAC,MAAM,WAAW,GAOpB,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE;IACzB,EAAE,EAAE,CAAC,CAAC,MAAM;IACZ,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC;IACjC,OAAO,EAAE,CAAC,CAAC,MAAM;CAClB,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,UAAU,GAAqD,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE;IAChG,IAAI,EAAE,CAAC,CAAC,MAAM;CACf,CAAC,CAAA;AAGF,MAAM,CAAC,MAAM,QAAQ,GACnB,CAAC,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;AAGhE,MAAM,CAAC,MAAM,UAAU,GAA8D,CAAC,CAAC,YAAY,CACjG,YAAY,EACZ,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CACrB,CAAA;AAGD,MAAM,CAAC,MAAM,cAAc,GAEvB,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worker-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-entry.d.ts","sourceRoot":"","sources":["../src/worker-entry.ts"],"names":[],"mappings":""}
@@ -0,0 +1,129 @@
1
+ import { Cause, Data, Effect, Either, Match, Option, Ref, Schema as S } from 'effect';
2
+ import { parentPort } from 'node:worker_threads';
3
+ import { BashRequest, EngineToWorker, HookDone, HookFailed, LogMessage, WorkerToEngine, } from '@playfast/muxmaxing-config/protocol';
4
+ import { HookBashError, isMuxmaxingConfig, } from '@playfast/muxmaxing-config';
5
+ const hasWebWorkerScope = typeof self !== 'undefined';
6
+ class WorkerHookError extends Data.TaggedError('WorkerHookError') {
7
+ // Cause.pretty would otherwise print the generic "An error has occurred".
8
+ get message() {
9
+ return this.reason;
10
+ }
11
+ }
12
+ const send = (message) => {
13
+ const encoded = S.encodeSync(WorkerToEngine)(message);
14
+ if (hasWebWorkerScope) {
15
+ self.postMessage(encoded);
16
+ return;
17
+ }
18
+ if (parentPort !== null) {
19
+ parentPort.postMessage(encoded);
20
+ return;
21
+ }
22
+ Effect.runSync(Effect.dieMessage('worker entry has no parent message port'));
23
+ };
24
+ const describe = (cause) => cause instanceof Error ? cause.message : String(cause);
25
+ const pendingBash = new Map();
26
+ const makeBridgedBash = (idRef, target) => (command) => Ref.updateAndGet(idRef, (previous) => previous + 1).pipe(Effect.flatMap((id) => Effect.async((resume) => {
27
+ pendingBash.set(id, (reply) => {
28
+ resume(Match.value(reply.result).pipe(Match.tags({
29
+ BashOk: (ok) => Effect.succeed({
30
+ stdout: ok.stdout,
31
+ stderr: ok.stderr,
32
+ exitCode: ok.exitCode,
33
+ }),
34
+ BashFailed: (failed) => Effect.fail(new HookBashError({ reason: failed.reason })),
35
+ }), Match.exhaustive));
36
+ });
37
+ send(BashRequest.make({ id, target, command }));
38
+ })));
39
+ const log = (line) => Effect.sync(() => send(LogMessage.make({ line })));
40
+ const loadConfig = (configPath) => Effect.tryPromise({
41
+ try: () => import(configPath),
42
+ catch: (cause) => new WorkerHookError({ reason: `config import failed: ${describe(cause)}` }),
43
+ }).pipe(Effect.flatMap((moduleExports) => {
44
+ const record = typeof moduleExports === 'object' && moduleExports !== null ? { ...moduleExports } : {};
45
+ const defaulted = Option.fromNullable(record['default']);
46
+ return Option.match(defaulted, {
47
+ onNone: () => Effect.fail(new WorkerHookError({ reason: 'config has no default export' })),
48
+ onSome: (config) => {
49
+ if (isMuxmaxingConfig(config)) {
50
+ return Effect.succeed(config);
51
+ }
52
+ return Effect.fail(new WorkerHookError({
53
+ reason: 'default export is not a muxmaxing config (expected defineConfig({ hostInput, collectHostDeviceInput, ... }))',
54
+ }));
55
+ },
56
+ });
57
+ }));
58
+ const decodeHostInput = (config, encoded) => S.decodeUnknown(config.hostInput)(encoded).pipe(Effect.mapError((issue) => new WorkerHookError({ reason: `hostInput decode failed: ${String(issue)}` })));
59
+ const hookFailure = (hookName) => (cause) => new WorkerHookError({ reason: `${hookName} failed: ${describe(cause)}` });
60
+ const runRequested = Effect.fn('runRequested')(function* (request) {
61
+ const config = yield* loadConfig(request.configPath);
62
+ const idRef = yield* Ref.make(0);
63
+ const unit = {
64
+ id: request.unit.id,
65
+ workspaceFolder: request.unit.workspaceFolder,
66
+ };
67
+ const workerEnv = typeof Bun === 'undefined' ? process.env : Bun.env;
68
+ const host = { bash: makeBridgedBash(idRef, 'host'), env: workerEnv };
69
+ const unitBridge = { ...unit, bash: makeBridgedBash(idRef, 'unit') };
70
+ // Undefined consuming hooks are intentional silent no-ops.
71
+ const runOptional = (hookName, hook, makeCtx) => Option.match(Option.fromNullable(hook), {
72
+ onNone: () => Effect.succeed(HookDone.make({ hostInput: null })),
73
+ onSome: (run) => decodeHostInput(config, request.hostInput).pipe(Effect.flatMap((hostInput) => run(makeCtx(hostInput)).pipe(Effect.mapError(hookFailure(hookName)))), Effect.map(() => HookDone.make({ hostInput: null }))),
74
+ });
75
+ return yield* Match.value(request.hook).pipe(Match.when('collect', () => config.collectHostDeviceInput({ host, unit, log }).pipe(Effect.mapError(hookFailure('collectHostDeviceInput')), Effect.flatMap((collected) => S.encodeUnknown(config.hostInput)(collected).pipe(Effect.mapError((issue) => new WorkerHookError({
76
+ reason: `hostInput encode failed: ${String(issue)}`,
77
+ })))), Effect.map((encoded) => HookDone.make({ hostInput: encoded ?? null })))), Match.when('machineCreated', () => runOptional('onWorkUnitMachineCreated', config.onWorkUnitMachineCreated, (hostInput) => ({
78
+ hostInput,
79
+ host,
80
+ unit: unitBridge,
81
+ log,
82
+ }))), Match.when('newTerminal', () => runOptional('onNewTerminal', config.onNewTerminal, (hostInput) => ({
83
+ hostInput,
84
+ host,
85
+ unit: unitBridge,
86
+ log,
87
+ }))), Match.when('removed', () => runOptional('onWorkUnitRemoved', config.onWorkUnitRemoved, (hostInput) => ({
88
+ hostInput,
89
+ host,
90
+ unit,
91
+ log,
92
+ }))), Match.exhaustive);
93
+ });
94
+ const handleRunHook = (request) => {
95
+ void Effect.runPromise(runRequested(request).pipe(Effect.flatMap((done) => Effect.sync(() => send(done))), Effect.catchAllCause((cause) => Effect.sync(() => send(HookFailed.make({ reason: Cause.pretty(cause) })))),
96
+ // Drop the listener so the event loop drains and the worker exits.
97
+ Effect.ensuring(Effect.sync(() => {
98
+ if (hasWebWorkerScope) {
99
+ self.onmessage = null;
100
+ return;
101
+ }
102
+ if (parentPort !== null) {
103
+ parentPort.close();
104
+ }
105
+ }))));
106
+ };
107
+ const handleMessage = (payload) => {
108
+ Either.match(S.decodeUnknownEither(EngineToWorker)(payload), {
109
+ onLeft: () => send(HookFailed.make({ reason: 'undecodable engine message' })),
110
+ onRight: (message) => Match.value(message).pipe(Match.tags({
111
+ RunHook: (request) => handleRunHook(request),
112
+ BashReply: (reply) => {
113
+ const resume = pendingBash.get(reply.id);
114
+ pendingBash.delete(reply.id);
115
+ resume?.(reply);
116
+ },
117
+ }), Match.exhaustive),
118
+ });
119
+ };
120
+ if (hasWebWorkerScope) {
121
+ self.onmessage = (event) => handleMessage(event.data);
122
+ }
123
+ if (!hasWebWorkerScope && parentPort !== null) {
124
+ parentPort.on('message', handleMessage);
125
+ }
126
+ if (!hasWebWorkerScope && parentPort === null) {
127
+ Effect.runSync(Effect.dieMessage('worker entry has no parent message port'));
128
+ }
129
+ //# sourceMappingURL=worker-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-entry.js","sourceRoot":"","sources":["../src/worker-entry.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,48 +1,60 @@
1
1
  {
2
2
  "name": "@playfast/muxmaxing-config",
3
- "version": "0.1.2",
4
- "type": "module",
3
+ "version": "0.3.0",
5
4
  "description": "Author API for muxmaxing.config.ts — a repo-committed hook bridge between the host device and muxmaxing work units: typed host-input collection plus Effect-native lifecycle hooks (machine created, new terminal, removed) with bash bridged into the unit.",
6
5
  "keywords": [
7
- "muxmaxing",
6
+ "devcontainer",
8
7
  "effect",
9
8
  "hooks",
10
- "devcontainer",
9
+ "muxmaxing",
11
10
  "provisioning"
12
11
  ],
12
+ "bugs": {
13
+ "url": "https://github.com/playfast/reform/issues"
14
+ },
13
15
  "license": "MIT",
14
16
  "repository": {
15
17
  "type": "git",
16
18
  "url": "https://github.com/playfast/reform.git",
17
19
  "directory": "packages/muxmaxing-config"
18
20
  },
19
- "bugs": {
20
- "url": "https://github.com/playfast/reform/issues"
21
- },
22
- "sideEffects": false,
23
- "exports": {
24
- "./package.json": "./package.json",
25
- ".": "./src/index.ts",
26
- "./*": "./src/*.ts"
27
- },
28
21
  "files": [
22
+ "dist",
29
23
  "src",
30
24
  "README.md"
31
25
  ],
26
+ "type": "module",
27
+ "sideEffects": false,
28
+ "main": "./dist/index.js",
29
+ "types": "./dist/index.d.ts",
30
+ "exports": {
31
+ "./package.json": "./package.json",
32
+ ".": {
33
+ "playfast-src": "./src/index.ts",
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "./*": {
38
+ "playfast-src": "./src/*.ts",
39
+ "types": "./dist/*.d.ts",
40
+ "default": "./dist/*.js"
41
+ }
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
32
46
  "scripts": {
33
47
  "clean": "rm -rf dist .tsbuildinfo",
34
48
  "check": "tsc --noEmit",
35
- "build": "tsc -p tsconfig.build.json",
49
+ "build": "rm -rf dist .tsbuildinfo && tsc -p tsconfig.build.json && bun ../../scripts/fix-esm-extensions.ts dist",
36
50
  "lint": "oxlint src",
37
- "lint:fix": "oxlint --fix src"
38
- },
39
- "peerDependencies": {
40
- "effect": "*"
51
+ "lint:fix": "oxlint --fix src",
52
+ "prepack": "bun run build"
41
53
  },
42
54
  "devDependencies": {
43
55
  "@types/bun": "^1.3.14"
44
56
  },
45
- "publishConfig": {
46
- "access": "public"
57
+ "peerDependencies": {
58
+ "effect": "*"
47
59
  }
48
60
  }
package/src/index.ts CHANGED
@@ -66,8 +66,7 @@ export interface MuxmaxingConfigExternalApi<A, I> {
66
66
 
67
67
  export type MuxmaxingConfig<A, I> = MuxmaxingConfigExternalApi<A, I>
68
68
 
69
- export const defineConfig = <A, I>(config: MuxmaxingConfig<A, I>): MuxmaxingConfig<A, I> =>
70
- config
69
+ export const defineConfig = <A, I>(config: MuxmaxingConfig<A, I>): MuxmaxingConfig<A, I> => config
71
70
 
72
71
  export const isMuxmaxingConfig = (
73
72
  candidate: unknown,
package/src/protocol.ts CHANGED
@@ -31,8 +31,10 @@ export const BashOk: S.TaggedStruct<
31
31
  > = S.TaggedStruct('BashOk', { stdout: S.String, stderr: S.String, exitCode: S.Number })
32
32
  export type BashOk = typeof BashOk.Type
33
33
 
34
- export const BashFailed: S.TaggedStruct<'BashFailed', { reason: typeof S.String }> =
35
- S.TaggedStruct('BashFailed', { reason: S.String })
34
+ export const BashFailed: S.TaggedStruct<'BashFailed', { reason: typeof S.String }> = S.TaggedStruct(
35
+ 'BashFailed',
36
+ { reason: S.String },
37
+ )
36
38
  export type BashFailed = typeof BashFailed.Type
37
39
 
38
40
  export const BashReply: S.TaggedStruct<
@@ -61,18 +63,19 @@ export const BashRequest: S.TaggedStruct<
61
63
  })
62
64
  export type BashRequest = typeof BashRequest.Type
63
65
 
64
- export const LogMessage: S.TaggedStruct<'Log', { line: typeof S.String }> = S.TaggedStruct(
65
- 'Log',
66
- { line: S.String },
67
- )
66
+ export const LogMessage: S.TaggedStruct<'Log', { line: typeof S.String }> = S.TaggedStruct('Log', {
67
+ line: S.String,
68
+ })
68
69
  export type LogMessage = typeof LogMessage.Type
69
70
 
70
71
  export const HookDone: S.TaggedStruct<'HookDone', { hostInput: S.NullOr<typeof S.Unknown> }> =
71
72
  S.TaggedStruct('HookDone', { hostInput: S.NullOr(S.Unknown) })
72
73
  export type HookDone = typeof HookDone.Type
73
74
 
74
- export const HookFailed: S.TaggedStruct<'HookFailed', { reason: typeof S.String }> =
75
- S.TaggedStruct('HookFailed', { reason: S.String })
75
+ export const HookFailed: S.TaggedStruct<'HookFailed', { reason: typeof S.String }> = S.TaggedStruct(
76
+ 'HookFailed',
77
+ { reason: S.String },
78
+ )
76
79
  export type HookFailed = typeof HookFailed.Type
77
80
 
78
81
  export const WorkerToEngine: S.Union<
@@ -1,4 +1,5 @@
1
1
  import { Cause, Data, Effect, Either, Match, Option, Ref, Schema as S } from 'effect'
2
+ import { parentPort } from 'node:worker_threads'
2
3
  import {
3
4
  type BashReply,
4
5
  BashRequest,
@@ -8,7 +9,7 @@ import {
8
9
  LogMessage,
9
10
  type RunHookRequest,
10
11
  WorkerToEngine,
11
- } from './protocol'
12
+ } from '@playfast/muxmaxing-config/protocol'
12
13
  import {
13
14
  type BashResult,
14
15
  HookBashError,
@@ -16,10 +17,12 @@ import {
16
17
  isMuxmaxingConfig,
17
18
  type MuxmaxingConfig,
18
19
  type UnitInfo,
19
- } from './index'
20
+ } from '@playfast/muxmaxing-config'
20
21
 
21
22
  declare const self: Worker
22
23
 
24
+ const hasWebWorkerScope = typeof self !== 'undefined'
25
+
23
26
  class WorkerHookError extends Data.TaggedError('WorkerHookError')<{
24
27
  readonly reason: string
25
28
  }> {
@@ -30,7 +33,16 @@ class WorkerHookError extends Data.TaggedError('WorkerHookError')<{
30
33
  }
31
34
 
32
35
  const send = (message: WorkerToEngine): void => {
33
- self.postMessage(S.encodeSync(WorkerToEngine)(message))
36
+ const encoded = S.encodeSync(WorkerToEngine)(message)
37
+ if (hasWebWorkerScope) {
38
+ self.postMessage(encoded)
39
+ return
40
+ }
41
+ if (parentPort !== null) {
42
+ parentPort.postMessage(encoded)
43
+ return
44
+ }
45
+ Effect.runSync(Effect.dieMessage('worker entry has no parent message port'))
34
46
  }
35
47
 
36
48
  const describe = (cause: unknown): string =>
@@ -54,8 +66,7 @@ const makeBridgedBash =
54
66
  stderr: ok.stderr,
55
67
  exitCode: ok.exitCode,
56
68
  }),
57
- BashFailed: (failed) =>
58
- Effect.fail(new HookBashError({ reason: failed.reason })),
69
+ BashFailed: (failed) => Effect.fail(new HookBashError({ reason: failed.reason })),
59
70
  }),
60
71
  Match.exhaustive,
61
72
  ),
@@ -74,18 +85,14 @@ const loadConfig = (
74
85
  ): Effect.Effect<MuxmaxingConfig<unknown, unknown>, WorkerHookError> =>
75
86
  Effect.tryPromise({
76
87
  try: (): Promise<unknown> => import(configPath),
77
- catch: (cause) =>
78
- new WorkerHookError({ reason: `config import failed: ${describe(cause)}` }),
88
+ catch: (cause) => new WorkerHookError({ reason: `config import failed: ${describe(cause)}` }),
79
89
  }).pipe(
80
90
  Effect.flatMap((moduleExports) => {
81
91
  const record: Record<string, unknown> =
82
- typeof moduleExports === 'object' && moduleExports !== null
83
- ? { ...moduleExports }
84
- : {}
92
+ typeof moduleExports === 'object' && moduleExports !== null ? { ...moduleExports } : {}
85
93
  const defaulted = Option.fromNullable(record['default'])
86
94
  return Option.match(defaulted, {
87
- onNone: () =>
88
- Effect.fail(new WorkerHookError({ reason: 'config has no default export' })),
95
+ onNone: () => Effect.fail(new WorkerHookError({ reason: 'config has no default export' })),
89
96
  onSome: (config) => {
90
97
  if (isMuxmaxingConfig(config)) {
91
98
  return Effect.succeed(config)
@@ -116,80 +123,80 @@ const hookFailure =
116
123
  (cause: unknown): WorkerHookError =>
117
124
  new WorkerHookError({ reason: `${hookName} failed: ${describe(cause)}` })
118
125
 
119
- const runRequested = Effect.fn('runRequested')(
120
- function* (request: RunHookRequest): Effect.fn.Return<HookDone, WorkerHookError> {
121
- const config = yield* loadConfig(request.configPath)
122
- const idRef = yield* Ref.make(0)
123
- const unit: UnitInfo = {
124
- id: request.unit.id,
125
- workspaceFolder: request.unit.workspaceFolder,
126
- }
127
- const host: HostBridge = { bash: makeBridgedBash(idRef, 'host'), env: Bun.env }
128
- const unitBridge = { ...unit, bash: makeBridgedBash(idRef, 'unit') }
129
-
130
- // Undefined consuming hooks are intentional silent no-ops.
131
- const runOptional = <Ctx>(
132
- hookName: string,
133
- hook: ((ctx: Ctx) => Effect.Effect<void, unknown>) | undefined,
134
- makeCtx: (hostInput: unknown) => Ctx,
135
- ): Effect.Effect<HookDone, WorkerHookError> =>
136
- Option.match(Option.fromNullable(hook), {
137
- onNone: () => Effect.succeed(HookDone.make({ hostInput: null })),
138
- onSome: (run) =>
139
- decodeHostInput(config, request.hostInput).pipe(
140
- Effect.flatMap((hostInput) =>
141
- run(makeCtx(hostInput)).pipe(Effect.mapError(hookFailure(hookName))),
142
- ),
143
- Effect.map(() => HookDone.make({ hostInput: null })),
126
+ const runRequested = Effect.fn('runRequested')(function* (
127
+ request: RunHookRequest,
128
+ ): Effect.fn.Return<HookDone, WorkerHookError> {
129
+ const config = yield* loadConfig(request.configPath)
130
+ const idRef = yield* Ref.make(0)
131
+ const unit: UnitInfo = {
132
+ id: request.unit.id,
133
+ workspaceFolder: request.unit.workspaceFolder,
134
+ }
135
+ const workerEnv = typeof Bun === 'undefined' ? process.env : Bun.env
136
+ const host: HostBridge = { bash: makeBridgedBash(idRef, 'host'), env: workerEnv }
137
+ const unitBridge = { ...unit, bash: makeBridgedBash(idRef, 'unit') }
138
+
139
+ // Undefined consuming hooks are intentional silent no-ops.
140
+ const runOptional = <Ctx>(
141
+ hookName: string,
142
+ hook: ((ctx: Ctx) => Effect.Effect<void, unknown>) | undefined,
143
+ makeCtx: (hostInput: unknown) => Ctx,
144
+ ): Effect.Effect<HookDone, WorkerHookError> =>
145
+ Option.match(Option.fromNullable(hook), {
146
+ onNone: () => Effect.succeed(HookDone.make({ hostInput: null })),
147
+ onSome: (run) =>
148
+ decodeHostInput(config, request.hostInput).pipe(
149
+ Effect.flatMap((hostInput) =>
150
+ run(makeCtx(hostInput)).pipe(Effect.mapError(hookFailure(hookName))),
144
151
  ),
145
- })
152
+ Effect.map(() => HookDone.make({ hostInput: null })),
153
+ ),
154
+ })
146
155
 
147
- return yield* Match.value(request.hook).pipe(
148
- Match.when('collect', () =>
149
- config
150
- .collectHostDeviceInput({ host, unit, log })
151
- .pipe(
152
- Effect.mapError(hookFailure('collectHostDeviceInput')),
153
- Effect.flatMap((collected) =>
154
- S.encodeUnknown(config.hostInput)(collected).pipe(
155
- Effect.mapError(
156
- (issue) =>
157
- new WorkerHookError({
158
- reason: `hostInput encode failed: ${String(issue)}`,
159
- }),
160
- ),
161
- ),
156
+ return yield* Match.value(request.hook).pipe(
157
+ Match.when('collect', () =>
158
+ config.collectHostDeviceInput({ host, unit, log }).pipe(
159
+ Effect.mapError(hookFailure('collectHostDeviceInput')),
160
+ Effect.flatMap((collected) =>
161
+ S.encodeUnknown(config.hostInput)(collected).pipe(
162
+ Effect.mapError(
163
+ (issue) =>
164
+ new WorkerHookError({
165
+ reason: `hostInput encode failed: ${String(issue)}`,
166
+ }),
162
167
  ),
163
- Effect.map((encoded) => HookDone.make({ hostInput: encoded ?? null })),
164
168
  ),
169
+ ),
170
+ Effect.map((encoded) => HookDone.make({ hostInput: encoded ?? null })),
165
171
  ),
166
- Match.when('machineCreated', () =>
167
- runOptional('onWorkUnitMachineCreated', config.onWorkUnitMachineCreated, (hostInput) => ({
168
- hostInput,
169
- host,
170
- unit: unitBridge,
171
- log,
172
- })),
173
- ),
174
- Match.when('newTerminal', () =>
175
- runOptional('onNewTerminal', config.onNewTerminal, (hostInput) => ({
176
- hostInput,
177
- host,
178
- unit: unitBridge,
179
- log,
180
- })),
181
- ),
182
- Match.when('removed', () =>
183
- runOptional('onWorkUnitRemoved', config.onWorkUnitRemoved, (hostInput) => ({
184
- hostInput,
185
- host,
186
- unit,
187
- log,
188
- })),
189
- ),
190
- Match.exhaustive,
191
- )
192
- })
172
+ ),
173
+ Match.when('machineCreated', () =>
174
+ runOptional('onWorkUnitMachineCreated', config.onWorkUnitMachineCreated, (hostInput) => ({
175
+ hostInput,
176
+ host,
177
+ unit: unitBridge,
178
+ log,
179
+ })),
180
+ ),
181
+ Match.when('newTerminal', () =>
182
+ runOptional('onNewTerminal', config.onNewTerminal, (hostInput) => ({
183
+ hostInput,
184
+ host,
185
+ unit: unitBridge,
186
+ log,
187
+ })),
188
+ ),
189
+ Match.when('removed', () =>
190
+ runOptional('onWorkUnitRemoved', config.onWorkUnitRemoved, (hostInput) => ({
191
+ hostInput,
192
+ host,
193
+ unit,
194
+ log,
195
+ })),
196
+ ),
197
+ Match.exhaustive,
198
+ )
199
+ })
193
200
 
194
201
  const handleRunHook = (request: RunHookRequest): void => {
195
202
  void Effect.runPromise(
@@ -201,15 +208,21 @@ const handleRunHook = (request: RunHookRequest): void => {
201
208
  // Drop the listener so the event loop drains and the worker exits.
202
209
  Effect.ensuring(
203
210
  Effect.sync(() => {
204
- self.onmessage = null
211
+ if (hasWebWorkerScope) {
212
+ self.onmessage = null
213
+ return
214
+ }
215
+ if (parentPort !== null) {
216
+ parentPort.close()
217
+ }
205
218
  }),
206
219
  ),
207
220
  ),
208
221
  )
209
222
  }
210
223
 
211
- self.onmessage = (event: MessageEvent): void => {
212
- Either.match(S.decodeUnknownEither(EngineToWorker)(event.data), {
224
+ const handleMessage = (payload: unknown): void => {
225
+ Either.match(S.decodeUnknownEither(EngineToWorker)(payload), {
213
226
  onLeft: () => send(HookFailed.make({ reason: 'undecodable engine message' })),
214
227
  onRight: (message) =>
215
228
  Match.value(message).pipe(
@@ -225,3 +238,13 @@ self.onmessage = (event: MessageEvent): void => {
225
238
  ),
226
239
  })
227
240
  }
241
+
242
+ if (hasWebWorkerScope) {
243
+ self.onmessage = (event: MessageEvent): void => handleMessage(event.data)
244
+ }
245
+ if (!hasWebWorkerScope && parentPort !== null) {
246
+ parentPort.on('message', handleMessage)
247
+ }
248
+ if (!hasWebWorkerScope && parentPort === null) {
249
+ Effect.runSync(Effect.dieMessage('worker entry has no parent message port'))
250
+ }