@godexture/js 0.0.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/LICENSE +21 -0
- package/dist/generated/go-main.d.ts +55 -0
- package/dist/generated/go-main.js +122 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +42 -0
- package/dist/main.wasm +0 -0
- package/dist/types.d.ts +113 -0
- package/dist/types.js +1 -0
- package/dist/wasm_exec.js +559 -0
- package/dist/worker.js +48 -0
- package/licenses/go.txt +27 -0
- package/package.json +32 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 godexture
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export declare class GoMain {
|
|
2
|
+
private worker;
|
|
3
|
+
private requestId;
|
|
4
|
+
private pending;
|
|
5
|
+
private nextCallbackId;
|
|
6
|
+
private callbacks;
|
|
7
|
+
private constructor();
|
|
8
|
+
static init(workerUrl: string): Promise<GoMain>;
|
|
9
|
+
terminate(): void;
|
|
10
|
+
private call;
|
|
11
|
+
private registerCallback;
|
|
12
|
+
/**
|
|
13
|
+
* Catalog returns the available demuxers, decoders, filters, encoders, and
|
|
14
|
+
* muxers, and which codecs each output format supports, as JSON.
|
|
15
|
+
*/
|
|
16
|
+
catalog(): Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* DescribeFilter resolves a filter's editable configuration and port topology
|
|
19
|
+
* for the given structural parameters.
|
|
20
|
+
*/
|
|
21
|
+
describeFilter(name: string, parameters: {
|
|
22
|
+
[key: string]: string;
|
|
23
|
+
}): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve negotiates a pipeline for inputs against the JSON-encoded spec
|
|
26
|
+
* without building or running it, returning the resolved node/edge topology
|
|
27
|
+
* as JSON. Used to preview a pipeline before starting a conversion.
|
|
28
|
+
*/
|
|
29
|
+
resolve(mainInput: Uint8Array, auxInputs: {
|
|
30
|
+
[key: string]: Uint8Array;
|
|
31
|
+
}, specJSON: string): Promise<string>;
|
|
32
|
+
/**
|
|
33
|
+
* Start negotiates, builds, and begins a conversion in the background under
|
|
34
|
+
* jobID (chosen by the caller, since Start's own return value only reaches
|
|
35
|
+
* JS once the conversion is done -- see reportProgress). onProgress is
|
|
36
|
+
* invoked with a JSON-encoded Progress a few times a second until the job
|
|
37
|
+
* finishes, and once more with the final outcome.
|
|
38
|
+
*/
|
|
39
|
+
start(jobID: string, mainInput: Uint8Array, auxInputs: {
|
|
40
|
+
[key: string]: Uint8Array;
|
|
41
|
+
}, specJSON: string, onProgress: (arg0: string) => void): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Snapshot reports a job's current progress and outcome as JSON.
|
|
44
|
+
*/
|
|
45
|
+
snapshot(jobID: string): Promise<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Cancel requests that a running job stop.
|
|
48
|
+
*/
|
|
49
|
+
cancel(jobID: string): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Result waits for a job to finish and returns its output bytes, releasing
|
|
52
|
+
* the job's resources. Call it at most once per job.
|
|
53
|
+
*/
|
|
54
|
+
result(jobID: string): Promise<Uint8Array>;
|
|
55
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// go-main.ts - Generated by gowasm-bindgen
|
|
2
|
+
// Package: main
|
|
3
|
+
export class GoMain {
|
|
4
|
+
worker;
|
|
5
|
+
requestId = 0;
|
|
6
|
+
pending = new Map();
|
|
7
|
+
nextCallbackId = 0;
|
|
8
|
+
callbacks = new Map();
|
|
9
|
+
constructor(worker) {
|
|
10
|
+
this.worker = worker;
|
|
11
|
+
}
|
|
12
|
+
static async init(workerUrl) {
|
|
13
|
+
const worker = new Worker(workerUrl);
|
|
14
|
+
const instance = new GoMain(worker);
|
|
15
|
+
await new Promise((resolve, reject) => {
|
|
16
|
+
worker.onmessage = (event) => {
|
|
17
|
+
const { type, id, result, error, callbackId, args } = event.data;
|
|
18
|
+
if (type === 'ready') {
|
|
19
|
+
resolve();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Handle callback invocations from Go
|
|
23
|
+
if (type === 'invokeCallback') {
|
|
24
|
+
const callback = instance.callbacks.get(callbackId);
|
|
25
|
+
if (callback) {
|
|
26
|
+
try {
|
|
27
|
+
callback(...args);
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
console.error('Callback error:', e);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const handler = instance.pending.get(id);
|
|
36
|
+
if (handler) {
|
|
37
|
+
instance.pending.delete(id);
|
|
38
|
+
if (error) {
|
|
39
|
+
handler.reject(new Error(error));
|
|
40
|
+
}
|
|
41
|
+
else if (result && typeof result === 'object' && '__error' in result) {
|
|
42
|
+
handler.reject(new Error(result.__error));
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
handler.resolve(result);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
worker.onerror = (e) => reject(new Error(e.message || 'Worker failed to load'));
|
|
50
|
+
});
|
|
51
|
+
return instance;
|
|
52
|
+
}
|
|
53
|
+
terminate() {
|
|
54
|
+
this.worker.terminate();
|
|
55
|
+
}
|
|
56
|
+
call(fn, args) {
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
const id = ++this.requestId;
|
|
59
|
+
this.pending.set(id, { resolve: resolve, reject });
|
|
60
|
+
this.worker.postMessage({ id, fn, args });
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
registerCallback(fn) {
|
|
64
|
+
const id = ++this.nextCallbackId;
|
|
65
|
+
this.callbacks.set(id, fn);
|
|
66
|
+
return id;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Catalog returns the available demuxers, decoders, filters, encoders, and
|
|
70
|
+
* muxers, and which codecs each output format supports, as JSON.
|
|
71
|
+
*/
|
|
72
|
+
catalog() {
|
|
73
|
+
return this.call("catalog", []);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* DescribeFilter resolves a filter's editable configuration and port topology
|
|
77
|
+
* for the given structural parameters.
|
|
78
|
+
*/
|
|
79
|
+
describeFilter(name, parameters) {
|
|
80
|
+
return this.call("describeFilter", [name, parameters]);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve negotiates a pipeline for inputs against the JSON-encoded spec
|
|
84
|
+
* without building or running it, returning the resolved node/edge topology
|
|
85
|
+
* as JSON. Used to preview a pipeline before starting a conversion.
|
|
86
|
+
*/
|
|
87
|
+
resolve(mainInput, auxInputs, specJSON) {
|
|
88
|
+
return this.call("resolve", [mainInput, auxInputs, specJSON]);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Start negotiates, builds, and begins a conversion in the background under
|
|
92
|
+
* jobID (chosen by the caller, since Start's own return value only reaches
|
|
93
|
+
* JS once the conversion is done -- see reportProgress). onProgress is
|
|
94
|
+
* invoked with a JSON-encoded Progress a few times a second until the job
|
|
95
|
+
* finishes, and once more with the final outcome.
|
|
96
|
+
*/
|
|
97
|
+
start(jobID, mainInput, auxInputs, specJSON, onProgress) {
|
|
98
|
+
const onProgressId = this.registerCallback(onProgress);
|
|
99
|
+
return this.call("start", [jobID, mainInput, auxInputs, specJSON, onProgressId]).finally(() => {
|
|
100
|
+
this.callbacks.delete(onProgressId);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Snapshot reports a job's current progress and outcome as JSON.
|
|
105
|
+
*/
|
|
106
|
+
snapshot(jobID) {
|
|
107
|
+
return this.call("snapshot", [jobID]);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Cancel requests that a running job stop.
|
|
111
|
+
*/
|
|
112
|
+
cancel(jobID) {
|
|
113
|
+
return this.call("cancel", [jobID]);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Result waits for a job to finish and returns its output bytes, releasing
|
|
117
|
+
* the job's resources. Call it at most once per job.
|
|
118
|
+
*/
|
|
119
|
+
result(jobID) {
|
|
120
|
+
return this.call("result", [jobID]);
|
|
121
|
+
}
|
|
122
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Catalog, ConversionSpec, FilterEntry, InputSet, PipelineDescription, Progress } from "./types";
|
|
2
|
+
export type { AuxInputSpec, Catalog, ConversionSpec, FilterEntry, FilterSpec, InputSet, JobStatus, NodeStatus, OutputFormat, PipelineDescription, PipelineEdge, PipelineNode, PluginEntry, PluginField, PluginSpec, PortRef, Progress, StreamInfo, } from "./types";
|
|
3
|
+
export declare class Godexture {
|
|
4
|
+
private goMain?;
|
|
5
|
+
init(workerUrl: string): Promise<void>;
|
|
6
|
+
terminate(): void;
|
|
7
|
+
private main;
|
|
8
|
+
getCatalog(): Promise<Catalog>;
|
|
9
|
+
describeFilter(name: string, parameters?: Record<string, string>): Promise<FilterEntry>;
|
|
10
|
+
resolvePipeline(inputs: InputSet, spec: ConversionSpec): Promise<PipelineDescription>;
|
|
11
|
+
start(jobId: string, inputs: InputSet, spec: ConversionSpec, onProgress: (progress: Progress) => void): Promise<string>;
|
|
12
|
+
snapshot(jobId: string): Promise<Progress>;
|
|
13
|
+
cancel(jobId: string): Promise<void>;
|
|
14
|
+
result(jobId: string): Promise<Uint8Array>;
|
|
15
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { GoMain } from "./generated/go-main";
|
|
2
|
+
export class Godexture {
|
|
3
|
+
goMain;
|
|
4
|
+
async init(workerUrl) {
|
|
5
|
+
if (this.goMain)
|
|
6
|
+
return;
|
|
7
|
+
this.goMain = await GoMain.init(workerUrl);
|
|
8
|
+
}
|
|
9
|
+
terminate() {
|
|
10
|
+
this.goMain?.terminate();
|
|
11
|
+
this.goMain = undefined;
|
|
12
|
+
}
|
|
13
|
+
main() {
|
|
14
|
+
if (!this.goMain) {
|
|
15
|
+
throw new Error("Godexture not initialized. Call init() first.");
|
|
16
|
+
}
|
|
17
|
+
return this.goMain;
|
|
18
|
+
}
|
|
19
|
+
async getCatalog() {
|
|
20
|
+
return JSON.parse(await this.main().catalog());
|
|
21
|
+
}
|
|
22
|
+
async describeFilter(name, parameters = {}) {
|
|
23
|
+
return JSON.parse(await this.main().describeFilter(name, parameters));
|
|
24
|
+
}
|
|
25
|
+
async resolvePipeline(inputs, spec) {
|
|
26
|
+
return JSON.parse(await this.main().resolve(inputs.main, inputs.aux ?? {}, JSON.stringify(spec)));
|
|
27
|
+
}
|
|
28
|
+
async start(jobId, inputs, spec, onProgress) {
|
|
29
|
+
return this.main().start(jobId, inputs.main, inputs.aux ?? {}, JSON.stringify(spec), (data) => {
|
|
30
|
+
onProgress(JSON.parse(data));
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async snapshot(jobId) {
|
|
34
|
+
return JSON.parse(await this.main().snapshot(jobId));
|
|
35
|
+
}
|
|
36
|
+
async cancel(jobId) {
|
|
37
|
+
await this.main().cancel(jobId);
|
|
38
|
+
}
|
|
39
|
+
async result(jobId) {
|
|
40
|
+
return this.main().result(jobId);
|
|
41
|
+
}
|
|
42
|
+
}
|
package/dist/main.wasm
ADDED
|
Binary file
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
export interface PluginField {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
help: string;
|
|
5
|
+
default: string;
|
|
6
|
+
choices?: string[];
|
|
7
|
+
dependsOn?: {
|
|
8
|
+
field: string;
|
|
9
|
+
values: string[];
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export interface PluginEntry {
|
|
13
|
+
role: string;
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
fields: PluginField[];
|
|
17
|
+
}
|
|
18
|
+
export interface FilterEntry extends PluginEntry {
|
|
19
|
+
parameters: PluginField[];
|
|
20
|
+
inputs: string[];
|
|
21
|
+
outputs: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface OutputFormat {
|
|
24
|
+
muxer: string;
|
|
25
|
+
extensions: string[];
|
|
26
|
+
codecs: string[];
|
|
27
|
+
defaultCodec: string;
|
|
28
|
+
}
|
|
29
|
+
export interface Catalog {
|
|
30
|
+
demuxers: PluginEntry[];
|
|
31
|
+
decoders: PluginEntry[];
|
|
32
|
+
filters: FilterEntry[];
|
|
33
|
+
encoders: PluginEntry[];
|
|
34
|
+
muxers: PluginEntry[];
|
|
35
|
+
outputs: OutputFormat[];
|
|
36
|
+
}
|
|
37
|
+
export interface PluginSpec {
|
|
38
|
+
name: string;
|
|
39
|
+
values?: Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
export interface PortRef {
|
|
42
|
+
alias: string;
|
|
43
|
+
port?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface FilterSpec extends PluginSpec {
|
|
46
|
+
alias?: string;
|
|
47
|
+
inputs?: Record<string, PortRef>;
|
|
48
|
+
parameters?: Record<string, string>;
|
|
49
|
+
}
|
|
50
|
+
export interface AuxInputSpec {
|
|
51
|
+
demuxer?: PluginSpec;
|
|
52
|
+
decoder?: PluginSpec;
|
|
53
|
+
}
|
|
54
|
+
export interface ConversionSpec {
|
|
55
|
+
demuxer?: PluginSpec;
|
|
56
|
+
decoder?: PluginSpec;
|
|
57
|
+
filters?: FilterSpec[];
|
|
58
|
+
auxInputs?: Record<string, AuxInputSpec>;
|
|
59
|
+
sink?: PortRef;
|
|
60
|
+
codec?: string;
|
|
61
|
+
encoder?: PluginSpec;
|
|
62
|
+
muxer: PluginSpec;
|
|
63
|
+
parallelism?: number;
|
|
64
|
+
}
|
|
65
|
+
export interface NodeStatus {
|
|
66
|
+
id: string;
|
|
67
|
+
role: string;
|
|
68
|
+
plugin: string;
|
|
69
|
+
autoInserted: boolean;
|
|
70
|
+
state: string;
|
|
71
|
+
elapsedMs: number;
|
|
72
|
+
error?: string;
|
|
73
|
+
}
|
|
74
|
+
export type JobStatus = "running" | "completed" | "failed" | "canceled";
|
|
75
|
+
export interface Progress {
|
|
76
|
+
status?: JobStatus;
|
|
77
|
+
error?: string;
|
|
78
|
+
percent: number;
|
|
79
|
+
processedMs: number;
|
|
80
|
+
totalMs: number;
|
|
81
|
+
processedItems: number;
|
|
82
|
+
speedRatio: number;
|
|
83
|
+
elapsedMs: number;
|
|
84
|
+
etaMs: number;
|
|
85
|
+
nodes: NodeStatus[];
|
|
86
|
+
}
|
|
87
|
+
export interface StreamInfo {
|
|
88
|
+
[key: string]: unknown;
|
|
89
|
+
}
|
|
90
|
+
export interface PipelineNode {
|
|
91
|
+
ID: string;
|
|
92
|
+
Role: string;
|
|
93
|
+
Plugin: string;
|
|
94
|
+
AutoInserted: boolean;
|
|
95
|
+
Inputs: StreamInfo[];
|
|
96
|
+
Outputs: StreamInfo[];
|
|
97
|
+
}
|
|
98
|
+
export interface PipelineEdge {
|
|
99
|
+
FromNode: string;
|
|
100
|
+
FromPort: string;
|
|
101
|
+
ToNode: string;
|
|
102
|
+
ToPort: string;
|
|
103
|
+
Stream: StreamInfo;
|
|
104
|
+
ProgressSource: boolean;
|
|
105
|
+
}
|
|
106
|
+
export interface PipelineDescription {
|
|
107
|
+
Nodes: PipelineNode[];
|
|
108
|
+
Edges: PipelineEdge[];
|
|
109
|
+
}
|
|
110
|
+
export interface InputSet {
|
|
111
|
+
main: Uint8Array;
|
|
112
|
+
aux?: Record<string, Uint8Array>;
|
|
113
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
// Copyright 2018 The Go Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
//
|
|
5
|
+
// This file has been modified for use by the TinyGo compiler.
|
|
6
|
+
|
|
7
|
+
(() => {
|
|
8
|
+
// Map multiple JavaScript environments to a single common API,
|
|
9
|
+
// preferring web standards over Node.js API.
|
|
10
|
+
//
|
|
11
|
+
// Environments considered:
|
|
12
|
+
// - Browsers
|
|
13
|
+
// - Node.js
|
|
14
|
+
// - Electron
|
|
15
|
+
// - Parcel
|
|
16
|
+
|
|
17
|
+
if (typeof global !== "undefined") {
|
|
18
|
+
// global already exists
|
|
19
|
+
} else if (typeof window !== "undefined") {
|
|
20
|
+
window.global = window;
|
|
21
|
+
} else if (typeof self !== "undefined") {
|
|
22
|
+
self.global = self;
|
|
23
|
+
} else {
|
|
24
|
+
throw new Error("cannot export Go (neither global, window nor self is defined)");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!global.require && typeof require !== "undefined") {
|
|
28
|
+
global.require = require;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!global.fs && global.require) {
|
|
32
|
+
global.fs = require("node:fs");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const enosys = () => {
|
|
36
|
+
const err = new Error("not implemented");
|
|
37
|
+
err.code = "ENOSYS";
|
|
38
|
+
return err;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (!global.fs) {
|
|
42
|
+
let outputBuf = "";
|
|
43
|
+
global.fs = {
|
|
44
|
+
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
|
|
45
|
+
writeSync(fd, buf) {
|
|
46
|
+
outputBuf += decoder.decode(buf);
|
|
47
|
+
const nl = outputBuf.lastIndexOf("\n");
|
|
48
|
+
if (nl != -1) {
|
|
49
|
+
console.log(outputBuf.substr(0, nl));
|
|
50
|
+
outputBuf = outputBuf.substr(nl + 1);
|
|
51
|
+
}
|
|
52
|
+
return buf.length;
|
|
53
|
+
},
|
|
54
|
+
write(fd, buf, offset, length, position, callback) {
|
|
55
|
+
if (offset !== 0 || length !== buf.length || position !== null) {
|
|
56
|
+
callback(enosys());
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const n = this.writeSync(fd, buf);
|
|
60
|
+
callback(null, n);
|
|
61
|
+
},
|
|
62
|
+
chmod(path, mode, callback) { callback(enosys()); },
|
|
63
|
+
chown(path, uid, gid, callback) { callback(enosys()); },
|
|
64
|
+
close(fd, callback) { callback(enosys()); },
|
|
65
|
+
fchmod(fd, mode, callback) { callback(enosys()); },
|
|
66
|
+
fchown(fd, uid, gid, callback) { callback(enosys()); },
|
|
67
|
+
fstat(fd, callback) { callback(enosys()); },
|
|
68
|
+
fsync(fd, callback) { callback(null); },
|
|
69
|
+
ftruncate(fd, length, callback) { callback(enosys()); },
|
|
70
|
+
lchown(path, uid, gid, callback) { callback(enosys()); },
|
|
71
|
+
link(path, link, callback) { callback(enosys()); },
|
|
72
|
+
lstat(path, callback) { callback(enosys()); },
|
|
73
|
+
mkdir(path, perm, callback) { callback(enosys()); },
|
|
74
|
+
open(path, flags, mode, callback) { callback(enosys()); },
|
|
75
|
+
read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
|
|
76
|
+
readdir(path, callback) { callback(enosys()); },
|
|
77
|
+
readlink(path, callback) { callback(enosys()); },
|
|
78
|
+
rename(from, to, callback) { callback(enosys()); },
|
|
79
|
+
rmdir(path, callback) { callback(enosys()); },
|
|
80
|
+
stat(path, callback) { callback(enosys()); },
|
|
81
|
+
symlink(path, link, callback) { callback(enosys()); },
|
|
82
|
+
truncate(path, length, callback) { callback(enosys()); },
|
|
83
|
+
unlink(path, callback) { callback(enosys()); },
|
|
84
|
+
utimes(path, atime, mtime, callback) { callback(enosys()); },
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!global.process) {
|
|
89
|
+
global.process = {
|
|
90
|
+
getuid() { return -1; },
|
|
91
|
+
getgid() { return -1; },
|
|
92
|
+
geteuid() { return -1; },
|
|
93
|
+
getegid() { return -1; },
|
|
94
|
+
getgroups() { throw enosys(); },
|
|
95
|
+
pid: -1,
|
|
96
|
+
ppid: -1,
|
|
97
|
+
umask() { throw enosys(); },
|
|
98
|
+
cwd() { throw enosys(); },
|
|
99
|
+
chdir() { throw enosys(); },
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!global.crypto) {
|
|
104
|
+
const nodeCrypto = require("node:crypto");
|
|
105
|
+
global.crypto = {
|
|
106
|
+
getRandomValues(b) {
|
|
107
|
+
nodeCrypto.randomFillSync(b);
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!global.performance) {
|
|
113
|
+
global.performance = {
|
|
114
|
+
now() {
|
|
115
|
+
const [sec, nsec] = process.hrtime();
|
|
116
|
+
return sec * 1000 + nsec / 1000000;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!global.TextEncoder) {
|
|
122
|
+
global.TextEncoder = require("node:util").TextEncoder;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!global.TextDecoder) {
|
|
126
|
+
global.TextDecoder = require("node:util").TextDecoder;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// End of polyfills for common API.
|
|
130
|
+
|
|
131
|
+
const encoder = new TextEncoder("utf-8");
|
|
132
|
+
const decoder = new TextDecoder("utf-8");
|
|
133
|
+
let reinterpretBuf = new DataView(new ArrayBuffer(8));
|
|
134
|
+
var logLine = [];
|
|
135
|
+
const wasmExit = {}; // thrown to exit via proc_exit (not an error)
|
|
136
|
+
|
|
137
|
+
global.Go = class {
|
|
138
|
+
constructor() {
|
|
139
|
+
this._callbackTimeouts = new Map();
|
|
140
|
+
this._nextCallbackTimeoutID = 1;
|
|
141
|
+
|
|
142
|
+
const mem = () => {
|
|
143
|
+
// The buffer may change when requesting more memory.
|
|
144
|
+
return new DataView(this._inst.exports.memory.buffer);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const unboxValue = (v_ref) => {
|
|
148
|
+
reinterpretBuf.setBigInt64(0, v_ref, true);
|
|
149
|
+
const f = reinterpretBuf.getFloat64(0, true);
|
|
150
|
+
if (f === 0) {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
if (!isNaN(f)) {
|
|
154
|
+
return f;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const id = v_ref & 0xffffffffn;
|
|
158
|
+
return this._values[id];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
const loadValue = (addr) => {
|
|
163
|
+
let v_ref = mem().getBigUint64(addr, true);
|
|
164
|
+
return unboxValue(v_ref);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const boxValue = (v) => {
|
|
168
|
+
const nanHead = 0x7FF80000n;
|
|
169
|
+
|
|
170
|
+
if (typeof v === "number") {
|
|
171
|
+
if (isNaN(v)) {
|
|
172
|
+
return nanHead << 32n;
|
|
173
|
+
}
|
|
174
|
+
if (v === 0) {
|
|
175
|
+
return (nanHead << 32n) | 1n;
|
|
176
|
+
}
|
|
177
|
+
reinterpretBuf.setFloat64(0, v, true);
|
|
178
|
+
return reinterpretBuf.getBigInt64(0, true);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
switch (v) {
|
|
182
|
+
case undefined:
|
|
183
|
+
return 0n;
|
|
184
|
+
case null:
|
|
185
|
+
return (nanHead << 32n) | 2n;
|
|
186
|
+
case true:
|
|
187
|
+
return (nanHead << 32n) | 3n;
|
|
188
|
+
case false:
|
|
189
|
+
return (nanHead << 32n) | 4n;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let id = this._ids.get(v);
|
|
193
|
+
if (id === undefined) {
|
|
194
|
+
id = this._idPool.pop();
|
|
195
|
+
if (id === undefined) {
|
|
196
|
+
id = BigInt(this._values.length);
|
|
197
|
+
}
|
|
198
|
+
this._values[id] = v;
|
|
199
|
+
this._goRefCounts[id] = 0;
|
|
200
|
+
this._ids.set(v, id);
|
|
201
|
+
}
|
|
202
|
+
this._goRefCounts[id]++;
|
|
203
|
+
let typeFlag = 1n;
|
|
204
|
+
switch (typeof v) {
|
|
205
|
+
case "string":
|
|
206
|
+
typeFlag = 2n;
|
|
207
|
+
break;
|
|
208
|
+
case "symbol":
|
|
209
|
+
typeFlag = 3n;
|
|
210
|
+
break;
|
|
211
|
+
case "function":
|
|
212
|
+
typeFlag = 4n;
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
return id | ((nanHead | typeFlag) << 32n);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const storeValue = (addr, v) => {
|
|
219
|
+
let v_ref = boxValue(v);
|
|
220
|
+
mem().setBigUint64(addr, v_ref, true);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const loadSlice = (array, len, cap) => {
|
|
224
|
+
return new Uint8Array(this._inst.exports.memory.buffer, array, len);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const loadSliceOfValues = (array, len, cap) => {
|
|
228
|
+
const a = new Array(len);
|
|
229
|
+
for (let i = 0; i < len; i++) {
|
|
230
|
+
a[i] = loadValue(array + i * 8);
|
|
231
|
+
}
|
|
232
|
+
return a;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const loadString = (ptr, len) => {
|
|
236
|
+
return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const timeOrigin = Date.now() - performance.now();
|
|
240
|
+
const wasi_EBADF = 8;
|
|
241
|
+
const wasi_ENOSYS = 52;
|
|
242
|
+
this.importObject = {
|
|
243
|
+
wasi_snapshot_preview1: {
|
|
244
|
+
// https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md
|
|
245
|
+
fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) {
|
|
246
|
+
let nwritten = 0;
|
|
247
|
+
if (fd == 1) {
|
|
248
|
+
for (let iovs_i=0; iovs_i<iovs_len;iovs_i++) {
|
|
249
|
+
let iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32
|
|
250
|
+
let ptr = mem().getUint32(iov_ptr + 0, true);
|
|
251
|
+
let len = mem().getUint32(iov_ptr + 4, true);
|
|
252
|
+
nwritten += len;
|
|
253
|
+
for (let i=0; i<len; i++) {
|
|
254
|
+
let c = mem().getUint8(ptr+i);
|
|
255
|
+
if (c == 13) { // CR
|
|
256
|
+
// ignore
|
|
257
|
+
} else if (c == 10) { // LF
|
|
258
|
+
// write line
|
|
259
|
+
let line = decoder.decode(new Uint8Array(logLine));
|
|
260
|
+
logLine = [];
|
|
261
|
+
console.log(line);
|
|
262
|
+
} else {
|
|
263
|
+
logLine.push(c);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
console.error('invalid file descriptor:', fd);
|
|
269
|
+
}
|
|
270
|
+
mem().setUint32(nwritten_ptr, nwritten, true);
|
|
271
|
+
return 0;
|
|
272
|
+
},
|
|
273
|
+
fd_read: () => wasi_ENOSYS,
|
|
274
|
+
fd_close: () => wasi_ENOSYS,
|
|
275
|
+
fd_fdstat_get: () => wasi_ENOSYS,
|
|
276
|
+
fd_prestat_get: () => wasi_EBADF, // wasi-libc relies on this errno value
|
|
277
|
+
fd_prestat_dir_name: () => wasi_ENOSYS,
|
|
278
|
+
fd_seek: () => wasi_ENOSYS,
|
|
279
|
+
path_open: () => wasi_ENOSYS,
|
|
280
|
+
proc_exit: (code) => {
|
|
281
|
+
this.exited = true;
|
|
282
|
+
this.exitCode = code;
|
|
283
|
+
this._resolveExitPromise();
|
|
284
|
+
throw wasmExit;
|
|
285
|
+
},
|
|
286
|
+
random_get: (bufPtr, bufLen) => {
|
|
287
|
+
crypto.getRandomValues(loadSlice(bufPtr, bufLen));
|
|
288
|
+
return 0;
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
gojs: {
|
|
292
|
+
// func ticks() int64
|
|
293
|
+
"runtime.ticks": () => {
|
|
294
|
+
return BigInt((timeOrigin + performance.now()) * 1e6);
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
// func sleepTicks(timeout int64)
|
|
298
|
+
"runtime.sleepTicks": (timeout) => {
|
|
299
|
+
// Do not sleep, only reactivate scheduler after the given timeout.
|
|
300
|
+
setTimeout(() => {
|
|
301
|
+
if (this.exited) return;
|
|
302
|
+
try {
|
|
303
|
+
this._inst.exports.go_scheduler();
|
|
304
|
+
} catch (e) {
|
|
305
|
+
if (e !== wasmExit) throw e;
|
|
306
|
+
}
|
|
307
|
+
}, Number(timeout)/1e6);
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
// func finalizeRef(v ref)
|
|
311
|
+
"syscall/js.finalizeRef": (v_ref) => {
|
|
312
|
+
// Note: TinyGo does not support finalizers so this is only called
|
|
313
|
+
// for one specific case, by js.go:jsString. and can/might leak memory.
|
|
314
|
+
const id = v_ref & 0xffffffffn;
|
|
315
|
+
if (this._goRefCounts?.[id] !== undefined) {
|
|
316
|
+
this._goRefCounts[id]--;
|
|
317
|
+
if (this._goRefCounts[id] === 0) {
|
|
318
|
+
const v = this._values[id];
|
|
319
|
+
this._values[id] = null;
|
|
320
|
+
this._ids.delete(v);
|
|
321
|
+
this._idPool.push(id);
|
|
322
|
+
}
|
|
323
|
+
} else {
|
|
324
|
+
console.error("syscall/js.finalizeRef: unknown id", id);
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
// func stringVal(value string) ref
|
|
329
|
+
"syscall/js.stringVal": (value_ptr, value_len) => {
|
|
330
|
+
value_ptr >>>= 0;
|
|
331
|
+
const s = loadString(value_ptr, value_len);
|
|
332
|
+
return boxValue(s);
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
// func valueGet(v ref, p string) ref
|
|
336
|
+
"syscall/js.valueGet": (v_ref, p_ptr, p_len) => {
|
|
337
|
+
let prop = loadString(p_ptr, p_len);
|
|
338
|
+
let v = unboxValue(v_ref);
|
|
339
|
+
let result = Reflect.get(v, prop);
|
|
340
|
+
return boxValue(result);
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
// func valueSet(v ref, p string, x ref)
|
|
344
|
+
"syscall/js.valueSet": (v_ref, p_ptr, p_len, x_ref) => {
|
|
345
|
+
const v = unboxValue(v_ref);
|
|
346
|
+
const p = loadString(p_ptr, p_len);
|
|
347
|
+
const x = unboxValue(x_ref);
|
|
348
|
+
Reflect.set(v, p, x);
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
// func valueDelete(v ref, p string)
|
|
352
|
+
"syscall/js.valueDelete": (v_ref, p_ptr, p_len) => {
|
|
353
|
+
const v = unboxValue(v_ref);
|
|
354
|
+
const p = loadString(p_ptr, p_len);
|
|
355
|
+
Reflect.deleteProperty(v, p);
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
// func valueIndex(v ref, i int) ref
|
|
359
|
+
"syscall/js.valueIndex": (v_ref, i) => {
|
|
360
|
+
return boxValue(Reflect.get(unboxValue(v_ref), i));
|
|
361
|
+
},
|
|
362
|
+
|
|
363
|
+
// valueSetIndex(v ref, i int, x ref)
|
|
364
|
+
"syscall/js.valueSetIndex": (v_ref, i, x_ref) => {
|
|
365
|
+
Reflect.set(unboxValue(v_ref), i, unboxValue(x_ref));
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
|
369
|
+
"syscall/js.valueCall": (ret_addr, v_ref, m_ptr, m_len, args_ptr, args_len, args_cap) => {
|
|
370
|
+
const v = unboxValue(v_ref);
|
|
371
|
+
const name = loadString(m_ptr, m_len);
|
|
372
|
+
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
|
373
|
+
try {
|
|
374
|
+
const m = Reflect.get(v, name);
|
|
375
|
+
storeValue(ret_addr, Reflect.apply(m, v, args));
|
|
376
|
+
mem().setUint8(ret_addr + 8, 1);
|
|
377
|
+
} catch (err) {
|
|
378
|
+
storeValue(ret_addr, err);
|
|
379
|
+
mem().setUint8(ret_addr + 8, 0);
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
|
|
383
|
+
// func valueInvoke(v ref, args []ref) (ref, bool)
|
|
384
|
+
"syscall/js.valueInvoke": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
|
|
385
|
+
try {
|
|
386
|
+
const v = unboxValue(v_ref);
|
|
387
|
+
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
|
388
|
+
storeValue(ret_addr, Reflect.apply(v, undefined, args));
|
|
389
|
+
mem().setUint8(ret_addr + 8, 1);
|
|
390
|
+
} catch (err) {
|
|
391
|
+
storeValue(ret_addr, err);
|
|
392
|
+
mem().setUint8(ret_addr + 8, 0);
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
|
|
396
|
+
// func valueNew(v ref, args []ref) (ref, bool)
|
|
397
|
+
"syscall/js.valueNew": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
|
|
398
|
+
const v = unboxValue(v_ref);
|
|
399
|
+
const args = loadSliceOfValues(args_ptr, args_len, args_cap);
|
|
400
|
+
try {
|
|
401
|
+
storeValue(ret_addr, Reflect.construct(v, args));
|
|
402
|
+
mem().setUint8(ret_addr + 8, 1);
|
|
403
|
+
} catch (err) {
|
|
404
|
+
storeValue(ret_addr, err);
|
|
405
|
+
mem().setUint8(ret_addr+ 8, 0);
|
|
406
|
+
}
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
// func valueLength(v ref) int
|
|
410
|
+
"syscall/js.valueLength": (v_ref) => {
|
|
411
|
+
return unboxValue(v_ref).length;
|
|
412
|
+
},
|
|
413
|
+
|
|
414
|
+
// valuePrepareString(v ref) (ref, int)
|
|
415
|
+
"syscall/js.valuePrepareString": (ret_addr, v_ref) => {
|
|
416
|
+
const s = String(unboxValue(v_ref));
|
|
417
|
+
const str = encoder.encode(s);
|
|
418
|
+
storeValue(ret_addr, str);
|
|
419
|
+
mem().setInt32(ret_addr + 8, str.length, true);
|
|
420
|
+
},
|
|
421
|
+
|
|
422
|
+
// valueLoadString(v ref, b []byte)
|
|
423
|
+
"syscall/js.valueLoadString": (v_ref, slice_ptr, slice_len, slice_cap) => {
|
|
424
|
+
const str = unboxValue(v_ref);
|
|
425
|
+
loadSlice(slice_ptr, slice_len, slice_cap).set(str);
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
// func valueInstanceOf(v ref, t ref) bool
|
|
429
|
+
"syscall/js.valueInstanceOf": (v_ref, t_ref) => {
|
|
430
|
+
return unboxValue(v_ref) instanceof unboxValue(t_ref);
|
|
431
|
+
},
|
|
432
|
+
|
|
433
|
+
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
|
434
|
+
"syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, src_ref) => {
|
|
435
|
+
let num_bytes_copied_addr = ret_addr;
|
|
436
|
+
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
|
|
437
|
+
|
|
438
|
+
const dst = loadSlice(dest_addr, dest_len);
|
|
439
|
+
const src = unboxValue(src_ref);
|
|
440
|
+
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
|
441
|
+
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
const toCopy = src.subarray(0, dst.length);
|
|
445
|
+
dst.set(toCopy);
|
|
446
|
+
mem().setUint32(num_bytes_copied_addr, toCopy.length, true);
|
|
447
|
+
mem().setUint8(returned_status_addr, 1); // Return "ok" status
|
|
448
|
+
},
|
|
449
|
+
|
|
450
|
+
// copyBytesToJS(dst ref, src []byte) (int, bool)
|
|
451
|
+
// Originally copied from upstream Go project, then modified:
|
|
452
|
+
// https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416
|
|
453
|
+
"syscall/js.copyBytesToJS": (ret_addr, dst_ref, src_addr, src_len, src_cap) => {
|
|
454
|
+
let num_bytes_copied_addr = ret_addr;
|
|
455
|
+
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
|
|
456
|
+
|
|
457
|
+
const dst = unboxValue(dst_ref);
|
|
458
|
+
const src = loadSlice(src_addr, src_len);
|
|
459
|
+
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
|
460
|
+
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const toCopy = src.subarray(0, dst.length);
|
|
464
|
+
dst.set(toCopy);
|
|
465
|
+
mem().setUint32(num_bytes_copied_addr, toCopy.length, true);
|
|
466
|
+
mem().setUint8(returned_status_addr, 1); // Return "ok" status
|
|
467
|
+
},
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
// Go 1.20 uses 'env'. Go 1.21 uses 'gojs'.
|
|
472
|
+
// For compatibility, we use both as long as Go 1.20 is supported.
|
|
473
|
+
this.importObject.env = this.importObject.gojs;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
async run(instance) {
|
|
477
|
+
this._inst = instance;
|
|
478
|
+
this._values = [ // JS values that Go currently has references to, indexed by reference id
|
|
479
|
+
NaN,
|
|
480
|
+
0,
|
|
481
|
+
null,
|
|
482
|
+
true,
|
|
483
|
+
false,
|
|
484
|
+
global,
|
|
485
|
+
this,
|
|
486
|
+
];
|
|
487
|
+
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
|
|
488
|
+
this._ids = new Map(); // mapping from JS values to reference ids
|
|
489
|
+
this._idPool = []; // unused ids that have been garbage collected
|
|
490
|
+
this.exited = false; // whether the Go program has exited
|
|
491
|
+
this.exitCode = 0;
|
|
492
|
+
|
|
493
|
+
if (this._inst.exports._start) {
|
|
494
|
+
let exitPromise = new Promise((resolve, reject) => {
|
|
495
|
+
this._resolveExitPromise = resolve;
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
// Run program, but catch the wasmExit exception that's thrown
|
|
499
|
+
// to return back here.
|
|
500
|
+
try {
|
|
501
|
+
this._inst.exports._start();
|
|
502
|
+
} catch (e) {
|
|
503
|
+
if (e !== wasmExit) throw e;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
await exitPromise;
|
|
507
|
+
return this.exitCode;
|
|
508
|
+
} else {
|
|
509
|
+
this._inst.exports._initialize();
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
_resume() {
|
|
514
|
+
if (this.exited) {
|
|
515
|
+
throw new Error("Go program has already exited");
|
|
516
|
+
}
|
|
517
|
+
try {
|
|
518
|
+
this._inst.exports.resume();
|
|
519
|
+
} catch (e) {
|
|
520
|
+
if (e !== wasmExit) throw e;
|
|
521
|
+
}
|
|
522
|
+
if (this.exited) {
|
|
523
|
+
this._resolveExitPromise();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
_makeFuncWrapper(id) {
|
|
528
|
+
const go = this;
|
|
529
|
+
return function () {
|
|
530
|
+
const event = { id: id, this: this, args: arguments };
|
|
531
|
+
go._pendingEvent = event;
|
|
532
|
+
go._resume();
|
|
533
|
+
return event.result;
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (
|
|
539
|
+
global.require &&
|
|
540
|
+
global.require.main === module &&
|
|
541
|
+
global.process &&
|
|
542
|
+
global.process.versions &&
|
|
543
|
+
!global.process.versions.electron
|
|
544
|
+
) {
|
|
545
|
+
if (process.argv.length != 3) {
|
|
546
|
+
console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
|
|
547
|
+
process.exit(1);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const go = new Go();
|
|
551
|
+
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then(async (result) => {
|
|
552
|
+
let exitCode = await go.run(result.instance);
|
|
553
|
+
process.exit(exitCode);
|
|
554
|
+
}).catch((err) => {
|
|
555
|
+
console.error(err);
|
|
556
|
+
process.exit(1);
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
})();
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Go WASM Web Worker
|
|
3
|
+
* Generated by gowasm-bindgen
|
|
4
|
+
*
|
|
5
|
+
* This worker loads the Go WASM module and handles function calls
|
|
6
|
+
* from the main thread via postMessage.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// Load Go WASM runtime
|
|
10
|
+
importScripts('wasm_exec.js');
|
|
11
|
+
|
|
12
|
+
const go = new Go();
|
|
13
|
+
let wasmReady = false;
|
|
14
|
+
|
|
15
|
+
// Global for Go to invoke callbacks (fire-and-forget)
|
|
16
|
+
// Go calls this to relay callback invocations to the main thread
|
|
17
|
+
self.invokeCallback = function(callbackId, args) {
|
|
18
|
+
self.postMessage({ type: 'invokeCallback', callbackId: callbackId, args: args });
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Initialize WASM
|
|
22
|
+
fetch('main.wasm')
|
|
23
|
+
.then(response => WebAssembly.instantiateStreaming(response, go.importObject))
|
|
24
|
+
.then(result => {
|
|
25
|
+
go.run(result.instance);
|
|
26
|
+
wasmReady = true;
|
|
27
|
+
self.postMessage({ type: 'ready' });
|
|
28
|
+
})
|
|
29
|
+
.catch(error => {
|
|
30
|
+
self.postMessage({ type: 'error', error: error.message });
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Handle function calls from main thread
|
|
34
|
+
self.onmessage = (event) => {
|
|
35
|
+
const { id, fn, args } = event.data;
|
|
36
|
+
|
|
37
|
+
if (!wasmReady) {
|
|
38
|
+
self.postMessage({ id, error: 'WASM not ready' });
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const result = self[fn](...args);
|
|
44
|
+
self.postMessage({ id, result });
|
|
45
|
+
} catch (error) {
|
|
46
|
+
self.postMessage({ id, error: error.message });
|
|
47
|
+
}
|
|
48
|
+
};
|
package/licenses/go.txt
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Copyright 2009 The Go Authors.
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions are
|
|
5
|
+
met:
|
|
6
|
+
|
|
7
|
+
* Redistributions of source code must retain the above copyright
|
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
|
9
|
+
* Redistributions in binary form must reproduce the above
|
|
10
|
+
copyright notice, this list of conditions and the following disclaimer
|
|
11
|
+
in the documentation and/or other materials provided with the
|
|
12
|
+
distribution.
|
|
13
|
+
* Neither the name of Google LLC nor the names of its
|
|
14
|
+
contributors may be used to endorse or promote products derived from
|
|
15
|
+
this software without specific prior written permission.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
18
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
19
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
20
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
21
|
+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
22
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
23
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
24
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
25
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
26
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
27
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@godexture/js",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "JavaScript/TypeScript bindings for godexture",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/godexture/bindings.git",
|
|
8
|
+
"directory": "js"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"licenses",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "bun build:wasm && bun build:ts",
|
|
20
|
+
"build:ts": "tsc -p tsconfig.app.json",
|
|
21
|
+
"build:wasm": "bun run scripts/build.ts",
|
|
22
|
+
"test": "bun run ./test"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/bun": "1.3.14",
|
|
26
|
+
"@types/node": "26.1.1",
|
|
27
|
+
"typescript": "7.0.2"
|
|
28
|
+
},
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public"
|
|
31
|
+
}
|
|
32
|
+
}
|