@lamplitisles/dsh-nanocodex 0.1.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +65 -0
- package/NOTICE +2 -0
- package/README.md +182 -0
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/cordis.patch.yml +52 -0
- package/dist/index.d.ts +435 -0
- package/dist/index.js +3405 -0
- package/dist/standard-preset.d.ts +7 -0
- package/dist/standard-preset.js +25 -0
- package/engine-release.json +14 -0
- package/package.json +119 -0
- package/presets/standard/agent.cordis.yml +6 -0
- package/presets/standard/preset.yml +2 -0
- package/vendor/nanocodex/README.md +1344 -0
- package/vendor/nanocodex/actions/events.d.mts +10 -0
- package/vendor/nanocodex/actions/events.mjs +163 -0
- package/vendor/nanocodex/actions/index.d.mts +13 -0
- package/vendor/nanocodex/actions/index.mjs +35 -0
- package/vendor/nanocodex/actions/session.d.mts +66 -0
- package/vendor/nanocodex/actions/session.mjs +59 -0
- package/vendor/nanocodex/actions/turn.d.mts +59 -0
- package/vendor/nanocodex/actions/turn.mjs +37 -0
- package/vendor/nanocodex/actions/voice.d.mts +22 -0
- package/vendor/nanocodex/actions/voice.mjs +50 -0
- package/vendor/nanocodex/browser/Agent.d.mts +55 -0
- package/vendor/nanocodex/browser/Agent.mjs +11 -0
- package/vendor/nanocodex/browser/ChatGptSubscription.d.mts +7 -0
- package/vendor/nanocodex/browser/ChatGptSubscription.mjs +19 -0
- package/vendor/nanocodex/browser/InlineAgent.mjs +266 -0
- package/vendor/nanocodex/browser/Transport.d.mts +74 -0
- package/vendor/nanocodex/browser/Transport.mjs +61 -0
- package/vendor/nanocodex/browser/Voice.d.mts +71 -0
- package/vendor/nanocodex/browser/Voice.mjs +291 -0
- package/vendor/nanocodex/browser/VoiceSession.mjs +688 -0
- package/vendor/nanocodex/browser/WorkerAgent.d.mts +65 -0
- package/vendor/nanocodex/browser/WorkerAgent.mjs +1472 -0
- package/vendor/nanocodex/browser/agent.worker.mjs +3 -0
- package/vendor/nanocodex/browser/config.d.mts +36 -0
- package/vendor/nanocodex/browser/config.mjs +439 -0
- package/vendor/nanocodex/browser/engine.mjs +13 -0
- package/vendor/nanocodex/browser/harness.mjs +55 -0
- package/vendor/nanocodex/browser/host.d.mts +83 -0
- package/vendor/nanocodex/browser/host.mjs +555 -0
- package/vendor/nanocodex/browser/hostManagedWebSocket.d.mts +14 -0
- package/vendor/nanocodex/browser/hostManagedWebSocket.mjs +110 -0
- package/vendor/nanocodex/browser/index.d.mts +92 -0
- package/vendor/nanocodex/browser/index.mjs +23 -0
- package/vendor/nanocodex/browser/indexeddb-durability-store.mjs +197 -0
- package/vendor/nanocodex/browser/workspace.d.mts +16 -0
- package/vendor/nanocodex/browser/workspace.mjs +107 -0
- package/vendor/nanocodex/cloud/Client.d.mts +83 -0
- package/vendor/nanocodex/cloud/Client.mjs +231 -0
- package/vendor/nanocodex/cloud/Decorator.d.mts +31 -0
- package/vendor/nanocodex/cloud/Decorator.mjs +37 -0
- package/vendor/nanocodex/cloud/Dialog.d.mts +113 -0
- package/vendor/nanocodex/cloud/Dialog.mjs +366 -0
- package/vendor/nanocodex/cloud/Errors.d.mts +22 -0
- package/vendor/nanocodex/cloud/Errors.mjs +39 -0
- package/vendor/nanocodex/cloud/Principal.d.mts +26 -0
- package/vendor/nanocodex/cloud/Principal.mjs +88 -0
- package/vendor/nanocodex/cloud/RemoteProvider.mjs +88 -0
- package/vendor/nanocodex/cloud/Transport.d.mts +47 -0
- package/vendor/nanocodex/cloud/Transport.mjs +454 -0
- package/vendor/nanocodex/cloud/actions/account.d.mts +9 -0
- package/vendor/nanocodex/cloud/actions/account.mjs +19 -0
- package/vendor/nanocodex/cloud/actions/agent.d.mts +18 -0
- package/vendor/nanocodex/cloud/actions/agent.mjs +428 -0
- package/vendor/nanocodex/cloud/actions/connection.d.mts +133 -0
- package/vendor/nanocodex/cloud/actions/connection.mjs +580 -0
- package/vendor/nanocodex/cloud/actions/grant.d.mts +10 -0
- package/vendor/nanocodex/cloud/actions/grant.mjs +12 -0
- package/vendor/nanocodex/cloud/actions/index.d.mts +7 -0
- package/vendor/nanocodex/cloud/actions/index.mjs +7 -0
- package/vendor/nanocodex/cloud/actions/machineUsd.d.mts +23 -0
- package/vendor/nanocodex/cloud/actions/machineUsd.mjs +37 -0
- package/vendor/nanocodex/cloud/actions/model.d.mts +12 -0
- package/vendor/nanocodex/cloud/actions/model.mjs +50 -0
- package/vendor/nanocodex/cloud/actions/mpp.d.mts +28 -0
- package/vendor/nanocodex/cloud/actions/mpp.mjs +39 -0
- package/vendor/nanocodex/cloud/index.d.mts +30 -0
- package/vendor/nanocodex/cloud/index.mjs +9 -0
- package/vendor/nanocodex/cloud/internal.mjs +533 -0
- package/vendor/nanocodex/cloud/mercator.mjs +108 -0
- package/vendor/nanocodex/cloud/server/HostPrincipal.d.mts +34 -0
- package/vendor/nanocodex/cloud/server/HostPrincipal.mjs +202 -0
- package/vendor/nanocodex/cloud/server/index.d.mts +1 -0
- package/vendor/nanocodex/cloud/server/index.mjs +1 -0
- package/vendor/nanocodex/cloud/types.d.mts +211 -0
- package/vendor/nanocodex/cloudflare/Agent.d.mts +133 -0
- package/vendor/nanocodex/cloudflare/Agent.mjs +811 -0
- package/vendor/nanocodex/cloudflare/egress-subject.mjs +19 -0
- package/vendor/nanocodex/cloudflare/egress.d.mts +41 -0
- package/vendor/nanocodex/cloudflare/egress.mjs +119 -0
- package/vendor/nanocodex/cloudflare/event-socket.mjs +316 -0
- package/vendor/nanocodex/cloudflare/index.d.mts +7 -0
- package/vendor/nanocodex/cloudflare/index.mjs +6 -0
- package/vendor/nanocodex/host/Agent.d.mts +55 -0
- package/vendor/nanocodex/host/Agent.mjs +1 -0
- package/vendor/nanocodex/host/index.d.mts +82 -0
- package/vendor/nanocodex/host/index.mjs +10 -0
- package/vendor/nanocodex/index.d.mts +81 -0
- package/vendor/nanocodex/index.mjs +12 -0
- package/vendor/nanocodex/internal.mjs +1275 -0
- package/vendor/nanocodex/managed/Agent.d.mts +380 -0
- package/vendor/nanocodex/managed/Agent.mjs +1694 -0
- package/vendor/nanocodex/managed/ManagedError.d.mts +9 -0
- package/vendor/nanocodex/managed/ManagedError.mjs +8 -0
- package/vendor/nanocodex/managed/README.md +241 -0
- package/vendor/nanocodex/managed/Voice.mjs +202 -0
- package/vendor/nanocodex/managed/index.d.mts +20 -0
- package/vendor/nanocodex/managed/index.mjs +2 -0
- package/vendor/nanocodex/managed/internal.mjs +119 -0
- package/vendor/nanocodex/node/Agent.d.mts +50 -0
- package/vendor/nanocodex/node/Agent.mjs +203 -0
- package/vendor/nanocodex/node/ChatGptSubscription.d.mts +9 -0
- package/vendor/nanocodex/node/ChatGptSubscription.mjs +17 -0
- package/vendor/nanocodex/node/Transport.d.mts +44 -0
- package/vendor/nanocodex/node/Transport.mjs +46 -0
- package/vendor/nanocodex/node/host.mjs +731 -0
- package/vendor/nanocodex/node/index.d.mts +73 -0
- package/vendor/nanocodex/node/index.mjs +17 -0
- package/vendor/nanocodex/node/workspace.d.mts +10 -0
- package/vendor/nanocodex/node/workspace.mjs +198 -0
- package/vendor/nanocodex/package.json +200 -0
- package/vendor/nanocodex/pkg-node/nanocodex.d.ts +675 -0
- package/vendor/nanocodex/pkg-node/nanocodex.js +2628 -0
- package/vendor/nanocodex/pkg-node/nanocodex_bg.wasm.d.ts +105 -0
- package/vendor/nanocodex/pkg-node/package.json +1 -0
- package/vendor/nanocodex/pkg-web/.nanocodex-bindgen-stamp +6 -0
- package/vendor/nanocodex/pkg-web/nanocodex-build.json +1 -0
- package/vendor/nanocodex/pkg-web/nanocodex.d.ts +805 -0
- package/vendor/nanocodex/pkg-web/nanocodex.js +2714 -0
- package/vendor/nanocodex/pkg-web/nanocodex_bg.js +2615 -0
- package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm +0 -0
- package/vendor/nanocodex/pkg-web/nanocodex_bg.wasm.d.ts +105 -0
- package/vendor/nanocodex/pkg-web/nanocodex_worker.js +9 -0
- package/vendor/nanocodex/pkg-web/package.json +1 -0
- package/vendor/nanocodex/runtime/chatgpt-subscription.mjs +212 -0
- package/vendor/nanocodex/runtime/cloudflare-durability-store.d.mts +26 -0
- package/vendor/nanocodex/runtime/cloudflare-durability-store.mjs +168 -0
- package/vendor/nanocodex/runtime/code-evaluator.worker.mjs +137 -0
- package/vendor/nanocodex/runtime/code-runtime.mjs +1 -0
- package/vendor/nanocodex/runtime/durability-store.d.mts +85 -0
- package/vendor/nanocodex/runtime/durability-store.mjs +631 -0
- package/vendor/nanocodex/runtime/durability.mjs +153 -0
- package/vendor/nanocodex/runtime/managed-transport.mjs +460 -0
- package/vendor/nanocodex/runtime/mcp-runtime.mjs +534 -0
- package/vendor/nanocodex/runtime/postgres-durability-store.d.mts +64 -0
- package/vendor/nanocodex/runtime/postgres-durability-store.mjs +532 -0
- package/vendor/nanocodex/runtime/quickjs-evaluator.d.mts +17 -0
- package/vendor/nanocodex/runtime/quickjs-evaluator.mjs +236 -0
- package/vendor/nanocodex/runtime/responses-transport.mjs +22 -0
- package/vendor/nanocodex/runtime/subagents.d.mts +107 -0
- package/vendor/nanocodex/runtime/subagents.mjs +54 -0
- package/vendor/nanocodex/runtime/subscription-store.d.mts +8 -0
- package/vendor/nanocodex/runtime/subscription-store.mjs +42 -0
- package/vendor/nanocodex/runtime/tempo-provider.d.mts +125 -0
- package/vendor/nanocodex/runtime/tempo-provider.mjs +264 -0
- package/vendor/nanocodex/runtime/tool-configuration.mjs +1 -0
- package/vendor/nanocodex/runtime/tool-router.mjs +1 -0
- package/vendor/nanocodex/runtime/utf8.mjs +1 -0
- package/vendor/nanocodex/runtime/worker-evaluator.mjs +162 -0
- package/vendor/nanocodex/runtime/workspace.d.mts +1 -0
- package/vendor/nanocodex/runtime/workspace.mjs +1 -0
- package/vendor/nanocodex/tools/Tools.d.mts +56 -0
- package/vendor/nanocodex/tools/Tools.mjs +136 -0
- package/vendor/nanocodex/tools/artifact.d.mts +1 -0
- package/vendor/nanocodex/tools/artifact.mjs +1 -0
- package/vendor/nanocodex/tools/attachment.mjs +1 -0
- package/vendor/nanocodex/tools/bash.d.mts +1 -0
- package/vendor/nanocodex/tools/bash.mjs +1 -0
- package/vendor/nanocodex/tools/browser/accountInfo.mjs +795 -0
- package/vendor/nanocodex/tools/browser/browserBuffer.mjs +18 -0
- package/vendor/nanocodex/tools/browser/browserCompiler.mjs +155 -0
- package/vendor/nanocodex/tools/browser/browserEgress.mjs +161 -0
- package/vendor/nanocodex/tools/browser/browserPython.mjs +133 -0
- package/vendor/nanocodex/tools/browser/browserShell.mjs +1075 -0
- package/vendor/nanocodex/tools/browser/browserSprintf.mjs +4 -0
- package/vendor/nanocodex/tools/browser/browserSsh.mjs +201 -0
- package/vendor/nanocodex/tools/browser/browserZlib.mjs +136 -0
- package/vendor/nanocodex/tools/browser/compiler.worker.mjs +160 -0
- package/vendor/nanocodex/tools/browser/devTunnelsSshBrowser.mjs +13 -0
- package/vendor/nanocodex/tools/browser/index.d.mts +209 -0
- package/vendor/nanocodex/tools/browser/index.mjs +174 -0
- package/vendor/nanocodex/tools/browser/opfsGit.mjs +248 -0
- package/vendor/nanocodex/tools/browser/python.worker.mjs +114 -0
- package/vendor/nanocodex/tools/browser/threadGit.mjs +197 -0
- package/vendor/nanocodex/tools/browser/unsupportedNodeRsa.mjs +5 -0
- package/vendor/nanocodex/tools/browser/workspace.mjs +83 -0
- package/vendor/nanocodex/tools/dataset.d.mts +1 -0
- package/vendor/nanocodex/tools/dataset.mjs +1 -0
- package/vendor/nanocodex/tools/datasetContract.mjs +1 -0
- package/vendor/nanocodex/tools/datasetEngine.mjs +1 -0
- package/vendor/nanocodex/tools/hostedCatalog.d.mts +1 -0
- package/vendor/nanocodex/tools/hostedCatalog.mjs +1 -0
- package/vendor/nanocodex/tools/index.d.mts +49 -0
- package/vendor/nanocodex/tools/index.mjs +19 -0
- package/vendor/nanocodex/tools/namedTool.mjs +1 -0
- package/vendor/nanocodex/tools/repository-workspace.d.mts +1 -0
- package/vendor/nanocodex/tools/repository-workspace.mjs +1 -0
- package/vendor/nanocodex/tools/ssh.d.mts +1 -0
- package/vendor/nanocodex/tools/ssh.mjs +1 -0
- package/vendor/nanocodex/tools/standard.mjs +1 -0
- package/vendor/nanocodex/tools/standardDescriptions.mjs +1 -0
- package/vendor/nanocodex/types.d.mts +663 -0
- package/vendor/nanocodex/wasm.d.mts +4 -0
- package/vendor/nanocodex/worker/ChatGptSubscription.d.mts +9 -0
- package/vendor/nanocodex/worker/ChatGptSubscription.mjs +29 -0
- package/vendor/nanocodex/worker/index.d.mts +18 -0
- package/vendor/nanocodex/worker/index.mjs +5 -0
- package/vendor/nanocodex-tools/README.md +65 -0
- package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.d.ts +7 -0
- package/vendor/nanocodex-tools/dist/hosted/app-tool-catalog.js +14 -0
- package/vendor/nanocodex-tools/dist/hosted/broker-core.d.ts +172 -0
- package/vendor/nanocodex-tools/dist/hosted/broker-core.js +1278 -0
- package/vendor/nanocodex-tools/dist/hosted/index.d.ts +3 -0
- package/vendor/nanocodex-tools/dist/hosted/index.js +3 -0
- package/vendor/nanocodex-tools/dist/hosted/protocol.d.ts +120 -0
- package/vendor/nanocodex-tools/dist/hosted/protocol.js +415 -0
- package/vendor/nanocodex-tools/dist/index.d.ts +19 -0
- package/vendor/nanocodex-tools/dist/index.js +14 -0
- package/vendor/nanocodex-tools/dist/memory.d.ts +204 -0
- package/vendor/nanocodex-tools/dist/memory.js +411 -0
- package/vendor/nanocodex-tools/dist/namespace.d.ts +87 -0
- package/vendor/nanocodex-tools/dist/namespace.js +338 -0
- package/vendor/nanocodex-tools/dist/repository-archive.d.ts +4 -0
- package/vendor/nanocodex-tools/dist/repository-archive.js +104 -0
- package/vendor/nanocodex-tools/dist/runtime.d.ts +30 -0
- package/vendor/nanocodex-tools/dist/runtime.js +37 -0
- package/vendor/nanocodex-tools/dist/session.d.ts +167 -0
- package/vendor/nanocodex-tools/dist/session.js +286 -0
- package/vendor/nanocodex-tools/dist/shell.d.ts +51 -0
- package/vendor/nanocodex-tools/dist/shell.js +553 -0
- package/vendor/nanocodex-tools/dist/ssh.d.ts +29 -0
- package/vendor/nanocodex-tools/dist/ssh.js +66 -0
- package/vendor/nanocodex-tools/dist/workspace.d.ts +45 -0
- package/vendor/nanocodex-tools/dist/workspace.js +237 -0
- package/vendor/nanocodex-tools/package.json +122 -0
- package/vendor/nanocodex-tools/runtime/code-runtime.mjs +817 -0
- package/vendor/nanocodex-tools/runtime/tool-configuration.mjs +50 -0
- package/vendor/nanocodex-tools/runtime/tool-router.mjs +730 -0
- package/vendor/nanocodex-tools/runtime/utf8.d.mts +2 -0
- package/vendor/nanocodex-tools/runtime/utf8.mjs +25 -0
- package/vendor/nanocodex-tools/tools/artifact.d.mts +69 -0
- package/vendor/nanocodex-tools/tools/artifact.mjs +270 -0
- package/vendor/nanocodex-tools/tools/attachment.mjs +603 -0
- package/vendor/nanocodex-tools/tools/bash.d.mts +90 -0
- package/vendor/nanocodex-tools/tools/bash.mjs +742 -0
- package/vendor/nanocodex-tools/tools/dataset.d.mts +9 -0
- package/vendor/nanocodex-tools/tools/dataset.mjs +47 -0
- package/vendor/nanocodex-tools/tools/datasetContract.mjs +54 -0
- package/vendor/nanocodex-tools/tools/datasetEngine.mjs +1167 -0
- package/vendor/nanocodex-tools/tools/execution-contract.d.mts +5 -0
- package/vendor/nanocodex-tools/tools/execution-contract.mjs +63 -0
- package/vendor/nanocodex-tools/tools/hostedCatalog.d.mts +20 -0
- package/vendor/nanocodex-tools/tools/hostedCatalog.mjs +67 -0
- package/vendor/nanocodex-tools/tools/hostedMachine.d.mts +10 -0
- package/vendor/nanocodex-tools/tools/hostedMachine.mjs +56 -0
- package/vendor/nanocodex-tools/tools/just-bash-browser.d.mts +1 -0
- package/vendor/nanocodex-tools/tools/just-bash-browser.mjs +1 -0
- package/vendor/nanocodex-tools/tools/namedTool.d.mts +3 -0
- package/vendor/nanocodex-tools/tools/namedTool.mjs +3 -0
- package/vendor/nanocodex-tools/tools/nodeProcess.d.mts +10 -0
- package/vendor/nanocodex-tools/tools/nodeProcess.mjs +314 -0
- package/vendor/nanocodex-tools/tools/processOutput.mjs +56 -0
- package/vendor/nanocodex-tools/tools/repository-workspace.d.mts +55 -0
- package/vendor/nanocodex-tools/tools/repository-workspace.mjs +397 -0
- package/vendor/nanocodex-tools/tools/ssh.d.mts +56 -0
- package/vendor/nanocodex-tools/tools/ssh.mjs +503 -0
- package/vendor/nanocodex-tools/tools/standard.mjs +458 -0
- package/vendor/nanocodex-tools/tools/standardDescriptions.mjs +3 -0
- package/vendor/nanocodex-tools/tools/types.d.mts +83 -0
- package/vendor/nanocodex-tools/tools/workspace.d.mts +25 -0
- package/vendor/nanocodex-tools/tools/workspace.mjs +282 -0
- package/vendor/nanocodex-tools/tools/x.d.mts +30 -0
- package/vendor/nanocodex-tools/tools/x.mjs +91 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { DialogBusyError, UserRejectedRequestError } from "./Errors.mjs";
|
|
2
|
+
|
|
3
|
+
export const DEFAULT_HOST = "https://nanocodex.gakonst.workers.dev/connect-dialog/";
|
|
4
|
+
|
|
5
|
+
const iframeInstances = new Map();
|
|
6
|
+
const popupInstances = new Map();
|
|
7
|
+
|
|
8
|
+
export function from(parameters) {
|
|
9
|
+
if (!parameters || typeof parameters !== "object") {
|
|
10
|
+
throw new TypeError("Dialog.from requires parameters");
|
|
11
|
+
}
|
|
12
|
+
if (typeof parameters.setup !== "function") {
|
|
13
|
+
throw new TypeError("Dialog.from requires setup");
|
|
14
|
+
}
|
|
15
|
+
return Object.freeze({
|
|
16
|
+
key: requiredString(parameters.key, "dialog key"),
|
|
17
|
+
name: requiredString(parameters.name, "dialog name"),
|
|
18
|
+
type: requiredString(parameters.type, "dialog type"),
|
|
19
|
+
setup: parameters.setup,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function iframe(options = {}) {
|
|
24
|
+
const host = new URL(options.host ?? DEFAULT_HOST).toString();
|
|
25
|
+
return from({
|
|
26
|
+
key: options.key ?? "nanocodex-iframe",
|
|
27
|
+
name: options.name ?? "Nanocodex Connect",
|
|
28
|
+
type: "iframe",
|
|
29
|
+
setup({ appId }) {
|
|
30
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
31
|
+
return {
|
|
32
|
+
host,
|
|
33
|
+
async open() {
|
|
34
|
+
throw new Error("The Nanocodex iframe dialog requires a browser");
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const source = dialogUrl(host, "iframe", appId);
|
|
39
|
+
let instance = iframeInstances.get(source);
|
|
40
|
+
if (!instance) {
|
|
41
|
+
instance = createIframeInstance(source);
|
|
42
|
+
iframeInstances.set(source, instance);
|
|
43
|
+
}
|
|
44
|
+
return instance;
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function popup(options = {}) {
|
|
50
|
+
const host = new URL(options.host ?? DEFAULT_HOST).toString();
|
|
51
|
+
return from({
|
|
52
|
+
key: options.key ?? "nanocodex-popup",
|
|
53
|
+
name: options.name ?? "Nanocodex Connect",
|
|
54
|
+
type: "popup",
|
|
55
|
+
setup({ appId }) {
|
|
56
|
+
if (typeof window === "undefined") {
|
|
57
|
+
return {
|
|
58
|
+
host,
|
|
59
|
+
async open() {
|
|
60
|
+
throw new Error("The Nanocodex popup dialog requires a browser");
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const source = dialogUrl(host, "popup", appId);
|
|
65
|
+
let instance = popupInstances.get(source);
|
|
66
|
+
if (!instance) {
|
|
67
|
+
instance = createPopupInstance(source, options);
|
|
68
|
+
popupInstances.set(source, instance);
|
|
69
|
+
}
|
|
70
|
+
return instance;
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function memory(options = {}) {
|
|
76
|
+
return from({
|
|
77
|
+
key: options.key ?? "nanocodex-memory",
|
|
78
|
+
name: options.name ?? "Nanocodex Connect playground",
|
|
79
|
+
type: "memory",
|
|
80
|
+
setup() {
|
|
81
|
+
const listeners = new Set();
|
|
82
|
+
let pending;
|
|
83
|
+
let snapshot;
|
|
84
|
+
|
|
85
|
+
function publish(value) {
|
|
86
|
+
snapshot = value;
|
|
87
|
+
for (const listener of [...listeners]) listener();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
host: options.host ?? "https://connect.nanocodex.xyz",
|
|
92
|
+
open(request) {
|
|
93
|
+
if (pending) return Promise.reject(new DialogBusyError());
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
95
|
+
pending = { reject, request, resolve };
|
|
96
|
+
publish(Object.freeze(request));
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
getRequest() {
|
|
100
|
+
return snapshot;
|
|
101
|
+
},
|
|
102
|
+
subscribe(listener) {
|
|
103
|
+
if (typeof listener !== "function") {
|
|
104
|
+
throw new TypeError("dialog subscription requires a listener");
|
|
105
|
+
}
|
|
106
|
+
listeners.add(listener);
|
|
107
|
+
return () => listeners.delete(listener);
|
|
108
|
+
},
|
|
109
|
+
respond(result) {
|
|
110
|
+
if (!pending) throw new Error("The Nanocodex dialog has no pending request");
|
|
111
|
+
const current = pending;
|
|
112
|
+
pending = undefined;
|
|
113
|
+
publish(undefined);
|
|
114
|
+
current.resolve(result);
|
|
115
|
+
},
|
|
116
|
+
reject(error = new UserRejectedRequestError()) {
|
|
117
|
+
if (!pending) throw new Error("The Nanocodex dialog has no pending request");
|
|
118
|
+
const current = pending;
|
|
119
|
+
pending = undefined;
|
|
120
|
+
publish(undefined);
|
|
121
|
+
current.reject(error);
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function createIframeInstance(host) {
|
|
129
|
+
let active;
|
|
130
|
+
let frame;
|
|
131
|
+
let modal;
|
|
132
|
+
let ready;
|
|
133
|
+
let walletFrame;
|
|
134
|
+
let walletHost;
|
|
135
|
+
let walletModal;
|
|
136
|
+
let walletReady;
|
|
137
|
+
let walletStale = false;
|
|
138
|
+
let walletVisible = false;
|
|
139
|
+
|
|
140
|
+
function mount() {
|
|
141
|
+
if (frame && modal) return;
|
|
142
|
+
modal = document.createElement("dialog");
|
|
143
|
+
modal.setAttribute("aria-label", "Nanocodex Connect permissions");
|
|
144
|
+
modal.style.cssText = "border:0;padding:0;background:transparent;max-width:none;max-height:none";
|
|
145
|
+
modal.addEventListener("cancel", (event) => {
|
|
146
|
+
event.preventDefault();
|
|
147
|
+
rejectActive(new UserRejectedRequestError());
|
|
148
|
+
});
|
|
149
|
+
modal.addEventListener("close", () => {
|
|
150
|
+
if (active) rejectActive(new UserRejectedRequestError());
|
|
151
|
+
});
|
|
152
|
+
frame = document.createElement("iframe");
|
|
153
|
+
frame.dataset.testid = "nanocodex-connect-dialog";
|
|
154
|
+
frame.title = "Nanocodex Connect permissions";
|
|
155
|
+
frame.src = host;
|
|
156
|
+
frame.tabIndex = -1;
|
|
157
|
+
frame.setAttribute("inert", "");
|
|
158
|
+
const dialogOrigin = new URL(host).origin;
|
|
159
|
+
frame.allow = [
|
|
160
|
+
`publickey-credentials-get ${dialogOrigin}`,
|
|
161
|
+
`publickey-credentials-create ${dialogOrigin}`,
|
|
162
|
+
"payment",
|
|
163
|
+
].join("; ");
|
|
164
|
+
frame.style.cssText = "border:0;width:min(440px,calc(100vw - 24px));height:min(720px,calc(100vh - 24px));background:#161616";
|
|
165
|
+
frame.style.display = "none";
|
|
166
|
+
modal.append(frame);
|
|
167
|
+
document.body.append(modal);
|
|
168
|
+
ready = new Promise((resolve) => frame.addEventListener("load", resolve, { once: true }));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function rejectActive(error) {
|
|
172
|
+
if (!active) return;
|
|
173
|
+
const current = active;
|
|
174
|
+
active = undefined;
|
|
175
|
+
if (modal?.open) modal.close();
|
|
176
|
+
frame.tabIndex = -1;
|
|
177
|
+
frame.setAttribute("inert", "");
|
|
178
|
+
frame.style.display = "none";
|
|
179
|
+
current.reject(error);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function onMessage(event) {
|
|
183
|
+
if (!active || event.origin !== new URL(host).origin || event.source !== frame?.contentWindow) return;
|
|
184
|
+
const message = event.data;
|
|
185
|
+
if (!message || message.type !== "nanocodex:response" || message.id !== active.request.id) return;
|
|
186
|
+
const current = active;
|
|
187
|
+
active = undefined;
|
|
188
|
+
modal?.close();
|
|
189
|
+
frame.tabIndex = -1;
|
|
190
|
+
frame.setAttribute("inert", "");
|
|
191
|
+
frame.style.display = "none";
|
|
192
|
+
if (message.error) {
|
|
193
|
+
current.reject(new UserRejectedRequestError(message.error.message));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
current.resolve(message.result);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
window.addEventListener("message", onMessage);
|
|
200
|
+
|
|
201
|
+
function mountWallet(nextHost) {
|
|
202
|
+
const url = new URL(nextHost ?? host);
|
|
203
|
+
if (!url.searchParams.has("origin")) url.searchParams.set("origin", window.location.origin);
|
|
204
|
+
url.searchParams.set("mode", "iframe");
|
|
205
|
+
const source = url.toString();
|
|
206
|
+
if (walletFrame && walletModal && walletHost === source) return;
|
|
207
|
+
walletModal?.remove();
|
|
208
|
+
walletModal = document.createElement("dialog");
|
|
209
|
+
walletModal.dataset.nanocodexConnectWallet = "";
|
|
210
|
+
walletModal.setAttribute("aria-label", "Nanocodex Connect");
|
|
211
|
+
walletModal.style.cssText = "border:0;outline:0;padding:0;background:transparent;max-width:none;max-height:none;width:100vw;height:100vh";
|
|
212
|
+
walletModal.addEventListener("cancel", (event) => event.preventDefault());
|
|
213
|
+
const style = document.createElement("style");
|
|
214
|
+
style.textContent = "dialog[data-nanocodex-connect-wallet]::backdrop{background:transparent}";
|
|
215
|
+
walletFrame = document.createElement("iframe");
|
|
216
|
+
walletFrame.dataset.testid = "nanocodex-connect-wallet";
|
|
217
|
+
walletFrame.title = "Nanocodex Connect";
|
|
218
|
+
walletReady = new Promise((resolve) => {
|
|
219
|
+
walletFrame.addEventListener("load", resolve, { once: true });
|
|
220
|
+
});
|
|
221
|
+
walletFrame.src = source;
|
|
222
|
+
const dialogOrigin = url.origin;
|
|
223
|
+
walletFrame.allow = [
|
|
224
|
+
`publickey-credentials-get ${dialogOrigin}`,
|
|
225
|
+
`publickey-credentials-create ${dialogOrigin}`,
|
|
226
|
+
"clipboard-write",
|
|
227
|
+
"payment",
|
|
228
|
+
].join("; ");
|
|
229
|
+
walletFrame.style.cssText = "border:0;position:fixed;inset:0;width:100%;height:100%;background:transparent;color-scheme:light dark";
|
|
230
|
+
setWalletInteractive(walletVisible);
|
|
231
|
+
walletModal.append(style, walletFrame);
|
|
232
|
+
document.body.append(walletModal);
|
|
233
|
+
walletHost = source;
|
|
234
|
+
walletStale = false;
|
|
235
|
+
if (walletVisible) walletModal.showModal();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async function refreshStaleWallet() {
|
|
239
|
+
if (!walletStale) return;
|
|
240
|
+
walletModal?.remove();
|
|
241
|
+
walletFrame = undefined;
|
|
242
|
+
walletHost = undefined;
|
|
243
|
+
walletModal = undefined;
|
|
244
|
+
walletReady = undefined;
|
|
245
|
+
mountWallet(host);
|
|
246
|
+
await walletReady;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function showWallet() {
|
|
250
|
+
walletVisible = true;
|
|
251
|
+
setWalletInteractive(true);
|
|
252
|
+
if (walletModal && !walletModal.open) walletModal.showModal();
|
|
253
|
+
walletFrame?.focus();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function hideWallet() {
|
|
257
|
+
walletVisible = false;
|
|
258
|
+
if (walletModal?.open) walletModal.close();
|
|
259
|
+
setWalletInteractive(false);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function resetWallet() {
|
|
263
|
+
walletVisible = false;
|
|
264
|
+
if (walletModal?.open) walletModal.close();
|
|
265
|
+
setWalletInteractive(false);
|
|
266
|
+
// The hosted account is still finishing its own logout when the Wata
|
|
267
|
+
// response reaches the parent. Keep that document alive until the next
|
|
268
|
+
// connect, then replace it before creating the next Provider session.
|
|
269
|
+
walletStale = true;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function setWalletInteractive(visible) {
|
|
273
|
+
if (!walletFrame) return;
|
|
274
|
+
walletFrame.tabIndex = visible ? 0 : -1;
|
|
275
|
+
walletFrame.style.display = visible ? "block" : "none";
|
|
276
|
+
if (visible) walletFrame.removeAttribute("inert");
|
|
277
|
+
else walletFrame.setAttribute("inert", "");
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Keep the hosted wallet warm from client creation. The iframe remains
|
|
281
|
+
// hidden and inert until a request is made, but its Accounts/WebAuthn
|
|
282
|
+
// runtime can load while the embedding app is already useful.
|
|
283
|
+
mountWallet(host);
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
host,
|
|
287
|
+
hideWallet,
|
|
288
|
+
resetWallet,
|
|
289
|
+
async open(request) {
|
|
290
|
+
if (active) throw new DialogBusyError();
|
|
291
|
+
mount();
|
|
292
|
+
await ready;
|
|
293
|
+
return new Promise((resolve, reject) => {
|
|
294
|
+
active = { reject, request, resolve };
|
|
295
|
+
frame.removeAttribute("inert");
|
|
296
|
+
frame.tabIndex = 0;
|
|
297
|
+
frame.style.display = "block";
|
|
298
|
+
modal.showModal();
|
|
299
|
+
frame.contentWindow.postMessage({
|
|
300
|
+
type: "nanocodex:request",
|
|
301
|
+
id: request.id,
|
|
302
|
+
request,
|
|
303
|
+
}, new URL(host).origin);
|
|
304
|
+
});
|
|
305
|
+
},
|
|
306
|
+
showWallet,
|
|
307
|
+
async waitForWallet() {
|
|
308
|
+
await refreshStaleWallet();
|
|
309
|
+
await walletReady;
|
|
310
|
+
},
|
|
311
|
+
walletTarget(options = {}) {
|
|
312
|
+
mountWallet(options.host);
|
|
313
|
+
if (walletVisible && walletModal && !walletModal.open) walletModal.showModal();
|
|
314
|
+
return walletFrame?.contentWindow;
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function createPopupInstance(host, options) {
|
|
320
|
+
const source = host;
|
|
321
|
+
const targetName = options.target ?? "nanocodex-connect";
|
|
322
|
+
const features = options.features ?? "popup=yes,width=440,height=720,resizable=yes,scrollbars=yes";
|
|
323
|
+
let walletWindow;
|
|
324
|
+
|
|
325
|
+
function showWallet() {
|
|
326
|
+
if (!walletWindow || walletWindow.closed) {
|
|
327
|
+
walletWindow = window.open(source, targetName, features);
|
|
328
|
+
}
|
|
329
|
+
if (!walletWindow) {
|
|
330
|
+
throw new Error("Nanocodex Connect was blocked. Allow the popup and try again.");
|
|
331
|
+
}
|
|
332
|
+
walletWindow.focus?.();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function hideWallet() {
|
|
336
|
+
if (walletWindow && !walletWindow.closed) walletWindow.close();
|
|
337
|
+
walletWindow = undefined;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return {
|
|
341
|
+
host: source,
|
|
342
|
+
async open() {
|
|
343
|
+
throw new Error("The Nanocodex popup supports account authorization only");
|
|
344
|
+
},
|
|
345
|
+
showWallet,
|
|
346
|
+
hideWallet,
|
|
347
|
+
walletTarget() {
|
|
348
|
+
return walletWindow && !walletWindow.closed ? walletWindow : undefined;
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function dialogUrl(host, mode, appId) {
|
|
354
|
+
const url = new URL(host);
|
|
355
|
+
url.searchParams.set("app_id", appId);
|
|
356
|
+
url.searchParams.set("origin", window.location.origin);
|
|
357
|
+
url.searchParams.set("mode", mode);
|
|
358
|
+
return url.toString();
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function requiredString(value, label) {
|
|
362
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
363
|
+
throw new TypeError(`${label} must be a non-empty string`);
|
|
364
|
+
}
|
|
365
|
+
return value;
|
|
366
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare class BaseError extends Error {
|
|
2
|
+
readonly code: string;
|
|
3
|
+
readonly status: number | undefined;
|
|
4
|
+
readonly metaMessages: readonly string[];
|
|
5
|
+
constructor(message: string, options?: Readonly<{
|
|
6
|
+
cause?: unknown;
|
|
7
|
+
code?: string | undefined;
|
|
8
|
+
status?: number | undefined;
|
|
9
|
+
metaMessages?: readonly string[] | undefined;
|
|
10
|
+
}>);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export declare class HttpError extends BaseError {
|
|
14
|
+
constructor(status: number, message: string, options?: Readonly<{
|
|
15
|
+
cause?: unknown;
|
|
16
|
+
code?: string | undefined;
|
|
17
|
+
}>);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export declare class InvalidResponseError extends BaseError {}
|
|
21
|
+
export declare class UserRejectedRequestError extends BaseError {}
|
|
22
|
+
export declare class DialogBusyError extends BaseError {}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class BaseError extends Error {
|
|
2
|
+
constructor(message, options = {}) {
|
|
3
|
+
super(message, options.cause === undefined ? undefined : { cause: options.cause });
|
|
4
|
+
this.name = "Connect.BaseError";
|
|
5
|
+
this.code = options.code ?? "connect_error";
|
|
6
|
+
this.status = options.status;
|
|
7
|
+
this.metaMessages = Object.freeze([...(options.metaMessages ?? [])]);
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class HttpError extends BaseError {
|
|
12
|
+
constructor(status, message, options = {}) {
|
|
13
|
+
super(message, { ...options, code: options.code ?? "http_error", status });
|
|
14
|
+
this.name = "Connect.HttpError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class InvalidResponseError extends BaseError {
|
|
19
|
+
constructor(message, options = {}) {
|
|
20
|
+
super(message, { ...options, code: "invalid_response" });
|
|
21
|
+
this.name = "Connect.InvalidResponseError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class UserRejectedRequestError extends BaseError {
|
|
26
|
+
constructor(message = "The Nanocodex request was rejected.", options = {}) {
|
|
27
|
+
super(message, { ...options, code: "user_rejected_request" });
|
|
28
|
+
this.name = "Connect.UserRejectedRequestError";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class DialogBusyError extends BaseError {
|
|
33
|
+
constructor() {
|
|
34
|
+
super("The Nanocodex dialog is already handling a request.", {
|
|
35
|
+
code: "dialog_busy",
|
|
36
|
+
});
|
|
37
|
+
this.name = "Connect.DialogBusyError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type Exchange = Readonly<{ token: string; expiresAt: number }>;
|
|
2
|
+
|
|
3
|
+
export type Instance = Readonly<{
|
|
4
|
+
create(options: Readonly<{
|
|
5
|
+
resources: readonly string[];
|
|
6
|
+
signal?: AbortSignal | undefined;
|
|
7
|
+
}>): Promise<Exchange>;
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
export type Principal<type extends string = string> = Readonly<{
|
|
11
|
+
key: string;
|
|
12
|
+
name: string;
|
|
13
|
+
type: type;
|
|
14
|
+
setup(context: Readonly<{
|
|
15
|
+
appId: string;
|
|
16
|
+
appOrigin: string | undefined;
|
|
17
|
+
}>): Instance;
|
|
18
|
+
}>;
|
|
19
|
+
|
|
20
|
+
export function host(options?: Readonly<{
|
|
21
|
+
/** Same-origin application route that verifies the current host login. */
|
|
22
|
+
url?: string | URL | undefined;
|
|
23
|
+
fetch?: typeof globalThis.fetch | undefined;
|
|
24
|
+
key?: string | undefined;
|
|
25
|
+
name?: string | undefined;
|
|
26
|
+
}>): Principal<"host">;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
const EXCHANGE_TOKEN = /^[A-Za-z0-9_-]{43}$/;
|
|
2
|
+
const MAX_EXCHANGE_TTL_SECONDS = 300;
|
|
3
|
+
|
|
4
|
+
/** Reads a one-time host-principal exchange from an application-owned route. */
|
|
5
|
+
export function host(options = {}) {
|
|
6
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
7
|
+
if (typeof fetchFn !== "function") throw new TypeError("host principal requires fetch");
|
|
8
|
+
return Object.freeze({
|
|
9
|
+
key: requiredString(options.key ?? "host-principal", "principal key"),
|
|
10
|
+
name: requiredString(options.name ?? "Host application principal", "principal name"),
|
|
11
|
+
type: "host",
|
|
12
|
+
setup({ appId, appOrigin }) {
|
|
13
|
+
const endpoint = principalEndpoint(
|
|
14
|
+
options.url ?? "/api/nanocodex/host-principal",
|
|
15
|
+
appOrigin,
|
|
16
|
+
);
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
async create({ resources, signal } = {}) {
|
|
19
|
+
const exactResources = principalResources(resources);
|
|
20
|
+
const response = await fetchFn(endpoint, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
credentials: "include",
|
|
23
|
+
headers: {
|
|
24
|
+
accept: "application/json",
|
|
25
|
+
"content-type": "application/json",
|
|
26
|
+
"x-nanocodex-app-id": appId,
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify({ resources: exactResources }),
|
|
29
|
+
signal,
|
|
30
|
+
});
|
|
31
|
+
const body = await response.json().catch(() => undefined);
|
|
32
|
+
if (!response.ok) {
|
|
33
|
+
const error = new Error(
|
|
34
|
+
body?.error?.message ?? `The host principal exchange failed with ${response.status}.`,
|
|
35
|
+
);
|
|
36
|
+
error.status = response.status;
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
return principalExchange(body);
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function principalEndpoint(value, appOrigin) {
|
|
47
|
+
let endpoint;
|
|
48
|
+
try {
|
|
49
|
+
endpoint = new URL(String(value), appOrigin);
|
|
50
|
+
} catch {
|
|
51
|
+
throw new TypeError("host principal url requires an absolute application origin");
|
|
52
|
+
}
|
|
53
|
+
if (!appOrigin || endpoint.origin !== appOrigin) {
|
|
54
|
+
throw new TypeError("host principal url must stay on the embedding application's origin");
|
|
55
|
+
}
|
|
56
|
+
if (endpoint.username || endpoint.password || endpoint.hash) {
|
|
57
|
+
throw new TypeError("host principal url cannot contain credentials or a fragment");
|
|
58
|
+
}
|
|
59
|
+
return endpoint;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function principalExchange(value) {
|
|
63
|
+
const now = Math.floor(Date.now() / 1_000);
|
|
64
|
+
if (!value || typeof value !== "object" || Array.isArray(value)
|
|
65
|
+
|| !EXCHANGE_TOKEN.test(value.token)
|
|
66
|
+
|| !Number.isSafeInteger(value.expires_at)
|
|
67
|
+
|| value.expires_at <= now
|
|
68
|
+
|| value.expires_at > now + MAX_EXCHANGE_TTL_SECONDS) {
|
|
69
|
+
throw new TypeError("host principal returned an invalid exchange");
|
|
70
|
+
}
|
|
71
|
+
return Object.freeze({ token: value.token, expiresAt: value.expires_at });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function principalResources(value) {
|
|
75
|
+
if (!Array.isArray(value) || value.length === 0 || value.length > 64
|
|
76
|
+
|| value.some((resource) => typeof resource !== "string"
|
|
77
|
+
|| resource.length === 0 || resource.length > 512)) {
|
|
78
|
+
throw new TypeError("host principal resources must be 1 through 64 bounded strings");
|
|
79
|
+
}
|
|
80
|
+
return Object.freeze([...value]);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function requiredString(value, label) {
|
|
84
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
85
|
+
throw new TypeError(`${label} must be a non-empty string`);
|
|
86
|
+
}
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Wata, postMessage } from "wata";
|
|
2
|
+
|
|
3
|
+
import { UserRejectedRequestError } from "./Errors.mjs";
|
|
4
|
+
|
|
5
|
+
export function create(parameters) {
|
|
6
|
+
const host = walletHost(parameters.host);
|
|
7
|
+
let session;
|
|
8
|
+
let queue = Promise.resolve();
|
|
9
|
+
let state = Object.freeze({ accounts: Object.freeze([]), activeAccount: 0, accessKeys: Object.freeze([]) });
|
|
10
|
+
|
|
11
|
+
function ensureSession() {
|
|
12
|
+
if (session) return session;
|
|
13
|
+
const next = Wata.create({
|
|
14
|
+
transports: [postMessage({
|
|
15
|
+
connect: "eager",
|
|
16
|
+
host,
|
|
17
|
+
target: ({ host: targetHost }) => {
|
|
18
|
+
const target = parameters.target({ host: targetHost });
|
|
19
|
+
if (!target) throw new Error("The Nanocodex Connect wallet host is unavailable.");
|
|
20
|
+
return target;
|
|
21
|
+
},
|
|
22
|
+
})],
|
|
23
|
+
}).start();
|
|
24
|
+
session = next;
|
|
25
|
+
void next.ready.catch(() => {
|
|
26
|
+
if (session === next) session = undefined;
|
|
27
|
+
});
|
|
28
|
+
next.onClose(() => {
|
|
29
|
+
if (session === next) session = undefined;
|
|
30
|
+
});
|
|
31
|
+
next.onNotification((event) => {
|
|
32
|
+
if (event.method !== "accountsChanged" || !Array.isArray(event.params)) return;
|
|
33
|
+
state = Object.freeze({
|
|
34
|
+
accounts: Object.freeze(event.params
|
|
35
|
+
.filter((address) => typeof address === "string")
|
|
36
|
+
.map((address) => Object.freeze({ address }))),
|
|
37
|
+
activeAccount: 0,
|
|
38
|
+
accessKeys: Object.freeze([]),
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
return next;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function request(request) {
|
|
45
|
+
const result = queue.then(async () => {
|
|
46
|
+
try {
|
|
47
|
+
const sent = await ensureSession().send({
|
|
48
|
+
method: request.method,
|
|
49
|
+
params: request.params ?? [],
|
|
50
|
+
...(request.context ? { context: request.context } : {}),
|
|
51
|
+
});
|
|
52
|
+
if (request.method === "wallet_disconnect") {
|
|
53
|
+
state = Object.freeze({ accounts: Object.freeze([]), activeAccount: 0, accessKeys: Object.freeze([]) });
|
|
54
|
+
}
|
|
55
|
+
return sent.result;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error?.code === 4001) {
|
|
58
|
+
throw new UserRejectedRequestError(error.message, { cause: error });
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
queue = result.catch(() => undefined);
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return Object.freeze({
|
|
68
|
+
prepare() {
|
|
69
|
+
return ensureSession().ready;
|
|
70
|
+
},
|
|
71
|
+
async reset() {
|
|
72
|
+
const current = session;
|
|
73
|
+
session = undefined;
|
|
74
|
+
state = Object.freeze({ accounts: Object.freeze([]), activeAccount: 0, accessKeys: Object.freeze([]) });
|
|
75
|
+
await current?.close();
|
|
76
|
+
},
|
|
77
|
+
request,
|
|
78
|
+
store: Object.freeze({ getState: () => state }),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function walletHost(host) {
|
|
83
|
+
if (typeof window === "undefined") return host;
|
|
84
|
+
const url = new URL(host);
|
|
85
|
+
url.searchParams.set("origin", window.location.origin);
|
|
86
|
+
if (!url.searchParams.has("mode")) url.searchParams.set("mode", "iframe");
|
|
87
|
+
return url.toString();
|
|
88
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const DEFAULT_API_URL: "https://api.nanocodex.xyz";
|
|
2
|
+
export const MOCK_ACCOUNT_ADDRESS: `0x${string}`;
|
|
3
|
+
export const MOCK_MACHINE_USD_ADDRESS: `0x${string}`;
|
|
4
|
+
|
|
5
|
+
export type Request = Readonly<{
|
|
6
|
+
path: string;
|
|
7
|
+
method?: "GET" | "POST" | "DELETE" | undefined;
|
|
8
|
+
headers?: HeadersInit | undefined;
|
|
9
|
+
body?: unknown;
|
|
10
|
+
signal?: AbortSignal | undefined;
|
|
11
|
+
}>;
|
|
12
|
+
|
|
13
|
+
export type Instance = Readonly<{
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
fetch?(input: RequestInfo | URL, init?: RequestInit | undefined): Promise<Response>;
|
|
16
|
+
request(request: Request): Promise<unknown>;
|
|
17
|
+
}>;
|
|
18
|
+
|
|
19
|
+
export type Transport<type extends string = string> = Readonly<{
|
|
20
|
+
key: string;
|
|
21
|
+
name: string;
|
|
22
|
+
type: type;
|
|
23
|
+
setup(options: Readonly<{ appId: string }>): Instance;
|
|
24
|
+
}>;
|
|
25
|
+
|
|
26
|
+
export function from<const type extends string>(parameters: Readonly<{
|
|
27
|
+
key: string;
|
|
28
|
+
name: string;
|
|
29
|
+
type: type;
|
|
30
|
+
setup(options: Readonly<{ appId: string }>): Instance;
|
|
31
|
+
}>): Transport<type>;
|
|
32
|
+
|
|
33
|
+
export function http(url?: string | undefined, options?: Readonly<{
|
|
34
|
+
credentials?: RequestCredentials | undefined;
|
|
35
|
+
fetch?: typeof globalThis.fetch | undefined;
|
|
36
|
+
key?: string | undefined;
|
|
37
|
+
name?: string | undefined;
|
|
38
|
+
}>): Transport<"http">;
|
|
39
|
+
|
|
40
|
+
export function mock(options?: Readonly<{
|
|
41
|
+
accountAddress?: `0x${string}` | undefined;
|
|
42
|
+
appName?: string | undefined;
|
|
43
|
+
appOrigin?: string | undefined;
|
|
44
|
+
key?: string | undefined;
|
|
45
|
+
machineUsdAddress?: `0x${string}` | undefined;
|
|
46
|
+
name?: string | undefined;
|
|
47
|
+
}>): Transport<"mock">;
|