@av-pi-studio/relay 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -0
- package/dist/base64.d.ts +10 -0
- package/dist/base64.d.ts.map +1 -0
- package/dist/base64.js +42 -0
- package/dist/base64.js.map +1 -0
- package/dist/cf-adapter.d.ts +58 -0
- package/dist/cf-adapter.d.ts.map +1 -0
- package/dist/cf-adapter.js +56 -0
- package/dist/cf-adapter.js.map +1 -0
- package/dist/channel.d.ts +72 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +189 -0
- package/dist/channel.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/session-bridge.d.ts +39 -0
- package/dist/session-bridge.d.ts.map +1 -0
- package/dist/session-bridge.js +76 -0
- package/dist/session-bridge.js.map +1 -0
- package/package.json +23 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../../../node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/typescript/lib/lib.es2023.d.ts","../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../src/base64.ts","../src/session-bridge.ts","../src/cf-adapter.ts","../../../node_modules/tweetnacl/nacl.d.ts","../src/channel.ts","../src/index.ts","../../../node_modules/@types/node/compatibility/disposable.d.ts","../../../node_modules/@types/node/compatibility/indexable.d.ts","../../../node_modules/@types/node/compatibility/iterators.d.ts","../../../node_modules/@types/node/compatibility/index.d.ts","../../../node_modules/@types/node/globals.typedarray.d.ts","../../../node_modules/@types/node/buffer.buffer.d.ts","../../../node_modules/@types/node/globals.d.ts","../../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../node_modules/@types/node/web-globals/domexception.d.ts","../../../node_modules/@types/node/web-globals/events.d.ts","../../../node_modules/undici-types/header.d.ts","../../../node_modules/undici-types/readable.d.ts","../../../node_modules/undici-types/file.d.ts","../../../node_modules/undici-types/fetch.d.ts","../../../node_modules/undici-types/formdata.d.ts","../../../node_modules/undici-types/connector.d.ts","../../../node_modules/undici-types/client.d.ts","../../../node_modules/undici-types/errors.d.ts","../../../node_modules/undici-types/dispatcher.d.ts","../../../node_modules/undici-types/global-dispatcher.d.ts","../../../node_modules/undici-types/global-origin.d.ts","../../../node_modules/undici-types/pool-stats.d.ts","../../../node_modules/undici-types/pool.d.ts","../../../node_modules/undici-types/handlers.d.ts","../../../node_modules/undici-types/balanced-pool.d.ts","../../../node_modules/undici-types/agent.d.ts","../../../node_modules/undici-types/mock-interceptor.d.ts","../../../node_modules/undici-types/mock-agent.d.ts","../../../node_modules/undici-types/mock-client.d.ts","../../../node_modules/undici-types/mock-pool.d.ts","../../../node_modules/undici-types/mock-errors.d.ts","../../../node_modules/undici-types/proxy-agent.d.ts","../../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../../node_modules/undici-types/retry-handler.d.ts","../../../node_modules/undici-types/retry-agent.d.ts","../../../node_modules/undici-types/api.d.ts","../../../node_modules/undici-types/interceptors.d.ts","../../../node_modules/undici-types/util.d.ts","../../../node_modules/undici-types/cookies.d.ts","../../../node_modules/undici-types/patch.d.ts","../../../node_modules/undici-types/websocket.d.ts","../../../node_modules/undici-types/eventsource.d.ts","../../../node_modules/undici-types/filereader.d.ts","../../../node_modules/undici-types/diagnostics-channel.d.ts","../../../node_modules/undici-types/content-type.d.ts","../../../node_modules/undici-types/cache.d.ts","../../../node_modules/undici-types/index.d.ts","../../../node_modules/@types/node/web-globals/fetch.d.ts","../../../node_modules/@types/node/web-globals/navigator.d.ts","../../../node_modules/@types/node/web-globals/storage.d.ts","../../../node_modules/@types/node/assert.d.ts","../../../node_modules/@types/node/assert/strict.d.ts","../../../node_modules/@types/node/async_hooks.d.ts","../../../node_modules/@types/node/buffer.d.ts","../../../node_modules/@types/node/child_process.d.ts","../../../node_modules/@types/node/cluster.d.ts","../../../node_modules/@types/node/console.d.ts","../../../node_modules/@types/node/constants.d.ts","../../../node_modules/@types/node/crypto.d.ts","../../../node_modules/@types/node/dgram.d.ts","../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/@types/node/dns.d.ts","../../../node_modules/@types/node/dns/promises.d.ts","../../../node_modules/@types/node/domain.d.ts","../../../node_modules/@types/node/events.d.ts","../../../node_modules/@types/node/fs.d.ts","../../../node_modules/@types/node/fs/promises.d.ts","../../../node_modules/@types/node/http.d.ts","../../../node_modules/@types/node/http2.d.ts","../../../node_modules/@types/node/https.d.ts","../../../node_modules/@types/node/inspector.d.ts","../../../node_modules/@types/node/inspector.generated.d.ts","../../../node_modules/@types/node/module.d.ts","../../../node_modules/@types/node/net.d.ts","../../../node_modules/@types/node/os.d.ts","../../../node_modules/@types/node/path.d.ts","../../../node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/@types/node/process.d.ts","../../../node_modules/@types/node/punycode.d.ts","../../../node_modules/@types/node/querystring.d.ts","../../../node_modules/@types/node/readline.d.ts","../../../node_modules/@types/node/readline/promises.d.ts","../../../node_modules/@types/node/repl.d.ts","../../../node_modules/@types/node/sea.d.ts","../../../node_modules/@types/node/sqlite.d.ts","../../../node_modules/@types/node/stream.d.ts","../../../node_modules/@types/node/stream/promises.d.ts","../../../node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/@types/node/stream/web.d.ts","../../../node_modules/@types/node/string_decoder.d.ts","../../../node_modules/@types/node/test.d.ts","../../../node_modules/@types/node/timers.d.ts","../../../node_modules/@types/node/timers/promises.d.ts","../../../node_modules/@types/node/tls.d.ts","../../../node_modules/@types/node/trace_events.d.ts","../../../node_modules/@types/node/tty.d.ts","../../../node_modules/@types/node/url.d.ts","../../../node_modules/@types/node/util.d.ts","../../../node_modules/@types/node/v8.d.ts","../../../node_modules/@types/node/vm.d.ts","../../../node_modules/@types/node/wasi.d.ts","../../../node_modules/@types/node/worker_threads.d.ts","../../../node_modules/@types/node/zlib.d.ts","../../../node_modules/@types/node/index.d.ts"],"fileIdsList":[[73,118,119,121,138,139],[73,120,121,138,139],[121,138,139],[73,121,126,138,139,156],[73,121,122,127,132,138,139,141,153,164],[73,121,122,123,132,138,139,141],[73,121,138,139],[68,69,70,73,121,138,139],[73,121,124,138,139,165],[73,121,125,126,133,138,139,142],[73,121,126,138,139,153,161],[73,121,127,129,132,138,139,141],[73,120,121,128,138,139],[73,121,129,130,138,139],[73,121,131,132,138,139],[73,120,121,132,138,139],[73,121,132,133,134,138,139,153,164],[73,121,132,133,134,138,139,148,153,156],[73,114,121,129,132,135,138,139,141,153,164],[73,121,132,133,135,136,138,139,141,153,161,164],[73,121,135,137,138,139,153,161,164],[71,72,73,74,75,76,77,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170],[73,121,132,138,139],[73,121,138,139,140,164],[73,121,129,132,138,139,141,153],[73,121,138,139,142],[73,121,138,139,143],[73,120,121,138,139,144],[73,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170],[73,121,138,139,146],[73,121,138,139,147],[73,121,132,138,139,148,149],[73,121,138,139,148,150,165,167],[73,121,133,138,139],[73,121,132,138,139,153,154,156],[73,121,138,139,155,156],[73,121,138,139,153,154],[73,121,138,139,156],[73,121,138,139,157],[73,118,121,138,139,153,158,164],[73,121,132,138,139,159,160],[73,121,138,139,159,160],[73,121,126,138,139,141,153,161],[73,121,138,139,162],[73,121,138,139,141,163],[73,121,135,138,139,147,164],[73,121,126,138,139,165],[73,121,138,139,153,166],[73,121,138,139,140,167],[73,121,138,139,168],[73,114,121,138,139],[73,114,121,132,134,138,139,144,153,156,164,166,167,169],[73,121,138,139,153,170],[73,86,90,121,138,139,164],[73,86,121,138,139,153,164],[73,81,121,138,139],[73,83,86,121,138,139,161,164],[73,121,138,139,141,161],[73,121,138,139,171],[73,81,121,138,139,171],[73,83,86,121,138,139,141,164],[73,78,79,82,85,121,132,138,139,153,164],[73,86,93,121,138,139],[73,78,84,121,138,139],[73,86,107,108,121,138,139],[73,82,86,121,138,139,156,164,171],[73,107,121,138,139,171],[73,80,81,121,138,139,171],[73,86,121,138,139],[73,80,81,82,83,84,85,86,87,88,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,108,109,110,111,112,113,121,138,139],[73,86,101,121,138,139],[73,86,93,94,121,138,139],[73,84,86,94,95,121,138,139],[73,85,121,138,139],[73,78,81,86,121,138,139],[73,86,90,94,95,121,138,139],[73,90,121,138,139],[73,84,86,89,121,138,139,164],[73,78,83,86,93,121,138,139],[73,121,138,139,153],[73,81,86,107,121,138,139,169,171],[63,73,121,138,139],[62,65,73,121,138,139],[62,63,64,66,73,121,138,139]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"3facaf05f0c5fc569c5649dd359892c98a85557e3e0c847964caeb67076f4d75","impliedFormat":1},{"version":"e44bb8bbac7f10ecc786703fe0a6a4b952189f908707980ba8f3c8975a760962","impliedFormat":1},{"version":"5e1c4c362065a6b95ff952c0eab010f04dcd2c3494e813b493ecfd4fcb9fc0d8","impliedFormat":1},{"version":"68d73b4a11549f9c0b7d352d10e91e5dca8faa3322bfb77b661839c42b1ddec7","impliedFormat":1},{"version":"5efce4fc3c29ea84e8928f97adec086e3dc876365e0982cc8479a07954a3efd4","impliedFormat":1},{"version":"feecb1be483ed332fad555aff858affd90a48ab19ba7272ee084704eb7167569","impliedFormat":1},{"version":"ee7bad0c15b58988daa84371e0b89d313b762ab83cb5b31b8a2d1162e8eb41c2","impliedFormat":1},{"version":"27bdc30a0e32783366a5abeda841bc22757c1797de8681bbe81fbc735eeb1c10","impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"d15bea3d62cbbdb9797079416b8ac375ae99162a7fba5de2c6c505446486ac0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"68d18b664c9d32a7336a70235958b8997ebc1c3b8505f4f1ae2b7e7753b87618","affectsGlobalScope":true,"impliedFormat":1},{"version":"eb3d66c8327153d8fa7dd03f9c58d351107fe824c79e9b56b462935176cdf12a","affectsGlobalScope":true,"impliedFormat":1},{"version":"38f0219c9e23c915ef9790ab1d680440d95419ad264816fa15009a8851e79119","affectsGlobalScope":true,"impliedFormat":1},{"version":"69ab18c3b76cd9b1be3d188eaf8bba06112ebbe2f47f6c322b5105a6fbc45a2e","affectsGlobalScope":true,"impliedFormat":1},{"version":"a680117f487a4d2f30ea46f1b4b7f58bef1480456e18ba53ee85c2746eeca012","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f11ff796926e0832f9ae148008138ad583bd181899ab7dd768a2666700b1893","affectsGlobalScope":true,"impliedFormat":1},{"version":"4de680d5bb41c17f7f68e0419412ca23c98d5749dcaaea1896172f06435891fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"954296b30da6d508a104a3a0b5d96b76495c709785c1d11610908e63481ee667","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac9538681b19688c8eae65811b329d3744af679e0bdfa5d842d0e32524c73e1c","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a969edff4bd52585473d24995c5ef223f6652d6ef46193309b3921d65dd4376","affectsGlobalScope":true,"impliedFormat":1},{"version":"9e9fbd7030c440b33d021da145d3232984c8bb7916f277e8ffd3dc2e3eae2bdb","affectsGlobalScope":true,"impliedFormat":1},{"version":"811ec78f7fefcabbda4bfa93b3eb67d9ae166ef95f9bff989d964061cbf81a0c","affectsGlobalScope":true,"impliedFormat":1},{"version":"717937616a17072082152a2ef351cb51f98802fb4b2fdabd32399843875974ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"d7e7d9b7b50e5f22c915b525acc5a49a7a6584cf8f62d0569e557c5cfc4b2ac2","affectsGlobalScope":true,"impliedFormat":1},{"version":"71c37f4c9543f31dfced6c7840e068c5a5aacb7b89111a4364b1d5276b852557","affectsGlobalScope":true,"impliedFormat":1},{"version":"576711e016cf4f1804676043e6a0a5414252560eb57de9faceee34d79798c850","affectsGlobalScope":true,"impliedFormat":1},{"version":"89c1b1281ba7b8a96efc676b11b264de7a8374c5ea1e6617f11880a13fc56dc6","affectsGlobalScope":true,"impliedFormat":1},{"version":"74f7fa2d027d5b33eb0471c8e82a6c87216223181ec31247c357a3e8e2fddc5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"d6d7ae4d1f1f3772e2a3cde568ed08991a8ae34a080ff1151af28b7f798e22ca","affectsGlobalScope":true,"impliedFormat":1},{"version":"063600664504610fe3e99b717a1223f8b1900087fab0b4cad1496a114744f8df","affectsGlobalScope":true,"impliedFormat":1},{"version":"934019d7e3c81950f9a8426d093458b65d5aff2c7c1511233c0fd5b941e608ab","affectsGlobalScope":true,"impliedFormat":1},{"version":"52ada8e0b6e0482b728070b7639ee42e83a9b1c22d205992756fe020fd9f4a47","affectsGlobalScope":true,"impliedFormat":1},{"version":"3bdefe1bfd4d6dee0e26f928f93ccc128f1b64d5d501ff4a8cf3c6371200e5e6","affectsGlobalScope":true,"impliedFormat":1},{"version":"59fb2c069260b4ba00b5643b907ef5d5341b167e7d1dbf58dfd895658bda2867","affectsGlobalScope":true,"impliedFormat":1},{"version":"639e512c0dfc3fad96a84caad71b8834d66329a1f28dc95e3946c9b58176c73a","affectsGlobalScope":true,"impliedFormat":1},{"version":"368af93f74c9c932edd84c58883e736c9e3d53cec1fe24c0b0ff451f529ceab1","affectsGlobalScope":true,"impliedFormat":1},{"version":"af3dd424cf267428f30ccfc376f47a2c0114546b55c44d8c0f1d57d841e28d74","affectsGlobalScope":true,"impliedFormat":1},{"version":"995c005ab91a498455ea8dfb63aa9f83fa2ea793c3d8aa344be4a1678d06d399","affectsGlobalScope":true,"impliedFormat":1},{"version":"959d36cddf5e7d572a65045b876f2956c973a586da58e5d26cde519184fd9b8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"965f36eae237dd74e6cca203a43e9ca801ce38824ead814728a2807b1910117d","affectsGlobalScope":true,"impliedFormat":1},{"version":"3925a6c820dcb1a06506c90b1577db1fdbf7705d65b62b99dce4be75c637e26b","affectsGlobalScope":true,"impliedFormat":1},{"version":"0a3d63ef2b853447ec4f749d3f368ce642264246e02911fcb1590d8c161b8005","affectsGlobalScope":true,"impliedFormat":1},{"version":"8cdf8847677ac7d20486e54dd3fcf09eda95812ac8ace44b4418da1bbbab6eb8","affectsGlobalScope":true,"impliedFormat":1},{"version":"8444af78980e3b20b49324f4a16ba35024fef3ee069a0eb67616ea6ca821c47a","affectsGlobalScope":true,"impliedFormat":1},{"version":"3287d9d085fbd618c3971944b65b4be57859f5415f495b33a6adc994edd2f004","affectsGlobalScope":true,"impliedFormat":1},{"version":"b4b67b1a91182421f5df999988c690f14d813b9850b40acd06ed44691f6727ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"df83c2a6c73228b625b0beb6669c7ee2a09c914637e2d35170723ad49c0f5cd4","affectsGlobalScope":true,"impliedFormat":1},{"version":"436aaf437562f276ec2ddbee2f2cdedac7664c1e4c1d2c36839ddd582eeb3d0a","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e3c06ea092138bf9fa5e874a1fdbc9d54805d074bee1de31b99a11e2fec239d","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"93d79f12c401be264bcb23d89f4e74c1e72a5605fcc42fbeefc0f404a51a545f","signature":"fdc8d72f90b3ac131587d78463fc03c479edc4ea623455ad17c72dadcc955299"},{"version":"70cd1ae64dac1d01603caad64f2f9b3dc1b5b39a021a640346dbbd69532746f4","signature":"69ee6c9e1da9cea7c05b53aba10a74ec8c56214d95563dd93a106f78db0e18a8"},{"version":"ecf8251ec9dd047961cac4d6da5574fa9ea5e7f095c7c0f777654ff364cb8041","signature":"ce3dc2e2dd5757bac8ac7629f26e0e241301fa2a17b2b50bee4283d651f0abe4"},{"version":"60592f5ae1b739c9607a99895d4a3ad5c865b16903e4180e50b256e360a4a104","impliedFormat":1},{"version":"a9dbb24cf673eafcae19f9ca4e897016408548a4e67a1fac55494520ed2a755e","signature":"a850bcf01aa5683c7c881619122e748159a3623a7c7f27fe41277bdee5c34d4e"},"5594a4bf850fcede314d66496e8d6411d67be1df7a4f8cbac4754c0e65591f10",{"version":"6c7176368037af28cb72f2392010fa1cef295d6d6744bca8cfb54985f3a18c3e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab41ef1f2cdafb8df48be20cd969d875602483859dc194e9c97c8a576892c052","affectsGlobalScope":true,"impliedFormat":1},{"version":"437e20f2ba32abaeb7985e0afe0002de1917bc74e949ba585e49feba65da6ca1","affectsGlobalScope":true,"impliedFormat":1},{"version":"21d819c173c0cf7cc3ce57c3276e77fd9a8a01d35a06ad87158781515c9a438a","impliedFormat":1},{"version":"98cffbf06d6bab333473c70a893770dbe990783904002c4f1a960447b4b53dca","affectsGlobalScope":true,"impliedFormat":1},{"version":"3af97acf03cc97de58a3a4bc91f8f616408099bc4233f6d0852e72a8ffb91ac9","affectsGlobalScope":true,"impliedFormat":1},{"version":"808069bba06b6768b62fd22429b53362e7af342da4a236ed2d2e1c89fcca3b4a","affectsGlobalScope":true,"impliedFormat":1},{"version":"1db0b7dca579049ca4193d034d835f6bfe73096c73663e5ef9a0b5779939f3d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"f26b11d8d8e4b8028f1c7d618b22274c892e4b0ef5b3678a8ccbad85419aef43","affectsGlobalScope":true,"impliedFormat":1},{"version":"5929864ce17fba74232584d90cb721a89b7ad277220627cc97054ba15a98ea8f","impliedFormat":1},{"version":"763fe0f42b3d79b440a9b6e51e9ba3f3f91352469c1e4b3b67bfa4ff6352f3f4","impliedFormat":1},{"version":"25c8056edf4314820382a5fdb4bb7816999acdcb929c8f75e3f39473b87e85bc","impliedFormat":1},{"version":"c464d66b20788266e5353b48dc4aa6bc0dc4a707276df1e7152ab0c9ae21fad8","impliedFormat":1},{"version":"78d0d27c130d35c60b5e5566c9f1e5be77caf39804636bc1a40133919a949f21","impliedFormat":1},{"version":"c6fd2c5a395f2432786c9cb8deb870b9b0e8ff7e22c029954fabdd692bff6195","impliedFormat":1},{"version":"1d6e127068ea8e104a912e42fc0a110e2aa5a66a356a917a163e8cf9a65e4a75","impliedFormat":1},{"version":"5ded6427296cdf3b9542de4471d2aa8d3983671d4cac0f4bf9c637208d1ced43","impliedFormat":1},{"version":"7f182617db458e98fc18dfb272d40aa2fff3a353c44a89b2c0ccb3937709bfb5","impliedFormat":1},{"version":"cadc8aced301244057c4e7e73fbcae534b0f5b12a37b150d80e5a45aa4bebcbd","impliedFormat":1},{"version":"385aab901643aa54e1c36f5ef3107913b10d1b5bb8cbcd933d4263b80a0d7f20","impliedFormat":1},{"version":"9670d44354bab9d9982eca21945686b5c24a3f893db73c0dae0fd74217a4c219","impliedFormat":1},{"version":"0b8a9268adaf4da35e7fa830c8981cfa22adbbe5b3f6f5ab91f6658899e657a7","impliedFormat":1},{"version":"11396ed8a44c02ab9798b7dca436009f866e8dae3c9c25e8c1fbc396880bf1bb","impliedFormat":1},{"version":"ba7bc87d01492633cb5a0e5da8a4a42a1c86270e7b3d2dea5d156828a84e4882","impliedFormat":1},{"version":"4893a895ea92c85345017a04ed427cbd6a1710453338df26881a6019432febdd","impliedFormat":1},{"version":"c21dc52e277bcfc75fac0436ccb75c204f9e1b3fa5e12729670910639f27343e","impliedFormat":1},{"version":"13f6f39e12b1518c6650bbb220c8985999020fe0f21d818e28f512b7771d00f9","impliedFormat":1},{"version":"9b5369969f6e7175740bf51223112ff209f94ba43ecd3bb09eefff9fd675624a","impliedFormat":1},{"version":"4fe9e626e7164748e8769bbf74b538e09607f07ed17c2f20af8d680ee49fc1da","impliedFormat":1},{"version":"24515859bc0b836719105bb6cc3d68255042a9f02a6022b3187948b204946bd2","impliedFormat":1},{"version":"ea0148f897b45a76544ae179784c95af1bd6721b8610af9ffa467a518a086a43","impliedFormat":1},{"version":"24c6a117721e606c9984335f71711877293a9651e44f59f3d21c1ea0856f9cc9","impliedFormat":1},{"version":"dd3273ead9fbde62a72949c97dbec2247ea08e0c6952e701a483d74ef92d6a17","impliedFormat":1},{"version":"405822be75ad3e4d162e07439bac80c6bcc6dbae1929e179cf467ec0b9ee4e2e","impliedFormat":1},{"version":"0db18c6e78ea846316c012478888f33c11ffadab9efd1cc8bcc12daded7a60b6","impliedFormat":1},{"version":"e61be3f894b41b7baa1fbd6a66893f2579bfad01d208b4ff61daef21493ef0a8","impliedFormat":1},{"version":"bd0532fd6556073727d28da0edfd1736417a3f9f394877b6d5ef6ad88fba1d1a","impliedFormat":1},{"version":"89167d696a849fce5ca508032aabfe901c0868f833a8625d5a9c6e861ef935d2","impliedFormat":1},{"version":"615ba88d0128ed16bf83ef8ccbb6aff05c3ee2db1cc0f89ab50a4939bfc1943f","impliedFormat":1},{"version":"a4d551dbf8746780194d550c88f26cf937caf8d56f102969a110cfaed4b06656","impliedFormat":1},{"version":"8bd86b8e8f6a6aa6c49b71e14c4ffe1211a0e97c80f08d2c8cc98838006e4b88","impliedFormat":1},{"version":"317e63deeb21ac07f3992f5b50cdca8338f10acd4fbb7257ebf56735bf52ab00","impliedFormat":1},{"version":"4732aec92b20fb28c5fe9ad99521fb59974289ed1e45aecb282616202184064f","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"bf67d53d168abc1298888693338cb82854bdb2e69ef83f8a0092093c2d562107","impliedFormat":1},{"version":"b52476feb4a0cbcb25e5931b930fc73cb6643fb1a5060bf8a3dda0eeae5b4b68","affectsGlobalScope":true,"impliedFormat":1},{"version":"f9501cc13ce624c72b61f12b3963e84fad210fbdf0ffbc4590e08460a3f04eba","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"0fa06ada475b910e2106c98c68b10483dc8811d0c14a8a8dd36efb2672485b29","impliedFormat":1},{"version":"33e5e9aba62c3193d10d1d33ae1fa75c46a1171cf76fef750777377d53b0303f","impliedFormat":1},{"version":"2b06b93fd01bcd49d1a6bd1f9b65ddcae6480b9a86e9061634d6f8e354c1468f","impliedFormat":1},{"version":"6a0cd27e5dc2cfbe039e731cf879d12b0e2dded06d1b1dedad07f7712de0d7f4","affectsGlobalScope":true,"impliedFormat":1},{"version":"13f5c844119c43e51ce777c509267f14d6aaf31eafb2c2b002ca35584cd13b29","impliedFormat":1},{"version":"e60477649d6ad21542bd2dc7e3d9ff6853d0797ba9f689ba2f6653818999c264","impliedFormat":1},{"version":"c2510f124c0293ab80b1777c44d80f812b75612f297b9857406468c0f4dafe29","affectsGlobalScope":true,"impliedFormat":1},{"version":"5524481e56c48ff486f42926778c0a3cce1cc85dc46683b92b1271865bcf015a","impliedFormat":1},{"version":"4c829ab315f57c5442c6667b53769975acbf92003a66aef19bce151987675bd1","affectsGlobalScope":true,"impliedFormat":1},{"version":"b2ade7657e2db96d18315694789eff2ddd3d8aea7215b181f8a0b303277cc579","impliedFormat":1},{"version":"9855e02d837744303391e5623a531734443a5f8e6e8755e018c41d63ad797db2","impliedFormat":1},{"version":"4d631b81fa2f07a0e63a9a143d6a82c25c5f051298651a9b69176ba28930756d","impliedFormat":1},{"version":"836a356aae992ff3c28a0212e3eabcb76dd4b0cc06bcb9607aeef560661b860d","impliedFormat":1},{"version":"1e0d1f8b0adfa0b0330e028c7941b5a98c08b600efe7f14d2d2a00854fb2f393","impliedFormat":1},{"version":"41670ee38943d9cbb4924e436f56fc19ee94232bc96108562de1a734af20dc2c","affectsGlobalScope":true,"impliedFormat":1},{"version":"c906fb15bd2aabc9ed1e3f44eb6a8661199d6c320b3aa196b826121552cb3695","impliedFormat":1},{"version":"22295e8103f1d6d8ea4b5d6211e43421fe4564e34d0dd8e09e520e452d89e659","impliedFormat":1},{"version":"58647d85d0f722a1ce9de50955df60a7489f0593bf1a7015521efe901c06d770","impliedFormat":1},{"version":"9018e9493596e2d041fc531f5101a0d05f9d2e1311f4ae3c74345b1766158c08","impliedFormat":1},{"version":"a10f0e1854f3316d7ee437b79649e5a6ae3ae14ffe6322b02d4987071a95362e","impliedFormat":1},{"version":"e208f73ef6a980104304b0d2ca5f6bf1b85de6009d2c7e404028b875020fa8f2","impliedFormat":1},{"version":"d163b6bc2372b4f07260747cbc6c0a6405ab3fbcea3852305e98ac43ca59f5bc","impliedFormat":1},{"version":"e6fa9ad47c5f71ff733744a029d1dc472c618de53804eae08ffc243b936f87ff","affectsGlobalScope":true,"impliedFormat":1},{"version":"a6f137d651076822d4fe884287e68fd61785a0d3d1fdb250a5059b691fa897db","impliedFormat":1},{"version":"24826ed94a78d5c64bd857570fdbd96229ad41b5cb654c08d75a9845e3ab7dde","impliedFormat":1},{"version":"8b479a130ccb62e98f11f136d3ac80f2984fdc07616516d29881f3061f2dd472","impliedFormat":1},{"version":"928af3d90454bf656a52a48679f199f64c1435247d6189d1caf4c68f2eaf921f","affectsGlobalScope":true,"impliedFormat":1},{"version":"bceb58df66ab8fb00170df20cd813978c5ab84be1d285710c4eb005d8e9d8efb","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f16a7e4deafa527ed9995a772bb380eb7d3c2c0fd4ae178c5263ed18394db2c","impliedFormat":1},{"version":"933921f0bb0ec12ef45d1062a1fc0f27635318f4d294e4d99de9a5493e618ca2","impliedFormat":1},{"version":"71a0f3ad612c123b57239a7749770017ecfe6b66411488000aba83e4546fde25","impliedFormat":1},{"version":"77fbe5eecb6fac4b6242bbf6eebfc43e98ce5ccba8fa44e0ef6a95c945ff4d98","impliedFormat":1},{"version":"4f9d8ca0c417b67b69eeb54c7ca1bedd7b56034bb9bfd27c5d4f3bc4692daca7","impliedFormat":1},{"version":"814118df420c4e38fe5ae1b9a3bafb6e9c2aa40838e528cde908381867be6466","impliedFormat":1},{"version":"a3fc63c0d7b031693f665f5494412ba4b551fe644ededccc0ab5922401079c95","impliedFormat":1},{"version":"80523c00b8544a2000ae0143e4a90a00b47f99823eb7926c1e03c494216fc363","impliedFormat":1},{"version":"37ba7b45141a45ce6e80e66f2a96c8a5ab1bcef0fc2d0f56bb58df96ec67e972","impliedFormat":1},{"version":"45650f47bfb376c8a8ed39d4bcda5902ab899a3150029684ee4c10676d9fbaee","impliedFormat":1},{"version":"746911b62b329587939560deb5c036aca48aece03147b021fa680223255d5183","affectsGlobalScope":true,"impliedFormat":1},{"version":"18fd40412d102c5564136f29735e5d1c3b455b8a37f920da79561f1fde068208","impliedFormat":1},{"version":"c8d3e5a18ba35629954e48c4cc8f11dc88224650067a172685c736b27a34a4dc","impliedFormat":1},{"version":"f0be1b8078cd549d91f37c30c222c2a187ac1cf981d994fb476a1adc61387b14","affectsGlobalScope":true,"impliedFormat":1},{"version":"0aaed1d72199b01234152f7a60046bc947f1f37d78d182e9ae09c4289e06a592","impliedFormat":1},{"version":"2b55d426ff2b9087485e52ac4bc7cfafe1dc420fc76dad926cd46526567c501a","impliedFormat":1},{"version":"66ba1b2c3e3a3644a1011cd530fb444a96b1b2dfe2f5e837a002d41a1a799e60","impliedFormat":1},{"version":"7e514f5b852fdbc166b539fdd1f4e9114f29911592a5eb10a94bb3a13ccac3c4","impliedFormat":1},{"version":"5b7aa3c4c1a5d81b411e8cb302b45507fea9358d3569196b27eb1a27ae3a90ef","affectsGlobalScope":true,"impliedFormat":1},{"version":"5987a903da92c7462e0b35704ce7da94d7fdc4b89a984871c0e2b87a8aae9e69","affectsGlobalScope":true,"impliedFormat":1},{"version":"ea08a0345023ade2b47fbff5a76d0d0ed8bff10bc9d22b83f40858a8e941501c","impliedFormat":1},{"version":"47613031a5a31510831304405af561b0ffaedb734437c595256bb61a90f9311b","impliedFormat":1},{"version":"ae062ce7d9510060c5d7e7952ae379224fb3f8f2dd74e88959878af2057c143b","impliedFormat":1},{"version":"8a1a0d0a4a06a8d278947fcb66bf684f117bf147f89b06e50662d79a53be3e9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"358765d5ea8afd285d4fd1532e78b88273f18cb3f87403a9b16fef61ac9fdcfe","impliedFormat":1},{"version":"9f55299850d4f0921e79b6bf344b47c420ce0f507b9dcf593e532b09ea7eeea1","impliedFormat":1}],"root":[[62,64],66,67],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"exactOptionalPropertyTypes":false,"module":99,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"noUncheckedIndexedAccess":true,"outDir":"./","rootDir":"../src","skipLibCheck":true,"sourceMap":true,"strict":true,"target":9,"tsBuildInfoFile":"./.tsbuildinfo","verbatimModuleSyntax":true},"referencedMap":[[118,1],[119,1],[120,2],[73,3],[121,4],[122,5],[123,6],[68,7],[71,8],[69,7],[70,7],[124,9],[125,10],[126,11],[127,12],[128,13],[129,14],[130,14],[131,15],[132,16],[133,17],[134,18],[74,7],[72,7],[135,19],[136,20],[137,21],[171,22],[138,23],[139,7],[140,24],[141,25],[142,26],[143,27],[144,28],[145,29],[146,30],[147,31],[148,32],[149,32],[150,33],[151,7],[152,34],[153,35],[155,36],[154,37],[156,38],[157,39],[158,40],[159,41],[160,42],[161,43],[162,44],[163,45],[164,46],[165,47],[166,48],[167,49],[168,50],[75,7],[76,7],[77,7],[115,51],[116,7],[117,7],[169,52],[170,53],[65,7],[60,7],[61,7],[12,7],[11,7],[2,7],[13,7],[14,7],[15,7],[16,7],[17,7],[18,7],[19,7],[20,7],[3,7],[21,7],[22,7],[4,7],[23,7],[27,7],[24,7],[25,7],[26,7],[28,7],[29,7],[30,7],[5,7],[31,7],[32,7],[33,7],[34,7],[6,7],[38,7],[35,7],[36,7],[37,7],[39,7],[7,7],[40,7],[45,7],[46,7],[41,7],[42,7],[43,7],[44,7],[8,7],[50,7],[47,7],[48,7],[49,7],[51,7],[9,7],[52,7],[53,7],[54,7],[56,7],[55,7],[57,7],[58,7],[10,7],[59,7],[1,7],[93,54],[103,55],[92,54],[113,56],[84,57],[83,58],[112,59],[106,60],[111,61],[86,62],[100,63],[85,64],[109,65],[81,66],[80,59],[110,67],[82,68],[87,69],[88,7],[91,69],[78,7],[114,70],[104,71],[95,72],[96,73],[98,74],[94,75],[97,76],[107,59],[89,77],[90,78],[99,79],[79,80],[102,71],[101,69],[105,7],[108,81],[62,7],[64,82],[66,83],[67,84],[63,7]],"latestChangedDtsFile":"./index.d.ts","version":"5.9.3"}
|
package/dist/base64.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-JS base64 codec (no Node `Buffer`) so the relay's crypto framing runs identically in the
|
|
3
|
+
* daemon (Node) and future browser/RN clients — see architecture/relay-e2ee.md § Behavior
|
|
4
|
+
* (per-message wire format uses `base64([nonce] ++ ciphertext)`).
|
|
5
|
+
*/
|
|
6
|
+
/** Encode raw bytes as standard (padded) base64. */
|
|
7
|
+
export declare function encodeBase64(bytes: Uint8Array): string;
|
|
8
|
+
/** Decode standard base64 (padded or not) into raw bytes. Throws on invalid characters. */
|
|
9
|
+
export declare function decodeBase64(input: string): Uint8Array;
|
|
10
|
+
//# sourceMappingURL=base64.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.d.ts","sourceRoot":"","sources":["../src/base64.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,oDAAoD;AACpD,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CActD;AAED,2FAA2F;AAC3F,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAgBtD"}
|
package/dist/base64.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure-JS base64 codec (no Node `Buffer`) so the relay's crypto framing runs identically in the
|
|
3
|
+
* daemon (Node) and future browser/RN clients — see architecture/relay-e2ee.md § Behavior
|
|
4
|
+
* (per-message wire format uses `base64([nonce] ++ ciphertext)`).
|
|
5
|
+
*/
|
|
6
|
+
const CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
7
|
+
/** Encode raw bytes as standard (padded) base64. */
|
|
8
|
+
export function encodeBase64(bytes) {
|
|
9
|
+
let out = "";
|
|
10
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
11
|
+
const b0 = bytes[i];
|
|
12
|
+
const hasB1 = i + 1 < bytes.length;
|
|
13
|
+
const hasB2 = i + 2 < bytes.length;
|
|
14
|
+
const b1 = hasB1 ? bytes[i + 1] : 0;
|
|
15
|
+
const b2 = hasB2 ? bytes[i + 2] : 0;
|
|
16
|
+
out += CHARS[b0 >> 2];
|
|
17
|
+
out += CHARS[((b0 & 0x03) << 4) | (b1 >> 4)];
|
|
18
|
+
out += hasB1 ? CHARS[((b1 & 0x0f) << 2) | (b2 >> 6)] : "=";
|
|
19
|
+
out += hasB2 ? CHARS[b2 & 0x3f] : "=";
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
/** Decode standard base64 (padded or not) into raw bytes. Throws on invalid characters. */
|
|
24
|
+
export function decodeBase64(input) {
|
|
25
|
+
const clean = input.replace(/=+$/, "");
|
|
26
|
+
const bytes = [];
|
|
27
|
+
let buffer = 0;
|
|
28
|
+
let bits = 0;
|
|
29
|
+
for (const ch of clean) {
|
|
30
|
+
const val = CHARS.indexOf(ch);
|
|
31
|
+
if (val === -1)
|
|
32
|
+
throw new Error(`invalid base64 character: ${JSON.stringify(ch)}`);
|
|
33
|
+
buffer = (buffer << 6) | val;
|
|
34
|
+
bits += 6;
|
|
35
|
+
if (bits >= 8) {
|
|
36
|
+
bits -= 8;
|
|
37
|
+
bytes.push((buffer >> bits) & 0xff);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return new Uint8Array(bytes);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=base64.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base64.js","sourceRoot":"","sources":["../src/base64.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,KAAK,GAAG,kEAAkE,CAAC;AAEjF,oDAAoD;AACpD,MAAM,UAAU,YAAY,CAAC,KAAiB;IAC5C,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACrB,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACnC,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QACnC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACrC,GAAG,IAAI,KAAK,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QACtB,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC3D,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACnF,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;QAC7B,IAAI,IAAI,CAAC,CAAC;QACV,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare Workers adapter (architecture/relay-e2ee.md § Channel API — "Cloudflare adapter |
|
|
3
|
+
* server | Relay server implementation hook for Cloudflare Workers"; § Purpose).
|
|
4
|
+
*
|
|
5
|
+
* Wraps a Cloudflare Workers `WebSocketPair` into the platform-agnostic `RelaySessionBridge`
|
|
6
|
+
* (`session-bridge.ts`) so a Workers `fetch` handler can accept a WebSocket upgrade and hand the
|
|
7
|
+
* server-side socket to the bridge with three lines of code. This module deliberately avoids a
|
|
8
|
+
* hard dependency on `@cloudflare/workers-types` (which would collide with this package's `"node"`
|
|
9
|
+
* ambient types and pull in a large type-only surface for a library package with zero runtime
|
|
10
|
+
* deps) — instead it declares the minimal STRUCTURAL shape it actually uses
|
|
11
|
+
* ({@link CfWebSocket}/{@link CfWebSocketPair}), which the real Workers runtime's objects satisfy
|
|
12
|
+
* naturally. A real deployment supplies the actual Workers globals; this adapter only needs
|
|
13
|
+
* `accept`/`send`/`addEventListener`/`close`.
|
|
14
|
+
*
|
|
15
|
+
* Hosted deployment/ops (wrangler config, the actual `fetch` export's `Request`/`Response`
|
|
16
|
+
* wiring) is explicitly out of scope for this task — see the task file § Out of scope. What's
|
|
17
|
+
* built here is the reusable bridging hook a `fetch` handler wires the upgrade through.
|
|
18
|
+
*/
|
|
19
|
+
import { RelaySessionBridge } from "./session-bridge.js";
|
|
20
|
+
/** Structural subset of the real Cloudflare Workers `WebSocket` this adapter depends on. */
|
|
21
|
+
export interface CfWebSocket {
|
|
22
|
+
accept(): void;
|
|
23
|
+
send(data: string): void;
|
|
24
|
+
addEventListener(type: "message", listener: (ev: {
|
|
25
|
+
data: string;
|
|
26
|
+
}) => void): void;
|
|
27
|
+
addEventListener(type: "close", listener: (ev: {
|
|
28
|
+
code: number;
|
|
29
|
+
reason: string;
|
|
30
|
+
}) => void): void;
|
|
31
|
+
close(code?: number, reason?: string): void;
|
|
32
|
+
}
|
|
33
|
+
/** Structural subset of the real Cloudflare Workers `WebSocketPair` (a 2-tuple: [client, server]). */
|
|
34
|
+
export type CfWebSocketPair = readonly [CfWebSocket, CfWebSocket];
|
|
35
|
+
export type WebSocketPairFactory = () => CfWebSocketPair;
|
|
36
|
+
export interface CloudflareRelayAdapterOptions {
|
|
37
|
+
bridge: RelaySessionBridge;
|
|
38
|
+
/**
|
|
39
|
+
* Injectable for tests. Defaults to the global `WebSocketPair` constructor, which only exists
|
|
40
|
+
* in the real Cloudflare Workers runtime — omit this in production; supply a fake in tests.
|
|
41
|
+
*/
|
|
42
|
+
createWebSocketPair?: WebSocketPairFactory;
|
|
43
|
+
}
|
|
44
|
+
export interface UpgradeResult {
|
|
45
|
+
/** HTTP status the caller's `fetch` handler should respond with (101 on success). */
|
|
46
|
+
status: number;
|
|
47
|
+
/** The CLIENT-side socket to return to the browser via `new Response(null, { webSocket, status: 101 })`. */
|
|
48
|
+
webSocket?: CfWebSocket;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create the relay's WebSocket-upgrade handler. A real Workers `fetch` export calls this with the
|
|
52
|
+
* incoming `Upgrade` header value; on a valid WebSocket upgrade it creates a `WebSocketPair`,
|
|
53
|
+
* accepts the SERVER side, attaches it to `bridge` (so it starts participating in session
|
|
54
|
+
* pairing/bridging per `session-bridge.ts`), and returns the CLIENT side for the caller to hand
|
|
55
|
+
* back in the 101 response. Non-WebSocket requests return a 400 with no socket.
|
|
56
|
+
*/
|
|
57
|
+
export declare function createCloudflareRelayHandler(opts: CloudflareRelayAdapterOptions): (upgradeHeader: string | null) => UpgradeResult;
|
|
58
|
+
//# sourceMappingURL=cf-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cf-adapter.d.ts","sourceRoot":"","sources":["../src/cf-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,kBAAkB,EAAoB,MAAM,qBAAqB,CAAC;AAE3E,4FAA4F;AAC5F,MAAM,WAAW,WAAW;IAC1B,MAAM,IAAI,IAAI,CAAC;IACf,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAClF,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IAChG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED,sGAAsG;AACtG,MAAM,MAAM,eAAe,GAAG,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;AAElE,MAAM,MAAM,oBAAoB,GAAG,MAAM,eAAe,CAAC;AAEzD,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,kBAAkB,CAAC;IAC3B;;;OAGG;IACH,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;CAC5C;AAYD,MAAM,WAAW,aAAa;IAC5B,qFAAqF;IACrF,MAAM,EAAE,MAAM,CAAC;IACf,4GAA4G;IAC5G,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,6BAA6B,GAClC,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,KAAK,aAAa,CAuBjD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare Workers adapter (architecture/relay-e2ee.md § Channel API — "Cloudflare adapter |
|
|
3
|
+
* server | Relay server implementation hook for Cloudflare Workers"; § Purpose).
|
|
4
|
+
*
|
|
5
|
+
* Wraps a Cloudflare Workers `WebSocketPair` into the platform-agnostic `RelaySessionBridge`
|
|
6
|
+
* (`session-bridge.ts`) so a Workers `fetch` handler can accept a WebSocket upgrade and hand the
|
|
7
|
+
* server-side socket to the bridge with three lines of code. This module deliberately avoids a
|
|
8
|
+
* hard dependency on `@cloudflare/workers-types` (which would collide with this package's `"node"`
|
|
9
|
+
* ambient types and pull in a large type-only surface for a library package with zero runtime
|
|
10
|
+
* deps) — instead it declares the minimal STRUCTURAL shape it actually uses
|
|
11
|
+
* ({@link CfWebSocket}/{@link CfWebSocketPair}), which the real Workers runtime's objects satisfy
|
|
12
|
+
* naturally. A real deployment supplies the actual Workers globals; this adapter only needs
|
|
13
|
+
* `accept`/`send`/`addEventListener`/`close`.
|
|
14
|
+
*
|
|
15
|
+
* Hosted deployment/ops (wrangler config, the actual `fetch` export's `Request`/`Response`
|
|
16
|
+
* wiring) is explicitly out of scope for this task — see the task file § Out of scope. What's
|
|
17
|
+
* built here is the reusable bridging hook a `fetch` handler wires the upgrade through.
|
|
18
|
+
*/
|
|
19
|
+
import { RelaySessionBridge } from "./session-bridge.js";
|
|
20
|
+
/** Wrap a Workers-side `CfWebSocket` (already `.accept()`-ed) as the bridge's `RelaySocket`. */
|
|
21
|
+
function wrapCfSocket(ws) {
|
|
22
|
+
return {
|
|
23
|
+
send: (data) => ws.send(data),
|
|
24
|
+
onMessage: (handler) => ws.addEventListener("message", (ev) => handler(ev.data)),
|
|
25
|
+
onClose: (handler) => ws.addEventListener("close", (ev) => handler(ev.reason)),
|
|
26
|
+
close: (code, reason) => ws.close(code, reason),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Create the relay's WebSocket-upgrade handler. A real Workers `fetch` export calls this with the
|
|
31
|
+
* incoming `Upgrade` header value; on a valid WebSocket upgrade it creates a `WebSocketPair`,
|
|
32
|
+
* accepts the SERVER side, attaches it to `bridge` (so it starts participating in session
|
|
33
|
+
* pairing/bridging per `session-bridge.ts`), and returns the CLIENT side for the caller to hand
|
|
34
|
+
* back in the 101 response. Non-WebSocket requests return a 400 with no socket.
|
|
35
|
+
*/
|
|
36
|
+
export function createCloudflareRelayHandler(opts) {
|
|
37
|
+
const { bridge } = opts;
|
|
38
|
+
const createPair = opts.createWebSocketPair ??
|
|
39
|
+
(() => {
|
|
40
|
+
const Ctor = globalThis.WebSocketPair;
|
|
41
|
+
if (!Ctor) {
|
|
42
|
+
throw new Error("createCloudflareRelayHandler: no WebSocketPair available — inject `createWebSocketPair` outside a real Workers runtime");
|
|
43
|
+
}
|
|
44
|
+
return new Ctor();
|
|
45
|
+
});
|
|
46
|
+
return (upgradeHeader) => {
|
|
47
|
+
if (!upgradeHeader || upgradeHeader.toLowerCase() !== "websocket") {
|
|
48
|
+
return { status: 400 };
|
|
49
|
+
}
|
|
50
|
+
const [client, server] = createPair();
|
|
51
|
+
server.accept();
|
|
52
|
+
bridge.attach(wrapCfSocket(server));
|
|
53
|
+
return { status: 101, webSocket: client };
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=cf-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cf-adapter.js","sourceRoot":"","sources":["../src/cf-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,kBAAkB,EAAoB,MAAM,qBAAqB,CAAC;AAyB3E,gGAAgG;AAChG,SAAS,YAAY,CAAC,EAAe;IACnC,OAAO;QACL,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;QAC7B,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QAChF,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QAC9E,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC;KAChD,CAAC;AACJ,CAAC;AASD;;;;;;GAMG;AACH,MAAM,UAAU,4BAA4B,CAC1C,IAAmC;IAEnC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB,MAAM,UAAU,GACd,IAAI,CAAC,mBAAmB;QACxB,CAAC,GAAG,EAAE;YACJ,MAAM,IAAI,GAAI,UAA4D,CAAC,aAAa,CAAC;YACzF,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,KAAK,CACb,wHAAwH,CACzH,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,CAAC,CAAC,CAAC;IAEL,OAAO,CAAC,aAA4B,EAAiB,EAAE;QACrD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC;YAClE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;QACzB,CAAC;QACD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;QACtC,MAAM,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;QACpC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAC5C,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** Which side of the handshake a channel plays. */
|
|
2
|
+
export type ConnectionRole = "client" | "daemon";
|
|
3
|
+
/** Minimal transport a channel rides on: send/receive UTF-8 text frames over the relay link. */
|
|
4
|
+
export interface Transport {
|
|
5
|
+
send(data: string): void;
|
|
6
|
+
onMessage(handler: (data: string) => void): void;
|
|
7
|
+
onClose(handler: (reason?: string) => void): void;
|
|
8
|
+
close(): void;
|
|
9
|
+
}
|
|
10
|
+
/** Events an `EncryptedChannel` emits to its owner. */
|
|
11
|
+
export interface EncryptedChannelEvents {
|
|
12
|
+
/** Fired once the E2EE handshake completes and app messages may flow. */
|
|
13
|
+
onReady?: () => void;
|
|
14
|
+
/** Fired for each successfully decrypted+authenticated app message. */
|
|
15
|
+
onMessage?: (plaintext: string) => void;
|
|
16
|
+
/** Fired when the underlying transport closes. */
|
|
17
|
+
onClose?: (reason?: string) => void;
|
|
18
|
+
/** Fired when a received frame fails authentication (tampered/corrupt) — the message is dropped. */
|
|
19
|
+
onAuthError?: (error: unknown) => void;
|
|
20
|
+
}
|
|
21
|
+
/** Opaque attachment describing which relay session a channel is bound to. */
|
|
22
|
+
export interface RelaySessionAttachment {
|
|
23
|
+
sessionId: string;
|
|
24
|
+
}
|
|
25
|
+
export interface EncryptedChannel {
|
|
26
|
+
readonly role: ConnectionRole;
|
|
27
|
+
readonly attachment: RelaySessionAttachment;
|
|
28
|
+
/** True once the handshake has completed and `send` will actually transmit. */
|
|
29
|
+
readonly ready: boolean;
|
|
30
|
+
/** Encrypt + send an application message. Throws if called before the handshake completes. */
|
|
31
|
+
send(plaintext: string): void;
|
|
32
|
+
close(): void;
|
|
33
|
+
}
|
|
34
|
+
export interface CreateDaemonChannelOptions {
|
|
35
|
+
transport: Transport;
|
|
36
|
+
attachment: RelaySessionAttachment;
|
|
37
|
+
/**
|
|
38
|
+
* The daemon's persistent Curve25519 keypair (architecture/relay-e2ee.md § Data & Persistence —
|
|
39
|
+
* `daemon-keypair.json`). Used directly for ECDH: the client derives its shared key from this
|
|
40
|
+
* same public key (via the pairing offer) before the handshake even starts, so the daemon MUST
|
|
41
|
+
* use its persistent secret key here, not a per-connection ephemeral one. The secret never
|
|
42
|
+
* leaves the daemon process.
|
|
43
|
+
*/
|
|
44
|
+
daemonKeypair: {
|
|
45
|
+
publicKey: Uint8Array;
|
|
46
|
+
secretKey: Uint8Array;
|
|
47
|
+
};
|
|
48
|
+
events?: EncryptedChannelEvents;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Daemon side of an encrypted relay channel. The daemon waits for the client's `e2ee_hello`,
|
|
52
|
+
* derives the shared key from its own persistent secret key + the client's fresh ephemeral public
|
|
53
|
+
* key, replies with `e2ee_ready`, and only then becomes `ready` (refusing all app traffic before
|
|
54
|
+
* that — architecture/relay-e2ee.md § Error Handling).
|
|
55
|
+
*/
|
|
56
|
+
export declare function createDaemonChannel(opts: CreateDaemonChannelOptions): EncryptedChannel;
|
|
57
|
+
export interface CreateClientChannelOptions {
|
|
58
|
+
transport: Transport;
|
|
59
|
+
attachment: RelaySessionAttachment;
|
|
60
|
+
/** The daemon's persistent public key, obtained out-of-band via the pairing offer (task-003). */
|
|
61
|
+
daemonPublicKey: Uint8Array;
|
|
62
|
+
events?: EncryptedChannelEvents;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Client side of an encrypted relay channel. The client already knows the daemon's persistent
|
|
66
|
+
* public key (from the pairing offer), so it generates a FRESH ephemeral keypair, derives the
|
|
67
|
+
* shared key immediately, and sends `e2ee_hello`. It becomes `ready` only after the daemon
|
|
68
|
+
* confirms with `e2ee_ready` — mirroring the daemon's "no app traffic before handshake" gating on
|
|
69
|
+
* the client side too, for a genuinely symmetric API.
|
|
70
|
+
*/
|
|
71
|
+
export declare function createClientChannel(opts: CreateClientChannelOptions): EncryptedChannel;
|
|
72
|
+
//# sourceMappingURL=channel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAsBA,mDAAmD;AACnD,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEjD,gGAAgG;AAChG,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACjD,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClD,KAAK,IAAI,IAAI,CAAC;CACf;AAED,uDAAuD;AACvD,MAAM,WAAW,sBAAsB;IACrC,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,uEAAuE;IACvE,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,kDAAkD;IAClD,OAAO,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,oGAAoG;IACpG,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACxC;AAED,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAC5C,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,8FAA8F;IAC9F,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,KAAK,IAAI,IAAI,CAAC;CACf;AA+FD,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,sBAAsB,CAAC;IACnC;;;;;;OAMG;IACH,aAAa,EAAE;QAAE,SAAS,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,UAAU,CAAA;KAAE,CAAC;IAChE,MAAM,CAAC,EAAE,sBAAsB,CAAC;CACjC;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,0BAA0B,GAAG,gBAAgB,CAkDtF;AAED,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,sBAAsB,CAAC;IACnC,iGAAiG;IACjG,eAAe,EAAE,UAAU,CAAC;IAC5B,MAAM,CAAC,EAAE,sBAAsB,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,0BAA0B,GAAG,gBAAgB,CAkDtF"}
|
package/dist/channel.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relay encrypted channel primitives (architecture/relay-e2ee.md § Channel API, § Handshake
|
|
3
|
+
* frames, § Behavior). `createClientChannel` and `createDaemonChannel` expose an IDENTICAL API so
|
|
4
|
+
* the daemon and client share the same E2EE code path over a relay-provided transport.
|
|
5
|
+
*
|
|
6
|
+
* Handshake:
|
|
7
|
+
* client → daemon: e2ee_hello { ephemeralPublicKey } (client's FRESH ephemeral Curve25519 key)
|
|
8
|
+
* daemon → client: e2ee_ready (handshake acknowledgement)
|
|
9
|
+
* both: sharedKey = ECDH(localSecret, remotePublic) (Curve25519 box.before)
|
|
10
|
+
*
|
|
11
|
+
* Per-message wire format (after handshake):
|
|
12
|
+
* frame = base64( [24-byte random nonce] ++ box(plaintext, nonce, sharedKey) ) // XSalsa20-Poly1305
|
|
13
|
+
* receive → split nonce/ciphertext → box_open → reject (drop, never throw to the app) on auth failure.
|
|
14
|
+
*
|
|
15
|
+
* The daemon secret never leaves the daemon; the client keypair is ephemeral per connection, so
|
|
16
|
+
* there is no persistent client-side secret to steal. Session keys are fresh per session, so
|
|
17
|
+
* ciphertext cannot replay across sessions — but replay protection WITHIN a live session is not
|
|
18
|
+
* implemented (random nonces, no counter) per architecture/relay-e2ee.md § Behavior TODO(verify).
|
|
19
|
+
*/
|
|
20
|
+
import nacl from "tweetnacl";
|
|
21
|
+
import { decodeBase64, encodeBase64 } from "./base64.js";
|
|
22
|
+
function parseFrame(data) {
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(data);
|
|
25
|
+
if (!parsed || typeof parsed.type !== "string")
|
|
26
|
+
return null;
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const NONCE_LENGTH = 24; // XSalsa20-Poly1305 nonce size (nacl.box.nonceLength)
|
|
34
|
+
/** Encrypt `plaintext` under `sharedKey`, producing the wire frame `base64(nonce ++ ciphertext)`. */
|
|
35
|
+
function seal(plaintext, sharedKey) {
|
|
36
|
+
const nonce = nacl.randomBytes(NONCE_LENGTH);
|
|
37
|
+
const message = new TextEncoder().encode(plaintext);
|
|
38
|
+
const ciphertext = nacl.box.after(message, nonce, sharedKey);
|
|
39
|
+
const combined = new Uint8Array(nonce.length + ciphertext.length);
|
|
40
|
+
combined.set(nonce, 0);
|
|
41
|
+
combined.set(ciphertext, nonce.length);
|
|
42
|
+
return encodeBase64(combined);
|
|
43
|
+
}
|
|
44
|
+
/** Decrypt a `base64(nonce ++ ciphertext)` wire frame under `sharedKey`, or return `null` on auth failure. */
|
|
45
|
+
function open(frame, sharedKey) {
|
|
46
|
+
let combined;
|
|
47
|
+
try {
|
|
48
|
+
combined = decodeBase64(frame);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
if (combined.length < NONCE_LENGTH)
|
|
54
|
+
return null;
|
|
55
|
+
const nonce = combined.slice(0, NONCE_LENGTH);
|
|
56
|
+
const ciphertext = combined.slice(NONCE_LENGTH);
|
|
57
|
+
const opened = nacl.box.open.after(ciphertext, nonce, sharedKey);
|
|
58
|
+
return opened ? new TextDecoder().decode(opened) : null;
|
|
59
|
+
}
|
|
60
|
+
/** Shared app-frame plumbing once both sides agree on `sharedKey` — identical for client/daemon. */
|
|
61
|
+
function wireAppMessages(role, attachment, transport, events, getSharedKey, isReady) {
|
|
62
|
+
let closed = false;
|
|
63
|
+
transport.onClose((reason) => {
|
|
64
|
+
closed = true;
|
|
65
|
+
events.onClose?.(reason);
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
handleAppFrame(frame) {
|
|
69
|
+
if (closed)
|
|
70
|
+
return;
|
|
71
|
+
const sharedKey = getSharedKey();
|
|
72
|
+
if (!isReady() || !sharedKey)
|
|
73
|
+
return; // refuse ANY app message before handshake completes
|
|
74
|
+
const plaintext = open(frame.frame, sharedKey);
|
|
75
|
+
if (plaintext === null) {
|
|
76
|
+
events.onAuthError?.(new Error(`relay ${role} channel: message failed authentication`));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
events.onMessage?.(plaintext);
|
|
80
|
+
},
|
|
81
|
+
send(plaintext) {
|
|
82
|
+
if (closed)
|
|
83
|
+
throw new Error(`relay ${role} channel: cannot send after close()`);
|
|
84
|
+
const sharedKey = getSharedKey();
|
|
85
|
+
if (!isReady() || !sharedKey) {
|
|
86
|
+
throw new Error(`relay ${role} channel: cannot send before the E2EE handshake completes`);
|
|
87
|
+
}
|
|
88
|
+
transport.send(JSON.stringify({ type: "e2ee_app", frame: seal(plaintext, sharedKey) }));
|
|
89
|
+
},
|
|
90
|
+
close() {
|
|
91
|
+
if (closed)
|
|
92
|
+
return;
|
|
93
|
+
closed = true;
|
|
94
|
+
transport.close();
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Daemon side of an encrypted relay channel. The daemon waits for the client's `e2ee_hello`,
|
|
100
|
+
* derives the shared key from its own persistent secret key + the client's fresh ephemeral public
|
|
101
|
+
* key, replies with `e2ee_ready`, and only then becomes `ready` (refusing all app traffic before
|
|
102
|
+
* that — architecture/relay-e2ee.md § Error Handling).
|
|
103
|
+
*/
|
|
104
|
+
export function createDaemonChannel(opts) {
|
|
105
|
+
const { transport, attachment, daemonKeypair } = opts;
|
|
106
|
+
const events = opts.events ?? {};
|
|
107
|
+
let sharedKey = null;
|
|
108
|
+
let ready = false;
|
|
109
|
+
const plumbing = wireAppMessages("daemon", attachment, transport, events, () => sharedKey, () => ready);
|
|
110
|
+
transport.onMessage((data) => {
|
|
111
|
+
const frame = parseFrame(data);
|
|
112
|
+
if (!frame)
|
|
113
|
+
return; // ignore anything the relay/peer sends that isn't a recognized frame
|
|
114
|
+
if (frame.type === "e2ee_hello") {
|
|
115
|
+
if (ready)
|
|
116
|
+
return; // handshake already completed for this channel; ignore replays
|
|
117
|
+
let remotePublicKey;
|
|
118
|
+
try {
|
|
119
|
+
remotePublicKey = decodeBase64(frame.ephemeralPublicKey);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
sharedKey = nacl.box.before(remotePublicKey, daemonKeypair.secretKey);
|
|
125
|
+
ready = true;
|
|
126
|
+
transport.send(JSON.stringify({ type: "e2ee_ready" }));
|
|
127
|
+
events.onReady?.();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (frame.type === "e2ee_app") {
|
|
131
|
+
plumbing.handleAppFrame(frame);
|
|
132
|
+
}
|
|
133
|
+
// `e2ee_ready` is never sent to a daemon channel; ignore if it arrives.
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
role: "daemon",
|
|
137
|
+
attachment,
|
|
138
|
+
get ready() {
|
|
139
|
+
return ready;
|
|
140
|
+
},
|
|
141
|
+
send: plumbing.send,
|
|
142
|
+
close: plumbing.close,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Client side of an encrypted relay channel. The client already knows the daemon's persistent
|
|
147
|
+
* public key (from the pairing offer), so it generates a FRESH ephemeral keypair, derives the
|
|
148
|
+
* shared key immediately, and sends `e2ee_hello`. It becomes `ready` only after the daemon
|
|
149
|
+
* confirms with `e2ee_ready` — mirroring the daemon's "no app traffic before handshake" gating on
|
|
150
|
+
* the client side too, for a genuinely symmetric API.
|
|
151
|
+
*/
|
|
152
|
+
export function createClientChannel(opts) {
|
|
153
|
+
const { transport, attachment, daemonPublicKey } = opts;
|
|
154
|
+
const events = opts.events ?? {};
|
|
155
|
+
const ephemeral = nacl.box.keyPair();
|
|
156
|
+
const sharedKey = nacl.box.before(daemonPublicKey, ephemeral.secretKey);
|
|
157
|
+
let ready = false;
|
|
158
|
+
const plumbing = wireAppMessages("client", attachment, transport, events, () => sharedKey, () => ready);
|
|
159
|
+
transport.onMessage((data) => {
|
|
160
|
+
const frame = parseFrame(data);
|
|
161
|
+
if (!frame)
|
|
162
|
+
return;
|
|
163
|
+
if (frame.type === "e2ee_ready") {
|
|
164
|
+
if (ready)
|
|
165
|
+
return;
|
|
166
|
+
ready = true;
|
|
167
|
+
events.onReady?.();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (frame.type === "e2ee_app") {
|
|
171
|
+
plumbing.handleAppFrame(frame);
|
|
172
|
+
}
|
|
173
|
+
// `e2ee_hello` is never sent to a client channel; ignore if it arrives.
|
|
174
|
+
});
|
|
175
|
+
transport.send(JSON.stringify({
|
|
176
|
+
type: "e2ee_hello",
|
|
177
|
+
ephemeralPublicKey: encodeBase64(ephemeral.publicKey),
|
|
178
|
+
}));
|
|
179
|
+
return {
|
|
180
|
+
role: "client",
|
|
181
|
+
attachment,
|
|
182
|
+
get ready() {
|
|
183
|
+
return ready;
|
|
184
|
+
},
|
|
185
|
+
send: plumbing.send,
|
|
186
|
+
close: plumbing.close,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=channel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-knowledge relay session bridge (architecture/relay-e2ee.md § Purpose, § Channel API —
|
|
3
|
+
* "Cloudflare adapter", § Error Handling). This is the platform-agnostic bridging core shared by
|
|
4
|
+
* any relay server implementation (Cloudflare Workers adapter in `cf-adapter.ts`, or any other
|
|
5
|
+
* host): it pairs sockets by session id and forwards every frame **verbatim** between the (at
|
|
6
|
+
* most two) peers sharing a session id, without ever decrypting or even parsing app traffic.
|
|
7
|
+
*
|
|
8
|
+
* The bridge inspects ONLY the very first frame a socket sends, to detect the registration frame
|
|
9
|
+
* `{ type: "relay_register", sessionId }` (matching the daemon/client sides built in task-002/003).
|
|
10
|
+
* Every frame after that — including the `e2ee_hello`/`e2ee_ready` handshake and all `e2ee_app`
|
|
11
|
+
* ciphertext frames — is forwarded byte-for-byte without inspection. This is exactly the trust
|
|
12
|
+
* boundary the spec describes: "a compromised relay can see only metadata (IPs, timing, sizes,
|
|
13
|
+
* session ids, and the plaintext public keys in the handshake) — never message contents, and it
|
|
14
|
+
* cannot forge or inject commands."
|
|
15
|
+
*/
|
|
16
|
+
/** Minimal socket shape the bridge operates on — any transport satisfying this can be bridged. */
|
|
17
|
+
export interface RelaySocket {
|
|
18
|
+
send(data: string): void;
|
|
19
|
+
onMessage(handler: (data: string) => void): void;
|
|
20
|
+
onClose(handler: (reason?: string) => void): void;
|
|
21
|
+
close(code?: number, reason?: string): void;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Pairs relay-attached sockets by session id and forwards non-registration frames verbatim between
|
|
25
|
+
* every OTHER socket sharing that session id. One bridge instance serves an entire relay server
|
|
26
|
+
* (or Cloudflare Durable Object instance); `attach()` is called once per newly accepted connection.
|
|
27
|
+
*/
|
|
28
|
+
export declare class RelaySessionBridge {
|
|
29
|
+
private readonly sessions;
|
|
30
|
+
/**
|
|
31
|
+
* Attach a raw socket. Its first frame MUST be a registration frame or it is silently ignored
|
|
32
|
+
* (never forwarded, never crashes the bridge) — an unregistered socket receives nothing and
|
|
33
|
+
* forwards nothing.
|
|
34
|
+
*/
|
|
35
|
+
attach(socket: RelaySocket): void;
|
|
36
|
+
/** Number of sockets currently registered under `sessionId` (observability / test helper). */
|
|
37
|
+
peerCount(sessionId: string): number;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=session-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-bridge.d.ts","sourceRoot":"","sources":["../src/session-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,kGAAkG;AAClG,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACjD,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAClD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAcD;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuC;IAEhE;;;;OAIG;IACH,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IA6BjC,8FAA8F;IAC9F,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;CAGrC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-knowledge relay session bridge (architecture/relay-e2ee.md § Purpose, § Channel API —
|
|
3
|
+
* "Cloudflare adapter", § Error Handling). This is the platform-agnostic bridging core shared by
|
|
4
|
+
* any relay server implementation (Cloudflare Workers adapter in `cf-adapter.ts`, or any other
|
|
5
|
+
* host): it pairs sockets by session id and forwards every frame **verbatim** between the (at
|
|
6
|
+
* most two) peers sharing a session id, without ever decrypting or even parsing app traffic.
|
|
7
|
+
*
|
|
8
|
+
* The bridge inspects ONLY the very first frame a socket sends, to detect the registration frame
|
|
9
|
+
* `{ type: "relay_register", sessionId }` (matching the daemon/client sides built in task-002/003).
|
|
10
|
+
* Every frame after that — including the `e2ee_hello`/`e2ee_ready` handshake and all `e2ee_app`
|
|
11
|
+
* ciphertext frames — is forwarded byte-for-byte without inspection. This is exactly the trust
|
|
12
|
+
* boundary the spec describes: "a compromised relay can see only metadata (IPs, timing, sizes,
|
|
13
|
+
* session ids, and the plaintext public keys in the handshake) — never message contents, and it
|
|
14
|
+
* cannot forge or inject commands."
|
|
15
|
+
*/
|
|
16
|
+
function tryParseSessionId(data) {
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(data);
|
|
19
|
+
if (parsed.type === "relay_register" && typeof parsed.sessionId === "string" && parsed.sessionId) {
|
|
20
|
+
return parsed.sessionId;
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Pairs relay-attached sockets by session id and forwards non-registration frames verbatim between
|
|
30
|
+
* every OTHER socket sharing that session id. One bridge instance serves an entire relay server
|
|
31
|
+
* (or Cloudflare Durable Object instance); `attach()` is called once per newly accepted connection.
|
|
32
|
+
*/
|
|
33
|
+
export class RelaySessionBridge {
|
|
34
|
+
sessions = new Map();
|
|
35
|
+
/**
|
|
36
|
+
* Attach a raw socket. Its first frame MUST be a registration frame or it is silently ignored
|
|
37
|
+
* (never forwarded, never crashes the bridge) — an unregistered socket receives nothing and
|
|
38
|
+
* forwards nothing.
|
|
39
|
+
*/
|
|
40
|
+
attach(socket) {
|
|
41
|
+
let sessionId = null;
|
|
42
|
+
socket.onMessage((data) => {
|
|
43
|
+
if (sessionId === null) {
|
|
44
|
+
const parsedSessionId = tryParseSessionId(data);
|
|
45
|
+
if (!parsedSessionId)
|
|
46
|
+
return; // not a registration frame; ignore malformed/unexpected input
|
|
47
|
+
sessionId = parsedSessionId;
|
|
48
|
+
const peers = this.sessions.get(sessionId) ?? new Set();
|
|
49
|
+
peers.add(socket);
|
|
50
|
+
this.sessions.set(sessionId, peers);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
// Forward verbatim to every OTHER socket sharing this session id. No JSON.parse, no
|
|
54
|
+
// inspection — this frame may be the E2EE handshake or opaque ciphertext.
|
|
55
|
+
for (const peer of this.sessions.get(sessionId) ?? []) {
|
|
56
|
+
if (peer !== socket)
|
|
57
|
+
peer.send(data);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
socket.onClose(() => {
|
|
61
|
+
if (sessionId === null)
|
|
62
|
+
return;
|
|
63
|
+
const peers = this.sessions.get(sessionId);
|
|
64
|
+
if (!peers)
|
|
65
|
+
return;
|
|
66
|
+
peers.delete(socket);
|
|
67
|
+
if (peers.size === 0)
|
|
68
|
+
this.sessions.delete(sessionId);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/** Number of sockets currently registered under `sessionId` (observability / test helper). */
|
|
72
|
+
peerCount(sessionId) {
|
|
73
|
+
return this.sessions.get(sessionId)?.size ?? 0;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=session-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-bridge.js","sourceRoot":"","sources":["../src/session-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAUH,SAAS,iBAAiB,CAAC,IAAY;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAA4C,CAAC;QAC3E,IAAI,MAAM,CAAC,IAAI,KAAK,gBAAgB,IAAI,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACjG,OAAO,MAAM,CAAC,SAAS,CAAC;QAC1B,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,kBAAkB;IACZ,QAAQ,GAAG,IAAI,GAAG,EAA4B,CAAC;IAEhE;;;;OAIG;IACH,MAAM,CAAC,MAAmB;QACxB,IAAI,SAAS,GAAkB,IAAI,CAAC;QAEpC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvB,MAAM,eAAe,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;gBAChD,IAAI,CAAC,eAAe;oBAAE,OAAO,CAAC,8DAA8D;gBAC5F,SAAS,GAAG,eAAe,CAAC;gBAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,GAAG,EAAe,CAAC;gBACrE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAClB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;gBACpC,OAAO;YACT,CAAC;YACD,oFAAoF;YACpF,0EAA0E;YAC1E,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtD,IAAI,IAAI,KAAK,MAAM;oBAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvC,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE;YAClB,IAAI,SAAS,KAAK,IAAI;gBAAE,OAAO;YAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK;gBAAE,OAAO;YACnB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACrB,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;gBAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACxD,CAAC,CAAC,CAAC;IACL,CAAC;IAED,8FAA8F;IAC9F,SAAS,CAAC,SAAiB;QACzB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC;IACjD,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@av-pi-studio/relay",
|
|
3
|
+
"version": "0.0.8",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -b",
|
|
18
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"tweetnacl": "^1.0.3"
|
|
22
|
+
}
|
|
23
|
+
}
|