├── test ├── README.md ├── src │ ├── fs │ │ ├── dir.js │ │ ├── fds.js │ │ ├── binding.js │ │ ├── handle.js │ │ ├── stats.js │ │ ├── stream.js │ │ └── constants.js │ ├── copy-map │ │ ├── file-a.js │ │ └── file-b.js │ ├── router-resolution │ │ ├── index.html │ │ ├── another-file.html │ │ ├── pages │ │ │ └── index.html │ │ ├── a-conflict-index.html │ │ ├── an-index-file │ │ │ ├── index.html │ │ │ └── a-html-file.html │ │ └── a-conflict-index │ │ │ └── index.html │ ├── test.js │ ├── commonjs │ │ ├── json.json │ │ ├── alpha │ │ │ ├── child.js │ │ │ └── index.js │ │ ├── beta │ │ │ ├── child.js │ │ │ ├── directory │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── node_modules │ │ │ └── a │ │ │ │ ├── b │ │ │ │ ├── node_modules │ │ │ │ │ └── c │ │ │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ ├── node-modules.js │ │ ├── scope.js │ │ ├── globals.js │ │ ├── index.js │ │ └── resolvers.js │ ├── icon.png │ ├── diagnostics.js │ ├── fs.js │ ├── webassembly │ │ ├── program.wasm │ │ └── README.md │ ├── extensions │ │ ├── wasm │ │ │ ├── ok.cc │ │ │ ├── ok.hh │ │ │ ├── socket.ini │ │ │ ├── extension.cc │ │ │ ├── extension.hh │ │ │ └── sapi.cc │ │ ├── wasm.js │ │ ├── simple.js │ │ ├── sqlite3 │ │ │ └── socket.ini │ │ ├── simple │ │ │ └── ipc-ping.cc │ │ └── feature-policies.js │ ├── runtime-core │ │ ├── ok.cc │ │ ├── preload.cc │ │ ├── ok.hh │ │ ├── version.cc │ │ ├── main.js │ │ ├── env.cc │ │ ├── main.cc │ │ ├── socket.ini │ │ ├── json.cc │ │ └── string.cc │ ├── extension.js │ ├── mapping.ini │ ├── frontend │ │ ├── index_no_js.html │ │ ├── index_no_js2.html │ │ ├── index_send_event.html │ │ └── index_send_event.js │ ├── enumeration.js │ ├── commonjs.js │ ├── backend │ │ └── backend.js │ ├── index.html │ ├── url.js │ ├── index.js │ ├── i18n │ │ └── locales │ │ │ ├── en │ │ │ └── messages.json │ │ │ └── fr-FR │ │ │ └── messages.json │ ├── copy-map.js │ ├── microtask.js │ ├── network │ │ └── index.js │ ├── application-url-event.js │ ├── language.js │ └── webassembly.js ├── fixtures │ ├── bin │ │ └── file │ ├── directory │ │ ├── 0.txt │ │ ├── 1.txt │ │ ├── 2.txt │ │ ├── a.txt │ │ ├── b.txt │ │ └── c.txt │ ├── file.txt │ ├── link.txt │ ├── chown.txt │ ├── file.js │ ├── file.json │ └── data.bin ├── deps │ └── ok │ │ ├── ok.c │ │ └── clib.json ├── clib.json ├── scripts │ ├── shell.sh │ ├── test-node.js │ ├── init-sqlite3-build.sh │ ├── test-desktop.js │ ├── test-android.js │ └── test-ios-simulator.js ├── package.json └── smoke.sh ├── VERSION.txt ├── api ├── internal │ ├── iterator.js │ ├── scheduler.js │ ├── service-worker.js │ ├── symbols.js │ ├── timers.js │ ├── streams.js │ ├── post-message.js │ ├── serialize.js │ └── globals.js ├── path │ ├── mounts.js │ └── index.js ├── test.js ├── latica.js ├── crypto │ └── sodium.js ├── index.js ├── ai.js ├── mime │ ├── font.json │ ├── params.js │ ├── multipart.json │ ├── model.json │ └── type.js ├── url.js ├── fs.js ├── worker.js ├── dns.js ├── fetch.js ├── mime.js ├── timers.js ├── diagnostics.js ├── node │ └── index.js ├── fs │ ├── bookmarks.js │ └── flags.js ├── diagnostics │ ├── index.js │ └── metric.js ├── shared-worker.js ├── timers │ ├── scheduler.js │ └── platform.js ├── signal.js ├── async_hooks.js ├── network.js ├── navigation.js ├── commonjs.js ├── window │ └── constants.js ├── shared-worker │ ├── global.js │ ├── debug.js │ └── state.js ├── vm │ ├── world.html │ └── index.html ├── service-worker.js ├── global.d.ts ├── node-esm-loader.js ├── module.js ├── service-worker │ └── debug.js ├── async.js ├── external │ └── libsodium │ │ └── LICENSE ├── fetch │ └── LICENSE ├── test │ ├── LICENSE │ ├── fast-deep-equal.js │ └── context.js ├── url │ ├── urlpattern │ │ └── LICENSE │ └── url │ │ └── LICENSE.txt ├── protocol-handlers.js ├── navigation │ └── LICENSE.md ├── stream │ └── web.js ├── path.js ├── async │ └── wrap.js └── tty.js ├── src ├── runtime │ ├── webview │ │ ├── client.cc │ │ ├── origin.cc │ │ ├── client.hh │ │ └── navigator.kt │ ├── ai.hh │ ├── os.hh │ ├── uuid.hh │ ├── cwd.hh │ ├── io.hh │ ├── ini.hh │ ├── options.hh │ ├── ini │ │ └── serialize.cc │ ├── json │ │ ├── null.cc │ │ ├── boolean.cc │ │ ├── raw.cc │ │ ├── number.cc │ │ └── string.cc │ ├── debug │ │ └── console.kt │ ├── platform │ │ ├── android │ │ │ ├── native.hh │ │ │ ├── mime.hh │ │ │ ├── mime.cc │ │ │ ├── types.hh │ │ │ └── string_wrap.hh │ │ ├── android.hh │ │ └── platform.cc │ ├── env.hh │ ├── version.hh │ ├── platform.hh │ ├── core │ │ ├── services │ │ │ ├── dns.hh │ │ │ ├── permissions.hh │ │ │ ├── media_devices.cc │ │ │ ├── platform.hh │ │ │ ├── media_devices.hh │ │ │ ├── network_status.hh │ │ │ ├── os.hh │ │ │ ├── timers.hh │ │ │ └── process.hh │ │ └── service.cc │ ├── cwd │ │ └── cwd.cc │ ├── io │ │ └── write.cc │ ├── webview.kt │ ├── resource.hh │ ├── config │ │ └── global.cc │ ├── udp │ │ └── ip.hh │ ├── javascript.hh │ ├── concurrent │ │ └── abort.cc │ ├── bridge │ │ └── manager.cc │ ├── crypto │ │ └── rand.cc │ ├── unique_client.hh │ ├── uuid │ │ └── v7.cc │ ├── http │ │ └── response.cc │ ├── crypto.hh │ ├── color │ │ └── color.cc │ └── runtime.hh ├── app │ └── app.cc ├── android │ ├── main.kt │ └── app.kt ├── app.hh ├── ios │ └── main.mm ├── desktop │ └── extension.hh ├── cli.hh ├── extension │ ├── javascript.cc │ └── env.cc ├── init.cc └── runtime.hh ├── .gitattributes ├── README.md ├── .npmrc ├── .clangd ├── include └── socket │ ├── webassembly │ ├── locale.h │ ├── arpa │ │ └── inet.h │ ├── bits │ │ ├── stdint.h │ │ ├── endian.h │ │ └── limits.h │ ├── uv.h │ ├── memory.h │ ├── err.h │ ├── endian.h │ ├── getopt.h │ ├── sys │ │ ├── param.h │ │ └── errno.h │ ├── stdarg.h │ ├── stdbool.h │ ├── libgen.h │ ├── errno.h │ ├── ulimit.h │ ├── unistd.h │ ├── assert.h │ ├── strings.h │ ├── ctype.h │ ├── features.h │ ├── float.h │ ├── stdio.h │ ├── regex.h │ └── string.h │ ├── _user-config-bytes.hh │ └── webassembly.h ├── npm ├── packages │ └── @socketsupply │ │ ├── socket-node │ │ ├── .npmignore │ │ ├── .gitignore │ │ ├── .npmrc │ │ ├── README.md │ │ ├── package.json │ │ └── LICENSE │ │ ├── socket-linux-x64 │ │ └── package.json │ │ ├── socket-darwin-x64 │ │ └── package.json │ │ ├── socket-linux-arm64 │ │ └── package.json │ │ ├── socket-darwin-arm64 │ │ └── package.json │ │ ├── socket-win32-x64 │ │ └── package.json │ │ └── socket │ │ └── package.json └── bin │ ├── verify-platform.js │ ├── ssc-platform.js │ └── ssc.js ├── pnpm-workspace.yaml ├── assets ├── icon.ico └── icon.png ├── .vimrc ├── .eslintrc ├── bin ├── Get-EnvVars.ps1 ├── ci_changes_check.sh ├── nmake.vsconfig ├── .vsconfig-app-build ├── .vsconfig ├── update-network-protocol.sh ├── generate-typescript-typings.sh ├── uninstall.sh ├── ci_version_check.sh ├── version.sh ├── ci_version_check.ps1 └── Get-VCVars.ps1 ├── clib.json ├── socket-runtime.pc.in ├── tsconfig.json ├── LICENSE.txt ├── .gitignore └── .github └── issue_template.md /test/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/fs/dir.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/fs/fds.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/bin/file: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/fs/binding.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/fs/handle.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/fs/stats.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/fs/stream.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /VERSION.txt: -------------------------------------------------------------------------------- 1 | 0.6.0-rc.8 2 | -------------------------------------------------------------------------------- /api/internal/iterator.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/copy-map/file-a.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/copy-map/file-b.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/src/fs/constants.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/runtime/webview/client.cc: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/directory/0.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/directory/1.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/directory/2.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/directory/a.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/directory/b.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/directory/c.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fixtures/file.txt: -------------------------------------------------------------------------------- 1 | test 123 2 | -------------------------------------------------------------------------------- /test/fixtures/link.txt: -------------------------------------------------------------------------------- 1 | test 123 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.h linguist-language=c 2 | -------------------------------------------------------------------------------- /api/path/mounts.js: -------------------------------------------------------------------------------- 1 | export default {} 2 | -------------------------------------------------------------------------------- /test/fixtures/chown.txt: -------------------------------------------------------------------------------- 1 | hello chown 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This Project has been deprecated. 2 | -------------------------------------------------------------------------------- /test/fixtures/file.js: -------------------------------------------------------------------------------- 1 | console.log('test 123') 2 | -------------------------------------------------------------------------------- /test/src/router-resolution/index.html: -------------------------------------------------------------------------------- 1 | /index.html 2 | -------------------------------------------------------------------------------- /test/src/test.js: -------------------------------------------------------------------------------- 1 | import './test/dom-helpers.js' 2 | -------------------------------------------------------------------------------- /test/fixtures/file.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": "test 123" 3 | } 4 | -------------------------------------------------------------------------------- /test/src/commonjs/json.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "value" 3 | } 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | no-lockfile=true 2 | ignore-workspace-root-check=true 3 | -------------------------------------------------------------------------------- /src/app/app.cc: -------------------------------------------------------------------------------- 1 | #include "../app.hh" 2 | namespace ssc::app {} 3 | -------------------------------------------------------------------------------- /test/src/commonjs/alpha/child.js: -------------------------------------------------------------------------------- 1 | module.exports.key = 'value' 2 | -------------------------------------------------------------------------------- /test/src/commonjs/beta/child.js: -------------------------------------------------------------------------------- 1 | module.exports.key = 'value' 2 | -------------------------------------------------------------------------------- /test/src/router-resolution/another-file.html: -------------------------------------------------------------------------------- 1 | /another-file.html 2 | -------------------------------------------------------------------------------- /test/src/router-resolution/pages/index.html: -------------------------------------------------------------------------------- 1 | /pages/index.html 2 | -------------------------------------------------------------------------------- /.clangd: -------------------------------------------------------------------------------- 1 | Diagnostics: 2 | Suppress: 'pp_including_mainfile_in_preamble' 3 | -------------------------------------------------------------------------------- /include/socket/webassembly/locale.h: -------------------------------------------------------------------------------- 1 | #error "'locale.h' is not supported" 2 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-node/.npmignore: -------------------------------------------------------------------------------- 1 | .github 2 | !index.cjs 3 | -------------------------------------------------------------------------------- /test/deps/ok/ok.c: -------------------------------------------------------------------------------- 1 | #define LIBOK_INCLUDE_IMPLEMENTATION 2 | #include "ok.h" 3 | -------------------------------------------------------------------------------- /test/src/commonjs/beta/directory/index.js: -------------------------------------------------------------------------------- 1 | module.exports.key = 'value' 2 | -------------------------------------------------------------------------------- /test/src/router-resolution/a-conflict-index.html: -------------------------------------------------------------------------------- 1 | /a-conflict-index.html 2 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - npm/packages/@socketsupply/socket-node 3 | -------------------------------------------------------------------------------- /test/src/commonjs/node_modules/a/b/node_modules/c/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'c' 2 | -------------------------------------------------------------------------------- /test/src/router-resolution/an-index-file/index.html: -------------------------------------------------------------------------------- 1 | /an-index-file/index.html 2 | -------------------------------------------------------------------------------- /assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/socketsupply/socket/HEAD/assets/icon.ico -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/socketsupply/socket/HEAD/assets/icon.png -------------------------------------------------------------------------------- /test/src/router-resolution/a-conflict-index/index.html: -------------------------------------------------------------------------------- 1 | /a-conflict-index/index.html 2 | -------------------------------------------------------------------------------- /test/src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/socketsupply/socket/HEAD/test/src/icon.png -------------------------------------------------------------------------------- /test/src/router-resolution/an-index-file/a-html-file.html: -------------------------------------------------------------------------------- 1 | /an-index-file/a-html-file.html 2 | -------------------------------------------------------------------------------- /test/src/commonjs/node_modules/a/b/index.js: -------------------------------------------------------------------------------- 1 | const c = require('c') 2 | module.exports = { c } 3 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-node/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | index.cjs 4 | -------------------------------------------------------------------------------- /test/fixtures/data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/socketsupply/socket/HEAD/test/fixtures/data.bin -------------------------------------------------------------------------------- /test/src/commonjs/alpha/index.js: -------------------------------------------------------------------------------- 1 | const child = require('./child.js') 2 | module.exports = child 3 | -------------------------------------------------------------------------------- /test/src/diagnostics.js: -------------------------------------------------------------------------------- 1 | // import './diagnostics/channels.js' 2 | import './diagnostics/window.js' 3 | -------------------------------------------------------------------------------- /include/socket/_user-config-bytes.hh: -------------------------------------------------------------------------------- 1 | constexpr unsigned char __socket_runtime_user_config_bytes[0] = {}; 2 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-node/.npmrc: -------------------------------------------------------------------------------- 1 | save-exact=true 2 | git-tag-version=false 3 | audit=false 4 | -------------------------------------------------------------------------------- /test/src/commonjs/node_modules/a/index.js: -------------------------------------------------------------------------------- 1 | const b = require('./b') 2 | module.exports = { 3 | b 4 | } 5 | -------------------------------------------------------------------------------- /api/test.js: -------------------------------------------------------------------------------- 1 | import test from './test/index.js' 2 | export * from './test/index.js' 3 | export default test 4 | -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | au BufNewFile,BufRead *.js set syntax=typescript 2 | au BufNewFile,BufRead *.js set filetype=typescript 3 | -------------------------------------------------------------------------------- /api/latica.js: -------------------------------------------------------------------------------- 1 | import def from './latica/index.js' 2 | export * from './latica/index.js' 3 | export default def 4 | -------------------------------------------------------------------------------- /test/src/fs.js: -------------------------------------------------------------------------------- 1 | import './fs/index.js' 2 | import './fs/promises.js' 3 | import './fs/flags.js' 4 | import './fs/web.js' 5 | -------------------------------------------------------------------------------- /test/src/webassembly/program.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/socketsupply/socket/HEAD/test/src/webassembly/program.wasm -------------------------------------------------------------------------------- /api/crypto/sodium.js: -------------------------------------------------------------------------------- 1 | import exports from '../external/libsodium/index.js' 2 | // default re-exports 3 | export default exports.libsodium 4 | -------------------------------------------------------------------------------- /src/runtime/ai.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_AI_H 2 | #define SOCKET_RUNTIME_AI_H 3 | #include "ai/llm.hh" 4 | #include "ai/chat.hh" 5 | #endif 6 | -------------------------------------------------------------------------------- /api/internal/scheduler.js: -------------------------------------------------------------------------------- 1 | import scheduler from '../timers/scheduler.js' 2 | export * from '../timers/scheduler.js' 3 | export default scheduler 4 | -------------------------------------------------------------------------------- /test/src/extensions/wasm/ok.cc: -------------------------------------------------------------------------------- 1 | // inline `libok` implementation here for single unit 2 | #define LIBOK_INCLUDE_IMPLEMENTATION 3 | #include "./ok.hh" 4 | -------------------------------------------------------------------------------- /test/src/runtime-core/ok.cc: -------------------------------------------------------------------------------- 1 | // inline `libok` implementation here for single unit 2 | #define LIBOK_INCLUDE_IMPLEMENTATION 3 | #include "./ok.hh" 4 | -------------------------------------------------------------------------------- /include/socket/webassembly/arpa/inet.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_ARPA_INET_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_ARPA_INET_H 3 | 4 | #endif 5 | -------------------------------------------------------------------------------- /api/index.js: -------------------------------------------------------------------------------- 1 | import { network, Cache, sha256, Encryption, Packet, NAT } from './node/index.js' 2 | export { network, Cache, sha256, Encryption, Packet, NAT } 3 | -------------------------------------------------------------------------------- /test/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socketsupply/socket", 3 | "private": true, 4 | "src": [], 5 | "dependencies": { 6 | "jwerle/libok": "0.6.5" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parserOptions": { 3 | "ecmaVersion": "latest", 4 | "sourceType": "module" 5 | }, 6 | "env": { 7 | "es6": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/android/main.kt: -------------------------------------------------------------------------------- 1 | // vim: set sw=2: 2 | package __BUNDLE_IDENTIFIER__ 3 | 4 | import socket.runtime.app.AppActivity 5 | 6 | open class MainActivity : AppActivity() {} 7 | -------------------------------------------------------------------------------- /test/src/commonjs/beta/index.js: -------------------------------------------------------------------------------- 1 | const directory = require('./directory') 2 | const child = require('./child') 3 | 4 | module.exports = { 5 | directory, 6 | child 7 | } 8 | -------------------------------------------------------------------------------- /test/src/extension.js: -------------------------------------------------------------------------------- 1 | import './extensions/simple.js' 2 | import './extensions/sqlite3.js' 3 | import './extensions/feature-policies.js' 4 | // import './extensions/wasm.js' 5 | -------------------------------------------------------------------------------- /include/socket/webassembly/bits/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_BITS_STDINT_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_BITS_STDINT_H 3 | // empty on purpose 4 | #endif 5 | -------------------------------------------------------------------------------- /api/ai.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | /** 3 | * @module ai 4 | */ 5 | import llm from './ai/llm.js' 6 | import chat from './ai/chat.js' 7 | export { llm, chat } 8 | export default { llm, chat } 9 | -------------------------------------------------------------------------------- /bin/Get-EnvVars.ps1: -------------------------------------------------------------------------------- 1 | param($vars_arg) 2 | 3 | (Get-ChildItem env:).GetEnumerator() | ForEach-Object{ 4 | $output = "{0}={1}" -f $_.key, $_.value 5 | Write-Output $output 6 | } -------------------------------------------------------------------------------- /include/socket/webassembly/uv.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_UV_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_UV_H 3 | 4 | struct uv_loop; 5 | typedef struct uv_loop uv_loop_t; 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /api/mime/font.json: -------------------------------------------------------------------------------- 1 | { 2 | "collection": "font/collection", 3 | "otf": "font/otf", 4 | "sfnt": "font/sfnt", 5 | "ttf": "font/ttf", 6 | "woff": "font/woff", 7 | "woff2": "font/woff2" 8 | } 9 | -------------------------------------------------------------------------------- /api/internal/service-worker.js: -------------------------------------------------------------------------------- 1 | import { ServiceWorkerContainer } from '../service-worker/container.js' 2 | 3 | export const serviceWorker = new ServiceWorkerContainer() 4 | export default serviceWorker 5 | -------------------------------------------------------------------------------- /npm/bin/verify-platform.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import assert from 'assert' 4 | 5 | const [platform, arch] = process.argv.slice(2) 6 | assert(process.platform === platform && process.arch === arch) 7 | -------------------------------------------------------------------------------- /bin/ci_changes_check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | git diff --quiet 4 | if [ $? -eq 1 ]; then 5 | echo "Documentation or TypeScript definitions need update. Please do \`npm run gen\`" 6 | exit 1 7 | fi 8 | -------------------------------------------------------------------------------- /bin/nmake.vsconfig: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "components": [ 4 | "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", 5 | "Microsoft.VisualStudio.Component.Windows10SDK.20348" 6 | ] 7 | } -------------------------------------------------------------------------------- /src/runtime/os.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_OS_H 2 | #define SOCKET_RUNTIME_OS_H 3 | 4 | #include "platform.hh" 5 | 6 | namespace ssc::runtime::os { 7 | const Map& constants (); 8 | } 9 | #endif 10 | -------------------------------------------------------------------------------- /test/src/extensions/wasm/ok.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_TESTS_EXTENSIONS_WASM_OK_H 2 | #define SOCKET_RUNTIME_TESTS_EXTENSIONS_WASM_OK_H 3 | 4 | #include 5 | 6 | #include "test/deps/ok/ok.h" 7 | #endif 8 | -------------------------------------------------------------------------------- /src/runtime/uuid.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_UUID_H 2 | #define SOCKET_RUNTIME_UUID_H 3 | 4 | #include "platform.hh" 5 | 6 | namespace ssc::runtime::uuid { 7 | String v7 (); 8 | void v7 (char*); 9 | } 10 | #endif 11 | -------------------------------------------------------------------------------- /test/src/runtime-core/preload.cc: -------------------------------------------------------------------------------- 1 | #include "tests.hh" 2 | 3 | namespace SSC::Tests { 4 | void preload (Harness& t) { 5 | t.assert(createPreload(WindowOptions {}), "createPreload() returns non-empty string");; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /api/url.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @notice This is a rexports of `url/index.js` so consumers will 3 | * need to only `import * as url from 'socket:url'` 4 | */ 5 | import URL from './url/index.js' 6 | export * from './url/index.js' 7 | export default URL 8 | -------------------------------------------------------------------------------- /include/socket/webassembly/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_MEMORY_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_MEMORY_H 3 | 4 | #if !defined(_MEMORY_H) 5 | #define _MEMORY_H 6 | #endif 7 | 8 | #include "string.h" 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /test/src/mapping.ini: -------------------------------------------------------------------------------- 1 | ## for the copy-map tests 2 | ./copy-map/file-a.js = ./copy-map/A.js 3 | ./copy-map/file-b.js = ./copy-map/B.js 4 | 5 | ## for configuration tests 6 | ../socket.ini = . 7 | 8 | ## test fixtures 9 | ../fixtures = . 10 | -------------------------------------------------------------------------------- /api/fs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @notice This is a rexports of `fs/index.js` so consumers will 3 | * need to only `import * as fs from 'socket:fs'` 4 | */ 5 | import * as exports from './fs/index.js' 6 | export * from './fs/index.js' 7 | export default exports 8 | -------------------------------------------------------------------------------- /api/mime/params.js: -------------------------------------------------------------------------------- 1 | export class MIMEParams extends Map { 2 | toString () { 3 | return Array 4 | .from(this.entries()) 5 | .map((entry) => entry.join('=')) 6 | .join(';') 7 | } 8 | } 9 | 10 | export default MIMEParams 11 | -------------------------------------------------------------------------------- /src/android/app.kt: -------------------------------------------------------------------------------- 1 | // vim: set sw=2: 2 | package __BUNDLE_IDENTIFIER__ 3 | 4 | open class App : socket.runtime.app.App() { 5 | companion object { 6 | init { 7 | socket.runtime.app.App.loadSocketRuntime() 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /api/internal/symbols.js: -------------------------------------------------------------------------------- 1 | export const dispose = Symbol.dispose ?? Symbol.for('socket.runtime.gc.finalizer') 2 | export const serialize = Symbol.serialize ?? Symbol.for('socket.runtime.serialize') 3 | 4 | export default { 5 | dispose, 6 | serialize 7 | } 8 | -------------------------------------------------------------------------------- /src/app.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_APP_H 2 | #define SOCKET_APP_H 3 | 4 | #include "runtime.hh" 5 | 6 | namespace ssc::app { 7 | class App : public runtime::app::App { 8 | public: 9 | using runtime::app::App::App; 10 | }; 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /api/worker.js: -------------------------------------------------------------------------------- 1 | import { ServiceWorker } from './service-worker/instance.js' 2 | import { SharedWorker } from './shared-worker/index.js' 3 | import { Worker } from './worker_threads.js' 4 | 5 | export { SharedWorker, ServiceWorker, Worker } 6 | export default Worker 7 | -------------------------------------------------------------------------------- /api/dns.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module dns 3 | * @notice This is a rexports of `dns/index.js` so consumers will 4 | * need to only `import dns from 'socket:dns'` 5 | */ 6 | import * as exports from './dns/index.js' 7 | export * from './dns/index.js' 8 | export default exports 9 | -------------------------------------------------------------------------------- /api/fetch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @ignore 3 | * @notice This is a rexports of `fetch/index.js` so consumers will 4 | * need to only `import * as fetch from 'socket:fetch'` 5 | */ 6 | import fetch from './fetch/index.js' 7 | export * from './fetch/index.js' 8 | export default fetch 9 | -------------------------------------------------------------------------------- /api/mime.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module mime 3 | * @notice This is a rexports of `mime/index.js` so consumers will 4 | * need to only `import mime from 'socket:mime'` 5 | */ 6 | import * as exports from './mime/index.js' 7 | export * from './mime/index.js' 8 | export default exports 9 | -------------------------------------------------------------------------------- /api/timers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @notice This is a re-exports of `timers/index.js` so consumers will 3 | * need to only `import * as timers from 'socket:timers'` 4 | */ 5 | import * as exports from './timers/index.js' 6 | export * from './timers/index.js' 7 | export default exports 8 | -------------------------------------------------------------------------------- /clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "socket", 3 | "repo": "socketsupply/socket", 4 | "version": "0.6.0-rc.8", 5 | "description": "Build and package lean, fast, native desktop and mobile applications using the web technologies you already know.", 6 | "install": "install.sh" 7 | } 8 | -------------------------------------------------------------------------------- /include/socket/webassembly/bits/endian.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_BITS_ENDIAN_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_BITS_ENDIAN_H 3 | 4 | #if defined(__BYTE_ORDER) 5 | #undef __BYTE_ORDER 6 | #endif 7 | 8 | #define __BYTE_ORDER __LITTLE_ENDIAN 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/runtime/cwd.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_cWD_H 2 | #define SOCKET_RUNTIME_cWD_H 3 | 4 | #include "platform.hh" 5 | 6 | namespace ssc::runtime { 7 | void setcwd (const String& value); 8 | const String getcwd_state_value (); 9 | const String getcwd (); 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /src/runtime/webview/origin.cc: -------------------------------------------------------------------------------- 1 | #include "../webview.hh" 2 | 3 | namespace ssc::runtime::webview { 4 | String Origin::name () const { 5 | if (!this->scheme.empty()) { 6 | return this->scheme + "://" + this->hostname; 7 | } 8 | 9 | return ""; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/src/frontend/index_no_js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Second window 2 6 | 7 | 8 |

window without JS

9 | 10 | 11 | -------------------------------------------------------------------------------- /src/runtime/io.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_IO_H 2 | #define SOCKET_RUNTIME_IO_H 3 | 4 | #include 5 | 6 | #include "platform.hh" 7 | #include "env.hh" 8 | 9 | namespace ssc::runtime::io { 10 | void write (const String& input, bool isErrorOutput = false); 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /test/scripts/shell.sh: -------------------------------------------------------------------------------- 1 | root="$(CDPATH='' cd -- "$(dirname "$(dirname -- "$0")")" && pwd)" 2 | filename="$1"; shift 3 | 4 | if [ "$(uname)" = "Linux" ] || [ "$(uname)" = "Darwin" ]; then 5 | env bash "$root/$filename" $@ 6 | else 7 | sh "$root/$filename" $@ 8 | fi 9 | 10 | exit $? 11 | -------------------------------------------------------------------------------- /test/src/extensions/wasm/socket.ini: -------------------------------------------------------------------------------- 1 | [meta] 2 | name = "wasm" 3 | type = "extension" 4 | 5 | [extension] 6 | target = "wasm32" 7 | sources[] = extension.cc 8 | sources[] = libc.cc 9 | sources[] = sapi.cc 10 | sources[] = ok.cc 11 | 12 | [extension.compiler] 13 | flags[] = -I ../../../../ 14 | -------------------------------------------------------------------------------- /api/diagnostics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @notice This is a rexports of `diagnostics/index.js` so consumers will 3 | * need to only `import * as diagnostics from 'socket:diagnostics'` 4 | */ 5 | import * as exports from './diagnostics/index.js' 6 | export * from './diagnostics/index.js' 7 | export default exports 8 | -------------------------------------------------------------------------------- /include/socket/webassembly/bits/limits.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_BITS_LIMITS_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_BITS_LIMITS_H 3 | 4 | #define PAGE_SIZE 4096 5 | #define LONG_BIT 32 6 | #define LONG_MAX 0x7fffffffL 7 | #define LLONG_MAX 0x7fffffffffffffffLL 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /test/src/frontend/index_no_js2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Second window 2 6 | 7 | 8 |

window without JS with a new path!

9 | 10 | 11 | -------------------------------------------------------------------------------- /include/socket/webassembly/err.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_ERR_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_ERR_H 3 | 4 | #if !defined(_ERR_H) 5 | #define _ERR_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #if defined(__cplusplus) 13 | } 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /test/src/enumeration.js: -------------------------------------------------------------------------------- 1 | import Enumeration from 'socket:enumeration' 2 | import test from 'socket:test' 3 | 4 | test('Enumeration.from(values)', (t) => { 5 | const abc = Enumeration.from(['a', 'b', 'c']) 6 | t.ok('a' in abc, 'a in abc') 7 | t.ok('b' in abc, 'b in abc') 8 | t.ok('c' in abc, 'c in abc') 9 | }) 10 | -------------------------------------------------------------------------------- /include/socket/webassembly/endian.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_ENDIAN_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_ENDIAN_H 3 | 4 | #if !defined(_ENDIAN_H) 5 | #define _ENDIAN_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #if defined(__cplusplus) 13 | } 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /include/socket/webassembly/getopt.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_GETOPT_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_GETOPT_H 3 | 4 | #if !defined(_GETOPT_H) 5 | #define _GETOPT_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #if defined(__cplusplus) 13 | } 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /test/src/webassembly/README.md: -------------------------------------------------------------------------------- 1 | WebAssembly modules here are compiled from C source code using https://wasmfiddle.com 2 | 3 | ## program.wasm 4 | 5 | ```c 6 | extern int myFunc(int); 7 | 8 | int identity(int num) { 9 | return num; 10 | } 11 | 12 | int runMyFunc(int num) { 13 | return myFunc(num); 14 | } 15 | ``` 16 | -------------------------------------------------------------------------------- /include/socket/webassembly/sys/param.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_SYS_PARAM_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_SYS_PARAM_H 3 | 4 | #if !defined(_PARAM_H) 5 | #define _PARAM_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #if defined(__cplusplus) 13 | } 14 | #endif 15 | #endif 16 | -------------------------------------------------------------------------------- /test/deps/ok/clib.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ok", 3 | "version": "0.6.5", 4 | "author": "Joseph Werle", 5 | "description": "Super tiny tap output library", 6 | "repo": "jwerle/libok", 7 | "src": [ 8 | "ok.h", 9 | "ok.c", 10 | "Makefile" 11 | ], 12 | "keywords": [ 13 | "tap", 14 | "test" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /test/src/commonjs.js: -------------------------------------------------------------------------------- 1 | import { createRequire } from 'socket:module' 2 | 3 | const require = createRequire(import.meta.url) 4 | 5 | require('./commonjs/') 6 | require('./commonjs/scope') 7 | require('./commonjs/globals') 8 | require('./commonjs/builtins') 9 | require('./commonjs/resolvers') 10 | require('./commonjs/node-modules') 11 | -------------------------------------------------------------------------------- /test/src/commonjs/node-modules.js: -------------------------------------------------------------------------------- 1 | const test = require('socket:test') 2 | const a = require('a') 3 | 4 | test('commonjs - node modules', (t) => { 5 | t.ok(typeof a === 'object', 'a object (from node_modules)') 6 | t.ok(typeof a.b === 'object', 'a.b object (child)') 7 | t.ok(typeof a.b.c === 'string', 'a.b.c string (from node_modules)') 8 | }) 9 | -------------------------------------------------------------------------------- /test/src/runtime-core/ok.hh: -------------------------------------------------------------------------------- 1 | #ifndef RUNTIME_CORE_TESTS_OK_H 2 | #define RUNTIME_CORE_TESTS_OK_H 3 | 4 | #include 5 | 6 | #define LIBOK_PRINTF_NEEDS_NEWLINE 0 7 | #define LIBOK_PRINTF(...) sapi_printf(0, __VA_ARGS__) 8 | #define LIBOK_FPRINTF(unsued, ...) sapi_printf(0, __VA_ARGS__) 9 | 10 | #include "test/deps/ok/ok.h" 11 | #endif 12 | -------------------------------------------------------------------------------- /api/node/index.js: -------------------------------------------------------------------------------- 1 | import api from '../latica/api.js' 2 | import { Cache, Packet, sha256, Encryption, NAT } from '../latica/index.js' 3 | import events from 'node:events' 4 | import dgram from 'node:dgram' 5 | 6 | const network = options => api(options, events, dgram) 7 | 8 | export { network, Cache, sha256, Encryption, Packet, NAT } 9 | export default network 10 | -------------------------------------------------------------------------------- /include/socket/webassembly/sys/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_SYS_ERRNO_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_SYS_ERRNO_H 3 | 4 | #if !defined(_ERRNO_H) 5 | #define _ERRNO_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #include "../bits/errno.h" 13 | 14 | #if defined(__cplusplus) 15 | } 16 | #endif 17 | #endif 18 | -------------------------------------------------------------------------------- /src/runtime/ini.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_RUNTIME_INI_H 2 | #define SOCKET_RUNTIME_RUNTIME_INI_H 3 | 4 | #include "platform.hh" 5 | 6 | namespace ssc::runtime::INI { 7 | using Map = Map; 8 | Map parse (const String& source); 9 | Map parse (const String& source, const String& keyPathSeparator); 10 | String serialize (const Map&); 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /test/src/frontend/index_send_event.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Secondary window 6 | 7 | 8 | 9 |

window that sends an event

10 | 11 | 12 | -------------------------------------------------------------------------------- /socket-runtime.pc.in: -------------------------------------------------------------------------------- 1 | Name: socket-runtime 2 | Version: {{VERSION}} 3 | Description: Build and package lean, fast, native desktop and mobile applications using the web technologies you already know. 4 | URL: https://github.com/socketsupply/socket 5 | Requires: {{DEPENDENCIES}} 6 | Libs: -L{{LIB_DIRECTORY}} -lsocket-runtime -luv -lllama {{LDFLAGS}} 7 | Cflags: -I{{INCLUDE_DIRECTORY}} {{CFLAGS}} 8 | -------------------------------------------------------------------------------- /src/ios/main.mm: -------------------------------------------------------------------------------- 1 | #include "../app.hh" 2 | #include "../cli.hh" 3 | 4 | using ssc::app::App; 5 | 6 | int main (int argc, char *argv[]) { 7 | struct rlimit limit; 8 | getrlimit(RLIMIT_NOFILE, &limit); 9 | limit.rlim_cur = 2048; 10 | setrlimit(RLIMIT_NOFILE, &limit); 11 | @autoreleasepool { 12 | App app(App::Options {}); 13 | return app.run(argc, argv); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/runtime/options.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_OPTIONS_H 2 | #define SOCKET_RUNTIME_OPTIONS_H 3 | 4 | #include "platform.hh" 5 | 6 | namespace ssc::runtime { 7 | struct Options { 8 | template const T& as () const { 9 | static_assert(std::is_base_of::value); 10 | return *reinterpret_cast(this); 11 | } 12 | }; 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /src/desktop/extension.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_DESKTOP_EXTENSION_H 2 | #define SOCKET_RUNTIME_DESKTOP_EXTENSION_H 3 | 4 | #include "../runtime/platform.hh" 5 | 6 | namespace ssc::desktop { 7 | struct WebExtensionContext { 8 | struct ConfigData { 9 | char* bytes = nullptr; 10 | size_t size = 0; 11 | }; 12 | 13 | ConfigData config; 14 | }; 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/runtime/ini/serialize.cc: -------------------------------------------------------------------------------- 1 | #include "../ini.hh" 2 | #include "../string.hh" 3 | 4 | using namespace ssc::runtime::string; 5 | 6 | namespace ssc::runtime::INI { 7 | String serialize (const Map& map) { 8 | StringStream stream; 9 | for (const auto& entry : map) { 10 | stream << entry.first << " = " << entry.second << "\n"; 11 | } 12 | return trim(stream.str()); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /include/socket/webassembly/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_STDARG_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_STDARG_H 3 | 4 | #if !defined(_STDARG_H) 5 | #define _STDARG_H 6 | #endif 7 | 8 | #define va_list __builtin_va_list 9 | #define va_start __builtin_va_start 10 | #define va_copy __builtin_va_copy 11 | #define va_arg __builtin_va_arg 12 | #define va_end __builtin_va_end 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/socket/webassembly/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_STDBOOL_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_STDBOOL_H 3 | 4 | #if !defined(_STDBOOL_H) 5 | #define _STDBOOL_H 6 | #endif 7 | 8 | // as defined by the C99 standard 9 | #define __bool_true_false_are_defined 1 10 | 11 | #if !defined(__cplusplus) 12 | #define true 1 13 | #define false 0 14 | #define bool _Bool 15 | #endif 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/runtime/json/null.cc: -------------------------------------------------------------------------------- 1 | #include "../json.hh" 2 | 3 | namespace ssc::runtime::JSON { 4 | const Null null = nullptr; 5 | 6 | Type Null::valueType = Type::Null; 7 | 8 | Null::Null (std::nullptr_t) 9 | : Null() 10 | {} 11 | 12 | const std::nullptr_t Null::value () const { 13 | return nullptr; 14 | } 15 | 16 | const runtime::String Null::str () const { 17 | return "null"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /api/fs/bookmarks.js: -------------------------------------------------------------------------------- 1 | /** 2 | * A map of known absolute file paths to file IDs that 3 | * have been granted access outside of the sandbox. 4 | * XXX(@jwerle): this is currently only used on linux, but valaues may 5 | * be added for all platforms, likely from a file system picker dialog. 6 | * @type {Map} 7 | */ 8 | export const temporary = new Map() 9 | 10 | export default { 11 | temporary 12 | } 13 | -------------------------------------------------------------------------------- /include/socket/webassembly/libgen.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_LIBGEN_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_LIBGEN_H 3 | 4 | #if !defined(_LIBGEN_H) 5 | #define _LIBGEN_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | extern char* basename (const char* path); 13 | extern char* dirname (const char* path); 14 | 15 | #if defined(__cplusplus) 16 | } 17 | #endif 18 | #endif 19 | -------------------------------------------------------------------------------- /include/socket/webassembly/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_ERRNO_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_ERRNO_H 3 | 4 | #if !defined(_ERRNO_H) 5 | #define _ERRNO_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #include "sys/errno.h" 13 | 14 | int *__errno_location(void); 15 | #define errno (*__errno_location()) 16 | 17 | #if defined(__cplusplus) 18 | } 19 | #endif 20 | #endif 21 | -------------------------------------------------------------------------------- /bin/.vsconfig-app-build: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "components": [ 4 | "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", 5 | "Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset", 6 | "Microsoft.VisualStudio.Component.VC.Llvm.Clang", 7 | "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Llvm.Clang", 8 | "Microsoft.VisualStudio.Component.Windows10SDK.20348" 9 | ] 10 | } -------------------------------------------------------------------------------- /api/diagnostics/index.js: -------------------------------------------------------------------------------- 1 | import channels from './channels.js' 2 | import window from './window.js' 3 | import runtime from './runtime.js' 4 | 5 | import * as exports from './index.js' 6 | 7 | export default exports 8 | export { channels, window, runtime } 9 | 10 | /** 11 | * @param {string} name 12 | * @return {import('./channels.js').Channel} 13 | */ 14 | export function channel (name) { 15 | return channels.channel(name) 16 | } 17 | -------------------------------------------------------------------------------- /test/src/commonjs/scope.js: -------------------------------------------------------------------------------- 1 | const test = require('socket:test') 2 | 3 | test('commonjs - scope', (t) => { 4 | t.equal(module.exports, exports, 'module.exports === exports') 5 | t.equal(typeof __filename, 'string', '__filename is string') 6 | t.equal(typeof __dirname, 'string', '__dirname is string') 7 | t.ok( 8 | __filename.includes(__dirname) && __filename.indexOf(__dirname) === 0, 9 | '__dirname in __filename' 10 | ) 11 | }) 12 | -------------------------------------------------------------------------------- /test/src/runtime-core/version.cc: -------------------------------------------------------------------------------- 1 | #include "tests.hh" 2 | 3 | namespace SSC::Tests { 4 | void version (Harness& t) { 5 | t.test("SSC::{VERSION_FULL_STRING,VERSION_HASH_STRING,VERSION_STRING}", [](auto t) { 6 | t.assert(VERSION_FULL_STRING, "VERSION_FULL_STRING is defined"); 7 | t.assert(VERSION_HASH_STRING, "VERSION_HASH_STRING is defined"); 8 | t.assert(VERSION_STRING, "VERSION_STRING is defined"); 9 | }); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /include/socket/webassembly/ulimit.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNULIMIT_WEBASSEMBLY_ULIMIT_H 2 | #define SOCKET_RUNULIMIT_WEBASSEMBLY_ULIMIT_H 3 | 4 | #if !defined(_ULIMIT_H) 5 | #define _ULIMIT_H 6 | #endif 7 | 8 | #include "stddef.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #define UL_GETFSIZE 1 15 | #define UL_SETFSIZE 2 16 | 17 | extern long ulimit (int, ...) WASM_NOOP; 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | #endif 23 | -------------------------------------------------------------------------------- /test/src/runtime-core/main.js: -------------------------------------------------------------------------------- 1 | import extension from 'socket:extension' 2 | import process from 'socket:process' 3 | 4 | const EXIT_TIMEOUT = 500 5 | 6 | try { 7 | await extension.load('runtime-core-tests') 8 | setTimeout(() => process.exit(0), EXIT_TIMEOUT) 9 | } catch (err) { 10 | if (!/failed to load/i.test(err?.message)) { 11 | console.error(err.message || err) 12 | } 13 | 14 | setTimeout(() => process.exit(1), EXIT_TIMEOUT) 15 | } 16 | -------------------------------------------------------------------------------- /src/runtime/webview/client.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBVIEW_CLIENT_H 2 | #define SOCKET_RUNTIME_WEBVIEW_CLIENT_H 3 | 4 | #include "../unique_client.hh" 5 | #include "preload.hh" 6 | 7 | namespace ssc::runtime::webview { 8 | struct Client : public UniqueClient { 9 | using UniqueClient::UniqueClient; 10 | Preload preload; 11 | 12 | Client (const UniqueClient& client) 13 | : UniqueClient(client) 14 | {} 15 | }; 16 | } 17 | #endif 18 | -------------------------------------------------------------------------------- /test/src/frontend/index_send_event.js: -------------------------------------------------------------------------------- 1 | import application from 'socket:application' 2 | 3 | const currentWindow = await application.getCurrentWindow() 4 | currentWindow.send({ event: 'secondary window loaded', window: 0 }) 5 | 6 | document.querySelector('body > h1').textContent += ` ${currentWindow.index}` 7 | 8 | window.addEventListener('character', e => { 9 | currentWindow.send({ event: 'message from secondary window', value: e.detail, window: 0 }) 10 | }) 11 | -------------------------------------------------------------------------------- /api/shared-worker.js: -------------------------------------------------------------------------------- 1 | import { SharedWorker } from './shared-worker/index.js' 2 | import { Environment } from './shared-worker/env.js' 3 | 4 | /** 5 | * A reference to the opened environment. This value is an instance of an 6 | * `Environment` if the scope is a ServiceWorker scope. 7 | * @type {Environment|null} 8 | */ 9 | export const env = Environment.instance 10 | 11 | export { 12 | Environment, 13 | SharedWorker 14 | } 15 | 16 | export default SharedWorker 17 | -------------------------------------------------------------------------------- /api/timers/scheduler.js: -------------------------------------------------------------------------------- 1 | import { setImmediate, setTimeout } from './promises.js' 2 | import platform from './platform.js' 3 | 4 | export async function wait (delay, options = null) { 5 | return await setTimeout(delay, undefined, options) 6 | } 7 | 8 | export async function postTask (callback, options = null) { 9 | return await platform.postTask(callback, options) 10 | } 11 | 12 | export default { 13 | postTask, 14 | yield: setImmediate, 15 | wait 16 | } 17 | -------------------------------------------------------------------------------- /src/runtime/debug/console.kt: -------------------------------------------------------------------------------- 1 | package socket.runtime.debug 2 | 3 | object console { 4 | val TAG = "Console" 5 | fun log (string: String) { 6 | android.util.Log.i(TAG, string) 7 | } 8 | 9 | fun info (string: String) { 10 | android.util.Log.i(TAG, string) 11 | } 12 | 13 | fun debug (string: String) { 14 | android.util.Log.d(TAG, string) 15 | } 16 | 17 | fun error (string: String) { 18 | android.util.Log.e(TAG, string) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/src/backend/backend.js: -------------------------------------------------------------------------------- 1 | import socket from '@socketsupply/socket-node' 2 | 3 | socket.on('20 minutes adventure', async (value) => { 4 | await socket.send({ 5 | window: 0, 6 | event: '20 minutes adventure', 7 | value 8 | }) 9 | }) 10 | 11 | await socket.send({ 12 | window: 0, 13 | event: 'backend:ready' 14 | }) 15 | await socket.send({ 16 | window: 0, 17 | event: 'character', 18 | value: { firstname: 'Morty', secondname: 'Smith' } 19 | }) 20 | -------------------------------------------------------------------------------- /src/runtime/platform/android/native.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_PLATFORM_ANDROID_NATIVE_H 2 | #define SOCKET_RUNTIME_PLATFORM_ANDROID_NATIVE_H 3 | #if defined(__ANDROID__) 4 | // Java Native Interface 5 | // @see https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #endif 12 | #endif 13 | -------------------------------------------------------------------------------- /test/src/extensions/wasm/extension.cc: -------------------------------------------------------------------------------- 1 | #include "extension.hh" 2 | 3 | static bool initialize ( 4 | sapi_context_t* context, 5 | const void* data 6 | ) { 7 | atexit([]() { 8 | ok("atexit callback called"); 9 | }); 10 | initialize_libc_tests(); 11 | initialize_sapi_tests(context); 12 | return true; 13 | } 14 | 15 | SOCKET_RUNTIME_REGISTER_EXTENSION( 16 | "wasm", 17 | initialize, 18 | NULL, 19 | "A native extension compiled to WASM", 20 | "0.0.1" 21 | ); 22 | -------------------------------------------------------------------------------- /src/runtime/env.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_ENV_H 2 | #define SOCKET_RUNTIME_ENV_H 3 | 4 | #include "platform.hh" 5 | 6 | namespace ssc::runtime::env { 7 | bool has (const char* name); 8 | bool has (const String& name); 9 | 10 | String get (const char* name); 11 | String get (const String& name); 12 | String get (const String& name, const String& fallback); 13 | 14 | void set (const String& name, const String& value); 15 | void set (const char* name); 16 | } 17 | #endif 18 | -------------------------------------------------------------------------------- /api/signal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module signal 3 | * @deprecated Use `socket:process/signal` instead. 4 | */ 5 | 6 | import signal from './process/signal.js' 7 | export * from './process/signal.js' 8 | export default signal 9 | 10 | // XXX(@jwerle): we should probably use a standard `deprecated()` function 11 | // like nodejs' `util.deprecate()` instead of `console.warn()` 12 | console.warn( 13 | 'The module "socket:signal" is deprecated. ' + 14 | 'Please use "socket:process/signal" instead"' 15 | ) 16 | -------------------------------------------------------------------------------- /include/socket/webassembly/unistd.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNUNISTD_WEBASSEMBLY_UNISTD_H 2 | #define SOCKET_RUNUNISTD_WEBASSEMBLY_UNISTD_H 3 | 4 | #if !defined(_UNISTD_H) 5 | #define _UNISTD_H 6 | #endif 7 | 8 | #include "stddef.h" 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | #define STDIN_FILENO 0 15 | #define STDOUT_FILENO 1 16 | #define STDERR_FILENO 2 17 | 18 | // TODO(@jwerle): figure out what we want to support here 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | #endif 24 | -------------------------------------------------------------------------------- /api/async_hooks.js: -------------------------------------------------------------------------------- 1 | import { 2 | executionAsyncResource, 3 | executionAsyncId, 4 | triggerAsyncId, 5 | createHook 6 | } from './async/hooks.js' 7 | 8 | import { AsyncLocalStorage } from './async/storage.js' 9 | import { AsyncResource } from './async/resource.js' 10 | import * as exports from './async_hooks.js' 11 | 12 | export { 13 | AsyncLocalStorage, 14 | AsyncResource, 15 | executionAsyncResource, 16 | executionAsyncId, 17 | triggerAsyncId, 18 | createHook 19 | } 20 | 21 | export default exports 22 | -------------------------------------------------------------------------------- /test/src/commonjs/globals.js: -------------------------------------------------------------------------------- 1 | const test = require('socket:test') 2 | 3 | test('commonjs - globals', (t) => { 4 | t.ok(process === require('socket:process'), 'process is global') 5 | t.ok(typeof global === 'object', 'global is global') 6 | t.ok(typeof module === 'object', 'module is global') 7 | t.ok(typeof exports === 'object' && exports === module.exports, 'exports is global') 8 | t.ok(typeof __filename === 'string', '__filename is global') 9 | t.ok(typeof __dirname === 'string', '__filename is global') 10 | }) 11 | -------------------------------------------------------------------------------- /test/src/commonjs/index.js: -------------------------------------------------------------------------------- 1 | const test = require('socket:test') 2 | 3 | const alpha = require('./alpha') 4 | const beta = require('./beta') 5 | const json = require('./json') 6 | 7 | test('commonjs - directories', (t) => { 8 | t.equal(alpha?.key, 'value', 'alpha.key == value') 9 | t.equal(beta?.directory?.key, 'value', 'beta.directory.key == value') 10 | t.equal(beta?.child?.key, 'value', 'beta.child.key == value') 11 | }) 12 | 13 | test('commonjs - json', (t) => { 14 | t.equal(json?.key, 'value', 'json.key == value') 15 | }) 16 | -------------------------------------------------------------------------------- /api/network.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module network 3 | * 4 | * Provides a higher level API over the latica protocol. 5 | * 6 | * @see {@link https://socketsupply.co/guides/#p2p-guide} 7 | * 8 | */ 9 | import api from './latica/api.js' 10 | import { Cache, Packet, sha256, Encryption, NAT } from './latica/index.js' 11 | import events from './events.js' 12 | import dgram from './dgram.js' 13 | 14 | const network = options => api(options, events, dgram) 15 | 16 | export { network, Cache, sha256, Encryption, Packet, NAT } 17 | export default network 18 | -------------------------------------------------------------------------------- /src/runtime/version.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_VERSION_H 2 | #define SOCKET_RUNTIME_VERSION_H 3 | 4 | #include "string.hh" 5 | #include "config.hh" 6 | 7 | namespace ssc::runtime::version { 8 | inline const auto VERSION_FULL_STRING = String(CONVERT_TO_STRING(SOCKET_RUNTIME_VERSION) " (" CONVERT_TO_STRING(SOCKET_RUNTIME_VERSION_HASH) ")"); 9 | inline const auto VERSION_HASH_STRING = String(CONVERT_TO_STRING(SOCKET_RUNTIME_VERSION_HASH)); 10 | inline const auto VERSION_STRING = String(CONVERT_TO_STRING(SOCKET_RUNTIME_VERSION)); 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /test/src/runtime-core/env.cc: -------------------------------------------------------------------------------- 1 | #include "tests.hh" 2 | 3 | namespace SSC::Tests { 4 | void env (Harness& t) { 5 | t.test("SSC::Env::get()", [](auto t) { 6 | const auto TEST_INJECTED_VARIABLE = SSC::Env::get("TEST_INJECTED_VARIABLE"); 7 | const auto HOME = SSC::Env::get("HOME"); 8 | t.equals( 9 | TEST_INJECTED_VARIABLE, 10 | "TEST_INJECTED_VARIABLE", 11 | "TEST_INJECTED_VARIABLE env var is set" 12 | ); 13 | 14 | t.assert(HOME, "HOME env var is set"); 15 | }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/cli.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_CLI_H 2 | #define SOCKET_CLI_H 3 | 4 | #include "runtime.hh" 5 | 6 | #include 7 | 8 | namespace ssc::cli { 9 | inline void notify (int signal) { 10 | #if !defined(_WIN32) 11 | static auto ppid = runtime::env::get("SSC_CLI_PID"); 12 | static auto pid = ppid.size() > 0 ? std::stoi(ppid) : 0; 13 | if (pid > 0) { 14 | kill(pid, signal); 15 | } 16 | #endif 17 | } 18 | 19 | inline void notify () { 20 | #if !defined(_WIN32) 21 | return notify(SIGUSR1); 22 | #endif 23 | } 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /test/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 13 | Socket Runtime JavaScript Tests 14 | 15 | 16 |

window 0

17 | 18 | 19 | -------------------------------------------------------------------------------- /bin/.vsconfig: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "components": [ 4 | "Microsoft.Component.MSBuild", 5 | "Microsoft.VisualStudio.Workload.VCTools", 6 | "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", 7 | "Microsoft.VisualStudio.Component.VC.CMake.Project", 8 | "Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset", 9 | "Microsoft.VisualStudio.Component.VC.Llvm.Clang", 10 | "Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Llvm.Clang", 11 | "Microsoft.VisualStudio.Component.Windows10SDK.20348" 12 | ] 13 | } -------------------------------------------------------------------------------- /src/extension/javascript.cc: -------------------------------------------------------------------------------- 1 | #include "extension.hh" 2 | 3 | void sapi_javascript_evaluate ( 4 | sapi_context_t* ctx, 5 | const char* name, 6 | const char* source 7 | ) { 8 | if (ctx == nullptr || name == nullptr || source == nullptr) return; 9 | if (!ctx->isAllowed("javascript_evaluate")) { 10 | sapi_debug(ctx, "'javascript_evaluate' is not allowed."); 11 | return; 12 | } 13 | 14 | auto script = ssc::runtime::javascript::createJavaScript(name, source); 15 | dynamic_cast(&ctx->router->bridge)->evaluateJavaScript(script); 16 | } 17 | -------------------------------------------------------------------------------- /api/navigation.js: -------------------------------------------------------------------------------- 1 | import './navigation/navigation.js' 2 | 3 | export const Navigation = globalThis.navigation 4 | ? Object.getPrototypeOf(globalThis.navigation).constructor 5 | : class Navigation extends EventTarget {} 6 | 7 | const currentEntry = globalThis.navigation 8 | ? globalThis.navigation.currentEntry 9 | : null 10 | 11 | export const NavigationHistoryEntry = currentEntry 12 | ? Object.getPrototypeOf(currentEntry).constructor 13 | : class NavigationHistoryEntry extends EventTarget {} 14 | 15 | export default globalThis.navigation ? globalThis.navigation : new Navigation() 16 | -------------------------------------------------------------------------------- /api/timers/platform.js: -------------------------------------------------------------------------------- 1 | export const platform = { 2 | setTimeout: globalThis.setTimeout.bind(globalThis), 3 | setInterval: globalThis.setInterval.bind(globalThis), 4 | setImmediate: globalThis.setTimeout.bind(globalThis), 5 | clearTimeout: globalThis.clearTimeout.bind(globalThis), 6 | clearInterval: globalThis.clearInterval.bind(globalThis), 7 | clearImmediate: globalThis.clearTimeout.bind(globalThis), 8 | postTask: ( 9 | globalThis.scheduler?.postTask?.bind?.(globalThis?.scheduler) ?? 10 | async function notSupported () {} 11 | ) 12 | } 13 | 14 | export default platform 15 | -------------------------------------------------------------------------------- /api/commonjs.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module commonjs 3 | */ 4 | import builtins, { defineBuiltin } from './commonjs/builtins.js' 5 | import createRequire from './commonjs/require.js' 6 | import Package from './commonjs/package.js' 7 | import Module from './commonjs/module.js' 8 | import Loader from './commonjs/loader.js' 9 | import Cache from './commonjs/cache.js' 10 | 11 | import * as exports from './commonjs.js' 12 | 13 | export default exports 14 | export { 15 | builtins, 16 | Cache, 17 | createRequire, 18 | Loader, 19 | Module, 20 | Package 21 | } 22 | 23 | defineBuiltin('commonjs', exports) 24 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "api/*.js", 4 | "api/**/*.js", 5 | "api/**/**/*.js" 6 | ], 7 | "compilerOptions": { 8 | "baseUrl": "socket:", 9 | "target": "ES2022", 10 | "types": [], 11 | "lib": ["ES2022", "DOM", "DOM.Iterable"], 12 | 13 | "strictNullChecks": false, 14 | "declarationMap": false, 15 | "alwaysStrict": true, 16 | "declaration": true, 17 | "sourceMap": false, 18 | "checkJs": false, 19 | "allowJs": true, 20 | "paths": { 21 | "npm:*": ["node_modules/*"], 22 | "socket:*": ["api/*"] 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/runtime/platform.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_PLATFORM_H 2 | #define SOCKET_RUNTIME_PLATFORM_H 3 | 4 | #include "platform/system.hh" 5 | #include "platform/types.hh" 6 | 7 | namespace ssc::runtime { 8 | using namespace ssc::runtime::types; 9 | struct RuntimePlatform { 10 | const String arch; 11 | const String os; 12 | bool mac = false; 13 | bool ios = false; 14 | bool win = false; 15 | bool android = false; 16 | bool linux = false; 17 | bool unix = false; 18 | }; 19 | 20 | extern const RuntimePlatform platform; 21 | void msleep (uint64_t ms); 22 | } 23 | #endif 24 | -------------------------------------------------------------------------------- /api/window/constants.js: -------------------------------------------------------------------------------- 1 | import * as exports from './constants.js' 2 | 3 | export const WINDOW_ERROR = -1 4 | export const WINDOW_NONE = 0 5 | export const WINDOW_CREATING = 10 6 | export const WINDOW_CREATED = 11 7 | export const WINDOW_HIDING = 20 8 | export const WINDOW_HIDDEN = 21 9 | export const WINDOW_SHOWING = 30 10 | export const WINDOW_SHOWN = 31 11 | export const WINDOW_CLOSING = 40 12 | export const WINDOW_CLOSED = 41 13 | export const WINDOW_EXITING = 50 14 | export const WINDOW_EXITED = 51 15 | export const WINDOW_KILLING = 60 16 | export const WINDOW_KILLED = 61 17 | 18 | export default exports 19 | -------------------------------------------------------------------------------- /src/runtime/platform/android/mime.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_PLATFORM_ANDROID_MIME_H 2 | #define SOCKET_RUNTIME_PLATFORM_ANDROID_MIME_H 3 | 4 | #include "../types.hh" 5 | #include "environment.hh" 6 | 7 | namespace ssc::runtime::android { 8 | using MimeTypeMapRef = jobject; 9 | 10 | struct MimeTypeMap { 11 | MimeTypeMapRef ref; 12 | JVMEnvironment jvm; 13 | static const MimeTypeMap* sharedMimeTypeMap (); 14 | String getMimeTypeFromExtension (const String& extension) const; 15 | }; 16 | 17 | void initializeMimeTypeMap (MimeTypeMapRef ref, JVMEnvironment jvm); 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /api/diagnostics/metric.js: -------------------------------------------------------------------------------- 1 | import { isArrayLike, format } from '../util.js' 2 | 3 | export class Metric { 4 | init () {} 5 | update (value) {} 6 | destroy () {} 7 | 8 | toJSON () { 9 | return {} 10 | } 11 | 12 | toString () { 13 | return format(this) 14 | } 15 | 16 | [Symbol.iterator] () { 17 | if (isArrayLike(this)) { 18 | return Array.from(this) 19 | } 20 | 21 | return [this] 22 | } 23 | 24 | [Symbol.toStringTag] () { 25 | const name = this.constructor.name.replace('Metric', '') 26 | return `DiagnosticMetric(${name})` 27 | } 28 | } 29 | 30 | export default Metric 31 | -------------------------------------------------------------------------------- /src/runtime/webview/navigator.kt: -------------------------------------------------------------------------------- 1 | // vim: set sw=2: 2 | package socket.runtime.webview 3 | 4 | import socket.runtime.bridge.Bridge 5 | 6 | open class Navigator (val bridge: Bridge) { 7 | fun isNavigationRequestAllowed ( 8 | currentURL: String, 9 | requestedURL: String 10 | ): Boolean { 11 | return this.isNavigationRequestAllowed( 12 | this.bridge.index, 13 | currentURL, 14 | requestedURL 15 | ) 16 | } 17 | 18 | @Throws(Exception::class) 19 | external fun isNavigationRequestAllowed ( 20 | index: Int, 21 | currentURL: String, 22 | requestedURL: String 23 | ): Boolean 24 | } 25 | -------------------------------------------------------------------------------- /api/shared-worker/global.js: -------------------------------------------------------------------------------- 1 | // events 2 | let onconnect = null 3 | 4 | export class SharedWorkerGlobalScope { 5 | get isSharedWorkerScope () { 6 | return true 7 | } 8 | 9 | get onconnect () { 10 | return onconnect 11 | } 12 | 13 | set onconnect (listener) { 14 | if (onconnect) { 15 | globalThis.removeEventListener('connect', onconnect) 16 | } 17 | 18 | onconnect = null 19 | 20 | if (typeof listener === 'function') { 21 | globalThis.addEventListener('connect', listener) 22 | onconnect = listener 23 | } 24 | } 25 | } 26 | 27 | export default SharedWorkerGlobalScope.prototype 28 | -------------------------------------------------------------------------------- /include/socket/webassembly/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_ASSERT_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_ASSERT_H 3 | 4 | #include "features.h" 5 | 6 | #if defined(assert) 7 | #undef assert 8 | #endif 9 | 10 | #define assert(x) ((void)((x) || (__assert_fail(#x, __FILE__, __LINE__, __func__), 0))) 11 | 12 | #if __STDC_VERSION__ >= 201112L && !defined(__cplusplus) 13 | #define static_assert _Static_assert 14 | #endif 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | extern void __assert_fail (const char*, const char*, int, const char*); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | #endif 26 | -------------------------------------------------------------------------------- /src/runtime/core/services/dns.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CORE_SERVICES_DNS_H 2 | #define SOCKET_RUNTIME_CORE_SERVICES_DNS_H 3 | 4 | #include "../../core.hh" 5 | 6 | namespace ssc::runtime::core::services { 7 | class DNS : public core::Service { 8 | public: 9 | struct LookupOptions { 10 | String hostname; 11 | int family; 12 | // TODO: support these options: hints, all, verbatim 13 | }; 14 | 15 | DNS (const Options& options) 16 | : core::Service(options) 17 | {} 18 | 19 | void lookup (const String&, const LookupOptions&, const Callback) const; 20 | }; 21 | } 22 | #endif 23 | -------------------------------------------------------------------------------- /api/vm/world.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/src/runtime-core/main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "tests.hh" 3 | 4 | static bool initialize (sapi_context_t* context, const void *data) { 5 | SSC::Tests::Harness harness; 6 | return harness.run("runtime-core-tests", [](auto t) { 7 | t.run(SSC::Tests::codec); 8 | t.run(SSC::Tests::config); 9 | t.run(SSC::Tests::env); 10 | t.run(SSC::Tests::ini); 11 | t.run(SSC::Tests::json); 12 | t.run(SSC::Tests::platform); 13 | t.run(SSC::Tests::preload); 14 | t.run(SSC::Tests::string); 15 | t.run(SSC::Tests::version); 16 | }); 17 | } 18 | 19 | SOCKET_RUNTIME_REGISTER_EXTENSION("runtime-core-tests", initialize); 20 | -------------------------------------------------------------------------------- /api/service-worker.js: -------------------------------------------------------------------------------- 1 | import { ExtendableEvent, FetchEvent } from './service-worker/events.js' 2 | import { Environment } from './service-worker/env.js' 3 | import { Context } from './service-worker/context.js' 4 | 5 | /** 6 | * A reference to the opened environment. This value is an instance of an 7 | * `Environment` if the scope is a ServiceWorker scope. 8 | * @type {Environment|null} 9 | */ 10 | export const env = Environment.instance 11 | 12 | export { 13 | ExtendableEvent, 14 | FetchEvent, 15 | Environment, 16 | Context 17 | } 18 | 19 | export default { 20 | ExtendableEvent, 21 | FetchEvent, 22 | Environment, 23 | Context, 24 | env 25 | } 26 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "private": true, 4 | "scripts": { 5 | "test": "npm run test:desktop", 6 | "test:desktop": "node ./scripts/test-desktop.js", 7 | "test:runtime-core": "ssc build --run --headless --only-build --test runtime-core/main.js", 8 | "test:android": "node ./scripts/test-android.js", 9 | "test:ios-simulator": "node ./scripts/test-ios-simulator.js", 10 | "test:android-emulator": "sh ./scripts/shell.sh ./scripts/test-android-emulator.sh", 11 | "test:node": "node ./scripts/test-node.js", 12 | "start": "npm test" 13 | }, 14 | "dependencies": { 15 | "@socketsupply/socket": "../api" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bin/update-network-protocol.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | npm link @socketsupply/latica 4 | 5 | version="${1:-"1.0.23-0"}" 6 | 7 | rm -rf api/latica.js || exit $? 8 | rm -rf api/latica || exit $? 9 | cp -rf node_modules/@socketsupply/latica/src api/latica || exit $? 10 | rm -rf node_modules/@socketsupply/{socket,socket-{darwin,linux,win32}*,latica} || exit $? 11 | 12 | for file in $(find api/latica -type f); do 13 | sed -i '' -e "s/'socket:\(.*\)'/'..\/\1.js'/g" "$file" || exit $? 14 | done 15 | 16 | { 17 | echo "import def from './latica/index.js'" 18 | echo "export * from './latica/index.js'" 19 | echo "export default def" 20 | } >> api/latica.js 21 | 22 | tree api/latica 23 | -------------------------------------------------------------------------------- /api/vm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /bin/generate-typescript-typings.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | declare root="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)" 4 | 5 | cd "$root" || exit $? 6 | 7 | "$root/node_modules/.bin/tsc" --emitDeclarationOnly --module es2022 --outFile api/index.tmp || exit $? 8 | 9 | cat api/index.tmp.d.ts api/global.d.ts \ 10 | | sed 's/declare module "\(.*\)"/\ndeclare module "socket:\1"/g' \ 11 | | sed 's/from "\(.*\)"/from "socket:\1"/g' \ 12 | | sed 's/import("\(.*\)")/import("socket:\1")/g' \ 13 | | sed 's/namespace \_\_\_.*$//g' > api/index.d.ts \ 14 | || exit $? 15 | 16 | rm -f api/index.tmp.d.ts 17 | -------------------------------------------------------------------------------- /src/runtime/cwd/cwd.cc: -------------------------------------------------------------------------------- 1 | #include "../filesystem.hh" 2 | 3 | #include "../cwd.hh" 4 | 5 | namespace ssc::runtime { 6 | static struct { Mutex mutex; String value = ""; } state; 7 | 8 | void setcwd (const String& value) { 9 | Lock lock(state.mutex); 10 | state.value = value; 11 | } 12 | 13 | const String getcwd_state_value () { 14 | Lock lock(state.mutex); 15 | return state.value; 16 | } 17 | 18 | const String getcwd () { 19 | Lock lock(state.mutex); 20 | 21 | if (state.value.size() > 0) { 22 | return state.value; 23 | } 24 | 25 | state.value = runtime::filesystem::Resource::getResourcesPath().string(); 26 | return state.value; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/src/url.js: -------------------------------------------------------------------------------- 1 | import test from 'socket:test' 2 | import url from 'socket:url' 3 | 4 | test('url.resolve(url, base)', (t) => { 5 | t.equal( 6 | url.resolve('/a/b/c', 'socket://com.app/index.html'), 7 | 'socket://com.app/index.html', 8 | '/a/b/c ~ socket://com.app/index.html -> socket://com.app/index.html' 9 | ) 10 | 11 | t.equal( 12 | url.resolve('socket:///a/b/c', '..'), 13 | 'socket:///a/', 14 | 'socket:///a/b/c ~ .. -> socket:///a/' 15 | ) 16 | 17 | t.equal(url.resolve('/a/b/c', '..'), '/a/', '/a/b/c ~ .. -> /a/') 18 | t.equal(url.resolve('/a/b/c', '.'), '/a/b/', '/a/b/c ~ . -> /a/b/') 19 | t.equal(url.resolve('/a/b/c', '/'), '/', '/a/b/c ~ / -> /') 20 | }) 21 | -------------------------------------------------------------------------------- /src/runtime/core/services/permissions.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CORE_SERVICES_PERMISSIONS_H 2 | #define SOCKET_RUNTIME_CORE_SERVICES_PERMISSIONS_H 3 | 4 | #include "../../ipc.hh" 5 | #include "../../core.hh" 6 | 7 | namespace ssc::runtime::core::services { 8 | class Permissions : public core::Service { 9 | public: 10 | Permissions (const Options& options) 11 | : core::Service(options) 12 | {} 13 | 14 | void query (const ipc::Message::Seq&, const String&, const Callback) const; 15 | void request (const ipc::Message::Seq&, const String&, const Map&, const Callback) const; 16 | bool hasRuntimePermission (const String& permission) const; 17 | }; 18 | } 19 | #endif 20 | -------------------------------------------------------------------------------- /src/runtime/io/write.cc: -------------------------------------------------------------------------------- 1 | #include "../../cli.hh" 2 | 3 | #include "../io.hh" 4 | 5 | namespace ssc::runtime::io { 6 | void write (const String& input, bool isErrorOutput) { 7 | static const auto GITHUB_ACTIONS_CI = env::get("GITHUB_ACTIONS_CI"); 8 | static const auto isGitHubActionsCI = GITHUB_ACTIONS_CI.size() > 0; 9 | auto& stream = isErrorOutput ? std::cerr : std::cout; 10 | 11 | stream << input; 12 | 13 | #if SOCKET_RUNTIME_PLATFORM_WINDOWS 14 | if (isGitHubActionsCI) { 15 | ssc::cli::notify(); 16 | // skip writing newline if running on Windows GHA CI 17 | return; 18 | } 19 | 20 | #endif 21 | stream << std::endl; 22 | 23 | ssc::cli::notify(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /api/global.d.ts: -------------------------------------------------------------------------------- 1 | type MenuItemSelection = { 2 | title: string 3 | parent: string 4 | state: '0' 5 | } 6 | declare interface Window { 7 | addEventListener( 8 | type: "menuItemSelected", 9 | listener: (event: CustomEvent) => void, 10 | options?: boolean | AddEventListenerOptions 11 | ): void; 12 | addEventListener( 13 | type: "process-error", 14 | listener: (event: CustomEvent) => void, 15 | options?: boolean | AddEventListenerOptions 16 | ): void; 17 | addEventListener( 18 | type: "backend-exit", 19 | listener: (event: CustomEvent) => void, 20 | options?: boolean | AddEventListenerOptions 21 | ): void; 22 | } -------------------------------------------------------------------------------- /include/socket/webassembly/strings.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_STRINGS_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_STRINGS_H 3 | 4 | #if !defined(_STRINGS_H) 5 | #define _STRINGS_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #include "stddef.h" 13 | 14 | extern int bcmp (const void*, const void*, size_t); 15 | extern void bcopy (const void*, void*, size_t); 16 | extern void bzero (void*, size_t); 17 | extern int ffs (int); 18 | extern char* index (const char*, int); 19 | extern char* rindex (const char*, int); 20 | extern int strcasecmp (const char*, const char*); 21 | extern int strncasecmp (const char*, const char*, size_t); 22 | 23 | #if defined(__cplusplus) 24 | } 25 | #endif 26 | #endif 27 | -------------------------------------------------------------------------------- /test/src/extensions/wasm/extension.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_TEST_EXTENSIONS_WASM_H 2 | #define SOCKET_RUNTIME_TEST_EXTENSIONS_WASM_H 3 | 4 | #include 5 | #include "ok.hh" 6 | 7 | #define _CONVERT_TO_STRING(value) #value 8 | #define CONVERT_TO_STRING(value) _CONVERT_TO_STRING(value) 9 | 10 | #define test(condition) ({ \ 11 | if ((condition)) { \ 12 | ok(CONVERT_TO_STRING(condition)); \ 13 | } else { \ 14 | notok(CONVERT_TO_STRING(condition)); \ 15 | } \ 16 | }) 17 | 18 | 19 | extern "C" { 20 | void initialize_libc_tests (); 21 | void initialize_sapi_tests (sapi_context_t*); 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /test/src/runtime-core/socket.ini: -------------------------------------------------------------------------------- 1 | [meta] 2 | name = "runtime-core-tests" 3 | type = "extension" 4 | 5 | [extension] 6 | # support files 7 | sources[] = ../../deps/ok/ok.h 8 | sources[] = ./harness.cc 9 | sources[] = ./main.cc 10 | sources[] = ./ok.cc 11 | 12 | # test files 13 | sources[] = ./codec.cc 14 | sources[] = ./config.cc 15 | sources[] = ./env.cc 16 | sources[] = ./ini.cc 17 | sources[] = ./json.cc 18 | sources[] = ./platform.cc 19 | sources[] = ./preload.cc 20 | sources[] = ./string.cc 21 | sources[] = ./version.cc 22 | 23 | [extension.compiler] 24 | flags[] = -I../../.. 25 | 26 | [extension.mac.compiler] 27 | flags[] = -fsanitize-undefined-trap-on-error 28 | flags[] = -fsanitize=undefined-trap 29 | flags[] = -ftrap-function=abort 30 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-node/README.md: -------------------------------------------------------------------------------- 1 | # SYNOPSIS 2 | 3 | A Node.js adapter for the Socket runtime 4 | 5 | # DESCRIPTION 6 | 7 | [Socket runtime][0] uses a simple uri-based protocol for brokering messages 8 | between the render process and the main process. Messages are sent over `stdin` 9 | and `stdout`. This module is an optional, higher level adapter for this protocol 10 | that should make Node.js developers feel more at-home. 11 | 12 | # Documentation 13 | 14 | You can find the full documentation in the [API.md](./API.md) file. 15 | 16 | # EXAMPLES 17 | 18 | Check out the [this][1] repo for some examples about how to use it. 19 | 20 | [0]:https://socketsupply.co/ 21 | [1]:https://github.com/socketsupply/socket-examples 22 | 23 | -------------------------------------------------------------------------------- /src/runtime/core/services/media_devices.cc: -------------------------------------------------------------------------------- 1 | #include "media_devices.hh" 2 | 3 | namespace ssc::runtime::core::services { 4 | MediaDevices::MediaDevices (const Options& options) 5 | : core::Service(options), 6 | permissionChangeObservers() 7 | {} 8 | 9 | MediaDevices::~MediaDevices () {} 10 | 11 | bool MediaDevices::addPermissionChangeObserver ( 12 | const PermissionChangeObserver& observer, 13 | const PermissionChangeObserver::Callback callback 14 | ) { 15 | return this->permissionChangeObservers.add(observer, callback); 16 | } 17 | 18 | bool MediaDevices::removePermissionChangeObserver (const PermissionChangeObserver& observer) { 19 | return this->permissionChangeObservers.remove(observer); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/scripts/test-node.js: -------------------------------------------------------------------------------- 1 | import test from '@socketsupply/socket/test.js' 2 | import { network, Encryption } from '@socketsupply/socket' 3 | 4 | test('network imports', async t => { 5 | const socket = await network({ 6 | clusterId: await Encryption.createClusterId(), 7 | signingKeys: await Encryption.createKeyPair(), 8 | peerId: await Encryption.createId('xxx') 9 | }) 10 | 11 | await new Promise(resolve => { 12 | socket.on('#ready', () => { 13 | t.equal(socket.peer.clusterId.length, 32, 'clusterId was a 32 byte buffer') 14 | t.equal(socket.constructor.name, 'EventEmitter', 'network function returned an event emitter') 15 | t.ok(true, 'socket became ready') 16 | resolve() 17 | }) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /test/src/index.js: -------------------------------------------------------------------------------- 1 | import './webview.js' 2 | import './hooks.js' 3 | import './diagnostics.js' 4 | import './ipc.js' 5 | import './os.js' 6 | import './process.js' 7 | import './path.js' 8 | import './dgram.js' 9 | import './dns.js' 10 | import './crypto.js' 11 | import './util.js' 12 | import './fs.js' 13 | import './window.js' 14 | import './application.js' 15 | import './copy-map.js' 16 | import './microtask.js' 17 | import './commonjs.js' 18 | import './extension.js' 19 | import './url.js' 20 | import './test.js' 21 | import './enumeration.js' 22 | import './language.js' 23 | import './i18n.js' 24 | import './router-resolution.js' 25 | import './mime.js' 26 | import './application-url-event.js' 27 | import './webassembly.js' 28 | import './vm.js' 29 | -------------------------------------------------------------------------------- /src/runtime/webview.kt: -------------------------------------------------------------------------------- 1 | // vim: set sw=2: 2 | package socket.runtime.webview 3 | 4 | import android.content.Context 5 | import android.webkit.WebResourceRequest 6 | import android.webkit.WebResourceResponse 7 | 8 | /** 9 | * @see https://developer.android.com/reference/kotlin/android/webkit/WebView 10 | */ 11 | open class WebView (context: android.content.Context) : android.webkit.WebView(context) 12 | 13 | /** 14 | * @see https://developer.android.com/reference/kotlin/android/webkit/WebChromeClient 15 | */ 16 | open class WebChromeClient : android.webkit.WebChromeClient() {} 17 | 18 | /** 19 | * @see https://developer.android.com/reference/kotlin/android/webkit/WebViewClient 20 | */ 21 | open class WebViewClient : android.webkit.WebViewClient() {} 22 | -------------------------------------------------------------------------------- /api/mime/multipart.json: -------------------------------------------------------------------------------- 1 | { 2 | "alternative": "multipart/alternative", 3 | "appledouble": "multipart/appledouble", 4 | "byteranges": "multipart/byteranges", 5 | "digest": "multipart/digest", 6 | "encrypted": "multipart/encrypted", 7 | "example": "multipart/example", 8 | "form-data": "multipart/form-data", 9 | "header-set": "multipart/header-set", 10 | "mixed": "multipart/mixex", 11 | "multilingual": "multipart/multilingual", 12 | "parallel": "multipart/parallel", 13 | "related": "multipart/related", 14 | "report": "multipart/report", 15 | "signed": "multipart/signed", 16 | "vnd.bint.med-plus": "multipart/vnd.bint.med-plus", 17 | "voice-message": "multipart/voice-message", 18 | "x-mixed-replace": "multipart/x-mixed-replace" 19 | } 20 | -------------------------------------------------------------------------------- /api/node-esm-loader.js: -------------------------------------------------------------------------------- 1 | const { SOCKET_MODULES = 'node_modules' } = process.env 2 | 3 | export async function resolve (specifier, ctx, next) { 4 | if (/^socket:modules/.test(specifier)) { 5 | let moduleName = specifier.replace('socket:modules/', '') 6 | if (moduleName.endsWith('.js')) { 7 | moduleName = moduleName.slice(0, -3) 8 | } 9 | 10 | specifier = `${SOCKET_MODULES}/${moduleName}.js` 11 | } else if (/^socket:/.test(specifier)) { 12 | let moduleName = specifier.replace('socket:', '') 13 | if (moduleName.endsWith('.js')) { 14 | moduleName = moduleName.slice(0, -3) 15 | } 16 | 17 | specifier = `@socketsupply/socket/${moduleName}.js` 18 | } 19 | 20 | return next(specifier) 21 | } 22 | 23 | export default resolve 24 | -------------------------------------------------------------------------------- /test/src/i18n/locales/en/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1": { 3 | "message": "A message for key1", 4 | "description": "A message for key1" 5 | }, 6 | "key2": { 7 | "message": "A message for key2", 8 | "description": "A message for key2" 9 | }, 10 | "key-with-indexed-substitutions": { 11 | "message": "first={0}, second=$1, third={2}", 12 | "description": "A message for 3 substitutions" 13 | }, 14 | "key-with-placeholder-substitutions": { 15 | "message": "first={first}, second=$second, third=$THIRD$", 16 | "description": "A message for 3 substitutions", 17 | "placeholders": { 18 | "first": { "content": "$0" }, 19 | "second": { "content": "{1}" }, 20 | "third": { "content": "$2$" } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/runtime/resource.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_RESOURCE_H 2 | #define SOCKET_RUNTIME_RESOURCE_H 3 | 4 | #include "platform.hh" 5 | #include "debug.hh" 6 | #include "url.hh" 7 | 8 | namespace ssc::runtime { 9 | class Resource { 10 | public: 11 | Atomic accessing = false; 12 | String name; 13 | String type; 14 | debug::Tracer tracer; 15 | Resource (const String& type, const String& name) 16 | : name(name), 17 | type(type), 18 | tracer(name) 19 | {} 20 | virtual ~Resource () {} 21 | virtual bool hasAccess () const noexcept { 22 | return this->accessing; 23 | } 24 | virtual bool startAccessing () = 0; 25 | virtual bool stopAccessing () = 0; 26 | }; 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /test/src/extensions/wasm.js: -------------------------------------------------------------------------------- 1 | import extension from 'socket:extension' 2 | import test from 'socket:test' 3 | 4 | test('extension.load(name) - wasm', async (t) => { 5 | const stats = await extension.stats() 6 | const wasm = await extension.load('wasm') 7 | 8 | t._result.pass += wasm.adapter.instance.exports.ok_count() 9 | t._result.fail += wasm.adapter.instance.exports.ok_failed() 10 | t.runner._id += t._result.pass + t._result.fail 11 | 12 | t.ok(wasm, 'wasm = extension.load()') 13 | t.equal(wasm.abi, stats.abi, 'wasm.abi === stats.abi') 14 | t.equal(wasm.name, 'wasm', 'name === "wasm"') 15 | t.equal(wasm.description, 'A native extension compiled to WASM') 16 | t.equal(wasm.version, '0.0.1', 'version === "0.0.1"') 17 | 18 | globalThis.wasm = wasm 19 | }) 20 | -------------------------------------------------------------------------------- /api/path/index.js: -------------------------------------------------------------------------------- 1 | import { Path } from './path.js' 2 | import * as posix from './posix.js' 3 | import * as win32 from './win32.js' 4 | import * as mounts from './mounts.js' 5 | import * as exports from './index.js' 6 | import { 7 | DOWNLOADS, 8 | DOCUMENTS, 9 | RESOURCES, 10 | PICTURES, 11 | DESKTOP, 12 | VIDEOS, 13 | CONFIG, 14 | MEDIA, 15 | MUSIC, 16 | HOME, 17 | DATA, 18 | LOG, 19 | TMP 20 | } from './well-known.js' 21 | 22 | export { 23 | mounts, 24 | posix, 25 | win32, 26 | Path, 27 | 28 | // well known paths 29 | DOWNLOADS, 30 | DOCUMENTS, 31 | RESOURCES, 32 | PICTURES, 33 | DESKTOP, 34 | VIDEOS, 35 | CONFIG, 36 | MEDIA, 37 | MUSIC, 38 | HOME, 39 | DATA, 40 | LOG, 41 | TMP 42 | } 43 | 44 | export default exports 45 | -------------------------------------------------------------------------------- /src/runtime/config/global.cc: -------------------------------------------------------------------------------- 1 | #include "../config.hh" 2 | #include "../ini.hh" 3 | 4 | namespace ssc::runtime::config { 5 | bool isDebugEnabled () { 6 | return socket_runtime_init_is_debug_enabled(); 7 | } 8 | 9 | const Map getUserConfig () { 10 | const auto bytes = socket_runtime_init_get_user_config_bytes(); 11 | const auto size = socket_runtime_init_get_user_config_bytes_size(); 12 | const auto string = String(reinterpret_cast(bytes), size); 13 | const auto userConfig = INI::parse(string); 14 | return userConfig; 15 | } 16 | 17 | const String getDevHost () { 18 | return socket_runtime_init_get_dev_host(); 19 | } 20 | 21 | int getDevPort () { 22 | return socket_runtime_init_get_dev_port(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/src/i18n/locales/fr-FR/messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1": { 3 | "message": "Un message pour la clé 1", 4 | "description": "A message for key1" 5 | }, 6 | "key2": { 7 | "message": "Un message pour la clé 2", 8 | "description": "A message for key2" 9 | }, 10 | "key-with-indexed-substitutions": { 11 | "message": "premier={0}, deuxième=$1, troisième={2}", 12 | "description": "A message for 3 substitutions" 13 | }, 14 | "key-with-placeholder-substitutions": { 15 | "message": "premier={first}, deuxième=$second$, troisième=$THIRD$", 16 | "description": "A message for 3 substitutions", 17 | "placeholders": { 18 | "first": { "content": "$0" }, 19 | "second": { "content": "{1}" }, 20 | "third": { "content": "$2$" } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /api/module.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module module 3 | */ 4 | import builtins, { defineBuiltin, isBuiltin } from './commonjs/builtins.js' 5 | import { createRequire, Module } from './commonjs/module.js' 6 | 7 | /** 8 | * @typedef {import('./commonjs/module.js').ModuleOptions} ModuleOptions 9 | * @typedef {import('./commonjs/module.js').ModuleResolver} ModuleResolver 10 | * @typedef {import('./commonjs/module.js').ModuleLoadOptions} ModuleLoadOptions 11 | * @typedef {import('./commonjs/module.js').RequireFunction} RequireFunction 12 | * @typedef {import('./commonjs/module.js').CreateRequireOptions} CreateRequireOptions 13 | */ 14 | 15 | export { createRequire, Module, builtins, isBuiltin } 16 | export const builtinModules = builtins 17 | 18 | export default Module 19 | 20 | defineBuiltin('module', Module, false) 21 | -------------------------------------------------------------------------------- /test/scripts/init-sqlite3-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | root="$(CDPATH='' cd -- "$(dirname "$(dirname -- "$0")")" && pwd)" 4 | 5 | build_dir="$root/build" 6 | sqlite3_build_dir="$root/build/sqlite3" 7 | sqlite3_zip_file="$sqlite3_build_dir/sqlite3.zip" 8 | sqlite3_download_url="https://sqlite.org/2023/sqlite-amalgamation-3420000.zip" 9 | 10 | if ! test -f "$sqlite3_zip_file"; then 11 | mkdir -p "$sqlite3_build_dir" 12 | curl -sL "$sqlite3_download_url" -o "$sqlite3_zip_file" 13 | fi 14 | 15 | if test -f "$sqlite3_zip_file"; then 16 | pushd . >/dev/null || exit $? 17 | cd "$sqlite3_build_dir" || exit $? 18 | rm -f *.c *.h || exit $? 19 | unzip -q "$sqlite3_zip_file" || exit $? 20 | mv sqlite-*/*.{c,h} . || exit $? 21 | rm -rf sqlite-* || exit $? 22 | popd >/dev/null || exit $? 23 | fi 24 | -------------------------------------------------------------------------------- /include/socket/webassembly/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_CTYPE_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_CTYPE_H 3 | 4 | #if !defined(_CTYPE_H) 5 | #define _CTYPE_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #define EOF -1 13 | 14 | #define _tolower(c) (c + 'a' - 'A') 15 | #define _toupper(c) (c + 'A' - 'a') 16 | 17 | extern int isascii (int); 18 | extern int isblank (int); 19 | extern int iscntrl (int); 20 | extern int isdigit (int); 21 | extern int isgraph (int); 22 | extern int islower (int); 23 | extern int isprint (int); 24 | extern int isspace (int); 25 | extern int isupper (int); 26 | extern int isxdigit (int); 27 | extern int toascii (int); 28 | extern int tolower (int); 29 | extern int toupper (int); 30 | 31 | #if defined(__cplusplus) 32 | } 33 | #endif 34 | #endif 35 | -------------------------------------------------------------------------------- /npm/bin/ssc-platform.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import installation from '../src/index.js' 4 | import { spawn } from 'node:child_process' 5 | 6 | let exiting = false 7 | 8 | const child = spawn(installation.bin.ssc, process.argv.slice(2), { 9 | env: { ...installation.env, ...process.env }, 10 | stdio: 'inherit', 11 | windowsHide: true 12 | }) 13 | 14 | child.once('exit', (code) => { 15 | if (!exiting) { 16 | exiting = true 17 | process.exit(code) 18 | } 19 | }) 20 | 21 | child.once('error', (err) => { 22 | console.error(err.message) 23 | if (!exiting) { 24 | process.exit(1) 25 | exiting = true 26 | } 27 | }) 28 | 29 | process.on('SIGTERM', () => { 30 | child.kill('SIGTERM') 31 | }) 32 | 33 | process.on('exit', () => { 34 | child.kill('SIGTERM') 35 | }) 36 | 37 | export default child 38 | -------------------------------------------------------------------------------- /src/runtime/core/service.cc: -------------------------------------------------------------------------------- 1 | #include "../core.hh" 2 | 3 | namespace ssc::runtime::core { 4 | Service::~Service () noexcept {} 5 | 6 | Service::Service (const Options& options) 7 | : dispatcher(options.dispatcher), 8 | services(options.services), 9 | context(options.context), 10 | enabled(options.enabled), 11 | queue(options.workerQueue), 12 | loop(options.loop) 13 | {} 14 | 15 | bool Service::dispatch (const context::Dispatcher::Callback callback) { 16 | return this->dispatcher.dispatch(callback); 17 | } 18 | 19 | bool Service::start () { 20 | return this->enabled.load(); 21 | } 22 | 23 | bool Service::stop () { 24 | return this->enabled.load(); 25 | } 26 | 27 | context::RuntimeContext* Service::getRuntimeContext () { 28 | return &this->context; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/runtime/udp/ip.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_UDP_IP_H 2 | #define SOCKET_RUNTIME_UDP_IP_H 3 | 4 | #include "../platform.hh" 5 | 6 | namespace ssc::runtime::udp::ip { 7 | static inline String addrToIPv4 (struct sockaddr_in* sin) { 8 | char buf[INET_ADDRSTRLEN]; 9 | inet_ntop(AF_INET, &sin->sin_addr, buf, INET_ADDRSTRLEN); 10 | return String(buf); 11 | } 12 | 13 | static inline String addrToIPv6 (struct sockaddr_in6* sin) { 14 | char buf[INET6_ADDRSTRLEN]; 15 | inet_ntop(AF_INET6, &sin->sin6_addr, buf, INET6_ADDRSTRLEN); 16 | return String(buf); 17 | } 18 | 19 | static inline void parseAddress (struct sockaddr *name, int* port, char* address) { 20 | struct sockaddr_in *name_in = (struct sockaddr_in *) name; 21 | *port = ntohs(name_in->sin_port); 22 | uv_ip4_name(name_in, address, 17); 23 | } 24 | } 25 | #endif 26 | -------------------------------------------------------------------------------- /src/init.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(__cplusplus) 4 | extern "C" { 5 | #endif 6 | const unsigned char* socket_runtime_init_get_user_config_bytes () { 7 | return __socket_runtime_user_config_bytes; 8 | } 9 | 10 | unsigned int socket_runtime_init_get_user_config_bytes_size () { 11 | return sizeof(__socket_runtime_user_config_bytes); 12 | } 13 | 14 | bool socket_runtime_init_is_debug_enabled () { 15 | #if DEBUG 16 | return true; 17 | #endif 18 | return false; 19 | } 20 | 21 | const char* socket_runtime_init_get_dev_host () { 22 | #if defined(HOST) 23 | return HOST; 24 | #endif 25 | return ""; 26 | } 27 | 28 | int socket_runtime_init_get_dev_port () { 29 | #if defined(PORT) 30 | return PORT; 31 | #endif 32 | return 0; 33 | } 34 | #if defined(__cplusplus) 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /api/shared-worker/debug.js: -------------------------------------------------------------------------------- 1 | import globals from '../internal/globals.js' 2 | import util from '../util.js' 3 | 4 | export function debug (...args) { 5 | const state = globals.get('SharedWorker.state') 6 | 7 | if (process.env.SOCKET_RUNTIME_SHARED_WORKER_DEBUG) { 8 | console.debug(...args) 9 | } 10 | 11 | if (args[0] instanceof Error) { 12 | globalThis.postMessage({ 13 | __shared_worker_debug: [ 14 | `[${state.sharedWorker.scriptURL}]: ${util.format(...args)}` 15 | ] 16 | }) 17 | 18 | if (typeof state?.reportError === 'function') { 19 | state.reportError(args[0]) 20 | } else if (typeof globalThis.reportError === 'function') { 21 | globalThis.reportError(args[0]) 22 | } 23 | } else { 24 | globalThis.postMessage({ __shared_worker_debug: [util.format(...args)] }) 25 | } 26 | } 27 | 28 | export default debug 29 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | 3 | Copyright 2023 Paolo Fragomeni 4 | Copyright 2023 Joseph Werle 5 | Copyright 2023 Sergey Rubanov 6 | Copyright 2022 Jake Verbaten 7 | Copyright 2022 Serge Zaitsev 8 | 9 | Copyright 2023 Socket Supply Co. 10 | 11 | Licensed under the Apache License, Version 2.0 (the "License"); 12 | you may not use this file except in compliance with the License. 13 | You may obtain a copy of the License at 14 | 15 | http://www.apache.org/licenses/LICENSE-2.0 16 | 17 | Unless required by applicable law or agreed to in writing, software 18 | distributed under the License is distributed on an "AS IS" BASIS, 19 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 | See the License for the specific language governing permissions and 21 | limitations under the License. 22 | -------------------------------------------------------------------------------- /api/service-worker/debug.js: -------------------------------------------------------------------------------- 1 | import globals from '../internal/globals.js' 2 | import util from '../util.js' 3 | 4 | export function debug (...args) { 5 | const state = globals.get('ServiceWorker.state') 6 | 7 | if (process.env.SOCKET_RUNTIME_SERVICE_WORKER_DEBUG) { 8 | console.debug(...args) 9 | } 10 | 11 | if (args[0] instanceof Error) { 12 | globalThis.postMessage({ 13 | __service_worker_debug: [ 14 | `[${state.serviceWorker.scriptURL}]: ${util.format(...args)}` 15 | ] 16 | }) 17 | 18 | if (typeof state?.reportError === 'function') { 19 | state.reportError(args[0]) 20 | } else if (typeof globalThis.reportError === 'function') { 21 | globalThis.reportError(args[0]) 22 | } 23 | } else { 24 | globalThis.postMessage({ __service_worker_debug: [util.format(...args)] }) 25 | } 26 | } 27 | 28 | export default debug 29 | -------------------------------------------------------------------------------- /test/src/runtime-core/json.cc: -------------------------------------------------------------------------------- 1 | #include "tests.hh" 2 | 3 | namespace SSC::Tests { 4 | void json (Harness& t) { 5 | t.test("SSC::JSON::Any", [](auto t) { 6 | t.comment("TODO"); 7 | }); 8 | 9 | t.test("SSC::JSON::Raw", [](auto t) { 10 | t.comment("TODO"); 11 | }); 12 | 13 | t.test("SSC::JSON::Null", [](auto t) { 14 | t.comment("TODO"); 15 | }); 16 | 17 | t.test("SSC::JSON::Object", [](auto t) { 18 | t.comment("TODO"); 19 | }); 20 | 21 | t.test("SSC::JSON::Array", [](auto t) { 22 | t.comment("TODO"); 23 | }); 24 | 25 | t.test("SSC::JSON::Boolean", [](auto t) { 26 | t.comment("TODO"); 27 | }); 28 | 29 | t.test("SSC::JSON::Number", [](auto t) { 30 | t.comment("TODO"); 31 | }); 32 | 33 | t.test("SSC::JSON::String", [](auto t) { 34 | t.comment("TODO"); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /api/async.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module async 3 | * 4 | * Various primitives for async hooks, storage, resources, and contexts. 5 | */ 6 | import AsyncLocalStorage from './async/storage.js' 7 | import AsyncResource from './async/resource.js' 8 | import AsyncContext from './async/context.js' 9 | import Deferred from './async/deferred.js' 10 | 11 | import { 12 | executionAsyncResource, 13 | executionAsyncId, 14 | triggerAsyncId, 15 | createHook, 16 | AsyncHook 17 | } from './async/hooks.js' 18 | 19 | import * as exports from './async.js' 20 | 21 | export { 22 | // async resources/storages 23 | AsyncLocalStorage, 24 | AsyncResource, 25 | // AsyncContext 26 | AsyncContext, 27 | // deferred 28 | Deferred, 29 | // async hooks 30 | executionAsyncResource, 31 | executionAsyncId, 32 | triggerAsyncId, 33 | createHook, 34 | AsyncHook 35 | } 36 | 37 | export default exports 38 | -------------------------------------------------------------------------------- /bin/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | declare root="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)" 4 | 5 | declare PREFIX="${PREFIX:-"/usr/local"}" 6 | declare SOCKET_HOME="${SOCKET_HOME:-"${XDG_DATA_HOME:-"$HOME/.local/share"}/socket"}" 7 | 8 | declare files=($(find "$SOCKET_HOME"/{bin,include,lib,objects,src,uv} -type f 2>/dev/null)) 9 | declare bins=("$PREFIX/bin/ssc") 10 | 11 | declare uninstalled=0 12 | 13 | for file in "${files[@]}"; do 14 | if test -f "$file"; then 15 | echo "# removing $file" 16 | rm -f "$file" 17 | (( uninstalled++ )) 18 | fi 19 | done 20 | 21 | for bin in "${bins[@]}"; do 22 | if test -f "$bin"; then 23 | echo "# removing $bin" 24 | rm -f "$bin" 25 | (( uninstalled++ )) 26 | fi 27 | done 28 | 29 | if (( uninstalled > 0 )); then 30 | echo "ok - uninstalled $uninstalled files" 31 | else 32 | exit 1 33 | fi 34 | -------------------------------------------------------------------------------- /src/runtime/core/services/platform.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CORE_SERVICES_PLATFORM_H 2 | #define SOCKET_RUNTIME_CORE_SERVICES_PLATFORM_H 3 | 4 | #include "../../ipc.hh" 5 | #include "../../core.hh" 6 | 7 | namespace ssc::runtime::core::services { 8 | class Platform : public core::Service { 9 | public: 10 | Atomic wasFirstDOMContentLoadedEventDispatched = false; 11 | 12 | Platform (const Options& options) 13 | : core::Service(options) 14 | {} 15 | 16 | void event ( 17 | const ipc::Message::Seq&, 18 | const String&, 19 | const String&, 20 | const String&, 21 | const String&, 22 | const Callback 23 | ); 24 | void openExternal (const ipc::Message::Seq&, const String&, const Callback); 25 | void revealFile ( const ipc::Message::Seq&, const String&, const Callback); 26 | }; 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /test/src/copy-map.js: -------------------------------------------------------------------------------- 1 | import test from 'socket:test' 2 | import path from 'socket:path' 3 | import fs from 'socket:fs/promises' 4 | import os from 'socket:os' 5 | 6 | if (!['android'].includes(os.platform())) { 7 | test('src/copy-map/file-a.js -> copy-map/A.js', async (t) => { 8 | t.ok(await fs.access(path.join('copy-map', 'A.js')), 'A.js exists') 9 | 10 | try { 11 | await fs.access(path.join('copy-map', 'file-a.js')) 12 | } catch (err) { 13 | t.ok(/no such file/i.test(err?.message), 'file-a.js does not exist') 14 | } 15 | }) 16 | 17 | test('src/copy-map/file-b.js -> copy-map/B.js', async (t) => { 18 | t.ok(await fs.access(path.join('copy-map', 'B.js')), 'B.js exists') 19 | try { 20 | await fs.access(path.join('copy-map', 'file-b.js')) 21 | } catch (err) { 22 | t.ok(/no such file/i.test(err?.message), 'file-b.js does not exist') 23 | } 24 | }) 25 | } 26 | -------------------------------------------------------------------------------- /api/external/libsodium/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2023 2 | Ahmad Ben Mrad 3 | Frank Denis 4 | Ryan Lester 5 | 6 | Permission to use, copy, modify, and/or distribute this software for any 7 | purpose with or without fee is hereby granted, provided that the above 8 | copyright notice and this permission notice appear in all copies. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | -------------------------------------------------------------------------------- /src/runtime/core/services/media_devices.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CORE_SERVICES_MEDIA_DEVICES_H 2 | #define SOCKET_RUNTIME_CORE_SERVICES_MEDIA_DEVICES_H 3 | 4 | #include "../../core.hh" 5 | 6 | namespace ssc::runtime::core::services { 7 | class MediaDevices : public core::Service { 8 | public: 9 | using PermissionChangeObserver = Observer; 10 | using PermissionChangeObservers = Observers; 11 | 12 | PermissionChangeObservers permissionChangeObservers; 13 | 14 | MediaDevices (const Options& options); 15 | ~MediaDevices (); 16 | 17 | bool removePermissionChangeObserver ( 18 | const PermissionChangeObserver& observer 19 | ); 20 | 21 | bool addPermissionChangeObserver ( 22 | const PermissionChangeObserver& observer, 23 | const PermissionChangeObserver::Callback callback 24 | ); 25 | }; 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /test/src/microtask.js: -------------------------------------------------------------------------------- 1 | import test from 'socket:test' 2 | 3 | test('queueMicrotask', async (t) => { 4 | await new Promise((resolve) => { 5 | queueMicrotask(resolve) 6 | }) 7 | 8 | t.pass('queueMicrotask calls callback') 9 | }) 10 | 11 | test('queueMicrotask - sync error', async (t) => { 12 | await new Promise((resolve) => { 13 | globalThis.addEventListener('error', resolve) 14 | queueMicrotask(() => { 15 | throw Object.assign(new Error('error'), { ignore: true }) 16 | }) 17 | }) 18 | 19 | t.pass('queueMicrotask bubbles sync error') 20 | }) 21 | 22 | test('queueMicrotask - async error', async (t) => { 23 | await new Promise((resolve) => { 24 | globalThis.addEventListener('unhandledrejection', resolve) 25 | queueMicrotask(async () => { 26 | throw Object.assign(new Error('error'), { ignore: true }) 27 | }) 28 | }) 29 | 30 | t.pass('queueMicrotask bubbles async error') 31 | }) 32 | -------------------------------------------------------------------------------- /src/runtime/javascript.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_JAVASCRIPT_H 2 | #define SOCKET_RUNTIME_JAVASCRIPT_H 3 | 4 | #include "platform.hh" 5 | #include "json.hh" 6 | 7 | namespace ssc::runtime::javascript { 8 | String createJavaScript (const String& name, const String& source); 9 | 10 | String getEmitToRenderProcessJavaScript ( 11 | const String& event, 12 | const String& value, 13 | const String& target, 14 | const JSON::Object& options 15 | ); 16 | 17 | String getEmitToRenderProcessJavaScript ( 18 | const String& event, 19 | const String& value 20 | ); 21 | 22 | String getResolveMenuSelectionJavaScript ( 23 | const String& seq, 24 | const String& title, 25 | const String& parent, 26 | const String type = "system" 27 | ); 28 | 29 | String getResolveToRenderProcessJavaScript ( 30 | const String& seq, 31 | const String& state, 32 | const String& value 33 | ); 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /api/internal/timers.js: -------------------------------------------------------------------------------- 1 | import { Timeout, Interval, Immediate } from '../timers/timer.js' 2 | import { platform } from '../timers.js' 3 | 4 | export function setTimeout (callback, ...args) { 5 | return Timeout.from(callback, ...args).id 6 | } 7 | 8 | export function clearTimeout (timeout) { 9 | return platform.clearTimeout(timeout) 10 | } 11 | 12 | export function setInterval (callback, ...args) { 13 | return Interval.from(callback, ...args).id 14 | } 15 | 16 | export function clearInterval (interval) { 17 | return platform.clearInterval(interval) 18 | } 19 | 20 | export function setImmediate (callback, ...args) { 21 | return Immediate.from(callback, ...args).id 22 | } 23 | 24 | export function clearImmediate (immediate) { 25 | return platform.clearTimeout(immediate) 26 | } 27 | 28 | export default { 29 | setTimeout, 30 | setInterval, 31 | setImmediate, 32 | clearTimeout, 33 | clearInterval, 34 | clearImmediate 35 | } 36 | -------------------------------------------------------------------------------- /test/src/extensions/simple.js: -------------------------------------------------------------------------------- 1 | import extension from 'socket:extension' 2 | import test from 'socket:test' 3 | import ipc from 'socket:ipc' 4 | 5 | test('extension.load(name) - simple', async (t) => { 6 | const stats = await extension.stats() 7 | try { 8 | const simple = await extension.load('simple-ipc-ping') 9 | t.ok(simple, 'simple = extension.load()') 10 | const result = await ipc.request('simple.ping', { value: 'hello world' }) 11 | t.equal(simple.abi, stats.abi, 'simple.abi === stats.abi') 12 | t.equal(simple.name, 'simple-ipc-ping', 'name === "simple-ipc-ping"') 13 | t.equal(simple.description, 'a simple IPC ping extension', 'description === "a simple IPC ping extension"') 14 | t.equal(simple.version, '0.1.2', 'version === "0.1.2"') 15 | t.equal(result.data, 'hello world', 'ipc://simple.ping mapped') 16 | t.ok(await simple.unload(), 'unload') 17 | } catch (err) { 18 | t.ifError(err) 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /test/src/extensions/sqlite3/socket.ini: -------------------------------------------------------------------------------- 1 | [meta] 2 | name = "sqlite3" 3 | type = "extension" 4 | 5 | [extension] 6 | sources[] = ./extension.cc 7 | sources[] = ../../../build/sqlite3/sqlite3.h 8 | sources[] = ../../../build/sqlite3/sqlite3.c 9 | 10 | [extension.build] 11 | script = sh ../../../scripts/shell.sh scripts/init-sqlite3-build.sh 12 | 13 | [extension.compiler] 14 | flags[] = -DSQLITE_ENABLE_COLUMN_METADATA 15 | flags[] = -DDSQLITE_ENABLE_SESSION 16 | flags[] = -DSQLITE_ENABLE_RTREE 17 | flags[] = -DSQLITE_ENABLE_FTS4 18 | flags[] = -DSQLITE_DQS=0 19 | flags[] = -lpthread -lm -ldl 20 | flags[] = -I../../../build/sqlite3 21 | flags[] = -Os 22 | 23 | [extension.win.compiler] 24 | flags[] = -DWIN64 25 | flags[] = -DNDEBUG 26 | flags[] = -D_WINDOWS 27 | flags[] = -D_USRDLL 28 | flags[] = -DNO_TCL 29 | flags[] = -D_CRT_SECURE_NO_DEPRECATE 30 | flags[] = -DTHREADSAFE=1 31 | flags[] = -DTEMP_STORE=1 32 | flags[] = -DSQLITE_MAX_EXPR_DEPTH=0 33 | flags[] = -m64 34 | -------------------------------------------------------------------------------- /src/runtime/json/boolean.cc: -------------------------------------------------------------------------------- 1 | #include "../json.hh" 2 | 3 | namespace ssc::runtime::JSON { 4 | Type Boolean::valueType = Type::Boolean; 5 | 6 | Boolean::Boolean (const Boolean& boolean) { 7 | this->data = boolean.value(); 8 | } 9 | 10 | Boolean::Boolean (bool boolean) { 11 | this->data = boolean; 12 | } 13 | 14 | Boolean::Boolean (int data) { 15 | this->data = data != 0; 16 | } 17 | 18 | Boolean::Boolean (int64_t data) { 19 | this->data = data != 0; 20 | } 21 | 22 | Boolean::Boolean (double data) { 23 | this->data = data != 0; 24 | } 25 | 26 | Boolean:: Boolean (void *data) { 27 | this->data = data != nullptr; 28 | } 29 | 30 | Boolean:: Boolean (const runtime::String& string) { 31 | this->data = string.size() > 0; 32 | } 33 | 34 | const bool Boolean::value () const { 35 | return this->data; 36 | } 37 | 38 | const runtime::String Boolean::str () const { 39 | return this->data ? "true" : "false"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /api/internal/streams.js: -------------------------------------------------------------------------------- 1 | import { 2 | ReadableStream, 3 | ReadableStreamBYOBReader, 4 | ReadableByteStreamController, 5 | ReadableStreamBYOBRequest, 6 | ReadableStreamDefaultController, 7 | ReadableStreamDefaultReader, 8 | 9 | WritableStream, 10 | WritableStreamDefaultController, 11 | WritableStreamDefaultWriter, 12 | 13 | TransformStream, 14 | TransformStreamDefaultController, 15 | 16 | ByteLengthQueuingStrategy, 17 | CountQueuingStrategy 18 | } from './streams/web.js' 19 | 20 | export { 21 | ReadableStream, 22 | ReadableStreamBYOBReader, 23 | ReadableByteStreamController, 24 | ReadableStreamBYOBRequest, 25 | ReadableStreamDefaultController, 26 | ReadableStreamDefaultReader, 27 | 28 | WritableStream, 29 | WritableStreamDefaultController, 30 | WritableStreamDefaultWriter, 31 | 32 | TransformStream, 33 | TransformStreamDefaultController, 34 | 35 | ByteLengthQueuingStrategy, 36 | CountQueuingStrategy 37 | } 38 | 39 | export default null 40 | -------------------------------------------------------------------------------- /test/src/network/index.js: -------------------------------------------------------------------------------- 1 | import test from 'socket:test' 2 | import { isIPv4 } from 'socket:ip' 3 | import { network, Encryption } from 'socket:network' 4 | 5 | test('basic network constructor', async t => { 6 | // eslint-disable-next-line 7 | const sharedKey = await Encryption.createSharedKey('TEST') 8 | const clusterId = await Encryption.createClusterId('TEST') 9 | const peerId = await Encryption.createId() 10 | const signingKeys = await Encryption.createKeyPair() 11 | 12 | const options = { 13 | clusterId, 14 | peerId, 15 | signingKeys 16 | } 17 | 18 | const socket = await network(options) 19 | 20 | await new Promise((resolve, reject) => { 21 | socket.on('#ready', info => { 22 | t.ok(isIPv4(info.address), 'got an ipv4 address') 23 | t.ok(!isNaN(info.port), 'got a valid port') 24 | t.equal(Buffer.from(info.peerId, 'hex').length, 32, 'valid peerid') 25 | resolve() 26 | }) 27 | socket.on('#error', reject) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /test/src/commonjs/resolvers.js: -------------------------------------------------------------------------------- 1 | const { Module } = require('socket:module') 2 | const dgram = require('socket:dgram') 3 | const test = require('socket:test') 4 | const fs = require('socket:fs') 5 | 6 | test('commonjs - custom resolver - mapping', (t) => { 7 | Module.resolvers.push((specifier, ctx, next) => { 8 | if (specifier === 'filesystem') { 9 | return next('socket:fs') 10 | } 11 | 12 | if (specifier === 'udp') { 13 | return next('socket:dgram') 14 | } 15 | 16 | return next(specifier) 17 | }) 18 | 19 | t.equal(require('filesystem'), fs, 'filesystem -> fs') 20 | t.equal(require('udp'), dgram, 'udp -> dgram') 21 | }) 22 | 23 | test('commonjs - custom resolver - virtual', (t) => { 24 | const virtual = { key: 'value' } 25 | Module.resolvers.push((specifier, ctx, next) => { 26 | if (specifier === 'virtual') { 27 | return virtual 28 | } 29 | 30 | return next(specifier) 31 | }) 32 | 33 | t.equal(require('virtual'), virtual, 'require(\'virtual\') -> virtual') 34 | }) 35 | -------------------------------------------------------------------------------- /src/extension/env.cc: -------------------------------------------------------------------------------- 1 | #include "extension.hh" 2 | 3 | using ssc::runtime::config::getUserConfig; 4 | using ssc::runtime::string::split; 5 | 6 | const char* sapi_env_get ( 7 | sapi_context_t* ctx, 8 | const char* name 9 | ) { 10 | if (ctx == nullptr || name == nullptr) return nullptr; 11 | if (!ctx->isAllowed("env_get")) { 12 | sapi_debug(ctx, "'env_get' is not allowed."); 13 | return nullptr; 14 | } 15 | 16 | static const auto userConfig = getUserConfig(); 17 | 18 | if (!userConfig.contains("build_env")) { 19 | return nullptr; 20 | } 21 | 22 | static const auto allowed = split(userConfig.at("build_env"), ' '); 23 | 24 | if (std::find(allowed.begin(), allowed.end(), name) == allowed.end()) { 25 | return nullptr; 26 | } 27 | 28 | auto value = ssc::runtime::env::get(name); 29 | if (value.size() == 0) { 30 | return nullptr; 31 | } 32 | 33 | auto pointer = ctx->memory.alloc(value.size()); 34 | return reinterpret_cast( 35 | memcpy(pointer, value.c_str(), value.size()) 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /test/scripts/test-desktop.js: -------------------------------------------------------------------------------- 1 | import { rmSync as rm, cpSync as cp } from 'node:fs' 2 | import { execSync as exec } from 'node:child_process' 3 | import path from 'node:path' 4 | import os from 'node:os' 5 | 6 | const dirname = path.dirname(import.meta.url.replace('file://', '').replace(/^\/[A-Za-z]:/, '')) 7 | const root = path.dirname(dirname) 8 | 9 | const SOCKET_HOME_API = path.join(root, '..', 'api') 10 | const { 11 | DEBUG, 12 | TMP, 13 | TMPDIR = TMP || os.tmpdir() 14 | } = process.env 15 | 16 | try { 17 | rm(path.join(TMPDIR, 'ssc-socket-test-fixtures'), { 18 | recursive: true, 19 | force: true 20 | }) 21 | } catch {} 22 | 23 | cp(path.join(root, 'fixtures'), path.join(TMPDIR, 'ssc-socket-test-fixtures'), { 24 | recursive: true 25 | }) 26 | 27 | try { 28 | exec(`ssc build -r --test=./index.js ${!DEBUG ? '-o --prod' : ''}`, { 29 | stdio: 'inherit', 30 | env: { 31 | SOCKET_HOME_API, 32 | ...process.env 33 | } 34 | }) 35 | } catch (err) { 36 | console.log({ err }) 37 | process.exit(err.status || 1) 38 | } 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore Gradle project-specific cache directory 2 | .gradle 3 | 4 | # Ignore Gradle build output directory 5 | build 6 | gradle 7 | gradlew 8 | gradlew.bat 9 | .project 10 | .settings/ 11 | .clang-format 12 | .sscrc 13 | .ssc.env 14 | .vscode 15 | *.gradle* 16 | compile_flags.txt 17 | .classpath 18 | gradle.properties 19 | include/WebView2/README.md 20 | include/WebView2/WebView2.h 21 | include/WebView2/WebView2EnvironmentOptions.h 22 | include/WebView2/WebView2Experimental.h 23 | lib/WebView2LoaderStatic.lib 24 | lib/libuv-ios.a 25 | lib/libuv.a 26 | /lib/uv 27 | /lib/libuv.a 28 | /lib/libuv-ios.a 29 | /bin/build 30 | /bin/ssc.exe 31 | /bin/ssc 32 | build/ 33 | META-INF/ 34 | 35 | # Junk 36 | *.tmp 37 | *.swp 38 | .DS_Store 39 | 40 | # Logs 41 | logs 42 | *.log 43 | npm-debug.log* 44 | yarn-debug.log* 45 | yarn-error.log* 46 | lerna-debug.log* 47 | .pnpm-debug.log* 48 | 49 | # Node.js things 50 | node_modules/ 51 | package-lock.json 52 | 53 | # Default output directory 54 | build/ 55 | 56 | # Provisioning profile 57 | *.mobileprovision 58 | dist/ 59 | *.o 60 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | 7 | 8 | ### What OS are you using (`uname -a`, or Windows version)? 9 | 10 | 14 | 15 | ### What version Socket Runtime are you using? 16 | 17 | 20 | 21 | 22 | ### What programming language are you using (C/C++/Go/Rust)? 23 | 24 | 30 | 31 | ### What did you expect to see and what you saw instead? 32 | 33 | 38 | -------------------------------------------------------------------------------- /src/runtime/core/services/network_status.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CORE_SERVICES_NETWORK_STATUS_H 2 | #define SOCKET_RUNTIME_CORE_SERVICES_NETWORK_STATUS_H 3 | 4 | #include "../../core.hh" 5 | 6 | namespace ssc::runtime::core::services { 7 | class NetworkStatus : public core::Service { 8 | public: 9 | using Observer = Observer; 10 | using Observers = Observers; 11 | 12 | #if SOCKET_RUNTIME_PLATFORM_APPLE 13 | dispatch_queue_t queue = nullptr; 14 | nw_path_monitor_t monitor = nullptr; 15 | #elif SOCKET_RUNTIME_PLATFORM_LINUX 16 | GNetworkMonitor* monitor = nullptr; 17 | guint signal = 0; 18 | #endif 19 | 20 | Observers observers; 21 | 22 | NetworkStatus (const Options&); 23 | ~NetworkStatus (); 24 | 25 | bool start () override; 26 | bool stop () override; 27 | bool addObserver ( 28 | const Observer& observer, 29 | const Observer::Callback callback = nullptr 30 | ); 31 | 32 | bool removeObserver (const Observer& observer); 33 | }; 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/socket/webassembly.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_H 3 | 4 | #include "webassembly/stdbool.h" 5 | #include "webassembly/stddef.h" 6 | #include "webassembly/stdint.h" 7 | #include "webassembly/stdio.h" 8 | #include "webassembly/stdlib.h" 9 | #include "webassembly/string.h" 10 | #include "webassembly/errno.h" 11 | #include "webassembly/uv.h" 12 | 13 | // platform 14 | #define SOCKET_RUNTIME_PLATFORM_NAME "wasm32" 15 | #define SOCKET_RUNTIME_PLATFORM_OS "web" 16 | #define SOCKET_RUNTIME_PLATFORM_ANDROID 0 17 | #define SOCKET_RUNTIME_PLATFORM_IOS 0 18 | #define SOCKET_RUNTIME_PLATFORM_IOS_SIMULATOR 0 19 | #define SOCKET_RUNTIME_PLATFORM_LINUX 0 20 | #define SOCKET_RUNTIME_PLATFORM_MACOS 0 21 | #define SOCKET_RUNTIME_PLATFORM_WINDOWS 0 22 | #define SOCKET_RUNTIME_PLATFORM_UXIX 0 23 | // when this header is included, this is always `1` 24 | #define SOCKET_RUNTIME_PLATFORM_WASM 1 25 | 26 | // arch 27 | #define SOCKET_RUNTIME_PLATFORM_ARCH_x64 0 28 | #define SOCKET_RUNTIME_PLATFORM_ARCH_ARM64 0 29 | #define SOCKET_RUNTIME_PLATFORM_ARCH_UNKNOWN 1 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socketsupply/socket-node", 3 | "version": "0.6.0-rc.8", 4 | "description": "A Node.js adapter for the Socket runtime", 5 | "main": "index.js", 6 | "exports": { 7 | "import": "./index.js", 8 | "require": "./index.cjs" 9 | }, 10 | "type": "module", 11 | "scripts": { 12 | "test": "standard index.js", 13 | "pub": "npm pub && npm publish --registry https://npm.pkg.github.com", 14 | "build": "esbuild index.js --outfile=index.cjs --platform=node --format=cjs", 15 | "prepublishOnly": "npm run build" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/socketsupply/socket.git" 20 | }, 21 | "author": "Socket Supply, Co ", 22 | "license": "Apache-2.0", 23 | "bugs": { 24 | "url": "https://github.com/socketsupply/socket/issues" 25 | }, 26 | "homepage": "https://github.com/socketsupply/socket#readme", 27 | "devDependencies": { 28 | "@types/node": "20.7.0", 29 | "esbuild": "0.19.3", 30 | "standard": "^17.1.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-linux-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socketsupply/socket-linux-x64", 3 | "version": "0.6.0-rc.8", 4 | "description": "A Cross-Platform, Native Runtime for Desktop and Mobile Apps — Create apps using HTML, CSS, and JavaScript. Written from the ground up to be small and maintainable.", 5 | "type": "module", 6 | "main": "src/index.js", 7 | "os": [ 8 | "linux" 9 | ], 10 | "cpu": [ 11 | "x64" 12 | ], 13 | "scripts": { 14 | "test": ":", 15 | "install": "bin/verify-platform.js linux x64" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+ssh://git@github.com/socketsupply/socket.git" 20 | }, 21 | "keywords": [ 22 | "socket", 23 | "runtime", 24 | "webview", 25 | "javascript", 26 | "desktop", 27 | "mobile", 28 | "linux", 29 | "x64" 30 | ], 31 | "author": "Socket Supply, Co ", 32 | "license": "Apache-2.0", 33 | "bugs": { 34 | "url": "https://github.com/socketsupply/socket/issues" 35 | }, 36 | "homepage": "https://github.com/socketsupply/socket#readme" 37 | } 38 | -------------------------------------------------------------------------------- /api/internal/post-message.js: -------------------------------------------------------------------------------- 1 | import serialize from './serialize.js' 2 | 3 | const { 4 | BroadcastChannel, 5 | MessagePort, 6 | postMessage 7 | } = globalThis 8 | 9 | const platform = { 10 | BroadcastChannelPostMessage: BroadcastChannel.prototype.postMessage, 11 | MessagePortPostMessage: MessagePort.prototype.postMessage, 12 | GlobalPostMessage: postMessage 13 | } 14 | 15 | BroadcastChannel.prototype.postMessage = function (message, ...args) { 16 | return platform.BroadcastChannelPostMessage.call( 17 | this, 18 | handlePostMessage(message), 19 | ...args 20 | ) 21 | } 22 | 23 | MessagePort.prototype.postMessage = function (message, ...args) { 24 | return platform.MessagePortPostMessage.call( 25 | this, 26 | handlePostMessage(message), 27 | ...args 28 | ) 29 | } 30 | 31 | globalThis.postMessage = function (message, ...args) { 32 | return platform.GlobalPostMessage.call( 33 | this, 34 | handlePostMessage(message), 35 | ...args 36 | ) 37 | } 38 | 39 | function handlePostMessage (message) { 40 | return serialize(message) 41 | } 42 | 43 | export default null 44 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-darwin-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socketsupply/socket-darwin-x64", 3 | "version": "0.6.0-rc.8", 4 | "description": "A Cross-Platform, Native Runtime for Desktop and Mobile Apps — Create apps using HTML, CSS, and JavaScript. Written from the ground up to be small and maintainable.", 5 | "type": "module", 6 | "main": "src/index.js", 7 | "os": [ 8 | "darwin" 9 | ], 10 | "cpu": [ 11 | "x64" 12 | ], 13 | "scripts": { 14 | "test": ":", 15 | "install": "bin/verify-platform.js darwin x64" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+ssh://git@github.com/socketsupply/socket.git" 20 | }, 21 | "keywords": [ 22 | "socket", 23 | "runtime", 24 | "webview", 25 | "javascript", 26 | "desktop", 27 | "mobile", 28 | "darwin", 29 | "arm64" 30 | ], 31 | "author": "Socket Supply, Co ", 32 | "license": "Apache-2.0", 33 | "bugs": { 34 | "url": "https://github.com/socketsupply/socket/issues" 35 | }, 36 | "homepage": "https://github.com/socketsupply/socket#readme" 37 | } 38 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-linux-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socketsupply/socket-linux-arm64", 3 | "version": "0.6.0-rc.8", 4 | "description": "A Cross-Platform, Native Runtime for Desktop and Mobile Apps — Create apps using HTML, CSS, and JavaScript. Written from the ground up to be small and maintainable.", 5 | "type": "module", 6 | "main": "src/index.js", 7 | "os": [ 8 | "linux" 9 | ], 10 | "cpu": [ 11 | "arm64" 12 | ], 13 | "scripts": { 14 | "test": ":", 15 | "install": "bin/verify-platform.js linux arm64" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+ssh://git@github.com/socketsupply/socket.git" 20 | }, 21 | "keywords": [ 22 | "socket", 23 | "runtime", 24 | "webview", 25 | "javascript", 26 | "desktop", 27 | "mobile", 28 | "linux", 29 | "arm64" 30 | ], 31 | "author": "Socket Supply, Co ", 32 | "license": "Apache-2.0", 33 | "bugs": { 34 | "url": "https://github.com/socketsupply/socket/issues" 35 | }, 36 | "homepage": "https://github.com/socketsupply/socket#readme" 37 | } 38 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-darwin-arm64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socketsupply/socket-darwin-arm64", 3 | "version": "0.6.0-rc.8", 4 | "description": "A Cross-Platform, Native Runtime for Desktop and Mobile Apps — Create apps using HTML, CSS, and JavaScript. Written from the ground up to be small and maintainable.", 5 | "type": "module", 6 | "main": "src/index.js", 7 | "os": [ 8 | "darwin" 9 | ], 10 | "cpu": [ 11 | "arm64" 12 | ], 13 | "scripts": { 14 | "test": ":", 15 | "install": "bin/verify-platform.js darwin arm64" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+ssh://git@github.com/socketsupply/socket.git" 20 | }, 21 | "keywords": [ 22 | "socket", 23 | "runtime", 24 | "webview", 25 | "javascript", 26 | "desktop", 27 | "mobile", 28 | "darwin", 29 | "arm64" 30 | ], 31 | "author": "Socket Supply, Co ", 32 | "license": "Apache-2.0", 33 | "bugs": { 34 | "url": "https://github.com/socketsupply/socket/issues" 35 | }, 36 | "homepage": "https://github.com/socketsupply/socket#readme" 37 | } 38 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-win32-x64/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socketsupply/socket-win32-x64", 3 | "version": "0.6.0-rc.8", 4 | "description": "A Cross-Platform, Native Runtime for Desktop and Mobile Apps — Create apps using HTML, CSS, and JavaScript. Written from the ground up to be small and maintainable.", 5 | "type": "module", 6 | "main": "src/index.js", 7 | "os": [ 8 | "win32" 9 | ], 10 | "cpu": [ 11 | "x64" 12 | ], 13 | "scripts": { 14 | "test": ":", 15 | "install": "cd bin && node verify-platform.js win32 x64 -" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+ssh://git@github.com/socketsupply/socket.git" 20 | }, 21 | "keywords": [ 22 | "socket", 23 | "runtime", 24 | "webview", 25 | "javascript", 26 | "desktop", 27 | "mobile", 28 | "linux", 29 | "x64" 30 | ], 31 | "author": "Socket Supply, Co ", 32 | "license": "Apache-2.0", 33 | "bugs": { 34 | "url": "https://github.com/socketsupply/socket/issues" 35 | }, 36 | "homepage": "https://github.com/socketsupply/socket#readme" 37 | } 38 | -------------------------------------------------------------------------------- /src/runtime/concurrent/abort.cc: -------------------------------------------------------------------------------- 1 | #include "../concurrent.hh" 2 | 3 | namespace ssc::runtime::concurrent { 4 | AbortSignal::AbortSignal (const AbortController* controller) 5 | : controller(controller) 6 | {} 7 | 8 | AbortSignal::AbortSignal (const AbortSignal& signal) 9 | : controller(signal.controller) 10 | {} 11 | 12 | AbortSignal::AbortSignal (AbortSignal&& signal) 13 | : controller(signal.controller) 14 | { 15 | signal.controller = nullptr; 16 | } 17 | 18 | AbortSignal& AbortSignal::operator = (const AbortSignal& signal) { 19 | this->controller = signal.controller; 20 | return *this; 21 | } 22 | 23 | AbortSignal& AbortSignal::operator = (AbortSignal&& signal) { 24 | this->controller = signal.controller; 25 | signal.controller = nullptr; 26 | return *this; 27 | } 28 | 29 | bool AbortSignal::aborted () const { 30 | if (this->controller == nullptr) { 31 | return false; 32 | } 33 | return this->controller->isAborted.load(std::memory_order_acquire); 34 | } 35 | 36 | void AbortController::abort () { 37 | this->isAborted = true; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /bin/ci_version_check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | VERSION_SSC=$(ssc -v | head -n 1) 4 | 5 | VERSION_TXT=$(cat VERSION.txt) 6 | VERSION_GIT=$(git rev-parse --short=8 HEAD) 7 | VERSION_EXPECTED="$VERSION_TXT ($VERSION_GIT)" 8 | 9 | if [ "$VERSION_SSC" = "$VERSION_EXPECTED" ]; then 10 | echo "Version check has passed"; 11 | else 12 | echo "Version check has failed"; 13 | echo "Expected: $VERSION_EXPECTED"; 14 | echo "Got: $VERSION_SSC"; 15 | exit 1; 16 | fi 17 | 18 | BASE_LIST=($(echo $VERSION_TXT | tr '.' ' ')) 19 | 20 | V_MAJOR=${BASE_LIST[0]} 21 | V_MINOR=${BASE_LIST[1]} 22 | 23 | VERSION_NODE=$(npm show ./npm/packages/@socketsupply/socket-node version) 24 | 25 | BASE_LIST=($(echo $VERSION_NODE | tr '.' ' ')) 26 | 27 | V_MAJOR_NODE=${BASE_LIST[0]} 28 | V_MINOR_NODE=${BASE_LIST[1]} 29 | 30 | if [ "$V_MAJOR" -ne "$V_MAJOR_NODE" ] || [ "$V_MINOR" -ne "$V_MINOR_NODE" ]; then 31 | echo "Version of @socketsupply/socket-node is not in sync with @socketsupply/socket"; 32 | echo "@socketsupply/socket version is $VERSION_TXT"; 33 | echo "@socketsupply/socket-node version is $VERSION_NODE"; 34 | exit 1; 35 | fi 36 | -------------------------------------------------------------------------------- /include/socket/webassembly/features.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_FEATURES_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_FEATURES_H 3 | 4 | #if !defined(_FEATURES_H) 5 | #define _FEATURES_H 6 | #endif 7 | 8 | #if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE) 9 | #define _GNU_SOURCE 1 10 | #endif 11 | 12 | #if defined(_DEFAULT_SOURCE) && !defined(_BSD_SOURCE) 13 | #define _BSD_SOURCE 1 14 | #endif 15 | 16 | #if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) && \ 17 | !defined(_XOPEN_SOURCE) && !defined(_GNU_SOURCE) && \ 18 | !defined(_BSD_SOURCE) && !defined(__STRICT_ANSI__) 19 | #define _BSD_SOURCE 1 20 | #define _XOPEN_SOURCE 700 21 | #endif 22 | 23 | #if __STDC_VERSION__ >= 199901L 24 | #define __restrict restrict 25 | #elif !defined(__GNUC__) 26 | #define __restrict 27 | #endif 28 | 29 | #if __STDC_VERSION__ >= 199901L || defined(__cplusplus) 30 | #define __inline inline 31 | #elif !defined(__GNUC__) 32 | #define __inline 33 | #endif 34 | 35 | #if __STDC_VERSION__ >= 201112L 36 | #elif defined(__GNUC__) 37 | #define _Noreturn __attribute__((__noreturn__)) 38 | #else 39 | #define _Noreturn 40 | #endif 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /api/fetch/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2023 GitHub, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /src/runtime/platform/android/mime.cc: -------------------------------------------------------------------------------- 1 | #include "mime.hh" 2 | #include "string_wrap.hh" 3 | 4 | namespace ssc::runtime::android { 5 | static MimeTypeMap sharedMimeTypeMap; 6 | 7 | void initializeMimeTypeMap (MimeTypeMapRef ref, JVMEnvironment jvm) { 8 | sharedMimeTypeMap.ref = ref; 9 | sharedMimeTypeMap.jvm = jvm; 10 | } 11 | 12 | const MimeTypeMap* MimeTypeMap::sharedMimeTypeMap () { 13 | return &android::sharedMimeTypeMap; 14 | } 15 | 16 | String MimeTypeMap::getMimeTypeFromExtension (const String& extension) const { 17 | const auto attachment = JNIEnvironmentAttachment(this->jvm); 18 | const auto extensionString = attachment.env->NewStringUTF(extension.c_str()); 19 | const auto mimeTypeString = (jstring) CallObjectClassMethodFromAndroidEnvironment( 20 | attachment.env, 21 | this->ref, 22 | "getMimeTypeFromExtension", 23 | "(Ljava/lang/String;)Ljava/lang/String;", 24 | extensionString 25 | ); 26 | 27 | const auto mimeType = StringWrap(attachment.env, mimeTypeString).str(); 28 | attachment.env->DeleteLocalRef(extensionString); 29 | return mimeType; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api/test/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jake Verbaten 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. 22 | -------------------------------------------------------------------------------- /api/url/urlpattern/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Intel Corporation 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/runtime/json/raw.cc: -------------------------------------------------------------------------------- 1 | #include "../json.hh" 2 | 3 | namespace ssc::runtime::JSON { 4 | Type Raw::valueType = Type::Raw; 5 | 6 | Raw::Raw (const Raw& raw) { 7 | this->data = raw.data; 8 | } 9 | 10 | Raw::Raw (Raw&& raw) { 11 | this->data = std::move(raw.data); 12 | raw.data = ""; 13 | } 14 | 15 | Raw::Raw (const Raw* raw) { 16 | if (raw != nullptr) { 17 | this->data = raw->data; 18 | } 19 | } 20 | 21 | Raw::Raw (const runtime::String& source) { 22 | this->data = source; 23 | } 24 | 25 | Raw::Raw (const Any& source) { 26 | if (source.isString()) { 27 | this->data = source.data; 28 | } else { 29 | this->data = source.str(); 30 | } 31 | } 32 | 33 | Raw& Raw::operator = (const Raw& raw) { 34 | this->data = raw.data; 35 | return *this; 36 | } 37 | 38 | Raw& Raw::operator = (Raw&& raw) { 39 | this->data = std::move(raw.data); 40 | raw.data = ""; 41 | return *this; 42 | } 43 | 44 | const runtime::String Raw::value () const { 45 | return this->data; 46 | } 47 | 48 | const runtime::String Raw::str () const { 49 | return this->data; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/runtime/platform/android/types.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_PLATFORM_ANDROID_TYPES_H 2 | #define SOCKET_RUNTIME_PLATFORM_ANDROID_TYPES_H 3 | 4 | #include "../types.hh" 5 | #include "native.hh" 6 | 7 | namespace ssc::runtime::android { 8 | using namespace ssc::runtime::types; 9 | 10 | /** 11 | * An Android AssetManager NDK type. 12 | */ 13 | using AssetManager = ::AAssetManager; 14 | 15 | /** 16 | * An Android AssetManager Asset NDK type. 17 | */ 18 | using Asset = ::AAsset; 19 | 20 | /** 21 | * An Android AssetManager AssetDirectory NDK type. 22 | */ 23 | using AssetDirectory = ::AAssetDir; 24 | 25 | /** 26 | * An opaque `Activity` instance. 27 | */ 28 | using Activity = ::jobject; 29 | 30 | /** 31 | * An opaque `Application` instance. 32 | */ 33 | using Application = ::jobject; 34 | 35 | /** 36 | * A container that holds Android OS build information. 37 | */ 38 | struct BuildInformation { 39 | String brand; 40 | String device; 41 | String fingerprint; 42 | String hardware; 43 | String model; 44 | String manufacturer; 45 | String product; 46 | }; 47 | } 48 | #endif 49 | -------------------------------------------------------------------------------- /api/url/url/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Sebastian Mayr 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /api/protocol-handlers.js: -------------------------------------------------------------------------------- 1 | import ipc from './ipc.js' 2 | 3 | /** 4 | * @typedef {{ scheme: string }} GetServiceWorkerOptions 5 | 6 | /** 7 | * @param {GetServiceWorkerOptions} options 8 | * @return {Promise 9 | */ 10 | export async function getServiceWorker (options) { 11 | const result = await ipc.request('protocol.getServiceWorkerRegistration', { 12 | scheme: options.scheme 13 | }) 14 | 15 | if (result.err) { 16 | throw result.err 17 | } 18 | 19 | if (result.data) { 20 | const { scope, scriptURL } = result.data 21 | const registrations = await globalThis.navigator.serviceWorker.getRegistrations() 22 | for (const registration of registrations) { 23 | const serviceWorker = ( 24 | registration.active || 25 | registration.waiting || 26 | registration.installing || 27 | null 28 | ) 29 | 30 | if ( 31 | serviceWorker && registration.scope === scope && 32 | serviceWorker.scriptURL === scriptURL 33 | ) { 34 | return serviceWorker 35 | } 36 | } 37 | } 38 | 39 | return null 40 | } 41 | 42 | export default { 43 | getServiceWorker 44 | } 45 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket-node/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Socket Supply Co. 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. -------------------------------------------------------------------------------- /api/navigation/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Axiom Applied Technologies and Development Limited 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. 22 | -------------------------------------------------------------------------------- /test/src/extensions/simple/ipc-ping.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void onping ( 4 | sapi_context_t* context, 5 | sapi_ipc_message_t* message, 6 | const sapi_ipc_router_t* router 7 | ) { 8 | const char* pong = sapi_ipc_message_get_value(message); 9 | sapi_ipc_result_t* result = sapi_ipc_result_create(context, message); 10 | sapi_ipc_result_set_json_data( 11 | result, 12 | sapi_json_any(sapi_json_string_create(context, pong)) 13 | ); 14 | sapi_ipc_reply(result); 15 | } 16 | 17 | bool initialize (sapi_context_t* context, const void *data) { 18 | if (sapi_extension_is_allowed(context, "ipc_router_map")) { 19 | sapi_ipc_router_map(context, "simple.ping", onping, data); 20 | } 21 | return true; 22 | } 23 | 24 | bool deinitialize (sapi_context_t* context, const void *data) { 25 | if (sapi_extension_is_allowed(context, "ipc_router_unmap")) { 26 | sapi_ipc_router_unmap(context, "simple.ping"); 27 | } 28 | return true; 29 | } 30 | 31 | SOCKET_RUNTIME_REGISTER_EXTENSION( 32 | "simple-ipc-ping", // name 33 | initialize, // initializer 34 | deinitialize, // deinitializer 35 | "a simple IPC ping extension", // description 36 | "0.1.2" // version 37 | ); 38 | -------------------------------------------------------------------------------- /src/runtime/core/services/os.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CORE_SERVICES_OS_H 2 | #define SOCKET_RUNTIME_CORE_SERVICES_OS_H 3 | 4 | #include "../../ipc.hh" 5 | #include "../../core.hh" 6 | 7 | namespace ssc::runtime::core::services { 8 | class OS : public core::Service { 9 | public: 10 | static const int RECV_BUFFER = 1; 11 | static const int SEND_BUFFER = 0; 12 | 13 | OS (const Options& options) 14 | : core::Service(options) 15 | {} 16 | 17 | void cpus ( const ipc::Message::Seq&, const Callback) const; 18 | void rusage (const ipc::Message::Seq&, const Callback) const; 19 | void uname (const ipc::Message::Seq&, const Callback) const; 20 | void uptime (const ipc::Message::Seq&, const Callback) const; 21 | void hrtime (const ipc::Message::Seq&, const Callback) const; 22 | void constants (const ipc::Message::Seq&, const Callback) const; 23 | void bufferSize (const ipc::Message::Seq&, uint64_t, size_t, int /* RECV_BUFFER|SEND_BUFFER */, const Callback) const; 24 | void availableMemory (const ipc::Message::Seq&, const Callback) const; 25 | void networkInterfaces (const ipc::Message::Seq&, const Callback) const; 26 | }; 27 | } 28 | #endif 29 | -------------------------------------------------------------------------------- /test/scripts/test-android.js: -------------------------------------------------------------------------------- 1 | import { execSync as exec } from 'node:child_process' 2 | import path from 'node:path' 3 | 4 | const { ANDROID_HOME, SSC_ANDROID_CI } = process.env 5 | const dirname = path.dirname(import.meta.url.replace('file://', '')) 6 | const root = path.dirname(dirname) 7 | const adb = `${ANDROID_HOME}/platform-tools/adb` 8 | const id = 'co.socketsupply.socket.tests' 9 | 10 | try { 11 | exec(`${adb} uninstall ${id}`, { stdio: 'inherit' }) 12 | } catch { 13 | } 14 | 15 | if (SSC_ANDROID_CI) { 16 | exec('ssc build -r -o --test=./index.js --headless --platform=android --env=CI --env=SSC_ANDROID_CI', { 17 | stdio: 'inherit' 18 | }) 19 | } else { 20 | exec('ssc build -r -o --test=./index.js --prod --headless --platform=android --env SOCKET_DEBUG_IPC', { 21 | stdio: 'inherit' 22 | }) 23 | } 24 | 25 | try { 26 | exec(`${adb} shell rm -rf /data/local/tmp/ssc-socket-test-fixtures`, { 27 | stdio: 'inherit' 28 | }) 29 | } catch { 30 | } 31 | 32 | exec(`${adb} push ${path.join(root, 'fixtures')} /data/local/tmp/ssc-socket-test-fixtures`, { 33 | stdio: 'inherit' 34 | }) 35 | 36 | exec(`${process.env.SHELL || 'sh'} ${path.resolve(root, 'scripts', 'poll-adb-logcat.sh')}`, { 37 | stdio: 'inherit' 38 | }) 39 | -------------------------------------------------------------------------------- /src/runtime/bridge/manager.cc: -------------------------------------------------------------------------------- 1 | #include "../runtime.hh" 2 | #include "../bridge.hh" 3 | 4 | namespace ssc::runtime::bridge { 5 | Manager::Manager (context::RuntimeContext& context) 6 | : context(context) 7 | {} 8 | 9 | Manager::~Manager () {} 10 | 11 | SharedPointer Manager::get (int index, const BridgeOptions& options) { 12 | Lock lock(this->mutex); 13 | if (index >= this->entries.size() || this->entries[index] == nullptr) { 14 | if (index >= this->entries.size()) { 15 | this->entries.resize(index + 1); 16 | } 17 | 18 | this->entries[index] = std::make_shared(Bridge::Options { 19 | .context = this->context, 20 | .dispatcher = static_cast(this->context).dispatcher, 21 | .userConfig = options.userConfig 22 | }); 23 | } 24 | 25 | return this->entries[index]; 26 | } 27 | 28 | bool Manager::has (int index) const { 29 | return index < this->entries.size() && this->entries.at(index) != nullptr; 30 | } 31 | 32 | bool Manager::remove (int index) { 33 | if (this->has(index)) { 34 | this->entries.erase(this->entries.begin() + index); 35 | return true; 36 | } 37 | 38 | return false; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/runtime/crypto/rand.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../crypto.hh" 4 | 5 | #define IMAX_BITS(m) ((m)/((m) % 255+1) / 255 % 255 * 8 + 7-86 / ((m) % 255+12)) 6 | #define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX) 7 | 8 | namespace ssc::runtime::crypto { 9 | uint64_t rand64 () { 10 | static const auto width = RAND_MAX_WIDTH; 11 | static bool init = false; 12 | 13 | if (!init) { 14 | init = true; 15 | srand(time(0)); 16 | } 17 | 18 | uint64_t r = 0; 19 | for (int i = 0; i < 64; i += width) { 20 | r <<= width; 21 | r ^= (unsigned) rand(); 22 | } 23 | return r; 24 | } 25 | 26 | int randint (int a, int b) { 27 | if (a == 0 && b == 0) { 28 | return 0; 29 | } 30 | 31 | static std::random_device rd; // non-deterministic random seed 32 | static std::mt19937 gen(rd()); // mersenne twister rng 33 | 34 | // Create a uniform distribution in the range of valid indices 35 | std::uniform_int_distribution dist(a, b); 36 | 37 | // Generate and return a random index 38 | return dist(gen); 39 | } 40 | 41 | int randint (int a) { 42 | return randint(a, INT_MAX); 43 | } 44 | 45 | int randint () { 46 | return randint(0, INT_MAX); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /test/src/application-url-event.js: -------------------------------------------------------------------------------- 1 | import application from 'socket:application' 2 | import test from 'socket:test' 3 | 4 | test('trigger from openExternal', async (t) => { 5 | const window = await application.getCurrentWindow() 6 | const expected = 'socket-tests://from-open-external?key=value' 7 | const pending = new Promise((resolve) => { 8 | globalThis.addEventListener('applicationurl', callback, { once: true }) 9 | function callback (event) { 10 | t.equal(typeof event.source, 'string', 'event.source is string') 11 | t.equal(event.isValid, true, 'event.isValid is true') 12 | t.ok(event.url instanceof URL, 'event.url is URL') 13 | t.equal(event.url.protocol, 'socket-tests:', 'event.url.protocol is "socket-test"') 14 | t.equal(event.url.hostname, 'from-open-external', 'event.url.hostname === "from-open-external"') 15 | t.equal(event.url.searchParams.get('key'), 'value', 'event.url.searchParams.get("key") is "value"') 16 | resolve() 17 | } 18 | }) 19 | 20 | try { 21 | const result = await window.openExternal({ value: expected }) 22 | t.equal(result.url, expected, 'result.url === expected') 23 | } catch (err) { 24 | return t.fail(err) 25 | } 26 | 27 | await pending 28 | }) 29 | -------------------------------------------------------------------------------- /src/runtime/unique_client.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_UNIQUE_CLIENT_H 2 | #define SOCKET_RUNTIME_UNIQUE_CLIENT_H 3 | 4 | #include "platform.hh" 5 | #include "crypto.hh" 6 | 7 | namespace ssc::runtime { 8 | struct UniqueClient { 9 | using ID = uint64_t; 10 | ID id = crypto::rand64(); 11 | int index = -1; 12 | 13 | UniqueClient () = default; 14 | UniqueClient (ID id) 15 | : id(id) 16 | {} 17 | 18 | UniqueClient (ID id, int index) 19 | : id(id), index(index) 20 | {} 21 | 22 | UniqueClient (const UniqueClient& client) 23 | : id(client.id), 24 | index(client.index) 25 | {} 26 | 27 | UniqueClient (UniqueClient&& client) 28 | : id(client.id), 29 | index(client.index) 30 | { 31 | client.id = 0; 32 | client.index = -1; 33 | } 34 | 35 | virtual ~UniqueClient () {} 36 | 37 | UniqueClient& operator = (const UniqueClient& client) { 38 | this->id = client.id; 39 | this->index = client.index; 40 | return *this; 41 | } 42 | 43 | UniqueClient& operator = (UniqueClient&& client) { 44 | this->id = client.id; 45 | this->index = client.index; 46 | client.id = 0; 47 | client.index = -1; 48 | return *this; 49 | } 50 | }; 51 | } 52 | #endif 53 | -------------------------------------------------------------------------------- /bin/version.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LATEST_HASH=$(git log --pretty=format:'%h' -n 1) 4 | 5 | BASE_STRING=$(cat VERSION.txt) 6 | BASE_LIST=($(echo $BASE_STRING | tr '.' ' ')) 7 | V_MAJOR=${BASE_LIST[0]} 8 | V_MINOR=${BASE_LIST[1]} 9 | V_PATCH=${BASE_LIST[2]} 10 | echo -e "Current version: $BASE_STRING" 11 | echo -e "Latest commit hash: $LATEST_HASH" 12 | V_PATCH=$((V_PATCH + 1)) 13 | SUGGESTED_VERSION="$V_MAJOR.$V_MINOR.$V_PATCH" 14 | echo -ne "Enter a version number [$SUGGESTED_VERSION]: " 15 | read INPUT_STRING 16 | if [ "$INPUT_STRING" = "" ]; then 17 | INPUT_STRING=$SUGGESTED_VERSION 18 | fi 19 | echo -e "Will set new version to be $INPUT_STRING" 20 | echo $INPUT_STRING > VERSION.txt 21 | jq ".version = \"$INPUT_STRING\"" clib.json > tmp.$$.json && mv tmp.$$.json clib.json 22 | 23 | BASE_LIST=($(echo $INPUT_STRING | tr '.' ' ')) 24 | V_MAJOR_NEW=${BASE_LIST[0]} 25 | V_MINOR_NEW=${BASE_LIST[1]} 26 | 27 | if [ "$V_MAJOR" -ne "$V_MAJOR_NEW" ] || [ "$V_MINOR" -ne "$V_MINOR_NEW" ]; then 28 | cd npm/packages/@socketsupply/socket-node 29 | npm version $V_MAJOR_NEW.$V_MINOR_NEW.0 30 | fi 31 | 32 | # git add VERSION.txt clib.json 33 | # git commit -m "Bump version to ${INPUT_STRING}." 34 | # git tag -a -m "Tag version ${INPUT_STRING}." "v$INPUT_STRING" 35 | # git push origin --tags 36 | 37 | echo -e "Finished." 38 | -------------------------------------------------------------------------------- /src/runtime.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_H 2 | #define SOCKET_RUNTIME_H 3 | 4 | #include "runtime/ai.hh" 5 | #include "runtime/app.hh" 6 | #include "runtime/cwd.hh" 7 | #include "runtime/core.hh" 8 | #include "runtime/bridge.hh" 9 | #include "runtime/env.hh" 10 | #include "runtime/filesystem.hh" 11 | #include "runtime/io.hh" 12 | #include "runtime/ini.hh" 13 | #include "runtime/ipc.hh" 14 | #include "runtime/json.hh" 15 | #include "runtime/javascript.hh" 16 | #include "runtime/loop.hh" 17 | #include "runtime/os.hh" 18 | #include "runtime/platform.hh" 19 | #include "runtime/process.hh" 20 | #include "runtime/runtime.hh" 21 | #include "runtime/string.hh" 22 | #include "runtime/udp.hh" 23 | #include "runtime/uuid.hh" 24 | #include "runtime/url.hh" 25 | #include "runtime/version.hh" 26 | #include "runtime/webview.hh" 27 | #include "runtime/window.hh" 28 | 29 | namespace ssc::runtime { 30 | inline const auto VERSION_FULL_STRING = version::VERSION_FULL_STRING; 31 | inline const auto VERSION_HASH_STRING = version::VERSION_HASH_STRING; 32 | inline const auto VERSION_STRING = version::VERSION_STRING; 33 | 34 | using App = app::App; 35 | using Bridge = bridge::Bridge; 36 | using Loop = loop::Loop; 37 | using Process = process::Process; 38 | using URL = url::URL; 39 | using Window = window::Window; 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /api/internal/serialize.js: -------------------------------------------------------------------------------- 1 | import Buffer from '../buffer.js' 2 | 3 | export default function serialize (value) { 4 | if (!value || typeof value !== 'object') { 5 | return value 6 | } 7 | 8 | return map(value, (value) => { 9 | if (Buffer.isBuffer(value)) return value 10 | 11 | if (typeof value[Symbol.serialize] === 'function') { 12 | return value[Symbol.serialize]() 13 | } 14 | 15 | if (typeof value.toJSON === 'function') { 16 | return value.toJSON() 17 | } 18 | 19 | return value 20 | }) 21 | } 22 | 23 | function map (object, callback, seen = new Set()) { 24 | if (seen.has(object)) { 25 | return object 26 | } 27 | 28 | if (Array.isArray(object)) { 29 | for (let i = 0; i < object.length; ++i) { 30 | object[i] = map(object[i], callback, seen) 31 | } 32 | } else if (object && typeof object === 'object') { 33 | object = callback(object) 34 | for (const key in object) { 35 | const descriptor = Object.getOwnPropertyDescriptor(object, key) 36 | if (descriptor && descriptor.writable) { 37 | object[key] = map(object[key], callback, seen) 38 | } 39 | } 40 | } 41 | 42 | seen.add(object) 43 | if (object && typeof object === 'object') { 44 | return callback(object) 45 | } else { 46 | return object 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/runtime/uuid/v7.cc: -------------------------------------------------------------------------------- 1 | #include "../crypto.hh" 2 | #include "../uuid.hh" 3 | 4 | namespace ssc::runtime::uuid { 5 | void v7 (char* buffer) { 6 | static Atomic seeded = 0; 7 | if (!seeded) { 8 | srand(static_cast(time(nullptr))); 9 | seeded = true; 10 | } 11 | 12 | struct timeval tv; 13 | gettimeofday(&tv, nullptr); 14 | uint64_t delta = ((uint64_t) tv.tv_sec * 1000) + (tv.tv_usec / 1000); 15 | uint64_t timestamp = delta & ((1ull << 60) - 1); 16 | uint64_t value = 0; 17 | 18 | for (int i = 0; i < 8; ++i) { 19 | value = (value << 8) | (crypto::rand64() % 256); 20 | } 21 | value &= ((1ull << 62) - 1); 22 | 23 | uint64_t part1 = (timestamp << 4) | 0x7; 24 | uint64_t part2 = value & ~0xc000000000000000ull; 25 | part2 |= 0x8000000000000000ull; 26 | 27 | 28 | sprintf( 29 | buffer, 30 | "%08x-%04x-%04x-%02x%02x-%012llx", 31 | (uint32_t) (part1 >> 32), 32 | (uint16_t) (part1 >> 16), 33 | (uint16_t) (part1), 34 | (uint8_t) (part2 >> 56), 35 | (uint8_t) (part2 >> 48), 36 | static_cast(part2 & 0x0000ffffffffffffull) 37 | ); 38 | } 39 | 40 | String v7 () { 41 | String output; 42 | output.resize(36); 43 | v7(output.data()); 44 | return output; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/runtime/platform/android/string_wrap.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_ANDROID_STRING_WRAP_H 2 | #define SOCKET_RUNTIME_ANDROID_STRING_WRAP_H 3 | 4 | #include "../types.hh" 5 | #include "native.hh" 6 | 7 | namespace ssc::runtime::android { 8 | using namespace types; 9 | 10 | /** 11 | * A container for a JNI string (jstring). 12 | */ 13 | class StringWrap { 14 | JNIEnv *env = nullptr; 15 | jstring ref = nullptr; 16 | const char *string = nullptr; 17 | size_t length = 0; 18 | jboolean needsRelease = false; 19 | 20 | public: 21 | StringWrap (JNIEnv *env); 22 | StringWrap (const StringWrap& copy); 23 | StringWrap (StringWrap&& copy); 24 | StringWrap (JNIEnv *env, jstring ref); 25 | StringWrap (JNIEnv *env, jobject ref); 26 | StringWrap (JNIEnv *env, String string); 27 | StringWrap (JNIEnv *env, const char *string); 28 | ~StringWrap (); 29 | 30 | void set (String string); 31 | void set (const char *string); 32 | void set (jstring ref); 33 | void release (); 34 | 35 | const String str (); 36 | const jstring j_str (); 37 | const char * c_str (); 38 | const size_t size (); 39 | 40 | const StringWrap& operator= (const StringWrap& string); 41 | StringWrap& operator= (StringWrap&& string); 42 | }; 43 | } 44 | #endif 45 | -------------------------------------------------------------------------------- /api/test/fast-deep-equal.js: -------------------------------------------------------------------------------- 1 | // Copied from fast-deep-equal@3.1.1. 2 | // @ts-nocheck 3 | export default function equal (a, b) { 4 | if (a === b) return true; 5 | 6 | if (a && b && typeof a == 'object' && typeof b == 'object') { 7 | if (a.constructor !== b.constructor) return false; 8 | 9 | var length, i, keys; 10 | if (Array.isArray(a)) { 11 | length = a.length; 12 | if (length != b.length) return false; 13 | for (i = length; i-- !== 0;) 14 | if (!equal(a[i], b[i])) return false; 15 | return true; 16 | } 17 | 18 | 19 | 20 | if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags; 21 | if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf(); 22 | if (a.toString !== Object.prototype.toString) return a.toString() === b.toString(); 23 | 24 | keys = Object.keys(a); 25 | length = keys.length; 26 | if (length !== Object.keys(b).length) return false; 27 | 28 | for (i = length; i-- !== 0;) 29 | if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false; 30 | 31 | for (i = length; i-- !== 0;) { 32 | var key = keys[i]; 33 | 34 | if (!equal(a[key], b[key])) return false; 35 | } 36 | 37 | return true; 38 | } 39 | 40 | // true if both NaN, false otherwise 41 | return a!==a && b!==b; 42 | } 43 | -------------------------------------------------------------------------------- /test/src/extensions/feature-policies.js: -------------------------------------------------------------------------------- 1 | import extension from 'socket:extension' 2 | import test from 'socket:test' 3 | import ipc from 'socket:ipc' 4 | 5 | test('extension.load(name) - feature policies', async (t) => { 6 | let result = null 7 | let simple = null 8 | 9 | try { 10 | simple = await extension.load('simple-ipc-ping') 11 | } catch (err) { 12 | return t.ifError(err) 13 | } 14 | 15 | result = await ipc.request('simple.ping', { value: 'hello world' }) 16 | if (result.err) return t.ifError(result.err) 17 | t.equal(result.data, 'hello world', 'ipc default') 18 | 19 | await simple.unload() 20 | 21 | try { 22 | simple = await extension.load('simple-ipc-ping', { allow: ['none'] }) 23 | } catch (err) { 24 | return t.ifError(err) 25 | } 26 | 27 | result = await ipc.request('simple.ping', { value: 'hello world' }) 28 | t.ok(/not found/i.test(result.err?.message), 'ipc disabled') 29 | 30 | await simple.unload() 31 | 32 | try { 33 | simple = await extension.load('simple-ipc-ping', { allow: ['context', 'ipc'] }) 34 | } catch (err) { 35 | return t.ifError(err) 36 | } 37 | 38 | result = await ipc.request('simple.ping', { value: 'hello world' }) 39 | if (result.err) return t.ifError(result.err) 40 | t.equal(result.data, 'hello world', 'ipc enabled') 41 | 42 | await simple.unload() 43 | }) 44 | -------------------------------------------------------------------------------- /bin/ci_version_check.ps1: -------------------------------------------------------------------------------- 1 | $BIN_PATH = "$env:LOCALAPPDATA\Programs\socketsupply\bin" 2 | 3 | if ($env:Path -notlike "*$BIN_PATH*") { 4 | $new_path = "$BIN_PATH;$env:Path" 5 | $env:Path = $new_path 6 | } 7 | 8 | $VERSION_SSC = $(ssc -v 2>&1 | Select-Object -First 1) | % ToString 9 | $VERSION_TXT = $(type VERSION.txt) 2>&1 | % ToString 10 | $VERSION_GIT = $(git rev-parse --short=8 HEAD) 2>&1 | % ToString 11 | $VERSION_EXPECTED = "$VERSION_TXT ($VERSION_GIT)" 12 | 13 | if ($VERSION_SSC -eq $VERSION_EXPECTED) { 14 | Write-Output "Version check has passed" 15 | } else { 16 | Write-Output "Version check has failed" 17 | Write-Output "Expected: $VERSION_EXPECTED" 18 | Write-Output "Got: $VERSION_SSC" 19 | Exit 1 20 | } 21 | 22 | $BASE_LIST = $VERSION_TXT -split '\.' 23 | 24 | $V_MAJOR = $BASE_LIST[0] 25 | $V_MINOR = $BASE_LIST[1] 26 | 27 | $VERSION_NODE = npm show ./npm/packages/@socketsupply/socket-node version 28 | 29 | $BASE_LIST = $VERSION_NODE -split '\.' 30 | 31 | $V_MAJOR_NODE = $BASE_LIST[0] 32 | $V_MINOR_NODE = $BASE_LIST[1] 33 | 34 | if (($V_MAJOR -ne $V_MAJOR_NODE) -or ($V_MINOR -ne $V_MINOR_NODE)) { 35 | Write-Output "Version of @socketsupply/socket-node is not in sync with @socketsupply/socket" 36 | Write-Output "@socketsupply/socket version is $VERSION_TXT" 37 | Write-Output "@socketsupply/socket-node version is $VERSION_NODE" 38 | exit 1 39 | } 40 | -------------------------------------------------------------------------------- /include/socket/webassembly/float.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_FLOAT_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_FLOAT_H 3 | 4 | #if !defined(_FLOAT_H) 5 | #define _FLOAT_H 6 | #endif 7 | 8 | #if defined(__cplusplus) 9 | extern "C" { 10 | #endif 11 | 12 | #define FLT_ROUNDS (__builtin_flt_rounds()) 13 | 14 | #define FLT_RADIX 2 15 | 16 | #define FLT_TRUE_MIN 1.40129846432481707092e-45F 17 | #define FLT_MIN 1.17549435082228750797e-38F 18 | #define FLT_MAX 3.40282346638528859812e+38F 19 | #define FLT_EPSILON 1.1920928955078125e-07F 20 | 21 | #define FLT_MANT_DIG 24 22 | #define FLT_MIN_EXP (-125) 23 | #define FLT_MAX_EXP 128 24 | #define FLT_HAS_SUBNORM 1 25 | 26 | #define FLT_DIG 6 27 | #define FLT_DECIMAL_DIG 9 28 | #define FLT_MIN_10_EXP (-37) 29 | #define FLT_MAX_10_EXP 38 30 | 31 | #define DBL_TRUE_MIN 4.94065645841246544177e-324 32 | #define DBL_MIN 2.22507385850720138309e-308 33 | #define DBL_MAX 1.79769313486231570815e+308 34 | #define DBL_EPSILON 2.22044604925031308085e-16 35 | 36 | #define DBL_MANT_DIG 53 37 | #define DBL_MIN_EXP (-1021) 38 | #define DBL_MAX_EXP 1024 39 | #define DBL_HAS_SUBNORM 1 40 | 41 | #define DBL_DIG 15 42 | #define DBL_DECIMAL_DIG 17 43 | #define DBL_MIN_10_EXP (-307) 44 | #define DBL_MAX_10_EXP 308 45 | 46 | #define LDBL_HAS_SUBNORM 1 47 | #define LDBL_DECIMAL_DIG DECIMAL_DIG 48 | 49 | #if defined(__cplusplus) 50 | } 51 | #endif 52 | #endif 53 | -------------------------------------------------------------------------------- /test/src/language.js: -------------------------------------------------------------------------------- 1 | import language from 'socket:language' 2 | import test from 'socket:test' 3 | 4 | test('language.lookup(query[, options])', (t) => { 5 | const pass = { 6 | names: true, 7 | codes: true 8 | } 9 | 10 | for (const name of language.names) { 11 | const results = language.lookup(name, { strict: true }) 12 | pass.names = pass.names && ( 13 | results.length && 14 | results[0]?.name && 15 | results[0]?.code && 16 | results[0]?.tags.length 17 | ) 18 | } 19 | 20 | for (const code of language.codes) { 21 | const results = language.lookup(code, { strict: true }) 22 | pass.codes = pass.codes && ( 23 | results.length === 1 && 24 | results[0].code === code && 25 | results[0].name && 26 | results[0].tags.length 27 | ) 28 | } 29 | 30 | t.ok(pass.names, 'lookup by name') 31 | t.ok(pass.codes, 'lookup by code') 32 | }) 33 | 34 | test('language.describe(tag[, options])', (t) => { 35 | let pass = true 36 | for (const tag of language.tags) { 37 | const results = language.describe(tag, { strict: true }) 38 | if (results.length) { 39 | pass = pass && ( 40 | results.length && 41 | results[0]?.tag === tag && 42 | results[0]?.code && 43 | results[0]?.description 44 | ) 45 | } 46 | } 47 | 48 | t.ok(pass, 'language descriptions') 49 | }) 50 | -------------------------------------------------------------------------------- /test/smoke.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | PLATFORM=`uname -s` 3 | 4 | declare root="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)" 5 | source "$root/bin/functions.sh" 6 | 7 | echo "TAP version 13" 8 | echo "1..N" 9 | 10 | TEST=true ./bin/install.sh ios 11 | die $? "the cli tool was built" 12 | 13 | mkdir -p test/tmp 14 | cd test/tmp 15 | 16 | echo # the init command creates dirs and ouputs files 17 | 18 | quiet ../../bin/cli init 19 | 20 | quiet stat src/index.html 21 | die $? "the index.html file exists" 22 | 23 | quiet stat socket.ini 24 | die $? "the config file exists" 25 | 26 | quiet ../../bin/cli compile . 27 | die $? "the compile command executed" 28 | 29 | # 30 | # MacOS 31 | # 32 | if [ "$PLATFORM" == "Darwin" ]; then 33 | quiet stat build/beepboop-dev.app/Contents/MacOS/boop-dev 34 | die $? "the compile command created a binary in the correct location" 35 | 36 | pathToApp=$PWD/build/beepboop-dev.app 37 | 38 | osascript < 3 | 4 | static void onhello ( 5 | sapi_context_t* context, 6 | sapi_ipc_message_t* message, 7 | const sapi_ipc_router_t* router 8 | ) { 9 | auto result = sapi_ipc_result_create(context, message); 10 | auto object = sapi_json_object_create(context); 11 | auto string = sapi_json_string_create(context, "world"); 12 | sapi_json_object_set(object, "hello", string); 13 | sapi_ipc_result_set_json_data(result, sapi_json_any(object)); 14 | sapi_ipc_result_set_header(result, "header-name", "header value"); 15 | sapi_ipc_reply(result); 16 | } 17 | 18 | void initialize_sapi_tests (sapi_context_t* context) { 19 | auto object = sapi_json_object_create(context); 20 | auto string = sapi_json_string_create(context, "world"); 21 | 22 | test(context != NULL); 23 | test(object != NULL); 24 | test(string != NULL); 25 | 26 | sapi_json_object_set(object, "hello", string); 27 | 28 | test(strcmp("{\"hello\":\"world\"}", sapi_json_stringify(object)) == 0); 29 | test(sapi_json_typeof(sapi_json_any(object)) == SAPI_JSON_TYPE_OBJECT); 30 | test(sapi_json_typeof(sapi_json_any(string)) == SAPI_JSON_TYPE_STRING); 31 | 32 | sapi_context_config_set(context, "foo", "bar"); 33 | test(strcmp("bar", sapi_context_config_get(context, "foo")) == 0); 34 | 35 | sapi_ipc_router_map(context, "wasm.hello", onhello, NULL); 36 | } 37 | -------------------------------------------------------------------------------- /api/shared-worker/state.js: -------------------------------------------------------------------------------- 1 | const descriptors = { 2 | channel: { 3 | configurable: false, 4 | enumerable: false, 5 | value: null 6 | }, 7 | 8 | sharedWorker: { 9 | configurable: false, 10 | enumerable: true, 11 | value: Object.create(null, { 12 | scriptURL: { 13 | configurable: false, 14 | enumerable: false, 15 | writable: true, 16 | value: null 17 | }, 18 | 19 | state: { 20 | configurable: false, 21 | enumerable: true, 22 | writable: true, 23 | value: 'parsed' 24 | }, 25 | 26 | id: { 27 | configurable: false, 28 | enumerable: true, 29 | writable: true, 30 | value: null 31 | } 32 | }) 33 | }, 34 | 35 | id: { 36 | configurable: false, 37 | enumerable: false, 38 | writable: true, 39 | value: null 40 | }, 41 | 42 | connect: { 43 | configurable: false, 44 | enumerable: false, 45 | writable: true, 46 | value: null 47 | }, 48 | 49 | env: { 50 | configurable: false, 51 | enumerable: false, 52 | writable: true, 53 | value: null 54 | }, 55 | 56 | reportError: { 57 | configurable: false, 58 | enumerable: false, 59 | writable: true, 60 | value: globalThis.reportError.bind(globalThis) 61 | } 62 | } 63 | 64 | export const state = Object.create(null, descriptors) 65 | 66 | export default state 67 | -------------------------------------------------------------------------------- /src/runtime/json/number.cc: -------------------------------------------------------------------------------- 1 | #include "../json.hh" 2 | #include "../debug.hh" 3 | 4 | namespace ssc::runtime::JSON { 5 | Type Number::valueType = Type::Number; 6 | 7 | Number::Number (const String& string) { 8 | this->data = std::stod(string.data); 9 | } 10 | 11 | Number::Number (const Number& number) { 12 | this->data = number.value(); 13 | } 14 | 15 | Number::Number (double number) { 16 | this->data = number; 17 | } 18 | 19 | Number::Number (char number) { 20 | this->data = (double) number; 21 | } 22 | 23 | Number::Number (int number) { 24 | this->data = (double) number; 25 | } 26 | 27 | Number::Number (int64_t number) { 28 | this->data = (double) number; 29 | } 30 | 31 | Number::Number (bool number) { 32 | this->data = (double) number; 33 | } 34 | 35 | const double Number::value () const { 36 | return this->data; 37 | } 38 | 39 | const runtime::String Number::str () const { 40 | if (this->data == 0) { 41 | return "0"; 42 | } 43 | 44 | auto value = this->data; 45 | auto output = std::to_string(value); 46 | auto decimal = output.find("."); 47 | 48 | // trim trailing zeros 49 | if (decimal >= 0) { 50 | auto i = output.size() - 1; 51 | while (output[i] == '0' && i >= decimal) { 52 | i--; 53 | } 54 | 55 | return output.substr(0, i); 56 | } 57 | 58 | return output; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/runtime/json/string.cc: -------------------------------------------------------------------------------- 1 | #include "../string.hh" 2 | 3 | #include "../json.hh" 4 | 5 | using ssc::runtime::string::replace; 6 | 7 | namespace ssc::runtime::JSON { 8 | Type String::valueType = Type::String; 9 | 10 | String::String (const Number& number) { 11 | this->data = number.str(); 12 | } 13 | 14 | String::String (const String& data) { 15 | this->data = runtime::String(data.value()); 16 | } 17 | 18 | String::String (const runtime::String& data) { 19 | this->data = data; 20 | } 21 | 22 | String::String (const char data) { 23 | this->data = runtime::String(1, data); 24 | } 25 | 26 | String::String (const char *data) { 27 | this->data = runtime::String(data); 28 | } 29 | 30 | String::String (const Any& any) { 31 | this->data = any.str(); 32 | } 33 | 34 | String::String (const Boolean& boolean) { 35 | this->data = boolean.str(); 36 | } 37 | 38 | String::String (const Error& error) { 39 | this->data = error.str(); 40 | } 41 | 42 | const runtime::String String::str () const { 43 | auto escaped = replace(this->data, "\"", "\\\""); 44 | escaped = replace(escaped, "\\n", "\\\\n"); 45 | return "\"" + replace(escaped, "\n", "\\n") + "\""; 46 | } 47 | 48 | const runtime::String String::value () const { 49 | return this->data; 50 | } 51 | 52 | runtime::String::size_type String::size () const { 53 | return this->data.size(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /api/test/context.js: -------------------------------------------------------------------------------- 1 | import console from '../console.js' 2 | import process from '../process.js' 3 | 4 | import '../application.js' 5 | 6 | let finishing = false 7 | let isInitialized = false 8 | 9 | export default function (GLOBAL_TEST_RUNNER) { 10 | if (isInitialized) return 11 | 12 | if (typeof globalThis?.addEventListener === 'function') { 13 | globalThis.addEventListener('error', onerror) 14 | globalThis.addEventListener('messageerror', onerror) 15 | globalThis.addEventListener('unhandledrejection', onerror) 16 | } 17 | 18 | GLOBAL_TEST_RUNNER.onFinish(({ fail }) => { 19 | if (!finishing) { 20 | finishing = true 21 | if (!process.env.DEBUG) { 22 | setTimeout(() => { 23 | process.exit(fail > 0 ? 1 : 0) 24 | }, 1024) // give app time to print TAP output 25 | } 26 | } 27 | }) 28 | 29 | isInitialized = true 30 | 31 | function onerror (e) { 32 | const err = e.error || e.stack || e.reason || e.message || e 33 | if (err.ignore || err[Symbol.for('socket.runtime.test.error.ignore')]) return 34 | if (globalThis.RUNTIME_TEST_FILENAME || GLOBAL_TEST_RUNNER.length > 0) { 35 | console.error(err) 36 | } 37 | 38 | if (finishing || process.env.DEBUG) { 39 | return 40 | } 41 | 42 | if (globalThis.RUNTIME_TEST_FILENAME || GLOBAL_TEST_RUNNER.length > 0) { 43 | process.nextTick(() => { 44 | process.exit(1) 45 | }) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /include/socket/webassembly/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_STDIO_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_STDIO_H 3 | 4 | #if !defined(_STDIO_H) 5 | #define _STDIO_H 6 | #endif 7 | 8 | #include "string.h" 9 | #include "stdint.h" 10 | #include "unistd.h" 11 | 12 | #if defined(BUFSIZ) 13 | #undef BUFSIZ 14 | #endif 15 | 16 | #define BUFSIZ 4096 17 | 18 | #if defined(__cplusplus) 19 | extern "C" { 20 | #endif 21 | 22 | struct _FILE { void* _internal; }; 23 | typedef struct _FILE FILE; 24 | 25 | static FILE* stdin = (FILE*) STDIN_FILENO; 26 | static FILE* stdout = (FILE*) STDOUT_FILENO; 27 | static FILE* stderr = (FILE*) STDERR_FILENO; 28 | 29 | extern "C" int printf (const char* __restrict format, ...); 30 | extern "C" int fprintf (FILE* __restrict stream, const char* __restrict format, ...); 31 | extern "C" int sprintf (char* __restrict str, const char* __restrict format, ...); 32 | extern "C" int snprintf (char* __restrict str, size_t size, const char* __restrict format, ...); 33 | extern "C" int puts (const char *s); 34 | extern "C" int putc (int c, FILE* stream); 35 | extern "C" int putchar (int c); 36 | 37 | extern "C" int fputc (int c, FILE* __restrict stream); 38 | extern "C" int fputs (const char* __restrict s, FILE*__restrict stream); 39 | extern "C" size_t fwrite( 40 | const void *__restrict ptr, 41 | size_t size, 42 | size_t nitems, 43 | FILE *__restrict stream 44 | ); 45 | 46 | #if defined(__cplusplus) 47 | } 48 | #endif 49 | #endif 50 | -------------------------------------------------------------------------------- /npm/packages/@socketsupply/socket/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@socketsupply/socket", 3 | "version": "0.6.0-rc.8", 4 | "description": "A Cross-Platform, Native Runtime for Desktop and Mobile Apps — Create apps using HTML, CSS, and JavaScript. Written from the ground up to be small and maintainable.", 5 | "type": "module", 6 | "main": "./index.js", 7 | "types": "./index.d.ts", 8 | "bin": { 9 | "ssc": "./bin/ssc.js" 10 | }, 11 | "os": [ 12 | "linux", 13 | "darwin", 14 | "win32" 15 | ], 16 | "cpu": [ 17 | "arm64", 18 | "x64" 19 | ], 20 | "scripts": { 21 | "test": ":" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+ssh://git@github.com/socketsupply/socket.git" 26 | }, 27 | "keywords": [ 28 | "socket", 29 | "runtime", 30 | "webview", 31 | "javascript", 32 | "desktop", 33 | "mobile" 34 | ], 35 | "author": "Socket Supply, Co ", 36 | "license": "Apache-2.0", 37 | "bugs": { 38 | "url": "https://github.com/socketsupply/socket/issues" 39 | }, 40 | "homepage": "https://github.com/socketsupply/socket#readme", 41 | "optionalDependencies": { 42 | "@socketsupply/socket-darwin-arm64": "0.6.0-rc.8", 43 | "@socketsupply/socket-darwin-x64": "0.6.0-rc.8", 44 | "@socketsupply/socket-linux-arm64": "0.6.0-rc.8", 45 | "@socketsupply/socket-linux-x64": "0.6.0-rc.8", 46 | "@socketsupply/socket-win32-x64": "0.6.0-rc.8" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /api/stream/web.js: -------------------------------------------------------------------------------- 1 | import { 2 | ReadableStream, 3 | ReadableStreamBYOBReader, 4 | ReadableByteStreamController, 5 | ReadableStreamBYOBRequest, 6 | ReadableStreamDefaultController, 7 | ReadableStreamDefaultReader, 8 | 9 | WritableStream, 10 | WritableStreamDefaultController, 11 | WritableStreamDefaultWriter, 12 | 13 | TransformStream, 14 | TransformStreamDefaultController, 15 | 16 | ByteLengthQueuingStrategy, 17 | CountQueuingStrategy 18 | } from '../internal/streams.js' 19 | 20 | import * as exports from './web.js' 21 | 22 | class UnsupportedStreamInterface {} 23 | 24 | export { 25 | ReadableStream, 26 | ReadableStreamBYOBReader, 27 | ReadableByteStreamController, 28 | ReadableStreamBYOBRequest, 29 | ReadableStreamDefaultController, 30 | ReadableStreamDefaultReader, 31 | 32 | WritableStream, 33 | WritableStreamDefaultController, 34 | WritableStreamDefaultWriter, 35 | 36 | TransformStream, 37 | TransformStreamDefaultController, 38 | 39 | ByteLengthQueuingStrategy, 40 | CountQueuingStrategy 41 | } 42 | 43 | export const TextEncoderStream = globalThis.TextEncoderStream ?? UnsupportedStreamInterface 44 | export const TextDecoderStream = globalThis.TextDecoderStream ?? UnsupportedStreamInterface 45 | export const CompressionStream = globalThis.CompressionStream ?? UnsupportedStreamInterface 46 | export const DecompressionStream = globalThis.DecompressionStream ?? UnsupportedStreamInterface 47 | 48 | export default exports 49 | -------------------------------------------------------------------------------- /include/socket/webassembly/regex.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_REGEX_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_REGEX_H 3 | 4 | #if !defined(_REGEX_H) 5 | #define _REGEX_H 6 | #endif 7 | 8 | #include "stddef.h" 9 | 10 | #if defined(__cplusplus) 11 | extern "C" { 12 | #endif 13 | 14 | #define REG_EXTENDED 0x1 15 | #define REG_ICASE 0x2 16 | #define REG_NOSUB 0x4 17 | #define REG_NEWLINE 0x8 18 | 19 | #define REG_NOMATCH 1 20 | #define REG_BADPAT 2 21 | #define REG_ECOLLATE 3 22 | #define REG_ECTYPE 4 23 | #define REG_EESCAPE 5 24 | #define REG_ESUBREG 6 25 | #define REG_EBRACK 7 26 | #define REG_EPAREN 8 27 | #define REG_EBRACE 9 28 | #define REG_BADBR 10 29 | #define REG_ERANGE 11 30 | #define REG_ESPACE 12 31 | #define REG_BADRPT 13 32 | #define REG_ENOSYS 14 33 | 34 | #define REG_NOTBOL 0x1 35 | #define REG_NOTEOL 0x2 36 | 37 | typedef long regoff_t; 38 | 39 | typedef struct { 40 | size_t re_nsub; 41 | void* re_pcre; 42 | } regex_t; 43 | 44 | typedef struct { 45 | regoff_t rm_so; 46 | regoff_t rm_eo; 47 | } regmatch_t; 48 | 49 | extern int regcomp (regex_t* regex, const char* pattern, int flags); 50 | extern size_t regerror ( 51 | int error, 52 | const regex_t* regex, 53 | char* buf, 54 | size_t buf_cnt 55 | ); 56 | 57 | extern int regexec ( 58 | const regex_t* regex, 59 | const char* string, 60 | size_t match_cnt, 61 | regmatch_t match[], 62 | int flags 63 | ); 64 | 65 | extern void regfree (regex_t* regex); 66 | 67 | #if defined(__cplusplus) 68 | } 69 | #endif 70 | #endif 71 | -------------------------------------------------------------------------------- /src/runtime/http/response.cc: -------------------------------------------------------------------------------- 1 | #include "../http.hh" 2 | 3 | namespace ssc::runtime::http { 4 | Response::Response (const String& input) 5 | : body(input) 6 | { 7 | this->setHeader("content-length", this->body.size()); 8 | } 9 | 10 | Response::Response (const Status& status, const String& input) 11 | : status(status), 12 | body(input) 13 | {} 14 | 15 | Response::Response (const Status& status, const JSON::Any& json) 16 | : status(status), 17 | body(json.str()) 18 | { 19 | this->setHeader("content-type", "application/json"); 20 | } 21 | 22 | Response::Response (const Headers& headers) 23 | : headers(headers) 24 | {} 25 | 26 | Response::Response (const Status& status) 27 | : status(status) 28 | {} 29 | 30 | Response::Response (const Status& status, const Headers& headers) 31 | : headers(headers), 32 | status(status) 33 | {} 34 | 35 | Response& Response::setHeader (const Headers::Header& header) { 36 | this->headers.set(header); 37 | return *this; 38 | } 39 | 40 | Response& Response::setHeader (const String& key, const Headers::Value& value) { 41 | this->headers.set(key, value); 42 | return *this; 43 | } 44 | 45 | const unsigned char* Response::data () const { 46 | return this->body.data(); 47 | } 48 | 49 | size_t Response::size () const { 50 | return this->body.size(); 51 | } 52 | 53 | String Response::str () const { 54 | return "HTTP/" + this->version + " " + this->status.str() + "\r\n" + this->headers.str(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/runtime/platform/android.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_PLATFORM_ANDROID_H 2 | #define SOCKET_RUNTIME_PLATFORM_ANDROID_H 3 | 4 | #include "android/content_resolver.hh" 5 | #include "android/environment.hh" 6 | #include "android/looper.hh" 7 | #include "android/mime.hh" 8 | #include "android/string_wrap.hh" 9 | #include "android/types.hh" 10 | 11 | /** 12 | * A macro to help define an Android external package class method 13 | * implementation as a JNI binding. 14 | */ 15 | #define ANDROID_EXTERNAL(packageName, className, methodName) \ 16 | JNIEXPORT JNICALL \ 17 | Java_socket_runtime_##packageName##_##className##_##methodName 18 | 19 | /** 20 | * Throw an exception with formatted message in the Android environment. 21 | * @param {JNIEnv*} env 22 | * @param {const char*} message 23 | * @param {...} 24 | */ 25 | #define ANDROID_THROW(env, message, ...) ({ \ 26 | char buffer[BUFSIZ] = {0}; \ 27 | sprintf(buffer, message, ##__VA_ARGS__); \ 28 | env->ThrowNew( \ 29 | GetExceptionClassFromAndroidEnvironment(env), \ 30 | buffer \ 31 | ); \ 32 | (void) 0; \ 33 | }) 34 | #endif 35 | -------------------------------------------------------------------------------- /test/scripts/test-ios-simulator.js: -------------------------------------------------------------------------------- 1 | import { rmSync as rm, cpSync as cp } from 'node:fs' 2 | import { execSync, spawn } from 'node:child_process' 3 | import path from 'node:path' 4 | 5 | const dirname = path.dirname(import.meta.url.replace('file://', '').replace(/^\/[A-Za-z]:/, '')) 6 | const root = path.dirname(dirname) 7 | const child = spawn('ssc', ['build', '--headless', '--test=./index.js', '--platform=ios-simulator', '-r', '-o', '--env', 'SOCKET_DEBUG_IPC'], { 8 | stdio: 'inherit' 9 | }) 10 | 11 | let retries = 1000 12 | 13 | const interval = setInterval(() => { 14 | let container = null 15 | if (child.exitCode !== null || child.killed) { 16 | console.warn('iOS Simulator exited before determining the container data directory') 17 | clearInterval(interval) 18 | return 19 | } 20 | 21 | try { 22 | container = execSync('xcrun simctl get_app_container booted co.socketsupply.socket.tests data') 23 | if (container) { 24 | container = container.toString().trim() 25 | } 26 | } catch (err) { 27 | if (--retries === 0) { 28 | clearInterval(interval) 29 | throw err 30 | } 31 | } 32 | 33 | if (!container) { 34 | return // continue 35 | } 36 | 37 | const TMPDIR = path.join(container, 'tmp') 38 | 39 | try { 40 | rm(path.join(TMPDIR, 'ssc-socket-test-fixtures'), { 41 | recursive: true, 42 | force: true 43 | }) 44 | } catch {} 45 | 46 | cp(path.join(root, 'fixtures'), path.join(TMPDIR, 'ssc-socket-test-fixtures'), { 47 | recursive: true 48 | }) 49 | 50 | clearInterval(interval) 51 | }, 200) 52 | -------------------------------------------------------------------------------- /api/path.js: -------------------------------------------------------------------------------- 1 | import { primordials } from './ipc.js' 2 | import { 3 | mounts, 4 | Path, 5 | posix, 6 | win32, 7 | 8 | // well known 9 | DOWNLOADS, 10 | DOCUMENTS, 11 | RESOURCES, 12 | PICTURES, 13 | DESKTOP, 14 | VIDEOS, 15 | CONFIG, 16 | MEDIA, 17 | MUSIC, 18 | HOME, 19 | DATA, 20 | LOG, 21 | TMP 22 | } from './path/index.js' 23 | 24 | const isWin32 = primordials.platform === 'win32' 25 | 26 | export const sep = isWin32 ? win32.sep : posix.sep 27 | export const delimiter = isWin32 ? win32.delimiter : posix.delimiter 28 | 29 | export const resolve = isWin32 ? win32.resolve : posix.resolve 30 | export const join = isWin32 ? win32.join : posix.join 31 | export const dirname = isWin32 ? win32.dirname : posix.dirname 32 | export const basename = isWin32 ? win32.basename : posix.basename 33 | export const extname = isWin32 ? win32.extname : posix.extname 34 | export const cwd = isWin32 ? win32.cwd : posix.cwd 35 | export const isAbsolute = isWin32 ? win32.isAbsolute : posix.isAbsolute 36 | export const parse = isWin32 ? win32.parse : posix.parse 37 | export const format = isWin32 ? win32.format : posix.format 38 | export const normalize = isWin32 ? win32.normalize : posix.normalize 39 | export const relative = isWin32 ? win32.relative : posix.relative 40 | 41 | export { 42 | Path, 43 | posix, 44 | win32, 45 | mounts, 46 | 47 | DOWNLOADS, 48 | DOCUMENTS, 49 | RESOURCES, 50 | PICTURES, 51 | DESKTOP, 52 | VIDEOS, 53 | CONFIG, 54 | MEDIA, 55 | MUSIC, 56 | HOME, 57 | DATA, 58 | LOG, 59 | TMP 60 | } 61 | 62 | export default isWin32 ? win32 : posix 63 | -------------------------------------------------------------------------------- /test/src/webassembly.js: -------------------------------------------------------------------------------- 1 | import { test } from 'socket:test' 2 | import fs from 'socket:fs' 3 | import { createFile } from 'socket:fs/web' 4 | 5 | const importObject = { 6 | env: { 7 | myFunc: arg => arg * arg 8 | } 9 | } 10 | 11 | test('instantiate wasm synchronously after load with FS module', async (t) => { 12 | const wasm = await fs.promises.readFile('./webassembly/program.wasm') 13 | const module = new WebAssembly.Module(wasm) 14 | const { exports } = new WebAssembly.Instance(module, importObject) 15 | t.equal(exports.runMyFunc(5), 25, 'imported function works') 16 | t.equal(exports.identity(42), 42, 'exported function works') 17 | }) 18 | 19 | test('instantiate wasm asynchronously after from with FS module', async (t) => { 20 | const file = await createFile('./webassembly/program.wasm') 21 | const stream = file.stream() 22 | const response = new Response(stream, { 23 | headers: { 24 | 'Content-Type': 'application/wasm' 25 | } 26 | }) 27 | const { instance } = await WebAssembly.instantiateStreaming(response, importObject) 28 | t.equal(instance.exports.runMyFunc(5), 25, 'imported function works') 29 | t.equal(instance.exports.identity(42), 42, 'exported function works') 30 | }) 31 | 32 | test('instantiate wasm asynchronously after load with fetch', async (t) => { 33 | const response = fetch('./webassembly/program.wasm') 34 | const { instance } = await WebAssembly.instantiateStreaming(response, importObject) 35 | t.equal(instance.exports.runMyFunc(5), 25, 'imported function works') 36 | t.equal(instance.exports.identity(42), 42, 'exported function works') 37 | }) 38 | -------------------------------------------------------------------------------- /api/async/wrap.js: -------------------------------------------------------------------------------- 1 | import { Snapshot } from './context.js' 2 | 3 | export const symbol = Symbol.for('socket.runtime.async') 4 | 5 | /** 6 | * Returns `true` if a given function `fn` has the "async" wrapped tag, 7 | * meaning it was "tagged" in a `wrap(fn)` call before, otherwise this 8 | * function will return `false`. 9 | * @ignore 10 | * @param {function} fn 11 | * @param {boolean} 12 | */ 13 | export function isTagged (fn) { 14 | if (typeof fn === 'function' && fn[symbol] === true) { 15 | return true 16 | } 17 | 18 | return false 19 | } 20 | 21 | /** 22 | * Tags a function `fn` as being "async wrapped" so subsequent calls to 23 | * `wrap(fn)` do not wrap an already wrapped function. 24 | * @ignore 25 | * @param {function} fn 26 | * @return {function} 27 | */ 28 | export function tag (fn) { 29 | if (typeof fn !== 'function') { 30 | return fn 31 | } 32 | 33 | if (fn[symbol] === true) { 34 | return fn 35 | } 36 | 37 | Object.defineProperty(fn, symbol, { 38 | configurable: false, 39 | enumerable: false, 40 | writable: false, 41 | value: true 42 | }) 43 | 44 | return fn 45 | } 46 | 47 | /** 48 | * Wraps a function `fn` that captures a snapshot of the current async 49 | * context. This function is idempotent and will not wrap a function more 50 | * than once. 51 | * @ignore 52 | * @param {function} fn 53 | * @return {function} 54 | */ 55 | export function wrap (fn) { 56 | if (typeof fn === 'function') { 57 | if (isTagged(fn)) { 58 | return fn 59 | } 60 | 61 | return tag(Snapshot.wrap(fn)) 62 | } 63 | 64 | return fn 65 | } 66 | 67 | export default wrap 68 | -------------------------------------------------------------------------------- /api/mime/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "3mf": "model/3mf", 3 | "e57": "model/e57", 4 | "example": "model/example", 5 | "gltf-binary": "model/gltf-binary", 6 | "gltf+json": "model/gltf+json", 7 | "JT": "model/JT", 8 | "iges": "model/iges", 9 | "mesh": "model/mesh", 10 | "mtl": "model/mtl", 11 | "obj": "model/obj", 12 | "prc": "model/prc", 13 | "step": "model/step", 14 | "step+xml": "model/step+xml", 15 | "step+zip": "model/step+zip", 16 | "step-xml+zip": "model/step-xml+zip", 17 | "stl": "model/stl", 18 | "u3d": "model/u3d", 19 | "vnd.bary": "model/vnd.bary", 20 | "vnd.cld": "model/vnd.cld", 21 | "vnd.collada+xml": "model/vnd.collada+xml", 22 | "vnd.dwf": "model/vnd.dwf", 23 | "vnd.flatland.3dml": "model/vnd.flatland.3dml", 24 | "vnd.gdl": "model/vnd.gdl", 25 | "vnd.gs-gdl": "model/vnd.gs-gdl", 26 | "vnd.gtw": "model/vnd.gtw", 27 | "vnd.moml+xml": "model/vnd.moml+xml", 28 | "vnd.mts": "model/vnd.mts", 29 | "vnd.opengex": "model/vnd.opengex", 30 | "vnd.parasolid.transmit.binary": "model/vnd.parasolid.transmit.binary", 31 | "vnd.parasolid.transmit.text": "model/vnd.parasolid.transmit.text", 32 | "vnd.pytha.pyox": "model/vnd.pytha.pyox", 33 | "vnd.rosette.annotated-data-model": "model/vnd.rosette.annotated-data-model", 34 | "vnd.sap.vds": "model/vnd.sap.vds", 35 | "vnd.usda": "model/vnd.usda", 36 | "vnd.usdz+zip": "model/vnd.usdz+zip", 37 | "vnd.valve.source.compiled-map": "model/vnd.valve.source.compiled-map", 38 | "vnd.vtu": "model/vnd.vtu", 39 | "vrml": "model/vrml", 40 | "x3d-vrml": "model/x3d-vrml", 41 | "x3d+fastinfoset": "model/x3d+fastinfoset", 42 | "x3d+xml": "model/x3d+xml" 43 | } 44 | -------------------------------------------------------------------------------- /src/runtime/core/services/timers.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CORE_SERVICES_TIMERS_H 2 | #define SOCKET_RUNTIME_CORE_SERVICES_TIMERS_H 3 | 4 | #include "../../core.hh" 5 | 6 | namespace ssc::runtime::core::services { 7 | class Timers : public core::Service { 8 | public: 9 | using ID = uint64_t; 10 | using CancelCallback = Function; 11 | using Callback = Function; 12 | using TimeoutCallback = Function; 13 | using IntervalCallback = Callback; 14 | using ImmediateCallback = TimeoutCallback; 15 | 16 | struct Timer { 17 | enum class Type { Timeout, Interval, Immediate }; 18 | 19 | Timers* timers = nullptr; 20 | ID id = 0; 21 | Callback callback = nullptr; 22 | bool repeat = false; 23 | bool cancelled = false; 24 | uv_timer_t timer; 25 | Type type; 26 | Timer (Timers* timers, ID id, Callback callback); 27 | }; 28 | 29 | using Handles = Map>; 30 | 31 | Handles handles; 32 | Mutex mutex; 33 | 34 | Timers (const Options& options) 35 | : core::Service(options) 36 | {} 37 | 38 | const ID setTimeout (uint64_t, const TimeoutCallback); 39 | const ID setInterval (uint64_t, const IntervalCallback); 40 | const ID setImmediate (const ImmediateCallback); 41 | 42 | bool cancelTimer (const ID id); 43 | bool clearTimeout (const ID id); 44 | bool clearInterval (const ID id); 45 | bool clearImmediate (const ID id); 46 | const ID createTimer (uint64_t, uint64_t, const Callback); 47 | }; 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /src/runtime/crypto.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CRYPTO_H 2 | #define SOCKET_RUNTIME_CRYPTO_H 3 | 4 | #include "platform.hh" 5 | 6 | #define SHA1_DIGEST_SIZE 20 7 | 8 | namespace ssc::runtime::crypto { 9 | uint64_t rand64 (); 10 | int randint (int a, int b); 11 | int randint (int a); 12 | int randint (); 13 | 14 | struct SHA1Context { 15 | uint32_t state[5]; 16 | uint64_t bitCount; 17 | unsigned char buffer[64]; 18 | }; 19 | 20 | void sha1_init (SHA1Context *ctx); 21 | void sha1_update ( 22 | SHA1Context *ctx, 23 | const unsigned char *data, 24 | size_t size 25 | ); 26 | 27 | void sha1_final ( 28 | SHA1Context *ctx, 29 | unsigned char out[SHA1_DIGEST_SIZE] 30 | ); 31 | 32 | void sha1 ( 33 | const unsigned char *data, 34 | size_t size, 35 | unsigned char out[SHA1_DIGEST_SIZE] 36 | ); 37 | 38 | class SHA1 { 39 | public: 40 | SHA1Context context; 41 | bool isFinalized = false; 42 | unsigned char output[SHA1_DIGEST_SIZE] = {0}; 43 | 44 | SHA1 (); 45 | SHA1 (const String&); 46 | SHA1 (const SharedPointer&, size_t); 47 | SHA1 (const unsigned char *, size_t); 48 | 49 | SHA1& update (const unsigned char *, size_t); 50 | SHA1& update (const String&); 51 | bool finalized () const; 52 | Vector finalize (); 53 | String str (); 54 | inline size_t size () const { 55 | return SHA1_DIGEST_SIZE; 56 | } 57 | }; 58 | 59 | const String sha1 (const String&); 60 | const String sha1 (const SharedPointer&, size_t); 61 | const String sha1 (const unsigned char *, size_t); 62 | } 63 | #endif 64 | -------------------------------------------------------------------------------- /api/fs/flags.js: -------------------------------------------------------------------------------- 1 | import { 2 | O_APPEND, 3 | O_RDONLY, 4 | O_WRONLY, 5 | O_TRUNC, 6 | O_CREAT, 7 | O_RDWR, 8 | O_EXCL, 9 | O_SYNC 10 | } from './constants.js' 11 | 12 | import * as exports from './flags.js' 13 | 14 | export function normalizeFlags (flags) { 15 | if (typeof flags === 'number') { 16 | return flags 17 | } 18 | 19 | if (flags !== undefined && typeof flags !== 'string') { 20 | throw new TypeError( 21 | `Expecting flags to be a string or number: Got ${typeof flags}` 22 | ) 23 | } 24 | 25 | switch (flags) { 26 | case 'r': 27 | return O_RDONLY 28 | 29 | case 'rs': case 'sr': 30 | return O_RDONLY | O_SYNC 31 | 32 | case 'r+': 33 | return O_RDWR 34 | 35 | case 'rs+': case 'sr+': 36 | return O_RDWR | O_SYNC 37 | 38 | case 'w': 39 | return O_TRUNC | O_CREAT | O_WRONLY 40 | 41 | case 'wx': case 'xw': 42 | return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL 43 | 44 | case 'w+': 45 | return O_TRUNC | O_CREAT | O_RDWR 46 | 47 | case 'wx+': case 'xw+': 48 | return O_TRUNC | O_CREAT | O_RDWR | O_EXCL 49 | 50 | case 'a': 51 | return O_APPEND | O_CREAT | O_WRONLY 52 | 53 | case 'ax': case 'xa': 54 | return O_APPEND | O_CREAT | O_WRONLY | O_EXCL 55 | 56 | case 'as': case 'sa': 57 | return O_APPEND | O_CREAT | O_WRONLY | O_SYNC 58 | 59 | case 'a+': 60 | return O_APPEND | O_CREAT | O_RDWR 61 | 62 | case 'ax+': case 'xa+': 63 | return O_APPEND | O_CREAT | O_RDWR | O_EXCL 64 | 65 | case 'as+': case 'sa+': 66 | return O_APPEND | O_CREAT | O_RDWR | O_SYNC 67 | } 68 | 69 | return O_RDONLY 70 | } 71 | 72 | export default exports 73 | -------------------------------------------------------------------------------- /api/mime/type.js: -------------------------------------------------------------------------------- 1 | import { MIMEParams } from './params.js' 2 | 3 | export class MIMEType { 4 | #type = null 5 | #params = null 6 | #subtype = null 7 | 8 | constructor (input) { 9 | input = String(input) 10 | 11 | const args = input.split(';') 12 | const mime = args.shift() 13 | const types = mime.split('/') 14 | 15 | if (types.length !== 2 || !types[0] || !types[1]) { 16 | throw new TypeError(`Invalid MIMEType input given: ${mime}`) 17 | } 18 | 19 | const [type, subtype] = types 20 | 21 | this.#type = type.toLowerCase() 22 | // @ts-ignore 23 | this.#params = new MIMEParams(args.map((a) => a.trim().split('=').map((v) => v.trim()))) 24 | this.#subtype = subtype 25 | } 26 | 27 | get type () { 28 | return this.#type 29 | } 30 | 31 | set type (value) { 32 | if (!value || typeof value !== 'string') { 33 | throw new TypeError('MIMEType type must be a string') 34 | } 35 | 36 | this.#type = value 37 | } 38 | 39 | get subtype () { 40 | return this.#subtype 41 | } 42 | 43 | set subtype (value) { 44 | if (!value || typeof value !== 'string') { 45 | throw new TypeError('MIMEType subtype must be a string') 46 | } 47 | 48 | this.#subtype = value 49 | } 50 | 51 | get essence () { 52 | return `${this.type}/${this.subtype}` 53 | } 54 | 55 | get params () { 56 | return this.#params 57 | } 58 | 59 | toString () { 60 | const params = this.params.toString() 61 | 62 | if (params) { 63 | return `${this.essence};${params}` 64 | } 65 | 66 | return this.essence 67 | } 68 | 69 | toJSON () { 70 | return this.toString() 71 | } 72 | } 73 | 74 | export default MIMEType 75 | -------------------------------------------------------------------------------- /npm/bin/ssc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { fork } from 'node:child_process' 4 | import path from 'node:path' 5 | import os from 'node:os' 6 | 7 | const dirname = path.dirname(import.meta.url).replace(`file://${os.platform() === 'win32' ? '/' : ''}`, '') 8 | 9 | let exiting = false 10 | 11 | export async function load () { 12 | const platform = os.platform() 13 | const arch = os.arch() 14 | const info = await import(`@socketsupply/socket-${platform}-${arch}`) 15 | return info?.default ?? info ?? null 16 | } 17 | 18 | async function main () { 19 | const installation = await load() 20 | const args = process.argv.slice(2) 21 | const env = { 22 | ...installation.env, 23 | SOCKET_HOME_API: path.dirname(dirname), 24 | ...process.env 25 | } 26 | 27 | if (typeof installation.firstTimeExperienceSetup === 'function' && !await installation.firstTimeExperienceSetup()) { 28 | // FTE not completed satisfactorally, or 'setup' was ran externally 29 | return 30 | } 31 | 32 | const child = fork(installation.bin['ssc-platform'], args, { 33 | env, 34 | stdio: 'inherit', 35 | windowsHide: true 36 | }) 37 | 38 | child.once('exit', (code) => { 39 | if (!exiting) { 40 | exiting = true 41 | process.exit(code) 42 | } 43 | }) 44 | 45 | child.once('error', (err) => { 46 | console.error(err.message) 47 | if (!exiting) { 48 | exiting = true 49 | process.exit(1) 50 | } 51 | }) 52 | 53 | process.on('SIGTERM', () => { 54 | child.kill('SIGTERM') 55 | }) 56 | 57 | process.on('exit', () => { 58 | child.kill('SIGTERM') 59 | }) 60 | } 61 | 62 | main().catch((err) => { 63 | console.error(err) 64 | process.exit(1) 65 | }) 66 | -------------------------------------------------------------------------------- /test/src/runtime-core/string.cc: -------------------------------------------------------------------------------- 1 | #include "tests.hh" 2 | 3 | namespace SSC::Tests { 4 | void string (Harness& t) { 5 | t.test("SSC::replace()", [](auto t) { 6 | t.comment("TODO"); 7 | }); 8 | 9 | t.test("SSC::tmpl()", [](auto t) { 10 | t.comment("TODO"); 11 | }); 12 | 13 | t.test("SSC::trim()", [](auto t) { 14 | t.comment("TODO"); 15 | }); 16 | 17 | t.test("SSC::convertStringToWString()", [](auto t) { 18 | t.comment("TODO"); 19 | }); 20 | 21 | t.test("SSC::convertWStringToString()", [](auto t) { 22 | t.comment("TODO"); 23 | }); 24 | 25 | t.test("SSC::split(const String&, const String&)", [](auto t) { 26 | const auto items = split("a && b && c && d && e", " && "); 27 | 28 | t.equals(items[0], "a", "items[0] == a"); 29 | t.equals(items[1], "b", "items[1] == b"); 30 | t.equals(items[2], "c", "items[2] == c"); 31 | t.equals(items[3], "d", "items[3] == d"); 32 | t.equals(items[4], "e", "items[4] == e"); 33 | }); 34 | 35 | t.test("SSC::split(const String&, char)", [](auto t) { 36 | const auto items = split("a|b|c|d|e", '|'); 37 | 38 | t.equals(items[0], "a", "items[0] == a"); 39 | t.equals(items[1], "b", "items[1] == b"); 40 | t.equals(items[2], "c", "items[2] == c"); 41 | t.equals(items[3], "d", "items[3] == d"); 42 | t.equals(items[4], "e", "items[4] == e"); 43 | }); 44 | 45 | t.test("SSC::join()", [](auto t) { 46 | const auto joined = join(split("a|b|c|d|e", '|'), '|'); 47 | t.equals(joined, "a|b|c|d|e", "joins vector"); 48 | }); 49 | 50 | t.test("SSC::parseStringList()", [](auto t) { 51 | t.comment("TODO"); 52 | }); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/runtime/color/color.cc: -------------------------------------------------------------------------------- 1 | #include "../string.hh" 2 | #include "../color.hh" 3 | 4 | using namespace ssc::runtime::string; 5 | 6 | namespace ssc::runtime::color { 7 | Color::Color (const ColorComponents&) {} 8 | 9 | Color::Color ( 10 | unsigned int red, 11 | unsigned int green, 12 | unsigned int blue, 13 | float alpha 14 | ) : ColorComponents(red, green, blue, alpha) 15 | {} 16 | 17 | Color::Color (const Color& color) 18 | : Color(color.red, color.green, color.blue, color.alpha) 19 | {} 20 | 21 | Color::Color (Color&& color) 22 | : Color(color.red, color.green, color.blue, color.alpha) 23 | { 24 | color.red = 0; 25 | color.green = 0; 26 | color.blue = 0; 27 | color.alpha = 0.0f; 28 | } 29 | 30 | Color& Color::operator = (const Color& color) { 31 | this->red = color.red; 32 | this->green = color.green; 33 | this->blue = color.blue; 34 | this->alpha = color.alpha; 35 | return *this; 36 | } 37 | 38 | Color& Color::operator = (Color&& color) { 39 | this->red = color.red; 40 | this->green = color.green; 41 | this->blue = color.blue; 42 | this->alpha = color.alpha; 43 | color.red = 0; 44 | color.green = 0; 45 | color.blue = 0; 46 | color.alpha = 0.0f; 47 | return *this; 48 | } 49 | 50 | bool Color::operator == (const Color& color) const { 51 | return this->pack() == color.pack(); 52 | } 53 | 54 | bool Color::operator != (const Color& color) const { 55 | return this->pack() != color.pack(); 56 | } 57 | 58 | bool Color::operator > (const Color& color) const { 59 | return this->pack() > color.pack(); 60 | } 61 | 62 | bool Color::operator < (const Color& color) const { 63 | return this->pack() < color.pack(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/runtime/core/services/process.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_CORE_SERVICES_PROCESS_H 2 | #define SOCKET_RUNTIME_CORE_SERVICES_PROCESS_H 3 | 4 | #include "../../ipc.hh" 5 | #include "../../core.hh" 6 | #include "../../process.hh" 7 | #include "../../queued_response.hh" 8 | 9 | #include "timers.hh" 10 | 11 | namespace ssc::runtime::core::services { 12 | class Process : public core::Service { 13 | public: 14 | using ID = uint64_t; 15 | using Handles = Map>; 16 | 17 | struct SpawnOptions { 18 | String cwd; 19 | const Vector env; 20 | bool allowStdin = true; 21 | bool allowStdout = true; 22 | bool allowStderr = true; 23 | }; 24 | 25 | struct ExecOptions { 26 | String cwd; 27 | const Vector env; 28 | bool allowStdout = true; 29 | bool allowStderr = true; 30 | uint64_t timeout = 0; 31 | #if SOCKET_RUNTIME_PLATFORM_WINDOWS || SOCKET_RUNTIME_PLATFORM_IOS 32 | int killSignal = 0; // unused 33 | #else 34 | int killSignal = SIGTERM; 35 | #endif 36 | }; 37 | 38 | Handles handles; 39 | Timers timers; 40 | Mutex mutex; 41 | 42 | Process (const Options& options) 43 | : core::Service(options), 44 | timers(options) 45 | {} 46 | 47 | void shutdown (); 48 | void exec (const ipc::Message::Seq&, ID, const Vector, const ExecOptions, const Callback); 49 | void spawn (const ipc::Message::Seq&, ID, const Vector, const SpawnOptions, const Callback); 50 | void kill (const ipc::Message::Seq&, ID, int, const Callback); 51 | void write (const ipc::Message::Seq&, ID, SharedPointer, size_t, const Callback); 52 | }; 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /src/runtime/runtime.hh: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_RUNTIME_H 2 | #define SOCKET_RUNTIME_RUNTIME_H 3 | 4 | #include "core.hh" 5 | #include "config.hh" 6 | #include "bridge.hh" 7 | #include "window.hh" 8 | #include "options.hh" 9 | #include "context.hh" 10 | #include "serviceworker.hh" 11 | 12 | #include "core/services.hh" 13 | 14 | namespace ssc::runtime { 15 | class Runtime : public context::RuntimeContext { 16 | public: 17 | using DispatchCallback = Function; 18 | using UserConfig = Map; 19 | using Features = core::Services::Features; 20 | 21 | struct Options : public runtime::Options { 22 | UserConfig userConfig = config::getUserConfig(); 23 | loop::Loop::Options loop; 24 | Features features; 25 | }; 26 | 27 | struct Counters { 28 | int logSeq = 0; 29 | }; 30 | 31 | // managers 32 | window::Manager windowManager; 33 | bridge::Manager bridgeManager; 34 | serviceworker::Manager serviceWorkerManager; 35 | 36 | context::Dispatcher dispatcher; 37 | UserConfig userConfig; 38 | core::Services services; 39 | Counters counters; 40 | Options options; 41 | 42 | Runtime (const Options&); 43 | Runtime () = delete; 44 | Runtime (const Runtime&) = delete; 45 | Runtime (Runtime&&) = delete; 46 | virtual ~Runtime(); 47 | 48 | Runtime& operator = (const Runtime&) = delete; 49 | Runtime& operator = (Runtime&&) = delete; 50 | 51 | void init (); 52 | bool start (); 53 | bool stop (); 54 | bool resume (); 55 | bool pause(); 56 | bool destroy (); 57 | bool dispatch (const DispatchCallback&); 58 | 59 | bool stopped () const; 60 | bool paused () const; 61 | 62 | bool hasPermission (const String& permission) const; 63 | }; 64 | } 65 | #endif 66 | -------------------------------------------------------------------------------- /include/socket/webassembly/string.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_RUNTIME_WEBASSEMBLY_STRING_H 2 | #define SOCKET_RUNTIME_WEBASSEMBLY_STRING_H 3 | 4 | #if !defined(_STRING_H) 5 | #define _STRING_H 6 | #endif 7 | 8 | #include "features.h" 9 | #include "stddef.h" 10 | 11 | #if defined(__cplusplus) 12 | extern "C" { 13 | #endif 14 | 15 | extern void* memcpy (void* __restrict, const void* __restrict, size_t); 16 | extern void* memmove (void*, const void*, size_t); 17 | extern void* memset (void*, int, size_t); 18 | extern int memcmp (const void*, const void*, size_t); 19 | extern void* memchr (const void*, int, size_t); 20 | extern char* strcpy (char* __restrict, const char* __restrict); 21 | extern char* strncpy (char* __restrict, const char* __restrict, size_t); 22 | extern char* strcat (char* __restrict, const char* __restrict); 23 | extern char* strncat (char* __restrict, const char* __restrict, size_t); 24 | extern int strcmp (const char*, const char*); 25 | extern int strncmp (const char*, const char*, size_t); 26 | extern int strcoll (const char*, const char*); 27 | extern size_t strxfrm (char* __restrict, const char* __restrict, size_t); 28 | extern char* strchr (const char*, int); 29 | extern char* strrchr (const char*, int); 30 | extern char* stpcpy (char* __restrict, const char* __restrict); 31 | extern char* stpncpy (char* __restrict, const char* __restrict, size_t); 32 | extern size_t strnlen (const char*, size_t); 33 | extern char* strdup (const char*); 34 | extern char* strndup (const char*, size_t); 35 | extern char* strsignal (int); 36 | extern char* strerror (int); 37 | extern size_t strcspn (const char*, const char*); 38 | extern size_t strspn (const char*, const char*); 39 | extern char* strpbrk (const char*, const char*); 40 | extern char* strstr (const char*, const char *); 41 | extern char* strtok (char* __restrict, const char* __restrict); 42 | extern size_t strlen (const char*); 43 | 44 | #if defined(__cplusplus) 45 | } 46 | #endif 47 | #endif 48 | -------------------------------------------------------------------------------- /src/runtime/platform/platform.cc: -------------------------------------------------------------------------------- 1 | #include "../platform.hh" 2 | 3 | namespace ssc::runtime { 4 | extern const RuntimePlatform platform = { 5 | #if defined(__x86_64__) || defined(_M_X64) 6 | .arch = "x86_64", 7 | #elif defined(__aarch64__) || defined(_M_ARM64) 8 | .arch = "arm64", 9 | #elif defined(__i386__) && !defined(__ANDROID__) 10 | # error Socket is not supported on i386. 11 | #else 12 | .arch = "unknown", 13 | #endif 14 | 15 | // Windows 16 | #if defined(_WIN32) 17 | .os = "win32", 18 | .win = true, 19 | #endif 20 | 21 | // macOS & iOS 22 | #if defined(__APPLE__) 23 | #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR 24 | .os = "ios", 25 | .ios = true, 26 | #else 27 | .os = "mac", 28 | .mac = true, 29 | #endif 30 | #if defined(__unix__) || defined(unix) || defined(__unix) 31 | .unix = true 32 | #else 33 | .unix = false 34 | #endif 35 | #endif 36 | 37 | // Android & Linux 38 | #if defined(__linux__) 39 | #undef linux 40 | #ifdef __ANDROID__ 41 | .os = "android", 42 | .android = true, 43 | .linux = true, 44 | #else 45 | .os = "linux", 46 | .linux = true, 47 | #endif 48 | 49 | #if defined(__unix__) || defined(unix) || defined(__unix) 50 | .unix = true 51 | #else 52 | .unix = false 53 | #endif 54 | #endif 55 | 56 | // FreeBSD 57 | #if defined(__FreeBSD__) 58 | .os = "freebsd", 59 | #if defined(__unix__) || defined(unix) || defined(__unix) 60 | .unix = true 61 | #else 62 | .unix = false 63 | #endif 64 | #endif 65 | 66 | // OpenBSD (possibly) 67 | #if !defined(__APPLE__) && defined(BSD) && (defined(__unix__) || defined(unix) || defined(__unix)) 68 | .os = "openbsd", 69 | .unix = true 70 | #endif 71 | }; 72 | 73 | void msleep (uint64_t ms) { 74 | std::this_thread::yield(); 75 | std::this_thread::sleep_for(std::chrono::milliseconds(ms)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /api/tty.js: -------------------------------------------------------------------------------- 1 | import { Writable, Readable } from './stream.js' 2 | import ipc from './ipc.js' 3 | 4 | const textEncoder = new TextEncoder() 5 | const textDecoder = new TextDecoder() 6 | 7 | export function WriteStream (fd) { 8 | if (fd !== 1 && fd !== 2) { 9 | throw new TypeError('"fd" must be 1 or 2.') 10 | } 11 | 12 | const stream = new Writable({ 13 | async write (data, cb) { 14 | if (data && typeof data === 'object') { 15 | data = textDecoder.decode(data) 16 | } 17 | 18 | for (const value of data.split('\n')) { 19 | if (fd === 1) { 20 | ipc.send('stdout', { resolve: false, value }) 21 | } else if (fd === 2) { 22 | ipc.send('stderr', { resolve: false, value }) 23 | } 24 | } 25 | 26 | cb(null) 27 | } 28 | }) 29 | 30 | return stream 31 | } 32 | 33 | export function ReadStream (fd) { 34 | if (fd !== 0) { 35 | throw new TypeError('"fd" must be 0.') 36 | } 37 | 38 | const stream = new Readable() 39 | 40 | if (!globalThis.process?.versions?.node) { 41 | globalThis.addEventListener('process.stdin', function onData (event) { 42 | if (stream.destroyed) { 43 | return globalThis.removeEventListener('process.stdin', onData) 44 | } 45 | 46 | if (event.detail && typeof event.detail === 'object') { 47 | process.stdin.push(Buffer.from(JSON.stringify(event.detail))) 48 | } else if (event.detail) { 49 | process.stdin.push(Buffer.from(textEncoder.encode(event.detail))) 50 | } 51 | }) 52 | } 53 | 54 | return stream 55 | } 56 | 57 | export function isatty (fd) { 58 | if (fd === 0) { 59 | return globalThis.__args?.argv?.includes?.('--stdin') !== true 60 | } 61 | 62 | if (fd === 1) { 63 | return true 64 | } 65 | 66 | if (fd === 2) { 67 | return true 68 | } 69 | 70 | return false 71 | } 72 | 73 | export default { 74 | WriteStream, 75 | ReadStream, 76 | isatty 77 | } 78 | --------------------------------------------------------------------------------