@ttsc/wasm 0.18.4 → 0.19.1

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/README.md CHANGED
@@ -47,6 +47,7 @@ The native sibling `main.go` is recommended when you want `go run ./cmd/your-was
47
47
  package main
48
48
 
49
49
  import (
50
+ "context"
50
51
  "fmt"
51
52
  "os"
52
53
 
@@ -60,7 +61,10 @@ func main() {
60
61
  name, command := os.Args[1], os.Args[2]
61
62
  for _, p := range plugins {
62
63
  if p.Name() == name {
63
- os.Exit(p.Run(command, os.Args[3:]))
64
+ result := host.InvokePlugin(context.Background(), p, command, os.Args[3:])
65
+ fmt.Fprint(os.Stdout, result.Stdout)
66
+ fmt.Fprint(os.Stderr, result.Stderr)
67
+ os.Exit(result.Code)
64
68
  }
65
69
  }
66
70
  }
@@ -169,12 +173,14 @@ Verbs and payload types:
169
173
 
170
174
  ```go
171
175
  type Plugin interface {
172
- Name() string // e.g. "@ttsc/banner"
173
- Run(command string, args []string) int // returns CLI exit code
176
+ Name() string
177
+ Run(invocation *PluginInvocation) int
174
178
  }
175
179
  ```
176
180
 
177
- The host installs `globalThis[apiName].plugin({ name, command, ...opts })` that translates the JS options object into a CLI-shaped argv and calls your plugin's `Run`. Your `Run` body can forward to the same function the native sidecar's `main.go` calls, for example `utility.RunBuild(args)` for plugins backed by `packages/ttsc/utility`.
181
+ The host installs `globalThis[apiName].plugin({ name, command, ...opts })` that translates the JS options object into `invocation.Command` and CLI-shaped `invocation.Args`. Write output to `invocation.Stdout` and `invocation.Stderr`. Utility-backed plugins can call `utility.RunBuildWithIO(invocation.Args, invocation.Stdout, invocation.Stderr)` so the native command and browser adapter share implementation without replacing process-global streams.
182
+
183
+ Use `invocation.Go` for asynchronous work that belongs to the result. Register it before `Run` returns; the host waits for registered work, closes registration when `Run` returns, and rejects later writes to the invocation streams.
178
184
 
179
185
  ## Published-tarball Go module layout
180
186
 
package/dist/go.mod CHANGED
@@ -39,6 +39,7 @@ require (
39
39
  github.com/microsoft/typescript-go/shim/checker v0.0.0 // indirect
40
40
  github.com/microsoft/typescript-go/shim/core v0.0.0 // indirect
41
41
  github.com/microsoft/typescript-go/shim/diagnosticwriter v0.0.0 // indirect
42
+ github.com/microsoft/typescript-go/shim/parser v0.0.0 // indirect
42
43
  github.com/microsoft/typescript-go/shim/printer v0.0.0 // indirect
43
44
  github.com/microsoft/typescript-go/shim/tsoptions v0.0.0 // indirect
44
45
  github.com/microsoft/typescript-go/shim/tspath v0.0.0 // indirect
package/dist/ttsc.wasm CHANGED
Binary file
package/go.mod CHANGED
@@ -39,6 +39,7 @@ require (
39
39
  github.com/microsoft/typescript-go/shim/checker v0.0.0 // indirect
40
40
  github.com/microsoft/typescript-go/shim/core v0.0.0 // indirect
41
41
  github.com/microsoft/typescript-go/shim/diagnosticwriter v0.0.0 // indirect
42
+ github.com/microsoft/typescript-go/shim/parser v0.0.0 // indirect
42
43
  github.com/microsoft/typescript-go/shim/printer v0.0.0 // indirect
43
44
  github.com/microsoft/typescript-go/shim/tsoptions v0.0.0 // indirect
44
45
  github.com/microsoft/typescript-go/shim/tspath v0.0.0 // indirect
package/host/api.go CHANGED
@@ -16,7 +16,7 @@ import (
16
16
  "github.com/samchon/ttsc/packages/ttsc/driver"
17
17
  )
18
18
 
19
- // APIResult is the stdout/stderr capture returned by runWithCapturedIO. The
19
+ // APIResult is the stdout/stderr capture returned by InvokePlugin. The
20
20
  // js/wasm binding wraps it in the same JS result envelope that build/check/
21
21
  // transform use, adding `result` when an endpoint has a JSON payload. `code`
22
22
  // follows the native CLI exit-code contract (0 success, 2 compiler/config/
package/host/host.go CHANGED
@@ -10,10 +10,10 @@
10
10
  package host
11
11
 
12
12
  import (
13
+ "context"
13
14
  "fmt"
14
15
  "os"
15
16
  "runtime"
16
- "sync"
17
17
  "sync/atomic"
18
18
  "syscall/js"
19
19
  "time"
@@ -81,7 +81,19 @@ func Expose(apiName string, cfg Config) {
81
81
  continue
82
82
  }
83
83
  if _, dup := plugins[name]; dup {
84
- panic(fmt.Sprintf("host.Expose: duplicate plugin name %q", name))
84
+ // A duplicate plugin name is a host-configuration error, but panicking
85
+ // here would terminate the Go runtime before any Ready/Failed signal is
86
+ // installed, leaving bootTtsc's `await ready` pending forever with no
87
+ // observable cause. Mirror the double-Expose path: surface the cause via
88
+ // console.error + the JS-visible Failed bridge, then return without
89
+ // starting the keepalive runtime so the boot rejects with the real
90
+ // reason instead of a generic "exited before readiness" error.
91
+ msg := fmt.Sprintf("host.Expose: duplicate plugin name %q", name)
92
+ fmt.Fprintln(os.Stderr, msg)
93
+ if failed := js.Global().Get(apiName + "Failed"); failed.Type() == js.TypeFunction {
94
+ failed.Invoke(js.Global().Get("Error").New(msg))
95
+ }
96
+ return
85
97
  }
86
98
  plugins[name] = p
87
99
  pluginNames = append(pluginNames, name)
@@ -168,9 +180,7 @@ func jsPluginDispatch(plugins map[string]Plugin) func(this js.Value, args []js.V
168
180
  return errorPromise(2, fmt.Sprintf("host: unknown plugin %q", name))
169
181
  }
170
182
  return makePromise(func() any {
171
- res := runWithCapturedIO(func() int {
172
- return plugin.Run(command, argv)
173
- })
183
+ res := InvokePlugin(context.Background(), plugin, command, argv)
174
184
  return js.ValueOf(map[string]any{
175
185
  "code": res.Code,
176
186
  "stdout": res.Stdout,
@@ -312,106 +322,3 @@ func stringProp(obj js.Value, key string) string {
312
322
  }
313
323
  return v.String()
314
324
  }
315
-
316
- // runWithCapturedIO redirects os.Stdout / os.Stderr to temp MemFS files for
317
- // the duration of `task`. Plugin Run methods write to os.Stdout / os.Stderr
318
- // the same way the native sidecar binaries do; capturing the output lets the
319
- // JS host render it in a console panel without spawning a subprocess.
320
- //
321
- // We use MemFS temp files instead of os.Pipe because Go's js/wasm runtime
322
- // returns `pipe: not implemented on js` for `syscall.Pipe` — pipes are not
323
- // supported on the wasm target. The temp-file approach works because the
324
- // MemFS shim implements file open/write/read.
325
- func runWithCapturedIO(task func() int) APIResult {
326
- captureMu.Lock()
327
- defer captureMu.Unlock()
328
-
329
- prevOut, prevErr := os.Stdout, os.Stderr
330
- // The defer is a safety net: if an early return skips the explicit restore
331
- // below, os.Stdout/os.Stderr are still restored. The explicit restore that
332
- // follows the task call is a no-op for the defer but makes the happy path
333
- // readable without tracing the defer.
334
- defer func() {
335
- os.Stdout = prevOut
336
- os.Stderr = prevErr
337
- }()
338
-
339
- stdoutPath := fmt.Sprintf("/tmp/ttsc-host-capture-%d-%d.stdout", os.Getpid(), captureCounter.Add(1))
340
- stderrPath := fmt.Sprintf("/tmp/ttsc-host-capture-%d-%d.stderr", os.Getpid(), captureCounter.Add(1))
341
-
342
- outFile, outErr := os.Create(stdoutPath)
343
- errFile, errErr := os.Create(stderrPath)
344
- if outErr != nil || errErr != nil {
345
- // Fall back to the original streams. Better to lose capture than the
346
- // call. The MemFS writeSync shim surfaces the failure to the host
347
- // console so the regression is visible.
348
- if outErr != nil {
349
- fmt.Fprintf(prevErr, "host.runWithCapturedIO: stdout temp file failed: %v\n", outErr)
350
- }
351
- if errErr != nil {
352
- fmt.Fprintf(prevErr, "host.runWithCapturedIO: stderr temp file failed: %v\n", errErr)
353
- }
354
- if outFile != nil {
355
- _ = outFile.Close()
356
- _ = os.Remove(stdoutPath)
357
- }
358
- if errFile != nil {
359
- _ = errFile.Close()
360
- _ = os.Remove(stderrPath)
361
- }
362
- return APIResult{Code: task()}
363
- }
364
- capturing := false
365
- defer func() {
366
- if capturing {
367
- os.Stdout = prevOut
368
- os.Stderr = prevErr
369
- }
370
- if outFile != nil {
371
- _ = outFile.Close()
372
- }
373
- if errFile != nil {
374
- _ = errFile.Close()
375
- }
376
- _ = os.Remove(stdoutPath)
377
- _ = os.Remove(stderrPath)
378
- }()
379
-
380
- os.Stdout = outFile
381
- os.Stderr = errFile
382
- capturing = true
383
-
384
- code := task()
385
-
386
- // Sync + close BEFORE swapping back, so the plugin's last writes hit the
387
- // file before we read it.
388
- _ = outFile.Sync()
389
- _ = errFile.Sync()
390
- _ = outFile.Close()
391
- outFile = nil
392
- _ = errFile.Close()
393
- errFile = nil
394
-
395
- os.Stdout = prevOut
396
- os.Stderr = prevErr
397
- capturing = false
398
-
399
- stdoutBytes, _ := os.ReadFile(stdoutPath)
400
- stderrBytes, _ := os.ReadFile(stderrPath)
401
-
402
- return APIResult{
403
- Code: code,
404
- Stdout: string(stdoutBytes),
405
- Stderr: string(stderrBytes),
406
- }
407
- }
408
-
409
- // captureCounter avoids temp-file name collisions when plugin dispatches
410
- // overlap (multiple goroutines could be in runWithCapturedIO concurrently
411
- // from independent JS callers).
412
- var captureCounter atomic.Uint64
413
-
414
- // captureMu serializes temporary replacement of package-global stdout/stderr.
415
- // The temp filenames are unique, but os.Stdout/os.Stderr themselves are shared
416
- // process state in the wasm runtime.
417
- var captureMu sync.Mutex
package/host/plugin.go CHANGED
@@ -1,60 +1,128 @@
1
1
  package host
2
2
 
3
- // API stability: experimental until v1.0; signatures may change between
4
- // minor releases. Pin exact versions in production playgrounds.
5
- //
3
+ import (
4
+ "bytes"
5
+ "context"
6
+ "io"
7
+ "sync"
8
+ )
9
+
6
10
  // Plugin is the in-process equivalent of ttsc's native CLI sidecar.
7
11
  //
8
- // The native CLI invokes plugins by spawning their binary with argv (e.g.
9
- // `@ttsc/lint check --tsconfig=tsconfig.json --plugins-json=...`). Inside the
10
- // wasm there is no subprocess support, so the consumer wasm bundles plugin
11
- // code directly and exposes the same dispatch through Plugin.Run.
12
- //
13
- // A typical Plugin implementation in the consumer wasm is a thin adapter that
14
- // forwards to the same Run* function the native sidecar's `main.go` calls:
15
- //
16
- // type bannerPlugin struct{}
17
- //
18
- // func (bannerPlugin) Name() string { return "@ttsc/banner" }
19
- // func (bannerPlugin) Run(command string, args []string) int {
20
- // switch command {
21
- // case "build": return utility.RunBuild(args)
22
- // case "check": return utility.RunCheck(args)
23
- // case "transform": return utility.RunTransform(args)
24
- // default: return 2
25
- // }
26
- // }
27
- //
28
- // The host installs the package-level writers in `runWithCapturedIO` before
29
- // calling Run, so anything the plugin writes to ttsc's `stdout` / `stderr`
30
- // streams is captured and returned to the JS caller.
12
+ // The browser cannot spawn plugin binaries, so a consumer wasm links their Go
13
+ // adapters and registers them with Config. Every run receives invocation-owned
14
+ // streams; a plugin must write only to those streams, never os.Stdout or
15
+ // os.Stderr.
31
16
  type Plugin interface {
32
- // Name is the npm-style plugin id (e.g. `@ttsc/banner`). The JS side
33
- // passes this exact string when dispatching:
34
- // `api.plugin({ name: "@ttsc/banner", command: "build", ...opts })`.
35
- // Names must be unique within a Config.
17
+ // Name is the npm-style plugin id passed to api.plugin.
36
18
  Name() string
37
19
 
38
- // Run dispatches a subcommand. `command` is the verb the JS caller asked
39
- // for (typically build / check / transform / fix / format / version);
40
- // `args` is the rest of the argv, already prefixed with `--flag=value`
41
- // pairs the host built from the JS options object.
42
- //
43
- // Return the exit code (0 for success, 2 for compiler/config/usage errors, 3
44
- // for runtime errors mirrors the native CLI exit-code contract). Anything written
45
- // to `os.Stdout` / `os.Stderr` is captured by the host.
46
- //
47
- // API stability: experimental until v1.0; the signature is expected to
48
- // change to `Run(ctx *PluginContext) int` in a follow-up release.
49
- Run(command string, args []string) int
20
+ // Run dispatches one subcommand and returns the native CLI exit code.
21
+ Run(invocation *PluginInvocation) int
22
+ }
23
+
24
+ // PluginInvocation owns all mutable state for one plugin call.
25
+ //
26
+ // A plugin that needs asynchronous work must register it with Go before Run
27
+ // returns. InvokePlugin waits for every registered function. Registration
28
+ // after Run returns is rejected, and writes made after the invocation closes
29
+ // return io.ErrClosedPipe. This gives child goroutines an explicit ownership
30
+ // boundary without sharing process-global output state.
31
+ type PluginInvocation struct {
32
+ Context context.Context
33
+ Command string
34
+ Args []string
35
+ Stdout io.Writer
36
+ Stderr io.Writer
37
+
38
+ childrenMu sync.Mutex
39
+ children sync.WaitGroup
40
+ acceptingChild bool
41
+ }
42
+
43
+ // Go registers and starts invocation-owned asynchronous work. It returns false
44
+ // when Run has already returned and the ownership boundary is closed.
45
+ func (invocation *PluginInvocation) Go(task func(context.Context)) bool {
46
+ if task == nil {
47
+ return false
48
+ }
49
+ invocation.childrenMu.Lock()
50
+ if !invocation.acceptingChild {
51
+ invocation.childrenMu.Unlock()
52
+ return false
53
+ }
54
+ invocation.children.Add(1)
55
+ invocation.childrenMu.Unlock()
56
+ go func() {
57
+ defer invocation.children.Done()
58
+ task(invocation.Context)
59
+ }()
60
+ return true
61
+ }
62
+
63
+ // InvokePlugin executes one plugin call and captures its request-owned output.
64
+ // Independent invocations may run concurrently without sharing buffers.
65
+ func InvokePlugin(ctx context.Context, plugin Plugin, command string, args []string) APIResult {
66
+ if ctx == nil {
67
+ ctx = context.Background()
68
+ }
69
+ stdout := &invocationBuffer{}
70
+ stderr := &invocationBuffer{}
71
+ invocation := &PluginInvocation{
72
+ Context: ctx,
73
+ Command: command,
74
+ Args: append([]string(nil), args...),
75
+ Stdout: stdout,
76
+ Stderr: stderr,
77
+ acceptingChild: true,
78
+ }
79
+ code := plugin.Run(invocation)
80
+
81
+ invocation.childrenMu.Lock()
82
+ invocation.acceptingChild = false
83
+ invocation.childrenMu.Unlock()
84
+ invocation.children.Wait()
85
+
86
+ stdout.close()
87
+ stderr.close()
88
+ return APIResult{
89
+ Code: code,
90
+ Stdout: stdout.String(),
91
+ Stderr: stderr.String(),
92
+ }
50
93
  }
51
94
 
52
95
  // Config carries the optional registrations the host applies before binding
53
- // `globalThis[name]`. Pass `Config{}` for a vanilla ttsc + tsgo wasm.
96
+ // globalThis[name]. Pass Config{} for a vanilla ttsc + tsgo wasm.
54
97
  type Config struct {
55
- // Plugins are dispatched through `api.plugin({ name, command, ...opts })` from
56
- // JS. Their Run methods share the same `os.Stdout` / `os.Stderr` streams
57
- // the base build/check/transform endpoints use, so diagnostics render
58
- // the same way no matter which lane produced them.
59
98
  Plugins []Plugin
60
99
  }
100
+
101
+ // invocationBuffer serializes writers owned by one invocation. Closing it
102
+ // prevents an unregistered or late goroutine from modifying a completed result.
103
+ type invocationBuffer struct {
104
+ mu sync.Mutex
105
+ data bytes.Buffer
106
+ closed bool
107
+ }
108
+
109
+ func (buffer *invocationBuffer) Write(data []byte) (int, error) {
110
+ buffer.mu.Lock()
111
+ defer buffer.mu.Unlock()
112
+ if buffer.closed {
113
+ return 0, io.ErrClosedPipe
114
+ }
115
+ return buffer.data.Write(data)
116
+ }
117
+
118
+ func (buffer *invocationBuffer) String() string {
119
+ buffer.mu.Lock()
120
+ defer buffer.mu.Unlock()
121
+ return buffer.data.String()
122
+ }
123
+
124
+ func (buffer *invocationBuffer) close() {
125
+ buffer.mu.Lock()
126
+ buffer.closed = true
127
+ buffer.mu.Unlock()
128
+ }
@@ -30,6 +30,8 @@ function errnoForCode(code) {
30
30
  return -2;
31
31
  case "EBADF":
32
32
  return -9;
33
+ case "EBUSY":
34
+ return -16;
33
35
  case "EEXIST":
34
36
  return -17;
35
37
  case "ENOTDIR":
@@ -40,6 +42,8 @@ function errnoForCode(code) {
40
42
  return -22;
41
43
  case "ESPIPE":
42
44
  return -29;
45
+ case "ENOTEMPTY":
46
+ return -39;
43
47
  default:
44
48
  return -1;
45
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MemFSError.js","sourceRoot":"","sources":["../../src/MemFSError.ts"],"names":[],"mappings":";;;AAAA;;;;;;;GAOG;AACH,gBAAwB,SAAQ,KAAK;IAC5B,IAAI,CAAS;IACb,KAAK,CAAS;IACd,IAAI,CAAU;IACd,OAAO,CAAU;IACxB,YAAY,IAAY,EAAE,OAAe,EAAE,IAAa;QACtD,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,IAAI,IAAI,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;;AAED,kFAAkF;AAClF,SAAS,YAAY,CAAC,IAAY;IAChC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,CAAC,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,CAAC,CAAC,CAAC;QACZ,KAAK,QAAQ;YACX,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,EAAE,CAAC;QACb;YACE,OAAO,CAAC,CAAC,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"MemFSError.js","sourceRoot":"","sources":["../../src/MemFSError.ts"],"names":[],"mappings":";;;AAAA;;;;;;;GAOG;AACH,gBAAwB,SAAQ,KAAK;IAC5B,IAAI,CAAS;IACb,KAAK,CAAS;IACd,IAAI,CAAU;IACd,OAAO,CAAU;IACxB,YAAY,IAAY,EAAE,OAAe,EAAE,IAAa;QACtD,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,IAAI,IAAI,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAClD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;;AAED,kFAAkF;AAClF,SAAS,YAAY,CAAC,IAAY;IAChC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,CAAC,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,CAAC,CAAC,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,CAAC,EAAE,CAAC;QACb,KAAK,WAAW;YACd,OAAO,CAAC,EAAE,CAAC;QACb;YACE,OAAO,CAAC,CAAC,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -95,46 +95,102 @@ async function bootTtscOnce(options, apiName) {
95
95
  const wasmExecUrl = options.wasmExecUrl ?? defaultWasmExecUrl(wasmUrl);
96
96
  const host = options.host ?? (0, createMemFS_1.createMemFS)();
97
97
  const globalAny = globalThis;
98
- // Only install fs / process if they aren't already in place. A caller
99
- // booting a second wasm over the same MemFS reuses the same shims.
100
- if (!globalAny.fs)
98
+ // Install fs / process only if they aren't already in place, and remember
99
+ // whether THIS attempt installed them. The Go runtime this boot starts reads
100
+ // `globalThis.fs` when it runs, so the returned `host` must be the exact host
101
+ // backing those globals. A caller booting a second wasm over the same MemFS
102
+ // (or reusing one host across retries) reuses the same shims. When an earlier
103
+ // failed attempt already installed a different host's shims, those are torn
104
+ // down on failure below so this attempt can install its own.
105
+ const installedFs = !globalAny.fs;
106
+ const installedProcess = !globalAny.process;
107
+ let processShim;
108
+ if (installedFs)
101
109
  globalAny.fs = host.fs;
102
- if (!globalAny.process)
103
- globalAny.process = createProcessShim();
104
- // wasm_exec.js installs `globalThis.Go`. It also reads globalThis.fs at
105
- // module-eval time, so this import must follow the assignment above.
106
- importScripts(wasmExecUrl);
107
- // Race the Ready resolver against a Failed signal so a wasm-side fault
108
- // (e.g. `host.Expose` refusing a duplicate call) surfaces here instead of
109
- // hanging on `await ready` forever. `go.run` is fire-and-forget so its
110
- // own rejection cannot reach this promise without an explicit channel.
111
- const ready = new Promise((resolve, reject) => {
112
- globalAny[apiName + "Ready"] = () => {
113
- delete globalAny[apiName + "Failed"];
114
- resolve();
115
- };
116
- globalAny[apiName + "Failed"] = (err) => {
117
- delete globalAny[apiName + "Ready"];
118
- reject(err instanceof Error ? err : new Error(String(err)));
119
- };
120
- });
121
- const goCtor = globalAny.Go;
122
- if (typeof goCtor !== "function") {
123
- throw new Error(`bootTtsc: globalThis.Go was not installed by ${wasmExecUrl} — the file may not have loaded (CSP block, wrong content type, 404), or it is not the wasm_exec.js shipped with the Go toolchain.`);
110
+ if (installedProcess) {
111
+ processShim = createProcessShim();
112
+ globalAny.process = processShim;
124
113
  }
125
- const go = new goCtor();
126
- const response = await fetch(wasmUrl);
127
- if (!response.ok) {
128
- throw new Error(`bootTtsc: failed to fetch ${wasmUrl}: ${response.status}`);
114
+ // Any failure after global installation must leave the globals as this
115
+ // attempt found them, so a retry installs its own host's fs (and the returned
116
+ // host keeps matching the runtime's filesystem). Only remove what we
117
+ // installed and only while it is still ours — never stomp a foreign fs or one
118
+ // a concurrently-booted runtime already claimed.
119
+ const restoreGlobals = () => {
120
+ if (installedFs && globalAny.fs === host.fs)
121
+ delete globalAny.fs;
122
+ if (installedProcess && globalAny.process === processShim)
123
+ delete globalAny.process;
124
+ };
125
+ try {
126
+ // wasm_exec.js installs `globalThis.Go`. It also reads globalThis.fs at
127
+ // module-eval time, so this import must follow the assignment above.
128
+ importScripts(wasmExecUrl);
129
+ // Race the Ready resolver against a Failed signal so a wasm-side fault
130
+ // (e.g. `host.Expose` refusing a duplicate call) surfaces here instead of
131
+ // hanging on `await ready` forever.
132
+ let readyCb;
133
+ let failedCb;
134
+ const ready = new Promise((resolve, reject) => {
135
+ readyCb = () => {
136
+ delete globalAny[apiName + "Failed"];
137
+ resolve();
138
+ };
139
+ failedCb = (err) => {
140
+ delete globalAny[apiName + "Ready"];
141
+ reject(err instanceof Error ? err : new Error(String(err)));
142
+ };
143
+ globalAny[apiName + "Ready"] = readyCb;
144
+ globalAny[apiName + "Failed"] = failedCb;
145
+ });
146
+ const goCtor = globalAny.Go;
147
+ if (typeof goCtor !== "function") {
148
+ throw new Error(`bootTtsc: globalThis.Go was not installed by ${wasmExecUrl} — the file may not have loaded (CSP block, wrong content type, 404), or it is not the wasm_exec.js shipped with the Go toolchain.`);
149
+ }
150
+ const go = new goCtor();
151
+ const response = await fetch(wasmUrl);
152
+ if (!response.ok) {
153
+ throw new Error(`bootTtsc: failed to fetch ${wasmUrl}: ${response.status}`);
154
+ }
155
+ const wasm = await WebAssembly.instantiateStreaming(response, go.importObject);
156
+ // A normal host keeps `go.run` pending forever after signaling Ready, so a
157
+ // settlement (fulfil OR reject) BEFORE Ready means the Go runtime exited or
158
+ // panicked before it could register — e.g. an early `host.Expose` panic
159
+ // that never reached the Failed bridge. Race that early exit against
160
+ // readiness so the boot rejects with an actionable cause instead of hanging.
161
+ // The standard Go runner discards the exit code, so an unknown early exit
162
+ // can only synthesize a generic message; known host validation failures
163
+ // reject through Failed above and keep their original cause.
164
+ const runPromise = Promise.resolve(go.run(wasm.instance));
165
+ const earlyExit = runPromise.then(() => {
166
+ throw new Error(`bootTtsc: the ${apiName} wasm runtime exited before signaling readiness (the host may have panicked; check the wasm stderr).`);
167
+ }, (err) => {
168
+ throw new Error(`bootTtsc: the ${apiName} wasm runtime failed before signaling readiness: ${err instanceof Error ? err.message : String(err)}`);
169
+ });
170
+ // When Ready wins, the long-running runtime's eventual `go.run` settlement
171
+ // must not surface as an unhandled rejection. Attach a terminal handler to
172
+ // the losing branch.
173
+ earlyExit.catch(() => { });
174
+ try {
175
+ await Promise.race([ready, earlyExit]);
176
+ }
177
+ finally {
178
+ // Drop this attempt's readiness bridge so a later boot for the same
179
+ // apiName installs a clean pair and no stale resolver survives.
180
+ if (globalAny[apiName + "Ready"] === readyCb)
181
+ delete globalAny[apiName + "Ready"];
182
+ if (globalAny[apiName + "Failed"] === failedCb)
183
+ delete globalAny[apiName + "Failed"];
184
+ }
185
+ const api = globalAny[apiName];
186
+ if (!api)
187
+ throw new Error(`bootTtsc: ${apiName} global was not set — was the wasm built with host.Expose(${JSON.stringify(apiName)}, ...)?`);
188
+ return { api, host };
189
+ }
190
+ catch (err) {
191
+ restoreGlobals();
192
+ throw err;
129
193
  }
130
- const wasm = await WebAssembly.instantiateStreaming(response, go.importObject);
131
- // go.run never resolves until the wasm exits; we don't await it.
132
- void go.run(wasm.instance);
133
- await ready;
134
- const api = globalAny[apiName];
135
- if (!api)
136
- throw new Error(`bootTtsc: ${apiName} global was not set — was the wasm built with host.Expose(${JSON.stringify(apiName)}, ...)?`);
137
- return { api, host };
138
194
  }
139
195
  /**
140
196
  * Derive the `wasm_exec.js` URL from the wasm URL by replacing the filename.
@@ -1 +1 @@
1
- {"version":3,"file":"bootTtsc.js","sourceRoot":"","sources":["../../src/bootTtsc.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bootTtsc.js","sourceRoot":"","sources":["../../src/bootTtsc.ts"],"names":[],"mappings":"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"}