@hellolynk-ai/codex-plugin 0.0.0-stage → 0.2.99
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/.agents/plugins/marketplace.json +20 -0
- package/LICENSE +92 -0
- package/README.md +86 -2
- package/bin/hellolynk-client-setup.mjs +2748 -0
- package/bin/hellolynk-mcp-config-shape.mjs +23 -0
- package/hellolynk-client-pack-manifest.json +619 -0
- package/hellolynk-client-pack-pin.json +4 -0
- package/package.json +58 -4
- package/plugins/hellolynk-codex/.app.json +3 -0
- package/plugins/hellolynk-codex/.codex-plugin/plugin.json +38 -0
- package/plugins/hellolynk-codex/.mcp.json +19 -0
- package/plugins/hellolynk-codex/assets/hellolynk-mark.png +0 -0
- package/plugins/hellolynk-codex/package.json +11 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-client-account.mjs +180 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-client-core.mjs +770 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-client-profile.mjs +191 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-host-auth.mjs +347 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-host-protected-store.mjs +2721 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-local-process-lock.mjs +157 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-neutral-host-installation-store.mjs +765 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-platform-credential-store.mjs +773 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-runtime-safety.cjs +471 -0
- package/plugins/hellolynk-codex/runtime/bootstrap/platform/windows/hellolynk-host-protected-store.ps1 +2866 -0
- package/plugins/hellolynk-codex/runtime/connect-activate.mjs +837 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-agent-configurator.mjs +701 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-client-account.mjs +180 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-client-core.mjs +770 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-client-profile.mjs +191 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update-entry.mjs +31 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update-runtime.mjs +600 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update.mjs +453 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-contact-request-e2ee.mjs +867 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-device-enrollment.mjs +435 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-direct-text-e2ee-client.mjs +1964 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-direct-text-e2ee.mjs +1207 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-host-auth.mjs +347 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-host-protected-store.mjs +2721 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-host-transport-client.mjs +946 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-host.mjs +2374 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-human-confirmation-ledger.mjs +256 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-human-relationship-controller.mjs +1234 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-inbox-read-state.mjs +11 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-indexed-message-store.mjs +1558 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-instance-conversation.mjs +185 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-local-contact-requests.mjs +1733 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-local-contacts.mjs +1228 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-local-data-migration.mjs +766 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-local-data-protection.mjs +747 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-local-identity-trust.mjs +274 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-local-messaging.mjs +3043 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-local-peer-transport.mjs +103 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-local-process-lock.mjs +157 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-model-inbox.mjs +230 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-model-notices.cjs +60 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-native-addressing-tools.cjs +231 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-native-conversations.mjs +280 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-native-human-confirmation-broker.mjs +1036 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-native-inbox-runtime.mjs +553 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-native-notice.mjs +50 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-native-reply-routes.mjs +96 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-native-worker-lease.mjs +84 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-assembly.mjs +955 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-installation-store.mjs +765 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-launcher.mjs +665 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-process.mjs +4374 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-store-adapters.mjs +548 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-workbench-read-model.mjs +1365 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-platform-credential-store.mjs +773 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-relay-client-cli.mjs +232 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-release-retention.mjs +160 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-runtime-safety.cjs +471 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-workbench-action-grants.mjs +457 -0
- package/plugins/hellolynk-codex/runtime/core/hellolynk-workbench-connection.mjs +234 -0
- package/plugins/hellolynk-codex/runtime/neutral-host-bootstrap.mjs +64 -0
- package/plugins/hellolynk-codex/runtime/neutral-host-release-entry.mjs +70 -0
- package/plugins/hellolynk-codex/runtime/neutral-host-release-loader.mjs +156 -0
- package/plugins/hellolynk-codex/runtime/neutral-host-release-manifest.json +358 -0
- package/plugins/hellolynk-codex/runtime/neutral-host-release-pin.json +4 -0
- package/plugins/hellolynk-codex/runtime/platform/windows/configure-agent.ps1 +281 -0
- package/plugins/hellolynk-codex/runtime/platform/windows/credential-store.ps1 +844 -0
- package/plugins/hellolynk-codex/runtime/platform/windows/hellolynk-host-protected-store.ps1 +2866 -0
- package/plugins/hellolynk-codex/runtime/platform/windows/hellolynk-human-confirmation-ledger.ps1 +155 -0
- package/plugins/hellolynk-codex/runtime/platform/windows/hellolynk-local-data-key.ps1 +300 -0
- package/plugins/hellolynk-codex/runtime/platform/windows/hellolynk-native-human-confirmation-broker.ps1 +216 -0
- package/plugins/hellolynk-codex/runtime/workbench/candidate-bootstrap.mjs +54 -0
- package/plugins/hellolynk-codex/runtime/workbench/contract.mjs +1314 -0
- package/plugins/hellolynk-codex/runtime/workbench/hellolynk-workbench-build.json +215 -0
- package/plugins/hellolynk-codex/runtime/workbench/host-capabilities.mjs +80 -0
- package/plugins/hellolynk-codex/runtime/workbench/i18n.mjs +1127 -0
- package/plugins/hellolynk-codex/runtime/workbench/loopback-surface.mjs +740 -0
- package/plugins/hellolynk-codex/runtime/workbench/mcp-app-bundle.mjs +97 -0
- package/plugins/hellolynk-codex/runtime/workbench/service.mjs +485 -0
- package/plugins/hellolynk-codex/runtime/workbench/state.mjs +421 -0
- package/plugins/hellolynk-codex/runtime/workbench/transports.mjs +171 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/app.mjs +6120 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/connection-form.mjs +155 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/hellolynk-mark.png +0 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/http-transport.mjs +247 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/icons/arrow-left.svg +3 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/icons/close.svg +3 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/icons/contacts.svg +3 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/icons/inbox.svg +3 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/icons/refresh.svg +3 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/icons/search.svg +3 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/icons/security.svg +3 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/icons/settings.svg +3 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/index.html +139 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/loopback-entry.mjs +26 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/mcp-app-client.mjs +151 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/mcp-app-entry.mjs +452 -0
- package/plugins/hellolynk-codex/runtime/workbench/ui/styles.css +686 -0
- package/plugins/hellolynk-codex/server/codex-neutral-production.mjs +520 -0
- package/plugins/hellolynk-codex/server/mcp-proxy.mjs +306 -0
- package/plugins/hellolynk-codex/server/mcp-server.mjs +1193 -0
- package/plugins/hellolynk-codex/server/native-conversation-directory.mjs +33 -0
- package/plugins/hellolynk-codex/server/native-reply-routes.mjs +32 -0
- package/plugins/hellolynk-codex/server/native-task-client.mjs +382 -0
- package/plugins/hellolynk-codex/server/native-task-runtime.mjs +8 -0
- package/plugins/hellolynk-codex/server/neutral-host-adapter.mjs +649 -0
- package/plugins/hellolynk-codex/server/workbench-runtime.mjs +180 -0
- package/plugins/hellolynk-codex/skills/hellolynk-open/SKILL.md +11 -0
- package/plugins/hellolynk-codex/skills/hellolynk-open/agents/openai.yaml +4 -0
- package/tools/hellolynk-activate-neutral-host-clients.mjs +837 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
5
|
+
const ID = /^[A-Za-z0-9][A-Za-z0-9_.:-]{2,240}$/;
|
|
6
|
+
const hash = (value) => crypto.createHash("sha256").update(value).digest("hex");
|
|
7
|
+
const valid = (value) => typeof value === "string" && ID.test(value);
|
|
8
|
+
const fail = () => { throw new Error("native_reply_route_invalid"); };
|
|
9
|
+
|
|
10
|
+
// Only local executor metadata supplies threadId. Neither message text nor a
|
|
11
|
+
// model-supplied tool argument can name the native destination.
|
|
12
|
+
export async function rememberNativeReplyRoute(scope, input) {
|
|
13
|
+
const { directory, scopeHash } = location(scope);
|
|
14
|
+
const record = { version: 1, scopeHash, clientMessageId: input.clientMessageId,
|
|
15
|
+
threadId: input.threadId, conversationKey: input.conversationKey ?? null,
|
|
16
|
+
peerDelegateId: input.peerDelegateId ?? null };
|
|
17
|
+
validate(record, scopeHash, input.clientMessageId);
|
|
18
|
+
await safeDirectory(scope.runtimeRoot);
|
|
19
|
+
await fs.mkdir(directory, { recursive: true, mode: 0o700 });
|
|
20
|
+
await safeDirectory(directory);
|
|
21
|
+
const file = path.join(directory, `${hash(record.clientMessageId)}.json`);
|
|
22
|
+
const temporary = `${file}.${process.pid}.${crypto.randomBytes(8).toString("hex")}.tmp`;
|
|
23
|
+
let handle, temporaryCreated = false;
|
|
24
|
+
try {
|
|
25
|
+
// Publish only a complete, synced record. A link is exclusive and atomic;
|
|
26
|
+
// an existing clientMessageId is never replaced or taken over.
|
|
27
|
+
handle = await fs.open(temporary, "wx", 0o600);
|
|
28
|
+
temporaryCreated = true;
|
|
29
|
+
await handle.writeFile(JSON.stringify(record));
|
|
30
|
+
await handle.sync();
|
|
31
|
+
await handle.close();
|
|
32
|
+
handle = null;
|
|
33
|
+
try {
|
|
34
|
+
await fs.link(temporary, file);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (error.code !== "EEXIST") throw error;
|
|
37
|
+
const existing = await readRecord(file, scopeHash, record.clientMessageId);
|
|
38
|
+
if (JSON.stringify(existing) !== JSON.stringify(record)) throw new Error("native_reply_route_conflict");
|
|
39
|
+
}
|
|
40
|
+
} finally {
|
|
41
|
+
// The body either published a complete route or already threw its cause.
|
|
42
|
+
// Cleanup must not replace that result with a secondary close/unlink error.
|
|
43
|
+
try { await handle?.close(); } catch {}
|
|
44
|
+
if (temporaryCreated) await fs.unlink(temporary).catch(() => {});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function readNativeReplyRoute(scope, message) {
|
|
49
|
+
if (message.replyToClientMessageId == null) return null;
|
|
50
|
+
if (!valid(message.replyToClientMessageId)) fail();
|
|
51
|
+
const { directory, scopeHash } = location(scope);
|
|
52
|
+
try {
|
|
53
|
+
await safeDirectory(directory);
|
|
54
|
+
const record = await readRecord(path.join(directory, `${hash(message.replyToClientMessageId)}.json`),
|
|
55
|
+
scopeHash, message.replyToClientMessageId);
|
|
56
|
+
if (record.conversationKey && record.conversationKey !== message.conversationKey) fail();
|
|
57
|
+
if (record.peerDelegateId && record.peerDelegateId !== message.peerDelegateId) fail();
|
|
58
|
+
return record;
|
|
59
|
+
} catch (error) { if (error.code === "ENOENT") return null; throw error; }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function nativeReplyRouteLocation(scope) {
|
|
63
|
+
if (!scope || !path.isAbsolute(scope.runtimeRoot || "") || !["codex", "claude-code", "dsh", "openclaw", "workbuddy", "cursor", "trae-work"].includes(scope.adapterId)) fail();
|
|
64
|
+
for (const key of ["region", "principalId", "delegateId"])
|
|
65
|
+
if (typeof scope[key] !== "string" || !/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,240}$/.test(scope[key])) fail();
|
|
66
|
+
const root = path.resolve(scope.runtimeRoot);
|
|
67
|
+
const scopeHash = hash(JSON.stringify([process.platform === "win32" ? root.toLowerCase() : root,
|
|
68
|
+
scope.region, scope.principalId, scope.delegateId, scope.adapterId]));
|
|
69
|
+
return { scopeHash, directory: path.join(root, "native-origins", scopeHash) };
|
|
70
|
+
}
|
|
71
|
+
const location = nativeReplyRouteLocation;
|
|
72
|
+
function validate(record, scopeHash, id) {
|
|
73
|
+
if (record?.version !== 1 || record.scopeHash !== scopeHash || record.clientMessageId !== id
|
|
74
|
+
|| !valid(id) || !valid(record.threadId)
|
|
75
|
+
|| (!record.conversationKey && !record.peerDelegateId)
|
|
76
|
+
|| (record.conversationKey !== null && !valid(record.conversationKey))
|
|
77
|
+
|| (record.peerDelegateId !== null && !valid(record.peerDelegateId))
|
|
78
|
+
|| Object.keys(record).sort().join() !== "clientMessageId,conversationKey,peerDelegateId,scopeHash,threadId,version") fail();
|
|
79
|
+
}
|
|
80
|
+
async function readRecord(file, scopeHash, id) {
|
|
81
|
+
const stat = await fs.lstat(file);
|
|
82
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 8192) fail();
|
|
83
|
+
const record = JSON.parse(await fs.readFile(file, "utf8"));
|
|
84
|
+
validate(record, scopeHash, id);
|
|
85
|
+
return record;
|
|
86
|
+
}
|
|
87
|
+
async function safeDirectory(value) {
|
|
88
|
+
let current = path.resolve(value);
|
|
89
|
+
while (true) {
|
|
90
|
+
const stat = await fs.lstat(current);
|
|
91
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) fail();
|
|
92
|
+
const parent = path.dirname(current);
|
|
93
|
+
if (current === parent) return;
|
|
94
|
+
current = parent;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import net from "node:net";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { withHelloLynkLocalMutationLock } from "./hellolynk-local-messaging.mjs";
|
|
7
|
+
|
|
8
|
+
// A live OS handle elects one receiver for a client/account. It has no expiry:
|
|
9
|
+
// slow model work must never let a second receiver take over. Process death
|
|
10
|
+
// closes the handle. Only election itself takes the short filesystem lock.
|
|
11
|
+
export async function tryAcquireNativeWorkerLease(scope) {
|
|
12
|
+
const { runtimeRoot, adapterId, principalId, delegateId, region } = scope || {};
|
|
13
|
+
if (typeof runtimeRoot !== "string" || !path.isAbsolute(runtimeRoot)
|
|
14
|
+
|| [adapterId, principalId, delegateId, region].some((value) =>
|
|
15
|
+
typeof value !== "string" || !/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,240}$/.test(value))) {
|
|
16
|
+
throw failure("native_worker_scope_invalid");
|
|
17
|
+
}
|
|
18
|
+
const root = process.platform === "win32" ? path.resolve(runtimeRoot).toLowerCase() : path.resolve(runtimeRoot);
|
|
19
|
+
const key = crypto.createHash("sha256").update(JSON.stringify([root, adapterId, principalId, delegateId, region])).digest("hex");
|
|
20
|
+
const guard = path.join(runtimeRoot, "native-workers", key);
|
|
21
|
+
let endpoint;
|
|
22
|
+
if (process.platform === "win32") endpoint = `\\\\.\\pipe\\hellolynk-native-${key}`;
|
|
23
|
+
else {
|
|
24
|
+
const directory = path.join(os.tmpdir(), `hellolynk-native-${process.getuid()}`);
|
|
25
|
+
await fs.mkdir(directory, { mode: 0o700 }).catch((error) => { if (error.code !== "EEXIST") throw error; });
|
|
26
|
+
const stat = await fs.lstat(directory);
|
|
27
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid() || (stat.mode & 0o077)) {
|
|
28
|
+
throw failure("native_worker_socket_directory_unsafe");
|
|
29
|
+
}
|
|
30
|
+
endpoint = path.join(directory, `${key.slice(0, 40)}.sock`);
|
|
31
|
+
}
|
|
32
|
+
return withHelloLynkLocalMutationLock(guard, async () => {
|
|
33
|
+
let server = await listen(endpoint);
|
|
34
|
+
if (!server && process.platform !== "win32" && await isStaleSocket(endpoint)) {
|
|
35
|
+
// Every acquisition/release uses the same guard, so a different worker
|
|
36
|
+
// cannot bind between the liveness check and removing the stale socket.
|
|
37
|
+
await fs.unlink(endpoint).catch((error) => { if (error.code !== "ENOENT") throw error; });
|
|
38
|
+
server = await listen(endpoint);
|
|
39
|
+
}
|
|
40
|
+
if (!server) return null;
|
|
41
|
+
let releaseFlight;
|
|
42
|
+
return Object.freeze({
|
|
43
|
+
release() {
|
|
44
|
+
if (!releaseFlight) releaseFlight = withHelloLynkLocalMutationLock(guard, () =>
|
|
45
|
+
new Promise((resolve, reject) => server.close((error) => error ? reject(error) : resolve())));
|
|
46
|
+
return releaseFlight;
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function listen(endpoint) {
|
|
53
|
+
return new Promise((resolve, reject) => {
|
|
54
|
+
const server = net.createServer((socket) => socket.destroy());
|
|
55
|
+
server.once("error", (error) => {
|
|
56
|
+
if (error.code === "EADDRINUSE") resolve(null);
|
|
57
|
+
else reject(error);
|
|
58
|
+
});
|
|
59
|
+
server.listen({ path: endpoint, exclusive: true }, () => {
|
|
60
|
+
server.unref();
|
|
61
|
+
resolve(server);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function isStaleSocket(endpoint) {
|
|
67
|
+
const stat = await fs.lstat(endpoint).catch((error) => {
|
|
68
|
+
if (error.code === "ENOENT") return null;
|
|
69
|
+
throw error;
|
|
70
|
+
});
|
|
71
|
+
if (!stat) return true;
|
|
72
|
+
if (!stat.isSocket() || stat.isSymbolicLink() || stat.uid !== process.getuid()) throw failure("native_worker_socket_unsafe");
|
|
73
|
+
return new Promise((resolve, reject) => {
|
|
74
|
+
const socket = net.createConnection(endpoint);
|
|
75
|
+
socket.once("connect", () => { socket.destroy(); resolve(false); });
|
|
76
|
+
socket.once("error", (error) => {
|
|
77
|
+
socket.destroy();
|
|
78
|
+
if (["ECONNREFUSED", "ENOENT"].includes(error.code)) resolve(true);
|
|
79
|
+
else reject(error);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function failure(code) { return Object.assign(new Error(code), { code }); }
|