├── .github
└── workflows
│ └── main.yml
├── .gitignore
├── LICENSE
├── README.md
├── demo
├── index.html
├── labor.js
├── main.go
├── package.json
├── sw.js
├── wasm_exec.js
└── yarn.lock
├── download.go
├── go.mod
├── promise.go
├── request.go
├── response.go
└── serve.go
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: ci
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | build:
7 | runs-on: ubuntu-latest
8 |
9 | steps:
10 | - uses: actions/checkout@v2
11 | - run: curl https://purge.jsdelivr.net/gh/yisar/labor/sw.js
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 | *.html
8 | *.htm
9 |
10 | # Test binary, built with `go test -c`
11 | *.test
12 |
13 | # Output of the go coverage tool, specifically when used with LiteIDE
14 | *.out
15 |
16 | # Dependency directories (remove the comment below to include it)
17 | **/node_modules/
18 | demo/out.wasm
19 |
20 | # Other
21 | .DS_Store
22 | /.idea
23 |
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Labor
2 |
3 | Implementation of [Web Container](https://github.com/stackblitz/webcontainer-core)
4 |
5 | ### Run
6 |
7 | ```shell
8 | $ cd demo
9 | $ yarn build
10 | $ yarn dev
11 | ```
12 |
13 | ### Detail
14 |
15 | ```js
16 | code => js runtime => rust/go wasm API
17 | ```
18 |
19 | 举个例子
20 |
21 | ```js
22 | const res = await readFile('a.js')
23 | ```
24 | 这一句代码中的 `readFile` 最终是要执行到 rust/go 中的 API 的,但到底怎么将 go 的 API 注入进去的呢?
25 |
26 | 此时就需要 go 注入到全局一个 API
27 |
28 | ```go
29 | js.Global().Set("readFile", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
30 | readFile(args[0].String()) // 相当于 eval
31 | return nil
32 | }))
33 | ```
34 | 我们在 js 侧,只需要直接调用,不需要发接口
35 |
36 | ```js
37 | new Function('readFile', `const res = await readFile('a.js')`)(readFile)
38 | ```
39 | 大功告成,就是如此简单,在 wasm 端实现 API,然后在 js 侧注入到字符串里即可
40 |
41 | 但还没完,那么问题来了,文件系统呢?http呢?
42 |
43 | 这就得看 go 对 WASI 的支持程度了,亲测 `net/http` 包大部分支持良好,但不能启端口,`osutil` 包内存 API 是支持的
44 |
45 |
46 | demo 只是打个比方,这个项目我会用 go 写,因为 docker 也是用 go 写的
47 |
48 | 值得一提的是,为了获得更好的性能和大小,我们接下来会使用类似 [tinygo](https://github.com/tinygo-org/tinygo) 的编译器
49 |
50 | 但是 trip worker 我还是会用 rust 实现,理由和 deno 一样,所以本质上,同一套标准库,我得写两遍了,呜呜呜
51 |
52 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | demo
6 |
26 |
27 |
28 |
29 | Name:
30 | Hello
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/demo/labor.js:
--------------------------------------------------------------------------------
1 | importScripts('./wasm_exec.js')
2 |
3 | self.labor = {
4 | http: {},
5 | fs: {},
6 | }
7 |
8 | function registerLaborListener(wasm, { base, args = [] } = {}) {
9 | let path = new URL(registration.scope).pathname
10 | if (base && base !== '') path = `${trimEnd(path, '/')}/${trimStart(base, '/')}`
11 |
12 | const handlerPromise = new Promise(setHandler => {
13 | self.labor.path = path
14 | self.labor.setHandler = setHandler
15 | })
16 |
17 | addEventListener('fetch', e => {
18 | const { pathname } = new URL(e.request.url)
19 | if (!pathname.startsWith(path)) return
20 | e.respondWith(handlerPromise.then(handler => handler(e.request)))
21 | })
22 |
23 | return new Promise((resolve) => {
24 | const go = new Go()
25 | go.argv = [wasm, ...args]
26 | WebAssembly.instantiateStreaming(fetch(wasm), go.importObject).then(({ instance }) => {
27 | go.run(instance)
28 | resolve(self.labor)
29 | })
30 | })
31 | }
32 |
33 | function excute(script){
34 | new Function('labor', `with(labor){${script}}`)(self.labor)
35 | }
36 |
37 | function trimStart(s, c) {
38 | let r = s
39 | while (r.startsWith(c)) r = r.slice(c.length)
40 | return r
41 | }
42 |
43 | function trimEnd(s, c) {
44 | let r = s
45 | while (r.endsWith(c)) r = r.slice(0, -c.length)
46 | return r
47 | }
48 |
49 | self.labor.require = (path) => {
50 | if (path in self.labor) {
51 | return self.labor[path]
52 | }
53 | }
--------------------------------------------------------------------------------
/demo/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "encoding/json"
5 | "fmt"
6 | "net/http"
7 | "syscall/js"
8 |
9 | labor "github.com/yisar/labor"
10 | )
11 |
12 | func main() {
13 |
14 | js.Global().Get("labor").Get("http").Set("get", js.FuncOf(func (this js.Value, args []js.Value) interface{} {
15 | path := args[0].String()
16 | httpGet(path)
17 | return nil
18 | }))
19 |
20 | js.Global().Get("labor").Get("http").Set("serve", js.FuncOf(func (this js.Value, args []js.Value) interface{} {
21 | labor.Serve(nil)
22 | return nil
23 | }))
24 |
25 | js.Global().Get("labor").Get("http").Set("download", js.FuncOf(func (this js.Value, args []js.Value) interface{} {
26 | body := labor.Download(args[0].String())
27 | return body
28 | }))
29 |
30 | select {}
31 | }
32 |
33 | func httpGet(path string) interface{}{
34 | http.HandleFunc(path, func(res http.ResponseWriter, req *http.Request) {
35 | params := make(map[string]string)
36 | if err := json.NewDecoder(req.Body).Decode(¶ms); err != nil {
37 | panic(err)
38 | }
39 |
40 | res.Header().Add("Content-Type", "application/json")
41 | if err := json.NewEncoder(res).Encode(map[string]string{
42 | "message": fmt.Sprintf("Hello %s!", params["name"]),
43 | }); err != nil {
44 | panic(err)
45 | }
46 | })
47 | return nil
48 | }
--------------------------------------------------------------------------------
/demo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "sw.js",
6 | "scripts": {
7 | "build": "cross-env GOOS=js GOARCH=wasm go build -o out.wasm main.go",
8 | "dev": "serve ."
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "cross-env": "^7.0.3",
15 | "serve": "^11.3.2"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/demo/sw.js:
--------------------------------------------------------------------------------
1 | importScripts('./labor.js')
2 |
3 | addEventListener('install', (event) => {
4 | event.waitUntil(skipWaiting())
5 | })
6 |
7 | addEventListener('activate', event => {
8 | event.waitUntil(clients.claim())
9 | })
10 |
11 | registerLaborListener('out.wasm', { base: 'api' }).then((labor) => {
12 | excute(`
13 | const http = require('http')
14 | http.get('/hello')
15 | http.serve()
16 | `)
17 |
18 | // const buffer = self.labor.http.download('https://berial.vercel.app')
19 | // console.log(buffer)
20 | })
21 |
--------------------------------------------------------------------------------
/demo/wasm_exec.js:
--------------------------------------------------------------------------------
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 | (() => {
6 | // Map multiple JavaScript environments to a single common API,
7 | // preferring web standards over Node.js API.
8 | //
9 | // Environments considered:
10 | // - Browsers
11 | // - Node.js
12 | // - Electron
13 | // - Parcel
14 | // - Webpack
15 |
16 | if (typeof global !== "undefined") {
17 | // global already exists
18 | } else if (typeof window !== "undefined") {
19 | window.global = window;
20 | } else if (typeof self !== "undefined") {
21 | self.global = self;
22 | } else {
23 | throw new Error("cannot export Go (neither global, window nor self is defined)");
24 | }
25 |
26 | if (!global.require && typeof require !== "undefined") {
27 | global.require = require;
28 | }
29 |
30 | if (!global.fs && global.require) {
31 | const fs = require("fs");
32 | if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) {
33 | global.fs = fs;
34 | }
35 | }
36 |
37 | const enosys = () => {
38 | const err = new Error("not implemented");
39 | err.code = "ENOSYS";
40 | return err;
41 | };
42 |
43 | if (!global.fs) {
44 | let outputBuf = "";
45 | global.fs = {
46 | constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
47 | writeSync(fd, buf) {
48 | outputBuf += decoder.decode(buf);
49 | const nl = outputBuf.lastIndexOf("\n");
50 | if (nl != -1) {
51 | console.log(outputBuf.substr(0, nl));
52 | outputBuf = outputBuf.substr(nl + 1);
53 | }
54 | return buf.length;
55 | },
56 | write(fd, buf, offset, length, position, callback) {
57 | if (offset !== 0 || length !== buf.length || position !== null) {
58 | callback(enosys());
59 | return;
60 | }
61 | const n = this.writeSync(fd, buf);
62 | callback(null, n);
63 | },
64 | chmod(path, mode, callback) { callback(enosys()); },
65 | chown(path, uid, gid, callback) { callback(enosys()); },
66 | close(fd, callback) { callback(enosys()); },
67 | fchmod(fd, mode, callback) { callback(enosys()); },
68 | fchown(fd, uid, gid, callback) { callback(enosys()); },
69 | fstat(fd, callback) { callback(enosys()); },
70 | fsync(fd, callback) { callback(null); },
71 | ftruncate(fd, length, callback) { callback(enosys()); },
72 | lchown(path, uid, gid, callback) { callback(enosys()); },
73 | link(path, link, callback) { callback(enosys()); },
74 | lstat(path, callback) { callback(enosys()); },
75 | mkdir(path, perm, callback) { callback(enosys()); },
76 | open(path, flags, mode, callback) { callback(enosys()); },
77 | read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
78 | readdir(path, callback) { callback(enosys()); },
79 | readlink(path, callback) { callback(enosys()); },
80 | rename(from, to, callback) { callback(enosys()); },
81 | rmdir(path, callback) { callback(enosys()); },
82 | stat(path, callback) { callback(enosys()); },
83 | symlink(path, link, callback) { callback(enosys()); },
84 | truncate(path, length, callback) { callback(enosys()); },
85 | unlink(path, callback) { callback(enosys()); },
86 | utimes(path, atime, mtime, callback) { callback(enosys()); },
87 | };
88 | }
89 |
90 | if (!global.process) {
91 | global.process = {
92 | getuid() { return -1; },
93 | getgid() { return -1; },
94 | geteuid() { return -1; },
95 | getegid() { return -1; },
96 | getgroups() { throw enosys(); },
97 | pid: -1,
98 | ppid: -1,
99 | umask() { throw enosys(); },
100 | cwd() { throw enosys(); },
101 | chdir() { throw enosys(); },
102 | }
103 | }
104 |
105 | if (!global.crypto && global.require) {
106 | const nodeCrypto = require("crypto");
107 | global.crypto = {
108 | getRandomValues(b) {
109 | nodeCrypto.randomFillSync(b);
110 | },
111 | };
112 | }
113 | if (!global.crypto) {
114 | throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
115 | }
116 |
117 | if (!global.performance) {
118 | global.performance = {
119 | now() {
120 | const [sec, nsec] = process.hrtime();
121 | return sec * 1000 + nsec / 1000000;
122 | },
123 | };
124 | }
125 |
126 | if (!global.TextEncoder && global.require) {
127 | global.TextEncoder = require("util").TextEncoder;
128 | }
129 | if (!global.TextEncoder) {
130 | throw new Error("global.TextEncoder is not available, polyfill required");
131 | }
132 |
133 | if (!global.TextDecoder && global.require) {
134 | global.TextDecoder = require("util").TextDecoder;
135 | }
136 | if (!global.TextDecoder) {
137 | throw new Error("global.TextDecoder is not available, polyfill required");
138 | }
139 |
140 | // End of polyfills for common API.
141 |
142 | const encoder = new TextEncoder("utf-8");
143 | const decoder = new TextDecoder("utf-8");
144 |
145 | global.Go = class {
146 | constructor() {
147 | this.argv = ["js"];
148 | this.env = {};
149 | this.exit = (code) => {
150 | if (code !== 0) {
151 | console.warn("exit code:", code);
152 | }
153 | };
154 | this._exitPromise = new Promise((resolve) => {
155 | this._resolveExitPromise = resolve;
156 | });
157 | this._pendingEvent = null;
158 | this._scheduledTimeouts = new Map();
159 | this._nextCallbackTimeoutID = 1;
160 |
161 | const setInt64 = (addr, v) => {
162 | this.mem.setUint32(addr + 0, v, true);
163 | this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
164 | }
165 |
166 | const getInt64 = (addr) => {
167 | const low = this.mem.getUint32(addr + 0, true);
168 | const high = this.mem.getInt32(addr + 4, true);
169 | return low + high * 4294967296;
170 | }
171 |
172 | const loadValue = (addr) => {
173 | const f = this.mem.getFloat64(addr, true);
174 | if (f === 0) {
175 | return undefined;
176 | }
177 | if (!isNaN(f)) {
178 | return f;
179 | }
180 |
181 | const id = this.mem.getUint32(addr, true);
182 | return this._values[id];
183 | }
184 |
185 | const storeValue = (addr, v) => {
186 | const nanHead = 0x7FF80000;
187 |
188 | if (typeof v === "number" && v !== 0) {
189 | if (isNaN(v)) {
190 | this.mem.setUint32(addr + 4, nanHead, true);
191 | this.mem.setUint32(addr, 0, true);
192 | return;
193 | }
194 | this.mem.setFloat64(addr, v, true);
195 | return;
196 | }
197 |
198 | if (v === undefined) {
199 | this.mem.setFloat64(addr, 0, true);
200 | return;
201 | }
202 |
203 | let id = this._ids.get(v);
204 | if (id === undefined) {
205 | id = this._idPool.pop();
206 | if (id === undefined) {
207 | id = this._values.length;
208 | }
209 | this._values[id] = v;
210 | this._goRefCounts[id] = 0;
211 | this._ids.set(v, id);
212 | }
213 | this._goRefCounts[id]++;
214 | let typeFlag = 0;
215 | switch (typeof v) {
216 | case "object":
217 | if (v !== null) {
218 | typeFlag = 1;
219 | }
220 | break;
221 | case "string":
222 | typeFlag = 2;
223 | break;
224 | case "symbol":
225 | typeFlag = 3;
226 | break;
227 | case "function":
228 | typeFlag = 4;
229 | break;
230 | }
231 | this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
232 | this.mem.setUint32(addr, id, true);
233 | }
234 |
235 | const loadSlice = (addr) => {
236 | const array = getInt64(addr + 0);
237 | const len = getInt64(addr + 8);
238 | return new Uint8Array(this._inst.exports.mem.buffer, array, len);
239 | }
240 |
241 | const loadSliceOfValues = (addr) => {
242 | const array = getInt64(addr + 0);
243 | const len = getInt64(addr + 8);
244 | const a = new Array(len);
245 | for (let i = 0; i < len; i++) {
246 | a[i] = loadValue(array + i * 8);
247 | }
248 | return a;
249 | }
250 |
251 | const loadString = (addr) => {
252 | const saddr = getInt64(addr + 0);
253 | const len = getInt64(addr + 8);
254 | return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
255 | }
256 |
257 | const timeOrigin = Date.now() - performance.now();
258 | this.importObject = {
259 | go: {
260 | // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
261 | // may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
262 | // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
263 | // This changes the SP, thus we have to update the SP used by the imported function.
264 |
265 | // func wasmExit(code int32)
266 | "runtime.wasmExit": (sp) => {
267 | sp >>>= 0;
268 | const code = this.mem.getInt32(sp + 8, true);
269 | this.exited = true;
270 | delete this._inst;
271 | delete this._values;
272 | delete this._goRefCounts;
273 | delete this._ids;
274 | delete this._idPool;
275 | this.exit(code);
276 | },
277 |
278 | // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
279 | "runtime.wasmWrite": (sp) => {
280 | sp >>>= 0;
281 | const fd = getInt64(sp + 8);
282 | const p = getInt64(sp + 16);
283 | const n = this.mem.getInt32(sp + 24, true);
284 | fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
285 | },
286 |
287 | // func resetMemoryDataView()
288 | "runtime.resetMemoryDataView": (sp) => {
289 | sp >>>= 0;
290 | this.mem = new DataView(this._inst.exports.mem.buffer);
291 | },
292 |
293 | // func nanotime1() int64
294 | "runtime.nanotime1": (sp) => {
295 | sp >>>= 0;
296 | setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
297 | },
298 |
299 | // func walltime1() (sec int64, nsec int32)
300 | "runtime.walltime1": (sp) => {
301 | sp >>>= 0;
302 | const msec = (new Date).getTime();
303 | setInt64(sp + 8, msec / 1000);
304 | this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
305 | },
306 |
307 | // func scheduleTimeoutEvent(delay int64) int32
308 | "runtime.scheduleTimeoutEvent": (sp) => {
309 | sp >>>= 0;
310 | const id = this._nextCallbackTimeoutID;
311 | this._nextCallbackTimeoutID++;
312 | this._scheduledTimeouts.set(id, setTimeout(
313 | () => {
314 | this._resume();
315 | while (this._scheduledTimeouts.has(id)) {
316 | // for some reason Go failed to register the timeout event, log and try again
317 | // (temporary workaround for https://github.com/golang/go/issues/28975)
318 | console.warn("scheduleTimeoutEvent: missed timeout event");
319 | this._resume();
320 | }
321 | },
322 | getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
323 | ));
324 | this.mem.setInt32(sp + 16, id, true);
325 | },
326 |
327 | // func clearTimeoutEvent(id int32)
328 | "runtime.clearTimeoutEvent": (sp) => {
329 | sp >>>= 0;
330 | const id = this.mem.getInt32(sp + 8, true);
331 | clearTimeout(this._scheduledTimeouts.get(id));
332 | this._scheduledTimeouts.delete(id);
333 | },
334 |
335 | // func getRandomData(r []byte)
336 | "runtime.getRandomData": (sp) => {
337 | sp >>>= 0;
338 | crypto.getRandomValues(loadSlice(sp + 8));
339 | },
340 |
341 | // func finalizeRef(v ref)
342 | "syscall/js.finalizeRef": (sp) => {
343 | sp >>>= 0;
344 | const id = this.mem.getUint32(sp + 8, true);
345 | this._goRefCounts[id]--;
346 | if (this._goRefCounts[id] === 0) {
347 | const v = this._values[id];
348 | this._values[id] = null;
349 | this._ids.delete(v);
350 | this._idPool.push(id);
351 | }
352 | },
353 |
354 | // func stringVal(value string) ref
355 | "syscall/js.stringVal": (sp) => {
356 | sp >>>= 0;
357 | storeValue(sp + 24, loadString(sp + 8));
358 | },
359 |
360 | // func valueGet(v ref, p string) ref
361 | "syscall/js.valueGet": (sp) => {
362 | sp >>>= 0;
363 | const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
364 | sp = this._inst.exports.getsp() >>> 0; // see comment above
365 | storeValue(sp + 32, result);
366 | },
367 |
368 | // func valueSet(v ref, p string, x ref)
369 | "syscall/js.valueSet": (sp) => {
370 | sp >>>= 0;
371 | Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
372 | },
373 |
374 | // func valueDelete(v ref, p string)
375 | "syscall/js.valueDelete": (sp) => {
376 | sp >>>= 0;
377 | Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
378 | },
379 |
380 | // func valueIndex(v ref, i int) ref
381 | "syscall/js.valueIndex": (sp) => {
382 | sp >>>= 0;
383 | storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
384 | },
385 |
386 | // valueSetIndex(v ref, i int, x ref)
387 | "syscall/js.valueSetIndex": (sp) => {
388 | sp >>>= 0;
389 | Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
390 | },
391 |
392 | // func valueCall(v ref, m string, args []ref) (ref, bool)
393 | "syscall/js.valueCall": (sp) => {
394 | sp >>>= 0;
395 | try {
396 | const v = loadValue(sp + 8);
397 | const m = Reflect.get(v, loadString(sp + 16));
398 | const args = loadSliceOfValues(sp + 32);
399 | const result = Reflect.apply(m, v, args);
400 | sp = this._inst.exports.getsp() >>> 0; // see comment above
401 | storeValue(sp + 56, result);
402 | this.mem.setUint8(sp + 64, 1);
403 | } catch (err) {
404 | storeValue(sp + 56, err);
405 | this.mem.setUint8(sp + 64, 0);
406 | }
407 | },
408 |
409 | // func valueInvoke(v ref, args []ref) (ref, bool)
410 | "syscall/js.valueInvoke": (sp) => {
411 | sp >>>= 0;
412 | try {
413 | const v = loadValue(sp + 8);
414 | const args = loadSliceOfValues(sp + 16);
415 | const result = Reflect.apply(v, undefined, args);
416 | sp = this._inst.exports.getsp() >>> 0; // see comment above
417 | storeValue(sp + 40, result);
418 | this.mem.setUint8(sp + 48, 1);
419 | } catch (err) {
420 | storeValue(sp + 40, err);
421 | this.mem.setUint8(sp + 48, 0);
422 | }
423 | },
424 |
425 | // func valueNew(v ref, args []ref) (ref, bool)
426 | "syscall/js.valueNew": (sp) => {
427 | sp >>>= 0;
428 | try {
429 | const v = loadValue(sp + 8);
430 | const args = loadSliceOfValues(sp + 16);
431 | const result = Reflect.construct(v, args);
432 | sp = this._inst.exports.getsp() >>> 0; // see comment above
433 | storeValue(sp + 40, result);
434 | this.mem.setUint8(sp + 48, 1);
435 | } catch (err) {
436 | storeValue(sp + 40, err);
437 | this.mem.setUint8(sp + 48, 0);
438 | }
439 | },
440 |
441 | // func valueLength(v ref) int
442 | "syscall/js.valueLength": (sp) => {
443 | sp >>>= 0;
444 | setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
445 | },
446 |
447 | // valuePrepareString(v ref) (ref, int)
448 | "syscall/js.valuePrepareString": (sp) => {
449 | sp >>>= 0;
450 | const str = encoder.encode(String(loadValue(sp + 8)));
451 | storeValue(sp + 16, str);
452 | setInt64(sp + 24, str.length);
453 | },
454 |
455 | // valueLoadString(v ref, b []byte)
456 | "syscall/js.valueLoadString": (sp) => {
457 | sp >>>= 0;
458 | const str = loadValue(sp + 8);
459 | loadSlice(sp + 16).set(str);
460 | },
461 |
462 | // func valueInstanceOf(v ref, t ref) bool
463 | "syscall/js.valueInstanceOf": (sp) => {
464 | sp >>>= 0;
465 | this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
466 | },
467 |
468 | // func copyBytesToGo(dst []byte, src ref) (int, bool)
469 | "syscall/js.copyBytesToGo": (sp) => {
470 | sp >>>= 0;
471 | const dst = loadSlice(sp + 8);
472 | const src = loadValue(sp + 32);
473 | if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
474 | this.mem.setUint8(sp + 48, 0);
475 | return;
476 | }
477 | const toCopy = src.subarray(0, dst.length);
478 | dst.set(toCopy);
479 | setInt64(sp + 40, toCopy.length);
480 | this.mem.setUint8(sp + 48, 1);
481 | },
482 |
483 | // func copyBytesToJS(dst ref, src []byte) (int, bool)
484 | "syscall/js.copyBytesToJS": (sp) => {
485 | sp >>>= 0;
486 | const dst = loadValue(sp + 8);
487 | const src = loadSlice(sp + 16);
488 | if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
489 | this.mem.setUint8(sp + 48, 0);
490 | return;
491 | }
492 | const toCopy = src.subarray(0, dst.length);
493 | dst.set(toCopy);
494 | setInt64(sp + 40, toCopy.length);
495 | this.mem.setUint8(sp + 48, 1);
496 | },
497 |
498 | "debug": (value) => {
499 | console.log(value);
500 | },
501 | }
502 | };
503 | }
504 |
505 | async run(instance) {
506 | if (!(instance instanceof WebAssembly.Instance)) {
507 | throw new Error("Go.run: WebAssembly.Instance expected");
508 | }
509 | this._inst = instance;
510 | this.mem = new DataView(this._inst.exports.mem.buffer);
511 | this._values = [ // JS values that Go currently has references to, indexed by reference id
512 | NaN,
513 | 0,
514 | null,
515 | true,
516 | false,
517 | global,
518 | this,
519 | ];
520 | this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
521 | this._ids = new Map([ // mapping from JS values to reference ids
522 | [0, 1],
523 | [null, 2],
524 | [true, 3],
525 | [false, 4],
526 | [global, 5],
527 | [this, 6],
528 | ]);
529 | this._idPool = []; // unused ids that have been garbage collected
530 | this.exited = false; // whether the Go program has exited
531 |
532 | // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
533 | let offset = 4096;
534 |
535 | const strPtr = (str) => {
536 | const ptr = offset;
537 | const bytes = encoder.encode(str + "\0");
538 | new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
539 | offset += bytes.length;
540 | if (offset % 8 !== 0) {
541 | offset += 8 - (offset % 8);
542 | }
543 | return ptr;
544 | };
545 |
546 | const argc = this.argv.length;
547 |
548 | const argvPtrs = [];
549 | this.argv.forEach((arg) => {
550 | argvPtrs.push(strPtr(arg));
551 | });
552 | argvPtrs.push(0);
553 |
554 | const keys = Object.keys(this.env).sort();
555 | keys.forEach((key) => {
556 | argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
557 | });
558 | argvPtrs.push(0);
559 |
560 | const argv = offset;
561 | argvPtrs.forEach((ptr) => {
562 | this.mem.setUint32(offset, ptr, true);
563 | this.mem.setUint32(offset + 4, 0, true);
564 | offset += 8;
565 | });
566 |
567 | this._inst.exports.run(argc, argv);
568 | if (this.exited) {
569 | this._resolveExitPromise();
570 | }
571 | await this._exitPromise;
572 | }
573 |
574 | _resume() {
575 | if (this.exited) {
576 | throw new Error("Go program has already exited");
577 | }
578 | this._inst.exports.resume();
579 | if (this.exited) {
580 | this._resolveExitPromise();
581 | }
582 | }
583 |
584 | _makeFuncWrapper(id) {
585 | const go = this;
586 | return function () {
587 | const event = { id: id, this: this, args: arguments };
588 | go._pendingEvent = event;
589 | go._resume();
590 | return event.result;
591 | };
592 | }
593 | }
594 |
595 | if (
596 | typeof module !== "undefined" &&
597 | global.require &&
598 | global.require.main === module &&
599 | global.process &&
600 | global.process.versions &&
601 | !global.process.versions.electron
602 | ) {
603 | if (process.argv.length < 3) {
604 | console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
605 | process.exit(1);
606 | }
607 |
608 | const go = new Go();
609 | go.argv = process.argv.slice(2);
610 | go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
611 | go.exit = process.exit;
612 | WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
613 | process.on("exit", (code) => { // Node.js exits if no event handler is pending
614 | if (code === 0 && !go.exited) {
615 | // deadlock, make Go print error and stack traces
616 | go._pendingEvent = { id: 0 };
617 | go._resume();
618 | }
619 | });
620 | return go.run(result.instance);
621 | }).catch((err) => {
622 | console.error(err);
623 | process.exit(1);
624 | });
625 | }
626 | })();
627 |
--------------------------------------------------------------------------------
/demo/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@zeit/schemas@2.6.0":
6 | version "2.6.0"
7 | resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.6.0.tgz#004e8e553b4cd53d538bd38eac7bcbf58a867fe3"
8 | integrity sha512-uUrgZ8AxS+Lio0fZKAipJjAh415JyrOZowliZAzmnJSsf7piVL5w+G0+gFJ0KSu3QRhvui/7zuvpLz03YjXAhg==
9 |
10 | accepts@~1.3.5:
11 | version "1.3.7"
12 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
13 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
14 | dependencies:
15 | mime-types "~2.1.24"
16 | negotiator "0.6.2"
17 |
18 | ajv@6.5.3:
19 | version "6.5.3"
20 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
21 | integrity sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==
22 | dependencies:
23 | fast-deep-equal "^2.0.1"
24 | fast-json-stable-stringify "^2.0.0"
25 | json-schema-traverse "^0.4.1"
26 | uri-js "^4.2.2"
27 |
28 | ansi-align@^2.0.0:
29 | version "2.0.0"
30 | resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
31 | integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
32 | dependencies:
33 | string-width "^2.0.0"
34 |
35 | ansi-regex@^3.0.0:
36 | version "3.0.0"
37 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
38 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
39 |
40 | ansi-styles@^3.2.1:
41 | version "3.2.1"
42 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
43 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
44 | dependencies:
45 | color-convert "^1.9.0"
46 |
47 | arch@^2.1.0:
48 | version "2.2.0"
49 | resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
50 | integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
51 |
52 | arg@2.0.0:
53 | version "2.0.0"
54 | resolved "https://registry.yarnpkg.com/arg/-/arg-2.0.0.tgz#c06e7ff69ab05b3a4a03ebe0407fac4cba657545"
55 | integrity sha512-XxNTUzKnz1ctK3ZIcI2XUPlD96wbHP2nGqkPKpvk/HNRlPveYrXIVSTk9m3LcqOgDPg3B1nMvdV/K8wZd7PG4w==
56 |
57 | balanced-match@^1.0.0:
58 | version "1.0.2"
59 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
60 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
61 |
62 | boxen@1.3.0:
63 | version "1.3.0"
64 | resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
65 | integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
66 | dependencies:
67 | ansi-align "^2.0.0"
68 | camelcase "^4.0.0"
69 | chalk "^2.0.1"
70 | cli-boxes "^1.0.0"
71 | string-width "^2.0.0"
72 | term-size "^1.2.0"
73 | widest-line "^2.0.0"
74 |
75 | brace-expansion@^1.1.7:
76 | version "1.1.11"
77 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
78 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
79 | dependencies:
80 | balanced-match "^1.0.0"
81 | concat-map "0.0.1"
82 |
83 | bytes@3.0.0:
84 | version "3.0.0"
85 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
86 | integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
87 |
88 | camelcase@^4.0.0:
89 | version "4.1.0"
90 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
91 | integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
92 |
93 | chalk@2.4.1:
94 | version "2.4.1"
95 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
96 | integrity sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==
97 | dependencies:
98 | ansi-styles "^3.2.1"
99 | escape-string-regexp "^1.0.5"
100 | supports-color "^5.3.0"
101 |
102 | chalk@^2.0.1:
103 | version "2.4.2"
104 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
105 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
106 | dependencies:
107 | ansi-styles "^3.2.1"
108 | escape-string-regexp "^1.0.5"
109 | supports-color "^5.3.0"
110 |
111 | cli-boxes@^1.0.0:
112 | version "1.0.0"
113 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
114 | integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
115 |
116 | clipboardy@1.2.3:
117 | version "1.2.3"
118 | resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef"
119 | integrity sha512-2WNImOvCRe6r63Gk9pShfkwXsVtKCroMAevIbiae021mS850UkWPbevxsBz3tnvjZIEGvlwaqCPsw+4ulzNgJA==
120 | dependencies:
121 | arch "^2.1.0"
122 | execa "^0.8.0"
123 |
124 | color-convert@^1.9.0:
125 | version "1.9.3"
126 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
127 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
128 | dependencies:
129 | color-name "1.1.3"
130 |
131 | color-name@1.1.3:
132 | version "1.1.3"
133 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
134 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
135 |
136 | compressible@~2.0.14:
137 | version "2.0.18"
138 | resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
139 | integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
140 | dependencies:
141 | mime-db ">= 1.43.0 < 2"
142 |
143 | compression@1.7.3:
144 | version "1.7.3"
145 | resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.3.tgz#27e0e176aaf260f7f2c2813c3e440adb9f1993db"
146 | integrity sha512-HSjyBG5N1Nnz7tF2+O7A9XUhyjru71/fwgNb7oIsEVHR0WShfs2tIS/EySLgiTe98aOK18YDlMXpzjCXY/n9mg==
147 | dependencies:
148 | accepts "~1.3.5"
149 | bytes "3.0.0"
150 | compressible "~2.0.14"
151 | debug "2.6.9"
152 | on-headers "~1.0.1"
153 | safe-buffer "5.1.2"
154 | vary "~1.1.2"
155 |
156 | concat-map@0.0.1:
157 | version "0.0.1"
158 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
159 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
160 |
161 | content-disposition@0.5.2:
162 | version "0.5.2"
163 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
164 | integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
165 |
166 | cross-env@^7.0.3:
167 | version "7.0.3"
168 | resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
169 | integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
170 | dependencies:
171 | cross-spawn "^7.0.1"
172 |
173 | cross-spawn@^5.0.1:
174 | version "5.1.0"
175 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
176 | integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
177 | dependencies:
178 | lru-cache "^4.0.1"
179 | shebang-command "^1.2.0"
180 | which "^1.2.9"
181 |
182 | cross-spawn@^7.0.1:
183 | version "7.0.3"
184 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
185 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
186 | dependencies:
187 | path-key "^3.1.0"
188 | shebang-command "^2.0.0"
189 | which "^2.0.1"
190 |
191 | debug@2.6.9:
192 | version "2.6.9"
193 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
194 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
195 | dependencies:
196 | ms "2.0.0"
197 |
198 | deep-extend@^0.6.0:
199 | version "0.6.0"
200 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
201 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
202 |
203 | escape-string-regexp@^1.0.5:
204 | version "1.0.5"
205 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
206 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
207 |
208 | execa@^0.7.0:
209 | version "0.7.0"
210 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
211 | integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
212 | dependencies:
213 | cross-spawn "^5.0.1"
214 | get-stream "^3.0.0"
215 | is-stream "^1.1.0"
216 | npm-run-path "^2.0.0"
217 | p-finally "^1.0.0"
218 | signal-exit "^3.0.0"
219 | strip-eof "^1.0.0"
220 |
221 | execa@^0.8.0:
222 | version "0.8.0"
223 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da"
224 | integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=
225 | dependencies:
226 | cross-spawn "^5.0.1"
227 | get-stream "^3.0.0"
228 | is-stream "^1.1.0"
229 | npm-run-path "^2.0.0"
230 | p-finally "^1.0.0"
231 | signal-exit "^3.0.0"
232 | strip-eof "^1.0.0"
233 |
234 | fast-deep-equal@^2.0.1:
235 | version "2.0.1"
236 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
237 | integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
238 |
239 | fast-json-stable-stringify@^2.0.0:
240 | version "2.1.0"
241 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
242 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
243 |
244 | fast-url-parser@1.1.3:
245 | version "1.1.3"
246 | resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d"
247 | integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=
248 | dependencies:
249 | punycode "^1.3.2"
250 |
251 | get-stream@^3.0.0:
252 | version "3.0.0"
253 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
254 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
255 |
256 | has-flag@^3.0.0:
257 | version "3.0.0"
258 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
259 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
260 |
261 | ini@~1.3.0:
262 | version "1.3.8"
263 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
264 | integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
265 |
266 | is-fullwidth-code-point@^2.0.0:
267 | version "2.0.0"
268 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
269 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
270 |
271 | is-stream@^1.1.0:
272 | version "1.1.0"
273 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
274 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
275 |
276 | isexe@^2.0.0:
277 | version "2.0.0"
278 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
279 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
280 |
281 | json-schema-traverse@^0.4.1:
282 | version "0.4.1"
283 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
284 | integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
285 |
286 | lru-cache@^4.0.1:
287 | version "4.1.5"
288 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
289 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
290 | dependencies:
291 | pseudomap "^1.0.2"
292 | yallist "^2.1.2"
293 |
294 | mime-db@1.47.0, "mime-db@>= 1.43.0 < 2":
295 | version "1.47.0"
296 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.47.0.tgz#8cb313e59965d3c05cfbf898915a267af46a335c"
297 | integrity sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==
298 |
299 | mime-db@~1.33.0:
300 | version "1.33.0"
301 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
302 | integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==
303 |
304 | mime-types@2.1.18:
305 | version "2.1.18"
306 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
307 | integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==
308 | dependencies:
309 | mime-db "~1.33.0"
310 |
311 | mime-types@~2.1.24:
312 | version "2.1.30"
313 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.30.tgz#6e7be8b4c479825f85ed6326695db73f9305d62d"
314 | integrity sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==
315 | dependencies:
316 | mime-db "1.47.0"
317 |
318 | minimatch@3.0.4:
319 | version "3.0.4"
320 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
321 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
322 | dependencies:
323 | brace-expansion "^1.1.7"
324 |
325 | minimist@^1.2.0:
326 | version "1.2.5"
327 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
328 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
329 |
330 | ms@2.0.0:
331 | version "2.0.0"
332 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
333 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
334 |
335 | negotiator@0.6.2:
336 | version "0.6.2"
337 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
338 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
339 |
340 | npm-run-path@^2.0.0:
341 | version "2.0.2"
342 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
343 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
344 | dependencies:
345 | path-key "^2.0.0"
346 |
347 | on-headers@~1.0.1:
348 | version "1.0.2"
349 | resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
350 | integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
351 |
352 | p-finally@^1.0.0:
353 | version "1.0.0"
354 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
355 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
356 |
357 | path-is-inside@1.0.2:
358 | version "1.0.2"
359 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
360 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
361 |
362 | path-key@^2.0.0:
363 | version "2.0.1"
364 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
365 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
366 |
367 | path-key@^3.1.0:
368 | version "3.1.1"
369 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
370 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
371 |
372 | path-to-regexp@2.2.1:
373 | version "2.2.1"
374 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45"
375 | integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ==
376 |
377 | pseudomap@^1.0.2:
378 | version "1.0.2"
379 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
380 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
381 |
382 | punycode@^1.3.2:
383 | version "1.4.1"
384 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
385 | integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
386 |
387 | punycode@^2.1.0:
388 | version "2.1.1"
389 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
390 | integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
391 |
392 | range-parser@1.2.0:
393 | version "1.2.0"
394 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
395 | integrity sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=
396 |
397 | rc@^1.0.1, rc@^1.1.6:
398 | version "1.2.8"
399 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
400 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
401 | dependencies:
402 | deep-extend "^0.6.0"
403 | ini "~1.3.0"
404 | minimist "^1.2.0"
405 | strip-json-comments "~2.0.1"
406 |
407 | registry-auth-token@3.3.2:
408 | version "3.3.2"
409 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20"
410 | integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==
411 | dependencies:
412 | rc "^1.1.6"
413 | safe-buffer "^5.0.1"
414 |
415 | registry-url@3.1.0:
416 | version "3.1.0"
417 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
418 | integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
419 | dependencies:
420 | rc "^1.0.1"
421 |
422 | safe-buffer@5.1.2:
423 | version "5.1.2"
424 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
425 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
426 |
427 | safe-buffer@^5.0.1:
428 | version "5.2.1"
429 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
430 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
431 |
432 | serve-handler@6.1.3:
433 | version "6.1.3"
434 | resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.3.tgz#1bf8c5ae138712af55c758477533b9117f6435e8"
435 | integrity sha512-FosMqFBNrLyeiIDvP1zgO6YoTzFYHxLDEIavhlmQ+knB2Z7l1t+kGLHkZIDN7UVWqQAmKI3D20A6F6jo3nDd4w==
436 | dependencies:
437 | bytes "3.0.0"
438 | content-disposition "0.5.2"
439 | fast-url-parser "1.1.3"
440 | mime-types "2.1.18"
441 | minimatch "3.0.4"
442 | path-is-inside "1.0.2"
443 | path-to-regexp "2.2.1"
444 | range-parser "1.2.0"
445 |
446 | serve@^11.3.2:
447 | version "11.3.2"
448 | resolved "https://registry.yarnpkg.com/serve/-/serve-11.3.2.tgz#b905e980616feecd170e51c8f979a7b2374098f5"
449 | integrity sha512-yKWQfI3xbj/f7X1lTBg91fXBP0FqjJ4TEi+ilES5yzH0iKJpN5LjNb1YzIfQg9Rqn4ECUS2SOf2+Kmepogoa5w==
450 | dependencies:
451 | "@zeit/schemas" "2.6.0"
452 | ajv "6.5.3"
453 | arg "2.0.0"
454 | boxen "1.3.0"
455 | chalk "2.4.1"
456 | clipboardy "1.2.3"
457 | compression "1.7.3"
458 | serve-handler "6.1.3"
459 | update-check "1.5.2"
460 |
461 | shebang-command@^1.2.0:
462 | version "1.2.0"
463 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
464 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
465 | dependencies:
466 | shebang-regex "^1.0.0"
467 |
468 | shebang-command@^2.0.0:
469 | version "2.0.0"
470 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
471 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
472 | dependencies:
473 | shebang-regex "^3.0.0"
474 |
475 | shebang-regex@^1.0.0:
476 | version "1.0.0"
477 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
478 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
479 |
480 | shebang-regex@^3.0.0:
481 | version "3.0.0"
482 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
483 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
484 |
485 | signal-exit@^3.0.0:
486 | version "3.0.3"
487 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
488 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
489 |
490 | string-width@^2.0.0, string-width@^2.1.1:
491 | version "2.1.1"
492 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
493 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
494 | dependencies:
495 | is-fullwidth-code-point "^2.0.0"
496 | strip-ansi "^4.0.0"
497 |
498 | strip-ansi@^4.0.0:
499 | version "4.0.0"
500 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
501 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
502 | dependencies:
503 | ansi-regex "^3.0.0"
504 |
505 | strip-eof@^1.0.0:
506 | version "1.0.0"
507 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
508 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
509 |
510 | strip-json-comments@~2.0.1:
511 | version "2.0.1"
512 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
513 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
514 |
515 | supports-color@^5.3.0:
516 | version "5.5.0"
517 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
518 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
519 | dependencies:
520 | has-flag "^3.0.0"
521 |
522 | term-size@^1.2.0:
523 | version "1.2.0"
524 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
525 | integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
526 | dependencies:
527 | execa "^0.7.0"
528 |
529 | update-check@1.5.2:
530 | version "1.5.2"
531 | resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.2.tgz#2fe09f725c543440b3d7dabe8971f2d5caaedc28"
532 | integrity sha512-1TrmYLuLj/5ZovwUS7fFd1jMH3NnFDN1y1A8dboedIDt7zs/zJMo6TwwlhYKkSeEwzleeiSBV5/3c9ufAQWDaQ==
533 | dependencies:
534 | registry-auth-token "3.3.2"
535 | registry-url "3.1.0"
536 |
537 | uri-js@^4.2.2:
538 | version "4.4.1"
539 | resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
540 | integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
541 | dependencies:
542 | punycode "^2.1.0"
543 |
544 | vary@~1.1.2:
545 | version "1.1.2"
546 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
547 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
548 |
549 | which@^1.2.9:
550 | version "1.3.1"
551 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
552 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
553 | dependencies:
554 | isexe "^2.0.0"
555 |
556 | which@^2.0.1:
557 | version "2.0.2"
558 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
559 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
560 | dependencies:
561 | isexe "^2.0.0"
562 |
563 | widest-line@^2.0.0:
564 | version "2.0.1"
565 | resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
566 | integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
567 | dependencies:
568 | string-width "^2.1.1"
569 |
570 | yallist@^2.1.2:
571 | version "2.1.2"
572 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
573 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
574 |
--------------------------------------------------------------------------------
/download.go:
--------------------------------------------------------------------------------
1 | package labor
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "net/http"
7 | "syscall/js"
8 | )
9 |
10 | func Download(url string) interface{} {
11 | res, _ := http.Get(url)
12 | b, _ := ioutil.ReadAll(res.Body)
13 | fmt.Println(res)
14 | body := js.Global().Get("Uint8Array").New(len(b))
15 | js.CopyBytesToJS(body, b)
16 | return body
17 | }
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/yisar/labor
2 |
3 | go 1.16
4 |
--------------------------------------------------------------------------------
/promise.go:
--------------------------------------------------------------------------------
1 | package labor
2 |
3 | import (
4 | "syscall/js"
5 | )
6 |
7 | func NewPromise() (p js.Value, resolve func(interface{}), reject func(interface{})) {
8 | var cbFunc js.Func
9 | cbFunc = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
10 | cbFunc.Release()
11 |
12 | resolve = func(value interface{}) {
13 | args[0].Invoke(value)
14 | }
15 |
16 | reject = func(value interface{}) {
17 | args[1].Invoke(value)
18 | }
19 |
20 | return js.Undefined()
21 | })
22 |
23 | p = js.Global().Get("Promise").New(cbFunc)
24 |
25 | return
26 | }
27 |
28 | func Await(p js.Value) (js.Value, error) {
29 | resCh := make(chan js.Value)
30 | var then js.Func
31 | then = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
32 | resCh <- args[0]
33 | return nil
34 | })
35 | defer then.Release()
36 |
37 | errCh := make(chan error)
38 | var catch js.Func
39 | catch = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
40 | errCh <- js.Error{args[0]}
41 | return nil
42 | })
43 | defer catch.Release()
44 |
45 | p.Call("then", then).Call("catch", catch)
46 |
47 | select {
48 | case res := <-resCh:
49 | return res, nil
50 | case err := <-errCh:
51 | return js.Undefined(), err
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/request.go:
--------------------------------------------------------------------------------
1 | package labor
2 |
3 | import (
4 | "bytes"
5 | "net/http"
6 | "net/http/httptest"
7 | "syscall/js"
8 | )
9 |
10 | func Request(r js.Value) *http.Request {
11 | jsBody := js.Global().Get("Uint8Array").New(Await(r.Call("arrayBuffer")))
12 | body := make([]byte, jsBody.Get("length").Int())
13 | js.CopyBytesToGo(body, jsBody)
14 |
15 | req := httptest.NewRequest(
16 | r.Get("method").String(),
17 | r.Get("url").String(),
18 | bytes.NewBuffer(body),
19 | )
20 |
21 | headersIt := r.Get("headers").Call("entries")
22 | for {
23 | e := headersIt.Call("next")
24 | if e.Get("done").Bool() {
25 | break
26 | }
27 | v := e.Get("value")
28 | req.Header.Set(v.Index(0).String(), v.Index(1).String())
29 | }
30 |
31 | return req
32 | }
33 |
--------------------------------------------------------------------------------
/response.go:
--------------------------------------------------------------------------------
1 | package labor
2 |
3 | import (
4 | "io/ioutil"
5 | "net/http/httptest"
6 | "syscall/js"
7 | )
8 |
9 | type ResponseRecorder struct {
10 | *httptest.ResponseRecorder
11 | }
12 |
13 | func NewResponseRecorder() ResponseRecorder {
14 | return ResponseRecorder{httptest.NewRecorder()}
15 | }
16 |
17 | var _ js.Wrapper = ResponseRecorder{}
18 |
19 | func (rr ResponseRecorder) JSValue() js.Value {
20 | var res = rr.Result()
21 |
22 | var body js.Value = js.Undefined()
23 | if res.ContentLength != 0 {
24 | var b, err = ioutil.ReadAll(res.Body)
25 | if err != nil {
26 | panic(err)
27 | }
28 | body = js.Global().Get("Uint8Array").New(len(b))
29 | js.CopyBytesToJS(body, b)
30 | }
31 |
32 | var init = make(map[string]interface{}, 2)
33 |
34 | if res.StatusCode != 0 {
35 | init["status"] = res.StatusCode
36 | }
37 |
38 | if len(res.Header) != 0 {
39 | var headers = make(map[string]interface{}, len(res.Header))
40 | for k := range res.Header {
41 | headers[k] = res.Header.Get(k)
42 | }
43 | init["headers"] = headers
44 | }
45 |
46 | return js.Global().Get("Response").New(body, init)
47 | }
48 |
--------------------------------------------------------------------------------
/serve.go:
--------------------------------------------------------------------------------
1 | package labor
2 |
3 | import (
4 | "fmt"
5 | "net/http"
6 | "strings"
7 | "syscall/js"
8 | )
9 |
10 | func Serve(handler http.Handler) func() {
11 | var h = handler
12 | if h == nil {
13 | h = http.DefaultServeMux
14 | }
15 |
16 | var prefix = js.Global().Get("labor").Get("path").String()
17 | for strings.HasSuffix(prefix, "/") {
18 | prefix = strings.TrimSuffix(prefix, "/")
19 | }
20 |
21 | if prefix != "" {
22 | var mux = http.NewServeMux()
23 | mux.Handle(prefix+"/", http.StripPrefix(prefix, h))
24 | h = mux
25 | }
26 |
27 | var cb = js.FuncOf(func(_ js.Value, args []js.Value) interface{} {
28 | var resPromise, resolve, reject = NewPromise()
29 |
30 | go func() {
31 | defer func() {
32 | if r := recover(); r != nil {
33 | if err, ok := r.(error); ok {
34 | reject(fmt.Sprintf("labor: panic: %+v\n", err))
35 | } else {
36 | reject(fmt.Sprintf("labor: panic: %v\n", r))
37 | }
38 | }
39 | }()
40 |
41 | var res = NewResponseRecorder()
42 |
43 | h.ServeHTTP(res, Request(args[0]))
44 |
45 | resolve(res)
46 | }()
47 |
48 | return resPromise
49 | })
50 |
51 | js.Global().Get("labor").Call("setHandler", cb)
52 |
53 | return cb.Release
54 | }
55 |
--------------------------------------------------------------------------------